1c84f3f3cSopenharmony_ci/* $OpenBSD: jobs.c,v 1.43 2015/09/10 22:48:58 nicm Exp $ */ 2c84f3f3cSopenharmony_ci 3c84f3f3cSopenharmony_ci/*- 4c84f3f3cSopenharmony_ci * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, 5c84f3f3cSopenharmony_ci * 2012, 2013, 2014, 2015, 2016, 2018, 2019 6c84f3f3cSopenharmony_ci * mirabilos <m@mirbsd.org> 7c84f3f3cSopenharmony_ci * 8c84f3f3cSopenharmony_ci * Provided that these terms and disclaimer and all copyright notices 9c84f3f3cSopenharmony_ci * are retained or reproduced in an accompanying document, permission 10c84f3f3cSopenharmony_ci * is granted to deal in this work without restriction, including un- 11c84f3f3cSopenharmony_ci * limited rights to use, publicly perform, distribute, sell, modify, 12c84f3f3cSopenharmony_ci * merge, give away, or sublicence. 13c84f3f3cSopenharmony_ci * 14c84f3f3cSopenharmony_ci * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to 15c84f3f3cSopenharmony_ci * the utmost extent permitted by applicable law, neither express nor 16c84f3f3cSopenharmony_ci * implied; without malicious intent or gross negligence. In no event 17c84f3f3cSopenharmony_ci * may a licensor, author or contributor be held liable for indirect, 18c84f3f3cSopenharmony_ci * direct, other damage, loss, or other issues arising in any way out 19c84f3f3cSopenharmony_ci * of dealing in the work, even if advised of the possibility of such 20c84f3f3cSopenharmony_ci * damage or existence of a defect, except proven that it results out 21c84f3f3cSopenharmony_ci * of said person's immediate fault when using the work as intended. 22c84f3f3cSopenharmony_ci */ 23c84f3f3cSopenharmony_ci 24c84f3f3cSopenharmony_ci#include "sh.h" 25c84f3f3cSopenharmony_ci 26c84f3f3cSopenharmony_ci__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.128 2019/12/11 19:46:20 tg Exp $"); 27c84f3f3cSopenharmony_ci 28c84f3f3cSopenharmony_ci#if HAVE_KILLPG 29c84f3f3cSopenharmony_ci#define mksh_killpg killpg 30c84f3f3cSopenharmony_ci#else 31c84f3f3cSopenharmony_ci/* cross fingers and hope kill is killpg-endowed */ 32c84f3f3cSopenharmony_ci#define mksh_killpg(p,s) kill(-(p), (s)) 33c84f3f3cSopenharmony_ci#endif 34c84f3f3cSopenharmony_ci 35c84f3f3cSopenharmony_ci/* Order important! */ 36c84f3f3cSopenharmony_ci#define PRUNNING 0 37c84f3f3cSopenharmony_ci#define PEXITED 1 38c84f3f3cSopenharmony_ci#define PSIGNALLED 2 39c84f3f3cSopenharmony_ci#define PSTOPPED 3 40c84f3f3cSopenharmony_ci 41c84f3f3cSopenharmony_citypedef struct proc Proc; 42c84f3f3cSopenharmony_ci/* to take alignment into consideration */ 43c84f3f3cSopenharmony_cistruct proc_dummy { 44c84f3f3cSopenharmony_ci Proc *next; 45c84f3f3cSopenharmony_ci pid_t pid; 46c84f3f3cSopenharmony_ci int state; 47c84f3f3cSopenharmony_ci int status; 48c84f3f3cSopenharmony_ci char command[128]; 49c84f3f3cSopenharmony_ci}; 50c84f3f3cSopenharmony_ci/* real structure */ 51c84f3f3cSopenharmony_cistruct proc { 52c84f3f3cSopenharmony_ci /* next process in pipeline (if any) */ 53c84f3f3cSopenharmony_ci Proc *next; 54c84f3f3cSopenharmony_ci /* process id of this Unix process in the job */ 55c84f3f3cSopenharmony_ci pid_t pid; 56c84f3f3cSopenharmony_ci /* one of the four P… above */ 57c84f3f3cSopenharmony_ci int state; 58c84f3f3cSopenharmony_ci /* wait status */ 59c84f3f3cSopenharmony_ci int status; 60c84f3f3cSopenharmony_ci /* process command string from vistree */ 61c84f3f3cSopenharmony_ci char command[256 - (ALLOC_OVERHEAD + 62c84f3f3cSopenharmony_ci offsetof(struct proc_dummy, command[0]))]; 63c84f3f3cSopenharmony_ci}; 64c84f3f3cSopenharmony_ci 65c84f3f3cSopenharmony_ci/* Notify/print flag - j_print() argument */ 66c84f3f3cSopenharmony_ci#define JP_SHORT 1 /* print signals processes were killed by */ 67c84f3f3cSopenharmony_ci#define JP_MEDIUM 2 /* print [job-num] -/+ command */ 68c84f3f3cSopenharmony_ci#define JP_LONG 3 /* print [job-num] -/+ pid command */ 69c84f3f3cSopenharmony_ci#define JP_PGRP 4 /* print pgrp */ 70c84f3f3cSopenharmony_ci 71c84f3f3cSopenharmony_ci/* put_job() flags */ 72c84f3f3cSopenharmony_ci#define PJ_ON_FRONT 0 /* at very front */ 73c84f3f3cSopenharmony_ci#define PJ_PAST_STOPPED 1 /* just past any stopped jobs */ 74c84f3f3cSopenharmony_ci 75c84f3f3cSopenharmony_ci/* Job.flags values */ 76c84f3f3cSopenharmony_ci#define JF_STARTED 0x001 /* set when all processes in job are started */ 77c84f3f3cSopenharmony_ci#define JF_WAITING 0x002 /* set if j_waitj() is waiting on job */ 78c84f3f3cSopenharmony_ci#define JF_W_ASYNCNOTIFY 0x004 /* set if waiting and async notification ok */ 79c84f3f3cSopenharmony_ci#define JF_XXCOM 0x008 /* set for $(command) jobs */ 80c84f3f3cSopenharmony_ci#define JF_FG 0x010 /* running in foreground (also has tty pgrp) */ 81c84f3f3cSopenharmony_ci#define JF_SAVEDTTY 0x020 /* j->ttystat is valid */ 82c84f3f3cSopenharmony_ci#define JF_CHANGED 0x040 /* process has changed state */ 83c84f3f3cSopenharmony_ci#define JF_KNOWN 0x080 /* $! referenced */ 84c84f3f3cSopenharmony_ci#define JF_ZOMBIE 0x100 /* known, unwaited process */ 85c84f3f3cSopenharmony_ci#define JF_REMOVE 0x200 /* flagged for removal (j_jobs()/j_noityf()) */ 86c84f3f3cSopenharmony_ci#define JF_USETTYMODE 0x400 /* tty mode saved if process exits normally */ 87c84f3f3cSopenharmony_ci#define JF_SAVEDTTYPGRP 0x800 /* j->saved_ttypgrp is valid */ 88c84f3f3cSopenharmony_ci 89c84f3f3cSopenharmony_citypedef struct job Job; 90c84f3f3cSopenharmony_cistruct job { 91c84f3f3cSopenharmony_ci ALLOC_ITEM alloc_INT; /* internal, do not touch */ 92c84f3f3cSopenharmony_ci Job *next; /* next job in list */ 93c84f3f3cSopenharmony_ci Proc *proc_list; /* process list */ 94c84f3f3cSopenharmony_ci Proc *last_proc; /* last process in list */ 95c84f3f3cSopenharmony_ci struct timeval systime; /* system time used by job */ 96c84f3f3cSopenharmony_ci struct timeval usrtime; /* user time used by job */ 97c84f3f3cSopenharmony_ci pid_t pgrp; /* process group of job */ 98c84f3f3cSopenharmony_ci pid_t ppid; /* pid of process that forked job */ 99c84f3f3cSopenharmony_ci int job; /* job number: %n */ 100c84f3f3cSopenharmony_ci int flags; /* see JF_* */ 101c84f3f3cSopenharmony_ci volatile int state; /* job state */ 102c84f3f3cSopenharmony_ci int status; /* exit status of last process */ 103c84f3f3cSopenharmony_ci int age; /* number of jobs started */ 104c84f3f3cSopenharmony_ci Coproc_id coproc_id; /* 0 or id of coprocess output pipe */ 105c84f3f3cSopenharmony_ci#ifndef MKSH_UNEMPLOYED 106c84f3f3cSopenharmony_ci mksh_ttyst ttystat; /* saved tty state for stopped jobs */ 107c84f3f3cSopenharmony_ci pid_t saved_ttypgrp; /* saved tty process group for stopped jobs */ 108c84f3f3cSopenharmony_ci#endif 109c84f3f3cSopenharmony_ci}; 110c84f3f3cSopenharmony_ci 111c84f3f3cSopenharmony_ci/* Flags for j_waitj() */ 112c84f3f3cSopenharmony_ci#define JW_NONE 0x00 113c84f3f3cSopenharmony_ci#define JW_INTERRUPT 0x01 /* ^C will stop the wait */ 114c84f3f3cSopenharmony_ci#define JW_ASYNCNOTIFY 0x02 /* asynchronous notification during wait ok */ 115c84f3f3cSopenharmony_ci#define JW_STOPPEDWAIT 0x04 /* wait even if job stopped */ 116c84f3f3cSopenharmony_ci#define JW_PIPEST 0x08 /* want PIPESTATUS */ 117c84f3f3cSopenharmony_ci 118c84f3f3cSopenharmony_ci/* Error codes for j_lookup() */ 119c84f3f3cSopenharmony_ci#define JL_NOSUCH 0 /* no such job */ 120c84f3f3cSopenharmony_ci#define JL_AMBIG 1 /* %foo or %?foo is ambiguous */ 121c84f3f3cSopenharmony_ci#define JL_INVALID 2 /* non-pid, non-% job id */ 122c84f3f3cSopenharmony_ci 123c84f3f3cSopenharmony_cistatic const char * const lookup_msgs[] = { 124c84f3f3cSopenharmony_ci "no such job", 125c84f3f3cSopenharmony_ci "ambiguous", 126c84f3f3cSopenharmony_ci "argument must be %job or process id" 127c84f3f3cSopenharmony_ci}; 128c84f3f3cSopenharmony_ci 129c84f3f3cSopenharmony_cistatic Job *job_list; /* job list */ 130c84f3f3cSopenharmony_cistatic Job *last_job; 131c84f3f3cSopenharmony_cistatic Job *async_job; 132c84f3f3cSopenharmony_cistatic pid_t async_pid; 133c84f3f3cSopenharmony_ci 134c84f3f3cSopenharmony_cistatic int nzombie; /* # of zombies owned by this process */ 135c84f3f3cSopenharmony_cistatic int njobs; /* # of jobs started */ 136c84f3f3cSopenharmony_ci 137c84f3f3cSopenharmony_ci#ifndef CHILD_MAX 138c84f3f3cSopenharmony_ci#define CHILD_MAX 25 139c84f3f3cSopenharmony_ci#endif 140c84f3f3cSopenharmony_ci 141c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 142c84f3f3cSopenharmony_ci/* held_sigchld is set if sigchld occurs before a job is completely started */ 143c84f3f3cSopenharmony_cistatic volatile sig_atomic_t held_sigchld; 144c84f3f3cSopenharmony_ci#endif 145c84f3f3cSopenharmony_ci 146c84f3f3cSopenharmony_ci#ifndef MKSH_UNEMPLOYED 147c84f3f3cSopenharmony_cistatic struct shf *shl_j; 148c84f3f3cSopenharmony_cistatic bool ttypgrp_ok; /* set if can use tty pgrps */ 149c84f3f3cSopenharmony_cistatic pid_t restore_ttypgrp = -1; 150c84f3f3cSopenharmony_cistatic int const tt_sigs[] = { SIGTSTP, SIGTTIN, SIGTTOU }; 151c84f3f3cSopenharmony_ci#endif 152c84f3f3cSopenharmony_ci 153c84f3f3cSopenharmony_cistatic void j_set_async(Job *); 154c84f3f3cSopenharmony_cistatic void j_startjob(Job *); 155c84f3f3cSopenharmony_cistatic int j_waitj(Job *, int, const char *); 156c84f3f3cSopenharmony_cistatic void j_sigchld(int); 157c84f3f3cSopenharmony_cistatic void j_print(Job *, int, struct shf *); 158c84f3f3cSopenharmony_cistatic Job *j_lookup(const char *, int *); 159c84f3f3cSopenharmony_cistatic Job *new_job(void); 160c84f3f3cSopenharmony_cistatic Proc *new_proc(void); 161c84f3f3cSopenharmony_cistatic void check_job(Job *); 162c84f3f3cSopenharmony_cistatic void put_job(Job *, int); 163c84f3f3cSopenharmony_cistatic void remove_job(Job *, const char *); 164c84f3f3cSopenharmony_cistatic int kill_job(Job *, int); 165c84f3f3cSopenharmony_ci 166c84f3f3cSopenharmony_cistatic void tty_init_talking(void); 167c84f3f3cSopenharmony_cistatic void tty_init_state(void); 168c84f3f3cSopenharmony_ci 169c84f3f3cSopenharmony_ci/* initialise job control */ 170c84f3f3cSopenharmony_civoid 171c84f3f3cSopenharmony_cij_init(void) 172c84f3f3cSopenharmony_ci{ 173c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 174c84f3f3cSopenharmony_ci (void)sigemptyset(&sm_default); 175c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &sm_default, NULL); 176c84f3f3cSopenharmony_ci 177c84f3f3cSopenharmony_ci (void)sigemptyset(&sm_sigchld); 178c84f3f3cSopenharmony_ci (void)sigaddset(&sm_sigchld, SIGCHLD); 179c84f3f3cSopenharmony_ci 180c84f3f3cSopenharmony_ci setsig(&sigtraps[SIGCHLD], j_sigchld, 181c84f3f3cSopenharmony_ci SS_RESTORE_ORIG|SS_FORCE|SS_SHTRAP); 182c84f3f3cSopenharmony_ci#else 183c84f3f3cSopenharmony_ci /* Make sure SIGCHLD isn't ignored - can do odd things under SYSV */ 184c84f3f3cSopenharmony_ci setsig(&sigtraps[SIGCHLD], SIG_DFL, SS_RESTORE_ORIG|SS_FORCE); 185c84f3f3cSopenharmony_ci#endif 186c84f3f3cSopenharmony_ci 187c84f3f3cSopenharmony_ci#ifndef MKSH_UNEMPLOYED 188c84f3f3cSopenharmony_ci if (Flag(FMONITOR) == 127) 189c84f3f3cSopenharmony_ci Flag(FMONITOR) = Flag(FTALKING); 190c84f3f3cSopenharmony_ci 191c84f3f3cSopenharmony_ci /* 192c84f3f3cSopenharmony_ci * shl_j is used to do asynchronous notification (used in 193c84f3f3cSopenharmony_ci * an interrupt handler, so need a distinct shf) 194c84f3f3cSopenharmony_ci */ 195c84f3f3cSopenharmony_ci shl_j = shf_fdopen(2, SHF_WR, NULL); 196c84f3f3cSopenharmony_ci 197c84f3f3cSopenharmony_ci if (Flag(FMONITOR) || Flag(FTALKING)) { 198c84f3f3cSopenharmony_ci int i; 199c84f3f3cSopenharmony_ci 200c84f3f3cSopenharmony_ci /* 201c84f3f3cSopenharmony_ci * the TF_SHELL_USES test is a kludge that lets us know if 202c84f3f3cSopenharmony_ci * if the signals have been changed by the shell. 203c84f3f3cSopenharmony_ci */ 204c84f3f3cSopenharmony_ci for (i = NELEM(tt_sigs); --i >= 0; ) { 205c84f3f3cSopenharmony_ci sigtraps[tt_sigs[i]].flags |= TF_SHELL_USES; 206c84f3f3cSopenharmony_ci /* j_change() sets this to SS_RESTORE_DFL if FMONITOR */ 207c84f3f3cSopenharmony_ci setsig(&sigtraps[tt_sigs[i]], SIG_IGN, 208c84f3f3cSopenharmony_ci SS_RESTORE_IGN|SS_FORCE); 209c84f3f3cSopenharmony_ci } 210c84f3f3cSopenharmony_ci } 211c84f3f3cSopenharmony_ci 212c84f3f3cSopenharmony_ci /* j_change() calls tty_init_talking() and tty_init_state() */ 213c84f3f3cSopenharmony_ci if (Flag(FMONITOR)) 214c84f3f3cSopenharmony_ci j_change(); 215c84f3f3cSopenharmony_ci else 216c84f3f3cSopenharmony_ci#endif 217c84f3f3cSopenharmony_ci if (Flag(FTALKING)) { 218c84f3f3cSopenharmony_ci tty_init_talking(); 219c84f3f3cSopenharmony_ci tty_init_state(); 220c84f3f3cSopenharmony_ci } 221c84f3f3cSopenharmony_ci} 222c84f3f3cSopenharmony_ci 223c84f3f3cSopenharmony_cistatic int 224c84f3f3cSopenharmony_ciproc_errorlevel(Proc *p) 225c84f3f3cSopenharmony_ci{ 226c84f3f3cSopenharmony_ci switch (p->state) { 227c84f3f3cSopenharmony_ci case PEXITED: 228c84f3f3cSopenharmony_ci return ((WEXITSTATUS(p->status)) & 255); 229c84f3f3cSopenharmony_ci case PSIGNALLED: 230c84f3f3cSopenharmony_ci return (ksh_sigmask(WTERMSIG(p->status))); 231c84f3f3cSopenharmony_ci default: 232c84f3f3cSopenharmony_ci return (0); 233c84f3f3cSopenharmony_ci } 234c84f3f3cSopenharmony_ci} 235c84f3f3cSopenharmony_ci 236c84f3f3cSopenharmony_ci#if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID 237c84f3f3cSopenharmony_ci/* suspend the shell */ 238c84f3f3cSopenharmony_civoid 239c84f3f3cSopenharmony_cij_suspend(void) 240c84f3f3cSopenharmony_ci{ 241c84f3f3cSopenharmony_ci struct sigaction sa, osa; 242c84f3f3cSopenharmony_ci 243c84f3f3cSopenharmony_ci /* Restore tty and pgrp. */ 244c84f3f3cSopenharmony_ci if (ttypgrp_ok) { 245c84f3f3cSopenharmony_ci if (tty_hasstate) 246c84f3f3cSopenharmony_ci mksh_tcset(tty_fd, &tty_state); 247c84f3f3cSopenharmony_ci if (restore_ttypgrp >= 0) { 248c84f3f3cSopenharmony_ci if (tcsetpgrp(tty_fd, restore_ttypgrp) < 0) { 249c84f3f3cSopenharmony_ci warningf(false, Tf_ssfaileds, 250c84f3f3cSopenharmony_ci Tj_suspend, "tcsetpgrp", cstrerror(errno)); 251c84f3f3cSopenharmony_ci } else if (setpgid(0, restore_ttypgrp) < 0) { 252c84f3f3cSopenharmony_ci warningf(false, Tf_ssfaileds, 253c84f3f3cSopenharmony_ci Tj_suspend, "setpgid", cstrerror(errno)); 254c84f3f3cSopenharmony_ci } 255c84f3f3cSopenharmony_ci } 256c84f3f3cSopenharmony_ci } 257c84f3f3cSopenharmony_ci 258c84f3f3cSopenharmony_ci /* Suspend the shell. */ 259c84f3f3cSopenharmony_ci memset(&sa, 0, sizeof(sa)); 260c84f3f3cSopenharmony_ci sigemptyset(&sa.sa_mask); 261c84f3f3cSopenharmony_ci sa.sa_handler = SIG_DFL; 262c84f3f3cSopenharmony_ci sigaction(SIGTSTP, &sa, &osa); 263c84f3f3cSopenharmony_ci kill(0, SIGTSTP); 264c84f3f3cSopenharmony_ci 265c84f3f3cSopenharmony_ci /* Back from suspend, reset signals, pgrp and tty. */ 266c84f3f3cSopenharmony_ci sigaction(SIGTSTP, &osa, NULL); 267c84f3f3cSopenharmony_ci if (ttypgrp_ok) { 268c84f3f3cSopenharmony_ci if (restore_ttypgrp >= 0) { 269c84f3f3cSopenharmony_ci if (setpgid(0, kshpid) < 0) { 270c84f3f3cSopenharmony_ci warningf(false, Tf_ssfaileds, 271c84f3f3cSopenharmony_ci Tj_suspend, "setpgid", cstrerror(errno)); 272c84f3f3cSopenharmony_ci ttypgrp_ok = false; 273c84f3f3cSopenharmony_ci } else if (tcsetpgrp(tty_fd, kshpid) < 0) { 274c84f3f3cSopenharmony_ci warningf(false, Tf_ssfaileds, 275c84f3f3cSopenharmony_ci Tj_suspend, "tcsetpgrp", cstrerror(errno)); 276c84f3f3cSopenharmony_ci ttypgrp_ok = false; 277c84f3f3cSopenharmony_ci } 278c84f3f3cSopenharmony_ci } 279c84f3f3cSopenharmony_ci tty_init_state(); 280c84f3f3cSopenharmony_ci } 281c84f3f3cSopenharmony_ci} 282c84f3f3cSopenharmony_ci#endif 283c84f3f3cSopenharmony_ci 284c84f3f3cSopenharmony_ci/* job cleanup before shell exit */ 285c84f3f3cSopenharmony_civoid 286c84f3f3cSopenharmony_cij_exit(void) 287c84f3f3cSopenharmony_ci{ 288c84f3f3cSopenharmony_ci /* kill stopped, and possibly running, jobs */ 289c84f3f3cSopenharmony_ci Job *j; 290c84f3f3cSopenharmony_ci bool killed = false; 291c84f3f3cSopenharmony_ci 292c84f3f3cSopenharmony_ci for (j = job_list; j != NULL; j = j->next) { 293c84f3f3cSopenharmony_ci if (j->ppid == procpid && 294c84f3f3cSopenharmony_ci (j->state == PSTOPPED || 295c84f3f3cSopenharmony_ci (j->state == PRUNNING && 296c84f3f3cSopenharmony_ci ((j->flags & JF_FG) || 297c84f3f3cSopenharmony_ci (Flag(FLOGIN) && !Flag(FNOHUP) && procpid == kshpid))))) { 298c84f3f3cSopenharmony_ci killed = true; 299c84f3f3cSopenharmony_ci if (j->pgrp == 0) 300c84f3f3cSopenharmony_ci kill_job(j, SIGHUP); 301c84f3f3cSopenharmony_ci else 302c84f3f3cSopenharmony_ci mksh_killpg(j->pgrp, SIGHUP); 303c84f3f3cSopenharmony_ci#ifndef MKSH_UNEMPLOYED 304c84f3f3cSopenharmony_ci if (j->state == PSTOPPED) { 305c84f3f3cSopenharmony_ci if (j->pgrp == 0) 306c84f3f3cSopenharmony_ci kill_job(j, SIGCONT); 307c84f3f3cSopenharmony_ci else 308c84f3f3cSopenharmony_ci mksh_killpg(j->pgrp, SIGCONT); 309c84f3f3cSopenharmony_ci } 310c84f3f3cSopenharmony_ci#endif 311c84f3f3cSopenharmony_ci } 312c84f3f3cSopenharmony_ci } 313c84f3f3cSopenharmony_ci if (killed) 314c84f3f3cSopenharmony_ci sleep(1); 315c84f3f3cSopenharmony_ci j_notify(); 316c84f3f3cSopenharmony_ci 317c84f3f3cSopenharmony_ci#ifndef MKSH_UNEMPLOYED 318c84f3f3cSopenharmony_ci if (kshpid == procpid && restore_ttypgrp >= 0) { 319c84f3f3cSopenharmony_ci /* 320c84f3f3cSopenharmony_ci * Need to restore the tty pgrp to what it was when the 321c84f3f3cSopenharmony_ci * shell started up, so that the process that started us 322c84f3f3cSopenharmony_ci * will be able to access the tty when we are done. 323c84f3f3cSopenharmony_ci * Also need to restore our process group in case we are 324c84f3f3cSopenharmony_ci * about to do an exec so that both our parent and the 325c84f3f3cSopenharmony_ci * process we are to become will be able to access the tty. 326c84f3f3cSopenharmony_ci */ 327c84f3f3cSopenharmony_ci tcsetpgrp(tty_fd, restore_ttypgrp); 328c84f3f3cSopenharmony_ci setpgid(0, restore_ttypgrp); 329c84f3f3cSopenharmony_ci } 330c84f3f3cSopenharmony_ci if (Flag(FMONITOR)) { 331c84f3f3cSopenharmony_ci Flag(FMONITOR) = 0; 332c84f3f3cSopenharmony_ci j_change(); 333c84f3f3cSopenharmony_ci } 334c84f3f3cSopenharmony_ci#endif 335c84f3f3cSopenharmony_ci} 336c84f3f3cSopenharmony_ci 337c84f3f3cSopenharmony_ci#ifndef MKSH_UNEMPLOYED 338c84f3f3cSopenharmony_ci/* turn job control on or off according to Flag(FMONITOR) */ 339c84f3f3cSopenharmony_civoid 340c84f3f3cSopenharmony_cij_change(void) 341c84f3f3cSopenharmony_ci{ 342c84f3f3cSopenharmony_ci int i; 343c84f3f3cSopenharmony_ci 344c84f3f3cSopenharmony_ci if (Flag(FMONITOR)) { 345c84f3f3cSopenharmony_ci bool use_tty = Flag(FTALKING); 346c84f3f3cSopenharmony_ci 347c84f3f3cSopenharmony_ci /* don't call mksh_tcget until we own the tty process group */ 348c84f3f3cSopenharmony_ci if (use_tty) 349c84f3f3cSopenharmony_ci tty_init_talking(); 350c84f3f3cSopenharmony_ci 351c84f3f3cSopenharmony_ci /* no controlling tty, no SIGT* */ 352c84f3f3cSopenharmony_ci#ifndef ADAPT_FOR_LITEOS_A 353c84f3f3cSopenharmony_ci if ((ttypgrp_ok = (use_tty && tty_fd >= 0 && tty_devtty))) { 354c84f3f3cSopenharmony_ci#else // ADAPT_FOR_LITEOS_A 355c84f3f3cSopenharmony_ci if ((ttypgrp_ok = (use_tty && tty_fd >= 0))) { 356c84f3f3cSopenharmony_ci#endif // ADAPT_FOR_LITEOS_A 357c84f3f3cSopenharmony_ci setsig(&sigtraps[SIGTTIN], SIG_DFL, 358c84f3f3cSopenharmony_ci SS_RESTORE_ORIG|SS_FORCE); 359c84f3f3cSopenharmony_ci /* wait to be given tty (POSIX.1, B.2, job control) */ 360c84f3f3cSopenharmony_ci while (/* CONSTCOND */ 1) { 361c84f3f3cSopenharmony_ci pid_t ttypgrp; 362c84f3f3cSopenharmony_ci 363c84f3f3cSopenharmony_ci if ((ttypgrp = tcgetpgrp(tty_fd)) < 0) { 364c84f3f3cSopenharmony_ci warningf(false, Tf_ssfaileds, 365c84f3f3cSopenharmony_ci "j_init", "tcgetpgrp", 366c84f3f3cSopenharmony_ci cstrerror(errno)); 367c84f3f3cSopenharmony_ci ttypgrp_ok = false; 368c84f3f3cSopenharmony_ci break; 369c84f3f3cSopenharmony_ci } 370c84f3f3cSopenharmony_ci if (ttypgrp == kshpgrp) 371c84f3f3cSopenharmony_ci break; 372c84f3f3cSopenharmony_ci kill(0, SIGTTIN); 373c84f3f3cSopenharmony_ci } 374c84f3f3cSopenharmony_ci } 375c84f3f3cSopenharmony_ci for (i = NELEM(tt_sigs); --i >= 0; ) 376c84f3f3cSopenharmony_ci setsig(&sigtraps[tt_sigs[i]], SIG_IGN, 377c84f3f3cSopenharmony_ci SS_RESTORE_DFL|SS_FORCE); 378c84f3f3cSopenharmony_ci if (ttypgrp_ok && kshpgrp != kshpid) { 379c84f3f3cSopenharmony_ci if (setpgid(0, kshpid) < 0) { 380c84f3f3cSopenharmony_ci warningf(false, Tf_ssfaileds, 381c84f3f3cSopenharmony_ci "j_init", "setpgid", cstrerror(errno)); 382c84f3f3cSopenharmony_ci ttypgrp_ok = false; 383c84f3f3cSopenharmony_ci } else { 384c84f3f3cSopenharmony_ci if (tcsetpgrp(tty_fd, kshpid) < 0) { 385c84f3f3cSopenharmony_ci warningf(false, Tf_ssfaileds, 386c84f3f3cSopenharmony_ci "j_init", "tcsetpgrp", 387c84f3f3cSopenharmony_ci cstrerror(errno)); 388c84f3f3cSopenharmony_ci ttypgrp_ok = false; 389c84f3f3cSopenharmony_ci } else 390c84f3f3cSopenharmony_ci restore_ttypgrp = kshpgrp; 391c84f3f3cSopenharmony_ci kshpgrp = kshpid; 392c84f3f3cSopenharmony_ci } 393c84f3f3cSopenharmony_ci } 394c84f3f3cSopenharmony_ci#ifndef MKSH_DISABLE_TTY_WARNING 395c84f3f3cSopenharmony_ci if (use_tty && !ttypgrp_ok) 396c84f3f3cSopenharmony_ci warningf(false, Tf_sD_s, "warning", 397c84f3f3cSopenharmony_ci "won't have full job control"); 398c84f3f3cSopenharmony_ci#endif 399c84f3f3cSopenharmony_ci } else { 400c84f3f3cSopenharmony_ci ttypgrp_ok = false; 401c84f3f3cSopenharmony_ci if (Flag(FTALKING)) 402c84f3f3cSopenharmony_ci for (i = NELEM(tt_sigs); --i >= 0; ) 403c84f3f3cSopenharmony_ci setsig(&sigtraps[tt_sigs[i]], SIG_IGN, 404c84f3f3cSopenharmony_ci SS_RESTORE_IGN|SS_FORCE); 405c84f3f3cSopenharmony_ci else 406c84f3f3cSopenharmony_ci for (i = NELEM(tt_sigs); --i >= 0; ) { 407c84f3f3cSopenharmony_ci if (sigtraps[tt_sigs[i]].flags & 408c84f3f3cSopenharmony_ci (TF_ORIG_IGN | TF_ORIG_DFL)) 409c84f3f3cSopenharmony_ci setsig(&sigtraps[tt_sigs[i]], 410c84f3f3cSopenharmony_ci (sigtraps[tt_sigs[i]].flags & TF_ORIG_IGN) ? 411c84f3f3cSopenharmony_ci SIG_IGN : SIG_DFL, 412c84f3f3cSopenharmony_ci SS_RESTORE_ORIG|SS_FORCE); 413c84f3f3cSopenharmony_ci } 414c84f3f3cSopenharmony_ci } 415c84f3f3cSopenharmony_ci tty_init_state(); 416c84f3f3cSopenharmony_ci} 417c84f3f3cSopenharmony_ci#endif 418c84f3f3cSopenharmony_ci 419c84f3f3cSopenharmony_ci#if HAVE_NICE 420c84f3f3cSopenharmony_ci/* run nice(3) and ignore the result */ 421c84f3f3cSopenharmony_cistatic void 422c84f3f3cSopenharmony_ciksh_nice(int ness) 423c84f3f3cSopenharmony_ci{ 424c84f3f3cSopenharmony_ci#if defined(__USE_FORTIFY_LEVEL) && (__USE_FORTIFY_LEVEL > 0) 425c84f3f3cSopenharmony_ci int eno; 426c84f3f3cSopenharmony_ci 427c84f3f3cSopenharmony_ci errno = 0; 428c84f3f3cSopenharmony_ci /* this is gonna annoy users; complain to your distro, people! */ 429c84f3f3cSopenharmony_ci if (nice(ness) == -1 && (eno = errno) != 0) 430c84f3f3cSopenharmony_ci warningf(false, Tf_sD_s, "bgnice", cstrerror(eno)); 431c84f3f3cSopenharmony_ci#else 432c84f3f3cSopenharmony_ci (void)nice(ness); 433c84f3f3cSopenharmony_ci#endif 434c84f3f3cSopenharmony_ci} 435c84f3f3cSopenharmony_ci#endif 436c84f3f3cSopenharmony_ci 437c84f3f3cSopenharmony_ci/* execute tree in child subprocess */ 438c84f3f3cSopenharmony_ciint 439c84f3f3cSopenharmony_ciexchild(struct op *t, int flags, 440c84f3f3cSopenharmony_ci volatile int *xerrok, 441c84f3f3cSopenharmony_ci /* used if XPCLOSE or XCCLOSE */ 442c84f3f3cSopenharmony_ci int close_fd) 443c84f3f3cSopenharmony_ci{ 444c84f3f3cSopenharmony_ci /* for pipelines */ 445c84f3f3cSopenharmony_ci static Proc *last_proc; 446c84f3f3cSopenharmony_ci 447c84f3f3cSopenharmony_ci int rv = 0, forksleep, jwflags = JW_NONE; 448c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 449c84f3f3cSopenharmony_ci sigset_t omask; 450c84f3f3cSopenharmony_ci#endif 451c84f3f3cSopenharmony_ci Proc *p; 452c84f3f3cSopenharmony_ci Job *j; 453c84f3f3cSopenharmony_ci pid_t cldpid; 454c84f3f3cSopenharmony_ci 455c84f3f3cSopenharmony_ci if (flags & XPIPEST) { 456c84f3f3cSopenharmony_ci flags &= ~XPIPEST; 457c84f3f3cSopenharmony_ci jwflags |= JW_PIPEST; 458c84f3f3cSopenharmony_ci } 459c84f3f3cSopenharmony_ci 460c84f3f3cSopenharmony_ci if (flags & XEXEC) 461c84f3f3cSopenharmony_ci /* 462c84f3f3cSopenharmony_ci * Clear XFORK|XPCLOSE|XCCLOSE|XCOPROC|XPIPEO|XPIPEI|XXCOM|XBGND 463c84f3f3cSopenharmony_ci * (also done in another execute() below) 464c84f3f3cSopenharmony_ci */ 465c84f3f3cSopenharmony_ci return (execute(t, flags & (XEXEC | XERROK), xerrok)); 466c84f3f3cSopenharmony_ci 467c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 468c84f3f3cSopenharmony_ci /* no SIGCHLDs while messing with job and process lists */ 469c84f3f3cSopenharmony_ci sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); 470c84f3f3cSopenharmony_ci#endif 471c84f3f3cSopenharmony_ci 472c84f3f3cSopenharmony_ci p = new_proc(); 473c84f3f3cSopenharmony_ci p->next = NULL; 474c84f3f3cSopenharmony_ci p->state = PRUNNING; 475c84f3f3cSopenharmony_ci p->status = 0; 476c84f3f3cSopenharmony_ci p->pid = 0; 477c84f3f3cSopenharmony_ci 478c84f3f3cSopenharmony_ci /* link process into jobs list */ 479c84f3f3cSopenharmony_ci if (flags & XPIPEI) { 480c84f3f3cSopenharmony_ci /* continuing with a pipe */ 481c84f3f3cSopenharmony_ci if (!last_job) 482c84f3f3cSopenharmony_ci internal_errorf("exchild: XPIPEI and no last_job - pid %d", 483c84f3f3cSopenharmony_ci (int)procpid); 484c84f3f3cSopenharmony_ci j = last_job; 485c84f3f3cSopenharmony_ci if (last_proc) 486c84f3f3cSopenharmony_ci last_proc->next = p; 487c84f3f3cSopenharmony_ci last_proc = p; 488c84f3f3cSopenharmony_ci } else { 489c84f3f3cSopenharmony_ci /* fills in j->job */ 490c84f3f3cSopenharmony_ci j = new_job(); 491c84f3f3cSopenharmony_ci /* 492c84f3f3cSopenharmony_ci * we don't consider XXCOMs foreground since they don't get 493c84f3f3cSopenharmony_ci * tty process group and we don't save or restore tty modes. 494c84f3f3cSopenharmony_ci */ 495c84f3f3cSopenharmony_ci j->flags = (flags & XXCOM) ? JF_XXCOM : 496c84f3f3cSopenharmony_ci ((flags & XBGND) ? 0 : (JF_FG|JF_USETTYMODE)); 497c84f3f3cSopenharmony_ci timerclear(&j->usrtime); 498c84f3f3cSopenharmony_ci timerclear(&j->systime); 499c84f3f3cSopenharmony_ci j->state = PRUNNING; 500c84f3f3cSopenharmony_ci j->pgrp = 0; 501c84f3f3cSopenharmony_ci j->ppid = procpid; 502c84f3f3cSopenharmony_ci j->age = ++njobs; 503c84f3f3cSopenharmony_ci j->proc_list = p; 504c84f3f3cSopenharmony_ci j->coproc_id = 0; 505c84f3f3cSopenharmony_ci last_job = j; 506c84f3f3cSopenharmony_ci last_proc = p; 507c84f3f3cSopenharmony_ci put_job(j, PJ_PAST_STOPPED); 508c84f3f3cSopenharmony_ci } 509c84f3f3cSopenharmony_ci 510c84f3f3cSopenharmony_ci vistree(p->command, sizeof(p->command), t); 511c84f3f3cSopenharmony_ci 512c84f3f3cSopenharmony_ci /* create child process */ 513c84f3f3cSopenharmony_ci forksleep = 1; 514c84f3f3cSopenharmony_ci while ((cldpid = fork()) < 0 && errno == EAGAIN && forksleep < 32) { 515c84f3f3cSopenharmony_ci if (intrsig) 516c84f3f3cSopenharmony_ci /* allow user to ^C out... */ 517c84f3f3cSopenharmony_ci break; 518c84f3f3cSopenharmony_ci sleep(forksleep); 519c84f3f3cSopenharmony_ci forksleep <<= 1; 520c84f3f3cSopenharmony_ci } 521c84f3f3cSopenharmony_ci /* ensure $RANDOM changes between parent and child */ 522c84f3f3cSopenharmony_ci rndset((unsigned long)cldpid); 523c84f3f3cSopenharmony_ci /* fork failed? */ 524c84f3f3cSopenharmony_ci if (cldpid < 0) { 525c84f3f3cSopenharmony_ci kill_job(j, SIGKILL); 526c84f3f3cSopenharmony_ci remove_job(j, "fork failed"); 527c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 528c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &omask, NULL); 529c84f3f3cSopenharmony_ci#endif 530c84f3f3cSopenharmony_ci errorf("can't fork - try again"); 531c84f3f3cSopenharmony_ci } 532c84f3f3cSopenharmony_ci p->pid = cldpid ? cldpid : (procpid = getpid()); 533c84f3f3cSopenharmony_ci 534c84f3f3cSopenharmony_ci#ifndef MKSH_UNEMPLOYED 535c84f3f3cSopenharmony_ci /* job control set up */ 536c84f3f3cSopenharmony_ci if (Flag(FMONITOR) && !(flags&XXCOM)) { 537c84f3f3cSopenharmony_ci bool dotty = false; 538c84f3f3cSopenharmony_ci 539c84f3f3cSopenharmony_ci if (j->pgrp == 0) { 540c84f3f3cSopenharmony_ci /* First process */ 541c84f3f3cSopenharmony_ci j->pgrp = p->pid; 542c84f3f3cSopenharmony_ci dotty = true; 543c84f3f3cSopenharmony_ci } 544c84f3f3cSopenharmony_ci 545c84f3f3cSopenharmony_ci /* 546c84f3f3cSopenharmony_ci * set pgrp in both parent and child to deal with race 547c84f3f3cSopenharmony_ci * condition 548c84f3f3cSopenharmony_ci */ 549c84f3f3cSopenharmony_ci setpgid(p->pid, j->pgrp); 550c84f3f3cSopenharmony_ci if (ttypgrp_ok && dotty && !(flags & XBGND)) 551c84f3f3cSopenharmony_ci tcsetpgrp(tty_fd, j->pgrp); 552c84f3f3cSopenharmony_ci } 553c84f3f3cSopenharmony_ci#endif 554c84f3f3cSopenharmony_ci 555c84f3f3cSopenharmony_ci /* used to close pipe input fd */ 556c84f3f3cSopenharmony_ci if (close_fd >= 0 && (((flags & XPCLOSE) && cldpid) || 557c84f3f3cSopenharmony_ci ((flags & XCCLOSE) && !cldpid))) 558c84f3f3cSopenharmony_ci close(close_fd); 559c84f3f3cSopenharmony_ci if (!cldpid) { 560c84f3f3cSopenharmony_ci /* child */ 561c84f3f3cSopenharmony_ci 562c84f3f3cSopenharmony_ci /* Do this before restoring signal */ 563c84f3f3cSopenharmony_ci if (flags & XCOPROC) 564c84f3f3cSopenharmony_ci coproc_cleanup(false); 565c84f3f3cSopenharmony_ci cleanup_parents_env(); 566c84f3f3cSopenharmony_ci#ifndef MKSH_UNEMPLOYED 567c84f3f3cSopenharmony_ci /* 568c84f3f3cSopenharmony_ci * If FMONITOR or FTALKING is set, these signals are ignored, 569c84f3f3cSopenharmony_ci * if neither FMONITOR nor FTALKING are set, the signals have 570c84f3f3cSopenharmony_ci * their inherited values. 571c84f3f3cSopenharmony_ci */ 572c84f3f3cSopenharmony_ci if (Flag(FMONITOR) && !(flags & XXCOM)) { 573c84f3f3cSopenharmony_ci for (forksleep = NELEM(tt_sigs); --forksleep >= 0; ) 574c84f3f3cSopenharmony_ci setsig(&sigtraps[tt_sigs[forksleep]], SIG_DFL, 575c84f3f3cSopenharmony_ci SS_RESTORE_DFL|SS_FORCE); 576c84f3f3cSopenharmony_ci } 577c84f3f3cSopenharmony_ci#endif 578c84f3f3cSopenharmony_ci#if HAVE_NICE 579c84f3f3cSopenharmony_ci if (Flag(FBGNICE) && (flags & XBGND)) 580c84f3f3cSopenharmony_ci ksh_nice(4); 581c84f3f3cSopenharmony_ci#endif 582c84f3f3cSopenharmony_ci if ((flags & XBGND) 583c84f3f3cSopenharmony_ci#ifndef MKSH_UNEMPLOYED 584c84f3f3cSopenharmony_ci && !Flag(FMONITOR) 585c84f3f3cSopenharmony_ci#endif 586c84f3f3cSopenharmony_ci ) { 587c84f3f3cSopenharmony_ci setsig(&sigtraps[SIGINT], SIG_IGN, 588c84f3f3cSopenharmony_ci SS_RESTORE_IGN|SS_FORCE); 589c84f3f3cSopenharmony_ci setsig(&sigtraps[SIGQUIT], SIG_IGN, 590c84f3f3cSopenharmony_ci SS_RESTORE_IGN|SS_FORCE); 591c84f3f3cSopenharmony_ci if ((!(flags & (XPIPEI | XCOPROC))) && 592c84f3f3cSopenharmony_ci ((forksleep = open("/dev/null", 0)) > 0)) { 593c84f3f3cSopenharmony_ci (void)ksh_dup2(forksleep, 0, true); 594c84f3f3cSopenharmony_ci close(forksleep); 595c84f3f3cSopenharmony_ci } 596c84f3f3cSopenharmony_ci } 597c84f3f3cSopenharmony_ci /* in case of $(jobs) command */ 598c84f3f3cSopenharmony_ci remove_job(j, "child"); 599c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 600c84f3f3cSopenharmony_ci /* remove_job needs SIGCHLD blocked still */ 601c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &omask, NULL); 602c84f3f3cSopenharmony_ci#endif 603c84f3f3cSopenharmony_ci nzombie = 0; 604c84f3f3cSopenharmony_ci#ifndef MKSH_UNEMPLOYED 605c84f3f3cSopenharmony_ci ttypgrp_ok = false; 606c84f3f3cSopenharmony_ci Flag(FMONITOR) = 0; 607c84f3f3cSopenharmony_ci#endif 608c84f3f3cSopenharmony_ci Flag(FTALKING) = 0; 609c84f3f3cSopenharmony_ci cleartraps(); 610c84f3f3cSopenharmony_ci /* no return */ 611c84f3f3cSopenharmony_ci execute(t, (flags & XERROK) | XEXEC, NULL); 612c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL 613c84f3f3cSopenharmony_ci if (t->type == TPIPE) 614c84f3f3cSopenharmony_ci unwind(LLEAVE); 615c84f3f3cSopenharmony_ci internal_warningf("%s: execute() returned", "exchild"); 616c84f3f3cSopenharmony_ci fptreef(shl_out, 8, "%s: tried to execute {\n\t%T\n}\n", 617c84f3f3cSopenharmony_ci "exchild", t); 618c84f3f3cSopenharmony_ci shf_flush(shl_out); 619c84f3f3cSopenharmony_ci#endif 620c84f3f3cSopenharmony_ci unwind(LLEAVE); 621c84f3f3cSopenharmony_ci /* NOTREACHED */ 622c84f3f3cSopenharmony_ci } 623c84f3f3cSopenharmony_ci 624c84f3f3cSopenharmony_ci /* shell (parent) stuff */ 625c84f3f3cSopenharmony_ci if (!(flags & XPIPEO)) { 626c84f3f3cSopenharmony_ci /* last process in a job */ 627c84f3f3cSopenharmony_ci j_startjob(j); 628c84f3f3cSopenharmony_ci if (flags & XCOPROC) { 629c84f3f3cSopenharmony_ci j->coproc_id = coproc.id; 630c84f3f3cSopenharmony_ci /* n jobs using co-process output */ 631c84f3f3cSopenharmony_ci coproc.njobs++; 632c84f3f3cSopenharmony_ci /* j using co-process input */ 633c84f3f3cSopenharmony_ci coproc.job = (void *)j; 634c84f3f3cSopenharmony_ci } 635c84f3f3cSopenharmony_ci if (flags & XBGND) { 636c84f3f3cSopenharmony_ci j_set_async(j); 637c84f3f3cSopenharmony_ci if (Flag(FTALKING)) { 638c84f3f3cSopenharmony_ci shf_fprintf(shl_out, "[%d]", j->job); 639c84f3f3cSopenharmony_ci for (p = j->proc_list; p; p = p->next) 640c84f3f3cSopenharmony_ci shf_fprintf(shl_out, Tf__d, 641c84f3f3cSopenharmony_ci (int)p->pid); 642c84f3f3cSopenharmony_ci shf_putchar('\n', shl_out); 643c84f3f3cSopenharmony_ci shf_flush(shl_out); 644c84f3f3cSopenharmony_ci } 645c84f3f3cSopenharmony_ci } else 646c84f3f3cSopenharmony_ci rv = j_waitj(j, jwflags, "jw:last proc"); 647c84f3f3cSopenharmony_ci } 648c84f3f3cSopenharmony_ci 649c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 650c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &omask, NULL); 651c84f3f3cSopenharmony_ci#endif 652c84f3f3cSopenharmony_ci 653c84f3f3cSopenharmony_ci return (rv); 654c84f3f3cSopenharmony_ci} 655c84f3f3cSopenharmony_ci 656c84f3f3cSopenharmony_ci/* start the last job: only used for $(command) jobs */ 657c84f3f3cSopenharmony_civoid 658c84f3f3cSopenharmony_cistartlast(void) 659c84f3f3cSopenharmony_ci{ 660c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 661c84f3f3cSopenharmony_ci sigset_t omask; 662c84f3f3cSopenharmony_ci 663c84f3f3cSopenharmony_ci sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); 664c84f3f3cSopenharmony_ci#endif 665c84f3f3cSopenharmony_ci 666c84f3f3cSopenharmony_ci /* no need to report error - waitlast() will do it */ 667c84f3f3cSopenharmony_ci if (last_job) { 668c84f3f3cSopenharmony_ci /* ensure it isn't removed by check_job() */ 669c84f3f3cSopenharmony_ci last_job->flags |= JF_WAITING; 670c84f3f3cSopenharmony_ci j_startjob(last_job); 671c84f3f3cSopenharmony_ci } 672c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 673c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &omask, NULL); 674c84f3f3cSopenharmony_ci#endif 675c84f3f3cSopenharmony_ci} 676c84f3f3cSopenharmony_ci 677c84f3f3cSopenharmony_ci/* wait for last job: only used for $(command) jobs */ 678c84f3f3cSopenharmony_ciint 679c84f3f3cSopenharmony_ciwaitlast(void) 680c84f3f3cSopenharmony_ci{ 681c84f3f3cSopenharmony_ci int rv; 682c84f3f3cSopenharmony_ci Job *j; 683c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 684c84f3f3cSopenharmony_ci sigset_t omask; 685c84f3f3cSopenharmony_ci 686c84f3f3cSopenharmony_ci sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); 687c84f3f3cSopenharmony_ci#endif 688c84f3f3cSopenharmony_ci 689c84f3f3cSopenharmony_ci j = last_job; 690c84f3f3cSopenharmony_ci if (!j || !(j->flags & JF_STARTED)) { 691c84f3f3cSopenharmony_ci if (!j) 692c84f3f3cSopenharmony_ci warningf(true, Tf_sD_s, "waitlast", "no last job"); 693c84f3f3cSopenharmony_ci else 694c84f3f3cSopenharmony_ci internal_warningf(Tf_sD_s, "waitlast", Tnot_started); 695c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 696c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &omask, NULL); 697c84f3f3cSopenharmony_ci#endif 698c84f3f3cSopenharmony_ci /* not so arbitrary, non-zero value */ 699c84f3f3cSopenharmony_ci return (125); 700c84f3f3cSopenharmony_ci } 701c84f3f3cSopenharmony_ci 702c84f3f3cSopenharmony_ci rv = j_waitj(j, JW_NONE, "waitlast"); 703c84f3f3cSopenharmony_ci 704c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 705c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &omask, NULL); 706c84f3f3cSopenharmony_ci#endif 707c84f3f3cSopenharmony_ci 708c84f3f3cSopenharmony_ci return (rv); 709c84f3f3cSopenharmony_ci} 710c84f3f3cSopenharmony_ci 711c84f3f3cSopenharmony_ci/* wait for child, interruptable. */ 712c84f3f3cSopenharmony_ciint 713c84f3f3cSopenharmony_ciwaitfor(const char *cp, int *sigp) 714c84f3f3cSopenharmony_ci{ 715c84f3f3cSopenharmony_ci int rv, ecode, flags = JW_INTERRUPT|JW_ASYNCNOTIFY; 716c84f3f3cSopenharmony_ci Job *j; 717c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 718c84f3f3cSopenharmony_ci sigset_t omask; 719c84f3f3cSopenharmony_ci 720c84f3f3cSopenharmony_ci sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); 721c84f3f3cSopenharmony_ci#endif 722c84f3f3cSopenharmony_ci 723c84f3f3cSopenharmony_ci *sigp = 0; 724c84f3f3cSopenharmony_ci 725c84f3f3cSopenharmony_ci if (cp == NULL) { 726c84f3f3cSopenharmony_ci /* 727c84f3f3cSopenharmony_ci * wait for an unspecified job - always returns 0, so 728c84f3f3cSopenharmony_ci * don't have to worry about exited/signaled jobs 729c84f3f3cSopenharmony_ci */ 730c84f3f3cSopenharmony_ci for (j = job_list; j; j = j->next) 731c84f3f3cSopenharmony_ci /* AT&T ksh will wait for stopped jobs - we don't */ 732c84f3f3cSopenharmony_ci if (j->ppid == procpid && j->state == PRUNNING) 733c84f3f3cSopenharmony_ci break; 734c84f3f3cSopenharmony_ci if (!j) { 735c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 736c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &omask, NULL); 737c84f3f3cSopenharmony_ci#endif 738c84f3f3cSopenharmony_ci return (-1); 739c84f3f3cSopenharmony_ci } 740c84f3f3cSopenharmony_ci } else if ((j = j_lookup(cp, &ecode))) { 741c84f3f3cSopenharmony_ci /* don't report normal job completion */ 742c84f3f3cSopenharmony_ci flags &= ~JW_ASYNCNOTIFY; 743c84f3f3cSopenharmony_ci if (j->ppid != procpid) { 744c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 745c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &omask, NULL); 746c84f3f3cSopenharmony_ci#endif 747c84f3f3cSopenharmony_ci return (-1); 748c84f3f3cSopenharmony_ci } 749c84f3f3cSopenharmony_ci } else { 750c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 751c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &omask, NULL); 752c84f3f3cSopenharmony_ci#endif 753c84f3f3cSopenharmony_ci if (ecode != JL_NOSUCH) 754c84f3f3cSopenharmony_ci bi_errorf(Tf_sD_s, cp, lookup_msgs[ecode]); 755c84f3f3cSopenharmony_ci return (-1); 756c84f3f3cSopenharmony_ci } 757c84f3f3cSopenharmony_ci 758c84f3f3cSopenharmony_ci /* AT&T ksh will wait for stopped jobs - we don't */ 759c84f3f3cSopenharmony_ci rv = j_waitj(j, flags, "jw:waitfor"); 760c84f3f3cSopenharmony_ci 761c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 762c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &omask, NULL); 763c84f3f3cSopenharmony_ci#endif 764c84f3f3cSopenharmony_ci 765c84f3f3cSopenharmony_ci if (rv < 0) 766c84f3f3cSopenharmony_ci /* we were interrupted */ 767c84f3f3cSopenharmony_ci *sigp = ksh_sigmask(-rv); 768c84f3f3cSopenharmony_ci 769c84f3f3cSopenharmony_ci return (rv); 770c84f3f3cSopenharmony_ci} 771c84f3f3cSopenharmony_ci 772c84f3f3cSopenharmony_ci/* kill (built-in) a job */ 773c84f3f3cSopenharmony_ciint 774c84f3f3cSopenharmony_cij_kill(const char *cp, int sig) 775c84f3f3cSopenharmony_ci{ 776c84f3f3cSopenharmony_ci Job *j; 777c84f3f3cSopenharmony_ci int rv = 0, ecode; 778c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 779c84f3f3cSopenharmony_ci sigset_t omask; 780c84f3f3cSopenharmony_ci 781c84f3f3cSopenharmony_ci sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); 782c84f3f3cSopenharmony_ci#endif 783c84f3f3cSopenharmony_ci 784c84f3f3cSopenharmony_ci if ((j = j_lookup(cp, &ecode)) == NULL) { 785c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 786c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &omask, NULL); 787c84f3f3cSopenharmony_ci#endif 788c84f3f3cSopenharmony_ci bi_errorf(Tf_sD_s, cp, lookup_msgs[ecode]); 789c84f3f3cSopenharmony_ci return (1); 790c84f3f3cSopenharmony_ci } 791c84f3f3cSopenharmony_ci 792c84f3f3cSopenharmony_ci if (j->pgrp == 0) { 793c84f3f3cSopenharmony_ci /* started when !Flag(FMONITOR) */ 794c84f3f3cSopenharmony_ci if (kill_job(j, sig) < 0) { 795c84f3f3cSopenharmony_ci bi_errorf(Tf_sD_s, cp, cstrerror(errno)); 796c84f3f3cSopenharmony_ci rv = 1; 797c84f3f3cSopenharmony_ci } 798c84f3f3cSopenharmony_ci } else { 799c84f3f3cSopenharmony_ci#ifndef MKSH_UNEMPLOYED 800c84f3f3cSopenharmony_ci if (j->state == PSTOPPED && (sig == SIGTERM || sig == SIGHUP)) 801c84f3f3cSopenharmony_ci mksh_killpg(j->pgrp, SIGCONT); 802c84f3f3cSopenharmony_ci#endif 803c84f3f3cSopenharmony_ci if (mksh_killpg(j->pgrp, sig) < 0) { 804c84f3f3cSopenharmony_ci bi_errorf(Tf_sD_s, cp, cstrerror(errno)); 805c84f3f3cSopenharmony_ci rv = 1; 806c84f3f3cSopenharmony_ci } 807c84f3f3cSopenharmony_ci } 808c84f3f3cSopenharmony_ci 809c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 810c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &omask, NULL); 811c84f3f3cSopenharmony_ci#endif 812c84f3f3cSopenharmony_ci 813c84f3f3cSopenharmony_ci return (rv); 814c84f3f3cSopenharmony_ci} 815c84f3f3cSopenharmony_ci 816c84f3f3cSopenharmony_ci#ifndef MKSH_UNEMPLOYED 817c84f3f3cSopenharmony_ci/* fg and bg built-ins: called only if Flag(FMONITOR) set */ 818c84f3f3cSopenharmony_ciint 819c84f3f3cSopenharmony_cij_resume(const char *cp, int bg) 820c84f3f3cSopenharmony_ci{ 821c84f3f3cSopenharmony_ci Job *j; 822c84f3f3cSopenharmony_ci Proc *p; 823c84f3f3cSopenharmony_ci int ecode, rv = 0; 824c84f3f3cSopenharmony_ci bool running; 825c84f3f3cSopenharmony_ci sigset_t omask; 826c84f3f3cSopenharmony_ci 827c84f3f3cSopenharmony_ci sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); 828c84f3f3cSopenharmony_ci 829c84f3f3cSopenharmony_ci if ((j = j_lookup(cp, &ecode)) == NULL) { 830c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &omask, NULL); 831c84f3f3cSopenharmony_ci bi_errorf(Tf_sD_s, cp, lookup_msgs[ecode]); 832c84f3f3cSopenharmony_ci return (1); 833c84f3f3cSopenharmony_ci } 834c84f3f3cSopenharmony_ci 835c84f3f3cSopenharmony_ci if (j->pgrp == 0) { 836c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &omask, NULL); 837c84f3f3cSopenharmony_ci bi_errorf("job not job-controlled"); 838c84f3f3cSopenharmony_ci return (1); 839c84f3f3cSopenharmony_ci } 840c84f3f3cSopenharmony_ci 841c84f3f3cSopenharmony_ci if (bg) 842c84f3f3cSopenharmony_ci shprintf("[%d] ", j->job); 843c84f3f3cSopenharmony_ci 844c84f3f3cSopenharmony_ci running = false; 845c84f3f3cSopenharmony_ci for (p = j->proc_list; p != NULL; p = p->next) { 846c84f3f3cSopenharmony_ci if (p->state == PSTOPPED) { 847c84f3f3cSopenharmony_ci p->state = PRUNNING; 848c84f3f3cSopenharmony_ci p->status = 0; 849c84f3f3cSopenharmony_ci running = true; 850c84f3f3cSopenharmony_ci } 851c84f3f3cSopenharmony_ci shf_puts(p->command, shl_stdout); 852c84f3f3cSopenharmony_ci if (p->next) 853c84f3f3cSopenharmony_ci shf_puts("| ", shl_stdout); 854c84f3f3cSopenharmony_ci } 855c84f3f3cSopenharmony_ci shf_putc('\n', shl_stdout); 856c84f3f3cSopenharmony_ci shf_flush(shl_stdout); 857c84f3f3cSopenharmony_ci if (running) 858c84f3f3cSopenharmony_ci j->state = PRUNNING; 859c84f3f3cSopenharmony_ci 860c84f3f3cSopenharmony_ci put_job(j, PJ_PAST_STOPPED); 861c84f3f3cSopenharmony_ci if (bg) 862c84f3f3cSopenharmony_ci j_set_async(j); 863c84f3f3cSopenharmony_ci else { 864c84f3f3cSopenharmony_ci /* attach tty to job */ 865c84f3f3cSopenharmony_ci if (j->state == PRUNNING) { 866c84f3f3cSopenharmony_ci if (ttypgrp_ok && (j->flags & JF_SAVEDTTY)) 867c84f3f3cSopenharmony_ci mksh_tcset(tty_fd, &j->ttystat); 868c84f3f3cSopenharmony_ci /* See comment in j_waitj regarding saved_ttypgrp. */ 869c84f3f3cSopenharmony_ci if (ttypgrp_ok && 870c84f3f3cSopenharmony_ci tcsetpgrp(tty_fd, (j->flags & JF_SAVEDTTYPGRP) ? 871c84f3f3cSopenharmony_ci j->saved_ttypgrp : j->pgrp) < 0) { 872c84f3f3cSopenharmony_ci rv = errno; 873c84f3f3cSopenharmony_ci if (j->flags & JF_SAVEDTTY) 874c84f3f3cSopenharmony_ci mksh_tcset(tty_fd, &tty_state); 875c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &omask, NULL); 876c84f3f3cSopenharmony_ci bi_errorf(Tf_ldfailed, 877c84f3f3cSopenharmony_ci "fg: 1st", "tcsetpgrp", tty_fd, 878c84f3f3cSopenharmony_ci (long)((j->flags & JF_SAVEDTTYPGRP) ? 879c84f3f3cSopenharmony_ci j->saved_ttypgrp : j->pgrp), 880c84f3f3cSopenharmony_ci cstrerror(rv)); 881c84f3f3cSopenharmony_ci return (1); 882c84f3f3cSopenharmony_ci } 883c84f3f3cSopenharmony_ci } 884c84f3f3cSopenharmony_ci j->flags |= JF_FG; 885c84f3f3cSopenharmony_ci j->flags &= ~JF_KNOWN; 886c84f3f3cSopenharmony_ci if (j == async_job) 887c84f3f3cSopenharmony_ci async_job = NULL; 888c84f3f3cSopenharmony_ci } 889c84f3f3cSopenharmony_ci 890c84f3f3cSopenharmony_ci if (j->state == PRUNNING && mksh_killpg(j->pgrp, SIGCONT) < 0) { 891c84f3f3cSopenharmony_ci int eno = errno; 892c84f3f3cSopenharmony_ci 893c84f3f3cSopenharmony_ci if (!bg) { 894c84f3f3cSopenharmony_ci j->flags &= ~JF_FG; 895c84f3f3cSopenharmony_ci if (ttypgrp_ok && (j->flags & JF_SAVEDTTY)) 896c84f3f3cSopenharmony_ci mksh_tcset(tty_fd, &tty_state); 897c84f3f3cSopenharmony_ci if (ttypgrp_ok && tcsetpgrp(tty_fd, kshpgrp) < 0) 898c84f3f3cSopenharmony_ci warningf(true, Tf_ldfailed, 899c84f3f3cSopenharmony_ci "fg: 2nd", "tcsetpgrp", tty_fd, 900c84f3f3cSopenharmony_ci (long)kshpgrp, cstrerror(errno)); 901c84f3f3cSopenharmony_ci } 902c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &omask, NULL); 903c84f3f3cSopenharmony_ci bi_errorf(Tf_s_sD_s, "can't continue job", 904c84f3f3cSopenharmony_ci cp, cstrerror(eno)); 905c84f3f3cSopenharmony_ci return (1); 906c84f3f3cSopenharmony_ci } 907c84f3f3cSopenharmony_ci if (!bg) { 908c84f3f3cSopenharmony_ci if (ttypgrp_ok) { 909c84f3f3cSopenharmony_ci j->flags &= ~(JF_SAVEDTTY | JF_SAVEDTTYPGRP); 910c84f3f3cSopenharmony_ci } 911c84f3f3cSopenharmony_ci rv = j_waitj(j, JW_NONE, "jw:resume"); 912c84f3f3cSopenharmony_ci } 913c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &omask, NULL); 914c84f3f3cSopenharmony_ci return (rv); 915c84f3f3cSopenharmony_ci} 916c84f3f3cSopenharmony_ci#endif 917c84f3f3cSopenharmony_ci 918c84f3f3cSopenharmony_ci/* are there any running or stopped jobs ? */ 919c84f3f3cSopenharmony_ciint 920c84f3f3cSopenharmony_cij_stopped_running(void) 921c84f3f3cSopenharmony_ci{ 922c84f3f3cSopenharmony_ci Job *j; 923c84f3f3cSopenharmony_ci int which = 0; 924c84f3f3cSopenharmony_ci 925c84f3f3cSopenharmony_ci for (j = job_list; j != NULL; j = j->next) { 926c84f3f3cSopenharmony_ci#ifndef MKSH_UNEMPLOYED 927c84f3f3cSopenharmony_ci if (j->ppid == procpid && j->state == PSTOPPED) 928c84f3f3cSopenharmony_ci which |= 1; 929c84f3f3cSopenharmony_ci#endif 930c84f3f3cSopenharmony_ci if (Flag(FLOGIN) && !Flag(FNOHUP) && procpid == kshpid && 931c84f3f3cSopenharmony_ci j->ppid == procpid && j->state == PRUNNING) 932c84f3f3cSopenharmony_ci which |= 2; 933c84f3f3cSopenharmony_ci } 934c84f3f3cSopenharmony_ci if (which) { 935c84f3f3cSopenharmony_ci shellf("You have %s%s%s jobs\n", 936c84f3f3cSopenharmony_ci which & 1 ? "stopped" : "", 937c84f3f3cSopenharmony_ci which == 3 ? " and " : "", 938c84f3f3cSopenharmony_ci which & 2 ? "running" : ""); 939c84f3f3cSopenharmony_ci return (1); 940c84f3f3cSopenharmony_ci } 941c84f3f3cSopenharmony_ci 942c84f3f3cSopenharmony_ci return (0); 943c84f3f3cSopenharmony_ci} 944c84f3f3cSopenharmony_ci 945c84f3f3cSopenharmony_ci 946c84f3f3cSopenharmony_ci/* list jobs for jobs built-in */ 947c84f3f3cSopenharmony_ciint 948c84f3f3cSopenharmony_cij_jobs(const char *cp, int slp, 949c84f3f3cSopenharmony_ci /* 0: short, 1: long, 2: pgrp */ 950c84f3f3cSopenharmony_ci int nflag) 951c84f3f3cSopenharmony_ci{ 952c84f3f3cSopenharmony_ci Job *j, *tmp; 953c84f3f3cSopenharmony_ci int how, zflag = 0; 954c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 955c84f3f3cSopenharmony_ci sigset_t omask; 956c84f3f3cSopenharmony_ci 957c84f3f3cSopenharmony_ci sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); 958c84f3f3cSopenharmony_ci#endif 959c84f3f3cSopenharmony_ci 960c84f3f3cSopenharmony_ci if (nflag < 0) { 961c84f3f3cSopenharmony_ci /* kludge: print zombies */ 962c84f3f3cSopenharmony_ci nflag = 0; 963c84f3f3cSopenharmony_ci zflag = 1; 964c84f3f3cSopenharmony_ci } 965c84f3f3cSopenharmony_ci if (cp) { 966c84f3f3cSopenharmony_ci int ecode; 967c84f3f3cSopenharmony_ci 968c84f3f3cSopenharmony_ci if ((j = j_lookup(cp, &ecode)) == NULL) { 969c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 970c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &omask, NULL); 971c84f3f3cSopenharmony_ci#endif 972c84f3f3cSopenharmony_ci bi_errorf(Tf_sD_s, cp, lookup_msgs[ecode]); 973c84f3f3cSopenharmony_ci return (1); 974c84f3f3cSopenharmony_ci } 975c84f3f3cSopenharmony_ci } else 976c84f3f3cSopenharmony_ci j = job_list; 977c84f3f3cSopenharmony_ci how = slp == 0 ? JP_MEDIUM : (slp == 1 ? JP_LONG : JP_PGRP); 978c84f3f3cSopenharmony_ci for (; j; j = j->next) { 979c84f3f3cSopenharmony_ci if ((!(j->flags & JF_ZOMBIE) || zflag) && 980c84f3f3cSopenharmony_ci (!nflag || (j->flags & JF_CHANGED))) { 981c84f3f3cSopenharmony_ci j_print(j, how, shl_stdout); 982c84f3f3cSopenharmony_ci if (j->state == PEXITED || j->state == PSIGNALLED) 983c84f3f3cSopenharmony_ci j->flags |= JF_REMOVE; 984c84f3f3cSopenharmony_ci } 985c84f3f3cSopenharmony_ci if (cp) 986c84f3f3cSopenharmony_ci break; 987c84f3f3cSopenharmony_ci } 988c84f3f3cSopenharmony_ci /* Remove jobs after printing so there won't be multiple + or - jobs */ 989c84f3f3cSopenharmony_ci for (j = job_list; j; j = tmp) { 990c84f3f3cSopenharmony_ci tmp = j->next; 991c84f3f3cSopenharmony_ci if (j->flags & JF_REMOVE) 992c84f3f3cSopenharmony_ci remove_job(j, Tjobs); 993c84f3f3cSopenharmony_ci } 994c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 995c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &omask, NULL); 996c84f3f3cSopenharmony_ci#endif 997c84f3f3cSopenharmony_ci return (0); 998c84f3f3cSopenharmony_ci} 999c84f3f3cSopenharmony_ci 1000c84f3f3cSopenharmony_ci/* list jobs for top-level notification */ 1001c84f3f3cSopenharmony_civoid 1002c84f3f3cSopenharmony_cij_notify(void) 1003c84f3f3cSopenharmony_ci{ 1004c84f3f3cSopenharmony_ci Job *j, *tmp; 1005c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 1006c84f3f3cSopenharmony_ci sigset_t omask; 1007c84f3f3cSopenharmony_ci 1008c84f3f3cSopenharmony_ci sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); 1009c84f3f3cSopenharmony_ci#endif 1010c84f3f3cSopenharmony_ci for (j = job_list; j; j = j->next) { 1011c84f3f3cSopenharmony_ci#ifndef MKSH_UNEMPLOYED 1012c84f3f3cSopenharmony_ci if (Flag(FMONITOR) && (j->flags & JF_CHANGED)) 1013c84f3f3cSopenharmony_ci j_print(j, JP_MEDIUM, shl_out); 1014c84f3f3cSopenharmony_ci#endif 1015c84f3f3cSopenharmony_ci /* 1016c84f3f3cSopenharmony_ci * Remove job after doing reports so there aren't 1017c84f3f3cSopenharmony_ci * multiple +/- jobs. 1018c84f3f3cSopenharmony_ci */ 1019c84f3f3cSopenharmony_ci if (j->state == PEXITED || j->state == PSIGNALLED) 1020c84f3f3cSopenharmony_ci j->flags |= JF_REMOVE; 1021c84f3f3cSopenharmony_ci } 1022c84f3f3cSopenharmony_ci for (j = job_list; j; j = tmp) { 1023c84f3f3cSopenharmony_ci tmp = j->next; 1024c84f3f3cSopenharmony_ci if (j->flags & JF_REMOVE) { 1025c84f3f3cSopenharmony_ci if (j == async_job || (j->flags & JF_KNOWN)) { 1026c84f3f3cSopenharmony_ci j->flags = (j->flags & ~JF_REMOVE) | JF_ZOMBIE; 1027c84f3f3cSopenharmony_ci j->job = -1; 1028c84f3f3cSopenharmony_ci nzombie++; 1029c84f3f3cSopenharmony_ci } else 1030c84f3f3cSopenharmony_ci remove_job(j, "notify"); 1031c84f3f3cSopenharmony_ci } 1032c84f3f3cSopenharmony_ci } 1033c84f3f3cSopenharmony_ci shf_flush(shl_out); 1034c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 1035c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &omask, NULL); 1036c84f3f3cSopenharmony_ci#endif 1037c84f3f3cSopenharmony_ci} 1038c84f3f3cSopenharmony_ci 1039c84f3f3cSopenharmony_ci/* Return pid of last process in last asynchronous job */ 1040c84f3f3cSopenharmony_cipid_t 1041c84f3f3cSopenharmony_cij_async(void) 1042c84f3f3cSopenharmony_ci{ 1043c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 1044c84f3f3cSopenharmony_ci sigset_t omask; 1045c84f3f3cSopenharmony_ci 1046c84f3f3cSopenharmony_ci sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); 1047c84f3f3cSopenharmony_ci#endif 1048c84f3f3cSopenharmony_ci 1049c84f3f3cSopenharmony_ci if (async_job) 1050c84f3f3cSopenharmony_ci async_job->flags |= JF_KNOWN; 1051c84f3f3cSopenharmony_ci 1052c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 1053c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &omask, NULL); 1054c84f3f3cSopenharmony_ci#endif 1055c84f3f3cSopenharmony_ci 1056c84f3f3cSopenharmony_ci return (async_pid); 1057c84f3f3cSopenharmony_ci} 1058c84f3f3cSopenharmony_ci 1059c84f3f3cSopenharmony_ci/* 1060c84f3f3cSopenharmony_ci * Make j the last async process 1061c84f3f3cSopenharmony_ci * 1062c84f3f3cSopenharmony_ci * If jobs are compiled in then this routine expects sigchld to be blocked. 1063c84f3f3cSopenharmony_ci */ 1064c84f3f3cSopenharmony_cistatic void 1065c84f3f3cSopenharmony_cij_set_async(Job *j) 1066c84f3f3cSopenharmony_ci{ 1067c84f3f3cSopenharmony_ci Job *jl, *oldest; 1068c84f3f3cSopenharmony_ci 1069c84f3f3cSopenharmony_ci if (async_job && (async_job->flags & (JF_KNOWN|JF_ZOMBIE)) == JF_ZOMBIE) 1070c84f3f3cSopenharmony_ci remove_job(async_job, "async"); 1071c84f3f3cSopenharmony_ci if (!(j->flags & JF_STARTED)) { 1072c84f3f3cSopenharmony_ci internal_warningf(Tf_sD_s, "j_async", Tjob_not_started); 1073c84f3f3cSopenharmony_ci return; 1074c84f3f3cSopenharmony_ci } 1075c84f3f3cSopenharmony_ci async_job = j; 1076c84f3f3cSopenharmony_ci async_pid = j->last_proc->pid; 1077c84f3f3cSopenharmony_ci while (nzombie > CHILD_MAX) { 1078c84f3f3cSopenharmony_ci oldest = NULL; 1079c84f3f3cSopenharmony_ci for (jl = job_list; jl; jl = jl->next) 1080c84f3f3cSopenharmony_ci if (jl != async_job && (jl->flags & JF_ZOMBIE) && 1081c84f3f3cSopenharmony_ci (!oldest || jl->age < oldest->age)) 1082c84f3f3cSopenharmony_ci oldest = jl; 1083c84f3f3cSopenharmony_ci if (!oldest) { 1084c84f3f3cSopenharmony_ci /* XXX debugging */ 1085c84f3f3cSopenharmony_ci if (!(async_job->flags & JF_ZOMBIE) || nzombie != 1) { 1086c84f3f3cSopenharmony_ci internal_warningf("%s: bad nzombie (%d)", 1087c84f3f3cSopenharmony_ci "j_async", nzombie); 1088c84f3f3cSopenharmony_ci nzombie = 0; 1089c84f3f3cSopenharmony_ci } 1090c84f3f3cSopenharmony_ci break; 1091c84f3f3cSopenharmony_ci } 1092c84f3f3cSopenharmony_ci remove_job(oldest, "zombie"); 1093c84f3f3cSopenharmony_ci } 1094c84f3f3cSopenharmony_ci} 1095c84f3f3cSopenharmony_ci 1096c84f3f3cSopenharmony_ci/* 1097c84f3f3cSopenharmony_ci * Start a job: set STARTED, check for held signals and set j->last_proc 1098c84f3f3cSopenharmony_ci * 1099c84f3f3cSopenharmony_ci * If jobs are compiled in then this routine expects sigchld to be blocked. 1100c84f3f3cSopenharmony_ci */ 1101c84f3f3cSopenharmony_cistatic void 1102c84f3f3cSopenharmony_cij_startjob(Job *j) 1103c84f3f3cSopenharmony_ci{ 1104c84f3f3cSopenharmony_ci Proc *p; 1105c84f3f3cSopenharmony_ci 1106c84f3f3cSopenharmony_ci j->flags |= JF_STARTED; 1107c84f3f3cSopenharmony_ci for (p = j->proc_list; p->next; p = p->next) 1108c84f3f3cSopenharmony_ci ; 1109c84f3f3cSopenharmony_ci j->last_proc = p; 1110c84f3f3cSopenharmony_ci 1111c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 1112c84f3f3cSopenharmony_ci if (held_sigchld) { 1113c84f3f3cSopenharmony_ci held_sigchld = 0; 1114c84f3f3cSopenharmony_ci /* Don't call j_sigchld() as it may remove job... */ 1115c84f3f3cSopenharmony_ci kill(procpid, SIGCHLD); 1116c84f3f3cSopenharmony_ci } 1117c84f3f3cSopenharmony_ci#endif 1118c84f3f3cSopenharmony_ci} 1119c84f3f3cSopenharmony_ci 1120c84f3f3cSopenharmony_ci/* 1121c84f3f3cSopenharmony_ci * wait for job to complete or change state 1122c84f3f3cSopenharmony_ci * 1123c84f3f3cSopenharmony_ci * If jobs are compiled in then this routine expects sigchld to be blocked. 1124c84f3f3cSopenharmony_ci */ 1125c84f3f3cSopenharmony_cistatic int 1126c84f3f3cSopenharmony_cij_waitj(Job *j, 1127c84f3f3cSopenharmony_ci /* see JW_* */ 1128c84f3f3cSopenharmony_ci int flags, 1129c84f3f3cSopenharmony_ci const char *where) 1130c84f3f3cSopenharmony_ci{ 1131c84f3f3cSopenharmony_ci Proc *p; 1132c84f3f3cSopenharmony_ci int rv; 1133c84f3f3cSopenharmony_ci#ifdef MKSH_NO_SIGSUSPEND 1134c84f3f3cSopenharmony_ci sigset_t omask; 1135c84f3f3cSopenharmony_ci#endif 1136c84f3f3cSopenharmony_ci 1137c84f3f3cSopenharmony_ci /* 1138c84f3f3cSopenharmony_ci * No auto-notify on the job we are waiting on. 1139c84f3f3cSopenharmony_ci */ 1140c84f3f3cSopenharmony_ci j->flags |= JF_WAITING; 1141c84f3f3cSopenharmony_ci if (flags & JW_ASYNCNOTIFY) 1142c84f3f3cSopenharmony_ci j->flags |= JF_W_ASYNCNOTIFY; 1143c84f3f3cSopenharmony_ci 1144c84f3f3cSopenharmony_ci#ifndef MKSH_UNEMPLOYED 1145c84f3f3cSopenharmony_ci if (!Flag(FMONITOR)) 1146c84f3f3cSopenharmony_ci#endif 1147c84f3f3cSopenharmony_ci flags |= JW_STOPPEDWAIT; 1148c84f3f3cSopenharmony_ci 1149c84f3f3cSopenharmony_ci while (j->state == PRUNNING || 1150c84f3f3cSopenharmony_ci ((flags & JW_STOPPEDWAIT) && j->state == PSTOPPED)) { 1151c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 1152c84f3f3cSopenharmony_ci#ifdef MKSH_NO_SIGSUSPEND 1153c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &sm_default, &omask); 1154c84f3f3cSopenharmony_ci pause(); 1155c84f3f3cSopenharmony_ci /* note that handlers may run here so they need to know */ 1156c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &omask, NULL); 1157c84f3f3cSopenharmony_ci#else 1158c84f3f3cSopenharmony_ci sigsuspend(&sm_default); 1159c84f3f3cSopenharmony_ci#endif 1160c84f3f3cSopenharmony_ci#else 1161c84f3f3cSopenharmony_ci j_sigchld(SIGCHLD); 1162c84f3f3cSopenharmony_ci#endif 1163c84f3f3cSopenharmony_ci if (fatal_trap) { 1164c84f3f3cSopenharmony_ci int oldf = j->flags & (JF_WAITING|JF_W_ASYNCNOTIFY); 1165c84f3f3cSopenharmony_ci j->flags &= ~(JF_WAITING|JF_W_ASYNCNOTIFY); 1166c84f3f3cSopenharmony_ci runtraps(TF_FATAL); 1167c84f3f3cSopenharmony_ci /* not reached... */ 1168c84f3f3cSopenharmony_ci j->flags |= oldf; 1169c84f3f3cSopenharmony_ci } 1170c84f3f3cSopenharmony_ci if ((flags & JW_INTERRUPT) && (rv = trap_pending())) { 1171c84f3f3cSopenharmony_ci j->flags &= ~(JF_WAITING|JF_W_ASYNCNOTIFY); 1172c84f3f3cSopenharmony_ci return (-rv); 1173c84f3f3cSopenharmony_ci } 1174c84f3f3cSopenharmony_ci } 1175c84f3f3cSopenharmony_ci j->flags &= ~(JF_WAITING|JF_W_ASYNCNOTIFY); 1176c84f3f3cSopenharmony_ci 1177c84f3f3cSopenharmony_ci if (j->flags & JF_FG) { 1178c84f3f3cSopenharmony_ci j->flags &= ~JF_FG; 1179c84f3f3cSopenharmony_ci#ifndef MKSH_UNEMPLOYED 1180c84f3f3cSopenharmony_ci if (Flag(FMONITOR) && ttypgrp_ok && j->pgrp) { 1181c84f3f3cSopenharmony_ci /* 1182c84f3f3cSopenharmony_ci * Save the tty's current pgrp so it can be restored 1183c84f3f3cSopenharmony_ci * when the job is foregrounded. This is to 1184c84f3f3cSopenharmony_ci * deal with things like the GNU su which does 1185c84f3f3cSopenharmony_ci * a fork/exec instead of an exec (the fork means 1186c84f3f3cSopenharmony_ci * the execed shell gets a different pid from its 1187c84f3f3cSopenharmony_ci * pgrp, so naturally it sets its pgrp and gets hosed 1188c84f3f3cSopenharmony_ci * when it gets foregrounded by the parent shell which 1189c84f3f3cSopenharmony_ci * has restored the tty's pgrp to that of the su 1190c84f3f3cSopenharmony_ci * process). 1191c84f3f3cSopenharmony_ci */ 1192c84f3f3cSopenharmony_ci if (j->state == PSTOPPED && 1193c84f3f3cSopenharmony_ci (j->saved_ttypgrp = tcgetpgrp(tty_fd)) >= 0) 1194c84f3f3cSopenharmony_ci j->flags |= JF_SAVEDTTYPGRP; 1195c84f3f3cSopenharmony_ci if (tcsetpgrp(tty_fd, kshpgrp) < 0) 1196c84f3f3cSopenharmony_ci warningf(true, Tf_ldfailed, 1197c84f3f3cSopenharmony_ci "j_waitj:", "tcsetpgrp", tty_fd, 1198c84f3f3cSopenharmony_ci (long)kshpgrp, cstrerror(errno)); 1199c84f3f3cSopenharmony_ci if (j->state == PSTOPPED) { 1200c84f3f3cSopenharmony_ci j->flags |= JF_SAVEDTTY; 1201c84f3f3cSopenharmony_ci mksh_tcget(tty_fd, &j->ttystat); 1202c84f3f3cSopenharmony_ci } 1203c84f3f3cSopenharmony_ci } 1204c84f3f3cSopenharmony_ci#endif 1205c84f3f3cSopenharmony_ci if (tty_hasstate) { 1206c84f3f3cSopenharmony_ci /* 1207c84f3f3cSopenharmony_ci * Only restore tty settings if job was originally 1208c84f3f3cSopenharmony_ci * started in the foreground. Problems can be 1209c84f3f3cSopenharmony_ci * caused by things like 'more foobar &' which will 1210c84f3f3cSopenharmony_ci * typically get and save the shell's vi/emacs tty 1211c84f3f3cSopenharmony_ci * settings before setting up the tty for itself; 1212c84f3f3cSopenharmony_ci * when more exits, it restores the 'original' 1213c84f3f3cSopenharmony_ci * settings, and things go down hill from there... 1214c84f3f3cSopenharmony_ci */ 1215c84f3f3cSopenharmony_ci if (j->state == PEXITED && j->status == 0 && 1216c84f3f3cSopenharmony_ci (j->flags & JF_USETTYMODE)) { 1217c84f3f3cSopenharmony_ci mksh_tcget(tty_fd, &tty_state); 1218c84f3f3cSopenharmony_ci } else { 1219c84f3f3cSopenharmony_ci mksh_tcset(tty_fd, &tty_state); 1220c84f3f3cSopenharmony_ci /*- 1221c84f3f3cSopenharmony_ci * Don't use tty mode if job is stopped and 1222c84f3f3cSopenharmony_ci * later restarted and exits. Consider 1223c84f3f3cSopenharmony_ci * the sequence: 1224c84f3f3cSopenharmony_ci * vi foo (stopped) 1225c84f3f3cSopenharmony_ci * ... 1226c84f3f3cSopenharmony_ci * stty something 1227c84f3f3cSopenharmony_ci * ... 1228c84f3f3cSopenharmony_ci * fg (vi; ZZ) 1229c84f3f3cSopenharmony_ci * mode should be that of the stty, not what 1230c84f3f3cSopenharmony_ci * was before the vi started. 1231c84f3f3cSopenharmony_ci */ 1232c84f3f3cSopenharmony_ci if (j->state == PSTOPPED) 1233c84f3f3cSopenharmony_ci j->flags &= ~JF_USETTYMODE; 1234c84f3f3cSopenharmony_ci } 1235c84f3f3cSopenharmony_ci } 1236c84f3f3cSopenharmony_ci#ifndef MKSH_UNEMPLOYED 1237c84f3f3cSopenharmony_ci /* 1238c84f3f3cSopenharmony_ci * If it looks like user hit ^C to kill a job, pretend we got 1239c84f3f3cSopenharmony_ci * one too to break out of for loops, etc. (AT&T ksh does this 1240c84f3f3cSopenharmony_ci * even when not monitoring, but this doesn't make sense since 1241c84f3f3cSopenharmony_ci * a tty generated ^C goes to the whole process group) 1242c84f3f3cSopenharmony_ci */ 1243c84f3f3cSopenharmony_ci if (Flag(FMONITOR) && j->state == PSIGNALLED && 1244c84f3f3cSopenharmony_ci WIFSIGNALED(j->last_proc->status)) { 1245c84f3f3cSopenharmony_ci int termsig; 1246c84f3f3cSopenharmony_ci 1247c84f3f3cSopenharmony_ci if ((termsig = WTERMSIG(j->last_proc->status)) > 0 && 1248c84f3f3cSopenharmony_ci termsig < ksh_NSIG && 1249c84f3f3cSopenharmony_ci (sigtraps[termsig].flags & TF_TTY_INTR)) 1250c84f3f3cSopenharmony_ci trapsig(termsig); 1251c84f3f3cSopenharmony_ci } 1252c84f3f3cSopenharmony_ci#endif 1253c84f3f3cSopenharmony_ci } 1254c84f3f3cSopenharmony_ci 1255c84f3f3cSopenharmony_ci j_usrtime = j->usrtime; 1256c84f3f3cSopenharmony_ci j_systime = j->systime; 1257c84f3f3cSopenharmony_ci rv = j->status; 1258c84f3f3cSopenharmony_ci 1259c84f3f3cSopenharmony_ci if (!(p = j->proc_list)) { 1260c84f3f3cSopenharmony_ci ; /* nothing */ 1261c84f3f3cSopenharmony_ci } else if (flags & JW_PIPEST) { 1262c84f3f3cSopenharmony_ci uint32_t num = 0; 1263c84f3f3cSopenharmony_ci struct tbl *vp; 1264c84f3f3cSopenharmony_ci 1265c84f3f3cSopenharmony_ci unset(vp_pipest, 1); 1266c84f3f3cSopenharmony_ci vp = vp_pipest; 1267c84f3f3cSopenharmony_ci vp->flag = DEFINED | ISSET | INTEGER | RDONLY | ARRAY | INT_U; 1268c84f3f3cSopenharmony_ci goto got_array; 1269c84f3f3cSopenharmony_ci 1270c84f3f3cSopenharmony_ci while (p != NULL) { 1271c84f3f3cSopenharmony_ci { 1272c84f3f3cSopenharmony_ci struct tbl *vq; 1273c84f3f3cSopenharmony_ci 1274c84f3f3cSopenharmony_ci /* strlen(vp_pipest->name) == 10 */ 1275c84f3f3cSopenharmony_ci vq = alloc(offsetof(struct tbl, name[0]) + 11, 1276c84f3f3cSopenharmony_ci vp_pipest->areap); 1277c84f3f3cSopenharmony_ci memset(vq, 0, offsetof(struct tbl, name[0])); 1278c84f3f3cSopenharmony_ci memcpy(vq->name, vp_pipest->name, 11); 1279c84f3f3cSopenharmony_ci vp->u.array = vq; 1280c84f3f3cSopenharmony_ci vp = vq; 1281c84f3f3cSopenharmony_ci } 1282c84f3f3cSopenharmony_ci vp->areap = vp_pipest->areap; 1283c84f3f3cSopenharmony_ci vp->ua.index = ++num; 1284c84f3f3cSopenharmony_ci vp->flag = DEFINED | ISSET | INTEGER | RDONLY | 1285c84f3f3cSopenharmony_ci ARRAY | INT_U | AINDEX; 1286c84f3f3cSopenharmony_ci got_array: 1287c84f3f3cSopenharmony_ci vp->val.i = proc_errorlevel(p); 1288c84f3f3cSopenharmony_ci if (Flag(FPIPEFAIL) && vp->val.i) 1289c84f3f3cSopenharmony_ci rv = vp->val.i; 1290c84f3f3cSopenharmony_ci p = p->next; 1291c84f3f3cSopenharmony_ci } 1292c84f3f3cSopenharmony_ci } else if (Flag(FPIPEFAIL)) { 1293c84f3f3cSopenharmony_ci do { 1294c84f3f3cSopenharmony_ci const int i = proc_errorlevel(p); 1295c84f3f3cSopenharmony_ci 1296c84f3f3cSopenharmony_ci if (i) 1297c84f3f3cSopenharmony_ci rv = i; 1298c84f3f3cSopenharmony_ci } while ((p = p->next)); 1299c84f3f3cSopenharmony_ci } 1300c84f3f3cSopenharmony_ci 1301c84f3f3cSopenharmony_ci if (!(flags & JW_ASYNCNOTIFY) 1302c84f3f3cSopenharmony_ci#ifndef MKSH_UNEMPLOYED 1303c84f3f3cSopenharmony_ci && (!Flag(FMONITOR) || j->state != PSTOPPED) 1304c84f3f3cSopenharmony_ci#endif 1305c84f3f3cSopenharmony_ci ) { 1306c84f3f3cSopenharmony_ci j_print(j, JP_SHORT, shl_out); 1307c84f3f3cSopenharmony_ci shf_flush(shl_out); 1308c84f3f3cSopenharmony_ci } 1309c84f3f3cSopenharmony_ci if (j->state != PSTOPPED 1310c84f3f3cSopenharmony_ci#ifndef MKSH_UNEMPLOYED 1311c84f3f3cSopenharmony_ci && (!Flag(FMONITOR) || !(flags & JW_ASYNCNOTIFY)) 1312c84f3f3cSopenharmony_ci#endif 1313c84f3f3cSopenharmony_ci ) 1314c84f3f3cSopenharmony_ci remove_job(j, where); 1315c84f3f3cSopenharmony_ci 1316c84f3f3cSopenharmony_ci return (rv); 1317c84f3f3cSopenharmony_ci} 1318c84f3f3cSopenharmony_ci 1319c84f3f3cSopenharmony_ci/* 1320c84f3f3cSopenharmony_ci * SIGCHLD handler to reap children and update job states 1321c84f3f3cSopenharmony_ci * 1322c84f3f3cSopenharmony_ci * If jobs are compiled in then this routine expects sigchld to be blocked. 1323c84f3f3cSopenharmony_ci */ 1324c84f3f3cSopenharmony_ci/* ARGSUSED */ 1325c84f3f3cSopenharmony_cistatic void 1326c84f3f3cSopenharmony_cij_sigchld(int sig MKSH_A_UNUSED) 1327c84f3f3cSopenharmony_ci{ 1328c84f3f3cSopenharmony_ci int saved_errno = errno; 1329c84f3f3cSopenharmony_ci Job *j; 1330c84f3f3cSopenharmony_ci Proc *p = NULL; 1331c84f3f3cSopenharmony_ci pid_t pid; 1332c84f3f3cSopenharmony_ci int status; 1333c84f3f3cSopenharmony_ci struct rusage ru0, ru1; 1334c84f3f3cSopenharmony_ci#ifdef MKSH_NO_SIGSUSPEND 1335c84f3f3cSopenharmony_ci sigset_t omask; 1336c84f3f3cSopenharmony_ci 1337c84f3f3cSopenharmony_ci /* this handler can run while SIGCHLD is not blocked, so block it now */ 1338c84f3f3cSopenharmony_ci sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); 1339c84f3f3cSopenharmony_ci#endif 1340c84f3f3cSopenharmony_ci 1341c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 1342c84f3f3cSopenharmony_ci /* 1343c84f3f3cSopenharmony_ci * Don't wait for any processes if a job is partially started. 1344c84f3f3cSopenharmony_ci * This is so we don't do away with the process group leader 1345c84f3f3cSopenharmony_ci * before all the processes in a pipe line are started (so the 1346c84f3f3cSopenharmony_ci * setpgid() won't fail) 1347c84f3f3cSopenharmony_ci */ 1348c84f3f3cSopenharmony_ci for (j = job_list; j; j = j->next) 1349c84f3f3cSopenharmony_ci if (j->ppid == procpid && !(j->flags & JF_STARTED)) { 1350c84f3f3cSopenharmony_ci held_sigchld = 1; 1351c84f3f3cSopenharmony_ci goto j_sigchld_out; 1352c84f3f3cSopenharmony_ci } 1353c84f3f3cSopenharmony_ci#endif 1354c84f3f3cSopenharmony_ci 1355c84f3f3cSopenharmony_ci getrusage(RUSAGE_CHILDREN, &ru0); 1356c84f3f3cSopenharmony_ci do { 1357c84f3f3cSopenharmony_ci#ifdef ADAPT_FOR_LITEOS_A 1358c84f3f3cSopenharmony_ci pid = waitpid(-1, &status, WNOHANG); 1359c84f3f3cSopenharmony_ci#else // ADAPT_FOR_LITEOS_A 1360c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 1361c84f3f3cSopenharmony_ci pid = waitpid(-1, &status, (WNOHANG | 1362c84f3f3cSopenharmony_ci#if defined(WCONTINUED) && defined(WIFCONTINUED) 1363c84f3f3cSopenharmony_ci WCONTINUED | 1364c84f3f3cSopenharmony_ci#endif 1365c84f3f3cSopenharmony_ci WUNTRACED)); 1366c84f3f3cSopenharmony_ci#else 1367c84f3f3cSopenharmony_ci pid = wait(&status); 1368c84f3f3cSopenharmony_ci#endif 1369c84f3f3cSopenharmony_ci#endif // ADAPT_FOR_LITEOS_A 1370c84f3f3cSopenharmony_ci 1371c84f3f3cSopenharmony_ci /* 1372c84f3f3cSopenharmony_ci * return if this would block (0) or no children 1373c84f3f3cSopenharmony_ci * or interrupted (-1) 1374c84f3f3cSopenharmony_ci */ 1375c84f3f3cSopenharmony_ci if (pid <= 0) 1376c84f3f3cSopenharmony_ci goto j_sigchld_out; 1377c84f3f3cSopenharmony_ci 1378c84f3f3cSopenharmony_ci getrusage(RUSAGE_CHILDREN, &ru1); 1379c84f3f3cSopenharmony_ci 1380c84f3f3cSopenharmony_ci /* find job and process structures for this pid */ 1381c84f3f3cSopenharmony_ci for (j = job_list; j != NULL; j = j->next) 1382c84f3f3cSopenharmony_ci for (p = j->proc_list; p != NULL; p = p->next) 1383c84f3f3cSopenharmony_ci if (p->pid == pid) 1384c84f3f3cSopenharmony_ci goto found; 1385c84f3f3cSopenharmony_ci found: 1386c84f3f3cSopenharmony_ci if (j == NULL) { 1387c84f3f3cSopenharmony_ci /* Can occur if process has kids, then execs shell 1388c84f3f3cSopenharmony_ci warningf(true, "bad process waited for (pid = %d)", 1389c84f3f3cSopenharmony_ci pid); 1390c84f3f3cSopenharmony_ci */ 1391c84f3f3cSopenharmony_ci ru0 = ru1; 1392c84f3f3cSopenharmony_ci continue; 1393c84f3f3cSopenharmony_ci } 1394c84f3f3cSopenharmony_ci 1395c84f3f3cSopenharmony_ci timeradd(&j->usrtime, &ru1.ru_utime, &j->usrtime); 1396c84f3f3cSopenharmony_ci timersub(&j->usrtime, &ru0.ru_utime, &j->usrtime); 1397c84f3f3cSopenharmony_ci timeradd(&j->systime, &ru1.ru_stime, &j->systime); 1398c84f3f3cSopenharmony_ci timersub(&j->systime, &ru0.ru_stime, &j->systime); 1399c84f3f3cSopenharmony_ci ru0 = ru1; 1400c84f3f3cSopenharmony_ci p->status = status; 1401c84f3f3cSopenharmony_ci#ifndef MKSH_UNEMPLOYED 1402c84f3f3cSopenharmony_ci if (WIFSTOPPED(status)) 1403c84f3f3cSopenharmony_ci p->state = PSTOPPED; 1404c84f3f3cSopenharmony_ci else 1405c84f3f3cSopenharmony_ci#if defined(WCONTINUED) && defined(WIFCONTINUED) 1406c84f3f3cSopenharmony_ci if (WIFCONTINUED(status)) { 1407c84f3f3cSopenharmony_ci p->state = j->state = PRUNNING; 1408c84f3f3cSopenharmony_ci /* skip check_job(), no-op in this case */ 1409c84f3f3cSopenharmony_ci continue; 1410c84f3f3cSopenharmony_ci } else 1411c84f3f3cSopenharmony_ci#endif 1412c84f3f3cSopenharmony_ci#endif 1413c84f3f3cSopenharmony_ci if (WIFSIGNALED(status)) 1414c84f3f3cSopenharmony_ci p->state = PSIGNALLED; 1415c84f3f3cSopenharmony_ci else 1416c84f3f3cSopenharmony_ci p->state = PEXITED; 1417c84f3f3cSopenharmony_ci 1418c84f3f3cSopenharmony_ci /* check to see if entire job is done */ 1419c84f3f3cSopenharmony_ci check_job(j); 1420c84f3f3cSopenharmony_ci } 1421c84f3f3cSopenharmony_ci#ifndef MKSH_NOPROSPECTOFWORK 1422c84f3f3cSopenharmony_ci while (/* CONSTCOND */ 1); 1423c84f3f3cSopenharmony_ci#else 1424c84f3f3cSopenharmony_ci while (/* CONSTCOND */ 0); 1425c84f3f3cSopenharmony_ci#endif 1426c84f3f3cSopenharmony_ci 1427c84f3f3cSopenharmony_ci j_sigchld_out: 1428c84f3f3cSopenharmony_ci#ifdef MKSH_NO_SIGSUSPEND 1429c84f3f3cSopenharmony_ci sigprocmask(SIG_SETMASK, &omask, NULL); 1430c84f3f3cSopenharmony_ci#endif 1431c84f3f3cSopenharmony_ci errno = saved_errno; 1432c84f3f3cSopenharmony_ci} 1433c84f3f3cSopenharmony_ci 1434c84f3f3cSopenharmony_ci/* 1435c84f3f3cSopenharmony_ci * Called only when a process in j has exited/stopped (ie, called only 1436c84f3f3cSopenharmony_ci * from j_sigchld()). If no processes are running, the job status 1437c84f3f3cSopenharmony_ci * and state are updated, asynchronous job notification is done and, 1438c84f3f3cSopenharmony_ci * if unneeded, the job is removed. 1439c84f3f3cSopenharmony_ci * 1440c84f3f3cSopenharmony_ci * If jobs are compiled in then this routine expects sigchld to be blocked. 1441c84f3f3cSopenharmony_ci */ 1442c84f3f3cSopenharmony_cistatic void 1443c84f3f3cSopenharmony_cicheck_job(Job *j) 1444c84f3f3cSopenharmony_ci{ 1445c84f3f3cSopenharmony_ci int jstate; 1446c84f3f3cSopenharmony_ci Proc *p; 1447c84f3f3cSopenharmony_ci 1448c84f3f3cSopenharmony_ci /* XXX debugging (nasty - interrupt routine using shl_out) */ 1449c84f3f3cSopenharmony_ci if (!(j->flags & JF_STARTED)) { 1450c84f3f3cSopenharmony_ci internal_warningf("check_job: job started (flags 0x%X)", 1451c84f3f3cSopenharmony_ci (unsigned int)j->flags); 1452c84f3f3cSopenharmony_ci return; 1453c84f3f3cSopenharmony_ci } 1454c84f3f3cSopenharmony_ci 1455c84f3f3cSopenharmony_ci jstate = PRUNNING; 1456c84f3f3cSopenharmony_ci for (p=j->proc_list; p != NULL; p = p->next) { 1457c84f3f3cSopenharmony_ci if (p->state == PRUNNING) 1458c84f3f3cSopenharmony_ci /* some processes still running */ 1459c84f3f3cSopenharmony_ci return; 1460c84f3f3cSopenharmony_ci if (p->state > jstate) 1461c84f3f3cSopenharmony_ci jstate = p->state; 1462c84f3f3cSopenharmony_ci } 1463c84f3f3cSopenharmony_ci j->state = jstate; 1464c84f3f3cSopenharmony_ci j->status = proc_errorlevel(j->last_proc); 1465c84f3f3cSopenharmony_ci 1466c84f3f3cSopenharmony_ci /* 1467c84f3f3cSopenharmony_ci * Note when co-process dies: can't be done in j_wait() nor 1468c84f3f3cSopenharmony_ci * remove_job() since neither may be called for non-interactive 1469c84f3f3cSopenharmony_ci * shells. 1470c84f3f3cSopenharmony_ci */ 1471c84f3f3cSopenharmony_ci if (j->state == PEXITED || j->state == PSIGNALLED) { 1472c84f3f3cSopenharmony_ci /* 1473c84f3f3cSopenharmony_ci * No need to keep co-process input any more 1474c84f3f3cSopenharmony_ci * (at least, this is what ksh93d thinks) 1475c84f3f3cSopenharmony_ci */ 1476c84f3f3cSopenharmony_ci if (coproc.job == j) { 1477c84f3f3cSopenharmony_ci coproc.job = NULL; 1478c84f3f3cSopenharmony_ci /* 1479c84f3f3cSopenharmony_ci * XXX would be nice to get the closes out of here 1480c84f3f3cSopenharmony_ci * so they aren't done in the signal handler. 1481c84f3f3cSopenharmony_ci * Would mean a check in coproc_getfd() to 1482c84f3f3cSopenharmony_ci * do "if job == 0 && write >= 0, close write". 1483c84f3f3cSopenharmony_ci */ 1484c84f3f3cSopenharmony_ci coproc_write_close(coproc.write); 1485c84f3f3cSopenharmony_ci } 1486c84f3f3cSopenharmony_ci /* Do we need to keep the output? */ 1487c84f3f3cSopenharmony_ci if (j->coproc_id && j->coproc_id == coproc.id && 1488c84f3f3cSopenharmony_ci --coproc.njobs == 0) 1489c84f3f3cSopenharmony_ci coproc_readw_close(coproc.read); 1490c84f3f3cSopenharmony_ci } 1491c84f3f3cSopenharmony_ci 1492c84f3f3cSopenharmony_ci j->flags |= JF_CHANGED; 1493c84f3f3cSopenharmony_ci#ifndef MKSH_UNEMPLOYED 1494c84f3f3cSopenharmony_ci if (Flag(FMONITOR) && !(j->flags & JF_XXCOM)) { 1495c84f3f3cSopenharmony_ci /* 1496c84f3f3cSopenharmony_ci * Only put stopped jobs at the front to avoid confusing 1497c84f3f3cSopenharmony_ci * the user (don't want finished jobs effecting %+ or %-) 1498c84f3f3cSopenharmony_ci */ 1499c84f3f3cSopenharmony_ci if (j->state == PSTOPPED) 1500c84f3f3cSopenharmony_ci put_job(j, PJ_ON_FRONT); 1501c84f3f3cSopenharmony_ci if (Flag(FNOTIFY) && 1502c84f3f3cSopenharmony_ci (j->flags & (JF_WAITING|JF_W_ASYNCNOTIFY)) != JF_WAITING) { 1503c84f3f3cSopenharmony_ci /* Look for the real file descriptor 2 */ 1504c84f3f3cSopenharmony_ci { 1505c84f3f3cSopenharmony_ci struct env *ep; 1506c84f3f3cSopenharmony_ci int fd = 2; 1507c84f3f3cSopenharmony_ci 1508c84f3f3cSopenharmony_ci for (ep = e; ep; ep = ep->oenv) 1509c84f3f3cSopenharmony_ci if (ep->savefd && ep->savefd[2]) 1510c84f3f3cSopenharmony_ci fd = ep->savefd[2]; 1511c84f3f3cSopenharmony_ci shf_reopen(fd, SHF_WR, shl_j); 1512c84f3f3cSopenharmony_ci } 1513c84f3f3cSopenharmony_ci /* 1514c84f3f3cSopenharmony_ci * Can't call j_notify() as it removes jobs. The job 1515c84f3f3cSopenharmony_ci * must stay in the job list as j_waitj() may be 1516c84f3f3cSopenharmony_ci * running with this job. 1517c84f3f3cSopenharmony_ci */ 1518c84f3f3cSopenharmony_ci j_print(j, JP_MEDIUM, shl_j); 1519c84f3f3cSopenharmony_ci shf_flush(shl_j); 1520c84f3f3cSopenharmony_ci if (!(j->flags & JF_WAITING) && j->state != PSTOPPED) 1521c84f3f3cSopenharmony_ci remove_job(j, "notify"); 1522c84f3f3cSopenharmony_ci } 1523c84f3f3cSopenharmony_ci } 1524c84f3f3cSopenharmony_ci#endif 1525c84f3f3cSopenharmony_ci if ( 1526c84f3f3cSopenharmony_ci#ifndef MKSH_UNEMPLOYED 1527c84f3f3cSopenharmony_ci !Flag(FMONITOR) && 1528c84f3f3cSopenharmony_ci#endif 1529c84f3f3cSopenharmony_ci !(j->flags & (JF_WAITING|JF_FG)) && 1530c84f3f3cSopenharmony_ci j->state != PSTOPPED) { 1531c84f3f3cSopenharmony_ci if (j == async_job || (j->flags & JF_KNOWN)) { 1532c84f3f3cSopenharmony_ci j->flags |= JF_ZOMBIE; 1533c84f3f3cSopenharmony_ci j->job = -1; 1534c84f3f3cSopenharmony_ci nzombie++; 1535c84f3f3cSopenharmony_ci } else 1536c84f3f3cSopenharmony_ci remove_job(j, "checkjob"); 1537c84f3f3cSopenharmony_ci } 1538c84f3f3cSopenharmony_ci} 1539c84f3f3cSopenharmony_ci 1540c84f3f3cSopenharmony_ci/* 1541c84f3f3cSopenharmony_ci * Print job status in either short, medium or long format. 1542c84f3f3cSopenharmony_ci * 1543c84f3f3cSopenharmony_ci * If jobs are compiled in then this routine expects sigchld to be blocked. 1544c84f3f3cSopenharmony_ci */ 1545c84f3f3cSopenharmony_cistatic void 1546c84f3f3cSopenharmony_cij_print(Job *j, int how, struct shf *shf) 1547c84f3f3cSopenharmony_ci{ 1548c84f3f3cSopenharmony_ci Proc *p; 1549c84f3f3cSopenharmony_ci int state; 1550c84f3f3cSopenharmony_ci int status; 1551c84f3f3cSopenharmony_ci#ifdef WCOREDUMP 1552c84f3f3cSopenharmony_ci bool coredumped; 1553c84f3f3cSopenharmony_ci#endif 1554c84f3f3cSopenharmony_ci char jobchar = ' '; 1555c84f3f3cSopenharmony_ci char buf[64]; 1556c84f3f3cSopenharmony_ci const char *filler; 1557c84f3f3cSopenharmony_ci int output = 0; 1558c84f3f3cSopenharmony_ci 1559c84f3f3cSopenharmony_ci if (how == JP_PGRP) { 1560c84f3f3cSopenharmony_ci /* 1561c84f3f3cSopenharmony_ci * POSIX doesn't say what to do it there is no process 1562c84f3f3cSopenharmony_ci * group leader (ie, !FMONITOR). We arbitrarily return 1563c84f3f3cSopenharmony_ci * last pid (which is what $! returns). 1564c84f3f3cSopenharmony_ci */ 1565c84f3f3cSopenharmony_ci shf_fprintf(shf, Tf_dN, (int)(j->pgrp ? j->pgrp : 1566c84f3f3cSopenharmony_ci (j->last_proc ? j->last_proc->pid : 0))); 1567c84f3f3cSopenharmony_ci return; 1568c84f3f3cSopenharmony_ci } 1569c84f3f3cSopenharmony_ci j->flags &= ~JF_CHANGED; 1570c84f3f3cSopenharmony_ci filler = j->job > 10 ? "\n " : "\n "; 1571c84f3f3cSopenharmony_ci if (j == job_list) 1572c84f3f3cSopenharmony_ci jobchar = '+'; 1573c84f3f3cSopenharmony_ci else if (j == job_list->next) 1574c84f3f3cSopenharmony_ci jobchar = '-'; 1575c84f3f3cSopenharmony_ci 1576c84f3f3cSopenharmony_ci for (p = j->proc_list; p != NULL;) { 1577c84f3f3cSopenharmony_ci#ifdef WCOREDUMP 1578c84f3f3cSopenharmony_ci coredumped = false; 1579c84f3f3cSopenharmony_ci#endif 1580c84f3f3cSopenharmony_ci switch (p->state) { 1581c84f3f3cSopenharmony_ci case PRUNNING: 1582c84f3f3cSopenharmony_ci memcpy(buf, "Running", 8); 1583c84f3f3cSopenharmony_ci break; 1584c84f3f3cSopenharmony_ci case PSTOPPED: { 1585c84f3f3cSopenharmony_ci int stopsig = WSTOPSIG(p->status); 1586c84f3f3cSopenharmony_ci 1587c84f3f3cSopenharmony_ci strlcpy(buf, stopsig > 0 && stopsig < ksh_NSIG ? 1588c84f3f3cSopenharmony_ci sigtraps[stopsig].mess : "Stopped", sizeof(buf)); 1589c84f3f3cSopenharmony_ci break; 1590c84f3f3cSopenharmony_ci } 1591c84f3f3cSopenharmony_ci case PEXITED: { 1592c84f3f3cSopenharmony_ci int exitstatus = (WEXITSTATUS(p->status)) & 255; 1593c84f3f3cSopenharmony_ci 1594c84f3f3cSopenharmony_ci if (how == JP_SHORT) 1595c84f3f3cSopenharmony_ci buf[0] = '\0'; 1596c84f3f3cSopenharmony_ci else if (exitstatus == 0) 1597c84f3f3cSopenharmony_ci memcpy(buf, "Done", 5); 1598c84f3f3cSopenharmony_ci else 1599c84f3f3cSopenharmony_ci shf_snprintf(buf, sizeof(buf), "Done (%d)", 1600c84f3f3cSopenharmony_ci exitstatus); 1601c84f3f3cSopenharmony_ci break; 1602c84f3f3cSopenharmony_ci } 1603c84f3f3cSopenharmony_ci case PSIGNALLED: { 1604c84f3f3cSopenharmony_ci int termsig = WTERMSIG(p->status); 1605c84f3f3cSopenharmony_ci#ifdef WCOREDUMP 1606c84f3f3cSopenharmony_ci if (WCOREDUMP(p->status)) 1607c84f3f3cSopenharmony_ci coredumped = true; 1608c84f3f3cSopenharmony_ci#endif 1609c84f3f3cSopenharmony_ci /* 1610c84f3f3cSopenharmony_ci * kludge for not reporting 'normal termination 1611c84f3f3cSopenharmony_ci * signals' (i.e. SIGINT, SIGPIPE) 1612c84f3f3cSopenharmony_ci */ 1613c84f3f3cSopenharmony_ci if (how == JP_SHORT && 1614c84f3f3cSopenharmony_ci#ifdef WCOREDUMP 1615c84f3f3cSopenharmony_ci !coredumped && 1616c84f3f3cSopenharmony_ci#endif 1617c84f3f3cSopenharmony_ci (termsig == SIGINT || termsig == SIGPIPE)) { 1618c84f3f3cSopenharmony_ci buf[0] = '\0'; 1619c84f3f3cSopenharmony_ci } else 1620c84f3f3cSopenharmony_ci strlcpy(buf, termsig > 0 && termsig < ksh_NSIG ? 1621c84f3f3cSopenharmony_ci sigtraps[termsig].mess : "Signalled", 1622c84f3f3cSopenharmony_ci sizeof(buf)); 1623c84f3f3cSopenharmony_ci break; 1624c84f3f3cSopenharmony_ci } 1625c84f3f3cSopenharmony_ci default: 1626c84f3f3cSopenharmony_ci buf[0] = '\0'; 1627c84f3f3cSopenharmony_ci } 1628c84f3f3cSopenharmony_ci 1629c84f3f3cSopenharmony_ci if (how != JP_SHORT) { 1630c84f3f3cSopenharmony_ci if (p == j->proc_list) 1631c84f3f3cSopenharmony_ci shf_fprintf(shf, "[%d] %c ", j->job, jobchar); 1632c84f3f3cSopenharmony_ci else 1633c84f3f3cSopenharmony_ci shf_puts(filler, shf); 1634c84f3f3cSopenharmony_ci } 1635c84f3f3cSopenharmony_ci 1636c84f3f3cSopenharmony_ci if (how == JP_LONG) 1637c84f3f3cSopenharmony_ci shf_fprintf(shf, "%5d ", (int)p->pid); 1638c84f3f3cSopenharmony_ci 1639c84f3f3cSopenharmony_ci if (how == JP_SHORT) { 1640c84f3f3cSopenharmony_ci if (buf[0]) { 1641c84f3f3cSopenharmony_ci output = 1; 1642c84f3f3cSopenharmony_ci#ifdef WCOREDUMP 1643c84f3f3cSopenharmony_ci shf_fprintf(shf, "%s%s ", 1644c84f3f3cSopenharmony_ci buf, coredumped ? " (core dumped)" : null); 1645c84f3f3cSopenharmony_ci#else 1646c84f3f3cSopenharmony_ci shf_puts(buf, shf); 1647c84f3f3cSopenharmony_ci shf_putchar(' ', shf); 1648c84f3f3cSopenharmony_ci#endif 1649c84f3f3cSopenharmony_ci } 1650c84f3f3cSopenharmony_ci } else { 1651c84f3f3cSopenharmony_ci output = 1; 1652c84f3f3cSopenharmony_ci shf_fprintf(shf, "%-20s %s%s%s", buf, p->command, 1653c84f3f3cSopenharmony_ci p->next ? "|" : null, 1654c84f3f3cSopenharmony_ci#ifdef WCOREDUMP 1655c84f3f3cSopenharmony_ci coredumped ? " (core dumped)" : 1656c84f3f3cSopenharmony_ci#endif 1657c84f3f3cSopenharmony_ci null); 1658c84f3f3cSopenharmony_ci } 1659c84f3f3cSopenharmony_ci 1660c84f3f3cSopenharmony_ci state = p->state; 1661c84f3f3cSopenharmony_ci status = p->status; 1662c84f3f3cSopenharmony_ci p = p->next; 1663c84f3f3cSopenharmony_ci while (p && p->state == state && p->status == status) { 1664c84f3f3cSopenharmony_ci if (how == JP_LONG) 1665c84f3f3cSopenharmony_ci shf_fprintf(shf, "%s%5d %-20s %s%s", filler, 1666c84f3f3cSopenharmony_ci (int)p->pid, T1space, p->command, 1667c84f3f3cSopenharmony_ci p->next ? "|" : null); 1668c84f3f3cSopenharmony_ci else if (how == JP_MEDIUM) 1669c84f3f3cSopenharmony_ci shf_fprintf(shf, Tf__ss, p->command, 1670c84f3f3cSopenharmony_ci p->next ? "|" : null); 1671c84f3f3cSopenharmony_ci p = p->next; 1672c84f3f3cSopenharmony_ci } 1673c84f3f3cSopenharmony_ci } 1674c84f3f3cSopenharmony_ci if (output) 1675c84f3f3cSopenharmony_ci shf_putc('\n', shf); 1676c84f3f3cSopenharmony_ci} 1677c84f3f3cSopenharmony_ci 1678c84f3f3cSopenharmony_ci/* 1679c84f3f3cSopenharmony_ci * Convert % sequence to job 1680c84f3f3cSopenharmony_ci * 1681c84f3f3cSopenharmony_ci * If jobs are compiled in then this routine expects sigchld to be blocked. 1682c84f3f3cSopenharmony_ci */ 1683c84f3f3cSopenharmony_cistatic Job * 1684c84f3f3cSopenharmony_cij_lookup(const char *cp, int *ecodep) 1685c84f3f3cSopenharmony_ci{ 1686c84f3f3cSopenharmony_ci Job *j, *last_match; 1687c84f3f3cSopenharmony_ci Proc *p; 1688c84f3f3cSopenharmony_ci size_t len; 1689c84f3f3cSopenharmony_ci int job = 0; 1690c84f3f3cSopenharmony_ci 1691c84f3f3cSopenharmony_ci if (ctype(*cp, C_DIGIT) && getn(cp, &job)) { 1692c84f3f3cSopenharmony_ci /* Look for last_proc->pid (what $! returns) first... */ 1693c84f3f3cSopenharmony_ci for (j = job_list; j != NULL; j = j->next) 1694c84f3f3cSopenharmony_ci if (j->last_proc && j->last_proc->pid == job) 1695c84f3f3cSopenharmony_ci return (j); 1696c84f3f3cSopenharmony_ci /* 1697c84f3f3cSopenharmony_ci * ...then look for process group (this is non-POSIX, 1698c84f3f3cSopenharmony_ci * but should not break anything 1699c84f3f3cSopenharmony_ci */ 1700c84f3f3cSopenharmony_ci for (j = job_list; j != NULL; j = j->next) 1701c84f3f3cSopenharmony_ci if (j->pgrp && j->pgrp == job) 1702c84f3f3cSopenharmony_ci return (j); 1703c84f3f3cSopenharmony_ci goto j_lookup_nosuch; 1704c84f3f3cSopenharmony_ci } 1705c84f3f3cSopenharmony_ci if (*cp != '%') { 1706c84f3f3cSopenharmony_ci j_lookup_invalid: 1707c84f3f3cSopenharmony_ci if (ecodep) 1708c84f3f3cSopenharmony_ci *ecodep = JL_INVALID; 1709c84f3f3cSopenharmony_ci return (NULL); 1710c84f3f3cSopenharmony_ci } 1711c84f3f3cSopenharmony_ci switch (*++cp) { 1712c84f3f3cSopenharmony_ci case '\0': /* non-standard */ 1713c84f3f3cSopenharmony_ci case '+': 1714c84f3f3cSopenharmony_ci case '%': 1715c84f3f3cSopenharmony_ci if (job_list != NULL) 1716c84f3f3cSopenharmony_ci return (job_list); 1717c84f3f3cSopenharmony_ci break; 1718c84f3f3cSopenharmony_ci 1719c84f3f3cSopenharmony_ci case '-': 1720c84f3f3cSopenharmony_ci if (job_list != NULL && job_list->next) 1721c84f3f3cSopenharmony_ci return (job_list->next); 1722c84f3f3cSopenharmony_ci break; 1723c84f3f3cSopenharmony_ci 1724c84f3f3cSopenharmony_ci case '0': case '1': case '2': case '3': case '4': 1725c84f3f3cSopenharmony_ci case '5': case '6': case '7': case '8': case '9': 1726c84f3f3cSopenharmony_ci if (!getn(cp, &job)) 1727c84f3f3cSopenharmony_ci goto j_lookup_invalid; 1728c84f3f3cSopenharmony_ci for (j = job_list; j != NULL; j = j->next) 1729c84f3f3cSopenharmony_ci if (j->job == job) 1730c84f3f3cSopenharmony_ci return (j); 1731c84f3f3cSopenharmony_ci break; 1732c84f3f3cSopenharmony_ci 1733c84f3f3cSopenharmony_ci /* %?string */ 1734c84f3f3cSopenharmony_ci case '?': 1735c84f3f3cSopenharmony_ci last_match = NULL; 1736c84f3f3cSopenharmony_ci for (j = job_list; j != NULL; j = j->next) 1737c84f3f3cSopenharmony_ci for (p = j->proc_list; p != NULL; p = p->next) 1738c84f3f3cSopenharmony_ci if (strstr(p->command, cp+1) != NULL) { 1739c84f3f3cSopenharmony_ci if (last_match) { 1740c84f3f3cSopenharmony_ci if (ecodep) 1741c84f3f3cSopenharmony_ci *ecodep = JL_AMBIG; 1742c84f3f3cSopenharmony_ci return (NULL); 1743c84f3f3cSopenharmony_ci } 1744c84f3f3cSopenharmony_ci last_match = j; 1745c84f3f3cSopenharmony_ci } 1746c84f3f3cSopenharmony_ci if (last_match) 1747c84f3f3cSopenharmony_ci return (last_match); 1748c84f3f3cSopenharmony_ci break; 1749c84f3f3cSopenharmony_ci 1750c84f3f3cSopenharmony_ci /* %string */ 1751c84f3f3cSopenharmony_ci default: 1752c84f3f3cSopenharmony_ci len = strlen(cp); 1753c84f3f3cSopenharmony_ci last_match = NULL; 1754c84f3f3cSopenharmony_ci for (j = job_list; j != NULL; j = j->next) 1755c84f3f3cSopenharmony_ci if (strncmp(cp, j->proc_list->command, len) == 0) { 1756c84f3f3cSopenharmony_ci if (last_match) { 1757c84f3f3cSopenharmony_ci if (ecodep) 1758c84f3f3cSopenharmony_ci *ecodep = JL_AMBIG; 1759c84f3f3cSopenharmony_ci return (NULL); 1760c84f3f3cSopenharmony_ci } 1761c84f3f3cSopenharmony_ci last_match = j; 1762c84f3f3cSopenharmony_ci } 1763c84f3f3cSopenharmony_ci if (last_match) 1764c84f3f3cSopenharmony_ci return (last_match); 1765c84f3f3cSopenharmony_ci break; 1766c84f3f3cSopenharmony_ci } 1767c84f3f3cSopenharmony_ci j_lookup_nosuch: 1768c84f3f3cSopenharmony_ci if (ecodep) 1769c84f3f3cSopenharmony_ci *ecodep = JL_NOSUCH; 1770c84f3f3cSopenharmony_ci return (NULL); 1771c84f3f3cSopenharmony_ci} 1772c84f3f3cSopenharmony_ci 1773c84f3f3cSopenharmony_cistatic Job *free_jobs; 1774c84f3f3cSopenharmony_cistatic Proc *free_procs; 1775c84f3f3cSopenharmony_ci 1776c84f3f3cSopenharmony_ci/* 1777c84f3f3cSopenharmony_ci * allocate a new job and fill in the job number. 1778c84f3f3cSopenharmony_ci * 1779c84f3f3cSopenharmony_ci * If jobs are compiled in then this routine expects sigchld to be blocked. 1780c84f3f3cSopenharmony_ci */ 1781c84f3f3cSopenharmony_cistatic Job * 1782c84f3f3cSopenharmony_cinew_job(void) 1783c84f3f3cSopenharmony_ci{ 1784c84f3f3cSopenharmony_ci int i; 1785c84f3f3cSopenharmony_ci Job *newj, *j; 1786c84f3f3cSopenharmony_ci 1787c84f3f3cSopenharmony_ci if (free_jobs != NULL) { 1788c84f3f3cSopenharmony_ci newj = free_jobs; 1789c84f3f3cSopenharmony_ci free_jobs = free_jobs->next; 1790c84f3f3cSopenharmony_ci } else { 1791c84f3f3cSopenharmony_ci char *cp; 1792c84f3f3cSopenharmony_ci 1793c84f3f3cSopenharmony_ci /* 1794c84f3f3cSopenharmony_ci * struct job includes ALLOC_ITEM for alignment constraints 1795c84f3f3cSopenharmony_ci * so first get the actually used memory, then assign it 1796c84f3f3cSopenharmony_ci */ 1797c84f3f3cSopenharmony_ci cp = alloc(sizeof(Job) - sizeof(ALLOC_ITEM), APERM); 1798c84f3f3cSopenharmony_ci /* undo what alloc() did to the malloc result address */ 1799c84f3f3cSopenharmony_ci newj = (void *)(cp - sizeof(ALLOC_ITEM)); 1800c84f3f3cSopenharmony_ci } 1801c84f3f3cSopenharmony_ci 1802c84f3f3cSopenharmony_ci /* brute force method */ 1803c84f3f3cSopenharmony_ci i = 0; 1804c84f3f3cSopenharmony_ci do { 1805c84f3f3cSopenharmony_ci ++i; 1806c84f3f3cSopenharmony_ci j = job_list; 1807c84f3f3cSopenharmony_ci while (j && j->job != i) 1808c84f3f3cSopenharmony_ci j = j->next; 1809c84f3f3cSopenharmony_ci } while (j); 1810c84f3f3cSopenharmony_ci newj->job = i; 1811c84f3f3cSopenharmony_ci 1812c84f3f3cSopenharmony_ci return (newj); 1813c84f3f3cSopenharmony_ci} 1814c84f3f3cSopenharmony_ci 1815c84f3f3cSopenharmony_ci/* 1816c84f3f3cSopenharmony_ci * Allocate new process struct 1817c84f3f3cSopenharmony_ci * 1818c84f3f3cSopenharmony_ci * If jobs are compiled in then this routine expects sigchld to be blocked. 1819c84f3f3cSopenharmony_ci */ 1820c84f3f3cSopenharmony_cistatic Proc * 1821c84f3f3cSopenharmony_cinew_proc(void) 1822c84f3f3cSopenharmony_ci{ 1823c84f3f3cSopenharmony_ci Proc *p; 1824c84f3f3cSopenharmony_ci 1825c84f3f3cSopenharmony_ci if (free_procs != NULL) { 1826c84f3f3cSopenharmony_ci p = free_procs; 1827c84f3f3cSopenharmony_ci free_procs = free_procs->next; 1828c84f3f3cSopenharmony_ci } else 1829c84f3f3cSopenharmony_ci p = alloc(sizeof(Proc), APERM); 1830c84f3f3cSopenharmony_ci 1831c84f3f3cSopenharmony_ci return (p); 1832c84f3f3cSopenharmony_ci} 1833c84f3f3cSopenharmony_ci 1834c84f3f3cSopenharmony_ci/* 1835c84f3f3cSopenharmony_ci * Take job out of job_list and put old structures into free list. 1836c84f3f3cSopenharmony_ci * Keeps nzombies, last_job and async_job up to date. 1837c84f3f3cSopenharmony_ci * 1838c84f3f3cSopenharmony_ci * If jobs are compiled in then this routine expects sigchld to be blocked. 1839c84f3f3cSopenharmony_ci */ 1840c84f3f3cSopenharmony_cistatic void 1841c84f3f3cSopenharmony_ciremove_job(Job *j, const char *where) 1842c84f3f3cSopenharmony_ci{ 1843c84f3f3cSopenharmony_ci Proc *p, *tmp; 1844c84f3f3cSopenharmony_ci Job **prev, *curr; 1845c84f3f3cSopenharmony_ci 1846c84f3f3cSopenharmony_ci prev = &job_list; 1847c84f3f3cSopenharmony_ci curr = job_list; 1848c84f3f3cSopenharmony_ci while (curr && curr != j) { 1849c84f3f3cSopenharmony_ci prev = &curr->next; 1850c84f3f3cSopenharmony_ci curr = *prev; 1851c84f3f3cSopenharmony_ci } 1852c84f3f3cSopenharmony_ci if (curr != j) { 1853c84f3f3cSopenharmony_ci internal_warningf("remove_job: job %s (%s)", Tnot_found, where); 1854c84f3f3cSopenharmony_ci return; 1855c84f3f3cSopenharmony_ci } 1856c84f3f3cSopenharmony_ci *prev = curr->next; 1857c84f3f3cSopenharmony_ci 1858c84f3f3cSopenharmony_ci /* free up proc structures */ 1859c84f3f3cSopenharmony_ci for (p = j->proc_list; p != NULL; ) { 1860c84f3f3cSopenharmony_ci tmp = p; 1861c84f3f3cSopenharmony_ci p = p->next; 1862c84f3f3cSopenharmony_ci tmp->next = free_procs; 1863c84f3f3cSopenharmony_ci free_procs = tmp; 1864c84f3f3cSopenharmony_ci } 1865c84f3f3cSopenharmony_ci 1866c84f3f3cSopenharmony_ci if ((j->flags & JF_ZOMBIE) && j->ppid == procpid) 1867c84f3f3cSopenharmony_ci --nzombie; 1868c84f3f3cSopenharmony_ci j->next = free_jobs; 1869c84f3f3cSopenharmony_ci free_jobs = j; 1870c84f3f3cSopenharmony_ci 1871c84f3f3cSopenharmony_ci if (j == last_job) 1872c84f3f3cSopenharmony_ci last_job = NULL; 1873c84f3f3cSopenharmony_ci if (j == async_job) 1874c84f3f3cSopenharmony_ci async_job = NULL; 1875c84f3f3cSopenharmony_ci} 1876c84f3f3cSopenharmony_ci 1877c84f3f3cSopenharmony_ci/* 1878c84f3f3cSopenharmony_ci * put j in a particular location (taking it out job_list if it is there 1879c84f3f3cSopenharmony_ci * already) 1880c84f3f3cSopenharmony_ci * 1881c84f3f3cSopenharmony_ci * If jobs are compiled in then this routine expects sigchld to be blocked. 1882c84f3f3cSopenharmony_ci */ 1883c84f3f3cSopenharmony_cistatic void 1884c84f3f3cSopenharmony_ciput_job(Job *j, int where) 1885c84f3f3cSopenharmony_ci{ 1886c84f3f3cSopenharmony_ci Job **prev, *curr; 1887c84f3f3cSopenharmony_ci 1888c84f3f3cSopenharmony_ci /* Remove job from list (if there) */ 1889c84f3f3cSopenharmony_ci prev = &job_list; 1890c84f3f3cSopenharmony_ci curr = job_list; 1891c84f3f3cSopenharmony_ci while (curr && curr != j) { 1892c84f3f3cSopenharmony_ci prev = &curr->next; 1893c84f3f3cSopenharmony_ci curr = *prev; 1894c84f3f3cSopenharmony_ci } 1895c84f3f3cSopenharmony_ci if (curr == j) 1896c84f3f3cSopenharmony_ci *prev = curr->next; 1897c84f3f3cSopenharmony_ci 1898c84f3f3cSopenharmony_ci switch (where) { 1899c84f3f3cSopenharmony_ci case PJ_ON_FRONT: 1900c84f3f3cSopenharmony_ci j->next = job_list; 1901c84f3f3cSopenharmony_ci job_list = j; 1902c84f3f3cSopenharmony_ci break; 1903c84f3f3cSopenharmony_ci 1904c84f3f3cSopenharmony_ci case PJ_PAST_STOPPED: 1905c84f3f3cSopenharmony_ci prev = &job_list; 1906c84f3f3cSopenharmony_ci curr = job_list; 1907c84f3f3cSopenharmony_ci for (; curr && curr->state == PSTOPPED; prev = &curr->next, 1908c84f3f3cSopenharmony_ci curr = *prev) 1909c84f3f3cSopenharmony_ci ; 1910c84f3f3cSopenharmony_ci j->next = curr; 1911c84f3f3cSopenharmony_ci *prev = j; 1912c84f3f3cSopenharmony_ci break; 1913c84f3f3cSopenharmony_ci } 1914c84f3f3cSopenharmony_ci} 1915c84f3f3cSopenharmony_ci 1916c84f3f3cSopenharmony_ci/* 1917c84f3f3cSopenharmony_ci * nuke a job (called when unable to start full job). 1918c84f3f3cSopenharmony_ci * 1919c84f3f3cSopenharmony_ci * If jobs are compiled in then this routine expects sigchld to be blocked. 1920c84f3f3cSopenharmony_ci */ 1921c84f3f3cSopenharmony_cistatic int 1922c84f3f3cSopenharmony_cikill_job(Job *j, int sig) 1923c84f3f3cSopenharmony_ci{ 1924c84f3f3cSopenharmony_ci Proc *p; 1925c84f3f3cSopenharmony_ci int rval = 0; 1926c84f3f3cSopenharmony_ci 1927c84f3f3cSopenharmony_ci for (p = j->proc_list; p != NULL; p = p->next) 1928c84f3f3cSopenharmony_ci if (p->pid != 0) 1929c84f3f3cSopenharmony_ci if (kill(p->pid, sig) < 0) 1930c84f3f3cSopenharmony_ci rval = -1; 1931c84f3f3cSopenharmony_ci return (rval); 1932c84f3f3cSopenharmony_ci} 1933c84f3f3cSopenharmony_ci 1934c84f3f3cSopenharmony_cistatic void 1935c84f3f3cSopenharmony_citty_init_talking(void) 1936c84f3f3cSopenharmony_ci{ 1937c84f3f3cSopenharmony_ci switch (tty_init_fd()) { 1938c84f3f3cSopenharmony_ci case 0: 1939c84f3f3cSopenharmony_ci break; 1940c84f3f3cSopenharmony_ci case 1: 1941c84f3f3cSopenharmony_ci#ifndef MKSH_DISABLE_TTY_WARNING 1942c84f3f3cSopenharmony_ci warningf(false, Tf_sD_s_sD_s, 1943c84f3f3cSopenharmony_ci "No controlling tty", Topen, T_devtty, cstrerror(errno)); 1944c84f3f3cSopenharmony_ci#endif 1945c84f3f3cSopenharmony_ci break; 1946c84f3f3cSopenharmony_ci case 2: 1947c84f3f3cSopenharmony_ci#ifndef MKSH_DISABLE_TTY_WARNING 1948c84f3f3cSopenharmony_ci warningf(false, Tf_s_sD_s, Tcant_find, Ttty_fd, 1949c84f3f3cSopenharmony_ci cstrerror(errno)); 1950c84f3f3cSopenharmony_ci#endif 1951c84f3f3cSopenharmony_ci break; 1952c84f3f3cSopenharmony_ci case 3: 1953c84f3f3cSopenharmony_ci warningf(false, Tf_ssfaileds, "j_ttyinit", 1954c84f3f3cSopenharmony_ci Ttty_fd_dupof, cstrerror(errno)); 1955c84f3f3cSopenharmony_ci break; 1956c84f3f3cSopenharmony_ci case 4: 1957c84f3f3cSopenharmony_ci warningf(false, Tf_sD_sD_s, "j_ttyinit", 1958c84f3f3cSopenharmony_ci "can't set close-on-exec flag", cstrerror(errno)); 1959c84f3f3cSopenharmony_ci break; 1960c84f3f3cSopenharmony_ci } 1961c84f3f3cSopenharmony_ci} 1962c84f3f3cSopenharmony_ci 1963c84f3f3cSopenharmony_cistatic void 1964c84f3f3cSopenharmony_citty_init_state(void) 1965c84f3f3cSopenharmony_ci{ 1966c84f3f3cSopenharmony_ci if (tty_fd >= 0) { 1967c84f3f3cSopenharmony_ci mksh_tcget(tty_fd, &tty_state); 1968c84f3f3cSopenharmony_ci tty_hasstate = true; 1969c84f3f3cSopenharmony_ci } 1970c84f3f3cSopenharmony_ci} 1971