aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2021-09-26 08:33:36 +0100
committerRon Yorston <rmy@pobox.com>2021-09-26 08:33:36 +0100
commit010abea6f548a367d0d89998aa6c38a45d756c0d (patch)
tree6d86f10e7a7753478c0600cb3659e23d5fe89b43
parentbcb1d0c76d6e665133d1f878590af2006b31de6e (diff)
downloadbusybox-w32-010abea6f548a367d0d89998aa6c38a45d756c0d.tar.gz
busybox-w32-010abea6f548a367d0d89998aa6c38a45d756c0d.tar.bz2
busybox-w32-010abea6f548a367d0d89998aa6c38a45d756c0d.zip
ash: additional support for background jobs
The rationale for the jobs builtin in POSIX notes: The jobs utility is not dependent on the job control option, as are the seemingly related bg and fg utilities because jobs is useful for examining background jobs, regardless of the condition of job control. When the user has invoked a set +m command and job control has been turned off, jobs can still be used to examine the background jobs associated with that current session. Similarly, kill can then be used to kill background jobs with kill %<background job number>. Although ash in busybox-w32 doesn't support job control it can handle background jobs. Allow the ASH_JOB_CONTROL setting to enable certain features: - the jobs builtin; - killing of jobs by job id in the kill builtin; - monitoring of changes to jobs. Since process groups aren't supported it's necessary to kill the processes constituting a background job individually. When doing this we ask kill(2) to kill all children too.
-rw-r--r--configs/mingw32_defconfig2
-rw-r--r--configs/mingw64_defconfig2
-rw-r--r--shell/ash.c51
3 files changed, 44 insertions, 11 deletions
diff --git a/configs/mingw32_defconfig b/configs/mingw32_defconfig
index 195020151..d41899fdc 100644
--- a/configs/mingw32_defconfig
+++ b/configs/mingw32_defconfig
@@ -1131,7 +1131,7 @@ CONFIG_ASH_INTERNAL_GLOB=y
1131CONFIG_ASH_BASH_COMPAT=y 1131CONFIG_ASH_BASH_COMPAT=y
1132# CONFIG_ASH_BASH_SOURCE_CURDIR is not set 1132# CONFIG_ASH_BASH_SOURCE_CURDIR is not set
1133CONFIG_ASH_BASH_NOT_FOUND_HOOK=y 1133CONFIG_ASH_BASH_NOT_FOUND_HOOK=y
1134# CONFIG_ASH_JOB_CONTROL is not set 1134CONFIG_ASH_JOB_CONTROL=y
1135CONFIG_ASH_ALIAS=y 1135CONFIG_ASH_ALIAS=y
1136CONFIG_ASH_RANDOM_SUPPORT=y 1136CONFIG_ASH_RANDOM_SUPPORT=y
1137CONFIG_ASH_EXPAND_PRMT=y 1137CONFIG_ASH_EXPAND_PRMT=y
diff --git a/configs/mingw64_defconfig b/configs/mingw64_defconfig
index aa704fe75..449f16ae6 100644
--- a/configs/mingw64_defconfig
+++ b/configs/mingw64_defconfig
@@ -1131,7 +1131,7 @@ CONFIG_ASH_INTERNAL_GLOB=y
1131CONFIG_ASH_BASH_COMPAT=y 1131CONFIG_ASH_BASH_COMPAT=y
1132# CONFIG_ASH_BASH_SOURCE_CURDIR is not set 1132# CONFIG_ASH_BASH_SOURCE_CURDIR is not set
1133CONFIG_ASH_BASH_NOT_FOUND_HOOK=y 1133CONFIG_ASH_BASH_NOT_FOUND_HOOK=y
1134# CONFIG_ASH_JOB_CONTROL is not set 1134CONFIG_ASH_JOB_CONTROL=y
1135CONFIG_ASH_ALIAS=y 1135CONFIG_ASH_ALIAS=y
1136CONFIG_ASH_RANDOM_SUPPORT=y 1136CONFIG_ASH_RANDOM_SUPPORT=y
1137CONFIG_ASH_EXPAND_PRMT=y 1137CONFIG_ASH_EXPAND_PRMT=y
diff --git a/shell/ash.c b/shell/ash.c
index fafbeb86e..6be99864f 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -24,7 +24,7 @@
24 * - command without ".exe" extension is still understood as executable 24 * - command without ".exe" extension is still understood as executable
25 * - shell scripts on the path are detected by the presence of '#!' 25 * - shell scripts on the path are detected by the presence of '#!'
26 * - both / and \ are supported in PATH. Usually you must use / 26 * - both / and \ are supported in PATH. Usually you must use /
27 * - job control doesn't work 27 * - job control doesn't work, though the jobs builtin is available
28 * - trap doesn't work for signals, only EXIT 28 * - trap doesn't work for signals, only EXIT
29 * - /dev/null is supported for redirection 29 * - /dev/null is supported for redirection
30 * - fake $PPID 30 * - fake $PPID
@@ -212,7 +212,17 @@
212 212
213#define PROFILE 0 213#define PROFILE 0
214 214
215/*
216 * Only one of JOBS or JOBS_WIN32 is enabled at a time (or neither).
217 * JOBS_WIN32 doesn't enable job control, just some job-related features.
218 */
219#if ENABLE_PLATFORM_MINGW32
220#define JOBS_WIN32 ENABLE_ASH_JOB_CONTROL
221#define JOBS 0
222#else
223#define JOBS_WIN32 0
215#define JOBS ENABLE_ASH_JOB_CONTROL 224#define JOBS ENABLE_ASH_JOB_CONTROL
225#endif
216 226
217#include <fnmatch.h> 227#include <fnmatch.h>
218#include <sys/times.h> 228#include <sys/times.h>
@@ -4112,10 +4122,13 @@ static int forkshell(struct job *, union node *, int);
4112#endif 4122#endif
4113static int waitforjob(struct job *); 4123static int waitforjob(struct job *);
4114 4124
4115#if !JOBS 4125#if !JOBS && !JOBS_WIN32
4116enum { doing_jobctl = 0 }; 4126enum { doing_jobctl = 0 };
4117#define setjobctl(on) do {} while (0) 4127#define setjobctl(on) do {} while (0)
4118#else 4128#elif JOBS_WIN32
4129static smallint doing_jobctl; //references:8
4130#define setjobctl(on) do { if (rootshell) doing_jobctl = on; } while (0)
4131#else /* JOBS */
4119static smallint doing_jobctl; //references:8 4132static smallint doing_jobctl; //references:8
4120static void setjobctl(int); 4133static void setjobctl(int);
4121#endif 4134#endif
@@ -4404,7 +4417,7 @@ set_curjob(struct job *jp, unsigned mode)
4404 } 4417 }
4405} 4418}
4406 4419
4407#if JOBS || DEBUG 4420#if JOBS || JOBS_WIN32 || DEBUG
4408static int 4421static int
4409jobno(const struct job *jp) 4422jobno(const struct job *jp)
4410{ 4423{
@@ -4617,7 +4630,9 @@ setjobctl(int on)
4617 ttyfd = fd; 4630 ttyfd = fd;
4618 doing_jobctl = on; 4631 doing_jobctl = on;
4619} 4632}
4633#endif
4620 4634
4635#if JOBS || JOBS_WIN32
4621static int FAST_FUNC 4636static int FAST_FUNC
4622killcmd(int argc, char **argv) 4637killcmd(int argc, char **argv)
4623{ 4638{
@@ -4647,8 +4662,10 @@ killcmd(int argc, char **argv)
4647 * sh -c 'true|sleep 1 & sleep 2; kill %1' 4662 * sh -c 'true|sleep 1 & sleep 2; kill %1'
4648 */ 4663 */
4649 n = jp->nprocs; /* can't be 0 (I hope) */ 4664 n = jp->nprocs; /* can't be 0 (I hope) */
4665#if !ENABLE_PLATFORM_MINGW32
4650 if (jp->jobctl) 4666 if (jp->jobctl)
4651 n = 1; 4667 n = 1;
4668#endif
4652 dst = alloca(n * sizeof(int)*4); 4669 dst = alloca(n * sizeof(int)*4);
4653 argv[i] = dst; 4670 argv[i] = dst;
4654 for (j = 0; j < n; j++) { 4671 for (j = 0; j < n; j++) {
@@ -4663,7 +4680,11 @@ killcmd(int argc, char **argv)
4663 * leading space. Needed to not confuse 4680 * leading space. Needed to not confuse
4664 * negative pids with "kill -SIGNAL_NO" syntax 4681 * negative pids with "kill -SIGNAL_NO" syntax
4665 */ 4682 */
4683#if !ENABLE_PLATFORM_MINGW32
4666 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid); 4684 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
4685#else
4686 dst += sprintf(dst, " -%u", (int)ps->ps_pid);
4687#endif
4667 } 4688 }
4668 *dst = '\0'; 4689 *dst = '\0';
4669 } 4690 }
@@ -4671,7 +4692,9 @@ killcmd(int argc, char **argv)
4671 } 4692 }
4672 return kill_main(argc, argv); 4693 return kill_main(argc, argv);
4673} 4694}
4695#endif
4674 4696
4697#if JOBS
4675static void 4698static void
4676showpipe(struct job *jp /*, FILE *out*/) 4699showpipe(struct job *jp /*, FILE *out*/)
4677{ 4700{
@@ -5048,7 +5071,7 @@ dowait(int block, struct job *jp)
5048#endif 5071#endif
5049} 5072}
5050 5073
5051#if JOBS 5074#if JOBS || JOBS_WIN32
5052static void 5075static void
5053showjob(struct job *jp, int mode) 5076showjob(struct job *jp, int mode)
5054{ 5077{
@@ -5085,8 +5108,10 @@ showjob(struct job *jp, int mode)
5085 col += sizeof("Running") - 1; 5108 col += sizeof("Running") - 1;
5086 } else { 5109 } else {
5087 int status = psend[-1].ps_status; 5110 int status = psend[-1].ps_status;
5111#if !ENABLE_PLATFORM_MINGW32
5088 if (jp->state == JOBSTOPPED) 5112 if (jp->state == JOBSTOPPED)
5089 status = jp->stopstatus; 5113 status = jp->stopstatus;
5114#endif
5090 col += sprint_status48(s + col, status, 0); 5115 col += sprint_status48(s + col, status, 0);
5091 } 5116 }
5092 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */ 5117 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
@@ -5107,12 +5132,16 @@ showjob(struct job *jp, int mode)
5107 if (mode & SHOW_PIDS) 5132 if (mode & SHOW_PIDS)
5108 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1; 5133 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
5109 start: 5134 start:
5135#if !ENABLE_PLATFORM_MINGW32
5110 fprintf(out, "%s%*c%s%s", 5136 fprintf(out, "%s%*c%s%s",
5111 s, 5137 s,
5112 33 - col >= 0 ? 33 - col : 0, ' ', 5138 33 - col >= 0 ? 33 - col : 0, ' ',
5113 ps == jp->ps ? "" : "| ", 5139 ps == jp->ps ? "" : "| ",
5114 ps->ps_cmd 5140 ps->ps_cmd
5115 ); 5141 );
5142#else
5143 fprintf(out, "%s", s);
5144#endif
5116 } while (++ps != psend); 5145 } while (++ps != psend);
5117 newline_and_flush(out); 5146 newline_and_flush(out);
5118 5147
@@ -5369,7 +5398,7 @@ makejob(/*union node *node,*/ int nprocs)
5369 break; 5398 break;
5370 if (jp->state != JOBDONE || !jp->waited) 5399 if (jp->state != JOBDONE || !jp->waited)
5371 continue; 5400 continue;
5372#if JOBS 5401#if JOBS || JOBS_WIN32
5373 if (doing_jobctl) 5402 if (doing_jobctl)
5374 continue; 5403 continue;
5375#endif 5404#endif
@@ -10997,7 +11026,7 @@ static const struct builtincmd builtintab[] = {
10997#if MAX_HISTORY 11026#if MAX_HISTORY
10998 { BUILTIN_NOSPEC "history" , historycmd }, 11027 { BUILTIN_NOSPEC "history" , historycmd },
10999#endif 11028#endif
11000#if JOBS 11029#if JOBS || JOBS_WIN32
11001 { BUILTIN_REGULAR "jobs" , jobscmd }, 11030 { BUILTIN_REGULAR "jobs" , jobscmd },
11002 { BUILTIN_REGULAR "kill" , killcmd }, 11031 { BUILTIN_REGULAR "kill" , killcmd },
11003#endif 11032#endif
@@ -11039,7 +11068,7 @@ static const struct builtincmd builtintab[] = {
11039 /* [ */ 1 * ENABLE_ASH_TEST + \ 11068 /* [ */ 1 * ENABLE_ASH_TEST + \
11040 /* [[ */ 1 * BASH_TEST2 + \ 11069 /* [[ */ 1 * BASH_TEST2 + \
11041 /* alias */ 1 * ENABLE_ASH_ALIAS + \ 11070 /* alias */ 1 * ENABLE_ASH_ALIAS + \
11042 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \ 11071 /* bg */ 1 * JOBS + \
11043 /* break cd cddir */ 3) 11072 /* break cd cddir */ 3)
11044#define EVALCMD (COMMANDCMD + \ 11073#define EVALCMD (COMMANDCMD + \
11045 /* command */ 1 * ENABLE_ASH_CMDCMD + \ 11074 /* command */ 1 * ENABLE_ASH_CMDCMD + \
@@ -14365,7 +14394,7 @@ cmdloop(int top)
14365 int skip; 14394 int skip;
14366 14395
14367 setstackmark(&smark); 14396 setstackmark(&smark);
14368#if JOBS 14397#if JOBS || JOBS_WIN32
14369 if (doing_jobctl) 14398 if (doing_jobctl)
14370 showjobs(SHOW_CHANGED|SHOW_STDERR); 14399 showjobs(SHOW_CHANGED|SHOW_STDERR);
14371#endif 14400#endif
@@ -16735,6 +16764,10 @@ forkshell_init(const char *idstr)
16735 else { 16764 else {
16736 SetConsoleCtrlHandler(ctrl_handler, TRUE); 16765 SetConsoleCtrlHandler(ctrl_handler, TRUE);
16737 } 16766 }
16767#if JOBS_WIN32
16768 /* do job control only in root shell */
16769 doing_jobctl = 0;
16770#endif
16738 end: 16771 end:
16739 forkshell_child(fs); 16772 forkshell_child(fs);
16740} 16773}