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