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 2005 Sun Microsystems, Inc. All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  *      misc.cc
  28  *
  29  *      This file contains various unclassified routines. Some main groups:
  30  *              getname
  31  *              Memory allocation
  32  *              String handling
  33  *              Property handling
  34  *              Error message handling
  35  *              Make internal state dumping
  36  *              main routine support
  37  */
  38 
  39 /*
  40  * Included files
  41  */
  42 #include <errno.h>
  43 #include <mk/defs.h>
  44 #include <mksh/macro.h>           /* SETVAR() */
  45 #include <mksh/misc.h>            /* enable_interrupt() */
  46 #include <stdarg.h>               /* va_list, va_start(), va_end() */
  47 #include <vroot/report.h> /* SUNPRO_DEPENDENCIES */
  48 
  49 
  50 #define MAXJOBS_ADJUST_RFE4694000
  51 
  52 #ifdef MAXJOBS_ADJUST_RFE4694000
  53 extern void job_adjust_fini();
  54 #endif /* MAXJOBS_ADJUST_RFE4694000 */
  55 
  56 
  57 /*
  58  * Defined macros
  59  */
  60 
  61 /*
  62  * typedefs & structs
  63  */
  64 
  65 /*
  66  * Static variables
  67  */
  68 
  69 /*
  70  * File table of contents
  71  */
  72 static  void            print_rule(register Name target);
  73 static  void            print_target_n_deps(register Name target);
  74 
  75 /*****************************************
  76  *
  77  *      getname
  78  */
  79 
  80 /*****************************************
  81  *
  82  *      Memory allocation
  83  */
  84 
  85 /*
  86  *      free_chain()
  87  *
  88  *      frees a chain of Name_vector's
  89  *
  90  *      Parameters:
  91  *              ptr             Pointer to the first element in the chain
  92  *                              to be freed.
  93  *
  94  *      Global variables used:
  95  */
  96 void 
  97 free_chain(Name_vector ptr)
  98 {
  99         if (ptr != NULL) {
 100                 if (ptr->next != NULL) {
 101                         free_chain(ptr->next);
 102                 }
 103                 free((char *) ptr);
 104         }
 105 }
 106 
 107 /*****************************************
 108  *
 109  *      String manipulation
 110  */
 111 
 112 /*****************************************
 113  *
 114  *      Nameblock property handling
 115  */
 116 
 117 /*****************************************
 118  *
 119  *      Error message handling
 120  */
 121 
 122 /*
 123  *      fatal(format, args...)
 124  *
 125  *      Print a message and die
 126  *
 127  *      Parameters:
 128  *              format          printf type format string
 129  *              args            Arguments to match the format
 130  *
 131  *      Global variables used:
 132  *              fatal_in_progress Indicates if this is a recursive call
 133  *              parallel_process_cnt Do we need to wait for anything?
 134  *              report_pwd      Should we report the current path?
 135  */
 136 /*VARARGS*/
 137 void
 138 fatal(const char *message, ...)
 139 {
 140         va_list args;
 141 
 142         va_start(args, message);
 143         (void) fflush(stdout);
 144         (void) fprintf(stderr, catgets(catd, 1, 263, "make: Fatal error: "));
 145         (void) vfprintf(stderr, message, args);
 146         (void) fprintf(stderr, "\n");
 147         va_end(args);
 148         if (report_pwd) {
 149                 (void) fprintf(stderr,
 150                                catgets(catd, 1, 156, "Current working directory %s\n"),
 151                                get_current_path());
 152         }
 153         (void) fflush(stderr);
 154         if (fatal_in_progress) {
 155                 exit_status = 1;
 156                 exit(1);
 157         }
 158         fatal_in_progress = true;
 159         /* Let all parallel children finish */
 160         if ((dmake_mode_type == parallel_mode) &&
 161             (parallel_process_cnt > 0)) {
 162                 (void) fprintf(stderr,
 163                                catgets(catd, 1, 157, "Waiting for %d %s to finish\n"),
 164                                parallel_process_cnt,
 165                                parallel_process_cnt == 1 ?
 166                                catgets(catd, 1, 158, "job") : catgets(catd, 1, 159, "jobs"));
 167                 (void) fflush(stderr);
 168         }
 169 
 170         while (parallel_process_cnt > 0) {
 171                 await_parallel(true);
 172                 finish_children(false);
 173         }
 174 
 175 #if defined (TEAMWARE_MAKE_CMN) && defined (MAXJOBS_ADJUST_RFE4694000)
 176         job_adjust_fini();
 177 #endif
 178 
 179         exit_status = 1;
 180         exit(1);
 181 }
 182 
 183 /*
 184  *      warning(format, args...)
 185  *
 186  *      Print a message and continue.
 187  *
 188  *      Parameters:
 189  *              format          printf type format string
 190  *              args            Arguments to match the format
 191  *
 192  *      Global variables used:
 193  *              report_pwd      Should we report the current path?
 194  */
 195 /*VARARGS*/
 196 void
 197 warning(char * message, ...)
 198 {
 199         va_list args;
 200 
 201         va_start(args, message);
 202         (void) fflush(stdout);
 203         (void) fprintf(stderr, catgets(catd, 1, 265, "make: Warning: "));
 204         (void) vfprintf(stderr, message, args);
 205         (void) fprintf(stderr, "\n");
 206         va_end(args);
 207         if (report_pwd) {
 208                 (void) fprintf(stderr,
 209                                catgets(catd, 1, 161, "Current working directory %s\n"),
 210                                get_current_path());
 211         }
 212         (void) fflush(stderr);
 213 }
 214 
 215 /*
 216  *      time_to_string(time)
 217  *
 218  *      Take a numeric time value and produce
 219  *      a proper string representation.
 220  *
 221  *      Return value:
 222  *                              The string representation of the time
 223  *
 224  *      Parameters:
 225  *              time            The time we need to translate
 226  *
 227  *      Global variables used:
 228  */
 229 char *
 230 time_to_string(const timestruc_t &time)
 231 {
 232         struct tm               *tm;
 233         char                    buf[128];
 234 
 235         if (time == file_doesnt_exist) {
 236                 return catgets(catd, 1, 163, "File does not exist");
 237         }
 238         if (time == file_max_time) {
 239                 return catgets(catd, 1, 164, "Younger than any file");
 240         }
 241         tm = localtime(&time.tv_sec);
 242         strftime(buf, sizeof (buf), NOCATGETS("%c %Z"), tm);
 243         buf[127] = (int) nul_char;
 244         return strdup(buf);
 245 }
 246 
 247 /*
 248  *      get_current_path()
 249  *
 250  *      Stuff current_path with the current path if it isnt there already.
 251  *
 252  *      Parameters:
 253  *
 254  *      Global variables used:
 255  */
 256 char *
 257 get_current_path(void)
 258 {
 259         char                    pwd[(MAXPATHLEN * MB_LEN_MAX)];
 260         static char             *current_path;
 261 
 262         if (current_path == NULL) {
 263                 getcwd(pwd, sizeof(pwd));
 264                 if (pwd[0] == (int) nul_char) {
 265                         pwd[0] = (int) slash_char;
 266                         pwd[1] = (int) nul_char;
 267                 }
 268                 current_path = strdup(pwd);
 269         }
 270         return current_path;
 271 }
 272 
 273 /*****************************************
 274  *
 275  *      Make internal state dumping
 276  *
 277  *      This is a set  of routines for dumping the internal make state
 278  *      Used for the -p option
 279  */
 280 
 281 /*
 282  *      dump_make_state()
 283  *
 284  *      Dump make's internal state to stdout
 285  *
 286  *      Parameters:
 287  *
 288  *      Global variables used:
 289  *              svr4                    Was ".SVR4" seen in makefile?
 290  *              svr4_name               The Name ".SVR4", printed
 291  *              posix                   Was ".POSIX" seen in makefile?
 292  *              posix_name              The Name ".POSIX", printed
 293  *              default_rule            Points to the .DEFAULT rule
 294  *              default_rule_name       The Name ".DEFAULT", printed
 295  *              default_target_to_build The first target to print
 296  *              dot_keep_state          The Name ".KEEP_STATE", printed
 297  *              dot_keep_state_file     The Name ".KEEP_STATE_FILE", printed
 298  *              hashtab                 The make hash table for Name blocks
 299  *              ignore_errors           Was ".IGNORE" seen in makefile?
 300  *              ignore_name             The Name ".IGNORE", printed
 301  *              keep_state              Was ".KEEP_STATE" seen in makefile?
 302  *              percent_list            The list of % rules
 303  *              precious                The Name ".PRECIOUS", printed
 304  *              sccs_get_name           The Name ".SCCS_GET", printed
 305  *              sccs_get_posix_name     The Name ".SCCS_GET_POSIX", printed
 306  *              get_name                The Name ".GET", printed
 307  *              get_posix_name          The Name ".GET_POSIX", printed
 308  *              sccs_get_rule           Points to the ".SCCS_GET" rule
 309  *              silent                  Was ".SILENT" seen in makefile?
 310  *              silent_name             The Name ".SILENT", printed
 311  *              suffixes                The suffix list from ".SUFFIXES"
 312  *              suffixes_name           The Name ".SUFFIX", printed
 313  */
 314 void
 315 dump_make_state(void)
 316 {
 317         Name_set::iterator      p, e;
 318         register Property       prop;
 319         register Dependency     dep;
 320         register Cmd_line       rule;
 321         Percent                 percent, percent_depe;
 322 
 323         /* Default target */
 324         if (default_target_to_build != NULL) {
 325                 print_rule(default_target_to_build);
 326         }
 327         (void) printf("\n");
 328 
 329         /* .POSIX */
 330         if (posix) {
 331                 (void) printf("%s:\n", posix_name->string_mb);
 332         }
 333 
 334         /* .DEFAULT */
 335         if (default_rule != NULL) {
 336                 (void) printf("%s:\n", default_rule_name->string_mb);
 337                 for (rule = default_rule; rule != NULL; rule = rule->next) {
 338                         (void) printf("\t%s\n", rule->command_line->string_mb);
 339                 }
 340         }
 341 
 342         /* .IGNORE */
 343         if (ignore_errors) {
 344                 (void) printf("%s:\n", ignore_name->string_mb);
 345         }
 346 
 347         /* .KEEP_STATE: */
 348         if (keep_state) {
 349                 (void) printf("%s:\n\n", dot_keep_state->string_mb);
 350         }
 351 
 352         /* .PRECIOUS */
 353         (void) printf("%s:", precious->string_mb);
 354         for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) {
 355                         if ((p->stat.is_precious) || (all_precious)) {
 356                                 (void) printf(" %s", p->string_mb);
 357                         }
 358         }
 359         (void) printf("\n");
 360 
 361         /* .SCCS_GET */
 362         if (sccs_get_rule != NULL) {
 363                 (void) printf("%s:\n", sccs_get_name->string_mb);
 364                 for (rule = sccs_get_rule; rule != NULL; rule = rule->next) {
 365                         (void) printf("\t%s\n", rule->command_line->string_mb);
 366                 }
 367         }
 368 
 369         /* .SILENT */
 370         if (silent) {
 371                 (void) printf("%s:\n", silent_name->string_mb);
 372         }
 373 
 374         /* .SUFFIXES: */
 375         (void) printf("%s:", suffixes_name->string_mb);
 376         for (dep = suffixes; dep != NULL; dep = dep->next) {
 377                 (void) printf(" %s", dep->name->string_mb);
 378                 build_suffix_list(dep->name);
 379         }
 380         (void) printf("\n\n");
 381 
 382         /* % rules */
 383         for (percent = percent_list;
 384              percent != NULL;
 385              percent = percent->next) {
 386                 (void) printf("%s:",
 387                               percent->name->string_mb);
 388                 
 389                 for (percent_depe = percent->dependencies;
 390                      percent_depe != NULL;
 391                      percent_depe = percent_depe->next) {
 392                         (void) printf(" %s", percent_depe->name->string_mb);
 393                 }
 394                 
 395                 (void) printf("\n");
 396 
 397                 for (rule = percent->command_template;
 398                      rule != NULL;
 399                      rule = rule->next) {
 400                         (void) printf("\t%s\n", rule->command_line->string_mb);
 401                 }
 402         }
 403 
 404         /* Suffix rules */
 405         for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) {
 406                         Wstring wcb(p);
 407                         if (wcb.get_string()[0] == (int) period_char) {
 408                                 print_rule(p);
 409                         }
 410         }
 411 
 412         /* Macro assignments */
 413         for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) {
 414                         if (((prop = get_prop(p->prop, macro_prop)) != NULL) &&
 415                             (prop->body.macro.value != NULL)) {
 416                                 (void) printf("%s", p->string_mb);
 417                                 print_value(prop->body.macro.value,
 418                                             (Daemon) prop->body.macro.daemon);
 419                         }
 420         }
 421         (void) printf("\n");
 422 
 423         /* Conditional macro assignments */
 424         for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) {
 425                         for (prop = get_prop(p->prop, conditional_prop);
 426                              prop != NULL;
 427                              prop = get_prop(prop->next, conditional_prop)) {
 428                                 (void) printf("%s := %s",
 429                                               p->string_mb,
 430                                               prop->body.conditional.name->
 431                                               string_mb);
 432                                 if (prop->body.conditional.append) {
 433                                         printf(" +");
 434                                 }
 435                                 else {
 436                                         printf(" ");
 437                                 }
 438                                 print_value(prop->body.conditional.value,
 439                                             no_daemon);
 440                         }
 441         }
 442         (void) printf("\n");
 443 
 444         /* All other dependencies */
 445         for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) {
 446                         if (p->colons != no_colon) {
 447                                 print_rule(p);
 448                         }
 449         }
 450         (void) printf("\n");
 451 }
 452 
 453 /*
 454  *      print_rule(target)
 455  *
 456  *      Print the rule for one target
 457  *
 458  *      Parameters:
 459  *              target          Target we print rule for
 460  *
 461  *      Global variables used:
 462  */
 463 static void
 464 print_rule(register Name target)
 465 {
 466         register Cmd_line       rule;
 467         register Property       line;
 468         register Dependency     dependency;
 469 
 470         if (target->dependency_printed ||
 471             ((line = get_prop(target->prop, line_prop)) == NULL) ||
 472             ((line->body.line.command_template == NULL) &&
 473              (line->body.line.dependencies == NULL))) {
 474                 return;
 475         }
 476         target->dependency_printed = true;
 477 
 478         (void) printf("%s:", target->string_mb);
 479 
 480         for (dependency = line->body.line.dependencies;
 481              dependency != NULL;
 482              dependency = dependency->next) {
 483                 (void) printf(" %s", dependency->name->string_mb);
 484         }
 485 
 486         (void) printf("\n");
 487 
 488         for (rule = line->body.line.command_template;
 489              rule != NULL;
 490              rule = rule->next) {
 491                 (void) printf("\t%s\n", rule->command_line->string_mb);
 492         }
 493 }
 494 
 495 void
 496 dump_target_list(void)
 497 {
 498         Name_set::iterator      p, e;
 499         Wstring str;
 500 
 501         for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) {
 502                         str.init(p);
 503                         wchar_t * wcb = str.get_string();
 504                         if ((p->colons != no_colon) &&
 505                             ((wcb[0] != (int) period_char) ||
 506                              ((wcb[0] == (int) period_char) &&
 507                               (wschr(wcb, (int) slash_char))))) {
 508                                 print_target_n_deps(p);
 509                         }
 510         }
 511 }
 512 
 513 static void
 514 print_target_n_deps(register Name target)
 515 {
 516         register Cmd_line       rule;
 517         register Property       line;
 518         register Dependency     dependency;
 519 
 520         if (target->dependency_printed) {
 521                 return;
 522         }
 523         target->dependency_printed = true;
 524 
 525         (void) printf("%s\n", target->string_mb);
 526 
 527         if ((line = get_prop(target->prop, line_prop)) == NULL) {
 528                 return;
 529         }
 530         for (dependency = line->body.line.dependencies;
 531              dependency != NULL;
 532              dependency = dependency->next) {
 533                 if (!dependency->automatic) {
 534                         print_target_n_deps(dependency->name);
 535                 }
 536         }
 537 }
 538 
 539 /*****************************************
 540  *
 541  *      main() support
 542  */
 543 
 544 /*
 545  *      load_cached_names()
 546  *
 547  *      Load the vector of cached names
 548  *
 549  *      Parameters:
 550  *
 551  *      Global variables used:
 552  *              Many many pointers to Name blocks.
 553  */
 554 void
 555 load_cached_names(void)
 556 {
 557         char            *cp;
 558         Name            dollar;
 559 
 560         /* Load the cached_names struct */
 561         MBSTOWCS(wcs_buffer, NOCATGETS(".BUILT_LAST_MAKE_RUN"));
 562         built_last_make_run = GETNAME(wcs_buffer, FIND_LENGTH);
 563         MBSTOWCS(wcs_buffer, NOCATGETS("@"));
 564         c_at = GETNAME(wcs_buffer, FIND_LENGTH);
 565         MBSTOWCS(wcs_buffer, NOCATGETS(" *conditionals* "));
 566         conditionals = GETNAME(wcs_buffer, FIND_LENGTH);
 567         /*
 568          * A version of make was released with NSE 1.0 that used
 569          * VERSION-1.1 but this version is identical to VERSION-1.0.
 570          * The version mismatch code makes a special case for this
 571          * situation.  If the version number is changed from 1.0
 572          * it should go to 1.2.
 573          */
 574         MBSTOWCS(wcs_buffer, NOCATGETS("VERSION-1.0"));
 575         current_make_version = GETNAME(wcs_buffer, FIND_LENGTH);
 576         MBSTOWCS(wcs_buffer, NOCATGETS(".SVR4"));
 577         svr4_name = GETNAME(wcs_buffer, FIND_LENGTH);
 578         MBSTOWCS(wcs_buffer, NOCATGETS(".POSIX"));
 579         posix_name = GETNAME(wcs_buffer, FIND_LENGTH);
 580         MBSTOWCS(wcs_buffer, NOCATGETS(".DEFAULT"));
 581         default_rule_name = GETNAME(wcs_buffer, FIND_LENGTH);
 582         MBSTOWCS(wcs_buffer, NOCATGETS("$"));
 583         dollar = GETNAME(wcs_buffer, FIND_LENGTH);
 584         MBSTOWCS(wcs_buffer, NOCATGETS(".DONE"));
 585         done = GETNAME(wcs_buffer, FIND_LENGTH);
 586         MBSTOWCS(wcs_buffer, NOCATGETS("."));
 587         dot = GETNAME(wcs_buffer, FIND_LENGTH);
 588         MBSTOWCS(wcs_buffer, NOCATGETS(".KEEP_STATE"));
 589         dot_keep_state = GETNAME(wcs_buffer, FIND_LENGTH);
 590         MBSTOWCS(wcs_buffer, NOCATGETS(".KEEP_STATE_FILE"));
 591         dot_keep_state_file = GETNAME(wcs_buffer, FIND_LENGTH);
 592         MBSTOWCS(wcs_buffer, NOCATGETS(""));
 593         empty_name = GETNAME(wcs_buffer, FIND_LENGTH);
 594         MBSTOWCS(wcs_buffer, NOCATGETS(" FORCE"));
 595         force = GETNAME(wcs_buffer, FIND_LENGTH);
 596         MBSTOWCS(wcs_buffer, NOCATGETS("HOST_ARCH"));
 597         host_arch = GETNAME(wcs_buffer, FIND_LENGTH);
 598         MBSTOWCS(wcs_buffer, NOCATGETS("HOST_MACH"));
 599         host_mach = GETNAME(wcs_buffer, FIND_LENGTH);
 600         MBSTOWCS(wcs_buffer, NOCATGETS(".IGNORE"));
 601         ignore_name = GETNAME(wcs_buffer, FIND_LENGTH);
 602         MBSTOWCS(wcs_buffer, NOCATGETS(".INIT"));
 603         init = GETNAME(wcs_buffer, FIND_LENGTH);
 604         MBSTOWCS(wcs_buffer, NOCATGETS(".LOCAL"));
 605         localhost_name = GETNAME(wcs_buffer, FIND_LENGTH);
 606         MBSTOWCS(wcs_buffer, NOCATGETS(".make.state"));
 607         make_state = GETNAME(wcs_buffer, FIND_LENGTH);
 608         MBSTOWCS(wcs_buffer, NOCATGETS("MAKEFLAGS"));
 609         makeflags = GETNAME(wcs_buffer, FIND_LENGTH);
 610         MBSTOWCS(wcs_buffer, NOCATGETS(".MAKE_VERSION"));
 611         make_version = GETNAME(wcs_buffer, FIND_LENGTH);
 612         MBSTOWCS(wcs_buffer, NOCATGETS(".NO_PARALLEL"));
 613         no_parallel_name = GETNAME(wcs_buffer, FIND_LENGTH);
 614         MBSTOWCS(wcs_buffer, NOCATGETS(".NOT_AUTO"));
 615         not_auto = GETNAME(wcs_buffer, FIND_LENGTH);
 616         MBSTOWCS(wcs_buffer, NOCATGETS(".PARALLEL"));
 617         parallel_name = GETNAME(wcs_buffer, FIND_LENGTH);
 618         MBSTOWCS(wcs_buffer, NOCATGETS("PATH"));
 619         path_name = GETNAME(wcs_buffer, FIND_LENGTH);
 620         MBSTOWCS(wcs_buffer, NOCATGETS("+"));
 621         plus = GETNAME(wcs_buffer, FIND_LENGTH);
 622         MBSTOWCS(wcs_buffer, NOCATGETS(".PRECIOUS"));
 623         precious = GETNAME(wcs_buffer, FIND_LENGTH);
 624         MBSTOWCS(wcs_buffer, NOCATGETS("?"));
 625         query = GETNAME(wcs_buffer, FIND_LENGTH);
 626         MBSTOWCS(wcs_buffer, NOCATGETS("^"));
 627         hat = GETNAME(wcs_buffer, FIND_LENGTH);
 628         MBSTOWCS(wcs_buffer, NOCATGETS(".RECURSIVE"));
 629         recursive_name = GETNAME(wcs_buffer, FIND_LENGTH);
 630         MBSTOWCS(wcs_buffer, NOCATGETS(".SCCS_GET"));
 631         sccs_get_name = GETNAME(wcs_buffer, FIND_LENGTH);
 632         MBSTOWCS(wcs_buffer, NOCATGETS(".SCCS_GET_POSIX"));
 633         sccs_get_posix_name = GETNAME(wcs_buffer, FIND_LENGTH);
 634         MBSTOWCS(wcs_buffer, NOCATGETS(".GET"));
 635         get_name = GETNAME(wcs_buffer, FIND_LENGTH);
 636         MBSTOWCS(wcs_buffer, NOCATGETS(".GET_POSIX"));
 637         get_posix_name = GETNAME(wcs_buffer, FIND_LENGTH);
 638         MBSTOWCS(wcs_buffer, NOCATGETS("SHELL"));
 639         shell_name = GETNAME(wcs_buffer, FIND_LENGTH);
 640         MBSTOWCS(wcs_buffer, NOCATGETS(".SILENT"));
 641         silent_name = GETNAME(wcs_buffer, FIND_LENGTH);
 642         MBSTOWCS(wcs_buffer, NOCATGETS(".SUFFIXES"));
 643         suffixes_name = GETNAME(wcs_buffer, FIND_LENGTH);
 644         MBSTOWCS(wcs_buffer, SUNPRO_DEPENDENCIES);
 645         sunpro_dependencies = GETNAME(wcs_buffer, FIND_LENGTH);
 646         MBSTOWCS(wcs_buffer, NOCATGETS("TARGET_ARCH"));
 647         target_arch = GETNAME(wcs_buffer, FIND_LENGTH);
 648         MBSTOWCS(wcs_buffer, NOCATGETS("TARGET_MACH"));
 649         target_mach = GETNAME(wcs_buffer, FIND_LENGTH);
 650         MBSTOWCS(wcs_buffer, NOCATGETS("VIRTUAL_ROOT"));
 651         virtual_root = GETNAME(wcs_buffer, FIND_LENGTH);
 652         MBSTOWCS(wcs_buffer, NOCATGETS("VPATH"));
 653         vpath_name = GETNAME(wcs_buffer, FIND_LENGTH);
 654         MBSTOWCS(wcs_buffer, NOCATGETS(".WAIT"));
 655         wait_name = GETNAME(wcs_buffer, FIND_LENGTH);
 656 
 657         wait_name->state = build_ok;
 658 
 659         /* Mark special targets so that the reader treats them properly */
 660         svr4_name->special_reader = svr4_special;
 661         posix_name->special_reader = posix_special;
 662         built_last_make_run->special_reader = built_last_make_run_special;
 663         default_rule_name->special_reader = default_special;
 664         dot_keep_state->special_reader = keep_state_special;
 665         dot_keep_state_file->special_reader = keep_state_file_special;
 666         ignore_name->special_reader = ignore_special;
 667         make_version->special_reader = make_version_special;
 668         no_parallel_name->special_reader = no_parallel_special;
 669         parallel_name->special_reader = parallel_special;
 670         localhost_name->special_reader = localhost_special;
 671         precious->special_reader = precious_special;
 672         sccs_get_name->special_reader = sccs_get_special;
 673         sccs_get_posix_name->special_reader = sccs_get_posix_special;
 674         get_name->special_reader = get_special;
 675         get_posix_name->special_reader = get_posix_special;
 676         silent_name->special_reader = silent_special;
 677         suffixes_name->special_reader = suffixes_special;
 678 
 679         /* The value of $$ is $ */
 680         (void) SETVAR(dollar, dollar, false);
 681         dollar->dollar = false;
 682 
 683         /* Set the value of $(SHELL) */
 684         if (posix) {
 685           MBSTOWCS(wcs_buffer, NOCATGETS("/usr/xpg4/bin/sh"));
 686         } else {
 687           MBSTOWCS(wcs_buffer, NOCATGETS("/bin/sh"));
 688         }
 689         (void) SETVAR(shell_name, GETNAME(wcs_buffer, FIND_LENGTH), false);
 690 
 691         /*
 692          * Use " FORCE" to simulate a FRC dependency for :: type
 693          * targets with no dependencies.
 694          */
 695         (void) append_prop(force, line_prop);
 696         force->stat.time = file_max_time;
 697 
 698         /* Make sure VPATH is defined before current dir is read */
 699         if ((cp = getenv(vpath_name->string_mb)) != NULL) {
 700                 MBSTOWCS(wcs_buffer, cp);
 701                 (void) SETVAR(vpath_name,
 702                               GETNAME(wcs_buffer, FIND_LENGTH),
 703                               false);
 704         }
 705 
 706         /* Check if there is NO PATH variable. If not we construct one. */
 707         if (getenv(path_name->string_mb) == NULL) {
 708                 vroot_path = NULL;
 709                 add_dir_to_path(NOCATGETS("."), &vroot_path, -1);
 710                 add_dir_to_path(NOCATGETS("/bin"), &vroot_path, -1);
 711                 add_dir_to_path(NOCATGETS("/usr/bin"), &vroot_path, -1);
 712         }
 713 }
 714 
 715 /* 
 716  * iterate on list of conditional macros in np, and place them in 
 717  * a String_rec starting with, and separated by the '$' character.
 718  */
 719 void
 720 cond_macros_into_string(Name np, String_rec *buffer)
 721 {
 722         Macro_list      macro_list;
 723 
 724         /* 
 725          * Put the version number at the start of the string
 726          */
 727         MBSTOWCS(wcs_buffer, DEPINFO_FMT_VERSION);
 728         append_string(wcs_buffer, buffer, FIND_LENGTH);
 729         /* 
 730          * Add the rest of the conditional macros to the buffer
 731          */
 732         if (np->depends_on_conditional){
 733                 for (macro_list = np->conditional_macro_list; 
 734                      macro_list != NULL; macro_list = macro_list->next){
 735                         append_string(macro_list->macro_name, buffer, 
 736                                 FIND_LENGTH);
 737                         append_char((int) equal_char, buffer);
 738                         append_string(macro_list->value, buffer, FIND_LENGTH);
 739                         append_char((int) dollar_char, buffer);
 740                 }
 741         }
 742 }
 743 /*
 744  *      Copyright (c) 1987-1992 Sun Microsystems, Inc.  All Rights Reserved.
 745  *      Sun considers its source code as an unpublished, proprietary
 746  *      trade secret, and it is available only under strict license
 747  *      provisions.  This copyright notice is placed here only to protect
 748  *      Sun in the event the source is deemed a published work.  Dissassembly,
 749  *      decompilation, or other means of reducing the object code to human
 750  *      readable form is prohibited by the license agreement under which
 751  *      this code is provided to the user or company in possession of this
 752  *      copy.
 753  *      RESTRICTED RIGHTS LEGEND: Use, duplication, or disclosure by the
 754  *      Government is subject to restrictions as set forth in subparagraph
 755  *      (c)(1)(ii) of the Rights in Technical Data and Computer Software
 756  *      clause at DFARS 52.227-7013 and in similar clauses in the FAR and
 757  *      NASA FAR Supplement.
 758  *
 759  * 1.3 91/09/30
 760  */
 761 
 762 
 763 /* Some includes are commented because of the includes at the beginning */
 764 /* #include <signal.h> */
 765 #include <sys/types.h>
 766 #include <sys/stat.h>
 767 #include <sys/param.h>
 768 /* #include <string.h> */
 769 #include <unistd.h>
 770 #include <stdlib.h>
 771 /* #include <stdio.h> */
 772 /* #include <avo/find_dir.h> */
 773 /* #ifndef TEAMWARE_MAKE_CMN
 774 #include <avo/find_dir.h>
 775 #endif */
 776 
 777 /* Routines to find the base directory name from which the various components
 778  * -executables, *crt* libraries etc will be accessed
 779  */
 780 
 781 /* This routine checks to see if a given filename is an executable or not.
 782    Logically similar to the csh statement : if  ( -x $i && ! -d $i )
 783  */
 784 
 785 static int
 786 check_if_exec(char *file)
 787 {
 788         struct stat stb;
 789         if (stat(file, &stb) < 0) {
 790                 return ( -1);
 791         }
 792         if (S_ISDIR(stb.st_mode)) {
 793                 return (-1);
 794         }
 795         if (!(stb.st_mode & S_IEXEC)) {
 796                 return ( -1);
 797         }
 798         return (0);
 799 }
 800 
 801 /* resolve - check for specified file in specified directory
 802  *      sets up dir, following symlinks.
 803  *      returns zero for success, or
 804  *      -1 for error (with errno set properly)
 805  */
 806 static int
 807 resolve (const char *indir,     /* search directory */
 808          const char *cmd,       /* search for name */
 809          char   *dir,   /* directory buffer */
 810          char   **run)  /* resultion name ptr ptr */
 811 {
 812     char               *p;
 813     int                 rv = -1;
 814     int                 sll;
 815     char                symlink[MAXPATHLEN + 1];
 816 
 817     do {
 818         errno = ENAMETOOLONG;
 819         if ((strlen (indir) + strlen (cmd) + 2) > (size_t) MAXPATHLEN)
 820             break;
 821 
 822         sprintf(dir, "%s/%s", indir, cmd);
 823         if (check_if_exec(dir) != 0)  /* check if dir is an executable */
 824         {
 825                 break;          /* Not an executable program */
 826         }
 827 
 828         /* follow symbolic links */
 829         while ((sll = readlink (dir, symlink, MAXPATHLEN)) >= 0) {
 830             symlink[sll] = 0;
 831             if (*symlink == '/')
 832                 strcpy (dir, symlink);
 833             else
 834                 sprintf (strrchr (dir, '/'), "/%s", symlink);
 835         }
 836         if (errno != EINVAL)
 837             break;
 838 
 839         p = strrchr (dir, '/');
 840         *p++ = 0;
 841         if (run)                /* user wants resolution name */
 842             *run = p;
 843         rv = 0;                 /* complete, with success! */
 844 
 845     } while (0);
 846 
 847     return rv;
 848 }
 849 
 850 /* 
 851  *find_run_directory - find executable file in PATH
 852  *
 853  * PARAMETERS:
 854  *      cmd     filename as typed by user (argv[0])
 855  *      cwd     buffer from which is read the working directory
 856  *               if first character is '/' or into which is
 857  *               copied working directory name otherwise
 858  *      dir     buffer into which is copied program's directory
 859  *      pgm     where to return pointer to tail of cmd (may be NULL
 860  *               if not wanted) 
 861  *      run     where to return pointer to tail of final resolved
 862  *               name ( dir/run is the program) (may be NULL
 863  *               if not wanted)
 864  *      path    user's path from environment
 865  *
 866  * Note: run and pgm will agree except when symbolic links have
 867  *      renamed files
 868  *
 869  * RETURNS:
 870  *      returns zero for success,
 871  *      -1 for error (with errno set properly).
 872  *
 873  * EXAMPLE:
 874  *      find_run_directory (argv[0], ".", &charray1, (char **) 0, (char **) 0,
 875  *                          getenv(NOGETTEXT("PATH")));
 876  */
 877 extern int
 878 find_run_directory (char        *cmd,
 879                     char        *cwd,
 880                     char        *dir,
 881                     char        **pgm,
 882                     char        **run,
 883                     char        *path)
 884 {
 885     int                 rv = 0;
 886     char                *f, *s;
 887     int                 i;
 888     char                tmp_path[MAXPATHLEN];
 889 
 890     if (!cmd || !*cmd || !cwd || !dir) {
 891         errno = EINVAL;         /* stupid arguments! */
 892         return -1;
 893     }
 894 
 895     if (*cwd != '/')
 896         if (!(getcwd (cwd, MAXPATHLEN)))
 897             return -1;          /* can not get working directory */
 898 
 899     f = strrchr (cmd, '/');
 900     if (pgm)                    /* user wants program name */
 901         *pgm = f ? f + 1 : cmd;
 902 
 903     /* get program directory */
 904     rv = -1;
 905     if (*cmd == '/')    /* absname given */
 906         rv = resolve ("", cmd + 1, dir, run);
 907     else if (f)         /* relname given */
 908         rv = resolve (cwd, cmd, dir, run);
 909     else {  /* from searchpath */
 910             if (!path || !*path) {      /* if missing or null path */
 911                     tmp_path[0] = '.';  /* assume sanity */
 912                     tmp_path[1] = '\0';
 913             } else {
 914                     strcpy(tmp_path, path);
 915             }
 916         f = tmp_path;
 917         rv = -1;
 918         errno = ENOENT; /* errno gets this if path empty */
 919         while (*f && (rv < 0)) {
 920             s = f;
 921             while (*f && (*f != ':'))
 922                 ++f;
 923             if (*f)
 924                 *f++ = 0;
 925             if (*s == '/')
 926                 rv = resolve (s, cmd, dir, run);
 927             else {
 928                 char                abuf[MAXPATHLEN];
 929 
 930                 sprintf (abuf, "%s/%s", cwd, s);
 931                 rv = resolve (abuf, cmd, dir, run);
 932             }
 933         }
 934     }
 935 
 936     /* Remove any trailing /. */
 937     i = strlen(dir);
 938     if ( dir[i-2] == '/' && dir[i-1] == '.') {
 939             dir[i-2] = '\0';
 940     }
 941 
 942     return rv;
 943 }
 944