home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume12 / cake / part03 / proc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-10-14  |  8.7 KB  |  485 lines

  1. /*
  2. **    Cake interface to the other processes.
  3. */
  4.  
  5. static    char
  6. rcs_id[] = "$Header: /mip/zs/src/sys/cake/RCS/proc.c,v 1.15 87/10/05 20:15:45 zs Exp $";
  7.  
  8. #include    "cake.h"
  9. #include    <ctype.h>
  10. #include    <errno.h>
  11. #include    <signal.h>
  12. #include    <fcntl.h>
  13. #include    <sys/param.h>
  14.  
  15. extern    List    *active_procs;        /* of Proc    */
  16.  
  17. /*
  18. **    Process the given command in the manner described by the args.
  19. */
  20.  
  21. int
  22. cake_proc(cmd, type, file, node, func, args)
  23. reg    char    *cmd;
  24. reg    A_kind    type;
  25. reg    char    *file;
  26. reg    Node    *node;
  27. reg    int    (*func)();
  28. reg    List    *args;
  29. {
  30.     extern    bool    has_meta();
  31.     extern    char    *strip_backslash();
  32.     extern    char    *shell_path[2];
  33.     extern    char    *shell_cmd[2];
  34.     extern    char    *shell_opt[2];
  35.     char        *argv[MAXARGS];
  36.     reg    Proc    *proc;
  37.     reg    int    pid;
  38.     reg    char    *script_filename;
  39.  
  40.     cmd = strip_backslash(cmd);
  41.  
  42. #ifdef    CAKEDEBUG
  43.     if (file != NULL)
  44.         cdebug("file is %s\n", file);
  45.     else
  46.         cdebug("file is NULL\n");
  47. #endif
  48.  
  49.     if (type == Exec && has_meta(cmd, TRUE))
  50.         type = System;
  51.  
  52.     cdebug("cake_proc, type %d: %s\n", type, cmd);
  53.     fflush(stdout);
  54.  
  55.     if (type == Exec)
  56.         parse_args(cmd, argv);
  57.     or (type == Script)
  58.     {
  59.         reg    FILE    *script_fp;
  60.  
  61.         script_filename = get_newname();
  62.         if ((script_fp = fopen(script_filename, "w")) == NULL)
  63.         {
  64.             sprintf(scratchbuf, "cake system error, fopen %s", script_filename);
  65.             perror(scratchbuf);
  66.             exit_cake(FALSE);
  67.         }
  68.  
  69.         fprintf(script_fp, "%s", cmd);
  70.         fclose(script_fp);
  71.     }
  72.  
  73.     mutex_lock();
  74.     if ((pid = vfork()) == 0)
  75.     {
  76.         reg    int    fd;
  77.  
  78. #ifdef    CLOSE_ALL
  79.         for (fd = 3; fd < NOFILE; fd++)
  80.             close(fd);
  81. #endif
  82.  
  83.         if (file != NULL)
  84.         {
  85.             if (close(1) != 0)
  86.             {
  87.                 perror("cake system error, close stdout");
  88.                 _exit(127);
  89.             }
  90.  
  91.             if ((fd = open(file, O_WRONLY|O_CREAT, 0600)) < 0)
  92.             {
  93.                 perror("cake system error, reopen stdout");
  94.                 _exit(127);
  95.             }
  96.  
  97.             if (fd != 1)
  98.             {
  99.                 fprintf(stderr, "cake system error: reopen stdout gives fd %d\n", fd);
  100.                 _exit(127);
  101.             }
  102.         }
  103.  
  104.         switch (type)
  105.         {
  106.  
  107.     when Script:    if (shell_opt[1] != NULL)
  108.                 execl(shell_path[1], shell_cmd[1], shell_opt[1], script_filename, 0);
  109.             else
  110.                 execl(shell_path[1], shell_cmd[1], script_filename, 0);
  111.  
  112.             perror("cake system error, shell script exec");
  113.             _exit(127);
  114.  
  115.     when System:    if (shell_opt[0] != NULL)
  116.                 execl(shell_path[0], shell_cmd[0], shell_opt[0], cmd, 0);
  117.             else
  118.                 execl(shell_path[0], shell_cmd[0], cmd, 0);
  119.  
  120.             perror("cake system error, shell exec");
  121.             _exit(127);
  122.  
  123.     when Exec:    execvp(argv[0], argv);
  124.             sprintf(scratchbuf, "cake system error, %s exec", argv[0]);
  125.             perror(scratchbuf);
  126.             _exit(127);
  127.  
  128.     otherwise:    fprintf(stderr, "cake internal error: type = %x in cake_proc\n", type);
  129.             _exit(127);
  130.         }
  131.     }
  132.     or (pid == -1)
  133.     {
  134.         perror("cake system error, fork");
  135.         exit_cake(FALSE);
  136.     }
  137.  
  138.     proc = make(Proc);
  139.     proc->pr_pid  = pid;
  140.     proc->pr_node = node;
  141.     proc->pr_func = func;
  142.     proc->pr_args = args;
  143.     proc->pr_run  = TRUE;
  144.     addtail(active_procs, proc);
  145.     cdebug("cake_proc pid = %d\n", pid);
  146.  
  147.     mutex_unlock();
  148.     if (type == Script && ! cakedebug)
  149.     {
  150.         cdebug("cake_proc unlink script_filename %s\n", script_filename);
  151.         if (unlink(script_filename) != 0)
  152.         {
  153.             sprintf(scratchbuf, "cake system error, unlink %s", script_filename);
  154.             perror(scratchbuf);
  155.             exit_cake(FALSE);
  156.         }
  157.     }
  158.  
  159.     return pid;
  160. }
  161.  
  162. /*
  163. **    The cake code allows many child processes to be running
  164. **    at any given time. Cake waits for these processes
  165. **    when their results are required. However, there is no
  166. **    necessary relationship between between when a process exits
  167. **    and when its product is needed.
  168. **
  169. **    The list of active processes contains all running processes
  170. **    and all exited processes that haven't been waited for yet.
  171. **    Cake_wait maintains this list. Whenever cake_wait gets
  172. **    an exit report from wait, it invokes the function (if any)
  173. **    associated with the exited process. If the exited process
  174. **    is the one cake_wait is looking for, it returns; otherwise
  175. **    it calls wait again and again until it finds that process.
  176. */
  177.  
  178. Wait
  179. cake_wait(pid)
  180. reg    int    pid;
  181. {
  182.     extern    List    *find_process();
  183.     reg    int    exitpid;
  184.     reg    List    *ptr;
  185.     reg    Proc    *proc;
  186.     Wait        status;
  187.  
  188.     mutex_lock();
  189.     ptr  = find_process(pid);
  190.     proc = (Proc *) ldata(ptr);
  191.     if (! proc->pr_run)
  192.     {
  193.         status = proc->pr_stat;
  194.         delete(active_procs, ptr);
  195.         mutex_unlock();
  196.         return status;
  197.     }
  198.  
  199.     while ((exitpid = wait(&status)) != -1)
  200.     {
  201.         mutex_lock();
  202.         ptr  = find_process(exitpid);
  203.         proc = (Proc *) ldata(ptr);
  204.         proc->pr_run  = FALSE;
  205.         proc->pr_stat = status;
  206.         cdebug("cake_wait pid = %d, status = %d\n", exitpid, status.w_status);
  207.         fflush(stdout);
  208.  
  209.         if (proc->pr_func != NULL)
  210.         {
  211.             cdebug("cake_wait calling function at %x\n", proc->pr_func);
  212.             fflush(stdout);
  213.             (*proc->pr_func)(status, proc->pr_args);
  214.         }
  215.  
  216.         if (exitpid == pid)
  217.         {
  218.             delete(active_procs, ptr);
  219.             mutex_unlock();
  220.             return status;    /* normal return */
  221.         }
  222.  
  223.         mutex_unlock();
  224.     }
  225.  
  226.     fprintf(stderr, "cake internal error: waiting for nonactive process %s\n", pid);
  227.     exit_cake(TRUE);
  228.     return status;    /* to shut up lint */
  229. }
  230.  
  231. /*
  232. **    Find an active process in the active process list.
  233. */
  234.  
  235. List *
  236. find_process(pid)
  237. reg    int    pid;
  238. {
  239.     reg    List    *ptr;
  240.     reg    Proc    *proc;
  241.     reg    bool    found;
  242.  
  243.     found = FALSE;
  244.     for_list (ptr, active_procs)
  245.     {
  246.         proc = (Proc *) ldata(ptr);
  247.         if (proc->pr_pid == pid)
  248.         {
  249.             found = TRUE;
  250.             break;
  251.         }
  252.     }
  253.  
  254.     if (! found)
  255.     {
  256.         fprintf(stderr, "cake internal error: cannot find active process %d\n", pid);
  257.         exit_cake(TRUE);
  258.     }
  259.  
  260.     return ptr;
  261. }
  262.  
  263. /*
  264. **    Open a filter the cake way, with an execv instead of an execl.
  265. */
  266.  
  267. #define        READSIDE    0
  268. #define        WRITESIDE    1
  269.  
  270. static    int    popen_pid[NOFILE];
  271.  
  272. FILE *
  273. cake_popen(argv, mode)
  274. reg    char    *argv[MAXARGS];
  275. reg    char    *mode;
  276. {
  277.     int        pdesc[2];
  278.     reg    int    parent_end, child_end;
  279.     reg    int    replaced, pid;
  280.     reg    Proc    *proc;
  281.  
  282.     if (pipe(pdesc) < 0)
  283.         return NULL;
  284.  
  285.     if (mode[0] == 'r')
  286.     {
  287.         parent_end = pdesc[READSIDE];
  288.         child_end  = pdesc[WRITESIDE];
  289.         replaced   = 1;
  290.     }
  291.     else
  292.     {
  293.         parent_end = pdesc[WRITESIDE];
  294.         child_end  = pdesc[READSIDE];
  295.         replaced   = 0;
  296.     }
  297.  
  298.     fflush(stdout);
  299.     mutex_lock();
  300.     if ((pid = vfork()) == 0)
  301.     {
  302.         close(parent_end);
  303.         close(replaced);
  304.         if (dup(child_end) != replaced)
  305.             _exit(127);
  306.  
  307.         close(child_end);
  308.         execv(argv[0], argv);
  309.         sprintf(scratchbuf, "cake system error, %s exec", argv[0]);
  310.         perror(scratchbuf);
  311.         _exit(127);
  312.     }
  313.     or (pid == -1)
  314.     {
  315.         close(parent_end);
  316.         close(child_end);
  317.         perror("cake system error, fork");
  318.         exit_cake(FALSE);
  319.     }
  320.  
  321.     proc = make(Proc);
  322.     proc->pr_pid  = pid;
  323.     proc->pr_func = NULL;
  324.     proc->pr_args = NULL;
  325.     proc->pr_run  = TRUE;
  326.     addtail(active_procs, proc);
  327.  
  328.     close(child_end);
  329.     popen_pid[parent_end] = pid;
  330.     mutex_unlock();
  331.  
  332.     return fdopen(parent_end, mode);
  333. }
  334.  
  335. int
  336. cake_pclose(fp)
  337. reg    FILE    *fp;
  338. {
  339.     Wait        code;
  340.     reg    int    f;
  341.  
  342.     f = fileno(fp);
  343.     fclose(fp);
  344.     code = cake_wait(popen_pid[f]);
  345.     return code.w_status;
  346. }
  347.  
  348. /*
  349. **    Parse the given command into argv, argc.
  350. */
  351.  
  352. int
  353. parse_args(cmd, vector)
  354. reg    char    *cmd;
  355. reg    char    **vector;
  356. {
  357.     char        buf[MAXARGSIZE];
  358.     reg    int    i, count;
  359.     reg    char    *s;
  360.     reg    bool    instring;
  361.  
  362.     cdebug("parse_args: ");
  363.  
  364.     s = cmd;
  365.     for (count = 0; *s != '\0'; count++)
  366.     {
  367.         while (*s != '\0' && isspace(*s))
  368.             s++;
  369.  
  370.         instring = FALSE;
  371.         for (i = 0; *s != '\0' && (! isspace(*s) || instring); s++)
  372.         {
  373.             if (*s == '\\')
  374.             {
  375.                 if (s[1] != '\0')
  376.                     buf[i++] = *++s;
  377.             }
  378.             or (*s == '"')
  379.                 instring = ! instring;
  380.             else
  381.                 buf[i++] = *s;
  382.         }
  383.  
  384.         buf[i] = '\0';
  385.         if (i >= MAXARGSIZE)
  386.         {
  387.             fprintf(stderr, "cake: argument '%s' too long\n", buf);
  388.             exit_cake(FALSE);
  389.         }
  390.  
  391.         if (count >= MAXARGS)
  392.         {
  393.             fprintf(stderr, "cake: '%s' has too many arguments\n", cmd);
  394.             exit_cake(FALSE);
  395.         }
  396.  
  397.         if (i == 0)
  398.             count--;
  399.         else
  400.         {
  401.             cdebug("<%s>", buf);
  402.             vector[count] = new_name(buf);
  403.         }
  404.     }
  405.  
  406.     vector[count] = NULL;
  407.     cdebug("/%d\n", count);
  408.     return count;
  409. }
  410.  
  411. /*
  412. **    Strip one level of backslashes from the given string.
  413. */
  414.  
  415. char *
  416. strip_backslash(str)
  417. reg    char    *str;
  418. {
  419.     char        buf[MAXSIZE];
  420.     reg    char    *s;
  421.     reg    int    i;
  422.  
  423.     if (index(str, '\\') == NULL)
  424.         return str;
  425.  
  426.     for (i = 0, s = str; *s != '\0'; s++)
  427.     {
  428.         if (*s != '\\')
  429.             buf[i++] = *s;
  430.         or (s[1] != '\0')
  431.             buf[i++] = *++s;
  432.     }
  433.  
  434.     buf[i] = '\0';
  435.     if (i >= MAXSIZE)
  436.     {
  437.         fprintf(stderr, "cake: command '%s' too long.\n", str);
  438.         exit_cake(FALSE);
  439.     }
  440.  
  441.     return new_name(buf);
  442. }
  443.  
  444. /*
  445. **    These functions implement mutual exclusion.
  446. **    They prevent cake from being interrupted
  447. **    between calls to lock and unlock.
  448. **    This is used to preserve the consistency
  449. **    of the active_procs data structure in the presence
  450. **    of multiple executing children.
  451. */
  452.  
  453. #if 0        /* mutual exclusion is not necessary & has bug */
  454. #ifdef    ATT
  455. int    (*signalint)();
  456. int    (*signalquit)();
  457. #else
  458. int    signalmask;
  459. #endif
  460. #endif
  461.  
  462. mutex_lock()
  463. {
  464. #if 0
  465. #ifdef    ATT
  466.     signalint  = signal(SIGINT,  SIG_IGN);
  467.     signalquit = signal(SIGQUIT, SIG_IGN);
  468. #else
  469.     signalmask = sigblock(mask(SIGINT)|mask(SIGQUIT));
  470. #endif
  471. #endif
  472. }
  473.  
  474. mutex_unlock()
  475. {
  476. #if 0
  477. #ifdef    ATT
  478.     signal(SIGINT,  signalint);
  479.     signal(SIGQUIT, signalquit);
  480. #else
  481.     sigsetmask(signalmask);
  482. #endif
  483. #endif
  484. }
  485.