00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #ifndef lint
00038 static char sccsid[] = "@(#)jobs.c 5.1 (Berkeley) 3/7/91";
00039 #endif
00040
00041 #include "shell.h"
00042 #if JOBS
00043 #include "sgtty.h"
00044 #undef CEOF
00045 #endif
00046 #include "main.h"
00047 #include "parser.h"
00048 #include "nodes.h"
00049 #include "jobs.h"
00050 #include "options.h"
00051 #include "trap.h"
00052 #include "signames.h"
00053 #include "syntax.h"
00054 #include "input.h"
00055 #include "output.h"
00056 #include "memalloc.h"
00057 #include "error.h"
00058 #include "mystring.h"
00059 #include "redir.h"
00060 #include <sys/types.h>
00061 #include <fcntl.h>
00062 #include <signal.h>
00063 #include <errno.h>
00064 #ifdef BSD
00065 #include <sys/types.h>
00066 #include <sys/wait.h>
00067 #include <sys/time.h>
00068 #include <sys/resource.h>
00069 #endif
00070 #if POSIX
00071 #include <sys/wait.h>
00072 #endif
00073
00074
00075
00076 struct job *jobtab;
00077 int njobs;
00078 MKINIT pid_t backgndpid = -1;
00079 #if JOBS
00080 int initialpgrp;
00081 pid_t curjob;
00082 #endif
00083
00084 #ifdef __STDC__
00085 STATIC void restartjob(struct job *);
00086 STATIC struct job *getjob(char *);
00087 STATIC void freejob(struct job *);
00088 STATIC int procrunning(int);
00089 STATIC int dowait(int, struct job *);
00090 STATIC int waitproc(int, int *);
00091 STATIC char *commandtext(union node *);
00092 #else
00093 STATIC void restartjob();
00094 STATIC struct job *getjob();
00095 STATIC void freejob();
00096 STATIC int procrunning();
00097 STATIC int dowait();
00098 STATIC int waitproc();
00099 STATIC char *commandtext();
00100 #endif
00101
00102
00103
00104 #if JOBS
00105
00106
00107
00108
00109
00110
00111
00112
00113 MKINIT int jobctl;
00114
00115 void
00116 setjobctl(on) {
00117 int ldisc;
00118
00119 if (on == jobctl || rootshell == 0)
00120 return;
00121 if (on) {
00122 do {
00123 if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
00124 out2str("ash: can't access tty; job control turned off\n");
00125 jflag = 0;
00126 return;
00127 }
00128 if (initialpgrp == -1)
00129 initialpgrp = getpgrp(0);
00130 else if (initialpgrp != getpgrp(0)) {
00131 killpg(initialpgrp, SIGTTIN);
00132 continue;
00133 }
00134 } while (0);
00135 if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
00136 out2str("ash: need new tty driver to run job control; job control turned off\n");
00137 jflag = 0;
00138 return;
00139 }
00140 setsignal(SIGTSTP);
00141 setsignal(SIGTTOU);
00142 setpgrp(0, rootpid);
00143 ioctl(2, TIOCSPGRP, (char *)&rootpid);
00144 } else {
00145 setpgrp(0, initialpgrp);
00146 ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
00147 setsignal(SIGTSTP);
00148 setsignal(SIGTTOU);
00149 }
00150 jobctl = on;
00151 }
00152 #endif
00153
00154
00155 #ifdef mkinit
00156
00157 SHELLPROC {
00158 backgndpid = -1;
00159 #if JOBS
00160 jobctl = 0;
00161 #endif
00162 }
00163
00164 #endif
00165
00166
00167
00168 #if JOBS
00169 fgcmd(argc, argv) char **argv; {
00170 struct job *jp;
00171 int pgrp;
00172 int status;
00173
00174 jp = getjob(argv[1]);
00175 if (jp->jobctl == 0)
00176 error("job not created under job control");
00177 pgrp = jp->ps[0].pid;
00178 ioctl(2, TIOCSPGRP, (char *)&pgrp);
00179 restartjob(jp);
00180 INTOFF;
00181 status = waitforjob(jp);
00182 INTON;
00183 return status;
00184 }
00185
00186
00187 bgcmd(argc, argv) char **argv; {
00188 struct job *jp;
00189
00190 do {
00191 jp = getjob(*++argv);
00192 if (jp->jobctl == 0)
00193 error("job not created under job control");
00194 restartjob(jp);
00195 } while (--argc > 1);
00196 return 0;
00197 }
00198
00199
00200 STATIC void
00201 restartjob(jp)
00202 struct job *jp;
00203 {
00204 struct procstat *ps;
00205 int i;
00206
00207 if (jp->state == JOBDONE)
00208 return;
00209 INTOFF;
00210 killpg(jp->ps[0].pid, SIGCONT);
00211 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
00212 if ((ps->status & 0377) == 0177) {
00213 ps->status = -1;
00214 jp->state = 0;
00215 }
00216 }
00217 INTON;
00218 }
00219 #endif
00220
00221
00222 int
00223 jobscmd(argc, argv) char **argv; {
00224 showjobs(0);
00225 return 0;
00226 }
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238 void
00239 showjobs(change) {
00240 int jobno;
00241 int procno;
00242 int i;
00243 struct job *jp;
00244 struct procstat *ps;
00245 int col;
00246 char s[64];
00247
00248 TRACE(("showjobs(%d) called\n", change));
00249 while (dowait(0, (struct job *)NULL) > 0);
00250 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
00251 if (! jp->used)
00252 continue;
00253 if (jp->nprocs == 0) {
00254 freejob(jp);
00255 continue;
00256 }
00257 if (change && ! jp->changed)
00258 continue;
00259 procno = jp->nprocs;
00260 for (ps = jp->ps ; ; ps++) {
00261 if (ps == jp->ps)
00262 fmtstr(s, 64, "[%d] %d ", jobno, ps->pid);
00263 else
00264 fmtstr(s, 64, " %d ", ps->pid);
00265 out1str(s);
00266 col = strlen(s);
00267 s[0] = '\0';
00268 if (ps->status == -1) {
00269
00270 } else if ((ps->status & 0xFF) == 0) {
00271 fmtstr(s, 64, "Exit %d", ps->status >> 8);
00272 } else {
00273 i = ps->status;
00274 #if JOBS
00275 if ((i & 0xFF) == 0177)
00276 i >>= 8;
00277 #endif
00278 if ((i & 0x7F) <= MAXSIG && sigmesg[i & 0x7F])
00279 scopy(sigmesg[i & 0x7F], s);
00280 else
00281 fmtstr(s, 64, "Signal %d", i & 0x7F);
00282 if (i & 0x80)
00283 strcat(s, " (core dumped)");
00284 }
00285 out1str(s);
00286 col += strlen(s);
00287 do {
00288 out1c(' ');
00289 col++;
00290 } while (col < 30);
00291 out1str(ps->cmd);
00292 out1c('\n');
00293 if (--procno <= 0)
00294 break;
00295 }
00296 jp->changed = 0;
00297 if (jp->state == JOBDONE) {
00298 freejob(jp);
00299 }
00300 }
00301 }
00302
00303
00304
00305
00306
00307
00308 STATIC void
00309 freejob(jp)
00310 struct job *jp;
00311 {
00312 struct procstat *ps;
00313 int i;
00314
00315 INTOFF;
00316 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
00317 if (ps->cmd != nullstr)
00318 ckfree(ps->cmd);
00319 }
00320 if (jp->ps != &jp->ps0)
00321 ckfree(jp->ps);
00322 jp->used = 0;
00323 #if JOBS
00324 if (curjob == jp - jobtab + 1)
00325 curjob = 0;
00326 #endif
00327 INTON;
00328 }
00329
00330
00331
00332 int
00333 waitcmd(argc, argv) char **argv; {
00334 struct job *job;
00335 int status;
00336 struct job *jp;
00337
00338 if (argc > 1) {
00339 job = getjob(argv[1]);
00340 } else {
00341 job = NULL;
00342 }
00343 for (;;) {
00344 if (job != NULL) {
00345 if (job->state) {
00346 status = job->ps[job->nprocs - 1].status;
00347 if ((status & 0xFF) == 0)
00348 status = status >> 8 & 0xFF;
00349 #if JOBS
00350 else if ((status & 0xFF) == 0177)
00351 status = (status >> 8 & 0x7F) + 128;
00352 #endif
00353 else
00354 status = (status & 0x7F) + 128;
00355 if (! iflag)
00356 freejob(job);
00357 return status;
00358 }
00359 } else {
00360 for (jp = jobtab ; ; jp++) {
00361 if (jp >= jobtab + njobs) {
00362 return 0;
00363 }
00364 if (jp->used && jp->state == 0)
00365 break;
00366 }
00367 }
00368 dowait(1, (struct job *)NULL);
00369 }
00370 }
00371
00372
00373
00374 jobidcmd(argc, argv) char **argv; {
00375 struct job *jp;
00376 int i;
00377
00378 jp = getjob(argv[1]);
00379 for (i = 0 ; i < jp->nprocs ; ) {
00380 out1fmt("%d", jp->ps[i].pid);
00381 out1c(++i < jp->nprocs? ' ' : '\n');
00382 }
00383 return 0;
00384 }
00385
00386
00387
00388
00389
00390
00391
00392 STATIC struct job *
00393 getjob(name)
00394 char *name;
00395 {
00396 int jobno;
00397 register struct job *jp;
00398 int pid;
00399 int i;
00400
00401 if (name == NULL) {
00402 #if JOBS
00403 currentjob:
00404 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
00405 error("No current job");
00406 return &jobtab[jobno - 1];
00407 #else
00408 error("No current job");
00409 #endif
00410 } else if (name[0] == '%') {
00411 if (is_digit(name[1])) {
00412 jobno = number(name + 1);
00413 if (jobno > 0 && jobno <= njobs
00414 && jobtab[jobno - 1].used != 0)
00415 return &jobtab[jobno - 1];
00416 #if JOBS
00417 } else if (name[1] == '%' && name[2] == '\0') {
00418 goto currentjob;
00419 #endif
00420 } else {
00421 register struct job *found = NULL;
00422 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
00423 if (jp->used && jp->nprocs > 0
00424 && prefix(name + 1, jp->ps[0].cmd)) {
00425 if (found)
00426 error("%s: ambiguous", name);
00427 found = jp;
00428 }
00429 }
00430 if (found)
00431 return found;
00432 }
00433 } else if (is_number(name)) {
00434 pid = number(name);
00435 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
00436 if (jp->used && jp->nprocs > 0
00437 && jp->ps[jp->nprocs - 1].pid == pid)
00438 return jp;
00439 }
00440 }
00441 error("No such job: %s", name);
00442 }
00443
00444
00445
00446
00447
00448
00449
00450 struct job *
00451 makejob(node, nprocs)
00452 union node *node;
00453 {
00454 int i;
00455 struct job *jp;
00456
00457 for (i = njobs, jp = jobtab ; ; jp++) {
00458 if (--i < 0) {
00459 INTOFF;
00460 if (njobs == 0) {
00461 jobtab = ckmalloc(4 * sizeof jobtab[0]);
00462 } else {
00463 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
00464 bcopy(jobtab, jp, njobs * sizeof jp[0]);
00465 for (i= 0; i<njobs; i++)
00466 {
00467 if (jobtab[i].ps == &jobtab[i].ps0)
00468 jp[i].ps= &jp[i].ps0;
00469 }
00470 ckfree(jobtab);
00471 jobtab = jp;
00472 }
00473 jp = jobtab + njobs;
00474 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
00475 INTON;
00476 break;
00477 }
00478 if (jp->used == 0)
00479 break;
00480 }
00481 INTOFF;
00482 jp->state = 0;
00483 jp->used = 1;
00484 jp->changed = 0;
00485 jp->nprocs = 0;
00486 #if JOBS
00487 jp->jobctl = jobctl;
00488 #endif
00489 if (nprocs > 1) {
00490 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
00491 } else {
00492 jp->ps = &jp->ps0;
00493 }
00494 INTON;
00495 TRACE(("makejob(0x%x, %d) returns %%%d\n", (int)node, nprocs, jp - jobtab + 1));
00496 return jp;
00497 }
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515 int
00516 forkshell(jp, n, mode)
00517 union node *n;
00518 struct job *jp;
00519 {
00520 int pid;
00521 int pgrp;
00522
00523 TRACE(("forkshell(%%%d, 0x%x, %d) called\n", jp - jobtab, (int)n, mode));
00524 INTOFF;
00525 pid = fork();
00526 if (pid == -1) {
00527 TRACE(("Fork failed, errno=%d\n", errno));
00528 INTON;
00529 error("Cannot fork");
00530 }
00531 if (pid == 0) {
00532 struct job *p;
00533 int wasroot;
00534 int i;
00535
00536 TRACE(("Child shell %d\n", getpid()));
00537 wasroot = rootshell;
00538 rootshell = 0;
00539 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
00540 if (p->used)
00541 freejob(p);
00542 closescript();
00543 INTON;
00544 clear_traps();
00545 #if JOBS
00546 jobctl = 0;
00547 if (wasroot && mode != FORK_NOJOB && jflag) {
00548 if (jp == NULL || jp->nprocs == 0)
00549 pgrp = getpid();
00550 else
00551 pgrp = jp->ps[0].pid;
00552 setpgrp(0, pgrp);
00553 if (mode == FORK_FG) {
00554
00555 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
00556 error("TIOCSPGRP failed, errno=%d\n", errno);
00557 }
00558 setsignal(SIGTSTP);
00559 setsignal(SIGTTOU);
00560 } else if (mode == FORK_BG) {
00561 ignoresig(SIGINT);
00562 ignoresig(SIGQUIT);
00563 if ((jp == NULL || jp->nprocs == 0)
00564 && ! fd0_redirected_p ()) {
00565 close(0);
00566 if (open("/dev/null", O_RDONLY) != 0)
00567 error("Can't open /dev/null");
00568 }
00569 }
00570 #else
00571 if (mode == FORK_BG) {
00572 ignoresig(SIGINT);
00573 ignoresig(SIGQUIT);
00574 if ((jp == NULL || jp->nprocs == 0)
00575 && ! fd0_redirected_p ()) {
00576 close(0);
00577 if (open("/dev/null", O_RDONLY) != 0)
00578 error("Can't open /dev/null");
00579 }
00580 }
00581 #endif
00582 if (wasroot && iflag) {
00583 setsignal(SIGINT);
00584 setsignal(SIGQUIT);
00585 setsignal(SIGTERM);
00586 }
00587 return pid;
00588 }
00589 if (rootshell && mode != FORK_NOJOB && jflag) {
00590 if (jp == NULL || jp->nprocs == 0)
00591 pgrp = pid;
00592 else
00593 pgrp = jp->ps[0].pid;
00594 #if JOBS
00595 setpgrp(pid, pgrp);
00596 #endif
00597 }
00598 if (mode == FORK_BG)
00599 backgndpid = pid;
00600 if (jp) {
00601 struct procstat *ps = &jp->ps[jp->nprocs++];
00602 ps->pid = pid;
00603 ps->status = -1;
00604 ps->cmd = nullstr;
00605 if (iflag && rootshell && n)
00606 ps->cmd = commandtext(n);
00607 }
00608 INTON;
00609 TRACE(("In parent shell: child = %d\n", pid));
00610 return pid;
00611 }
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634 int
00635 waitforjob(jp)
00636 register struct job *jp;
00637 {
00638 #if JOBS
00639 int mypgrp = getpgrp(0);
00640 #endif
00641 int status;
00642 int st;
00643
00644 INTOFF;
00645 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
00646 while (jp->state == 0 && dowait(1, jp) != -1) ;
00647 #if JOBS
00648 if (jp->jobctl) {
00649 if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
00650 error("TIOCSPGRP failed, errno=%d\n", errno);
00651 }
00652 if (jp->state == JOBSTOPPED)
00653 curjob = jp - jobtab + 1;
00654 #endif
00655 status = jp->ps[jp->nprocs - 1].status;
00656
00657 if ((status & 0xFF) == 0)
00658 st = status >> 8 & 0xFF;
00659 #if JOBS
00660 else if ((status & 0xFF) == 0177)
00661 st = (status >> 8 & 0x7F) + 128;
00662 #endif
00663 else
00664 st = (status & 0x7F) + 128;
00665 if (! JOBS || jp->state == JOBDONE)
00666 freejob(jp);
00667 CLEAR_PENDING_INT;
00668 if ((status & 0x7F) == SIGINT)
00669 kill(getpid(), SIGINT);
00670 INTON;
00671 return st;
00672 }
00673
00674
00675
00676
00677
00678
00679
00680 STATIC int
00681 dowait(block, job)
00682 struct job *job;
00683 {
00684 int pid;
00685 int status;
00686 struct procstat *sp;
00687 struct job *jp;
00688 struct job *thisjob;
00689 int done;
00690 int stopped;
00691 int core;
00692
00693 TRACE(("dowait(%d) called\n", block));
00694 do {
00695 pid = waitproc(block, &status);
00696 TRACE(("wait returns %d, status=%d, errno=%d\n",
00697 pid, status, errno));
00698 } while (pid == -1 && errno == EINTR);
00699 if (pid <= 0)
00700 return pid;
00701 INTOFF;
00702 thisjob = NULL;
00703 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
00704 if (jp->used) {
00705 done = 1;
00706 stopped = 1;
00707 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
00708 if (sp->pid == -1)
00709 continue;
00710 if (sp->pid == pid) {
00711 TRACE(("Changin status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
00712 sp->status = status;
00713 thisjob = jp;
00714 }
00715 if (sp->status == -1)
00716 stopped = 0;
00717 else if ((sp->status & 0377) == 0177)
00718 done = 0;
00719 }
00720 if (stopped) {
00721 int state = done? JOBDONE : JOBSTOPPED;
00722 if (jp->state != state) {
00723 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
00724 jp->state = state;
00725 #if JOBS
00726 if (done && curjob == jp - jobtab + 1)
00727 curjob = 0;
00728 #endif
00729 }
00730 }
00731 }
00732 }
00733 INTON;
00734 if (! rootshell || ! iflag || (job && thisjob == job)) {
00735 #if JOBS
00736 if ((status & 0xFF) == 0177)
00737 status >>= 8;
00738 #endif
00739 core = status & 0x80;
00740 status &= 0x7F;
00741 if (status != 0 && status != SIGINT && status != SIGPIPE) {
00742 if (thisjob != job)
00743 outfmt(out2, "%d: ", pid);
00744 #if JOBS
00745 if (status == SIGTSTP && rootshell && iflag)
00746 outfmt(out2, "%%%d ", job - jobtab + 1);
00747 #endif
00748 if (status <= MAXSIG && sigmesg[status])
00749 out2str(sigmesg[status]);
00750 else
00751 outfmt(out2, "Signal %d", status);
00752 if (core)
00753 out2str(" - core dumped");
00754 out2c('\n');
00755 flushout(&errout);
00756 } else {
00757 TRACE(("Not printing status: status=%d\n", status));
00758 }
00759 } else {
00760 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
00761 if (thisjob)
00762 thisjob->changed = 1;
00763 }
00764 return pid;
00765 }
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798 #ifdef SYSV
00799 STATIC int gotsigchild;
00800
00801 STATIC int onsigchild() {
00802 gotsigchild = 1;
00803 }
00804 #endif
00805
00806
00807 STATIC int
00808 waitproc(block, status)
00809 int *status;
00810 {
00811 #ifdef BSD
00812 int flags;
00813
00814 #if JOBS
00815 flags = WUNTRACED;
00816 #else
00817 flags = 0;
00818 #endif
00819 if (block == 0)
00820 flags |= WNOHANG;
00821 return wait3((union wait *)status, flags, (struct rusage *)NULL);
00822 #else
00823 #ifdef SYSV
00824 int (*save)();
00825
00826 if (block == 0) {
00827 gotsigchild = 0;
00828 save = signal(SIGCLD, onsigchild);
00829 signal(SIGCLD, save);
00830 if (gotsigchild == 0)
00831 return 0;
00832 }
00833 return wait(status);
00834 #else
00835 #if POSIX
00836 return waitpid(-1, status, block == 0 ? WNOHANG : 0);
00837 #else
00838 if (block == 0)
00839 return 0;
00840 return wait(status);
00841 #endif
00842 #endif
00843 #endif
00844 }
00845
00846
00847
00848
00849
00850
00851
00852
00853 STATIC char *cmdnextc;
00854 STATIC int cmdnleft;
00855 STATIC void cmdtxt(), cmdputs();
00856
00857 STATIC char *
00858 commandtext(n)
00859 union node *n;
00860 {
00861 char *name;
00862
00863 cmdnextc = name = ckmalloc(50);
00864 cmdnleft = 50 - 4;
00865 cmdtxt(n);
00866 *cmdnextc = '\0';
00867 return name;
00868 }
00869
00870
00871 STATIC void
00872 cmdtxt(n)
00873 union node *n;
00874 {
00875 union node *np;
00876 struct nodelist *lp;
00877 char *p;
00878 int i;
00879 char s[2];
00880
00881 if (n == NULL) return;
00882
00883 switch (n->type) {
00884 case NSEMI:
00885 cmdtxt(n->nbinary.ch1);
00886 cmdputs("; ");
00887 cmdtxt(n->nbinary.ch2);
00888 break;
00889 case NAND:
00890 cmdtxt(n->nbinary.ch1);
00891 cmdputs(" && ");
00892 cmdtxt(n->nbinary.ch2);
00893 break;
00894 case NOR:
00895 cmdtxt(n->nbinary.ch1);
00896 cmdputs(" || ");
00897 cmdtxt(n->nbinary.ch2);
00898 break;
00899 case NPIPE:
00900 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
00901 cmdtxt(lp->n);
00902 if (lp->next)
00903 cmdputs(" | ");
00904 }
00905 break;
00906 case NSUBSHELL:
00907 cmdputs("(");
00908 cmdtxt(n->nredir.n);
00909 cmdputs(")");
00910 break;
00911 case NREDIR:
00912 case NBACKGND:
00913 cmdtxt(n->nredir.n);
00914 break;
00915 case NIF:
00916 cmdputs("if ");
00917 cmdtxt(n->nif.test);
00918 cmdputs("; then ");
00919 cmdtxt(n->nif.ifpart);
00920 cmdputs("...");
00921 break;
00922 case NWHILE:
00923 cmdputs("while ");
00924 goto until;
00925 case NUNTIL:
00926 cmdputs("until ");
00927 until:
00928 cmdtxt(n->nbinary.ch1);
00929 cmdputs("; do ");
00930 cmdtxt(n->nbinary.ch2);
00931 cmdputs("; done");
00932 break;
00933 case NFOR:
00934 cmdputs("for ");
00935 cmdputs(n->nfor.var);
00936 cmdputs(" in ...");
00937 break;
00938 case NCASE:
00939 cmdputs("case ");
00940 cmdputs(n->ncase.expr->narg.text);
00941 cmdputs(" in ...");
00942 break;
00943 case NDEFUN:
00944 cmdputs(n->narg.text);
00945 cmdputs("() ...");
00946 break;
00947 case NCMD:
00948 for (np = n->ncmd.args ; np ; np = np->narg.next) {
00949 cmdtxt(np);
00950 if (np->narg.next)
00951 cmdputs(" ");
00952 }
00953 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
00954 cmdputs(" ");
00955 cmdtxt(np);
00956 }
00957 break;
00958 case NARG:
00959 cmdputs(n->narg.text);
00960 break;
00961 case NTO:
00962 p = ">"; i = 1; goto redir;
00963 case NAPPEND:
00964 p = ">>"; i = 1; goto redir;
00965 case NTOFD:
00966 p = ">&"; i = 1; goto redir;
00967 case NFROM:
00968 p = "<"; i = 0; goto redir;
00969 case NFROMFD:
00970 p = "<&"; i = 0; goto redir;
00971 redir:
00972 if (n->nfile.fd != i) {
00973 s[0] = n->nfile.fd + '0';
00974 s[1] = '\0';
00975 cmdputs(s);
00976 }
00977 cmdputs(p);
00978 if (n->type == NTOFD || n->type == NFROMFD) {
00979 s[0] = n->ndup.dupfd + '0';
00980 s[1] = '\0';
00981 cmdputs(s);
00982 } else {
00983 cmdtxt(n->nfile.fname);
00984 }
00985 break;
00986 case NHERE:
00987 case NXHERE:
00988 cmdputs("<<...");
00989 break;
00990 default:
00991 cmdputs("???");
00992 break;
00993 }
00994 }
00995
00996
00997
00998 STATIC void
00999 cmdputs(s)
01000 char *s;
01001 {
01002 register char *p, *q;
01003 register char c;
01004 int subtype = 0;
01005
01006 if (cmdnleft <= 0)
01007 return;
01008 p = s;
01009 q = cmdnextc;
01010 while ((c = *p++) != '\0') {
01011 if (c == CTLESC)
01012 *q++ = *p++;
01013 else if (c == CTLVAR) {
01014 *q++ = '$';
01015 if (--cmdnleft > 0)
01016 *q++ = '{';
01017 subtype = *p++;
01018 } else if (c == '=' && subtype != 0) {
01019 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
01020 subtype = 0;
01021 } else if (c == CTLENDVAR) {
01022 *q++ = '}';
01023 } else if (c == CTLBACKQ | c == CTLBACKQ+CTLQUOTE)
01024 cmdnleft++;
01025 else
01026 *q++ = c;
01027 if (--cmdnleft <= 0) {
01028 *q++ = '.';
01029 *q++ = '.';
01030 *q++ = '.';
01031 break;
01032 }
01033 }
01034 cmdnextc = q;
01035 }