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