home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume12 / cake / part02 / act.c next >
Encoding:
C/C++ Source or Header  |  1987-10-14  |  12.3 KB  |  650 lines

  1. /*
  2. **    Module to execute Cake actions.
  3. */
  4.  
  5. static    char
  6. rcs_id[] = "$Header: /mip/zs/src/sys/cake/RCS/act.c,v 1.14 86/07/19 12:22:18 zs Exp $";
  7.  
  8. #include    "cake.h"
  9.  
  10. /*
  11. **    Update the node by executing the attached actions.
  12. **    Actually, all the buddies will be updated, and
  13. **    no action will be executed unless it is necessary.
  14. **
  15. **    The level of a file is one greater than the level of its
  16. **    parent in the chase graph; the level of !MAINCAKE! is 0.
  17. **    This controls the printing of messages about the primary
  18. **    targets.
  19. */
  20.  
  21. update(node, level, force_exec)
  22. reg    Node    *node;
  23. reg    int    level;
  24. reg    bool    force_exec;
  25. {
  26.     extern        get_utime();
  27.     extern        save_novol();
  28.     extern    bool    diff_novol();
  29.     extern    Wait    carry_out();
  30.     extern    char    *list_names();
  31.     reg    Node    *bnode, *onode;
  32.     reg    List    *ptr, *ptr1;
  33.     reg    bool    oksofar, needact, mayskip;
  34.     reg    List    *errnodes;
  35.     Wait        code;
  36.  
  37.     put_trail("update", "start");
  38.     cdebug("hunting %s at level %d\n", node->n_name, level);
  39.  
  40.     /* force printing of "up-to-date" messages */
  41.     if (level == 0 && is_ok(node))
  42.         node->n_kind = n_CANDO;
  43.         
  44.     if (off_node(node, nf_ERR) && is_ok(node))
  45.     {
  46.         cdebug("everything a-ok, nothing to do\n");
  47.         if (level == 1)
  48.         {
  49.             if (on_node(node, nf_ORIG))
  50.             {
  51.                 printf("cake: target %s has no ancestors\n", node->n_name);
  52.                 node->n_kind = n_NOWAY;
  53.             }
  54.             or (! xflag)
  55.                 printf("cake: %s is up to date\n", node->n_name);
  56.         }
  57.  
  58.         put_trail("update", "finish");
  59.         return;
  60.     }
  61.  
  62. #ifdef    CAKEDEBUG
  63.     if (cakedebug)
  64.     {
  65.         printf("starting update of\n");
  66.         print_node(node);
  67.     }
  68. #endif
  69.  
  70.     if (on_node(node, nf_ERR))
  71.     {
  72.         trace_errs(node);
  73.         return;
  74.     }
  75.  
  76.     errnodes = NULL;
  77.  
  78.     /* skip the actions if they are useless or not needed */
  79.     oksofar = TRUE;
  80.     needact = FALSE;
  81.     mayskip = FALSE;
  82.     for_list (ptr, node->n_new)
  83.     {
  84.         bnode  = (Node *) ldata(ptr);
  85.  
  86.         if (on_node(bnode, nf_ERR))
  87.         {
  88.             oksofar = FALSE;
  89.             errnodes = addtail(errnodes, bnode);
  90.         }
  91.         else
  92.         {
  93.             if (off_node(bnode, nf_EXIST) || bnode->n_rtime < bnode->n_utime)
  94.                 needact = TRUE;
  95.             
  96.             if (on_node(bnode, nf_DEPNONVOL))
  97.                 mayskip = TRUE;
  98.         }
  99.     }
  100.  
  101.     if (! oksofar)
  102.     {
  103.         cdebug("error in buddies\n");
  104.         if (vflag && strdiff(node->n_name, CHASEROOT))
  105.         {
  106.             sprintf(scratchbuf, "cannot proceed with update of %s because of problems with %s %s",
  107.                 node->n_name, (length(errnodes) == 1)? "buddy": "buddies", list_names(errnodes));
  108.             add_error(node, new_name(scratchbuf), errnodes, TRUE);
  109.             trace_errs(node);
  110.         }
  111.  
  112.         goto endit;
  113.     }
  114.  
  115.     if (! needact)
  116.     {
  117.         cdebug("no need for actions\n");
  118.         if (strdiff(node->n_name, CHASEROOT))
  119.             printf("cake: %s is up to date\n", node->n_name);
  120.  
  121.         goto endit;
  122.     }
  123.  
  124.     /* update all ancestors of all buddies */
  125.     for_list (ptr, node->n_new)
  126.     {
  127.         bnode  = (Node *) ldata(ptr);
  128.         for_list (ptr1, bnode->n_old)
  129.         {
  130.             onode = (Node *) ldata(ptr1);
  131.             update(onode, level+1, force_exec);
  132.             if (on_node(onode, nf_ERR) || ! is_ok(onode))
  133.             {
  134.                 oksofar = FALSE;
  135.                 errnodes = addtail(errnodes, onode);
  136.             }
  137.         }
  138.     }
  139.  
  140.     /* skip the actions if any ancestors are missing */
  141.     if (! oksofar)
  142.     {
  143.         cdebug("error in prerequisites\n");
  144.         if (vflag && strdiff(node->n_name, CHASEROOT))
  145.         {
  146.             sprintf(scratchbuf, "cannot proceed with update of %s because of problems with %s %s",
  147.                 node->n_name, (length(errnodes) == 1)? "ancestor": "ancestors", list_names(errnodes));
  148.             add_error(node, new_name(scratchbuf), errnodes, TRUE);
  149.             trace_errs(node);
  150.         }
  151.  
  152.         goto endit;
  153.     }
  154.  
  155.     /* skip the actions; node is a missing base file */
  156.     if (is_noway(node))
  157.     {
  158.         cdebug("error in planning\n");
  159.         trace_errs(node);
  160.         goto endit;
  161.     }
  162.  
  163.     /* find any NOWAY buddies; these may have n_old == [] */
  164.     for_list (ptr, node->n_new)
  165.     {
  166.         bnode  = (Node *) ldata(ptr);
  167.         if (is_noway(bnode))
  168.         {
  169.             oksofar = FALSE;
  170.             errnodes = addtail(errnodes, bnode);
  171.         }
  172.     }
  173.  
  174.     /* skip the actions if there are any NOWAY buddies */
  175.     if (! oksofar)
  176.     {
  177.         cdebug("error in buddy planning\n");
  178.         sprintf(scratchbuf, "dare not update %s because of possible effects on %s %s", node->n_name,
  179.             (length(errnodes) == 1)? "buddy": "buddies", list_names(errnodes));
  180.         add_error(node, new_name(scratchbuf), LNULL, TRUE);
  181.         trace_errs(node);
  182.         goto endit;
  183.     }
  184.  
  185.     /* reevaluate the necessity to act in the light of the */
  186.     /* actions taken to update possibly nonvolatile ancestors */
  187.     if (mayskip)
  188.     {
  189.         needact = FALSE; /* assume so for the moment */
  190.         cdebug("deciding whether to skip\n");
  191.         for_list (ptr, node->n_new)
  192.         {
  193.             bnode  = (Node *) ldata(ptr);
  194.  
  195.             if (on_node(bnode, nf_DEPNONVOL))
  196.             {
  197.                 cdebug("considering %s\n", bnode->n_name);
  198.                 get_utime(bnode, FALSE);
  199.             }
  200.  
  201.             if (off_node(bnode, nf_EXIST) || bnode->n_rtime < bnode->n_utime)
  202.             {
  203.                 cdebug("%s needs action\n", bnode->n_name);
  204.                 needact = TRUE;
  205.             }
  206.         }
  207.     }
  208.  
  209.     if (! needact)
  210.     {
  211.         cdebug("no need for actions after all\n");
  212.         if (strdiff(node->n_name, CHASEROOT))
  213.             printf("cake: %s is up to date\n", node->n_name);
  214.  
  215.         goto endit;
  216.     }
  217.  
  218.     if (tflag)
  219.     {
  220.         /* instead of action just touch the targets */
  221.         for_list (ptr, node->n_new)
  222.         {
  223.             bnode = (Node *) ldata(ptr);
  224.             if (on_node(bnode, nf_PSEUDO))
  225.                 continue;
  226.  
  227.             if (rflag)
  228.                 cake_utimes(bnode, bnode->n_utime);
  229.             else
  230.                 cake_utimes(bnode, GENESIS);
  231.             
  232.             printf("touch %s\n", bnode->n_name);
  233.         }
  234.     }
  235.     else
  236.     {
  237.         /* prepare for actions */
  238.         for_list (ptr, node->n_new)
  239.         {
  240.             bnode = (Node *) ldata(ptr);
  241.             if (on_node(bnode, nf_NONVOL))
  242.                 save_novol(bnode);
  243.         }
  244.  
  245.         /* execute actions */
  246.         code = carry_out(node, force_exec);
  247.         if (code.w_status != 0)
  248.         {
  249.             oksofar = FALSE;
  250.             sprintf(scratchbuf, "error in actions for %s", node->n_name);
  251.             for_list (ptr, node->n_new)
  252.             {
  253.                 bnode = (Node *) ldata(ptr);
  254.                 add_error(bnode, new_name(scratchbuf), LNULL, TRUE);
  255.             }
  256.  
  257.             if (! xflag)
  258.             {
  259.                 if (code.w_termsig == 0)
  260.                     printf("*** Error code %d\n", code.w_retcode);
  261.                 else
  262.                     printf("*** Termination code %d\n", code.w_termsig);
  263.             }
  264.             
  265.             cake_error(node);
  266.             goto endit;
  267.         }
  268.  
  269.         /* clean up after actions */
  270.         for_list (ptr, node->n_new)
  271.         {
  272.             bnode = (Node *) ldata(ptr);
  273.             if (on_node(bnode, nf_NONVOL) && ! diff_novol(bnode))
  274.                 node_resetstat(bnode);
  275.             or (rflag)
  276.                 node_setstat(bnode);
  277.             else
  278.                 node_stat(bnode);
  279.         }
  280.     }
  281.  
  282. endit:
  283.  
  284.     cdebug("update finished\n");
  285.     for_list (ptr, node->n_new)
  286.     {
  287.         bnode = (Node *) ldata(ptr);
  288.         if (oksofar)
  289.         {
  290.             if (on_node(bnode, nf_EXIST) || on_node(bnode, nf_PSEUDO) || nflag)
  291.                 bnode->n_kind = n_OK;
  292.             else
  293.             {
  294.                 set_node(bnode, nf_ERR);
  295.                 if (length(node->n_act) == 0)
  296.                     sprintf(scratchbuf, "no actions to make %s with", bnode->n_name);
  297.                 else
  298.                     sprintf(scratchbuf, "action did not create %s", bnode->n_name);
  299.  
  300.                 add_error(bnode, new_name(scratchbuf), LNULL, TRUE);
  301.                 trace_errs(bnode);
  302.             }
  303.         }
  304.  
  305. #ifdef    CAKEDEBUG
  306.         if (cakedebug)
  307.             print_node(bnode);
  308. #endif
  309.     }
  310.  
  311.     put_trail("update", "finish");
  312. }
  313.  
  314. /*
  315. **    Execute the plan prepared by chase.c
  316. **    Prevent the deletion of the primary targets by cleanup.
  317. */
  318.  
  319. execute(root)
  320. reg    Node    *root;
  321. {
  322.     reg    List    *ptr;
  323.     reg    Node    *target;
  324.  
  325.     for_list (ptr, root->n_old)
  326.     {
  327.         target = (Node *) ldata(ptr);
  328.         set_node(target, nf_NODELETE);
  329.     }
  330.  
  331.     update(root, 0, FALSE);
  332. }
  333.  
  334. /*
  335. **    Carry out the specified actions and return the exit code.
  336. **    Note that an empty list of actions is perfectly acceptable.
  337. */
  338.  
  339. #define    START_SCRIPT    "{"
  340. #define    FINISH_SCRIPT    "}"
  341.  
  342. Wait
  343. carry_out(node, force_exec)
  344. reg    Node    *node;
  345. reg    bool    force_exec;
  346. {
  347.     extern    char    *expand_cmds();
  348.     extern    Wait    action();
  349.     reg    List    *ptr;
  350.     reg    Act    *act;
  351.     reg    Node    *bnode;
  352.     Wait        code;
  353.  
  354.     if (Gflag && ! nflag)
  355.     {
  356.         for_list (ptr, node->n_new)
  357.         {
  358.             bnode = (Node *) ldata(ptr);
  359.             if (on_node(bnode, nf_EXIST))
  360.             {
  361.                 cdebug("removing %s for -G\n", bnode->n_name);
  362.                 cake_remove(bnode->n_name);
  363.             }
  364.         }
  365.     }
  366.  
  367.     for_list (ptr, node->n_act)
  368.     {
  369.         act = (Act *) ldata(ptr);
  370.  
  371.         if (nflag)
  372.         {
  373.             if (off_act(act, af_MINUSN) && ! force_exec)
  374.                 show_act(act->a_str, (char *) NULL);
  375.             else
  376.             {
  377.                 reset_act(act, af_SILENT);
  378.                 printf("executing ...\n");
  379.                 code = action(act, node);
  380.                 printf("... done\n");
  381.                 if (code.w_status != 0)
  382.                     return code;
  383.             }
  384.  
  385.             continue;
  386.         }
  387.  
  388.         code = action(act, node);
  389.         if (code.w_status != 0)
  390.             return code;
  391.     }
  392.  
  393.     code.w_status = 0;
  394.     return code;
  395. }
  396.  
  397. /*
  398. **    Execute the given command and return its status,
  399. **    modified by flags and prefixes.
  400. */
  401.  
  402. Wait
  403. action(act, node)
  404. reg    Act    *act;
  405. reg    Node    *node;
  406. {
  407.     extern    int    cake_proc();
  408.     extern    Wait    cake_wait();
  409.     Wait        code;
  410.     reg    A_kind    type;
  411.     reg    int    pid;
  412.     reg    char    *after;
  413.  
  414.     put_trail("action", "start");
  415.     after = expand_cmds(act->a_str);
  416.     if (! (on_act(act, af_SILENT) || sflag))
  417.         show_act(act->a_str, after);
  418.     act->a_str = after;
  419.  
  420.     if (on_act(act, af_SCRIPT))
  421.         type = Script;
  422.     or (on_act(act, af_SYSTEM))
  423.         type = System;
  424.     else
  425.         type = Exec;
  426.  
  427.     pid = cake_proc(act->a_str, type, (char *) NULL, node, (int (*)()) NULL, (List *) NULL);
  428.     code = cake_wait(pid);
  429.  
  430.     if (on_act(act, af_IGNORE) || iflag)
  431.         code.w_status = 0;
  432.  
  433.     if (code.w_status != 0 && ! kflag)
  434.         exit_cake(FALSE);
  435.  
  436.     put_trail("action", "finish");
  437.     return code;
  438. }
  439.  
  440. /*
  441. **    Print an action in the format specified by the options.
  442. **    The two args are the action before and after expansion.
  443. **    The second may be NULL, in which case show_act does the
  444. **    expansion itself.
  445. */
  446.  
  447. show_act(before, after)
  448. reg    char    *before;
  449. reg    char    *after;
  450. {
  451.     extern    char    *squeeze();
  452.     reg    char    *form;
  453.  
  454.     if (bflag)
  455.         form = before;
  456.     or (after != NULL)
  457.         form = after;
  458.     else
  459.         form = expand_cmds(before);
  460.  
  461.     if (wflag)
  462.         printf("%s", form);
  463.     else
  464.         printf("%s", squeeze(form));
  465. }
  466.  
  467. /*
  468. **    Reduce the width of the given command string
  469. **    by squeezing out extra spaces and tabs.
  470. */
  471.  
  472. char *
  473. squeeze(cmd)
  474. reg    char    *cmd;
  475. {
  476.     char        buf[MAXSIZE];
  477.     reg    char    *s;
  478.     reg    int    i, oldi;
  479.     reg    bool    inquotes;
  480.     reg    bool    insingle;
  481.     reg    bool    indouble;
  482.     reg    bool    lastblank;
  483.  
  484.     s = cmd;
  485.     i = 0;
  486.     lastblank = FALSE;
  487.     while (*s != '\0')
  488.     {
  489.         while (*s != '\0' && (*s == ' ' || *s == '\t'))
  490.             s++;
  491.  
  492.         if (lastblank && (*s == '\n' || *s == '\r' || *s == '\f'))
  493.             i--;
  494.  
  495.         oldi = i;
  496.         inquotes = FALSE;
  497.         for (; *s != '\0' && ((*s != ' ' && *s != '\t') || inquotes); s++)
  498.         {
  499.             if (*s == '\\')
  500.             {
  501.                 buf[i++] = *s;
  502.                 if (s[1] != '\0')
  503.                     buf[i++] = *++s;
  504.             }
  505.             else
  506.             {
  507.                 if (*s == '"' && ! (inquotes && insingle))
  508.                 {
  509.                     inquotes = ! inquotes;
  510.                     indouble = TRUE;
  511.                     insingle = FALSE;
  512.                 }
  513.                 or (*s == '\'' && ! (inquotes && indouble))
  514.                 {
  515.                     inquotes = ! inquotes;
  516.                     insingle = TRUE;
  517.                     indouble = FALSE;
  518.                 }
  519.  
  520.                 buf[i++] = *s;
  521.             }
  522.         }
  523.  
  524.         if (i == oldi || buf[i-1] == '\n' || buf[i-1] == '\r' || buf[i-1] == '\f')
  525.             lastblank = FALSE;
  526.         else
  527.         {
  528.             lastblank = TRUE;
  529.             buf[i++] = ' ';
  530.         }
  531.     }
  532.  
  533.     buf[i] = '\0';
  534.     if (i >= MAXSIZE)
  535.     {
  536.         fprintf(stderr, "cake internal error: command '%s' too long\n", buf);
  537.         exit_cake(FALSE);
  538.     }
  539.  
  540.     while (buf[i-1] == ' ' || buf[i-1] == '\t')
  541.         buf[--i] = '\0';
  542.  
  543.     return new_name(buf);
  544. }
  545.  
  546. /*
  547. **    Clean up after an error or interrupt.
  548. */
  549.  
  550. cake_error(node)
  551. reg    Node    *node;
  552. {
  553.     reg    List    *ptr, *ptr1;
  554.     reg    Node    *bnode, *onode;
  555.  
  556.     for_list (ptr, node->n_new)
  557.     {
  558.         bnode = (Node *) ldata(ptr);
  559.         for_list (ptr1, bnode->n_old)
  560.         {
  561.             onode = (Node *) ldata(ptr1);
  562.             set_node(onode, nf_NODELETE);
  563.         }
  564.  
  565.         if (on_node(bnode, nf_EXIST) && off_node(bnode, nf_PRECIOUS))
  566.             cake_remove(bnode->n_name);
  567.     }
  568. }
  569.  
  570. /*
  571. **    Clean up after all the fuss.
  572. */
  573.  
  574. cleanup()
  575. {
  576.     extern    List    *get_allnodes();
  577.     reg    List    *ptr, *ptr1;
  578.     reg    List    *nodes;
  579.     reg    Node    *node, *onode;
  580.  
  581.     cdebug("cleanup:\n");
  582.  
  583.     if (nflag)
  584.         return;
  585.  
  586.     nodes = get_allnodes();
  587.     for_list (ptr, nodes)
  588.     {
  589.         node = (Node *) ldata(ptr);
  590.         cdebug("considering %s: ", node->n_name);
  591.  
  592.         if (off_node(node, nf_EXIST))
  593.         {
  594.             cdebug("nonexistent\n");
  595.             continue;
  596.         }
  597.  
  598.         if (on_node(node, nf_ERR) || is_noway(node))
  599.         {
  600.             cdebug("errors or noway\n");
  601.             continue;
  602.         }
  603.  
  604.         if (! dflag && off_node(node, nf_REDUNDANT))
  605.         {
  606.             cdebug("no flag\n");
  607.             continue;
  608.         }
  609.  
  610.         /* file exists and OK, shall we delete it ? */
  611.  
  612.         /* not if we thought earlier it need it */
  613.         if (on_node(node, nf_NODELETE))
  614.         {
  615.             cdebug("nodelete flag\n");
  616.             continue;
  617.         }
  618.  
  619.         /* not if it cannot be regenerated at all */
  620.         if (length(node->n_act) == 0)
  621.         {
  622.             cdebug("nonregenerable\n");
  623.             continue;
  624.         }
  625.  
  626.         /* not if it cannot be regenerated as is */
  627.         if ((node->n_utime < node->n_rtime) && off_node(node, nf_NEWFILE))
  628.         {
  629.             cdebug("nonregenerable as is\n");
  630.             continue;
  631.         }
  632.  
  633.         /* or if its ancestors are not all OK */
  634.         for_list (ptr1, node->n_old)
  635.         {
  636.             onode = (Node *) ldata(ptr1);
  637.             if (! is_ok(onode))
  638.             {
  639.                 cdebug("ancestor not ok\n");
  640.                 goto nextnode;
  641.             }
  642.         }
  643.  
  644.         cdebug("DELETED\n");
  645.         cake_remove(node->n_name);
  646.     
  647.     nextnode:    ;
  648.     }
  649. }
  650.