aboutsummaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c145
1 files changed, 70 insertions, 75 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 1f57c2d7e..b8f75af05 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -240,17 +240,17 @@
240#define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT 240#define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT
241/* BASH_TEST2: [[ EXPR ]] 241/* BASH_TEST2: [[ EXPR ]]
242 * Status of [[ support: 242 * Status of [[ support:
243 * We replace && and || with -a and -o 243 * && and || work as they should
244 * = is glob match operator, not equality operator: STR = GLOB
245 * == same as =
246 * =~ is regex match operator: STR =~ REGEX
244 * TODO: 247 * TODO:
245 * singleword+noglob expansion: 248 * singleword+noglob expansion:
246 * v='a b'; [[ $v = 'a b' ]]; echo 0:$? 249 * v='a b'; [[ $v = 'a b' ]]; echo 0:$?
247 * [[ /bin/n* ]]; echo 0:$? 250 * [[ /bin/n* ]]; echo 0:$?
248 * -a/-o are not AND/OR ops! (they are just strings)
249 * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc) 251 * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc)
250 * = is glob match operator, not equality operator: STR = GLOB 252 * ( ) < > should not have special meaning (IOW: should not require quoting)
251 * (in GLOB, quoting is significant on char-by-char basis: a*cd"*") 253 * in word = GLOB, quoting should be significant on char-by-char basis: a*cd"*"
252 * == same as =
253 * add =~ regex match operator: STR =~ REGEX
254 */ 254 */
255#define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST) 255#define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST)
256#define BASH_SOURCE ENABLE_ASH_BASH_COMPAT 256#define BASH_SOURCE ENABLE_ASH_BASH_COMPAT
@@ -3173,7 +3173,7 @@ updatepwd(const char *dir)
3173 lim++; 3173 lim++;
3174 } 3174 }
3175 } 3175 }
3176 p = strtok(cdcomppath, "/"); 3176 p = strtok_r(cdcomppath, "/", &cdcomppath);
3177 while (p) { 3177 while (p) {
3178 switch (*p) { 3178 switch (*p) {
3179 case '.': 3179 case '.':
@@ -3192,7 +3192,7 @@ updatepwd(const char *dir)
3192 new = stack_putstr(p, new); 3192 new = stack_putstr(p, new);
3193 USTPUTC('/', new); 3193 USTPUTC('/', new);
3194 } 3194 }
3195 p = strtok(NULL, "/"); 3195 p = strtok_r(NULL, "/", &cdcomppath);
3196 } 3196 }
3197 if (new > lim) 3197 if (new > lim)
3198 STUNPUTC(new); 3198 STUNPUTC(new);
@@ -4780,61 +4780,54 @@ waitpid_child(int *status, int wait_flags)
4780 return pid; 4780 return pid;
4781} 4781}
4782#define waitpid(p, s, f) waitpid_child(s, f) 4782#define waitpid(p, s, f) waitpid_child(s, f)
4783#define wait_block_or_sig(s) waitpid_child(s, 0) 4783#endif
4784 4784
4785#else 4785#define DOWAIT_NONBLOCK 0
4786#define DOWAIT_BLOCK 1
4787#define DOWAIT_BLOCK_OR_SIG 2
4788#if BASH_WAIT_N
4789# define DOWAIT_JOBSTATUS 0x10 /* OR this to get job's exitstatus instead of pid */
4790#endif
4786 4791
4787static int 4792static int
4788wait_block_or_sig(int *status) 4793waitproc(int block, int *status)
4789{ 4794{
4790 int pid; 4795#if !ENABLE_PLATFORM_MINGW32
4796 sigset_t oldmask;
4797 int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG;
4798 int err;
4791 4799
4792 do { 4800#if JOBS
4793 sigset_t mask; 4801 if (doing_jobctl)
4802 flags |= WUNTRACED;
4803#endif
4794 4804
4795 /* Poll all children for changes in their state */ 4805 do {
4796 got_sigchld = 0; 4806 got_sigchld = 0;
4797 /* if job control is active, accept stopped processes too */ 4807 do
4798 pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG); 4808 err = waitpid(-1, status, flags);
4799 if (pid != 0) 4809 while (err < 0 && errno == EINTR);
4800 break; /* Error (e.g. EINTR, ECHILD) or pid */
4801 4810
4802 /* Children exist, but none are ready. Sleep until interesting signal */ 4811 if (err || (err = -!block))
4803#if 1 4812 break;
4804 sigfillset(&mask); 4813
4805 sigprocmask2(SIG_SETMASK, &mask); /* mask is updated */ 4814 sigfillset(&oldmask);
4806 while (!got_sigchld && !pending_sig) { 4815 sigprocmask2(SIG_SETMASK, &oldmask); /* mask is updated */
4807 sigsuspend(&mask);
4808 /* ^^^ add "sigdelset(&mask, SIGCHLD);" before sigsuspend
4809 * to make sure SIGCHLD is not masked off?
4810 * It was reported that this:
4811 * fn() { : | return; }
4812 * shopt -s lastpipe
4813 * fn
4814 * exec ash SCRIPT
4815 * under bash 4.4.23 runs SCRIPT with SIGCHLD masked,
4816 * making "wait" commands in SCRIPT block forever.
4817 */
4818 }
4819 sigprocmask(SIG_SETMASK, &mask, NULL);
4820#else /* unsafe: a signal can set pending_sig after check, but before pause() */
4821 while (!got_sigchld && !pending_sig) 4816 while (!got_sigchld && !pending_sig)
4822 pause(); 4817 sigsuspend(&oldmask);
4823#endif 4818 sigprocmask(SIG_SETMASK, &oldmask, NULL);
4819 //simpler, but unsafe: a signal can set pending_sig after check, but before pause():
4820 //while (!got_sigchld && !pending_sig)
4821 // pause();
4824 4822
4825 /* If it was SIGCHLD, poll children again */
4826 } while (got_sigchld); 4823 } while (got_sigchld);
4827 4824
4828 return pid; 4825 return err;
4829} 4826#else
4830#endif 4827 int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG;
4831 4828 return waitpid(-1, status, flags);
4832#define DOWAIT_NONBLOCK 0
4833#define DOWAIT_BLOCK 1
4834#define DOWAIT_BLOCK_OR_SIG 2
4835#if BASH_WAIT_N
4836# define DOWAIT_JOBSTATUS 0x10 /* OR this to get job's exitstatus instead of pid */
4837#endif 4829#endif
4830}
4838 4831
4839static int 4832static int
4840waitone(int block, struct job *job) 4833waitone(int block, struct job *job)
@@ -4842,7 +4835,7 @@ waitone(int block, struct job *job)
4842 int pid; 4835 int pid;
4843 int status; 4836 int status;
4844 struct job *jp; 4837 struct job *jp;
4845 struct job *thisjob; 4838 struct job *thisjob = NULL;
4846#if BASH_WAIT_N 4839#if BASH_WAIT_N
4847 bool want_jobexitstatus = (block & DOWAIT_JOBSTATUS); 4840 bool want_jobexitstatus = (block & DOWAIT_JOBSTATUS);
4848 block = (block & ~DOWAIT_JOBSTATUS); 4841 block = (block & ~DOWAIT_JOBSTATUS);
@@ -4869,21 +4862,8 @@ waitone(int block, struct job *job)
4869 * SIG_DFL handler does not wake sigsuspend(). 4862 * SIG_DFL handler does not wake sigsuspend().
4870 */ 4863 */
4871 INT_OFF; 4864 INT_OFF;
4872 if (block == DOWAIT_BLOCK_OR_SIG) { 4865 pid = waitproc(block, &status);
4873 pid = wait_block_or_sig(&status); 4866 TRACE(("wait returns pid %d, status=%d\n", pid, status));
4874 } else {
4875 int wait_flags = 0;
4876 if (block == DOWAIT_NONBLOCK)
4877 wait_flags = WNOHANG;
4878 /* if job control is active, accept stopped processes too */
4879 if (doing_jobctl)
4880 wait_flags |= WUNTRACED;
4881 /* NB: _not_ safe_waitpid, we need to detect EINTR */
4882 pid = waitpid(-1, &status, wait_flags);
4883 }
4884 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4885 pid, status, errno, strerror(errno)));
4886 thisjob = NULL;
4887 if (pid <= 0) 4867 if (pid <= 0)
4888 goto out; 4868 goto out;
4889 4869
@@ -4971,21 +4951,35 @@ static int
4971dowait(int block, struct job *jp) 4951dowait(int block, struct job *jp)
4972{ 4952{
4973#if !ENABLE_PLATFORM_MINGW32 4953#if !ENABLE_PLATFORM_MINGW32
4974 int pid = block == DOWAIT_NONBLOCK ? got_sigchld : 1; 4954 smallint gotchld = *(volatile smallint *)&got_sigchld;
4955 int rpid;
4956 int pid;
4957
4958 if (jp && jp->state != JOBRUNNING)
4959 block = DOWAIT_NONBLOCK;
4960
4961 if (block == DOWAIT_NONBLOCK && !gotchld)
4962 return 1;
4963
4964 rpid = 1;
4975 4965
4976 while (jp ? jp->state == JOBRUNNING : pid > 0) { 4966 do {
4977 if (!jp)
4978 got_sigchld = 0;
4979 pid = waitone(block, jp); 4967 pid = waitone(block, jp);
4980 } 4968 rpid &= !!pid;
4969
4970 if (!pid || (jp && jp->state != JOBRUNNING))
4971 block = DOWAIT_NONBLOCK;
4972 } while (pid >= 0);
4973
4974 return rpid;
4981#else 4975#else
4982 int pid = 1; 4976 int pid = 1;
4983 4977
4984 while (jp ? jp->state == JOBRUNNING : pid > 0) 4978 while (jp ? jp->state == JOBRUNNING : pid > 0)
4985 pid = waitone(block, jp); 4979 pid = waitone(block, jp);
4986#endif
4987 4980
4988 return pid; 4981 return pid;
4982#endif
4989} 4983}
4990 4984
4991#if JOBS 4985#if JOBS
@@ -5232,7 +5226,7 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
5232 job = getjob(*argv, 0); 5226 job = getjob(*argv, 0);
5233 } 5227 }
5234 /* loop until process terminated or stopped */ 5228 /* loop until process terminated or stopped */
5235 dowait(DOWAIT_BLOCK_OR_SIG, NULL); 5229 dowait(DOWAIT_BLOCK_OR_SIG, job);
5236 if (pending_sig) 5230 if (pending_sig)
5237 goto sigout; 5231 goto sigout;
5238 job->waited = 1; 5232 job->waited = 1;
@@ -12622,7 +12616,8 @@ simplecmd(void)
12622 tokpushback = 1; 12616 tokpushback = 1;
12623 goto out; 12617 goto out;
12624 } 12618 }
12625 wordtext = (char *) (t == TAND ? "-a" : "-o"); 12619 /* pass "&&" or "||" to [[ ]] as literal args */
12620 wordtext = (char *) (t == TAND ? "&&" : "||");
12626#endif 12621#endif
12627 case TWORD: 12622 case TWORD:
12628 n = stzalloc(sizeof(struct narg)); 12623 n = stzalloc(sizeof(struct narg));
@@ -13600,7 +13595,7 @@ parsebackq: {
13600 goto done; 13595 goto done;
13601 13596
13602 case '\\': 13597 case '\\':
13603 pc = pgetc(); /* or pgetc_eatbnl()? why (example)? */ 13598 pc = pgetc(); /* not pgetc_eatbnl! */
13604 if (pc != '\\' && pc != '`' && pc != '$' 13599 if (pc != '\\' && pc != '`' && pc != '$'
13605 && (!synstack->dblquote || pc != '"') 13600 && (!synstack->dblquote || pc != '"')
13606 ) { 13601 ) {