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