diff options
author | Ron Yorston <rmy@pobox.com> | 2023-08-08 09:51:03 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2023-08-08 09:51:03 +0100 |
commit | 7b692ddf0c746014f94813bcb6418f0c95d85afc (patch) | |
tree | fddfea9a93fb7b80744e6e33291b6913105bc4f9 | |
parent | de317f125912fd5726708c24b99e3a3c879f6c1b (diff) | |
download | busybox-w32-7b692ddf0c746014f94813bcb6418f0c95d85afc.tar.gz busybox-w32-7b692ddf0c746014f94813bcb6418f0c95d85afc.tar.bz2 busybox-w32-7b692ddf0c746014f94813bcb6418f0c95d85afc.zip |
ash: improved support for jobs built-in
Pass job data to child shells. This makes it possible to use
the 'jobs' built-in with command substitution, process substitution
and in pipelines.
Costs 576-672 bytes
(GitHub issue #350)
-rw-r--r-- | shell/ash.c | 148 |
1 files changed, 141 insertions, 7 deletions
diff --git a/shell/ash.c b/shell/ash.c index 4d4137800..d0ecd501a 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -390,6 +390,11 @@ struct forkshell { | |||
390 | char **history; | 390 | char **history; |
391 | int cnt_history; | 391 | int cnt_history; |
392 | #endif | 392 | #endif |
393 | #if JOBS_WIN32 | ||
394 | struct job *jobtab; | ||
395 | unsigned njobs; | ||
396 | struct job *curjob; | ||
397 | #endif | ||
393 | /* struct parsefile *g_parsefile; */ | 398 | /* struct parsefile *g_parsefile; */ |
394 | HANDLE hMapFile; | 399 | HANDLE hMapFile; |
395 | char *old_base; | 400 | char *old_base; |
@@ -406,6 +411,9 @@ struct forkshell { | |||
406 | /* generic data, used by forkshell_child */ | 411 | /* generic data, used by forkshell_child */ |
407 | int mode; | 412 | int mode; |
408 | int nprocs; | 413 | int nprocs; |
414 | #if JOBS_WIN32 | ||
415 | int jpnull; | ||
416 | #endif | ||
409 | 417 | ||
410 | /* optional data, used by forkshell_child */ | 418 | /* optional data, used by forkshell_child */ |
411 | int flags; | 419 | int flags; |
@@ -16447,6 +16455,9 @@ spawn_forkshell(struct forkshell *fs, struct job *jp, union node *n, int mode) | |||
16447 | 16455 | ||
16448 | new->mode = mode; | 16456 | new->mode = mode; |
16449 | new->nprocs = jp == NULL ? 0 : jp->nprocs; | 16457 | new->nprocs = jp == NULL ? 0 : jp->nprocs; |
16458 | #if JOBS_WIN32 | ||
16459 | new->jpnull = jp == NULL; | ||
16460 | #endif | ||
16450 | sprintf(buf, "%p", new->hMapFile); | 16461 | sprintf(buf, "%p", new->hMapFile); |
16451 | argv[2] = buf; | 16462 | argv[2] = buf; |
16452 | ret = spawnve(P_NOWAIT, bb_busybox_exec_path, (char *const *)argv, NULL); | 16463 | ret = spawnve(P_NOWAIT, bb_busybox_exec_path, (char *const *)argv, NULL); |
@@ -16730,6 +16741,94 @@ history_copy(void) | |||
16730 | } | 16741 | } |
16731 | #endif | 16742 | #endif |
16732 | 16743 | ||
16744 | #if JOBS_WIN32 | ||
16745 | /* | ||
16746 | * struct procstat | ||
16747 | */ | ||
16748 | static struct datasize | ||
16749 | procstat_size(struct datasize ds, int nj) | ||
16750 | { | ||
16751 | struct job *jp = jobtab + nj; | ||
16752 | |||
16753 | ds.funcblocksize += sizeof(struct procstat) * jp->nprocs; | ||
16754 | for (int i = 0; i < jp->nprocs; i++) | ||
16755 | ds.funcstringsize += align_len(jp->ps[i].ps_cmd); | ||
16756 | return ds; | ||
16757 | } | ||
16758 | |||
16759 | static struct procstat * | ||
16760 | procstat_copy(int nj) | ||
16761 | { | ||
16762 | struct job *jp = jobtab + nj; | ||
16763 | struct procstat *new = funcblock; | ||
16764 | |||
16765 | funcblock = (char *)funcblock + sizeof(struct procstat) * jp->nprocs; | ||
16766 | memcpy(new, jp->ps, sizeof(struct procstat) * jp->nprocs); | ||
16767 | |||
16768 | for (int i = 0; i < jp->nprocs; i++) { | ||
16769 | new[i].ps_cmd = nodeckstrdup(jp->ps[i].ps_cmd); | ||
16770 | SAVE_PTR(new[i].ps_cmd, | ||
16771 | xasprintf("jobtab[%d].ps[%d].ps_cmd '%s'", | ||
16772 | nj, i, jp->ps[i].ps_cmd), FREE); | ||
16773 | } | ||
16774 | return new; | ||
16775 | } | ||
16776 | |||
16777 | /* | ||
16778 | * struct jobs | ||
16779 | */ | ||
16780 | static struct datasize | ||
16781 | jobtab_size(struct datasize ds) | ||
16782 | { | ||
16783 | int i; | ||
16784 | |||
16785 | ds.funcblocksize += sizeof(struct job) * njobs; | ||
16786 | for (i = 0; i < njobs; i++) { | ||
16787 | if (!jobtab[i].used) | ||
16788 | continue; | ||
16789 | |||
16790 | if (jobtab[i].ps == &jobtab[i].ps0) | ||
16791 | ds.funcstringsize += align_len(jobtab[i].ps0.ps_cmd); | ||
16792 | else | ||
16793 | ds = procstat_size(ds, i); | ||
16794 | } | ||
16795 | return ds; | ||
16796 | } | ||
16797 | |||
16798 | static struct job * | ||
16799 | jobtab_copy(void) | ||
16800 | { | ||
16801 | struct job *new = funcblock; | ||
16802 | int i; | ||
16803 | |||
16804 | funcblock = (char *)funcblock + sizeof(struct job) * njobs; | ||
16805 | memcpy(new, jobtab, sizeof(struct job) * njobs); | ||
16806 | |||
16807 | for (i = 0; i < njobs; i++) { | ||
16808 | if (!jobtab[i].used) | ||
16809 | continue; | ||
16810 | |||
16811 | if (jobtab[i].ps == &jobtab[i].ps0) { | ||
16812 | new[i].ps0.ps_cmd = nodeckstrdup(jobtab[i].ps0.ps_cmd); | ||
16813 | SAVE_PTR(new[i].ps0.ps_cmd, | ||
16814 | xasprintf("jobtab[%d].ps0.ps_cmd '%s'", | ||
16815 | i, jobtab[i].ps0.ps_cmd), FREE); | ||
16816 | new[i].ps = &new[i].ps0; | ||
16817 | } else { | ||
16818 | new[i].ps = procstat_copy(i); | ||
16819 | } | ||
16820 | SAVE_PTR(new[i].ps, xasprintf("jobtab[%d].ps", i), FREE); | ||
16821 | |||
16822 | if (jobtab[i].prev_job) { | ||
16823 | new[i].prev_job = new + (jobtab[i].prev_job - jobtab); | ||
16824 | SAVE_PTR(new[i].prev_job, | ||
16825 | xasprintf("jobtab[%d].prev_job", i), FREE); | ||
16826 | } | ||
16827 | } | ||
16828 | return new; | ||
16829 | } | ||
16830 | #endif | ||
16831 | |||
16733 | /* | 16832 | /* |
16734 | * struct redirtab | 16833 | * struct redirtab |
16735 | */ | 16834 | */ |
@@ -16872,7 +16971,8 @@ forkshell_size(struct forkshell *fs) | |||
16872 | ds.funcblocksize = calcsize(ds.funcblocksize, fs->n); | 16971 | ds.funcblocksize = calcsize(ds.funcblocksize, fs->n); |
16873 | ds = argv_size(ds, fs->argv); | 16972 | ds = argv_size(ds, fs->argv); |
16874 | 16973 | ||
16875 | if ((ENABLE_ASH_ALIAS || MAX_HISTORY) && fs->fpid != FS_SHELLEXEC) { | 16974 | if ((ENABLE_ASH_ALIAS || MAX_HISTORY || JOBS_WIN32) && |
16975 | fs->fpid != FS_SHELLEXEC) { | ||
16876 | #if ENABLE_ASH_ALIAS | 16976 | #if ENABLE_ASH_ALIAS |
16877 | ds = atab_size(ds); | 16977 | ds = atab_size(ds); |
16878 | #endif | 16978 | #endif |
@@ -16880,6 +16980,9 @@ forkshell_size(struct forkshell *fs) | |||
16880 | if (line_input_state) | 16980 | if (line_input_state) |
16881 | ds = history_size(ds); | 16981 | ds = history_size(ds); |
16882 | #endif | 16982 | #endif |
16983 | #if JOBS_WIN32 | ||
16984 | ds = jobtab_size(ds); | ||
16985 | #endif | ||
16883 | } | 16986 | } |
16884 | return ds; | 16987 | return ds; |
16885 | } | 16988 | } |
@@ -16906,7 +17009,8 @@ forkshell_copy(struct forkshell *fs, struct forkshell *new) | |||
16906 | SAVE_PTR(new->n, "n", NO_FREE); | 17009 | SAVE_PTR(new->n, "n", NO_FREE); |
16907 | SAVE_PTR(new->argv, "argv", NO_FREE); | 17010 | SAVE_PTR(new->argv, "argv", NO_FREE); |
16908 | 17011 | ||
16909 | if ((ENABLE_ASH_ALIAS || MAX_HISTORY) && fs->fpid != FS_SHELLEXEC) { | 17012 | if ((ENABLE_ASH_ALIAS || MAX_HISTORY || JOBS_WIN32) && |
17013 | fs->fpid != FS_SHELLEXEC) { | ||
16910 | #if ENABLE_ASH_ALIAS | 17014 | #if ENABLE_ASH_ALIAS |
16911 | new->atab = atab_copy(); | 17015 | new->atab = atab_copy(); |
16912 | SAVE_PTR(new->atab, "atab", NO_FREE); | 17016 | SAVE_PTR(new->atab, "atab", NO_FREE); |
@@ -16918,12 +17022,23 @@ forkshell_copy(struct forkshell *fs, struct forkshell *new) | |||
16918 | new->cnt_history = line_input_state->cnt_history; | 17022 | new->cnt_history = line_input_state->cnt_history; |
16919 | } | 17023 | } |
16920 | #endif | 17024 | #endif |
17025 | #if JOBS_WIN32 | ||
17026 | new->jobtab = jobtab_copy(); | ||
17027 | SAVE_PTR(new->jobtab, "jobtab", NO_FREE); | ||
17028 | new->njobs = njobs; | ||
17029 | if (curjob) { | ||
17030 | new->curjob = new->jobtab + (curjob - jobtab); | ||
17031 | SAVE_PTR(new->curjob, "curjob", NO_FREE); | ||
17032 | } | ||
17033 | #endif | ||
16921 | } | 17034 | } |
16922 | } | 17035 | } |
16923 | 17036 | ||
16924 | #if FORKSHELL_DEBUG | 17037 | #if FORKSHELL_DEBUG |
16925 | /* fp and notes can each be NULL */ | 17038 | #define NUM_BLOCKS FUNCSTRING |
16926 | #define NUM_BLOCKS 7 | 17039 | enum {GVP, GMP, CMDTABLE, NODE, ARGV, ATAB, HISTORY, JOBTAB, FUNCSTRING}; |
17040 | |||
17041 | /* fp0 and notes can each be NULL */ | ||
16927 | static void | 17042 | static void |
16928 | forkshell_print(FILE *fp0, struct forkshell *fs, const char **notes) | 17043 | forkshell_print(FILE *fp0, struct forkshell *fs, const char **notes) |
16929 | { | 17044 | { |
@@ -16935,7 +17050,6 @@ forkshell_print(FILE *fp0, struct forkshell *fs, const char **notes) | |||
16935 | int count, i, total; | 17050 | int count, i, total; |
16936 | int size[NUM_BLOCKS]; | 17051 | int size[NUM_BLOCKS]; |
16937 | char *lptr[NUM_BLOCKS+1]; | 17052 | char *lptr[NUM_BLOCKS+1]; |
16938 | enum {GVP, GMP, CMDTABLE, NODE, ARGV, ATAB, HISTORY, FUNCSTRING}; | ||
16939 | const char *fsname[] = { | 17053 | const char *fsname[] = { |
16940 | "FS_OPENHERE", | 17054 | "FS_OPENHERE", |
16941 | "FS_EVALBACKCMD", | 17055 | "FS_EVALBACKCMD", |
@@ -16972,10 +17086,15 @@ forkshell_print(FILE *fp0, struct forkshell *fs, const char **notes) | |||
16972 | /* Depending on the configuration and the type of forkshell | 17086 | /* Depending on the configuration and the type of forkshell |
16973 | * some items may not be present. */ | 17087 | * some items may not be present. */ |
16974 | lptr[FUNCSTRING] = lfuncstring; | 17088 | lptr[FUNCSTRING] = lfuncstring; |
17089 | #if JOBS_WIN32 | ||
17090 | lptr[JOBTAB] = fs->jobtab ? (char *)fs->jobtab : lptr[FUNCSTRING]; | ||
17091 | #else | ||
17092 | lptr[JOBTAB] = lptr[FUNCSTRING]; | ||
17093 | #endif | ||
16975 | #if MAX_HISTORY | 17094 | #if MAX_HISTORY |
16976 | lptr[HISTORY] = fs->history ? (char *)fs->history : lptr[FUNCSTRING]; | 17095 | lptr[HISTORY] = fs->history ? (char *)fs->history : lptr[JOBTAB]; |
16977 | #else | 17096 | #else |
16978 | lptr[HISTORY] = lptr[FUNCSTRING]; | 17097 | lptr[HISTORY] = lptr[JOBTAB]; |
16979 | #endif | 17098 | #endif |
16980 | lptr[ATAB] = IF_ASH_ALIAS(fs->atab ? (char *)fs->atab :) lptr[HISTORY]; | 17099 | lptr[ATAB] = IF_ASH_ALIAS(fs->atab ? (char *)fs->atab :) lptr[HISTORY]; |
16981 | lptr[ARGV] = fs->argv ? (char *)fs->argv : lptr[ATAB]; | 17100 | lptr[ARGV] = fs->argv ? (char *)fs->argv : lptr[ATAB]; |
@@ -17185,6 +17304,11 @@ forkshell_init(const char *idstr) | |||
17185 | line_input_state->history[i] = fs->history[i]; | 17304 | line_input_state->history[i] = fs->history[i]; |
17186 | } | 17305 | } |
17187 | #endif | 17306 | #endif |
17307 | #if JOBS_WIN32 | ||
17308 | jobtab = fs->jobtab; | ||
17309 | njobs = fs->njobs; | ||
17310 | curjob = fs->curjob; | ||
17311 | #endif | ||
17188 | 17312 | ||
17189 | CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */ | 17313 | CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */ |
17190 | 17314 | ||
@@ -17211,6 +17335,16 @@ forkshell_init(const char *idstr) | |||
17211 | #if JOBS_WIN32 | 17335 | #if JOBS_WIN32 |
17212 | /* do job control only in root shell */ | 17336 | /* do job control only in root shell */ |
17213 | doing_jobctl = 0; | 17337 | doing_jobctl = 0; |
17338 | |||
17339 | if (fs->n && fs->n->type == NCMD && fs->n->ncmd.args && | ||
17340 | strcmp(fs->n->ncmd.args->narg.text, "jobs") == 0) { | ||
17341 | TRACE(("Job hack\n")); | ||
17342 | if (!fs->jpnull) | ||
17343 | freejob(curjob); | ||
17344 | goto end; | ||
17345 | } | ||
17346 | for (struct job *jp = curjob; jp; jp = jp->prev_job) | ||
17347 | freejob(jp); | ||
17214 | #endif | 17348 | #endif |
17215 | end: | 17349 | end: |
17216 | forkshell_child(fs); | 17350 | forkshell_child(fs); |