1 1.124 kre /* $NetBSD: jobs.c,v 1.124 2025/04/09 12:04:19 kre Exp $ */ 2 1.15 cgd 3 1.1 cgd /*- 4 1.8 jtc * Copyright (c) 1991, 1993 5 1.8 jtc * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * This code is derived from software contributed to Berkeley by 8 1.1 cgd * Kenneth Almquist. 9 1.1 cgd * 10 1.1 cgd * Redistribution and use in source and binary forms, with or without 11 1.1 cgd * modification, are permitted provided that the following conditions 12 1.1 cgd * are met: 13 1.1 cgd * 1. Redistributions of source code must retain the above copyright 14 1.1 cgd * notice, this list of conditions and the following disclaimer. 15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 cgd * notice, this list of conditions and the following disclaimer in the 17 1.1 cgd * documentation and/or other materials provided with the distribution. 18 1.58 agc * 3. Neither the name of the University nor the names of its contributors 19 1.1 cgd * may be used to endorse or promote products derived from this software 20 1.1 cgd * without specific prior written permission. 21 1.1 cgd * 22 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 cgd * SUCH DAMAGE. 33 1.1 cgd */ 34 1.1 cgd 35 1.22 christos #include <sys/cdefs.h> 36 1.1 cgd #ifndef lint 37 1.15 cgd #if 0 38 1.16 christos static char sccsid[] = "@(#)jobs.c 8.5 (Berkeley) 5/4/95"; 39 1.15 cgd #else 40 1.124 kre __RCSID("$NetBSD: jobs.c,v 1.124 2025/04/09 12:04:19 kre Exp $"); 41 1.15 cgd #endif 42 1.1 cgd #endif /* not lint */ 43 1.1 cgd 44 1.95 kre #include <stdio.h> 45 1.16 christos #include <fcntl.h> 46 1.16 christos #include <signal.h> 47 1.16 christos #include <errno.h> 48 1.16 christos #include <unistd.h> 49 1.16 christos #include <stdlib.h> 50 1.26 fair #include <paths.h> 51 1.16 christos #include <sys/types.h> 52 1.16 christos #include <sys/param.h> 53 1.16 christos #ifdef BSD 54 1.16 christos #include <sys/wait.h> 55 1.16 christos #include <sys/time.h> 56 1.16 christos #include <sys/resource.h> 57 1.16 christos #endif 58 1.19 christos #include <sys/ioctl.h> 59 1.16 christos 60 1.1 cgd #include "shell.h" 61 1.1 cgd #if JOBS 62 1.19 christos #if OLD_TTY_DRIVER 63 1.1 cgd #include "sgtty.h" 64 1.19 christos #else 65 1.19 christos #include <termios.h> 66 1.19 christos #endif 67 1.1 cgd #undef CEOF /* syntax.h redefines this */ 68 1.1 cgd #endif 69 1.16 christos #include "redir.h" 70 1.16 christos #include "show.h" 71 1.1 cgd #include "main.h" 72 1.1 cgd #include "parser.h" 73 1.1 cgd #include "nodes.h" 74 1.1 cgd #include "jobs.h" 75 1.95 kre #include "var.h" 76 1.1 cgd #include "options.h" 77 1.69 christos #include "builtins.h" 78 1.1 cgd #include "trap.h" 79 1.1 cgd #include "syntax.h" 80 1.1 cgd #include "input.h" 81 1.1 cgd #include "output.h" 82 1.1 cgd #include "memalloc.h" 83 1.1 cgd #include "error.h" 84 1.1 cgd #include "mystring.h" 85 1.1 cgd 86 1.1 cgd 87 1.91 kre #ifndef WCONTINUED 88 1.91 kre #define WCONTINUED 0 /* So we can compile on old systems */ 89 1.91 kre #endif 90 1.91 kre #ifndef WIFCONTINUED 91 1.91 kre #define WIFCONTINUED(x) (0) /* ditto */ 92 1.91 kre #endif 93 1.91 kre 94 1.91 kre 95 1.55 christos static struct job *jobtab; /* array of jobs */ 96 1.55 christos static int njobs; /* size of array */ 97 1.55 christos static int jobs_invalid; /* set in child */ 98 1.55 christos MKINIT pid_t backgndpid = -1; /* pid of last background process */ 99 1.1 cgd #if JOBS 100 1.1 cgd int initialpgrp; /* pgrp of shell on invocation */ 101 1.55 christos static int curjob = -1; /* current job */ 102 1.1 cgd #endif 103 1.44 christos static int ttyfd = -1; 104 1.1 cgd 105 1.55 christos STATIC void restartjob(struct job *); 106 1.55 christos STATIC void freejob(struct job *); 107 1.55 christos STATIC struct job *getjob(const char *, int); 108 1.95 kre STATIC int dowait(int, struct job *, struct job **); 109 1.68 christos #define WBLOCK 1 110 1.68 christos #define WNOFREE 2 111 1.91 kre #define WSILENT 4 112 1.90 kre STATIC int jobstatus(const struct job *, int); 113 1.55 christos STATIC int waitproc(int, struct job *, int *); 114 1.121 kre STATIC int cmdtxt(union node *, int); 115 1.55 christos STATIC void cmdlist(union node *, int); 116 1.55 christos STATIC void cmdputs(const char *); 117 1.78 kre inline static void cmdputi(int); 118 1.1 cgd 119 1.116 kre #define JNUM(j) ((int)((j) != NULL ? ((j) - jobtab) + 1 : 0)) 120 1.116 kre 121 1.66 dholland #ifdef SYSV 122 1.66 dholland STATIC int onsigchild(void); 123 1.66 dholland #endif 124 1.66 dholland 125 1.44 christos #ifdef OLD_TTY_DRIVER 126 1.55 christos static pid_t tcgetpgrp(int fd); 127 1.55 christos static int tcsetpgrp(int fd, pid_t pgrp); 128 1.44 christos 129 1.44 christos static pid_t 130 1.55 christos tcgetpgrp(int fd) 131 1.44 christos { 132 1.44 christos pid_t pgrp; 133 1.44 christos if (ioctl(fd, TIOCGPGRP, (char *)&pgrp) == -1) 134 1.44 christos return -1; 135 1.44 christos else 136 1.44 christos return pgrp; 137 1.44 christos } 138 1.44 christos 139 1.44 christos static int 140 1.55 christos tcsetpgrp(int fd, pid_tpgrp) 141 1.44 christos { 142 1.44 christos return ioctl(fd, TIOCSPGRP, (char *)&pgrp); 143 1.44 christos } 144 1.44 christos #endif 145 1.8 jtc 146 1.80 kre static void 147 1.80 kre ttyfd_change(int from, int to) 148 1.80 kre { 149 1.80 kre if (ttyfd == from) 150 1.80 kre ttyfd = to; 151 1.80 kre } 152 1.80 kre 153 1.1 cgd /* 154 1.1 cgd * Turn job control on and off. 155 1.1 cgd * 156 1.1 cgd * Note: This code assumes that the third arg to ioctl is a character 157 1.1 cgd * pointer, which is true on Berkeley systems but not System V. Since 158 1.1 cgd * System V doesn't have job control yet, this isn't a problem now. 159 1.1 cgd */ 160 1.1 cgd 161 1.1 cgd MKINIT int jobctl; 162 1.1 cgd 163 1.1 cgd void 164 1.55 christos setjobctl(int on) 165 1.13 cgd { 166 1.8 jtc #ifdef OLD_TTY_DRIVER 167 1.1 cgd int ldisc; 168 1.8 jtc #endif 169 1.1 cgd 170 1.1 cgd if (on == jobctl || rootshell == 0) 171 1.1 cgd return; 172 1.1 cgd if (on) { 173 1.44 christos #if defined(FIOCLEX) || defined(FD_CLOEXEC) 174 1.57 christos int i; 175 1.80 kre 176 1.44 christos if (ttyfd != -1) 177 1.80 kre sh_close(ttyfd); 178 1.45 christos if ((ttyfd = open("/dev/tty", O_RDWR)) == -1) { 179 1.45 christos for (i = 0; i < 3; i++) { 180 1.45 christos if (isatty(i) && (ttyfd = dup(i)) != -1) 181 1.45 christos break; 182 1.45 christos } 183 1.45 christos if (i == 3) 184 1.45 christos goto out; 185 1.45 christos } 186 1.76 christos ttyfd = to_upper_fd(ttyfd); /* Move to a high fd */ 187 1.80 kre register_sh_fd(ttyfd, ttyfd_change); 188 1.18 mycroft #else 189 1.44 christos out2str("sh: Need FIOCLEX or FD_CLOEXEC to support job control"); 190 1.44 christos goto out; 191 1.18 mycroft #endif 192 1.114 rillig if ((initialpgrp = tcgetpgrp(ttyfd)) < 0) { 193 1.80 kre out: 194 1.114 rillig out2str("sh: can't access tty; job control turned off\n"); 195 1.114 rillig mflag = 0; 196 1.114 rillig return; 197 1.114 rillig } 198 1.114 rillig if (initialpgrp == -1) 199 1.114 rillig initialpgrp = getpgrp(); 200 1.114 rillig else if (initialpgrp != getpgrp()) 201 1.114 rillig killpg(0, SIGTTIN); 202 1.44 christos 203 1.8 jtc #ifdef OLD_TTY_DRIVER 204 1.44 christos if (ioctl(ttyfd, TIOCGETD, (char *)&ldisc) < 0 205 1.44 christos || ldisc != NTTYDISC) { 206 1.8 jtc out2str("sh: need new tty driver to run job control; job control turned off\n"); 207 1.8 jtc mflag = 0; 208 1.1 cgd return; 209 1.1 cgd } 210 1.8 jtc #endif 211 1.47 christos setsignal(SIGTSTP, 0); 212 1.47 christos setsignal(SIGTTOU, 0); 213 1.47 christos setsignal(SIGTTIN, 0); 214 1.64 tv if (getpgrp() != rootpid && setpgid(0, rootpid) == -1) 215 1.47 christos error("Cannot set process group (%s) at %d", 216 1.47 christos strerror(errno), __LINE__); 217 1.47 christos if (tcsetpgrp(ttyfd, rootpid) == -1) 218 1.47 christos error("Cannot set tty process group (%s) at %d", 219 1.47 christos strerror(errno), __LINE__); 220 1.1 cgd } else { /* turning job control off */ 221 1.64 tv if (getpgrp() != initialpgrp && setpgid(0, initialpgrp) == -1) 222 1.47 christos error("Cannot set process group (%s) at %d", 223 1.47 christos strerror(errno), __LINE__); 224 1.47 christos if (tcsetpgrp(ttyfd, initialpgrp) == -1) 225 1.47 christos error("Cannot set tty process group (%s) at %d", 226 1.47 christos strerror(errno), __LINE__); 227 1.80 kre sh_close(ttyfd); 228 1.44 christos ttyfd = -1; 229 1.47 christos setsignal(SIGTSTP, 0); 230 1.47 christos setsignal(SIGTTOU, 0); 231 1.47 christos setsignal(SIGTTIN, 0); 232 1.1 cgd } 233 1.1 cgd jobctl = on; 234 1.1 cgd } 235 1.1 cgd 236 1.1 cgd 237 1.1 cgd #ifdef mkinit 238 1.16 christos INCLUDE <stdlib.h> 239 1.1 cgd 240 1.1 cgd SHELLPROC { 241 1.1 cgd backgndpid = -1; 242 1.1 cgd #if JOBS 243 1.1 cgd jobctl = 0; 244 1.1 cgd #endif 245 1.1 cgd } 246 1.1 cgd 247 1.1 cgd #endif 248 1.1 cgd 249 1.1 cgd 250 1.1 cgd 251 1.1 cgd #if JOBS 252 1.71 dsl static int 253 1.71 dsl do_fgcmd(const char *arg_ptr) 254 1.13 cgd { 255 1.1 cgd struct job *jp; 256 1.47 christos int i; 257 1.1 cgd int status; 258 1.1 cgd 259 1.91 kre if (jobs_invalid) 260 1.91 kre error("No current jobs"); 261 1.71 dsl jp = getjob(arg_ptr, 0); 262 1.1 cgd if (jp->jobctl == 0) 263 1.1 cgd error("job not created under job control"); 264 1.55 christos out1fmt("%s", jp->ps[0].cmd); 265 1.55 christos for (i = 1; i < jp->nprocs; i++) 266 1.55 christos out1fmt(" | %s", jp->ps[i].cmd ); 267 1.55 christos out1c('\n'); 268 1.55 christos flushall(); 269 1.47 christos 270 1.117 kre if (tcsetpgrp(ttyfd, jp->pgrp) == -1) { 271 1.47 christos error("Cannot set tty process group (%s) at %d", 272 1.47 christos strerror(errno), __LINE__); 273 1.47 christos } 274 1.104 kre INTOFF; 275 1.1 cgd restartjob(jp); 276 1.1 cgd status = waitforjob(jp); 277 1.1 cgd INTON; 278 1.1 cgd return status; 279 1.1 cgd } 280 1.1 cgd 281 1.71 dsl int 282 1.71 dsl fgcmd(int argc, char **argv) 283 1.71 dsl { 284 1.71 dsl nextopt(""); 285 1.71 dsl return do_fgcmd(*argptr); 286 1.71 dsl } 287 1.71 dsl 288 1.71 dsl int 289 1.71 dsl fgcmd_percent(int argc, char **argv) 290 1.71 dsl { 291 1.71 dsl nextopt(""); 292 1.71 dsl return do_fgcmd(*argv); 293 1.71 dsl } 294 1.71 dsl 295 1.55 christos static void 296 1.55 christos set_curjob(struct job *jp, int mode) 297 1.55 christos { 298 1.55 christos struct job *jp1, *jp2; 299 1.55 christos int i, ji; 300 1.55 christos 301 1.55 christos ji = jp - jobtab; 302 1.55 christos 303 1.55 christos /* first remove from list */ 304 1.55 christos if (ji == curjob) 305 1.55 christos curjob = jp->prev_job; 306 1.55 christos else { 307 1.55 christos for (i = 0; i < njobs; i++) { 308 1.55 christos if (jobtab[i].prev_job != ji) 309 1.55 christos continue; 310 1.55 christos jobtab[i].prev_job = jp->prev_job; 311 1.55 christos break; 312 1.55 christos } 313 1.55 christos } 314 1.55 christos 315 1.55 christos /* Then re-insert in correct position */ 316 1.55 christos switch (mode) { 317 1.55 christos case 0: /* job being deleted */ 318 1.55 christos jp->prev_job = -1; 319 1.55 christos break; 320 1.55 christos case 1: /* newly created job or backgrounded job, 321 1.55 christos put after all stopped jobs. */ 322 1.55 christos if (curjob != -1 && jobtab[curjob].state == JOBSTOPPED) { 323 1.55 christos for (jp1 = jobtab + curjob; ; jp1 = jp2) { 324 1.55 christos if (jp1->prev_job == -1) 325 1.55 christos break; 326 1.55 christos jp2 = jobtab + jp1->prev_job; 327 1.55 christos if (jp2->state != JOBSTOPPED) 328 1.55 christos break; 329 1.55 christos } 330 1.55 christos jp->prev_job = jp1->prev_job; 331 1.55 christos jp1->prev_job = ji; 332 1.55 christos break; 333 1.55 christos } 334 1.55 christos /* FALLTHROUGH */ 335 1.55 christos case 2: /* newly stopped job - becomes curjob */ 336 1.55 christos jp->prev_job = curjob; 337 1.55 christos curjob = ji; 338 1.55 christos break; 339 1.55 christos } 340 1.55 christos } 341 1.1 cgd 342 1.13 cgd int 343 1.55 christos bgcmd(int argc, char **argv) 344 1.13 cgd { 345 1.1 cgd struct job *jp; 346 1.55 christos int i; 347 1.1 cgd 348 1.55 christos nextopt(""); 349 1.91 kre if (jobs_invalid) 350 1.91 kre error("No current jobs"); 351 1.1 cgd do { 352 1.55 christos jp = getjob(*argptr, 0); 353 1.1 cgd if (jp->jobctl == 0) 354 1.1 cgd error("job not created under job control"); 355 1.55 christos set_curjob(jp, 1); 356 1.116 kre out1fmt("[%d] %s", JNUM(jp), jp->ps[0].cmd); 357 1.55 christos for (i = 1; i < jp->nprocs; i++) 358 1.55 christos out1fmt(" | %s", jp->ps[i].cmd ); 359 1.55 christos out1c('\n'); 360 1.55 christos flushall(); 361 1.1 cgd restartjob(jp); 362 1.55 christos } while (*argptr && *++argptr); 363 1.1 cgd return 0; 364 1.1 cgd } 365 1.1 cgd 366 1.1 cgd 367 1.1 cgd STATIC void 368 1.55 christos restartjob(struct job *jp) 369 1.13 cgd { 370 1.1 cgd struct procstat *ps; 371 1.105 kre int i, e; 372 1.1 cgd 373 1.1 cgd if (jp->state == JOBDONE) 374 1.1 cgd return; 375 1.117 kre if (jp->pgrp == 0) 376 1.117 kre error("Job [%d] does not have a process group", JNUM(jp)); 377 1.117 kre 378 1.1 cgd INTOFF; 379 1.105 kre for (e = i = 0; i < jp->nprocs; i++) { 380 1.108 kre /* 381 1.108 kre * Don't touch a process we already waited for and collected 382 1.108 kre * exit status, that pid may have been reused for something 383 1.108 kre * else - even another of our jobs 384 1.108 kre */ 385 1.108 kre if (jp->ps[i].status != -1 && !WIFSTOPPED(jp->ps[i].status)) 386 1.108 kre continue; 387 1.108 kre 388 1.108 kre /* 389 1.108 kre * Otherwise tell it to continue, if it worked, we're done 390 1.108 kre * (we signal the whole process group) 391 1.108 kre */ 392 1.117 kre if (killpg(jp->pgrp, SIGCONT) != -1) 393 1.47 christos break; 394 1.117 kre e = errno; 395 1.117 kre break; /* no point trying again */ 396 1.105 kre } 397 1.117 kre 398 1.117 kre if (e != 0) 399 1.117 kre error("Cannot continue job (%s)", strerror(e)); 400 1.117 kre else if (i >= jp->nprocs) 401 1.117 kre error("Job [%d] has no stopped processes", JNUM(jp)); 402 1.108 kre 403 1.108 kre /* 404 1.108 kre * Now change state of all stopped processes in the job to running 405 1.108 kre * If there were any, the job is now running as well. 406 1.108 kre */ 407 1.1 cgd for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) { 408 1.23 christos if (WIFSTOPPED(ps->status)) { 409 1.92 kre VTRACE(DBG_JOBS, ( 410 1.116 kre "restartjob: [%d] pid %d status change" 411 1.92 kre " from %#x (stopped) to -1 (running)\n", 412 1.116 kre JNUM(jp), ps->pid, ps->status)); 413 1.1 cgd ps->status = -1; 414 1.55 christos jp->state = JOBRUNNING; 415 1.1 cgd } 416 1.1 cgd } 417 1.1 cgd INTON; 418 1.1 cgd } 419 1.1 cgd #endif 420 1.1 cgd 421 1.78 kre inline static void 422 1.77 kre cmdputi(int n) 423 1.77 kre { 424 1.77 kre char str[20]; 425 1.77 kre 426 1.77 kre fmtstr(str, sizeof str, "%d", n); 427 1.77 kre cmdputs(str); 428 1.77 kre } 429 1.77 kre 430 1.55 christos static void 431 1.55 christos showjob(struct output *out, struct job *jp, int mode) 432 1.55 christos { 433 1.55 christos int procno; 434 1.55 christos int st; 435 1.55 christos struct procstat *ps; 436 1.55 christos int col; 437 1.55 christos char s[64]; 438 1.55 christos 439 1.55 christos #if JOBS 440 1.55 christos if (mode & SHOW_PGID) { 441 1.117 kre /* output only the process group ID (lead process ID) */ 442 1.119 kre outfmt(out, "%ld\n", 443 1.119 kre jp->pgrp != 0 ? (long)jp->pgrp : (long)jp->ps->pid); 444 1.55 christos return; 445 1.55 christos } 446 1.55 christos #endif 447 1.55 christos 448 1.55 christos procno = jp->nprocs; 449 1.55 christos if (!procno) 450 1.55 christos return; 451 1.55 christos 452 1.55 christos if (mode & SHOW_PID) 453 1.55 christos mode |= SHOW_MULTILINE; 454 1.55 christos 455 1.55 christos if ((procno > 1 && !(mode & SHOW_MULTILINE)) 456 1.55 christos || (mode & SHOW_SIGNALLED)) { 457 1.55 christos /* See if we have more than one status to report */ 458 1.55 christos ps = jp->ps; 459 1.55 christos st = ps->status; 460 1.55 christos do { 461 1.55 christos int st1 = ps->status; 462 1.55 christos if (st1 != st) 463 1.55 christos /* yes - need multi-line output */ 464 1.55 christos mode |= SHOW_MULTILINE; 465 1.55 christos if (st1 == -1 || !(mode & SHOW_SIGNALLED) || WIFEXITED(st1)) 466 1.55 christos continue; 467 1.55 christos if (WIFSTOPPED(st1) || ((st1 = WTERMSIG(st1) & 0x7f) 468 1.55 christos && st1 != SIGINT && st1 != SIGPIPE)) 469 1.55 christos mode |= SHOW_ISSIG; 470 1.55 christos 471 1.55 christos } while (ps++, --procno); 472 1.55 christos procno = jp->nprocs; 473 1.55 christos } 474 1.55 christos 475 1.55 christos if (mode & SHOW_SIGNALLED && !(mode & SHOW_ISSIG)) { 476 1.55 christos if (jp->state == JOBDONE && !(mode & SHOW_NO_FREE)) { 477 1.87 kre VTRACE(DBG_JOBS, ("showjob: freeing job %d\n", 478 1.116 kre JNUM(jp))); 479 1.55 christos freejob(jp); 480 1.55 christos } 481 1.55 christos return; 482 1.55 christos } 483 1.55 christos 484 1.55 christos for (ps = jp->ps; --procno >= 0; ps++) { /* for each process */ 485 1.55 christos if (ps == jp->ps) 486 1.116 kre fmtstr(s, 16, "[%d] %c ", 487 1.116 kre JNUM(jp), 488 1.55 christos #if JOBS 489 1.98 kre jp - jobtab == curjob ? 490 1.98 kre '+' : 491 1.98 kre curjob != -1 && 492 1.98 kre jp - jobtab == jobtab[curjob].prev_job ? 493 1.98 kre '-' : 494 1.55 christos #endif 495 1.55 christos ' '); 496 1.55 christos else 497 1.55 christos fmtstr(s, 16, " " ); 498 1.55 christos col = strlen(s); 499 1.55 christos if (mode & SHOW_PID) { 500 1.55 christos fmtstr(s + col, 16, "%ld ", (long)ps->pid); 501 1.55 christos col += strlen(s + col); 502 1.55 christos } 503 1.55 christos if (ps->status == -1) { 504 1.55 christos scopy("Running", s + col); 505 1.55 christos } else if (WIFEXITED(ps->status)) { 506 1.55 christos st = WEXITSTATUS(ps->status); 507 1.55 christos if (st) 508 1.55 christos fmtstr(s + col, 16, "Done(%d)", st); 509 1.55 christos else 510 1.55 christos fmtstr(s + col, 16, "Done"); 511 1.55 christos } else { 512 1.55 christos #if JOBS 513 1.91 kre if (WIFSTOPPED(ps->status)) 514 1.55 christos st = WSTOPSIG(ps->status); 515 1.55 christos else /* WIFSIGNALED(ps->status) */ 516 1.55 christos #endif 517 1.55 christos st = WTERMSIG(ps->status); 518 1.102 kre scopyn(strsignal(st), s + col, 32); 519 1.55 christos if (WCOREDUMP(ps->status)) { 520 1.55 christos col += strlen(s + col); 521 1.55 christos scopyn(" (core dumped)", s + col, 64 - col); 522 1.55 christos } 523 1.55 christos } 524 1.55 christos col += strlen(s + col); 525 1.55 christos outstr(s, out); 526 1.55 christos do { 527 1.55 christos outc(' ', out); 528 1.55 christos col++; 529 1.55 christos } while (col < 30); 530 1.55 christos outstr(ps->cmd, out); 531 1.55 christos if (mode & SHOW_MULTILINE) { 532 1.55 christos if (procno > 0) { 533 1.55 christos outc(' ', out); 534 1.55 christos outc('|', out); 535 1.55 christos } 536 1.55 christos } else { 537 1.55 christos while (--procno >= 0) 538 1.55 christos outfmt(out, " | %s", (++ps)->cmd ); 539 1.55 christos } 540 1.55 christos outc('\n', out); 541 1.55 christos } 542 1.55 christos flushout(out); 543 1.95 kre jp->flags &= ~JOBCHANGED; 544 1.55 christos if (jp->state == JOBDONE && !(mode & SHOW_NO_FREE)) 545 1.55 christos freejob(jp); 546 1.55 christos } 547 1.55 christos 548 1.1 cgd int 549 1.55 christos jobscmd(int argc, char **argv) 550 1.13 cgd { 551 1.55 christos int mode, m; 552 1.55 christos 553 1.55 christos mode = 0; 554 1.111 christos while ((m = nextopt("lpZ"))) 555 1.111 christos switch (m) { 556 1.111 christos case 'l': 557 1.55 christos mode = SHOW_PID; 558 1.111 christos break; 559 1.111 christos case 'p': 560 1.55 christos mode = SHOW_PGID; 561 1.111 christos break; 562 1.111 christos case 'Z': 563 1.111 christos mode = SHOW_PROCTITLE; 564 1.111 christos break; 565 1.111 christos } 566 1.111 christos 567 1.111 christos if (mode == SHOW_PROCTITLE) { 568 1.112 kre if (*argptr && **argptr) 569 1.112 kre setproctitle("%s", *argptr); 570 1.112 kre else 571 1.112 kre setproctitle(NULL); 572 1.111 christos return 0; 573 1.111 christos } 574 1.105 kre 575 1.105 kre if (!iflag && !posix) 576 1.91 kre mode |= SHOW_NO_FREE; 577 1.105 kre 578 1.105 kre if (*argptr) { 579 1.55 christos do 580 1.55 christos showjob(out1, getjob(*argptr,0), mode); 581 1.55 christos while (*++argptr); 582 1.105 kre } else 583 1.55 christos showjobs(out1, mode); 584 1.1 cgd return 0; 585 1.1 cgd } 586 1.1 cgd 587 1.1 cgd 588 1.1 cgd /* 589 1.1 cgd * Print a list of jobs. If "change" is nonzero, only print jobs whose 590 1.1 cgd * statuses have changed since the last call to showjobs. 591 1.1 cgd * 592 1.1 cgd * If the shell is interrupted in the process of creating a job, the 593 1.1 cgd * result may be a job structure containing zero processes. Such structures 594 1.1 cgd * will be freed here. 595 1.1 cgd */ 596 1.1 cgd 597 1.1 cgd void 598 1.55 christos showjobs(struct output *out, int mode) 599 1.13 cgd { 600 1.1 cgd int jobno; 601 1.1 cgd struct job *jp; 602 1.47 christos int silent = 0, gotpid; 603 1.1 cgd 604 1.87 kre CTRACE(DBG_JOBS, ("showjobs(%x) called\n", mode)); 605 1.47 christos 606 1.108 kre /* Collect everything pending in the kernel */ 607 1.108 kre if ((gotpid = dowait(WSILENT, NULL, NULL)) > 0) 608 1.108 kre while (dowait(WSILENT, NULL, NULL) > 0) 609 1.108 kre continue; 610 1.47 christos #ifdef JOBS 611 1.47 christos /* 612 1.47 christos * Check if we are not in our foreground group, and if not 613 1.47 christos * put us in it. 614 1.47 christos */ 615 1.54 christos if (mflag && gotpid != -1 && tcgetpgrp(ttyfd) != getpid()) { 616 1.47 christos if (tcsetpgrp(ttyfd, getpid()) == -1) 617 1.47 christos error("Cannot set tty process group (%s) at %d", 618 1.47 christos strerror(errno), __LINE__); 619 1.87 kre VTRACE(DBG_JOBS|DBG_INPUT, ("repaired tty process group\n")); 620 1.47 christos silent = 1; 621 1.47 christos } 622 1.47 christos #endif 623 1.55 christos 624 1.1 cgd for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) { 625 1.55 christos if (!jp->used) 626 1.1 cgd continue; 627 1.1 cgd if (jp->nprocs == 0) { 628 1.101 kre if (!jobs_invalid) 629 1.101 kre freejob(jp); 630 1.1 cgd continue; 631 1.1 cgd } 632 1.95 kre if ((mode & SHOW_CHANGED) && !(jp->flags & JOBCHANGED)) 633 1.1 cgd continue; 634 1.95 kre if (silent && (jp->flags & JOBCHANGED)) { 635 1.95 kre jp->flags &= ~JOBCHANGED; 636 1.47 christos continue; 637 1.47 christos } 638 1.55 christos showjob(out, jp, mode); 639 1.1 cgd } 640 1.1 cgd } 641 1.1 cgd 642 1.1 cgd /* 643 1.1 cgd * Mark a job structure as unused. 644 1.1 cgd */ 645 1.1 cgd 646 1.1 cgd STATIC void 647 1.55 christos freejob(struct job *jp) 648 1.55 christos { 649 1.1 cgd INTOFF; 650 1.41 christos if (jp->ps != &jp->ps0) { 651 1.1 cgd ckfree(jp->ps); 652 1.41 christos jp->ps = &jp->ps0; 653 1.41 christos } 654 1.41 christos jp->nprocs = 0; 655 1.1 cgd jp->used = 0; 656 1.1 cgd #if JOBS 657 1.55 christos set_curjob(jp, 0); 658 1.1 cgd #endif 659 1.1 cgd INTON; 660 1.1 cgd } 661 1.1 cgd 662 1.90 kre /* 663 1.90 kre * Extract the status of a completed job (for $?) 664 1.90 kre */ 665 1.90 kre STATIC int 666 1.90 kre jobstatus(const struct job *jp, int raw) 667 1.90 kre { 668 1.90 kre int status = 0; 669 1.90 kre int retval; 670 1.90 kre 671 1.100 kre if ((jp->flags & JPIPEFAIL) && jp->nprocs) { 672 1.90 kre int i; 673 1.90 kre 674 1.90 kre for (i = 0; i < jp->nprocs; i++) 675 1.90 kre if (jp->ps[i].status != 0) 676 1.90 kre status = jp->ps[i].status; 677 1.90 kre } else 678 1.90 kre status = jp->ps[jp->nprocs ? jp->nprocs - 1 : 0].status; 679 1.90 kre 680 1.90 kre if (raw) 681 1.90 kre return status; 682 1.90 kre 683 1.90 kre if (WIFEXITED(status)) 684 1.90 kre retval = WEXITSTATUS(status); 685 1.90 kre #if JOBS 686 1.90 kre else if (WIFSTOPPED(status)) 687 1.90 kre retval = WSTOPSIG(status) + 128; 688 1.90 kre #endif 689 1.90 kre else { 690 1.90 kre /* XXX: limits number of signals */ 691 1.90 kre retval = WTERMSIG(status) + 128; 692 1.90 kre } 693 1.90 kre 694 1.90 kre return retval; 695 1.90 kre } 696 1.90 kre 697 1.1 cgd 698 1.1 cgd 699 1.1 cgd int 700 1.55 christos waitcmd(int argc, char **argv) 701 1.13 cgd { 702 1.95 kre struct job *job, *last; 703 1.90 kre int retval; 704 1.1 cgd struct job *jp; 705 1.95 kre int i; 706 1.95 kre int any = 0; 707 1.95 kre int found; 708 1.122 kre int oldwait = 0; 709 1.95 kre char *pid = NULL, *fpid; 710 1.95 kre char **arg; 711 1.95 kre char idstring[20]; 712 1.95 kre 713 1.95 kre while ((i = nextopt("np:")) != '\0') { 714 1.95 kre switch (i) { 715 1.95 kre case 'n': 716 1.95 kre any = 1; 717 1.95 kre break; 718 1.95 kre case 'p': 719 1.95 kre if (pid) 720 1.95 kre error("more than one -p unsupported"); 721 1.95 kre pid = optionarg; 722 1.95 kre break; 723 1.95 kre } 724 1.95 kre } 725 1.1 cgd 726 1.122 kre if (!any && *argptr == 0) 727 1.122 kre oldwait = 1; 728 1.122 kre 729 1.95 kre if (pid != NULL) { 730 1.95 kre if (!validname(pid, '\0', NULL)) 731 1.95 kre error("invalid name: -p '%s'", pid); 732 1.95 kre if (unsetvar(pid, 0)) 733 1.95 kre error("%s readonly", pid); 734 1.95 kre } 735 1.55 christos 736 1.91 kre /* 737 1.91 kre * If we have forked, and not yet created any new jobs, then 738 1.91 kre * we have no children, whatever jobtab claims, 739 1.91 kre * so simply return in that case. 740 1.91 kre * 741 1.91 kre * The return code is 127 if we had any pid args (none are found) 742 1.95 kre * or if we had -n (nothing exited), but 0 for plain old "wait". 743 1.91 kre */ 744 1.95 kre if (jobs_invalid) { 745 1.95 kre CTRACE(DBG_WAIT, ("builtin wait%s%s in child, invalid jobtab\n", 746 1.95 kre any ? " -n" : "", *argptr ? " pid..." : "")); 747 1.122 kre return oldwait ? 0 : 127; 748 1.95 kre } 749 1.91 kre 750 1.106 kre /* 751 1.106 kre * clear stray flags left from previous waitcmd 752 1.106 kre * or set them instead if anything will do ("wait -n") 753 1.106 kre */ 754 1.95 kre for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) { 755 1.106 kre if (any && *argptr == NULL) 756 1.106 kre jp->flags |= JOBWANTED; 757 1.106 kre else 758 1.106 kre jp->flags &= ~JOBWANTED; 759 1.95 kre jp->ref = NULL; 760 1.1 cgd } 761 1.55 christos 762 1.95 kre CTRACE(DBG_WAIT, 763 1.95 kre ("builtin wait%s%s\n", any ? " -n" : "", *argptr ? " pid..." : "")); 764 1.95 kre 765 1.95 kre /* 766 1.95 kre * First, validate the jobnum args, count how many refer to 767 1.95 kre * (different) running jobs, and if we had -n, and found that one has 768 1.95 kre * already finished, we return that one. Otherwise remember 769 1.95 kre * which ones we are looking for (JOBWANTED). 770 1.95 kre */ 771 1.95 kre found = 0; 772 1.95 kre last = NULL; 773 1.124 kre #ifdef DEBUG 774 1.124 kre job = NULL; 775 1.124 kre #endif 776 1.95 kre for (arg = argptr; *arg; arg++) { 777 1.95 kre last = jp = getjob(*arg, 1); 778 1.95 kre if (!jp) 779 1.55 christos continue; 780 1.95 kre if (jp->ref == NULL) 781 1.95 kre jp->ref = *arg; 782 1.95 kre if (any && jp->state == JOBDONE) { 783 1.95 kre /* 784 1.95 kre * We just want any of them, and this one is 785 1.95 kre * ready for consumption, bon apetit ... 786 1.95 kre */ 787 1.95 kre retval = jobstatus(jp, 0); 788 1.95 kre if (pid) 789 1.95 kre setvar(pid, *arg, 0); 790 1.95 kre if (!iflag) 791 1.95 kre freejob(jp); 792 1.95 kre CTRACE(DBG_WAIT, ("wait -n found %s already done: %d\n", *arg, retval)); 793 1.95 kre return retval; 794 1.55 christos } 795 1.95 kre if (!(jp->flags & JOBWANTED)) { 796 1.95 kre /* 797 1.95 kre * It is possible to list the same job several 798 1.95 kre * times - the obvious "wait 1 1 1" or 799 1.95 kre * "wait %% %2 102" where job 2 is current and pid 102 800 1.95 kre * However many times it is requested, it is found once. 801 1.95 kre */ 802 1.95 kre found++; 803 1.95 kre jp->flags |= JOBWANTED; 804 1.95 kre } 805 1.124 kre #ifdef DEBUG 806 1.95 kre job = jp; 807 1.124 kre #endif 808 1.95 kre } 809 1.95 kre 810 1.95 kre VTRACE(DBG_WAIT, ("wait %s%s%sfound %d candidates (last %s)\n", 811 1.95 kre any ? "-n " : "", *argptr ? *argptr : "", 812 1.95 kre argptr[0] && argptr[1] ? "... " : " ", found, 813 1.110 kre job && job->used ? (job->ref ? job->ref : "<no-arg>") : "none")); 814 1.95 kre 815 1.95 kre /* 816 1.95 kre * If we were given a list of jobnums: 817 1.95 kre * and none of those exist, then we're done. 818 1.95 kre */ 819 1.95 kre if (*argptr && found == 0) 820 1.95 kre return 127; 821 1.95 kre 822 1.95 kre /* 823 1.95 kre * Otherwise we need to wait for something to complete 824 1.95 kre * When it does, we check and see if it is one of the 825 1.95 kre * jobs we're waiting on, and if so, we clean it up. 826 1.95 kre * If we had -n, then we're done, otherwise we do it all again 827 1.95 kre * until all we had listed are done, of if there were no 828 1.95 kre * jobnum args, all are done. 829 1.95 kre */ 830 1.95 kre 831 1.95 kre retval = any || *argptr ? 127 : 0; 832 1.95 kre fpid = NULL; 833 1.95 kre for (;;) { 834 1.95 kre VTRACE(DBG_WAIT, ("wait waiting (%d remain): ", found)); 835 1.106 kre job = NULL; 836 1.95 kre for (jp = jobtab, i = njobs; --i >= 0; jp++) { 837 1.95 kre if (jp->used && jp->flags & JOBWANTED && 838 1.106 kre jp->state == JOBDONE) { 839 1.106 kre job = jp; 840 1.95 kre break; 841 1.106 kre } 842 1.95 kre if (jp->used && jp->state == JOBRUNNING) 843 1.106 kre job = jp; 844 1.95 kre } 845 1.106 kre if (i < 0 && job == NULL) { 846 1.95 kre CTRACE(DBG_WAIT, ("nothing running (ret: %d) fpid %s\n", 847 1.95 kre retval, fpid ? fpid : "unset")); 848 1.95 kre if (pid && fpid) 849 1.95 kre setvar(pid, fpid, 0); 850 1.95 kre return retval; 851 1.95 kre } 852 1.106 kre jp = job; 853 1.95 kre VTRACE(DBG_WAIT, ("found @%d/%d state: %d\n", njobs-i, njobs, 854 1.95 kre jp->state)); 855 1.95 kre 856 1.95 kre /* 857 1.95 kre * There is at least 1 job running, so we can 858 1.108 kre * safely wait() (blocking) for something to exit. 859 1.95 kre */ 860 1.95 kre if (jp->state == JOBRUNNING) { 861 1.95 kre job = NULL; 862 1.95 kre if ((i = dowait(WBLOCK|WNOFREE, NULL, &job)) == -1) 863 1.75 christos return 128 + lastsig(); 864 1.95 kre 865 1.108 kre /* 866 1.108 kre * This happens if an interloper has died 867 1.108 kre * (eg: a child of the executable that exec'd us) 868 1.108 kre * Simply go back and start all over again 869 1.108 kre * (this is rare). 870 1.118 kre */ 871 1.108 kre if (job == NULL) 872 1.107 kre continue; 873 1.107 kre 874 1.95 kre /* 875 1.108 kre * one of the reported job's processes exited, 876 1.108 kre * but there are more still running, back for more 877 1.95 kre */ 878 1.95 kre if (job->state == JOBRUNNING) 879 1.95 kre continue; 880 1.95 kre } else 881 1.95 kre job = jp; /* we want this, and it is done */ 882 1.95 kre 883 1.106 kre if (job->flags & JOBWANTED) { 884 1.95 kre int rv; 885 1.95 kre 886 1.95 kre job->flags &= ~JOBWANTED; /* got it */ 887 1.95 kre rv = jobstatus(job, 0); 888 1.95 kre VTRACE(DBG_WAIT, ( 889 1.95 kre "wanted %d (%s) done: st=%d", i, 890 1.95 kre job->ref ? job->ref : "", rv)); 891 1.95 kre if (any || job == last) { 892 1.95 kre retval = rv; 893 1.95 kre fpid = job->ref; 894 1.95 kre 895 1.95 kre VTRACE(DBG_WAIT, (" save")); 896 1.95 kre if (pid) { 897 1.95 kre /* 898 1.95 kre * don't need fpid unless we are going 899 1.95 kre * to return it. 900 1.95 kre */ 901 1.95 kre if (fpid == NULL) { 902 1.95 kre /* 903 1.95 kre * this only happens with "wait -n" 904 1.95 kre * (that is, no pid args) 905 1.95 kre */ 906 1.95 kre snprintf(idstring, sizeof idstring, 907 1.118 kre "%d", job->ps[ job->nprocs ? 908 1.118 kre job->nprocs-1 : 0 ].pid); 909 1.95 kre fpid = idstring; 910 1.95 kre } 911 1.95 kre VTRACE(DBG_WAIT, (" (for %s)", fpid)); 912 1.95 kre } 913 1.95 kre } 914 1.95 kre 915 1.95 kre if (job->state == JOBDONE) { 916 1.95 kre VTRACE(DBG_WAIT, (" free")); 917 1.95 kre freejob(job); 918 1.95 kre } 919 1.95 kre 920 1.95 kre if (any || (found > 0 && --found == 0)) { 921 1.95 kre if (pid && fpid) 922 1.95 kre setvar(pid, fpid, 0); 923 1.95 kre VTRACE(DBG_WAIT, (" return %d\n", retval)); 924 1.95 kre return retval; 925 1.95 kre } 926 1.95 kre VTRACE(DBG_WAIT, ("\n")); 927 1.95 kre continue; 928 1.55 christos } 929 1.95 kre 930 1.95 kre /* this is to handle "wait" (no args) */ 931 1.122 kre if (oldwait && job->state == JOBDONE) { 932 1.95 kre VTRACE(DBG_JOBS|DBG_WAIT, ("Cleanup: %d\n", i)); 933 1.55 christos freejob(job); 934 1.95 kre } 935 1.1 cgd } 936 1.1 cgd } 937 1.1 cgd 938 1.1 cgd 939 1.13 cgd int 940 1.55 christos jobidcmd(int argc, char **argv) 941 1.13 cgd { 942 1.1 cgd struct job *jp; 943 1.1 cgd int i; 944 1.92 kre int pg = 0, onep = 0, job = 0; 945 1.92 kre 946 1.92 kre while ((i = nextopt("gjp"))) { 947 1.92 kre switch (i) { 948 1.92 kre case 'g': pg = 1; break; 949 1.92 kre case 'j': job = 1; break; 950 1.92 kre case 'p': onep = 1; break; 951 1.92 kre } 952 1.92 kre } 953 1.92 kre CTRACE(DBG_JOBS, ("jobidcmd%s%s%s%s %s\n", pg ? " -g" : "", 954 1.92 kre onep ? " -p" : "", job ? " -j" : "", jobs_invalid ? " [inv]" : "", 955 1.92 kre *argptr ? *argptr : "<implicit %%>")); 956 1.92 kre if (pg + onep + job > 1) 957 1.92 kre error("-g -j and -p options cannot be combined"); 958 1.92 kre 959 1.92 kre if (argptr[0] && argptr[1]) 960 1.92 kre error("usage: jobid [-g|-p|-r] jobid"); 961 1.1 cgd 962 1.55 christos jp = getjob(*argptr, 0); 963 1.92 kre if (job) { 964 1.116 kre out1fmt("%%%d\n", JNUM(jp)); 965 1.92 kre return 0; 966 1.92 kre } 967 1.92 kre if (pg) { 968 1.92 kre if (jp->pgrp != 0) { 969 1.92 kre out1fmt("%ld\n", (long)jp->pgrp); 970 1.92 kre return 0; 971 1.92 kre } 972 1.92 kre return 1; 973 1.92 kre } 974 1.92 kre if (onep) { 975 1.92 kre i = jp->nprocs - 1; 976 1.92 kre if (i < 0) 977 1.92 kre return 1; 978 1.92 kre out1fmt("%ld\n", (long)jp->ps[i].pid); 979 1.92 kre return 0; 980 1.92 kre } 981 1.1 cgd for (i = 0 ; i < jp->nprocs ; ) { 982 1.27 christos out1fmt("%ld", (long)jp->ps[i].pid); 983 1.55 christos out1c(++i < jp->nprocs ? ' ' : '\n'); 984 1.1 cgd } 985 1.1 cgd return 0; 986 1.1 cgd } 987 1.1 cgd 988 1.123 kre #if JOBS 989 1.123 kre #ifndef SMALL 990 1.123 kre 991 1.123 kre static int 992 1.123 kre stop_me(int sig, int force, int pgrp, pid_t pid) 993 1.123 kre { 994 1.123 kre if (force || (!loginsh && mflag && rootshell)) { 995 1.123 kre struct sigaction sig_dfl, sig_was; 996 1.123 kre 997 1.123 kre sig_dfl.sa_handler = SIG_DFL; 998 1.123 kre sig_dfl.sa_flags = 0; 999 1.123 kre sigemptyset(&sig_dfl.sa_mask); 1000 1.123 kre 1001 1.123 kre (void)sigaction(sig, &sig_dfl, &sig_was); 1002 1.123 kre 1003 1.123 kre if (kill(pgrp ? 0 : pid, sig) == -1) { 1004 1.123 kre sh_warn("suspend myself"); 1005 1.123 kre (void)sigaction(sig, &sig_was, NULL); 1006 1.123 kre error(NULL); 1007 1.123 kre } 1008 1.123 kre 1009 1.123 kre (void)sigaction(sig, &sig_was, NULL); 1010 1.123 kre 1011 1.123 kre return 0; 1012 1.123 kre } 1013 1.123 kre 1014 1.123 kre if (!rootshell) 1015 1.123 kre sh_warnx("subshell environment"); 1016 1.123 kre else if (!mflag) 1017 1.123 kre sh_warnx("job control disabled"); 1018 1.123 kre else if (loginsh) 1019 1.123 kre sh_warnx("login shell"); 1020 1.123 kre else 1021 1.123 kre sh_warnx("not possible??"); 1022 1.123 kre 1023 1.123 kre return 1; 1024 1.123 kre } 1025 1.123 kre 1026 1.123 kre int 1027 1.123 kre suspendcmd(int argc, char **argv) 1028 1.123 kre { 1029 1.123 kre int sig = SIGTSTP; 1030 1.123 kre int force = 0; 1031 1.123 kre int pgrp = 0; 1032 1.123 kre int status = 0; 1033 1.123 kre char *target; 1034 1.123 kre int c; 1035 1.123 kre 1036 1.123 kre while ((c = nextopt("fgs:")) != 0) { 1037 1.123 kre switch (c) { 1038 1.123 kre case 'f': 1039 1.123 kre force = 1; 1040 1.123 kre break; 1041 1.123 kre case 'g': 1042 1.123 kre pgrp = 1; 1043 1.123 kre break; 1044 1.123 kre case 's': 1045 1.123 kre sig = signame_to_signum(optionarg); 1046 1.123 kre 1047 1.123 kre if (sig != SIGSTOP && sig != SIGTSTP && 1048 1.123 kre sig != SIGTTIN && sig != SIGTTOU) 1049 1.123 kre error("bad signal '%s'", optionarg); 1050 1.123 kre break; 1051 1.123 kre } 1052 1.123 kre } 1053 1.123 kre 1054 1.123 kre if (!*argptr) /* suspend myself */ 1055 1.123 kre return stop_me(sig, force, pgrp, getpid()); 1056 1.123 kre 1057 1.123 kre while ((target = *argptr++) != NULL) 1058 1.123 kre { 1059 1.123 kre int pid; 1060 1.123 kre 1061 1.123 kre if (is_number(target)) { 1062 1.123 kre if ((pid = number(target)) == 0) { 1063 1.123 kre sh_warnx("Cannot (yet) suspend kernel (%s)", 1064 1.123 kre target); 1065 1.123 kre status = 1; 1066 1.123 kre continue; 1067 1.123 kre } 1068 1.123 kre } else if ((pid = getjobpgrp(target)) == 0) { 1069 1.123 kre sh_warnx("Unknown job: %s", target); 1070 1.123 kre status = 1; 1071 1.123 kre continue; 1072 1.123 kre } 1073 1.123 kre 1074 1.123 kre if (pid == rootpid || pid == getpid()) { 1075 1.123 kre status |= stop_me(sig, force, pgrp, pid); 1076 1.123 kre continue; 1077 1.123 kre } 1078 1.123 kre 1079 1.123 kre if (pid == 1 || pid == -1) { 1080 1.123 kre sh_warnx("Don't be funny"); 1081 1.123 kre status = 1; 1082 1.123 kre continue; 1083 1.123 kre } 1084 1.123 kre 1085 1.123 kre if (pid > 0 && pgrp) 1086 1.123 kre pid = -pid; 1087 1.123 kre 1088 1.123 kre if (kill(pid, sig) == -1) { 1089 1.123 kre sh_warn("failed to suspend %s", target); 1090 1.123 kre status = 1; 1091 1.123 kre } 1092 1.123 kre } 1093 1.123 kre 1094 1.123 kre return status; 1095 1.123 kre } 1096 1.123 kre #endif /* SMALL */ 1097 1.123 kre #endif /* JOBS */ 1098 1.123 kre 1099 1.55 christos int 1100 1.55 christos getjobpgrp(const char *name) 1101 1.55 christos { 1102 1.55 christos struct job *jp; 1103 1.1 cgd 1104 1.91 kre if (jobs_invalid) 1105 1.123 kre return 0; 1106 1.55 christos jp = getjob(name, 1); 1107 1.55 christos if (jp == 0) 1108 1.55 christos return 0; 1109 1.109 kre return -jp->pgrp; 1110 1.55 christos } 1111 1.1 cgd 1112 1.1 cgd /* 1113 1.1 cgd * Convert a job name to a job structure. 1114 1.1 cgd */ 1115 1.1 cgd 1116 1.1 cgd STATIC struct job * 1117 1.55 christos getjob(const char *name, int noerror) 1118 1.55 christos { 1119 1.55 christos int jobno = -1; 1120 1.21 tls struct job *jp; 1121 1.1 cgd int pid; 1122 1.1 cgd int i; 1123 1.55 christos const char *err_msg = "No such job: %s"; 1124 1.91 kre 1125 1.1 cgd if (name == NULL) { 1126 1.1 cgd #if JOBS 1127 1.55 christos jobno = curjob; 1128 1.1 cgd #endif 1129 1.55 christos err_msg = "No current job"; 1130 1.1 cgd } else if (name[0] == '%') { 1131 1.55 christos if (is_number(name + 1)) { 1132 1.55 christos jobno = number(name + 1) - 1; 1133 1.95 kre } else if (!name[1] || !name[2]) { 1134 1.55 christos switch (name[1]) { 1135 1.1 cgd #if JOBS 1136 1.55 christos case 0: 1137 1.55 christos case '+': 1138 1.55 christos case '%': 1139 1.55 christos jobno = curjob; 1140 1.55 christos err_msg = "No current job"; 1141 1.55 christos break; 1142 1.55 christos case '-': 1143 1.55 christos jobno = curjob; 1144 1.55 christos if (jobno != -1) 1145 1.55 christos jobno = jobtab[jobno].prev_job; 1146 1.55 christos err_msg = "No previous job"; 1147 1.55 christos break; 1148 1.1 cgd #endif 1149 1.55 christos default: 1150 1.55 christos goto check_pattern; 1151 1.55 christos } 1152 1.1 cgd } else { 1153 1.55 christos struct job *found; 1154 1.55 christos check_pattern: 1155 1.55 christos found = NULL; 1156 1.1 cgd for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) { 1157 1.55 christos if (!jp->used || jp->nprocs <= 0) 1158 1.55 christos continue; 1159 1.55 christos if ((name[1] == '?' 1160 1.55 christos && strstr(jp->ps[0].cmd, name + 2)) 1161 1.55 christos || prefix(name + 1, jp->ps[0].cmd)) { 1162 1.55 christos if (found) { 1163 1.55 christos err_msg = "%s: ambiguous"; 1164 1.55 christos found = 0; 1165 1.55 christos break; 1166 1.55 christos } 1167 1.1 cgd found = jp; 1168 1.1 cgd } 1169 1.1 cgd } 1170 1.1 cgd if (found) 1171 1.1 cgd return found; 1172 1.1 cgd } 1173 1.55 christos 1174 1.1 cgd } else if (is_number(name)) { 1175 1.1 cgd pid = number(name); 1176 1.1 cgd for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) { 1177 1.1 cgd if (jp->used && jp->nprocs > 0 1178 1.1 cgd && jp->ps[jp->nprocs - 1].pid == pid) 1179 1.1 cgd return jp; 1180 1.1 cgd } 1181 1.1 cgd } 1182 1.55 christos 1183 1.91 kre if (jobno >= 0 && jobno < njobs) { 1184 1.55 christos jp = jobtab + jobno; 1185 1.55 christos if (jp->used) 1186 1.55 christos return jp; 1187 1.55 christos } 1188 1.55 christos if (!noerror) 1189 1.55 christos error(err_msg, name); 1190 1.55 christos return 0; 1191 1.1 cgd } 1192 1.1 cgd 1193 1.1 cgd 1194 1.110 kre /* 1195 1.110 kre * Find out if there are any running (that is, unwaited upon) 1196 1.110 kre * background children of the current shell. 1197 1.110 kre * 1198 1.110 kre * Return 1/0 (yes, no). 1199 1.110 kre * 1200 1.110 kre * Needed as we cannot optimise away sub-shell creation if 1201 1.110 kre * we have such a child, or a "wait" in that sub-shell would 1202 1.110 kre * observe the already existing job. 1203 1.110 kre */ 1204 1.110 kre int 1205 1.110 kre anyjobs(void) 1206 1.110 kre { 1207 1.110 kre struct job *jp; 1208 1.110 kre int i; 1209 1.110 kre 1210 1.110 kre if (jobs_invalid) 1211 1.110 kre return 0; 1212 1.110 kre 1213 1.110 kre for (i = njobs, jp = jobtab ; --i >= 0 ; jp++) { 1214 1.110 kre if (jp->used) 1215 1.110 kre return 1; 1216 1.110 kre } 1217 1.110 kre 1218 1.110 kre return 0; 1219 1.110 kre } 1220 1.1 cgd 1221 1.1 cgd /* 1222 1.120 kre * Output the (new) POSIX required "[%d] %d" string whenever an 1223 1.120 kre * async (ie: background) job is started in an interactive shell. 1224 1.120 kre * Note that a subshell environment is not regarded as interactive. 1225 1.120 kre */ 1226 1.120 kre void 1227 1.120 kre jobstarted(struct job *jp) 1228 1.120 kre { 1229 1.120 kre if (!iflag || !rootshell) 1230 1.120 kre return; 1231 1.120 kre 1232 1.120 kre outfmt(out2, "[%d] %ld\n", JNUM(jp), 1233 1.120 kre jp->pgrp != 0 ? (long)jp->pgrp : (long)jp->ps->pid); 1234 1.120 kre } 1235 1.120 kre 1236 1.120 kre /* 1237 1.1 cgd * Return a new job structure, 1238 1.1 cgd */ 1239 1.1 cgd 1240 1.1 cgd struct job * 1241 1.55 christos makejob(union node *node, int nprocs) 1242 1.13 cgd { 1243 1.1 cgd int i; 1244 1.1 cgd struct job *jp; 1245 1.1 cgd 1246 1.55 christos if (jobs_invalid) { 1247 1.110 kre VTRACE(DBG_JOBS, ("makejob(%p, %d) clearing jobtab (%d)\n", 1248 1.110 kre (void *)node, nprocs, njobs)); 1249 1.55 christos for (i = njobs, jp = jobtab ; --i >= 0 ; jp++) { 1250 1.55 christos if (jp->used) 1251 1.55 christos freejob(jp); 1252 1.55 christos } 1253 1.55 christos jobs_invalid = 0; 1254 1.55 christos } 1255 1.55 christos 1256 1.1 cgd for (i = njobs, jp = jobtab ; ; jp++) { 1257 1.1 cgd if (--i < 0) { 1258 1.1 cgd INTOFF; 1259 1.1 cgd if (njobs == 0) { 1260 1.1 cgd jobtab = ckmalloc(4 * sizeof jobtab[0]); 1261 1.1 cgd } else { 1262 1.1 cgd jp = ckmalloc((njobs + 4) * sizeof jobtab[0]); 1263 1.12 mycroft memcpy(jp, jobtab, njobs * sizeof jp[0]); 1264 1.17 pk /* Relocate `ps' pointers */ 1265 1.17 pk for (i = 0; i < njobs; i++) 1266 1.17 pk if (jp[i].ps == &jobtab[i].ps0) 1267 1.17 pk jp[i].ps = &jp[i].ps0; 1268 1.1 cgd ckfree(jobtab); 1269 1.1 cgd jobtab = jp; 1270 1.1 cgd } 1271 1.1 cgd jp = jobtab + njobs; 1272 1.97 christos for (i = 4 ; --i >= 0 ; njobs++) { 1273 1.97 christos jobtab[njobs].used = 0; 1274 1.97 christos jobtab[njobs].prev_job = -1; 1275 1.97 christos } 1276 1.1 cgd INTON; 1277 1.1 cgd break; 1278 1.1 cgd } 1279 1.1 cgd if (jp->used == 0) 1280 1.1 cgd break; 1281 1.1 cgd } 1282 1.1 cgd INTOFF; 1283 1.55 christos jp->state = JOBRUNNING; 1284 1.1 cgd jp->used = 1; 1285 1.100 kre jp->flags = pipefail ? JPIPEFAIL : 0; 1286 1.1 cgd jp->nprocs = 0; 1287 1.92 kre jp->pgrp = 0; 1288 1.1 cgd #if JOBS 1289 1.1 cgd jp->jobctl = jobctl; 1290 1.55 christos set_curjob(jp, 1); 1291 1.1 cgd #endif 1292 1.1 cgd if (nprocs > 1) { 1293 1.1 cgd jp->ps = ckmalloc(nprocs * sizeof (struct procstat)); 1294 1.1 cgd } else { 1295 1.1 cgd jp->ps = &jp->ps0; 1296 1.1 cgd } 1297 1.1 cgd INTON; 1298 1.100 kre VTRACE(DBG_JOBS, ("makejob(%p, %d)%s returns %%%d\n", (void *)node, 1299 1.116 kre nprocs, (jp->flags & JPIPEFAIL) ? " PF" : "", JNUM(jp))); 1300 1.1 cgd return jp; 1301 1.19 christos } 1302 1.1 cgd 1303 1.1 cgd 1304 1.1 cgd /* 1305 1.37 lukem * Fork off a subshell. If we are doing job control, give the subshell its 1306 1.1 cgd * own process group. Jp is a job structure that the job is to be added to. 1307 1.1 cgd * N is the command that will be evaluated by the child. Both jp and n may 1308 1.1 cgd * be NULL. The mode parameter can be one of the following: 1309 1.1 cgd * FORK_FG - Fork off a foreground process. 1310 1.1 cgd * FORK_BG - Fork off a background process. 1311 1.1 cgd * FORK_NOJOB - Like FORK_FG, but don't give the process its own 1312 1.1 cgd * process group even if job control is on. 1313 1.1 cgd * 1314 1.1 cgd * When job control is turned off, background processes have their standard 1315 1.1 cgd * input redirected to /dev/null (except for the second and later processes 1316 1.1 cgd * in a pipeline). 1317 1.1 cgd */ 1318 1.1 cgd 1319 1.1 cgd int 1320 1.55 christos forkshell(struct job *jp, union node *n, int mode) 1321 1.13 cgd { 1322 1.72 christos pid_t pid; 1323 1.72 christos int serrno; 1324 1.1 cgd 1325 1.87 kre CTRACE(DBG_JOBS, ("forkshell(%%%d, %p, %d) called\n", 1326 1.116 kre JNUM(jp), n, mode)); 1327 1.87 kre 1328 1.47 christos switch ((pid = fork())) { 1329 1.47 christos case -1: 1330 1.72 christos serrno = errno; 1331 1.87 kre VTRACE(DBG_JOBS, ("Fork failed, errno=%d\n", serrno)); 1332 1.72 christos error("Cannot fork (%s)", strerror(serrno)); 1333 1.47 christos break; 1334 1.47 christos case 0: 1335 1.85 kre SHELL_FORKED(); 1336 1.51 christos forkchild(jp, n, mode, 0); 1337 1.47 christos return 0; 1338 1.47 christos default: 1339 1.51 christos return forkparent(jp, n, mode, pid); 1340 1.1 cgd } 1341 1.47 christos } 1342 1.47 christos 1343 1.47 christos int 1344 1.55 christos forkparent(struct job *jp, union node *n, int mode, pid_t pid) 1345 1.47 christos { 1346 1.117 kre int pgrp = 0; 1347 1.1 cgd 1348 1.53 mycroft if (rootshell && mode != FORK_NOJOB && mflag) { 1349 1.117 kre /* 1350 1.117 kre * The process group ID must always be that of the 1351 1.117 kre * first process created for the job. If this proc 1352 1.117 kre * is the first, that's us, otherwise the pgrp has 1353 1.117 kre * already been determined. 1354 1.117 kre */ 1355 1.53 mycroft if (jp == NULL || jp->nprocs == 0) 1356 1.53 mycroft pgrp = pid; 1357 1.53 mycroft else 1358 1.117 kre pgrp = jp->pgrp; 1359 1.53 mycroft /* This can fail because we are doing it in the child also */ 1360 1.53 mycroft (void)setpgid(pid, pgrp); 1361 1.53 mycroft } 1362 1.1 cgd if (mode == FORK_BG) 1363 1.1 cgd backgndpid = pid; /* set $! */ 1364 1.1 cgd if (jp) { 1365 1.1 cgd struct procstat *ps = &jp->ps[jp->nprocs++]; 1366 1.1 cgd ps->pid = pid; 1367 1.1 cgd ps->status = -1; 1368 1.55 christos ps->cmd[0] = 0; 1369 1.117 kre jp->pgrp = pgrp; /* 0 if !mflag */ 1370 1.55 christos if (/* iflag && rootshell && */ n) 1371 1.55 christos commandtext(ps, n); 1372 1.1 cgd } 1373 1.89 kre CTRACE(DBG_JOBS, ("In parent shell: child = %d (mode %d)\n",pid,mode)); 1374 1.1 cgd return pid; 1375 1.1 cgd } 1376 1.1 cgd 1377 1.47 christos void 1378 1.55 christos forkchild(struct job *jp, union node *n, int mode, int vforked) 1379 1.47 christos { 1380 1.47 christos int wasroot; 1381 1.47 christos int pgrp; 1382 1.47 christos const char *devnull = _PATH_DEVNULL; 1383 1.47 christos const char *nullerr = "Can't open %s"; 1384 1.47 christos 1385 1.51 christos wasroot = rootshell; 1386 1.91 kre CTRACE(DBG_JOBS, ("Child shell %d %sforked from %d (mode %d)\n", 1387 1.91 kre getpid(), vforked?"v":"", getppid(), mode)); 1388 1.103 kre 1389 1.103 kre if (!vforked) { 1390 1.51 christos rootshell = 0; 1391 1.103 kre handler = &main_handler; 1392 1.103 kre } 1393 1.55 christos 1394 1.47 christos closescript(vforked); 1395 1.47 christos clear_traps(vforked); 1396 1.47 christos #if JOBS 1397 1.47 christos if (!vforked) 1398 1.47 christos jobctl = 0; /* do job control only in root shell */ 1399 1.47 christos if (wasroot && mode != FORK_NOJOB && mflag) { 1400 1.47 christos if (jp == NULL || jp->nprocs == 0) 1401 1.47 christos pgrp = getpid(); 1402 1.47 christos else 1403 1.47 christos pgrp = jp->ps[0].pid; 1404 1.53 mycroft /* This can fail because we are doing it in the parent also */ 1405 1.53 mycroft (void)setpgid(0, pgrp); 1406 1.47 christos if (mode == FORK_FG) { 1407 1.47 christos if (tcsetpgrp(ttyfd, pgrp) == -1) 1408 1.47 christos error("Cannot set tty process group (%s) at %d", 1409 1.47 christos strerror(errno), __LINE__); 1410 1.47 christos } 1411 1.47 christos setsignal(SIGTSTP, vforked); 1412 1.47 christos setsignal(SIGTTOU, vforked); 1413 1.47 christos } else if (mode == FORK_BG) { 1414 1.47 christos ignoresig(SIGINT, vforked); 1415 1.47 christos ignoresig(SIGQUIT, vforked); 1416 1.47 christos if ((jp == NULL || jp->nprocs == 0) && 1417 1.47 christos ! fd0_redirected_p ()) { 1418 1.47 christos close(0); 1419 1.47 christos if (open(devnull, O_RDONLY) != 0) 1420 1.47 christos error(nullerr, devnull); 1421 1.47 christos } 1422 1.47 christos } 1423 1.47 christos #else 1424 1.47 christos if (mode == FORK_BG) { 1425 1.47 christos ignoresig(SIGINT, vforked); 1426 1.47 christos ignoresig(SIGQUIT, vforked); 1427 1.47 christos if ((jp == NULL || jp->nprocs == 0) && 1428 1.47 christos ! fd0_redirected_p ()) { 1429 1.47 christos close(0); 1430 1.47 christos if (open(devnull, O_RDONLY) != 0) 1431 1.47 christos error(nullerr, devnull); 1432 1.47 christos } 1433 1.47 christos } 1434 1.47 christos #endif 1435 1.47 christos if (wasroot && iflag) { 1436 1.47 christos setsignal(SIGINT, vforked); 1437 1.47 christos setsignal(SIGQUIT, vforked); 1438 1.47 christos setsignal(SIGTERM, vforked); 1439 1.47 christos } 1440 1.55 christos 1441 1.55 christos if (!vforked) 1442 1.55 christos jobs_invalid = 1; 1443 1.47 christos } 1444 1.47 christos 1445 1.1 cgd /* 1446 1.1 cgd * Wait for job to finish. 1447 1.1 cgd * 1448 1.1 cgd * Under job control we have the problem that while a child process is 1449 1.1 cgd * running interrupts generated by the user are sent to the child but not 1450 1.1 cgd * to the shell. This means that an infinite loop started by an inter- 1451 1.1 cgd * active user may be hard to kill. With job control turned off, an 1452 1.1 cgd * interactive user may place an interactive program inside a loop. If 1453 1.1 cgd * the interactive program catches interrupts, the user doesn't want 1454 1.1 cgd * these interrupts to also abort the loop. The approach we take here 1455 1.1 cgd * is to have the shell ignore interrupt signals while waiting for a 1456 1.115 andvar * foreground process to terminate, and then send itself an interrupt 1457 1.1 cgd * signal if the child process was terminated by an interrupt signal. 1458 1.1 cgd * Unfortunately, some programs want to do a bit of cleanup and then 1459 1.1 cgd * exit on interrupt; unless these processes terminate themselves by 1460 1.1 cgd * sending a signal to themselves (instead of calling exit) they will 1461 1.1 cgd * confuse this approach. 1462 1.1 cgd */ 1463 1.1 cgd 1464 1.1 cgd int 1465 1.55 christos waitforjob(struct job *jp) 1466 1.55 christos { 1467 1.1 cgd #if JOBS 1468 1.10 jtc int mypgrp = getpgrp(); 1469 1.1 cgd #endif 1470 1.1 cgd int status; 1471 1.1 cgd int st; 1472 1.1 cgd 1473 1.1 cgd INTOFF; 1474 1.116 kre VTRACE(DBG_JOBS, ("waitforjob(%%%d) called\n", JNUM(jp))); 1475 1.55 christos while (jp->state == JOBRUNNING) { 1476 1.95 kre dowait(WBLOCK, jp, NULL); 1477 1.1 cgd } 1478 1.1 cgd #if JOBS 1479 1.1 cgd if (jp->jobctl) { 1480 1.47 christos if (tcsetpgrp(ttyfd, mypgrp) == -1) 1481 1.47 christos error("Cannot set tty process group (%s) at %d", 1482 1.47 christos strerror(errno), __LINE__); 1483 1.1 cgd } 1484 1.55 christos if (jp->state == JOBSTOPPED && curjob != jp - jobtab) 1485 1.55 christos set_curjob(jp, 2); 1486 1.1 cgd #endif 1487 1.90 kre status = jobstatus(jp, 1); 1488 1.90 kre 1489 1.1 cgd /* convert to 8 bits */ 1490 1.23 christos if (WIFEXITED(status)) 1491 1.23 christos st = WEXITSTATUS(status); 1492 1.1 cgd #if JOBS 1493 1.23 christos else if (WIFSTOPPED(status)) 1494 1.23 christos st = WSTOPSIG(status) + 128; 1495 1.1 cgd #endif 1496 1.1 cgd else 1497 1.23 christos st = WTERMSIG(status) + 128; 1498 1.87 kre 1499 1.87 kre VTRACE(DBG_JOBS, ("waitforjob: job %d, nproc %d, status %d, st %x\n", 1500 1.116 kre JNUM(jp), jp->nprocs, status, st)); 1501 1.32 mycroft #if JOBS 1502 1.32 mycroft if (jp->jobctl) { 1503 1.32 mycroft /* 1504 1.32 mycroft * This is truly gross. 1505 1.32 mycroft * If we're doing job control, then we did a TIOCSPGRP which 1506 1.32 mycroft * caused us (the shell) to no longer be in the controlling 1507 1.32 mycroft * session -- so we wouldn't have seen any ^C/SIGINT. So, we 1508 1.32 mycroft * intuit from the subprocess exit status whether a SIGINT 1509 1.40 wiz * occurred, and if so interrupt ourselves. Yuck. - mycroft 1510 1.32 mycroft */ 1511 1.32 mycroft if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT) 1512 1.32 mycroft raise(SIGINT); 1513 1.32 mycroft } 1514 1.32 mycroft #endif 1515 1.1 cgd if (! JOBS || jp->state == JOBDONE) 1516 1.1 cgd freejob(jp); 1517 1.1 cgd INTON; 1518 1.1 cgd return st; 1519 1.1 cgd } 1520 1.1 cgd 1521 1.1 cgd 1522 1.1 cgd 1523 1.1 cgd /* 1524 1.108 kre * Wait for a process (any process) to terminate. 1525 1.108 kre * 1526 1.108 kre * If "job" is given (not NULL), then its jobcontrol status (and mflag) 1527 1.108 kre * are used to determine if we wait for stopping/continuing processes or 1528 1.108 kre * only terminating ones, and the decision whether to report to stdout 1529 1.108 kre * or not varies depending what happened, and whether the affected job 1530 1.108 kre * is the one that was requested or not. 1531 1.108 kre * 1532 1.108 kre * If "changed" is not NULL, then the job which changed because a 1533 1.108 kre * process terminated/stopped will be reported by setting *changed, 1534 1.108 kre * if there is any such job, otherwise we set *changed = NULL. 1535 1.1 cgd */ 1536 1.1 cgd 1537 1.1 cgd STATIC int 1538 1.95 kre dowait(int flags, struct job *job, struct job **changed) 1539 1.13 cgd { 1540 1.1 cgd int pid; 1541 1.1 cgd int status; 1542 1.1 cgd struct procstat *sp; 1543 1.1 cgd struct job *jp; 1544 1.1 cgd struct job *thisjob; 1545 1.1 cgd int done; 1546 1.1 cgd int stopped; 1547 1.108 kre int err; 1548 1.1 cgd 1549 1.108 kre VTRACE(DBG_JOBS|DBG_PROCS, ("dowait(%x) called for job %d%s\n", 1550 1.116 kre flags, JNUM(job), changed ? " [report change]" : "")); 1551 1.95 kre 1552 1.95 kre if (changed != NULL) 1553 1.95 kre *changed = NULL; 1554 1.95 kre 1555 1.108 kre /* 1556 1.108 kre * First deal with the kernel, collect info on any (one) of our 1557 1.108 kre * children that has changed state since we last asked. 1558 1.108 kre * (loop if we're interrupted by a signal that we aren't processing) 1559 1.108 kre */ 1560 1.1 cgd do { 1561 1.108 kre err = 0; 1562 1.68 christos pid = waitproc(flags & WBLOCK, job, &status); 1563 1.108 kre if (pid == -1) 1564 1.108 kre err = errno; 1565 1.108 kre VTRACE(DBG_JOBS|DBG_PROCS, 1566 1.108 kre ("wait returns pid %d (e:%d), status %#x (ps=%d)\n", 1567 1.108 kre pid, err, status, pendingsigs)); 1568 1.108 kre } while (pid == -1 && err == EINTR && pendingsigs == 0); 1569 1.108 kre 1570 1.108 kre /* 1571 1.108 kre * if nothing exited/stopped/..., we have nothing else to do 1572 1.108 kre */ 1573 1.1 cgd if (pid <= 0) 1574 1.1 cgd return pid; 1575 1.108 kre 1576 1.108 kre /* 1577 1.108 kre * Otherwise, try to find the process, somewhere in our job table 1578 1.108 kre */ 1579 1.1 cgd INTOFF; 1580 1.1 cgd thisjob = NULL; 1581 1.1 cgd for (jp = jobtab ; jp < jobtab + njobs ; jp++) { 1582 1.1 cgd if (jp->used) { 1583 1.108 kre /* 1584 1.108 kre * For each job that is in use (this is one) 1585 1.108 kre */ 1586 1.108 kre done = 1; /* assume it is finished */ 1587 1.108 kre stopped = 1; /* and has stopped */ 1588 1.108 kre 1589 1.108 kre /* 1590 1.108 kre * Now scan all our child processes of the job 1591 1.108 kre */ 1592 1.1 cgd for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) { 1593 1.1 cgd if (sp->pid == -1) 1594 1.1 cgd continue; 1595 1.108 kre /* 1596 1.108 kre * If the process that changed is the one 1597 1.108 kre * we're looking at, and it was previously 1598 1.108 kre * running (-1) or was stopped (anything else 1599 1.108 kre * and it must have already finished earlier, 1600 1.108 kre * so cannot be the process that just changed) 1601 1.108 kre * then we update its status 1602 1.108 kre */ 1603 1.91 kre if (sp->pid == pid && 1604 1.91 kre (sp->status==-1 || WIFSTOPPED(sp->status))) { 1605 1.87 kre VTRACE(DBG_JOBS | DBG_PROCS, 1606 1.116 kre ("Job %d: changing status of proc %d from %#x to ", 1607 1.116 kre JNUM(jp), pid, sp->status)); 1608 1.108 kre 1609 1.108 kre /* 1610 1.108 kre * If the process continued, 1611 1.108 kre * then update its status to running 1612 1.108 kre * and mark the job running as well. 1613 1.108 kre * 1614 1.108 kre * If it was anything but running 1615 1.108 kre * before, flag it as a change for 1616 1.108 kre * reporting purposes later 1617 1.108 kre */ 1618 1.91 kre if (WIFCONTINUED(status)) { 1619 1.91 kre if (sp->status != -1) 1620 1.95 kre jp->flags |= JOBCHANGED; 1621 1.91 kre sp->status = -1; 1622 1.116 kre jp->state = JOBRUNNING; 1623 1.116 kre VTRACE(DBG_JOBS|DBG_PROCS, 1624 1.116 kre ("running\n")); 1625 1.108 kre } else { 1626 1.108 kre /* otherwise update status */ 1627 1.91 kre sp->status = status; 1628 1.116 kre VTRACE(DBG_JOBS|DBG_PROCS, 1629 1.116 kre ("%#x\n", status)); 1630 1.108 kre } 1631 1.108 kre 1632 1.108 kre /* 1633 1.108 kre * We now know the affected job 1634 1.108 kre */ 1635 1.1 cgd thisjob = jp; 1636 1.95 kre if (changed != NULL) 1637 1.95 kre *changed = jp; 1638 1.1 cgd } 1639 1.108 kre /* 1640 1.108 kre * After any update that might have just 1641 1.108 kre * happened, if this process is running, 1642 1.108 kre * the job is not stopped, or if the process 1643 1.108 kre * simply stopped (not terminated) then the 1644 1.108 kre * job is certainly not completed (done). 1645 1.108 kre */ 1646 1.1 cgd if (sp->status == -1) 1647 1.1 cgd stopped = 0; 1648 1.23 christos else if (WIFSTOPPED(sp->status)) 1649 1.1 cgd done = 0; 1650 1.1 cgd } 1651 1.108 kre 1652 1.108 kre /* 1653 1.108 kre * Once we have examined all processes for the 1654 1.108 kre * job, if we still show it as stopped, then... 1655 1.108 kre */ 1656 1.1 cgd if (stopped) { /* stopped or done */ 1657 1.108 kre /* 1658 1.108 kre * it might be stopped, or finished, decide: 1659 1.108 kre */ 1660 1.55 christos int state = done ? JOBDONE : JOBSTOPPED; 1661 1.91 kre 1662 1.108 kre /* 1663 1.108 kre * If that wasn't the same as it was before 1664 1.108 kre * then update its state, and if it just 1665 1.108 kre * completed, make it be the current job (%%) 1666 1.108 kre */ 1667 1.1 cgd if (jp->state != state) { 1668 1.87 kre VTRACE(DBG_JOBS, 1669 1.87 kre ("Job %d: changing state from %d to %d\n", 1670 1.116 kre JNUM(jp), jp->state, state)); 1671 1.1 cgd jp->state = state; 1672 1.1 cgd #if JOBS 1673 1.55 christos if (done) 1674 1.55 christos set_curjob(jp, 0); 1675 1.1 cgd #endif 1676 1.1 cgd } 1677 1.1 cgd } 1678 1.1 cgd } 1679 1.1 cgd } 1680 1.23 christos 1681 1.108 kre /* 1682 1.108 kre * Now we have scanned all jobs. If we found the job that 1683 1.108 kre * the process that changed state belonged to (we occasionally 1684 1.108 kre * fork processes without associating them with a job, when one 1685 1.108 kre * of those finishes, we simply ignore it, the zombie has been 1686 1.108 kre * cleaned up, which is all that matters) then we need to 1687 1.108 kre * determine if we should say something about it to stdout 1688 1.108 kre */ 1689 1.108 kre 1690 1.95 kre if (thisjob && 1691 1.95 kre (thisjob->state != JOBRUNNING || thisjob->flags & JOBCHANGED)) { 1692 1.55 christos int mode = 0; 1693 1.91 kre 1694 1.55 christos if (!rootshell || !iflag) 1695 1.55 christos mode = SHOW_SIGNALLED; 1696 1.68 christos if ((job == thisjob && (flags & WNOFREE) == 0) || 1697 1.91 kre job != thisjob) 1698 1.55 christos mode = SHOW_SIGNALLED | SHOW_NO_FREE; 1699 1.91 kre if (mode && (flags & WSILENT) == 0) 1700 1.55 christos showjob(out2, thisjob, mode); 1701 1.55 christos else { 1702 1.87 kre VTRACE(DBG_JOBS, 1703 1.108 kre ("Not printing status for %p [%d], " 1704 1.108 kre "mode=%#x rootshell=%d, job=%p [%d]\n", 1705 1.116 kre thisjob, JNUM(thisjob), mode, rootshell, 1706 1.116 kre job, JNUM(job))); 1707 1.95 kre thisjob->flags |= JOBCHANGED; 1708 1.1 cgd } 1709 1.1 cgd } 1710 1.55 christos 1711 1.47 christos INTON; 1712 1.108 kre /* 1713 1.108 kre * Finally tell our caller that something happened (in general all 1714 1.108 kre * anyone tests for is <= 0 (or >0) so the actual pid value here 1715 1.116 kre * doesn't matter much, but we know pid is >0 so we may as well 1716 1.108 kre * give back something meaningful 1717 1.108 kre */ 1718 1.1 cgd return pid; 1719 1.1 cgd } 1720 1.1 cgd 1721 1.1 cgd 1722 1.1 cgd 1723 1.1 cgd /* 1724 1.1 cgd * Do a wait system call. If job control is compiled in, we accept 1725 1.1 cgd * stopped processes. If block is zero, we return a value of zero 1726 1.1 cgd * rather than blocking. 1727 1.1 cgd * 1728 1.1 cgd * System V doesn't have a non-blocking wait system call. It does 1729 1.65 snj * have a SIGCLD signal that is sent to a process when one of its 1730 1.1 cgd * children dies. The obvious way to use SIGCLD would be to install 1731 1.1 cgd * a handler for SIGCLD which simply bumped a counter when a SIGCLD 1732 1.1 cgd * was received, and have waitproc bump another counter when it got 1733 1.1 cgd * the status of a process. Waitproc would then know that a wait 1734 1.1 cgd * system call would not block if the two counters were different. 1735 1.1 cgd * This approach doesn't work because if a process has children that 1736 1.1 cgd * have not been waited for, System V will send it a SIGCLD when it 1737 1.1 cgd * installs a signal handler for SIGCLD. What this means is that when 1738 1.1 cgd * a child exits, the shell will be sent SIGCLD signals continuously 1739 1.1 cgd * until is runs out of stack space, unless it does a wait call before 1740 1.1 cgd * restoring the signal handler. The code below takes advantage of 1741 1.1 cgd * this (mis)feature by installing a signal handler for SIGCLD and 1742 1.1 cgd * then checking to see whether it was called. If there are any 1743 1.1 cgd * children to be waited for, it will be. 1744 1.1 cgd * 1745 1.1 cgd * If neither SYSV nor BSD is defined, we don't implement nonblocking 1746 1.1 cgd * waits at all. In this case, the user will not be informed when 1747 1.116 kre * a background process ends until the next time she runs a real program 1748 1.1 cgd * (as opposed to running a builtin command or just typing return), 1749 1.1 cgd * and the jobs command may give out of date information. 1750 1.1 cgd */ 1751 1.1 cgd 1752 1.1 cgd #ifdef SYSV 1753 1.1 cgd STATIC int gotsigchild; 1754 1.1 cgd 1755 1.1 cgd STATIC int onsigchild() { 1756 1.1 cgd gotsigchild = 1; 1757 1.1 cgd } 1758 1.1 cgd #endif 1759 1.1 cgd 1760 1.1 cgd 1761 1.1 cgd STATIC int 1762 1.55 christos waitproc(int block, struct job *jp, int *status) 1763 1.13 cgd { 1764 1.1 cgd #ifdef BSD 1765 1.38 christos int flags = 0; 1766 1.1 cgd 1767 1.1 cgd #if JOBS 1768 1.91 kre if (mflag || (jp != NULL && jp->jobctl)) 1769 1.91 kre flags |= WUNTRACED | WCONTINUED; 1770 1.1 cgd #endif 1771 1.1 cgd if (block == 0) 1772 1.1 cgd flags |= WNOHANG; 1773 1.91 kre VTRACE(DBG_WAIT, ("waitproc: doing waitpid(flags=%#x)\n", flags)); 1774 1.64 tv return waitpid(-1, status, flags); 1775 1.1 cgd #else 1776 1.1 cgd #ifdef SYSV 1777 1.1 cgd int (*save)(); 1778 1.1 cgd 1779 1.1 cgd if (block == 0) { 1780 1.1 cgd gotsigchild = 0; 1781 1.1 cgd save = signal(SIGCLD, onsigchild); 1782 1.1 cgd signal(SIGCLD, save); 1783 1.1 cgd if (gotsigchild == 0) 1784 1.1 cgd return 0; 1785 1.1 cgd } 1786 1.1 cgd return wait(status); 1787 1.1 cgd #else 1788 1.1 cgd if (block == 0) 1789 1.1 cgd return 0; 1790 1.1 cgd return wait(status); 1791 1.1 cgd #endif 1792 1.1 cgd #endif 1793 1.1 cgd } 1794 1.1 cgd 1795 1.8 jtc /* 1796 1.8 jtc * return 1 if there are stopped jobs, otherwise 0 1797 1.8 jtc */ 1798 1.8 jtc int job_warning = 0; 1799 1.8 jtc int 1800 1.55 christos stoppedjobs(void) 1801 1.8 jtc { 1802 1.21 tls int jobno; 1803 1.21 tls struct job *jp; 1804 1.8 jtc 1805 1.55 christos if (job_warning || jobs_invalid) 1806 1.8 jtc return (0); 1807 1.8 jtc for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) { 1808 1.8 jtc if (jp->used == 0) 1809 1.8 jtc continue; 1810 1.8 jtc if (jp->state == JOBSTOPPED) { 1811 1.8 jtc out2str("You have stopped jobs.\n"); 1812 1.8 jtc job_warning = 2; 1813 1.8 jtc return (1); 1814 1.8 jtc } 1815 1.8 jtc } 1816 1.1 cgd 1817 1.8 jtc return (0); 1818 1.8 jtc } 1819 1.1 cgd 1820 1.1 cgd /* 1821 1.1 cgd * Return a string identifying a command (to be printed by the 1822 1.55 christos * jobs command). 1823 1.1 cgd */ 1824 1.1 cgd 1825 1.1 cgd STATIC char *cmdnextc; 1826 1.1 cgd STATIC int cmdnleft; 1827 1.1 cgd 1828 1.55 christos void 1829 1.55 christos commandtext(struct procstat *ps, union node *n) 1830 1.55 christos { 1831 1.55 christos int len; 1832 1.1 cgd 1833 1.55 christos cmdnextc = ps->cmd; 1834 1.99 kre if (iflag || mflag || sizeof(ps->cmd) <= 60) 1835 1.55 christos len = sizeof(ps->cmd); 1836 1.99 kre else if (sizeof ps->cmd <= 400) 1837 1.99 kre len = 50; 1838 1.99 kre else if (sizeof ps->cmd <= 800) 1839 1.99 kre len = 80; 1840 1.55 christos else 1841 1.55 christos len = sizeof(ps->cmd) / 10; 1842 1.55 christos cmdnleft = len; 1843 1.121 kre (void)cmdtxt(n, 1); 1844 1.55 christos if (cmdnleft <= 0) { 1845 1.55 christos char *p = ps->cmd + len - 4; 1846 1.55 christos p[0] = '.'; 1847 1.55 christos p[1] = '.'; 1848 1.55 christos p[2] = '.'; 1849 1.55 christos p[3] = 0; 1850 1.55 christos } else 1851 1.55 christos *cmdnextc = '\0'; 1852 1.87 kre 1853 1.87 kre VTRACE(DBG_JOBS, 1854 1.99 kre ("commandtext: ps->cmd %p, end %p, left %d\n\t\"%s\"\n", 1855 1.87 kre ps->cmd, cmdnextc, cmdnleft, ps->cmd)); 1856 1.1 cgd } 1857 1.1 cgd 1858 1.1 cgd 1859 1.121 kre /* 1860 1.121 kre * Generate a string describing tree node n & its descendants (recursive calls) 1861 1.121 kre * 1862 1.121 kre * Return true (non-zero) if the output is complete (ends with an operator) 1863 1.121 kre * so no ';' need be added before the following command. Return false (zero) 1864 1.121 kre * if a ';' is needed to terminate the output if it is followed by something 1865 1.121 kre * which is not an operator. 1866 1.121 kre */ 1867 1.121 kre STATIC int 1868 1.121 kre cmdtxt(union node *n, int top) 1869 1.55 christos { 1870 1.1 cgd union node *np; 1871 1.1 cgd struct nodelist *lp; 1872 1.31 christos const char *p; 1873 1.1 cgd int i; 1874 1.1 cgd 1875 1.55 christos if (n == NULL || cmdnleft <= 0) 1876 1.121 kre return 1; 1877 1.1 cgd switch (n->type) { 1878 1.1 cgd case NSEMI: 1879 1.121 kre if (!cmdtxt(n->nbinary.ch1, 0)) 1880 1.121 kre cmdputs(";"); 1881 1.121 kre cmdputs(" "); 1882 1.121 kre return cmdtxt(n->nbinary.ch2, 0); 1883 1.1 cgd case NAND: 1884 1.121 kre (void)cmdtxt(n->nbinary.ch1, 0); 1885 1.1 cgd cmdputs(" && "); 1886 1.121 kre return cmdtxt(n->nbinary.ch2, 0); 1887 1.1 cgd case NOR: 1888 1.121 kre (void) cmdtxt(n->nbinary.ch1, 0); 1889 1.1 cgd cmdputs(" || "); 1890 1.121 kre return cmdtxt(n->nbinary.ch2, 0); 1891 1.83 kre case NDNOT: 1892 1.83 kre cmdputs("! "); 1893 1.83 kre /* FALLTHROUGH */ 1894 1.81 kre case NNOT: 1895 1.81 kre cmdputs("! "); 1896 1.121 kre return cmdtxt(n->nnot.com, 0); 1897 1.81 kre break; 1898 1.1 cgd case NPIPE: 1899 1.1 cgd for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 1900 1.121 kre (void) cmdtxt(lp->n, 0); 1901 1.1 cgd if (lp->next) 1902 1.1 cgd cmdputs(" | "); 1903 1.1 cgd } 1904 1.121 kre if (!top && n->npipe.backgnd) { 1905 1.79 kre cmdputs(" &"); 1906 1.121 kre return 1; 1907 1.121 kre } 1908 1.121 kre return 0; 1909 1.1 cgd case NSUBSHELL: 1910 1.1 cgd cmdputs("("); 1911 1.121 kre (void) cmdtxt(n->nredir.n, 0); 1912 1.1 cgd cmdputs(")"); 1913 1.121 kre return 0; 1914 1.1 cgd case NREDIR: 1915 1.1 cgd case NBACKGND: 1916 1.121 kre return cmdtxt(n->nredir.n, top); 1917 1.1 cgd case NIF: 1918 1.1 cgd cmdputs("if "); 1919 1.121 kre if (!cmdtxt(n->nif.test, 0)) 1920 1.121 kre cmdputs(";"); 1921 1.121 kre cmdputs(" then "); 1922 1.121 kre i = cmdtxt(n->nif.ifpart, 0); 1923 1.55 christos if (n->nif.elsepart) { 1924 1.121 kre if (i == 0) 1925 1.121 kre cmdputs(";"); 1926 1.121 kre cmdputs(" else "); 1927 1.121 kre i = cmdtxt(n->nif.elsepart, 0); 1928 1.121 kre } 1929 1.121 kre if (i == 0) 1930 1.121 kre cmdputs(";"); 1931 1.121 kre cmdputs(" fi"); 1932 1.121 kre return 0; 1933 1.1 cgd case NWHILE: 1934 1.1 cgd cmdputs("while "); 1935 1.1 cgd goto until; 1936 1.1 cgd case NUNTIL: 1937 1.1 cgd cmdputs("until "); 1938 1.80 kre until: 1939 1.121 kre if (!cmdtxt(n->nbinary.ch1, 0)) 1940 1.121 kre cmdputs(";"); 1941 1.121 kre cmdputs(" do "); 1942 1.121 kre if (!cmdtxt(n->nbinary.ch2, 0)) 1943 1.121 kre cmdputs(";"); 1944 1.121 kre cmdputs(" done"); 1945 1.121 kre return 0; 1946 1.1 cgd case NFOR: 1947 1.1 cgd cmdputs("for "); 1948 1.1 cgd cmdputs(n->nfor.var); 1949 1.55 christos cmdputs(" in "); 1950 1.55 christos cmdlist(n->nfor.args, 1); 1951 1.55 christos cmdputs("; do "); 1952 1.121 kre if (!cmdtxt(n->nfor.body, 0)) 1953 1.121 kre cmdputs(";"); 1954 1.121 kre cmdputs(" done"); 1955 1.121 kre return 0; 1956 1.1 cgd case NCASE: 1957 1.1 cgd cmdputs("case "); 1958 1.1 cgd cmdputs(n->ncase.expr->narg.text); 1959 1.55 christos cmdputs(" in "); 1960 1.55 christos for (np = n->ncase.cases; np; np = np->nclist.next) { 1961 1.121 kre (void) cmdtxt(np->nclist.pattern, 0); 1962 1.55 christos cmdputs(") "); 1963 1.121 kre (void) cmdtxt(np->nclist.body, 0); 1964 1.82 kre switch (n->type) { /* switch (not if) for later */ 1965 1.82 kre case NCLISTCONT: 1966 1.121 kre cmdputs(" ;& "); 1967 1.82 kre break; 1968 1.82 kre default: 1969 1.121 kre cmdputs(" ;; "); 1970 1.82 kre break; 1971 1.82 kre } 1972 1.55 christos } 1973 1.55 christos cmdputs("esac"); 1974 1.121 kre return 0; 1975 1.1 cgd case NDEFUN: 1976 1.1 cgd cmdputs(n->narg.text); 1977 1.55 christos cmdputs("() { ... }"); 1978 1.121 kre return 0; 1979 1.1 cgd case NCMD: 1980 1.55 christos cmdlist(n->ncmd.args, 1); 1981 1.55 christos cmdlist(n->ncmd.redirect, 0); 1982 1.121 kre if (!top && n->ncmd.backgnd) { 1983 1.79 kre cmdputs(" &"); 1984 1.121 kre return 1; 1985 1.121 kre } 1986 1.121 kre return 0; 1987 1.1 cgd case NARG: 1988 1.1 cgd cmdputs(n->narg.text); 1989 1.121 kre return 0; 1990 1.1 cgd case NTO: 1991 1.1 cgd p = ">"; i = 1; goto redir; 1992 1.46 christos case NCLOBBER: 1993 1.46 christos p = ">|"; i = 1; goto redir; 1994 1.1 cgd case NAPPEND: 1995 1.1 cgd p = ">>"; i = 1; goto redir; 1996 1.1 cgd case NTOFD: 1997 1.1 cgd p = ">&"; i = 1; goto redir; 1998 1.1 cgd case NFROM: 1999 1.1 cgd p = "<"; i = 0; goto redir; 2000 1.1 cgd case NFROMFD: 2001 1.1 cgd p = "<&"; i = 0; goto redir; 2002 1.29 christos case NFROMTO: 2003 1.29 christos p = "<>"; i = 0; goto redir; 2004 1.80 kre redir: 2005 1.77 kre if (n->nfile.fd != i) 2006 1.77 kre cmdputi(n->nfile.fd); 2007 1.1 cgd cmdputs(p); 2008 1.1 cgd if (n->type == NTOFD || n->type == NFROMFD) { 2009 1.77 kre if (n->ndup.dupfd < 0) 2010 1.77 kre cmdputs("-"); 2011 1.77 kre else 2012 1.77 kre cmdputi(n->ndup.dupfd); 2013 1.1 cgd } else { 2014 1.121 kre (void) cmdtxt(n->nfile.fname, 0); 2015 1.1 cgd } 2016 1.121 kre return 0; 2017 1.1 cgd case NHERE: 2018 1.1 cgd case NXHERE: 2019 1.1 cgd cmdputs("<<..."); 2020 1.121 kre return 0; 2021 1.1 cgd default: 2022 1.1 cgd cmdputs("???"); 2023 1.121 kre return 0; 2024 1.1 cgd } 2025 1.121 kre return 0; 2026 1.1 cgd } 2027 1.1 cgd 2028 1.55 christos STATIC void 2029 1.55 christos cmdlist(union node *np, int sep) 2030 1.55 christos { 2031 1.55 christos for (; np; np = np->narg.next) { 2032 1.55 christos if (!sep) 2033 1.55 christos cmdputs(" "); 2034 1.121 kre (void) cmdtxt(np, 0); 2035 1.55 christos if (sep && np->narg.next) 2036 1.55 christos cmdputs(" "); 2037 1.55 christos } 2038 1.55 christos } 2039 1.1 cgd 2040 1.1 cgd 2041 1.1 cgd STATIC void 2042 1.55 christos cmdputs(const char *s) 2043 1.55 christos { 2044 1.55 christos const char *p, *str = 0; 2045 1.55 christos char c, cc[2] = " "; 2046 1.55 christos char *nextc; 2047 1.55 christos int nleft; 2048 1.1 cgd int subtype = 0; 2049 1.55 christos int quoted = 0; 2050 1.55 christos static char vstype[16][4] = { "", "}", "-", "+", "?", "=", 2051 1.84 kre "#", "##", "%", "%%", "}" }; 2052 1.1 cgd 2053 1.1 cgd p = s; 2054 1.55 christos nextc = cmdnextc; 2055 1.55 christos nleft = cmdnleft; 2056 1.55 christos while (nleft > 0 && (c = *p++) != 0) { 2057 1.55 christos switch (c) { 2058 1.86 kre case CTLNONL: 2059 1.86 kre c = '\0'; 2060 1.86 kre break; 2061 1.55 christos case CTLESC: 2062 1.55 christos c = *p++; 2063 1.55 christos break; 2064 1.55 christos case CTLVAR: 2065 1.1 cgd subtype = *p++; 2066 1.86 kre if (subtype & VSLINENO) { /* undo LINENO hack */ 2067 1.84 kre if ((subtype & VSTYPE) == VSLENGTH) 2068 1.86 kre str = "${#LINENO"; /*}*/ 2069 1.84 kre else 2070 1.86 kre str = "${LINENO"; /*}*/ 2071 1.84 kre while (is_digit(*p)) 2072 1.84 kre p++; 2073 1.84 kre } else if ((subtype & VSTYPE) == VSLENGTH) 2074 1.86 kre str = "${#"; /*}*/ 2075 1.55 christos else 2076 1.86 kre str = "${"; /*}*/ 2077 1.55 christos if (!(subtype & VSQUOTE) != !(quoted & 1)) { 2078 1.55 christos quoted ^= 1; 2079 1.55 christos c = '"'; 2080 1.84 kre } else { 2081 1.55 christos c = *str++; 2082 1.84 kre } 2083 1.55 christos break; 2084 1.86 kre case CTLENDVAR: /*{*/ 2085 1.84 kre c = '}'; 2086 1.84 kre if (quoted & 1) 2087 1.84 kre str = "\""; 2088 1.55 christos quoted >>= 1; 2089 1.1 cgd subtype = 0; 2090 1.55 christos break; 2091 1.55 christos case CTLBACKQ: 2092 1.55 christos c = '$'; 2093 1.55 christos str = "(...)"; 2094 1.55 christos break; 2095 1.55 christos case CTLBACKQ+CTLQUOTE: 2096 1.55 christos c = '"'; 2097 1.55 christos str = "$(...)\""; 2098 1.55 christos break; 2099 1.55 christos case CTLARI: 2100 1.55 christos c = '$'; 2101 1.86 kre if (*p == ' ') 2102 1.86 kre p++; 2103 1.86 kre str = "(("; /*))*/ 2104 1.55 christos break; 2105 1.86 kre case CTLENDARI: /*((*/ 2106 1.55 christos c = ')'; 2107 1.55 christos str = ")"; 2108 1.55 christos break; 2109 1.55 christos case CTLQUOTEMARK: 2110 1.55 christos quoted ^= 1; 2111 1.55 christos c = '"'; 2112 1.55 christos break; 2113 1.84 kre case CTLQUOTEEND: 2114 1.84 kre quoted >>= 1; 2115 1.84 kre c = '"'; 2116 1.84 kre break; 2117 1.55 christos case '=': 2118 1.55 christos if (subtype == 0) 2119 1.55 christos break; 2120 1.55 christos str = vstype[subtype & VSTYPE]; 2121 1.55 christos if (subtype & VSNUL) 2122 1.55 christos c = ':'; 2123 1.55 christos else 2124 1.86 kre c = *str++; /*{*/ 2125 1.55 christos if (c != '}') 2126 1.55 christos quoted <<= 1; 2127 1.84 kre else if (*p == CTLENDVAR) 2128 1.84 kre c = *str++; 2129 1.84 kre subtype = 0; 2130 1.55 christos break; 2131 1.55 christos case '\'': 2132 1.55 christos case '\\': 2133 1.55 christos case '"': 2134 1.55 christos case '$': 2135 1.55 christos /* These can only happen inside quotes */ 2136 1.55 christos cc[0] = c; 2137 1.55 christos str = cc; 2138 1.55 christos c = '\\'; 2139 1.55 christos break; 2140 1.55 christos default: 2141 1.1 cgd break; 2142 1.1 cgd } 2143 1.84 kre if (c != '\0') do { /* c == 0 implies nothing in str */ 2144 1.55 christos *nextc++ = c; 2145 1.55 christos } while (--nleft > 0 && str && (c = *str++)); 2146 1.55 christos str = 0; 2147 1.55 christos } 2148 1.55 christos if ((quoted & 1) && nleft) { 2149 1.55 christos *nextc++ = '"'; 2150 1.55 christos nleft--; 2151 1.1 cgd } 2152 1.55 christos cmdnleft = nleft; 2153 1.55 christos cmdnextc = nextc; 2154 1.1 cgd } 2155