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