Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/shell/ash.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/shell/ash.c
r1772 r2725 2 2 /* 3 3 * ash shell port for busybox 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Kenneth Almquist. 7 * 8 * Original BSD copyright notice is retained at the end of this file. 4 9 * 5 10 * Copyright (c) 1989, 1991, 1993, 1994 … … 9 14 * was re-ported from NetBSD and debianized. 10 15 * 11 * 12 * This code is derived from software contributed to Berkeley by 13 * Kenneth Almquist. 14 * 15 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. 16 * 17 * Original BSD copyright notice is retained at the end of this file. 18 */ 19 20 /* 21 * rewrite arith.y to micro stack based cryptic algorithm by 22 * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com> 23 * 24 * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support 25 * dynamic variables. 26 * 27 * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2005 to be 28 * used in busybox and size optimizations, 29 * rewrote arith (see notes to this), added locale support, 30 * rewrote dynamic variables. 31 * 32 */ 33 34 /* 35 * The follow should be set to reflect the type of system you have: 16 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 17 */ 18 19 /* 20 * The following should be set to reflect the type of system you have: 36 21 * JOBS -> 1 if you have Berkeley job control, 0 otherwise. 37 22 * define SYSV if you are running under System V. … … 43 28 */ 44 29 #define DEBUG 0 45 #define IFS_BROKEN 30 /* Tweak debug output verbosity here */ 31 #define DEBUG_TIME 0 32 #define DEBUG_PID 1 33 #define DEBUG_SIG 1 34 46 35 #define PROFILE 0 47 #if ENABLE_ASH_JOB_CONTROL 48 #define JOBS 1 49 #else 50 #define JOBS 0 51 #endif 52 53 #if DEBUG 54 #define _GNU_SOURCE 55 #endif 56 #include "busybox.h" /* for struct bb_applet */ 36 37 #define JOBS ENABLE_ASH_JOB_CONTROL 38 39 #include "busybox.h" /* for applet_names */ 57 40 #include <paths.h> 58 41 #include <setjmp.h> 59 42 #include <fnmatch.h> 60 #if JOBS || ENABLE_ASH_READ_NCHARS 61 #include <termios.h> 62 #endif 63 extern char **environ; 64 65 #if defined(__uClinux__) 66 #error "Do not even bother, ash will not run on uClinux" 67 #endif 68 69 70 /* ============ Misc helpers */ 71 72 #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0) 73 74 /* C99 say: "char" declaration may be signed or unsigned default */ 75 #define signed_char2int(sc) ((int)((signed char)sc)) 43 #include <sys/times.h> 44 45 #include "shell_common.h" 46 #if ENABLE_SH_MATH_SUPPORT 47 # include "math.h" 48 #endif 49 #if ENABLE_ASH_RANDOM_SUPPORT 50 # include "random.h" 51 #else 52 # define CLEAR_RANDOM_T(rnd) ((void)0) 53 #endif 54 55 #include "NUM_APPLETS.h" 56 #if NUM_APPLETS == 1 57 /* STANDALONE does not make sense, and won't compile */ 58 # undef CONFIG_FEATURE_SH_STANDALONE 59 # undef ENABLE_FEATURE_SH_STANDALONE 60 # undef IF_FEATURE_SH_STANDALONE 61 # undef IF_NOT_FEATURE_SH_STANDALONE 62 # define ENABLE_FEATURE_SH_STANDALONE 0 63 # define IF_FEATURE_SH_STANDALONE(...) 64 # define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__ 65 #endif 66 67 #ifndef PIPE_BUF 68 # define PIPE_BUF 4096 /* amount of buffering in a pipe */ 69 #endif 70 71 #if !BB_MMU 72 # error "Do not even bother, ash will not run on NOMMU machine" 73 #endif 74 75 //applet:IF_ASH(APPLET(ash, _BB_DIR_BIN, _BB_SUID_DROP)) 76 //applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, _BB_DIR_BIN, _BB_SUID_DROP, sh)) 77 //applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, _BB_DIR_BIN, _BB_SUID_DROP, bash)) 78 79 //kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o 80 //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o 81 82 //config:config ASH 83 //config: bool "ash" 84 //config: default y 85 //config: depends on !NOMMU 86 //config: help 87 //config: Tha 'ash' shell adds about 60k in the default configuration and is 88 //config: the most complete and most pedantically correct shell included with 89 //config: busybox. This shell is actually a derivative of the Debian 'dash' 90 //config: shell (by Herbert Xu), which was created by porting the 'ash' shell 91 //config: (written by Kenneth Almquist) from NetBSD. 92 //config: 93 //config:config ASH_BASH_COMPAT 94 //config: bool "bash-compatible extensions" 95 //config: default y 96 //config: depends on ASH 97 //config: help 98 //config: Enable bash-compatible extensions. 99 //config: 100 //config:config ASH_JOB_CONTROL 101 //config: bool "Job control" 102 //config: default y 103 //config: depends on ASH 104 //config: help 105 //config: Enable job control in the ash shell. 106 //config: 107 //config:config ASH_ALIAS 108 //config: bool "alias support" 109 //config: default y 110 //config: depends on ASH 111 //config: help 112 //config: Enable alias support in the ash shell. 113 //config: 114 //config:config ASH_GETOPTS 115 //config: bool "Builtin getopt to parse positional parameters" 116 //config: default y 117 //config: depends on ASH 118 //config: help 119 //config: Enable getopts builtin in the ash shell. 120 //config: 121 //config:config ASH_BUILTIN_ECHO 122 //config: bool "Builtin version of 'echo'" 123 //config: default y 124 //config: depends on ASH 125 //config: help 126 //config: Enable support for echo, builtin to ash. 127 //config: 128 //config:config ASH_BUILTIN_PRINTF 129 //config: bool "Builtin version of 'printf'" 130 //config: default y 131 //config: depends on ASH 132 //config: help 133 //config: Enable support for printf, builtin to ash. 134 //config: 135 //config:config ASH_BUILTIN_TEST 136 //config: bool "Builtin version of 'test'" 137 //config: default y 138 //config: depends on ASH 139 //config: help 140 //config: Enable support for test, builtin to ash. 141 //config: 142 //config:config ASH_CMDCMD 143 //config: bool "'command' command to override shell builtins" 144 //config: default y 145 //config: depends on ASH 146 //config: help 147 //config: Enable support for the ash 'command' builtin, which allows 148 //config: you to run the specified command with the specified arguments, 149 //config: even when there is an ash builtin command with the same name. 150 //config: 151 //config:config ASH_MAIL 152 //config: bool "Check for new mail on interactive shells" 153 //config: default n 154 //config: depends on ASH 155 //config: help 156 //config: Enable "check for new mail" in the ash shell. 157 //config: 158 //config:config ASH_OPTIMIZE_FOR_SIZE 159 //config: bool "Optimize for size instead of speed" 160 //config: default y 161 //config: depends on ASH 162 //config: help 163 //config: Compile ash for reduced size at the price of speed. 164 //config: 165 //config:config ASH_RANDOM_SUPPORT 166 //config: bool "Pseudorandom generator and $RANDOM variable" 167 //config: default y 168 //config: depends on ASH 169 //config: help 170 //config: Enable pseudorandom generator and dynamic variable "$RANDOM". 171 //config: Each read of "$RANDOM" will generate a new pseudorandom value. 172 //config: You can reset the generator by using a specified start value. 173 //config: After "unset RANDOM" the generator will switch off and this 174 //config: variable will no longer have special treatment. 175 //config: 176 //config:config ASH_EXPAND_PRMT 177 //config: bool "Expand prompt string" 178 //config: default y 179 //config: depends on ASH 180 //config: help 181 //config: "PS#" may contain volatile content, such as backquote commands. 182 //config: This option recreates the prompt string from the environment 183 //config: variable each time it is displayed. 184 //config: 185 186 //usage:#define ash_trivial_usage NOUSAGE_STR 187 //usage:#define ash_full_usage "" 188 //usage:#define sh_trivial_usage NOUSAGE_STR 189 //usage:#define sh_full_usage "" 190 //usage:#define bash_trivial_usage NOUSAGE_STR 191 //usage:#define bash_full_usage "" 192 193 194 /* ============ Hash table sizes. Configurable. */ 195 196 #define VTABSIZE 39 197 #define ATABSIZE 39 198 #define CMDTABLESIZE 31 /* should be prime */ 76 199 77 200 … … 93 216 "u" "nounset", 94 217 "\0" "vi" 218 #if ENABLE_ASH_BASH_COMPAT 219 ,"\0" "pipefail" 220 #endif 95 221 #if DEBUG 96 222 ,"\0" "nolog" … … 99 225 }; 100 226 101 #define optletters(n) optletters_optnames[(n)][0]102 #define optnames(n) (&optletters_optnames[(n)][1])227 #define optletters(n) optletters_optnames[n][0] 228 #define optnames(n) (optletters_optnames[n] + 1) 103 229 104 230 enum { NOPTS = ARRAY_SIZE(optletters_optnames) }; 105 231 106 static char optlist[NOPTS] ALIGN1; 107 232 233 /* ============ Misc data */ 234 235 #define msg_illnum "Illegal number: %s" 236 237 /* 238 * We enclose jmp_buf in a structure so that we can declare pointers to 239 * jump locations. The global variable handler contains the location to 240 * jump to when an exception occurs, and the global variable exception_type 241 * contains a code identifying the exception. To implement nested 242 * exception handlers, the user should save the value of handler on entry 243 * to an inner scope, set handler to point to a jmploc structure for the 244 * inner scope, and restore handler on exit from the scope. 245 */ 246 struct jmploc { 247 jmp_buf loc; 248 }; 249 250 struct globals_misc { 251 /* pid of main shell */ 252 int rootpid; 253 /* shell level: 0 for the main shell, 1 for its children, and so on */ 254 int shlvl; 255 #define rootshell (!shlvl) 256 char *minusc; /* argument to -c option */ 257 258 char *curdir; // = nullstr; /* current working directory */ 259 char *physdir; // = nullstr; /* physical working directory */ 260 261 char *arg0; /* value of $0 */ 262 263 struct jmploc *exception_handler; 264 265 volatile int suppress_int; /* counter */ 266 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */ 267 /* last pending signal */ 268 volatile /*sig_atomic_t*/ smallint pending_sig; 269 smallint exception_type; /* kind of exception (0..5) */ 270 /* exceptions */ 271 #define EXINT 0 /* SIGINT received */ 272 #define EXERROR 1 /* a generic error */ 273 #define EXSHELLPROC 2 /* execute a shell procedure */ 274 #define EXEXEC 3 /* command execution failed */ 275 #define EXEXIT 4 /* exit the shell */ 276 #define EXSIG 5 /* trapped signal in wait(1) */ 277 278 smallint isloginsh; 279 char nullstr[1]; /* zero length string */ 280 281 char optlist[NOPTS]; 108 282 #define eflag optlist[0] 109 283 #define fflag optlist[1] … … 120 294 #define uflag optlist[12] 121 295 #define viflag optlist[13] 296 #if ENABLE_ASH_BASH_COMPAT 297 # define pipefail optlist[14] 298 #else 299 # define pipefail 0 300 #endif 122 301 #if DEBUG 123 #define nolog optlist[14] 124 #define debug optlist[15] 125 #endif 126 127 128 /* ============ Misc data */ 129 130 static char nullstr[1] ALIGN1; /* zero length string */ 131 static const char homestr[] ALIGN1 = "HOME"; 132 static const char snlfmt[] ALIGN1 = "%s\n"; 133 static const char illnum[] ALIGN1 = "Illegal number: %s"; 134 135 static char *minusc; /* argument to -c option */ 136 137 /* pid of main shell */ 138 static int rootpid; 139 /* shell level: 0 for the main shell, 1 for its children, and so on */ 140 static int shlvl; 141 #define rootshell (!shlvl) 142 /* trap handler commands */ 143 static char *trap[NSIG]; 144 static smallint isloginsh; 145 /* current value of signal */ 146 static char sigmode[NSIG - 1]; 147 /* indicates specified signal received */ 148 static char gotsig[NSIG - 1]; 149 static char *arg0; /* value of $0 */ 302 # define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT] 303 # define debug optlist[15 + ENABLE_ASH_BASH_COMPAT] 304 #endif 305 306 /* trap handler commands */ 307 /* 308 * Sigmode records the current value of the signal handlers for the various 309 * modes. A value of zero means that the current handler is not known. 310 * S_HARD_IGN indicates that the signal was ignored on entry to the shell. 311 */ 312 char sigmode[NSIG - 1]; 313 #define S_DFL 1 /* default signal handling (SIG_DFL) */ 314 #define S_CATCH 2 /* signal is caught */ 315 #define S_IGN 3 /* signal is ignored (SIG_IGN) */ 316 #define S_HARD_IGN 4 /* signal is ignored permenantly */ 317 318 /* indicates specified signal received */ 319 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ 320 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */ 321 char *trap[NSIG]; 322 char **trap_ptr; /* used only by "trap hack" */ 323 324 /* Rarely referenced stuff */ 325 #if ENABLE_ASH_RANDOM_SUPPORT 326 random_t random_gen; 327 #endif 328 pid_t backgndpid; /* pid of last background process */ 329 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */ 330 }; 331 extern struct globals_misc *const ash_ptr_to_globals_misc; 332 #define G_misc (*ash_ptr_to_globals_misc) 333 #define rootpid (G_misc.rootpid ) 334 #define shlvl (G_misc.shlvl ) 335 #define minusc (G_misc.minusc ) 336 #define curdir (G_misc.curdir ) 337 #define physdir (G_misc.physdir ) 338 #define arg0 (G_misc.arg0 ) 339 #define exception_handler (G_misc.exception_handler) 340 #define exception_type (G_misc.exception_type ) 341 #define suppress_int (G_misc.suppress_int ) 342 #define pending_int (G_misc.pending_int ) 343 #define pending_sig (G_misc.pending_sig ) 344 #define isloginsh (G_misc.isloginsh ) 345 #define nullstr (G_misc.nullstr ) 346 #define optlist (G_misc.optlist ) 347 #define sigmode (G_misc.sigmode ) 348 #define gotsig (G_misc.gotsig ) 349 #define may_have_traps (G_misc.may_have_traps ) 350 #define trap (G_misc.trap ) 351 #define trap_ptr (G_misc.trap_ptr ) 352 #define random_gen (G_misc.random_gen ) 353 #define backgndpid (G_misc.backgndpid ) 354 #define job_warning (G_misc.job_warning) 355 #define INIT_G_misc() do { \ 356 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \ 357 barrier(); \ 358 curdir = nullstr; \ 359 physdir = nullstr; \ 360 trap_ptr = trap; \ 361 } while (0) 362 363 364 /* ============ DEBUG */ 365 #if DEBUG 366 static void trace_printf(const char *fmt, ...); 367 static void trace_vprintf(const char *fmt, va_list va); 368 # define TRACE(param) trace_printf param 369 # define TRACEV(param) trace_vprintf param 370 # define close(fd) do { \ 371 int dfd = (fd); \ 372 if (close(dfd) < 0) \ 373 bb_error_msg("bug on %d: closing %d(0x%x)", \ 374 __LINE__, dfd, dfd); \ 375 } while (0) 376 #else 377 # define TRACE(param) 378 # define TRACEV(param) 379 #endif 380 381 382 /* ============ Utility functions */ 383 #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0) 384 385 static int isdigit_str9(const char *str) 386 { 387 int maxlen = 9 + 1; /* max 9 digits: 999999999 */ 388 while (--maxlen && isdigit(*str)) 389 str++; 390 return (*str == '\0'); 391 } 392 393 static const char *var_end(const char *var) 394 { 395 while (*var) 396 if (*var++ == '=') 397 break; 398 return var; 399 } 150 400 151 401 152 402 /* ============ Interrupts / exceptions */ 153 154 /*155 * We enclose jmp_buf in a structure so that we can declare pointers to156 * jump locations. The global variable handler contains the location to157 * jump to when an exception occurs, and the global variable exception158 * contains a code identifying the exception. To implement nested159 * exception handlers, the user should save the value of handler on entry160 * to an inner scope, set handler to point to a jmploc structure for the161 * inner scope, and restore handler on exit from the scope.162 */163 struct jmploc {164 jmp_buf loc;165 };166 static struct jmploc *exception_handler;167 static int exception;168 /* exceptions */169 #define EXINT 0 /* SIGINT received */170 #define EXERROR 1 /* a generic error */171 #define EXSHELLPROC 2 /* execute a shell procedure */172 #define EXEXEC 3 /* command execution failed */173 #define EXEXIT 4 /* exit the shell */174 #define EXSIG 5 /* trapped signal in wait(1) */175 static volatile int suppressint;176 static volatile sig_atomic_t intpending;177 /* do we generate EXSIG events */178 static int exsig;179 /* last pending signal */180 static volatile sig_atomic_t pendingsig;181 182 /*183 * Sigmode records the current value of the signal handlers for the various184 * modes. A value of zero means that the current handler is not known.185 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,186 */187 188 #define S_DFL 1 /* default signal handling (SIG_DFL) */189 #define S_CATCH 2 /* signal is caught */190 #define S_IGN 3 /* signal is ignored (SIG_IGN) */191 #define S_HARD_IGN 4 /* signal is ignored permenantly */192 #define S_RESET 5 /* temporary - to reset a hard ignored sig */193 194 403 /* 195 404 * These macros allow the user to suspend the handling of interrupt signals 196 * over a period of time. This is similar to SIGHOLD to orsigblock, but405 * over a period of time. This is similar to SIGHOLD or to sigblock, but 197 406 * much more efficient and portable. (But hacking the kernel is so much 198 407 * more fun than worrying about efficiency and portability. :-)) 199 408 */ 200 #define INT_OFF \ 201 do { \ 202 suppressint++; \ 203 xbarrier(); \ 204 } while (0) 409 #define INT_OFF do { \ 410 suppress_int++; \ 411 xbarrier(); \ 412 } while (0) 205 413 206 414 /* 207 415 * Called to raise an exception. Since C doesn't include exceptions, we 208 416 * just do a longjmp to the exception handler. The type of exception is 209 * stored in the global variable "exception ".210 */ 211 static void raise_exception(int) ATTRIBUTE_NORETURN;417 * stored in the global variable "exception_type". 418 */ 419 static void raise_exception(int) NORETURN; 212 420 static void 213 421 raise_exception(int e) … … 218 426 #endif 219 427 INT_OFF; 220 exception = e;428 exception_type = e; 221 429 longjmp(exception_handler->loc, 1); 222 430 } 431 #if DEBUG 432 #define raise_exception(e) do { \ 433 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \ 434 raise_exception(e); \ 435 } while (0) 436 #endif 223 437 224 438 /* … … 229 443 * defensive programming.) 230 444 */ 231 static void raise_interrupt(void) ATTRIBUTE_NORETURN;445 static void raise_interrupt(void) NORETURN; 232 446 static void 233 447 raise_interrupt(void) 234 448 { 235 int i; 236 sigset_t mask; 237 238 intpending = 0; 239 /* Signal is not automatically re-enabled after it is raised, 240 * do it ourself */ 241 sigemptyset(&mask); 242 sigprocmask(SIG_SETMASK, &mask, 0); 243 /* pendingsig = 0; - now done in onsig() */ 244 245 i = EXSIG; 449 int ex_type; 450 451 pending_int = 0; 452 /* Signal is not automatically unmasked after it is raised, 453 * do it ourself - unmask all signals */ 454 sigprocmask_allsigs(SIG_UNBLOCK); 455 /* pending_sig = 0; - now done in signal_handler() */ 456 457 ex_type = EXSIG; 246 458 if (gotsig[SIGINT - 1] && !trap[SIGINT]) { 247 459 if (!(rootshell && iflag)) { 460 /* Kill ourself with SIGINT */ 248 461 signal(SIGINT, SIG_DFL); 249 462 raise(SIGINT); 250 463 } 251 i= EXINT;252 } 253 raise_exception( i);464 ex_type = EXINT; 465 } 466 raise_exception(ex_type); 254 467 /* NOTREACHED */ 255 468 } 256 257 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE 258 static void 469 #if DEBUG 470 #define raise_interrupt() do { \ 471 TRACE(("raising interrupt on line %d\n", __LINE__)); \ 472 raise_interrupt(); \ 473 } while (0) 474 #endif 475 476 static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void 259 477 int_on(void) 260 478 { 261 if (--suppressint == 0 && intpending) { 479 xbarrier(); 480 if (--suppress_int == 0 && pending_int) { 262 481 raise_interrupt(); 263 482 } 264 483 } 265 484 #define INT_ON int_on() 266 static void485 static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void 267 486 force_int_on(void) 268 487 { 269 suppressint = 0; 270 if (intpending) 488 xbarrier(); 489 suppress_int = 0; 490 if (pending_int) 271 491 raise_interrupt(); 272 492 } 273 493 #define FORCE_INT_ON force_int_on() 274 #else 275 #define INT_ON \ 276 do { \ 277 xbarrier(); \ 278 if (--suppressint == 0 && intpending) \ 279 raise_interrupt(); \ 280 } while (0) 281 #define FORCE_INT_ON \ 282 do { \ 283 xbarrier(); \ 284 suppressint = 0; \ 285 if (intpending) \ 286 raise_interrupt(); \ 287 } while (0) 288 #endif /* ASH_OPTIMIZE_FOR_SIZE */ 289 290 #define SAVE_INT(v) ((v) = suppressint) 291 292 #define RESTORE_INT(v) \ 293 do { \ 294 xbarrier(); \ 295 suppressint = (v); \ 296 if (suppressint == 0 && intpending) \ 297 raise_interrupt(); \ 298 } while (0) 299 300 #define EXSIGON \ 301 do { \ 302 exsig++; \ 303 xbarrier(); \ 304 if (pendingsig) \ 305 raise_exception(EXSIG); \ 306 } while (0) 307 /* EXSIG is turned off by evalbltin(). */ 308 309 /* 310 * Ignore a signal. Only one usage site - in forkchild() 311 */ 312 static void 313 ignoresig(int signo) 314 { 315 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { 316 signal(signo, SIG_IGN); 317 } 318 sigmode[signo - 1] = S_HARD_IGN; 319 } 320 321 /* 322 * Signal handler. Only one usage site - in setsignal() 323 */ 324 static void 325 onsig(int signo) 326 { 327 gotsig[signo - 1] = 1; 328 pendingsig = signo; 329 330 if (exsig || (signo == SIGINT && !trap[SIGINT])) { 331 if (!suppressint) { 332 pendingsig = 0; 333 raise_interrupt(); 334 } 335 intpending = 1; 336 } 337 } 494 495 #define SAVE_INT(v) ((v) = suppress_int) 496 497 #define RESTORE_INT(v) do { \ 498 xbarrier(); \ 499 suppress_int = (v); \ 500 if (suppress_int == 0 && pending_int) \ 501 raise_interrupt(); \ 502 } while (0) 338 503 339 504 … … 352 517 { 353 518 INT_OFF; 354 fflush(stdout); 355 fflush(stderr); 356 INT_ON; 357 } 358 359 static void 360 flush_stderr(void) 361 { 362 INT_OFF; 363 fflush(stderr); 519 fflush_all(); 364 520 INT_ON; 365 521 } … … 414 570 { 415 571 outstr(p, stderr); 416 flush_std err();572 flush_stdout_stderr(); 417 573 } 418 574 … … 421 577 422 578 /* control characters in argument strings */ 423 #define CTLESC '\201' /* escape next character */ 424 #define CTLVAR '\202' /* variable defn */ 425 #define CTLENDVAR '\203' 426 #define CTLBACKQ '\204' 579 #define CTL_FIRST CTLESC 580 #define CTLESC ((unsigned char)'\201') /* escape next character */ 581 #define CTLVAR ((unsigned char)'\202') /* variable defn */ 582 #define CTLENDVAR ((unsigned char)'\203') 583 #define CTLBACKQ ((unsigned char)'\204') 427 584 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */ 428 585 /* CTLBACKQ | CTLQUOTE == '\205' */ 429 #define CTLARI '\206' /* arithmetic expression */ 430 #define CTLENDARI '\207' 431 #define CTLQUOTEMARK '\210' 586 #define CTLARI ((unsigned char)'\206') /* arithmetic expression */ 587 #define CTLENDARI ((unsigned char)'\207') 588 #define CTLQUOTEMARK ((unsigned char)'\210') 589 #define CTL_LAST CTLQUOTEMARK 432 590 433 591 /* variable substitution byte (follows CTLVAR) */ … … 437 595 438 596 /* values of VSTYPE field */ 439 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */ 440 #define VSMINUS 0x2 /* ${var-text} */ 441 #define VSPLUS 0x3 /* ${var+text} */ 442 #define VSQUESTION 0x4 /* ${var?message} */ 443 #define VSASSIGN 0x5 /* ${var=text} */ 444 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */ 445 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */ 446 #define VSTRIMLEFT 0x8 /* ${var#pattern} */ 447 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */ 448 #define VSLENGTH 0xa /* ${#var} */ 597 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */ 598 #define VSMINUS 0x2 /* ${var-text} */ 599 #define VSPLUS 0x3 /* ${var+text} */ 600 #define VSQUESTION 0x4 /* ${var?message} */ 601 #define VSASSIGN 0x5 /* ${var=text} */ 602 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */ 603 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */ 604 #define VSTRIMLEFT 0x8 /* ${var#pattern} */ 605 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */ 606 #define VSLENGTH 0xa /* ${#var} */ 607 #if ENABLE_ASH_BASH_COMPAT 608 #define VSSUBSTR 0xc /* ${var:position:length} */ 609 #define VSREPLACE 0xd /* ${var/pattern/replacement} */ 610 #define VSREPLACEALL 0xe /* ${var//pattern/replacement} */ 611 #endif 449 612 450 613 static const char dolatstr[] ALIGN1 = { … … 452 615 }; 453 616 454 #define NCMD 0455 #define NPIPE 1456 #define NREDIR 2457 #define NBACKGND 3617 #define NCMD 0 618 #define NPIPE 1 619 #define NREDIR 2 620 #define NBACKGND 3 458 621 #define NSUBSHELL 4 459 #define NAND 5 460 #define NOR 6 461 #define NSEMI 7 462 #define NIF 8 463 #define NWHILE 9 464 #define NUNTIL 10 465 #define NFOR 11 466 #define NCASE 12 467 #define NCLIST 13 468 #define NDEFUN 14 469 #define NARG 15 470 #define NTO 16 471 #define NCLOBBER 17 472 #define NFROM 18 473 #define NFROMTO 19 474 #define NAPPEND 20 475 #define NTOFD 21 476 #define NFROMFD 22 477 #define NHERE 23 478 #define NXHERE 24 479 #define NNOT 25 622 #define NAND 5 623 #define NOR 6 624 #define NSEMI 7 625 #define NIF 8 626 #define NWHILE 9 627 #define NUNTIL 10 628 #define NFOR 11 629 #define NCASE 12 630 #define NCLIST 13 631 #define NDEFUN 14 632 #define NARG 15 633 #define NTO 16 634 #if ENABLE_ASH_BASH_COMPAT 635 #define NTO2 17 636 #endif 637 #define NCLOBBER 18 638 #define NFROM 19 639 #define NFROMTO 20 640 #define NAPPEND 21 641 #define NTOFD 22 642 #define NFROMFD 23 643 #define NHERE 24 644 #define NXHERE 25 645 #define NNOT 26 646 #define N_NUMBER 27 480 647 481 648 union node; 482 649 483 650 struct ncmd { 484 int type;651 smallint type; /* Nxxxx */ 485 652 union node *assign; 486 653 union node *args; … … 489 656 490 657 struct npipe { 491 int type;492 intbackgnd;658 smallint type; 659 smallint pipe_backgnd; 493 660 struct nodelist *cmdlist; 494 661 }; 495 662 496 663 struct nredir { 497 int type;664 smallint type; 498 665 union node *n; 499 666 union node *redirect; … … 501 668 502 669 struct nbinary { 503 int type;670 smallint type; 504 671 union node *ch1; 505 672 union node *ch2; … … 507 674 508 675 struct nif { 509 int type;676 smallint type; 510 677 union node *test; 511 678 union node *ifpart; … … 514 681 515 682 struct nfor { 516 int type;683 smallint type; 517 684 union node *args; 518 685 union node *body; … … 521 688 522 689 struct ncase { 523 int type;690 smallint type; 524 691 union node *expr; 525 692 union node *cases; … … 527 694 528 695 struct nclist { 529 int type;696 smallint type; 530 697 union node *next; 531 698 union node *pattern; … … 534 701 535 702 struct narg { 536 int type;703 smallint type; 537 704 union node *next; 538 705 char *text; … … 540 707 }; 541 708 709 /* nfile and ndup layout must match! 710 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight 711 * that it is actually NTO2 (>&file), and change its type. 712 */ 542 713 struct nfile { 543 int type;714 smallint type; 544 715 union node *next; 545 716 int fd; 717 int _unused_dupfd; 546 718 union node *fname; 547 719 char *expfname; … … 549 721 550 722 struct ndup { 551 int type;723 smallint type; 552 724 union node *next; 553 725 int fd; 554 726 int dupfd; 555 727 union node *vname; 728 char *_unused_expfname; 556 729 }; 557 730 558 731 struct nhere { 559 int type;732 smallint type; 560 733 union node *next; 561 734 int fd; … … 564 737 565 738 struct nnot { 566 int type;739 smallint type; 567 740 union node *com; 568 741 }; 569 742 570 743 union node { 571 int type;744 smallint type; 572 745 struct ncmd ncmd; 573 746 struct npipe npipe; … … 585 758 }; 586 759 760 /* 761 * NODE_EOF is returned by parsecmd when it encounters an end of file. 762 * It must be distinct from NULL. 763 */ 764 #define NODE_EOF ((union node *) -1L) 765 587 766 struct nodelist { 588 767 struct nodelist *next; … … 619 798 if (debug != 1) 620 799 return; 800 if (DEBUG_TIME) 801 fprintf(tracefile, "%u ", (int) time(NULL)); 802 if (DEBUG_PID) 803 fprintf(tracefile, "[%u] ", (int) getpid()); 804 if (DEBUG_SIG) 805 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int); 621 806 va_start(va, fmt); 622 807 vfprintf(tracefile, fmt, va); … … 629 814 if (debug != 1) 630 815 return; 816 if (DEBUG_TIME) 817 fprintf(tracefile, "%u ", (int) time(NULL)); 818 if (DEBUG_PID) 819 fprintf(tracefile, "[%u] ", (int) getpid()); 820 if (DEBUG_SIG) 821 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int); 631 822 vfprintf(tracefile, fmt, va); 632 823 } … … 650 841 putc('"', tracefile); 651 842 for (p = s; *p; p++) { 652 switch ( *p) {653 case '\n': c = 'n';goto backslash;654 case '\t': c = 't';goto backslash;655 case '\r': c = 'r';goto backslash;656 case ' "': c = '"';goto backslash;657 case '\\': c = '\\';goto backslash;658 case CTLESC: c = 'e';goto backslash;659 case CTLVAR: c = 'v';goto backslash;660 case CTLVAR+CTLQUOTE: 661 case CTLBACKQ: c = 'q';goto backslash;662 case CTLBACKQ+CTLQUOTE: 843 switch ((unsigned char)*p) { 844 case '\n': c = 'n'; goto backslash; 845 case '\t': c = 't'; goto backslash; 846 case '\r': c = 'r'; goto backslash; 847 case '\"': c = '\"'; goto backslash; 848 case '\\': c = '\\'; goto backslash; 849 case CTLESC: c = 'e'; goto backslash; 850 case CTLVAR: c = 'v'; goto backslash; 851 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash; 852 case CTLBACKQ: c = 'q'; goto backslash; 853 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash; 663 854 backslash: 664 855 putc('\\', tracefile); … … 670 861 else { 671 862 putc('\\', tracefile); 672 putc( *p >> 6& 03, tracefile);673 putc( *p >> 3& 07, tracefile);863 putc((*p >> 6) & 03, tracefile); 864 putc((*p >> 3) & 07, tracefile); 674 865 putc(*p & 07, tracefile); 675 866 } … … 755 946 char *p; 756 947 struct nodelist *bqlist; 757 intsubtype;948 unsigned char subtype; 758 949 759 950 if (arg->type != NARG) { … … 763 954 bqlist = arg->narg.backquote; 764 955 for (p = arg->narg.text; *p; p++) { 765 switch ( *p) {956 switch ((unsigned char)*p) { 766 957 case CTLESC: 767 putc(*++p, fp); 958 p++; 959 putc(*p, fp); 768 960 break; 769 961 case CTLVAR: … … 774 966 putc('#', fp); 775 967 776 while (*p != '=') 777 putc(*p++, fp); 968 while (*p != '=') { 969 putc(*p, fp); 970 p++; 971 } 778 972 779 973 if (subtype & VSNUL) … … 856 1050 case NCLOBBER: s = ">|"; dftfd = 1; break; 857 1051 case NAPPEND: s = ">>"; dftfd = 1; break; 1052 #if ENABLE_ASH_BASH_COMPAT 1053 case NTO2: 1054 #endif 858 1055 case NTOFD: s = ">&"; dftfd = 1; break; 859 case NFROM: s = "<"; 1056 case NFROM: s = "<"; break; 860 1057 case NFROMFD: s = "<&"; break; 861 1058 case NFROMTO: s = "<>"; break; … … 884 1081 885 1082 indent(ind, pfx, fp); 1083 1084 if (n == NODE_EOF) { 1085 fputs("<EOF>", fp); 1086 return; 1087 } 1088 886 1089 switch (n->type) { 887 1090 case NSEMI: … … 906 1109 case NPIPE: 907 1110 for (lp = n->npipe.cmdlist; lp; lp = lp->next) { 908 sh cmd(lp->n, fp);1111 shtree(lp->n, 0, NULL, fp); 909 1112 if (lp->next) 910 1113 fputs(" | ", fp); 911 1114 } 912 if (n->npipe. backgnd)1115 if (n->npipe.pipe_backgnd) 913 1116 fputs(" &", fp); 914 1117 if (ind >= 0) … … 927 1130 { 928 1131 trace_puts("showtree called\n"); 929 shtree(n, 1, NULL, stdout); 930 } 931 932 #define TRACE(param) trace_printf param 933 #define TRACEV(param) trace_vprintf param 934 935 #else 936 937 #define TRACE(param) 938 #define TRACEV(param) 1132 shtree(n, 1, NULL, stderr); 1133 } 939 1134 940 1135 #endif /* DEBUG */ … … 951 1146 }; 952 1147 953 #if ENABLE_ASH_ALIAS954 1148 struct alias; 955 #endif956 1149 957 1150 struct strpush { 958 1151 struct strpush *prev; /* preceding string on stack */ 959 char *prev string;960 int prev nleft;1152 char *prev_string; 1153 int prev_left_in_line; 961 1154 #if ENABLE_ASH_ALIAS 962 1155 struct alias *ap; /* if push was associated with an alias */ … … 968 1161 struct parsefile *prev; /* preceding file on stack */ 969 1162 int linno; /* current line */ 970 int fd;/* file descriptor (or -1 if string) */971 int nleft;/* number of chars left in this line */972 int l left; /* number of chars left in this buffer*/973 char *next c;/* next char in buffer */1163 int pf_fd; /* file descriptor (or -1 if string) */ 1164 int left_in_line; /* number of chars left in this line */ 1165 int left_in_buffer; /* number of chars left in this buffer past the line */ 1166 char *next_to_pgetc; /* next char in buffer */ 974 1167 char *buf; /* input buffer */ 975 1168 struct strpush *strpush; /* for pushing strings at this level */ … … 977 1170 }; 978 1171 979 static struct parsefile basepf; 980 static struct parsefile * parsefile = &basepf; /* current input file */1172 static struct parsefile basepf; /* top level input file */ 1173 static struct parsefile *g_parsefile = &basepf; /* current input file */ 981 1174 static int startlinno; /* line # where last token started */ 982 1175 static char *commandname; /* currently executing command */ 983 1176 static struct strlist *cmdenviron; /* environment for builtin command */ 984 static int exitstatus;/* exit status of last command */1177 static uint8_t exitstatus; /* exit status of last command */ 985 1178 986 1179 … … 994 1187 if (strcmp(arg0, commandname)) 995 1188 fprintf(stderr, "%s: ", commandname); 996 if (!iflag || parsefile->fd)1189 if (!iflag || g_parsefile->pf_fd > 0) 997 1190 fprintf(stderr, "line %d: ", startlinno); 998 1191 } … … 1006 1199 * formatting. It then raises the error exception. 1007 1200 */ 1008 static void ash_vmsg_and_raise(int, const char *, va_list) ATTRIBUTE_NORETURN;1201 static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN; 1009 1202 static void 1010 1203 ash_vmsg_and_raise(int cond, const char *msg, va_list ap) … … 1026 1219 } 1027 1220 1028 static void ash_msg_and_raise_error(const char *, ...) ATTRIBUTE_NORETURN;1221 static void ash_msg_and_raise_error(const char *, ...) NORETURN; 1029 1222 static void 1030 1223 ash_msg_and_raise_error(const char *msg, ...) … … 1038 1231 } 1039 1232 1040 static void ash_msg_and_raise(int, const char *, ...) ATTRIBUTE_NORETURN; 1233 static void raise_error_syntax(const char *) NORETURN; 1234 static void 1235 raise_error_syntax(const char *msg) 1236 { 1237 ash_msg_and_raise_error("syntax error: %s", msg); 1238 /* NOTREACHED */ 1239 } 1240 1241 static void ash_msg_and_raise(int, const char *, ...) NORETURN; 1041 1242 static void 1042 1243 ash_msg_and_raise(int cond, const char *msg, ...) … … 1079 1280 1080 1281 /* ============ Memory allocation */ 1282 1283 #if 0 1284 /* I consider these wrappers nearly useless: 1285 * ok, they return you to nearest exception handler, but 1286 * how much memory do you leak in the process, making 1287 * memory starvation worse? 1288 */ 1289 static void * 1290 ckrealloc(void * p, size_t nbytes) 1291 { 1292 p = realloc(p, nbytes); 1293 if (!p) 1294 ash_msg_and_raise_error(bb_msg_memory_exhausted); 1295 return p; 1296 } 1297 1298 static void * 1299 ckmalloc(size_t nbytes) 1300 { 1301 return ckrealloc(NULL, nbytes); 1302 } 1303 1304 static void * 1305 ckzalloc(size_t nbytes) 1306 { 1307 return memset(ckmalloc(nbytes), 0, nbytes); 1308 } 1309 1310 static char * 1311 ckstrdup(const char *s) 1312 { 1313 char *p = strdup(s); 1314 if (!p) 1315 ash_msg_and_raise_error(bb_msg_memory_exhausted); 1316 return p; 1317 } 1318 #else 1319 /* Using bbox equivalents. They exit if out of memory */ 1320 # define ckrealloc xrealloc 1321 # define ckmalloc xmalloc 1322 # define ckzalloc xzalloc 1323 # define ckstrdup xstrdup 1324 #endif 1081 1325 1082 1326 /* … … 1089 1333 * in some way. The following macro will get this right 1090 1334 * on many machines. */ 1091 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,1335 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1, 1092 1336 /* Minimum size of a block */ 1093 MINSIZE 1337 MINSIZE = SHELL_ALIGN(504), 1094 1338 }; 1095 1339 … … 1106 1350 }; 1107 1351 1108 static struct stack_block stackbase; 1109 static struct stack_block *stackp = &stackbase; 1110 static struct stackmark *markp; 1111 static char *stacknxt = stackbase.space; 1112 static size_t stacknleft = MINSIZE; 1113 static char *sstrend = stackbase.space + MINSIZE; 1114 static int herefd = -1; 1115 1116 #define stackblock() ((void *)stacknxt) 1117 #define stackblocksize() stacknleft 1118 1119 static void * 1120 ckrealloc(void * p, size_t nbytes) 1121 { 1122 p = realloc(p, nbytes); 1123 if (!p) 1124 ash_msg_and_raise_error(bb_msg_memory_exhausted); 1125 return p; 1126 } 1127 1128 static void * 1129 ckmalloc(size_t nbytes) 1130 { 1131 return ckrealloc(NULL, nbytes); 1132 } 1133 1134 /* 1135 * Make a copy of a string in safe storage. 1136 */ 1137 static char * 1138 ckstrdup(const char *s) 1139 { 1140 char *p = strdup(s); 1141 if (!p) 1142 ash_msg_and_raise_error(bb_msg_memory_exhausted); 1143 return p; 1144 } 1352 1353 struct globals_memstack { 1354 struct stack_block *g_stackp; // = &stackbase; 1355 struct stackmark *markp; 1356 char *g_stacknxt; // = stackbase.space; 1357 char *sstrend; // = stackbase.space + MINSIZE; 1358 size_t g_stacknleft; // = MINSIZE; 1359 int herefd; // = -1; 1360 struct stack_block stackbase; 1361 }; 1362 extern struct globals_memstack *const ash_ptr_to_globals_memstack; 1363 #define G_memstack (*ash_ptr_to_globals_memstack) 1364 #define g_stackp (G_memstack.g_stackp ) 1365 #define markp (G_memstack.markp ) 1366 #define g_stacknxt (G_memstack.g_stacknxt ) 1367 #define sstrend (G_memstack.sstrend ) 1368 #define g_stacknleft (G_memstack.g_stacknleft) 1369 #define herefd (G_memstack.herefd ) 1370 #define stackbase (G_memstack.stackbase ) 1371 #define INIT_G_memstack() do { \ 1372 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \ 1373 barrier(); \ 1374 g_stackp = &stackbase; \ 1375 g_stacknxt = stackbase.space; \ 1376 g_stacknleft = MINSIZE; \ 1377 sstrend = stackbase.space + MINSIZE; \ 1378 herefd = -1; \ 1379 } while (0) 1380 1381 1382 #define stackblock() ((void *)g_stacknxt) 1383 #define stackblocksize() g_stacknleft 1145 1384 1146 1385 /* … … 1159 1398 1160 1399 aligned = SHELL_ALIGN(nbytes); 1161 if (aligned > stacknleft) {1400 if (aligned > g_stacknleft) { 1162 1401 size_t len; 1163 1402 size_t blocksize; … … 1172 1411 INT_OFF; 1173 1412 sp = ckmalloc(len); 1174 sp->prev = stackp;1175 stacknxt = sp->space;1176 stacknleft = blocksize;1177 sstrend = stacknxt + blocksize;1178 stackp = sp;1413 sp->prev = g_stackp; 1414 g_stacknxt = sp->space; 1415 g_stacknleft = blocksize; 1416 sstrend = g_stacknxt + blocksize; 1417 g_stackp = sp; 1179 1418 INT_ON; 1180 1419 } 1181 p = stacknxt;1182 stacknxt += aligned;1183 stacknleft -= aligned;1420 p = g_stacknxt; 1421 g_stacknxt += aligned; 1422 g_stacknleft -= aligned; 1184 1423 return p; 1424 } 1425 1426 static void * 1427 stzalloc(size_t nbytes) 1428 { 1429 return memset(stalloc(nbytes), 0, nbytes); 1185 1430 } 1186 1431 … … 1189 1434 { 1190 1435 #if DEBUG 1191 if (!p || ( stacknxt < (char *)p) || ((char *)p <stackp->space)) {1192 write( 2, "stunalloc\n", 10);1436 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) { 1437 write(STDERR_FILENO, "stunalloc\n", 10); 1193 1438 abort(); 1194 1439 } 1195 1440 #endif 1196 stacknleft +=stacknxt - (char *)p;1197 stacknxt = p;1441 g_stacknleft += g_stacknxt - (char *)p; 1442 g_stacknxt = p; 1198 1443 } 1199 1444 … … 1211 1456 setstackmark(struct stackmark *mark) 1212 1457 { 1213 mark->stackp = stackp;1214 mark->stacknxt = stacknxt;1215 mark->stacknleft = stacknleft;1458 mark->stackp = g_stackp; 1459 mark->stacknxt = g_stacknxt; 1460 mark->stacknleft = g_stacknleft; 1216 1461 mark->marknext = markp; 1217 1462 markp = mark; … … 1228 1473 INT_OFF; 1229 1474 markp = mark->marknext; 1230 while ( stackp != mark->stackp) {1231 sp = stackp;1232 stackp = sp->prev;1475 while (g_stackp != mark->stackp) { 1476 sp = g_stackp; 1477 g_stackp = sp->prev; 1233 1478 free(sp); 1234 1479 } 1235 stacknxt = mark->stacknxt;1236 stacknleft = mark->stacknleft;1480 g_stacknxt = mark->stacknxt; 1481 g_stacknleft = mark->stacknleft; 1237 1482 sstrend = mark->stacknxt + mark->stacknleft; 1238 1483 INT_ON; … … 1253 1498 size_t newlen; 1254 1499 1255 newlen = stacknleft * 2;1256 if (newlen < stacknleft)1500 newlen = g_stacknleft * 2; 1501 if (newlen < g_stacknleft) 1257 1502 ash_msg_and_raise_error(bb_msg_memory_exhausted); 1258 1503 if (newlen < 128) 1259 1504 newlen += 128; 1260 1505 1261 if ( stacknxt == stackp->space &&stackp != &stackbase) {1506 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) { 1262 1507 struct stack_block *oldstackp; 1263 1508 struct stackmark *xmark; … … 1267 1512 1268 1513 INT_OFF; 1269 oldstackp = stackp;1270 sp = stackp;1514 oldstackp = g_stackp; 1515 sp = g_stackp; 1271 1516 prevstackp = sp->prev; 1272 1517 grosslen = newlen + sizeof(struct stack_block) - MINSIZE; 1273 1518 sp = ckrealloc(sp, grosslen); 1274 1519 sp->prev = prevstackp; 1275 stackp = sp;1276 stacknxt = sp->space;1277 stacknleft = newlen;1520 g_stackp = sp; 1521 g_stacknxt = sp->space; 1522 g_stacknleft = newlen; 1278 1523 sstrend = sp->space + newlen; 1279 1524 … … 1284 1529 xmark = markp; 1285 1530 while (xmark != NULL && xmark->stackp == oldstackp) { 1286 xmark->stackp = stackp;1287 xmark->stacknxt = stacknxt;1288 xmark->stacknleft = stacknleft;1531 xmark->stackp = g_stackp; 1532 xmark->stacknxt = g_stacknxt; 1533 xmark->stacknleft = g_stacknleft; 1289 1534 xmark = xmark->marknext; 1290 1535 } 1291 1536 INT_ON; 1292 1537 } else { 1293 char *oldspace = stacknxt;1294 int oldlen =stacknleft;1538 char *oldspace = g_stacknxt; 1539 size_t oldlen = g_stacknleft; 1295 1540 char *p = stalloc(newlen); 1296 1541 1297 1542 /* free the space we just allocated */ 1298 stacknxt = memcpy(p, oldspace, oldlen);1299 stacknleft += newlen;1543 g_stacknxt = memcpy(p, oldspace, oldlen); 1544 g_stacknleft += newlen; 1300 1545 } 1301 1546 } … … 1305 1550 { 1306 1551 len = SHELL_ALIGN(len); 1307 stacknxt += len;1308 stacknleft -= len;1552 g_stacknxt += len; 1553 g_stacknleft -= len; 1309 1554 } 1310 1555 … … 1335 1580 } 1336 1581 growstackblock(); 1337 return stackblock() + len;1582 return (char *)stackblock() + len; 1338 1583 } 1339 1584 … … 1344 1589 makestrspace(size_t newlen, char *p) 1345 1590 { 1346 size_t len = p - stacknxt;1591 size_t len = p - g_stacknxt; 1347 1592 size_t size = stackblocksize(); 1348 1593 … … 1356 1601 growstackblock(); 1357 1602 } 1358 return stackblock() + len;1603 return (char *)stackblock() + len; 1359 1604 } 1360 1605 … … 1363 1608 { 1364 1609 p = makestrspace(n, p); 1365 p = memcpy(p, s, n) + n;1610 p = (char *)memcpy(p, s, n) + n; 1366 1611 return p; 1367 1612 } … … 1384 1629 #define STARTSTACKSTR(p) ((p) = stackblock()) 1385 1630 #define STPUTC(c, p) ((p) = _STPUTC((c), (p))) 1386 #define CHECKSTRSPACE(n, p) \ 1387 do { \ 1388 char *q = (p); \ 1389 size_t l = (n); \ 1390 size_t m = sstrend - q; \ 1391 if (l > m) \ 1392 (p) = makestrspace(l, q); \ 1393 } while (0) 1394 #define USTPUTC(c, p) (*p++ = (c)) 1395 #define STACKSTRNUL(p) \ 1396 do { \ 1397 if ((p) == sstrend) \ 1398 p = growstackstr(); \ 1399 *p = '\0'; \ 1400 } while (0) 1401 #define STUNPUTC(p) (--p) 1402 #define STTOPC(p) (p[-1]) 1403 #define STADJUST(amount, p) (p += (amount)) 1631 #define CHECKSTRSPACE(n, p) do { \ 1632 char *q = (p); \ 1633 size_t l = (n); \ 1634 size_t m = sstrend - q; \ 1635 if (l > m) \ 1636 (p) = makestrspace(l, q); \ 1637 } while (0) 1638 #define USTPUTC(c, p) (*(p)++ = (c)) 1639 #define STACKSTRNUL(p) do { \ 1640 if ((p) == sstrend) \ 1641 (p) = growstackstr(); \ 1642 *(p) = '\0'; \ 1643 } while (0) 1644 #define STUNPUTC(p) (--(p)) 1645 #define STTOPC(p) ((p)[-1]) 1646 #define STADJUST(amount, p) ((p) += (amount)) 1404 1647 1405 1648 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock()) 1406 #define ungrabstackstr(s, p) stunalloc( (s))1649 #define ungrabstackstr(s, p) stunalloc(s) 1407 1650 #define stackstrend() ((void *)sstrend) 1408 1651 … … 1418 1661 while (*pfx) { 1419 1662 if (*pfx++ != *string++) 1420 return 0;1663 return NULL; 1421 1664 } 1422 1665 return (char *) string; … … 1444 1687 { 1445 1688 if (!is_number(s)) 1446 ash_msg_and_raise_error( illnum, s);1689 ash_msg_and_raise_error(msg_illnum, s); 1447 1690 return atoi(s); 1448 1691 } … … 1468 1711 1469 1712 *q++ = '\''; 1470 q = memcpy(q, s, len) + len;1713 q = (char *)memcpy(q, s, len) + len; 1471 1714 *q++ = '\''; 1472 1715 s += len; … … 1474 1717 STADJUST(q - p, p); 1475 1718 1476 len = strspn(s, "'"); 1477 if (!len) 1719 if (*s != '\'') 1478 1720 break; 1721 len = 0; 1722 do len++; while (*++s == '\''); 1479 1723 1480 1724 q = p = makestrspace(len + 3, p); 1481 1725 1482 1726 *q++ = '"'; 1483 q = memcpy(q, s, len) + len;1727 q = (char *)memcpy(q, s - len, len) + len; 1484 1728 *q++ = '"'; 1485 s += len;1486 1729 1487 1730 STADJUST(q - p, p); 1488 1731 } while (*s); 1489 1732 1490 USTPUTC( 0, p);1733 USTPUTC('\0', p); 1491 1734 1492 1735 return stackblock(); … … 1501 1744 1502 1745 /* 1503 * XXX - should get rid of. have all builtins use getopt(3). the1504 * library getopt must have the BSD extension static variable "optreset"1505 * otherwise it can't be used within the shell safely.1746 * XXX - should get rid of. Have all builtins use getopt(3). 1747 * The library getopt must have the BSD extension static variable 1748 * "optreset", otherwise it can't be used within the shell safely. 1506 1749 * 1507 * Standard option processing (a la getopt) for builtin routines. The1508 * only argument that is passed to nextopt is the option string; the1509 * other arguments are unnecessary. It return the character, or '\0' on1510 * end of input.1750 * Standard option processing (a la getopt) for builtin routines. 1751 * The only argument that is passed to nextopt is the option string; 1752 * the other arguments are unnecessary. It returns the character, 1753 * or '\0' on end of input. 1511 1754 */ 1512 1755 static int … … 1519 1762 p = optptr; 1520 1763 if (p == NULL || *p == '\0') { 1764 /* We ate entire "-param", take next one */ 1521 1765 p = *argptr; 1522 if (p == NULL || *p != '-' || *++p == '\0') 1766 if (p == NULL) 1767 return '\0'; 1768 if (*p != '-') 1769 return '\0'; 1770 if (*++p == '\0') /* just "-" ? */ 1523 1771 return '\0'; 1524 1772 argptr++; 1525 if (LONE_DASH(p)) /* check for "--"*/1773 if (LONE_DASH(p)) /* "--" ? */ 1526 1774 return '\0'; 1527 } 1775 /* p => next "-param" */ 1776 } 1777 /* p => some option char in the middle of a "-param" */ 1528 1778 c = *p++; 1529 for (q = optstring; *q != c; 1779 for (q = optstring; *q != c;) { 1530 1780 if (*q == '\0') 1531 1781 ash_msg_and_raise_error("illegal option -%c", c); … … 1534 1784 } 1535 1785 if (*++q == ':') { 1536 if (*p == '\0' && (p = *argptr++) == NULL) 1537 ash_msg_and_raise_error("no arg for -%c option", c); 1786 if (*p == '\0') { 1787 p = *argptr++; 1788 if (p == NULL) 1789 ash_msg_and_raise_error("no arg for -%c option", c); 1790 } 1538 1791 optionarg = p; 1539 1792 p = NULL; … … 1544 1797 1545 1798 1546 /* ============ Math support definitions */1547 1548 #if ENABLE_ASH_MATH_SUPPORT_641549 typedef int64_t arith_t;1550 #define arith_t_type long long1551 #else1552 typedef long arith_t;1553 #define arith_t_type long1554 #endif1555 1556 #if ENABLE_ASH_MATH_SUPPORT1557 static arith_t dash_arith(const char *);1558 static arith_t arith(const char *expr, int *perrcode);1559 #endif1560 1561 #if ENABLE_ASH_RANDOM_SUPPORT1562 static unsigned long rseed;1563 #ifndef DYNAMIC_VAR1564 #define DYNAMIC_VAR1565 #endif1566 #endif1567 1568 1569 1799 /* ============ Shell variables */ 1800 1801 /* 1802 * The parsefile structure pointed to by the global variable parsefile 1803 * contains information about the current file being read. 1804 */ 1805 struct shparam { 1806 int nparam; /* # of positional parameters (without $0) */ 1807 #if ENABLE_ASH_GETOPTS 1808 int optind; /* next parameter to be processed by getopts */ 1809 int optoff; /* used by getopts */ 1810 #endif 1811 unsigned char malloced; /* if parameter list dynamically allocated */ 1812 char **p; /* parameter list */ 1813 }; 1814 1815 /* 1816 * Free the list of positional parameters. 1817 */ 1818 static void 1819 freeparam(volatile struct shparam *param) 1820 { 1821 if (param->malloced) { 1822 char **ap, **ap1; 1823 ap = ap1 = param->p; 1824 while (*ap) 1825 free(*ap++); 1826 free(ap1); 1827 } 1828 } 1829 1830 #if ENABLE_ASH_GETOPTS 1831 static void FAST_FUNC getoptsreset(const char *value); 1832 #endif 1833 1834 struct var { 1835 struct var *next; /* next entry in hash list */ 1836 int flags; /* flags are defined above */ 1837 const char *var_text; /* name=value */ 1838 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */ 1839 /* the variable gets set/unset */ 1840 }; 1841 1842 struct localvar { 1843 struct localvar *next; /* next local variable in list */ 1844 struct var *vp; /* the variable that was made local */ 1845 int flags; /* saved flags */ 1846 const char *text; /* saved text */ 1847 }; 1570 1848 1571 1849 /* flags */ … … 1579 1857 #define VNOSET 0x80 /* do not set variable - just readonly test */ 1580 1858 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */ 1581 #if def DYNAMIC_VAR1859 #if ENABLE_ASH_RANDOM_SUPPORT 1582 1860 # define VDYNAMIC 0x200 /* dynamic variable */ 1583 1861 #else … … 1585 1863 #endif 1586 1864 1587 #ifdef IFS_BROKEN 1588 static const char defifsvar[] ALIGN1 = "IFS= \t\n"; 1589 #define defifs (defifsvar + 4) 1590 #else 1591 static const char defifs[] ALIGN1 = " \t\n"; 1592 #endif 1593 1594 struct shparam { 1595 int nparam; /* # of positional parameters (without $0) */ 1596 unsigned char malloc; /* if parameter list dynamically allocated */ 1597 char **p; /* parameter list */ 1598 #if ENABLE_ASH_GETOPTS 1599 int optind; /* next parameter to be processed by getopts */ 1600 int optoff; /* used by getopts */ 1601 #endif 1602 }; 1603 1604 static struct shparam shellparam; /* $@ current positional parameters */ 1605 1606 /* 1607 * Free the list of positional parameters. 1608 */ 1609 static void 1610 freeparam(volatile struct shparam *param) 1611 { 1612 char **ap; 1613 1614 if (param->malloc) { 1615 for (ap = param->p; *ap; ap++) 1616 free(*ap); 1617 free(param->p); 1618 } 1619 } 1620 1621 #if ENABLE_ASH_GETOPTS 1622 static void 1623 getoptsreset(const char *value) 1624 { 1625 shellparam.optind = number(value); 1626 shellparam.optoff = -1; 1627 } 1628 #endif 1629 1630 struct var { 1631 struct var *next; /* next entry in hash list */ 1632 int flags; /* flags are defined above */ 1633 const char *text; /* name=value */ 1634 void (*func)(const char *); /* function to be called when */ 1635 /* the variable gets set/unset */ 1636 }; 1637 1638 struct localvar { 1639 struct localvar *next; /* next local variable in list */ 1640 struct var *vp; /* the variable that was made local */ 1641 int flags; /* saved flags */ 1642 const char *text; /* saved text */ 1643 }; 1644 1645 /* Forward decls for varinit[] */ 1865 1866 /* Need to be before varinit_data[] */ 1646 1867 #if ENABLE_LOCALE_SUPPORT 1647 static void 1868 static void FAST_FUNC 1648 1869 change_lc_all(const char *value) 1649 1870 { … … 1651 1872 setlocale(LC_ALL, value); 1652 1873 } 1653 static void 1874 static void FAST_FUNC 1654 1875 change_lc_ctype(const char *value) 1655 1876 { … … 1660 1881 #if ENABLE_ASH_MAIL 1661 1882 static void chkmail(void); 1662 static void changemail(const char *) ;1663 #endif 1664 static void changepath(const char *) ;1883 static void changemail(const char *) FAST_FUNC; 1884 #endif 1885 static void changepath(const char *) FAST_FUNC; 1665 1886 #if ENABLE_ASH_RANDOM_SUPPORT 1666 static void change_random(const char *); 1667 #endif 1668 1669 static struct var varinit[] = { 1670 #ifdef IFS_BROKEN 1671 { NULL, VSTRFIXED|VTEXTFIXED, defifsvar, NULL }, 1887 static void change_random(const char *) FAST_FUNC; 1888 #endif 1889 1890 static const struct { 1891 int flags; 1892 const char *var_text; 1893 void (*var_func)(const char *) FAST_FUNC; 1894 } varinit_data[] = { 1895 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL }, 1896 #if ENABLE_ASH_MAIL 1897 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail }, 1898 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail }, 1899 #endif 1900 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath }, 1901 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL }, 1902 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL }, 1903 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL }, 1904 #if ENABLE_ASH_GETOPTS 1905 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset }, 1906 #endif 1907 #if ENABLE_ASH_RANDOM_SUPPORT 1908 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random }, 1909 #endif 1910 #if ENABLE_LOCALE_SUPPORT 1911 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all }, 1912 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype }, 1913 #endif 1914 #if ENABLE_FEATURE_EDITING_SAVEHISTORY 1915 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL }, 1916 #endif 1917 }; 1918 1919 struct redirtab; 1920 1921 struct globals_var { 1922 struct shparam shellparam; /* $@ current positional parameters */ 1923 struct redirtab *redirlist; 1924 int g_nullredirs; 1925 int preverrout_fd; /* save fd2 before print debug if xflag is set. */ 1926 struct var *vartab[VTABSIZE]; 1927 struct var varinit[ARRAY_SIZE(varinit_data)]; 1928 }; 1929 extern struct globals_var *const ash_ptr_to_globals_var; 1930 #define G_var (*ash_ptr_to_globals_var) 1931 #define shellparam (G_var.shellparam ) 1932 //#define redirlist (G_var.redirlist ) 1933 #define g_nullredirs (G_var.g_nullredirs ) 1934 #define preverrout_fd (G_var.preverrout_fd) 1935 #define vartab (G_var.vartab ) 1936 #define varinit (G_var.varinit ) 1937 #define INIT_G_var() do { \ 1938 unsigned i; \ 1939 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \ 1940 barrier(); \ 1941 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \ 1942 varinit[i].flags = varinit_data[i].flags; \ 1943 varinit[i].var_text = varinit_data[i].var_text; \ 1944 varinit[i].var_func = varinit_data[i].var_func; \ 1945 } \ 1946 } while (0) 1947 1948 #define vifs varinit[0] 1949 #if ENABLE_ASH_MAIL 1950 # define vmail (&vifs)[1] 1951 # define vmpath (&vmail)[1] 1952 # define vpath (&vmpath)[1] 1672 1953 #else 1673 { NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", NULL }, 1674 #endif 1675 #if ENABLE_ASH_MAIL 1676 { NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail }, 1677 { NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail }, 1678 #endif 1679 { NULL, VSTRFIXED|VTEXTFIXED, bb_PATH_root_path, changepath }, 1680 { NULL, VSTRFIXED|VTEXTFIXED, "PS1=$ ", NULL }, 1681 { NULL, VSTRFIXED|VTEXTFIXED, "PS2=> ", NULL }, 1682 { NULL, VSTRFIXED|VTEXTFIXED, "PS4=+ ", NULL }, 1954 # define vpath (&vifs)[1] 1955 #endif 1956 #define vps1 (&vpath)[1] 1957 #define vps2 (&vps1)[1] 1958 #define vps4 (&vps2)[1] 1683 1959 #if ENABLE_ASH_GETOPTS 1684 { NULL, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset }, 1685 #endif 1686 #if ENABLE_ASH_RANDOM_SUPPORT 1687 { NULL, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random }, 1688 #endif 1689 #if ENABLE_LOCALE_SUPPORT 1690 { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all }, 1691 { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype }, 1692 #endif 1693 #if ENABLE_FEATURE_EDITING_SAVEHISTORY 1694 { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL }, 1695 #endif 1696 }; 1697 1698 #define vifs varinit[0] 1699 #if ENABLE_ASH_MAIL 1700 #define vmail (&vifs)[1] 1701 #define vmpath (&vmail)[1] 1960 # define voptind (&vps4)[1] 1961 # if ENABLE_ASH_RANDOM_SUPPORT 1962 # define vrandom (&voptind)[1] 1963 # endif 1702 1964 #else 1703 #define vmpath vifs 1704 #endif 1705 #define vpath (&vmpath)[1] 1706 #define vps1 (&vpath)[1] 1707 #define vps2 (&vps1)[1] 1708 #define vps4 (&vps2)[1] 1709 #define voptind (&vps4)[1] 1710 #if ENABLE_ASH_GETOPTS 1711 #define vrandom (&voptind)[1] 1712 #else 1713 #define vrandom (&vps4)[1] 1965 # if ENABLE_ASH_RANDOM_SUPPORT 1966 # define vrandom (&vps4)[1] 1967 # endif 1714 1968 #endif 1715 1969 … … 1719 1973 * for unset variables. 1720 1974 */ 1721 #define ifsval() (vifs. text + 4)1975 #define ifsval() (vifs.var_text + 4) 1722 1976 #define ifsset() ((vifs.flags & VUNSET) == 0) 1723 #define mailval() (vmail.text + 5) 1724 #define mpathval() (vmpath.text + 9) 1725 #define pathval() (vpath.text + 5) 1726 #define ps1val() (vps1.text + 4) 1727 #define ps2val() (vps2.text + 4) 1728 #define ps4val() (vps4.text + 4) 1729 #define optindval() (voptind.text + 7) 1730 1731 #define mpathset() ((vmpath.flags & VUNSET) == 0) 1732 1733 /* 1734 * The parsefile structure pointed to by the global variable parsefile 1735 * contains information about the current file being read. 1736 */ 1737 struct redirtab { 1738 struct redirtab *next; 1739 int renamed[10]; 1740 int nullredirs; 1741 }; 1742 1743 static struct redirtab *redirlist; 1744 static int nullredirs; 1745 static int preverrout_fd; /* save fd2 before print debug if xflag is set. */ 1746 1747 #define VTABSIZE 39 1748 1749 static struct var *vartab[VTABSIZE]; 1750 1977 #if ENABLE_ASH_MAIL 1978 # define mailval() (vmail.var_text + 5) 1979 # define mpathval() (vmpath.var_text + 9) 1980 # define mpathset() ((vmpath.flags & VUNSET) == 0) 1981 #endif 1982 #define pathval() (vpath.var_text + 5) 1983 #define ps1val() (vps1.var_text + 4) 1984 #define ps2val() (vps2.var_text + 4) 1985 #define ps4val() (vps4.var_text + 4) 1986 #if ENABLE_ASH_GETOPTS 1987 # define optindval() (voptind.var_text + 7) 1988 #endif 1989 1990 #if ENABLE_ASH_GETOPTS 1991 static void FAST_FUNC 1992 getoptsreset(const char *value) 1993 { 1994 shellparam.optind = number(value); 1995 shellparam.optoff = -1; 1996 } 1997 #endif 1998 1999 /* math.h has these, otherwise define our private copies */ 2000 #if !ENABLE_SH_MATH_SUPPORT 1751 2001 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) 1752 2002 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) 1753 1754 /* 1755 * Return of a legal variable name (a letter or underscore followed by zero or 1756 * more letters, underscores, and digits). 1757 */ 1758 static char * 2003 /* 2004 * Return the pointer to the first char which is not part of a legal variable name 2005 * (a letter or underscore followed by letters, underscores, and digits). 2006 */ 2007 static const char* 1759 2008 endofname(const char *name) 1760 2009 { 1761 char *p; 1762 1763 p = (char *) name; 1764 if (!is_name(*p)) 1765 return p; 1766 while (*++p) { 1767 if (!is_in_name(*p)) 2010 if (!is_name(*name)) 2011 return name; 2012 while (*++name) { 2013 if (!is_in_name(*name)) 1768 2014 break; 1769 2015 } 1770 return p; 1771 } 2016 return name; 2017 } 2018 #endif 1772 2019 1773 2020 /* … … 1795 2042 } 1796 2043 1797 static int1798 varequal(const char *a, const char *b)1799 {1800 return !varcmp(a, b);1801 }1802 1803 2044 /* 1804 2045 * Find the appropriate entry in the hash table from the name. … … 1835 2076 */ 1836 2077 #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT 1837 vps1. text = "PS1=\\w \\$ ";2078 vps1.var_text = "PS1=\\w \\$ "; 1838 2079 #else 1839 2080 if (!geteuid()) 1840 vps1. text = "PS1=# ";2081 vps1.var_text = "PS1=# "; 1841 2082 #endif 1842 2083 vp = varinit; 1843 2084 end = vp + ARRAY_SIZE(varinit); 1844 2085 do { 1845 vpp = hashvar(vp-> text);2086 vpp = hashvar(vp->var_text); 1846 2087 vp->next = *vpp; 1847 2088 *vpp = vp; … … 1853 2094 { 1854 2095 for (; *vpp; vpp = &(*vpp)->next) { 1855 if (var equal((*vpp)->text, name)) {2096 if (varcmp((*vpp)->var_text, name) == 0) { 1856 2097 break; 1857 2098 } … … 1863 2104 * Find the value of a variable. Returns NULL if not set. 1864 2105 */ 1865 static c har *2106 static const char* FAST_FUNC 1866 2107 lookupvar(const char *name) 1867 2108 { … … 1870 2111 v = *findvar(hashvar(name), name); 1871 2112 if (v) { 1872 #if def DYNAMIC_VAR2113 #if ENABLE_ASH_RANDOM_SUPPORT 1873 2114 /* 1874 2115 * Dynamic variables are implemented roughly the same way they are … … 1877 2118 * lookup will no longer happen at that point. -- PFM. 1878 2119 */ 1879 if ( (v->flags & VDYNAMIC))1880 (*v->func)(NULL);2120 if (v->flags & VDYNAMIC) 2121 v->var_func(NULL); 1881 2122 #endif 1882 2123 if (!(v->flags & VUNSET)) 1883 return strchrnul(v->text, '=') + 1;2124 return var_end(v->var_text); 1884 2125 } 1885 2126 return NULL; … … 1889 2130 * Search the environment of a builtin command. 1890 2131 */ 1891 static c har *2132 static const char * 1892 2133 bltinlookup(const char *name) 1893 2134 { … … 1895 2136 1896 2137 for (sp = cmdenviron; sp; sp = sp->next) { 1897 if (var equal(sp->text, name))1898 return strchrnul(sp->text, '=') + 1;2138 if (varcmp(sp->text, name) == 0) 2139 return var_end(sp->text); 1899 2140 } 1900 2141 return lookupvar(name); … … 1922 2163 if (flags & VNOSAVE) 1923 2164 free(s); 1924 n = vp-> text;2165 n = vp->var_text; 1925 2166 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n); 1926 2167 } … … 1929 2170 return; 1930 2171 1931 if (vp-> func && (flags & VNOFUNC) == 0)1932 (*vp->func)(strchrnul(s, '=') + 1);1933 1934 if ( (vp->flags & (VTEXTFIXED|VSTACK)) == 0)1935 free((char*)vp-> text);2172 if (vp->var_func && !(flags & VNOFUNC)) 2173 vp->var_func(var_end(s)); 2174 2175 if (!(vp->flags & (VTEXTFIXED|VSTACK))) 2176 free((char*)vp->var_text); 1936 2177 1937 2178 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET); 1938 2179 } else { 2180 /* variable s is not found */ 1939 2181 if (flags & VNOSET) 1940 2182 return; 1941 /* not found */ 1942 vp = ckmalloc(sizeof(*vp)); 2183 vp = ckzalloc(sizeof(*vp)); 1943 2184 vp->next = *vpp; 1944 vp->func = NULL;2185 /*vp->func = NULL; - ckzalloc did it */ 1945 2186 *vpp = vp; 1946 2187 } 1947 2188 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE))) 1948 2189 s = ckstrdup(s); 1949 vp-> text = s;2190 vp->var_text = s; 1950 2191 vp->flags = flags; 1951 2192 } … … 1958 2199 setvar(const char *name, const char *val, int flags) 1959 2200 { 1960 char *p, *q; 2201 const char *q; 2202 char *p; 2203 char *nameeq; 1961 2204 size_t namelen; 1962 char *nameeq;1963 2205 size_t vallen; 1964 2206 … … 1974 2216 vallen = strlen(val); 1975 2217 } 2218 1976 2219 INT_OFF; 1977 2220 nameeq = ckmalloc(namelen + vallen + 2); … … 1984 2227 setvareq(nameeq, flags | VNOSAVE); 1985 2228 INT_ON; 2229 } 2230 2231 static void FAST_FUNC 2232 setvar2(const char *name, const char *val) 2233 { 2234 setvar(name, val, 0); 1986 2235 } 1987 2236 … … 2031 2280 if (flags & VREADONLY) 2032 2281 goto out; 2033 #if def DYNAMIC_VAR2282 #if ENABLE_ASH_RANDOM_SUPPORT 2034 2283 vp->flags &= ~VDYNAMIC; 2035 2284 #endif … … 2039 2288 INT_OFF; 2040 2289 if ((flags & (VTEXTFIXED|VSTACK)) == 0) 2041 free((char*)vp-> text);2290 free((char*)vp->var_text); 2042 2291 *vpp = vp->next; 2043 2292 free(vp); … … 2091 2340 if (ep == stackstrend()) 2092 2341 ep = growstackstr(); 2093 *ep++ = (char *) vp->text;2342 *ep++ = (char*)vp->var_text; 2094 2343 } 2095 2344 } … … 2107 2356 * 2108 2357 * The variable path (passed by reference) should be set to the start 2109 * of the path before the first call; pa dvance will update2110 * this value as it proceeds. Successive calls to pa dvance will return2358 * of the path before the first call; path_advance will update 2359 * this value as it proceeds. Successive calls to path_advance will return 2111 2360 * the possible path expansions in sequence. If an option (indicated by 2112 2361 * a percent sign) appears in the path entry then the global variable … … 2114 2363 * NULL. 2115 2364 */ 2116 static const char *pathopt; /* set by pa dvance */2365 static const char *pathopt; /* set by path_advance */ 2117 2366 2118 2367 static char * 2119 pa dvance(const char **path, const char *name)2368 path_advance(const char **path, const char *name) 2120 2369 { 2121 2370 const char *p; … … 2127 2376 return NULL; 2128 2377 start = *path; 2129 for (p = start; *p && *p != ':' && *p != '%'; p++); 2378 for (p = start; *p && *p != ':' && *p != '%'; p++) 2379 continue; 2130 2380 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ 2131 2381 while (stackblocksize() < len) … … 2141 2391 if (*p == '%') { 2142 2392 pathopt = ++p; 2143 while (*p && *p != ':') p++; 2393 while (*p && *p != ':') 2394 p++; 2144 2395 } 2145 2396 if (*p == ':') … … 2153 2404 /* ============ Prompt */ 2154 2405 2155 static int doprompt; /* if set, prompt the user */2156 static int needprompt; /* true if interactive and at start of line */2406 static smallint doprompt; /* if set, prompt the user */ 2407 static smallint needprompt; /* true if interactive and at start of line */ 2157 2408 2158 2409 #if ENABLE_FEATURE_EDITING … … 2185 2436 2186 2437 static void 2187 setprompt (int whichprompt)2438 setprompt_if(smallint do_set, int whichprompt) 2188 2439 { 2189 2440 const char *prompt; 2190 #if ENABLE_ASH_EXPAND_PRMT 2191 struct stackmark smark; 2192 #endif 2441 IF_ASH_EXPAND_PRMT(struct stackmark smark;) 2442 2443 if (!do_set) 2444 return; 2193 2445 2194 2446 needprompt = 0; … … 2220 2472 #define CD_PRINT 2 2221 2473 2222 static int docd(const char *, int);2223 2224 static char *curdir = nullstr; /* current working directory */2225 static char *physdir = nullstr; /* physical working directory */2226 2227 2474 static int 2228 2475 cdopt(void) … … 2232 2479 2233 2480 j = 'L'; 2234 while ((i = nextopt("LP")) ) {2481 while ((i = nextopt("LP")) != '\0') { 2235 2482 if (i != j) { 2236 2483 flags ^= CD_PHYSICAL; … … 2262 2509 } 2263 2510 new = makestrspace(strlen(dir) + 2, new); 2264 lim = stackblock() + 1;2511 lim = (char *)stackblock() + 1; 2265 2512 if (*dir != '/') { 2266 2513 if (new[-1] != '/') … … 2311 2558 getpwd(void) 2312 2559 { 2313 char *dir = getcwd( 0, 0);2560 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */ 2314 2561 return dir ? dir : nullstr; 2315 2562 } … … 2355 2602 docd(const char *dest, int flags) 2356 2603 { 2357 const char *dir = 0;2604 const char *dir = NULL; 2358 2605 int err; 2359 2606 … … 2376 2623 } 2377 2624 2378 static int 2379 cdcmd(int argc , char **argv)2625 static int FAST_FUNC 2626 cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 2380 2627 { 2381 2628 const char *dest; … … 2389 2636 dest = *argptr; 2390 2637 if (!dest) 2391 dest = bltinlookup( homestr);2638 dest = bltinlookup("HOME"); 2392 2639 else if (LONE_DASH(dest)) { 2393 2640 dest = bltinlookup("OLDPWD"); … … 2422 2669 do { 2423 2670 c = *path; 2424 p = pa dvance(&path, dest);2671 p = path_advance(&path, dest); 2425 2672 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { 2426 2673 if (c && c != ':') … … 2436 2683 out: 2437 2684 if (flags & CD_PRINT) 2438 out1fmt( snlfmt, curdir);2685 out1fmt("%s\n", curdir); 2439 2686 return 0; 2440 2687 } 2441 2688 2442 static int 2443 pwdcmd(int argc , char **argv)2689 static int FAST_FUNC 2690 pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 2444 2691 { 2445 2692 int flags; … … 2452 2699 dir = physdir; 2453 2700 } 2454 out1fmt( snlfmt, dir);2701 out1fmt("%s\n", dir); 2455 2702 return 0; 2456 2703 } … … 2459 2706 /* ============ ... */ 2460 2707 2461 #define IBUFSIZ (BUFSIZ + 1) 2462 #define basebuf bb_common_bufsiz1 /* buffer for top level input file */2708 2709 #define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024) 2463 2710 2464 2711 /* Syntax classes */ 2465 #define CWORD 0/* character is nothing special */2466 #define CNL 1/* newline character */2467 #define CBACK 2/* a backslash character */2468 #define CSQUOTE 3/* single quote */2469 #define CDQUOTE 4/* double quote */2712 #define CWORD 0 /* character is nothing special */ 2713 #define CNL 1 /* newline character */ 2714 #define CBACK 2 /* a backslash character */ 2715 #define CSQUOTE 3 /* single quote */ 2716 #define CDQUOTE 4 /* double quote */ 2470 2717 #define CENDQUOTE 5 /* a terminating quote */ 2471 #define CBQUOTE 6/* backwards single quote */2472 #define CVAR 7/* a dollar sign */2473 #define CENDVAR 8/* a '}' character */2474 #define CLP 9/* a left paren in arithmetic */2475 #define CRP 10/* a right paren in arithmetic */2718 #define CBQUOTE 6 /* backwards single quote */ 2719 #define CVAR 7 /* a dollar sign */ 2720 #define CENDVAR 8 /* a '}' character */ 2721 #define CLP 9 /* a left paren in arithmetic */ 2722 #define CRP 10 /* a right paren in arithmetic */ 2476 2723 #define CENDFILE 11 /* end of file */ 2477 #define CCTL 12 /* like CWORD, except it must be escaped */ 2478 #define CSPCL 13 /* these terminate a word */ 2479 #define CIGN 14 /* character should be ignored */ 2480 2724 #define CCTL 12 /* like CWORD, except it must be escaped */ 2725 #define CSPCL 13 /* these terminate a word */ 2726 #define CIGN 14 /* character should be ignored */ 2727 2728 #define PEOF 256 2481 2729 #if ENABLE_ASH_ALIAS 2482 #define SYNBASE 130 2483 #define PEOF -130 2484 #define PEOA -129 2485 #define PEOA_OR_PEOF PEOA 2730 # define PEOA 257 2731 #endif 2732 2733 #define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE 2734 2735 #if ENABLE_SH_MATH_SUPPORT 2736 # define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12)) 2486 2737 #else 2487 #define SYNBASE 129 2488 #define PEOF -129 2489 #define PEOA_OR_PEOF PEOF 2490 #endif 2491 2492 /* number syntax index */ 2738 # define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8)) 2739 #endif 2740 static const uint16_t S_I_T[] = { 2741 #if ENABLE_ASH_ALIAS 2742 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */ 2743 #endif 2744 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */ 2745 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */ 2746 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */ 2747 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */ 2748 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */ 2749 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */ 2750 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */ 2751 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */ 2752 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */ 2753 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */ 2754 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */ 2755 #if !USE_SIT_FUNCTION 2756 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */ 2757 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */ 2758 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */ 2759 #endif 2760 #undef SIT_ITEM 2761 }; 2762 /* Constants below must match table above */ 2763 enum { 2764 #if ENABLE_ASH_ALIAS 2765 CSPCL_CIGN_CIGN_CIGN , /* 0 */ 2766 #endif 2767 CSPCL_CWORD_CWORD_CWORD , /* 1 */ 2768 CNL_CNL_CNL_CNL , /* 2 */ 2769 CWORD_CCTL_CCTL_CWORD , /* 3 */ 2770 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */ 2771 CVAR_CVAR_CWORD_CVAR , /* 5 */ 2772 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */ 2773 CSPCL_CWORD_CWORD_CLP , /* 7 */ 2774 CSPCL_CWORD_CWORD_CRP , /* 8 */ 2775 CBACK_CBACK_CCTL_CBACK , /* 9 */ 2776 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */ 2777 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */ 2778 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */ 2779 CWORD_CWORD_CWORD_CWORD , /* 13 */ 2780 CCTL_CCTL_CCTL_CCTL , /* 14 */ 2781 }; 2782 2783 /* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF, 2784 * caller must ensure proper cast on it if c is *char_ptr! 2785 */ 2786 /* Values for syntax param */ 2493 2787 #define BASESYNTAX 0 /* not in quotes */ 2494 2788 #define DQSYNTAX 1 /* in double quotes */ 2495 2789 #define SQSYNTAX 2 /* in single quotes */ 2496 2790 #define ARISYNTAX 3 /* in arithmetic */ 2497 2498 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE 2499 #define USE_SIT_FUNCTION 2500 #endif 2501 2502 #if ENABLE_ASH_MATH_SUPPORT 2503 static const char S_I_T[][4] = { 2504 #if ENABLE_ASH_ALIAS 2505 { CSPCL, CIGN, CIGN, CIGN }, /* 0, PEOA */ 2506 #endif 2507 { CSPCL, CWORD, CWORD, CWORD }, /* 1, ' ' */ 2508 { CNL, CNL, CNL, CNL }, /* 2, \n */ 2509 { CWORD, CCTL, CCTL, CWORD }, /* 3, !*-/:=?[]~ */ 2510 { CDQUOTE, CENDQUOTE, CWORD, CWORD }, /* 4, '"' */ 2511 { CVAR, CVAR, CWORD, CVAR }, /* 5, $ */ 2512 { CSQUOTE, CWORD, CENDQUOTE, CWORD }, /* 6, "'" */ 2513 { CSPCL, CWORD, CWORD, CLP }, /* 7, ( */ 2514 { CSPCL, CWORD, CWORD, CRP }, /* 8, ) */ 2515 { CBACK, CBACK, CCTL, CBACK }, /* 9, \ */ 2516 { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* 10, ` */ 2517 { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* 11, } */ 2518 #ifndef USE_SIT_FUNCTION 2519 { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */ 2520 { CWORD, CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */ 2521 { CCTL, CCTL, CCTL, CCTL } /* 14, CTLESC ... */ 2522 #endif 2523 }; 2524 #else 2525 static const char S_I_T[][3] = { 2526 #if ENABLE_ASH_ALIAS 2527 { CSPCL, CIGN, CIGN }, /* 0, PEOA */ 2528 #endif 2529 { CSPCL, CWORD, CWORD }, /* 1, ' ' */ 2530 { CNL, CNL, CNL }, /* 2, \n */ 2531 { CWORD, CCTL, CCTL }, /* 3, !*-/:=?[]~ */ 2532 { CDQUOTE, CENDQUOTE, CWORD }, /* 4, '"' */ 2533 { CVAR, CVAR, CWORD }, /* 5, $ */ 2534 { CSQUOTE, CWORD, CENDQUOTE }, /* 6, "'" */ 2535 { CSPCL, CWORD, CWORD }, /* 7, ( */ 2536 { CSPCL, CWORD, CWORD }, /* 8, ) */ 2537 { CBACK, CBACK, CCTL }, /* 9, \ */ 2538 { CBQUOTE, CBQUOTE, CWORD }, /* 10, ` */ 2539 { CENDVAR, CENDVAR, CWORD }, /* 11, } */ 2540 #ifndef USE_SIT_FUNCTION 2541 { CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */ 2542 { CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */ 2543 { CCTL, CCTL, CCTL } /* 14, CTLESC ... */ 2544 #endif 2545 }; 2546 #endif /* ASH_MATH_SUPPORT */ 2547 2548 #ifdef USE_SIT_FUNCTION 2791 #define PSSYNTAX 4 /* prompt. never passed to SIT() */ 2792 2793 #if USE_SIT_FUNCTION 2549 2794 2550 2795 static int … … 2552 2797 { 2553 2798 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~"; 2554 # if ENABLE_ASH_ALIAS2555 static const charsyntax_index_table[] ALIGN1 = {2799 # if ENABLE_ASH_ALIAS 2800 static const uint8_t syntax_index_table[] ALIGN1 = { 2556 2801 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */ 2557 2802 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */ … … 2559 2804 11, 3 /* "}~" */ 2560 2805 }; 2561 # else2562 static const charsyntax_index_table[] ALIGN1 = {2806 # else 2807 static const uint8_t syntax_index_table[] ALIGN1 = { 2563 2808 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */ 2564 2809 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */ … … 2566 2811 10, 2 /* "}~" */ 2567 2812 }; 2568 # endif2813 # endif 2569 2814 const char *s; 2570 2815 int indx; 2571 2816 2572 if (c == PEOF) /* 2^8+2 */2817 if (c == PEOF) 2573 2818 return CENDFILE; 2574 # if ENABLE_ASH_ALIAS2575 if (c == PEOA) /* 2^8+1 */2819 # if ENABLE_ASH_ALIAS 2820 if (c == PEOA) 2576 2821 indx = 0; 2577 2822 else 2578 #endif 2579 #define U_C(c) ((unsigned char)(c)) 2580 2581 if ((unsigned char)c >= (unsigned char)(CTLESC) 2582 && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK) 2583 ) { 2584 return CCTL; 2585 } else { 2586 s = strchr(spec_symbls, c); 2587 if (s == NULL || *s == '\0') 2823 # endif 2824 { 2825 /* Cast is purely for paranoia here, 2826 * just in case someone passed signed char to us */ 2827 if ((unsigned char)c >= CTL_FIRST 2828 && (unsigned char)c <= CTL_LAST 2829 ) { 2830 return CCTL; 2831 } 2832 s = strchrnul(spec_symbls, c); 2833 if (*s == '\0') 2588 2834 return CWORD; 2589 indx = syntax_index_table[ (s - spec_symbls)];2590 } 2591 return S_I_T[indx][syntax];2835 indx = syntax_index_table[s - spec_symbls]; 2836 } 2837 return (S_I_T[indx] >> (syntax*4)) & 0xf; 2592 2838 } 2593 2839 2594 2840 #else /* !USE_SIT_FUNCTION */ 2595 2841 2596 #if ENABLE_ASH_ALIAS 2597 #define CSPCL_CIGN_CIGN_CIGN 0 2598 #define CSPCL_CWORD_CWORD_CWORD 1 2599 #define CNL_CNL_CNL_CNL 2 2600 #define CWORD_CCTL_CCTL_CWORD 3 2601 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4 2602 #define CVAR_CVAR_CWORD_CVAR 5 2603 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6 2604 #define CSPCL_CWORD_CWORD_CLP 7 2605 #define CSPCL_CWORD_CWORD_CRP 8 2606 #define CBACK_CBACK_CCTL_CBACK 9 2607 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10 2608 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11 2609 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12 2610 #define CWORD_CWORD_CWORD_CWORD 13 2611 #define CCTL_CCTL_CCTL_CCTL 14 2612 #else 2613 #define CSPCL_CWORD_CWORD_CWORD 0 2614 #define CNL_CNL_CNL_CNL 1 2615 #define CWORD_CCTL_CCTL_CWORD 2 2616 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3 2617 #define CVAR_CVAR_CWORD_CVAR 4 2618 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5 2619 #define CSPCL_CWORD_CWORD_CLP 6 2620 #define CSPCL_CWORD_CWORD_CRP 7 2621 #define CBACK_CBACK_CCTL_CBACK 8 2622 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9 2623 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10 2624 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11 2625 #define CWORD_CWORD_CWORD_CWORD 12 2626 #define CCTL_CCTL_CCTL_CCTL 13 2627 #endif 2628 2629 static const char syntax_index_table[258] = { 2842 static const uint8_t syntax_index_table[] = { 2630 2843 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */ 2631 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,2632 #if ENABLE_ASH_ALIAS 2633 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,2634 #endif 2635 /* 2 -128 0x80*/ CWORD_CWORD_CWORD_CWORD,2636 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,2637 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,2638 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,2639 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,2640 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,2641 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,2642 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,2643 /* 1 0 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,2644 /* 1 1 -119*/ CWORD_CWORD_CWORD_CWORD,2645 /* 1 2 -118*/ CWORD_CWORD_CWORD_CWORD,2646 /* 1 3 -117*/ CWORD_CWORD_CWORD_CWORD,2647 /* 1 4 -116 */ CWORD_CWORD_CWORD_CWORD,2648 /* 1 5 -115*/ CWORD_CWORD_CWORD_CWORD,2649 /* 1 6 -114*/ CWORD_CWORD_CWORD_CWORD,2650 /* 1 7 -113*/ CWORD_CWORD_CWORD_CWORD,2651 /* 18 -112*/ CWORD_CWORD_CWORD_CWORD,2652 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,2653 /* 2 0 -110*/ CWORD_CWORD_CWORD_CWORD,2654 /* 2 1 -109*/ CWORD_CWORD_CWORD_CWORD,2655 /* 2 2 -108*/ CWORD_CWORD_CWORD_CWORD,2656 /* 2 3 -107*/ CWORD_CWORD_CWORD_CWORD,2657 /* 2 4 -106 */ CWORD_CWORD_CWORD_CWORD,2658 /* 2 5 -105*/ CWORD_CWORD_CWORD_CWORD,2659 /* 2 6 -104*/ CWORD_CWORD_CWORD_CWORD,2660 /* 2 7 -103*/ CWORD_CWORD_CWORD_CWORD,2661 /* 28 -102*/ CWORD_CWORD_CWORD_CWORD,2662 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,2663 /* 3 0 -100 */ CWORD_CWORD_CWORD_CWORD,2664 /* 3 1 -99 */ CWORD_CWORD_CWORD_CWORD,2665 /* 3 2 -98 */ CWORD_CWORD_CWORD_CWORD,2666 /* 3 3 -97*/ CWORD_CWORD_CWORD_CWORD,2667 /* 3 4 -96 */ CWORD_CWORD_CWORD_CWORD,2668 /* 3 5 -95*/ CWORD_CWORD_CWORD_CWORD,2669 /* 3 6 -94 */ CWORD_CWORD_CWORD_CWORD,2670 /* 3 7 -93 */ CWORD_CWORD_CWORD_CWORD,2671 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,2672 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,2673 /* 4 0 -90 */ CWORD_CWORD_CWORD_CWORD,2674 /* 4 1 -89*/ CWORD_CWORD_CWORD_CWORD,2675 /* 4 2 -88*/ CWORD_CWORD_CWORD_CWORD,2676 /* 4 3 -87 */ CWORD_CWORD_CWORD_CWORD,2677 /* 4 4 -86*/ CWORD_CWORD_CWORD_CWORD,2678 /* 4 5 -85 */ CWORD_CWORD_CWORD_CWORD,2679 /* 4 6 -84*/ CWORD_CWORD_CWORD_CWORD,2680 /* 4 7 -83*/ CWORD_CWORD_CWORD_CWORD,2681 /* 48 -82*/ CWORD_CWORD_CWORD_CWORD,2682 /* 49 -81*/ CWORD_CWORD_CWORD_CWORD,2683 /* 5 0 -80*/ CWORD_CWORD_CWORD_CWORD,2684 /* 5 1 -79*/ CWORD_CWORD_CWORD_CWORD,2685 /* 5 2 -78*/ CWORD_CWORD_CWORD_CWORD,2686 /* 5 3 -77*/ CWORD_CWORD_CWORD_CWORD,2687 /* 5 4 -76*/ CWORD_CWORD_CWORD_CWORD,2688 /* 5 5 -75*/ CWORD_CWORD_CWORD_CWORD,2689 /* 5 6 -74 */ CWORD_CWORD_CWORD_CWORD,2690 /* 5 7 -73 */ CWORD_CWORD_CWORD_CWORD,2691 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,2692 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,2693 /* 6 0 -70 */ CWORD_CWORD_CWORD_CWORD,2694 /* 6 1 -69 */ CWORD_CWORD_CWORD_CWORD,2695 /* 6 2 -68*/ CWORD_CWORD_CWORD_CWORD,2696 /* 6 3 -67*/ CWORD_CWORD_CWORD_CWORD,2697 /* 6 4 -66*/ CWORD_CWORD_CWORD_CWORD,2698 /* 6 5 -65*/ CWORD_CWORD_CWORD_CWORD,2699 /* 6 6 -64*/ CWORD_CWORD_CWORD_CWORD,2700 /* 6 7 -63*/ CWORD_CWORD_CWORD_CWORD,2701 /* 68 -62*/ CWORD_CWORD_CWORD_CWORD,2702 /* 69 -61*/ CWORD_CWORD_CWORD_CWORD,2703 /* 7 0 -60*/ CWORD_CWORD_CWORD_CWORD,2704 /* 7 1 -59*/ CWORD_CWORD_CWORD_CWORD,2705 /* 7 2 -58*/ CWORD_CWORD_CWORD_CWORD,2706 /* 7 3 -57*/ CWORD_CWORD_CWORD_CWORD,2707 /* 7 4 -56*/ CWORD_CWORD_CWORD_CWORD,2708 /* 7 5 -55*/ CWORD_CWORD_CWORD_CWORD,2709 /* 7 6 -54*/ CWORD_CWORD_CWORD_CWORD,2710 /* 7 7 -53*/ CWORD_CWORD_CWORD_CWORD,2711 /* 78 -52*/ CWORD_CWORD_CWORD_CWORD,2712 /* 79 -51*/ CWORD_CWORD_CWORD_CWORD,2713 /* 8 0 -50*/ CWORD_CWORD_CWORD_CWORD,2714 /* 8 1 -49*/ CWORD_CWORD_CWORD_CWORD,2715 /* 8 2 -48*/ CWORD_CWORD_CWORD_CWORD,2716 /* 8 3 -47*/ CWORD_CWORD_CWORD_CWORD,2717 /* 8 4 -46*/ CWORD_CWORD_CWORD_CWORD,2718 /* 8 5 -45*/ CWORD_CWORD_CWORD_CWORD,2719 /* 8 6 -44*/ CWORD_CWORD_CWORD_CWORD,2720 /* 8 7 -43*/ CWORD_CWORD_CWORD_CWORD,2721 /* 88 -42*/ CWORD_CWORD_CWORD_CWORD,2722 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,2723 /* 9 0 -40 */ CWORD_CWORD_CWORD_CWORD,2724 /* 9 1 -39 */ CWORD_CWORD_CWORD_CWORD,2725 /* 9 2 -38*/ CWORD_CWORD_CWORD_CWORD,2726 /* 9 3 -37*/ CWORD_CWORD_CWORD_CWORD,2727 /* 9 4 -36 */ CWORD_CWORD_CWORD_CWORD,2728 /* 9 5 -35*/ CWORD_CWORD_CWORD_CWORD,2729 /* 9 6 -34*/ CWORD_CWORD_CWORD_CWORD,2730 /* 9 7 -33*/ CWORD_CWORD_CWORD_CWORD,2731 /* 98 -32*/ CWORD_CWORD_CWORD_CWORD,2732 /* 99 -31*/ CWORD_CWORD_CWORD_CWORD,2733 /* 10 0 -30*/ CWORD_CWORD_CWORD_CWORD,2734 /* 10 1 -29*/ CWORD_CWORD_CWORD_CWORD,2735 /* 10 2 -28*/ CWORD_CWORD_CWORD_CWORD,2736 /* 10 3 -27*/ CWORD_CWORD_CWORD_CWORD,2737 /* 10 4 -26*/ CWORD_CWORD_CWORD_CWORD,2738 /* 10 5 -25*/ CWORD_CWORD_CWORD_CWORD,2739 /* 10 6 -24*/ CWORD_CWORD_CWORD_CWORD,2740 /* 10 7 -23*/ CWORD_CWORD_CWORD_CWORD,2741 /* 1 08 -22*/ CWORD_CWORD_CWORD_CWORD,2742 /* 1 09 -21*/ CWORD_CWORD_CWORD_CWORD,2743 /* 11 0 -20*/ CWORD_CWORD_CWORD_CWORD,2744 /* 11 1 -19*/ CWORD_CWORD_CWORD_CWORD,2745 /* 11 2 -18*/ CWORD_CWORD_CWORD_CWORD,2746 /* 11 3 -17*/ CWORD_CWORD_CWORD_CWORD,2747 /* 11 4 -16*/ CWORD_CWORD_CWORD_CWORD,2748 /* 11 5 -15*/ CWORD_CWORD_CWORD_CWORD,2749 /* 11 6 -14*/ CWORD_CWORD_CWORD_CWORD,2750 /* 11 7 -13*/ CWORD_CWORD_CWORD_CWORD,2751 /* 1 18 -12*/ CWORD_CWORD_CWORD_CWORD,2752 /* 1 19 -11*/ CWORD_CWORD_CWORD_CWORD,2753 /* 12 0 -10*/ CWORD_CWORD_CWORD_CWORD,2754 /* 12 1 -9*/ CWORD_CWORD_CWORD_CWORD,2755 /* 12 2 -8 */ CWORD_CWORD_CWORD_CWORD,2756 /* 12 3 -7 */ CWORD_CWORD_CWORD_CWORD,2757 /* 12 4 -6 */ CWORD_CWORD_CWORD_CWORD,2758 /* 12 5 -5*/ CWORD_CWORD_CWORD_CWORD,2759 /* 12 6 -4*/ CWORD_CWORD_CWORD_CWORD,2760 /* 12 7 -3 */ CWORD_CWORD_CWORD_CWORD,2761 /* 1 28 -2 */ CWORD_CWORD_CWORD_CWORD,2762 /* 1 29 -1 */ CWORD_CWORD_CWORD_CWORD,2763 /* 13 0 0 */ CWORD_CWORD_CWORD_CWORD,2764 /* 13 1 1 */ CWORD_CWORD_CWORD_CWORD,2765 /* 13 2 2 */ CWORD_CWORD_CWORD_CWORD,2766 /* 13 3 3 */ CWORD_CWORD_CWORD_CWORD,2767 /* 13 4 4 */ CWORD_CWORD_CWORD_CWORD,2768 /* 13 5 5*/ CWORD_CWORD_CWORD_CWORD,2769 /* 13 6 6*/ CWORD_CWORD_CWORD_CWORD,2770 /* 13 7 7*/ CWORD_CWORD_CWORD_CWORD,2771 /* 1 38 8*/ CWORD_CWORD_CWORD_CWORD,2772 /* 1 39 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,2773 /* 14 0 10 "\n" */ CNL_CNL_CNL_CNL,2774 /* 14 1 11*/ CWORD_CWORD_CWORD_CWORD,2775 /* 14 2 12*/ CWORD_CWORD_CWORD_CWORD,2776 /* 14 3 13*/ CWORD_CWORD_CWORD_CWORD,2777 /* 14 4 14*/ CWORD_CWORD_CWORD_CWORD,2778 /* 14 5 15*/ CWORD_CWORD_CWORD_CWORD,2779 /* 14 6 16*/ CWORD_CWORD_CWORD_CWORD,2780 /* 14 7 17*/ CWORD_CWORD_CWORD_CWORD,2781 /* 1 48 18*/ CWORD_CWORD_CWORD_CWORD,2782 /* 1 49 19*/ CWORD_CWORD_CWORD_CWORD,2783 /* 15 0 20*/ CWORD_CWORD_CWORD_CWORD,2784 /* 15 1 21*/ CWORD_CWORD_CWORD_CWORD,2785 /* 15 2 22*/ CWORD_CWORD_CWORD_CWORD,2786 /* 15 3 23*/ CWORD_CWORD_CWORD_CWORD,2787 /* 15 4 24*/ CWORD_CWORD_CWORD_CWORD,2788 /* 15 5 25*/ CWORD_CWORD_CWORD_CWORD,2789 /* 15 6 26*/ CWORD_CWORD_CWORD_CWORD,2790 /* 15 7 27*/ CWORD_CWORD_CWORD_CWORD,2791 /* 1 58 28*/ CWORD_CWORD_CWORD_CWORD,2792 /* 1 59 29*/ CWORD_CWORD_CWORD_CWORD,2793 /* 16 0 30*/ CWORD_CWORD_CWORD_CWORD,2794 /* 16 1 31*/ CWORD_CWORD_CWORD_CWORD,2795 /* 16 2 32 " " */ CSPCL_CWORD_CWORD_CWORD,2796 /* 16 3 33 "!" */ CWORD_CCTL_CCTL_CWORD,2797 /* 16 4 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,2798 /* 16 5 35 "#"*/ CWORD_CWORD_CWORD_CWORD,2799 /* 16 6 36 "$" */ CVAR_CVAR_CWORD_CVAR,2800 /* 16 7 37 "%"*/ CWORD_CWORD_CWORD_CWORD,2801 /* 1 68 38 "&" */ CSPCL_CWORD_CWORD_CWORD,2802 /* 1 69 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,2803 /* 17 0 40 "(" */ CSPCL_CWORD_CWORD_CLP,2804 /* 17 1 41 ")" */ CSPCL_CWORD_CWORD_CRP,2805 /* 17 2 42 "*" */ CWORD_CCTL_CCTL_CWORD,2806 /* 17 3 43 "+"*/ CWORD_CWORD_CWORD_CWORD,2807 /* 17 4 44 ","*/ CWORD_CWORD_CWORD_CWORD,2808 /* 17 5 45 "-" */ CWORD_CCTL_CCTL_CWORD,2809 /* 17 6 46 "."*/ CWORD_CWORD_CWORD_CWORD,2810 /* 17 7 47 "/" */ CWORD_CCTL_CCTL_CWORD,2811 /* 1 78 48 "0"*/ CWORD_CWORD_CWORD_CWORD,2812 /* 1 79 49 "1"*/ CWORD_CWORD_CWORD_CWORD,2813 /* 18 0 50 "2"*/ CWORD_CWORD_CWORD_CWORD,2814 /* 18 1 51 "3"*/ CWORD_CWORD_CWORD_CWORD,2815 /* 18 2 52 "4"*/ CWORD_CWORD_CWORD_CWORD,2816 /* 18 3 53 "5"*/ CWORD_CWORD_CWORD_CWORD,2817 /* 18 4 54 "6"*/ CWORD_CWORD_CWORD_CWORD,2818 /* 18 5 55 "7"*/ CWORD_CWORD_CWORD_CWORD,2819 /* 18 6 56 "8"*/ CWORD_CWORD_CWORD_CWORD,2820 /* 18 7 57 "9"*/ CWORD_CWORD_CWORD_CWORD,2821 /* 1 88 58 ":" */ CWORD_CCTL_CCTL_CWORD,2822 /* 1 89 59 ";" */ CSPCL_CWORD_CWORD_CWORD,2823 /* 19 0 60 "<" */ CSPCL_CWORD_CWORD_CWORD,2824 /* 19 1 61 "=" */ CWORD_CCTL_CCTL_CWORD,2825 /* 19 2 62 ">" */ CSPCL_CWORD_CWORD_CWORD,2826 /* 19 3 63 "?" */ CWORD_CCTL_CCTL_CWORD,2827 /* 19 4 64 "@"*/ CWORD_CWORD_CWORD_CWORD,2828 /* 19 5 65 "A"*/ CWORD_CWORD_CWORD_CWORD,2829 /* 19 6 66 "B"*/ CWORD_CWORD_CWORD_CWORD,2830 /* 19 7 67 "C"*/ CWORD_CWORD_CWORD_CWORD,2831 /* 198 68 "D"*/ CWORD_CWORD_CWORD_CWORD,2832 /* 199 69 "E"*/ CWORD_CWORD_CWORD_CWORD,2833 /* 20 0 70 "F"*/ CWORD_CWORD_CWORD_CWORD,2834 /* 20 1 71 "G"*/ CWORD_CWORD_CWORD_CWORD,2835 /* 20 2 72 "H"*/ CWORD_CWORD_CWORD_CWORD,2836 /* 20 3 73 "I"*/ CWORD_CWORD_CWORD_CWORD,2837 /* 20 4 74 "J"*/ CWORD_CWORD_CWORD_CWORD,2838 /* 20 5 75 "K"*/ CWORD_CWORD_CWORD_CWORD,2839 /* 20 6 76 "L"*/ CWORD_CWORD_CWORD_CWORD,2840 /* 20 7 77 "M"*/ CWORD_CWORD_CWORD_CWORD,2841 /* 2 08 78 "N"*/ CWORD_CWORD_CWORD_CWORD,2842 /* 2 09 79 "O"*/ CWORD_CWORD_CWORD_CWORD,2843 /* 21 0 80 "P"*/ CWORD_CWORD_CWORD_CWORD,2844 /* 21 1 81 "Q"*/ CWORD_CWORD_CWORD_CWORD,2845 /* 21 2 82 "R"*/ CWORD_CWORD_CWORD_CWORD,2846 /* 21 3 83 "S"*/ CWORD_CWORD_CWORD_CWORD,2847 /* 21 4 84 "T"*/ CWORD_CWORD_CWORD_CWORD,2848 /* 21 5 85 "U"*/ CWORD_CWORD_CWORD_CWORD,2849 /* 21 6 86 "V"*/ CWORD_CWORD_CWORD_CWORD,2850 /* 21 7 87 "W"*/ CWORD_CWORD_CWORD_CWORD,2851 /* 2 18 88 "X"*/ CWORD_CWORD_CWORD_CWORD,2852 /* 2 19 89 "Y"*/ CWORD_CWORD_CWORD_CWORD,2853 /* 22 0 90 "Z"*/ CWORD_CWORD_CWORD_CWORD,2854 /* 22 1 91 "[" */ CWORD_CCTL_CCTL_CWORD,2855 /* 22 2 92 "\" */ CBACK_CBACK_CCTL_CBACK,2856 /* 22 3 93 "]" */ CWORD_CCTL_CCTL_CWORD,2857 /* 22 4 94 "^"*/ CWORD_CWORD_CWORD_CWORD,2858 /* 22 5 95 "_"*/ CWORD_CWORD_CWORD_CWORD,2859 /* 22 6 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,2860 /* 22 7 97 "a"*/ CWORD_CWORD_CWORD_CWORD,2861 /* 2 28 98 "b"*/ CWORD_CWORD_CWORD_CWORD,2862 /* 2 29 99 "c"*/ CWORD_CWORD_CWORD_CWORD,2863 /* 23 0 100 "d"*/ CWORD_CWORD_CWORD_CWORD,2864 /* 23 1 101 "e"*/ CWORD_CWORD_CWORD_CWORD,2865 /* 23 2 102 "f"*/ CWORD_CWORD_CWORD_CWORD,2866 /* 23 3 103 "g"*/ CWORD_CWORD_CWORD_CWORD,2867 /* 23 4 104 "h"*/ CWORD_CWORD_CWORD_CWORD,2868 /* 23 5 105 "i"*/ CWORD_CWORD_CWORD_CWORD,2869 /* 23 6 106 "j"*/ CWORD_CWORD_CWORD_CWORD,2870 /* 23 7 107 "k"*/ CWORD_CWORD_CWORD_CWORD,2871 /* 23 8 108 "l"*/ CWORD_CWORD_CWORD_CWORD,2872 /* 2 39 109 "m"*/ CWORD_CWORD_CWORD_CWORD,2873 /* 24 0 110 "n"*/ CWORD_CWORD_CWORD_CWORD,2874 /* 24 1 111 "o"*/ CWORD_CWORD_CWORD_CWORD,2875 /* 24 2 112 "p"*/ CWORD_CWORD_CWORD_CWORD,2876 /* 24 3 113 "q"*/ CWORD_CWORD_CWORD_CWORD,2877 /* 24 4 114 "r"*/ CWORD_CWORD_CWORD_CWORD,2878 /* 24 5 115 "s"*/ CWORD_CWORD_CWORD_CWORD,2879 /* 24 6 116 "t"*/ CWORD_CWORD_CWORD_CWORD,2880 /* 24 7 117 "u"*/ CWORD_CWORD_CWORD_CWORD,2881 /* 2 48 118 "v"*/ CWORD_CWORD_CWORD_CWORD,2882 /* 2 49 119 "w"*/ CWORD_CWORD_CWORD_CWORD,2883 /* 25 0 120 "x"*/ CWORD_CWORD_CWORD_CWORD,2884 /* 25 1 121 "y"*/ CWORD_CWORD_CWORD_CWORD,2885 /* 25 2 122 "z"*/ CWORD_CWORD_CWORD_CWORD,2886 /* 25 3 123 "{"*/ CWORD_CWORD_CWORD_CWORD,2887 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,2888 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR, 2889 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,2890 /* 257 127 */ CWORD_CWORD_CWORD_CWORD, 2844 /* 0 */ CWORD_CWORD_CWORD_CWORD, 2845 /* 1 */ CWORD_CWORD_CWORD_CWORD, 2846 /* 2 */ CWORD_CWORD_CWORD_CWORD, 2847 /* 3 */ CWORD_CWORD_CWORD_CWORD, 2848 /* 4 */ CWORD_CWORD_CWORD_CWORD, 2849 /* 5 */ CWORD_CWORD_CWORD_CWORD, 2850 /* 6 */ CWORD_CWORD_CWORD_CWORD, 2851 /* 7 */ CWORD_CWORD_CWORD_CWORD, 2852 /* 8 */ CWORD_CWORD_CWORD_CWORD, 2853 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD, 2854 /* 10 "\n" */ CNL_CNL_CNL_CNL, 2855 /* 11 */ CWORD_CWORD_CWORD_CWORD, 2856 /* 12 */ CWORD_CWORD_CWORD_CWORD, 2857 /* 13 */ CWORD_CWORD_CWORD_CWORD, 2858 /* 14 */ CWORD_CWORD_CWORD_CWORD, 2859 /* 15 */ CWORD_CWORD_CWORD_CWORD, 2860 /* 16 */ CWORD_CWORD_CWORD_CWORD, 2861 /* 17 */ CWORD_CWORD_CWORD_CWORD, 2862 /* 18 */ CWORD_CWORD_CWORD_CWORD, 2863 /* 19 */ CWORD_CWORD_CWORD_CWORD, 2864 /* 20 */ CWORD_CWORD_CWORD_CWORD, 2865 /* 21 */ CWORD_CWORD_CWORD_CWORD, 2866 /* 22 */ CWORD_CWORD_CWORD_CWORD, 2867 /* 23 */ CWORD_CWORD_CWORD_CWORD, 2868 /* 24 */ CWORD_CWORD_CWORD_CWORD, 2869 /* 25 */ CWORD_CWORD_CWORD_CWORD, 2870 /* 26 */ CWORD_CWORD_CWORD_CWORD, 2871 /* 27 */ CWORD_CWORD_CWORD_CWORD, 2872 /* 28 */ CWORD_CWORD_CWORD_CWORD, 2873 /* 29 */ CWORD_CWORD_CWORD_CWORD, 2874 /* 30 */ CWORD_CWORD_CWORD_CWORD, 2875 /* 31 */ CWORD_CWORD_CWORD_CWORD, 2876 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD, 2877 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD, 2878 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD, 2879 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD, 2880 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR, 2881 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD, 2882 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD, 2883 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD, 2884 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP, 2885 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP, 2886 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD, 2887 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD, 2888 /* 44 "," */ CWORD_CWORD_CWORD_CWORD, 2889 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD, 2890 /* 46 "." */ CWORD_CWORD_CWORD_CWORD, 2891 /* 47 "/" */ CWORD_CCTL_CCTL_CWORD, 2892 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD, 2893 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD, 2894 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD, 2895 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD, 2896 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD, 2897 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD, 2898 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD, 2899 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD, 2900 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD, 2901 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD, 2902 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD, 2903 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD, 2904 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD, 2905 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD, 2906 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD, 2907 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD, 2908 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD, 2909 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD, 2910 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD, 2911 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD, 2912 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD, 2913 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD, 2914 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD, 2915 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD, 2916 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD, 2917 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD, 2918 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD, 2919 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD, 2920 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD, 2921 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD, 2922 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD, 2923 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD, 2924 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD, 2925 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD, 2926 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD, 2927 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD, 2928 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD, 2929 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD, 2930 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD, 2931 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD, 2932 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD, 2933 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD, 2934 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD, 2935 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD, 2936 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK, 2937 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD, 2938 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD, 2939 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD, 2940 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE, 2941 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD, 2942 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD, 2943 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD, 2944 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD, 2945 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD, 2946 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD, 2947 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD, 2948 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD, 2949 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD, 2950 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD, 2951 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD, 2952 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD, 2953 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD, 2954 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD, 2955 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD, 2956 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD, 2957 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD, 2958 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD, 2959 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD, 2960 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD, 2961 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD, 2962 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD, 2963 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD, 2964 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD, 2965 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD, 2966 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD, 2967 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD, 2968 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD, 2969 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR, 2970 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD, 2971 /* 127 del */ CWORD_CWORD_CWORD_CWORD, 2972 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD, 2973 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL, 2974 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL, 2975 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL, 2976 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL, 2977 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL, 2978 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL, 2979 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL, 2980 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL, 2981 /* 137 */ CWORD_CWORD_CWORD_CWORD, 2982 /* 138 */ CWORD_CWORD_CWORD_CWORD, 2983 /* 139 */ CWORD_CWORD_CWORD_CWORD, 2984 /* 140 */ CWORD_CWORD_CWORD_CWORD, 2985 /* 141 */ CWORD_CWORD_CWORD_CWORD, 2986 /* 142 */ CWORD_CWORD_CWORD_CWORD, 2987 /* 143 */ CWORD_CWORD_CWORD_CWORD, 2988 /* 144 */ CWORD_CWORD_CWORD_CWORD, 2989 /* 145 */ CWORD_CWORD_CWORD_CWORD, 2990 /* 146 */ CWORD_CWORD_CWORD_CWORD, 2991 /* 147 */ CWORD_CWORD_CWORD_CWORD, 2992 /* 148 */ CWORD_CWORD_CWORD_CWORD, 2993 /* 149 */ CWORD_CWORD_CWORD_CWORD, 2994 /* 150 */ CWORD_CWORD_CWORD_CWORD, 2995 /* 151 */ CWORD_CWORD_CWORD_CWORD, 2996 /* 152 */ CWORD_CWORD_CWORD_CWORD, 2997 /* 153 */ CWORD_CWORD_CWORD_CWORD, 2998 /* 154 */ CWORD_CWORD_CWORD_CWORD, 2999 /* 155 */ CWORD_CWORD_CWORD_CWORD, 3000 /* 156 */ CWORD_CWORD_CWORD_CWORD, 3001 /* 157 */ CWORD_CWORD_CWORD_CWORD, 3002 /* 158 */ CWORD_CWORD_CWORD_CWORD, 3003 /* 159 */ CWORD_CWORD_CWORD_CWORD, 3004 /* 160 */ CWORD_CWORD_CWORD_CWORD, 3005 /* 161 */ CWORD_CWORD_CWORD_CWORD, 3006 /* 162 */ CWORD_CWORD_CWORD_CWORD, 3007 /* 163 */ CWORD_CWORD_CWORD_CWORD, 3008 /* 164 */ CWORD_CWORD_CWORD_CWORD, 3009 /* 165 */ CWORD_CWORD_CWORD_CWORD, 3010 /* 166 */ CWORD_CWORD_CWORD_CWORD, 3011 /* 167 */ CWORD_CWORD_CWORD_CWORD, 3012 /* 168 */ CWORD_CWORD_CWORD_CWORD, 3013 /* 169 */ CWORD_CWORD_CWORD_CWORD, 3014 /* 170 */ CWORD_CWORD_CWORD_CWORD, 3015 /* 171 */ CWORD_CWORD_CWORD_CWORD, 3016 /* 172 */ CWORD_CWORD_CWORD_CWORD, 3017 /* 173 */ CWORD_CWORD_CWORD_CWORD, 3018 /* 174 */ CWORD_CWORD_CWORD_CWORD, 3019 /* 175 */ CWORD_CWORD_CWORD_CWORD, 3020 /* 176 */ CWORD_CWORD_CWORD_CWORD, 3021 /* 177 */ CWORD_CWORD_CWORD_CWORD, 3022 /* 178 */ CWORD_CWORD_CWORD_CWORD, 3023 /* 179 */ CWORD_CWORD_CWORD_CWORD, 3024 /* 180 */ CWORD_CWORD_CWORD_CWORD, 3025 /* 181 */ CWORD_CWORD_CWORD_CWORD, 3026 /* 182 */ CWORD_CWORD_CWORD_CWORD, 3027 /* 183 */ CWORD_CWORD_CWORD_CWORD, 3028 /* 184 */ CWORD_CWORD_CWORD_CWORD, 3029 /* 185 */ CWORD_CWORD_CWORD_CWORD, 3030 /* 186 */ CWORD_CWORD_CWORD_CWORD, 3031 /* 187 */ CWORD_CWORD_CWORD_CWORD, 3032 /* 188 */ CWORD_CWORD_CWORD_CWORD, 3033 /* 189 */ CWORD_CWORD_CWORD_CWORD, 3034 /* 190 */ CWORD_CWORD_CWORD_CWORD, 3035 /* 191 */ CWORD_CWORD_CWORD_CWORD, 3036 /* 192 */ CWORD_CWORD_CWORD_CWORD, 3037 /* 193 */ CWORD_CWORD_CWORD_CWORD, 3038 /* 194 */ CWORD_CWORD_CWORD_CWORD, 3039 /* 195 */ CWORD_CWORD_CWORD_CWORD, 3040 /* 196 */ CWORD_CWORD_CWORD_CWORD, 3041 /* 197 */ CWORD_CWORD_CWORD_CWORD, 3042 /* 198 */ CWORD_CWORD_CWORD_CWORD, 3043 /* 199 */ CWORD_CWORD_CWORD_CWORD, 3044 /* 200 */ CWORD_CWORD_CWORD_CWORD, 3045 /* 201 */ CWORD_CWORD_CWORD_CWORD, 3046 /* 202 */ CWORD_CWORD_CWORD_CWORD, 3047 /* 203 */ CWORD_CWORD_CWORD_CWORD, 3048 /* 204 */ CWORD_CWORD_CWORD_CWORD, 3049 /* 205 */ CWORD_CWORD_CWORD_CWORD, 3050 /* 206 */ CWORD_CWORD_CWORD_CWORD, 3051 /* 207 */ CWORD_CWORD_CWORD_CWORD, 3052 /* 208 */ CWORD_CWORD_CWORD_CWORD, 3053 /* 209 */ CWORD_CWORD_CWORD_CWORD, 3054 /* 210 */ CWORD_CWORD_CWORD_CWORD, 3055 /* 211 */ CWORD_CWORD_CWORD_CWORD, 3056 /* 212 */ CWORD_CWORD_CWORD_CWORD, 3057 /* 213 */ CWORD_CWORD_CWORD_CWORD, 3058 /* 214 */ CWORD_CWORD_CWORD_CWORD, 3059 /* 215 */ CWORD_CWORD_CWORD_CWORD, 3060 /* 216 */ CWORD_CWORD_CWORD_CWORD, 3061 /* 217 */ CWORD_CWORD_CWORD_CWORD, 3062 /* 218 */ CWORD_CWORD_CWORD_CWORD, 3063 /* 219 */ CWORD_CWORD_CWORD_CWORD, 3064 /* 220 */ CWORD_CWORD_CWORD_CWORD, 3065 /* 221 */ CWORD_CWORD_CWORD_CWORD, 3066 /* 222 */ CWORD_CWORD_CWORD_CWORD, 3067 /* 223 */ CWORD_CWORD_CWORD_CWORD, 3068 /* 224 */ CWORD_CWORD_CWORD_CWORD, 3069 /* 225 */ CWORD_CWORD_CWORD_CWORD, 3070 /* 226 */ CWORD_CWORD_CWORD_CWORD, 3071 /* 227 */ CWORD_CWORD_CWORD_CWORD, 3072 /* 228 */ CWORD_CWORD_CWORD_CWORD, 3073 /* 229 */ CWORD_CWORD_CWORD_CWORD, 3074 /* 230 */ CWORD_CWORD_CWORD_CWORD, 3075 /* 231 */ CWORD_CWORD_CWORD_CWORD, 3076 /* 232 */ CWORD_CWORD_CWORD_CWORD, 3077 /* 233 */ CWORD_CWORD_CWORD_CWORD, 3078 /* 234 */ CWORD_CWORD_CWORD_CWORD, 3079 /* 235 */ CWORD_CWORD_CWORD_CWORD, 3080 /* 236 */ CWORD_CWORD_CWORD_CWORD, 3081 /* 237 */ CWORD_CWORD_CWORD_CWORD, 3082 /* 238 */ CWORD_CWORD_CWORD_CWORD, 3083 /* 239 */ CWORD_CWORD_CWORD_CWORD, 3084 /* 230 */ CWORD_CWORD_CWORD_CWORD, 3085 /* 241 */ CWORD_CWORD_CWORD_CWORD, 3086 /* 242 */ CWORD_CWORD_CWORD_CWORD, 3087 /* 243 */ CWORD_CWORD_CWORD_CWORD, 3088 /* 244 */ CWORD_CWORD_CWORD_CWORD, 3089 /* 245 */ CWORD_CWORD_CWORD_CWORD, 3090 /* 246 */ CWORD_CWORD_CWORD_CWORD, 3091 /* 247 */ CWORD_CWORD_CWORD_CWORD, 3092 /* 248 */ CWORD_CWORD_CWORD_CWORD, 3093 /* 249 */ CWORD_CWORD_CWORD_CWORD, 3094 /* 250 */ CWORD_CWORD_CWORD_CWORD, 3095 /* 251 */ CWORD_CWORD_CWORD_CWORD, 3096 /* 252 */ CWORD_CWORD_CWORD_CWORD, 3097 /* 253 */ CWORD_CWORD_CWORD_CWORD, 3098 /* 254 */ CWORD_CWORD_CWORD_CWORD, 3099 /* 255 */ CWORD_CWORD_CWORD_CWORD, 3100 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE, 3101 # if ENABLE_ASH_ALIAS 3102 /* PEOA */ CSPCL_CIGN_CIGN_CIGN, 3103 # endif 2891 3104 }; 2892 3105 2893 # define SIT(c, syntax) (S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax])2894 2895 #endif /* USE_SIT_FUNCTION */3106 # define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf) 3107 3108 #endif /* !USE_SIT_FUNCTION */ 2896 3109 2897 3110 … … 2902 3115 #define ALIASINUSE 1 2903 3116 #define ALIASDEAD 2 2904 2905 #define ATABSIZE 392906 3117 2907 3118 struct alias { … … 2912 3123 }; 2913 3124 2914 static struct alias *atab[ATABSIZE]; 3125 3126 static struct alias **atab; // [ATABSIZE]; 3127 #define INIT_G_alias() do { \ 3128 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \ 3129 } while (0) 3130 2915 3131 2916 3132 static struct alias ** … … 2983 3199 } else { 2984 3200 /* not found */ 2985 ap = ck malloc(sizeof(struct alias));3201 ap = ckzalloc(sizeof(struct alias)); 2986 3202 ap->name = ckstrdup(name); 2987 3203 ap->val = ckstrdup(val); 2988 ap->flag = 0;2989 ap->next = 0;3204 /*ap->flag = 0; - ckzalloc did it */ 3205 /*ap->next = NULL;*/ 2990 3206 *app = ap; 2991 3207 } … … 3038 3254 * TODO - sort output 3039 3255 */ 3040 static int 3041 aliascmd(int argc , char **argv)3256 static int FAST_FUNC 3257 aliascmd(int argc UNUSED_PARAM, char **argv) 3042 3258 { 3043 3259 char *n, *v; … … 3045 3261 struct alias *ap; 3046 3262 3047 if ( argc == 1) {3263 if (!argv[1]) { 3048 3264 int i; 3049 3265 3050 for (i = 0; i < ATABSIZE; i++) 3266 for (i = 0; i < ATABSIZE; i++) { 3051 3267 for (ap = atab[i]; ap; ap = ap->next) { 3052 3268 printalias(ap); 3053 3269 } 3270 } 3054 3271 return 0; 3055 3272 } … … 3072 3289 } 3073 3290 3074 static int 3075 unaliascmd(int argc , char **argv)3291 static int FAST_FUNC 3292 unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 3076 3293 { 3077 3294 int i; … … 3099 3316 3100 3317 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ 3101 #define FORK_FG 03102 #define FORK_BG 13318 #define FORK_FG 0 3319 #define FORK_BG 1 3103 3320 #define FORK_NOJOB 2 3104 3321 3105 3322 /* mode flags for showjob(s) */ 3106 #define SHOW_ PGID 0x01 /* only show pgid - for jobs -p*/3107 #define SHOW_PID 0x04 /* include process pid*/3108 #define SHOW_CHANGED 0x0 8/* only jobs whose state has changed */3323 #define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */ 3324 #define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */ 3325 #define SHOW_CHANGED 0x04 /* only jobs whose state has changed */ 3109 3326 3110 3327 /* … … 3114 3331 * array of pids. 3115 3332 */ 3116 3117 3333 struct procstat { 3118 pid_t p id;/* process id */3119 int status;/* last process status from wait() */3120 char * cmd;/* text of command being run */3334 pid_t ps_pid; /* process id */ 3335 int ps_status; /* last process status from wait() */ 3336 char *ps_cmd; /* text of command being run */ 3121 3337 }; 3122 3338 … … 3143 3359 }; 3144 3360 3145 static pid_t backgndpid; /* pid of last background process */ 3146 static smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */ 3147 3148 static struct job *makejob(union node *, int); 3361 static struct job *makejob(/*union node *,*/ int); 3149 3362 static int forkshell(struct job *, union node *, int); 3150 3363 static int waitforjob(struct job *); 3151 3364 3152 3365 #if !JOBS 3153 enum { jobctl = 0 };3366 enum { doing_jobctl = 0 }; 3154 3367 #define setjobctl(on) do {} while (0) 3155 3368 #else 3156 static smallint jobctl; /* true if doing job control */3369 static smallint doing_jobctl; //references:8 3157 3370 static void setjobctl(int); 3158 3371 #endif 3372 3373 /* 3374 * Ignore a signal. 3375 */ 3376 static void 3377 ignoresig(int signo) 3378 { 3379 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */ 3380 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { 3381 /* No, need to do it */ 3382 signal(signo, SIG_IGN); 3383 } 3384 sigmode[signo - 1] = S_HARD_IGN; 3385 } 3386 3387 /* 3388 * Only one usage site - in setsignal() 3389 */ 3390 static void 3391 signal_handler(int signo) 3392 { 3393 gotsig[signo - 1] = 1; 3394 3395 if (signo == SIGINT && !trap[SIGINT]) { 3396 if (!suppress_int) { 3397 pending_sig = 0; 3398 raise_interrupt(); /* does not return */ 3399 } 3400 pending_int = 1; 3401 } else { 3402 pending_sig = signo; 3403 } 3404 } 3159 3405 3160 3406 /* … … 3165 3411 setsignal(int signo) 3166 3412 { 3167 int action;3168 char *t, tsig;3413 char *t; 3414 char cur_act, new_act; 3169 3415 struct sigaction act; 3170 3416 3171 3417 t = trap[signo]; 3172 if (t == NULL) 3173 action = S_DFL; 3174 else if (*t != '\0') 3175 action = S_CATCH; 3176 else 3177 action = S_IGN; 3178 if (rootshell && action == S_DFL) { 3418 new_act = S_DFL; 3419 if (t != NULL) { /* trap for this sig is set */ 3420 new_act = S_CATCH; 3421 if (t[0] == '\0') /* trap is "": ignore this sig */ 3422 new_act = S_IGN; 3423 } 3424 3425 if (rootshell && new_act == S_DFL) { 3179 3426 switch (signo) { 3180 3427 case SIGINT: 3181 3428 if (iflag || minusc || sflag == 0) 3182 action= S_CATCH;3429 new_act = S_CATCH; 3183 3430 break; 3184 3431 case SIGQUIT: … … 3187 3434 break; 3188 3435 #endif 3189 /* FALLTHROUGH */ 3436 /* man bash: 3437 * "In all cases, bash ignores SIGQUIT. Non-builtin 3438 * commands run by bash have signal handlers 3439 * set to the values inherited by the shell 3440 * from its parent". */ 3441 new_act = S_IGN; 3442 break; 3190 3443 case SIGTERM: 3191 3444 if (iflag) 3192 action= S_IGN;3445 new_act = S_IGN; 3193 3446 break; 3194 3447 #if JOBS … … 3196 3449 case SIGTTOU: 3197 3450 if (mflag) 3198 action= S_IGN;3451 new_act = S_IGN; 3199 3452 break; 3200 3453 #endif 3201 3454 } 3202 3455 } 3456 //TODO: if !rootshell, we reset SIGQUIT to DFL, 3457 //whereas we have to restore it to what shell got on entry 3458 //from the parent. See comment above 3203 3459 3204 3460 t = &sigmode[signo - 1]; 3205 tsig = *t; 3206 if (tsig == 0) { 3207 /* 3208 * current setting unknown 3209 */ 3210 if (sigaction(signo, 0, &act) == -1) { 3211 /* 3212 * Pretend it worked; maybe we should give a warning 3213 * here, but other shells don't. We don't alter 3214 * sigmode, so that we retry every time. 3215 */ 3461 cur_act = *t; 3462 if (cur_act == 0) { 3463 /* current setting is not yet known */ 3464 if (sigaction(signo, NULL, &act)) { 3465 /* pretend it worked; maybe we should give a warning, 3466 * but other shells don't. We don't alter sigmode, 3467 * so we retry every time. 3468 * btw, in Linux it never fails. --vda */ 3216 3469 return; 3217 3470 } 3218 3471 if (act.sa_handler == SIG_IGN) { 3472 cur_act = S_HARD_IGN; 3219 3473 if (mflag 3220 3474 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU) 3221 3475 ) { 3222 tsig = S_IGN; /* don't hard ignore these */ 3223 } else 3224 tsig = S_HARD_IGN; 3225 } else { 3226 tsig = S_RESET; /* force to be set */ 3227 } 3228 } 3229 if (tsig == S_HARD_IGN || tsig == action) 3476 cur_act = S_IGN; /* don't hard ignore these */ 3477 } 3478 } 3479 } 3480 if (cur_act == S_HARD_IGN || cur_act == new_act) 3230 3481 return; 3231 switch (action) { 3482 3483 act.sa_handler = SIG_DFL; 3484 switch (new_act) { 3232 3485 case S_CATCH: 3233 act.sa_handler = onsig; 3486 act.sa_handler = signal_handler; 3487 act.sa_flags = 0; /* matters only if !DFL and !IGN */ 3488 sigfillset(&act.sa_mask); /* ditto */ 3234 3489 break; 3235 3490 case S_IGN: 3236 3491 act.sa_handler = SIG_IGN; 3237 3492 break; 3238 default: 3239 act.sa_handler = SIG_DFL; 3240 } 3241 *t = action; 3242 act.sa_flags = 0; 3243 sigfillset(&act.sa_mask); 3244 sigaction(signo, &act, 0); 3493 } 3494 sigaction_set(signo, &act); 3495 3496 *t = new_act; 3245 3497 } 3246 3498 … … 3251 3503 3252 3504 /* mode flags for dowait */ 3253 #define DOWAIT_NO RMAL 03254 #define DOWAIT_BLOCK 13505 #define DOWAIT_NONBLOCK WNOHANG 3506 #define DOWAIT_BLOCK 0 3255 3507 3256 3508 #if JOBS 3257 3509 /* pgrp of shell on invocation */ 3258 static int initialpgrp; 3259 static int ttyfd = -1; 3510 static int initialpgrp; //references:2 3511 static int ttyfd = -1; //5 3260 3512 #endif 3261 3513 /* array of jobs */ 3262 static struct job *jobtab; 3514 static struct job *jobtab; //5 3263 3515 /* size of array */ 3264 static unsigned njobs; 3516 static unsigned njobs; //4 3265 3517 /* current job */ 3266 static struct job *curjob; 3518 static struct job *curjob; //lots 3267 3519 /* number of presumed living untracked jobs */ 3268 static int jobless; 3520 static int jobless; //4 3269 3521 3270 3522 static void … … 3327 3579 * Convert a job name to a job structure. 3328 3580 */ 3581 #if !JOBS 3582 #define getjob(name, getctl) getjob(name) 3583 #endif 3329 3584 static struct job * 3330 3585 getjob(const char *name, int getctl) … … 3332 3587 struct job *jp; 3333 3588 struct job *found; 3334 const char *err_msg = " No such job: %s";3589 const char *err_msg = "%s: no such job"; 3335 3590 unsigned num; 3336 3591 int c; … … 3383 3638 } 3384 3639 3385 found = 0; 3386 while (1) { 3387 if (!jp) 3388 goto err; 3389 if (match(jp->ps[0].cmd, p)) { 3640 found = NULL; 3641 while (jp) { 3642 if (match(jp->ps[0].ps_cmd, p)) { 3390 3643 if (found) 3391 3644 goto err; … … 3395 3648 jp = jp->prev_job; 3396 3649 } 3650 if (!found) 3651 goto err; 3652 jp = found; 3397 3653 3398 3654 gotit: … … 3418 3674 INT_OFF; 3419 3675 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) { 3420 if (ps-> cmd != nullstr)3421 free(ps-> cmd);3676 if (ps->ps_cmd != nullstr) 3677 free(ps->ps_cmd); 3422 3678 } 3423 3679 if (jp->ps != &jp->ps0) … … 3433 3689 { 3434 3690 if (tcsetpgrp(fd, pgrp)) 3435 ash_msg_and_raise_error("can not set tty process group (%m)");3691 ash_msg_and_raise_error("can't set tty process group (%m)"); 3436 3692 } 3437 3693 … … 3451 3707 int pgrp; 3452 3708 3453 if (on == jobctl || rootshell == 0)3709 if (on == doing_jobctl || rootshell == 0) 3454 3710 return; 3455 3711 if (on) { … … 3461 3717 * Obviously, a workaround for bugs when someone 3462 3718 * failed to provide a controlling tty to bash! :) */ 3463 fd += 3; 3464 while (!isatty(fd) && --fd >= 0) 3465 ; 3719 fd = 2; 3720 while (!isatty(fd)) 3721 if (--fd < 0) 3722 goto out; 3466 3723 } 3467 3724 fd = fcntl(fd, F_DUPFD, 10); 3468 close(ofd); 3725 if (ofd >= 0) 3726 close(ofd); 3469 3727 if (fd < 0) 3470 3728 goto out; 3471 fcntl(fd, F_SETFD, FD_CLOEXEC); 3729 /* fd is a tty at this point */ 3730 close_on_exec_on(fd); 3472 3731 do { /* while we are in the background */ 3473 3732 pgrp = tcgetpgrp(fd); … … 3495 3754 pgrp = initialpgrp; 3496 3755 /* was xtcsetpgrp, but this can make exiting ash 3497 * with pty already deleted loop forever*/3756 * loop forever if pty is already deleted */ 3498 3757 tcsetpgrp(fd, pgrp); 3499 3758 setpgid(0, pgrp); … … 3502 3761 setsignal(SIGTTIN); 3503 3762 close: 3504 close(fd); 3763 if (fd >= 0) 3764 close(fd); 3505 3765 fd = -1; 3506 3766 } 3507 3767 ttyfd = fd; 3508 jobctl = on;3509 } 3510 3511 static int 3768 doing_jobctl = on; 3769 } 3770 3771 static int FAST_FUNC 3512 3772 killcmd(int argc, char **argv) 3513 3773 { 3774 int i = 1; 3514 3775 if (argv[1] && strcmp(argv[1], "-l") != 0) { 3515 int i = 1;3516 3776 do { 3517 3777 if (argv[i][0] == '%') { 3518 3778 struct job *jp = getjob(argv[i], 0); 3519 unsigned pid = jp->ps[0].p id;3779 unsigned pid = jp->ps[0].ps_pid; 3520 3780 /* Enough space for ' -NNN<nul>' */ 3521 3781 argv[i] = alloca(sizeof(int)*3 + 3); … … 3531 3791 3532 3792 static void 3533 showpipe(struct job *jp , FILE *out)3534 { 3535 struct procstat * sp;3536 struct procstat * spend;3537 3538 spend = jp->ps + jp->nprocs;3539 for ( sp = jp->ps + 1; sp < spend; sp++)3540 fprintf(out, " | %s", sp->cmd);3541 outcslow('\n', out);3793 showpipe(struct job *jp /*, FILE *out*/) 3794 { 3795 struct procstat *ps; 3796 struct procstat *psend; 3797 3798 psend = jp->ps + jp->nprocs; 3799 for (ps = jp->ps + 1; ps < psend; ps++) 3800 printf(" | %s", ps->ps_cmd); 3801 outcslow('\n', stdout); 3542 3802 flush_stdout_stderr(); 3543 3803 } … … 3556 3816 goto out; 3557 3817 jp->state = JOBRUNNING; 3558 pgid = jp->ps ->pid;3818 pgid = jp->ps[0].ps_pid; 3559 3819 if (mode == FORK_FG) 3560 3820 xtcsetpgrp(ttyfd, pgid); … … 3563 3823 i = jp->nprocs; 3564 3824 do { 3565 if (WIFSTOPPED(ps-> status)) {3566 ps-> status = -1;3825 if (WIFSTOPPED(ps->ps_status)) { 3826 ps->ps_status = -1; 3567 3827 } 3568 3828 ps++; … … 3574 3834 } 3575 3835 3576 static int 3577 fg_bgcmd(int argc , char **argv)3836 static int FAST_FUNC 3837 fg_bgcmd(int argc UNUSED_PARAM, char **argv) 3578 3838 { 3579 3839 struct job *jp; 3580 FILE *out;3581 3840 int mode; 3582 3841 int retval; … … 3585 3844 nextopt(nullstr); 3586 3845 argv = argptr; 3587 out = stdout;3588 3846 do { 3589 3847 jp = getjob(*argv, 1); 3590 3848 if (mode == FORK_BG) { 3591 3849 set_curjob(jp, CUR_RUNNING); 3592 fprintf(out,"[%d] ", jobno(jp));3593 } 3594 out str(jp->ps->cmd, out);3595 showpipe(jp , out);3850 printf("[%d] ", jobno(jp)); 3851 } 3852 out1str(jp->ps[0].ps_cmd); 3853 showpipe(jp /*, stdout*/); 3596 3854 retval = restartjob(jp, mode); 3597 3855 } while (*argv && *++argv); … … 3638 3896 } 3639 3897 3640 /*3641 * Do a wait system call. If job control is compiled in, we accept3642 * stopped processes. If block is zero, we return a value of zero3643 * rather than blocking.3644 *3645 * System V doesn't have a non-blocking wait system call. It does3646 * have a SIGCLD signal that is sent to a process when one of it's3647 * children dies. The obvious way to use SIGCLD would be to install3648 * a handler for SIGCLD which simply bumped a counter when a SIGCLD3649 * was received, and have waitproc bump another counter when it got3650 * the status of a process. Waitproc would then know that a wait3651 * system call would not block if the two counters were different.3652 * This approach doesn't work because if a process has children that3653 * have not been waited for, System V will send it a SIGCLD when it3654 * installs a signal handler for SIGCLD. What this means is that when3655 * a child exits, the shell will be sent SIGCLD signals continuously3656 * until is runs out of stack space, unless it does a wait call before3657 * restoring the signal handler. The code below takes advantage of3658 * this (mis)feature by installing a signal handler for SIGCLD and3659 * then checking to see whether it was called. If there are any3660 * children to be waited for, it will be.3661 *3662 * If neither SYSV nor BSD is defined, we don't implement nonblocking3663 * waits at all. In this case, the user will not be informed when3664 * a background process until the next time she runs a real program3665 * (as opposed to running a builtin command or just typing return),3666 * and the jobs command may give out of date information.3667 */3668 3898 static int 3669 waitproc(int block, int *status) 3670 { 3671 int flags = 0; 3672 3673 #if JOBS 3674 if (jobctl) 3675 flags |= WUNTRACED; 3676 #endif 3677 if (block == 0) 3678 flags |= WNOHANG; 3679 return wait3(status, flags, (struct rusage *)NULL); 3680 } 3681 3682 /* 3683 * Wait for a process to terminate. 3684 */ 3685 static int 3686 dowait(int block, struct job *job) 3899 dowait(int wait_flags, struct job *job) 3687 3900 { 3688 3901 int pid; … … 3692 3905 int state; 3693 3906 3694 TRACE(("dowait(%d) called\n", block)); 3695 pid = waitproc(block, &status); 3696 TRACE(("wait returns pid %d, status=%d\n", pid, status)); 3907 TRACE(("dowait(0x%x) called\n", wait_flags)); 3908 3909 /* Do a wait system call. If job control is compiled in, we accept 3910 * stopped processes. wait_flags may have WNOHANG, preventing blocking. 3911 * NB: _not_ safe_waitpid, we need to detect EINTR */ 3912 if (doing_jobctl) 3913 wait_flags |= WUNTRACED; 3914 pid = waitpid(-1, &status, wait_flags); 3915 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", 3916 pid, status, errno, strerror(errno))); 3697 3917 if (pid <= 0) 3698 3918 return pid; 3919 3699 3920 INT_OFF; 3700 3921 thisjob = NULL; 3701 3922 for (jp = curjob; jp; jp = jp->prev_job) { 3702 struct procstat * sp;3703 struct procstat * spend;3923 struct procstat *ps; 3924 struct procstat *psend; 3704 3925 if (jp->state == JOBDONE) 3705 3926 continue; 3706 3927 state = JOBDONE; 3707 spend = jp->ps + jp->nprocs;3708 sp = jp->ps;3928 ps = jp->ps; 3929 psend = ps + jp->nprocs; 3709 3930 do { 3710 if ( sp->pid == pid) {3931 if (ps->ps_pid == pid) { 3711 3932 TRACE(("Job %d: changing status of proc %d " 3712 3933 "from 0x%x to 0x%x\n", 3713 jobno(jp), pid, sp->status, status));3714 sp->status = status;3934 jobno(jp), pid, ps->ps_status, status)); 3935 ps->ps_status = status; 3715 3936 thisjob = jp; 3716 3937 } 3717 if ( sp->status == -1)3938 if (ps->ps_status == -1) 3718 3939 state = JOBRUNNING; 3719 3940 #if JOBS 3720 3941 if (state == JOBRUNNING) 3721 3942 continue; 3722 if (WIFSTOPPED( sp->status)) {3723 jp->stopstatus = sp->status;3943 if (WIFSTOPPED(ps->ps_status)) { 3944 jp->stopstatus = ps->ps_status; 3724 3945 state = JOBSTOPPED; 3725 3946 } 3726 3947 #endif 3727 } while (++ sp < spend);3948 } while (++ps < psend); 3728 3949 if (thisjob) 3729 3950 goto gotjob; … … 3732 3953 if (!WIFSTOPPED(status)) 3733 3954 #endif 3734 3735 3955 jobless--; 3736 3956 goto out; … … 3762 3982 if (len) { 3763 3983 s[len] = '\n'; 3764 s[len + 1] = 0;3984 s[len + 1] = '\0'; 3765 3985 out2str(s); 3766 3986 } 3767 3987 } 3988 return pid; 3989 } 3990 3991 static int 3992 blocking_wait_with_raise_on_sig(void) 3993 { 3994 pid_t pid = dowait(DOWAIT_BLOCK, NULL); 3995 if (pid <= 0 && pending_sig) 3996 raise_exception(EXSIG); 3768 3997 return pid; 3769 3998 } … … 3781 4010 ps = jp->ps; 3782 4011 3783 if (mode & SHOW_ PGID) {4012 if (mode & SHOW_ONLY_PGID) { /* jobs -p */ 3784 4013 /* just output process (group) id of pipeline */ 3785 fprintf(out, "%d\n", ps->p id);4014 fprintf(out, "%d\n", ps->ps_pid); 3786 4015 return; 3787 4016 } … … 3791 4020 3792 4021 if (jp == curjob) 3793 s[col - 2] = '+';4022 s[col - 3] = '+'; 3794 4023 else if (curjob && jp == curjob->prev_job) 3795 s[col - 2] = '-';3796 3797 if (mode & SHOW_PID )3798 col += fmtstr(s + col, 16, "%d ", ps->p id);4024 s[col - 3] = '-'; 4025 4026 if (mode & SHOW_PIDS) 4027 col += fmtstr(s + col, 16, "%d ", ps->ps_pid); 3799 4028 3800 4029 psend = ps + jp->nprocs; … … 3804 4033 col += sizeof("Running") - 1; 3805 4034 } else { 3806 int status = psend[-1]. status;4035 int status = psend[-1].ps_status; 3807 4036 if (jp->state == JOBSTOPPED) 3808 4037 status = jp->stopstatus; 3809 4038 col += sprint_status(s + col, status, 0); 3810 4039 } 3811 4040 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */ 4041 4042 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line 4043 * or prints several "PID | <cmdN>" lines, 4044 * depending on SHOW_PIDS bit. 4045 * We do not print status of individual processes 4046 * between PID and <cmdN>. bash does it, but not very well: 4047 * first line shows overall job status, not process status, 4048 * making it impossible to know 1st process status. 4049 */ 3812 4050 goto start; 3813 3814 4051 do { 3815 4052 /* for each process */ 3816 col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3; 4053 s[0] = '\0'; 4054 col = 33; 4055 if (mode & SHOW_PIDS) 4056 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1; 3817 4057 start: 3818 fprintf(out, "%s%*c%s", 3819 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd 4058 fprintf(out, "%s%*c%s%s", 4059 s, 4060 33 - col >= 0 ? 33 - col : 0, ' ', 4061 ps == jp->ps ? "" : "| ", 4062 ps->ps_cmd 3820 4063 ); 3821 if (!(mode & SHOW_PID)) { 3822 showpipe(jp, out); 3823 break; 3824 } 3825 if (++ps == psend) { 3826 outcslow('\n', out); 3827 break; 3828 } 3829 } while (1); 4064 } while (++ps != psend); 4065 outcslow('\n', out); 3830 4066 3831 4067 jp->changed = 0; … … 3846 4082 struct job *jp; 3847 4083 3848 TRACE(("showjobs( %x) called\n", mode));3849 3850 /* If not even one one job changed, there is nothing to do*/3851 while (dowait(DOWAIT_NO RMAL, NULL) > 0)4084 TRACE(("showjobs(0x%x) called\n", mode)); 4085 4086 /* Handle all finished jobs */ 4087 while (dowait(DOWAIT_NONBLOCK, NULL) > 0) 3852 4088 continue; 3853 4089 … … 3859 4095 } 3860 4096 3861 static int 3862 jobscmd(int argc , char **argv)4097 static int FAST_FUNC 4098 jobscmd(int argc UNUSED_PARAM, char **argv) 3863 4099 { 3864 4100 int mode, m; 3865 4101 3866 4102 mode = 0; 3867 while ((m = nextopt("lp")) ) {4103 while ((m = nextopt("lp")) != '\0') { 3868 4104 if (m == 'l') 3869 mode = SHOW_PID;4105 mode |= SHOW_PIDS; 3870 4106 else 3871 mode = SHOW_PGID;4107 mode |= SHOW_ONLY_PGID; 3872 4108 } 3873 4109 … … 3875 4111 if (*argv) { 3876 4112 do 3877 showjob(stdout, getjob(*argv, 0), mode);4113 showjob(stdout, getjob(*argv, 0), mode); 3878 4114 while (*++argv); 3879 } else 4115 } else { 3880 4116 showjobs(stdout, mode); 4117 } 3881 4118 3882 4119 return 0; … … 3884 4121 #endif /* JOBS */ 3885 4122 4123 /* Called only on finished or stopped jobs (no members are running) */ 3886 4124 static int 3887 4125 getstatus(struct job *job) … … 3889 4127 int status; 3890 4128 int retval; 3891 3892 status = job->ps[job->nprocs - 1].status; 4129 struct procstat *ps; 4130 4131 /* Fetch last member's status */ 4132 ps = job->ps + job->nprocs - 1; 4133 status = ps->ps_status; 4134 if (pipefail) { 4135 /* "set -o pipefail" mode: use last _nonzero_ status */ 4136 while (status == 0 && --ps >= job->ps) 4137 status = ps->ps_status; 4138 } 4139 3893 4140 retval = WEXITSTATUS(status); 3894 4141 if (!WIFEXITED(status)) { … … 3907 4154 retval += 128; 3908 4155 } 3909 TRACE(("getstatus: job %d, nproc %d, status %x, retval%x\n",4156 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n", 3910 4157 jobno(job), job->nprocs, status, retval)); 3911 4158 return retval; 3912 4159 } 3913 4160 3914 static int 3915 waitcmd(int argc , char **argv)4161 static int FAST_FUNC 4162 waitcmd(int argc UNUSED_PARAM, char **argv) 3916 4163 { 3917 4164 struct job *job; … … 3919 4166 struct job *jp; 3920 4167 3921 EXSIGON; 4168 if (pending_sig) 4169 raise_exception(EXSIG); 3922 4170 3923 4171 nextopt(nullstr); … … 3930 4178 jp = curjob; 3931 4179 while (1) { 3932 if (!jp) { 3933 /* no running procs */ 3934 goto out; 3935 } 4180 if (!jp) /* no running procs */ 4181 goto ret; 3936 4182 if (jp->state == JOBRUNNING) 3937 4183 break; … … 3939 4185 jp = jp->prev_job; 3940 4186 } 3941 dowait(DOWAIT_BLOCK, 0); 4187 blocking_wait_with_raise_on_sig(); 4188 /* man bash: 4189 * "When bash is waiting for an asynchronous command via 4190 * the wait builtin, the reception of a signal for which a trap 4191 * has been set will cause the wait builtin to return immediately 4192 * with an exit status greater than 128, immediately after which 4193 * the trap is executed." 4194 * 4195 * blocking_wait_with_raise_on_sig raises signal handlers 4196 * if it gets no pid (pid < 0). However, 4197 * if child sends us a signal *and immediately exits*, 4198 * blocking_wait_with_raise_on_sig gets pid > 0 4199 * and does not handle pending_sig. Check this case: */ 4200 if (pending_sig) 4201 raise_exception(EXSIG); 3942 4202 } 3943 4203 } … … 3948 4208 pid_t pid = number(*argv); 3949 4209 job = curjob; 3950 goto start; 3951 do { 3952 if (job->ps[job->nprocs - 1].pid == pid) 4210 while (1) { 4211 if (!job) 4212 goto repeat; 4213 if (job->ps[job->nprocs - 1].ps_pid == pid) 3953 4214 break; 3954 4215 job = job->prev_job; 3955 start: 3956 if (!job) 3957 goto repeat; 3958 } while (1); 4216 } 3959 4217 } else 3960 4218 job = getjob(*argv, 0); 3961 4219 /* loop until process terminated or stopped */ 3962 4220 while (job->state == JOBRUNNING) 3963 dowait(DOWAIT_BLOCK, 0);4221 blocking_wait_with_raise_on_sig(); 3964 4222 job->waited = 1; 3965 4223 retval = getstatus(job); 3966 repeat: 3967 ; 4224 repeat: ; 3968 4225 } while (*++argv); 3969 4226 3970 out:4227 ret: 3971 4228 return retval; 3972 4229 } … … 4020 4277 */ 4021 4278 static struct job * 4022 makejob( union node *node,int nprocs)4279 makejob(/*union node *node,*/ int nprocs) 4023 4280 { 4024 4281 int i; … … 4035 4292 continue; 4036 4293 #if JOBS 4037 if ( jobctl)4294 if (doing_jobctl) 4038 4295 continue; 4039 4296 #endif … … 4045 4302 /* jp->jobctl is a bitfield. 4046 4303 * "jp->jobctl |= jobctl" likely to give awful code */ 4047 if ( jobctl)4304 if (doing_jobctl) 4048 4305 jp->jobctl = 1; 4049 4306 #endif … … 4055 4312 jp->ps = ckmalloc(nprocs * sizeof(struct procstat)); 4056 4313 } 4057 TRACE(("makejob( 0x%lx, %d) returns %%%d\n", (long)node, nprocs,4314 TRACE(("makejob(%d) returns %%%d\n", nprocs, 4058 4315 jobno(jp))); 4059 4316 return jp; … … 4070 4327 cmdputs(const char *s) 4071 4328 { 4072 const char *p, *str; 4073 char c, cc[2] = " "; 4074 char *nextc; 4075 int subtype = 0; 4076 int quoted = 0; 4077 static const char vstype[VSTYPE + 1][4] = { 4329 static const char vstype[VSTYPE + 1][3] = { 4078 4330 "", "}", "-", "+", "?", "=", 4079 4331 "%", "%%", "#", "##" 4332 IF_ASH_BASH_COMPAT(, ":", "/", "//") 4080 4333 }; 4081 4334 4335 const char *p, *str; 4336 char cc[2]; 4337 char *nextc; 4338 unsigned char c; 4339 unsigned char subtype = 0; 4340 int quoted = 0; 4341 4342 cc[1] = '\0'; 4082 4343 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc); 4083 4344 p = s; 4084 while ((c = *p++) != 0) {4085 str = 0;4345 while ((c = *p++) != '\0') { 4346 str = NULL; 4086 4347 switch (c) { 4087 4348 case CTLESC: … … 4110 4371 str = "\"$(...)\""; 4111 4372 goto dostr; 4112 #if ENABLE_ ASH_MATH_SUPPORT4373 #if ENABLE_SH_MATH_SUPPORT 4113 4374 case CTLARI: 4114 4375 str = "$(("; … … 4150 4411 continue; 4151 4412 dostr: 4152 while ((c = *str++) ) {4413 while ((c = *str++) != '\0') { 4153 4414 USTPUTC(c, nextc); 4154 4415 } 4155 } 4416 } /* while *p++ not NUL */ 4417 4156 4418 if (quoted & 1) { 4157 4419 USTPUTC('"', nextc); … … 4182 4444 struct nodelist *lp; 4183 4445 const char *p; 4184 char s[2];4185 4446 4186 4447 if (!n) … … 4228 4489 cmdtxt(n->nif.test); 4229 4490 cmdputs("; then "); 4230 n = n->nif.ifpart;4231 4491 if (n->nif.elsepart) { 4232 cmdtxt(n );4492 cmdtxt(n->nif.ifpart); 4233 4493 cmdputs("; else "); 4234 4494 n = n->nif.elsepart; 4495 } else { 4496 n = n->nif.ifpart; 4235 4497 } 4236 4498 p = "; fi"; … … 4302 4564 p = ">>"; 4303 4565 goto redir; 4566 #if ENABLE_ASH_BASH_COMPAT 4567 case NTO2: 4568 #endif 4304 4569 case NTOFD: 4305 4570 p = ">&"; … … 4314 4579 p = "<>"; 4315 4580 redir: 4316 s[0] = n->nfile.fd + '0'; 4317 s[1] = '\0'; 4318 cmdputs(s); 4581 cmdputs(utoa(n->nfile.fd)); 4319 4582 cmdputs(p); 4320 4583 if (n->type == NTOFD || n->type == NFROMFD) { 4321 s[0] = n->ndup.dupfd + '0'; 4322 p = s; 4323 goto dotail2; 4584 cmdputs(utoa(n->ndup.dupfd)); 4585 break; 4324 4586 } 4325 4587 n = n->nfile.fname; … … 4367 4629 4368 4630 for (tp = trap; tp < &trap[NSIG]; tp++) { 4369 if (*tp && **tp) { /* trap not NULL or SIG_IGN*/4631 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */ 4370 4632 INT_OFF; 4371 free(*tp); 4633 if (trap_ptr == trap) 4634 free(*tp); 4635 /* else: it "belongs" to trap_ptr vector, don't free */ 4372 4636 *tp = NULL; 4373 if ( tp != &trap[0])4637 if ((tp - trap) != 0) 4374 4638 setsignal(tp - trap); 4375 4639 INT_ON; 4376 4640 } 4377 4641 } 4642 may_have_traps = 0; 4378 4643 } 4379 4644 … … 4382 4647 4383 4648 /* Called after fork(), in child */ 4384 static void4649 static NOINLINE void 4385 4650 forkchild(struct job *jp, union node *n, int mode) 4386 4651 { … … 4391 4656 shlvl++; 4392 4657 4658 /* man bash: "Non-builtin commands run by bash have signal handlers 4659 * set to the values inherited by the shell from its parent". 4660 * Do we do it correctly? */ 4661 4393 4662 closescript(); 4663 4664 if (mode == FORK_NOJOB /* is it `xxx` ? */ 4665 && n && n->type == NCMD /* is it single cmd? */ 4666 /* && n->ncmd.args->type == NARG - always true? */ 4667 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0 4668 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */ 4669 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */ 4670 ) { 4671 TRACE(("Trap hack\n")); 4672 /* Awful hack for `trap` or $(trap). 4673 * 4674 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html 4675 * contains an example where "trap" is executed in a subshell: 4676 * 4677 * save_traps=$(trap) 4678 * ... 4679 * eval "$save_traps" 4680 * 4681 * Standard does not say that "trap" in subshell shall print 4682 * parent shell's traps. It only says that its output 4683 * must have suitable form, but then, in the above example 4684 * (which is not supposed to be normative), it implies that. 4685 * 4686 * bash (and probably other shell) does implement it 4687 * (traps are reset to defaults, but "trap" still shows them), 4688 * but as a result, "trap" logic is hopelessly messed up: 4689 * 4690 * # trap 4691 * trap -- 'echo Ho' SIGWINCH <--- we have a handler 4692 * # (trap) <--- trap is in subshell - no output (correct, traps are reset) 4693 * # true | trap <--- trap is in subshell - no output (ditto) 4694 * # echo `true | trap` <--- in subshell - output (but traps are reset!) 4695 * trap -- 'echo Ho' SIGWINCH 4696 * # echo `(trap)` <--- in subshell in subshell - output 4697 * trap -- 'echo Ho' SIGWINCH 4698 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output! 4699 * trap -- 'echo Ho' SIGWINCH 4700 * 4701 * The rules when to forget and when to not forget traps 4702 * get really complex and nonsensical. 4703 * 4704 * Our solution: ONLY bare $(trap) or `trap` is special. 4705 */ 4706 /* Save trap handler strings for trap builtin to print */ 4707 trap_ptr = memcpy(xmalloc(sizeof(trap)), trap, sizeof(trap)); 4708 /* Fall through into clearing traps */ 4709 } 4394 4710 clear_traps(); 4395 4711 #if JOBS 4396 4712 /* do job control only in root shell */ 4397 jobctl = 0;4713 doing_jobctl = 0; 4398 4714 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) { 4399 4715 pid_t pgrp; … … 4402 4718 pgrp = getpid(); 4403 4719 else 4404 pgrp = jp->ps[0].p id;4405 /* This can fail because we are doing it in the parent also */4406 (void)setpgid(0, pgrp);4720 pgrp = jp->ps[0].ps_pid; 4721 /* this can fail because we are doing it in the parent also */ 4722 setpgid(0, pgrp); 4407 4723 if (mode == FORK_FG) 4408 4724 xtcsetpgrp(ttyfd, pgrp); … … 4412 4728 #endif 4413 4729 if (mode == FORK_BG) { 4730 /* man bash: "When job control is not in effect, 4731 * asynchronous commands ignore SIGINT and SIGQUIT" */ 4414 4732 ignoresig(SIGINT); 4415 4733 ignoresig(SIGQUIT); … … 4417 4735 close(0); 4418 4736 if (open(bb_dev_null, O_RDONLY) != 0) 4419 ash_msg_and_raise_error("can't open %s", bb_dev_null); 4420 } 4421 } 4422 if (!oldlvl && iflag) { 4423 setsignal(SIGINT); 4737 ash_msg_and_raise_error("can't open '%s'", bb_dev_null); 4738 } 4739 } 4740 if (!oldlvl) { 4741 if (iflag) { /* why if iflag only? */ 4742 setsignal(SIGINT); 4743 setsignal(SIGTERM); 4744 } 4745 /* man bash: 4746 * "In all cases, bash ignores SIGQUIT. Non-builtin 4747 * commands run by bash have signal handlers 4748 * set to the values inherited by the shell 4749 * from its parent". 4750 * Take care of the second rule: */ 4424 4751 setsignal(SIGQUIT); 4425 setsignal(SIGTERM); 4426 } 4752 } 4753 #if JOBS 4754 if (n && n->type == NCMD 4755 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0 4756 ) { 4757 TRACE(("Job hack\n")); 4758 /* "jobs": we do not want to clear job list for it, 4759 * instead we remove only _its_ own_ job from job list. 4760 * This makes "jobs .... | cat" more useful. 4761 */ 4762 freejob(curjob); 4763 return; 4764 } 4765 #endif 4427 4766 for (jp = curjob; jp; jp = jp->prev_job) 4428 4767 freejob(jp); … … 4431 4770 4432 4771 /* Called after fork(), in parent */ 4772 #if !JOBS 4773 #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid) 4774 #endif 4433 4775 static void 4434 4776 forkparent(struct job *jp, union node *n, int mode, pid_t pid) … … 4436 4778 TRACE(("In parent shell: child = %d\n", pid)); 4437 4779 if (!jp) { 4438 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0); 4780 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) 4781 continue; 4439 4782 jobless++; 4440 4783 return; … … 4447 4790 pgrp = pid; 4448 4791 else 4449 pgrp = jp->ps[0].p id;4792 pgrp = jp->ps[0].ps_pid; 4450 4793 /* This can fail because we are doing it in the child also */ 4451 4794 setpgid(pid, pgrp); … … 4458 4801 if (jp) { 4459 4802 struct procstat *ps = &jp->ps[jp->nprocs++]; 4460 ps->p id = pid;4461 ps-> status = -1;4462 ps-> cmd = nullstr;4803 ps->ps_pid = pid; 4804 ps->ps_status = -1; 4805 ps->ps_cmd = nullstr; 4463 4806 #if JOBS 4464 if ( jobctl && n)4465 ps-> cmd = commandtext(n);4807 if (doing_jobctl && n) 4808 ps->ps_cmd = commandtext(n); 4466 4809 #endif 4467 4810 } … … 4479 4822 if (jp) 4480 4823 freejob(jp); 4481 ash_msg_and_raise_error("cannot fork"); 4482 } 4483 if (pid == 0) 4824 ash_msg_and_raise_error("can't fork"); 4825 } 4826 if (pid == 0) { 4827 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */ 4484 4828 forkchild(jp, n, mode); 4485 else4829 } else { 4486 4830 forkparent(jp, n, mode, pid); 4831 } 4487 4832 return pid; 4488 4833 } … … 4491 4836 * Wait for job to finish. 4492 4837 * 4493 * Under job control we have the problem that while a child process is4494 * running interrupts generated by the user are sent to the child but not4495 * to the shell. This means that an infinite loop started by an inter-4496 * a ctive user may be hard to kill. With job control turned off, an4497 * interactive user may place an interactive program inside a loop. If4498 * the interactive program catches interrupts, the user doesn't want4838 * Under job control we have the problem that while a child process 4839 * is running interrupts generated by the user are sent to the child 4840 * but not to the shell. This means that an infinite loop started by 4841 * an interactive user may be hard to kill. With job control turned off, 4842 * an interactive user may place an interactive program inside a loop. 4843 * If the interactive program catches interrupts, the user doesn't want 4499 4844 * these interrupts to also abort the loop. The approach we take here 4500 4845 * is to have the shell ignore interrupt signals while waiting for a … … 4514 4859 4515 4860 TRACE(("waitforjob(%%%d) called\n", jobno(jp))); 4861 4862 INT_OFF; 4516 4863 while (jp->state == JOBRUNNING) { 4864 /* In non-interactive shells, we _can_ get 4865 * a keyboard signal here and be EINTRed, 4866 * but we just loop back, waiting for command to complete. 4867 * 4868 * man bash: 4869 * "If bash is waiting for a command to complete and receives 4870 * a signal for which a trap has been set, the trap 4871 * will not be executed until the command completes." 4872 * 4873 * Reality is that even if trap is not set, bash 4874 * will not act on the signal until command completes. 4875 * Try this. sleep5intoff.c: 4876 * #include <signal.h> 4877 * #include <unistd.h> 4878 * int main() { 4879 * sigset_t set; 4880 * sigemptyset(&set); 4881 * sigaddset(&set, SIGINT); 4882 * sigaddset(&set, SIGQUIT); 4883 * sigprocmask(SIG_BLOCK, &set, NULL); 4884 * sleep(5); 4885 * return 0; 4886 * } 4887 * $ bash -c './sleep5intoff; echo hi' 4888 * ^C^C^C^C <--- pressing ^C once a second 4889 * $ _ 4890 * $ bash -c './sleep5intoff; echo hi' 4891 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT) 4892 * $ _ 4893 */ 4517 4894 dowait(DOWAIT_BLOCK, jp); 4518 4895 } 4896 INT_ON; 4897 4519 4898 st = getstatus(jp); 4520 4899 #if JOBS … … 4529 4908 * occurred, and if so interrupt ourselves. Yuck. - mycroft 4530 4909 */ 4531 if (jp->sigint) 4532 raise(SIGINT); 4910 if (jp->sigint) /* TODO: do the same with all signals */ 4911 raise(SIGINT); /* ... by raise(jp->sig) instead? */ 4533 4912 } 4534 4913 if (jp->state == JOBDONE) … … 4567 4946 4568 4947 #define EMPTY -2 /* marks an unused slot in redirtab */ 4569 #ifndef PIPE_BUF 4570 # define PIPESIZE 4096 /* amount of buffering in a pipe */ 4571 #else 4572 # define PIPESIZE PIPE_BUF 4573 #endif 4948 #define CLOSED -3 /* marks a slot of previously-closed fd */ 4574 4949 4575 4950 /* … … 4621 4996 * replaced, return the file descriptor. 4622 4997 */ 4623 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) 4624 && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino) 4998 if (fstat(fd, &finfo2) == 0 4999 && !S_ISREG(finfo2.st_mode) 5000 && finfo.st_dev == finfo2.st_dev 5001 && finfo.st_ino == finfo2.st_ino 5002 ) { 4625 5003 return fd; 5004 } 4626 5005 4627 5006 /* The file has been replaced. badness. */ … … 4648 5027 if (redir->type == NHERE) { 4649 5028 len = strlen(redir->nhere.doc->narg.text); 4650 if (len <= PIPE SIZE) {5029 if (len <= PIPE_BUF) { 4651 5030 full_write(pip[1], redir->nhere.doc->narg.text, len); 4652 5031 goto out; … … 4654 5033 } 4655 5034 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { 5035 /* child */ 4656 5036 close(pip[0]); 4657 signal(SIGINT, SIG_IGN); 4658 signal(SIGQUIT, SIG_IGN); 4659 signal(SIGHUP, SIG_IGN); 4660 #ifdef SIGTSTP 4661 signal(SIGTSTP, SIG_IGN); 4662 #endif 5037 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN); 5038 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN); 5039 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN); 5040 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN); 4663 5041 signal(SIGPIPE, SIG_DFL); 4664 5042 if (redir->type == NHERE) 4665 5043 full_write(pip[1], redir->nhere.doc->narg.text, len); 4666 else 5044 else /* NXHERE */ 4667 5045 expandhere(redir->nhere.doc, pip[1]); 4668 _exit( 0);5046 _exit(EXIT_SUCCESS); 4669 5047 } 4670 5048 out: … … 4688 5066 case NFROMTO: 4689 5067 fname = redir->nfile.expfname; 4690 f = open(fname, O_RDWR|O_CREAT |O_TRUNC, 0666);5068 f = open(fname, O_RDWR|O_CREAT, 0666); 4691 5069 if (f < 0) 4692 5070 goto ecreate; 4693 5071 break; 4694 5072 case NTO: 5073 #if ENABLE_ASH_BASH_COMPAT 5074 case NTO2: 5075 #endif 4695 5076 /* Take care of noclobber mode. */ 4696 5077 if (Cflag) { … … 4719 5100 #endif 4720 5101 /* Fall through to eliminate warning. */ 4721 case NTOFD: 4722 case NFROMFD: 4723 f = -1; 4724 break; 5102 /* Our single caller does this itself */ 5103 // case NTOFD: 5104 // case NFROMFD: 5105 // f = -1; 5106 // break; 4725 5107 case NHERE: 4726 5108 case NXHERE: … … 4731 5113 return f; 4732 5114 ecreate: 4733 ash_msg_and_raise_error("can not create %s: %s", fname, errmsg(errno, "nonexistent directory"));5115 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory")); 4734 5116 eopen: 4735 ash_msg_and_raise_error("can not open %s: %s", fname, errmsg(errno, "no such file"));5117 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file")); 4736 5118 } 4737 5119 … … 4741 5123 * file descriptors left. 4742 5124 */ 5125 /* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD). 5126 * old code was doing close(to) prior to copyfd() to achieve the same */ 5127 enum { 5128 COPYFD_EXACT = (int)~(INT_MAX), 5129 COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1), 5130 }; 4743 5131 static int 4744 5132 copyfd(int from, int to) … … 4746 5134 int newfd; 4747 5135 4748 newfd = fcntl(from, F_DUPFD, to); 5136 if (to & COPYFD_EXACT) { 5137 to &= ~COPYFD_EXACT; 5138 /*if (from != to)*/ 5139 newfd = dup2(from, to); 5140 } else { 5141 newfd = fcntl(from, F_DUPFD, to); 5142 } 4749 5143 if (newfd < 0) { 4750 5144 if (errno == EMFILE) 4751 5145 return EMPTY; 5146 /* Happens when source fd is not open: try "echo >&99" */ 4752 5147 ash_msg_and_raise_error("%d: %m", from); 4753 5148 } … … 4755 5150 } 4756 5151 4757 static void 4758 dupredirect(union node *redir, int f) 4759 { 4760 int fd = redir->nfile.fd; 4761 4762 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) { 4763 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ 4764 copyfd(redir->ndup.dupfd, fd); 4765 } 4766 return; 4767 } 4768 4769 if (f != fd) { 4770 copyfd(f, fd); 4771 close(f); 4772 } 5152 /* Struct def and variable are moved down to the first usage site */ 5153 struct two_fd_t { 5154 int orig, copy; 5155 }; 5156 struct redirtab { 5157 struct redirtab *next; 5158 int nullredirs; 5159 int pair_count; 5160 struct two_fd_t two_fd[]; 5161 }; 5162 #define redirlist (G_var.redirlist) 5163 5164 static int need_to_remember(struct redirtab *rp, int fd) 5165 { 5166 int i; 5167 5168 if (!rp) /* remembering was not requested */ 5169 return 0; 5170 5171 for (i = 0; i < rp->pair_count; i++) { 5172 if (rp->two_fd[i].orig == fd) { 5173 /* already remembered */ 5174 return 0; 5175 } 5176 } 5177 return 1; 5178 } 5179 5180 /* "hidden" fd is a fd used to read scripts, or a copy of such */ 5181 static int is_hidden_fd(struct redirtab *rp, int fd) 5182 { 5183 int i; 5184 struct parsefile *pf; 5185 5186 if (fd == -1) 5187 return 0; 5188 /* Check open scripts' fds */ 5189 pf = g_parsefile; 5190 while (pf) { 5191 /* We skip pf_fd == 0 case because of the following case: 5192 * $ ash # running ash interactively 5193 * $ . ./script.sh 5194 * and in script.sh: "exec 9>&0". 5195 * Even though top-level pf_fd _is_ 0, 5196 * it's still ok to use it: "read" builtin uses it, 5197 * why should we cripple "exec" builtin? 5198 */ 5199 if (pf->pf_fd > 0 && fd == pf->pf_fd) { 5200 return 1; 5201 } 5202 pf = pf->prev; 5203 } 5204 5205 if (!rp) 5206 return 0; 5207 /* Check saved fds of redirects */ 5208 fd |= COPYFD_RESTORE; 5209 for (i = 0; i < rp->pair_count; i++) { 5210 if (rp->two_fd[i].copy == fd) { 5211 return 1; 5212 } 5213 } 5214 return 0; 4773 5215 } 4774 5216 … … 4776 5218 * Process a list of redirection commands. If the REDIR_PUSH flag is set, 4777 5219 * old file descriptors are stashed away so that the redirection can be 4778 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the 4779 * standard output, and the standard error if it becomes a duplicate of 4780 * stdout, is saved in memory. 5220 * undone by calling popredir. 4781 5221 */ 4782 5222 /* flags passed to redirect */ … … 4786 5226 redirect(union node *redir, int flags) 4787 5227 { 4788 union node *n;4789 5228 struct redirtab *sv; 5229 int sv_pos; 4790 5230 int i; 4791 5231 int fd; 4792 5232 int newfd; 4793 int *p; 4794 nullredirs++; 5233 int copied_fd2 = -1; 5234 5235 g_nullredirs++; 4795 5236 if (!redir) { 4796 5237 return; 4797 5238 } 5239 4798 5240 sv = NULL; 5241 sv_pos = 0; 4799 5242 INT_OFF; 4800 5243 if (flags & REDIR_PUSH) { 4801 struct redirtab *q; 4802 q = ckmalloc(sizeof(struct redirtab)); 4803 q->next = redirlist; 4804 redirlist = q; 4805 q->nullredirs = nullredirs - 1; 4806 for (i = 0; i < 10; i++) 4807 q->renamed[i] = EMPTY; 4808 nullredirs = 0; 4809 sv = q; 4810 } 4811 n = redir; 5244 union node *tmp = redir; 5245 do { 5246 sv_pos++; 5247 #if ENABLE_ASH_BASH_COMPAT 5248 if (tmp->nfile.type == NTO2) 5249 sv_pos++; 5250 #endif 5251 tmp = tmp->nfile.next; 5252 } while (tmp); 5253 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0])); 5254 sv->next = redirlist; 5255 sv->pair_count = sv_pos; 5256 redirlist = sv; 5257 sv->nullredirs = g_nullredirs - 1; 5258 g_nullredirs = 0; 5259 while (sv_pos > 0) { 5260 sv_pos--; 5261 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY; 5262 } 5263 } 5264 4812 5265 do { 4813 fd = n->nfile.fd; 4814 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) 4815 && n->ndup.dupfd == fd) 4816 continue; /* redirect from/to same file descriptor */ 4817 4818 newfd = openredirect(n); 4819 if (fd == newfd) 4820 continue; 4821 if (sv && *(p = &sv->renamed[fd]) == EMPTY) { 4822 i = fcntl(fd, F_DUPFD, 10); 4823 5266 int right_fd = -1; 5267 fd = redir->nfile.fd; 5268 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) { 5269 right_fd = redir->ndup.dupfd; 5270 //bb_error_msg("doing %d > %d", fd, right_fd); 5271 /* redirect from/to same file descriptor? */ 5272 if (right_fd == fd) 5273 continue; 5274 /* "echo >&10" and 10 is a fd opened to a sh script? */ 5275 if (is_hidden_fd(sv, right_fd)) { 5276 errno = EBADF; /* as if it is closed */ 5277 ash_msg_and_raise_error("%d: %m", right_fd); 5278 } 5279 newfd = -1; 5280 } else { 5281 newfd = openredirect(redir); /* always >= 0 */ 5282 if (fd == newfd) { 5283 /* Descriptor wasn't open before redirect. 5284 * Mark it for close in the future */ 5285 if (need_to_remember(sv, fd)) { 5286 goto remember_to_close; 5287 } 5288 continue; 5289 } 5290 } 5291 #if ENABLE_ASH_BASH_COMPAT 5292 redirect_more: 5293 #endif 5294 if (need_to_remember(sv, fd)) { 5295 /* Copy old descriptor */ 5296 /* Careful to not accidentally "save" 5297 * to the same fd as right side fd in N>&M */ 5298 int minfd = right_fd < 10 ? 10 : right_fd + 1; 5299 i = fcntl(fd, F_DUPFD, minfd); 5300 /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds 5301 * are closed in popredir() in the child, preventing them from leaking 5302 * into child. (popredir() also cleans up the mess in case of failures) 5303 */ 4824 5304 if (i == -1) { 4825 5305 i = errno; 4826 5306 if (i != EBADF) { 4827 close(newfd); 5307 /* Strange error (e.g. "too many files" EMFILE?) */ 5308 if (newfd >= 0) 5309 close(newfd); 4828 5310 errno = i; 4829 5311 ash_msg_and_raise_error("%d: %m", fd); 4830 5312 /* NOTREACHED */ 4831 5313 } 5314 /* EBADF: it is not open - good, remember to close it */ 5315 remember_to_close: 5316 i = CLOSED; 5317 } else { /* fd is open, save its copy */ 5318 /* "exec fd>&-" should not close fds 5319 * which point to script file(s). 5320 * Force them to be restored afterwards */ 5321 if (is_hidden_fd(sv, fd)) 5322 i |= COPYFD_RESTORE; 5323 } 5324 if (fd == 2) 5325 copied_fd2 = i; 5326 sv->two_fd[sv_pos].orig = fd; 5327 sv->two_fd[sv_pos].copy = i; 5328 sv_pos++; 5329 } 5330 if (newfd < 0) { 5331 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */ 5332 if (redir->ndup.dupfd < 0) { /* "fd>&-" */ 5333 /* Don't want to trigger debugging */ 5334 if (fd != -1) 5335 close(fd); 4832 5336 } else { 4833 *p = i; 4834 close(fd); 5337 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT); 4835 5338 } 4836 } else { 4837 close(fd); 4838 } 4839 dupredirect(n, newfd); 4840 } while ((n = n->nfile.next)); 5339 } else if (fd != newfd) { /* move newfd to fd */ 5340 copyfd(newfd, fd | COPYFD_EXACT); 5341 #if ENABLE_ASH_BASH_COMPAT 5342 if (!(redir->nfile.type == NTO2 && fd == 2)) 5343 #endif 5344 close(newfd); 5345 } 5346 #if ENABLE_ASH_BASH_COMPAT 5347 if (redir->nfile.type == NTO2 && fd == 1) { 5348 /* We already redirected it to fd 1, now copy it to 2 */ 5349 newfd = 1; 5350 fd = 2; 5351 goto redirect_more; 5352 } 5353 #endif 5354 } while ((redir = redir->nfile.next) != NULL); 5355 4841 5356 INT_ON; 4842 if ( flags & REDIR_SAVEFD2 && sv && sv->renamed[2]>= 0)4843 preverrout_fd = sv->renamed[2];5357 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0) 5358 preverrout_fd = copied_fd2; 4844 5359 } 4845 5360 … … 4848 5363 */ 4849 5364 static void 4850 popredir(int drop )5365 popredir(int drop, int restore) 4851 5366 { 4852 5367 struct redirtab *rp; 4853 5368 int i; 4854 5369 4855 if (-- nullredirs >= 0)5370 if (--g_nullredirs >= 0) 4856 5371 return; 4857 5372 INT_OFF; 4858 5373 rp = redirlist; 4859 for (i = 0; i < 10; i++) { 4860 if (rp->renamed[i] != EMPTY) { 4861 if (!drop) { 4862 close(i); 4863 copyfd(rp->renamed[i], i); 5374 for (i = 0; i < rp->pair_count; i++) { 5375 int fd = rp->two_fd[i].orig; 5376 int copy = rp->two_fd[i].copy; 5377 if (copy == CLOSED) { 5378 if (!drop) 5379 close(fd); 5380 continue; 5381 } 5382 if (copy != EMPTY) { 5383 if (!drop || (restore && (copy & COPYFD_RESTORE))) { 5384 copy &= ~COPYFD_RESTORE; 5385 /*close(fd);*/ 5386 copyfd(copy, fd | COPYFD_EXACT); 4864 5387 } 4865 close( rp->renamed[i]);5388 close(copy & ~COPYFD_RESTORE); 4866 5389 } 4867 5390 } 4868 5391 redirlist = rp->next; 4869 nullredirs = rp->nullredirs;5392 g_nullredirs = rp->nullredirs; 4870 5393 free(rp); 4871 5394 INT_ON; … … 4883 5406 { 4884 5407 for (;;) { 4885 nullredirs = 0;5408 g_nullredirs = 0; 4886 5409 if (!redirlist) 4887 5410 break; 4888 popredir(drop );5411 popredir(drop, /*restore:*/ 0); 4889 5412 } 4890 5413 } … … 4899 5422 4900 5423 SAVE_INT(saveint); 4901 err = setjmp(jmploc.loc) * 2; 5424 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */ 5425 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2; 4902 5426 if (!err) { 4903 5427 exception_handler = &jmploc; … … 4905 5429 } 4906 5430 exception_handler = savehandler; 4907 if (err && exception != EXERROR)5431 if (err && exception_type != EXERROR) 4908 5432 longjmp(exception_handler->loc, 1); 4909 5433 RESTORE_INT(saveint); … … 4916 5440 * We have to deal with backquotes, shell variables, and file metacharacters. 4917 5441 */ 5442 5443 #if ENABLE_SH_MATH_SUPPORT 5444 static arith_t 5445 ash_arith(const char *s) 5446 { 5447 arith_state_t math_state; 5448 arith_t result; 5449 5450 math_state.lookupvar = lookupvar; 5451 math_state.setvar = setvar2; 5452 //math_state.endofname = endofname; 5453 5454 INT_OFF; 5455 result = arith(&math_state, s); 5456 if (math_state.errmsg) 5457 ash_msg_and_raise_error(math_state.errmsg); 5458 INT_ON; 5459 5460 return result; 5461 } 5462 #endif 4918 5463 4919 5464 /* … … 4930 5475 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */ 4931 5476 /* 4932 * _rmescape() flags5477 * rmescape() flags 4933 5478 */ 4934 5479 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ … … 4968 5513 * Our own itoa(). 4969 5514 */ 5515 #if !ENABLE_SH_MATH_SUPPORT 5516 /* cvtnum() is used even if math support is off (to prepare $? values and such) */ 5517 typedef long arith_t; 5518 # define ARITH_FMT "%ld" 5519 #endif 4970 5520 static int 4971 5521 cvtnum(arith_t num) … … 4974 5524 4975 5525 expdest = makestrspace(32, expdest); 4976 #if ENABLE_ASH_MATH_SUPPORT_64 4977 len = fmtstr(expdest, 32, "%lld", (long long) num); 4978 #else 4979 len = fmtstr(expdest, 32, "%ld", num); 4980 #endif 5526 len = fmtstr(expdest, 32, ARITH_FMT, num); 4981 5527 STADJUST(len, expdest); 4982 5528 return len; … … 4988 5534 size_t esc = 0; 4989 5535 4990 while (p > start && *--p == CTLESC) {5536 while (p > start && (unsigned char)*--p == CTLESC) { 4991 5537 esc++; 4992 5538 } … … 4998 5544 */ 4999 5545 static char * 5000 _rmescapes(char *str, int flag)5546 rmescapes(char *str, int flag) 5001 5547 { 5002 5548 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' }; … … 5004 5550 char *p, *q, *r; 5005 5551 unsigned inquotes; 5006 int notescaped;5007 intglobbing;5552 unsigned protect_against_glob; 5553 unsigned globbing; 5008 5554 5009 5555 p = strpbrk(str, qchars); 5010 if (!p) {5556 if (!p) 5011 5557 return str; 5012 } 5558 5013 5559 q = p; 5014 5560 r = str; … … 5018 5564 5019 5565 if (flag & RMESCAPE_GROW) { 5566 int strloc = str - (char *)stackblock(); 5020 5567 r = makestrspace(fulllen, expdest); 5568 /* p and str may be invalidated by makestrspace */ 5569 str = (char *)stackblock() + strloc; 5570 p = str + len; 5021 5571 } else if (flag & RMESCAPE_HEAP) { 5022 5572 r = ckmalloc(fulllen); … … 5026 5576 q = r; 5027 5577 if (len > 0) { 5028 q = memcpy(q, str, len) + len; 5029 } 5030 } 5578 q = (char *)memcpy(q, str, len) + len; 5579 } 5580 } 5581 5031 5582 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED; 5032 5583 globbing = flag & RMESCAPE_GLOB; 5033 notescaped= globbing;5584 protect_against_glob = globbing; 5034 5585 while (*p) { 5035 if (*p == CTLQUOTEMARK) { 5586 if ((unsigned char)*p == CTLQUOTEMARK) { 5587 // TODO: if no RMESCAPE_QUOTED in flags, inquotes never becomes 0 5588 // (alternates between RMESCAPE_QUOTED and ~RMESCAPE_QUOTED). Is it ok? 5589 // Note: both inquotes and protect_against_glob only affect whether 5590 // CTLESC,<ch> gets converted to <ch> or to \<ch> 5036 5591 inquotes = ~inquotes; 5037 5592 p++; 5038 notescaped= globbing;5593 protect_against_glob = globbing; 5039 5594 continue; 5040 5595 } 5041 5596 if (*p == '\\') { 5042 5597 /* naked back slash */ 5043 notescaped= 0;5598 protect_against_glob = 0; 5044 5599 goto copy; 5045 5600 } 5046 if ( *p == CTLESC) {5601 if ((unsigned char)*p == CTLESC) { 5047 5602 p++; 5048 if ( notescaped&& inquotes && *p != '/') {5603 if (protect_against_glob && inquotes && *p != '/') { 5049 5604 *q++ = '\\'; 5050 5605 } 5051 5606 } 5052 notescaped= globbing;5607 protect_against_glob = globbing; 5053 5608 copy: 5054 5609 *q++ = *p++; … … 5061 5616 return r; 5062 5617 } 5063 #define rmescapes(p) _rmescapes((p), 0)5064 5065 5618 #define pmatch(a, b) !fnmatch((a), (b), 0) 5066 5619 … … 5077 5630 flag |= RMESCAPE_QUOTED; 5078 5631 } 5079 return _rmescapes((char *)pattern, flag);5632 return rmescapes((char *)pattern, flag); 5080 5633 } 5081 5634 … … 5088 5641 char *q = expdest; 5089 5642 5090 q = makestrspace( len * 2, q);5643 q = makestrspace(quotes ? len * 2 : len, q); 5091 5644 5092 5645 while (len--) { 5093 int c = signed_char2int(*p++);5094 if ( !c)5646 unsigned char c = *p++; 5647 if (c == '\0') 5095 5648 continue; 5096 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK)) 5097 USTPUTC(CTLESC, q); 5649 if (quotes) { 5650 int n = SIT(c, syntax); 5651 if (n == CCTL || n == CBACK) 5652 USTPUTC(CTLESC, q); 5653 } 5098 5654 USTPUTC(c, q); 5099 5655 } … … 5121 5677 } else { 5122 5678 INT_OFF; 5123 ifsp = ck malloc(sizeof(*ifsp));5124 ifsp->next = NULL;5679 ifsp = ckzalloc(sizeof(*ifsp)); 5680 /*ifsp->next = NULL; - ckzalloc did it */ 5125 5681 ifslastp->next = ifsp; 5126 5682 INT_ON; … … 5139 5695 5140 5696 if (ifsfirst.endoff > endoff) { 5141 while (ifsfirst.next != NULL) {5697 while (ifsfirst.next) { 5142 5698 struct ifsregion *ifsp; 5143 5699 INT_OFF; … … 5147 5703 INT_ON; 5148 5704 } 5149 if (ifsfirst.begoff > endoff) 5705 if (ifsfirst.begoff > endoff) { 5150 5706 ifslastp = NULL; 5151 else {5707 } else { 5152 5708 ifslastp = &ifsfirst; 5153 5709 ifsfirst.endoff = endoff; … … 5158 5714 ifslastp = &ifsfirst; 5159 5715 while (ifslastp->next && ifslastp->next->begoff < endoff) 5160 ifslastp =ifslastp->next;5161 while (ifslastp->next != NULL) {5716 ifslastp = ifslastp->next; 5717 while (ifslastp->next) { 5162 5718 struct ifsregion *ifsp; 5163 5719 INT_OFF; … … 5172 5728 5173 5729 static char * 5174 exptilde(char *startp, char *p, int flag )5175 { 5176 char c;5730 exptilde(char *startp, char *p, int flags) 5731 { 5732 unsigned char c; 5177 5733 char *name; 5178 5734 struct passwd *pw; 5179 5735 const char *home; 5180 int quotes = flag & (EXP_FULL | EXP_CASE);5736 int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); 5181 5737 int startloc; 5182 5738 … … 5190 5746 return startp; 5191 5747 case ':': 5192 if (flag & EXP_VARTILDE)5748 if (flags & EXP_VARTILDE) 5193 5749 goto done; 5194 5750 break; … … 5201 5757 *p = '\0'; 5202 5758 if (*name == '\0') { 5203 home = lookupvar( homestr);5759 home = lookupvar("HOME"); 5204 5760 } else { 5205 5761 pw = getpwnam(name); … … 5228 5784 struct backcmd { /* result of evalbackcmd */ 5229 5785 int fd; /* file descriptor to read from */ 5786 int nleft; /* number of chars in buffer */ 5230 5787 char *buf; /* buffer */ 5231 int nleft; /* number of chars in buffer */5232 5788 struct job *jp; /* job structure for command */ 5233 5789 }; 5234 5790 5235 5791 /* These forward decls are needed to use "eval" code for backticks handling: */ 5236 static int back_exitstatus; /* exit status of backquoted command */5792 static uint8_t back_exitstatus; /* exit status of backquoted command */ 5237 5793 #define EV_EXIT 01 /* exit after evaluating tree */ 5238 5794 static void evaltree(union node *, int); 5239 5795 5240 static void 5796 static void FAST_FUNC 5241 5797 evalbackcmd(union node *n, struct backcmd *result) 5242 5798 { … … 5247 5803 result->nleft = 0; 5248 5804 result->jp = NULL; 5249 if (n == NULL) {5805 if (n == NULL) 5250 5806 goto out; 5251 }5252 5807 5253 5808 saveherefd = herefd; … … 5260 5815 if (pipe(pip) < 0) 5261 5816 ash_msg_and_raise_error("pipe call failed"); 5262 jp = makejob( n,1);5817 jp = makejob(/*n,*/ 1); 5263 5818 if (forkshell(jp, n, FORK_NOJOB) == 0) { 5264 5819 FORCE_INT_ON; 5265 5820 close(pip[0]); 5266 5821 if (pip[1] != 1) { 5267 close(1);5268 copyfd(pip[1], 1 );5822 /*close(1);*/ 5823 copyfd(pip[1], 1 | COPYFD_EXACT); 5269 5824 close(pip[1]); 5270 5825 } … … 5295 5850 char *dest; 5296 5851 int startloc; 5297 int syntax = quoted ? DQSYNTAX : BASESYNTAX;5852 int syntax = quoted ? DQSYNTAX : BASESYNTAX; 5298 5853 struct stackmark smark; 5299 5854 … … 5315 5870 if (in.fd < 0) 5316 5871 break; 5317 i = safe_read(in.fd, buf, sizeof(buf));5872 i = nonblock_safe_read(in.fd, buf, sizeof(buf)); 5318 5873 TRACE(("expbackq: read returns %d\n", i)); 5319 5874 if (i <= 0) … … 5322 5877 } 5323 5878 5324 if (in.buf) 5325 free(in.buf); 5879 free(in.buf); 5326 5880 if (in.fd >= 0) { 5327 5881 close(in.fd); … … 5338 5892 if (quoted == 0) 5339 5893 recordregion(startloc, dest - (char *)stackblock(), 0); 5340 TRACE(("evalbackq: size =%d: \"%.*s\"\n",5341 ( dest - (char *)stackblock()) - startloc,5342 ( dest - (char *)stackblock()) - startloc,5894 TRACE(("evalbackq: size:%d:'%.*s'\n", 5895 (int)((dest - (char *)stackblock()) - startloc), 5896 (int)((dest - (char *)stackblock()) - startloc), 5343 5897 stackblock() + startloc)); 5344 5898 } 5345 5899 5346 #if ENABLE_ ASH_MATH_SUPPORT5900 #if ENABLE_SH_MATH_SUPPORT 5347 5901 /* 5348 5902 * Expand arithmetic expression. Backup to start of expression, … … 5357 5911 int len; 5358 5912 5359 /* 5913 /* ifsfree(); */ 5360 5914 5361 5915 /* … … 5371 5925 int esc; 5372 5926 5373 while ( *p != CTLARI) {5927 while ((unsigned char)*p != CTLARI) { 5374 5928 p--; 5375 5929 #if DEBUG … … 5397 5951 5398 5952 if (quotes) 5399 rmescapes(p + 2 );5400 5401 len = cvtnum( dash_arith(p + 2));5953 rmescapes(p + 2, 0); 5954 5955 len = cvtnum(ash_arith(p + 2)); 5402 5956 5403 5957 if (flag != '"') … … 5407 5961 5408 5962 /* argstr needs it */ 5409 static char *evalvar(char *p, int flag );5963 static char *evalvar(char *p, int flags, struct strlist *var_str_list); 5410 5964 5411 5965 /* … … 5413 5967 * characters to allow for further processing. Otherwise treat 5414 5968 * $@ like $* since no splitting will be performed. 5969 * 5970 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence 5971 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it 5972 * for correct expansion of "B=$A" word. 5415 5973 */ 5416 5974 static void 5417 argstr(char *p, int flag )5975 argstr(char *p, int flags, struct strlist *var_str_list) 5418 5976 { 5419 5977 static const char spclchars[] ALIGN1 = { … … 5426 5984 CTLBACKQ, 5427 5985 CTLBACKQ | CTLQUOTE, 5428 #if ENABLE_ ASH_MATH_SUPPORT5986 #if ENABLE_SH_MATH_SUPPORT 5429 5987 CTLENDARI, 5430 5988 #endif 5431 05989 '\0' 5432 5990 }; 5433 5991 const char *reject = spclchars; 5434 int c; 5435 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */ 5436 int breakall = flag & EXP_WORD; 5992 int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */ 5993 int breakall = flags & EXP_WORD; 5437 5994 int inquotes; 5438 5995 size_t length; 5439 5996 int startloc; 5440 5997 5441 if (!(flag & EXP_VARTILDE)) {5998 if (!(flags & EXP_VARTILDE)) { 5442 5999 reject += 2; 5443 } else if (flag & EXP_VARTILDE2) {6000 } else if (flags & EXP_VARTILDE2) { 5444 6001 reject++; 5445 6002 } 5446 6003 inquotes = 0; 5447 6004 length = 0; 5448 if (flag & EXP_TILDE) {6005 if (flags & EXP_TILDE) { 5449 6006 char *q; 5450 6007 5451 flag &= ~EXP_TILDE;6008 flags &= ~EXP_TILDE; 5452 6009 tilde: 5453 6010 q = p; 5454 if ( *q == CTLESC && (flag& EXP_QWORD))6011 if ((unsigned char)*q == CTLESC && (flags & EXP_QWORD)) 5455 6012 q++; 5456 6013 if (*q == '~') 5457 p = exptilde(p, q, flag );6014 p = exptilde(p, q, flags); 5458 6015 } 5459 6016 start: 5460 6017 startloc = expdest - (char *)stackblock(); 5461 6018 for (;;) { 6019 unsigned char c; 6020 5462 6021 length += strcspn(p + length, reject); 5463 6022 c = p[length]; 5464 if (c && (!(c & 0x80)5465 #if ENABLE_ASH_MATH_SUPPORT 5466 || c == CTLENDARI5467 #endif 5468 )) {5469 /* c == '=' || c == ':' || c == CTLENDARI */5470 length++;6023 if (c) { 6024 if (!(c & 0x80) 6025 IF_SH_MATH_SUPPORT(|| c == CTLENDARI) 6026 ) { 6027 /* c == '=' || c == ':' || c == CTLENDARI */ 6028 length++; 6029 } 5471 6030 } 5472 6031 if (length > 0) { … … 5486 6045 goto breakloop; 5487 6046 case '=': 5488 if (flag & EXP_VARTILDE2) {6047 if (flags & EXP_VARTILDE2) { 5489 6048 p--; 5490 6049 continue; 5491 6050 } 5492 flag |= EXP_VARTILDE2;6051 flags |= EXP_VARTILDE2; 5493 6052 reject++; 5494 6053 /* fall through */ … … 5509 6068 case CTLQUOTEMARK: 5510 6069 /* "$@" syntax adherence hack */ 5511 if ( 5512 !inquotes && 5513 !memcmp(p, dolatstr, 4) && 5514 (p[4] == CTLQUOTEMARK || ( 5515 p[4] == CTLENDVAR && 5516 p[5] == CTLQUOTEMARK 5517 )) 6070 if (!inquotes 6071 && memcmp(p, dolatstr, 4) == 0 6072 && ( p[4] == (char)CTLQUOTEMARK 6073 || (p[4] == (char)CTLENDVAR && p[5] == (char)CTLQUOTEMARK) 6074 ) 5518 6075 ) { 5519 p = evalvar(p + 1, flag ) + 1;6076 p = evalvar(p + 1, flags, /* var_str_list: */ NULL) + 1; 5520 6077 goto start; 5521 6078 } … … 5533 6090 goto addquote; 5534 6091 case CTLVAR: 5535 p = evalvar(p, flag );6092 p = evalvar(p, flags, var_str_list); 5536 6093 goto start; 5537 6094 case CTLBACKQ: 5538 c = 0;6095 c = '\0'; 5539 6096 case CTLBACKQ|CTLQUOTE: 5540 6097 expbackq(argbackq->n, c, quotes); 5541 6098 argbackq = argbackq->next; 5542 6099 goto start; 5543 #if ENABLE_ ASH_MATH_SUPPORT6100 #if ENABLE_SH_MATH_SUPPORT 5544 6101 case CTLENDARI: 5545 6102 p--; … … 5549 6106 } 5550 6107 } 5551 breakloop: 5552 ; 6108 breakloop: ; 5553 6109 } 5554 6110 5555 6111 static char * 5556 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes, 5557 int zero) 5558 { 5559 char *loc; 5560 char *loc2; 6112 scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM, 6113 char *pattern, int quotes, int zero) 6114 { 6115 char *loc, *loc2; 5561 6116 char c; 5562 6117 … … 5566 6121 int match; 5567 6122 const char *s = loc2; 6123 5568 6124 c = *loc2; 5569 6125 if (zero) { … … 5571 6127 s = rmesc; 5572 6128 } 5573 match = pmatch(str, s); 6129 match = pmatch(pattern, s); 6130 5574 6131 *loc2 = c; 5575 6132 if (match) 5576 6133 return loc; 5577 if (quotes && *loc == CTLESC)6134 if (quotes && (unsigned char)*loc == CTLESC) 5578 6135 loc++; 5579 6136 loc++; 5580 6137 loc2++; 5581 6138 } while (c); 5582 return 0;6139 return NULL; 5583 6140 } 5584 6141 5585 6142 static char * 5586 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes, 5587 int zero) 5588 { 6143 scanright(char *startp, char *rmesc, char *rmescend, 6144 char *pattern, int quotes, int match_at_start) 6145 { 6146 #if !ENABLE_ASH_OPTIMIZE_FOR_SIZE 6147 int try2optimize = match_at_start; 6148 #endif 5589 6149 int esc = 0; 5590 6150 char *loc; 5591 6151 char *loc2; 5592 6152 5593 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) { 6153 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}": 6154 * startp="escaped_value_of_v" rmesc="raw_value_of_v" 6155 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1 6156 * Logic: 6157 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc, 6158 * and on each iteration they go back two/one char until they reach the beginning. 6159 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc. 6160 */ 6161 /* TODO: document in what other circumstances we are called. */ 6162 6163 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) { 5594 6164 int match; 5595 6165 char c = *loc2; 5596 6166 const char *s = loc2; 5597 if ( zero) {6167 if (match_at_start) { 5598 6168 *loc2 = '\0'; 5599 6169 s = rmesc; 5600 6170 } 5601 match = pmatch(str, s); 6171 match = pmatch(pattern, s); 6172 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match); 5602 6173 *loc2 = c; 5603 6174 if (match) 5604 6175 return loc; 6176 #if !ENABLE_ASH_OPTIMIZE_FOR_SIZE 6177 if (try2optimize) { 6178 /* Maybe we can optimize this: 6179 * if pattern ends with unescaped *, we can avoid checking 6180 * shorter strings: if "foo*" doesnt match "raw_value_of_v", 6181 * it wont match truncated "raw_value_of_" strings too. 6182 */ 6183 unsigned plen = strlen(pattern); 6184 /* Does it end with "*"? */ 6185 if (plen != 0 && pattern[--plen] == '*') { 6186 /* "xxxx*" is not escaped */ 6187 /* "xxx\*" is escaped */ 6188 /* "xx\\*" is not escaped */ 6189 /* "x\\\*" is escaped */ 6190 int slashes = 0; 6191 while (plen != 0 && pattern[--plen] == '\\') 6192 slashes++; 6193 if (!(slashes & 1)) 6194 break; /* ends with unescaped "*" */ 6195 } 6196 try2optimize = 0; 6197 } 6198 #endif 5605 6199 loc--; 5606 6200 if (quotes) { … … 5614 6208 } 5615 6209 } 5616 return 0;5617 } 5618 5619 static void varunset(const char *, const char *, const char *, int) ATTRIBUTE_NORETURN;6210 return NULL; 6211 } 6212 6213 static void varunset(const char *, const char *, const char *, int) NORETURN; 5620 6214 static void 5621 6215 varunset(const char *end, const char *var, const char *umsg, int varflags) … … 5627 6221 msg = "parameter not set"; 5628 6222 if (umsg) { 5629 if ( *end == CTLENDVAR) {6223 if ((unsigned char)*end == CTLENDVAR) { 5630 6224 if (varflags & VSNUL) 5631 6225 tail = " or null"; 5632 } else 6226 } else { 5633 6227 msg = umsg; 5634 } 5635 ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail); 5636 } 6228 } 6229 } 6230 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail); 6231 } 6232 6233 #if ENABLE_ASH_BASH_COMPAT 6234 static char * 6235 parse_sub_pattern(char *arg, int varflags) 6236 { 6237 char *idx, *repl = NULL; 6238 unsigned char c; 6239 6240 //char *org_arg = arg; 6241 //bb_error_msg("arg:'%s' varflags:%x", arg, varflags); 6242 idx = arg; 6243 while (1) { 6244 c = *arg; 6245 if (!c) 6246 break; 6247 if (c == '/') { 6248 /* Only the first '/' seen is our separator */ 6249 if (!repl) { 6250 repl = idx + 1; 6251 c = '\0'; 6252 } 6253 } 6254 *idx++ = c; 6255 arg++; 6256 /* 6257 * Example: v='ab\c'; echo ${v/\\b/_\\_\z_} 6258 * The result is a_\_z_c (not a\_\_z_c)! 6259 * 6260 * Enable debug prints in this function and you'll see: 6261 * ash: arg:'\\b/_\\_z_' varflags:d 6262 * ash: pattern:'\\b' repl:'_\_z_' 6263 * That is, \\b is interpreted as \\b, but \\_ as \_! 6264 * IOW: search pattern and replace string treat backslashes 6265 * differently! That is the reason why we check repl below: 6266 */ 6267 if (c == '\\' && *arg == '\\' && repl && !(varflags & VSQUOTE)) 6268 arg++; /* skip both '\', not just first one */ 6269 } 6270 *idx = c; /* NUL */ 6271 //bb_error_msg("pattern:'%s' repl:'%s'", org_arg, repl); 6272 6273 return repl; 6274 } 6275 #endif /* ENABLE_ASH_BASH_COMPAT */ 5637 6276 5638 6277 static const char * 5639 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes) 5640 { 6278 subevalvar(char *p, char *varname, int strloc, int subtype, 6279 int startloc, int varflags, int quotes, struct strlist *var_str_list) 6280 { 6281 struct nodelist *saveargbackq = argbackq; 5641 6282 char *startp; 5642 6283 char *loc; 6284 char *rmesc, *rmescend; 6285 char *str; 6286 IF_ASH_BASH_COMPAT(const char *repl = NULL;) 6287 IF_ASH_BASH_COMPAT(int pos, len, orig_len;) 5643 6288 int saveherefd = herefd; 5644 struct nodelist *saveargbackq = argbackq; 5645 int amount; 5646 char *rmesc, *rmescend; 6289 int amount, workloc, resetloc; 5647 6290 int zero; 5648 char *(*scan)(char *, char *, char *, char *, int , int); 6291 char *(*scan)(char*, char*, char*, char*, int, int); 6292 6293 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)", 6294 // p, varname, strloc, subtype, startloc, varflags, quotes); 5649 6295 5650 6296 herefd = -1; 5651 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0); 6297 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0, 6298 var_str_list); 5652 6299 STPUTC('\0', expdest); 5653 6300 herefd = saveherefd; 5654 6301 argbackq = saveargbackq; 5655 startp = stackblock() + startloc;6302 startp = (char *)stackblock() + startloc; 5656 6303 5657 6304 switch (subtype) { 5658 6305 case VSASSIGN: 5659 setvar( str, startp, 0);6306 setvar(varname, startp, 0); 5660 6307 amount = startp - expdest; 5661 6308 STADJUST(amount, expdest); … … 5663 6310 5664 6311 case VSQUESTION: 5665 varunset(p, str, startp, varflags);6312 varunset(p, varname, startp, varflags); 5666 6313 /* NOTREACHED */ 5667 } 6314 6315 #if ENABLE_ASH_BASH_COMPAT 6316 case VSSUBSTR: 6317 loc = str = stackblock() + strloc; 6318 /* Read POS in ${var:POS:LEN} */ 6319 pos = atoi(loc); /* number(loc) errors out on "1:4" */ 6320 len = str - startp - 1; 6321 6322 /* *loc != '\0', guaranteed by parser */ 6323 if (quotes) { 6324 char *ptr; 6325 6326 /* Adjust the length by the number of escapes */ 6327 for (ptr = startp; ptr < (str - 1); ptr++) { 6328 if ((unsigned char)*ptr == CTLESC) { 6329 len--; 6330 ptr++; 6331 } 6332 } 6333 } 6334 orig_len = len; 6335 6336 if (*loc++ == ':') { 6337 /* ${var::LEN} */ 6338 len = number(loc); 6339 } else { 6340 /* Skip POS in ${var:POS:LEN} */ 6341 len = orig_len; 6342 while (*loc && *loc != ':') { 6343 /* TODO? 6344 * bash complains on: var=qwe; echo ${var:1a:123} 6345 if (!isdigit(*loc)) 6346 ash_msg_and_raise_error(msg_illnum, str); 6347 */ 6348 loc++; 6349 } 6350 if (*loc++ == ':') { 6351 len = number(loc); 6352 } 6353 } 6354 if (pos >= orig_len) { 6355 pos = 0; 6356 len = 0; 6357 } 6358 if (len > (orig_len - pos)) 6359 len = orig_len - pos; 6360 6361 for (str = startp; pos; str++, pos--) { 6362 if (quotes && (unsigned char)*str == CTLESC) 6363 str++; 6364 } 6365 for (loc = startp; len; len--) { 6366 if (quotes && (unsigned char)*str == CTLESC) 6367 *loc++ = *str++; 6368 *loc++ = *str++; 6369 } 6370 *loc = '\0'; 6371 amount = loc - expdest; 6372 STADJUST(amount, expdest); 6373 return loc; 6374 #endif 6375 } 6376 6377 resetloc = expdest - (char *)stackblock(); 6378 6379 /* We'll comeback here if we grow the stack while handling 6380 * a VSREPLACE or VSREPLACEALL, since our pointers into the 6381 * stack will need rebasing, and we'll need to remove our work 6382 * areas each time 6383 */ 6384 IF_ASH_BASH_COMPAT(restart:) 6385 6386 amount = expdest - ((char *)stackblock() + resetloc); 6387 STADJUST(-amount, expdest); 6388 startp = (char *)stackblock() + startloc; 6389 6390 rmesc = startp; 6391 rmescend = (char *)stackblock() + strloc; 6392 if (quotes) { 6393 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW); 6394 if (rmesc != startp) { 6395 rmescend = expdest; 6396 startp = (char *)stackblock() + startloc; 6397 } 6398 } 6399 rmescend--; 6400 str = (char *)stackblock() + strloc; 6401 preglob(str, varflags & VSQUOTE, 0); 6402 workloc = expdest - (char *)stackblock(); 6403 6404 #if ENABLE_ASH_BASH_COMPAT 6405 if (subtype == VSREPLACE || subtype == VSREPLACEALL) { 6406 char *idx, *end; 6407 6408 if (!repl) { 6409 repl = parse_sub_pattern(str, varflags); 6410 //bb_error_msg("repl:'%s'", repl); 6411 if (!repl) 6412 repl = nullstr; 6413 } 6414 6415 /* If there's no pattern to match, return the expansion unmolested */ 6416 if (str[0] == '\0') 6417 return NULL; 6418 6419 len = 0; 6420 idx = startp; 6421 end = str - 1; 6422 while (idx < end) { 6423 try_to_match: 6424 loc = scanright(idx, rmesc, rmescend, str, quotes, 1); 6425 //bb_error_msg("scanright('%s'):'%s'", str, loc); 6426 if (!loc) { 6427 /* No match, advance */ 6428 char *restart_detect = stackblock(); 6429 skip_matching: 6430 STPUTC(*idx, expdest); 6431 if (quotes && (unsigned char)*idx == CTLESC) { 6432 idx++; 6433 len++; 6434 STPUTC(*idx, expdest); 6435 } 6436 if (stackblock() != restart_detect) 6437 goto restart; 6438 idx++; 6439 len++; 6440 rmesc++; 6441 /* continue; - prone to quadratic behavior, smarter code: */ 6442 if (idx >= end) 6443 break; 6444 if (str[0] == '*') { 6445 /* Pattern is "*foo". If "*foo" does not match "long_string", 6446 * it would never match "ong_string" etc, no point in trying. 6447 */ 6448 goto skip_matching; 6449 } 6450 goto try_to_match; 6451 } 6452 6453 if (subtype == VSREPLACEALL) { 6454 while (idx < loc) { 6455 if (quotes && (unsigned char)*idx == CTLESC) 6456 idx++; 6457 idx++; 6458 rmesc++; 6459 } 6460 } else { 6461 idx = loc; 6462 } 6463 6464 //bb_error_msg("repl:'%s'", repl); 6465 for (loc = (char*)repl; *loc; loc++) { 6466 char *restart_detect = stackblock(); 6467 if (quotes && *loc == '\\') { 6468 STPUTC(CTLESC, expdest); 6469 len++; 6470 } 6471 STPUTC(*loc, expdest); 6472 if (stackblock() != restart_detect) 6473 goto restart; 6474 len++; 6475 } 6476 6477 if (subtype == VSREPLACE) { 6478 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes); 6479 while (*idx) { 6480 char *restart_detect = stackblock(); 6481 STPUTC(*idx, expdest); 6482 if (stackblock() != restart_detect) 6483 goto restart; 6484 len++; 6485 idx++; 6486 } 6487 break; 6488 } 6489 } 6490 6491 /* We've put the replaced text into a buffer at workloc, now 6492 * move it to the right place and adjust the stack. 6493 */ 6494 STPUTC('\0', expdest); 6495 startp = (char *)stackblock() + startloc; 6496 memmove(startp, (char *)stackblock() + workloc, len + 1); 6497 //bb_error_msg("startp:'%s'", startp); 6498 amount = expdest - (startp + len); 6499 STADJUST(-amount, expdest); 6500 return startp; 6501 } 6502 #endif /* ENABLE_ASH_BASH_COMPAT */ 5668 6503 5669 6504 subtype -= VSTRIMRIGHT; 5670 6505 #if DEBUG 5671 if (subtype < 0 || subtype > 3)6506 if (subtype < 0 || subtype > 7) 5672 6507 abort(); 5673 6508 #endif 5674 5675 rmesc = startp; 5676 rmescend = stackblock() + strloc; 5677 if (quotes) { 5678 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW); 5679 if (rmesc != startp) { 5680 rmescend = expdest; 5681 startp = stackblock() + startloc; 5682 } 5683 } 5684 rmescend--; 5685 str = stackblock() + strloc; 5686 preglob(str, varflags & VSQUOTE, 0); 5687 5688 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */ 6509 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */ 5689 6510 zero = subtype >> 1; 5690 6511 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */ … … 5706 6527 /* 5707 6528 * Add the value of a specialized variable to the stack string. 5708 */ 5709 static ssize_t 5710 varvalue(char *name, int varflags, int flags) 5711 { 6529 * name parameter (examples): 6530 * ash -c 'echo $1' name:'1=' 6531 * ash -c 'echo $qwe' name:'qwe=' 6532 * ash -c 'echo $$' name:'$=' 6533 * ash -c 'echo ${$}' name:'$=' 6534 * ash -c 'echo ${$##q}' name:'$=q' 6535 * ash -c 'echo ${#$}' name:'$=' 6536 * note: examples with bad shell syntax: 6537 * ash -c 'echo ${#$1}' name:'$=1' 6538 * ash -c 'echo ${#1#}' name:'1=#' 6539 */ 6540 static NOINLINE ssize_t 6541 varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) 6542 { 6543 const char *p; 5712 6544 int num; 5713 char *p;5714 6545 int i; 5715 int sep = 0;5716 6546 int sepq = 0; 5717 6547 ssize_t len = 0; 5718 char **ap;5719 int syntax;6548 int subtype = varflags & VSTYPE; 6549 int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); 5720 6550 int quoted = varflags & VSQUOTE; 5721 int subtype = varflags & VSTYPE; 5722 int quotes = flags & (EXP_FULL | EXP_CASE); 5723 5724 if (quoted && (flags & EXP_FULL)) 5725 sep = 1 << CHAR_BIT; 5726 5727 syntax = quoted ? DQSYNTAX : BASESYNTAX; 6551 int syntax = quoted ? DQSYNTAX : BASESYNTAX; 6552 5728 6553 switch (*name) { 5729 6554 case '$': … … 5742 6567 numvar: 5743 6568 len = cvtnum(num); 5744 break;6569 goto check_1char_name; 5745 6570 case '-': 5746 p= makestrspace(NOPTS, expdest);6571 expdest = makestrspace(NOPTS, expdest); 5747 6572 for (i = NOPTS - 1; i >= 0; i--) { 5748 6573 if (optlist[i]) { 5749 USTPUTC(optletters(i), p);6574 USTPUTC(optletters(i), expdest); 5750 6575 len++; 5751 6576 } 5752 6577 } 5753 expdest = p; 6578 check_1char_name: 6579 #if 0 6580 /* handles cases similar to ${#$1} */ 6581 if (name[2] != '\0') 6582 raise_error_syntax("bad substitution"); 6583 #endif 5754 6584 break; 5755 case '@': 5756 if (sep) 6585 case '@': { 6586 char **ap; 6587 int sep; 6588 6589 if (quoted && (flags & EXP_FULL)) { 6590 /* note: this is not meant as PEOF value */ 6591 sep = 1 << CHAR_BIT; 5757 6592 goto param; 6593 } 5758 6594 /* fall through */ 5759 6595 case '*': 5760 sep = ifsset() ? signed_char2int(ifsval()[0]) : ' '; 5761 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK)) 6596 sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' '; 6597 i = SIT(sep, syntax); 6598 if (quotes && (i == CCTL || i == CBACK)) 5762 6599 sepq = 1; 5763 6600 param: … … 5765 6602 if (!ap) 5766 6603 return -1; 5767 while ((p = *ap++) ) {6604 while ((p = *ap++) != NULL) { 5768 6605 size_t partlen; 5769 6606 … … 5784 6621 if (sepq) 5785 6622 STPUTC(CTLESC, q); 6623 /* note: may put NUL despite sep != 0 6624 * (see sep = 1 << CHAR_BIT above) */ 5786 6625 STPUTC(sep, q); 5787 6626 expdest = q; … … 5789 6628 } 5790 6629 return len; 6630 } /* case '@' and '*' */ 5791 6631 case '0': 5792 6632 case '1': … … 5799 6639 case '8': 5800 6640 case '9': 5801 num = atoi(name); 6641 num = atoi(name); /* number(name) fails on ${N#str} etc */ 5802 6642 if (num < 0 || num > shellparam.nparam) 5803 6643 return -1; … … 5805 6645 goto value; 5806 6646 default: 6647 /* NB: name has form "VAR=..." */ 6648 6649 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings 6650 * which should be considered before we check variables. */ 6651 if (var_str_list) { 6652 unsigned name_len = (strchrnul(name, '=') - name) + 1; 6653 p = NULL; 6654 do { 6655 char *str, *eq; 6656 str = var_str_list->text; 6657 eq = strchr(str, '='); 6658 if (!eq) /* stop at first non-assignment */ 6659 break; 6660 eq++; 6661 if (name_len == (unsigned)(eq - str) 6662 && strncmp(str, name, name_len) == 0 6663 ) { 6664 p = eq; 6665 /* goto value; - WRONG! */ 6666 /* think "A=1 A=2 B=$A" */ 6667 } 6668 var_str_list = var_str_list->next; 6669 } while (var_str_list); 6670 if (p) 6671 goto value; 6672 } 5807 6673 p = lookupvar(name); 5808 6674 value: … … 5826 6692 */ 5827 6693 static char * 5828 evalvar(char *p, int flag) 5829 { 5830 int subtype; 5831 int varflags; 6694 evalvar(char *p, int flags, struct strlist *var_str_list) 6695 { 6696 char varflags; 6697 char subtype; 6698 char quoted; 6699 char easy; 5832 6700 char *var; 5833 6701 int patloc; 5834 int c;5835 6702 int startloc; 5836 6703 ssize_t varlen; 5837 int easy; 5838 int quotes; 5839 int quoted; 5840 5841 quotes = flag & (EXP_FULL | EXP_CASE); 5842 varflags = *p++; 6704 6705 varflags = (unsigned char) *p++; 5843 6706 subtype = varflags & VSTYPE; 5844 6707 quoted = varflags & VSQUOTE; … … 5846 6709 easy = (!quoted || (*var == '@' && shellparam.nparam)); 5847 6710 startloc = expdest - (char *)stackblock(); 5848 p = strchr(p, '=') + 1; 6711 p = strchr(p, '=') + 1; //TODO: use var_end(p)? 5849 6712 5850 6713 again: 5851 varlen = varvalue(var, varflags, flag );6714 varlen = varvalue(var, varflags, flags, var_str_list); 5852 6715 if (varflags & VSNUL) 5853 6716 varlen--; … … 5862 6725 if (varlen < 0) { 5863 6726 argstr( 5864 p, flag | EXP_TILDE | 5865 (quoted ? EXP_QWORD : EXP_WORD) 6727 p, 6728 flags | (quoted ? EXP_TILDE|EXP_QWORD : EXP_TILDE|EXP_WORD), 6729 var_str_list 5866 6730 ); 5867 6731 goto end; … … 5874 6738 if (subtype == VSASSIGN || subtype == VSQUESTION) { 5875 6739 if (varlen < 0) { 5876 if (subevalvar(p, var, 0, subtype, startloc, varflags, 0)) { 6740 if (subevalvar(p, var, /* strloc: */ 0, 6741 subtype, startloc, varflags, 6742 /* quotes: */ 0, 6743 var_str_list) 6744 ) { 5877 6745 varflags &= ~VSNUL; 5878 6746 /* … … 5899 6767 5900 6768 if (subtype == VSNORMAL) { 5901 if (!easy) 5902 goto end; 5903 record: 5904 recordregion(startloc, expdest - (char *)stackblock(), quoted); 6769 if (easy) 6770 goto record; 5905 6771 goto end; 5906 6772 } … … 5912 6778 case VSTRIMRIGHT: 5913 6779 case VSTRIMRIGHTMAX: 6780 #if ENABLE_ASH_BASH_COMPAT 6781 case VSSUBSTR: 6782 case VSREPLACE: 6783 case VSREPLACEALL: 6784 #endif 5914 6785 break; 5915 6786 default: … … 5925 6796 STPUTC('\0', expdest); 5926 6797 patloc = expdest - (char *)stackblock(); 5927 if (subevalvar(p, NULL, patloc, subtype, 5928 startloc, varflags, quotes) == 0) { 6798 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype, 6799 startloc, varflags, 6800 //TODO: | EXP_REDIR too? All other such places do it too 6801 /* quotes: */ flags & (EXP_FULL | EXP_CASE), 6802 var_str_list) 6803 ) { 5929 6804 int amount = expdest - ( 5930 6805 (char *)stackblock() + patloc - 1 … … 5934 6809 /* Remove any recorded regions beyond start of variable */ 5935 6810 removerecordregions(startloc); 5936 goto record; 6811 record: 6812 recordregion(startloc, expdest - (char *)stackblock(), quoted); 5937 6813 } 5938 6814 … … 5941 6817 int nesting = 1; 5942 6818 for (;;) { 5943 c = *p++;6819 unsigned char c = *p++; 5944 6820 if (c == CTLESC) 5945 6821 p++; … … 5989 6865 while (p < string + ifsp->endoff) { 5990 6866 q = p; 5991 if ( *p == CTLESC)6867 if ((unsigned char)*p == CTLESC) 5992 6868 p++; 5993 6869 if (!strchr(ifs, *p)) { … … 6004 6880 } 6005 6881 *q = '\0'; 6006 sp = st alloc(sizeof(*sp));6882 sp = stzalloc(sizeof(*sp)); 6007 6883 sp->text = start; 6008 6884 *arglist->lastp = sp; … … 6015 6891 } 6016 6892 q = p; 6017 if ( *p == CTLESC)6893 if ((unsigned char)*p == CTLESC) 6018 6894 p++; 6019 if (strchr(ifs, *p) == NULL 6895 if (strchr(ifs, *p) == NULL) { 6020 6896 p = q; 6021 6897 break; 6022 } else if (strchr(defifs, *p) == NULL) { 6898 } 6899 if (strchr(defifs, *p) == NULL) { 6023 6900 if (ifsspc) { 6024 6901 p++; … … 6044 6921 6045 6922 add: 6046 sp = st alloc(sizeof(*sp));6923 sp = stzalloc(sizeof(*sp)); 6047 6924 sp->text = start; 6048 6925 *arglist->lastp = sp; … … 6076 6953 struct strlist *sp; 6077 6954 6078 sp = st alloc(sizeof(*sp));6955 sp = stzalloc(sizeof(*sp)); 6079 6956 sp->text = ststrdup(name); 6080 6957 *exparg.lastp = sp; … … 6082 6959 } 6083 6960 6084 static char *expdir;6085 6086 6961 /* 6087 6962 * Do metacharacter (i.e. *, ?, [...]) expansion. 6088 6963 */ 6089 6964 static void 6090 expmeta(char *e nddir, char *name)6965 expmeta(char *expdir, char *enddir, char *name) 6091 6966 { 6092 6967 char *p; … … 6176 7051 if (*p == '.') 6177 7052 matchdot++; 6178 while (! intpending&& (dp = readdir(dirp)) != NULL) {6179 if (dp->d_name[0] == '.' && ! 7053 while (!pending_int && (dp = readdir(dirp)) != NULL) { 7054 if (dp->d_name[0] == '.' && !matchdot) 6180 7055 continue; 6181 7056 if (pmatch(start, dp->d_name)) { … … 6187 7062 continue; 6188 7063 p[-1] = '/'; 6189 expmeta( p, endname);7064 expmeta(expdir, p, endname); 6190 7065 } 6191 7066 } 6192 7067 } 6193 7068 closedir(dirp); 6194 if (! 7069 if (!atend) 6195 7070 endname[-1] = '/'; 6196 7071 } … … 6208 7083 half = len >> 1; 6209 7084 p = list; 6210 for (n = half; --n >= 0; 7085 for (n = half; --n >= 0;) { 6211 7086 q = p; 6212 7087 p = p->next; … … 6261 7136 6262 7137 static void 6263 expandmeta(struct strlist *str , int flag)7138 expandmeta(struct strlist *str /*, int flag*/) 6264 7139 { 6265 7140 static const char metachars[] ALIGN1 = { … … 6269 7144 6270 7145 while (str) { 7146 char *expdir; 6271 7147 struct strlist **savelastp; 6272 7148 struct strlist *sp; … … 6285 7161 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ 6286 7162 } 6287 6288 expmeta(expdir, p); 7163 expmeta(expdir, expdir, p); 6289 7164 free(expdir); 6290 7165 if (p != str->text) … … 6297 7172 nometa: 6298 7173 *exparg.lastp = str; 6299 rmescapes(str->text );7174 rmescapes(str->text, 0); 6300 7175 exparg.lastp = &str->next; 6301 7176 } else { … … 6326 7201 ifsfirst.next = NULL; 6327 7202 ifslastp = NULL; 6328 argstr(arg->narg.text, flag); 7203 argstr(arg->narg.text, flag, 7204 /* var_str_list: */ arglist ? arglist->list : NULL); 6329 7205 p = _STPUTC('\0', expdest); 6330 7206 expdest = p - 1; … … 6341 7217 *exparg.lastp = NULL; 6342 7218 exparg.lastp = &exparg.list; 6343 expandmeta(exparg.list , flag);7219 expandmeta(exparg.list /*, flag*/); 6344 7220 } else { 6345 7221 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */ 6346 rmescapes(p );6347 sp = st alloc(sizeof(*sp));7222 rmescapes(p, 0); 7223 sp = stzalloc(sizeof(*sp)); 6348 7224 sp->text = p; 6349 7225 *exparg.lastp = sp; … … 6392 7268 STARTSTACKSTR(expdest); 6393 7269 ifslastp = NULL; 6394 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); 7270 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE, 7271 /* var_str_list: */ NULL); 6395 7272 STACKSTRNUL(expdest); 6396 7273 result = patmatch(stackblock(), val); … … 6404 7281 struct builtincmd { 6405 7282 const char *name; 6406 int (*builtin)(int, char **) ;7283 int (*builtin)(int, char **) FAST_FUNC; 6407 7284 /* unsigned flags; */ 6408 7285 }; 6409 7286 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1) 7287 /* "regular" builtins always take precedence over commands, 7288 * regardless of PATH=....%builtin... position */ 6410 7289 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2) 6411 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)7290 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4) 6412 7291 6413 7292 struct cmdentry { 6414 int cmdtype;7293 smallint cmdtype; /* CMDxxx */ 6415 7294 union param { 6416 7295 int index; 7296 /* index >= 0 for commands without path (slashes) */ 7297 /* (TODO: what exactly does the value mean? PATH position?) */ 7298 /* index == -1 for commands with slashes */ 7299 /* index == (-2 - applet_no) for NOFORK applets */ 6417 7300 const struct builtincmd *cmd; 6418 7301 struct funcnode *func; … … 6446 7329 */ 6447 7330 6448 #define CMDTABLESIZE 31 /* should be prime */6449 #define ARB 1 /* actual size determined at run time */6450 6451 7331 struct tblentry { 6452 7332 struct tblentry *next; /* next entry in hash chain */ 6453 7333 union param param; /* definition of builtin function */ 6454 s hort cmdtype; /* index identifying command*/7334 smallint cmdtype; /* CMDxxx */ 6455 7335 char rehash; /* if set, cd done since entry created */ 6456 char cmdname[ ARB];/* name of command */7336 char cmdname[1]; /* name of command */ 6457 7337 }; 6458 7338 6459 static struct tblentry *cmdtable[CMDTABLESIZE]; 6460 static int builtinloc = -1; /* index in path of %builtin, or -1 */ 7339 static struct tblentry **cmdtable; 7340 #define INIT_G_cmdtable() do { \ 7341 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \ 7342 } while (0) 7343 7344 static int builtinloc = -1; /* index in path of %builtin, or -1 */ 7345 6461 7346 6462 7347 static void 6463 tryexec( char *cmd, char **argv, char **envp)7348 tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp) 6464 7349 { 6465 7350 int repeated = 0; 6466 7351 6467 7352 #if ENABLE_FEATURE_SH_STANDALONE 6468 if (strchr(cmd, '/') == NULL) { 6469 const struct bb_applet *a; 6470 6471 a = find_applet_by_name(cmd); 6472 if (a) { 6473 if (a->noexec) { 6474 current_applet = a; 6475 run_current_applet_and_exit(argv); 6476 } 6477 /* re-exec ourselves with the new arguments */ 6478 execve(bb_busybox_exec_path, argv, envp); 6479 /* If they called chroot or otherwise made the binary no longer 6480 * executable, fall through */ 6481 } 7353 if (applet_no >= 0) { 7354 if (APPLET_IS_NOEXEC(applet_no)) { 7355 clearenv(); 7356 while (*envp) 7357 putenv(*envp++); 7358 run_applet_no_and_exit(applet_no, argv); 7359 } 7360 /* re-exec ourselves with the new arguments */ 7361 execve(bb_busybox_exec_path, argv, envp); 7362 /* If they called chroot or otherwise made the binary no longer 7363 * executable, fall through */ 6482 7364 } 6483 7365 #endif … … 6491 7373 execve(cmd, argv, envp); 6492 7374 #endif 6493 if (repeated ++) {7375 if (repeated) { 6494 7376 free(argv); 6495 } else if (errno == ENOEXEC) { 7377 return; 7378 } 7379 if (errno == ENOEXEC) { 6496 7380 char **ap; 6497 7381 char **new; 6498 7382 6499 7383 for (ap = argv; *ap; ap++) 6500 ;6501 ap = new = ckmalloc((ap - argv + 2) * sizeof( char *));7384 continue; 7385 ap = new = ckmalloc((ap - argv + 2) * sizeof(ap[0])); 6502 7386 ap[1] = cmd; 6503 7387 ap[0] = cmd = (char *)DEFAULT_SHELL; 6504 7388 ap += 2; 6505 7389 argv++; 6506 while ((*ap++ = *argv++) )6507 ;7390 while ((*ap++ = *argv++) != NULL) 7391 continue; 6508 7392 argv = new; 7393 repeated++; 6509 7394 goto repeat; 6510 7395 } … … 6515 7400 * have to change the find_command routine as well. 6516 7401 */ 6517 #define environment() listvars(VEXPORT, VUNSET, 0) 6518 static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN; 7402 static void shellexec(char **, const char *, int) NORETURN; 6519 7403 static void 6520 7404 shellexec(char **argv, const char *path, int idx) … … 6524 7408 char **envp; 6525 7409 int exerrno; 6526 6527 clearredir(1);6528 envp = environment();6529 if (strchr(argv[0], '/')6530 7410 #if ENABLE_FEATURE_SH_STANDALONE 6531 || find_applet_by_name(argv[0]) 7411 int applet_no = -1; 7412 #endif 7413 7414 clearredir(/*drop:*/ 1); 7415 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); 7416 if (strchr(argv[0], '/') != NULL 7417 #if ENABLE_FEATURE_SH_STANDALONE 7418 || (applet_no = find_applet_by_name(argv[0])) >= 0 6532 7419 #endif 6533 7420 ) { 6534 tryexec( argv[0], argv, envp);7421 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp); 6535 7422 e = errno; 6536 7423 } else { 6537 7424 e = ENOENT; 6538 while ((cmdname = pa dvance(&path, argv[0])) != NULL) {7425 while ((cmdname = path_advance(&path, argv[0])) != NULL) { 6539 7426 if (--idx < 0 && pathopt == NULL) { 6540 tryexec( cmdname, argv, envp);7427 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp); 6541 7428 if (errno != ENOENT && errno != ENOTDIR) 6542 7429 e = errno; … … 6559 7446 } 6560 7447 exitstatus = exerrno; 6561 TRACE(("shellexec failed for %s, errno %d, suppress int %d\n",6562 argv[0], e, suppress int));7448 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n", 7449 argv[0], e, suppress_int)); 6563 7450 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found")); 6564 7451 /* NOTREACHED */ … … 6575 7462 path = pathval(); 6576 7463 do { 6577 name = pa dvance(&path, cmdp->cmdname);7464 name = path_advance(&path, cmdp->cmdname); 6578 7465 stunalloc(name); 6579 7466 } while (--idx >= 0); … … 6642 7529 } 6643 7530 if (add && cmdp == NULL) { 6644 cmdp = *pp = ckmalloc(sizeof(struct tblentry) - ARB 6645 + strlen(name) + 1); 6646 cmdp->next = NULL; 7531 cmdp = *pp = ckzalloc(sizeof(struct tblentry) 7532 + strlen(name) 7533 /* + 1 - already done because 7534 * tblentry::cmdname is char[1] */); 7535 /*cmdp->next = NULL; - ckzalloc did it */ 6647 7536 cmdp->cmdtype = CMDUNKNOWN; 6648 7537 strcpy(cmdp->cmdname, name); … … 6687 7576 } 6688 7577 6689 static int 6690 hashcmd(int argc , char **argv)7578 static int FAST_FUNC 7579 hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 6691 7580 { 6692 7581 struct tblentry **pp; … … 6696 7585 char *name; 6697 7586 6698 while ((c = nextopt("r")) != '\0') {7587 if (nextopt("r") != '\0') { 6699 7588 clearcmdentry(0); 6700 7589 return 0; 6701 7590 } 7591 6702 7592 if (*argptr == NULL) { 6703 7593 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) { … … 6709 7599 return 0; 6710 7600 } 7601 6711 7602 c = 0; 6712 7603 while ((name = *argptr) != NULL) { … … 6714 7605 if (cmdp != NULL 6715 7606 && (cmdp->cmdtype == CMDNORMAL 6716 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))) 7607 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)) 7608 ) { 6717 7609 delete_cmd_entry(); 7610 } 6718 7611 find_command(name, &entry, DO_ERR, pathval()); 6719 7612 if (entry.cmdtype == CMDUNKNOWN) … … 6736 7629 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) { 6737 7630 for (cmdp = *pp; cmdp; cmdp = cmdp->next) { 6738 if (cmdp->cmdtype == CMDNORMAL || (6739 cmdp->cmdtype == CMDBUILTIN &&6740 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&6741 builtinloc > 06742 ) )7631 if (cmdp->cmdtype == CMDNORMAL 7632 || (cmdp->cmdtype == CMDBUILTIN 7633 && !IS_BUILTIN_REGULAR(cmdp->param.cmd) 7634 && builtinloc > 0) 7635 ) { 6743 7636 cmdp->rehash = 1; 7637 } 6744 7638 } 6745 7639 } … … 6752 7646 * Called with interrupts off. 6753 7647 */ 6754 static void 6755 changepath(const char *newval) 6756 { 6757 const char *old, *new; 7648 static void FAST_FUNC 7649 changepath(const char *new) 7650 { 7651 const char *old; 7652 int firstchange; 6758 7653 int idx; 6759 int firstchange;6760 7654 int idx_bltin; 6761 7655 6762 7656 old = pathval(); 6763 new = newval;6764 7657 firstchange = 9999; /* assume no change */ 6765 7658 idx = 0; … … 6769 7662 firstchange = idx; 6770 7663 if ((*old == '\0' && *new == ':') 6771 || (*old == ':' && *new == '\0')) 7664 || (*old == ':' && *new == '\0') 7665 ) { 6772 7666 firstchange++; 7667 } 6773 7668 old = new; /* ignore subsequent differences */ 6774 7669 } … … 6777 7672 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin")) 6778 7673 idx_bltin = idx; 6779 if (*new == ':') {7674 if (*new == ':') 6780 7675 idx++; 6781 }6782 new++,old++;7676 new++; 7677 old++; 6783 7678 } 6784 7679 if (builtinloc < 0 && idx_bltin >= 0) … … 6819 7714 #define TBEGIN 27 6820 7715 #define TEND 28 7716 typedef smallint token_id_t; 6821 7717 6822 7718 /* first char is indicating which tokens mark the end of a list */ … … 6855 7751 }; 6856 7752 6857 static const char *6858 tokname(int tok)6859 {6860 static char buf[16];6861 6862 //try this:6863 //if (tok < TSEMI) return tokname_array[tok] + 1;6864 //sprintf(buf, "\"%s\"", tokname_array[tok] + 1);6865 //return buf;6866 6867 if (tok >= TSEMI)6868 buf[0] = '"';6869 sprintf(buf + (tok >= TSEMI), "%s%c",6870 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));6871 return buf;6872 }6873 6874 7753 /* Wrapper around strcmp for qsort/bsearch/... */ 6875 7754 static int … … 6937 7816 int j = entry.u.index; 6938 7817 char *p; 6939 if (j == -1) {7818 if (j < 0) { 6940 7819 p = command; 6941 7820 } else { 6942 7821 do { 6943 p = pa dvance(&path, command);7822 p = path_advance(&path, command); 6944 7823 stunalloc(p); 6945 7824 } while (--j >= 0); … … 6981 7860 } 6982 7861 out: 6983 out str("\n", stdout);7862 out1str("\n"); 6984 7863 return 0; 6985 7864 } 6986 7865 6987 static int 6988 typecmd(int argc , char **argv)7866 static int FAST_FUNC 7867 typecmd(int argc UNUSED_PARAM, char **argv) 6989 7868 { 6990 7869 int i = 1; … … 6997 7876 verbose = 0; 6998 7877 } 6999 while ( i < argc) {7878 while (argv[i]) { 7000 7879 err |= describe_command(argv[i++], verbose); 7001 7880 } … … 7004 7883 7005 7884 #if ENABLE_ASH_CMDCMD 7006 static int 7007 commandcmd(int argc , char **argv)7885 static int FAST_FUNC 7886 commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 7008 7887 { 7009 7888 int c; … … 7022 7901 abort(); 7023 7902 #endif 7024 if (verify) 7903 /* Mimic bash: just "command -v" doesn't complain, it's a nop */ 7904 if (verify && (*argptr != NULL)) { 7025 7905 return describe_command(*argptr, verify - VERIFY_BRIEF); 7906 } 7026 7907 7027 7908 return 0; … … 7032 7913 /* ============ eval.c */ 7033 7914 7034 static int funcblocksize; 7035 static int funcstringsize; 7036 static void *funcblock; 7037 static char *funcstring; 7915 static int funcblocksize; /* size of structures in function */ 7916 static int funcstringsize; /* size of strings in node */ 7917 static void *funcblock; /* block to allocate function from */ 7918 static char *funcstring; /* block to allocate strings from */ 7038 7919 7039 7920 /* flags in argument to evaltree */ 7040 #define EV_EXIT 01/* exit after evaluating tree */7041 #define EV_TESTED 02/* exit status is checked; ignore -e flag */7921 #define EV_EXIT 01 /* exit after evaluating tree */ 7922 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */ 7042 7923 #define EV_BACKCMD 04 /* command executing within back quotes */ 7043 7924 7044 static const short nodesize[26] = { 7045 SHELL_ALIGN(sizeof(struct ncmd)), 7046 SHELL_ALIGN(sizeof(struct npipe)), 7047 SHELL_ALIGN(sizeof(struct nredir)), 7048 SHELL_ALIGN(sizeof(struct nredir)), 7049 SHELL_ALIGN(sizeof(struct nredir)), 7050 SHELL_ALIGN(sizeof(struct nbinary)), 7051 SHELL_ALIGN(sizeof(struct nbinary)), 7052 SHELL_ALIGN(sizeof(struct nbinary)), 7053 SHELL_ALIGN(sizeof(struct nif)), 7054 SHELL_ALIGN(sizeof(struct nbinary)), 7055 SHELL_ALIGN(sizeof(struct nbinary)), 7056 SHELL_ALIGN(sizeof(struct nfor)), 7057 SHELL_ALIGN(sizeof(struct ncase)), 7058 SHELL_ALIGN(sizeof(struct nclist)), 7059 SHELL_ALIGN(sizeof(struct narg)), 7060 SHELL_ALIGN(sizeof(struct narg)), 7061 SHELL_ALIGN(sizeof(struct nfile)), 7062 SHELL_ALIGN(sizeof(struct nfile)), 7063 SHELL_ALIGN(sizeof(struct nfile)), 7064 SHELL_ALIGN(sizeof(struct nfile)), 7065 SHELL_ALIGN(sizeof(struct nfile)), 7066 SHELL_ALIGN(sizeof(struct ndup)), 7067 SHELL_ALIGN(sizeof(struct ndup)), 7068 SHELL_ALIGN(sizeof(struct nhere)), 7069 SHELL_ALIGN(sizeof(struct nhere)), 7070 SHELL_ALIGN(sizeof(struct nnot)), 7925 static const uint8_t nodesize[N_NUMBER] = { 7926 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)), 7927 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)), 7928 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)), 7929 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)), 7930 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)), 7931 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)), 7932 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)), 7933 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)), 7934 [NIF ] = SHELL_ALIGN(sizeof(struct nif)), 7935 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)), 7936 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)), 7937 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)), 7938 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)), 7939 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)), 7940 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)), 7941 [NARG ] = SHELL_ALIGN(sizeof(struct narg)), 7942 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)), 7943 #if ENABLE_ASH_BASH_COMPAT 7944 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)), 7945 #endif 7946 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)), 7947 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)), 7948 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)), 7949 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)), 7950 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)), 7951 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)), 7952 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)), 7953 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)), 7954 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)), 7071 7955 }; 7072 7956 … … 7138 8022 break; 7139 8023 case NTO: 8024 #if ENABLE_ASH_BASH_COMPAT 8025 case NTO2: 8026 #endif 7140 8027 case NCLOBBER: 7141 8028 case NFROM: … … 7209 8096 case NPIPE: 7210 8097 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); 7211 new->npipe. backgnd = n->npipe.backgnd;8098 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; 7212 8099 break; 7213 8100 case NREDIR: … … 7251 8138 break; 7252 8139 case NTO: 8140 #if ENABLE_ASH_BASH_COMPAT 8141 case NTO2: 8142 #endif 7253 8143 case NCLOBBER: 7254 8144 case NFROM: … … 7316 8206 } 7317 8207 7318 static int evalskip; /* set if we are skipping commands */ 7319 /* reasons for skipping commands (see comment on breakcmd routine) */ 8208 /* Reasons for skipping commands (see comment on breakcmd routine) */ 7320 8209 #define SKIPBREAK (1 << 0) 7321 8210 #define SKIPCONT (1 << 1) … … 7323 8212 #define SKIPFILE (1 << 3) 7324 8213 #define SKIPEVAL (1 << 4) 8214 static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ 7325 8215 static int skipcount; /* number of levels to skip */ 7326 8216 static int funcnest; /* depth of function calls */ 7327 7328 /* forward decl way out to parsing code - dotrap needs it */ 8217 static int loopnest; /* current loop nesting level */ 8218 8219 /* Forward decl way out to parsing code - dotrap needs it */ 7329 8220 static int evalstring(char *s, int mask); 7330 8221 7331 /* 7332 * Called to execute a trap. Perhaps we should avoid entering new trap 7333 * handlers while we are executing a trap handler. 8222 /* Called to execute a trap. 8223 * Single callsite - at the end of evaltree(). 8224 * If we return non-zero, evaltree raises EXEXIT exception. 8225 * 8226 * Perhaps we should avoid entering new trap handlers 8227 * while we are executing a trap handler. [is it a TODO?] 7334 8228 */ 7335 8229 static int 7336 8230 dotrap(void) 7337 8231 { 7338 char *p; 7339 char *q; 7340 int i; 7341 int savestatus; 7342 int skip = 0; 8232 uint8_t *g; 8233 int sig; 8234 uint8_t savestatus; 7343 8235 7344 8236 savestatus = exitstatus; 7345 pending sig = 0;8237 pending_sig = 0; 7346 8238 xbarrier(); 7347 8239 7348 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) { 7349 if (!*q) 8240 TRACE(("dotrap entered\n")); 8241 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) { 8242 int want_exexit; 8243 char *t; 8244 8245 if (*g == 0) 7350 8246 continue; 7351 *q = '\0';7352 7353 p = trap[i + 1];7354 if ( !p)8247 t = trap[sig]; 8248 /* non-trapped SIGINT is handled separately by raise_interrupt, 8249 * don't upset it by resetting gotsig[SIGINT-1] */ 8250 if (sig == SIGINT && !t) 7355 8251 continue; 7356 skip = evalstring(p, SKIPEVAL); 8252 8253 TRACE(("sig %d is active, will run handler '%s'\n", sig, t)); 8254 *g = 0; 8255 if (!t) 8256 continue; 8257 want_exexit = evalstring(t, SKIPEVAL); 7357 8258 exitstatus = savestatus; 7358 if (skip) 7359 break; 7360 } 7361 7362 return skip; 8259 if (want_exexit) { 8260 TRACE(("dotrap returns %d\n", want_exexit)); 8261 return want_exexit; 8262 } 8263 } 8264 8265 TRACE(("dotrap returns 0\n")); 8266 return 0; 7363 8267 } 7364 8268 … … 7381 8285 evaltree(union node *n, int flags) 7382 8286 { 8287 struct jmploc *volatile savehandler = exception_handler; 8288 struct jmploc jmploc; 7383 8289 int checkexit = 0; 7384 8290 void (*evalfn)(union node *, int); 7385 unsigned isor;7386 8291 int status; 8292 int int_level; 8293 8294 SAVE_INT(int_level); 8295 7387 8296 if (n == NULL) { 7388 8297 TRACE(("evaltree(NULL) called\n")); 7389 goto out; 7390 } 7391 TRACE(("pid %d, evaltree(%p: %d, %d) called\n", 7392 getpid(), n, n->type, flags)); 8298 goto out1; 8299 } 8300 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags)); 8301 8302 exception_handler = &jmploc; 8303 { 8304 int err = setjmp(jmploc.loc); 8305 if (err) { 8306 /* if it was a signal, check for trap handlers */ 8307 if (exception_type == EXSIG) { 8308 TRACE(("exception %d (EXSIG) in evaltree, err=%d\n", 8309 exception_type, err)); 8310 goto out; 8311 } 8312 /* continue on the way out */ 8313 TRACE(("exception %d in evaltree, propagating err=%d\n", 8314 exception_type, err)); 8315 exception_handler = savehandler; 8316 longjmp(exception_handler->loc, err); 8317 } 8318 } 8319 7393 8320 switch (n->type) { 7394 8321 default: 7395 8322 #if DEBUG 7396 8323 out1fmt("Node type = %d\n", n->type); 7397 fflush (stdout);8324 fflush_all(); 7398 8325 break; 7399 8326 #endif … … 7409 8336 status = exitstatus; 7410 8337 } 7411 popredir( 0);8338 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */); 7412 8339 goto setstatus; 7413 8340 case NCMD: … … 7436 8363 case NAND: 7437 8364 case NOR: 7438 case NSEMI: 8365 case NSEMI: { 8366 7439 8367 #if NAND + 1 != NOR 7440 8368 #error NAND + 1 != NOR … … 7443 8371 #error NOR + 1 != NSEMI 7444 8372 #endif 7445 isor = n->type - NAND;8373 unsigned is_or = n->type - NAND; 7446 8374 evaltree( 7447 8375 n->nbinary.ch1, 7448 (flags | ((is or >> 1) - 1)) & EV_TESTED8376 (flags | ((is_or >> 1) - 1)) & EV_TESTED 7449 8377 ); 7450 if (!exitstatus == is or)8378 if (!exitstatus == is_or) 7451 8379 break; 7452 8380 if (!evalskip) { … … 7459 8387 } 7460 8388 break; 8389 } 7461 8390 case NIF: 7462 8391 evaltree(n->nif.test, EV_TESTED); … … 7466 8395 n = n->nif.ifpart; 7467 8396 goto evaln; 7468 } else if (n->nif.elsepart) { 8397 } 8398 if (n->nif.elsepart) { 7469 8399 n = n->nif.elsepart; 7470 8400 goto evaln; … … 7479 8409 break; 7480 8410 } 8411 7481 8412 out: 7482 if ((checkexit & exitstatus)) 8413 exception_handler = savehandler; 8414 8415 out1: 8416 /* Order of checks below is important: 8417 * signal handlers trigger before exit caused by "set -e". 8418 */ 8419 if (pending_sig && dotrap()) 8420 goto exexit; 8421 if (checkexit & exitstatus) 7483 8422 evalskip |= SKIPEVAL; 7484 else if (pendingsig && dotrap())7485 goto exexit;7486 8423 7487 8424 if (flags & EV_EXIT) { … … 7489 8426 raise_exception(EXEXIT); 7490 8427 } 8428 8429 RESTORE_INT(int_level); 8430 TRACE(("leaving evaltree (no interrupts)\n")); 7491 8431 } 7492 8432 … … 7495 8435 #endif 7496 8436 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__)); 7497 7498 static int loopnest; /* current loop nesting level */7499 8437 7500 8438 static void … … 7543 8481 7544 8482 setstackmark(&smark); 8483 arglist.list = NULL; 7545 8484 arglist.lastp = &arglist.list; 7546 8485 for (argp = n->nfor.args; argp; argp = argp->narg.next) { … … 7582 8521 7583 8522 setstackmark(&smark); 8523 arglist.list = NULL; 7584 8524 arglist.lastp = &arglist.list; 7585 8525 expandarg(n->ncase.expr, &arglist, EXP_TILDE); … … 7610 8550 7611 8551 expredir(n->nredir.redirect); 7612 if (!backgnd && flags & EV_EXIT && !trap[0])8552 if (!backgnd && (flags & EV_EXIT) && !may_have_traps) 7613 8553 goto nofork; 7614 8554 INT_OFF; 7615 jp = makejob( n,1);8555 jp = makejob(/*n,*/ 1); 7616 8556 if (forkshell(jp, n, backgnd) == 0) { 8557 /* child */ 7617 8558 INT_ON; 7618 8559 flags |= EV_EXIT; 7619 8560 if (backgnd) 7620 flags &= ~EV_TESTED;8561 flags &= ~EV_TESTED; 7621 8562 nofork: 7622 8563 redirect(n->nredir.redirect, 0); … … 7625 8566 } 7626 8567 status = 0; 7627 if (! 8568 if (!backgnd) 7628 8569 status = waitforjob(jp); 7629 8570 exitstatus = status; … … 7643 8584 struct arglist fn; 7644 8585 7645 memset(&fn, 0, sizeof(fn));8586 fn.list = NULL; 7646 8587 fn.lastp = &fn.list; 7647 8588 switch (redir->type) { … … 7649 8590 case NFROM: 7650 8591 case NTO: 8592 #if ENABLE_ASH_BASH_COMPAT 8593 case NTO2: 8594 #endif 7651 8595 case NCLOBBER: 7652 8596 case NAPPEND: 7653 8597 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 8598 #if ENABLE_ASH_BASH_COMPAT 8599 store_expfname: 8600 #endif 7654 8601 redir->nfile.expfname = fn.list->text; 7655 8602 break; 7656 8603 case NFROMFD: 7657 case NTOFD: 8604 case NTOFD: /* >& */ 7658 8605 if (redir->ndup.vname) { 7659 8606 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); 7660 8607 if (fn.list == NULL) 7661 8608 ash_msg_and_raise_error("redir error"); 8609 #if ENABLE_ASH_BASH_COMPAT 8610 //FIXME: we used expandarg with different args! 8611 if (!isdigit_str9(fn.list->text)) { 8612 /* >&file, not >&fd */ 8613 if (redir->nfile.fd != 1) /* 123>&file - BAD */ 8614 ash_msg_and_raise_error("redir error"); 8615 redir->type = NTO2; 8616 goto store_expfname; 8617 } 8618 #endif 7662 8619 fixredir(redir, fn.list->text, 1); 7663 8620 } … … 7688 8645 flags |= EV_EXIT; 7689 8646 INT_OFF; 7690 jp = makejob( n,pipelen);8647 jp = makejob(/*n,*/ pipelen); 7691 8648 prevfd = -1; 7692 8649 for (lp = n->npipe.cmdlist; lp; lp = lp->next) { … … 7699 8656 } 7700 8657 } 7701 if (forkshell(jp, lp->n, n->npipe. backgnd) == 0) {8658 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { 7702 8659 INT_ON; 7703 8660 if (pip[1] >= 0) { … … 7718 8675 close(prevfd); 7719 8676 prevfd = pip[0]; 7720 close(pip[1]); 7721 } 7722 if (n->npipe.backgnd == 0) { 8677 /* Don't want to trigger debugging */ 8678 if (pip[1] != -1) 8679 close(pip[1]); 8680 } 8681 if (n->npipe.pipe_backgnd == 0) { 7723 8682 exitstatus = waitforjob(jp); 7724 8683 TRACE(("evalpipe: job done exit status %d\n", exitstatus)); … … 7733 8692 setinteractive(int on) 7734 8693 { 7735 static int is_interactive;8694 static smallint is_interactive; 7736 8695 7737 8696 if (++on == is_interactive) … … 7747 8706 7748 8707 if (!did_banner) { 7749 out1fmt( 7750 "\n\n" 7751 "%s built-in shell (ash)\n" 8708 /* note: ash and hush share this string */ 8709 out1fmt("\n\n%s %s\n" 7752 8710 "Enter 'help' for a list of built-in commands." 7753 8711 "\n\n", 7754 bb_banner); 8712 bb_banner, 8713 "built-in shell (ash)" 8714 ); 7755 8715 did_banner = 1; 7756 8716 } … … 7758 8718 #endif 7759 8719 } 7760 7761 #if ENABLE_FEATURE_EDITING_VI7762 #define setvimode(on) do { \7763 if (on) line_input_state->flags |= VI_MODE; \7764 else line_input_state->flags &= ~VI_MODE; \7765 } while (0)7766 #else7767 #define setvimode(on) viflag = 0 /* forcibly keep the option off */7768 #endif7769 8720 7770 8721 static void … … 7776 8727 setinteractive(iflag); 7777 8728 setjobctl(mflag); 7778 setvimode(viflag); 8729 #if ENABLE_FEATURE_EDITING_VI 8730 if (viflag) 8731 line_input_state->flags |= VI_MODE; 8732 else 8733 line_input_state->flags &= ~VI_MODE; 8734 #else 8735 viflag = 0; /* forcibly keep the option off */ 8736 #endif 7779 8737 } 7780 8738 … … 7794 8752 localvars = lvp->next; 7795 8753 vp = lvp->vp; 7796 TRACE(("poplocalvar %s ", vp ? vp->text : "-"));8754 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-")); 7797 8755 if (vp == NULL) { /* $- saved */ 7798 8756 memcpy(optlist, lvp->text, sizeof(optlist)); … … 7800 8758 optschanged(); 7801 8759 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { 7802 unsetvar(vp-> text);8760 unsetvar(vp->var_text); 7803 8761 } else { 7804 if (vp-> func)7805 (*vp->func)(strchrnul(lvp->text, '=') + 1);8762 if (vp->var_func) 8763 vp->var_func(var_end(lvp->text)); 7806 8764 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) 7807 free((char*)vp-> text);8765 free((char*)vp->var_text); 7808 8766 vp->flags = lvp->flags; 7809 vp-> text = lvp->text;8767 vp->var_text = lvp->text; 7810 8768 } 7811 8769 free(lvp); … … 7832 8790 exception_handler = &jmploc; 7833 8791 localvars = NULL; 7834 shellparam.malloc = 0;8792 shellparam.malloced = 0; 7835 8793 func->count++; 7836 8794 funcnest++; … … 7843 8801 #endif 7844 8802 evaltree(&func->n, flags & EV_TESTED); 7845 funcdone:8803 funcdone: 7846 8804 INT_OFF; 7847 8805 funcnest--; … … 7906 8864 7907 8865 INT_OFF; 7908 lvp = ck malloc(sizeof(struct localvar));8866 lvp = ckzalloc(sizeof(struct localvar)); 7909 8867 if (LONE_DASH(name)) { 7910 8868 char *p; … … 7926 8884 lvp->flags = VUNSET; 7927 8885 } else { 7928 lvp->text = vp-> text;8886 lvp->text = vp->var_text; 7929 8887 lvp->flags = vp->flags; 7930 8888 vp->flags |= VSTRFIXED|VTEXTFIXED; … … 7942 8900 * The "local" command. 7943 8901 */ 7944 static int 7945 localcmd(int argc , char **argv)8902 static int FAST_FUNC 8903 localcmd(int argc UNUSED_PARAM, char **argv) 7946 8904 { 7947 8905 char *name; … … 7954 8912 } 7955 8913 7956 static int 7957 falsecmd(int argc , char **argv)8914 static int FAST_FUNC 8915 falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 7958 8916 { 7959 8917 return 1; 7960 8918 } 7961 8919 7962 static int 7963 truecmd(int argc , char **argv)8920 static int FAST_FUNC 8921 truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 7964 8922 { 7965 8923 return 0; 7966 8924 } 7967 8925 7968 static int 7969 execcmd(int argc , char **argv)7970 { 7971 if (arg c > 1) {8926 static int FAST_FUNC 8927 execcmd(int argc UNUSED_PARAM, char **argv) 8928 { 8929 if (argv[1]) { 7972 8930 iflag = 0; /* exit on error */ 7973 8931 mflag = 0; … … 7981 8939 * The return command. 7982 8940 */ 7983 static int 7984 returncmd(int argc , char **argv)8941 static int FAST_FUNC 8942 returncmd(int argc UNUSED_PARAM, char **argv) 7985 8943 { 7986 8944 /* … … 7993 8951 7994 8952 /* Forward declarations for builtintab[] */ 7995 static int breakcmd(int, char **); 7996 static int dotcmd(int, char **); 7997 static int evalcmd(int, char **); 7998 #if ENABLE_ASH_BUILTIN_ECHO 7999 static int echocmd(int, char **); 8000 #endif 8001 #if ENABLE_ASH_BUILTIN_TEST 8002 static int testcmd(int, char **); 8003 #endif 8004 static int exitcmd(int, char **); 8005 static int exportcmd(int, char **); 8953 static int breakcmd(int, char **) FAST_FUNC; 8954 static int dotcmd(int, char **) FAST_FUNC; 8955 static int evalcmd(int, char **) FAST_FUNC; 8956 static int exitcmd(int, char **) FAST_FUNC; 8957 static int exportcmd(int, char **) FAST_FUNC; 8006 8958 #if ENABLE_ASH_GETOPTS 8007 static int getoptscmd(int, char **) ;8959 static int getoptscmd(int, char **) FAST_FUNC; 8008 8960 #endif 8009 8961 #if !ENABLE_FEATURE_SH_EXTRA_QUIET 8010 static int helpcmd(int argc, char **argv);8011 #endif 8012 #if ENABLE_ ASH_MATH_SUPPORT8013 static int letcmd(int, char **) ;8014 #endif 8015 static int readcmd(int, char **) ;8016 static int setcmd(int, char **) ;8017 static int shiftcmd(int, char **) ;8018 static int timescmd(int, char **) ;8019 static int trapcmd(int, char **) ;8020 static int umaskcmd(int, char **) ;8021 static int unsetcmd(int, char **) ;8022 static int ulimitcmd(int, char **) ;8962 static int helpcmd(int, char **) FAST_FUNC; 8963 #endif 8964 #if ENABLE_SH_MATH_SUPPORT 8965 static int letcmd(int, char **) FAST_FUNC; 8966 #endif 8967 static int readcmd(int, char **) FAST_FUNC; 8968 static int setcmd(int, char **) FAST_FUNC; 8969 static int shiftcmd(int, char **) FAST_FUNC; 8970 static int timescmd(int, char **) FAST_FUNC; 8971 static int trapcmd(int, char **) FAST_FUNC; 8972 static int umaskcmd(int, char **) FAST_FUNC; 8973 static int unsetcmd(int, char **) FAST_FUNC; 8974 static int ulimitcmd(int, char **) FAST_FUNC; 8023 8975 8024 8976 #define BUILTIN_NOSPEC "0" … … 8031 8983 #define BUILTIN_SPEC_REG_ASSG "7" 8032 8984 8033 /* make sure to keep these in proper order since it is searched via bsearch() */ 8985 /* Stubs for calling non-FAST_FUNC's */ 8986 #if ENABLE_ASH_BUILTIN_ECHO 8987 static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); } 8988 #endif 8989 #if ENABLE_ASH_BUILTIN_PRINTF 8990 static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); } 8991 #endif 8992 #if ENABLE_ASH_BUILTIN_TEST 8993 static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); } 8994 #endif 8995 8996 /* Keep these in proper order since it is searched via bsearch() */ 8034 8997 static const struct builtincmd builtintab[] = { 8035 { BUILTIN_SPEC_REG "." , dotcmd},8036 { BUILTIN_SPEC_REG ":" , truecmd},8998 { BUILTIN_SPEC_REG "." , dotcmd }, 8999 { BUILTIN_SPEC_REG ":" , truecmd }, 8037 9000 #if ENABLE_ASH_BUILTIN_TEST 8038 { BUILTIN_REGULAR "[", testcmd }, 8039 { BUILTIN_REGULAR "[[", testcmd }, 9001 { BUILTIN_REGULAR "[" , testcmd }, 9002 #if ENABLE_ASH_BASH_COMPAT 9003 { BUILTIN_REGULAR "[[" , testcmd }, 9004 #endif 8040 9005 #endif 8041 9006 #if ENABLE_ASH_ALIAS 8042 { BUILTIN_REG_ASSG "alias" , aliascmd},9007 { BUILTIN_REG_ASSG "alias" , aliascmd }, 8043 9008 #endif 8044 9009 #if JOBS 8045 { BUILTIN_REGULAR "bg" , fg_bgcmd},8046 #endif 8047 { BUILTIN_SPEC_REG "break" , breakcmd},8048 { BUILTIN_REGULAR "cd" , cdcmd},8049 { BUILTIN_NOSPEC "chdir" , cdcmd},9010 { BUILTIN_REGULAR "bg" , fg_bgcmd }, 9011 #endif 9012 { BUILTIN_SPEC_REG "break" , breakcmd }, 9013 { BUILTIN_REGULAR "cd" , cdcmd }, 9014 { BUILTIN_NOSPEC "chdir" , cdcmd }, 8050 9015 #if ENABLE_ASH_CMDCMD 8051 { BUILTIN_REGULAR "command" , commandcmd },8052 #endif 8053 { BUILTIN_SPEC_REG "continue", breakcmd },9016 { BUILTIN_REGULAR "command" , commandcmd }, 9017 #endif 9018 { BUILTIN_SPEC_REG "continue", breakcmd }, 8054 9019 #if ENABLE_ASH_BUILTIN_ECHO 8055 { BUILTIN_REGULAR "echo" , echocmd},8056 #endif 8057 { BUILTIN_SPEC_REG "eval" , evalcmd},8058 { BUILTIN_SPEC_REG "exec" , execcmd},8059 { BUILTIN_SPEC_REG "exit" , exitcmd},8060 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd},8061 { BUILTIN_REGULAR "false" , falsecmd},9020 { BUILTIN_REGULAR "echo" , echocmd }, 9021 #endif 9022 { BUILTIN_SPEC_REG "eval" , evalcmd }, 9023 { BUILTIN_SPEC_REG "exec" , execcmd }, 9024 { BUILTIN_SPEC_REG "exit" , exitcmd }, 9025 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd }, 9026 { BUILTIN_REGULAR "false" , falsecmd }, 8062 9027 #if JOBS 8063 { BUILTIN_REGULAR "fg" , fg_bgcmd},9028 { BUILTIN_REGULAR "fg" , fg_bgcmd }, 8064 9029 #endif 8065 9030 #if ENABLE_ASH_GETOPTS 8066 { BUILTIN_REGULAR "getopts" , getoptscmd },8067 #endif 8068 { BUILTIN_NOSPEC "hash" , hashcmd},9031 { BUILTIN_REGULAR "getopts" , getoptscmd }, 9032 #endif 9033 { BUILTIN_NOSPEC "hash" , hashcmd }, 8069 9034 #if !ENABLE_FEATURE_SH_EXTRA_QUIET 8070 { BUILTIN_NOSPEC "help" , helpcmd},9035 { BUILTIN_NOSPEC "help" , helpcmd }, 8071 9036 #endif 8072 9037 #if JOBS 8073 { BUILTIN_REGULAR "jobs", jobscmd }, 8074 { BUILTIN_REGULAR "kill", killcmd }, 8075 #endif 8076 #if ENABLE_ASH_MATH_SUPPORT 8077 { BUILTIN_NOSPEC "let", letcmd }, 8078 #endif 8079 { BUILTIN_ASSIGN "local", localcmd }, 8080 { BUILTIN_NOSPEC "pwd", pwdcmd }, 8081 { BUILTIN_REGULAR "read", readcmd }, 8082 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd }, 8083 { BUILTIN_SPEC_REG "return", returncmd }, 8084 { BUILTIN_SPEC_REG "set", setcmd }, 8085 { BUILTIN_SPEC_REG "shift", shiftcmd }, 8086 { BUILTIN_SPEC_REG "source", dotcmd }, 9038 { BUILTIN_REGULAR "jobs" , jobscmd }, 9039 { BUILTIN_REGULAR "kill" , killcmd }, 9040 #endif 9041 #if ENABLE_SH_MATH_SUPPORT 9042 { BUILTIN_NOSPEC "let" , letcmd }, 9043 #endif 9044 { BUILTIN_ASSIGN "local" , localcmd }, 9045 #if ENABLE_ASH_BUILTIN_PRINTF 9046 { BUILTIN_REGULAR "printf" , printfcmd }, 9047 #endif 9048 { BUILTIN_NOSPEC "pwd" , pwdcmd }, 9049 { BUILTIN_REGULAR "read" , readcmd }, 9050 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd }, 9051 { BUILTIN_SPEC_REG "return" , returncmd }, 9052 { BUILTIN_SPEC_REG "set" , setcmd }, 9053 { BUILTIN_SPEC_REG "shift" , shiftcmd }, 9054 #if ENABLE_ASH_BASH_COMPAT 9055 { BUILTIN_SPEC_REG "source" , dotcmd }, 9056 #endif 8087 9057 #if ENABLE_ASH_BUILTIN_TEST 8088 { BUILTIN_REGULAR "test", testcmd},8089 #endif 8090 { BUILTIN_SPEC_REG "times" , timescmd},8091 { BUILTIN_SPEC_REG "trap" , trapcmd},8092 { BUILTIN_REGULAR "true" , truecmd},8093 { BUILTIN_NOSPEC "type" , typecmd},8094 { BUILTIN_NOSPEC "ulimit" , ulimitcmd},8095 { BUILTIN_REGULAR "umask" , umaskcmd},9058 { BUILTIN_REGULAR "test" , testcmd }, 9059 #endif 9060 { BUILTIN_SPEC_REG "times" , timescmd }, 9061 { BUILTIN_SPEC_REG "trap" , trapcmd }, 9062 { BUILTIN_REGULAR "true" , truecmd }, 9063 { BUILTIN_NOSPEC "type" , typecmd }, 9064 { BUILTIN_NOSPEC "ulimit" , ulimitcmd }, 9065 { BUILTIN_REGULAR "umask" , umaskcmd }, 8096 9066 #if ENABLE_ASH_ALIAS 8097 { BUILTIN_REGULAR "unalias" , unaliascmd },8098 #endif 8099 { BUILTIN_SPEC_REG "unset" , unsetcmd},8100 { BUILTIN_REGULAR "wait" , waitcmd},9067 { BUILTIN_REGULAR "unalias" , unaliascmd }, 9068 #endif 9069 { BUILTIN_SPEC_REG "unset" , unsetcmd }, 9070 { BUILTIN_REGULAR "wait" , waitcmd }, 8101 9071 }; 8102 9072 8103 8104 #define COMMANDCMD (builtintab + 5 + \ 8105 2 * ENABLE_ASH_BUILTIN_TEST + \ 8106 ENABLE_ASH_ALIAS + \ 8107 ENABLE_ASH_JOB_CONTROL) 8108 #define EXECCMD (builtintab + 7 + \ 8109 2 * ENABLE_ASH_BUILTIN_TEST + \ 8110 ENABLE_ASH_ALIAS + \ 8111 ENABLE_ASH_JOB_CONTROL + \ 8112 ENABLE_ASH_CMDCMD + \ 8113 ENABLE_ASH_BUILTIN_ECHO) 9073 /* Should match the above table! */ 9074 #define COMMANDCMD (builtintab + \ 9075 2 + \ 9076 1 * ENABLE_ASH_BUILTIN_TEST + \ 9077 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \ 9078 1 * ENABLE_ASH_ALIAS + \ 9079 1 * ENABLE_ASH_JOB_CONTROL + \ 9080 3) 9081 #define EXECCMD (builtintab + \ 9082 2 + \ 9083 1 * ENABLE_ASH_BUILTIN_TEST + \ 9084 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \ 9085 1 * ENABLE_ASH_ALIAS + \ 9086 1 * ENABLE_ASH_JOB_CONTROL + \ 9087 3 + \ 9088 1 * ENABLE_ASH_CMDCMD + \ 9089 1 + \ 9090 ENABLE_ASH_BUILTIN_ECHO + \ 9091 1) 8114 9092 8115 9093 /* … … 8131 9109 * Execute a simple command. 8132 9110 */ 8133 static int back_exitstatus; /* exit status of backquoted command */8134 9111 static int 8135 9112 isassignment(const char *p) … … 8140 9117 return *q == '='; 8141 9118 } 8142 static int 8143 bltincmd(int argc , char **argv)9119 static int FAST_FUNC 9120 bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 8144 9121 { 8145 9122 /* Preserve exitstatus of a previous possible redirection … … 8150 9127 evalcommand(union node *cmd, int flags) 8151 9128 { 8152 static const struct builtincmd bltin = {8153 "\0\0", bltincmd 9129 static const struct builtincmd null_bltin = { 9130 "\0\0", bltincmd /* why three NULs? */ 8154 9131 }; 8155 9132 struct stackmark smark; … … 8165 9142 const char *path; 8166 9143 int spclbltin; 8167 int cmd_is_exec;8168 9144 int status; 8169 9145 char **nargv; 8170 9146 struct builtincmd *bcmd; 8171 int pseudovarflag = 0; 9147 smallint cmd_is_exec; 9148 smallint pseudovarflag = 0; 8172 9149 8173 9150 /* First expand the arguments. */ … … 8177 9154 8178 9155 cmdentry.cmdtype = CMDBUILTIN; 8179 cmdentry.u.cmd = & bltin;9156 cmdentry.u.cmd = &null_bltin; 8180 9157 varlist.lastp = &varlist.list; 8181 9158 *varlist.lastp = NULL; … … 8217 9194 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2); 8218 9195 8219 path = vpath. text;9196 path = vpath.var_text; 8220 9197 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { 8221 9198 struct strlist **spp; … … 8230 9207 */ 8231 9208 p = (*spp)->text; 8232 if (var equal(p, path))9209 if (varcmp(p, path) == 0) 8233 9210 path = p; 8234 9211 } … … 8237 9214 if (xflag) { 8238 9215 int n; 8239 const char *p = " %s"; 8240 8241 p++; 8242 dprintf(preverrout_fd, p, expandstr(ps4val())); 8243 9216 const char *p = " %s" + 1; 9217 9218 fdprintf(preverrout_fd, p, expandstr(ps4val())); 8244 9219 sp = varlist.list; 8245 9220 for (n = 0; n < 2; n++) { 8246 9221 while (sp) { 8247 dprintf(preverrout_fd, p, sp->text);9222 fdprintf(preverrout_fd, p, sp->text); 8248 9223 sp = sp->next; 8249 if (*p == '%') { 8250 p--; 8251 } 9224 p = " %s"; 8252 9225 } 8253 9226 sp = arglist.list; 8254 9227 } 8255 full_write(preverrout_fd, "\n", 1);9228 safe_write(preverrout_fd, "\n", 1); 8256 9229 } 8257 9230 … … 8269 9242 find_command(argv[0], &cmdentry, cmd_flag, path); 8270 9243 if (cmdentry.cmdtype == CMDUNKNOWN) { 9244 flush_stdout_stderr(); 8271 9245 status = 127; 8272 flush_stderr();8273 9246 goto bail; 8274 9247 } … … 8280 9253 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd); 8281 9254 if (cmdentry.u.cmd == EXECCMD) 8282 cmd_is_exec ++;9255 cmd_is_exec = 1; 8283 9256 #if ENABLE_ASH_CMDCMD 8284 9257 if (cmdentry.u.cmd == COMMANDCMD) { … … 8307 9280 /* Execute the command. */ 8308 9281 switch (cmdentry.cmdtype) { 8309 default: 8310 /* Fork off a child process if necessary. */ 8311 if (!(flags & EV_EXIT) || trap[0]) { 9282 default: { 9283 9284 #if ENABLE_FEATURE_SH_NOFORK 9285 /* (1) BUG: if variables are set, we need to fork, or save/restore them 9286 * around run_nofork_applet() call. 9287 * (2) Should this check also be done in forkshell()? 9288 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...) 9289 */ 9290 /* find_command() encodes applet_no as (-2 - applet_no) */ 9291 int applet_no = (- cmdentry.u.index - 2); 9292 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) { 9293 listsetvar(varlist.list, VEXPORT|VSTACK); 9294 /* run <applet>_main() */ 9295 exitstatus = run_nofork_applet(applet_no, argv); 9296 break; 9297 } 9298 #endif 9299 /* Can we avoid forking off? For example, very last command 9300 * in a script or a subshell does not need forking, 9301 * we can just exec it. 9302 */ 9303 if (!(flags & EV_EXIT) || may_have_traps) { 9304 /* No, forking off a child is necessary */ 8312 9305 INT_OFF; 8313 jp = makejob( cmd,1);9306 jp = makejob(/*cmd,*/ 1); 8314 9307 if (forkshell(jp, cmd, FORK_FG) != 0) { 9308 /* parent */ 8315 9309 exitstatus = waitforjob(jp); 8316 9310 INT_ON; 9311 TRACE(("forked child exited with %d\n", exitstatus)); 8317 9312 break; 8318 9313 } 9314 /* child */ 8319 9315 FORCE_INT_ON; 9316 /* fall through to exec'ing external program */ 8320 9317 } 8321 9318 listsetvar(varlist.list, VEXPORT|VSTACK); 8322 9319 shellexec(argv, path, cmdentry.u.index); 8323 9320 /* NOTREACHED */ 8324 9321 } /* default */ 8325 9322 case CMDBUILTIN: 8326 9323 cmdenviron = varlist.list; … … 8335 9332 listsetvar(list, i); 8336 9333 } 9334 /* Tight loop with builtins only: 9335 * "while kill -0 $child; do true; done" 9336 * will never exit even if $child died, unless we do this 9337 * to reap the zombie and make kill detect that it's gone: */ 9338 dowait(DOWAIT_NONBLOCK, NULL); 9339 8337 9340 if (evalbltin(cmdentry.u.cmd, argc, argv)) { 8338 9341 int exit_status; 8339 int i, j; 8340 8341 i = exception; 9342 int i = exception_type; 8342 9343 if (i == EXEXIT) 8343 9344 goto raise; 8344 8345 9345 exit_status = 2; 8346 j = 0;8347 9346 if (i == EXINT) 8348 j =SIGINT;9347 exit_status = 128 + SIGINT; 8349 9348 if (i == EXSIG) 8350 j = pendingsig; 8351 if (j) 8352 exit_status = j + 128; 9349 exit_status = 128 + pending_sig; 8353 9350 exitstatus = exit_status; 8354 8355 9351 if (i == EXINT || spclbltin > 0) { 8356 9352 raise: … … 8363 9359 case CMDFUNCTION: 8364 9360 listsetvar(varlist.list, 0); 9361 /* See above for the rationale */ 9362 dowait(DOWAIT_NONBLOCK, NULL); 8365 9363 if (evalfun(cmdentry.u.func, argc, argv, flags)) 8366 9364 goto raise; 8367 9365 break; 8368 } 9366 9367 } /* switch */ 8369 9368 8370 9369 out: 8371 popredir( cmd_is_exec);8372 if (lastarg) 9370 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec); 9371 if (lastarg) { 8373 9372 /* dsl: I think this is intended to be used to support 8374 9373 * '_' in 'vi' command mode during line editing... … … 8376 9375 */ 8377 9376 setvar("_", lastarg, 0); 9377 } 8378 9378 popstackmark(&smark); 8379 9379 } … … 8402 9402 clearerr(stdout); 8403 9403 commandname = savecmdname; 8404 exsig = 0;8405 9404 exception_handler = savehandler; 8406 9405 … … 8411 9410 goodname(const char *p) 8412 9411 { 8413 return !*endofname(p);9412 return endofname(p)[0] == '\0'; 8414 9413 } 8415 9414 … … 8447 9446 * in the standard shell so we don't make it one here. 8448 9447 */ 8449 static int 8450 breakcmd(int argc , char **argv)8451 { 8452 int n = arg c > 1? number(argv[1]) : 1;9448 static int FAST_FUNC 9449 breakcmd(int argc UNUSED_PARAM, char **argv) 9450 { 9451 int n = argv[1] ? number(argv[1]) : 1; 8453 9452 8454 9453 if (n <= 0) 8455 ash_msg_and_raise_error( illnum, argv[1]);9454 ash_msg_and_raise_error(msg_illnum, argv[1]); 8456 9455 if (n > loopnest) 8457 9456 n = loopnest; … … 8469 9468 */ 8470 9469 8471 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */8472 8473 9470 enum { 8474 9471 INPUT_PUSH_FILE = 1, … … 8476 9473 }; 8477 9474 8478 /* 8479 * NEOF is returned by parsecmd when it encounters an end of file. It 8480 * must be distinct from NULL, so we use the address of a variable that 8481 * happens to be handy. 8482 */ 8483 static int plinno = 1; /* input line number */ 8484 /* number of characters left in input buffer */ 8485 static int parsenleft; /* copy of parsefile->nleft */ 8486 static int parselleft; /* copy of parsefile->lleft */ 8487 /* next character in input buffer */ 8488 static char *parsenextc; /* copy of parsefile->nextc */ 8489 8490 static int checkkwd; 9475 static smallint checkkwd; 8491 9476 /* values of checkkwd variable */ 8492 9477 #define CHKALIAS 0x1 … … 8494 9479 #define CHKNL 0x4 8495 9480 9481 /* 9482 * Push a string back onto the input at this current parsefile level. 9483 * We handle aliases this way. 9484 */ 9485 #if !ENABLE_ASH_ALIAS 9486 #define pushstring(s, ap) pushstring(s) 9487 #endif 9488 static void 9489 pushstring(char *s, struct alias *ap) 9490 { 9491 struct strpush *sp; 9492 int len; 9493 9494 len = strlen(s); 9495 INT_OFF; 9496 if (g_parsefile->strpush) { 9497 sp = ckzalloc(sizeof(*sp)); 9498 sp->prev = g_parsefile->strpush; 9499 } else { 9500 sp = &(g_parsefile->basestrpush); 9501 } 9502 g_parsefile->strpush = sp; 9503 sp->prev_string = g_parsefile->next_to_pgetc; 9504 sp->prev_left_in_line = g_parsefile->left_in_line; 9505 #if ENABLE_ASH_ALIAS 9506 sp->ap = ap; 9507 if (ap) { 9508 ap->flag |= ALIASINUSE; 9509 sp->string = s; 9510 } 9511 #endif 9512 g_parsefile->next_to_pgetc = s; 9513 g_parsefile->left_in_line = len; 9514 INT_ON; 9515 } 9516 8496 9517 static void 8497 9518 popstring(void) 8498 9519 { 8499 struct strpush *sp = parsefile->strpush;9520 struct strpush *sp = g_parsefile->strpush; 8500 9521 8501 9522 INT_OFF; 8502 9523 #if ENABLE_ASH_ALIAS 8503 9524 if (sp->ap) { 8504 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') { 9525 if (g_parsefile->next_to_pgetc[-1] == ' ' 9526 || g_parsefile->next_to_pgetc[-1] == '\t' 9527 ) { 8505 9528 checkkwd |= CHKALIAS; 8506 9529 } … … 8514 9537 } 8515 9538 #endif 8516 parsenextc = sp->prevstring; 8517 parsenleft = sp->prevnleft; 8518 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ 8519 parsefile->strpush = sp->prev; 8520 if (sp != &(parsefile->basestrpush)) 9539 g_parsefile->next_to_pgetc = sp->prev_string; 9540 g_parsefile->left_in_line = sp->prev_left_in_line; 9541 g_parsefile->strpush = sp->prev; 9542 if (sp != &(g_parsefile->basestrpush)) 8521 9543 free(sp); 8522 9544 INT_ON; 8523 9545 } 8524 9546 9547 //FIXME: BASH_COMPAT with "...&" does TWO pungetc(): 9548 //it peeks whether it is &>, and then pushes back both chars. 9549 //This function needs to save last *next_to_pgetc to buf[0] 9550 //to make two pungetc() reliable. Currently, 9551 // pgetc (out of buf: does preadfd), pgetc, pungetc, pungetc won't work... 8525 9552 static int 8526 9553 preadfd(void) 8527 9554 { 8528 9555 int nr; 8529 char *buf = parsefile->buf; 8530 parsenextc = buf; 8531 9556 char *buf = g_parsefile->buf; 9557 9558 g_parsefile->next_to_pgetc = buf; 9559 #if ENABLE_FEATURE_EDITING 8532 9560 retry: 8533 #if ENABLE_FEATURE_EDITING 8534 if (!iflag || parsefile->fd) 8535 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); 9561 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) 9562 nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); 8536 9563 else { 8537 9564 #if ENABLE_FEATURE_TAB_COMPLETION 8538 9565 line_input_state->path_lookup = pathval(); 8539 9566 #endif 8540 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);9567 nr = read_line_input(cmdedit_prompt, buf, IBUFSIZ, line_input_state); 8541 9568 if (nr == 0) { 8542 9569 /* Ctrl+C pressed */ … … 8550 9577 } 8551 9578 if (nr < 0 && errno == 0) { 8552 /* Ctrl+D pres end */9579 /* Ctrl+D pressed */ 8553 9580 nr = 0; 8554 9581 } 8555 9582 } 8556 9583 #else 8557 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); 8558 #endif 8559 9584 nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); 9585 #endif 9586 9587 #if 0 9588 /* nonblock_safe_read() handles this problem */ 8560 9589 if (nr < 0) { 8561 9590 if (parsefile->fd == 0 && errno == EWOULDBLOCK) { 8562 9591 int flags = fcntl(0, F_GETFL); 8563 if (flags >= 0 && flags & O_NONBLOCK) {8564 flags &= ~O_NONBLOCK;9592 if (flags >= 0 && (flags & O_NONBLOCK)) { 9593 flags &= ~O_NONBLOCK; 8565 9594 if (fcntl(0, F_SETFL, flags) >= 0) { 8566 9595 out2str("sh: turning off NDELAY mode\n"); … … 8570 9599 } 8571 9600 } 9601 #endif 8572 9602 return nr; 8573 9603 } … … 8577 9607 * 8578 9608 * 1) If a string was pushed back on the input, pop it; 8579 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading 8580 * from a string so we can't refill the buffer, return EOF. 8581 * 3) If the is more stuff in this buffer, use it else call read to fill it. 9609 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM) 9610 * or we are reading from a string so we can't refill the buffer, 9611 * return EOF. 9612 * 3) If there is more stuff in this buffer, use it else call read to fill it. 8582 9613 * 4) Process input up to the next newline, deleting nul characters. 8583 9614 */ 9615 //#define pgetc_debug(...) bb_error_msg(__VA_ARGS__) 9616 #define pgetc_debug(...) ((void)0) 8584 9617 static int 8585 9618 preadbuffer(void) … … 8587 9620 char *q; 8588 9621 int more; 8589 char savec; 8590 8591 while (parsefile->strpush) { 9622 9623 while (g_parsefile->strpush) { 8592 9624 #if ENABLE_ASH_ALIAS 8593 if (parsenleft == -1 && parsefile->strpush->ap && 8594 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') { 9625 if (g_parsefile->left_in_line == -1 9626 && g_parsefile->strpush->ap 9627 && g_parsefile->next_to_pgetc[-1] != ' ' 9628 && g_parsefile->next_to_pgetc[-1] != '\t' 9629 ) { 9630 pgetc_debug("preadbuffer PEOA"); 8595 9631 return PEOA; 8596 9632 } 8597 9633 #endif 8598 9634 popstring(); 8599 if (--parsenleft >= 0) 8600 return signed_char2int(*parsenextc++); 8601 } 8602 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) 9635 /* try "pgetc" now: */ 9636 pgetc_debug("preadbuffer internal pgetc at %d:%p'%s'", 9637 g_parsefile->left_in_line, 9638 g_parsefile->next_to_pgetc, 9639 g_parsefile->next_to_pgetc); 9640 if (--g_parsefile->left_in_line >= 0) 9641 return (unsigned char)(*g_parsefile->next_to_pgetc++); 9642 } 9643 /* on both branches above g_parsefile->left_in_line < 0. 9644 * "pgetc" needs refilling. 9645 */ 9646 9647 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read", 9648 * pungetc() may increment it a few times. 9649 * Assuming it won't increment it to less than -90. 9650 */ 9651 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) { 9652 pgetc_debug("preadbuffer PEOF1"); 9653 /* even in failure keep left_in_line and next_to_pgetc 9654 * in lock step, for correct multi-layer pungetc. 9655 * left_in_line was decremented before preadbuffer(), 9656 * must inc next_to_pgetc: */ 9657 g_parsefile->next_to_pgetc++; 8603 9658 return PEOF; 8604 flush_stdout_stderr();8605 8606 more = parselleft;9659 } 9660 9661 more = g_parsefile->left_in_buffer; 8607 9662 if (more <= 0) { 9663 flush_stdout_stderr(); 8608 9664 again: 8609 9665 more = preadfd(); 8610 9666 if (more <= 0) { 8611 parselleft = parsenleft = EOF_NLEFT; 9667 /* don't try reading again */ 9668 g_parsefile->left_in_line = -99; 9669 pgetc_debug("preadbuffer PEOF2"); 9670 g_parsefile->next_to_pgetc++; 8612 9671 return PEOF; 8613 9672 } 8614 9673 } 8615 9674 8616 q = parsenextc; 8617 8618 /* delete nul characters */ 9675 /* Find out where's the end of line. 9676 * Set g_parsefile->left_in_line 9677 * and g_parsefile->left_in_buffer acordingly. 9678 * NUL chars are deleted. 9679 */ 9680 q = g_parsefile->next_to_pgetc; 8619 9681 for (;;) { 8620 intc;9682 char c; 8621 9683 8622 9684 more--; 9685 8623 9686 c = *q; 8624 8625 if (!c) 9687 if (c == '\0') { 8626 9688 memmove(q, q + 1, more); 8627 else {9689 } else { 8628 9690 q++; 8629 9691 if (c == '\n') { 8630 parsenleft = q - parsenextc - 1;9692 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1; 8631 9693 break; 8632 9694 } … … 8634 9696 8635 9697 if (more <= 0) { 8636 parsenleft = q - parsenextc - 1;8637 if ( parsenleft< 0)9698 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1; 9699 if (g_parsefile->left_in_line < 0) 8638 9700 goto again; 8639 9701 break; 8640 9702 } 8641 9703 } 8642 parselleft = more; 8643 8644 savec = *q; 8645 *q = '\0'; 9704 g_parsefile->left_in_buffer = more; 8646 9705 8647 9706 if (vflag) { 8648 out2str(parsenextc); 8649 } 8650 8651 *q = savec; 8652 8653 return signed_char2int(*parsenextc++); 8654 } 8655 8656 #define pgetc_as_macro() (--parsenleft >= 0? signed_char2int(*parsenextc++) : preadbuffer()) 9707 char save = *q; 9708 *q = '\0'; 9709 out2str(g_parsefile->next_to_pgetc); 9710 *q = save; 9711 } 9712 9713 pgetc_debug("preadbuffer at %d:%p'%s'", 9714 g_parsefile->left_in_line, 9715 g_parsefile->next_to_pgetc, 9716 g_parsefile->next_to_pgetc); 9717 return (unsigned char)*g_parsefile->next_to_pgetc++; 9718 } 9719 9720 #define pgetc_as_macro() \ 9721 (--g_parsefile->left_in_line >= 0 \ 9722 ? (unsigned char)*g_parsefile->next_to_pgetc++ \ 9723 : preadbuffer() \ 9724 ) 9725 8657 9726 static int 8658 9727 pgetc(void) 8659 9728 { 9729 pgetc_debug("pgetc_fast at %d:%p'%s'", 9730 g_parsefile->left_in_line, 9731 g_parsefile->next_to_pgetc, 9732 g_parsefile->next_to_pgetc); 8660 9733 return pgetc_as_macro(); 8661 9734 } 8662 9735 8663 9736 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE 8664 # define pgetc_macro() pgetc()9737 # define pgetc_fast() pgetc() 8665 9738 #else 8666 #define pgetc_macro() pgetc_as_macro() 8667 #endif 8668 8669 /* 8670 * Same as pgetc(), but ignores PEOA. 8671 */ 9739 # define pgetc_fast() pgetc_as_macro() 9740 #endif 9741 8672 9742 #if ENABLE_ASH_ALIAS 8673 9743 static int 8674 pgetc 2(void)9744 pgetc_without_PEOA(void) 8675 9745 { 8676 9746 int c; 8677 8678 9747 do { 8679 c = pgetc_macro(); 9748 pgetc_debug("pgetc_fast at %d:%p'%s'", 9749 g_parsefile->left_in_line, 9750 g_parsefile->next_to_pgetc, 9751 g_parsefile->next_to_pgetc); 9752 c = pgetc_fast(); 8680 9753 } while (c == PEOA); 8681 9754 return c; 8682 9755 } 8683 9756 #else 8684 static int 8685 pgetc2(void) 8686 { 8687 return pgetc_macro(); 8688 } 9757 # define pgetc_without_PEOA() pgetc() 8689 9758 #endif 8690 9759 … … 8700 9769 8701 9770 while (--nleft > 0) { 8702 c = pgetc 2();9771 c = pgetc_without_PEOA(); 8703 9772 if (c == PEOF) { 8704 9773 if (p == line) … … 8721 9790 pungetc(void) 8722 9791 { 8723 parsenleft++; 8724 parsenextc--; 8725 } 8726 8727 /* 8728 * Push a string back onto the input at this current parsefile level. 8729 * We handle aliases this way. 8730 */ 8731 static void 8732 pushstring(char *s, void *ap) 8733 { 8734 struct strpush *sp; 8735 size_t len; 8736 8737 len = strlen(s); 8738 INT_OFF; 8739 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/ 8740 if (parsefile->strpush) { 8741 sp = ckmalloc(sizeof(struct strpush)); 8742 sp->prev = parsefile->strpush; 8743 parsefile->strpush = sp; 8744 } else 8745 sp = parsefile->strpush = &(parsefile->basestrpush); 8746 sp->prevstring = parsenextc; 8747 sp->prevnleft = parsenleft; 8748 #if ENABLE_ASH_ALIAS 8749 sp->ap = (struct alias *)ap; 8750 if (ap) { 8751 ((struct alias *)ap)->flag |= ALIASINUSE; 8752 sp->string = s; 8753 } 8754 #endif 8755 parsenextc = s; 8756 parsenleft = len; 8757 INT_ON; 9792 g_parsefile->left_in_line++; 9793 g_parsefile->next_to_pgetc--; 9794 pgetc_debug("pushed back to %d:%p'%s'", 9795 g_parsefile->left_in_line, 9796 g_parsefile->next_to_pgetc, 9797 g_parsefile->next_to_pgetc); 8758 9798 } 8759 9799 … … 8767 9807 struct parsefile *pf; 8768 9808 8769 parsefile->nleft = parsenleft; 8770 parsefile->lleft = parselleft; 8771 parsefile->nextc = parsenextc; 8772 parsefile->linno = plinno; 8773 pf = ckmalloc(sizeof(*pf)); 8774 pf->prev = parsefile; 8775 pf->fd = -1; 8776 pf->strpush = NULL; 8777 pf->basestrpush.prev = NULL; 8778 parsefile = pf; 9809 pf = ckzalloc(sizeof(*pf)); 9810 pf->prev = g_parsefile; 9811 pf->pf_fd = -1; 9812 /*pf->strpush = NULL; - ckzalloc did it */ 9813 /*pf->basestrpush.prev = NULL;*/ 9814 g_parsefile = pf; 8779 9815 } 8780 9816 … … 8782 9818 popfile(void) 8783 9819 { 8784 struct parsefile *pf = parsefile;9820 struct parsefile *pf = g_parsefile; 8785 9821 8786 9822 INT_OFF; 8787 if (pf->fd >= 0) 8788 close(pf->fd); 8789 if (pf->buf) 8790 free(pf->buf); 9823 if (pf->pf_fd >= 0) 9824 close(pf->pf_fd); 9825 free(pf->buf); 8791 9826 while (pf->strpush) 8792 9827 popstring(); 8793 parsefile = pf->prev;9828 g_parsefile = pf->prev; 8794 9829 free(pf); 8795 parsenleft = parsefile->nleft;8796 parselleft = parsefile->lleft;8797 parsenextc = parsefile->nextc;8798 plinno = parsefile->linno;8799 9830 INT_ON; 8800 9831 } … … 8806 9837 popallfiles(void) 8807 9838 { 8808 while ( parsefile != &basepf)9839 while (g_parsefile != &basepf) 8809 9840 popfile(); 8810 9841 } … … 8818 9849 { 8819 9850 popallfiles(); 8820 if ( parsefile->fd > 0) {8821 close( parsefile->fd);8822 parsefile->fd = 0;9851 if (g_parsefile->pf_fd > 0) { 9852 close(g_parsefile->pf_fd); 9853 g_parsefile->pf_fd = 0; 8823 9854 } 8824 9855 } … … 8831 9862 setinputfd(int fd, int push) 8832 9863 { 8833 fcntl(fd, F_SETFD, FD_CLOEXEC);9864 close_on_exec_on(fd); 8834 9865 if (push) { 8835 9866 pushfile(); 8836 parsefile->buf = 0; 8837 } 8838 parsefile->fd = fd; 8839 if (parsefile->buf == NULL) 8840 parsefile->buf = ckmalloc(IBUFSIZ); 8841 parselleft = parsenleft = 0; 8842 plinno = 1; 9867 g_parsefile->buf = NULL; 9868 } 9869 g_parsefile->pf_fd = fd; 9870 if (g_parsefile->buf == NULL) 9871 g_parsefile->buf = ckmalloc(IBUFSIZ); 9872 g_parsefile->left_in_buffer = 0; 9873 g_parsefile->left_in_line = 0; 9874 g_parsefile->linno = 1; 8843 9875 } 8844 9876 … … 8858 9890 if (flags & INPUT_NOFILE_OK) 8859 9891 goto out; 8860 ash_msg_and_raise_error("can't open %s", fname);9892 ash_msg_and_raise_error("can't open '%s'", fname); 8861 9893 } 8862 9894 if (fd < 10) { … … 8881 9913 INT_OFF; 8882 9914 pushfile(); 8883 parsenextc = string;8884 parsenleft= strlen(string);8885 parsefile->buf = NULL;8886 plinno = 1;9915 g_parsefile->next_to_pgetc = string; 9916 g_parsefile->left_in_line = strlen(string); 9917 g_parsefile->buf = NULL; 9918 g_parsefile->linno = 1; 8887 9919 INT_ON; 8888 9920 } … … 8901 9933 static time_t mailtime[MAXMBOXES]; 8902 9934 /* Set if MAIL or MAILPATH is changed. */ 8903 static int mail_var_path_changed;9935 static smallint mail_var_path_changed; 8904 9936 8905 9937 /* … … 8922 9954 mpath = mpathset() ? mpathval() : mailval(); 8923 9955 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) { 8924 p = pa dvance(&mpath, nullstr);9956 p = path_advance(&mpath, nullstr); 8925 9957 if (p == NULL) 8926 9958 break; 8927 9959 if (*p == '\0') 8928 9960 continue; 8929 for (q = p; *q; q++); 9961 for (q = p; *q; q++) 9962 continue; 8930 9963 #if DEBUG 8931 9964 if (q[-1] != '/') … … 8939 9972 if (!mail_var_path_changed && statb.st_mtime != *mtp) { 8940 9973 fprintf( 8941 stderr, snlfmt,9974 stderr, "%s\n", 8942 9975 pathopt ? pathopt : "you have mail" 8943 9976 ); … … 8949 9982 } 8950 9983 8951 static void 8952 changemail(const char *val )8953 { 8954 mail_var_path_changed ++;9984 static void FAST_FUNC 9985 changemail(const char *val UNUSED_PARAM) 9986 { 9987 mail_var_path_changed = 1; 8955 9988 } 8956 9989 … … 8970 10003 int nparam; 8971 10004 8972 for (nparam = 0; argv[nparam]; nparam++); 10005 for (nparam = 0; argv[nparam]; nparam++) 10006 continue; 8973 10007 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap)); 8974 10008 while (*argv) { … … 8977 10011 *ap = NULL; 8978 10012 freeparam(&shellparam); 8979 shellparam.malloc = 1;10013 shellparam.malloced = 1; 8980 10014 shellparam.nparam = nparam; 8981 10015 shellparam.p = newparam; … … 8989 10023 * Process shell options. The global variable argptr contains a pointer 8990 10024 * to the argument list; we advance it past the options. 8991 */ 8992 static void 8993 minus_o(char *name, int val) 10025 * 10026 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says: 10027 * For a non-interactive shell, an error condition encountered 10028 * by a special built-in ... shall cause the shell to write a diagnostic message 10029 * to standard error and exit as shown in the following table: 10030 * Error Special Built-In 10031 * ... 10032 * Utility syntax error (option or operand error) Shall exit 10033 * ... 10034 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142) 10035 * we see that bash does not do that (set "finishes" with error code 1 instead, 10036 * and shell continues), and people rely on this behavior! 10037 * Testcase: 10038 * set -o barfoo 2>/dev/null 10039 * echo $? 10040 * 10041 * Oh well. Let's mimic that. 10042 */ 10043 static int 10044 plus_minus_o(char *name, int val) 8994 10045 { 8995 10046 int i; … … 8999 10050 if (strcmp(name, optnames(i)) == 0) { 9000 10051 optlist[i] = val; 9001 return ;10052 return 0; 9002 10053 } 9003 10054 } 9004 ash_msg_and_raise_error("illegal option -o %s", name); 9005 } 9006 out1str("Current option settings\n"); 9007 for (i = 0; i < NOPTS; i++) 9008 out1fmt("%-16s%s\n", optnames(i), 9009 optlist[i] ? "on" : "off"); 10055 ash_msg("illegal option %co %s", val ? '-' : '+', name); 10056 return 1; 10057 } 10058 for (i = 0; i < NOPTS; i++) { 10059 if (val) { 10060 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off"); 10061 } else { 10062 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i)); 10063 } 10064 } 10065 return 0; 9010 10066 } 9011 10067 static void … … 9020 10076 } 9021 10077 } 9022 ash_msg_and_raise_error("illegal option -%c", flag);10078 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag); 9023 10079 /* NOTREACHED */ 9024 10080 } 9025 static void10081 static int 9026 10082 options(int cmdline) 9027 10083 { … … 9058 10114 minusc = p; /* command is after shell args */ 9059 10115 } else if (c == 'o') { 9060 minus_o(*argptr, val); 10116 if (plus_minus_o(*argptr, val)) { 10117 /* it already printed err message */ 10118 return 1; /* error */ 10119 } 9061 10120 if (*argptr) 9062 10121 argptr++; … … 9073 10132 } 9074 10133 } 10134 return 0; 9075 10135 } 9076 10136 … … 9078 10138 * The shift builtin command. 9079 10139 */ 9080 static int 9081 shiftcmd(int argc , char **argv)10140 static int FAST_FUNC 10141 shiftcmd(int argc UNUSED_PARAM, char **argv) 9082 10142 { 9083 10143 int n; … … 9085 10145 9086 10146 n = 1; 9087 if (arg c > 1)10147 if (argv[1]) 9088 10148 n = number(argv[1]); 9089 10149 if (n > shellparam.nparam) 9090 ash_msg_and_raise_error("can't shift that many");10150 n = 0; /* bash compat, was = shellparam.nparam; */ 9091 10151 INT_OFF; 9092 10152 shellparam.nparam -= n; 9093 10153 for (ap1 = shellparam.p; --n >= 0; ap1++) { 9094 if (shellparam.malloc )10154 if (shellparam.malloced) 9095 10155 free(*ap1); 9096 10156 } 9097 10157 ap2 = shellparam.p; 9098 while ((*ap2++ = *ap1++) != NULL); 10158 while ((*ap2++ = *ap1++) != NULL) 10159 continue; 9099 10160 #if ENABLE_ASH_GETOPTS 9100 10161 shellparam.optind = 1; … … 9139 10200 * The set command builtin. 9140 10201 */ 9141 static int 9142 setcmd(int argc, char **argv) 9143 { 9144 if (argc == 1) 10202 static int FAST_FUNC 10203 setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 10204 { 10205 int retval; 10206 10207 if (!argv[1]) 9145 10208 return showvars(nullstr, 0, VUNSET); 9146 10209 INT_OFF; 9147 options(0); 9148 optschanged(); 9149 if (*argptr != NULL) { 9150 setparam(argptr); 10210 retval = 1; 10211 if (!options(0)) { /* if no parse error... */ 10212 retval = 0; 10213 optschanged(); 10214 if (*argptr != NULL) { 10215 setparam(argptr); 10216 } 9151 10217 } 9152 10218 INT_ON; 9153 return 0;10219 return retval; 9154 10220 } 9155 10221 9156 10222 #if ENABLE_ASH_RANDOM_SUPPORT 9157 /* Roughly copied from bash.. */ 9158 static void 10223 static void FAST_FUNC 9159 10224 change_random(const char *value) 9160 10225 { 10226 uint32_t t; 10227 9161 10228 if (value == NULL) { 9162 10229 /* "get", generate */ 9163 char buf[16]; 9164 9165 rseed = rseed * 1103515245 + 12345; 9166 sprintf(buf, "%d", (unsigned int)((rseed & 32767))); 10230 t = next_random(&random_gen); 9167 10231 /* set without recursion */ 9168 setvar(vrandom. text, buf, VNOFUNC);10232 setvar(vrandom.var_text, utoa(t), VNOFUNC); 9169 10233 vrandom.flags &= ~VNOFUNC; 9170 10234 } else { 9171 10235 /* set/reset */ 9172 rseed = strtoul(value, (char **)NULL, 10); 10236 t = strtoul(value, NULL, 10); 10237 INIT_RANDOM_T(&random_gen, (t ? t : 1), t); 9173 10238 } 9174 10239 } … … 9190 10255 optnext = optfirst + *param_optind - 1; 9191 10256 9192 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)10257 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff) 9193 10258 p = NULL; 9194 10259 else … … 9209 10274 9210 10275 c = *p++; 9211 for (q = optstr; *q != c; 10276 for (q = optstr; *q != c;) { 9212 10277 if (*q == '\0') { 9213 10278 if (optstr[0] == ':') { … … 9270 10335 * then it's the first time getopts has been called. 9271 10336 */ 9272 static int 10337 static int FAST_FUNC 9273 10338 getoptscmd(int argc, char **argv) 9274 10339 { … … 9299 10364 /* ============ Shell parser */ 9300 10365 9301 static int tokpushback; /* last token pushed back */ 9302 #define NEOF ((union node *)&tokpushback) 9303 static int parsebackquote; /* nonzero if we are inside backquotes */ 9304 static int lasttoken; /* last token read */ 10366 struct heredoc { 10367 struct heredoc *next; /* next here document in list */ 10368 union node *here; /* redirection node */ 10369 char *eofmark; /* string indicating end of input */ 10370 smallint striptabs; /* if set, strip leading tabs */ 10371 }; 10372 10373 static smallint tokpushback; /* last token pushed back */ 10374 static smallint parsebackquote; /* nonzero if we are inside backquotes */ 10375 static smallint quoteflag; /* set if (part of) last token was quoted */ 10376 static token_id_t lasttoken; /* last token read (integer id Txxx) */ 10377 static struct heredoc *heredoclist; /* list of here documents to read */ 9305 10378 static char *wordtext; /* text of last word returned by readtoken */ 9306 10379 static struct nodelist *backquotelist; 9307 10380 static union node *redirnode; 9308 10381 static struct heredoc *heredoc; 9309 static int quoteflag; /* set if (part of) last token was quoted */ 9310 9311 static void raise_error_syntax(const char *) ATTRIBUTE_NORETURN; 9312 static void 9313 raise_error_syntax(const char *msg)9314 { 9315 ash_msg_and_raise_error("syntax error: %s", msg);9316 /* NOTREACHED */9317 } 9318 9319 /* 10382 10383 static const char * 10384 tokname(char *buf, int tok) 10385 { 10386 if (tok < TSEMI) 10387 return tokname_array[tok] + 1; 10388 sprintf(buf, "\"%s\"", tokname_array[tok] + 1); 10389 return buf; 10390 } 10391 10392 /* raise_error_unexpected_syntax: 9320 10393 * Called when an unexpected token is read during the parse. The argument 9321 10394 * is the token that is expected, or -1 if more than one type of token can 9322 10395 * occur at this point. 9323 10396 */ 9324 static void raise_error_unexpected_syntax(int) ATTRIBUTE_NORETURN;10397 static void raise_error_unexpected_syntax(int) NORETURN; 9325 10398 static void 9326 10399 raise_error_unexpected_syntax(int token) 9327 10400 { 9328 10401 char msg[64]; 10402 char buf[16]; 9329 10403 int l; 9330 10404 9331 l = sprintf(msg, " %s unexpected", tokname(lasttoken));10405 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken)); 9332 10406 if (token >= 0) 9333 sprintf(msg + l, " (expecting %s)", tokname( token));10407 sprintf(msg + l, " (expecting %s)", tokname(buf, token)); 9334 10408 raise_error_syntax(msg); 9335 10409 /* NOTREACHED */ … … 9337 10411 9338 10412 #define EOFMARKLEN 79 9339 9340 struct heredoc {9341 struct heredoc *next; /* next here document in list */9342 union node *here; /* redirection node */9343 char *eofmark; /* string indicating end of input */9344 int striptabs; /* if set, strip leading tabs */9345 };9346 9347 static struct heredoc *heredoclist; /* list of here documents to read */9348 10413 9349 10414 /* parsing is heavily cross-recursive, need these forward decls */ … … 9370 10435 if (tok == TBACKGND) { 9371 10436 if (n2->type == NPIPE) { 9372 n2->npipe. backgnd = 1;10437 n2->npipe.pipe_backgnd = 1; 9373 10438 } else { 9374 10439 if (n2->type != NREDIR) { 9375 n3 = st alloc(sizeof(struct nredir));10440 n3 = stzalloc(sizeof(struct nredir)); 9376 10441 n3->nredir.n = n2; 9377 n3->nredir.redirect = NULL;10442 /*n3->nredir.redirect = NULL; - stzalloc did it */ 9378 10443 n2 = n3; 9379 10444 } … … 9384 10449 n1 = n2; 9385 10450 } else { 9386 n3 = st alloc(sizeof(struct nbinary));10451 n3 = stzalloc(sizeof(struct nbinary)); 9387 10452 n3->type = NSEMI; 9388 10453 n3->nbinary.ch1 = n1; … … 9401 10466 return n1; 9402 10467 } else { 9403 tokpushback ++;10468 tokpushback = 1; 9404 10469 } 9405 10470 checkkwd = CHKNL | CHKKWD | CHKALIAS; … … 9416 10481 if (nlflag == 1) 9417 10482 raise_error_unexpected_syntax(-1); 9418 tokpushback ++;10483 tokpushback = 1; 9419 10484 return n1; 9420 10485 } … … 9436 10501 t = NOR; 9437 10502 } else { 9438 tokpushback ++;10503 tokpushback = 1; 9439 10504 return n1; 9440 10505 } 9441 10506 checkkwd = CHKNL | CHKKWD | CHKALIAS; 9442 10507 n2 = pipeline(); 9443 n3 = st alloc(sizeof(struct nbinary));10508 n3 = stzalloc(sizeof(struct nbinary)); 9444 10509 n3->type = t; 9445 10510 n3->nbinary.ch1 = n1; … … 9462 10527 checkkwd = CHKKWD | CHKALIAS; 9463 10528 } else 9464 tokpushback ++;10529 tokpushback = 1; 9465 10530 n1 = parse_command(); 9466 10531 if (readtoken() == TPIPE) { 9467 pipenode = st alloc(sizeof(struct npipe));10532 pipenode = stzalloc(sizeof(struct npipe)); 9468 10533 pipenode->type = NPIPE; 9469 pipenode->npipe.backgnd = 0;9470 lp = st alloc(sizeof(struct nodelist));10534 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */ 10535 lp = stzalloc(sizeof(struct nodelist)); 9471 10536 pipenode->npipe.cmdlist = lp; 9472 10537 lp->n = n1; 9473 10538 do { 9474 10539 prev = lp; 9475 lp = st alloc(sizeof(struct nodelist));10540 lp = stzalloc(sizeof(struct nodelist)); 9476 10541 checkkwd = CHKNL | CHKKWD | CHKALIAS; 9477 10542 lp->n = parse_command(); … … 9481 10546 n1 = pipenode; 9482 10547 } 9483 tokpushback ++;10548 tokpushback = 1; 9484 10549 if (negate) { 9485 n2 = st alloc(sizeof(struct nnot));10550 n2 = stzalloc(sizeof(struct nnot)); 9486 10551 n2->type = NNOT; 9487 10552 n2->nnot.com = n1; … … 9496 10561 union node *n; 9497 10562 9498 n = st alloc(sizeof(struct narg));10563 n = stzalloc(sizeof(struct narg)); 9499 10564 n->type = NARG; 9500 n->narg.next = NULL;10565 /*n->narg.next = NULL; - stzalloc did it */ 9501 10566 n->narg.text = wordtext; 9502 10567 n->narg.backquote = backquotelist; … … 9507 10572 fixredir(union node *n, const char *text, int err) 9508 10573 { 10574 int fd; 10575 9509 10576 TRACE(("Fix redir %s %d\n", text, err)); 9510 10577 if (!err) 9511 10578 n->ndup.vname = NULL; 9512 10579 9513 if (isdigit(text[0]) && text[1] == '\0') 9514 n->ndup.dupfd = text[0] - '0'; 10580 fd = bb_strtou(text, NULL, 10); 10581 if (!errno && fd >= 0) 10582 n->ndup.dupfd = fd; 9515 10583 else if (LONE_DASH(text)) 9516 10584 n->ndup.dupfd = -1; 9517 10585 else { 9518 10586 if (err) 9519 raise_error_syntax(" Bad fd number");10587 raise_error_syntax("bad fd number"); 9520 10588 n->ndup.vname = makename(); 9521 10589 } … … 9527 10595 */ 9528 10596 static int 9529 noexpand(char *text) 9530 { 9531 char *p; 9532 char c; 9533 9534 p = text; 9535 while ((c = *p++) != '\0') { 10597 noexpand(const char *text) 10598 { 10599 unsigned char c; 10600 10601 while ((c = *text++) != '\0') { 9536 10602 if (c == CTLQUOTEMARK) 9537 10603 continue; 9538 10604 if (c == CTLESC) 9539 p++;10605 text++; 9540 10606 else if (SIT(c, BASESYNTAX) == CCTL) 9541 10607 return 0; … … 9560 10626 TRACE(("Here document %d\n", n->type)); 9561 10627 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) 9562 raise_error_syntax(" Illegal eof marker for << redirection");9563 rmescapes(wordtext );10628 raise_error_syntax("illegal eof marker for << redirection"); 10629 rmescapes(wordtext, 0); 9564 10630 here->eofmark = wordtext; 9565 10631 here->next = NULL; … … 9567 10633 heredoclist = here; 9568 10634 else { 9569 for (p = heredoclist; p->next; p = p->next); 10635 for (p = heredoclist; p->next; p = p->next) 10636 continue; 9570 10637 p->next = here; 9571 10638 } … … 9585 10652 union node **rpp, *redir; 9586 10653 int savecheckkwd; 10654 #if ENABLE_ASH_BASH_COMPAT 10655 smallint double_brackets_flag = 0; 10656 #endif 9587 10657 9588 10658 args = NULL; … … 9595 10665 savecheckkwd = CHKALIAS; 9596 10666 for (;;) { 10667 int t; 9597 10668 checkkwd = savecheckkwd; 9598 switch (readtoken()) { 10669 t = readtoken(); 10670 switch (t) { 10671 #if ENABLE_ASH_BASH_COMPAT 10672 case TAND: /* "&&" */ 10673 case TOR: /* "||" */ 10674 if (!double_brackets_flag) { 10675 tokpushback = 1; 10676 goto out; 10677 } 10678 wordtext = (char *) (t == TAND ? "-a" : "-o"); 10679 #endif 9599 10680 case TWORD: 9600 n = st alloc(sizeof(struct narg));10681 n = stzalloc(sizeof(struct narg)); 9601 10682 n->type = NARG; 10683 /*n->narg.next = NULL; - stzalloc did it */ 9602 10684 n->narg.text = wordtext; 10685 #if ENABLE_ASH_BASH_COMPAT 10686 if (strcmp("[[", wordtext) == 0) 10687 double_brackets_flag = 1; 10688 else if (strcmp("]]", wordtext) == 0) 10689 double_brackets_flag = 0; 10690 #endif 9603 10691 n->narg.backquote = backquotelist; 9604 10692 if (savecheckkwd && isassignment(wordtext)) { … … 9630 10718 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd)) 9631 10719 ) { 9632 raise_error_syntax(" Bad function name");10720 raise_error_syntax("bad function name"); 9633 10721 } 9634 10722 n->type = NDEFUN; … … 9639 10727 /* fall through */ 9640 10728 default: 9641 tokpushback ++;10729 tokpushback = 1; 9642 10730 goto out; 9643 10731 } … … 9647 10735 *vpp = NULL; 9648 10736 *rpp = NULL; 9649 n = st alloc(sizeof(struct ncmd));10737 n = stzalloc(sizeof(struct ncmd)); 9650 10738 n->type = NCMD; 9651 10739 n->ncmd.args = args; … … 9673 10761 /* NOTREACHED */ 9674 10762 case TIF: 9675 n1 = st alloc(sizeof(struct nif));10763 n1 = stzalloc(sizeof(struct nif)); 9676 10764 n1->type = NIF; 9677 10765 n1->nif.test = list(0); … … 9681 10769 n2 = n1; 9682 10770 while (readtoken() == TELIF) { 9683 n2->nif.elsepart = st alloc(sizeof(struct nif));10771 n2->nif.elsepart = stzalloc(sizeof(struct nif)); 9684 10772 n2 = n2->nif.elsepart; 9685 10773 n2->type = NIF; … … 9693 10781 else { 9694 10782 n2->nif.elsepart = NULL; 9695 tokpushback ++;10783 tokpushback = 1; 9696 10784 } 9697 10785 t = TFI; … … 9700 10788 case TUNTIL: { 9701 10789 int got; 9702 n1 = st alloc(sizeof(struct nbinary));10790 n1 = stzalloc(sizeof(struct nbinary)); 9703 10791 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL; 9704 10792 n1->nbinary.ch1 = list(0); 9705 10793 got = readtoken(); 9706 10794 if (got != TDO) { 9707 TRACE(("expecting DO got %s %s\n", tokname(got),10795 TRACE(("expecting DO got '%s' %s\n", tokname_array[got] + 1, 9708 10796 got == TWORD ? wordtext : "")); 9709 10797 raise_error_unexpected_syntax(TDO); … … 9714 10802 } 9715 10803 case TFOR: 9716 if (readtoken() != TWORD || quoteflag || ! 9717 raise_error_syntax(" Bad for loop variable");9718 n1 = st alloc(sizeof(struct nfor));10804 if (readtoken() != TWORD || quoteflag || !goodname(wordtext)) 10805 raise_error_syntax("bad for loop variable"); 10806 n1 = stzalloc(sizeof(struct nfor)); 9719 10807 n1->type = NFOR; 9720 10808 n1->nfor.var = wordtext; … … 9723 10811 app = ≈ 9724 10812 while (readtoken() == TWORD) { 9725 n2 = st alloc(sizeof(struct narg));10813 n2 = stzalloc(sizeof(struct narg)); 9726 10814 n2->type = NARG; 10815 /*n2->narg.next = NULL; - stzalloc did it */ 9727 10816 n2->narg.text = wordtext; 9728 10817 n2->narg.backquote = backquotelist; … … 9735 10824 raise_error_unexpected_syntax(-1); 9736 10825 } else { 9737 n2 = st alloc(sizeof(struct narg));10826 n2 = stzalloc(sizeof(struct narg)); 9738 10827 n2->type = NARG; 10828 /*n2->narg.next = NULL; - stzalloc did it */ 9739 10829 n2->narg.text = (char *)dolatstr; 9740 n2->narg.backquote = NULL; 9741 n2->narg.next = NULL; 10830 /*n2->narg.backquote = NULL;*/ 9742 10831 n1->nfor.args = n2; 9743 10832 /* … … 9746 10835 */ 9747 10836 if (lasttoken != TNL && lasttoken != TSEMI) 9748 tokpushback ++;10837 tokpushback = 1; 9749 10838 } 9750 10839 checkkwd = CHKNL | CHKKWD | CHKALIAS; … … 9755 10844 break; 9756 10845 case TCASE: 9757 n1 = st alloc(sizeof(struct ncase));10846 n1 = stzalloc(sizeof(struct ncase)); 9758 10847 n1->type = NCASE; 9759 10848 if (readtoken() != TWORD) 9760 10849 raise_error_unexpected_syntax(TWORD); 9761 n1->ncase.expr = n2 = st alloc(sizeof(struct narg));10850 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg)); 9762 10851 n2->type = NARG; 10852 /*n2->narg.next = NULL; - stzalloc did it */ 9763 10853 n2->narg.text = wordtext; 9764 10854 n2->narg.backquote = backquotelist; 9765 n2->narg.next = NULL;9766 10855 do { 9767 10856 checkkwd = CHKKWD | CHKALIAS; … … 9776 10865 if (lasttoken == TLP) 9777 10866 readtoken(); 9778 *cpp = cp = st alloc(sizeof(struct nclist));10867 *cpp = cp = stzalloc(sizeof(struct nclist)); 9779 10868 cp->type = NCLIST; 9780 10869 app = &cp->nclist.pattern; 9781 10870 for (;;) { 9782 *app = ap = st alloc(sizeof(struct narg));10871 *app = ap = stzalloc(sizeof(struct narg)); 9783 10872 ap->type = NARG; 10873 /*ap->narg.next = NULL; - stzalloc did it */ 9784 10874 ap->narg.text = wordtext; 9785 10875 ap->narg.backquote = backquotelist; … … 9789 10879 readtoken(); 9790 10880 } 9791 ap->narg.next = NULL;10881 //ap->narg.next = NULL; 9792 10882 if (lasttoken != TRP) 9793 10883 raise_error_unexpected_syntax(TRP); … … 9807 10897 goto redir; 9808 10898 case TLP: 9809 n1 = st alloc(sizeof(struct nredir));10899 n1 = stzalloc(sizeof(struct nredir)); 9810 10900 n1->type = NSUBSHELL; 9811 10901 n1->nredir.n = list(0); 9812 n1->nredir.redirect = NULL;10902 /*n1->nredir.redirect = NULL; - stzalloc did it */ 9813 10903 t = TRP; 9814 10904 break; … … 9819 10909 case TWORD: 9820 10910 case TREDIR: 9821 tokpushback ++;10911 tokpushback = 1; 9822 10912 return simplecmd(); 9823 10913 } … … 9835 10925 parsefname(); 9836 10926 } 9837 tokpushback ++;10927 tokpushback = 1; 9838 10928 *rpp = NULL; 9839 10929 if (redir) { 9840 10930 if (n1->type != NSUBSHELL) { 9841 n2 = st alloc(sizeof(struct nredir));10931 n2 = stzalloc(sizeof(struct nredir)); 9842 10932 n2->type = NREDIR; 9843 10933 n2->nredir.n = n1; … … 9849 10939 } 9850 10940 10941 #if ENABLE_ASH_BASH_COMPAT 10942 static int decode_dollar_squote(void) 10943 { 10944 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567"; 10945 int c, cnt; 10946 char *p; 10947 char buf[4]; 10948 10949 c = pgetc(); 10950 p = strchr(C_escapes, c); 10951 if (p) { 10952 buf[0] = c; 10953 p = buf; 10954 cnt = 3; 10955 if ((unsigned char)(c - '0') <= 7) { /* \ooo */ 10956 do { 10957 c = pgetc(); 10958 *++p = c; 10959 } while ((unsigned char)(c - '0') <= 7 && --cnt); 10960 pungetc(); 10961 } else if (c == 'x') { /* \xHH */ 10962 do { 10963 c = pgetc(); 10964 *++p = c; 10965 } while (isxdigit(c) && --cnt); 10966 pungetc(); 10967 if (cnt == 3) { /* \x but next char is "bad" */ 10968 c = 'x'; 10969 goto unrecognized; 10970 } 10971 } else { /* simple seq like \\ or \t */ 10972 p++; 10973 } 10974 *p = '\0'; 10975 p = buf; 10976 c = bb_process_escape_sequence((void*)&p); 10977 } else { /* unrecognized "\z": print both chars unless ' or " */ 10978 if (c != '\'' && c != '"') { 10979 unrecognized: 10980 c |= 0x100; /* "please encode \, then me" */ 10981 } 10982 } 10983 return c; 10984 } 10985 #endif 10986 9851 10987 /* 9852 10988 * If eofmark is NULL, read a word or a redirection symbol. If eofmark 9853 10989 * is not NULL, read a here document. In the latter case, eofmark is the 9854 10990 * word which marks the end of the document and striptabs is true if 9855 * leading tabs should be stripped from the document. The argument firstc10991 * leading tabs should be stripped from the document. The argument c 9856 10992 * is the first character of the input token or document. 9857 10993 * … … 9860 10996 * will run code that appears at the end of readtoken1. 9861 10997 */ 9862 9863 static int parsebackquote; /* nonzero if we are inside backquotes */9864 9865 10998 #define CHECKEND() {goto checkend; checkend_return:;} 9866 10999 #define PARSEREDIR() {goto parseredir; parseredir_return:;} … … 9869 11002 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} 9870 11003 #define PARSEARITH() {goto parsearith; parsearith_return:;} 9871 9872 11004 static int 9873 readtoken1(int firstc, int syntax, char *eofmark, int striptabs) 9874 { 9875 int c = firstc; 11005 readtoken1(int c, int syntax, char *eofmark, int striptabs) 11006 { 11007 /* NB: syntax parameter fits into smallint */ 11008 /* c parameter is an unsigned char or PEOF or PEOA */ 9876 11009 char *out; 9877 11010 int len; 9878 11011 char line[EOFMARKLEN + 1]; 9879 struct nodelist *bqlist = 0; 9880 int quotef = 0; 9881 int dblquote = 0; 9882 int varnest = 0; /* levels of variables expansion */ 9883 int arinest = 0; /* levels of arithmetic expansion */ 9884 int parenlevel = 0; /* levels of parens in arithmetic */ 9885 int dqvarnest = 0; /* levels of variables expansion within double quotes */ 9886 int oldstyle = 0; 9887 int prevsyntax = 0; /* syntax before arithmetic */ 11012 struct nodelist *bqlist; 11013 smallint quotef; 11014 smallint dblquote; 11015 smallint oldstyle; 11016 smallint prevsyntax; /* syntax before arithmetic */ 11017 #if ENABLE_ASH_EXPAND_PRMT 11018 smallint pssyntax; /* we are expanding a prompt string */ 11019 #endif 11020 int varnest; /* levels of variables expansion */ 11021 int arinest; /* levels of arithmetic expansion */ 11022 int parenlevel; /* levels of parens in arithmetic */ 11023 int dqvarnest; /* levels of variables expansion within double quotes */ 11024 11025 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;) 11026 9888 11027 #if __GNUC__ 9889 11028 /* Avoid longjmp clobbering */ … … 9899 11038 (void) &syntax; 9900 11039 #endif 9901 9902 startlinno = plinno; 9903 dblquote = 0; 9904 if (syntax == DQSYNTAX) 9905 dblquote = 1; 11040 startlinno = g_parsefile->linno; 11041 bqlist = NULL; 9906 11042 quotef = 0; 9907 bqlist = NULL; 11043 prevsyntax = 0; 11044 #if ENABLE_ASH_EXPAND_PRMT 11045 pssyntax = (syntax == PSSYNTAX); 11046 if (pssyntax) 11047 syntax = DQSYNTAX; 11048 #endif 11049 dblquote = (syntax == DQSYNTAX); 9908 11050 varnest = 0; 9909 11051 arinest = 0; … … 9912 11054 9913 11055 STARTSTACKSTR(out); 9914 loop: { /* for each line, until end of word */ 9915 CHECKEND(); /* set c to PEOF if at end of here document */ 9916 for (;;) { /* until end of line or end of word */ 9917 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */ 9918 switch (SIT(c, syntax)) { 9919 case CNL: /* '\n' */ 9920 if (syntax == BASESYNTAX) 9921 goto endword; /* exit outer loop */ 9922 USTPUTC(c, out); 9923 plinno++; 9924 if (doprompt) 9925 setprompt(2); 9926 c = pgetc(); 9927 goto loop; /* continue outer loop */ 9928 case CWORD: 9929 USTPUTC(c, out); 9930 break; 9931 case CCTL: 9932 if (eofmark == NULL || dblquote) 11056 loop: 11057 /* For each line, until end of word */ 11058 CHECKEND(); /* set c to PEOF if at end of here document */ 11059 for (;;) { /* until end of line or end of word */ 11060 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */ 11061 switch (SIT(c, syntax)) { 11062 case CNL: /* '\n' */ 11063 if (syntax == BASESYNTAX) 11064 goto endword; /* exit outer loop */ 11065 USTPUTC(c, out); 11066 g_parsefile->linno++; 11067 setprompt_if(doprompt, 2); 11068 c = pgetc(); 11069 goto loop; /* continue outer loop */ 11070 case CWORD: 11071 USTPUTC(c, out); 11072 break; 11073 case CCTL: 11074 if (eofmark == NULL || dblquote) 11075 USTPUTC(CTLESC, out); 11076 #if ENABLE_ASH_BASH_COMPAT 11077 if (c == '\\' && bash_dollar_squote) { 11078 c = decode_dollar_squote(); 11079 if (c & 0x100) { 11080 USTPUTC('\\', out); 11081 c = (unsigned char)c; 11082 } 11083 } 11084 #endif 11085 USTPUTC(c, out); 11086 break; 11087 case CBACK: /* backslash */ 11088 c = pgetc_without_PEOA(); 11089 if (c == PEOF) { 11090 USTPUTC(CTLESC, out); 11091 USTPUTC('\\', out); 11092 pungetc(); 11093 } else if (c == '\n') { 11094 setprompt_if(doprompt, 2); 11095 } else { 11096 #if ENABLE_ASH_EXPAND_PRMT 11097 if (c == '$' && pssyntax) { 11098 USTPUTC(CTLESC, out); 11099 USTPUTC('\\', out); 11100 } 11101 #endif 11102 /* Backslash is retained if we are in "str" and next char isn't special */ 11103 if (dblquote 11104 && c != '\\' 11105 && c != '`' 11106 && c != '$' 11107 && (c != '"' || eofmark != NULL) 11108 ) { 11109 USTPUTC(CTLESC, out); 11110 USTPUTC('\\', out); 11111 } 11112 if (SIT(c, SQSYNTAX) == CCTL) 9933 11113 USTPUTC(CTLESC, out); 9934 11114 USTPUTC(c, out); 9935 break; 9936 case CBACK: /* backslash */ 9937 c = pgetc2(); 9938 if (c == PEOF) { 9939 USTPUTC(CTLESC, out); 9940 USTPUTC('\\', out); 11115 quotef = 1; 11116 } 11117 break; 11118 case CSQUOTE: 11119 syntax = SQSYNTAX; 11120 quotemark: 11121 if (eofmark == NULL) { 11122 USTPUTC(CTLQUOTEMARK, out); 11123 } 11124 break; 11125 case CDQUOTE: 11126 syntax = DQSYNTAX; 11127 dblquote = 1; 11128 goto quotemark; 11129 case CENDQUOTE: 11130 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;) 11131 if (eofmark != NULL && arinest == 0 11132 && varnest == 0 11133 ) { 11134 USTPUTC(c, out); 11135 } else { 11136 if (dqvarnest == 0) { 11137 syntax = BASESYNTAX; 11138 dblquote = 0; 11139 } 11140 quotef = 1; 11141 goto quotemark; 11142 } 11143 break; 11144 case CVAR: /* '$' */ 11145 PARSESUB(); /* parse substitution */ 11146 break; 11147 case CENDVAR: /* '}' */ 11148 if (varnest > 0) { 11149 varnest--; 11150 if (dqvarnest > 0) { 11151 dqvarnest--; 11152 } 11153 c = CTLENDVAR; 11154 } 11155 USTPUTC(c, out); 11156 break; 11157 #if ENABLE_SH_MATH_SUPPORT 11158 case CLP: /* '(' in arithmetic */ 11159 parenlevel++; 11160 USTPUTC(c, out); 11161 break; 11162 case CRP: /* ')' in arithmetic */ 11163 if (parenlevel > 0) { 11164 parenlevel--; 11165 } else { 11166 if (pgetc() == ')') { 11167 if (--arinest == 0) { 11168 syntax = prevsyntax; 11169 dblquote = (syntax == DQSYNTAX); 11170 c = CTLENDARI; 11171 } 11172 } else { 11173 /* 11174 * unbalanced parens 11175 * (don't 2nd guess - no error) 11176 */ 9941 11177 pungetc(); 9942 } else if (c == '\n') {9943 if (doprompt)9944 setprompt(2);9945 } else {9946 if (dblquote &&9947 c != '\\' && c != '`' &&9948 c != '$' && (9949 c != '"' ||9950 eofmark != NULL)9951 ) {9952 USTPUTC(CTLESC, out);9953 USTPUTC('\\', out);9954 }9955 if (SIT(c, SQSYNTAX) == CCTL)9956 USTPUTC(CTLESC, out);9957 USTPUTC(c, out);9958 quotef++;9959 11178 } 9960 break; 9961 case CSQUOTE: 9962 syntax = SQSYNTAX; 9963 quotemark: 9964 if (eofmark == NULL) { 9965 USTPUTC(CTLQUOTEMARK, out); 11179 } 11180 USTPUTC(c, out); 11181 break; 11182 #endif 11183 case CBQUOTE: /* '`' */ 11184 PARSEBACKQOLD(); 11185 break; 11186 case CENDFILE: 11187 goto endword; /* exit outer loop */ 11188 case CIGN: 11189 break; 11190 default: 11191 if (varnest == 0) { 11192 #if ENABLE_ASH_BASH_COMPAT 11193 if (c == '&') { 11194 if (pgetc() == '>') 11195 c = 0x100 + '>'; /* flag &> */ 11196 pungetc(); 9966 11197 } 9967 break; 9968 case CDQUOTE: 9969 syntax = DQSYNTAX; 9970 dblquote = 1; 9971 goto quotemark; 9972 case CENDQUOTE: 9973 if (eofmark != NULL && arinest == 0 9974 && varnest == 0 9975 ) { 9976 USTPUTC(c, out); 9977 } else { 9978 if (dqvarnest == 0) { 9979 syntax = BASESYNTAX; 9980 dblquote = 0; 9981 } 9982 quotef++; 9983 goto quotemark; 9984 } 9985 break; 9986 case CVAR: /* '$' */ 9987 PARSESUB(); /* parse substitution */ 9988 break; 9989 case CENDVAR: /* '}' */ 9990 if (varnest > 0) { 9991 varnest--; 9992 if (dqvarnest > 0) { 9993 dqvarnest--; 9994 } 9995 USTPUTC(CTLENDVAR, out); 9996 } else { 9997 USTPUTC(c, out); 9998 } 9999 break; 10000 #if ENABLE_ASH_MATH_SUPPORT 10001 case CLP: /* '(' in arithmetic */ 10002 parenlevel++; 11198 #endif 11199 goto endword; /* exit outer loop */ 11200 } 11201 IF_ASH_ALIAS(if (c != PEOA)) 10003 11202 USTPUTC(c, out); 10004 break; 10005 case CRP: /* ')' in arithmetic */ 10006 if (parenlevel > 0) { 10007 USTPUTC(c, out); 10008 --parenlevel; 10009 } else { 10010 if (pgetc() == ')') { 10011 if (--arinest == 0) { 10012 USTPUTC(CTLENDARI, out); 10013 syntax = prevsyntax; 10014 if (syntax == DQSYNTAX) 10015 dblquote = 1; 10016 else 10017 dblquote = 0; 10018 } else 10019 USTPUTC(')', out); 10020 } else { 10021 /* 10022 * unbalanced parens 10023 * (don't 2nd guess - no error) 10024 */ 10025 pungetc(); 10026 USTPUTC(')', out); 10027 } 10028 } 10029 break; 10030 #endif 10031 case CBQUOTE: /* '`' */ 10032 PARSEBACKQOLD(); 10033 break; 10034 case CENDFILE: 10035 goto endword; /* exit outer loop */ 10036 case CIGN: 10037 break; 10038 default: 10039 if (varnest == 0) 10040 goto endword; /* exit outer loop */ 10041 #if ENABLE_ASH_ALIAS 10042 if (c != PEOA) 10043 #endif 10044 USTPUTC(c, out); 10045 10046 } 10047 c = pgetc_macro(); 10048 } 10049 } 11203 } 11204 c = pgetc_fast(); 11205 } /* for (;;) */ 10050 11206 endword: 10051 #if ENABLE_ASH_MATH_SUPPORT 11207 11208 #if ENABLE_SH_MATH_SUPPORT 10052 11209 if (syntax == ARISYNTAX) 10053 raise_error_syntax(" Missing '))'");11210 raise_error_syntax("missing '))'"); 10054 11211 #endif 10055 11212 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL) 10056 raise_error_syntax(" Unterminated quoted string");11213 raise_error_syntax("unterminated quoted string"); 10057 11214 if (varnest != 0) { 10058 startlinno = plinno;11215 startlinno = g_parsefile->linno; 10059 11216 /* { */ 10060 raise_error_syntax(" Missing '}'");11217 raise_error_syntax("missing '}'"); 10061 11218 } 10062 11219 USTPUTC('\0', out); … … 10064 11221 out = stackblock(); 10065 11222 if (eofmark == NULL) { 10066 if ((c == '>' || c == '<' )11223 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>')) 10067 11224 && quotef == 0 10068 && len <= 2 10069 && (*out == '\0' || isdigit(*out))) { 10070 PARSEREDIR(); 10071 return lasttoken = TREDIR; 10072 } else { 10073 pungetc(); 10074 } 11225 ) { 11226 if (isdigit_str9(out)) { 11227 PARSEREDIR(); /* passed as params: out, c */ 11228 lasttoken = TREDIR; 11229 return lasttoken; 11230 } 11231 /* else: non-number X seen, interpret it 11232 * as "NNNX>file" = "NNNX >file" */ 11233 } 11234 pungetc(); 10075 11235 } 10076 11236 quoteflag = quotef; … … 10090 11250 if (eofmark) { 10091 11251 #if ENABLE_ASH_ALIAS 10092 if (c == PEOA) { 10093 c = pgetc2(); 10094 } 11252 if (c == PEOA) 11253 c = pgetc_without_PEOA(); 10095 11254 #endif 10096 11255 if (striptabs) { 10097 11256 while (c == '\t') { 10098 c = pgetc 2();11257 c = pgetc_without_PEOA(); 10099 11258 } 10100 11259 } … … 10104 11263 10105 11264 p = line; 10106 for (q = eofmark + 1; *q && *p == *q; p++, q++); 11265 for (q = eofmark + 1; *q && *p == *q; p++, q++) 11266 continue; 10107 11267 if (*p == '\n' && *q == '\0') { 10108 11268 c = PEOF; 10109 plinno++;11269 g_parsefile->linno++; 10110 11270 needprompt = doprompt; 10111 11271 } else { … … 10124 11284 */ 10125 11285 parseredir: { 10126 char fd = *out; 11286 /* out is already checked to be a valid number or "" */ 11287 int fd = (*out == '\0' ? -1 : atoi(out)); 10127 11288 union node *np; 10128 11289 10129 np = st alloc(sizeof(struct nfile));11290 np = stzalloc(sizeof(struct nfile)); 10130 11291 if (c == '>') { 10131 11292 np->nfile.fd = 1; … … 10137 11298 else if (c == '&') 10138 11299 np->type = NTOFD; 11300 /* it also can be NTO2 (>&file), but we can't figure it out yet */ 10139 11301 else { 10140 11302 np->type = NTO; 10141 11303 pungetc(); 10142 11304 } 10143 } else { /* c == '<' */ 10144 np->nfile.fd = 0; 11305 } 11306 #if ENABLE_ASH_BASH_COMPAT 11307 else if (c == 0x100 + '>') { /* this flags &> redirection */ 11308 np->nfile.fd = 1; 11309 pgetc(); /* this is '>', no need to check */ 11310 np->type = NTO2; 11311 } 11312 #endif 11313 else { /* c == '<' */ 11314 /*np->nfile.fd = 0; - stzalloc did it */ 10145 11315 c = pgetc(); 10146 11316 switch (c) { 10147 11317 case '<': 10148 11318 if (sizeof(struct nfile) != sizeof(struct nhere)) { 10149 np = st alloc(sizeof(struct nhere));10150 np->nfile.fd = 0;11319 np = stzalloc(sizeof(struct nhere)); 11320 /*np->nfile.fd = 0; - stzalloc did it */ 10151 11321 } 10152 11322 np->type = NHERE; 10153 heredoc = st alloc(sizeof(struct heredoc));11323 heredoc = stzalloc(sizeof(struct heredoc)); 10154 11324 heredoc->here = np; 10155 11325 c = pgetc(); … … 10157 11327 heredoc->striptabs = 1; 10158 11328 } else { 10159 heredoc->striptabs = 0;11329 /*heredoc->striptabs = 0; - stzalloc did it */ 10160 11330 pungetc(); 10161 11331 } … … 10176 11346 } 10177 11347 } 10178 if (fd != '\0')10179 np->nfile.fd = fd - '0';11348 if (fd >= 0) 11349 np->nfile.fd = fd; 10180 11350 redirnode = np; 10181 11351 goto parseredir_return; … … 10190 11360 * (assuming ascii char codes, as the original implementation did) */ 10191 11361 #define is_special(c) \ 10192 ((( (unsigned int)c) - 33 < 32) \10193 && ((0xc1ff920dU L >> (((unsigned int)c) - 33)) & 1))11362 (((unsigned)(c) - 33 < 32) \ 11363 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1)) 10194 11364 parsesub: { 10195 intsubtype;11365 unsigned char subtype; 10196 11366 int typeloc; 10197 11367 int flags; 10198 char *p;10199 static const char types[] ALIGN1 = "}-+?=";10200 11368 10201 11369 c = pgetc(); 10202 if ( 10203 c <= PEOA_OR_PEOF || 10204 (c != '(' && c != '{' && !is_name(c) && !is_special(c)) 11370 if (c > 255 /* PEOA or PEOF */ 11371 || (c != '(' && c != '{' && !is_name(c) && !is_special(c)) 10205 11372 ) { 10206 USTPUTC('$', out); 11373 #if ENABLE_ASH_BASH_COMPAT 11374 if (c == '\'') 11375 bash_dollar_squote = 1; 11376 else 11377 #endif 11378 USTPUTC('$', out); 10207 11379 pungetc(); 10208 } else if (c == '(') { /* $(command) or $((arith)) */ 11380 } else if (c == '(') { 11381 /* $(command) or $((arith)) */ 10209 11382 if (pgetc() == '(') { 10210 #if ENABLE_ ASH_MATH_SUPPORT11383 #if ENABLE_SH_MATH_SUPPORT 10211 11384 PARSEARITH(); 10212 11385 #else 10213 raise_error_syntax(" We unsupport $((arith))");11386 raise_error_syntax("you disabled math support for $((arith)) syntax"); 10214 11387 #endif 10215 11388 } else { … … 10218 11391 } 10219 11392 } else { 11393 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */ 10220 11394 USTPUTC(CTLVAR, out); 10221 11395 typeloc = out - (char *)stackblock(); … … 10227 11401 c = pgetc(); 10228 11402 if (c == '}') 10229 c = '#'; 11403 c = '#'; /* ${#} - same as $# */ 10230 11404 else 10231 subtype = VSLENGTH; 10232 } else 11405 subtype = VSLENGTH; /* ${#VAR} */ 11406 } else { 10233 11407 subtype = 0; 10234 } 10235 if (c > PEOA_OR_PEOF && is_name(c)) { 11408 } 11409 } 11410 if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) { 11411 /* $[{[#]]NAME[}] */ 10236 11412 do { 10237 11413 STPUTC(c, out); 10238 11414 c = pgetc(); 10239 } while (c > PEOA_OR_PEOF&& is_in_name(c));11415 } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c)); 10240 11416 } else if (isdigit(c)) { 11417 /* $[{[#]]NUM[}] */ 10241 11418 do { 10242 11419 STPUTC(c, out); … … 10244 11421 } while (isdigit(c)); 10245 11422 } else if (is_special(c)) { 11423 /* $[{[#]]<specialchar>[}] */ 10246 11424 USTPUTC(c, out); 10247 11425 c = pgetc(); 10248 } else 10249 badsub: raise_error_syntax("Bad substitution"); 11426 } else { 11427 badsub: 11428 raise_error_syntax("bad substitution"); 11429 } 11430 if (c != '}' && subtype == VSLENGTH) { 11431 /* ${#VAR didn't end with } */ 11432 goto badsub; 11433 } 10250 11434 10251 11435 STPUTC('=', out); 10252 11436 flags = 0; 10253 11437 if (subtype == 0) { 11438 /* ${VAR...} but not $VAR or ${#VAR} */ 11439 /* c == first char after VAR */ 10254 11440 switch (c) { 10255 11441 case ':': 11442 c = pgetc(); 11443 #if ENABLE_ASH_BASH_COMPAT 11444 if (c == ':' || c == '$' || isdigit(c)) { 11445 //TODO: support more general format ${v:EXPR:EXPR}, 11446 // where EXPR follows $(()) rules 11447 subtype = VSSUBSTR; 11448 pungetc(); 11449 break; /* "goto do_pungetc" is bigger (!) */ 11450 } 11451 #endif 10256 11452 flags = VSNUL; 10257 c = pgetc();10258 11453 /*FALLTHROUGH*/ 10259 default: 10260 p = strchr(types, c); 11454 default: { 11455 static const char types[] ALIGN1 = "}-+?="; 11456 const char *p = strchr(types, c); 10261 11457 if (p == NULL) 10262 11458 goto badsub; 10263 11459 subtype = p - types + VSNORMAL; 10264 11460 break; 11461 } 10265 11462 case '%': 10266 case '#': 10267 { 10268 int cc = c; 10269 subtype = c == '#' ? VSTRIMLEFT : 10270 VSTRIMRIGHT; 10271 c = pgetc(); 10272 if (c == cc) 10273 subtype++; 10274 else 10275 pungetc(); 10276 break; 10277 } 11463 case '#': { 11464 int cc = c; 11465 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT); 11466 c = pgetc(); 11467 if (c != cc) 11468 goto do_pungetc; 11469 subtype++; 11470 break; 11471 } 11472 #if ENABLE_ASH_BASH_COMPAT 11473 case '/': 11474 /* ${v/[/]pattern/repl} */ 11475 //TODO: encode pattern and repl separately. 11476 // Currently ${v/$var_with_slash/repl} is horribly broken 11477 subtype = VSREPLACE; 11478 c = pgetc(); 11479 if (c != '/') 11480 goto do_pungetc; 11481 subtype++; /* VSREPLACEALL */ 11482 break; 11483 #endif 10278 11484 } 10279 11485 } else { 11486 do_pungetc: 10280 11487 pungetc(); 10281 11488 } 10282 11489 if (dblquote || arinest) 10283 11490 flags |= VSQUOTE; 10284 *((char *)stackblock() + typeloc)= subtype | flags;11491 ((unsigned char *)stackblock())[typeloc] = subtype | flags; 10285 11492 if (subtype != VSNORMAL) { 10286 11493 varnest++; … … 10301 11508 parsebackq: { 10302 11509 struct nodelist **nlpp; 10303 int savepbq;11510 smallint savepbq; 10304 11511 union node *n; 10305 11512 char *volatile str; … … 10307 11514 struct jmploc *volatile savehandler; 10308 11515 size_t savelen; 10309 int saveprompt = 0; 11516 smallint saveprompt = 0; 11517 10310 11518 #ifdef __GNUC__ 10311 11519 (void) &saveprompt; 10312 11520 #endif 10313 10314 11521 savepbq = parsebackquote; 10315 11522 if (setjmp(jmploc.loc)) { 10316 if (str) 10317 free(str); 11523 free(str); 10318 11524 parsebackquote = 0; 10319 11525 exception_handler = savehandler; … … 10335 11541 reread it as input, interpreting it normally. */ 10336 11542 char *pout; 10337 int pc;10338 11543 size_t psavelen; 10339 11544 char *pstr; 10340 11545 10341 10342 11546 STARTSTACKSTR(pout); 10343 11547 for (;;) { 10344 i f (needprompt) {10345 setprompt(2); 10346 }11548 int pc; 11549 11550 setprompt_if(needprompt, 2); 10347 11551 pc = pgetc(); 10348 11552 switch (pc) { … … 10353 11557 pc = pgetc(); 10354 11558 if (pc == '\n') { 10355 plinno++; 10356 if (doprompt) 10357 setprompt(2); 11559 g_parsefile->linno++; 11560 setprompt_if(doprompt, 2); 10358 11561 /* 10359 11562 * If eating a newline, avoid putting … … 10365 11568 } 10366 11569 if (pc != '\\' && pc != '`' && pc != '$' 10367 && (!dblquote || pc != '"')) 11570 && (!dblquote || pc != '"') 11571 ) { 10368 11572 STPUTC('\\', pout); 10369 if (pc > PEOA_OR_PEOF) { 11573 } 11574 if (pc <= 255 /* not PEOA or PEOF */) { 10370 11575 break; 10371 11576 } … … 10373 11578 10374 11579 case PEOF: 10375 #if ENABLE_ASH_ALIAS 10376 case PEOA: 10377 #endif 10378 startlinno = plinno; 11580 IF_ASH_ALIAS(case PEOA:) 11581 startlinno = g_parsefile->linno; 10379 11582 raise_error_syntax("EOF in backquote substitution"); 10380 11583 10381 11584 case '\n': 10382 plinno++;11585 g_parsefile->linno++; 10383 11586 needprompt = doprompt; 10384 11587 break; … … 10400 11603 while (*nlpp) 10401 11604 nlpp = &(*nlpp)->next; 10402 *nlpp = st alloc(sizeof(**nlpp));10403 (*nlpp)->next = NULL;11605 *nlpp = stzalloc(sizeof(**nlpp)); 11606 /* (*nlpp)->next = NULL; - stzalloc did it */ 10404 11607 parsebackquote = oldstyle; 10405 11608 … … 10447 11650 } 10448 11651 10449 #if ENABLE_ ASH_MATH_SUPPORT11652 #if ENABLE_SH_MATH_SUPPORT 10450 11653 /* 10451 11654 * Parse an arithmetic expansion (indicate start of one and set state) … … 10494 11697 /* singles must be first! */ 10495 11698 static const char xxreadtoken_chars[7] ALIGN1 = { 10496 '\n', '(', ')', '&', '|', ';', 0 11699 '\n', '(', ')', /* singles */ 11700 '&', '|', ';', /* doubles */ 11701 0 10497 11702 }; 11703 11704 #define xxreadtoken_singles 3 11705 #define xxreadtoken_doubles 3 10498 11706 10499 11707 static const char xxreadtoken_tokens[] ALIGN1 = { … … 10504 11712 }; 10505 11713 10506 #define xxreadtoken_doubles \10507 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))10508 #define xxreadtoken_singles \10509 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)10510 10511 11714 static int 10512 11715 xxreadtoken(void) … … 10518 11721 return lasttoken; 10519 11722 } 10520 if (needprompt) { 10521 setprompt(2); 10522 } 10523 startlinno = plinno; 11723 setprompt_if(needprompt, 2); 11724 startlinno = g_parsefile->linno; 10524 11725 for (;;) { /* until token or start of word found */ 10525 c = pgetc_macro(); 10526 10527 if ((c != ' ') && (c != '\t') 10528 #if ENABLE_ASH_ALIAS 10529 && (c != PEOA) 10530 #endif 10531 ) { 10532 if (c == '#') { 10533 while ((c = pgetc()) != '\n' && c != PEOF); 11726 c = pgetc_fast(); 11727 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA)) 11728 continue; 11729 11730 if (c == '#') { 11731 while ((c = pgetc()) != '\n' && c != PEOF) 11732 continue; 11733 pungetc(); 11734 } else if (c == '\\') { 11735 if (pgetc() != '\n') { 10534 11736 pungetc(); 10535 } else if (c == '\\') { 10536 if (pgetc() != '\n') { 10537 pungetc(); 10538 goto READTOKEN1; 11737 break; /* return readtoken1(...) */ 11738 } 11739 startlinno = ++g_parsefile->linno; 11740 setprompt_if(doprompt, 2); 11741 } else { 11742 const char *p; 11743 11744 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1; 11745 if (c != PEOF) { 11746 if (c == '\n') { 11747 g_parsefile->linno++; 11748 needprompt = doprompt; 10539 11749 } 10540 startlinno = ++plinno; 10541 if (doprompt) 10542 setprompt(2); 10543 } else { 10544 const char *p 10545 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1; 10546 10547 if (c != PEOF) { 10548 if (c == '\n') { 10549 plinno++; 10550 needprompt = doprompt; 10551 } 10552 10553 p = strchr(xxreadtoken_chars, c); 10554 if (p == NULL) { 10555 READTOKEN1: 10556 return readtoken1(c, BASESYNTAX, (char *) NULL, 0); 10557 } 10558 10559 if (p - xxreadtoken_chars >= xxreadtoken_singles) { 10560 if (pgetc() == *p) { /* double occurrence? */ 10561 p += xxreadtoken_doubles + 1; 10562 } else { 10563 pungetc(); 10564 } 11750 11751 p = strchr(xxreadtoken_chars, c); 11752 if (p == NULL) 11753 break; /* return readtoken1(...) */ 11754 11755 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) { 11756 int cc = pgetc(); 11757 if (cc == c) { /* double occurrence? */ 11758 p += xxreadtoken_doubles + 1; 11759 } else { 11760 pungetc(); 11761 #if ENABLE_ASH_BASH_COMPAT 11762 if (c == '&' && cc == '>') /* &> */ 11763 break; /* return readtoken1(...) */ 11764 #endif 10565 11765 } 10566 11766 } 10567 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];10568 11767 } 10569 } 10570 } /* for */ 10571 } 10572 #else 11768 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars]; 11769 return lasttoken; 11770 } 11771 } /* for (;;) */ 11772 11773 return readtoken1(c, BASESYNTAX, (char *) NULL, 0); 11774 } 11775 #else /* old xxreadtoken */ 10573 11776 #define RETURN(token) return lasttoken = token 10574 11777 static int … … 10581 11784 return lasttoken; 10582 11785 } 10583 if (needprompt) { 10584 setprompt(2); 10585 } 10586 startlinno = plinno; 11786 setprompt_if(needprompt, 2); 11787 startlinno = g_parsefile->linno; 10587 11788 for (;;) { /* until token or start of word found */ 10588 c = pgetc_ macro();11789 c = pgetc_fast(); 10589 11790 switch (c) { 10590 11791 case ' ': case '\t': 10591 #if ENABLE_ASH_ALIAS 10592 case PEOA: 10593 #endif 11792 IF_ASH_ALIAS(case PEOA:) 10594 11793 continue; 10595 11794 case '#': 10596 while ((c = pgetc()) != '\n' && c != PEOF); 11795 while ((c = pgetc()) != '\n' && c != PEOF) 11796 continue; 10597 11797 pungetc(); 10598 11798 continue; 10599 11799 case '\\': 10600 11800 if (pgetc() == '\n') { 10601 startlinno = ++plinno; 10602 if (doprompt) 10603 setprompt(2); 11801 startlinno = ++g_parsefile->linno; 11802 setprompt_if(doprompt, 2); 10604 11803 continue; 10605 11804 } … … 10607 11806 goto breakloop; 10608 11807 case '\n': 10609 plinno++;11808 g_parsefile->linno++; 10610 11809 needprompt = doprompt; 10611 11810 RETURN(TNL); … … 10639 11838 #undef RETURN 10640 11839 } 10641 #endif /* NEW_xxreadtoken */11840 #endif /* old xxreadtoken */ 10642 11841 10643 11842 static int … … 10646 11845 int t; 10647 11846 #if DEBUG 10648 int alreadyseen = tokpushback;11847 smallint alreadyseen = tokpushback; 10649 11848 #endif 10650 11849 … … 10678 11877 if (pp) { 10679 11878 lasttoken = t = pp - tokname_array; 10680 TRACE(("keyword %s recognized\n", tokname(t)));11879 TRACE(("keyword '%s' recognized\n", tokname_array[t] + 1)); 10681 11880 goto out; 10682 11881 } … … 10699 11898 #if DEBUG 10700 11899 if (!alreadyseen) 10701 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));11900 TRACE(("token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : "")); 10702 11901 else 10703 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));11902 TRACE(("reread token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : "")); 10704 11903 #endif 10705 11904 return t; … … 10712 11911 10713 11912 t = readtoken(); 10714 tokpushback ++;11913 tokpushback = 1; 10715 11914 return tokname_array[t][0]; 10716 11915 } 10717 11916 10718 11917 /* 10719 * Read and parse a command. Returns N EOF on end of file. (NULL is a10720 * valid parse tree indicating a blank line.)11918 * Read and parse a command. Returns NODE_EOF on end of file. 11919 * (NULL is a valid parse tree indicating a blank line.) 10721 11920 */ 10722 11921 static union node * … … 10727 11926 tokpushback = 0; 10728 11927 doprompt = interact; 10729 if (doprompt) 10730 setprompt(doprompt); 11928 setprompt_if(doprompt, doprompt); 10731 11929 needprompt = 0; 10732 11930 t = readtoken(); 10733 11931 if (t == TEOF) 10734 return N EOF;11932 return NODE_EOF; 10735 11933 if (t == TNL) 10736 11934 return NULL; 10737 tokpushback ++;11935 tokpushback = 1; 10738 11936 return list(1); 10739 11937 } … … 10749 11947 10750 11948 here = heredoclist; 10751 heredoclist = 0;11949 heredoclist = NULL; 10752 11950 10753 11951 while (here) { 10754 if (needprompt) { 10755 setprompt(2); 10756 } 10757 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, 11952 setprompt_if(needprompt, 2); 11953 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX, 10758 11954 here->eofmark, here->striptabs); 10759 n = st alloc(sizeof(struct narg));11955 n = stzalloc(sizeof(struct narg)); 10760 11956 n->narg.type = NARG; 10761 n->narg.next = NULL;11957 /*n->narg.next = NULL; - stzalloc did it */ 10762 11958 n->narg.text = wordtext; 10763 11959 n->narg.backquote = backquotelist; … … 10777 11973 union node n; 10778 11974 10779 /* XXX Fix (char *) cast. */ 11975 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value, 11976 * and token processing _can_ alter it (delete NULs etc). */ 10780 11977 setinputstring((char *)ps); 10781 readtoken1(pgetc(), DQSYNTAX, nullstr, 0);11978 readtoken1(pgetc(), PSSYNTAX, nullstr, 0); 10782 11979 popfile(); 10783 11980 … … 10806 12003 10807 12004 skip = 0; 10808 while ((n = parsecmd(0)) != N EOF) {12005 while ((n = parsecmd(0)) != NODE_EOF) { 10809 12006 evaltree(n, 0); 10810 12007 popstackmark(&smark); … … 10823 12020 * The eval command. 10824 12021 */ 10825 static int 10826 evalcmd(int argc , char **argv)12022 static int FAST_FUNC 12023 evalcmd(int argc UNUSED_PARAM, char **argv) 10827 12024 { 10828 12025 char *p; 10829 12026 char *concat; 10830 char **ap; 10831 10832 if (argc > 1) { 12027 12028 if (argv[1]) { 10833 12029 p = argv[1]; 10834 if (argc > 2) { 12030 argv += 2; 12031 if (argv[0]) { 10835 12032 STARTSTACKSTR(concat); 10836 ap = argv + 2;10837 12033 for (;;) { 10838 12034 concat = stack_putstr(p, concat); 10839 p = *a p++;12035 p = *argv++; 10840 12036 if (p == NULL) 10841 12037 break; … … 10846 12042 } 10847 12043 evalstring(p, ~SKIPEVAL); 10848 10849 12044 } 10850 12045 return exitstatus; … … 10852 12047 10853 12048 /* 10854 * Read and execute commands. "Top" is nonzero for the top level command 10855 * loop; it turns on prompting if the shell is interactive. 12049 * Read and execute commands. 12050 * "Top" is nonzero for the top level command loop; 12051 * it turns on prompting if the shell is interactive. 10856 12052 */ 10857 12053 static int … … 10869 12065 setstackmark(&smark); 10870 12066 #if JOBS 10871 if ( jobctl)12067 if (doing_jobctl) 10872 12068 showjobs(stderr, SHOW_CHANGED); 10873 12069 #endif … … 10880 12076 } 10881 12077 n = parsecmd(inter); 10882 /* showtree(n); DEBUG */ 10883 if (n == NEOF) { 12078 #if DEBUG 12079 if (DEBUG > 2 && debug && (n != NODE_EOF)) 12080 showtree(n); 12081 #endif 12082 if (n == NODE_EOF) { 10884 12083 if (!top || numeof >= 50) 10885 12084 break; … … 10922 12121 return name; 10923 12122 10924 while ((fullname = padvance(&path, name)) != NULL) { 12123 /* IIRC standards do not say whether . is to be searched. 12124 * And it is even smaller this way, making it unconditional for now: 12125 */ 12126 if (1) { /* ENABLE_ASH_BASH_COMPAT */ 12127 fullname = name; 12128 goto try_cur_dir; 12129 } 12130 12131 while ((fullname = path_advance(&path, name)) != NULL) { 12132 try_cur_dir: 10925 12133 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) { 10926 12134 /* … … 10930 12138 return fullname; 10931 12139 } 10932 stunalloc(fullname); 12140 if (fullname != name) 12141 stunalloc(fullname); 10933 12142 } 10934 12143 … … 10938 12147 } 10939 12148 10940 static int 12149 static int FAST_FUNC 10941 12150 dotcmd(int argc, char **argv) 10942 12151 { 12152 char *fullname; 10943 12153 struct strlist *sp; 10944 12154 volatile struct shparam saveparam; 10945 int status = 0;10946 12155 10947 12156 for (sp = cmdenviron; sp; sp = sp->next) 10948 12157 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED); 10949 12158 10950 if (argc >= 2) { /* That's what SVR2 does */ 10951 char *fullname; 10952 10953 fullname = find_dot_file(argv[1]); 10954 10955 if (argc > 2) { 10956 saveparam = shellparam; 10957 shellparam.malloc = 0; 10958 shellparam.nparam = argc - 2; 10959 shellparam.p = argv + 2; 10960 }; 10961 10962 setinputfile(fullname, INPUT_PUSH_FILE); 10963 commandname = fullname; 10964 cmdloop(0); 10965 popfile(); 10966 10967 if (argc > 2) { 10968 freeparam(&shellparam); 10969 shellparam = saveparam; 10970 }; 10971 status = exitstatus; 10972 } 10973 return status; 10974 } 10975 10976 static int 10977 exitcmd(int argc, char **argv) 12159 if (!argv[1]) { 12160 /* bash says: "bash: .: filename argument required" */ 12161 return 2; /* bash compat */ 12162 } 12163 12164 /* "false; . empty_file; echo $?" should print 0, not 1: */ 12165 exitstatus = 0; 12166 12167 fullname = find_dot_file(argv[1]); 12168 12169 argv += 2; 12170 argc -= 2; 12171 if (argc) { /* argc > 0, argv[0] != NULL */ 12172 saveparam = shellparam; 12173 shellparam.malloced = 0; 12174 shellparam.nparam = argc; 12175 shellparam.p = argv; 12176 }; 12177 12178 setinputfile(fullname, INPUT_PUSH_FILE); 12179 commandname = fullname; 12180 cmdloop(0); 12181 popfile(); 12182 12183 if (argc) { 12184 freeparam(&shellparam); 12185 shellparam = saveparam; 12186 }; 12187 12188 return exitstatus; 12189 } 12190 12191 static int FAST_FUNC 12192 exitcmd(int argc UNUSED_PARAM, char **argv) 10978 12193 { 10979 12194 if (stoppedjobs()) 10980 12195 return 0; 10981 if (arg c > 1)12196 if (argv[1]) 10982 12197 exitstatus = number(argv[1]); 10983 12198 raise_exception(EXEXIT); 10984 12199 /* NOTREACHED */ 10985 12200 } 10986 10987 #if ENABLE_ASH_BUILTIN_ECHO10988 static int10989 echocmd(int argc, char **argv)10990 {10991 return bb_echo(argv);10992 }10993 #endif10994 10995 #if ENABLE_ASH_BUILTIN_TEST10996 static int10997 testcmd(int argc, char **argv)10998 {10999 return test_main(argc, argv);11000 }11001 #endif11002 12201 11003 12202 /* … … 11099 12298 11100 12299 #if ENABLE_FEATURE_SH_STANDALONE 11101 if (find_applet_by_name(name)) { 11102 entry->cmdtype = CMDNORMAL; 11103 entry->u.index = -1; 11104 return; 12300 { 12301 int applet_no = find_applet_by_name(name); 12302 if (applet_no >= 0) { 12303 entry->cmdtype = CMDNORMAL; 12304 entry->u.index = -2 - applet_no; 12305 return; 12306 } 11105 12307 } 11106 12308 #endif … … 11118 12320 idx = -1; 11119 12321 loop: 11120 while ((fullname = pa dvance(&path, name)) != NULL) {12322 while ((fullname = path_advance(&path, name)) != NULL) { 11121 12323 stunalloc(fullname); 11122 12324 /* NB: code below will still use fullname … … 11128 12330 goto builtin_success; 11129 12331 continue; 11130 } else if (!(act & DO_NOFUNC) 11131 && prefix(pathopt, "func")) { 11132 /* handled below */ 11133 } else { 11134 /* ignore unimplemented options */ 12332 } 12333 if ((act & DO_NOFUNC) 12334 || !prefix(pathopt, "func") 12335 ) { /* ignore unimplemented options */ 11135 12336 continue; 11136 12337 } … … 11212 12413 * The trap builtin. 11213 12414 */ 11214 static int 11215 trapcmd(int argc , char **argv)12415 static int FAST_FUNC 12416 trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 11216 12417 { 11217 12418 char *action; 11218 12419 char **ap; 11219 int signo ;12420 int signo, exitcode; 11220 12421 11221 12422 nextopt(nullstr); … … 11223 12424 if (!*ap) { 11224 12425 for (signo = 0; signo < NSIG; signo++) { 11225 if (trap[signo] != NULL) { 11226 const char *sn; 11227 11228 sn = get_signame(signo); 12426 char *tr = trap_ptr[signo]; 12427 if (tr) { 12428 /* note: bash adds "SIG", but only if invoked 12429 * as "bash". If called as "sh", or if set -o posix, 12430 * then it prints short signal names. 12431 * We are printing short names: */ 11229 12432 out1fmt("trap -- %s %s\n", 11230 single_quote(trap[signo]), sn); 12433 single_quote(tr), 12434 get_signame(signo)); 12435 /* trap_ptr != trap only if we are in special-cased `trap` code. 12436 * In this case, we will exit very soon, no need to free(). */ 12437 /* if (trap_ptr != trap && tp[0]) */ 12438 /* free(tr); */ 11231 12439 } 11232 12440 } 12441 /* 12442 if (trap_ptr != trap) { 12443 free(trap_ptr); 12444 trap_ptr = trap; 12445 } 12446 */ 11233 12447 return 0; 11234 12448 } 11235 if (!ap[1]) 11236 11237 else12449 12450 action = NULL; 12451 if (ap[1]) 11238 12452 action = *ap++; 12453 exitcode = 0; 11239 12454 while (*ap) { 11240 12455 signo = get_signum(*ap); 11241 if (signo < 0) 11242 ash_msg_and_raise_error("%s: bad trap", *ap); 12456 if (signo < 0) { 12457 /* Mimic bash message exactly */ 12458 ash_msg("%s: invalid signal specification", *ap); 12459 exitcode = 1; 12460 goto next; 12461 } 11243 12462 INT_OFF; 11244 12463 if (action) { … … 11248 12467 action = ckstrdup(action); 11249 12468 } 11250 if (trap[signo]) 11251 free(trap[signo]); 12469 free(trap[signo]); 12470 if (action) 12471 may_have_traps = 1; 11252 12472 trap[signo] = action; 11253 12473 if (signo != 0) 11254 12474 setsignal(signo); 11255 12475 INT_ON; 12476 next: 11256 12477 ap++; 11257 12478 } 11258 return 0;12479 return exitcode; 11259 12480 } 11260 12481 … … 11266 12487 * Lists available builtins 11267 12488 */ 11268 static int 11269 helpcmd(int argc, char **argv) 11270 { 11271 int col, i; 11272 11273 out1fmt("\nBuilt-in commands:\n-------------------\n"); 12489 static int FAST_FUNC 12490 helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 12491 { 12492 unsigned col; 12493 unsigned i; 12494 12495 out1fmt( 12496 "Built-in commands:\n" 12497 "------------------\n"); 11274 12498 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) { 11275 12499 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), … … 11281 12505 } 11282 12506 #if ENABLE_FEATURE_SH_STANDALONE 11283 for (i = 0; i < NUM_APPLETS; i++) { 11284 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name); 11285 if (col > 60) { 11286 out1fmt("\n"); 11287 col = 0; 12507 { 12508 const char *a = applet_names; 12509 while (*a) { 12510 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a); 12511 if (col > 60) { 12512 out1fmt("\n"); 12513 col = 0; 12514 } 12515 a += strlen(a) + 1; 11288 12516 } 11289 12517 } … … 11297 12525 * The export and readonly commands. 11298 12526 */ 11299 static int 11300 exportcmd(int argc , char **argv)12527 static int FAST_FUNC 12528 exportcmd(int argc UNUSED_PARAM, char **argv) 11301 12529 { 11302 12530 struct var *vp; … … 11304 12532 const char *p; 11305 12533 char **aptr; 11306 int flag = argv[0][0] == 'r' ? VREADONLY : VEXPORT;12534 int flag = argv[0][0] == 'r' ? VREADONLY : VEXPORT; 11307 12535 11308 12536 if (nextopt("p") != 'p') { … … 11339 12567 11340 12568 cmdp = cmdlookup(name, 0); 11341 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)12569 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION) 11342 12570 delete_cmd_entry(); 11343 12571 } … … 11348 12576 * with the same name. 11349 12577 */ 11350 static int 11351 unsetcmd(int argc , char **argv)12578 static int FAST_FUNC 12579 unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 11352 12580 { 11353 12581 char **ap; … … 11356 12584 int ret = 0; 11357 12585 11358 while ((i = nextopt("vf")) != '\0') {12586 while ((i = nextopt("vf")) != 0) { 11359 12587 flag = i; 11360 12588 } … … 11372 12600 return ret & 1; 11373 12601 } 11374 11375 11376 /* setmode.c */11377 11378 #include <sys/times.h>11379 12602 11380 12603 static const unsigned char timescmd_str[] ALIGN1 = { … … 11385 12608 0 11386 12609 }; 11387 11388 static int 11389 timescmd(int ac, char **av) 11390 { 11391 long clk_tck, s, t; 12610 static int FAST_FUNC 12611 timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 12612 { 12613 unsigned long clk_tck, s, t; 11392 12614 const unsigned char *p; 11393 12615 struct tms buf; … … 11400 12622 t = *(clock_t *)(((char *) &buf) + p[1]); 11401 12623 s = t / clk_tck; 11402 out1fmt("%ldm%ld.%.3lds%c", 11403 s/60, s%60, 11404 ((t - s * clk_tck) * 1000) / clk_tck, 12624 t = t % clk_tck; 12625 out1fmt("%lum%lu.%03lus%c", 12626 s / 60, s % 60, 12627 (t * 1000) / clk_tck, 11405 12628 p[0]); 11406 } while (*(p += 2)); 12629 p += 2; 12630 } while (*p); 11407 12631 11408 12632 return 0; 11409 12633 } 11410 12634 11411 #if ENABLE_ASH_MATH_SUPPORT 11412 static arith_t 11413 dash_arith(const char *s) 11414 { 11415 arith_t result; 11416 int errcode = 0; 11417 11418 INT_OFF; 11419 result = arith(s, &errcode); 11420 if (errcode < 0) { 11421 if (errcode == -3) 11422 ash_msg_and_raise_error("exponent less than 0"); 11423 if (errcode == -2) 11424 ash_msg_and_raise_error("divide by zero"); 11425 if (errcode == -5) 11426 ash_msg_and_raise_error("expression recursion loop detected"); 11427 raise_error_syntax(s); 11428 } 11429 INT_ON; 11430 11431 return result; 11432 } 11433 11434 /* 11435 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell. 11436 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc. 12635 #if ENABLE_SH_MATH_SUPPORT 12636 /* 12637 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell. 12638 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc. 11437 12639 * 11438 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru> 11439 */ 11440 static int 11441 letcmd(int argc, char **argv) 11442 { 11443 char **ap; 11444 arith_t i = 0; 11445 11446 ap = argv + 1; 11447 if (!*ap) 12640 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru> 12641 */ 12642 static int FAST_FUNC 12643 letcmd(int argc UNUSED_PARAM, char **argv) 12644 { 12645 arith_t i; 12646 12647 argv++; 12648 if (!*argv) 11448 12649 ash_msg_and_raise_error("expression expected"); 11449 for (ap = argv + 1; *ap; ap++){11450 i = dash_arith(*ap);11451 } 12650 do { 12651 i = ash_arith(*argv); 12652 } while (*++argv); 11452 12653 11453 12654 return !i; 11454 12655 } 11455 #endif /* ASH_MATH_SUPPORT */ 11456 11457 11458 /* ============ miscbltin.c 11459 * 11460 * Miscellaneous builtins. 11461 */ 11462 11463 #undef rflag 11464 11465 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1 11466 typedef enum __rlimit_resource rlim_t; 11467 #endif 11468 11469 /* 11470 * The read builtin. The -e option causes backslashes to escape the 11471 * following character. 11472 * 12656 #endif 12657 12658 /* 12659 * The read builtin. Options: 12660 * -r Do not interpret '\' specially 12661 * -s Turn off echo (tty only) 12662 * -n NCHARS Read NCHARS max 12663 * -p PROMPT Display PROMPT on stderr (if input is from tty) 12664 * -t SECONDS Timeout after SECONDS (tty or pipe only) 12665 * -u FD Read from given FD instead of fd 0 11473 12666 * This uses unbuffered input, which may be avoidable in some cases. 11474 */ 11475 static int 11476 readcmd(int argc, char **argv) 11477 { 11478 char **ap; 11479 int backslash; 11480 char c; 11481 int rflag; 11482 char *prompt; 11483 const char *ifs; 11484 char *p; 11485 int startword; 11486 int status; 12667 * TODO: bash also has: 12668 * -a ARRAY Read into array[0],[1],etc 12669 * -d DELIM End on DELIM char, not newline 12670 * -e Use line editing (tty only) 12671 */ 12672 static int FAST_FUNC 12673 readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 12674 { 12675 char *opt_n = NULL; 12676 char *opt_p = NULL; 12677 char *opt_t = NULL; 12678 char *opt_u = NULL; 12679 int read_flags = 0; 12680 const char *r; 11487 12681 int i; 11488 #if ENABLE_ASH_READ_NCHARS 11489 int nch_flag = 0; 11490 int nchars = 0; 11491 int silent = 0; 11492 struct termios tty, old_tty; 11493 #endif 11494 #if ENABLE_ASH_READ_TIMEOUT 11495 fd_set set; 11496 struct timeval ts; 11497 11498 ts.tv_sec = ts.tv_usec = 0; 11499 #endif 11500 11501 rflag = 0; 11502 prompt = NULL; 11503 #if ENABLE_ASH_READ_NCHARS && ENABLE_ASH_READ_TIMEOUT 11504 while ((i = nextopt("p:rt:n:s")) != '\0') 11505 #elif ENABLE_ASH_READ_NCHARS 11506 while ((i = nextopt("p:rn:s")) != '\0') 11507 #elif ENABLE_ASH_READ_TIMEOUT 11508 while ((i = nextopt("p:rt:")) != '\0') 11509 #else 11510 while ((i = nextopt("p:r")) != '\0') 11511 #endif 11512 { 12682 12683 while ((i = nextopt("p:u:rt:n:s")) != '\0') { 11513 12684 switch (i) { 11514 12685 case 'p': 11515 prompt= optionarg;12686 opt_p = optionarg; 11516 12687 break; 11517 #if ENABLE_ASH_READ_NCHARS11518 12688 case 'n': 11519 nchars = strtol(optionarg, &p, 10); 11520 if (*p) 11521 ash_msg_and_raise_error("invalid count"); 11522 nch_flag = (nchars > 0); 12689 opt_n = optionarg; 11523 12690 break; 11524 12691 case 's': 11525 silent = 1;12692 read_flags |= BUILTIN_READ_SILENT; 11526 12693 break; 11527 #endif11528 #if ENABLE_ASH_READ_TIMEOUT11529 12694 case 't': 11530 ts.tv_sec = strtol(optionarg, &p, 10); 11531 ts.tv_usec = 0; 11532 if (*p == '.') { 11533 char *p2; 11534 if (*++p) { 11535 int scale; 11536 ts.tv_usec = strtol(p, &p2, 10); 11537 if (*p2) 11538 ash_msg_and_raise_error("invalid timeout"); 11539 scale = p2 - p; 11540 /* normalize to usec */ 11541 if (scale > 6) 11542 ash_msg_and_raise_error("invalid timeout"); 11543 while (scale++ < 6) 11544 ts.tv_usec *= 10; 11545 } 11546 } else if (*p) { 11547 ash_msg_and_raise_error("invalid timeout"); 11548 } 11549 if ( ! ts.tv_sec && ! ts.tv_usec) 11550 ash_msg_and_raise_error("invalid timeout"); 12695 opt_t = optionarg; 11551 12696 break; 11552 #endif11553 12697 case 'r': 11554 rflag = 1; 12698 read_flags |= BUILTIN_READ_RAW; 12699 break; 12700 case 'u': 12701 opt_u = optionarg; 11555 12702 break; 11556 12703 default: … … 11558 12705 } 11559 12706 } 11560 if (prompt && isatty(0)) { 11561 out2str(prompt); 11562 } 11563 ap = argptr; 11564 if (*ap == NULL) 11565 ash_msg_and_raise_error("arg count"); 11566 ifs = bltinlookup("IFS"); 11567 if (ifs == NULL) 11568 ifs = defifs; 11569 #if ENABLE_ASH_READ_NCHARS 11570 if (nch_flag || silent) { 11571 tcgetattr(0, &tty); 11572 old_tty = tty; 11573 if (nch_flag) { 11574 tty.c_lflag &= ~ICANON; 11575 tty.c_cc[VMIN] = nchars; 11576 } 11577 if (silent) { 11578 tty.c_lflag &= ~(ECHO|ECHOK|ECHONL); 11579 11580 } 11581 tcsetattr(0, TCSANOW, &tty); 11582 } 11583 #endif 11584 #if ENABLE_ASH_READ_TIMEOUT 11585 if (ts.tv_sec || ts.tv_usec) { 11586 FD_ZERO(&set); 11587 FD_SET(0, &set); 11588 11589 i = select(FD_SETSIZE, &set, NULL, NULL, &ts); 11590 if (!i) { 11591 #if ENABLE_ASH_READ_NCHARS 11592 if (nch_flag) 11593 tcsetattr(0, TCSANOW, &old_tty); 11594 #endif 11595 return 1; 11596 } 11597 } 11598 #endif 11599 status = 0; 11600 startword = 1; 11601 backslash = 0; 11602 STARTSTACKSTR(p); 11603 #if ENABLE_ASH_READ_NCHARS 11604 while (!nch_flag || nchars--) 11605 #else 11606 for (;;) 11607 #endif 11608 { 11609 if (read(0, &c, 1) != 1) { 11610 status = 1; 11611 break; 11612 } 11613 if (c == '\0') 11614 continue; 11615 if (backslash) { 11616 backslash = 0; 11617 if (c != '\n') 11618 goto put; 11619 continue; 11620 } 11621 if (!rflag && c == '\\') { 11622 backslash++; 11623 continue; 11624 } 11625 if (c == '\n') 11626 break; 11627 if (startword && *ifs == ' ' && strchr(ifs, c)) { 11628 continue; 11629 } 11630 startword = 0; 11631 if (ap[1] != NULL && strchr(ifs, c) != NULL) { 11632 STACKSTRNUL(p); 11633 setvar(*ap, stackblock(), 0); 11634 ap++; 11635 startword = 1; 11636 STARTSTACKSTR(p); 11637 } else { 11638 put: 11639 STPUTC(c, p); 11640 } 11641 } 11642 #if ENABLE_ASH_READ_NCHARS 11643 if (nch_flag || silent) 11644 tcsetattr(0, TCSANOW, &old_tty); 11645 #endif 11646 11647 STACKSTRNUL(p); 11648 /* Remove trailing blanks */ 11649 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL) 11650 *p = '\0'; 11651 setvar(*ap, stackblock(), 0); 11652 while (*++ap != NULL) 11653 setvar(*ap, nullstr, 0); 11654 return status; 11655 } 11656 11657 static int 11658 umaskcmd(int argc, char **argv) 12707 12708 r = shell_builtin_read(setvar2, 12709 argptr, 12710 bltinlookup("IFS"), /* can be NULL */ 12711 read_flags, 12712 opt_n, 12713 opt_p, 12714 opt_t, 12715 opt_u 12716 ); 12717 12718 if ((uintptr_t)r > 1) 12719 ash_msg_and_raise_error(r); 12720 12721 return (uintptr_t)r; 12722 } 12723 12724 static int FAST_FUNC 12725 umaskcmd(int argc UNUSED_PARAM, char **argv) 11659 12726 { 11660 12727 static const char permuser[3] ALIGN1 = "ugo"; … … 11665 12732 S_IROTH, S_IWOTH, S_IXOTH 11666 12733 }; 12734 12735 /* TODO: use bb_parse_mode() instead */ 11667 12736 11668 12737 char *ap; … … 11708 12777 do { 11709 12778 if (*ap >= '8' || *ap < '0') 11710 ash_msg_and_raise_error( illnum, argv[1]);12779 ash_msg_and_raise_error(msg_illnum, argv[1]); 11711 12780 mask = (mask << 3) + (*ap - '0'); 11712 12781 } while (*++ap != '\0'); … … 11723 12792 } 11724 12793 11725 /* 11726 * ulimit builtin 11727 * 11728 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and 11729 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with 11730 * ash by J.T. Conklin. 11731 * 11732 * Public domain. 11733 */ 11734 11735 struct limits { 11736 const char *name; 11737 int cmd; 11738 int factor; /* multiply by to get rlim_{cur,max} values */ 11739 char option; 11740 }; 11741 11742 static const struct limits limits[] = { 11743 #ifdef RLIMIT_CPU 11744 { "time(seconds)", RLIMIT_CPU, 1, 't' }, 11745 #endif 11746 #ifdef RLIMIT_FSIZE 11747 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' }, 11748 #endif 11749 #ifdef RLIMIT_DATA 11750 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' }, 11751 #endif 11752 #ifdef RLIMIT_STACK 11753 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' }, 11754 #endif 11755 #ifdef RLIMIT_CORE 11756 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' }, 11757 #endif 11758 #ifdef RLIMIT_RSS 11759 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' }, 11760 #endif 11761 #ifdef RLIMIT_MEMLOCK 11762 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' }, 11763 #endif 11764 #ifdef RLIMIT_NPROC 11765 { "process", RLIMIT_NPROC, 1, 'p' }, 11766 #endif 11767 #ifdef RLIMIT_NOFILE 11768 { "nofiles", RLIMIT_NOFILE, 1, 'n' }, 11769 #endif 11770 #ifdef RLIMIT_AS 11771 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' }, 11772 #endif 11773 #ifdef RLIMIT_LOCKS 11774 { "locks", RLIMIT_LOCKS, 1, 'w' }, 11775 #endif 11776 { NULL, 0, 0, '\0' } 11777 }; 11778 11779 enum limtype { SOFT = 0x1, HARD = 0x2 }; 11780 11781 static void 11782 printlim(enum limtype how, const struct rlimit *limit, 11783 const struct limits *l) 11784 { 11785 rlim_t val; 11786 11787 val = limit->rlim_max; 11788 if (how & SOFT) 11789 val = limit->rlim_cur; 11790 11791 if (val == RLIM_INFINITY) 11792 out1fmt("unlimited\n"); 11793 else { 11794 val /= l->factor; 11795 out1fmt("%lld\n", (long long) val); 11796 } 11797 } 11798 11799 static int 11800 ulimitcmd(int argc, char **argv) 11801 { 11802 int c; 11803 rlim_t val = 0; 11804 enum limtype how = SOFT | HARD; 11805 const struct limits *l; 11806 int set, all = 0; 11807 int optc, what; 11808 struct rlimit limit; 11809 11810 what = 'f'; 11811 while ((optc = nextopt("HSa" 11812 #ifdef RLIMIT_CPU 11813 "t" 11814 #endif 11815 #ifdef RLIMIT_FSIZE 11816 "f" 11817 #endif 11818 #ifdef RLIMIT_DATA 11819 "d" 11820 #endif 11821 #ifdef RLIMIT_STACK 11822 "s" 11823 #endif 11824 #ifdef RLIMIT_CORE 11825 "c" 11826 #endif 11827 #ifdef RLIMIT_RSS 11828 "m" 11829 #endif 11830 #ifdef RLIMIT_MEMLOCK 11831 "l" 11832 #endif 11833 #ifdef RLIMIT_NPROC 11834 "p" 11835 #endif 11836 #ifdef RLIMIT_NOFILE 11837 "n" 11838 #endif 11839 #ifdef RLIMIT_AS 11840 "v" 11841 #endif 11842 #ifdef RLIMIT_LOCKS 11843 "w" 11844 #endif 11845 )) != '\0') 11846 switch (optc) { 11847 case 'H': 11848 how = HARD; 11849 break; 11850 case 'S': 11851 how = SOFT; 11852 break; 11853 case 'a': 11854 all = 1; 11855 break; 11856 default: 11857 what = optc; 11858 } 11859 11860 for (l = limits; l->option != what; l++) 11861 ; 11862 11863 set = *argptr ? 1 : 0; 11864 if (set) { 11865 char *p = *argptr; 11866 11867 if (all || argptr[1]) 11868 ash_msg_and_raise_error("too many arguments"); 11869 if (strncmp(p, "unlimited\n", 9) == 0) 11870 val = RLIM_INFINITY; 11871 else { 11872 val = (rlim_t) 0; 11873 11874 while ((c = *p++) >= '0' && c <= '9') { 11875 val = (val * 10) + (long)(c - '0'); 11876 if (val < (rlim_t) 0) 11877 break; 11878 } 11879 if (c) 11880 ash_msg_and_raise_error("bad number"); 11881 val *= l->factor; 11882 } 11883 } 11884 if (all) { 11885 for (l = limits; l->name; l++) { 11886 getrlimit(l->cmd, &limit); 11887 out1fmt("%-20s ", l->name); 11888 printlim(how, &limit, l); 11889 } 11890 return 0; 11891 } 11892 11893 getrlimit(l->cmd, &limit); 11894 if (set) { 11895 if (how & HARD) 11896 limit.rlim_max = val; 11897 if (how & SOFT) 11898 limit.rlim_cur = val; 11899 if (setrlimit(l->cmd, &limit) < 0) 11900 ash_msg_and_raise_error("error setting limit (%m)"); 11901 } else { 11902 printlim(how, &limit, l); 11903 } 11904 return 0; 11905 } 11906 11907 11908 /* ============ Math support */ 11909 11910 #if ENABLE_ASH_MATH_SUPPORT 11911 11912 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com> 11913 11914 Permission is hereby granted, free of charge, to any person obtaining 11915 a copy of this software and associated documentation files (the 11916 "Software"), to deal in the Software without restriction, including 11917 without limitation the rights to use, copy, modify, merge, publish, 11918 distribute, sublicense, and/or sell copies of the Software, and to 11919 permit persons to whom the Software is furnished to do so, subject to 11920 the following conditions: 11921 11922 The above copyright notice and this permission notice shall be 11923 included in all copies or substantial portions of the Software. 11924 11925 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 11926 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 11927 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 11928 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 11929 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 11930 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 11931 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 11932 */ 11933 11934 /* This is my infix parser/evaluator. It is optimized for size, intended 11935 * as a replacement for yacc-based parsers. However, it may well be faster 11936 * than a comparable parser written in yacc. The supported operators are 11937 * listed in #defines below. Parens, order of operations, and error handling 11938 * are supported. This code is thread safe. The exact expression format should 11939 * be that which POSIX specifies for shells. */ 11940 11941 /* The code uses a simple two-stack algorithm. See 11942 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html 11943 * for a detailed explanation of the infix-to-postfix algorithm on which 11944 * this is based (this code differs in that it applies operators immediately 11945 * to the stack instead of adding them to a queue to end up with an 11946 * expression). */ 11947 11948 /* To use the routine, call it with an expression string and error return 11949 * pointer */ 11950 11951 /* 11952 * Aug 24, 2001 Manuel Novoa III 11953 * 11954 * Reduced the generated code size by about 30% (i386) and fixed several bugs. 11955 * 11956 * 1) In arith_apply(): 11957 * a) Cached values of *numptr and &(numptr[-1]). 11958 * b) Removed redundant test for zero denominator. 11959 * 11960 * 2) In arith(): 11961 * a) Eliminated redundant code for processing operator tokens by moving 11962 * to a table-based implementation. Also folded handling of parens 11963 * into the table. 11964 * b) Combined all 3 loops which called arith_apply to reduce generated 11965 * code size at the cost of speed. 11966 * 11967 * 3) The following expressions were treated as valid by the original code: 11968 * 1() , 0! , 1 ( *3 ) . 11969 * These bugs have been fixed by internally enclosing the expression in 11970 * parens and then checking that all binary ops and right parens are 11971 * preceded by a valid expression (NUM_TOKEN). 11972 * 11973 * Note: It may be desirable to replace Aaron's test for whitespace with 11974 * ctype's isspace() if it is used by another busybox applet or if additional 11975 * whitespace chars should be considered. Look below the "#include"s for a 11976 * precompiler test. 11977 */ 11978 11979 /* 11980 * Aug 26, 2001 Manuel Novoa III 11981 * 11982 * Return 0 for null expressions. Pointed out by Vladimir Oleynik. 11983 * 11984 * Merge in Aaron's comments previously posted to the busybox list, 11985 * modified slightly to take account of my changes to the code. 11986 * 11987 */ 11988 11989 /* 11990 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru> 11991 * 11992 * - allow access to variable, 11993 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6) 11994 * - realize assign syntax (VAR=expr, +=, *= etc) 11995 * - realize exponentiation (** operator) 11996 * - realize comma separated - expr, expr 11997 * - realise ++expr --expr expr++ expr-- 11998 * - realise expr ? expr : expr (but, second expr calculate always) 11999 * - allow hexadecimal and octal numbers 12000 * - was restored loses XOR operator 12001 * - remove one goto label, added three ;-) 12002 * - protect $((num num)) as true zero expr (Manuel`s error) 12003 * - always use special isspace(), see comment from bash ;-) 12004 */ 12005 12006 #define arith_isspace(arithval) \ 12007 (arithval == ' ' || arithval == '\n' || arithval == '\t') 12008 12009 typedef unsigned char operator; 12010 12011 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the 12012 * precedence, and 3 high bits are an ID unique across operators of that 12013 * precedence. The ID portion is so that multiple operators can have the 12014 * same precedence, ensuring that the leftmost one is evaluated first. 12015 * Consider * and /. */ 12016 12017 #define tok_decl(prec,id) (((id)<<5)|(prec)) 12018 #define PREC(op) ((op) & 0x1F) 12019 12020 #define TOK_LPAREN tok_decl(0,0) 12021 12022 #define TOK_COMMA tok_decl(1,0) 12023 12024 #define TOK_ASSIGN tok_decl(2,0) 12025 #define TOK_AND_ASSIGN tok_decl(2,1) 12026 #define TOK_OR_ASSIGN tok_decl(2,2) 12027 #define TOK_XOR_ASSIGN tok_decl(2,3) 12028 #define TOK_PLUS_ASSIGN tok_decl(2,4) 12029 #define TOK_MINUS_ASSIGN tok_decl(2,5) 12030 #define TOK_LSHIFT_ASSIGN tok_decl(2,6) 12031 #define TOK_RSHIFT_ASSIGN tok_decl(2,7) 12032 12033 #define TOK_MUL_ASSIGN tok_decl(3,0) 12034 #define TOK_DIV_ASSIGN tok_decl(3,1) 12035 #define TOK_REM_ASSIGN tok_decl(3,2) 12036 12037 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */ 12038 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0) 12039 12040 /* conditional is right associativity too */ 12041 #define TOK_CONDITIONAL tok_decl(4,0) 12042 #define TOK_CONDITIONAL_SEP tok_decl(4,1) 12043 12044 #define TOK_OR tok_decl(5,0) 12045 12046 #define TOK_AND tok_decl(6,0) 12047 12048 #define TOK_BOR tok_decl(7,0) 12049 12050 #define TOK_BXOR tok_decl(8,0) 12051 12052 #define TOK_BAND tok_decl(9,0) 12053 12054 #define TOK_EQ tok_decl(10,0) 12055 #define TOK_NE tok_decl(10,1) 12056 12057 #define TOK_LT tok_decl(11,0) 12058 #define TOK_GT tok_decl(11,1) 12059 #define TOK_GE tok_decl(11,2) 12060 #define TOK_LE tok_decl(11,3) 12061 12062 #define TOK_LSHIFT tok_decl(12,0) 12063 #define TOK_RSHIFT tok_decl(12,1) 12064 12065 #define TOK_ADD tok_decl(13,0) 12066 #define TOK_SUB tok_decl(13,1) 12067 12068 #define TOK_MUL tok_decl(14,0) 12069 #define TOK_DIV tok_decl(14,1) 12070 #define TOK_REM tok_decl(14,2) 12071 12072 /* exponent is right associativity */ 12073 #define TOK_EXPONENT tok_decl(15,1) 12074 12075 /* For now unary operators. */ 12076 #define UNARYPREC 16 12077 #define TOK_BNOT tok_decl(UNARYPREC,0) 12078 #define TOK_NOT tok_decl(UNARYPREC,1) 12079 12080 #define TOK_UMINUS tok_decl(UNARYPREC+1,0) 12081 #define TOK_UPLUS tok_decl(UNARYPREC+1,1) 12082 12083 #define PREC_PRE (UNARYPREC+2) 12084 12085 #define TOK_PRE_INC tok_decl(PREC_PRE, 0) 12086 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1) 12087 12088 #define PREC_POST (UNARYPREC+3) 12089 12090 #define TOK_POST_INC tok_decl(PREC_POST, 0) 12091 #define TOK_POST_DEC tok_decl(PREC_POST, 1) 12092 12093 #define SPEC_PREC (UNARYPREC+4) 12094 12095 #define TOK_NUM tok_decl(SPEC_PREC, 0) 12096 #define TOK_RPAREN tok_decl(SPEC_PREC, 1) 12097 12098 #define NUMPTR (*numstackptr) 12099 12100 static int 12101 tok_have_assign(operator op) 12102 { 12103 operator prec = PREC(op); 12104 12105 convert_prec_is_assing(prec); 12106 return (prec == PREC(TOK_ASSIGN) || 12107 prec == PREC_PRE || prec == PREC_POST); 12108 } 12109 12110 static int 12111 is_right_associativity(operator prec) 12112 { 12113 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) 12114 || prec == PREC(TOK_CONDITIONAL)); 12115 } 12116 12117 typedef struct ARITCH_VAR_NUM { 12118 arith_t val; 12119 arith_t contidional_second_val; 12120 char contidional_second_val_initialized; 12121 char *var; /* if NULL then is regular number, 12122 else is variable name */ 12123 } v_n_t; 12124 12125 typedef struct CHK_VAR_RECURSIVE_LOOPED { 12126 const char *var; 12127 struct CHK_VAR_RECURSIVE_LOOPED *next; 12128 } chk_var_recursive_looped_t; 12129 12130 static chk_var_recursive_looped_t *prev_chk_var_recursive; 12131 12132 static int 12133 arith_lookup_val(v_n_t *t) 12134 { 12135 if (t->var) { 12136 const char * p = lookupvar(t->var); 12137 12138 if (p) { 12139 int errcode; 12140 12141 /* recursive try as expression */ 12142 chk_var_recursive_looped_t *cur; 12143 chk_var_recursive_looped_t cur_save; 12144 12145 for (cur = prev_chk_var_recursive; cur; cur = cur->next) { 12146 if (strcmp(cur->var, t->var) == 0) { 12147 /* expression recursion loop detected */ 12148 return -5; 12149 } 12150 } 12151 /* save current lookuped var name */ 12152 cur = prev_chk_var_recursive; 12153 cur_save.var = t->var; 12154 cur_save.next = cur; 12155 prev_chk_var_recursive = &cur_save; 12156 12157 t->val = arith (p, &errcode); 12158 /* restore previous ptr after recursiving */ 12159 prev_chk_var_recursive = cur; 12160 return errcode; 12161 } 12162 /* allow undefined var as 0 */ 12163 t->val = 0; 12164 } 12165 return 0; 12166 } 12167 12168 /* "applying" a token means performing it on the top elements on the integer 12169 * stack. For a unary operator it will only change the top element, but a 12170 * binary operator will pop two arguments and push a result */ 12171 static int 12172 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr) 12173 { 12174 v_n_t *numptr_m1; 12175 arith_t numptr_val, rez; 12176 int ret_arith_lookup_val; 12177 12178 /* There is no operator that can work without arguments */ 12179 if (NUMPTR == numstack) goto err; 12180 numptr_m1 = NUMPTR - 1; 12181 12182 /* check operand is var with noninteger value */ 12183 ret_arith_lookup_val = arith_lookup_val(numptr_m1); 12184 if (ret_arith_lookup_val) 12185 return ret_arith_lookup_val; 12186 12187 rez = numptr_m1->val; 12188 if (op == TOK_UMINUS) 12189 rez *= -1; 12190 else if (op == TOK_NOT) 12191 rez = !rez; 12192 else if (op == TOK_BNOT) 12193 rez = ~rez; 12194 else if (op == TOK_POST_INC || op == TOK_PRE_INC) 12195 rez++; 12196 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC) 12197 rez--; 12198 else if (op != TOK_UPLUS) { 12199 /* Binary operators */ 12200 12201 /* check and binary operators need two arguments */ 12202 if (numptr_m1 == numstack) goto err; 12203 12204 /* ... and they pop one */ 12205 --NUMPTR; 12206 numptr_val = rez; 12207 if (op == TOK_CONDITIONAL) { 12208 if (! numptr_m1->contidional_second_val_initialized) { 12209 /* protect $((expr1 ? expr2)) without ": expr" */ 12210 goto err; 12211 } 12212 rez = numptr_m1->contidional_second_val; 12213 } else if (numptr_m1->contidional_second_val_initialized) { 12214 /* protect $((expr1 : expr2)) without "expr ? " */ 12215 goto err; 12216 } 12217 numptr_m1 = NUMPTR - 1; 12218 if (op != TOK_ASSIGN) { 12219 /* check operand is var with noninteger value for not '=' */ 12220 ret_arith_lookup_val = arith_lookup_val(numptr_m1); 12221 if (ret_arith_lookup_val) 12222 return ret_arith_lookup_val; 12223 } 12224 if (op == TOK_CONDITIONAL) { 12225 numptr_m1->contidional_second_val = rez; 12226 } 12227 rez = numptr_m1->val; 12228 if (op == TOK_BOR || op == TOK_OR_ASSIGN) 12229 rez |= numptr_val; 12230 else if (op == TOK_OR) 12231 rez = numptr_val || rez; 12232 else if (op == TOK_BAND || op == TOK_AND_ASSIGN) 12233 rez &= numptr_val; 12234 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN) 12235 rez ^= numptr_val; 12236 else if (op == TOK_AND) 12237 rez = rez && numptr_val; 12238 else if (op == TOK_EQ) 12239 rez = (rez == numptr_val); 12240 else if (op == TOK_NE) 12241 rez = (rez != numptr_val); 12242 else if (op == TOK_GE) 12243 rez = (rez >= numptr_val); 12244 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN) 12245 rez >>= numptr_val; 12246 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN) 12247 rez <<= numptr_val; 12248 else if (op == TOK_GT) 12249 rez = (rez > numptr_val); 12250 else if (op == TOK_LT) 12251 rez = (rez < numptr_val); 12252 else if (op == TOK_LE) 12253 rez = (rez <= numptr_val); 12254 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN) 12255 rez *= numptr_val; 12256 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN) 12257 rez += numptr_val; 12258 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN) 12259 rez -= numptr_val; 12260 else if (op == TOK_ASSIGN || op == TOK_COMMA) 12261 rez = numptr_val; 12262 else if (op == TOK_CONDITIONAL_SEP) { 12263 if (numptr_m1 == numstack) { 12264 /* protect $((expr : expr)) without "expr ? " */ 12265 goto err; 12266 } 12267 numptr_m1->contidional_second_val_initialized = op; 12268 numptr_m1->contidional_second_val = numptr_val; 12269 } else if (op == TOK_CONDITIONAL) { 12270 rez = rez ? 12271 numptr_val : numptr_m1->contidional_second_val; 12272 } else if (op == TOK_EXPONENT) { 12273 if (numptr_val < 0) 12274 return -3; /* exponent less than 0 */ 12275 else { 12276 arith_t c = 1; 12277 12278 if (numptr_val) 12279 while (numptr_val--) 12280 c *= rez; 12281 rez = c; 12282 } 12283 } else if (numptr_val==0) /* zero divisor check */ 12284 return -2; 12285 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN) 12286 rez /= numptr_val; 12287 else if (op == TOK_REM || op == TOK_REM_ASSIGN) 12288 rez %= numptr_val; 12289 } 12290 if (tok_have_assign(op)) { 12291 char buf[sizeof(arith_t_type)*3 + 2]; 12292 12293 if (numptr_m1->var == NULL) { 12294 /* Hmm, 1=2 ? */ 12295 goto err; 12296 } 12297 /* save to shell variable */ 12298 #if ENABLE_ASH_MATH_SUPPORT_64 12299 snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez); 12300 #else 12301 snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez); 12302 #endif 12303 setvar(numptr_m1->var, buf, 0); 12304 /* after saving, make previous value for v++ or v-- */ 12305 if (op == TOK_POST_INC) 12306 rez--; 12307 else if (op == TOK_POST_DEC) 12308 rez++; 12309 } 12310 numptr_m1->val = rez; 12311 /* protect geting var value, is number now */ 12312 numptr_m1->var = NULL; 12313 return 0; 12314 err: 12315 return -1; 12316 } 12317 12318 /* longest must be first */ 12319 static const char op_tokens[] ALIGN1 = { 12320 '<','<','=',0, TOK_LSHIFT_ASSIGN, 12321 '>','>','=',0, TOK_RSHIFT_ASSIGN, 12322 '<','<', 0, TOK_LSHIFT, 12323 '>','>', 0, TOK_RSHIFT, 12324 '|','|', 0, TOK_OR, 12325 '&','&', 0, TOK_AND, 12326 '!','=', 0, TOK_NE, 12327 '<','=', 0, TOK_LE, 12328 '>','=', 0, TOK_GE, 12329 '=','=', 0, TOK_EQ, 12330 '|','=', 0, TOK_OR_ASSIGN, 12331 '&','=', 0, TOK_AND_ASSIGN, 12332 '*','=', 0, TOK_MUL_ASSIGN, 12333 '/','=', 0, TOK_DIV_ASSIGN, 12334 '%','=', 0, TOK_REM_ASSIGN, 12335 '+','=', 0, TOK_PLUS_ASSIGN, 12336 '-','=', 0, TOK_MINUS_ASSIGN, 12337 '-','-', 0, TOK_POST_DEC, 12338 '^','=', 0, TOK_XOR_ASSIGN, 12339 '+','+', 0, TOK_POST_INC, 12340 '*','*', 0, TOK_EXPONENT, 12341 '!', 0, TOK_NOT, 12342 '<', 0, TOK_LT, 12343 '>', 0, TOK_GT, 12344 '=', 0, TOK_ASSIGN, 12345 '|', 0, TOK_BOR, 12346 '&', 0, TOK_BAND, 12347 '*', 0, TOK_MUL, 12348 '/', 0, TOK_DIV, 12349 '%', 0, TOK_REM, 12350 '+', 0, TOK_ADD, 12351 '-', 0, TOK_SUB, 12352 '^', 0, TOK_BXOR, 12353 /* uniq */ 12354 '~', 0, TOK_BNOT, 12355 ',', 0, TOK_COMMA, 12356 '?', 0, TOK_CONDITIONAL, 12357 ':', 0, TOK_CONDITIONAL_SEP, 12358 ')', 0, TOK_RPAREN, 12359 '(', 0, TOK_LPAREN, 12360 0 12361 }; 12362 /* ptr to ")" */ 12363 #define endexpression &op_tokens[sizeof(op_tokens)-7] 12364 12365 static arith_t 12366 arith(const char *expr, int *perrcode) 12367 { 12368 char arithval; /* Current character under analysis */ 12369 operator lasttok, op; 12370 operator prec; 12371 12372 const char *p = endexpression; 12373 int errcode; 12374 12375 size_t datasizes = strlen(expr) + 2; 12376 12377 /* Stack of integers */ 12378 /* The proof that there can be no more than strlen(startbuf)/2+1 integers 12379 * in any given correct or incorrect expression is left as an exercise to 12380 * the reader. */ 12381 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)), 12382 *numstackptr = numstack; 12383 /* Stack of operator tokens */ 12384 operator *stack = alloca((datasizes) * sizeof(operator)), 12385 *stackptr = stack; 12386 12387 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */ 12388 *perrcode = errcode = 0; 12389 12390 while (1) { 12391 arithval = *expr; 12392 if (arithval == 0) { 12393 if (p == endexpression) { 12394 /* Null expression. */ 12395 return 0; 12396 } 12397 12398 /* This is only reached after all tokens have been extracted from the 12399 * input stream. If there are still tokens on the operator stack, they 12400 * are to be applied in order. At the end, there should be a final 12401 * result on the integer stack */ 12402 12403 if (expr != endexpression + 1) { 12404 /* If we haven't done so already, */ 12405 /* append a closing right paren */ 12406 expr = endexpression; 12407 /* and let the loop process it. */ 12408 continue; 12409 } 12410 /* At this point, we're done with the expression. */ 12411 if (numstackptr != numstack+1) { 12412 /* ... but if there isn't, it's bad */ 12413 err: 12414 return (*perrcode = -1); 12415 } 12416 if (numstack->var) { 12417 /* expression is $((var)) only, lookup now */ 12418 errcode = arith_lookup_val(numstack); 12419 } 12420 ret: 12421 *perrcode = errcode; 12422 return numstack->val; 12423 } 12424 12425 /* Continue processing the expression. */ 12426 if (arith_isspace(arithval)) { 12427 /* Skip whitespace */ 12428 goto prologue; 12429 } 12430 p = endofname(expr); 12431 if (p != expr) { 12432 size_t var_name_size = (p-expr) + 1; /* trailing zero */ 12433 12434 numstackptr->var = alloca(var_name_size); 12435 safe_strncpy(numstackptr->var, expr, var_name_size); 12436 expr = p; 12437 num: 12438 numstackptr->contidional_second_val_initialized = 0; 12439 numstackptr++; 12440 lasttok = TOK_NUM; 12441 continue; 12442 } 12443 if (isdigit(arithval)) { 12444 numstackptr->var = NULL; 12445 #if ENABLE_ASH_MATH_SUPPORT_64 12446 numstackptr->val = strtoll(expr, (char **) &expr, 0); 12447 #else 12448 numstackptr->val = strtol(expr, (char **) &expr, 0); 12449 #endif 12450 goto num; 12451 } 12452 for (p = op_tokens; ; p++) { 12453 const char *o; 12454 12455 if (*p == 0) { 12456 /* strange operator not found */ 12457 goto err; 12458 } 12459 for (o = expr; *p && *o == *p; p++) 12460 o++; 12461 if (! *p) { 12462 /* found */ 12463 expr = o - 1; 12464 break; 12465 } 12466 /* skip tail uncompared token */ 12467 while (*p) 12468 p++; 12469 /* skip zero delim */ 12470 p++; 12471 } 12472 op = p[1]; 12473 12474 /* post grammar: a++ reduce to num */ 12475 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC) 12476 lasttok = TOK_NUM; 12477 12478 /* Plus and minus are binary (not unary) _only_ if the last 12479 * token was as number, or a right paren (which pretends to be 12480 * a number, since it evaluates to one). Think about it. 12481 * It makes sense. */ 12482 if (lasttok != TOK_NUM) { 12483 switch (op) { 12484 case TOK_ADD: 12485 op = TOK_UPLUS; 12486 break; 12487 case TOK_SUB: 12488 op = TOK_UMINUS; 12489 break; 12490 case TOK_POST_INC: 12491 op = TOK_PRE_INC; 12492 break; 12493 case TOK_POST_DEC: 12494 op = TOK_PRE_DEC; 12495 break; 12496 } 12497 } 12498 /* We don't want a unary operator to cause recursive descent on the 12499 * stack, because there can be many in a row and it could cause an 12500 * operator to be evaluated before its argument is pushed onto the 12501 * integer stack. */ 12502 /* But for binary operators, "apply" everything on the operator 12503 * stack until we find an operator with a lesser priority than the 12504 * one we have just extracted. */ 12505 /* Left paren is given the lowest priority so it will never be 12506 * "applied" in this way. 12507 * if associativity is right and priority eq, applied also skip 12508 */ 12509 prec = PREC(op); 12510 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) { 12511 /* not left paren or unary */ 12512 if (lasttok != TOK_NUM) { 12513 /* binary op must be preceded by a num */ 12514 goto err; 12515 } 12516 while (stackptr != stack) { 12517 if (op == TOK_RPAREN) { 12518 /* The algorithm employed here is simple: while we don't 12519 * hit an open paren nor the bottom of the stack, pop 12520 * tokens and apply them */ 12521 if (stackptr[-1] == TOK_LPAREN) { 12522 --stackptr; 12523 /* Any operator directly after a */ 12524 lasttok = TOK_NUM; 12525 /* close paren should consider itself binary */ 12526 goto prologue; 12527 } 12528 } else { 12529 operator prev_prec = PREC(stackptr[-1]); 12530 12531 convert_prec_is_assing(prec); 12532 convert_prec_is_assing(prev_prec); 12533 if (prev_prec < prec) 12534 break; 12535 /* check right assoc */ 12536 if (prev_prec == prec && is_right_associativity(prec)) 12537 break; 12538 } 12539 errcode = arith_apply(*--stackptr, numstack, &numstackptr); 12540 if (errcode) goto ret; 12541 } 12542 if (op == TOK_RPAREN) { 12543 goto err; 12544 } 12545 } 12546 12547 /* Push this operator to the stack and remember it. */ 12548 *stackptr++ = lasttok = op; 12549 prologue: 12550 ++expr; 12551 } /* while */ 12552 } 12553 #endif /* ASH_MATH_SUPPORT */ 12554 12794 static int FAST_FUNC 12795 ulimitcmd(int argc UNUSED_PARAM, char **argv) 12796 { 12797 return shell_builtin_ulimit(argv); 12798 } 12555 12799 12556 12800 /* ============ main() and helpers */ … … 12559 12803 * Called to exit the shell. 12560 12804 */ 12561 static void exitshell(void) ATTRIBUTE_NORETURN;12805 static void exitshell(void) NORETURN; 12562 12806 static void 12563 12807 exitshell(void) … … 12570 12814 TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); 12571 12815 if (setjmp(loc.loc)) { 12572 if (exception == EXEXIT)12816 if (exception_type == EXEXIT) 12573 12817 /* dash bug: it just does _exit(exitstatus) here 12574 12818 * but we have to do setjobctl(0) first! … … 12583 12827 trap[0] = NULL; 12584 12828 evalstring(p, 0); 12829 free(p); 12585 12830 } 12586 12831 flush_stdout_stderr(); … … 12595 12840 { 12596 12841 /* from input.c: */ 12597 basepf.nextc = basepf.buf = basebuf; 12842 /* we will never free this */ 12843 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); 12598 12844 12599 12845 /* from trap.c: */ 12600 12846 signal(SIGCHLD, SIG_DFL); 12847 /* bash re-enables SIGHUP which is SIG_IGNed on entry. 12848 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$" 12849 */ 12850 signal(SIGHUP, SIG_DFL); 12601 12851 12602 12852 /* from var.c: */ 12603 12853 { 12604 12854 char **envp; 12605 char ppid[sizeof(int)*3 + 1];12606 12855 const char *p; 12607 12856 struct stat st1, st2; … … 12614 12863 } 12615 12864 12616 snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid()); 12617 setvar("PPID", ppid, 0); 12865 setvar("PPID", utoa(getppid()), 0); 12618 12866 12619 12867 p = lookupvar("PWD"); … … 12630 12878 */ 12631 12879 static void 12632 procargs( int argc,char **argv)12880 procargs(char **argv) 12633 12881 { 12634 12882 int i; … … 12638 12886 xargv = argv; 12639 12887 arg0 = xargv[0]; 12640 if (argc > 0)12888 /* if (xargv[0]) - mmm, this is always true! */ 12641 12889 xargv++; 12642 12890 for (i = 0; i < NOPTS; i++) 12643 12891 optlist[i] = 2; 12644 12892 argptr = xargv; 12645 options(1); 12893 if (options(1)) { 12894 /* it already printed err message */ 12895 raise_exception(EXERROR); 12896 } 12646 12897 xargv = argptr; 12647 12898 xminusc = minusc; … … 12678 12929 shellparam.optoff = -1; 12679 12930 #endif 12680 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */12931 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */ 12681 12932 while (*xargv) { 12682 12933 shellparam.nparam++; … … 12713 12964 loopnest = 0; 12714 12965 /* from input.c: */ 12715 parselleft = parsenleft = 0; /* clear input buffer */ 12966 g_parsefile->left_in_buffer = 0; 12967 g_parsefile->left_in_line = 0; /* clear input buffer */ 12716 12968 popallfiles(); 12717 12969 /* from parser.c: */ … … 12719 12971 checkkwd = 0; 12720 12972 /* from redir.c: */ 12721 clearredir( 0);12973 clearredir(/*drop:*/ 0); 12722 12974 } 12723 12975 … … 12734 12986 * is used to figure out how far we had gotten. 12735 12987 */ 12736 int ash_main(int argc, char **argv) ;12737 int ash_main(int argc , char **argv)12738 { 12739 c har *shinit;12740 volatile int state;12988 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 12989 int ash_main(int argc UNUSED_PARAM, char **argv) 12990 { 12991 const char *shinit; 12992 volatile smallint state; 12741 12993 struct jmploc jmploc; 12742 12994 struct stackmark smark; 12743 12995 12996 /* Initialize global data */ 12997 INIT_G_misc(); 12998 INIT_G_memstack(); 12999 INIT_G_var(); 13000 #if ENABLE_ASH_ALIAS 13001 INIT_G_alias(); 13002 #endif 13003 INIT_G_cmdtable(); 13004 12744 13005 #if PROFILE 12745 13006 monitor(4, etext, profile_buf, sizeof(profile_buf), 50); … … 12751 13012 state = 0; 12752 13013 if (setjmp(jmploc.loc)) { 12753 int e;12754 int s;13014 smallint e; 13015 smallint s; 12755 13016 12756 13017 reset(); 12757 13018 12758 e = exception ;13019 e = exception_type; 12759 13020 if (e == EXERROR) 12760 13021 exitstatus = 2; 12761 13022 s = state; 12762 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) 13023 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) { 12763 13024 exitshell(); 12764 13025 } 12765 13026 if (e == EXINT) { 12766 13027 outcslow('\n', stderr); 12767 13028 } 13029 12768 13030 popstackmark(&smark); 12769 13031 FORCE_INT_ON; /* enable interrupts */ … … 12779 13041 #if DEBUG 12780 13042 opentrace(); 12781 trace_puts("Shell args: ");13043 TRACE(("Shell args: ")); 12782 13044 trace_puts_args(argv); 12783 13045 #endif 12784 13046 rootpid = getpid(); 12785 13047 12786 #if ENABLE_ASH_RANDOM_SUPPORT12787 rseed = rootpid + time(NULL);12788 #endif12789 13048 init(); 12790 13049 setstackmark(&smark); 12791 procargs(argc, argv); 13050 procargs(argv); 13051 12792 13052 #if ENABLE_FEATURE_EDITING_SAVEHISTORY 12793 13053 if (iflag) { … … 12804 13064 } 12805 13065 #endif 12806 if ( argv[0] &&argv[0][0] == '-')13066 if (/* argv[0] && */ argv[0][0] == '-') 12807 13067 isloginsh = 1; 12808 13068 if (isloginsh) { … … 12828 13088 state3: 12829 13089 state = 4; 12830 if (minusc) 13090 if (minusc) { 13091 /* evalstring pushes parsefile stack. 13092 * Ensure we don't falsely claim that 0 (stdin) 13093 * is one of stacked source fds. 13094 * Testcase: ash -c 'exec 1>&0' must not complain. */ 13095 // if (!sflag) g_parsefile->pf_fd = -1; 13096 // ^^ not necessary since now we special-case fd 0 13097 // in is_hidden_fd() to not be considered "hidden fd" 12831 13098 evalstring(minusc, 0); 13099 } 12832 13100 12833 13101 if (sflag || minusc == NULL) { 12834 #if ENABLE_FEATURE_EDITING_SAVEHISTORY12835 if ( iflag) {13102 #if defined MAX_HISTORY && MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY 13103 if (iflag) { 12836 13104 const char *hp = lookupvar("HISTFILE"); 12837 12838 if (hp != NULL) 13105 if (hp) 12839 13106 line_input_state->hist_file = hp; 12840 13107 } … … 12852 13119 } 12853 13120 #endif 13121 TRACE(("End of main reached\n")); 12854 13122 exitshell(); 12855 13123 /* NOTREACHED */ 12856 13124 } 12857 12858 #if DEBUG12859 const char *applet_name = "debug stuff usage";12860 int main(int argc, char **argv)12861 {12862 return ash_main(argc, argv);12863 }12864 #endif12865 13125 12866 13126
Note:
See TracChangeset
for help on using the changeset viewer.