1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  *      doname.c
  28  *
  29  *      Figure out which targets are out of date and rebuild them
  30  */
  31 
  32 /*
  33  * Included files
  34  */
  35 #include <avo/avo_alloca.h>               /* alloca() */
  36 #if defined(TEAMWARE_MAKE_CMN)
  37 #include <avo/util.h>             /* avo_get_user(), avo_hostname() */
  38 #endif
  39 
  40 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
  41 #       include <avo/strings.h>   /* AVO_STRDUP() */
  42 #       include <dm/Avo_MToolJobResultMsg.h>
  43 #       include <dm/Avo_MToolJobStartMsg.h>
  44 #       include <dm/Avo_MToolRsrcInfoMsg.h>
  45 #       include <dm/Avo_macro_defs.h> /* AVO_BLOCK_INTERUPTS & AVO_UNBLOCK_INTERUPTS */
  46 #       include <dmthread/Avo_ServerState.h>
  47 #       include <rw/pstream.h>
  48 #       include <rw/xdrstrea.h>
  49 #endif
  50 
  51 #include <fcntl.h>
  52 #include <mk/defs.h>
  53 #include <mksh/i18n.h>            /* get_char_semantics_value() */
  54 #include <mksh/macro.h>           /* getvar(), expand_value() */
  55 #include <mksh/misc.h>            /* getmem() */
  56 #include <poll.h>
  57 
  58 #ifdef PARALLEL
  59 #       include <rx/api.h>
  60 #endif
  61 
  62 #include <signal.h>
  63 
  64 #       include <stropts.h>
  65 
  66 #include <sys/errno.h>
  67 #include <sys/stat.h>
  68 #include <sys/types.h>
  69 #include <sys/utsname.h>  /* uname() */
  70 #include <sys/wait.h>
  71 #include <unistd.h>               /* close() */
  72 
  73 /*
  74  * Defined macros
  75  */
  76 #ifndef PARALLEL
  77 #       define LOCALHOST "localhost"
  78 #endif
  79 
  80 #define MAXRULES 100
  81 
  82 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
  83 #define SEND_MTOOL_MSG(cmds) \
  84         if (send_mtool_msgs) { \
  85                 cmds \
  86         }
  87 #else
  88 #define SEND_MTOOL_MSG(cmds) 
  89 #endif
  90 
  91 // Sleep for .1 seconds between stat()'s
  92 const int       STAT_RETRY_SLEEP_TIME = 100000;
  93 
  94 /*
  95  * typedefs & structs
  96  */
  97 
  98 /*
  99  * Static variables
 100  */
 101 static char     hostName[MAXNAMELEN] = "";
 102 static char     userName[MAXNAMELEN] = "";
 103 
 104 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
 105         static FILE     *mtool_msgs_fp;
 106         static XDR      xdrs;
 107         static int      sent_rsrc_info_msg = 0;
 108 #endif
 109 
 110 static int      second_pass = 0;
 111 
 112 /*
 113  * File table of contents
 114  */
 115 extern  Doname          doname_check(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic);
 116 extern  Doname          doname(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic);
 117 static  Boolean         check_dependencies(Doname *result, Property line, Boolean do_get, Name target, Name true_target, Boolean doing_subtree, Chain *out_of_date_tail, Property old_locals, Boolean implicit, Property *command, Name less, Boolean rechecking_target, Boolean recheck_conditionals);
 118 void            dynamic_dependencies(Name target);
 119 static  Doname          run_command(register Property line, Boolean print_machine);
 120 extern  Doname          execute_serial(Property line);
 121 extern  Name            vpath_translation(register Name cmd);
 122 extern  void            check_state(Name temp_file_name);
 123 static  void            read_dependency_file(register Name filename);
 124 static  void            check_read_state_file(void);
 125 static  void            do_assign(register Name line, register Name target);
 126 static  void            build_command_strings(Name target, register Property line);
 127 static  Doname          touch_command(register Property line, register Name target, Doname result);
 128 extern  void            update_target(Property line, Doname result);
 129 static  Doname          sccs_get(register Name target, register Property *command);
 130 extern  void            read_directory_of_file(register Name file);
 131 static  void            add_pattern_conditionals(register Name target);
 132 extern  void            set_locals(register Name target, register Property old_locals);
 133 extern  void            reset_locals(register Name target, register Property old_locals, register Property conditional, register int index);
 134 extern  Boolean         check_auto_dependencies(Name target, int auto_count, Name *automatics);
 135 static  void            delete_query_chain(Chain ch);
 136 
 137 // From read2.cc
 138 extern  Name            normalize_name(register wchar_t *name_string, register int length);
 139 
 140 
 141 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
 142         static void             append_job_result_msg(Avo_MToolJobResultMsg *job_result_msg);
 143         static int              pollResults(char *outFn, char *errFn, char *hostNm);
 144         static void             pollResultsAction(char *outFn, char *errFn);
 145         static void             rxmGetNextResultsBlock(int fd);
 146         static int              us_sleep(unsigned int nusecs);
 147         extern "C" void         Avo_PollResultsAction_Sigusr1Handler(int foo);
 148 #endif
 149 
 150 /*
 151  * DONE.
 152  *
 153  *      doname_check(target, do_get, implicit, automatic)
 154  *
 155  *      Will call doname() and then inspect the return value
 156  *
 157  *      Return value:
 158  *                              Indication if the build failed or not
 159  *
 160  *      Parameters:
 161  *              target          The target to build
 162  *              do_get          Passed thru to doname()
 163  *              implicit        Passed thru to doname()
 164  *              automatic       Are we building a hidden dependency?
 165  *
 166  *      Global variables used:
 167  *              build_failed_seen       Set if -k is on and error occurs
 168  *              continue_after_error    Indicates that -k is on
 169  *              report_dependencies     No error msg if -P is on
 170  */
 171 Doname
 172 doname_check(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic)
 173 {
 174         int first_time = 1;
 175         (void) fflush(stdout);
 176 try_again:
 177         switch (doname(target, do_get, implicit, automatic)) {
 178         case build_ok:
 179                 second_pass = 0;
 180                 return build_ok;
 181         case build_running:
 182                 second_pass = 0;
 183                 return build_running;
 184         case build_failed:
 185                 if (!continue_after_error) {
 186                         fatal(catgets(catd, 1, 13, "Target `%s' not remade because of errors"),
 187                               target->string_mb);
 188                 }
 189                 build_failed_seen = true;
 190                 second_pass = 0;
 191                 return build_failed;
 192         case build_dont_know:
 193                 /*
 194                  * If we can't figure out how to build an automatic
 195                  * (hidden) dependency, we just ignore it.
 196                  * We later declare the target to be out of date just in
 197                  * case something changed.
 198                  * Also, don't complain if just reporting the dependencies
 199                  * and not building anything.
 200                  */
 201                 if (automatic || (report_dependencies_level > 0)) {
 202                         second_pass = 0;
 203                         return build_dont_know;
 204                 }
 205                 if(first_time) {
 206                         first_time = 0;
 207                         second_pass = 1;
 208                         goto try_again;
 209                 }
 210                 second_pass = 0;
 211                 if (continue_after_error && !svr4) {
 212                         warning(catgets(catd, 1, 14, "Don't know how to make target `%s'"),
 213                                 target->string_mb);
 214                         build_failed_seen = true;
 215                         return build_failed;
 216                 }
 217                 fatal(catgets(catd, 1, 15, "Don't know how to make target `%s'"), target->string_mb);
 218                 break;
 219         }
 220 #ifdef lint
 221         return build_failed;
 222 #endif
 223 }
 224 
 225 
 226 void
 227 enter_explicit_rule_from_dynamic_rule(Name target, Name source)
 228 {
 229         Property line, source_line;
 230         Dependency dependency;
 231 
 232         source_line = get_prop(source->prop, line_prop);
 233         line = maybe_append_prop(target, line_prop);
 234         line->body.line.sccs_command = false;
 235         line->body.line.target = target;
 236         if (line->body.line.command_template == NULL) {
 237                 line->body.line.command_template = source_line->body.line.command_template;
 238                 for (dependency = source_line->body.line.dependencies;
 239                      dependency != NULL;
 240                      dependency = dependency->next) {
 241                         enter_dependency(line, dependency->name, false);
 242                 }
 243                 line->body.line.less = target;
 244         }
 245         line->body.line.percent = NULL;
 246 }
 247 
 248 
 249 
 250 Name
 251 find_dyntarget(Name target)
 252 {
 253         Dyntarget               p;
 254         int                     i;
 255         String_rec              string;
 256         wchar_t                 buffer[STRING_BUFFER_LENGTH];
 257         wchar_t                 *pp, * bufend;
 258         wchar_t                 tbuffer[MAXPATHLEN];
 259         Wstring                 wcb(target);
 260 
 261         for (p = dyntarget_list; p != NULL; p = p->next) {
 262                 INIT_STRING_FROM_STACK(string, buffer);
 263                 expand_value(p->name, &string, false);
 264                 i = 0;
 265                 pp = string.buffer.start;
 266                 bufend = pp + STRING_BUFFER_LENGTH;
 267                 while((*pp != nul_char) && (pp < bufend)) {
 268                         if(iswspace(*pp)) {
 269                                 tbuffer[i] = nul_char;
 270                                 if(i > 0) {
 271                                         if (wcb.equal(tbuffer)) {
 272                                                 enter_explicit_rule_from_dynamic_rule(target, p->name);
 273                                                 return(target);
 274                                         }
 275                                 }
 276                                 pp++;
 277                                 i = 0;
 278                                 continue;
 279                         }
 280                         tbuffer[i] = *pp;
 281                         i++;
 282                         pp++;
 283                         if(*pp == nul_char) {
 284                                 tbuffer[i] = nul_char;
 285                                 if(i > 0) {
 286                                         if (wcb.equal(tbuffer)) {
 287                                                 enter_explicit_rule_from_dynamic_rule(target, p->name);
 288                                                 return(target);
 289                                         }
 290                                 }
 291                                 break;
 292                         }
 293                 }
 294         }
 295         return(NULL);
 296 }
 297 
 298 /*
 299  * DONE.
 300  *
 301  *      doname(target, do_get, implicit)
 302  *
 303  *      Chases all files the target depends on and builds any that
 304  *      are out of date. If the target is out of date it is then rebuilt.
 305  *
 306  *      Return value:
 307  *                              Indiates if build failed or nt
 308  *
 309  *      Parameters:
 310  *              target          Target to build
 311  *              do_get          Run sccs get is nessecary
 312  *              implicit        doname is trying to find an implicit rule
 313  *
 314  *      Global variables used:
 315  *              assign_done     True if command line assgnment has happened
 316  *              commands_done   Preserved for the case that we need local value
 317  *              debug_level     Should we trace make's actions?
 318  *              default_rule    The rule for ".DEFAULT", used as last resort
 319  *              empty_name      The Name "", used when looking for single sfx
 320  *              keep_state      Indicates that .KEEP_STATE is on
 321  *              parallel        True if building in parallel
 322  *              recursion_level Used for tracing
 323  *              report_dependencies make -P is on
 324  */
 325 Doname
 326 doname(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic)
 327 {
 328         Doname                  result = build_dont_know;
 329         Chain                   out_of_date_list = NULL;
 330 #ifdef TEAMWARE_MAKE_CMN
 331         Chain                   target_group;
 332 #endif
 333         Property                old_locals = NULL;
 334         register Property       line;
 335         Property                command = NULL;
 336         register Dependency     dependency;
 337         Name                    less = NULL;
 338         Name                    true_target = target;
 339         Name                    *automatics = NULL;
 340         register int            auto_count;
 341         Boolean                 rechecking_target = false;
 342         Boolean                 saved_commands_done;
 343         Boolean                 restart = false;
 344         Boolean                 save_parallel = parallel;
 345 #ifdef NSE
 346         Boolean                 save_readdep;
 347 #endif
 348         Boolean                 doing_subtree = false;
 349 
 350         Boolean                 recheck_conditionals = false;
 351 
 352         if (target->state == build_running) {
 353                 return build_running;
 354         }
 355         line = get_prop(target->prop, line_prop);
 356 #ifdef TEAMWARE_MAKE_CMN
 357         if (line != NULL) {
 358                 /*
 359                  * If this target is a member of target group and one of the
 360                  * other members of the group is running, mark this target
 361                  * as running.
 362                  */
 363                 for (target_group = line->body.line.target_group;
 364                      target_group != NULL;
 365                      target_group = target_group->next) {
 366                         if (is_running(target_group->name)) {
 367                                 target->state = build_running;
 368                                 add_pending(target,
 369                                             recursion_level,
 370                                             do_get,
 371                                             implicit,
 372                                             false);
 373                                 return build_running;
 374                         }
 375                 }
 376         }
 377 #ifdef NSE
 378         nse_check_file_backquotes(target->string);
 379 #endif
 380 #endif
 381         /*
 382          * If the target is a constructed one for a "::" target,
 383          * we need to consider that.
 384          */
 385         if (target->has_target_prop) {
 386                 true_target = get_prop(target->prop,
 387                                        target_prop)->body.target.target;
 388                 if (true_target->colon_splits > 0) {
 389                         /* Make sure we have a valid time for :: targets */
 390                         Property        time;
 391 
 392                         time = get_prop(true_target->prop, time_prop);
 393                         if (time != NULL) {
 394                                 true_target->stat.time = time->body.time.time;
 395                         }
 396                 }
 397         }
 398         (void) exists(true_target);
 399         /*
 400          * If the target has been processed, we don't need to do it again,
 401          * unless it depends on conditional macros or a delayed assignment,
 402          * or it has been done when KEEP_STATE is on.
 403          */
 404         if (target->state == build_ok) {
 405                 if((!keep_state || (!target->depends_on_conditional && !assign_done))) {
 406                         return build_ok;
 407                 } else {
 408                         recheck_conditionals = true;
 409                 }
 410         }
 411         if (target->state == build_subtree) {
 412                 /* A dynamic macro subtree is being built */
 413                 target->state = build_dont_know;
 414                 doing_subtree = true;
 415                 if (!target->checking_subtree) {
 416                         /*
 417                          * This target has been started before and therefore
 418                          * not all dependencies have to be built.
 419                          */
 420                         restart = true;
 421                 }
 422         } else if (target->state == build_pending) {
 423                 target->state = build_dont_know;
 424                 restart = true;
 425 /*
 426 #ifdef TEAMWARE_MAKE_CMN
 427         } else if (parallel &&
 428                    keep_state &&
 429                    (target->conditional_cnt > 0)) {
 430             if (!parallel_ok(target, false)) {
 431                 add_subtree(target, recursion_level, do_get, implicit);
 432                 target->state = build_running;
 433                 return build_running;
 434             }
 435 #endif
 436  */
 437         }
 438         /*
 439          * If KEEP_STATE is on, we have to rebuild the target if the
 440          * building of it caused new automatic dependencies to be reported.
 441          * This is where we restart the build.
 442          */
 443         if (line != NULL) {
 444                 line->body.line.percent = NULL;
 445         }
 446 recheck_target:
 447         /* Init all local variables */
 448         result = build_dont_know;
 449         out_of_date_list = NULL;
 450         command = NULL;
 451         less = NULL;
 452         auto_count = 0;
 453         if (!restart && line != NULL) {
 454                 /*
 455                  * If this target has never been built before, mark all
 456                  * of the dependencies as never built.
 457                  */
 458                 for (dependency = line->body.line.dependencies;
 459                      dependency != NULL;
 460                      dependency = dependency->next) {
 461                         dependency->built = false;
 462                 }
 463         }
 464         /* Save the set of automatic depes defined for this target */
 465         if (keep_state &&
 466             (line != NULL) &&
 467             (line->body.line.dependencies != NULL)) {
 468                 Name *p;
 469 
 470                 /*
 471                  * First run thru the dependency list to see how many
 472                  * autos there are.
 473                  */
 474                 for (dependency = line->body.line.dependencies;
 475                      dependency != NULL;
 476                      dependency = dependency->next) {
 477                         if (dependency->automatic && !dependency->stale) {
 478                                 auto_count++;
 479                         }
 480                 }
 481                 /* Create vector to hold the current autos */
 482                 automatics =
 483                   (Name *) alloca((int) (auto_count * sizeof (Name)));
 484                 /* Copy them */
 485                 for (p = automatics, dependency = line->body.line.dependencies;
 486                      dependency != NULL;
 487                      dependency = dependency->next) {
 488                         if (dependency->automatic && !dependency->stale) {
 489                                 *p++ = dependency->name;
 490                         }
 491                 }
 492         }
 493         if (debug_level > 1) {
 494                 (void) printf(NOCATGETS("%*sdoname(%s)\n"),
 495                               recursion_level,
 496                               "",
 497                               target->string_mb);
 498         }
 499         recursion_level++;
 500         /* Avoid infinite loops */
 501         if (target->state == build_in_progress) {
 502                 warning(catgets(catd, 1, 16, "Infinite loop: Target `%s' depends on itself"),
 503                         target->string_mb);
 504                 return build_ok;
 505         }
 506         target->state = build_in_progress;
 507 
 508         /* Activate conditional macros for the target */
 509         if (!target->added_pattern_conditionals) {
 510                 add_pattern_conditionals(target);
 511                 target->added_pattern_conditionals = true;
 512         }
 513         if (target->conditional_cnt > 0) {
 514                 old_locals = (Property) alloca(target->conditional_cnt *
 515                                                sizeof (Property_rec));
 516                 set_locals(target, old_locals);
 517         }
 518 
 519 /*
 520  * after making the call to dynamic_dependecies unconditional we can handle
 521  * target names that are same as file name. In this case $$@ in the 
 522  * dependencies did not mean anything. WIth this change it expands it
 523  * as expected.
 524  */
 525         if (!target->has_depe_list_expanded)
 526         {
 527 #ifdef NSE
 528                 save_readdep = reading_dependencies;
 529                 reading_dependencies= true;
 530 #endif
 531                 dynamic_dependencies(target);
 532 #ifdef NSE
 533                 reading_dependencies= save_readdep;
 534 #endif
 535         }
 536 
 537 /*
 538  *      FIRST SECTION -- GO THROUGH DEPENDENCIES AND COLLECT EXPLICIT
 539  *      COMMANDS TO RUN
 540  */
 541         if ((line = get_prop(target->prop, line_prop)) != NULL) {
 542                 if (check_dependencies(&result,
 543                                        line,
 544                                        do_get,
 545                                        target,
 546                                        true_target,
 547                                        doing_subtree,
 548                                        &out_of_date_list,
 549                                        old_locals,
 550                                        implicit,
 551                                        &command,
 552                                        less,
 553                                        rechecking_target,
 554                                        recheck_conditionals)) {
 555                         return build_running;
 556                 }
 557                 if (line->body.line.query != NULL) {
 558                         delete_query_chain(line->body.line.query);
 559                 }
 560                 line->body.line.query = out_of_date_list;
 561         }
 562 
 563 #ifdef PARALLEL
 564         if (doing_subtree) {
 565                 parallel = false;
 566         }
 567 #endif
 568 
 569 /*
 570  * If the target is a :: type, do not try to find the rule for the target,
 571  * all actions will be taken by separate branches.
 572  * Else, we try to find an implicit rule using various methods,
 573  * we quit as soon as one is found.
 574  *
 575  * [tolik, 12 Sep 2002] Do not try to find implicit rule for the target
 576  * being rechecked - the target is being rechecked means that it already
 577  * has explicit dependencies derived from an implicit rule found
 578  * in previous step.
 579  */
 580         if (target->colon_splits == 0 && !rechecking_target) {
 581                 /* Look for percent matched rule */
 582                 if ((result == build_dont_know) &&
 583                     (command == NULL)) {
 584                         switch (find_percent_rule(
 585                                         target,
 586                                         &command,
 587                                         recheck_conditionals)) {
 588                         case build_failed:
 589                                 result = build_failed;
 590                                 break;
 591 #ifdef TEAMWARE_MAKE_CMN
 592                         case build_running:
 593                                 target->state = build_running;
 594                                 add_pending(target,
 595                                             --recursion_level,
 596                                             do_get,
 597                                             implicit,
 598                                             false);
 599                                 if (target->conditional_cnt > 0) {
 600                                         reset_locals(target,
 601                                                      old_locals,
 602                                                      get_prop(target->prop,
 603                                                              conditional_prop),
 604                                                      0);
 605                                 }
 606                                 return build_running;
 607 #endif
 608                         case build_ok:
 609                                 result = build_ok;
 610                                 break;
 611                         }
 612                 }
 613                 /* Look for double suffix rule */
 614                 if (result == build_dont_know) {
 615                         Property member;
 616 
 617                         if (target->is_member &&
 618                             ((member = get_prop(target->prop, member_prop)) !=
 619                              NULL)) {
 620                                 switch (find_ar_suffix_rule(target,
 621                                                 member->body.
 622                                                 member.member,
 623                                                 &command,
 624                                                 recheck_conditionals)) {
 625                                 case build_failed:
 626                                         result = build_failed;
 627                                         break;
 628 #ifdef TEAMWARE_MAKE_CMN
 629                                 case build_running:
 630                                         target->state = build_running;
 631                                         add_pending(target,
 632                                                     --recursion_level,
 633                                                     do_get,
 634                                                     implicit,
 635                                                     false);
 636                                     if (target->conditional_cnt > 0) {
 637                                             reset_locals(target,
 638                                                          old_locals,
 639                                                          get_prop(target->prop,
 640                                                              conditional_prop),
 641                                                          0);
 642                                     }
 643                                         return build_running;
 644 #endif
 645                                 default:
 646                                         /* ALWAYS bind $% for old style */
 647                                         /* ar rules */
 648                                         if (line == NULL) {
 649                                                 line =
 650                                                   maybe_append_prop(target,
 651                                                                     line_prop);
 652                                         }
 653                                         line->body.line.percent =
 654                                           member->body.member.member;
 655                                         break;
 656                                 }
 657                         } else {
 658                                 switch (find_double_suffix_rule(target,
 659                                                 &command,
 660                                                 recheck_conditionals)) {
 661                                 case build_failed:
 662                                         result = build_failed;
 663                                         break;
 664 #ifdef TEAMWARE_MAKE_CMN
 665                                 case build_running:
 666                                         target->state = build_running;
 667                                         add_pending(target,
 668                                                     --recursion_level,
 669                                                     do_get,
 670                                                     implicit,
 671                                                     false);
 672                                         if (target->conditional_cnt > 0) {
 673                                                 reset_locals(target,
 674                                                              old_locals,
 675                                                              get_prop(target->
 676                                                                       prop,
 677                                                                       conditional_prop),
 678                                                              0);
 679                                         }
 680                                         return build_running;
 681 #endif
 682                                 }
 683                         }
 684                 }
 685                 /* Look for single suffix rule */
 686 
 687 /* /tolik/
 688  * I commented !implicit to fix bug 1247448: Suffix Rules failed when combine with Pattern Matching Rules.
 689  * This caused problem with SVR4 tilde rules (infinite recursion). So I made some changes in "implicit.cc"
 690  */
 691 /* /tolik, 06.21.96/
 692  * Regression! See BugId 1255360
 693  * If more than one percent rules are defined for the same target then
 694  * the behaviour of 'make' with my previous fix may be different from one
 695  * of the 'old make'. 
 696  * The global variable second_pass (maybe it should be an argument to doname())
 697  * is intended to avoid this regression. It is set in doname_check().
 698  * First, 'make' will work as it worked before. Only when it is
 699  * going to say "don't know how to make target" it sets second_pass to true and
 700  * run 'doname' again but now trying to use Single Suffix Rules.
 701  */
 702                 if ((result == build_dont_know) && !automatic && (!implicit || second_pass) &&
 703                     ((line == NULL) ||
 704                      ((line->body.line.target != NULL) &&
 705                       !line->body.line.target->has_regular_dependency))) {
 706                         switch (find_suffix_rule(target,
 707                                                  target,
 708                                                  empty_name,
 709                                                  &command,
 710                                                  recheck_conditionals)) {
 711                         case build_failed:
 712                                 result = build_failed;
 713                                 break;
 714 #ifdef TEAMWARE_MAKE_CMN
 715                         case build_running:
 716                                 target->state = build_running;
 717                                 add_pending(target,
 718                                             --recursion_level,
 719                                             do_get,
 720                                             implicit,
 721                                             false);
 722                                 if (target->conditional_cnt > 0) {
 723                                         reset_locals(target,
 724                                                      old_locals,
 725                                                      get_prop(target->prop,
 726                                                              conditional_prop),
 727                                                      0);
 728                                 }
 729                                 return build_running;
 730 #endif
 731                         }
 732                 }
 733                 /* Try to sccs get */
 734                 if ((command == NULL) &&
 735                     (result == build_dont_know) &&
 736                     do_get) {
 737                         result = sccs_get(target, &command);
 738                 }
 739 
 740                 /* Use .DEFAULT rule if it is defined. */
 741                 if ((command == NULL) &&
 742                     (result == build_dont_know) &&
 743                     (true_target->colons == no_colon) &&
 744                     default_rule &&
 745                     !implicit) {
 746                         /* Make sure we have a line prop */
 747                         line = maybe_append_prop(target, line_prop);
 748                         command = line;
 749                         Boolean out_of_date;
 750                         if (true_target->is_member) {
 751                                 out_of_date = (Boolean) OUT_OF_DATE_SEC(true_target->stat.time,
 752                                                                         line->body.line.dependency_time);
 753                         } else {
 754                                 out_of_date = (Boolean) OUT_OF_DATE(true_target->stat.time,
 755                                                                     line->body.line.dependency_time);
 756                         }
 757                         if (build_unconditional || out_of_date) {
 758                                 line->body.line.is_out_of_date = true;
 759                                 if (debug_level > 0) {
 760                                         (void) printf(catgets(catd, 1, 17, "%*sBuilding %s using .DEFAULT because it is out of date\n"),
 761                                                       recursion_level,
 762                                                       "",
 763                                                       true_target->string_mb);
 764                                 }
 765                         }
 766                         line->body.line.sccs_command = false;
 767                         line->body.line.command_template = default_rule;
 768                         line->body.line.target = true_target;
 769                         line->body.line.star = NULL;
 770                         line->body.line.less = true_target;
 771                         line->body.line.percent = NULL;
 772                 }
 773         }
 774 
 775         /* We say "target up to date" if no cmd were executed for the target */
 776         if (!target->is_double_colon_parent) {
 777                 commands_done = false;
 778         }
 779 
 780         silent = silent_all;
 781         ignore_errors = ignore_errors_all;
 782         if  (posix)
 783         {
 784           if  (!silent)
 785           {
 786             silent = (Boolean) target->silent_mode;
 787           }
 788           if  (!ignore_errors)
 789           {
 790             ignore_errors = (Boolean) target->ignore_error_mode;
 791           }
 792         }
 793 
 794         int doname_dyntarget = 0;
 795 r_command:
 796         /* Run commands if any. */
 797         if ((command != NULL) &&
 798             (command->body.line.command_template != NULL)) {
 799                 if (result != build_failed) {
 800                         result = run_command(command, 
 801                                              (Boolean) ((parallel || save_parallel) && !silent));
 802 #ifdef NSE
 803                         nse_check_no_deps_no_rule(target,
 804                                 get_prop(target->prop, line_prop), command);
 805 #endif
 806                 }
 807                 switch (result) {
 808 #ifdef TEAMWARE_MAKE_CMN
 809                 case build_running:
 810                         add_running(target,
 811                                     true_target,
 812                                     command,
 813                                     --recursion_level,
 814                                     auto_count,
 815                                     automatics,
 816                                     do_get,
 817                                     implicit);
 818                         target->state = build_running;
 819                         if ((line = get_prop(target->prop,
 820                                              line_prop)) != NULL) {
 821                                 if (line->body.line.query != NULL) {
 822                                         delete_query_chain(line->body.line.query);
 823                                 }
 824                                 line->body.line.query = NULL;
 825                         }
 826                         if (target->conditional_cnt > 0) {
 827                                 reset_locals(target,
 828                                              old_locals,
 829                                              get_prop(target->prop,
 830                                                      conditional_prop),
 831                                              0);
 832                         }
 833                         return build_running;
 834                 case build_serial:
 835                         add_serial(target,
 836                                    --recursion_level,
 837                                    do_get,
 838                                    implicit);
 839                         target->state = build_running;
 840                         line = get_prop(target->prop, line_prop);
 841                         if (line != NULL) {
 842                                 if (line->body.line.query != NULL) {
 843                                         delete_query_chain(line->body.line.query);
 844                                 }
 845                                 line->body.line.query = NULL;
 846                         }
 847                         if (target->conditional_cnt > 0) {
 848                                 reset_locals(target,
 849                                              old_locals,
 850                                              get_prop(target->prop,
 851                                                      conditional_prop),
 852                                              0);
 853                         }
 854                         return build_running;
 855 #endif
 856                 case build_ok:
 857                         /* If all went OK set a nice timestamp */
 858                         if (true_target->stat.time == file_doesnt_exist) {
 859                                 true_target->stat.time = file_max_time;
 860                         }
 861                         break;
 862                 }
 863         } else {
 864                 /*
 865                  * If no command was found for the target, and it doesn't
 866                  * exist, and it is mentioned as a target in the makefile,
 867                  * we say it is extremely new and that it is OK.
 868                  */
 869                 if (target->colons != no_colon) {
 870                         if (true_target->stat.time == file_doesnt_exist){
 871                                 true_target->stat.time = file_max_time;
 872                         }
 873                         result = build_ok;
 874                 }
 875                 /*
 876                  * Trying dynamic targets.
 877                  */
 878                 if(!doname_dyntarget) {
 879                         doname_dyntarget = 1;
 880                         Name dtarg = find_dyntarget(target);
 881                         if(dtarg!=NULL) {
 882                                 if (!target->has_depe_list_expanded) {
 883                                         dynamic_dependencies(target);
 884                                 }
 885                                 if ((line = get_prop(target->prop, line_prop)) != NULL) {
 886                                         if (check_dependencies(&result,
 887                                                                line,
 888                                                                do_get,
 889                                                                target,
 890                                                                true_target,
 891                                                                doing_subtree,
 892                                                                &out_of_date_list,
 893                                                                old_locals,
 894                                                                implicit,
 895                                                                &command,
 896                                                                less,
 897                                                                rechecking_target,
 898                                                                recheck_conditionals))
 899                                         {
 900                                                 return build_running;
 901                                         }
 902                                         if (line->body.line.query != NULL) {
 903                                                 delete_query_chain(line->body.line.query);
 904                                         }
 905                                         line->body.line.query = out_of_date_list;
 906                                 }
 907                                 goto r_command;
 908                         }
 909                 }
 910                 /*
 911                  * If the file exists, it is OK that we couldnt figure
 912                  * out how to build it.
 913                  */
 914                 (void) exists(target);
 915                 if ((target->stat.time != file_doesnt_exist) &&
 916                     (result == build_dont_know)) {
 917                         result = build_ok;
 918                 }
 919         }
 920 
 921         /*
 922          * Some of the following is duplicated in the function finish_doname.
 923          * If anything is changed here, check to see if it needs to be
 924          * changed there.
 925          */
 926         if ((line = get_prop(target->prop, line_prop)) != NULL) {
 927                 if (line->body.line.query != NULL) {
 928                         delete_query_chain(line->body.line.query);
 929                 }
 930                 line->body.line.query = NULL;
 931         }
 932         target->state = result;
 933         parallel = save_parallel;
 934         if (target->conditional_cnt > 0) {
 935                 reset_locals(target,
 936                              old_locals,
 937                              get_prop(target->prop, conditional_prop),
 938                              0);
 939         }
 940         recursion_level--;
 941         if (target->is_member) {
 942                 Property member;
 943 
 944                 /* Propagate the timestamp from the member file to the member*/
 945                 if ((target->stat.time != file_max_time) &&
 946                     ((member = get_prop(target->prop, member_prop)) != NULL) &&
 947                     (exists(member->body.member.member) > file_doesnt_exist)) {
 948                         target->stat.time =
 949                           member->body.member.member->stat.time;
 950                 }
 951         }
 952         /*
 953          * Check if we found any new auto dependencies when we
 954          * built the target.
 955          */
 956         if ((result == build_ok) && check_auto_dependencies(target,
 957                                                             auto_count,
 958                                                             automatics)) {
 959                 if (debug_level > 0) {
 960                         (void) printf(catgets(catd, 1, 18, "%*sTarget `%s' acquired new dependencies from build, rechecking all dependencies\n"),
 961                                       recursion_level,
 962                                       "",
 963                                       true_target->string_mb);
 964                 }
 965                 rechecking_target = true;
 966                 saved_commands_done = commands_done;
 967                 goto recheck_target;
 968         }
 969 
 970         if (rechecking_target && !commands_done) {
 971                 commands_done = saved_commands_done;
 972         }
 973 
 974         return result;
 975 }
 976 
 977 /*
 978  * DONE.
 979  *
 980  *      check_dependencies(result, line, do_get,
 981  *                      target, true_target, doing_subtree, out_of_date_tail,
 982  *                      old_locals, implicit, command, less, rechecking_target)
 983  *
 984  *      Return value:
 985  *                              True returned if some dependencies left running
 986  *                              
 987  *      Parameters:
 988  *              result          Pointer to cell we update if build failed
 989  *              line            We get the dependencies from here
 990  *              do_get          Allow use of sccs get in recursive doname()
 991  *              target          The target to chase dependencies for
 992  *              true_target     The real one for :: and lib(member)
 993  *              doing_subtree   True if building a conditional macro subtree
 994  *              out_of_date_tail Used to set the $? list
 995  *              old_locals      Used for resetting the local macros
 996  *              implicit        Called when scanning for implicit rules?
 997  *              command         Place to stuff command
 998  *              less            Set to $< value
 999  *
1000  *      Global variables used:
1001  *              command_changed Set if we suspect .make.state needs rewrite
1002  *              debug_level     Should we trace actions?
1003  *              force           The Name " FORCE", compared against
1004  *              recursion_level Used for tracing
1005  *              rewrite_statefile Set if .make.state needs rewriting
1006  *              wait_name       The Name ".WAIT", compared against
1007  */
1008 static Boolean
1009 #ifdef TEAMWARE_MAKE_CMN
1010 check_dependencies(Doname *result, Property line, Boolean do_get, Name target, Name true_target, Boolean doing_subtree, Chain *out_of_date_tail, Property old_locals, Boolean implicit, Property *command, Name less, Boolean rechecking_target, Boolean recheck_conditionals)
1011 #else
1012 check_dependencies(Doname *result, Property line, Boolean do_get, Name target, Name true_target, Boolean, Chain *out_of_date_tail, Property, Boolean, Property *command, Name less, Boolean rechecking_target, Boolean recheck_conditionals)
1013 #endif
1014 {
1015         Boolean                 dependencies_running;
1016         register Dependency     dependency;
1017         Doname                  dep_result;
1018         Boolean                 dependency_changed = false;
1019 
1020         line->body.line.dependency_time = file_doesnt_exist;
1021         if (line->body.line.query != NULL) {
1022                 delete_query_chain(line->body.line.query);
1023         }
1024         line->body.line.query = NULL;
1025         line->body.line.is_out_of_date = false;
1026         dependencies_running = false;
1027         /*
1028          * Run thru all the dependencies and call doname() recursively
1029          * on each of them.
1030          */
1031         for (dependency = line->body.line.dependencies;
1032              dependency != NULL;
1033              dependency = dependency->next) {
1034                 Boolean this_dependency_changed = false;
1035 
1036                 if (!dependency->automatic &&
1037                     (rechecking_target || target->rechecking_target)) {
1038                         /*
1039                          * We only bother with the autos when rechecking
1040                          */
1041                         continue;
1042                 }
1043 
1044                 if (dependency->name == wait_name) {
1045                         /*
1046                          * The special target .WAIT means finish all of
1047                          * the prior dependencies before continuing.
1048                          */
1049                         if (dependencies_running) {
1050                                 break;
1051                         }
1052 #ifdef DISTRIBUTED
1053                 } else if ((!parallel_ok(dependency->name, false)) &&
1054                            (dependencies_running)) {
1055                         /*
1056                          * If we can't execute the current dependency in
1057                          * parallel, hold off the dependency processing
1058                          * to preserve the order of the dependencies.
1059                          */
1060                         break;
1061 #endif
1062                 } else {
1063                         timestruc_t     depe_time = file_doesnt_exist;
1064 
1065 
1066                         if (true_target->is_member) {
1067                                 depe_time = exists(dependency->name);
1068                         }
1069                         if (dependency->built ||
1070                             (dependency->name->state == build_failed)) {
1071                                 dep_result = (Doname) dependency->name->state;
1072                         } else {
1073 #ifdef NSE
1074                                 nse_check_sccs(target->string,
1075                                                dependency->name->string);
1076                                 nse_check_derived_src(target,
1077                                                dependency->name->string,
1078                                                line->body.line.command_template);
1079 #endif
1080                                 dep_result = doname_check(dependency->name,
1081                                                           do_get,
1082                                                           false,
1083                                                           (Boolean) dependency->automatic);
1084                         }
1085                         if (true_target->is_member || dependency->name->is_member) {
1086                                 /* should compare only secs, cause lib members does not have nsec time resolution */
1087                                 if (depe_time.tv_sec != dependency->name->stat.time.tv_sec) {
1088                                         this_dependency_changed =
1089                                           dependency_changed =
1090                                             true;
1091                                 }
1092                         } else {
1093                                 if (depe_time != dependency->name->stat.time) {
1094                                         this_dependency_changed =
1095                                           dependency_changed =
1096                                             true;
1097                                 }
1098                         }
1099                         dependency->built = true;
1100                         switch (dep_result) {
1101                         case build_running:
1102                                 dependencies_running = true;
1103                                 continue;
1104                         case build_failed:
1105                                 *result = build_failed;
1106                                 break;
1107                         case build_dont_know:
1108 /*
1109  * If make can't figure out how to make a dependency, maybe the dependency
1110  * is out of date. In this case, we just declare the target out of date
1111  * and go on. If we really need the dependency, the make'ing of the target
1112  * will fail. This will only happen for automatic (hidden) dependencies.
1113  */
1114                                 if(!recheck_conditionals) {
1115                                         line->body.line.is_out_of_date = true;
1116                                 }
1117                                 /*
1118                                  * Make sure the dependency is not saved
1119                                  * in the state file.
1120                                  */
1121                                 dependency->stale = true;
1122                                 rewrite_statefile =
1123                                   command_changed =
1124                                     true;
1125                                 if (debug_level > 0) {
1126                                         (void) printf(catgets(catd, 1, 19, "Target %s rebuilt because dependency %s does not exist\n"),
1127                                                      true_target->string_mb,
1128                                                      dependency->name->string_mb);
1129                                 }
1130                                 break;
1131                         }
1132                         if (dependency->name->depends_on_conditional) {
1133                                 target->depends_on_conditional = true;
1134                         }
1135                         if (dependency->name == force) {
1136                                 target->stat.time =
1137                                   dependency->name->stat.time;
1138                         }
1139                         /*
1140                          * Propagate new timestamp from "member" to
1141                          * "lib.a(member)".
1142                          */
1143                         (void) exists(dependency->name);
1144 
1145                         /* Collect the timestamp of the youngest dependency */
1146                         line->body.line.dependency_time =
1147                           MAX(dependency->name->stat.time,
1148                               line->body.line.dependency_time);
1149 
1150                         /* Correction: do not consider nanosecs for members */
1151                         if(true_target->is_member || dependency->name->is_member) {
1152                                 line->body.line.dependency_time.tv_nsec = 0;
1153                         }
1154 
1155                         if (debug_level > 1) {
1156                                 (void) printf(catgets(catd, 1, 20, "%*sDate(%s)=%s \n"),
1157                                               recursion_level,
1158                                               "",
1159                                               dependency->name->string_mb,
1160                                               time_to_string(dependency->name->
1161                                                              stat.time));
1162                                 if (dependency->name->stat.time > line->body.line.dependency_time) {
1163                                         (void) printf(catgets(catd, 1, 21, "%*sDate-dependencies(%s) set to %s\n"),
1164                                                       recursion_level,
1165                                                       "",
1166                                                       true_target->string_mb,
1167                                                       time_to_string(line->body.line.
1168                                                                      dependency_time));
1169                                 }
1170                         }
1171 
1172                         /* Build the $? list */
1173                         if (true_target->is_member) {
1174                                 if (this_dependency_changed == true) {
1175                                         true_target->stat.time = dependency->name->stat.time;
1176                                         true_target->stat.time.tv_sec--;
1177                                 } else {
1178                                         /* Dina: 
1179                                          * The next statement is commented
1180                                          * out as a fix for bug #1051032.
1181                                          * if dependency hasn't changed
1182                                          * then there's no need to invalidate
1183                                          * true_target. This statemnt causes
1184                                          * make to take much longer to process
1185                                          * an already-built archive. Soren
1186                                          * said it was a quick fix for some
1187                                          * problem he doesn't remember.
1188                                         true_target->stat.time = file_no_time;
1189                                          */
1190                                         (void) exists(true_target);
1191                                 }
1192                         } else {
1193                                 (void) exists(true_target);
1194                         }
1195                         Boolean out_of_date;
1196                         if (true_target->is_member || dependency->name->is_member) {
1197                                 out_of_date = (Boolean) OUT_OF_DATE_SEC(true_target->stat.time,
1198                                                                         dependency->name->stat.time);
1199                         } else {
1200                                 out_of_date = (Boolean) OUT_OF_DATE(true_target->stat.time,
1201                                                                     dependency->name->stat.time);
1202                         }
1203                         if ((build_unconditional || out_of_date) &&
1204                             (dependency->name != force) &&
1205                             (dependency->stale == false)) {
1206                                 *out_of_date_tail = ALLOC(Chain);
1207                                 if (dependency->name->is_member &&
1208                                     (get_prop(dependency->name->prop,
1209                                               member_prop) != NULL)) {
1210                                         (*out_of_date_tail)->name =
1211                                           get_prop(dependency->name->prop,
1212                                                    member_prop)->
1213                                                      body.member.member;
1214                                 } else {
1215                                         (*out_of_date_tail)->name =
1216                                           dependency->name;
1217                                 }
1218                                 (*out_of_date_tail)->next = NULL;
1219                                 out_of_date_tail = &(*out_of_date_tail)->next;
1220                                 if (debug_level > 0) {
1221                                         if (dependency->name->stat.time == file_max_time) {
1222                                                 (void) printf(catgets(catd, 1, 22, "%*sBuilding %s because %s does not exist\n"),
1223                                                               recursion_level,
1224                                                               "",
1225                                                               true_target->string_mb,
1226                                                               dependency->name->string_mb);
1227                                         } else {
1228                                                 (void) printf(catgets(catd, 1, 23, "%*sBuilding %s because it is out of date relative to %s\n"),
1229                                                               recursion_level,
1230                                                               "",
1231                                                               true_target->string_mb,
1232                                                               dependency->name->string_mb);
1233                                         }
1234                                 }
1235                         }
1236                         if (dependency->name == force) {
1237                                 force->stat.time =
1238                                   file_max_time;
1239                                 force->state = build_dont_know;
1240                         }
1241                 }
1242         }
1243 #ifdef TEAMWARE_MAKE_CMN
1244         if (dependencies_running) {
1245                 if (doing_subtree) {
1246                         if (target->conditional_cnt > 0) {
1247                                 reset_locals(target,
1248                                              old_locals,
1249                                              get_prop(target->prop,
1250                                                       conditional_prop),
1251                                              0);
1252                         }
1253                         return true;
1254                 } else {
1255                         target->state = build_running;
1256                         add_pending(target,
1257                                     --recursion_level,
1258                                     do_get,
1259                                     implicit,
1260                                     false);
1261                         if (target->conditional_cnt > 0) {
1262                                 reset_locals(target,
1263                                              old_locals,
1264                                              get_prop(target->prop,
1265                                                       conditional_prop),
1266                                              0);
1267                         }
1268                         return true;
1269                 }
1270         }
1271 #endif
1272         /*
1273          * Collect the timestamp of the youngest double colon target
1274          * dependency.
1275          */
1276         if (target->is_double_colon_parent) {
1277                 for (dependency = line->body.line.dependencies;
1278                      dependency != NULL;
1279                      dependency = dependency->next) {
1280                         Property        tmp_line;
1281 
1282                         if ((tmp_line = get_prop(dependency->name->prop, line_prop)) != NULL) {
1283                                 if(tmp_line->body.line.dependency_time != file_max_time) {
1284                                         target->stat.time =
1285                                           MAX(tmp_line->body.line.dependency_time,
1286                                               target->stat.time);
1287                                 }
1288                         }
1289                 }
1290         }
1291         if ((true_target->is_member) && (dependency_changed == true)) {
1292                 true_target->stat.time = file_no_time;
1293         }
1294         /*
1295          * After scanning all the dependencies, we check the rule
1296          * if we found one.
1297          */
1298         if (line->body.line.command_template != NULL) {
1299                 if (line->body.line.command_template_redefined) {
1300                         warning(catgets(catd, 1, 24, "Too many rules defined for target %s"),
1301                                 target->string_mb);
1302                 }
1303                 *command = line;
1304                 /* Check if the target is out of date */
1305                 Boolean out_of_date;
1306                 if (true_target->is_member) {
1307                         out_of_date = (Boolean) OUT_OF_DATE_SEC(true_target->stat.time,
1308                                                                 line->body.line.dependency_time);
1309                 } else {
1310                         out_of_date = (Boolean) OUT_OF_DATE(true_target->stat.time,
1311                                                             line->body.line.dependency_time);
1312                 }
1313                 if (build_unconditional || out_of_date){
1314                         if(!recheck_conditionals) {
1315                                 line->body.line.is_out_of_date = true;
1316                         }
1317                 }
1318                 line->body.line.sccs_command = false;
1319                 line->body.line.target = true_target;
1320                 if(gnu_style) {
1321 
1322                         // set $< for explicit rule
1323                         if(line->body.line.dependencies != NULL) {
1324                                 less = line->body.line.dependencies->name;
1325                         }
1326 
1327                         // set $* for explicit rule
1328                         Name                    target_body;
1329                         Name                    tt = true_target;
1330                         Property                member;
1331                         register wchar_t        *target_end;
1332                         register Dependency     suffix;
1333                         register int            suffix_length;
1334                         Wstring                 targ_string;
1335                         Wstring                 suf_string;
1336 
1337                         if (true_target->is_member &&
1338                             ((member = get_prop(target->prop, member_prop)) !=
1339                              NULL)) {
1340                                 tt = member->body.member.member;
1341                         }
1342                         targ_string.init(tt);
1343                         target_end = targ_string.get_string() + tt->hash.length;
1344                         for (suffix = suffixes; suffix != NULL; suffix = suffix->next) {
1345                                 suffix_length = suffix->name->hash.length;
1346                                 suf_string.init(suffix->name);
1347                                 if (tt->hash.length < suffix_length) {
1348                                         continue;
1349                                 } else if (!IS_WEQUALN(suf_string.get_string(),
1350                                                 (target_end - suffix_length),
1351                                                 suffix_length)) {
1352                                         continue;
1353                                 }
1354                                 target_body = GETNAME(
1355                                         targ_string.get_string(),
1356                                         (int)(tt->hash.length - suffix_length)
1357                                 );
1358                                 line->body.line.star = target_body;
1359                         }
1360 
1361                         // set result = build_ok so that implicit rules are not used.
1362                         if(*result == build_dont_know) {
1363                                 *result = build_ok;
1364                         }
1365                 }
1366                 if (less != NULL) {
1367                         line->body.line.less = less;
1368                 }
1369         }
1370 
1371         return false;
1372 }
1373 
1374 /*
1375  *      dynamic_dependencies(target)
1376  *
1377  *      Checks if any dependency contains a macro ref
1378  *      If so, it replaces the dependency with the expanded version.
1379  *      Here, "$@" gets translated to target->string. That is
1380  *      the current name on the left of the colon in the
1381  *      makefile.  Thus,
1382  *              xyz:    s.$@.c
1383  *      translates into
1384  *              xyz:    s.xyz.c
1385  *
1386  *      Also, "$(@F)" translates to the same thing without a preceeding
1387  *      directory path (if one exists).
1388  *      Note, to enter "$@" on a dependency line in a makefile
1389  *      "$$@" must be typed. This is because make expands
1390  *      macros in dependency lists upon reading them.
1391  *      dynamic_dependencies() also expands file wildcards.
1392  *      If there are any Shell meta characters in the name,
1393  *      search the directory, and replace the dependency
1394  *      with the set of files the pattern matches
1395  *
1396  *      Parameters:
1397  *              target          Target to sanitize dependencies for
1398  *
1399  *      Global variables used:
1400  *              c_at            The Name "@", used to set macro value
1401  *              debug_level     Should we trace actions?
1402  *              dot             The Name ".", used to read directory
1403  *              recursion_level Used for tracing
1404  */
1405 void
1406 dynamic_dependencies(Name target)
1407 {
1408         wchar_t                 pattern[MAXPATHLEN];
1409         register wchar_t        *p;
1410         Property                line;
1411         register Dependency     dependency;
1412         register Dependency     *remove;
1413         String_rec              string;
1414         wchar_t                 buffer[MAXPATHLEN];
1415         register Boolean        set_at = false;
1416         register wchar_t        *start;
1417         Dependency              new_depe;
1418         register Boolean        reuse_cell;
1419         Dependency              first_member;
1420         Name                    directory;
1421         Name                    lib;
1422         Name                    member;
1423         Property                prop;
1424         Name                    true_target = target;
1425         wchar_t                 *library;
1426 
1427         if ((line = get_prop(target->prop, line_prop)) == NULL) {
1428                 return;
1429         }
1430         /* If the target is constructed from a "::" target we consider that */
1431         if (target->has_target_prop) {
1432                 true_target = get_prop(target->prop,
1433                                        target_prop)->body.target.target;
1434         }
1435         /* Scan all dependencies and process the ones that contain "$" chars */
1436         for (dependency = line->body.line.dependencies;
1437              dependency != NULL;
1438              dependency = dependency->next) {
1439                 if (!dependency->name->dollar) {
1440                         continue;
1441                 }
1442                 target->has_depe_list_expanded = true;
1443 
1444                 /* The make macro $@ is bound to the target name once per */
1445                 /* invocation of dynamic_dependencies() */
1446                 if (!set_at) {
1447                         (void) SETVAR(c_at, true_target, false);
1448                         set_at = true;
1449                 }
1450                 /* Expand this dependency string */
1451                 INIT_STRING_FROM_STACK(string, buffer);
1452                 expand_value(dependency->name, &string, false);
1453                 /* Scan the expanded string. It could contain whitespace */
1454                 /* which mean it expands to several dependencies */
1455                 start = string.buffer.start;
1456                 while (iswspace(*start)) {
1457                         start++;
1458                 }
1459                 /* Remove the cell (later) if the macro was empty */
1460                 if (start[0] == (int) nul_char) {
1461                         dependency->name = NULL;
1462                 }
1463 
1464 /* azv 10/26/95 to fix bug BID_1170218 */
1465                 if ((start[0] == (int) period_char) &&
1466                     (start[1] == (int) slash_char)) {
1467                         start += 2;
1468                 }
1469 /* azv */
1470 
1471                 first_member = NULL;
1472                 /* We use the original dependency cell for the first */
1473                 /* dependency from the expansion */
1474                 reuse_cell = true;
1475                 /* We also have to deal with dependencies that expand to */
1476                 /* lib.a(members) notation */
1477                 for (p = start; *p != (int) nul_char; p++) {
1478                         if ((*p == (int) parenleft_char)) {
1479                                 lib = GETNAME(start, p - start);
1480                                 lib->is_member = true;
1481                                 first_member = dependency;
1482                                 start = p + 1;
1483                                 while (iswspace(*start)) {
1484                                         start++;
1485                                 }
1486                                 break;
1487                         }
1488                 }
1489                 do {
1490                     /* First skip whitespace */
1491                         for (p = start; *p != (int) nul_char; p++) {
1492                                 if ((*p == (int) nul_char) ||
1493                                     iswspace(*p) ||
1494                                     (*p == (int) parenright_char)) {
1495                                         break;
1496                                 }
1497                         }
1498                         /* Enter dependency from expansion */
1499                         if (p != start) {
1500                                 /* Create new dependency cell if */
1501                                 /* this is not the first dependency */
1502                                 /* picked from the expansion */
1503                                 if (!reuse_cell) {
1504                                         new_depe = ALLOC(Dependency);
1505                                         new_depe->next = dependency->next;
1506                                         new_depe->automatic = false;
1507                                         new_depe->stale = false;
1508                                         new_depe->built = false;
1509                                         dependency->next = new_depe;
1510                                         dependency = new_depe;
1511                                 }
1512                                 reuse_cell = false;
1513                                 /* Internalize the dependency name */
1514                                 // tolik. Fix for bug 4110429: inconsistent expansion for macros that
1515                                 // include "//" and "/./"
1516                                 //dependency->name = GETNAME(start, p - start);
1517                                 dependency->name = normalize_name(start, p - start);
1518                                 if ((debug_level > 0) &&
1519                                     (first_member == NULL)) {
1520                                         (void) printf(catgets(catd, 1, 25, "%*sDynamic dependency `%s' for target `%s'\n"),
1521                                                       recursion_level,
1522                                                       "",
1523                                                       dependency->name->string_mb,
1524                                                       true_target->string_mb);
1525                                 }
1526                                 for (start = p; iswspace(*start); start++);
1527                                 p = start;
1528                         }
1529                 } while ((*p != (int) nul_char) &&
1530                          (*p != (int) parenright_char));
1531                 /* If the expansion was of lib.a(members) format we now */
1532                 /* enter the proper member cells */
1533                 if (first_member != NULL) {
1534                         /* Scan the new dependencies and transform them from */
1535                         /* "foo" to "lib.a(foo)" */
1536                         for (; 1; first_member = first_member->next) {
1537                                 /* Build "lib.a(foo)" name */
1538                                 INIT_STRING_FROM_STACK(string, buffer);
1539                                 APPEND_NAME(lib,
1540                                               &string,
1541                                               (int) lib->hash.length);
1542                                 append_char((int) parenleft_char, &string);
1543                                 APPEND_NAME(first_member->name,
1544                                               &string,
1545                                               FIND_LENGTH);
1546                                 append_char((int) parenright_char, &string);
1547                                 member = first_member->name;
1548                                 /* Replace "foo" with "lib.a(foo)" */
1549                                 first_member->name =
1550                                   GETNAME(string.buffer.start, FIND_LENGTH);
1551                                 if (string.free_after_use) {
1552                                         retmem(string.buffer.start);
1553                                 }
1554                                 if (debug_level > 0) {
1555                                         (void) printf(catgets(catd, 1, 26, "%*sDynamic dependency `%s' for target `%s'\n"),
1556                                                       recursion_level,
1557                                                       "",
1558                                                       first_member->name->
1559                                                       string_mb,
1560                                                       true_target->string_mb);
1561                                 }
1562                                 first_member->name->is_member = lib->is_member;
1563                                 /* Add member property to member */
1564                                 prop = maybe_append_prop(first_member->name,
1565                                                          member_prop);
1566                                 prop->body.member.library = lib;
1567                                 prop->body.member.entry = NULL;
1568                                 prop->body.member.member = member;
1569                                 if (first_member == dependency) {
1570                                         break;
1571                                 }
1572                         }
1573                 }
1574         }
1575         Wstring wcb;
1576         /* Then scan all the dependencies again. This time we want to expand */
1577         /* shell file wildcards */
1578         for (remove = &line->body.line.dependencies, dependency = *remove;
1579              dependency != NULL;
1580              dependency = *remove) {
1581                 if (dependency->name == NULL) {
1582                         dependency = *remove = (*remove)->next;
1583                         continue;
1584                 }
1585                 /* If dependency name string contains shell wildcards */
1586                 /* replace the name with the expansion */
1587                 if (dependency->name->wildcard) {
1588 #ifdef NSE
1589                         nse_wildcard(target->string, dependency->name->string);
1590 #endif
1591                         wcb.init(dependency->name);
1592                         if ((start = (wchar_t *) wschr(wcb.get_string(),
1593                                            (int) parenleft_char)) != NULL) {
1594                                 /* lib(*) type pattern */
1595                                 library = buffer;
1596                                 (void) wsncpy(buffer,
1597                                               wcb.get_string(),
1598                                               start - wcb.get_string());
1599                                 buffer[start-wcb.get_string()] =
1600                                   (int) nul_char;
1601                                 (void) wsncpy(pattern,
1602                                               start + 1,
1603 (int) (dependency->name->hash.length-(start-wcb.get_string())-2));
1604                                 pattern[dependency->name->hash.length -
1605                                         (start-wcb.get_string()) - 2] =
1606                                           (int) nul_char;
1607                         } else {
1608                                 library = NULL;
1609                                 (void) wsncpy(pattern,
1610                                               wcb.get_string(),
1611                                               (int) dependency->name->hash.length);
1612                                 pattern[dependency->name->hash.length] =
1613                                   (int) nul_char;
1614                         }
1615                         start = (wchar_t *) wsrchr(pattern, (int) slash_char);
1616                         if (start == NULL) {
1617                                 directory = dot;
1618                                 p = pattern;
1619                         } else {
1620                                 directory = GETNAME(pattern, start-pattern);
1621                                 p = start+1;
1622                         }
1623                         /* The expansion is handled by the read_dir() routine*/
1624                         if (read_dir(directory, p, line, library)) {
1625                                 *remove = (*remove)->next;
1626                         } else {
1627                                 remove = &dependency->next;
1628                         }
1629                 } else {
1630                         remove = &dependency->next;
1631                 }
1632         }
1633 
1634         /* Then unbind $@ */
1635         (void) SETVAR(c_at, (Name) NULL, false);
1636 }
1637 
1638 /*
1639  * DONE.
1640  *
1641  *      run_command(line)
1642  *
1643  *      Takes one Cmd_line and runs the commands from it.
1644  *
1645  *      Return value:
1646  *                              Indicates if the command failed or not
1647  *
1648  *      Parameters:
1649  *              line            The command line to run
1650  *
1651  *      Global variables used:
1652  *              commands_done   Set if we do run command
1653  *              current_line    Set to the line we run a command from
1654  *              current_target  Set to the target we run a command for
1655  *              file_number     Used to form temp file name
1656  *              keep_state      Indicates that .KEEP_STATE is on
1657  *              make_state      The Name ".make.state", used to check timestamp
1658  *              parallel        True if currently building in parallel
1659  *              parallel_process_cnt Count of parallel processes running
1660  *              quest           Indicates that make -q is on
1661  *              rewrite_statefile Set if we do run a command
1662  *              sunpro_dependencies The Name "SUNPRO_DEPENDENCIES", set value
1663  *              temp_file_directory Used to form temp fie name
1664  *              temp_file_name  Set to the name of the temp file
1665  *              touch           Indicates that make -t is on
1666  */
1667 static Doname
1668 run_command(register Property line, Boolean)
1669 {
1670         register Doname         result = build_ok;
1671         register Boolean        remember_only = false;
1672         register Name           target = line->body.line.target;
1673         wchar_t                 *string;
1674         char                    tmp_file_path[MAXPATHLEN];
1675 
1676         if (!line->body.line.is_out_of_date && target->rechecking_target) {
1677                 target->rechecking_target = false;
1678                 return build_ok;
1679         }
1680 
1681         /*
1682          * Build the command if we know the target is out of date,
1683          * or if we want to check cmd consistency.
1684          */
1685         if (line->body.line.is_out_of_date || keep_state) {
1686                 /* Hack for handling conditional macros in DMake. */
1687                 if (!line->body.line.dont_rebuild_command_used) {
1688                         build_command_strings(target, line);
1689                 }
1690         }
1691         /* Never mind */
1692         if (!line->body.line.is_out_of_date) {
1693                 return build_ok;
1694         }
1695         /* If quest, then exit(1) because the target is out of date */
1696         if (quest) {
1697                 if (posix) {
1698 #ifdef TEAMWARE_MAKE_CMN
1699                         result = execute_parallel(line, true);
1700 #else
1701                         result = execute_serial(line);
1702 #endif
1703                 }
1704                 exit_status = 1;
1705                 exit(1);
1706         }
1707         /* We actually had to do something this time */
1708         rewrite_statefile = commands_done = true;
1709         /*
1710          * If this is an sccs command, we have to do some extra checking
1711          * and possibly complain. If the file can't be gotten because it's
1712          * checked out, we complain and behave as if the command was
1713          * executed eventhough we ignored the command.
1714          */
1715         if (!touch &&
1716             line->body.line.sccs_command &&
1717             (target->stat.time != file_doesnt_exist) &&
1718             ((target->stat.mode & 0222) != 0)) {
1719                 fatal(catgets(catd, 1, 27, "%s is writable so it cannot be sccs gotten"),
1720                       target->string_mb);
1721                 target->has_complained = remember_only = true;
1722         }
1723         /*
1724          * If KEEP_STATE is on, we make sure we have the timestamp for
1725          * .make.state. If .make.state changes during the command run,
1726          * we reread .make.state after the command. We also setup the
1727          * environment variable that asks utilities to report dependencies.
1728          */
1729         if (!touch &&
1730             keep_state &&
1731             !remember_only) {
1732                 (void) exists(make_state);
1733                 if((strlen(temp_file_directory) == 1) && 
1734                         (temp_file_directory[0] == '/')) {
1735                    tmp_file_path[0] = '\0';
1736                 } else {
1737                    strcpy(tmp_file_path, temp_file_directory);
1738                 }
1739                 sprintf(mbs_buffer,
1740                                 NOCATGETS("%s/.make.dependency.%08x.%d.%d"),
1741                                 tmp_file_path,
1742                                 hostid,
1743                                 getpid(),
1744                                 file_number++);
1745                 MBSTOWCS(wcs_buffer, mbs_buffer);
1746                 Boolean fnd;
1747                 temp_file_name = getname_fn(wcs_buffer, FIND_LENGTH, false, &fnd);
1748                 temp_file_name->stat.is_file = true;
1749                 int len = 2*MAXPATHLEN + strlen(target->string_mb) + 2;
1750                 wchar_t *to = string = ALLOC_WC(len);
1751                 for (wchar_t *from = wcs_buffer; *from != (int) nul_char; ) {
1752                         if (*from == (int) space_char) {
1753                                 *to++ = (int) backslash_char;
1754                         }
1755                         *to++ = *from++;
1756                 }
1757                 *to++ = (int) space_char;
1758                 MBSTOWCS(to, target->string_mb);
1759                 Name sprodep_name = getname_fn(string, FIND_LENGTH, false, &fnd);
1760                 (void) SETVAR(sunpro_dependencies,
1761                               sprodep_name,
1762                               false);
1763                 retmem(string);
1764         } else {
1765                 temp_file_name = NULL;
1766         }
1767 
1768         /*
1769          * In case we are interrupted, we need to know what was going on.
1770          */
1771         current_target = target;
1772         /*
1773          * We also need to be able to save an empty command instead of the
1774          * interrupted one in .make.state.
1775          */
1776         current_line = line;
1777         if (remember_only) {
1778                 /* Empty block!!! */
1779         } else if (touch) {
1780                 result = touch_command(line, target, result);
1781                 if (posix) {
1782 #ifdef TEAMWARE_MAKE_CMN
1783                         result = execute_parallel(line, true);
1784 #else
1785                         result = execute_serial(line);
1786 #endif
1787                 }
1788         } else {
1789                 /*
1790                  * If this is not a touch run, we need to execute the
1791                  * proper command(s) for the target.
1792                  */
1793 #ifdef TEAMWARE_MAKE_CMN
1794                 if (parallel) {
1795                         if (!parallel_ok(target, true)) {
1796                                 /*
1797                                  * We are building in parallel, but
1798                                  * this target must be built in serial.
1799                                  */
1800                                 /*
1801                                  * If nothing else is building,
1802                                  * do this one, else wait.
1803                                  */
1804                                 if (parallel_process_cnt == 0) {
1805 #ifdef TEAMWARE_MAKE_CMN
1806                                         result = execute_parallel(line, true, target->localhost);
1807 #else
1808                                         result = execute_serial(line);
1809 #endif
1810                                 } else {
1811                                         current_target = NULL;
1812                                         current_line = NULL;
1813 /*
1814                                         line->body.line.command_used = NULL;
1815  */
1816                                         line->body.line.dont_rebuild_command_used = true;
1817                                         return build_serial;
1818                                 }
1819                         } else {
1820                                 result = execute_parallel(line, false);
1821                                 switch (result) {
1822                                 case build_running:
1823                                         return build_running;
1824                                 case build_serial:
1825                                         if (parallel_process_cnt == 0) {
1826 #ifdef TEAMWARE_MAKE_CMN
1827                                                 result = execute_parallel(line, true, target->localhost);
1828 #else
1829                                                 result = execute_serial(line);
1830 #endif
1831                                         } else {
1832                                                 current_target = NULL;
1833                                                 current_line = NULL;
1834                                                 target->parallel = false;
1835                                                 line->body.line.command_used =
1836                                                                         NULL;
1837                                                 return build_serial;
1838                                         }
1839                                 }
1840                         }
1841                 } else {
1842 #endif
1843 #ifdef TEAMWARE_MAKE_CMN
1844                         result = execute_parallel(line, true, target->localhost);
1845 #else
1846                         result = execute_serial(line);
1847 #endif
1848 #ifdef TEAMWARE_MAKE_CMN
1849                 }
1850 #endif
1851         }
1852         temp_file_name = NULL;
1853         if (report_dependencies_level == 0){
1854                 update_target(line, result);
1855         }
1856         current_target = NULL;
1857         current_line = NULL;
1858         return result;
1859 }
1860 
1861 /*
1862  *      execute_serial(line)
1863  *
1864  *      Runs thru the command line for the target and
1865  *      executes the rules one by one.
1866  *
1867  *      Return value:
1868  *                              The result of the command build
1869  *
1870  *      Parameters:     
1871  *              line            The command to execute
1872  *
1873  *      Static variables used:
1874  *
1875  *      Global variables used:
1876  *              continue_after_error -k flag
1877  *              do_not_exec_rule -n flag
1878  *              report_dependencies -P flag
1879  *              silent          Don't echo commands before executing
1880  *              temp_file_name  Temp file for auto dependencies
1881  *              vpath_defined   If true, translate path for command
1882  */
1883 Doname
1884 execute_serial(Property line)
1885 {
1886         int                     child_pid = 0;
1887 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
1888         Avo_MToolJobResultMsg   *job_result_msg;
1889         RWCollectable           *xdr_msg;
1890 #endif
1891         Boolean                 printed_serial;
1892         Doname                  result = build_ok;
1893         Cmd_line                rule, cmd_tail, command = NULL;
1894         char                    mbstring[MAXPATHLEN];
1895         int                     filed;
1896         Name                    target = line->body.line.target;
1897 
1898         SEND_MTOOL_MSG(
1899                 if (!sent_rsrc_info_msg) {
1900                         if (userName[0] == '\0') {
1901                                 avo_get_user(userName, NULL);
1902                         }
1903                         if (hostName[0] == '\0') {
1904                                 strcpy(hostName, avo_hostname());
1905                         }
1906                         send_rsrc_info_msg(1, hostName, userName);
1907                         sent_rsrc_info_msg = 1;
1908                 }
1909                 send_job_start_msg(line);
1910                 job_result_msg = new Avo_MToolJobResultMsg();
1911         );
1912 
1913         target->has_recursive_dependency = false;
1914         // We have to create a copy of the rules chain for processing because
1915         // the original one can be destroyed during .make.state file rereading.
1916         for (rule = line->body.line.command_used;
1917              rule != NULL;
1918              rule = rule->next) {
1919                 if (command == NULL) {
1920                         command = cmd_tail = ALLOC(Cmd_line);
1921                 } else {
1922                         cmd_tail->next = ALLOC(Cmd_line);
1923                         cmd_tail = cmd_tail->next;
1924                 }
1925                 *cmd_tail = *rule;
1926         }
1927         if (command) {
1928                 cmd_tail->next = NULL;
1929         }
1930         for (rule = command; rule != NULL; rule = rule->next) {
1931                 if (posix && (touch || quest) && !rule->always_exec) {
1932                         continue;
1933                 }
1934                 if (vpath_defined) {
1935                         rule->command_line =
1936                           vpath_translation(rule->command_line);
1937                 }
1938                 /* Echo command line, maybe. */
1939                 if ((rule->command_line->hash.length > 0) &&
1940                     !silent &&
1941                     (!rule->silent || do_not_exec_rule) &&
1942                     (report_dependencies_level == 0)) {
1943                         (void) printf("%s\n", rule->command_line->string_mb);
1944                         SEND_MTOOL_MSG(
1945                                 job_result_msg->appendOutput(AVO_STRDUP(rule->command_line->string_mb));
1946                         );
1947                 }
1948                 if (rule->command_line->hash.length > 0) {
1949                         SEND_MTOOL_MSG(
1950                                 (void) sprintf(mbstring,
1951                                                 NOCATGETS("%s/make.stdout.%d.%d.XXXXXX"),
1952                                                 tmpdir,
1953                                                 getpid(),
1954                                                 file_number++);
1955 
1956                                 int tmp_fd = mkstemp(mbstring);
1957                                 if(tmp_fd) {
1958                                         (void) close(tmp_fd);
1959                                 }
1960 
1961                                 stdout_file = strdup(mbstring);
1962                                 stderr_file = NULL;
1963                                 child_pid = pollResults(stdout_file,
1964                                                         (char *)NULL,
1965                                                         (char *)NULL);
1966                         );
1967                         /* Do assignment if command line prefixed with "=" */
1968                         if (rule->assign) {
1969                                 result = build_ok;
1970                                 do_assign(rule->command_line, target);
1971                         } else if (report_dependencies_level == 0) {
1972                                 /* Execute command line. */
1973 #ifdef DISTRIBUTED
1974                                 setvar_envvar((Avo_DoJobMsg *)NULL);
1975 #else
1976                                 setvar_envvar();
1977 #endif
1978                                 result = dosys(rule->command_line,
1979                                                (Boolean) rule->ignore_error,
1980                                                (Boolean) rule->make_refd,
1981                                                /* ds 98.04.23 bug #4085164. make should always show error messages */
1982                                                false,
1983                                                /* BOOLEAN(rule->silent &&
1984                                                        rule->ignore_error), */
1985                                                (Boolean) rule->always_exec,
1986                                                target,
1987                                                send_mtool_msgs);
1988 #ifdef NSE
1989                                 nse_did_recursion= false;
1990 #endif
1991                                 check_state(temp_file_name);
1992 #ifdef NSE
1993                                 nse_check_cd(line);
1994 #endif
1995                         }
1996                         SEND_MTOOL_MSG(
1997                                 append_job_result_msg(job_result_msg);
1998                                 if (child_pid > 0) {
1999                                         kill(child_pid, SIGUSR1);
2000                                         while (!((waitpid(child_pid, 0, 0) == -1)
2001                                                 && (errno == ECHILD)));
2002                                 }
2003                                 child_pid = 0;
2004                                 (void) unlink(stdout_file);
2005                                 retmem_mb(stdout_file);
2006                                 stdout_file = NULL;
2007                         );
2008                 } else {
2009                         result = build_ok;
2010                 }
2011                 if (result == build_failed) {
2012                         if (silent || rule->silent) {
2013                                 (void) printf(catgets(catd, 1, 242, "The following command caused the error:\n%s\n"),
2014                                               rule->command_line->string_mb);
2015                                 SEND_MTOOL_MSG(
2016                                         job_result_msg->appendOutput(AVO_STRDUP(catgets(catd, 1, 243, "The following command caused the error:")));
2017                                         job_result_msg->appendOutput(AVO_STRDUP(rule->command_line->string_mb));
2018                                 );
2019                         }
2020                         if (!rule->ignore_error && !ignore_errors) {
2021                                 if (!continue_after_error) {
2022                                         SEND_MTOOL_MSG(
2023                                                 job_result_msg->setResult(job_msg_id, (result == build_ok) ? 0 : 1, DONE);
2024                                                 xdr_msg = (RWCollectable*)
2025                                                         job_result_msg;
2026                                                 xdr(&xdrs, xdr_msg);
2027                                                 (void) fflush(mtool_msgs_fp);
2028                                                 delete job_result_msg;
2029                                         );
2030                                         fatal(catgets(catd, 1, 244, "Command failed for target `%s'"),
2031                                               target->string_mb);
2032                                 }
2033                                 /*
2034                                  * Make sure a failing command is not
2035                                  * saved in .make.state.
2036                                  */
2037                                 line->body.line.command_used = NULL;
2038                                 break;
2039                         } else {
2040                                 result = build_ok;
2041                         }
2042                 }
2043         }
2044         for (rule = command; rule != NULL; rule = cmd_tail) {
2045                 cmd_tail = rule->next;
2046                 free(rule);
2047         }
2048         command = NULL;
2049         SEND_MTOOL_MSG(
2050                 job_result_msg->setResult(job_msg_id, (result == build_ok) ? 0 : 1, DONE);
2051                 xdr_msg = (RWCollectable*) job_result_msg;
2052                 xdr(&xdrs, xdr_msg);
2053                 (void) fflush(mtool_msgs_fp);
2054 
2055                 delete job_result_msg;
2056         );
2057         if (temp_file_name != NULL) {
2058                 free_name(temp_file_name);
2059         }
2060         temp_file_name = NULL;
2061 
2062         Property spro = get_prop(sunpro_dependencies->prop, macro_prop);
2063         if(spro != NULL) {
2064                 Name val = spro->body.macro.value;
2065                 if(val != NULL) {
2066                         free_name(val);
2067                         spro->body.macro.value = NULL;
2068                 }
2069         }
2070         spro = get_prop(sunpro_dependencies->prop, env_mem_prop);
2071         if(spro) {
2072                 char *val = spro->body.env_mem.value;
2073                 if(val != NULL) {
2074                         /* 
2075                          * Do not return memory allocated for SUNPRO_DEPENDENCIES
2076                          * It will be returned in setvar_daemon() in macro.cc 
2077                          */
2078                         //      retmem_mb(val);
2079                         spro->body.env_mem.value = NULL;
2080                 }
2081         }
2082         
2083         return result;
2084 }
2085 
2086 
2087 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
2088 
2089 /*
2090  * Create and send an Avo_MToolRsrcInfoMsg.
2091  */
2092 void
2093 send_rsrc_info_msg(int max_jobs, char *hostname, char *username)
2094 {
2095         static int              first = 1;
2096         Avo_MToolRsrcInfoMsg    *msg;
2097         RWSlistCollectables     server_list;
2098         Avo_ServerState         *server_state;
2099         RWCollectable           *xdr_msg;
2100 
2101         if (!first) {
2102                 return;
2103         }
2104         first = 0;
2105 
2106         create_xdrs_ptr();
2107 
2108         server_state = new Avo_ServerState(max_jobs, hostname, username);
2109         server_list.append(server_state);
2110         msg = new Avo_MToolRsrcInfoMsg(&server_list);
2111 
2112         xdr_msg = (RWCollectable *)msg;
2113         xdr(get_xdrs_ptr(), xdr_msg);
2114         (void) fflush(get_mtool_msgs_fp());
2115 
2116         delete server_state;
2117         delete msg;
2118 }
2119 
2120 /*
2121  * Create and send an Avo_MToolJobStartMsg.
2122  */
2123 void
2124 send_job_start_msg(Property line)
2125 {
2126         int                     cmd_options = 0;
2127         Avo_MToolJobStartMsg    *msg;
2128         Cmd_line                rule;
2129         Name                    target = line->body.line.target;
2130         RWCollectable           *xdr_msg;
2131 
2132         if (userName[0] == '\0') {
2133                 avo_get_user(userName, NULL);
2134         }
2135         if (hostName[0] == '\0') {
2136                 strcpy(hostName, avo_hostname());
2137         }
2138 
2139         msg = new Avo_MToolJobStartMsg();
2140         msg->setJobId(++job_msg_id);
2141         msg->setTarget(AVO_STRDUP(target->string_mb));
2142         msg->setHost(AVO_STRDUP(hostName));
2143         msg->setUser(AVO_STRDUP(userName));
2144 
2145         for (rule = line->body.line.command_used;
2146              rule != NULL;
2147              rule = rule->next) {
2148                 if (posix && (touch || quest) && !rule->always_exec) {
2149                         continue;
2150                 }
2151                 if (vpath_defined) {
2152                         rule->command_line =
2153                           vpath_translation(rule->command_line);
2154                 }
2155                 cmd_options = 0;
2156                 if (rule->ignore_error || ignore_errors) {
2157                         cmd_options |= ignore_mask;
2158                 }
2159                 if (rule->silent || silent) {
2160                         cmd_options |= silent_mask;
2161                 }
2162                 if (rule->command_line->meta) {
2163                         cmd_options |= meta_mask;
2164                 }
2165                 if (!touch && (rule->command_line->hash.length > 0)) {
2166                         msg->appendCmd(new Avo_DmakeCommand(rule->command_line->string_mb, cmd_options));
2167                 }
2168         }
2169 
2170         xdr_msg = (RWCollectable*) msg;
2171         xdr(&xdrs, xdr_msg);
2172         (void) fflush(mtool_msgs_fp);
2173 
2174 /* tolik, 08/39/2002.
2175    I commented out this code because it causes using unallocated memory.
2176         delete msg;
2177 */
2178 }
2179 
2180 /*
2181  * Append the stdout/err to Avo_MToolJobResultMsg.
2182  */
2183 static void
2184 append_job_result_msg(Avo_MToolJobResultMsg *job_result_msg)
2185 {
2186         FILE            *fp;
2187         char            line[MAXPATHLEN];
2188         char            stdout_file2[MAXPATHLEN];
2189 
2190         if (stdout_file != NULL) {
2191                 fp = fopen(stdout_file, "r");
2192                 if (fp == NULL) {
2193                         /* Hmmm... what should we do here? */
2194                         warning(catgets(catd, 1, 326, "fopen() of stdout_file failed. Output may be lost"));
2195                         return;
2196                 }
2197                 while (fgets(line, MAXPATHLEN, fp) != NULL) {
2198                         if (line[strlen(line) - 1] == '\n') {
2199                                 line[strlen(line) - 1] = '\0';
2200                         }
2201                         job_result_msg->appendOutput(AVO_STRDUP(line));
2202                 }
2203                 (void) fclose(fp);
2204                 us_sleep(STAT_RETRY_SLEEP_TIME);
2205         } else {
2206                 /* Hmmm... stdout_file shouldn't be NULL */
2207                 warning(catgets(catd, 1, 327, "Internal stdout_file variable shouldn't be NULL. Output may be lost"));
2208         }
2209 }
2210 #endif /* TEAMWARE_MAKE_CMN */
2211 
2212 /*
2213  *      vpath_translation(cmd)
2214  *
2215  *      Translates one command line by
2216  *      checking each word. If the word has an alias it is translated.
2217  *
2218  *      Return value:
2219  *                              The translated command
2220  *
2221  *      Parameters:
2222  *              cmd             Command to translate
2223  *
2224  *      Global variables used:
2225  */
2226 Name
2227 vpath_translation(register Name cmd)
2228 {
2229         wchar_t                 buffer[STRING_BUFFER_LENGTH];
2230         String_rec              new_cmd;
2231         wchar_t                 *p;
2232         wchar_t                 *start;
2233 
2234         if (!vpath_defined || (cmd == NULL) || (cmd->hash.length == 0)) {
2235                 return cmd;
2236         }
2237         INIT_STRING_FROM_STACK(new_cmd, buffer);
2238 
2239         Wstring wcb(cmd);
2240         p = wcb.get_string();
2241 
2242         while (*p != (int) nul_char) {
2243                 while (iswspace(*p) && (*p != (int) nul_char)) {
2244                         append_char(*p++, &new_cmd);
2245                 }
2246                 start = p;
2247                 while (!iswspace(*p) && (*p != (int) nul_char)) {
2248                         p++;
2249                 }
2250                 cmd = GETNAME(start, p - start);
2251                 if (cmd->has_vpath_alias_prop) {
2252                         cmd = get_prop(cmd->prop, vpath_alias_prop)->
2253                                                 body.vpath_alias.alias;
2254                         APPEND_NAME(cmd,
2255                                       &new_cmd,
2256                                       (int) cmd->hash.length);
2257                 } else {
2258                         append_string(start, &new_cmd, p - start);
2259                 }
2260         }
2261         cmd = GETNAME(new_cmd.buffer.start, FIND_LENGTH);
2262         if (new_cmd.free_after_use) {
2263                 retmem(new_cmd.buffer.start);
2264         }
2265         return cmd;
2266 }
2267 
2268 /*
2269  *      check_state(temp_file_name)
2270  *
2271  *      Reads and checks the state changed by the previously executed command.
2272  *
2273  *      Parameters:
2274  *              temp_file_name  The auto dependency temp file
2275  *
2276  *      Global variables used:
2277  */
2278 void
2279 check_state(Name temp_file_name)
2280 {
2281         if (!keep_state) {
2282                 return;
2283         }
2284 
2285         /*
2286          * Then read the temp file that now might 
2287          * contain dependency reports from utilities 
2288          */
2289         read_dependency_file(temp_file_name);
2290 
2291         /*
2292          * And reread .make.state if it
2293          * changed (the command ran recursive makes) 
2294          */
2295         check_read_state_file();
2296         if (temp_file_name != NULL) {
2297                 (void) unlink(temp_file_name->string_mb);
2298         }
2299 }
2300 
2301 /*
2302  *      read_dependency_file(filename)
2303  *
2304  *      Read the temp file used for reporting dependencies to make
2305  *
2306  *      Parameters:
2307  *              filename        The name of the file with the state info
2308  *
2309  *      Global variables used:
2310  *              makefile_type   The type of makefile being read
2311  *              read_trace_level Debug flag
2312  *              temp_file_number The always increasing number for unique files
2313  *              trace_reader    Debug flag
2314  */
2315 static void
2316 read_dependency_file(register Name filename)
2317 {
2318         register Makefile_type  save_makefile_type;
2319 
2320         if (filename == NULL) {
2321                 return;
2322         }
2323         filename->stat.time = file_no_time;
2324         if (exists(filename) > file_doesnt_exist) {
2325                 save_makefile_type = makefile_type;
2326                 makefile_type = reading_cpp_file;
2327                 if (read_trace_level > 1) {
2328                         trace_reader = true;
2329                 }
2330                 temp_file_number++;
2331                 (void) read_simple_file(filename,
2332                                         false,
2333                                         false,
2334                                         false,
2335                                         false,
2336                                         false,
2337                                         false);
2338                 trace_reader = false;
2339                 makefile_type = save_makefile_type;
2340         }
2341 }
2342 
2343 /*
2344  *      check_read_state_file()
2345  *
2346  *      Check if .make.state has changed
2347  *      If it has we reread it
2348  *
2349  *      Parameters:
2350  *
2351  *      Global variables used:
2352  *              make_state      Make state file name
2353  *              makefile_type   Type of makefile being read
2354  *              read_trace_level Debug flag
2355  *              trace_reader    Debug flag
2356  */
2357 static void
2358 check_read_state_file(void)
2359 {
2360         timestruc_t             previous = make_state->stat.time;
2361         register Makefile_type  save_makefile_type;
2362         register Property       makefile;
2363 
2364         make_state->stat.time = file_no_time;
2365         if ((exists(make_state) == file_doesnt_exist) ||
2366             (make_state->stat.time == previous)) {
2367                 return;
2368         }
2369         save_makefile_type = makefile_type;
2370         makefile_type = rereading_statefile;
2371         /* Make sure we clear the old cached contents of .make.state */
2372         makefile = maybe_append_prop(make_state, makefile_prop);
2373         if (makefile->body.makefile.contents != NULL) {
2374                 retmem(makefile->body.makefile.contents);
2375                 makefile->body.makefile.contents = NULL;
2376         }
2377         if (read_trace_level > 1) {
2378                 trace_reader = true;
2379         }
2380         temp_file_number++;
2381         (void) read_simple_file(make_state,
2382                                 false,
2383                                 false,
2384                                 false,
2385                                 false,
2386                                 false,
2387                                 true);
2388         trace_reader = false;
2389         makefile_type = save_makefile_type;
2390 }
2391 
2392 /*
2393  *      do_assign(line, target)
2394  *
2395  *      Handles runtime assignments for command lines prefixed with "=".
2396  *
2397  *      Parameters:
2398  *              line            The command that contains an assignment
2399  *              target          The Name of the target, used for error reports
2400  *
2401  *      Global variables used:
2402  *              assign_done     Set to indicate doname needs to reprocess
2403  */
2404 static void
2405 do_assign(register Name line, register Name target)
2406 {
2407         Wstring wcb(line);
2408         register wchar_t        *string = wcb.get_string();
2409         register wchar_t        *equal;
2410         register Name           name;
2411         register Boolean        append = false;
2412 
2413         /*
2414          * If any runtime assignments are done, doname() must reprocess all
2415          * targets in the future since the macro values used to build the
2416          * command lines for the targets might have changed.
2417          */
2418         assign_done = true;
2419         /* Skip white space. */
2420         while (iswspace(*string)) {
2421                 string++;
2422         }
2423         equal = string;
2424         /* Find "+=" or "=". */
2425         while (!iswspace(*equal) &&
2426                (*equal != (int) plus_char) &&
2427                (*equal != (int) equal_char)) {
2428                 equal++;
2429         }
2430         /* Internalize macro name. */
2431         name = GETNAME(string, equal - string);
2432         /* Skip over "+=" "=". */
2433         while (!((*equal == (int) nul_char) ||
2434                  (*equal == (int) equal_char) ||
2435                  (*equal == (int) plus_char))) {
2436                 equal++;
2437         }
2438         switch (*equal) {
2439         case nul_char:
2440                 fatal(catgets(catd, 1, 31, "= expected in rule `%s' for target `%s'"),
2441                       line->string_mb,
2442                       target->string_mb);
2443         case plus_char:
2444                 append = true;
2445                 equal++;
2446                 break;
2447         }
2448         equal++;
2449         /* Skip over whitespace in front of value. */
2450         while (iswspace(*equal)) {
2451                 equal++;
2452         }
2453         /* Enter new macro value. */
2454         enter_equal(name,
2455                     GETNAME(equal, wcb.get_string() + line->hash.length - equal),
2456                     append);
2457 }
2458 
2459 /*
2460  *      build_command_strings(target, line)
2461  *
2462  *      Builds the command string to used when
2463  *      building a target. If the string is different from the previous one
2464  *      is_out_of_date is set.
2465  *
2466  *      Parameters:
2467  *              target          Target to build commands for
2468  *              line            Where to stuff result
2469  *
2470  *      Global variables used:
2471  *              c_at            The Name "@", used to set macro value
2472  *              command_changed Set if command is different from old
2473  *              debug_level     Should we trace activities?
2474  *              do_not_exec_rule Always echo when running -n
2475  *              empty_name      The Name "", used for empty rule
2476  *              funny           Semantics of characters
2477  *              ignore_errors   Used to init field for line
2478  *              is_conditional  Set to false befor evaling macro, checked
2479  *                              after expanding macros
2480  *              keep_state      Indicates that .KEEP_STATE is on
2481  *              make_word_mentioned Set by macro eval, inits field for cmd
2482  *              query           The Name "?", used to set macro value
2483  *              query_mentioned Set by macro eval, inits field for cmd
2484  *              recursion_level Used for tracing
2485  *              silent          Used to init field for line
2486  */
2487 static void
2488 build_command_strings(Name target, register Property line)
2489 {
2490         String_rec              command_line;
2491         register Cmd_line       command_template = line->body.line.command_template;
2492         register Cmd_line       *insert = &line->body.line.command_used;
2493         register Cmd_line       used = *insert;
2494         wchar_t                 buffer[STRING_BUFFER_LENGTH];
2495         wchar_t                 *start;
2496         Name                    new_command_line;
2497         register Boolean        new_command_longer = false;
2498         register Boolean        ignore_all_command_dependency = true;
2499         Property                member;
2500         static Name             less_name;
2501         static Name             percent_name;
2502         static Name             star;
2503         Name                    tmp_name;
2504 
2505         if (less_name == NULL) {
2506                 MBSTOWCS(wcs_buffer, "<");
2507                 less_name = GETNAME(wcs_buffer, FIND_LENGTH);
2508                 MBSTOWCS(wcs_buffer, "%");
2509                 percent_name = GETNAME(wcs_buffer, FIND_LENGTH);
2510                 MBSTOWCS(wcs_buffer, "*");
2511                 star = GETNAME(wcs_buffer, FIND_LENGTH);
2512         }
2513 
2514         /* We have to check if a target depends on conditional macros */
2515         /* Targets that do must be reprocessed by doname() each time around */
2516         /* since the macro values used when building the target might have */
2517         /* changed */
2518         conditional_macro_used = false;
2519         /* If we are building a lib.a(member) target $@ should be bound */
2520         /* to lib.a */
2521         if (target->is_member &&
2522             ((member = get_prop(target->prop, member_prop)) != NULL)) {
2523                 target = member->body.member.library;
2524         }
2525         /* If we are building a "::" help target $@ should be bound to */
2526         /* the real target name */
2527         /* A lib.a(member) target is never :: */
2528         if (target->has_target_prop) {
2529                 target = get_prop(target->prop, target_prop)->
2530                   body.target.target;
2531         }
2532         /* Bind the magic macros that make supplies */
2533         tmp_name = target;
2534         if(tmp_name != NULL) {
2535                 if (tmp_name->has_vpath_alias_prop) {
2536                         tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)->
2537                                         body.vpath_alias.alias;
2538                 }
2539         }
2540         (void) SETVAR(c_at, tmp_name, false);
2541 
2542         tmp_name = line->body.line.star;
2543         if(tmp_name != NULL) {
2544                 if (tmp_name->has_vpath_alias_prop) {
2545                         tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)->
2546                                         body.vpath_alias.alias;
2547                 }
2548         }
2549         (void) SETVAR(star, tmp_name, false);
2550 
2551         tmp_name = line->body.line.less;
2552         if(tmp_name != NULL) {
2553                 if (tmp_name->has_vpath_alias_prop) {
2554                         tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)->
2555                                         body.vpath_alias.alias;
2556                 }
2557         }
2558         (void) SETVAR(less_name, tmp_name, false);
2559 
2560         tmp_name = line->body.line.percent;
2561         if(tmp_name != NULL) {
2562                 if (tmp_name->has_vpath_alias_prop) {
2563                         tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)->
2564                                         body.vpath_alias.alias;
2565                 }
2566         }
2567         (void) SETVAR(percent_name, tmp_name, false);
2568 
2569         /* $? is seldom used and it is expensive to build */
2570         /* so we store the list form and build the string on demand */
2571         Chain query_list = NULL;
2572         Chain *query_list_tail = &query_list;
2573 
2574         for (Chain ch = line->body.line.query; ch != NULL; ch = ch->next) {
2575                 *query_list_tail = ALLOC(Chain);
2576                 (*query_list_tail)->name = ch->name;
2577                 if ((*query_list_tail)->name->has_vpath_alias_prop) {
2578                         (*query_list_tail)->name =
2579                                 get_prop((*query_list_tail)->name->prop,
2580                                         vpath_alias_prop)->body.vpath_alias.alias;
2581                 }
2582                 (*query_list_tail)->next = NULL;
2583                 query_list_tail = &(*query_list_tail)->next;
2584         }
2585         (void) setvar_daemon(query,
2586                              (Name) query_list,
2587                              false,
2588                              chain_daemon,
2589                              false,
2590                              debug_level);
2591 
2592         /* build $^ */
2593         Chain hat_list = NULL;
2594         Chain *hat_list_tail = &hat_list;
2595 
2596         for (Dependency dependency = line->body.line.dependencies; 
2597                 dependency != NULL;
2598                 dependency = dependency->next) {
2599                 /* skip automatic dependencies */
2600                 if (!dependency->automatic) {
2601                         if ((dependency->name != force) &&
2602                                 (dependency->stale == false)) {
2603                                 *hat_list_tail = ALLOC(Chain);
2604                         
2605                                 if (dependency->name->is_member &&
2606                                         (get_prop(dependency->name->prop, member_prop) != NULL)) {
2607                                         (*hat_list_tail)->name = 
2608                                                         get_prop(dependency->name->prop,
2609                                                                 member_prop)->body.member.member;
2610                                 } else {
2611                                         (*hat_list_tail)->name = dependency->name;
2612                                 }
2613 
2614                                 if((*hat_list_tail)->name != NULL) {
2615                                         if ((*hat_list_tail)->name->has_vpath_alias_prop) {
2616                                                 (*hat_list_tail)->name =
2617                                                         get_prop((*hat_list_tail)->name->prop,
2618                                                                 vpath_alias_prop)->body.vpath_alias.alias;
2619                                         }
2620                                 }
2621 
2622                                 (*hat_list_tail)->next = NULL;
2623                                 hat_list_tail = &(*hat_list_tail)->next;
2624                         }
2625                 }
2626         }
2627         (void) setvar_daemon(hat,
2628                              (Name) hat_list,
2629                              false,
2630                              chain_daemon,
2631                              false,
2632                              debug_level);
2633 
2634 /* We have two command sequences we need to handle */
2635 /* The old one that we probably read from .make.state */
2636 /* and the new one we are building that will replace the old one */
2637 /* Even when KEEP_STATE is not on we build a new command sequence and store */
2638 /* it in the line prop. This command sequence is then executed by */
2639 /* run_command(). If KEEP_STATE is on it is also later written to */
2640 /* .make.state. The routine replaces the old command line by line with the */
2641 /* new one trying to reuse Cmd_lines */
2642 
2643         /* If there is no old command_used we have to start creating */
2644         /* Cmd_lines to keep the new cmd in */
2645         if (used == NULL) {
2646                 new_command_longer = true;
2647                 *insert = used = ALLOC(Cmd_line);
2648                 used->next = NULL;
2649                 used->command_line = NULL;
2650                 insert = &used->next;
2651         }
2652         /* Run thru the template for the new command and build the expanded */
2653         /* new command lines */
2654         for (;
2655              command_template != NULL;
2656              command_template = command_template->next, insert = &used->next, used = *insert) {
2657                 /* If there is no old command_used Cmd_line we need to */
2658                 /* create one and say that cmd consistency failed */
2659                 if (used == NULL) {
2660                         new_command_longer = true;
2661                         *insert = used = ALLOC(Cmd_line);
2662                         used->next = NULL;
2663                         used->command_line = empty_name;
2664                 }
2665                 /* Prepare the Cmd_line for the processing */
2666                 /* The command line prefixes "@-=?" are stripped and that */
2667                 /* information is saved in the Cmd_line */
2668                 used->assign = false;
2669                 used->ignore_error = ignore_errors;
2670                 used->silent = silent;
2671                 used->always_exec = false;
2672                 /* Expand the macros in the command line */
2673                 INIT_STRING_FROM_STACK(command_line, buffer);
2674                 make_word_mentioned =
2675                   query_mentioned =
2676                     false;
2677                 expand_value(command_template->command_line, &command_line, true);
2678                 /* If the macro $(MAKE) is mentioned in the command */
2679                 /* "make -n" runs actually execute the command */
2680                 used->make_refd = make_word_mentioned;
2681                 used->ignore_command_dependency = query_mentioned;
2682                 /* Strip the prefixes */
2683                 start = command_line.buffer.start;
2684                 for (;
2685                      iswspace(*start) ||
2686                      (get_char_semantics_value(*start) & (int) command_prefix_sem);
2687                      start++) {
2688                         switch (*start) {
2689                         case question_char:
2690                                 used->ignore_command_dependency = true;
2691                                 break;
2692                         case exclam_char:
2693                                 used->ignore_command_dependency = false;
2694                                 break;
2695                         case equal_char:
2696                                 used->assign = true;
2697                                 break;
2698                         case hyphen_char:
2699                                 used->ignore_error = true;
2700                                 break;
2701                         case at_char:
2702                                 if (!do_not_exec_rule) {
2703                                         used->silent = true;
2704                                 }
2705                                 break;
2706                         case plus_char:
2707                                 if(posix) {
2708                                   used->always_exec  = true;
2709                                 }
2710                                 break;
2711                         }
2712                 }
2713                 /* If all command lines of the template are prefixed with "?"*/
2714                 /* the VIRTUAL_ROOT is not used for cmd consistency checks */
2715                 if (!used->ignore_command_dependency) {
2716                         ignore_all_command_dependency = false;
2717                 }
2718                 /* Internalize the expanded and stripped command line */
2719                 new_command_line = GETNAME(start, FIND_LENGTH);
2720                 if ((used->command_line == NULL) &&
2721                     (line->body.line.sccs_command)) {
2722                         used->command_line = new_command_line;
2723                         new_command_longer = false;
2724                 }
2725                 /* Compare it with the old one for command consistency */
2726                 if (used->command_line != new_command_line) {
2727                         Name vpath_translated = vpath_translation(new_command_line);
2728                         if (keep_state &&
2729                             !used->ignore_command_dependency && (vpath_translated != used->command_line)) {
2730                                 if (debug_level > 0) {
2731                                         if (used->command_line != NULL
2732                                             && *used->command_line->string_mb !=
2733                                             '\0') {
2734                                                 (void) printf(catgets(catd, 1, 32, "%*sBuilding %s because new command \n\t%s\n%*sdifferent from old\n\t%s\n"),
2735                                                               recursion_level,
2736                                                               "",
2737                                                               target->string_mb,
2738                                                               vpath_translated->string_mb,
2739                                                               recursion_level,
2740                                                               "",
2741                                                               used->
2742                                                               command_line->
2743                                                               string_mb);
2744                                         } else {
2745                                                 (void) printf(catgets(catd, 1, 33, "%*sBuilding %s because new command \n\t%s\n%*sdifferent from empty old command\n"),
2746                                                               recursion_level,
2747                                                               "",
2748                                                               target->string_mb,
2749                                                               vpath_translated->string_mb,
2750                                                               recursion_level,
2751                                                               "");
2752                                         }
2753                                 }
2754                                 command_changed = true;
2755                                 line->body.line.is_out_of_date = true;
2756                         }
2757                         used->command_line = new_command_line;
2758                 }
2759                 if (command_line.free_after_use) {
2760                         retmem(command_line.buffer.start);
2761                 }
2762         }
2763         /* Check if the old command is longer than the new for */
2764         /* command consistency */
2765         if (used != NULL) {
2766                 *insert = NULL;
2767                 if (keep_state &&
2768                     !ignore_all_command_dependency) {
2769                         if (debug_level > 0) {
2770                                 (void) printf(catgets(catd, 1, 34, "%*sBuilding %s because new command shorter than old\n"),
2771                                               recursion_level,
2772                                               "",
2773                                               target->string_mb);
2774                         }
2775                         command_changed = true;
2776                         line->body.line.is_out_of_date = true;
2777                 }
2778         }
2779         /* Check if the new command is longer than the old command for */
2780         /* command consistency */
2781         if (new_command_longer &&
2782             !ignore_all_command_dependency &&
2783             keep_state) {
2784                 if (debug_level > 0) {
2785                         (void) printf(catgets(catd, 1, 35, "%*sBuilding %s because new command longer than old\n"),
2786                                       recursion_level,
2787                                       "",
2788                                       target->string_mb);
2789                 }
2790                 command_changed = true;
2791                 line->body.line.is_out_of_date = true;
2792         }
2793         /* Unbind the magic macros */
2794         (void) SETVAR(c_at, (Name) NULL, false);
2795         (void) SETVAR(star, (Name) NULL, false);
2796         (void) SETVAR(less_name, (Name) NULL, false);
2797         (void) SETVAR(percent_name, (Name) NULL, false);
2798         (void) SETVAR(query, (Name) NULL, false);
2799         if (query_list != NULL) {
2800                 delete_query_chain(query_list);
2801         }
2802         (void) SETVAR(hat, (Name) NULL, false);
2803         if (hat_list != NULL) {
2804                 delete_query_chain(hat_list);
2805         }
2806 
2807         if (conditional_macro_used) {
2808                 target->conditional_macro_list = cond_macro_list;
2809                 cond_macro_list = NULL;
2810                 target->depends_on_conditional = true;
2811         }
2812 }
2813 
2814 /*
2815  *      touch_command(line, target, result)
2816  *
2817  *      If this is an "make -t" run we do this.
2818  *      We touch all targets in the target group ("foo + fie:") if any.
2819  *
2820  *      Return value:
2821  *                              Indicates if the command failed or not
2822  *
2823  *      Parameters:
2824  *              line            The command line to update
2825  *              target          The target we are touching
2826  *              result          Initial value for the result we return
2827  *
2828  *      Global variables used:
2829  *              do_not_exec_rule Indicates that -n is on
2830  *              silent          Do not echo commands
2831  */
2832 static Doname
2833 touch_command(register Property line, register Name target, Doname result)
2834 {
2835         Name                    name;
2836         register Chain          target_group;
2837         String_rec              touch_string;
2838         wchar_t                 buffer[MAXPATHLEN];
2839         Name                    touch_cmd;
2840         Cmd_line                rule;
2841 
2842 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
2843         Avo_MToolJobResultMsg   *job_result_msg;
2844         RWCollectable           *xdr_msg;
2845         int                     child_pid = 0;
2846         wchar_t                 string[MAXPATHLEN];
2847         char                    mbstring[MAXPATHLEN];
2848         int                     filed;
2849 #endif
2850 
2851         SEND_MTOOL_MSG(
2852                 if (!sent_rsrc_info_msg) {
2853                         if (userName[0] == '\0') {
2854                                 avo_get_user(userName, NULL);
2855                         }
2856                         if (hostName[0] == '\0') {
2857                                 strcpy(hostName, avo_hostname());
2858                         }
2859                         send_rsrc_info_msg(1, hostName, userName);
2860                         sent_rsrc_info_msg = 1;
2861                 }
2862                 send_job_start_msg(line);
2863                 job_result_msg = new Avo_MToolJobResultMsg();
2864         );
2865         for (name = target, target_group = NULL; name != NULL;) {
2866                 if (!name->is_member) {
2867                         /*
2868                          * Build a touch command that can be passed
2869                          * to dosys(). If KEEP_STATE is on, "make -t"
2870                          * will save the proper command, not the
2871                          * "touch" in .make.state.
2872                          */
2873                         INIT_STRING_FROM_STACK(touch_string, buffer);
2874                         MBSTOWCS(wcs_buffer, NOCATGETS("touch "));
2875                         append_string(wcs_buffer, &touch_string, FIND_LENGTH);
2876                         touch_cmd = name;
2877                         if (name->has_vpath_alias_prop) {
2878                                 touch_cmd = get_prop(name->prop,
2879                                                  vpath_alias_prop)->
2880                                                    body.vpath_alias.alias;
2881                         }
2882                         APPEND_NAME(touch_cmd,
2883                                       &touch_string,
2884                                       FIND_LENGTH);
2885                         touch_cmd = GETNAME(touch_string.buffer.start,
2886                                             FIND_LENGTH);
2887                         if (touch_string.free_after_use) {
2888                                 retmem(touch_string.buffer.start);
2889                         }
2890                         if (!silent ||
2891                             do_not_exec_rule &&
2892                             (target_group == NULL)) {
2893                                 (void) printf("%s\n", touch_cmd->string_mb);
2894                                 SEND_MTOOL_MSG(
2895                                         job_result_msg->appendOutput(AVO_STRDUP(touch_cmd->string_mb));
2896                                 );
2897                         }
2898                         /* Run the touch command, or simulate it */
2899                         if (!do_not_exec_rule) {
2900 
2901                                 SEND_MTOOL_MSG(
2902                                         (void) sprintf(mbstring,
2903                                                         NOCATGETS("%s/make.stdout.%d.%d.XXXXXX"),
2904                                                         tmpdir,
2905                                                         getpid(),
2906                                                         file_number++);
2907                                 
2908                                         int tmp_fd = mkstemp(mbstring);
2909                                         if(tmp_fd) {
2910                                                 (void) close(tmp_fd);
2911                                         }
2912 
2913                                         stdout_file = strdup(mbstring);
2914                                         stderr_file = NULL;
2915                                         child_pid = pollResults(stdout_file,
2916                                                                 (char *)NULL,
2917                                                                 (char *)NULL);
2918                                 );
2919 
2920                                 result = dosys(touch_cmd,
2921                                                false,
2922                                                false,
2923                                                false,
2924                                                false,
2925                                                name,
2926                                                send_mtool_msgs);
2927 
2928                                 SEND_MTOOL_MSG(
2929                                         append_job_result_msg(job_result_msg);
2930                                         if (child_pid > 0) {
2931                                                 kill(child_pid, SIGUSR1);
2932                                                 while (!((waitpid(child_pid, 0, 0) == -1)
2933                                                         && (errno == ECHILD)));
2934                                         }
2935                                         child_pid = 0;
2936                                         (void) unlink(stdout_file);
2937                                         retmem_mb(stdout_file);
2938                                         stdout_file = NULL;
2939                                 );
2940 
2941                         } else {
2942                                 result = build_ok;
2943                         }
2944                 } else {
2945                         result = build_ok;
2946                 }
2947                 if (target_group == NULL) {
2948                         target_group = line->body.line.target_group;
2949                 } else {
2950                         target_group = target_group->next;
2951                 }
2952                 if (target_group != NULL) {
2953                         name = target_group->name;
2954                 } else {
2955                         name = NULL;
2956                 }
2957         }
2958         SEND_MTOOL_MSG(
2959                 job_result_msg->setResult(job_msg_id, (result == build_ok) ? 0 : 1, DONE);
2960                 xdr_msg = (RWCollectable*) job_result_msg;
2961                 xdr(&xdrs, xdr_msg);
2962                 (void) fflush(mtool_msgs_fp);
2963                 delete job_result_msg;
2964         );
2965         return result;
2966 }
2967 
2968 /*
2969  *      update_target(line, result)
2970  *
2971  *      updates the status of a target after executing its commands.
2972  *
2973  *      Parameters:
2974  *              line            The command line block to update
2975  *              result          Indicates that build is OK so can update
2976  *
2977  *      Global variables used:
2978  *              do_not_exec_rule Indicates that -n is on
2979  *              touch           Fake the new timestamp if we are just touching
2980  */
2981 void
2982 update_target(Property line, Doname result)
2983 {
2984         Name                    target;
2985         Chain                   target_group;
2986         Property                line2;
2987         timestruc_t             old_stat_time;
2988         Property                member;
2989 
2990         /*
2991          * [tolik] Additional fix for bug 1063790. It was fixed
2992          * for serial make long ago, but DMake dumps core when
2993          * target is a symlink and sccs file is newer then target. 
2994          * In this case, finish_children() calls update_target()
2995          * with line==NULL.
2996          */
2997         if(line == NULL) {
2998                 /* XXX. Should we do anything here? */
2999                 return;
3000         }       
3001 
3002         target = line->body.line.target;
3003 
3004         if ((result == build_ok) && (line->body.line.command_used != NULL)) {
3005                 if (do_not_exec_rule ||
3006                     touch ||
3007                     (target->is_member &&
3008                      (line->body.line.command_template != NULL) &&
3009                      (line->body.line.command_template->command_line->string_mb[0] == 0) &&
3010                      (line->body.line.command_template->next == NULL))) {
3011                         /* If we are simulating execution we need to fake a */
3012                         /* new timestamp for the target we didnt build */
3013                         target->stat.time = file_max_time;
3014                 } else {
3015                         /*
3016                          * If we really built the target we read the new
3017                          * timestamp.
3018                          * Fix for bug #1110906: if .c file is newer than
3019                          * the corresponding .o file which is in an archive
3020                          * file, make will compile the .c file but it won't
3021                          * update the object in the .a file.
3022                          */
3023                         old_stat_time = target->stat.time;
3024                         target->stat.time = file_no_time;
3025                         (void) exists(target);
3026                         if ((target->is_member) &&
3027                             (target->stat.time == old_stat_time)) {
3028                                 member = get_prop(target->prop, member_prop);
3029                                 if (member != NULL) {
3030                                         target->stat.time = member->body.member.library->stat.time;
3031                                         target->stat.time.tv_sec++;
3032                                 }
3033                         }
3034                 }
3035                 /* If the target is part of a group we need to propagate the */
3036                 /* result of the run to all members */
3037                 for (target_group = line->body.line.target_group;
3038                      target_group != NULL;
3039                      target_group = target_group->next) {
3040                         target_group->name->stat.time = target->stat.time;
3041                         line2 = maybe_append_prop(target_group->name,
3042                                                   line_prop);
3043                         line2->body.line.command_used =
3044                           line->body.line.command_used;
3045                         line2->body.line.target = target_group->name;
3046                 }
3047         }
3048         target->has_built = true;
3049 }
3050 
3051 /*
3052  *      sccs_get(target, command)
3053  *
3054  *      Figures out if it possible to sccs get a file
3055  *      and builds the command to do it if it is.
3056  *
3057  *      Return value:
3058  *                              Indicates if sccs get failed or not
3059  *
3060  *      Parameters:
3061  *              target          Target to get
3062  *              command         Where to deposit command to use
3063  *
3064  *      Global variables used:
3065  *              debug_level     Should we trace activities?
3066  *              recursion_level Used for tracing
3067  *              sccs_get_rule   The rule to used for sccs getting
3068  */
3069 static Doname
3070 sccs_get(register Name target, register Property *command)
3071 {
3072         register int            result;
3073         char                    link[MAXPATHLEN];
3074         String_rec              string;
3075         wchar_t                 name[MAXPATHLEN];
3076         register wchar_t        *p;
3077         timestruc_t             sccs_time;
3078         register Property       line;
3079         int                     sym_link_depth = 0;
3080 
3081         /* For sccs, we need to chase symlinks. */
3082         while (target->stat.is_sym_link) {
3083                 if (sym_link_depth++ > 90) {
3084                         fatal(catgets(catd, 1, 95, "Can't read symbolic link `%s': Number of symbolic links encountered during path name traversal exceeds 90."),
3085                               target->string_mb);
3086                 }
3087                 /* Read the value of the link. */
3088                 result = readlink_vroot(target->string_mb,
3089                                         link,
3090                                         sizeof(link),
3091                                         NULL,
3092                                         VROOT_DEFAULT);
3093                 if (result == -1) {
3094                         fatal(catgets(catd, 1, 36, "Can't read symbolic link `%s': %s"),
3095                               target->string_mb, errmsg(errno));
3096                 }
3097                 link[result] = 0;
3098                 /* Use the value to build the proper filename. */
3099                 INIT_STRING_FROM_STACK(string, name);
3100 
3101                 Wstring wcb(target);
3102                 if ((link[0] != slash_char) &&
3103                     ((p = (wchar_t *) wsrchr(wcb.get_string(), slash_char)) != NULL)) {
3104                         append_string(wcb.get_string(), &string, p - wcb.get_string() + 1);
3105                 }
3106                 append_string(link, &string, result);
3107                 /* Replace the old name with the translated name. */
3108                 target = normalize_name(string.buffer.start, string.text.p - string.buffer.start);
3109                 (void) exists(target);
3110                 if (string.free_after_use) {
3111                         retmem(string.buffer.start);
3112                 }
3113         }
3114 
3115         /*
3116          * read_dir() also reads the ?/SCCS dir and saves information
3117          * about which files have SCSC/s. files.
3118          */
3119         if (target->stat.has_sccs == DONT_KNOW_SCCS) {
3120                 read_directory_of_file(target);
3121         }
3122         switch (target->stat.has_sccs) {
3123         case DONT_KNOW_SCCS:
3124                 /* We dont know by now there is no SCCS/s.* */
3125                 target->stat.has_sccs = NO_SCCS;
3126         case NO_SCCS:
3127                 /*
3128                  * If there is no SCCS/s.* but the plain file exists,
3129                  * we say things are OK.
3130                  */
3131                 if (target->stat.time > file_doesnt_exist) {
3132                         return build_ok;
3133                 }
3134                 /* If we cant find the plain file, we give up. */
3135                 return build_dont_know;
3136         case HAS_SCCS:
3137                 /*
3138                  * Pay dirt. We now need to figure out if the plain file
3139                  * is out of date relative to the SCCS/s.* file.
3140                  */
3141                 sccs_time = exists(get_prop(target->prop,
3142                                             sccs_prop)->body.sccs.file);
3143                 break;
3144         }
3145 
3146         if ((!target->has_complained &&
3147             (sccs_time != file_doesnt_exist) &&
3148             (sccs_get_rule != NULL))) {
3149                 /* only checking */
3150                 if (command == NULL) {
3151                         return build_ok;
3152                 }
3153                 /*
3154                  * We provide a command line for the target. The line is a
3155                  * "sccs get" command from default.mk.
3156                  */
3157                 line = maybe_append_prop(target, line_prop);
3158                 *command = line;
3159                 if (sccs_time > target->stat.time) {
3160                         /*
3161                          * And only if the plain file is out of date do we
3162                          * request execution of the command.
3163                          */
3164                         line->body.line.is_out_of_date = true;
3165                         if (debug_level > 0) {
3166                                 (void) printf(catgets(catd, 1, 37, "%*sSccs getting %s because s. file is younger than source file\n"),
3167                                               recursion_level,
3168                                               "",
3169                                               target->string_mb);
3170                         }
3171                 }
3172                 line->body.line.sccs_command = true;
3173                 line->body.line.command_template = sccs_get_rule;
3174                 if(!svr4 && (!allrules_read || posix)) {
3175                    if((target->prop) &&
3176                       (target->prop->body.sccs.file) &&
3177                       (target->prop->body.sccs.file->string_mb)) {
3178                       if((strlen(target->prop->body.sccs.file->string_mb) ==
3179                         strlen(target->string_mb) + 2) && 
3180                         (target->prop->body.sccs.file->string_mb[0] == 's') &&
3181                         (target->prop->body.sccs.file->string_mb[1] == '.')) {
3182 
3183                          line->body.line.command_template = get_posix_rule;
3184                       }
3185                    }
3186                 }
3187                 line->body.line.target = target;
3188                 /*
3189                  * Also make sure the rule is build with $* and $<
3190                  * bound properly.
3191                  */
3192                 line->body.line.star = NULL;
3193                 line->body.line.less = NULL;
3194                 line->body.line.percent = NULL;
3195                 return build_ok;
3196         }
3197         return build_dont_know;
3198 }
3199 
3200 /*
3201  *      read_directory_of_file(file)
3202  *
3203  *      Reads the directory the specified file lives in.
3204  *
3205  *      Parameters:
3206  *              file            The file we need to read dir for
3207  *
3208  *      Global variables used:
3209  *              dot             The Name ".", used as the default dir
3210  */
3211 void
3212 read_directory_of_file(register Name file)
3213 {
3214 
3215         Wstring file_string(file);
3216         wchar_t * wcb = file_string.get_string();
3217         wchar_t usr_include_buf[MAXPATHLEN];
3218         wchar_t usr_include_sys_buf[MAXPATHLEN];
3219 
3220         register Name           directory = dot;
3221         register wchar_t        *p = (wchar_t *) wsrchr(wcb,
3222                                                         (int) slash_char);
3223         register int            length = p - wcb;
3224         static Name             usr_include;
3225         static Name             usr_include_sys;
3226 
3227         if (usr_include == NULL) {
3228                 MBSTOWCS(usr_include_buf, NOCATGETS("/usr/include"));
3229                 usr_include = GETNAME(usr_include_buf, FIND_LENGTH);
3230                 MBSTOWCS(usr_include_sys_buf, NOCATGETS("/usr/include/sys"));
3231                 usr_include_sys = GETNAME(usr_include_sys_buf, FIND_LENGTH);
3232         }
3233 
3234         /*
3235          * If the filename contains a "/" we have to extract the path
3236          * Else the path defaults to ".".
3237          */
3238         if (p != NULL) {
3239                 /*
3240                  * Check some popular directories first to possibly
3241                  * save time. Compare string length first to gain speed.
3242                  */
3243                 if ((usr_include->hash.length == length) &&
3244                     IS_WEQUALN(usr_include_buf,
3245                                wcb,
3246                                length)) {
3247                         directory = usr_include;
3248                 } else if ((usr_include_sys->hash.length == length) &&
3249                            IS_WEQUALN(usr_include_sys_buf,
3250                                       wcb,
3251                                       length)) {
3252                         directory = usr_include_sys;
3253                 } else {
3254                         directory = GETNAME(wcb, length);
3255                 }
3256         }
3257         (void) read_dir(directory,
3258                         (wchar_t *) NULL,
3259                         (Property) NULL,
3260                         (wchar_t *) NULL);
3261 }
3262 
3263 /*
3264  *      add_pattern_conditionals(target)
3265  *
3266  *      Scan the list of conditionals defined for pattern targets and add any
3267  *      that match this target to its list of conditionals.
3268  *
3269  *      Parameters:
3270  *              target          The target we should add conditionals for
3271  *
3272  *      Global variables used:
3273  *              conditionals    The list of pattern conditionals
3274  */
3275 static void
3276 add_pattern_conditionals(register Name target)
3277 {
3278         register Property       conditional;
3279         Property                new_prop;
3280         Property                *previous;
3281         Name_rec                dummy;
3282         wchar_t                 *pattern;
3283         wchar_t                 *percent;
3284         int                     length;
3285 
3286         Wstring wcb(target);
3287         Wstring wcb1;
3288 
3289         for (conditional = get_prop(conditionals->prop, conditional_prop);
3290              conditional != NULL;
3291              conditional = get_prop(conditional->next, conditional_prop)) {
3292                 wcb1.init(conditional->body.conditional.target);
3293                 pattern = wcb1.get_string();
3294                 if (pattern[1] != 0) {
3295                         percent = (wchar_t *) wschr(pattern, (int) percent_char);
3296                         if (!wcb.equaln(pattern, percent-pattern) ||
3297                             !IS_WEQUAL(wcb.get_string(wcb.length()-wslen(percent+1)), percent+1)) {
3298                                 continue;
3299                         }
3300                 }
3301                 for (previous = &target->prop;
3302                      *previous != NULL;
3303                      previous = &(*previous)->next) {
3304                         if (((*previous)->type == conditional_prop) &&
3305                             ((*previous)->body.conditional.sequence >
3306                              conditional->body.conditional.sequence)) {
3307                                 break;
3308                         }
3309                 }
3310                 if (*previous == NULL) {
3311                         new_prop = append_prop(target, conditional_prop);
3312                 } else {
3313                         dummy.prop = NULL;
3314                         new_prop = append_prop(&dummy, conditional_prop);
3315                         new_prop->next = *previous;
3316                         *previous = new_prop;
3317                 }
3318                 target->conditional_cnt++;
3319                 new_prop->body.conditional = conditional->body.conditional;
3320         }
3321 }
3322 
3323 /*
3324  *      set_locals(target, old_locals)
3325  *
3326  *      Sets any conditional macros for the target.
3327  *      Each target carries a possibly empty set of conditional properties.
3328  *
3329  *      Parameters:
3330  *              target          The target to set conditional macros for
3331  *              old_locals      Space to store old values in
3332  *
3333  *      Global variables used:
3334  *              debug_level     Should we trace activity?
3335  *              is_conditional  We need to preserve this value
3336  *              recursion_level Used for tracing
3337  */
3338 void
3339 set_locals(register Name target, register Property old_locals)
3340 {
3341         register Property       conditional;
3342         register int            i;
3343         register Boolean        saved_conditional_macro_used;
3344         Chain                   cond_name;
3345         Chain                   cond_chain;
3346 
3347 #ifdef DISTRIBUTED
3348         if (target->dont_activate_cond_values) {
3349                 return;
3350         }
3351 #endif
3352 
3353         saved_conditional_macro_used = conditional_macro_used;
3354 
3355         /* Scan the list of conditional properties and apply each one */
3356         for (conditional = get_prop(target->prop, conditional_prop), i = 0;
3357              conditional != NULL;
3358              conditional = get_prop(conditional->next, conditional_prop),
3359              i++) {
3360                 /* Save the old value */
3361                 old_locals[i].body.macro =
3362                   maybe_append_prop(conditional->body.conditional.name,
3363                                     macro_prop)->body.macro;
3364                 if (debug_level > 1) {
3365                         (void) printf(catgets(catd, 1, 38, "%*sActivating conditional value: "),
3366                                       recursion_level,
3367                                       "");
3368                 }
3369                 /* Set the conditional value. Macros are expanded when the */
3370                 /* macro is refd as usual */
3371                 if ((conditional->body.conditional.name != virtual_root) ||
3372                     (conditional->body.conditional.value != virtual_root)) {
3373                         (void) SETVAR(conditional->body.conditional.name,
3374                                       conditional->body.conditional.value,
3375                                       (Boolean) conditional->body.conditional.append);
3376                 }
3377                 cond_name = ALLOC(Chain);
3378                 cond_name->name = conditional->body.conditional.name;
3379         }
3380         /* Put this target on the front of the chain of conditional targets */
3381         cond_chain = ALLOC(Chain);
3382         cond_chain->name = target;
3383         cond_chain->next = conditional_targets;
3384         conditional_targets = cond_chain;
3385         conditional_macro_used = saved_conditional_macro_used;
3386 }
3387 
3388 /*
3389  *      reset_locals(target, old_locals, conditional, index)
3390  *
3391  *      Removes any conditional macros for the target.
3392  *
3393  *      Parameters:
3394  *              target          The target we are retoring values for
3395  *              old_locals      The values to restore
3396  *              conditional     The first conditional block for the target
3397  *              index           into the old_locals vector
3398  *      Global variables used:
3399  *              debug_level     Should we trace activities?
3400  *              recursion_level Used for tracing
3401  */
3402 void
3403 reset_locals(register Name target, register Property old_locals, register Property conditional, register int index)
3404 {
3405         register Property       this_conditional;
3406         Chain                   cond_chain;
3407 
3408 #ifdef DISTRIBUTED
3409         if (target->dont_activate_cond_values) {
3410                 return;
3411         }
3412 #endif
3413 
3414         /* Scan the list of conditional properties and restore the old value */
3415         /* to each one Reverse the order relative to when we assigned macros */
3416         this_conditional = get_prop(conditional->next, conditional_prop);
3417         if (this_conditional != NULL) {
3418                 reset_locals(target, old_locals, this_conditional, index+1);
3419         } else {
3420                 /* Remove conditional target from chain */
3421                 if (conditional_targets == NULL ||
3422                     conditional_targets->name != target) {
3423                         warning(catgets(catd, 1, 39, "Internal error: reset target not at head of condtional_targets chain"));
3424                 } else {
3425                         cond_chain = conditional_targets->next;
3426                         retmem_mb((caddr_t) conditional_targets);
3427                         conditional_targets = cond_chain;
3428                 }
3429         }
3430         get_prop(conditional->body.conditional.name->prop,
3431                  macro_prop)->body.macro = old_locals[index].body.macro;
3432         if (conditional->body.conditional.name == virtual_root) {
3433                 (void) SETVAR(virtual_root, getvar(virtual_root), false);
3434         }
3435         if (debug_level > 1) {
3436                 if (old_locals[index].body.macro.value != NULL) {
3437                         (void) printf(catgets(catd, 1, 40, "%*sdeactivating conditional value: %s= %s\n"),
3438                                       recursion_level,
3439                                       "",
3440                                       conditional->body.conditional.name->
3441                                       string_mb,
3442                                       old_locals[index].body.macro.value->
3443                                       string_mb);
3444                 } else {
3445                         (void) printf(catgets(catd, 1, 41, "%*sdeactivating conditional value: %s =\n"),
3446                                       recursion_level,
3447                                       "",
3448                                       conditional->body.conditional.name->
3449                                       string_mb);
3450                 }
3451         }
3452 }
3453 
3454 /*
3455  *      check_auto_dependencies(target, auto_count, automatics)
3456  *
3457  *      Returns true if the target now has a dependency
3458  *      it didn't previously have (saved on automatics).
3459  *
3460  *      Return value:
3461  *                              true if new dependency found
3462  *
3463  *      Parameters:
3464  *              target          Target we check
3465  *              auto_count      Number of old automatic vars
3466  *              automatics      Saved old automatics
3467  *
3468  *      Global variables used:
3469  *              keep_state      Indicates that .KEEP_STATE is on
3470  */
3471 Boolean
3472 check_auto_dependencies(Name target, int auto_count, Name *automatics)
3473 {
3474         Name            *p;
3475         int             n;
3476         Property        line;
3477         Dependency      dependency;
3478 
3479         if (keep_state) {
3480                 if ((line = get_prop(target->prop, line_prop)) == NULL) {
3481                         return false;
3482                 }
3483                 /* Go thru new list of automatic depes */
3484                 for (dependency = line->body.line.dependencies;
3485                      dependency != NULL;
3486                      dependency = dependency->next) {
3487                         /* And make sure that each one existed before we */
3488                         /* built the target */
3489                         if (dependency->automatic && !dependency->stale) {
3490                                 for (n = auto_count, p = automatics;
3491                                      n > 0;
3492                                      n--) {
3493                                         if (*p++ == dependency->name) {
3494                                                 /* If we can find it on the */
3495                                                 /* saved list of autos we */
3496                                                 /* are OK  */
3497                                                 goto not_new;
3498                                         }
3499                                 }
3500                                 /* But if we scan over the old list */
3501                                 /* of auto. without finding it it is */
3502                                 /* new and we must check it */
3503                                 return true;
3504                         }
3505                 not_new:;
3506                 }
3507                 return false;
3508         } else {
3509                 return false;
3510         }
3511 }
3512 
3513 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
3514 void
3515 create_xdrs_ptr(void)
3516 {
3517         static int      xdrs_init = 0;
3518 
3519         if (!xdrs_init) {
3520                 xdrs_init = 1;
3521                 mtool_msgs_fp = fdopen(mtool_msgs_fd, "a");
3522                 xdrstdio_create(&xdrs,
3523                                 mtool_msgs_fp,
3524                                 XDR_ENCODE);
3525         }
3526 }
3527 
3528 XDR *
3529 get_xdrs_ptr(void)
3530 {
3531         return &xdrs;
3532 }
3533 
3534 FILE *
3535 get_mtool_msgs_fp(void)
3536 {
3537         return mtool_msgs_fp;
3538 }
3539 
3540 int
3541 get_job_msg_id(void)
3542 {
3543         return job_msg_id;
3544 }
3545 
3546 // Continuously poll and show the results of remotely executing a job,
3547 // i.e., output the stdout and stderr files.
3548 
3549 static int
3550 pollResults(char *outFn, char *errFn, char *hostNm)
3551 {
3552         int             child;
3553 
3554         child = fork();
3555         switch (child) {
3556         case -1:
3557                 break;
3558         case 0:
3559                 enable_interrupt((void (*) (int))SIG_DFL);
3560                 (void) sigset(SIGUSR1, Avo_PollResultsAction_Sigusr1Handler);
3561                 pollResultsAction(outFn, errFn);
3562 
3563                 exit(0);
3564                 break;
3565         default:
3566                 break;
3567         }
3568         return child;
3569 }
3570 
3571 // This is the PollResultsAction SIGUSR1 handler.
3572 
3573 static bool_t pollResultsActionTimeToFinish = FALSE;
3574 
3575 extern "C" void
3576 Avo_PollResultsAction_Sigusr1Handler(int foo)
3577 {
3578         pollResultsActionTimeToFinish = TRUE;
3579 }
3580 
3581 static void
3582 pollResultsAction(char *outFn, char *errFn)
3583 {
3584         int                     fd;
3585         time_t                  file_time = 0;
3586         long                    file_time_nsec = 0;
3587         struct stat             statbuf;
3588         int                     stat_rc;
3589 
3590         // Keep stat'ing until file exists.
3591         while (((stat_rc = stat(outFn, &statbuf)) != 0) &&
3592                (errno == ENOENT) && 
3593                !pollResultsActionTimeToFinish) {
3594                 us_sleep(STAT_RETRY_SLEEP_TIME);
3595         }
3596         // The previous stat() could be failed due to EINTR
3597         // So one more try is needed
3598         if (stat_rc != 0 && stat(outFn, &statbuf) != 0) {
3599                 // stat() failed
3600                 warning(NOCATGETS("Internal error: stat(\"%s\", ...) failed: %s\n"),
3601                         outFn, strerror(errno));
3602                 exit(1);
3603         }
3604 
3605         if ((fd = open(outFn, O_RDONLY)) < 0
3606                 && (errno != EINTR || (fd = open(outFn, O_RDONLY)) < 0)) {
3607                 // open() failed
3608                 warning(NOCATGETS("Internal error: open(\"%s\", O_RDONLY) failed: %s\n"),
3609                         outFn, strerror(errno));
3610                 exit(1);
3611         }
3612 
3613         while (!pollResultsActionTimeToFinish && stat(outFn, &statbuf) == 0) {
3614                 if ((statbuf.st_mtim.tv_sec > file_time) ||
3615                     ((statbuf.st_mtim.tv_sec == file_time) &&
3616                     (statbuf.st_mtim.tv_nsec > file_time_nsec))
3617                    ) {
3618                         file_time = statbuf.st_mtim.tv_sec;
3619                         file_time_nsec = statbuf.st_mtim.tv_nsec;
3620                         rxmGetNextResultsBlock(fd);
3621                 }
3622                 us_sleep(STAT_RETRY_SLEEP_TIME);
3623         }
3624         // Check for the rest of output
3625         rxmGetNextResultsBlock(fd);
3626 
3627         (void) close(fd);
3628 }
3629 
3630 static void
3631 rxmGetNextResultsBlock(int fd)
3632 {
3633         size_t                  to_read = 8 * 1024;
3634         ssize_t                 bytes_read;
3635         ssize_t                 bytes_written;
3636         char                    results_buf[8 * 1024];
3637         sigset_t                newset;
3638         sigset_t                oldset;
3639 
3640         // Read some more from the output/results file.
3641         // Hopefully the kernel managed to prefetch the stuff.
3642         bytes_read = read(fd, results_buf, to_read);
3643         while (bytes_read > 0) {
3644                 AVO_BLOCK_INTERUPTS;
3645                 bytes_written = write(1, results_buf, bytes_read);
3646                 AVO_UNBLOCK_INTERUPTS;
3647                 if (bytes_written != bytes_read) {
3648                         // write() failed
3649                         warning(NOCATGETS("Internal error: write(1, ...) failed: %s\n"),
3650                                 strerror(errno));
3651                         exit(1);
3652                 }
3653                 bytes_read = read(fd, results_buf, to_read);
3654         }
3655 }
3656 
3657 // Generic, interruptable microsecond resolution sleep member function.
3658 
3659 static int
3660 us_sleep(unsigned int nusecs)
3661 {
3662         struct pollfd dummy;
3663         int timeout;
3664 
3665         if ((timeout = nusecs/1000) <= 0) {
3666                 timeout = 1;
3667         }
3668         return poll(&dummy, 0, timeout);
3669 }
3670 #endif /* TEAMWARE_MAKE_CMN */
3671 
3672 // Recursively delete each of the Chain struct on the chain.
3673 
3674 static void
3675 delete_query_chain(Chain ch)
3676 {
3677         if (ch == NULL) {
3678                 return;
3679         } else {
3680                 delete_query_chain(ch->next);
3681                 retmem_mb((char *) ch);
3682         }
3683 }
3684 
3685 Doname
3686 target_can_be_built(register Name target) {
3687         Doname          result = build_dont_know;
3688         Name            true_target = target;
3689         Property        line;
3690 
3691         if (target == wait_name) {
3692                 return(build_ok);
3693         }
3694         /*
3695          * If the target is a constructed one for a "::" target,
3696          * we need to consider that.
3697          */
3698         if (target->has_target_prop) {
3699                 true_target = get_prop(target->prop,
3700                                        target_prop)->body.target.target;
3701         }
3702 
3703         (void) exists(true_target);
3704 
3705         if (true_target->state == build_running) {
3706                 return(build_running);
3707         }
3708         if (true_target->stat.time != file_doesnt_exist) {
3709                 result = build_ok;
3710         }
3711 
3712         /* get line property for the target */
3713         line = get_prop(true_target->prop, line_prop);
3714 
3715         /* first check for explicit rule */
3716         if (line != NULL && line->body.line.command_template != NULL) {
3717                 result = build_ok;
3718         }
3719         /* try to find pattern rule */
3720         if (result == build_dont_know) {
3721                 result = find_percent_rule(target, NULL, false);
3722         }
3723         
3724         /* try to find double suffix rule */
3725         if (result == build_dont_know) {
3726                 if (target->is_member) {
3727                         Property member = get_prop(target->prop, member_prop);
3728                         if (member != NULL && member->body.member.member != NULL) {
3729                                 result = find_ar_suffix_rule(target, member->body.member.member, NULL, false);
3730                         } else {
3731                                 result = find_double_suffix_rule(target, NULL, false);
3732                         }
3733                 } else {
3734                         result = find_double_suffix_rule(target, NULL, false);
3735                 }
3736         }
3737         
3738         /* try to find suffix rule */
3739         if ((result == build_dont_know) && second_pass) {
3740                 result = find_suffix_rule(target, target, empty_name, NULL, false);
3741         }
3742         
3743         /* check for sccs */
3744         if (result == build_dont_know) {
3745                 result = sccs_get(target, NULL);
3746         }
3747         
3748         /* try to find dyn target */
3749         if (result == build_dont_know) {
3750                 Name dtarg = find_dyntarget(target);
3751                 if (dtarg != NULL) {
3752                         result = target_can_be_built(dtarg);
3753                 }
3754         }
3755         
3756         /* check whether target was mentioned in makefile */
3757         if (result == build_dont_know) {
3758                 if (target->colons != no_colon) {
3759                         result = build_ok;
3760                 }
3761         }
3762 
3763         /* result */
3764         return result;
3765 }