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