aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2023-08-08 09:51:03 +0100
committerRon Yorston <rmy@pobox.com>2023-08-08 09:51:03 +0100
commit7b692ddf0c746014f94813bcb6418f0c95d85afc (patch)
treefddfea9a93fb7b80744e6e33291b6913105bc4f9
parentde317f125912fd5726708c24b99e3a3c879f6c1b (diff)
downloadbusybox-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.c148
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 */
16748static struct datasize
16749procstat_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
16759static struct procstat *
16760procstat_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 */
16780static struct datasize
16781jobtab_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
16798static struct job *
16799jobtab_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 17039enum {GVP, GMP, CMDTABLE, NODE, ARGV, ATAB, HISTORY, JOBTAB, FUNCSTRING};
17040
17041/* fp0 and notes can each be NULL */
16927static void 17042static void
16928forkshell_print(FILE *fp0, struct forkshell *fs, const char **notes) 17043forkshell_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);