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