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 /shell | |
| 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)
Diffstat (limited to 'shell')
| -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); |
