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