home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 5 / FreshFish_July-August1994.bin / bbs / util / jade-3.0.lha / Jade / src / unix_processes.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-19  |  25.3 KB  |  996 lines

  1. /* unix_processes.c -- Subprocess handling for Unix
  2.    Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
  3.  
  4. This file is part of Jade.
  5.  
  6. Jade is free software; you can redistribute it and/or modify it
  7. under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. Jade is distributed in the hope that it will be useful, but
  12. WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with Jade; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include "jade.h"
  21. #include "jade_protos.h"
  22.  
  23. #include <sys/types.h>
  24. #include <sys/wait.h>
  25. #include <sys/signal.h>
  26. #include <sys/fcntl.h>
  27. #include <sys/time.h>
  28. #include <sys/stat.h>
  29. #include <sys/ioctl.h>
  30. #include <errno.h>
  31. #include <unistd.h>
  32. #include <termios.h>
  33.  
  34. _PR void protect_procs(void);
  35. _PR void unprotect_procs(void);
  36. _PR void readfromproc(int);
  37. _PR int  writetoproc(VALUE, u_char *);
  38. _PR void proc_mark(VALUE);
  39. _PR void proc_sweep(void);
  40. _PR void proc_prin(VALUE, VALUE);
  41. _PR void sys_proc_init(void);
  42. _PR void sys_proc_kill(void);
  43.  
  44. #define USE_SIGACTION
  45.  
  46. #ifdef USE_SIGACTION
  47. static struct sigaction ChldAct;
  48. static sigset_t ChldSet;
  49. #endif
  50.  
  51. struct Proc
  52. {
  53.     u_char    pr_Type;
  54.     char    pr_Status;    /* PR_?? value */
  55.     struct Proc *pr_Next;
  56.     pid_t    pr_Pid;
  57.     /* pr_Stdin is where we write, pr_Stdout where we read, they may be the
  58.        same.  */
  59.     int        pr_Stdin, pr_Stdout;
  60.     VALUE    pr_OutputStream;
  61.     int        pr_ExitStatus;
  62.     VALUE    pr_ExitFunc;
  63.     VALUE    pr_File;
  64.     VALUE    pr_Argv;
  65. };
  66.  
  67. /* <= 0 means process not running, > 0 means could be running...  */
  68. #define PR_STOPPED  2        /* waiting to be continued */
  69. #define PR_RUNNING  1        /* running merrily */
  70. #define PR_DEAD        0        /* nothing happening on this obj */
  71. #define PR_EXITED  -1        /* process dead but no EOF from pty */
  72.  
  73. /* Handy debugging macro */
  74. #if 0
  75. # define DB(x) fprintf x
  76. #else
  77. # define DB(x)
  78. #endif
  79.  
  80. static struct Proc *ProcChain;
  81. static int ProcRunCount;
  82.  
  83. static void
  84. callexitfunc(struct Proc *pr)
  85. {
  86.     if(!NILP(pr->pr_ExitFunc))
  87.     {
  88.     int oldgci = GCinhibit;
  89.     GCinhibit = TRUE;
  90.     calllisp1(pr->pr_ExitFunc, pr);
  91.     GCinhibit = oldgci;
  92.     }
  93. }
  94.  
  95. /*
  96.  * Checks if any of my children are zombies, takes appropriate action.
  97.  */
  98. static void
  99. checkforzombies(void)
  100. {
  101.     int status;
  102.     pid_t pid;
  103.     if(!ProcRunCount)
  104.     return;
  105.     while((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0)
  106.     {
  107.     struct Proc *pr = ProcChain;
  108. #ifdef DEBUG
  109.     settitlefmt("SIGCHLD: pid %d -- status 0x%x", pid, status);
  110. #endif
  111.     while(pr)
  112.     {
  113.         if((pr->pr_Status > 0) && (pr->pr_Pid == pid))
  114.         break;
  115.         pr = pr->pr_Next;
  116.     }
  117.     if(pr)
  118.     {
  119.         if(WIFSTOPPED(status))
  120.         pr->pr_Status = PR_STOPPED;
  121.         else
  122.         {
  123.         pr->pr_ExitStatus = status;
  124.         ProcRunCount--;
  125. #if 0
  126.         if(pr->pr_Stdout)
  127.             close(pr->pr_Stdout);
  128.         if(pr->pr_Stdin && (pr->pr_Stdin != pr->pr_Stdout))
  129.             close(pr->pr_Stdin);
  130.         pr->pr_Stdout = pr->pr_Stdin = 0;
  131.         pr->pr_Status = PR_DEAD;
  132. #else
  133.         /* It seems that I can't just nuke the pty once the child's
  134.            dead -- there can be data pending on it still. So, I set
  135.            pr_Status to an in-between value and hope to get an eof
  136.            over pr_Stdin RSN
  137.            Another consideration is what happens if the process I ran
  138.            on the pty forked another process which is still using
  139.            my pty. This means that I don't get an EOF until it
  140.            exits (if it does). hmmm...    */
  141.  
  142.         if(pr->pr_Stdout || pr->pr_Stdin)
  143.             pr->pr_Status = PR_EXITED;
  144.         else
  145.         {
  146.             pr->pr_Status = PR_DEAD;
  147.             callexitfunc(pr);
  148.             pr->pr_File = pr->pr_Argv = sym_nil;
  149.         }
  150. #endif
  151.         }
  152.     }
  153.     }
  154. }
  155.  
  156. /*
  157.  * This semaphorey thing protects all operations done on process structures
  158.  * from SIGCHLD and the process reaping it causes.
  159.  */
  160. static int ProcMutex = -1;
  161. static bool GotSig;
  162. INLINE void
  163. protect_procs(void)
  164. {
  165.     ProcMutex++;
  166. }
  167. void
  168. unprotect_procs(void)
  169. {
  170.     if((ProcMutex == 0) && GotSig)
  171.     {
  172.     /* Have to leave (ProcMutex == 0) while looking for zombies.  */
  173.     GotSig = FALSE;
  174.     checkforzombies();
  175.     }
  176.     ProcMutex--;
  177. }
  178.  
  179. static void
  180. sigchld_handler(int sig)
  181. {
  182.     if(ProcMutex < 0)
  183.     checkforzombies();
  184.     else
  185.     GotSig = TRUE;
  186. #ifndef USE_SIGACTION
  187.     signal(SIGCHLD, sigchld_handler);
  188. #endif
  189. }
  190.  
  191. void
  192. readfromproc(int fd)
  193. {
  194.     struct Proc *pr = ProcChain;
  195.     protect_procs();
  196.     while(pr)
  197.     {
  198.     if((pr->pr_Status != PR_DEAD) && (pr->pr_Stdout == fd))
  199.         break;
  200.     pr = pr->pr_Next;
  201.     }
  202.     if(pr)
  203.     {
  204.     u_char buf[1025];
  205.     int actual;
  206.     cursor(CurrVW, CURS_OFF);
  207.     do {
  208.         if((actual = read(fd, buf, 1024)) > 0)
  209.         {
  210.         buf[actual] = 0;
  211.         streamputs(pr->pr_OutputStream, buf, FALSE);
  212.         }
  213.     } while((actual > 0) || (errno == EINTR));
  214.  
  215.     /* what happens when a child closes the pty slave (or dies)???
  216.        it seems that I get EIO on Linux. This might handle most
  217.        situations (or should I change !EWOULDBLOCK to EIO??)  */
  218.     if((actual <= 0) && (errno != EWOULDBLOCK) && (errno != EAGAIN))
  219.     {
  220.         /* assume eof  */
  221.         FD_CLR(pr->pr_Stdout, &FdReadSet);
  222.         FdReadAction[pr->pr_Stdout] = NULL;
  223.         close(pr->pr_Stdout);
  224.         if(pr->pr_Stdin && (pr->pr_Stdin != pr->pr_Stdout))
  225.         close(pr->pr_Stdin);
  226.         pr->pr_Stdout = pr->pr_Stdin = 0;
  227.  
  228.         /* This means that the process has already exited and we were
  229.            just waiting for the dregs of its output.  */
  230.         if(pr->pr_Status < 0)
  231.         {
  232.         pr->pr_Status = PR_DEAD;
  233.         callexitfunc(pr);
  234.         pr->pr_File = pr->pr_Argv = sym_nil;
  235.         }
  236.     }
  237.     refreshworld();
  238.     cursor(CurrVW, CURS_ON);
  239.     }
  240.     unprotect_procs();
  241. }
  242.  
  243. int
  244. writetoproc(VALUE pr, u_char *buf)
  245. {
  246.     int act = 0;
  247.     if(!PROCESSP(pr))
  248.     return(0);
  249.     protect_procs();
  250.     if(VPROC(pr)->pr_Status == PR_RUNNING)
  251.     {
  252.     if(VPROC(pr)->pr_Stdin)
  253.     {
  254.         /* This will block. Needs to handle EINTR as well (oh well...)  */
  255.         act = write(VPROC(pr)->pr_Stdin, buf, strlen(buf));
  256.     }
  257.     if(act < 0)
  258.     {
  259.         settitlefmt("Error: %s", VSTR(geterrstring()));
  260.         act = 0;
  261.     }
  262.     }
  263.     else
  264.     cmd_signal(sym_process_error, list_2(pr, MKSTR("Not running")));
  265.     unprotect_procs();
  266.     return(act);
  267. }
  268.  
  269. static bool
  270. signalprocess(struct Proc *pr, int sig)
  271. {
  272.     bool rc = TRUE;
  273.     protect_procs();
  274.     if(pr->pr_Stdin)
  275.     {
  276.     pid_t gid;
  277. #ifdef SIGNALS_VIA_CHARS
  278.     switch(sig)
  279.     {
  280.         struct termios term;
  281.     case SIGINT:
  282.         tcgetattr(pr->pr_Stdin, &term);
  283.         write(pr->pr_Stdin, &term.c_cc[VINTR], 1);
  284.         break;
  285.     case SIGQUIT:
  286.         tcgetattr(pr->pr_Stdin, &term);
  287.         write(pr->pr_Stdin, &term.c_cc[VQUIT], 1);
  288.         break;
  289.     case SIGTSTP:
  290.         /* This doesn't work?? sending SIGSTOP directly does :) */
  291.         tcgetattr(pr->pr_Stdin, &term);
  292.         write(pr->pr_Stdin, &term.c_cc[VSUSP], 1);
  293.         break;
  294.     default:
  295. #endif
  296.         gid = tcgetpgrp(pr->pr_Stdin);
  297.         if(gid != -1)
  298.         killpg(gid, sig);
  299.         else if(pr->pr_Status != PR_DEAD)
  300.         killpg(pr->pr_Pid, sig);
  301.         else
  302.         rc = FALSE;
  303. #ifdef SIGNALS_VIA_CHARS
  304.     }
  305. #endif
  306.     }
  307.     else if(pr->pr_Status != PR_DEAD)
  308.     killpg(pr->pr_Pid, sig);
  309.     else
  310.     rc = FALSE;
  311.     unprotect_procs();
  312.     return(rc);
  313. }
  314.  
  315. /*
  316.  * This is only called during GC, when the process isn't being referenced.
  317.  * it will already have been taken out of the chain
  318.  */
  319. static void
  320. killproc(struct Proc *pr)
  321. {
  322.     protect_procs();
  323.     if(pr->pr_Status != PR_DEAD)
  324.     {
  325.     if(pr->pr_Status == PR_RUNNING)
  326.     {
  327.         /* is this too heavy-handed?? */
  328.         if(!signalprocess(pr, SIGKILL))
  329.         killpg(pr->pr_Pid, SIGKILL);
  330.         waitpid(pr->pr_Pid, &pr->pr_ExitStatus, 0);
  331.         ProcRunCount--;
  332.     }
  333.     if(pr->pr_Stdout)
  334.     {
  335.         FD_CLR(pr->pr_Stdout, &FdReadSet);
  336.         FdReadAction[pr->pr_Stdout] = NULL;
  337.         close(pr->pr_Stdout);
  338.     }
  339.     if(pr->pr_Stdin && (pr->pr_Stdin != pr->pr_Stdout))
  340.         close(pr->pr_Stdin);
  341.     }
  342.     mystrfree(pr);
  343.     unprotect_procs();
  344. }
  345.  
  346. static int
  347. getpty(char *slavenam)
  348. {
  349.     char c;
  350.     int i, master;
  351.     struct stat statb;
  352.     for(c = FIRST_PTY_LETTER; c < 'z'; c++)
  353.     {
  354.     for(i = 0; i < 16; i++)
  355.     {
  356.         sprintf(slavenam, "/dev/pty%c%x", c, i);
  357.         if(stat(slavenam, &statb) < 0)
  358.         goto none;
  359.         if((master = open(slavenam, O_RDWR)) >= 0)
  360.         {
  361.         slavenam[sizeof("/dev/")-1] = 't';
  362.         if(access(slavenam, R_OK | W_OK) == 0)
  363.             return(master);
  364.         close(master);
  365.         }
  366.     }
  367.     }
  368. none:
  369.     cmd_signal(sym_process_error, LIST_1(MKSTR("Can't find spare pty")));
  370.     return(-1);
  371. }
  372.  
  373. /*
  374.  * does the dirty stuff of getting the process running. if `async' is
  375.  * TRUE then return straight away, otherwise shovel all output to
  376.  * the correct stream and return when the process dies.
  377.  */
  378. static bool
  379. runproc(struct Proc *pr, u_char *file, char **argv, bool async)
  380. {
  381.     bool rc = FALSE;
  382.     protect_procs();
  383.     if(pr->pr_Status == PR_DEAD)
  384.     {
  385.     int master;
  386.     char slavenam[32];
  387.     pr->pr_ExitStatus = -1;
  388.     if((master = getpty(slavenam)) >= 0)
  389.     {
  390.         switch(pr->pr_Pid = fork())
  391.         {
  392.         int slave;
  393.         struct termios st;
  394.         case 0:
  395.         if(setsid() < 0)
  396.         {
  397.             perror("child: setsid()");
  398.             exit(255);
  399.         }
  400.         if((slave = open(slavenam, O_RDWR)) < 0)
  401.         {
  402.             perror("child: open(slave)");
  403.             exit(255);
  404.         }
  405.         close(master);
  406.         dup2(slave, 0);
  407.         dup2(slave, 1);
  408.         dup2(slave, 2);
  409.         if(slave > 2)
  410.             close(slave);
  411. #ifdef TIOCSCTTY
  412.         ioctl(slave, TIOCSCTTY, 0);
  413. #endif
  414.         tcgetattr(0, &st);
  415.         st.c_iflag = 0;
  416.         st.c_oflag = 0;
  417.         st.c_cflag = B9600 | CS8 | CREAD;
  418.         st.c_lflag = ISIG;
  419.         st.c_cc[VMIN] = 1;
  420.         st.c_cc[VTIME] = 0;
  421.         tcsetattr(0, TCSANOW, &st);
  422.         execvp(file, (char **)argv);
  423.         perror("child: execvp");
  424.         exit(255);
  425.         case -1:
  426.         perror("fork()");
  427.         break;
  428.         default:
  429.         pr->pr_Stdout = master;
  430.         pr->pr_Stdin = master;
  431.         pr->pr_Status = PR_RUNNING;
  432.         if(async)
  433.         {
  434.             /* So that write's to the process block, set up another
  435.                fd for writing to.  */
  436.             if((pr->pr_Stdin = dup(master)) < 0)
  437.             {
  438.             perror("dup(master)");
  439.             pr->pr_Stdin = master;
  440.             }
  441.             else
  442.             fcntl(pr->pr_Stdin, F_SETFD, 1);
  443.             fcntl(master, F_SETFD, 1);
  444.             fcntl(master, F_SETFL, O_NONBLOCK);
  445.             FD_SET(master, &FdReadSet);
  446.             FdReadAction[master] = readfromproc;
  447.             ProcRunCount++;
  448.         }
  449.         else
  450.         {
  451.             u_char buf[1025];
  452.             int actual;
  453.             do {
  454.             actual = read(master, buf, 1024);
  455.             if(actual > 0)
  456.             {
  457.                 buf[actual] = 0;
  458.                 streamputs(&pr->pr_OutputStream, buf, FALSE);
  459.             }
  460.             } while((actual > 0) || (errno == EINTR));
  461.             waitpid(pr->pr_Pid, &pr->pr_ExitStatus, 0);
  462.             close(pr->pr_Stdout);
  463.             if(pr->pr_Stdin && (pr->pr_Stdin != pr->pr_Stdout))
  464.             close(pr->pr_Stdin);
  465.             pr->pr_Stdin = pr->pr_Stdout = 0;
  466.             pr->pr_Status = PR_DEAD;
  467.             callexitfunc(pr);
  468.         }
  469.         rc = TRUE;
  470.         break;
  471.         }
  472.     }
  473.     }
  474.     else
  475.     cmd_signal(sym_process_error, list_2(pr, MKSTR("Already running")));
  476.     unprotect_procs();
  477.     return(rc);
  478. }
  479.  
  480. void
  481. proc_mark(VALUE pr)
  482. {
  483.     MARKVAL(VPROC(pr)->pr_OutputStream);
  484.     MARKVAL(VPROC(pr)->pr_ExitFunc);
  485.     MARKVAL(VPROC(pr)->pr_File);
  486.     MARKVAL(VPROC(pr)->pr_Argv);
  487. }
  488. void
  489. proc_sweep(void)
  490. {
  491.     struct Proc *pr = ProcChain;
  492.     ProcChain = NULL;
  493.     while(pr)
  494.     {
  495.     struct Proc *nxt = pr->pr_Next;
  496.     if(!GC_MARKEDP(pr))
  497.         killproc(pr);
  498.     else
  499.     {
  500.         GC_CLR(pr);
  501.         pr->pr_Next = ProcChain;
  502.         ProcChain = pr;
  503.     }
  504.     pr = nxt;
  505.     }
  506. }
  507. void
  508. proc_prin(VALUE strm, VALUE obj)
  509. {
  510.     struct Proc *pr = VPROC(obj);
  511.     u_char buf[40];
  512.     streamputs(strm, "#<process", FALSE);
  513.     protect_procs();
  514.     switch(pr->pr_Status)
  515.     {
  516.     case PR_RUNNING:
  517.     streamputs(strm, " running: ", FALSE);
  518.     streamputs(strm, VSTR(pr->pr_File), TRUE);
  519.     break;
  520.     case PR_STOPPED:
  521.     streamputs(strm, " stopped: ", FALSE);
  522.     streamputs(strm, VSTR(pr->pr_File), TRUE);
  523.     break;
  524.     case PR_DEAD:
  525.     case PR_EXITED:
  526.     if(pr->pr_ExitStatus != -1)
  527.     {
  528.         sprintf(buf, " exited: 0x%x", pr->pr_ExitStatus);
  529.         streamputs(strm, buf, FALSE);
  530.         if(pr->pr_Status == PR_EXITED)
  531.         streamputs(strm, " [waiting for eof]", FALSE);
  532.     }
  533.     break;
  534.     }
  535.     unprotect_procs();
  536.     streamputc(strm, '>');
  537. }
  538.  
  539. _PR VALUE cmd_make_process(VALUE stream, VALUE exitfn);
  540. DEFUN("make-process", cmd_make_process, subr_make_process, (VALUE stream, VALUE exitfn), V_Subr2, DOC_make_process) /*
  541. ::doc:make_process::
  542. (make-process [OUTPUT-STREAM] [EXIT-FUNCTION]) <UNIX-ONLY>
  543. Creates a new process-object, OUTPUT-STREAM is where all output from this
  544. process goes, EXIT-FUNCTION is a function to call each time a process running
  545. on this object exits.
  546. ::end:: */
  547. {
  548.     struct Proc *pr = mystralloc(sizeof(struct Proc));
  549.     if(pr)
  550.     {
  551.     pr->pr_Type = V_Process;
  552.     pr->pr_Next = ProcChain;
  553.     ProcChain = pr;
  554.     pr->pr_Status = PR_DEAD;
  555.     pr->pr_Pid = 0;
  556.     pr->pr_Stdin = pr->pr_Stdout = 0;
  557.     pr->pr_OutputStream = sym_nil;
  558.     pr->pr_ExitStatus = -1;
  559.     pr->pr_File = sym_nil;
  560.     pr->pr_Argv = sym_nil;
  561.     pr->pr_OutputStream = stream;
  562.     pr->pr_ExitFunc = exitfn;
  563.     return(pr);
  564.     }
  565.     return(NULL);
  566. }
  567.  
  568. _PR VALUE cmd_fork_process(VALUE proc, VALUE file, VALUE vargv);
  569. DEFUN("fork-process", cmd_fork_process, subr_fork_process, (VALUE proc, VALUE file, VALUE vargv), V_Subr3, DOC_fork_process) /*
  570. ::doc:fork_process::
  571. (fork-process PROCESS FILE-NAME ARGV) <UNIX-ONLY>
  572. Starts a process running on process-object PROCESS. The child-process runs
  573. asynchronously with the editor.
  574.  
  575. FILE-NAME is the filename of the binary image, it will be searched for in
  576. all directories listed in the `PATH' environment variable.
  577. ARGV is a vector of all arguments to give to the process (including
  578. argument zero, normally the name of the process).
  579. ::end:: */
  580. {
  581.     char **argv;
  582.     VALUE res = sym_nil;
  583.     DECLARE1(proc, PROCESSP);
  584.     DECLARE2(file, STRINGP);
  585.     DECLARE3(vargv, VECTORP);
  586.     protect_procs();
  587.     argv = mystralloc(sizeof(char *) * (VVECT(vargv)->vc_Size + 1));
  588.     if(argv)
  589.     {
  590.     int i;
  591.     for(i = 0; i < VVECT(vargv)->vc_Size; i++)
  592.     {
  593.         if(STRINGP(VVECT(vargv)->vc_Array[i]))
  594.         argv[i] = VSTR(VVECT(vargv)->vc_Array[i]);
  595.         else
  596.         argv[i] = "";
  597.     }
  598.     argv[i] = NULL;
  599.     if(runproc(VPROC(proc), VSTR(file), argv, TRUE))
  600.     {
  601.         VPROC(proc)->pr_File = file;
  602.         VPROC(proc)->pr_Argv = vargv;
  603.         res = proc;
  604.     }
  605.     mystrfree(argv);
  606.     }
  607.     unprotect_procs();
  608.     return(res);
  609. }
  610. _PR VALUE cmd_run_process(VALUE proc, VALUE file, VALUE vargv);
  611. DEFUN("run-process", cmd_run_process, subr_run_process, (VALUE proc, VALUE file, VALUE vargv), V_Subr3, DOC_run_process) /*
  612. ::doc:run_process::
  613. (run-process PROCESS FILE-NAME ARGV) <UNIX-ONLY>
  614. Starts a process running on process-object PROCESS. Waits for the child to
  615. exit, then returns the exit-value of the child.
  616.  
  617. FILE-NAME is the filename of the binary image, it will be searched for in
  618. all directories listed in the `PATH' environment variable.
  619. ARGV is a vector of all arguments to give to the process (including
  620. argument zero, normally the name of the process).
  621. ::end:: */
  622. {
  623.     char **argv;
  624.     VALUE res = sym_nil;
  625.     DECLARE1(proc, PROCESSP);
  626.     DECLARE2(file, STRINGP);
  627.     DECLARE3(vargv, VECTORP);
  628.     protect_procs();
  629.     argv = mystralloc(sizeof(char *) * (VVECT(vargv)->vc_Size + 1));
  630.     if(argv)
  631.     {
  632.     int i;
  633.     for(i = 0; i < VVECT(vargv)->vc_Size; i++)
  634.     {
  635.         if(STRINGP(VVECT(vargv)->vc_Array[i]))
  636.         argv[i] = VSTR(VVECT(vargv)->vc_Array[i]);
  637.         else
  638.         argv[i] = "";
  639.     }
  640.     argv[i] = NULL;
  641.     if(runproc(VPROC(proc), VSTR(file), argv, FALSE))
  642.         res = newnumber(VPROC(proc)->pr_ExitStatus);
  643.     mystrfree(argv);
  644.     }
  645.     unprotect_procs();
  646.     return(res);
  647. }
  648.  
  649. _PR VALUE cmd_signal_process(VALUE proc, VALUE sig);
  650. DEFUN("signal-process", cmd_signal_process, subr_signal_process, (VALUE proc, VALUE sig), V_Subr2, DOC_signal_process) /*
  651. ::doc:signal_process::
  652. (signal-process PROCESS SIGNAL) <UNIX-ONLY>
  653. If PROCESS is running asynchronously (or has been, and the pty is still being
  654. used by a child) then send signal number SIGNAL to all processes running under
  655. PROCESS's pseudo-terminal (if the process-group of the pseudo-terminal is
  656. unobtainable, send the signal to the process group with PROCESS as leader).
  657. ::end:: */
  658. {
  659.     VALUE res = sym_nil;
  660.     DECLARE1(proc, PROCESSP);
  661.     DECLARE2(sig, NUMBERP);
  662.     protect_procs();
  663.     if(VPROC(proc)->pr_Status > 0)
  664.     {
  665.     if(signalprocess(VPROC(proc), VNUM(sig)))
  666.         res = sym_t;
  667.     }
  668.     else
  669.     res = cmd_signal(sym_process_error, list_2(proc, MKSTR("Not running")));
  670.     unprotect_procs();
  671.     return(res);
  672. }
  673.  
  674. _PR VALUE cmd_interrupt_process(VALUE proc);
  675. DEFUN("interrupt-process", cmd_interrupt_process, subr_interrupt_process, (VALUE proc), V_Subr1, DOC_interrupt_process) /*
  676. ::doc:interrupt_process::
  677. (interrupt-process PROCESS) <UNIX-ONLY>
  678. Do (signal-process PROCESS SIGINT) or equivalent.
  679. ::end:: */
  680. {
  681.     return(cmd_signal_process(proc, newnumber(SIGINT)));
  682. }
  683.  
  684. _PR VALUE cmd_kill_process(VALUE proc);
  685. DEFUN("kill-process", cmd_kill_process, subr_kill_process, (VALUE proc), V_Subr1, DOC_kill_process) /*
  686. ::doc:kill_process::
  687. (kill-process PROCESS) <UNIX-ONLY>
  688. Do (signal-process PROCESS SIGKILL) or equivalent.
  689. ::end:: */
  690. {
  691.     return(cmd_signal_process(proc, newnumber(SIGKILL)));
  692. }
  693.  
  694. _PR VALUE cmd_stop_process(VALUE proc);
  695. DEFUN("stop-process", cmd_stop_process, subr_stop_process, (VALUE proc), V_Subr1, DOC_stop_process) /*
  696. ::doc:stop_process::
  697. (stop-process PROCESS) <UNIX-ONLY>
  698. Suspends execution of PROCESS, see `continue-process'.
  699. ::end:: */
  700. {
  701.     return(cmd_signal_process(proc, newnumber(SIGSTOP)));
  702. }
  703.  
  704. _PR VALUE cmd_continue_process(VALUE proc);
  705. DEFUN("continue-process", cmd_continue_process, subr_continue_process, (VALUE proc), V_Subr1, DOC_continue_process) /*
  706. ::doc:continue_process::
  707. (continue-process PROCESS) <UNIX-ONLY>
  708. Restarts PROCESS after it has been stopped (via `stop-process').
  709. ::end:: */
  710. {
  711.     VALUE res = sym_t;
  712.     DECLARE1(proc, PROCESSP);
  713.     protect_procs();
  714.     if(VPROC(proc)->pr_Status == PR_STOPPED)
  715.     {
  716.     if(signalprocess(VPROC(proc), SIGCONT))
  717.     {
  718.         VPROC(proc)->pr_Status = PR_RUNNING;
  719.         res = sym_t;
  720.     }
  721.     }
  722.     else
  723.     res = cmd_signal(sym_process_error, list_2(proc, MKSTR("Not stopped")));
  724.     unprotect_procs();
  725.     return(res);
  726. }
  727.  
  728. _PR VALUE cmd_process_exit_status(VALUE proc);
  729. DEFUN("process-exit-status", cmd_process_exit_status, subr_process_exit_status, (VALUE proc), V_Subr1, DOC_process_exit_status) /*
  730. ::doc:process_exit_status::
  731. (process-exit-status PROCESS) <UNIX-ONLY>
  732. Returns the unprocessed exit-status of the last process to be run on the
  733. process-object PROCESS. If PROCESS is currently running, return nil.
  734. ::end:: */
  735. {
  736.     VALUE res = sym_nil;
  737.     DECLARE1(proc, PROCESSP);
  738.     protect_procs();
  739.     if(VPROC(proc)->pr_Status <= 0)
  740.     {
  741.     if(VPROC(proc)->pr_ExitStatus != -1)
  742.         res = newnumber(VPROC(proc)->pr_ExitStatus);
  743.     }
  744.     unprotect_procs();
  745.     return(res);
  746. }
  747.  
  748. _PR VALUE cmd_process_exit_value(VALUE proc);
  749. DEFUN("process-exit-value", cmd_process_exit_value, subr_process_exit_value, (VALUE proc), V_Subr1, DOC_process_exit_value) /*
  750. ::doc:process_exit_value::
  751. (process-exit-value PROCESS) <UNIX-ONLY>
  752. Returns the return-value of the last process to be run on PROCESS, or nil if:
  753.   a) no process has run on PROCESS
  754.   b) PROCESS is still running
  755.   c) PROCESS exited abnormally
  756. ::end:: */
  757. {
  758.     VALUE res = sym_nil;
  759.     DECLARE1(proc, PROCESSP);
  760.     protect_procs();
  761.     if((VPROC(proc)->pr_Status <= 0) && (VPROC(proc)->pr_ExitStatus != -1))
  762.     res = newnumber(WEXITSTATUS(VPROC(proc)->pr_ExitStatus));
  763.     unprotect_procs();
  764.     return(res);
  765. }
  766.  
  767. _PR VALUE cmd_process_id(VALUE proc);
  768. DEFUN("process-id", cmd_process_id, subr_process_id, (VALUE proc), V_Subr1, DOC_process_id) /*
  769. ::doc:process_id::
  770. (process-id PROCESS) <UNIX-ONLY>
  771. If PROCESS is running, return the process-identifier associated with it
  772. (ie, its pid).
  773. ::end:: */
  774. {
  775.     VALUE res = sym_nil;
  776.     DECLARE1(proc, PROCESSP);
  777.     protect_procs();
  778.     if(VPROC(proc)->pr_Status > 0)
  779.     res = newnumber(VPROC(proc)->pr_Pid);
  780.     unprotect_procs();
  781.     return(res);
  782. }
  783.  
  784. _PR VALUE cmd_process_running_p(VALUE proc);
  785. DEFUN("process-running-p", cmd_process_running_p, subr_process_running_p, (VALUE proc), V_Subr1, DOC_process_running_p) /*
  786. ::doc:process_running_p::
  787. (process-running-p PROCESS) <UNIX-ONLY>
  788. Return t if PROCESS is running.
  789. ::end:: */
  790. {
  791.     VALUE res;
  792.     DECLARE1(proc, PROCESSP);
  793.     protect_procs();
  794.     if(VPROC(proc)->pr_Status == PR_RUNNING)
  795.     res = sym_t;
  796.     else
  797.     res = sym_nil;
  798.     unprotect_procs();
  799.     return(res);
  800. }
  801.  
  802. _PR VALUE cmd_process_stopped_p(VALUE proc);
  803. DEFUN("process-stopped-p", cmd_process_stopped_p, subr_process_stopped_p, (VALUE proc), V_Subr1, DOC_process_stopped_p) /*
  804. ::doc:process_stopped_p::
  805. (process-stopped-p PROCESS) <UNIX-ONLY>
  806. Return t if PROCESS has been stopped.
  807. ::end:: */
  808. {
  809.     VALUE res;
  810.     DECLARE1(proc, PROCESSP);
  811.     protect_procs();
  812.     if(VPROC(proc)->pr_Status == PR_STOPPED)
  813.     res = sym_t;
  814.     else
  815.     res = sym_nil;
  816.     unprotect_procs();
  817.     return(res);
  818. }
  819.  
  820. _PR VALUE cmd_process_in_use_p(VALUE proc);
  821. DEFUN("process-in-use-p", cmd_process_in_use_p, subr_process_in_use_p, (VALUE proc), V_Subr1, DOC_process_in_use_p) /*
  822. ::doc:process_in_use_p::
  823. (process-in-use-p PROCESS) <UNIX-ONLY>
  824. Similar to `process-running-p' except that this returns t even when the
  825. process has stopped, or has exited but the pty connected to `PROCESS' is still
  826. in use.
  827. ::end:: */
  828. {
  829.     VALUE res;
  830.     DECLARE1(proc, PROCESSP);
  831.     protect_procs();
  832.     if(VPROC(proc)->pr_Status != PR_DEAD)
  833.     res = sym_t;
  834.     else
  835.     res = sym_nil;
  836.     unprotect_procs();
  837.     return(res);
  838. }
  839.  
  840. _PR VALUE cmd_process_p(VALUE arg);
  841. DEFUN("process-p", cmd_process_p, subr_process_p, (VALUE arg), V_Subr1, DOC_process_p) /*
  842. ::doc:process_p::
  843. (process-p ARG) <UNIX-ONLY>
  844. Return t is ARG is a process-object.
  845. ::end:: */
  846. {
  847.     if(PROCESSP(arg))
  848.     return(sym_t);
  849.     return(sym_nil);
  850. }
  851.  
  852. _PR VALUE cmd_process_name(VALUE proc);
  853. DEFUN("process-name", cmd_process_name, subr_process_name, (VALUE proc), V_Subr1, DOC_process_name) /*
  854. ::doc:process_name::
  855. (process-name PROCESS) <UNIX-ONLY>
  856. Return the name of the program running on PROCESS.
  857. ::end:: */
  858. {
  859.     VALUE res;
  860.     DECLARE1(proc, PROCESSP);
  861.     protect_procs();
  862.     res = VPROC(proc)->pr_File;
  863.     unprotect_procs();
  864.     return(res);
  865. }
  866. _PR VALUE cmd_process_argv(VALUE proc);
  867. DEFUN("process-argv", cmd_process_argv, subr_process_argv, (VALUE proc), V_Subr1, DOC_process_argv) /*
  868. ::doc:process_argv::
  869. (process-argv PROCESS) <UNIX-ONLY>
  870. Return the arguments of the process running on PROCESS.
  871. ::end:: */
  872. {
  873.     VALUE res;
  874.     DECLARE1(proc, PROCESSP);
  875.     protect_procs();
  876.     res = VPROC(proc)->pr_Argv;
  877.     unprotect_procs();
  878.     return(res);
  879. }
  880.  
  881. _PR VALUE cmd_process_output_stream(VALUE proc);
  882. DEFUN("process-output-stream", cmd_process_output_stream, subr_process_output_stream, (VALUE proc), V_Subr1, DOC_process_output_stream) /*
  883. ::doc:process_output_stream::
  884. (process-output-stream PROCESS) <UNIX-ONLY>
  885. Return the stream to which all output from PROCESS is sent.
  886. ::end:: */
  887. {
  888.     VALUE res;
  889.     DECLARE1(proc, PROCESSP);
  890.     protect_procs();
  891.     res = VPROC(proc)->pr_OutputStream;
  892.     unprotect_procs();
  893.     return(res);
  894. }
  895.  
  896. _PR VALUE cmd_set_process_output_stream(VALUE proc, VALUE stream);
  897. DEFUN("set-process-output-stream", cmd_set_process_output_stream, subr_set_process_output_stream, (VALUE proc, VALUE stream), V_Subr2, DOC_set_process_output_stream) /*
  898. ::doc:set_process_output_stream::
  899. (set-process-output-stream PROCESS STREAM) <UNIX-ONLY>
  900. Set the output-stream of PROCESS to STREAM.
  901. ::end:: */
  902. {
  903.     DECLARE1(proc, PROCESSP);
  904.     protect_procs();
  905.     VPROC(proc)->pr_OutputStream = stream;
  906.     unprotect_procs();
  907.     return(stream);
  908. }
  909.  
  910. _PR VALUE cmd_process_exit_function(VALUE proc);
  911. DEFUN("process-exit-function", cmd_process_exit_function, subr_process_exit_function, (VALUE proc), V_Subr1, DOC_process_exit_function) /*
  912. ::doc:process_exit_function::
  913. (process-exit-function PROCESS) <UNIX-ONLY>
  914. Return the function which is called when PROCESS exits.
  915. ::end:: */
  916. {
  917.     VALUE res;
  918.     DECLARE1(proc, PROCESSP);
  919.     protect_procs();
  920.     res = VPROC(proc)->pr_ExitFunc;
  921.     unprotect_procs();
  922.     return(res);
  923. }
  924.  
  925. _PR VALUE cmd_set_process_exit_function(VALUE proc, VALUE fn);
  926. DEFUN("set-process-exit-function", cmd_set_process_exit_function, subr_set_process_exit_function, (VALUE proc, VALUE fn), V_Subr2, DOC_set_process_exit_function) /*
  927. ::doc:set_process_exit_function::
  928. (set-process-exit-function PROCESS FUNCTION) <UNIX-ONLY>
  929. Set the function which is called when PROCESS exits to FUNCTION.
  930. ::end:: */
  931. {
  932.     DECLARE1(proc, PROCESSP);
  933.     protect_procs();
  934.     VPROC(proc)->pr_ExitFunc = fn;
  935.     unprotect_procs();
  936.     return(fn);
  937. }
  938.  
  939. void
  940. sys_proc_init(void)
  941. {
  942. #ifdef USE_SIGACTION
  943.     /* Setup SIGCHLD stuff.  */
  944.     sigemptyset(&ChldSet);
  945.     sigaddset(&ChldSet, SIGCHLD);
  946.     ChldAct.sa_handler = sigchld_handler;
  947.     ChldAct.sa_mask = ChldSet;
  948. # ifdef SA_RESTART
  949.     ChldAct.sa_flags = SA_RESTART;
  950. # else
  951.     ChldAct.sa_flags = 0;
  952. # endif
  953.     sigaction(SIGCHLD, &ChldAct, NULL);
  954. #else
  955.     signal(SIGCHLD, sigchld_handler);
  956. #endif
  957.  
  958.     /* Is this necessary?? Better safe than core-dumped ;-)  */
  959.     signal(SIGPIPE, SIG_IGN);
  960.  
  961.     setpgrp();
  962.  
  963.     ADD_SUBR(subr_make_process);
  964.     ADD_SUBR(subr_fork_process);
  965.     ADD_SUBR(subr_run_process);
  966.     ADD_SUBR(subr_signal_process);
  967.     ADD_SUBR(subr_interrupt_process);
  968.     ADD_SUBR(subr_kill_process);
  969.     ADD_SUBR(subr_stop_process);
  970.     ADD_SUBR(subr_continue_process);
  971.     ADD_SUBR(subr_process_exit_status);
  972.     ADD_SUBR(subr_process_exit_value);
  973.     ADD_SUBR(subr_process_id);
  974.     ADD_SUBR(subr_process_running_p);
  975.     ADD_SUBR(subr_process_stopped_p);
  976.     ADD_SUBR(subr_process_in_use_p);
  977.     ADD_SUBR(subr_process_output_stream);
  978.     ADD_SUBR(subr_set_process_output_stream);
  979.     ADD_SUBR(subr_process_exit_function);
  980.     ADD_SUBR(subr_set_process_exit_function);
  981. }
  982. void
  983. sys_proc_kill(void)
  984. {
  985.     struct Proc *pr = ProcChain;
  986.     protect_procs();
  987.     while(pr)
  988.     {
  989.     struct Proc *nxt = pr->pr_Next;
  990.     killproc(pr);
  991.     pr = nxt;
  992.     }
  993.     unprotect_procs();
  994.     signal(SIGCHLD, SIG_IGN);
  995. }
  996.