Changeset 3232 in MondoRescue for branches/3.2/mindi-busybox/shell
- Timestamp:
- Jan 1, 2014, 12:47:38 AM (10 years ago)
- Location:
- branches/3.2/mindi-busybox/shell
- Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/3.2/mindi-busybox/shell/Config.src
r2725 r3232 124 124 depends on (HUSH || ASH) && FEATURE_PREFER_APPLETS 125 125 help 126 This option causes busybox shells [currently only ash]127 to not execute typical fork/exec/wait sequence, but call <applet>_main128 directly,if possible. (Sometimes it is not possible: for example,126 This option causes busybox shells to not execute typical 127 fork/exec/wait sequence, but call <applet>_main directly, 128 if possible. (Sometimes it is not possible: for example, 129 129 this is not possible in pipes). 130 130 … … 134 134 This may significantly speed up some shell scripts. 135 135 136 This feature is relatively new. Use with care. 136 This feature is relatively new. Use with care. Report bugs 137 to project mailing list. 138 139 config FEATURE_SH_HISTFILESIZE 140 bool "Use $HISTFILESIZE" 141 default y 142 depends on HUSH || ASH 143 help 144 This option makes busybox shells to use $HISTFILESIZE variable 145 to set shell history size. Note that its max value is capped 146 by "History size" setting in library tuning section. 147 137 148 138 149 endmenu -
branches/3.2/mindi-busybox/shell/ash.c
r2725 r3232 24 24 * define DEBUG=2 to compile in and turn on debugging. 25 25 * 26 * When debugging is on, debugging info will be written to ./trace and 27 * a quit signal will generate a core dump. 26 * When debugging is on (DEBUG is 1 and "set -o debug" was executed), 27 * debugging info will be written to ./trace and a quit signal 28 * will generate a core dump. 28 29 */ 29 30 #define DEBUG 0 … … 37 38 #define JOBS ENABLE_ASH_JOB_CONTROL 38 39 39 #include "busybox.h" /* for applet_names */40 40 #include <paths.h> 41 41 #include <setjmp.h> 42 42 #include <fnmatch.h> 43 43 #include <sys/times.h> 44 45 #include "busybox.h" /* for applet_names */ 46 #include "unicode.h" 44 47 45 48 #include "shell_common.h" … … 72 75 # error "Do not even bother, ash will not run on NOMMU machine" 73 76 #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.o80 //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o81 77 82 78 //config:config ASH … … 98 94 //config: Enable bash-compatible extensions. 99 95 //config: 96 //config:config ASH_IDLE_TIMEOUT 97 //config: bool "Idle timeout variable" 98 //config: default n 99 //config: depends on ASH 100 //config: help 101 //config: Enables bash-like auto-logout after $TMOUT seconds of idle time. 102 //config: 100 103 //config:config ASH_JOB_CONTROL 101 104 //config: bool "Job control" … … 106 109 //config: 107 110 //config:config ASH_ALIAS 108 //config: bool " alias support"111 //config: bool "Alias support" 109 112 //config: default y 110 113 //config: depends on ASH … … 117 120 //config: depends on ASH 118 121 //config: help 119 //config: Enable getopts builtin in the ash shell.122 //config: Enable support for getopts builtin in ash. 120 123 //config: 121 124 //config:config ASH_BUILTIN_ECHO … … 124 127 //config: depends on ASH 125 128 //config: help 126 //config: Enable support for echo , builtin toash.129 //config: Enable support for echo builtin in ash. 127 130 //config: 128 131 //config:config ASH_BUILTIN_PRINTF … … 131 134 //config: depends on ASH 132 135 //config: help 133 //config: Enable support for printf , builtin toash.136 //config: Enable support for printf builtin in ash. 134 137 //config: 135 138 //config:config ASH_BUILTIN_TEST … … 138 141 //config: depends on ASH 139 142 //config: help 140 //config: Enable support for test , builtin toash.143 //config: Enable support for test builtin in ash. 141 144 //config: 142 145 //config:config ASH_CMDCMD … … 154 157 //config: depends on ASH 155 158 //config: help 156 //config: Enable "check for new mail" in the ash shell.159 //config: Enable "check for new mail" function in the ash shell. 157 160 //config: 158 161 //config:config ASH_OPTIMIZE_FOR_SIZE … … 184 187 //config: 185 188 186 // usage:#define ash_trivial_usage NOUSAGE_STR187 // usage:#define ash_full_usage ""188 // usage:#define sh_trivial_usage NOUSAGE_STR189 //usage:#define sh_full_usage "" 190 // usage:#define bash_trivial_usage NOUSAGE_STR191 // usage:#define bash_full_usage ""189 //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) 190 //applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh)) 191 //applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, bash)) 192 193 //kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o 194 //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o 192 195 193 196 … … 401 404 402 405 /* ============ Interrupts / exceptions */ 406 407 static void exitshell(void) NORETURN; 408 403 409 /* 404 410 * These macros allow the user to suspend the handling of interrupt signals … … 1881 1887 #if ENABLE_ASH_MAIL 1882 1888 static void chkmail(void); 1883 static void changemail(const char *) FAST_FUNC; 1889 static void changemail(const char *var_value) FAST_FUNC; 1890 #else 1891 # define chkmail() ((void)0) 1884 1892 #endif 1885 1893 static void changepath(const char *) FAST_FUNC; … … 1893 1901 void (*var_func)(const char *) FAST_FUNC; 1894 1902 } varinit_data[] = { 1903 /* 1904 * Note: VEXPORT would not work correctly here for NOFORK applets: 1905 * some environment strings may be constant. 1906 */ 1895 1907 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL }, 1896 1908 #if ENABLE_ASH_MAIL … … 3485 3497 case S_CATCH: 3486 3498 act.sa_handler = signal_handler; 3487 act.sa_flags = 0; /* matters only if !DFL and !IGN */3488 sigfillset(&act.sa_mask); /* ditto */3489 3499 break; 3490 3500 case S_IGN: … … 3492 3502 break; 3493 3503 } 3504 3505 /* flags and mask matter only if !DFL and !IGN, but we do it 3506 * for all cases for more deterministic behavior: 3507 */ 3508 act.sa_flags = 0; 3509 sigfillset(&act.sa_mask); 3510 3494 3511 sigaction_set(signo, &act); 3495 3512 … … 3528 3545 /* first remove from list */ 3529 3546 jpp = curp = &curjob; 3530 do{3547 while (1) { 3531 3548 jp1 = *jpp; 3532 3549 if (jp1 == jp) 3533 3550 break; 3534 3551 jpp = &jp1->prev_job; 3535 } while (1);3552 } 3536 3553 *jpp = jp1->prev_job; 3537 3554 … … 3548 3565 case CUR_RUNNING: 3549 3566 /* newly created job or backgrounded job, 3550 put after all stopped jobs. */ 3551 do { 3567 * put after all stopped jobs. 3568 */ 3569 while (1) { 3552 3570 jp1 = *jpp; 3553 3571 #if JOBS … … 3556 3574 break; 3557 3575 jpp = &jp1->prev_job; 3558 } while (1);3576 } 3559 3577 /* FALLTHROUGH */ 3560 3578 #if JOBS … … 3729 3747 /* fd is a tty at this point */ 3730 3748 close_on_exec_on(fd); 3731 do{ /* while we are in the background */3749 while (1) { /* while we are in the background */ 3732 3750 pgrp = tcgetpgrp(fd); 3733 3751 if (pgrp < 0) { … … 3740 3758 break; 3741 3759 killpg(0, SIGTTIN); 3742 } while (1);3760 } 3743 3761 initialpgrp = pgrp; 3744 3762 … … 3772 3790 killcmd(int argc, char **argv) 3773 3791 { 3774 int i = 1;3775 3792 if (argv[1] && strcmp(argv[1], "-l") != 0) { 3793 int i = 1; 3776 3794 do { 3777 3795 if (argv[i][0] == '%') { 3778 struct job *jp = getjob(argv[i], 0); 3779 unsigned pid = jp->ps[0].ps_pid; 3780 /* Enough space for ' -NNN<nul>' */ 3781 argv[i] = alloca(sizeof(int)*3 + 3); 3782 /* kill_main has matching code to expect 3783 * leading space. Needed to not confuse 3784 * negative pids with "kill -SIGNAL_NO" syntax */ 3785 sprintf(argv[i], " -%u", pid); 3796 /* 3797 * "kill %N" - job kill 3798 * Converting to pgrp / pid kill 3799 */ 3800 struct job *jp; 3801 char *dst; 3802 int j, n; 3803 3804 jp = getjob(argv[i], 0); 3805 /* 3806 * In jobs started under job control, we signal 3807 * entire process group by kill -PGRP_ID. 3808 * This happens, f.e., in interactive shell. 3809 * 3810 * Otherwise, we signal each child via 3811 * kill PID1 PID2 PID3. 3812 * Testcases: 3813 * sh -c 'sleep 1|sleep 1 & kill %1' 3814 * sh -c 'true|sleep 2 & sleep 1; kill %1' 3815 * sh -c 'true|sleep 1 & sleep 2; kill %1' 3816 */ 3817 n = jp->nprocs; /* can't be 0 (I hope) */ 3818 if (jp->jobctl) 3819 n = 1; 3820 dst = alloca(n * sizeof(int)*4); 3821 argv[i] = dst; 3822 for (j = 0; j < n; j++) { 3823 struct procstat *ps = &jp->ps[j]; 3824 /* Skip non-running and not-stopped members 3825 * (i.e. dead members) of the job 3826 */ 3827 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status)) 3828 continue; 3829 /* 3830 * kill_main has matching code to expect 3831 * leading space. Needed to not confuse 3832 * negative pids with "kill -SIGNAL_NO" syntax 3833 */ 3834 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid); 3835 } 3836 *dst = '\0'; 3786 3837 } 3787 3838 } while (argv[++i]); … … 3881 3932 } 3882 3933 st &= 0x7f; 3934 //TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata 3883 3935 col = fmtstr(s, 32, strsignal(st)); 3884 3936 if (WCOREDUMP(status)) { … … 4215 4267 job = job->prev_job; 4216 4268 } 4217 } else 4269 } else { 4218 4270 job = getjob(*argv, 0); 4271 } 4219 4272 /* loop until process terminated or stopped */ 4220 4273 while (job->state == JOBRUNNING) … … 4712 4765 /* do job control only in root shell */ 4713 4766 doing_jobctl = 0; 4714 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {4767 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) { 4715 4768 pid_t pgrp; 4716 4769 … … 4738 4791 } 4739 4792 } 4740 if ( !oldlvl) {4793 if (oldlvl == 0) { 4741 4794 if (iflag) { /* why if iflag only? */ 4742 4795 setsignal(SIGINT); … … 4945 4998 */ 4946 4999 5000 #undef EMPTY 5001 #undef CLOSED 4947 5002 #define EMPTY -2 /* marks an unused slot in redirtab */ 4948 5003 #define CLOSED -3 /* marks a slot of previously-closed fd */ … … 5057 5112 int f; 5058 5113 5114 fname = redir->nfile.expfname; 5059 5115 switch (redir->nfile.type) { 5060 5116 case NFROM: 5061 fname = redir->nfile.expfname;5062 5117 f = open(fname, O_RDONLY); 5063 5118 if (f < 0) … … 5065 5120 break; 5066 5121 case NFROMTO: 5067 fname = redir->nfile.expfname;5068 5122 f = open(fname, O_RDWR|O_CREAT, 0666); 5069 5123 if (f < 0) … … 5076 5130 /* Take care of noclobber mode. */ 5077 5131 if (Cflag) { 5078 fname = redir->nfile.expfname;5079 5132 f = noclobberopen(fname); 5080 5133 if (f < 0) … … 5084 5137 /* FALLTHROUGH */ 5085 5138 case NCLOBBER: 5086 fname = redir->nfile.expfname;5087 5139 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666); 5088 5140 if (f < 0) … … 5090 5142 break; 5091 5143 case NAPPEND: 5092 fname = redir->nfile.expfname;5093 5144 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); 5094 5145 if (f < 0) … … 5870 5921 if (in.fd < 0) 5871 5922 break; 5872 i = nonblock_ safe_read(in.fd, buf, sizeof(buf));5923 i = nonblock_immune_read(in.fd, buf, sizeof(buf), /*loop_on_EINTR:*/ 1); 5873 5924 TRACE(("expbackq: read returns %d\n", i)); 5874 5925 if (i <= 0) … … 5922 5973 *p = '\0'; 5923 5974 p--; 5924 do{5975 while (1) { 5925 5976 int esc; 5926 5977 … … 5940 5991 5941 5992 p -= esc + 1; 5942 } while (1);5993 } 5943 5994 5944 5995 begoff = p - start; … … 6090 6141 goto addquote; 6091 6142 case CTLVAR: 6143 TRACE(("argstr: evalvar('%s')\n", p)); 6092 6144 p = evalvar(p, flags, var_str_list); 6145 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock())); 6093 6146 goto start; 6094 6147 case CTLBACKQ: … … 6287 6340 IF_ASH_BASH_COMPAT(int pos, len, orig_len;) 6288 6341 int saveherefd = herefd; 6289 int amount, workloc, resetloc; 6342 int amount, resetloc; 6343 IF_ASH_BASH_COMPAT(int workloc;) 6290 6344 int zero; 6291 6345 char *(*scan)(char*, char*, char*, char*, int, int); … … 6400 6454 str = (char *)stackblock() + strloc; 6401 6455 preglob(str, varflags & VSQUOTE, 0); 6456 6457 #if ENABLE_ASH_BASH_COMPAT 6402 6458 workloc = expdest - (char *)stackblock(); 6403 6404 #if ENABLE_ASH_BASH_COMPAT6405 6459 if (subtype == VSREPLACE || subtype == VSREPLACEALL) { 6406 6460 char *idx, *end; … … 6798 6852 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype, 6799 6853 startloc, varflags, 6800 //TODO: | EXP_REDIR too? All other such places do it too 6801 /* quotes: */ flags & (EXP_FULL | EXP_CASE), 6854 /* quotes: */ flags & (EXP_FULL | EXP_CASE | EXP_REDIR), 6802 6855 var_str_list) 6803 6856 ) { … … 7201 7254 ifsfirst.next = NULL; 7202 7255 ifslastp = NULL; 7256 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag)); 7203 7257 argstr(arg->narg.text, flag, 7204 7258 /* var_str_list: */ arglist ? arglist->list : NULL); … … 7209 7263 } 7210 7264 p = grabstackstr(p); 7265 TRACE(("expandarg: p:'%s'\n", p)); 7211 7266 exparg.lastp = &exparg.list; 7212 7267 /* … … 7219 7274 expandmeta(exparg.list /*, flag*/); 7220 7275 } else { 7221 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */7276 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */ 7222 7277 rmescapes(p, 0); 7278 TRACE(("expandarg: rmescapes:'%s'\n", p)); 7279 } 7223 7280 sp = stzalloc(sizeof(*sp)); 7224 7281 sp->text = p; … … 7348 7405 tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp) 7349 7406 { 7350 int repeated = 0;7351 7352 7407 #if ENABLE_FEATURE_SH_STANDALONE 7353 7408 if (applet_no >= 0) { … … 7373 7428 execve(cmd, argv, envp); 7374 7429 #endif 7375 if (repeated) { 7430 if (cmd == (char*) bb_busybox_exec_path) { 7431 /* We already visited ENOEXEC branch below, don't do it again */ 7432 //TODO: try execve(initial_argv0_of_shell, argv, envp) before giving up? 7376 7433 free(argv); 7377 7434 return; 7378 7435 } 7379 7436 if (errno == ENOEXEC) { 7437 /* Run "cmd" as a shell script: 7438 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html 7439 * "If the execve() function fails with ENOEXEC, the shell 7440 * shall execute a command equivalent to having a shell invoked 7441 * with the command name as its first operand, 7442 * with any remaining arguments passed to the new shell" 7443 * 7444 * That is, do not use $SHELL, user's shell, or /bin/sh; 7445 * just call ourselves. 7446 * 7447 * Note that bash reads ~80 chars of the file, and if it sees 7448 * a zero byte before it sees newline, it doesn't try to 7449 * interpret it, but fails with "cannot execute binary file" 7450 * message and exit code 126. For one, this prevents attempts 7451 * to interpret foreign ELF binaries as shell scripts. 7452 */ 7380 7453 char **ap; 7381 7454 char **new; … … 7383 7456 for (ap = argv; *ap; ap++) 7384 7457 continue; 7385 ap = new = ckmalloc((ap - argv + 2) * sizeof(ap[0])); 7386 ap[1] = cmd; 7387 ap[0] = cmd = (char *)DEFAULT_SHELL; 7388 ap += 2; 7389 argv++; 7390 while ((*ap++ = *argv++) != NULL) 7458 new = ckmalloc((ap - argv + 2) * sizeof(new[0])); 7459 new[0] = (char*) "ash"; 7460 new[1] = cmd; 7461 ap = new + 2; 7462 while ((*ap++ = *++argv) != NULL) 7391 7463 continue; 7464 cmd = (char*) bb_busybox_exec_path; 7392 7465 argv = new; 7393 repeated++;7394 7466 goto repeat; 7395 7467 } … … 7408 7480 char **envp; 7409 7481 int exerrno; 7410 #if ENABLE_FEATURE_SH_STANDALONE 7411 int applet_no = -1; 7412 #endif 7482 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ 7413 7483 7414 7484 clearredir(/*drop:*/ 1); … … 7420 7490 ) { 7421 7491 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp); 7492 if (applet_no >= 0) { 7493 /* We tried execing ourself, but it didn't work. 7494 * Maybe /proc/self/exe doesn't exist? 7495 * Try $PATH search. 7496 */ 7497 goto try_PATH; 7498 } 7422 7499 e = errno; 7423 7500 } else { 7501 try_PATH: 7424 7502 e = ENOENT; 7425 7503 while ((cmdname = path_advance(&path, argv[0])) != NULL) { … … 8596 8674 case NAPPEND: 8597 8675 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 8676 TRACE(("expredir expanded to '%s'\n", fn.list->text)); 8598 8677 #if ENABLE_ASH_BASH_COMPAT 8599 8678 store_expfname: 8679 #endif 8680 #if 0 8681 // By the design of stack allocator, the loop of this kind: 8682 // while true; do while true; do break; done </dev/null; done 8683 // will look like a memory leak: ash plans to free expfname's 8684 // of "/dev/null" as soon as it finishes running the loop 8685 // (in this case, never). 8686 // This "fix" is wrong: 8687 if (redir->nfile.expfname) 8688 stunalloc(redir->nfile.expfname); 8689 // It results in corrupted state of stacked allocations. 8600 8690 #endif 8601 8691 redir->nfile.expfname = fn.list->text; … … 9234 9324 /* Now locate the command. */ 9235 9325 if (argc) { 9236 const char *oldpath;9237 9326 int cmd_flag = DO_ERR; 9238 9327 #if ENABLE_ASH_CMDCMD 9328 const char *oldpath = path + 5; 9329 #endif 9239 9330 path += 5; 9240 oldpath = path;9241 9331 for (;;) { 9242 9332 find_command(argv[0], &cmdentry, cmd_flag, path); … … 9560 9650 retry: 9561 9651 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) 9562 nr = nonblock_ safe_read(g_parsefile->pf_fd, buf, IBUFSIZ -1);9652 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1); 9563 9653 else { 9564 #if ENABLE_FEATURE_TAB_COMPLETION 9654 int timeout = -1; 9655 # if ENABLE_ASH_IDLE_TIMEOUT 9656 if (iflag) { 9657 const char *tmout_var = lookupvar("TMOUT"); 9658 if (tmout_var) { 9659 timeout = atoi(tmout_var) * 1000; 9660 if (timeout <= 0) 9661 timeout = -1; 9662 } 9663 } 9664 # endif 9665 # if ENABLE_FEATURE_TAB_COMPLETION 9565 9666 line_input_state->path_lookup = pathval(); 9566 #endif 9567 nr = read_line_input(cmdedit_prompt, buf, IBUFSIZ, line_input_state); 9667 # endif 9668 /* Unicode support should be activated even if LANG is set 9669 * _during_ shell execution, not only if it was set when 9670 * shell was started. Therefore, re-check LANG every time: 9671 */ 9672 reinit_unicode(lookupvar("LANG")); 9673 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout); 9568 9674 if (nr == 0) { 9569 9675 /* Ctrl+C pressed */ … … 9576 9682 goto retry; 9577 9683 } 9578 if (nr < 0 && errno == 0) { 9579 /* Ctrl+D pressed */ 9580 nr = 0; 9684 if (nr < 0) { 9685 if (errno == 0) { 9686 /* Ctrl+D pressed */ 9687 nr = 0; 9688 } 9689 # if ENABLE_ASH_IDLE_TIMEOUT 9690 else if (errno == EAGAIN && timeout > 0) { 9691 printf("\007timed out waiting for input: auto-logout\n"); 9692 exitshell(); 9693 } 9694 # endif 9581 9695 } 9582 9696 } 9583 9697 #else 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 */ 9698 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1); 9699 #endif 9700 9701 #if 0 /* disabled: nonblock_immune_read() handles this problem */ 9589 9702 if (nr < 0) { 9590 9703 if (parsefile->fd == 0 && errno == EWOULDBLOCK) { … … 10105 10218 setparam(argptr); 10106 10219 } 10107 break; /* "-" or 10220 break; /* "-" or "--" terminates options */ 10108 10221 } 10109 10222 } … … 10207 10320 if (!argv[1]) 10208 10321 return showvars(nullstr, 0, VUNSET); 10322 10209 10323 INT_OFF; 10210 retval = 1; 10211 if (!options(0)) { /* if no parse error... */ 10212 retval = 0; 10324 retval = options(/*cmdline:*/ 0); 10325 if (retval == 0) { /* if no parse error... */ 10213 10326 optschanged(); 10214 10327 if (*argptr != NULL) { … … 11538 11651 if (oldstyle) { 11539 11652 /* We must read until the closing backquote, giving special 11540 treatment to some slashes, and then push the string and 11541 reread it as input, interpreting it normally. */ 11653 * treatment to some slashes, and then push the string and 11654 * reread it as input, interpreting it normally. 11655 */ 11542 11656 char *pout; 11543 11657 size_t psavelen; … … 12071 12185 if (iflag && top) { 12072 12186 inter++; 12073 #if ENABLE_ASH_MAIL12074 12187 chkmail(); 12075 #endif12076 12188 } 12077 12189 n = parsecmd(inter); … … 12532 12644 const char *p; 12533 12645 char **aptr; 12534 int flag = argv[0][0] == 'r' ? VREADONLY : VEXPORT; 12535 12536 if (nextopt("p") != 'p') { 12646 char opt; 12647 int flag; 12648 int flag_off; 12649 12650 /* "readonly" in bash accepts, but ignores -n. 12651 * We do the same: it saves a conditional in nextopt's param. 12652 */ 12653 flag_off = 0; 12654 while ((opt = nextopt("np")) != '\0') { 12655 if (opt == 'n') 12656 flag_off = VEXPORT; 12657 } 12658 flag = VEXPORT; 12659 if (argv[0][0] == 'r') { 12660 flag = VREADONLY; 12661 flag_off = 0; /* readonly ignores -n */ 12662 } 12663 flag_off = ~flag_off; 12664 12665 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */ 12666 { 12537 12667 aptr = argptr; 12538 12668 name = *aptr; … … 12545 12675 vp = *findvar(hashvar(name), name); 12546 12676 if (vp) { 12547 vp->flags |= flag;12677 vp->flags = ((vp->flags | flag) & flag_off); 12548 12678 continue; 12549 12679 } 12550 12680 } 12551 setvar(name, p, flag);12681 setvar(name, p, (flag & flag_off)); 12552 12682 } while ((name = *++aptr) != NULL); 12553 12683 return 0; 12554 12684 } 12555 12685 } 12686 12687 /* No arguments. Show the list of exported or readonly vars. 12688 * -n is ignored. 12689 */ 12556 12690 showvars(argv[0], flag, 0); 12557 12691 return 0; … … 12706 12840 } 12707 12841 12842 /* "read -s" needs to save/restore termios, can't allow ^C 12843 * to jump out of it. 12844 */ 12845 INT_OFF; 12708 12846 r = shell_builtin_read(setvar2, 12709 12847 argptr, … … 12715 12853 opt_u 12716 12854 ); 12855 INT_ON; 12717 12856 12718 12857 if ((uintptr_t)r > 1) … … 12803 12942 * Called to exit the shell. 12804 12943 */ 12805 static void exitshell(void) NORETURN;12806 12944 static void 12807 12945 exitshell(void) … … 12810 12948 char *p; 12811 12949 int status; 12950 12951 #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 12952 save_history(line_input_state); 12953 #endif 12812 12954 12813 12955 status = exitstatus; … … 12866 13008 12867 13009 p = lookupvar("PWD"); 12868 if (p) 13010 if (p) { 12869 13011 if (*p != '/' || stat(p, &st1) || stat(".", &st2) 12870 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) 13012 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino 13013 ) { 12871 13014 p = '\0'; 13015 } 13016 } 12872 13017 setpwd(p, 0); 12873 13018 } 12874 13019 } 13020 13021 13022 //usage:#define ash_trivial_usage 13023 //usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]" 13024 //usage:#define ash_full_usage "\n\n" 13025 //usage: "Unix shell interpreter" 13026 13027 //usage:#if ENABLE_FEATURE_SH_IS_ASH 13028 //usage:# define sh_trivial_usage ash_trivial_usage 13029 //usage:# define sh_full_usage ash_full_usage 13030 //usage:#endif 13031 //usage:#if ENABLE_FEATURE_BASH_IS_ASH 13032 //usage:# define bash_trivial_usage ash_trivial_usage 13033 //usage:# define bash_full_usage ash_full_usage 13034 //usage:#endif 12875 13035 12876 13036 /* … … 12891 13051 optlist[i] = 2; 12892 13052 argptr = xargv; 12893 if (options( 1)) {13053 if (options(/*cmdline:*/ 1)) { 12894 13054 /* it already printed err message */ 12895 13055 raise_exception(EXERROR); … … 13053 13213 if (iflag) { 13054 13214 const char *hp = lookupvar("HISTFILE"); 13055 13056 if (hp == NULL) { 13215 if (!hp) { 13057 13216 hp = lookupvar("HOME"); 13058 if (hp != NULL) {13217 if (hp) { 13059 13218 char *defhp = concat_path_file(hp, ".ash_history"); 13060 13219 setvar("HISTFILE", defhp, 0); … … 13064 13223 } 13065 13224 #endif 13066 if ( /* argv[0] && */argv[0][0] == '-')13225 if (argv[0] && argv[0][0] == '-') 13067 13226 isloginsh = 1; 13068 13227 if (isloginsh) { … … 13100 13259 13101 13260 if (sflag || minusc == NULL) { 13102 #if defined MAX_HISTORY &&MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY13261 #if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY 13103 13262 if (iflag) { 13104 13263 const char *hp = lookupvar("HISTFILE"); 13105 13264 if (hp) 13106 13265 line_input_state->hist_file = hp; 13266 # if ENABLE_FEATURE_SH_HISTFILESIZE 13267 hp = lookupvar("HISTFILESIZE"); 13268 line_input_state->max_history = size_from_HISTFILESIZE(hp); 13269 # endif 13107 13270 } 13108 13271 #endif -
branches/3.2/mindi-busybox/shell/ash_test/ash-redir/redir.right
r2725 r3232 1 ash: write error: Bad file descriptor 1 2 TEST -
branches/3.2/mindi-busybox/shell/cttyhack.c
r2725 r3232 7 7 #include "libbb.h" 8 8 9 //applet:IF_CTTYHACK(APPLET(cttyhack, _BB_DIR_BIN, _BB_SUID_DROP))9 //applet:IF_CTTYHACK(APPLET(cttyhack, BB_DIR_BIN, BB_SUID_DROP)) 10 10 11 11 //kbuild:lib-$(CONFIG_CTTYHACK) += cttyhack.o … … 15 15 //config: default y 16 16 //config: help 17 //config: One common problem reported on the mailing list is "can't access tty; 18 //config: job control turned off" error message which typically appears when 19 //config: one tries to use shell with stdin/stdout opened to /dev/console. 17 //config: One common problem reported on the mailing list is the "can't 18 //config: access tty; job control turned off" error message, which typically 19 //config: appears when one tries to use a shell with stdin/stdout on 20 //config: /dev/console. 20 21 //config: This device is special - it cannot be a controlling tty. 21 22 //config: 22 //config: Proper solution is to use correct device instead of /dev/console. 23 //config: The proper solution is to use the correct device instead of 24 //config: /dev/console. 23 25 //config: 24 //config: cttyhack provides "quick and dirty" solution to this problem.26 //config: cttyhack provides a "quick and dirty" solution to this problem. 25 27 //config: It analyzes stdin with various ioctls, trying to determine whether 26 28 //config: it is a /dev/ttyN or /dev/ttySN (virtual terminal or serial line). 27 //config: If it detects one, it closes stdin/out/err and reopens that device. 28 //config: Then it executes given program. Opening the device will make 29 //config: On Linux it also checks sysfs for a pointer to the active console. 30 //config: If cttyhack is able to find the real console device, it closes 31 //config: stdin/out/err and reopens that device. 32 //config: Then it executes the given program. Opening the device will make 29 33 //config: that device a controlling tty. This may require cttyhack 30 34 //config: to be a session leader. … … 47 51 //config: # exec setsid sh -c 'exec sh </dev/tty1 >/dev/tty1 2>&1' 48 52 //config: 53 //config: Starting getty on a controlling tty from a shell script: 54 //config: 55 //config: # getty 115200 $(cttyhack) 49 56 50 57 //usage:#define cttyhack_trivial_usage 51 //usage: " PROG ARGS"58 //usage: "[PROG ARGS]" 52 59 //usage:#define cttyhack_full_usage "\n\n" 53 60 //usage: "Give PROG a controlling tty if possible." … … 105 112 } u; 106 113 107 if (!*++argv) { 108 bb_show_usage(); 114 strcpy(console, "/dev/tty"); 115 fd = open(console, O_RDWR); 116 if (fd < 0) { 117 /* We don't have ctty (or don't have "/dev/tty" node...) */ 118 do { 119 #ifdef __linux__ 120 /* Note that this method does not use _stdin_. 121 * Thus, "cttyhack </dev/something" can't be used. 122 * However, this method is more reliable than 123 * TIOCGSERIAL check, which assumes that all 124 * serial lines follow /dev/ttySn convention - 125 * which is not always the case. 126 * Therefore, we use this method first: 127 */ 128 int s = open_read_close("/sys/class/tty/console/active", 129 console + 5, sizeof(console) - 5); 130 if (s > 0) { 131 char *last; 132 /* Found active console via sysfs (Linux 2.6.38+). 133 * It looks like "[tty0 ]ttyS0\n" so zap the newline: 134 */ 135 console[4 + s] = '\0'; 136 /* If there are multiple consoles, 137 * take the last one: 138 */ 139 last = strrchr(console + 5, ' '); 140 if (last) 141 overlapping_strcpy(console + 5, last + 1); 142 break; 143 } 144 145 if (ioctl(0, VT_GETSTATE, &u.vt) == 0) { 146 /* this is linux virtual tty */ 147 sprintf(console + 8, "S%u" + 1, (int)u.vt.v_active); 148 break; 149 } 150 #endif 151 #ifdef TIOCGSERIAL 152 if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) { 153 /* this is a serial console; assuming it is named /dev/ttySn */ 154 sprintf(console + 8, "S%u", (int)u.sr.line); 155 break; 156 } 157 #endif 158 /* nope, could not find it */ 159 console[0] = '\0'; 160 } while (0); 109 161 } 110 162 111 strcpy(console, "/dev/tty"); 112 fd = open(console, O_RDWR); 113 if (fd >= 0) { 114 /* We already have ctty, nothing to do */ 115 close(fd); 116 } else { 117 /* We don't have ctty (or don't have "/dev/tty" node...) */ 118 if (0) {} 119 #ifdef TIOCGSERIAL 120 else if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) { 121 /* this is a serial console */ 122 sprintf(console + 8, "S%d", u.sr.line); 123 } 124 #endif 125 #ifdef __linux__ 126 else if (ioctl(0, VT_GETSTATE, &u.vt) == 0) { 127 /* this is linux virtual tty */ 128 sprintf(console + 8, "S%d" + 1, u.vt.v_active); 129 } 130 #endif 131 if (console[8]) { 132 fd = xopen(console, O_RDWR); 133 //bb_error_msg("switching to '%s'", console); 134 dup2(fd, 0); 135 dup2(fd, 1); 136 dup2(fd, 2); 137 while (fd > 2) 138 close(fd--); 139 /* Some other session may have it as ctty, 140 * steal it from them: 141 */ 142 ioctl(0, TIOCSCTTY, 1); 143 } 163 argv++; 164 if (!argv[0]) { 165 if (!console[0]) 166 return EXIT_FAILURE; 167 puts(console); 168 return EXIT_SUCCESS; 144 169 } 145 170 171 if (fd < 0) { 172 fd = open_or_warn(console, O_RDWR); 173 if (fd < 0) 174 goto ret; 175 } 176 //bb_error_msg("switching to '%s'", console); 177 dup2(fd, 0); 178 dup2(fd, 1); 179 dup2(fd, 2); 180 while (fd > 2) 181 close(fd--); 182 /* Some other session may have it as ctty, 183 * try to steal it from them: 184 */ 185 ioctl(0, TIOCSCTTY, 1); 186 ret: 146 187 BB_EXECVP_or_die(argv); 147 188 } -
branches/3.2/mindi-busybox/shell/hush.c
r2859 r3232 82 82 * aaa 83 83 */ 84 #include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ 85 #include <malloc.h> /* for malloc_trim */ 84 #if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ 85 || defined(__APPLE__) \ 86 ) 87 # include <malloc.h> /* for malloc_trim */ 88 #endif 86 89 #include <glob.h> 87 90 /* #include <dmalloc.h> */ … … 90 93 #endif 91 94 95 #include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ 96 #include "unicode.h" 92 97 #include "shell_common.h" 93 98 #include "math.h" … … 101 106 # define PIPE_BUF 4096 /* amount of buffering in a pipe */ 102 107 #endif 103 104 //applet:IF_HUSH(APPLET(hush, _BB_DIR_BIN, _BB_SUID_DROP))105 //applet:IF_MSH(APPLET(msh, _BB_DIR_BIN, _BB_SUID_DROP))106 //applet:IF_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, _BB_DIR_BIN, _BB_SUID_DROP, sh))107 //applet:IF_FEATURE_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, _BB_DIR_BIN, _BB_SUID_DROP, bash))108 109 //kbuild:lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o110 //kbuild:lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o111 108 112 109 //config:config HUSH … … 246 243 //config: 247 244 248 //usage:#define hush_trivial_usage NOUSAGE_STR 249 //usage:#define hush_full_usage "" 250 //usage:#define msh_trivial_usage NOUSAGE_STR 251 //usage:#define msh_full_usage "" 252 //usage:#define sh_trivial_usage NOUSAGE_STR 253 //usage:#define sh_full_usage "" 254 //usage:#define bash_trivial_usage NOUSAGE_STR 255 //usage:#define bash_full_usage "" 245 //applet:IF_HUSH(APPLET(hush, BB_DIR_BIN, BB_SUID_DROP)) 246 //applet:IF_MSH(APPLET(msh, BB_DIR_BIN, BB_SUID_DROP)) 247 //applet:IF_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, BB_DIR_BIN, BB_SUID_DROP, sh)) 248 //applet:IF_FEATURE_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, BB_DIR_BIN, BB_SUID_DROP, bash)) 249 250 //kbuild:lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o 251 //kbuild:lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o 252 253 /* -i (interactive) and -s (read stdin) are also accepted, 254 * but currently do nothing, therefore aren't shown in help. 255 * NOMMU-specific options are not meant to be used by users, 256 * therefore we don't show them either. 257 */ 258 //usage:#define hush_trivial_usage 259 //usage: "[-nxl] [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]" 260 //usage:#define hush_full_usage "\n\n" 261 //usage: "Unix shell interpreter" 262 263 //usage:#define msh_trivial_usage hush_trivial_usage 264 //usage:#define msh_full_usage hush_full_usage 265 266 //usage:#if ENABLE_FEATURE_SH_IS_HUSH 267 //usage:# define sh_trivial_usage hush_trivial_usage 268 //usage:# define sh_full_usage hush_full_usage 269 //usage:#endif 270 //usage:#if ENABLE_FEATURE_BASH_IS_HUSH 271 //usage:# define bash_trivial_usage hush_trivial_usage 272 //usage:# define bash_full_usage hush_full_usage 273 //usage:#endif 256 274 257 275 … … 303 321 # undef ENABLE_FEATURE_EDITING_FANCY_PROMPT 304 322 # define ENABLE_FEATURE_EDITING_FANCY_PROMPT 0 323 # undef ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 324 # define ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 0 305 325 #endif 306 326 … … 437 457 #endif 438 458 439 /* I can almost use ordinary FILE*. Is open_memstream() universally440 * available? Where is it documented? */441 459 typedef struct in_str { 442 460 const char *p; … … 445 463 char peek_buf[2]; 446 464 #if ENABLE_HUSH_INTERACTIVE 447 smallint promptme;448 465 smallint promptmode; /* 0: PS1, 1: PS2 */ 449 466 #endif 467 int last_char; 450 468 FILE *file; 451 469 int (*get) (struct in_str *) FAST_FUNC; … … 505 523 pid_t pid; /* 0 if exited */ 506 524 int assignment_cnt; /* how many argv[i] are assignments? */ 507 smallint is_stopped; /* is the command currently running? */508 525 smallint cmd_type; /* CMD_xxx */ 509 526 #define CMD_NORMAL 0 … … 677 694 * xtrace off 678 695 */ 679 static const char o_opt_strings[] ALIGN1 = "pipefail\0"; 696 static const char o_opt_strings[] ALIGN1 = 697 "pipefail\0" 698 "noexec\0" 699 #if ENABLE_HUSH_MODE_X 700 "xtrace\0" 701 #endif 702 ; 680 703 enum { 681 704 OPT_O_PIPEFAIL, 705 OPT_O_NOEXEC, 706 #if ENABLE_HUSH_MODE_X 707 OPT_O_XTRACE, 708 #endif 682 709 NUM_OPT_O 683 710 }; … … 727 754 #endif 728 755 char o_opt[NUM_OPT_O]; 756 #if ENABLE_HUSH_MODE_X 757 # define G_x_mode (G.o_opt[OPT_O_XTRACE]) 758 #else 759 # define G_x_mode 0 760 #endif 729 761 smallint flag_SIGINT; 730 762 #if ENABLE_HUSH_LOOPS … … 738 770 smallint flag_return_in_progress; 739 771 #endif 740 smallint n_mode;741 #if ENABLE_HUSH_MODE_X742 smallint x_mode;743 # define G_x_mode (G.x_mode)744 #else745 # define G_x_mode 0746 #endif747 772 smallint exiting; /* used to prevent EXIT trap recursion */ 748 773 /* These four support $?, $#, and $1 */ … … 750 775 /* are global_argv and global_argv[1..n] malloced? (note: not [0]) */ 751 776 smalluint global_args_malloced; 752 smalluint inherited_set_is_saved;753 777 /* how many non-NULL argv's we have. NB: $# + 1 */ 754 778 int global_argc; … … 778 802 smallint we_have_children; 779 803 #endif 780 /* which signals have non-DFL handler (even with no traps set)? */ 781 unsigned non_DFL_mask; 804 /* Which signals have non-DFL handler (even with no traps set)? 805 * Set at the start to: 806 * (SIGQUIT + maybe SPECIAL_INTERACTIVE_SIGS + maybe SPECIAL_JOBSTOP_SIGS) 807 * SPECIAL_INTERACTIVE_SIGS are cleared after fork. 808 * The rest is cleared right before execv syscalls. 809 * Other than these two times, never modified. 810 */ 811 unsigned special_sig_mask; 812 #if ENABLE_HUSH_JOB 813 unsigned fatal_sig_mask; 814 # define G_fatal_sig_mask G.fatal_sig_mask 815 #else 816 # define G_fatal_sig_mask 0 817 #endif 782 818 char **traps; /* char *traps[NSIG] */ 783 sigset_t blocked_set; 784 sigset_t inherited_set; 819 sigset_t pending_set; 785 820 #if HUSH_DEBUG 786 821 unsigned long memleak_value; 787 822 int debug_indent; 788 823 #endif 824 struct sigaction sa; 789 825 char user_input_buf[ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 2]; 790 826 }; … … 795 831 #define INIT_G() do { \ 796 832 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ 833 /* memset(&G.sa, 0, sizeof(G.sa)); */ \ 834 sigfillset(&G.sa.sa_mask); \ 835 G.sa.sa_flags = SA_RESTART; \ 797 836 } while (0) 798 837 … … 1062 1101 } 1063 1102 1064 static void syntax_error(unsigned lineno , const char *msg)1103 static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg) 1065 1104 { 1066 1105 if (msg) 1067 die_if_script(lineno,"syntax error: %s", msg);1106 bb_error_msg("syntax error: %s", msg); 1068 1107 else 1069 die_if_script(lineno, "syntax error", NULL); 1070 } 1071 1072 static void syntax_error_at(unsigned lineno, const char *msg) 1073 { 1074 die_if_script(lineno, "syntax error at '%s'", msg); 1075 } 1076 1077 static void syntax_error_unterm_str(unsigned lineno, const char *s) 1078 { 1079 die_if_script(lineno, "syntax error: unterminated %s", s); 1080 } 1081 1082 /* It so happens that all such cases are totally fatal 1083 * even if shell is interactive: EOF while looking for closing 1084 * delimiter. There is nowhere to read stuff from after that, 1085 * it's EOF! The only choice is to terminate. 1086 */ 1087 static void syntax_error_unterm_ch(unsigned lineno, char ch) NORETURN; 1108 bb_error_msg("syntax error"); 1109 } 1110 1111 static void syntax_error_at(unsigned lineno UNUSED_PARAM, const char *msg) 1112 { 1113 bb_error_msg("syntax error at '%s'", msg); 1114 } 1115 1116 static void syntax_error_unterm_str(unsigned lineno UNUSED_PARAM, const char *s) 1117 { 1118 bb_error_msg("syntax error: unterminated %s", s); 1119 } 1120 1088 1121 static void syntax_error_unterm_ch(unsigned lineno, char ch) 1089 1122 { 1090 1123 char msg[2] = { ch, '\0' }; 1091 1124 syntax_error_unterm_str(lineno, msg); 1092 xfunc_die(); 1093 } 1094 1095 static void syntax_error_unexpected_ch(unsigned lineno, int ch) 1125 } 1126 1127 static void syntax_error_unexpected_ch(unsigned lineno UNUSED_PARAM, int ch) 1096 1128 { 1097 1129 char msg[2]; 1098 1130 msg[0] = ch; 1099 1131 msg[1] = '\0'; 1100 die_if_script(lineno,"syntax error: unexpected %s", ch == EOF ? "EOF" : msg);1132 bb_error_msg("syntax error: unexpected %s", ch == EOF ? "EOF" : msg); 1101 1133 } 1102 1134 … … 1312 1344 * Example 3: this does not wait 5 sec, but executes ls: 1313 1345 * "sleep 5; ls -l" + press ^C 1346 * Example 4: this does not wait and does not execute ls: 1347 * "sleep 5 & wait; ls -l" + press ^C 1314 1348 * 1315 1349 * (What happens to signals which are IGN on shell start?) 1316 1350 * (What happens with signal mask on shell start?) 1317 1351 * 1318 * Implementation in hush1319 * ================== ====1352 * Old implementation 1353 * ================== 1320 1354 * We use in-kernel pending signal mask to determine which signals were sent. 1321 1355 * We block all signals which we don't want to take action immediately, … … 1325 1359 * and act on them. 1326 1360 * 1327 * unsigned non_DFL_mask: a mask of such "special" signals1361 * unsigned special_sig_mask: a mask of such "special" signals 1328 1362 * sigset_t blocked_set: current blocked signal set 1329 1363 * 1330 1364 * "trap - SIGxxx": 1331 * clear bit in blocked_set unless it is also in non_DFL_mask1365 * clear bit in blocked_set unless it is also in special_sig_mask 1332 1366 * "trap 'cmd' SIGxxx": 1333 1367 * set bit in blocked_set (even if 'cmd' is '') … … 1348 1382 * are set to the default actions". bash interprets it so that traps which 1349 1383 * are set to '' (ignore) are NOT reset to defaults. We do the same. 1384 * 1385 * Problem: the above approach makes it unwieldy to catch signals while 1386 * we are in read builtin, of while we read commands from stdin: 1387 * masked signals are not visible! 1388 * 1389 * New implementation 1390 * ================== 1391 * We record each signal we are interested in by installing signal handler 1392 * for them - a bit like emulating kernel pending signal mask in userspace. 1393 * We are interested in: signals which need to have special handling 1394 * as described above, and all signals which have traps set. 1395 * Signals are rocorded in pending_set. 1396 * After each pipe execution, we extract any pending signals 1397 * and act on them. 1398 * 1399 * unsigned special_sig_mask: a mask of shell-special signals. 1400 * unsigned fatal_sig_mask: a mask of signals on which we restore tty pgrp. 1401 * char *traps[sig] if trap for sig is set (even if it's ''). 1402 * sigset_t pending_set: set of sigs we received. 1403 * 1404 * "trap - SIGxxx": 1405 * if sig is in special_sig_mask, set handler back to: 1406 * record_pending_signo, or to IGN if it's a tty stop signal 1407 * if sig is in fatal_sig_mask, set handler back to sigexit. 1408 * else: set handler back to SIG_DFL 1409 * "trap 'cmd' SIGxxx": 1410 * set handler to record_pending_signo. 1411 * "trap '' SIGxxx": 1412 * set handler to SIG_IGN. 1413 * after [v]fork, if we plan to be a shell: 1414 * set signals with special interactive handling to SIG_DFL 1415 * (because child shell is not interactive), 1416 * unset all traps except '' (note: regardless of child shell's type - {}, (), etc) 1417 * after [v]fork, if we plan to exec: 1418 * POSIX says fork clears pending signal mask in child - no need to clear it. 1419 * 1420 * To make wait builtin interruptible, we handle SIGCHLD as special signal, 1421 * otherwise (if we leave it SIG_DFL) sigsuspend in wait builtin will not wake up on it. 1422 * 1423 * Note (compat): 1424 * Standard says "When a subshell is entered, traps that are not being ignored 1425 * are set to the default actions". bash interprets it so that traps which 1426 * are set to '' (ignore) are NOT reset to defaults. We do the same. 1350 1427 */ 1351 1428 enum { … … 1355 1432 | (1 << SIGHUP) 1356 1433 , 1357 SPECIAL_JOB _SIGS = 01434 SPECIAL_JOBSTOP_SIGS = 0 1358 1435 #if ENABLE_HUSH_JOB 1359 1436 | (1 << SIGTTIN) … … 1361 1438 | (1 << SIGTSTP) 1362 1439 #endif 1440 , 1363 1441 }; 1364 1442 1443 static void record_pending_signo(int sig) 1444 { 1445 sigaddset(&G.pending_set, sig); 1365 1446 #if ENABLE_HUSH_FAST 1366 static void SIGCHLD_handler(int sig UNUSED_PARAM) 1367 { 1368 G.count_SIGCHLD++; 1447 if (sig == SIGCHLD) { 1448 G.count_SIGCHLD++; 1369 1449 //bb_error_msg("[%d] SIGCHLD_handler: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); 1370 } 1371 #endif 1450 } 1451 #endif 1452 } 1453 1454 static sighandler_t install_sighandler(int sig, sighandler_t handler) 1455 { 1456 struct sigaction old_sa; 1457 1458 /* We could use signal() to install handlers... almost: 1459 * except that we need to mask ALL signals while handlers run. 1460 * I saw signal nesting in strace, race window isn't small. 1461 * SA_RESTART is also needed, but in Linux, signal() 1462 * sets SA_RESTART too. 1463 */ 1464 /* memset(&G.sa, 0, sizeof(G.sa)); - already done */ 1465 /* sigfillset(&G.sa.sa_mask); - already done */ 1466 /* G.sa.sa_flags = SA_RESTART; - already done */ 1467 G.sa.sa_handler = handler; 1468 sigaction(sig, &G.sa, &old_sa); 1469 return old_sa.sa_handler; 1470 } 1372 1471 1373 1472 #if ENABLE_HUSH_JOB … … 1386 1485 static void sigexit(int sig) 1387 1486 { 1388 /* Disable all signals: job control, SIGPIPE, etc. */1389 sigprocmask_allsigs(SIG_BLOCK);1390 1391 1487 /* Careful: we can end up here after [v]fork. Do not restore 1392 1488 * tty pgrp then, only top-level shell process does that */ 1393 if (G_saved_tty_pgrp && getpid() == G.root_pid) 1489 if (G_saved_tty_pgrp && getpid() == G.root_pid) { 1490 /* Disable all signals: job control, SIGPIPE, etc. 1491 * Mostly paranoid measure, to prevent infinite SIGTTOU. 1492 */ 1493 sigprocmask_allsigs(SIG_BLOCK); 1394 1494 tcsetpgrp(G_interactive_fd, G_saved_tty_pgrp); 1495 } 1395 1496 1396 1497 /* Not a signal, just exit */ … … 1407 1508 #endif 1408 1509 1510 static sighandler_t pick_sighandler(unsigned sig) 1511 { 1512 sighandler_t handler = SIG_DFL; 1513 if (sig < sizeof(unsigned)*8) { 1514 unsigned sigmask = (1 << sig); 1515 1516 #if ENABLE_HUSH_JOB 1517 /* is sig fatal? */ 1518 if (G_fatal_sig_mask & sigmask) 1519 handler = sigexit; 1520 else 1521 #endif 1522 /* sig has special handling? */ 1523 if (G.special_sig_mask & sigmask) { 1524 handler = record_pending_signo; 1525 /* TTIN/TTOU/TSTP can't be set to record_pending_signo 1526 * in order to ignore them: they will be raised 1527 * in an endless loop when we try to do some 1528 * terminal ioctls! We do have to _ignore_ these. 1529 */ 1530 if (SPECIAL_JOBSTOP_SIGS & sigmask) 1531 handler = SIG_IGN; 1532 } 1533 } 1534 return handler; 1535 } 1536 1409 1537 /* Restores tty foreground process group, and exits. */ 1410 1538 static void hush_exit(int exitcode) NORETURN; 1411 1539 static void hush_exit(int exitcode) 1412 1540 { 1541 #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 1542 save_history(G.line_input_state); 1543 #endif 1544 1545 fflush_all(); 1413 1546 if (G.exiting <= 0 && G.traps && G.traps[0] && G.traps[0][0]) { 1414 /* Prevent recursion:1415 * trap "echo Hi; exit" EXIT; exit1416 */1417 1547 char *argv[3]; 1418 1548 /* argv[0] is unused */ … … 1451 1581 1452 1582 1453 static int check_and_run_traps(int sig) 1454 { 1455 /* I want it in rodata, not in bss. 1456 * gcc 4.2.1 puts it in rodata only if it has { 0, 0 } 1457 * initializer. But other compilers may still use bss. 1458 * TODO: find more portable solution. 1459 */ 1460 static const struct timespec zero_timespec = { 0, 0 }; 1461 smalluint save_rcode; 1583 //TODO: return a mask of ALL handled sigs? 1584 static int check_and_run_traps(void) 1585 { 1462 1586 int last_sig = 0; 1463 1587 1464 if (sig)1465 goto jump_in;1466 1588 while (1) { 1467 sig = sigtimedwait(&G.blocked_set, NULL, &zero_timespec); 1468 if (sig <= 0) 1589 int sig; 1590 1591 if (sigisemptyset(&G.pending_set)) 1469 1592 break; 1470 jump_in: 1471 last_sig = sig; 1593 sig = 0; 1594 do { 1595 sig++; 1596 if (sigismember(&G.pending_set, sig)) { 1597 sigdelset(&G.pending_set, sig); 1598 goto got_sig; 1599 } 1600 } while (sig < NSIG); 1601 break; 1602 got_sig: 1472 1603 if (G.traps && G.traps[sig]) { 1473 1604 if (G.traps[sig][0]) { 1474 1605 /* We have user-defined handler */ 1606 smalluint save_rcode; 1475 1607 char *argv[3]; 1476 1608 /* argv[0] is unused */ … … 1480 1612 builtin_eval(argv); 1481 1613 G.last_exitcode = save_rcode; 1614 last_sig = sig; 1482 1615 } /* else: "" trap, ignoring signal */ 1483 1616 continue; … … 1485 1618 /* not a trap: special action */ 1486 1619 switch (sig) { 1487 #if ENABLE_HUSH_FAST1488 case SIGCHLD:1489 G.count_SIGCHLD++;1490 //bb_error_msg("[%d] check_and_run_traps: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);1491 break;1492 #endif1493 1620 case SIGINT: 1494 1621 /* Builtin was ^C'ed, make it look prettier: */ 1495 1622 bb_putchar('\n'); 1496 1623 G.flag_SIGINT = 1; 1624 last_sig = sig; 1497 1625 break; 1498 1626 #if ENABLE_HUSH_JOB … … 1511 1639 } 1512 1640 #endif 1641 #if ENABLE_HUSH_FAST 1642 case SIGCHLD: 1643 G.count_SIGCHLD++; 1644 //bb_error_msg("[%d] check_and_run_traps: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); 1645 /* Note: 1646 * We dont do 'last_sig = sig' here -> NOT returning this sig. 1647 * This simplifies wait builtin a bit. 1648 */ 1649 break; 1650 #endif 1513 1651 default: /* ignored: */ 1514 1652 /* SIGTERM, SIGQUIT, SIGTTIN, SIGTTOU, SIGTSTP */ 1653 /* Note: 1654 * We dont do 'last_sig = sig' here -> NOT returning this sig. 1655 * Example: wait is not interrupted by TERM 1656 * in interactive shell, because TERM is ignored. 1657 */ 1515 1658 break; 1516 1659 } … … 1834 1977 if (ch != '\0') { 1835 1978 i->p++; 1979 i->last_char = ch; 1836 1980 return ch; 1837 1981 } … … 1891 2035 * is actually being read */ 1892 2036 do { 2037 /* Unicode support should be activated even if LANG is set 2038 * _during_ shell execution, not only if it was set when 2039 * shell was started. Therefore, re-check LANG every time: 2040 */ 2041 reinit_unicode(get_local_var_value("LANG")); 2042 1893 2043 G.flag_SIGINT = 0; 1894 2044 /* buglet: SIGINT will not make new prompt to appear _at once_, 1895 2045 * only after <Enter>. (^C will work) */ 1896 r = read_line_input( prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, G.line_input_state);2046 r = read_line_input(G.line_input_state, prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, /*timeout*/ -1); 1897 2047 /* catch *SIGINT* etc (^C is handled by read_line_input) */ 1898 check_and_run_traps( 0);2048 check_and_run_traps(); 1899 2049 } while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */ 1900 2050 i->eof_flag = (r < 0); … … 1906 2056 do { 1907 2057 G.flag_SIGINT = 0; 1908 fputs(prompt_str, stdout); 2058 if (i->last_char == '\0' || i->last_char == '\n') { 2059 /* Why check_and_run_traps here? Try this interactively: 2060 * $ trap 'echo INT' INT; (sleep 2; kill -INT $$) & 2061 * $ <[enter], repeatedly...> 2062 * Without check_and_run_traps, handler never runs. 2063 */ 2064 check_and_run_traps(); 2065 fputs(prompt_str, stdout); 2066 } 1909 2067 fflush_all(); 1910 2068 G.user_input_buf[0] = r = fgetc(i->file); 1911 2069 /*G.user_input_buf[1] = '\0'; - already is and never changed */ 1912 //do we need check_and_run_traps(0)? (maybe only if stdin)1913 2070 } while (G.flag_SIGINT); 1914 2071 i->eof_flag = (r == EOF); … … 1938 2095 * more complicated by now, like sourcing or substituting. */ 1939 2096 #if ENABLE_HUSH_INTERACTIVE 1940 if (G_interactive_fd && i-> promptme && i->file == stdin) {2097 if (G_interactive_fd && i->file == stdin) { 1941 2098 do { 1942 2099 get_user_input(i); 1943 2100 } while (!*i->p); /* need non-empty line */ 1944 2101 i->promptmode = 1; /* PS2 */ 1945 i->promptme = 0;1946 2102 goto take_cached; 1947 2103 } … … 1950 2106 } 1951 2107 debug_printf("file_get: got '%c' %d\n", ch, ch); 1952 #if ENABLE_HUSH_INTERACTIVE 1953 if (ch == '\n') 1954 i->promptme = 1; 1955 #endif 2108 i->last_char = ch; 1956 2109 return ch; 1957 2110 } … … 1980 2133 static void setup_file_in_str(struct in_str *i, FILE *f) 1981 2134 { 2135 memset(i, 0, sizeof(*i)); 1982 2136 i->peek = file_peek; 1983 2137 i->get = file_get; 1984 #if ENABLE_HUSH_INTERACTIVE 1985 i->promptme = 1; 1986 i->promptmode = 0; /* PS1 */ 1987 #endif 2138 /* i->promptmode = 0; - PS1 (memset did it) */ 1988 2139 i->file = f; 1989 i->p = NULL;2140 /* i->p = NULL; */ 1990 2141 } 1991 2142 1992 2143 static void setup_string_in_str(struct in_str *i, const char *s) 1993 2144 { 2145 memset(i, 0, sizeof(*i)); 1994 2146 i->peek = static_peek; 1995 2147 i->get = static_get; 1996 #if ENABLE_HUSH_INTERACTIVE 1997 i->promptme = 1; 1998 i->promptmode = 0; /* PS1 */ 1999 #endif 2148 /* i->promptmode = 0; - PS1 (memset did it) */ 2000 2149 i->p = s; 2001 i->eof_flag = 0;2150 /* i->eof_flag = 0; */ 2002 2151 } 2003 2152 … … 2134 2283 o_addblock(o, str, ordinary_cnt); 2135 2284 if (ordinary_cnt == len) 2136 return; 2285 return; /* NUL is already added by o_addblock */ 2137 2286 str += ordinary_cnt; 2138 2287 len -= ordinary_cnt + 1; /* we are processing + 1 char below */ … … 2148 2297 o->data[o->length] = ch; 2149 2298 o->length++; 2150 o->data[o->length] = '\0';2151 }2299 } 2300 o->data[o->length] = '\0'; 2152 2301 } 2153 2302 … … 2238 2387 o->has_empty_slot = 0; 2239 2388 } 2389 o->has_quoted_part = 0; 2240 2390 list[n] = (char*)(uintptr_t)string_len; 2241 2391 return n + 1; … … 3117 3267 p += 3; 3118 3268 } 3119 if (p == word->data || p[0] != '\0') {3120 /* saw no "$@", or not only "$@" but some3121 * real text is there too */3122 /* insert "empty variable" reference, this makes3123 * e.g. "", $empty"" etc to not disappear */3124 o_addchr(word, SPECIAL_VAR_SYMBOL);3125 o_addchr(word, SPECIAL_VAR_SYMBOL);3126 }3127 3269 } 3128 3270 command->argv = add_string_to_strings(command->argv, xstrdup(word->data)); … … 3322 3464 3323 3465 goto jump_in; 3466 3324 3467 while (1) { 3325 3468 ch = i_getch(input); … … 3533 3676 #if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS 3534 3677 /* Subroutines for copying $(...) and `...` things */ 3535 static voidadd_till_backquote(o_string *dest, struct in_str *input, int in_dquote);3678 static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote); 3536 3679 /* '...' */ 3537 static voidadd_till_single_quote(o_string *dest, struct in_str *input)3680 static int add_till_single_quote(o_string *dest, struct in_str *input) 3538 3681 { 3539 3682 while (1) { … … 3541 3684 if (ch == EOF) { 3542 3685 syntax_error_unterm_ch('\''); 3543 /*xfunc_die(); - redundant */3686 return 0; 3544 3687 } 3545 3688 if (ch == '\'') 3546 return ;3689 return 1; 3547 3690 o_addchr(dest, ch); 3548 3691 } 3549 3692 } 3550 3693 /* "...\"...`..`...." - do we need to handle "...$(..)..." too? */ 3551 static voidadd_till_double_quote(o_string *dest, struct in_str *input)3694 static int add_till_double_quote(o_string *dest, struct in_str *input) 3552 3695 { 3553 3696 while (1) { … … 3555 3698 if (ch == EOF) { 3556 3699 syntax_error_unterm_ch('"'); 3557 /*xfunc_die(); - redundant */3700 return 0; 3558 3701 } 3559 3702 if (ch == '"') 3560 return ;3703 return 1; 3561 3704 if (ch == '\\') { /* \x. Copy both chars. */ 3562 3705 o_addchr(dest, ch); … … 3565 3708 o_addchr(dest, ch); 3566 3709 if (ch == '`') { 3567 add_till_backquote(dest, input, /*in_dquote:*/ 1); 3710 if (!add_till_backquote(dest, input, /*in_dquote:*/ 1)) 3711 return 0; 3568 3712 o_addchr(dest, ch); 3569 3713 continue; … … 3586 3730 * echo `echo '\'TEST\`echo ZZ\`BEST` \TESTZZBEST 3587 3731 */ 3588 static voidadd_till_backquote(o_string *dest, struct in_str *input, int in_dquote)3732 static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote) 3589 3733 { 3590 3734 while (1) { 3591 3735 int ch = i_getch(input); 3592 3736 if (ch == '`') 3593 return ;3737 return 1; 3594 3738 if (ch == '\\') { 3595 3739 /* \x. Copy both unless it is \`, \$, \\ and maybe \" */ … … 3605 3749 if (ch == EOF) { 3606 3750 syntax_error_unterm_ch('`'); 3607 /*xfunc_die(); - redundant */3751 return 0; 3608 3752 } 3609 3753 o_addchr(dest, ch); … … 3641 3785 if (ch == EOF) { 3642 3786 syntax_error_unterm_ch(end_ch); 3643 /*xfunc_die(); - redundant */3787 return 0; 3644 3788 } 3645 3789 if (ch == end_ch IF_HUSH_BASH_COMPAT( || ch == end_char2)) { … … 3655 3799 if (ch == '(' || ch == '{') { 3656 3800 ch = (ch == '(' ? ')' : '}'); 3657 add_till_closing_bracket(dest, input, ch); 3801 if (!add_till_closing_bracket(dest, input, ch)) 3802 return 0; 3658 3803 o_addchr(dest, ch); 3659 3804 continue; 3660 3805 } 3661 3806 if (ch == '\'') { 3662 add_till_single_quote(dest, input); 3807 if (!add_till_single_quote(dest, input)) 3808 return 0; 3663 3809 o_addchr(dest, ch); 3664 3810 continue; 3665 3811 } 3666 3812 if (ch == '"') { 3667 add_till_double_quote(dest, input); 3813 if (!add_till_double_quote(dest, input)) 3814 return 0; 3668 3815 o_addchr(dest, ch); 3669 3816 continue; 3670 3817 } 3671 3818 if (ch == '`') { 3672 add_till_backquote(dest, input, /*in_dquote:*/ 0); 3819 if (!add_till_backquote(dest, input, /*in_dquote:*/ 0)) 3820 return 0; 3673 3821 o_addchr(dest, ch); 3674 3822 continue; … … 3679 3827 if (ch == EOF) { 3680 3828 syntax_error_unterm_ch(')'); 3681 /*xfunc_die(); - redundant */3829 return 0; 3682 3830 } 3683 3831 o_addchr(dest, ch); … … 3750 3898 bad_dollar_syntax: 3751 3899 syntax_error_unterm_str("${name}"); 3752 debug_printf_parse("parse_dollar return 1: unterminated ${name}\n");3753 return 1;3900 debug_printf_parse("parse_dollar return 0: unterminated ${name}\n"); 3901 return 0; 3754 3902 } 3755 3903 nommu_addchr(as_string, ch); … … 3807 3955 #if ENABLE_HUSH_DOLLAR_OPS 3808 3956 last_ch = add_till_closing_bracket(dest, input, end_ch); 3957 if (last_ch == 0) /* error? */ 3958 return 0; 3809 3959 #else 3810 3960 #error Simple code to only allow ${var} is not implemented … … 3851 4001 if (!BB_MMU) 3852 4002 pos = dest->length; 3853 add_till_closing_bracket(dest, input, ')' | DOUBLE_CLOSE_CHAR_FLAG); 4003 if (!add_till_closing_bracket(dest, input, ')' | DOUBLE_CLOSE_CHAR_FLAG)) 4004 return 0; /* error */ 3854 4005 if (as_string) { 3855 4006 o_addstr(as_string, dest->data + pos); … … 3866 4017 if (!BB_MMU) 3867 4018 pos = dest->length; 3868 add_till_closing_bracket(dest, input, ')'); 4019 if (!add_till_closing_bracket(dest, input, ')')) 4020 return 0; /* error */ 3869 4021 if (as_string) { 3870 4022 o_addstr(as_string, dest->data + pos); … … 3893 4045 o_addQchr(dest, '$'); 3894 4046 } 3895 debug_printf_parse("parse_dollar return 0\n");3896 return 0;4047 debug_printf_parse("parse_dollar return 1 (ok)\n"); 4048 return 1; 3897 4049 #undef as_string 3898 4050 } … … 3935 4087 nommu_addchr(as_string, ch); 3936 4088 if (ch == dquote_end) { /* may be only '"' or EOF */ 3937 debug_printf_parse("encode_string return 0\n");3938 return 0;4089 debug_printf_parse("encode_string return 1 (ok)\n"); 4090 return 1; 3939 4091 } 3940 4092 /* note: can't move it above ch == dquote_end check! */ 3941 4093 if (ch == EOF) { 3942 4094 syntax_error_unterm_ch('"'); 3943 /*xfunc_die(); - redundant*/4095 return 0; /* error */ 3944 4096 } 3945 4097 next = '\0'; … … 3972 4124 } 3973 4125 if (ch == '$') { 3974 if ( parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80) != 0) {3975 debug_printf_parse("encode_string return 1: "3976 "parse_dollar returned non-0\n");3977 return 1;4126 if (!parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80)) { 4127 debug_printf_parse("encode_string return 0: " 4128 "parse_dollar returned 0 (error)\n"); 4129 return 0; 3978 4130 } 3979 4131 goto again; … … 3984 4136 o_addchr(dest, SPECIAL_VAR_SYMBOL); 3985 4137 o_addchr(dest, 0x80 | '`'); 3986 add_till_backquote(dest, input, /*in_dquote:*/ dquote_end == '"'); 4138 if (!add_till_backquote(dest, input, /*in_dquote:*/ dquote_end == '"')) 4139 return 0; /* error */ 3987 4140 o_addchr(dest, SPECIAL_VAR_SYMBOL); 3988 4141 //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos); … … 3999 4152 * Return a list of pipes to execute, or NULL on EOF 4000 4153 * or if end_trigger character is met. 4001 * On syntax error, exit i sshell is not interactive,4154 * On syntax error, exit if shell is not interactive, 4002 4155 * reset parsing machinery and start parsing anew, 4003 4156 * or return ERR_PTR. … … 4028 4181 */ 4029 4182 4030 reset: /* we come back here only on syntax errors in interactive shell */4031 4032 #if ENABLE_HUSH_INTERACTIVE4033 input->promptmode = 0; /* PS1 */4034 #endif4035 4183 if (MAYBE_ASSIGNMENT != 0) 4036 4184 dest.o_assignment = MAYBE_ASSIGNMENT; … … 4058 4206 * checking only ')' */ 4059 4207 if (end_trigger == ')') { 4060 syntax_error_unterm_ch('('); /* exits */4061 /* goto parse_error; */4208 syntax_error_unterm_ch('('); 4209 goto parse_error; 4062 4210 } 4063 4211 … … 4072 4220 * bash says: "syntax error near unexpected token '&'") */ 4073 4221 if (pi->num_cmds == 0 4074 IF_HAS_KEYWORDS(&& pi->res_word == RES_NONE)4222 IF_HAS_KEYWORDS(&& pi->res_word == RES_NONE) 4075 4223 ) { 4076 4224 free_pipe_list(pi); … … 4225 4373 /* Do we sit outside of any if's, loops or case's? */ 4226 4374 if (!HAS_KEYWORDS 4227 4375 IF_HAS_KEYWORDS(|| (ctx.ctx_res_w == RES_NONE && ctx.old_flag == 0)) 4228 4376 ) { 4229 4377 o_free(&dest); … … 4354 4502 break; 4355 4503 case '$': 4356 if ( parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0) != 0) {4504 if (!parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0)) { 4357 4505 debug_printf_parse("parse_stream parse error: " 4358 "parse_dollar returned non-0\n");4506 "parse_dollar returned 0 (error)\n"); 4359 4507 goto parse_error; 4360 4508 } … … 4362 4510 case '\'': 4363 4511 dest.has_quoted_part = 1; 4364 while (1) { 4365 ch = i_getch(input); 4366 if (ch == EOF) { 4367 syntax_error_unterm_ch('\''); 4368 /*xfunc_die(); - redundant */ 4512 if (next == '\'' && !ctx.pending_redirect) { 4513 insert_empty_quoted_str_marker: 4514 nommu_addchr(&ctx.as_string, next); 4515 i_getch(input); /* eat second ' */ 4516 o_addchr(&dest, SPECIAL_VAR_SYMBOL); 4517 o_addchr(&dest, SPECIAL_VAR_SYMBOL); 4518 } else { 4519 while (1) { 4520 ch = i_getch(input); 4521 if (ch == EOF) { 4522 syntax_error_unterm_ch('\''); 4523 goto parse_error; 4524 } 4525 nommu_addchr(&ctx.as_string, ch); 4526 if (ch == '\'') 4527 break; 4528 o_addqchr(&dest, ch); 4369 4529 } 4370 nommu_addchr(&ctx.as_string, ch);4371 if (ch == '\'')4372 break;4373 o_addqchr(&dest, ch);4374 4530 } 4375 4531 break; 4376 4532 case '"': 4377 4533 dest.has_quoted_part = 1; 4534 if (next == '"' && !ctx.pending_redirect) 4535 goto insert_empty_quoted_str_marker; 4378 4536 if (dest.o_assignment == NOT_ASSIGNMENT) 4379 4537 dest.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; 4380 if ( encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1))4538 if (!encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1)) 4381 4539 goto parse_error; 4382 4540 dest.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS; … … 4384 4542 #if ENABLE_HUSH_TICK 4385 4543 case '`': { 4386 unsigned pos;4544 USE_FOR_NOMMU(unsigned pos;) 4387 4545 4388 4546 o_addchr(&dest, SPECIAL_VAR_SYMBOL); 4389 4547 o_addchr(&dest, '`'); 4390 pos = dest.length; 4391 add_till_backquote(&dest, input, /*in_dquote:*/ 0); 4548 USE_FOR_NOMMU(pos = dest.length;) 4549 if (!add_till_backquote(&dest, input, /*in_dquote:*/ 0)) 4550 goto parse_error; 4392 4551 # if !BB_MMU 4393 4552 o_addstr(&ctx.as_string, dest.data + pos); … … 4528 4687 IF_HAS_KEYWORDS(pctx = p2;) 4529 4688 } while (HAS_KEYWORDS && pctx); 4530 /* Free text, clear all dest fields */ 4689 4531 4690 o_free(&dest); 4532 /* If we are not in top-level parse, we return, 4533 * our caller will propagate error. 4534 */ 4535 if (end_trigger != ';') { 4691 G.last_exitcode = 1; 4536 4692 #if !BB_MMU 4537 if (pstring) 4538 *pstring = NULL; 4539 #endif 4540 debug_leave(); 4541 return ERR_PTR; 4542 } 4543 /* Discard cached input, force prompt */ 4544 input->p = NULL; 4545 IF_HUSH_INTERACTIVE(input->promptme = 1;) 4546 goto reset; 4693 if (pstring) 4694 *pstring = NULL; 4695 #endif 4696 debug_leave(); 4697 return ERR_PTR; 4547 4698 } 4548 4699 } … … 4604 4755 /* Store given string, finalizing the word and starting new one whenever 4605 4756 * we encounter IFS char(s). This is used for expanding variable values. 4606 * End-of-string does NOT finalize word: think about 'echo -$VAR-' */ 4607 static int expand_on_ifs(o_string *output, int n, const char *str) 4608 { 4757 * End-of-string does NOT finalize word: think about 'echo -$VAR-'. 4758 * Return in *ended_with_ifs: 4759 * 1 - ended with IFS char, else 0 (this includes case of empty str). 4760 */ 4761 static int expand_on_ifs(int *ended_with_ifs, o_string *output, int n, const char *str) 4762 { 4763 int last_is_ifs = 0; 4764 4609 4765 while (1) { 4610 int word_len = strcspn(str, G.ifs); 4766 int word_len; 4767 4768 if (!*str) /* EOL - do not finalize word */ 4769 break; 4770 word_len = strcspn(str, G.ifs); 4611 4771 if (word_len) { 4772 /* We have WORD_LEN leading non-IFS chars */ 4612 4773 if (!(output->o_expflags & EXP_FLAG_GLOB)) { 4613 4774 o_addblock(output, str, word_len); … … 4622 4783 /*o_addqblock(output, str, word_len); - WRONG: "v='*'; echo Z$v" prints "Z*" instead of Z* files */ 4623 4784 } 4785 last_is_ifs = 0; 4624 4786 str += word_len; 4625 } 4787 if (!*str) /* EOL - do not finalize word */ 4788 break; 4789 } 4790 4791 /* We know str here points to at least one IFS char */ 4792 last_is_ifs = 1; 4793 str += strspn(str, G.ifs); /* skip IFS chars */ 4626 4794 if (!*str) /* EOL - do not finalize word */ 4627 4795 break; 4628 o_addchr(output, '\0'); 4629 debug_print_list("expand_on_ifs", output, n); 4630 n = o_save_ptr(output, n); 4631 str += strspn(str, G.ifs); /* skip ifs chars */ 4632 } 4796 4797 /* Start new word... but not always! */ 4798 /* Case "v=' a'; echo ''$v": we do need to finalize empty word: */ 4799 if (output->has_quoted_part 4800 /* Case "v=' a'; echo $v": 4801 * here nothing precedes the space in $v expansion, 4802 * therefore we should not finish the word 4803 * (IOW: if there *is* word to finalize, only then do it): 4804 */ 4805 || (n > 0 && output->data[output->length - 1]) 4806 ) { 4807 o_addchr(output, '\0'); 4808 debug_print_list("expand_on_ifs", output, n); 4809 n = o_save_ptr(output, n); 4810 } 4811 } 4812 4813 if (ended_with_ifs) 4814 *ended_with_ifs = last_is_ifs; 4633 4815 debug_print_list("expand_on_ifs[1]", output, n); 4634 4816 return n; … … 4667 4849 setup_string_in_str(&input, str); 4668 4850 encode_string(NULL, &dest, &input, EOF, process_bkslash); 4851 //TODO: error check (encode_string returns 0 on error)? 4669 4852 //bb_error_msg("'%s' -> '%s'", str, dest.data); 4670 4853 exp_str = expand_string_to_string(dest.data, /*unbackslash:*/ do_unbackslash); … … 5044 5227 */ 5045 5228 char cant_be_null = 0; /* only bit 0x80 matters */ 5229 int ended_in_ifs = 0; /* did last unquoted expansion end with IFS chars? */ 5046 5230 char *p; 5047 5231 … … 5062 5246 char arith_buf[sizeof(arith_t)*3 + 2]; 5063 5247 #endif 5248 5249 if (ended_in_ifs) { 5250 o_addchr(output, '\0'); 5251 n = o_save_ptr(output, n); 5252 ended_in_ifs = 0; 5253 } 5254 5064 5255 o_addblock(output, arg, p - arg); 5065 5256 debug_print_list("expand_vars_to_list[1]", output, n); … … 5090 5281 if (!(first_ch & 0x80)) { /* unquoted $* or $@ */ 5091 5282 while (G.global_argv[i]) { 5092 n = expand_on_ifs( output, n, G.global_argv[i]);5283 n = expand_on_ifs(NULL, output, n, G.global_argv[i]); 5093 5284 debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, G.global_argc - 1); 5094 5285 if (G.global_argv[i++][0] && G.global_argv[i]) { … … 5123 5314 o_addchr(output, G.ifs[0]); 5124 5315 } 5316 output->has_quoted_part = 1; 5125 5317 } 5126 5318 break; … … 5128 5320 case SPECIAL_VAR_SYMBOL: /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_SYMBOL> */ 5129 5321 /* "Empty variable", used to make "" etc to not disappear */ 5322 output->has_quoted_part = 1; 5130 5323 arg++; 5131 5324 cant_be_null = 0x80; … … 5165 5358 !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); 5166 5359 if (val && val[0]) { 5167 n = expand_on_ifs( output, n, val);5360 n = expand_on_ifs(&ended_in_ifs, output, n, val); 5168 5361 val = NULL; 5169 5362 } 5170 5363 } else { /* quoted $VAR, val will be appended below */ 5364 output->has_quoted_part = 1; 5171 5365 debug_printf_expand("quoted '%s', output->o_escape:%d\n", val, 5172 5366 !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); … … 5193 5387 5194 5388 if (arg[0]) { 5389 if (ended_in_ifs) { 5390 o_addchr(output, '\0'); 5391 n = o_save_ptr(output, n); 5392 } 5195 5393 debug_print_list("expand_vars_to_list[a]", output, n); 5196 5394 /* this part is literal, and it was already pre-quoted … … 5323 5521 5324 5522 5523 static void switch_off_special_sigs(unsigned mask) 5524 { 5525 unsigned sig = 0; 5526 while ((mask >>= 1) != 0) { 5527 sig++; 5528 if (!(mask & 1)) 5529 continue; 5530 if (G.traps) { 5531 if (G.traps[sig] && !G.traps[sig][0]) 5532 /* trap is '', has to remain SIG_IGN */ 5533 continue; 5534 free(G.traps[sig]); 5535 G.traps[sig] = NULL; 5536 } 5537 /* We are here only if no trap or trap was not '' */ 5538 install_sighandler(sig, SIG_DFL); 5539 } 5540 } 5541 5325 5542 #if BB_MMU 5326 5543 /* never called */ … … 5342 5559 * Same goes for SIGTERM, SIGHUP, SIGINT. 5343 5560 */ 5344 if (!G.traps && !(G.non_DFL_mask & SPECIAL_INTERACTIVE_SIGS)) 5345 return; /* already no traps and no SPECIAL_INTERACTIVE_SIGS */ 5346 5347 /* Switching off SPECIAL_INTERACTIVE_SIGS. 5348 * Stupid. It can be done with *single* &= op, but we can't use 5349 * the fact that G.blocked_set is implemented as a bitmask 5350 * in libc... */ 5351 mask = (SPECIAL_INTERACTIVE_SIGS >> 1); 5352 sig = 1; 5353 while (1) { 5354 if (mask & 1) { 5355 /* Careful. Only if no trap or trap is not "" */ 5356 if (!G.traps || !G.traps[sig] || G.traps[sig][0]) 5357 sigdelset(&G.blocked_set, sig); 5358 } 5359 mask >>= 1; 5360 if (!mask) 5361 break; 5362 sig++; 5363 } 5364 /* Our homegrown sig mask is saner to work with :) */ 5365 G.non_DFL_mask &= ~SPECIAL_INTERACTIVE_SIGS; 5366 5367 /* Resetting all traps to default except empty ones */ 5368 mask = G.non_DFL_mask; 5369 if (G.traps) for (sig = 0; sig < NSIG; sig++, mask >>= 1) { 5370 if (!G.traps[sig] || !G.traps[sig][0]) 5371 continue; 5561 mask = (G.special_sig_mask & SPECIAL_INTERACTIVE_SIGS) | G_fatal_sig_mask; 5562 if (!G.traps && !mask) 5563 return; /* already no traps and no special sigs */ 5564 5565 /* Switch off special sigs */ 5566 switch_off_special_sigs(mask); 5567 #if ENABLE_HUSH_JOB 5568 G_fatal_sig_mask = 0; 5569 #endif 5570 G.special_sig_mask &= ~SPECIAL_INTERACTIVE_SIGS; 5571 /* SIGQUIT,SIGCHLD and maybe SPECIAL_JOBSTOP_SIGS 5572 * remain set in G.special_sig_mask */ 5573 5574 if (!G.traps) 5575 return; 5576 5577 /* Reset all sigs to default except ones with empty traps */ 5578 for (sig = 0; sig < NSIG; sig++) { 5579 if (!G.traps[sig]) 5580 continue; /* no trap: nothing to do */ 5581 if (!G.traps[sig][0]) 5582 continue; /* empty trap: has to remain SIG_IGN */ 5583 /* sig has non-empty trap, reset it: */ 5372 5584 free(G.traps[sig]); 5373 5585 G.traps[sig] = NULL; 5374 /* There is no signal for 0 (EXIT) */5586 /* There is no signal for trap 0 (EXIT) */ 5375 5587 if (sig == 0) 5376 5588 continue; 5377 /* There was a trap handler, we just removed it. 5378 * But if sig still has non-DFL handling, 5379 * we should not unblock the sig. */ 5380 if (mask & 1) 5381 continue; 5382 sigdelset(&G.blocked_set, sig); 5383 } 5384 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); 5589 install_sighandler(sig, pick_sighandler(sig)); 5590 } 5385 5591 } 5386 5592 … … 5493 5699 * 5494 5700 * I conclude it means we don't need to pass active traps here. 5495 * Even if we would use signal handlers instead of signal masking5496 * in order to implement trap handling,5497 * exec syscall below resets signals to SIG_DFL for us.5498 5701 */ 5499 5702 *pp++ = (char *) "-c"; … … 5512 5715 do_exec: 5513 5716 debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s); 5514 sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); 5717 /* Don't propagate SIG_IGN to the child */ 5718 if (SPECIAL_JOBSTOP_SIGS != 0) 5719 switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS); 5515 5720 execve(bb_busybox_exec_path, argv, pp); 5516 5721 /* Fallback. Useful for init=/bin/hush usage etc */ … … 5543 5748 struct pipe *pipe_list; 5544 5749 5750 #if ENABLE_HUSH_INTERACTIVE 5751 if (end_trigger == ';') 5752 inp->promptmode = 0; /* PS1 */ 5753 #endif 5545 5754 pipe_list = parse_stream(NULL, inp, end_trigger); 5546 if (!pipe_list) { /* EOF */ 5547 if (empty) 5755 if (!pipe_list || pipe_list == ERR_PTR) { /* EOF/error */ 5756 /* If we are in "big" script 5757 * (not in `cmd` or something similar)... 5758 */ 5759 if (pipe_list == ERR_PTR && end_trigger == ';') { 5760 /* Discard cached input (rest of line) */ 5761 int ch = inp->last_char; 5762 while (ch != EOF && ch != '\n') { 5763 //bb_error_msg("Discarded:'%c'", ch); 5764 ch = i_getch(inp); 5765 } 5766 /* Force prompt */ 5767 inp->p = NULL; 5768 /* This stream isn't empty */ 5769 empty = 0; 5770 continue; 5771 } 5772 if (!pipe_list && empty) 5548 5773 G.last_exitcode = 0; 5549 5774 break; … … 5553 5778 run_and_free_list(pipe_list); 5554 5779 empty = 0; 5780 #if ENABLE_HUSH_FUNCTIONS 5781 if (G.flag_return_in_progress == 1) 5782 break; 5783 #endif 5555 5784 } 5556 5785 } … … 6119 6348 { 6120 6349 #if BB_MMU 6121 int rcode = x->b_function(argv); 6350 int rcode; 6351 fflush_all(); 6352 rcode = x->b_function(argv); 6122 6353 fflush_all(); 6123 6354 _exit(rcode); 6124 6355 #else 6356 fflush_all(); 6125 6357 /* On NOMMU, we must never block! 6126 6358 * Example: { sleep 99 | read line; } & echo Ok … … 6139 6371 { 6140 6372 debug_printf_exec("execing '%s'\n", argv[0]); 6141 sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); 6373 /* Don't propagate SIG_IGN to the child */ 6374 if (SPECIAL_JOBSTOP_SIGS != 0) 6375 switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS); 6142 6376 execvp(argv[0], argv); 6143 6377 bb_perror_msg("can't execute '%s'", argv[0]); … … 6271 6505 /* Re-exec ourselves */ 6272 6506 debug_printf_exec("re-execing applet '%s'\n", argv[0]); 6273 sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); 6507 /* Don't propagate SIG_IGN to the child */ 6508 if (SPECIAL_JOBSTOP_SIGS != 0) 6509 switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS); 6274 6510 execv(bb_busybox_exec_path, argv); 6275 6511 /* If they called chroot or otherwise made the binary no longer … … 6514 6750 ex = WEXITSTATUS(status); 6515 6751 /* bash prints killer signal's name for *last* 6516 * process in pipe (prints just newline for SIGINT ).6752 * process in pipe (prints just newline for SIGINT/SIGPIPE). 6517 6753 * Mimic this. Example: "sleep 5" + (^\ or kill -QUIT) 6518 6754 */ … … 6520 6756 int sig = WTERMSIG(status); 6521 6757 if (i == fg_pipe->num_cmds-1) 6522 printf("%s\n", sig == SIGINT ? "" : get_signame(sig)); 6758 /* TODO: use strsignal() instead for bash compat? but that's bloat... */ 6759 printf("%s\n", sig == SIGINT || sig == SIGPIPE ? "" : get_signame(sig)); 6760 /* TODO: if (WCOREDUMP(status)) + " (core dumped)"; */ 6523 6761 /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here? 6524 6762 * Maybe we need to use sig | 128? */ … … 6527 6765 fg_pipe->cmds[i].cmd_exitcode = ex; 6528 6766 } else { 6529 fg_pipe->cmds[i].is_stopped = 1;6530 6767 fg_pipe->stopped_cmds++; 6531 6768 } … … 6588 6825 } else { 6589 6826 /* child stopped */ 6590 pi->cmds[i].is_stopped = 1;6591 6827 pi->stopped_cmds++; 6592 6828 } … … 6629 6865 * cmd && ... { list } && ... 6630 6866 * cmd || ... { list } || ... 6631 * If it is, then we can run cmd as a builtin, NOFORK [do we do this?],6867 * If it is, then we can run cmd as a builtin, NOFORK, 6632 6868 * or (if SH_STANDALONE) an applet, and we can run the { list } 6633 6869 * with run_list. If it isn't one of these, we fork and exec cmd. … … 6811 7047 6812 7048 /* Expand the rest into (possibly) many strings each */ 6813 if (0) {}6814 7049 #if ENABLE_HUSH_BASH_COMPAT 6815 elseif (command->cmd_type == CMD_SINGLEWORD_NOGLOB) {7050 if (command->cmd_type == CMD_SINGLEWORD_NOGLOB) { 6816 7051 argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt); 6817 } 6818 #endif 6819 else{7052 } else 7053 #endif 7054 { 6820 7055 argv_expanded = expand_strvec_to_strvec(argv + command->assignment_cnt); 6821 7056 } … … 6847 7082 debug_printf_exec(": builtin '%s' '%s'...\n", 6848 7083 x->b_cmd, argv_expanded[1]); 7084 fflush_all(); 6849 7085 rcode = x->b_function(argv_expanded) & 0xff; 6850 7086 fflush_all(); … … 6879 7115 } 6880 7116 6881 if (ENABLE_FEATURE_SH_ STANDALONE) {7117 if (ENABLE_FEATURE_SH_NOFORK) { 6882 7118 int n = find_applet_by_name(argv_expanded[0]); 6883 7119 if (n >= 0 && APPLET_IS_NOFORK(n)) { … … 6968 7204 _exit(1); 6969 7205 6970 /* Restore default handlers just prior to exec */6971 /*signal(SIGCHLD, SIG_DFL); - so far we don't have any handlers */6972 6973 7206 /* Stores to nommu_save list of env vars putenv'ed 6974 7207 * (NOMMU, on MMU we don't need that) */ … … 7248 7481 G.last_exitcode = rcode; 7249 7482 debug_printf_exec(": builtin/func exitcode %d\n", rcode); 7250 check_and_run_traps( 0);7483 check_and_run_traps(); 7251 7484 #if ENABLE_HUSH_LOOPS 7252 7485 /* Was it "break" or "continue"? */ … … 7280 7513 * try "{ { sleep 10; echo DEEP; } & echo HERE; } &". 7281 7514 * I'm NOT treating inner &'s as jobs */ 7282 check_and_run_traps( 0);7515 check_and_run_traps(); 7283 7516 #if ENABLE_HUSH_JOB 7284 7517 if (G.run_list_level == 1) … … 7295 7528 rcode = checkjobs_and_fg_shell(pi); 7296 7529 debug_printf_exec(": checkjobs_and_fg_shell exitcode %d\n", rcode); 7297 check_and_run_traps( 0);7530 check_and_run_traps(); 7298 7531 } else 7299 7532 #endif … … 7301 7534 rcode = checkjobs(pi); 7302 7535 debug_printf_exec(": checkjobs exitcode %d\n", rcode); 7303 check_and_run_traps( 0);7536 check_and_run_traps(); 7304 7537 } 7305 7538 G.last_exitcode = rcode; … … 7316 7549 if (pi->next 7317 7550 && (pi->next->res_word == RES_DO || pi->next->res_word == RES_DONE) 7318 /* (the second check above is needed for "while ...; do \n done" case)*/7551 /* check for RES_DONE is needed for "while ...; do \n done" case */ 7319 7552 ) { 7320 7553 if (rword == RES_WHILE) { … … 7362 7595 int rcode = 0; 7363 7596 debug_printf_exec("run_and_free_list entered\n"); 7364 if (!G. n_mode) {7597 if (!G.o_opt[OPT_O_NOEXEC]) { 7365 7598 debug_printf_exec(": run_list: 1st pipe with %d cmds\n", pi->num_cmds); 7366 7599 rcode = run_list(pi); … … 7375 7608 7376 7609 7610 static void install_sighandlers(unsigned mask) 7611 { 7612 sighandler_t old_handler; 7613 unsigned sig = 0; 7614 while ((mask >>= 1) != 0) { 7615 sig++; 7616 if (!(mask & 1)) 7617 continue; 7618 old_handler = install_sighandler(sig, pick_sighandler(sig)); 7619 /* POSIX allows shell to re-enable SIGCHLD 7620 * even if it was SIG_IGN on entry. 7621 * Therefore we skip IGN check for it: 7622 */ 7623 if (sig == SIGCHLD) 7624 continue; 7625 if (old_handler == SIG_IGN) { 7626 /* oops... restore back to IGN, and record this fact */ 7627 install_sighandler(sig, old_handler); 7628 if (!G.traps) 7629 G.traps = xzalloc(sizeof(G.traps[0]) * NSIG); 7630 free(G.traps[sig]); 7631 G.traps[sig] = xzalloc(1); /* == xstrdup(""); */ 7632 } 7633 } 7634 } 7635 7377 7636 /* Called a few times only (or even once if "sh -c") */ 7378 static void init_sigmasks(void) 7379 { 7380 unsigned sig; 7637 static void install_special_sighandlers(void) 7638 { 7381 7639 unsigned mask; 7382 sigset_t old_blocked_set; 7383 7384 if (!G.inherited_set_is_saved) { 7385 sigprocmask(SIG_SETMASK, NULL, &G.blocked_set); 7386 G.inherited_set = G.blocked_set; 7387 } 7388 old_blocked_set = G.blocked_set; 7389 7390 mask = (1 << SIGQUIT); 7640 7641 /* Which signals are shell-special? */ 7642 mask = (1 << SIGQUIT) | (1 << SIGCHLD); 7391 7643 if (G_interactive_fd) { 7392 mask = (1 << SIGQUIT) |SPECIAL_INTERACTIVE_SIGS;7644 mask |= SPECIAL_INTERACTIVE_SIGS; 7393 7645 if (G_saved_tty_pgrp) /* we have ctty, job control sigs work */ 7394 mask |= SPECIAL_JOB_SIGS; 7395 } 7396 G.non_DFL_mask = mask; 7397 7398 sig = 0; 7399 while (mask) { 7400 if (mask & 1) 7401 sigaddset(&G.blocked_set, sig); 7402 mask >>= 1; 7403 sig++; 7404 } 7405 sigdelset(&G.blocked_set, SIGCHLD); 7406 7407 if (memcmp(&old_blocked_set, &G.blocked_set, sizeof(old_blocked_set)) != 0) 7408 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); 7409 7410 /* POSIX allows shell to re-enable SIGCHLD 7411 * even if it was SIG_IGN on entry */ 7412 #if ENABLE_HUSH_FAST 7413 G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ 7414 if (!G.inherited_set_is_saved) 7415 signal(SIGCHLD, SIGCHLD_handler); 7416 #else 7417 if (!G.inherited_set_is_saved) 7418 signal(SIGCHLD, SIG_DFL); 7419 #endif 7420 7421 G.inherited_set_is_saved = 1; 7646 mask |= SPECIAL_JOBSTOP_SIGS; 7647 } 7648 /* Careful, do not re-install handlers we already installed */ 7649 if (G.special_sig_mask != mask) { 7650 unsigned diff = mask & ~G.special_sig_mask; 7651 G.special_sig_mask = mask; 7652 install_sighandlers(diff); 7653 } 7422 7654 } 7423 7655 7424 7656 #if ENABLE_HUSH_JOB 7425 7657 /* helper */ 7426 static void maybe_set_to_sigexit(int sig) 7427 { 7428 void (*handler)(int); 7429 /* non_DFL_mask'ed signals are, well, masked, 7430 * no need to set handler for them. 7658 /* Set handlers to restore tty pgrp and exit */ 7659 static void install_fatal_sighandlers(void) 7660 { 7661 unsigned mask; 7662 7663 /* We will restore tty pgrp on these signals */ 7664 mask = 0 7665 + (1 << SIGILL ) * HUSH_DEBUG 7666 + (1 << SIGFPE ) * HUSH_DEBUG 7667 + (1 << SIGBUS ) * HUSH_DEBUG 7668 + (1 << SIGSEGV) * HUSH_DEBUG 7669 + (1 << SIGTRAP) * HUSH_DEBUG 7670 + (1 << SIGABRT) 7671 /* bash 3.2 seems to handle these just like 'fatal' ones */ 7672 + (1 << SIGPIPE) 7673 + (1 << SIGALRM) 7674 /* if we are interactive, SIGHUP, SIGTERM and SIGINT are special sigs. 7675 * if we aren't interactive... but in this case 7676 * we never want to restore pgrp on exit, and this fn is not called 7431 7677 */ 7432 if (!((G.non_DFL_mask >> sig) & 1)) { 7433 handler = signal(sig, sigexit); 7434 if (handler == SIG_IGN) /* oops... restore back to IGN! */ 7435 signal(sig, handler); 7436 } 7437 } 7438 /* Set handlers to restore tty pgrp and exit */ 7439 static void set_fatal_handlers(void) 7440 { 7441 /* We _must_ restore tty pgrp on fatal signals */ 7442 if (HUSH_DEBUG) { 7443 maybe_set_to_sigexit(SIGILL ); 7444 maybe_set_to_sigexit(SIGFPE ); 7445 maybe_set_to_sigexit(SIGBUS ); 7446 maybe_set_to_sigexit(SIGSEGV); 7447 maybe_set_to_sigexit(SIGTRAP); 7448 } /* else: hush is perfect. what SEGV? */ 7449 maybe_set_to_sigexit(SIGABRT); 7450 /* bash 3.2 seems to handle these just like 'fatal' ones */ 7451 maybe_set_to_sigexit(SIGPIPE); 7452 maybe_set_to_sigexit(SIGALRM); 7453 /* if we are interactive, SIGHUP, SIGTERM and SIGINT are masked. 7454 * if we aren't interactive... but in this case 7455 * we never want to restore pgrp on exit, and this fn is not called */ 7456 /*maybe_set_to_sigexit(SIGHUP );*/ 7457 /*maybe_set_to_sigexit(SIGTERM);*/ 7458 /*maybe_set_to_sigexit(SIGINT );*/ 7678 /*+ (1 << SIGHUP )*/ 7679 /*+ (1 << SIGTERM)*/ 7680 /*+ (1 << SIGINT )*/ 7681 ; 7682 G_fatal_sig_mask = mask; 7683 7684 install_sighandlers(mask); 7459 7685 } 7460 7686 #endif … … 7465 7691 switch (mode) { 7466 7692 case 'n': 7467 G. n_mode= state;7693 G.o_opt[OPT_O_NOEXEC] = state; 7468 7694 break; 7469 7695 case 'x': … … 7502 7728 int hush_main(int argc, char **argv) 7503 7729 { 7730 enum { 7731 OPT_login = (1 << 0), 7732 }; 7733 unsigned flags; 7504 7734 int opt; 7505 7735 unsigned builtin_argc; … … 7509 7739 7510 7740 INIT_G(); 7511 if (EXIT_SUCCESS ) /* if EXIT_SUCCESS == 0, it is already done */7741 if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */ 7512 7742 G.last_exitcode = EXIT_SUCCESS; 7743 #if ENABLE_HUSH_FAST 7744 G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ 7745 #endif 7513 7746 #if !BB_MMU 7514 7747 G.argv0_for_re_execing = argv[0]; … … 7584 7817 #if ENABLE_FEATURE_EDITING 7585 7818 G.line_input_state = new_line_input_t(FOR_SHELL); 7586 # if defined MAX_HISTORY && MAX_HISTORY > 0 && ENABLE_HUSH_SAVEHISTORY 7587 { 7588 const char *hp = get_local_var_value("HISTFILE"); 7589 if (!hp) { 7590 hp = get_local_var_value("HOME"); 7591 if (hp) { 7592 G.line_input_state->hist_file = concat_path_file(hp, ".hush_history"); 7593 //set_local_var(xasprintf("HISTFILE=%s", ...)); 7594 } 7595 } 7596 } 7597 # endif 7598 #endif 7599 7600 G.global_argc = argc; 7601 G.global_argv = argv; 7819 #endif 7820 7602 7821 /* Initialize some more globals to non-zero values */ 7603 7822 cmdedit_update_prompt(); … … 7611 7830 7612 7831 /* Shell is non-interactive at first. We need to call 7613 * in it_sigmasks() if we are going to execute "sh <script>",7832 * install_special_sighandlers() if we are going to execute "sh <script>", 7614 7833 * "sh -c <cmds>" or login shell's /etc/profile and friends. 7615 * If we later decide that we are interactive, we run in it_sigmasks()7834 * If we later decide that we are interactive, we run install_special_sighandlers() 7616 7835 * in order to intercept (more) signals. 7617 7836 */ … … 7619 7838 /* Parse options */ 7620 7839 /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ 7840 flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0; 7621 7841 builtin_argc = 0; 7622 7842 while (1) { 7623 opt = getopt(argc, argv, "+c:xins "7843 opt = getopt(argc, argv, "+c:xinsl" 7624 7844 #if !BB_MMU 7625 7845 "<:$:R:V:" … … 7653 7873 const struct built_in_command *x; 7654 7874 7655 in it_sigmasks();7875 install_special_sighandlers(); 7656 7876 x = find_builtin(optarg); 7657 7877 if (x) { /* paranoia */ … … 7659 7879 G.global_argv += builtin_argc; 7660 7880 G.global_argv[-1] = NULL; /* replace "" */ 7881 fflush_all(); 7661 7882 G.last_exitcode = x->b_function(argv + optind - 1); 7662 7883 } … … 7669 7890 G.global_argc++; 7670 7891 } /* else -c 'script' ARG0 [ARG1...]: $0 is ARG0 */ 7671 in it_sigmasks();7892 install_special_sighandlers(); 7672 7893 parse_and_run_string(optarg); 7673 7894 goto final_return; … … 7680 7901 /* "-s" means "read from stdin", but this is how we always 7681 7902 * operate, so simply do nothing here. */ 7903 break; 7904 case 'l': 7905 flags |= OPT_login; 7682 7906 break; 7683 7907 #if !BB_MMU … … 7701 7925 if (empty_trap_mask != 0) { 7702 7926 int sig; 7703 in it_sigmasks();7927 install_special_sighandlers(); 7704 7928 G.traps = xzalloc(sizeof(G.traps[0]) * NSIG); 7705 7929 for (sig = 1; sig < NSIG; sig++) { 7706 7930 if (empty_trap_mask & (1LL << sig)) { 7707 7931 G.traps[sig] = xzalloc(1); /* == xstrdup(""); */ 7708 sigaddset(&G.blocked_set, sig);7932 install_sighandler(sig, SIG_IGN); 7709 7933 } 7710 7934 } 7711 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);7712 7935 } 7713 7936 # if ENABLE_HUSH_LOOPS … … 7747 7970 } /* option parsing loop */ 7748 7971 7972 /* Skip options. Try "hush -l": $1 should not be "-l"! */ 7973 G.global_argc = argc - (optind - 1); 7974 G.global_argv = argv + (optind - 1); 7975 G.global_argv[0] = argv[0]; 7976 7749 7977 if (!G.root_pid) { 7750 7978 G.root_pid = getpid(); … … 7753 7981 7754 7982 /* If we are login shell... */ 7755 if ( argv[0] && argv[0][0] == '-') {7983 if (flags & OPT_login) { 7756 7984 FILE *input; 7757 7985 debug_printf("sourcing /etc/profile\n"); … … 7759 7987 if (input != NULL) { 7760 7988 close_on_exec_on(fileno(input)); 7761 in it_sigmasks();7989 install_special_sighandlers(); 7762 7990 parse_and_run_file(input); 7763 7991 fclose(input); … … 7772 8000 } 7773 8001 7774 if ( argv[optind]) {8002 if (G.global_argv[1]) { 7775 8003 FILE *input; 7776 8004 /* … … 7779 8007 * If called as sh, does the same but with $ENV. 7780 8008 */ 7781 debug_printf("running script '%s'\n", argv[optind]);7782 G.global_argv = argv + optind;7783 G.global_argc = argc - optind;7784 input = xfopen_for_read( argv[optind]);8009 G.global_argc--; 8010 G.global_argv++; 8011 debug_printf("running script '%s'\n", G.global_argv[0]); 8012 input = xfopen_for_read(G.global_argv[0]); 7785 8013 close_on_exec_on(fileno(input)); 7786 in it_sigmasks();8014 install_special_sighandlers(); 7787 8015 parse_and_run_file(input); 7788 8016 #if ENABLE_FEATURE_CLEAN_UP … … 7793 8021 7794 8022 /* Up to here, shell was non-interactive. Now it may become one. 7795 * NB: don't forget to (re)run in it_sigmasks() as needed.8023 * NB: don't forget to (re)run install_special_sighandlers() as needed. 7796 8024 */ 7797 8025 … … 7845 8073 } 7846 8074 7847 /* Block some signals */7848 in it_sigmasks();8075 /* Install more signal handlers */ 8076 install_special_sighandlers(); 7849 8077 7850 8078 if (G_saved_tty_pgrp) { 7851 8079 /* Set other signals to restore saved_tty_pgrp */ 7852 set_fatal_handlers();8080 install_fatal_sighandlers(); 7853 8081 /* Put ourselves in our own process group 7854 8082 * (bash, too, does this only if ctty is available) */ … … 7860 8088 * (we reset die_sleep = 0 whereever we [v]fork) */ 7861 8089 enable_restore_tty_pgrp_on_exit(); /* sets die_sleep = -1 */ 8090 8091 # if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0 8092 { 8093 const char *hp = get_local_var_value("HISTFILE"); 8094 if (!hp) { 8095 hp = get_local_var_value("HOME"); 8096 if (hp) 8097 hp = concat_path_file(hp, ".hush_history"); 8098 } else { 8099 hp = xstrdup(hp); 8100 } 8101 if (hp) { 8102 G.line_input_state->hist_file = hp; 8103 //set_local_var(xasprintf("HISTFILE=%s", ...)); 8104 } 8105 # if ENABLE_FEATURE_SH_HISTFILESIZE 8106 hp = get_local_var_value("HISTFILESIZE"); 8107 G.line_input_state->max_history = size_from_HISTFILESIZE(hp); 8108 # endif 8109 } 8110 # endif 7862 8111 } else { 7863 in it_sigmasks();8112 install_special_sighandlers(); 7864 8113 } 7865 8114 #elif ENABLE_HUSH_INTERACTIVE … … 7878 8127 close_on_exec_on(G_interactive_fd); 7879 8128 } 7880 in it_sigmasks();8129 install_special_sighandlers(); 7881 8130 #else 7882 8131 /* We have interactiveness code disabled */ 7883 in it_sigmasks();8132 install_special_sighandlers(); 7884 8133 #endif 7885 8134 /* bash: … … 8015 8264 8016 8265 /* TODO: if exec fails, bash does NOT exit! We do. 8017 * We'll need to undo sigprocmask(it's inside execvp_or_die)8266 * We'll need to undo trap cleanup (it's inside execvp_or_die) 8018 8267 * and tcsetpgrp, and this is inherently racy. 8019 8268 */ … … 8033 8282 * # exit 8034 8283 * exit 8035 #EEE (then bash exits)8284 * EEE (then bash exits) 8036 8285 * 8037 8286 * TODO: we can use G.exiting = -1 as indicator "last cmd was exit" … … 8212 8461 ret = EXIT_SUCCESS; 8213 8462 while (*argv) { 8463 sighandler_t handler; 8464 8214 8465 sig = get_signum(*argv++); 8215 8466 if (sig < 0 || sig >= NSIG) { … … 8230 8481 continue; 8231 8482 8232 if (new_cmd) { 8233 sigaddset(&G.blocked_set, sig); 8234 } else { 8235 /* There was a trap handler, we are removing it 8236 * (if sig has non-DFL handling, 8237 * we don't need to do anything) */ 8238 if (sig < 32 && (G.non_DFL_mask & (1 << sig))) 8239 continue; 8240 sigdelset(&G.blocked_set, sig); 8241 } 8242 } 8243 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); 8483 if (new_cmd) 8484 handler = (new_cmd[0] ? record_pending_signo : SIG_IGN); 8485 else 8486 /* We are removing trap handler */ 8487 handler = pick_sighandler(sig); 8488 install_sighandler(sig, handler); 8489 } 8244 8490 return ret; 8245 8491 } … … 8346 8592 for (i = 0; i < pi->num_cmds; i++) { 8347 8593 debug_printf_jobs("reviving pid %d\n", pi->cmds[i].pid); 8348 pi->cmds[i].is_stopped = 0;8349 8594 } 8350 8595 pi->stopped_cmds = 0; … … 8442 8687 } 8443 8688 8689 /* Interruptibility of read builtin in bash 8690 * (tested on bash-4.2.8 by sending signals (not by ^C)): 8691 * 8692 * Empty trap makes read ignore corresponding signal, for any signal. 8693 * 8694 * SIGINT: 8695 * - terminates non-interactive shell; 8696 * - interrupts read in interactive shell; 8697 * if it has non-empty trap: 8698 * - executes trap and returns to command prompt in interactive shell; 8699 * - executes trap and returns to read in non-interactive shell; 8700 * SIGTERM: 8701 * - is ignored (does not interrupt) read in interactive shell; 8702 * - terminates non-interactive shell; 8703 * if it has non-empty trap: 8704 * - executes trap and returns to read; 8705 * SIGHUP: 8706 * - terminates shell (regardless of interactivity); 8707 * if it has non-empty trap: 8708 * - executes trap and returns to read; 8709 */ 8444 8710 static int FAST_FUNC builtin_read(char **argv) 8445 8711 { … … 8449 8715 char *opt_t = NULL; 8450 8716 char *opt_u = NULL; 8717 const char *ifs; 8451 8718 int read_flags; 8452 8719 … … 8458 8725 return EXIT_FAILURE; 8459 8726 argv += optind; 8460 8727 ifs = get_local_var_value("IFS"); /* can be NULL */ 8728 8729 again: 8461 8730 r = shell_builtin_read(set_local_var_from_halves, 8462 8731 argv, 8463 get_local_var_value("IFS"), /* can be NULL */8732 ifs, 8464 8733 read_flags, 8465 8734 opt_n, … … 8468 8737 opt_u 8469 8738 ); 8739 8740 if ((uintptr_t)r == 1 && errno == EINTR) { 8741 unsigned sig = check_and_run_traps(); 8742 if (sig && sig != SIGINT) 8743 goto again; 8744 } 8470 8745 8471 8746 if ((uintptr_t)r > 1) { … … 8701 8976 { 8702 8977 int ret = EXIT_SUCCESS; 8703 int status , sig;8978 int status; 8704 8979 8705 8980 argv = skip_dash_dash(argv); … … 8721 8996 * $ 8722 8997 */ 8723 sigaddset(&G.blocked_set, SIGCHLD);8724 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);8725 8998 while (1) { 8726 checkjobs(NULL); 8727 if (errno == ECHILD) 8999 int sig; 9000 sigset_t oldset, allsigs; 9001 9002 /* waitpid is not interruptible by SA_RESTARTed 9003 * signals which we use. Thus, this ugly dance: 9004 */ 9005 9006 /* Make sure possible SIGCHLD is stored in kernel's 9007 * pending signal mask before we call waitpid. 9008 * Or else we may race with SIGCHLD, lose it, 9009 * and get stuck in sigwaitinfo... 9010 */ 9011 sigfillset(&allsigs); 9012 sigprocmask(SIG_SETMASK, &allsigs, &oldset); 9013 9014 if (!sigisemptyset(&G.pending_set)) { 9015 /* Crap! we raced with some signal! */ 9016 // sig = 0; 9017 goto restore; 9018 } 9019 9020 checkjobs(NULL); /* waitpid(WNOHANG) inside */ 9021 if (errno == ECHILD) { 9022 sigprocmask(SIG_SETMASK, &oldset, NULL); 8728 9023 break; 8729 /* Wait for SIGCHLD or any other signal of interest */ 8730 /* sigtimedwait with infinite timeout: */ 8731 sig = sigwaitinfo(&G.blocked_set, NULL); 8732 if (sig > 0) { 8733 sig = check_and_run_traps(sig); 8734 if (sig && sig != SIGCHLD) { /* see note 2 */ 8735 ret = 128 + sig; 8736 break; 8737 } 8738 } 8739 } 8740 sigdelset(&G.blocked_set, SIGCHLD); 8741 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); 9024 } 9025 9026 /* Wait for SIGCHLD or any other signal */ 9027 //sig = sigwaitinfo(&allsigs, NULL); 9028 /* It is vitally important for sigsuspend that SIGCHLD has non-DFL handler! */ 9029 /* Note: sigsuspend invokes signal handler */ 9030 sigsuspend(&oldset); 9031 restore: 9032 sigprocmask(SIG_SETMASK, &oldset, NULL); 9033 9034 /* So, did we get a signal? */ 9035 //if (sig > 0) 9036 // raise(sig); /* run handler */ 9037 sig = check_and_run_traps(); 9038 if (sig /*&& sig != SIGCHLD - always true */) { 9039 /* see note 2 */ 9040 ret = 128 + sig; 9041 break; 9042 } 9043 /* SIGCHLD, or no signal, or ignored one, such as SIGQUIT. Repeat */ 9044 } 8742 9045 return ret; 8743 9046 } -
branches/3.2/mindi-busybox/shell/hush_test/hush-parsing/starquoted2.right
r2725 r3232 1 1 Should be printed 2 Would not be printed by bash 3 Would not be printed by bash 4 Would not be printed by bash 2 5 Should be printed 3 6 Empty: -
branches/3.2/mindi-busybox/shell/hush_test/hush-parsing/starquoted2.tests
r2725 r3232 9 9 # treating "" as "this word cannot be expanded to nothing, 10 10 # but must be at least null string". Now it can be expanded to nothing. 11 for a in "$@"""; do echo Should not be printed; done12 for a in """$@"; do echo Should not be printed; done13 for a in """$@"''"$@"''; do echo Should not be printed; done11 for a in "$@"""; do echo Would not be printed by bash; done 12 for a in """$@"; do echo Would not be printed by bash; done 13 for a in """$@"''"$@"''; do echo Would not be printed by bash; done 14 14 for a in ""; do echo Should be printed; done 15 15 -
branches/3.2/mindi-busybox/shell/hush_test/run-all
r2725 r3232 49 49 #*) echo $x ; sh $x ;; 50 50 *) 51 echo -n "$1/$x:" 51 52 sh "$x" >"../$1-$x.fail" 2>&1 && \ 52 { echo "$1/$x: ok"; rm "../$1-$x.fail"; } || echo "$1/$x: fail";53 { { echo " ok"; rm "../$1-$x.fail"; } || echo " fail"; } 53 54 ;; 54 55 esac … … 61 62 test -f "$name.right" || continue 62 63 # echo Running test: "$x" 64 echo -n "$1/$x:" 63 65 ( 64 66 "$THIS_SH" "./$x" >"$name.xx" 2>&1 … … 71 73 ) 72 74 case $? in 73 0) echo " $1/$x:ok";;74 77) echo " $1/$x:skip (feature disabled)";;75 *) echo " $1/$x:fail"; tret=1;;75 0) echo " ok";; 76 77) echo " skip (feature disabled)";; 77 *) echo " fail"; tret=1;; 76 78 esac 77 79 done -
branches/3.2/mindi-busybox/shell/math.c
r2725 r3232 411 411 c = 1; 412 412 while (--right_side_val >= 0) 413 413 c *= rez; 414 414 rez = c; 415 415 } -
branches/3.2/mindi-busybox/shell/shell_common.c
r2725 r3232 19 19 #include "libbb.h" 20 20 #include "shell_common.h" 21 #include <sys/resource.h> /* getrlimit */ 21 22 22 23 const char defifsvar[] ALIGN1 = "IFS= \t\n"; … … 37 38 /* read builtin */ 38 39 40 /* Needs to be interruptible: shell mush handle traps and shell-special signals 41 * while inside read. To implement this, be sure to not loop on EINTR 42 * and return errno == EINTR reliably. 43 */ 39 44 //TODO: use more efficient setvar() which takes a pointer to malloced "VAR=VAL" 40 45 //string. hush naturally has it, and ash has setvareq(). … … 52 57 ) 53 58 { 59 unsigned err; 54 60 unsigned end_ms; /* -t TIMEOUT */ 55 61 int fd; /* -u FD */ … … 62 68 int startword; 63 69 smallint backslash; 70 71 errno = err = 0; 64 72 65 73 pp = argv; … … 132 140 if (nchars) { 133 141 tty.c_lflag &= ~ICANON; 134 tty.c_cc[VMIN] = nchars < 256 ? nchars : 255; 142 // Setting it to more than 1 breaks poll(): 143 // it blocks even if there's data. !?? 144 //tty.c_cc[VMIN] = nchars < 256 ? nchars : 255; 145 /* reads would block only if < 1 char is available */ 146 tty.c_cc[VMIN] = 1; 147 /* no timeout (reads block forever) */ 148 tty.c_cc[VTIME] = 0; 135 149 } 136 150 if (read_flags & BUILTIN_READ_SILENT) { … … 153 167 do { 154 168 char c; 155 169 struct pollfd pfd[1]; 170 int timeout; 171 172 if ((bufpos & 0xff) == 0) 173 buffer = xrealloc(buffer, bufpos + 0x101); 174 175 timeout = -1; 156 176 if (end_ms) { 157 int timeout;158 struct pollfd pfd[1];159 160 pfd[0].fd = fd;161 pfd[0].events = POLLIN;162 177 timeout = end_ms - (unsigned)monotonic_ms(); 163 if (timeout <= 0 /* already late? */ 164 || safe_poll(pfd, 1, timeout) != 1 /* no? wait... */ 165 ) { /* timed out! */ 178 if (timeout <= 0) { /* already late? */ 166 179 retval = (const char *)(uintptr_t)1; 167 180 goto ret; … … 169 182 } 170 183 171 if ((bufpos & 0xff) == 0) 172 buffer = xrealloc(buffer, bufpos + 0x100); 173 if (nonblock_safe_read(fd, &buffer[bufpos], 1) != 1) { 184 /* We must poll even if timeout is -1: 185 * we want to be interrupted if signal arrives, 186 * regardless of SA_RESTART-ness of that signal! 187 */ 188 errno = 0; 189 pfd[0].fd = fd; 190 pfd[0].events = POLLIN; 191 if (poll(pfd, 1, timeout) != 1) { 192 /* timed out, or EINTR */ 193 err = errno; 194 retval = (const char *)(uintptr_t)1; 195 goto ret; 196 } 197 if (read(fd, &buffer[bufpos], 1) != 1) { 198 err = errno; 174 199 retval = (const char *)(uintptr_t)1; 175 200 break; 176 201 } 202 177 203 c = buffer[bufpos]; 178 204 if (c == '\0') … … 241 267 if (read_flags & BUILTIN_READ_SILENT) 242 268 tcsetattr(fd, TCSANOW, &old_tty); 269 270 errno = err; 243 271 return retval; 244 272 } … … 287 315 { RLIMIT_LOCKS, 0, 'w', "locks" }, 288 316 #endif 317 #ifdef RLIMIT_NICE 318 { RLIMIT_NICE, 0, 'e', "scheduling priority" }, 319 #endif 320 #ifdef RLIMIT_RTPRIO 321 { RLIMIT_RTPRIO, 0, 'r', "real-time priority" }, 322 #endif 289 323 }; 290 324 … … 328 362 #ifdef RLIMIT_LOCKS 329 363 "w::" 364 #endif 365 #ifdef RLIMIT_NICE 366 "e::" 367 #endif 368 #ifdef RLIMIT_RTPRIO 369 "r::" 330 370 #endif 331 371 ; … … 369 409 /* optarg = NULL; opterr = 0; optopt = 0; - do we need this?? */ 370 410 371 372 373 411 argc = 1; 412 while (argv[argc]) 413 argc++; 374 414 375 415 opts = 0; -
branches/3.2/mindi-busybox/shell/shell_common.h
r3045 r3232 19 19 #ifndef SHELL_COMMON_H 20 20 #define SHELL_COMMON_H 1 21 /* BCO: From http://paste.pound-python.org/show/23796/ - Fix #632 */22 #include <sys/resource.h>23 /* End BCO */24 21 25 22 PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 26 23 27 extern const char defifsvar[] ; /* "IFS= \t\n" */24 extern const char defifsvar[] ALIGN1; /* "IFS= \t\n" */ 28 25 #define defifs (defifsvar + 4) 29 26
Note:
See TracChangeset
for help on using the changeset viewer.