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