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