xref: /illumos-gate/usr/src/cmd/make/bin/main.cc (revision e7afc443)
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 2006 Sun Microsystems, Inc. All rights reserved.
23  * Use is subject to license terms.
24  *
25  * Copyright 2019, Joyent, Inc.
26  * Copyright 2019 RackTop Systems.
27  * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
28  */
29 
30 /*
31  *	main.cc
32  *
33  *	make program main routine plus some helper routines
34  */
35 
36 /*
37  * Included files
38  */
39 #include <bsd/bsd.h>		/* bsd_signal() */
40 
41 
42 #include <locale.h>		/* setlocale() */
43 #include <libgen.h>
44 #include <mk/defs.h>
45 #include <mksh/macro.h>		/* getvar() */
46 #include <mksh/misc.h>		/* getmem(), setup_char_semantics() */
47 
48 #include <pwd.h>		/* getpwnam() */
49 #include <setjmp.h>
50 #include <signal.h>
51 #include <stdlib.h>
52 #include <sys/errno.h>		/* ENOENT */
53 #include <sys/stat.h>		/* fstat() */
54 #include <fcntl.h>		/* open() */
55 
56 #	include <sys/systeminfo.h>	/* sysinfo() */
57 
58 #include <sys/types.h>		/* stat() */
59 #include <sys/wait.h>		/* wait() */
60 #include <unistd.h>		/* execv(), unlink(), access() */
61 #include <vroot/report.h>	/* report_dependency(), get_report_file() */
62 
63 // From read2.cc
64 extern	Name		normalize_name(wchar_t *name_string, int length);
65 
66 extern void job_adjust_fini();
67 
68 
69 /*
70  * Defined macros
71  */
72 #define	LD_SUPPORT_ENV_VAR	"SGS_SUPPORT_32"
73 #define	LD_SUPPORT_ENV_VAR_32	"SGS_SUPPORT_32"
74 #define	LD_SUPPORT_ENV_VAR_64	"SGS_SUPPORT_64"
75 #define	LD_SUPPORT_MAKE_LIB	"libmakestate.so.1"
76 #ifdef __x86
77 #define	LD_SUPPORT_MAKE_ARCH	"i386"
78 #elif __sparc
79 #define	LD_SUPPORT_MAKE_ARCH	"sparc"
80 #else
81 #error "Unsupported architecture"
82 #endif
83 
84 /*
85  * typedefs & structs
86  */
87 
88 /*
89  * Static variables
90  */
91 static	char		*argv_zero_string;
92 static	Boolean		build_failed_ever_seen;
93 static	Boolean		continue_after_error_ever_seen;	/* `-k' */
94 static	Boolean		dmake_group_specified;		/* `-g' */
95 static	Boolean		dmake_max_jobs_specified;	/* `-j' */
96 static	Boolean		dmake_mode_specified;		/* `-m' */
97 static	Boolean		dmake_add_mode_specified;	/* `-x' */
98 static	Boolean		dmake_output_mode_specified;	/* `-x DMAKE_OUTPUT_MODE=' */
99 static	Boolean		dmake_compat_mode_specified;	/* `-x SUN_MAKE_COMPAT_MODE=' */
100 static	Boolean		dmake_odir_specified;		/* `-o' */
101 static	Boolean		dmake_rcfile_specified;		/* `-c' */
102 static	Boolean		env_wins;			/* `-e' */
103 static	Boolean		ignore_default_mk;		/* `-r' */
104 static	Boolean		list_all_targets;		/* `-T' */
105 static	int		mf_argc;
106 static	char		**mf_argv;
107 static	Dependency_rec  not_auto_depen_struct;
108 static	Dependency	not_auto_depen = &not_auto_depen_struct;
109 static	Boolean		pmake_cap_r_specified;		/* `-R' */
110 static	Boolean		pmake_machinesfile_specified;	/* `-M' */
111 static	Boolean		stop_after_error_ever_seen;	/* `-S' */
112 static	Boolean		trace_status;			/* `-p' */
113 
114 #ifdef DMAKE_STATISTICS
115 static	Boolean		getname_stat = false;
116 #endif
117 
118 	static	time_t		start_time;
119 	static	int		g_argc;
120 	static	char		**g_argv;
121 
122 /*
123  * File table of contents
124  */
125 	extern "C" void		cleanup_after_exit(void);
126 
127 extern "C" {
128 	extern	void		dmake_exit_callback(void);
129 	extern	void		dmake_message_callback(char *);
130 }
131 
132 extern	Name		normalize_name(wchar_t *name_string, int length);
133 
134 extern	int		main(int, char * []);
135 
136 static	void		append_makeflags_string(Name, String);
137 static	void		doalarm(int);
138 static	void		enter_argv_values(int , char **, ASCII_Dyn_Array *);
139 static	void		make_targets(int, char **, Boolean);
140 static	int		parse_command_option(char);
141 static	void		read_command_options(int, char **);
142 static	void		read_environment(Boolean);
143 static	void		read_files_and_state(int, char **);
144 static	Boolean		read_makefile(Name, Boolean, Boolean, Boolean);
145 static	void		report_recursion(Name);
146 static	void		set_sgs_support(void);
147 static	void		setup_for_projectdir(void);
148 static	void		setup_makeflags_argv(void);
149 static	void		report_dir_enter_leave(Boolean entering);
150 
151 extern void expand_value(Name, String , Boolean);
152 
153 static const char	verstring[] = "illumos make";
154 
155 jmp_buf jmpbuffer;
156 
157 /*
158  *	main(argc, argv)
159  *
160  *	Parameters:
161  *		argc			You know what this is
162  *		argv			You know what this is
163  *
164  *	Static variables used:
165  *		list_all_targets	make -T seen
166  *		trace_status		make -p seen
167  *
168  *	Global variables used:
169  *		debug_level		Should we trace make actions?
170  *		keep_state		Set if .KEEP_STATE seen
171  *		makeflags		The Name "MAKEFLAGS", used to get macro
172  *		remote_command_name	Name of remote invocation cmd ("on")
173  *		running_list		List of parallel running processes
174  *		stdout_stderr_same	true if stdout and stderr are the same
175  *		auto_dependencies	The Name "SUNPRO_DEPENDENCIES"
176  *		temp_file_directory	Set to the dir where we create tmp file
177  *		trace_reader		Set to reflect tracing status
178  *		working_on_targets	Set when building user targets
179  */
180 int
main(int argc,char * argv[])181 main(int argc, char *argv[])
182 {
183 	/*
184 	 * cp is a -> to the value of the MAKEFLAGS env var,
185 	 * which has to be regular chars.
186 	 */
187 	char		*cp;
188 	char			make_state_dir[MAXPATHLEN];
189 	Boolean			parallel_flag = false;
190 	Boolean			argv_zero_relative = false;
191 	char			*prognameptr;
192 	char			*slash_ptr;
193 	mode_t			um;
194 	int			i;
195 	struct itimerval	value;
196 	char			def_dmakerc_path[MAXPATHLEN];
197 	Name			dmake_name, dmake_name2;
198 	Name			dmake_value, dmake_value2;
199 	Property		prop, prop2;
200 	struct stat		statbuf;
201 	int			statval;
202 
203 	struct stat		out_stat, err_stat;
204 	hostid = gethostid();
205 	bsd_signals();
206 
207 	(void) setlocale(LC_ALL, "");
208 
209 
210 #ifdef DMAKE_STATISTICS
211 	if (getenv("DMAKE_STATISTICS")) {
212 		getname_stat = true;
213 	}
214 #endif
215 
216 #ifndef TEXT_DOMAIN
217 #define	TEXT_DOMAIN	"SYS_TEST"
218 #endif
219 	textdomain(TEXT_DOMAIN);
220 
221 	g_argc = argc;
222 	g_argv = (char **) malloc((g_argc + 1) * sizeof(char *));
223 	for (i = 0; i < argc; i++) {
224 		g_argv[i] = argv[i];
225 	}
226 	g_argv[i] = NULL;
227 
228 	/*
229 	 * Set argv_zero_string to some form of argv[0] for
230 	 * recursive MAKE builds.
231 	 */
232 
233 	if (*argv[0] == (int) slash_char) {
234 		/* argv[0] starts with a slash */
235 		argv_zero_string = strdup(argv[0]);
236 	} else if (strchr(argv[0], (int) slash_char) == NULL) {
237 		/* argv[0] contains no slashes */
238 		argv_zero_string = strdup(argv[0]);
239 	} else {
240 		/*
241 		 * argv[0] contains at least one slash,
242 		 * but doesn't start with a slash
243 		 */
244 		char	*tmp_current_path;
245 		char	*tmp_string;
246 
247 		tmp_current_path = get_current_path();
248 		tmp_string = getmem(strlen(tmp_current_path) + 1 +
249 		                    strlen(argv[0]) + 1);
250 		(void) sprintf(tmp_string,
251 		               "%s/%s",
252 		               tmp_current_path,
253 		               argv[0]);
254 		argv_zero_string = strdup(tmp_string);
255 		retmem_mb(tmp_string);
256 		argv_zero_relative = true;
257 	}
258 
259 	/*
260 	 * The following flags are reset if we don't have the
261 	 * (.nse_depinfo or .make.state) files locked and only set
262 	 * AFTER the file has been locked. This ensures that if the user
263 	 * interrupts the program while file_lock() is waiting to lock
264 	 * the file, the interrupt handler doesn't remove a lock
265 	 * that doesn't belong to us.
266 	 */
267 	make_state_lockfile = NULL;
268 	make_state_locked = false;
269 
270 
271 	/*
272 	 * look for last slash char in the path to look at the binary
273 	 * name. This is to resolve the hard link and invoke make
274 	 * in svr4 mode.
275 	 */
276 
277 	/* Sun OS make standard */
278 	svr4 = false;
279 	posix = false;
280 	if(!strcmp(argv_zero_string, "/usr/xpg4/bin/make")) {
281 		svr4 = false;
282 		posix = true;
283 	} else {
284 		prognameptr = strrchr(argv[0], '/');
285 		if(prognameptr) {
286 			prognameptr++;
287 		} else {
288 			prognameptr = argv[0];
289 		}
290 		if(!strcmp(prognameptr, "svr4.make")) {
291 			svr4 = true;
292 			posix = false;
293 		}
294 	}
295 	if (getenv(USE_SVR4_MAKE) || getenv("USE_SVID")){
296 	   svr4 = true;
297 	   posix = false;
298 	}
299 
300 	/*
301 	 * Find the dmake_compat_mode: posix, sun, svr4, or gnu_style, .
302 	 */
303 	char * dmake_compat_mode_var = getenv("SUN_MAKE_COMPAT_MODE");
304 	if (dmake_compat_mode_var != NULL) {
305 		if (0 == strcasecmp(dmake_compat_mode_var, "GNU")) {
306 			gnu_style = true;
307 		}
308 		//svr4 = false;
309 		//posix = false;
310 	}
311 
312 	/*
313 	 * Temporary directory set up.
314 	 */
315 	char * tmpdir_var = getenv("TMPDIR");
316 	if (tmpdir_var != NULL && *tmpdir_var == '/' && strlen(tmpdir_var) < MAXPATHLEN) {
317 		strcpy(mbs_buffer, tmpdir_var);
318 		for (tmpdir_var = mbs_buffer+strlen(mbs_buffer);
319 			*(--tmpdir_var) == '/' && tmpdir_var > mbs_buffer;
320 			*tmpdir_var = '\0');
321 		if (strlen(mbs_buffer) + 32 < MAXPATHLEN) { /* 32 = strlen("/dmake.stdout.%d.%d.XXXXXX") */
322 			sprintf(mbs_buffer2, "%s/dmake.tst.%d.XXXXXX",
323 				mbs_buffer, getpid());
324 			int fd = mkstemp(mbs_buffer2);
325 			if (fd >= 0) {
326 				close(fd);
327 				unlink(mbs_buffer2);
328 				tmpdir = strdup(mbs_buffer);
329 			}
330 		}
331 	}
332 
333 	/* find out if stdout and stderr point to the same place */
334 	if (fstat(1, &out_stat) < 0) {
335 		fatal(gettext("fstat of standard out failed: %s"), errmsg(errno));
336 	}
337 	if (fstat(2, &err_stat) < 0) {
338 		fatal(gettext("fstat of standard error failed: %s"), errmsg(errno));
339 	}
340 	if ((out_stat.st_dev == err_stat.st_dev) &&
341 	    (out_stat.st_ino == err_stat.st_ino)) {
342 		stdout_stderr_same = true;
343 	} else {
344 		stdout_stderr_same = false;
345 	}
346 	/* Make the vroot package scan the path using shell semantics */
347 	set_path_style(0);
348 
349 	setup_char_semantics();
350 
351 	/*
352 	 * If running with .KEEP_STATE, curdir will be set with
353 	 * the connected directory.
354 	 */
355 	(void) atexit(cleanup_after_exit);
356 
357 	load_cached_names();
358 
359 /*
360  *	Set command line flags
361  */
362 	setup_makeflags_argv();
363 	read_command_options(mf_argc, mf_argv);
364 	read_command_options(argc, argv);
365 	if (debug_level > 0) {
366 		cp = getenv(makeflags->string_mb);
367 		(void) printf(gettext("MAKEFLAGS value: %s\n"), cp == NULL ? "" : cp);
368 	}
369 
370 	/*
371 	 * Reset argv_zero_string if it was built from a relative path and the
372 	 * -C option was specified.
373 	 */
374 	if (argv_zero_relative && rebuild_arg0) {
375 		char	*tmp_current_path;
376 		char	*tmp_string;
377 
378 		free(argv_zero_string);
379 		tmp_current_path = get_current_path();
380 		tmp_string = getmem(strlen(tmp_current_path) + 1 +
381 		                    strlen(argv[0]) + 1);
382 		(void) sprintf(tmp_string,
383 		               "%s/%s",
384 		               tmp_current_path,
385 		               argv[0]);
386 		argv_zero_string = strdup(tmp_string);
387 		retmem_mb(tmp_string);
388 	}
389 
390 	setup_for_projectdir();
391 
392 	setup_interrupt(handle_interrupt);
393 
394 	read_files_and_state(argc, argv);
395 
396 	/*
397 	 * Find the dmake_output_mode: TXT1, TXT2 or HTML1.
398 	 */
399 	MBSTOWCS(wcs_buffer, "DMAKE_OUTPUT_MODE");
400 	dmake_name2 = GETNAME(wcs_buffer, FIND_LENGTH);
401 	prop2 = get_prop(dmake_name2->prop, macro_prop);
402 	if (prop2 == NULL) {
403 		/* DMAKE_OUTPUT_MODE not defined, default to TXT1 mode */
404 		output_mode = txt1_mode;
405 	} else {
406 		dmake_value2 = prop2->body.macro.value;
407 		if ((dmake_value2 == NULL) ||
408 		    (IS_EQUAL(dmake_value2->string_mb, "TXT1"))) {
409 			output_mode = txt1_mode;
410 		} else if (IS_EQUAL(dmake_value2->string_mb, "TXT2")) {
411 			output_mode = txt2_mode;
412 		} else if (IS_EQUAL(dmake_value2->string_mb, "HTML1")) {
413 			output_mode = html1_mode;
414 		} else {
415 			warning(gettext("Unsupported value `%s' for DMAKE_OUTPUT_MODE after -x flag (ignored)"),
416 			      dmake_value2->string_mb);
417 		}
418 	}
419 	/*
420 	 * Find the dmake_mode: parallel, or serial.
421 	 */
422     if ((!pmake_cap_r_specified) &&
423         (!pmake_machinesfile_specified)) {
424 	char *s, *b;
425 
426 	if ((s = strdup(argv[0])) == NULL)
427 		fatal(gettext("Out of memory"));
428 
429 	b = basename(s);
430 
431 	MBSTOWCS(wcs_buffer, "DMAKE_MODE");
432 	dmake_name2 = GETNAME(wcs_buffer, FIND_LENGTH);
433 	prop2 = get_prop(dmake_name2->prop, macro_prop);
434 	// If we're invoked as 'make' run serially, regardless of DMAKE_MODE
435 	// If we're invoked as 'make' but passed -j, run parallel
436 	// If we're invoked as 'dmake', without DMAKE_MODE, default parallel
437 	// If we're invoked as 'dmake' and DMAKE_MODE is set, honour it.
438 	if ((strcmp(b, "make") == 0) &&
439 	    !dmake_max_jobs_specified) {
440 		dmake_mode_type = serial_mode;
441 		no_parallel = true;
442 	} else if (prop2 == NULL) {
443 		/* DMAKE_MODE not defined, default based on our name */
444 		if (strcmp(b, "dmake") == 0) {
445 			dmake_mode_type = parallel_mode;
446 			no_parallel = false;
447 		}
448 	} else {
449 		dmake_value2 = prop2->body.macro.value;
450 		if (IS_EQUAL(dmake_value2->string_mb, "parallel")) {
451 			dmake_mode_type = parallel_mode;
452 			no_parallel = false;
453 		} else if (IS_EQUAL(dmake_value2->string_mb, "serial")) {
454 			dmake_mode_type = serial_mode;
455 			no_parallel = true;
456 		} else {
457 			fatal(gettext("Unknown dmake mode argument `%s' after -m flag"), dmake_value2->string_mb);
458 		}
459 	}
460 	free(s);
461     }
462 
463 	parallel_flag = true;
464 	putenv(strdup("DMAKE_CHILD=TRUE"));
465 
466 //
467 // If dmake is running with -t option, set dmake_mode_type to serial.
468 // This is done because doname() calls touch_command() that runs serially.
469 // If we do not do that, maketool will have problems.
470 //
471 	if(touch) {
472 		dmake_mode_type = serial_mode;
473 		no_parallel = true;
474 	}
475 
476 	/*
477 	 * Check whether stdout and stderr are physically same.
478 	 * This is in order to decide whether we need to redirect
479 	 * stderr separately from stdout.
480 	 * This check is performed only if __DMAKE_SEPARATE_STDERR
481 	 * is not set. This variable may be used in order to preserve
482 	 * the 'old' behaviour.
483 	 */
484 	out_err_same = true;
485 	char * dmake_sep_var = getenv("__DMAKE_SEPARATE_STDERR");
486 	if (dmake_sep_var == NULL || (0 != strcasecmp(dmake_sep_var, "NO"))) {
487 		struct stat stdout_stat;
488 		struct stat stderr_stat;
489 		if( (fstat(1, &stdout_stat) == 0)
490 		 && (fstat(2, &stderr_stat) == 0) )
491 		{
492 			if( (stdout_stat.st_dev != stderr_stat.st_dev)
493 			 || (stdout_stat.st_ino != stderr_stat.st_ino) )
494 			{
495 				out_err_same = false;
496 			}
497 		}
498 	}
499 
500 
501 /*
502  *	Enable interrupt handler for alarms
503  */
504         (void) bsd_signal(SIGALRM, (SIG_PF)doalarm);
505 
506 /*
507  *	Check if make should report
508  */
509 	if (getenv(sunpro_dependencies->string_mb) != NULL) {
510 		FILE	*report_file;
511 
512 		report_dependency("");
513 		report_file = get_report_file();
514 		if ((report_file != NULL) && (report_file != (FILE*)-1)) {
515 			(void) fprintf(report_file, "\n");
516 		}
517 	}
518 
519 /*
520  *	Make sure SUNPRO_DEPENDENCIES is exported (or not) properly.
521  */
522 	if (keep_state) {
523 		maybe_append_prop(sunpro_dependencies, macro_prop)->
524 		  body.macro.exported = true;
525 	} else {
526 		maybe_append_prop(sunpro_dependencies, macro_prop)->
527 		  body.macro.exported = false;
528 	}
529 
530 	working_on_targets = true;
531 	if (trace_status) {
532 		dump_make_state();
533 		fclose(stdout);
534 		fclose(stderr);
535 		exit_status = 0;
536 		exit(0);
537 	}
538 	if (list_all_targets) {
539 		dump_target_list();
540 		fclose(stdout);
541 		fclose(stderr);
542 		exit_status = 0;
543 		exit(0);
544 	}
545 	trace_reader = false;
546 
547 	/*
548 	 * Set temp_file_directory to the directory the .make.state
549 	 * file is written to.
550 	 */
551 	if ((slash_ptr = strrchr(make_state->string_mb, (int) slash_char)) == NULL) {
552 		temp_file_directory = strdup(get_current_path());
553 	} else {
554 		*slash_ptr = (int) nul_char;
555 		(void) strcpy(make_state_dir, make_state->string_mb);
556 		*slash_ptr = (int) slash_char;
557 		   /* when there is only one slash and it's the first
558 		   ** character, make_state_dir should point to '/'.
559 		   */
560 		if(make_state_dir[0] == '\0') {
561 		   make_state_dir[0] = '/';
562 		   make_state_dir[1] = '\0';
563 		}
564 		if (make_state_dir[0] == (int) slash_char) {
565 			temp_file_directory = strdup(make_state_dir);
566 		} else {
567 			char	tmp_current_path2[MAXPATHLEN];
568 
569 			(void) sprintf(tmp_current_path2,
570 			               "%s/%s",
571 			               get_current_path(),
572 			               make_state_dir);
573 			temp_file_directory = strdup(tmp_current_path2);
574 		}
575 	}
576 
577 
578 	report_dir_enter_leave(true);
579 
580 	make_targets(argc, argv, parallel_flag);
581 
582 	report_dir_enter_leave(false);
583 
584 	if (build_failed_ever_seen) {
585 		if (posix) {
586 			exit_status = 1;
587 		}
588 		exit(1);
589 	}
590 	exit_status = 0;
591 	exit(0);
592 	/* NOTREACHED */
593 }
594 
595 /*
596  *	cleanup_after_exit()
597  *
598  *	Called from exit(), performs cleanup actions.
599  *
600  *	Parameters:
601  *		status		The argument exit() was called with
602  *		arg		Address of an argument vector to
603  *				cleanup_after_exit()
604  *
605  *	Global variables used:
606  *		command_changed	Set if we think .make.state should be rewritten
607  *		current_line	Is set we set commands_changed
608  *		do_not_exec_rule
609  *				True if -n flag on
610  *		done		The Name ".DONE", rule we run
611  *		keep_state	Set if .KEEP_STATE seen
612  *		parallel	True if building in parallel
613  *		quest		If -q is on we do not run .DONE
614  *		report_dependencies
615  *				True if -P flag on
616  *		running_list	List of parallel running processes
617  *		temp_file_name	The temp file is removed, if any
618  */
619 extern "C" void
cleanup_after_exit(void)620 cleanup_after_exit(void)
621 {
622 	Running		rp;
623 
624 extern long	getname_bytes_count;
625 extern long	getname_names_count;
626 extern long	getname_struct_count;
627 extern long	freename_bytes_count;
628 extern long	freename_names_count;
629 extern long	freename_struct_count;
630 extern long	other_alloc;
631 
632 extern long	env_alloc_num;
633 extern long	env_alloc_bytes;
634 
635 
636 #ifdef DMAKE_STATISTICS
637 if(getname_stat) {
638 	printf(">>> Getname statistics:\n");
639 	printf("  Allocated:\n");
640 	printf("        Names: %ld\n", getname_names_count);
641 	printf("      Strings: %ld Kb (%ld bytes)\n", getname_bytes_count/1000, getname_bytes_count);
642 	printf("      Structs: %ld Kb (%ld bytes)\n", getname_struct_count/1000, getname_struct_count);
643 	printf("  Total bytes: %ld Kb (%ld bytes)\n", getname_struct_count/1000 + getname_bytes_count/1000, getname_struct_count + getname_bytes_count);
644 
645 	printf("\n  Unallocated: %ld\n", freename_names_count);
646 	printf("        Names: %ld\n", freename_names_count);
647 	printf("      Strings: %ld Kb (%ld bytes)\n", freename_bytes_count/1000, freename_bytes_count);
648 	printf("      Structs: %ld Kb (%ld bytes)\n", freename_struct_count/1000, freename_struct_count);
649 	printf("  Total bytes: %ld Kb (%ld bytes)\n", freename_struct_count/1000 + freename_bytes_count/1000, freename_struct_count + freename_bytes_count);
650 
651 	printf("\n  Total used: %ld Kb (%ld bytes)\n", (getname_struct_count/1000 + getname_bytes_count/1000) - (freename_struct_count/1000 + freename_bytes_count/1000), (getname_struct_count + getname_bytes_count) - (freename_struct_count + freename_bytes_count));
652 
653 	printf("\n>>> Other:\n");
654 	printf(
655 		"       Env (%ld): %ld Kb (%ld bytes)\n",
656 		env_alloc_num,
657 		env_alloc_bytes/1000,
658 		env_alloc_bytes
659 	);
660 
661 }
662 #endif
663 
664 	parallel = false;
665 	/* If we used the SVR4_MAKE, don't build .DONE or .FAILED */
666 	if (!getenv(USE_SVR4_MAKE)){
667 	    /* Build the target .DONE or .FAILED if we caught an error */
668 	    if (!quest && !list_all_targets) {
669 		Name		failed_name;
670 
671 		MBSTOWCS(wcs_buffer, ".FAILED");
672 		failed_name = GETNAME(wcs_buffer, FIND_LENGTH);
673 		if ((exit_status != 0) && (failed_name->prop != NULL)) {
674 			/*
675 			 * [tolik] switch DMake to serial mode
676 			 */
677 			dmake_mode_type = serial_mode;
678 			no_parallel = true;
679 			(void) doname(failed_name, false, true);
680 		} else {
681 		    if (!trace_status) {
682 			/*
683 			 * Switch DMake to serial mode
684 			 */
685 			dmake_mode_type = serial_mode;
686 			no_parallel = true;
687 			(void) doname(done, false, true);
688 		    }
689 		}
690 	    }
691 	}
692 	/*
693 	 * Remove the temp file utilities report dependencies thru if it
694 	 * is still around
695 	 */
696 	if (temp_file_name != NULL) {
697 		(void) unlink(temp_file_name->string_mb);
698 	}
699 	/*
700 	 * Do not save the current command in .make.state if make
701 	 * was interrupted.
702 	 */
703 	if (current_line != NULL) {
704 		command_changed = true;
705 		current_line->body.line.command_used = NULL;
706 	}
707 	/*
708 	 * For each parallel build process running, remove the temp files
709 	 * and zap the command line so it won't be put in .make.state
710 	 */
711 	for (rp = running_list; rp != NULL; rp = rp->next) {
712 		if (rp->temp_file != NULL) {
713 			(void) unlink(rp->temp_file->string_mb);
714 		}
715 		if (rp->stdout_file != NULL) {
716 			(void) unlink(rp->stdout_file);
717 			retmem_mb(rp->stdout_file);
718 			rp->stdout_file = NULL;
719 		}
720 		if (rp->stderr_file != NULL) {
721 			(void) unlink(rp->stderr_file);
722 			retmem_mb(rp->stderr_file);
723 			rp->stderr_file = NULL;
724 		}
725 		command_changed = true;
726 /*
727 		line = get_prop(rp->target->prop, line_prop);
728 		if (line != NULL) {
729 			line->body.line.command_used = NULL;
730 		}
731  */
732 	}
733 	/* Remove the statefile lock file if the file has been locked */
734 	if ((make_state_lockfile != NULL) && (make_state_locked)) {
735 		(void) unlink(make_state_lockfile);
736 		make_state_lockfile = NULL;
737 		make_state_locked = false;
738 	}
739 	/* Write .make.state */
740 	write_state_file(1, (Boolean) 1);
741 
742 	job_adjust_fini();
743 }
744 
745 /*
746  *	handle_interrupt()
747  *
748  *	This is where C-C traps are caught.
749  *
750  *	Parameters:
751  *
752  *	Global variables used (except DMake 1.0):
753  *		current_target		Sometimes the current target is removed
754  *		do_not_exec_rule	But not if -n is on
755  *		quest			or -q
756  *		running_list		List of parallel running processes
757  *		touch			Current target is not removed if -t on
758  */
759 void
handle_interrupt(int)760 handle_interrupt(int)
761 {
762 	Property		member;
763 	Running			rp;
764 
765 	(void) fflush(stdout);
766 	if (childPid > 0) {
767 		kill(childPid, SIGTERM);
768 		childPid = -1;
769 	}
770 	for (rp = running_list; rp != NULL; rp = rp->next) {
771 		if (rp->state != build_running) {
772 			continue;
773 		}
774 		if (rp->pid > 0) {
775 			kill(rp->pid, SIGTERM);
776 			rp->pid = -1;
777 		}
778 	}
779 	if (getpid() == getpgrp()) {
780 		bsd_signal(SIGTERM, SIG_IGN);
781 		kill (-getpid(), SIGTERM);
782 	}
783 	/* Clean up all parallel children already finished */
784         finish_children(false);
785 
786 	/* Make sure the processes running under us terminate first */
787 
788 	while (wait((int *) NULL) != -1);
789 	/* Delete the current targets unless they are precious */
790 	if ((current_target != NULL) &&
791 	    current_target->is_member &&
792 	    ((member = get_prop(current_target->prop, member_prop)) != NULL)) {
793 		current_target = member->body.member.library;
794 	}
795 	if (!do_not_exec_rule &&
796 	    !touch &&
797 	    !quest &&
798 	    (current_target != NULL) &&
799 	    !(current_target->stat.is_precious || all_precious)) {
800 
801 /* BID_1030811 */
802 /* azv 16 Oct 95 */
803 		current_target->stat.time = file_no_time;
804 
805 		if (exists(current_target) != file_doesnt_exist) {
806 			(void) fprintf(stderr,
807 				       "\n*** %s ",
808 				       current_target->string_mb);
809 			if (current_target->stat.is_dir) {
810 				(void) fprintf(stderr,
811 					       gettext("not removed.\n"),
812 					       current_target->string_mb);
813 			} else if (unlink(current_target->string_mb) == 0) {
814 				(void) fprintf(stderr,
815 					       gettext("removed.\n"),
816 					       current_target->string_mb);
817 			} else {
818 				(void) fprintf(stderr,
819 					       gettext("could not be removed: %s.\n"),
820 					       current_target->string_mb,
821 					       errmsg(errno));
822 			}
823 		}
824 	}
825 	for (rp = running_list; rp != NULL; rp = rp->next) {
826 		if (rp->state != build_running) {
827 			continue;
828 		}
829 		if (rp->target->is_member &&
830 		    ((member = get_prop(rp->target->prop, member_prop)) !=
831 		     NULL)) {
832 			rp->target = member->body.member.library;
833 		}
834 		if (!do_not_exec_rule &&
835 		    !touch &&
836 		    !quest &&
837 		    !(rp->target->stat.is_precious || all_precious)) {
838 
839 			rp->target->stat.time = file_no_time;
840 			if (exists(rp->target) != file_doesnt_exist) {
841 				(void) fprintf(stderr,
842 					       "\n*** %s ",
843 					       rp->target->string_mb);
844 				if (rp->target->stat.is_dir) {
845 					(void) fprintf(stderr,
846 						       gettext("not removed.\n"),
847 						       rp->target->string_mb);
848 				} else if (unlink(rp->target->string_mb) == 0) {
849 					(void) fprintf(stderr,
850 						       gettext("removed.\n"),
851 						       rp->target->string_mb);
852 				} else {
853 					(void) fprintf(stderr,
854 						       gettext("could not be removed: %s.\n"),
855 						       rp->target->string_mb,
856 						       errmsg(errno));
857 				}
858 			}
859 		}
860 	}
861 
862 
863 	/* Have we locked .make.state or .nse_depinfo? */
864 	if ((make_state_lockfile != NULL) && (make_state_locked)) {
865 		unlink(make_state_lockfile);
866 		make_state_lockfile = NULL;
867 		make_state_locked = false;
868 	}
869 	/*
870 	 * Re-read .make.state file (it might be changed by recursive make)
871 	 */
872 	check_state(NULL);
873 
874 	report_dir_enter_leave(false);
875 
876 	exit_status = 2;
877 	exit(2);
878 }
879 
880 /*
881  *	doalarm(sig, ...)
882  *
883  *	Handle the alarm interrupt but do nothing.  Side effect is to
884  *	cause return from wait3.
885  *
886  *	Parameters:
887  *		sig
888  *
889  *	Global variables used:
890  */
891 static void
doalarm(int sig)892 doalarm(int sig __attribute__((unused)))
893 {
894 	return;
895 }
896 
897 
898 /*
899  *	read_command_options(argc, argv)
900  *
901  *	Scan the cmd line options and process the ones that start with "-"
902  *
903  *	Return value:
904  *				-M argument, if any
905  *
906  *	Parameters:
907  *		argc		You know what this is
908  *		argv		You know what this is
909  *
910  *	Global variables used:
911  */
912 static void
read_command_options(int argc,char ** argv)913 read_command_options(int argc, char **argv)
914 {
915 	int		ch;
916 	int			current_optind = 1;
917 	int			last_optind_with_double_hyphen = 0;
918 	int			last_optind;
919 	int			last_current_optind;
920 	int		i;
921 	int		j;
922 	int		k;
923 	int		makefile_next = 0; /*
924 						    * flag to note options:
925 						    * -c, f, g, j, m, o
926 						    */
927 	const char		*tptr;
928 	const char		*CMD_OPTS;
929 
930 	extern char		*optarg;
931 	extern int		optind, opterr, optopt;
932 
933 #define SUNPRO_CMD_OPTS	"-~Bbc:C:Ddef:g:ij:K:kM:m:NnO:o:PpqRrSsTtuVvwx:"
934 
935 #	define SVR4_CMD_OPTS   "-c:C:ef:g:ij:km:nO:o:pqrsTtVv"
936 
937 	/*
938 	 * Added V in SVR4_CMD_OPTS also, which is going to be a hidden
939 	 * option, just to make sure that the getopt doesn't fail when some
940 	 * users leave their USE_SVR4_MAKE set and try to use the makefiles
941 	 * that are designed to issue commands like $(MAKE) -V. Anyway it
942 	 * sets the same flag but ensures that getopt doesn't fail.
943 	 */
944 
945 	opterr = 0;
946 	optind = 1;
947 	while (1) {
948 		last_optind=optind;			/* Save optind and current_optind values */
949 		last_current_optind=current_optind;	/* in case we have to repeat this round. */
950 		if (svr4) {
951 			CMD_OPTS=SVR4_CMD_OPTS;
952 			ch = getopt(argc, argv, SVR4_CMD_OPTS);
953 		} else {
954 			CMD_OPTS=SUNPRO_CMD_OPTS;
955 			ch = getopt(argc, argv, SUNPRO_CMD_OPTS);
956 		}
957 		if (ch == EOF) {
958 			if(optind < argc) {
959 				/*
960 				 * Fixing bug 4102537:
961 				 *    Strange behaviour of command make using -- option.
962 				 * Not all argv have been processed
963 				 * Skip non-flag argv and continue processing.
964 				 */
965 				optind++;
966 				current_optind++;
967 				continue;
968 			} else {
969 				break;
970 			}
971 
972 		}
973 		if (ch == '?') {
974 			if (optopt == '-') {
975 				/* Bug 5060758: getopt() changed behavior (s10_60),
976 				 * and now we have to deal with cases when options
977 				 * with double hyphen appear here, from -$(MAKEFLAGS)
978 				 */
979 				i = current_optind;
980 				if (argv[i][0] == '-') {
981 				  if (argv[i][1] == '-') {
982 				    if (argv[i][2] != '\0') {
983 				      /* Check if this option is allowed */
984 				      tptr = strchr(CMD_OPTS, argv[i][2]);
985 				      if (tptr) {
986 				        if (last_optind_with_double_hyphen != current_optind) {
987 				          /* This is first time we are trying to fix "--"
988 				           * problem with this option. If we come here second
989 				           * time, we will go to fatal error.
990 				           */
991 				          last_optind_with_double_hyphen = current_optind;
992 
993 				          /* Eliminate first hyphen character */
994 				          for (j=0; argv[i][j] != '\0'; j++) {
995 				            argv[i][j] = argv[i][j+1];
996 				          }
997 
998 				          /* Repeat the processing of this argument */
999 				          optind=last_optind;
1000 				          current_optind=last_current_optind;
1001 				          continue;
1002 				        }
1003 				      }
1004 				    }
1005 				  }
1006 				}
1007 			}
1008 		}
1009 
1010 		if (ch == '?') {
1011 			if (svr4) {
1012 				fprintf(stderr,
1013 					gettext("Usage : dmake [ -f makefile ][ -c dmake_rcfile ][ -g dmake_group ][-C directory]\n"));
1014 				fprintf(stderr,
1015 					gettext("              [ -j dmake_max_jobs ][ -m dmake_mode ][ -o dmake_odir ]...\n"));
1016 				fprintf(stderr,
1017 					gettext("              [ -e ][ -i ][ -k ][ -n ][ -p ][ -q ][ -r ][ -s ][ -t ][ -v ]\n"));
1018 				tptr = strchr(SVR4_CMD_OPTS, optopt);
1019 			} else {
1020 				fprintf(stderr,
1021 					gettext("Usage : dmake [ -f makefile ][ -c dmake_rcfile ][ -g dmake_group ][-C directory]\n"));
1022 				fprintf(stderr,
1023 					gettext("              [ -j dmake_max_jobs ][ -K statefile ][ -m dmake_mode ][ -x MODE_NAME=VALUE ][ -o dmake_odir ]...\n"));
1024 				fprintf(stderr,
1025 					gettext("              [ -d ][ -dd ][ -D ][ -DD ][ -e ][ -i ][ -k ][ -n ][ -p ][ -P ][ -u ][ -w ]\n"));
1026 				fprintf(stderr,
1027 					gettext("              [ -q ][ -r ][ -s ][ -S ][ -t ][ -v ][ -V ][ target... ][ macro=value... ][ \"macro +=value\"... ]\n"));
1028 				tptr = strchr(SUNPRO_CMD_OPTS, optopt);
1029 			}
1030 			if (!tptr) {
1031 				fatal(gettext("Unknown option `-%c'"), optopt);
1032 			} else {
1033 				fatal(gettext("Missing argument after `-%c'"), optopt);
1034 			}
1035 		}
1036 
1037 
1038 
1039 		makefile_next |= parse_command_option(ch);
1040 		/*
1041 		 * If we're done processing all of the options of
1042 		 * ONE argument string...
1043 		 */
1044 		if (current_optind < optind) {
1045 			i = current_optind;
1046 			k = 0;
1047 			/* If there's an argument for an option... */
1048 			if ((optind - current_optind) > 1) {
1049 				k = i + 1;
1050 			}
1051 			switch (makefile_next) {
1052 			case 0:
1053 				argv[i] = NULL;
1054 				/* This shouldn't happen */
1055 				if (k) {
1056 					argv[k] = NULL;
1057 				}
1058 				break;
1059 			case 1:	/* -f seen */
1060 				argv[i] = (char *)"-f";
1061 				break;
1062 			case 2:	/* -c seen */
1063 				argv[i] = (char *)"-c";
1064 				break;
1065 			case 4:	/* -g seen */
1066 				argv[i] = (char *)"-g";
1067 				break;
1068 			case 8:	/* -j seen */
1069 				argv[i] = (char *)"-j";
1070 				break;
1071 			case 16: /* -M seen */
1072 				argv[i] = (char *)"-M";
1073 				break;
1074 			case 32: /* -m seen */
1075 				argv[i] = (char *)"-m";
1076 				break;
1077 			case 128: /* -O seen */
1078 				argv[i] = (char *)"-O";
1079 				break;
1080 			case 256: /* -K seen */
1081 				argv[i] = (char *)"-K";
1082 			        break;
1083 			case 512:	/* -o seen */
1084 				argv[i] = (char *)"-o";
1085 				break;
1086 			case 1024: /* -x seen */
1087 				argv[i] = (char *)"-x";
1088 				break;
1089 			case 2048:
1090 				argv[i] = (char *)"-C";
1091 				if (chdir(argv[k]) != 0) {
1092 					fatal(gettext("failed to change to directory %s: %s"),
1093 					    argv[k], strerror(errno));
1094 				}
1095 				path_reset = true;
1096 				rebuild_arg0 = true;
1097 				(void) get_current_path();
1098 				break;
1099 			default: /* > 1 of -c, f, g, j, K, M, m, O, o, x seen */
1100 				fatal(gettext("Illegal command line. More than one option requiring\nan argument given in the same argument group"));
1101 			}
1102 
1103 			makefile_next = 0;
1104 			current_optind = optind;
1105 		}
1106 	}
1107 }
1108 
1109 static void
quote_str(char * str,char * qstr)1110 quote_str(char *str, char *qstr)
1111 {
1112 	char		*to;
1113 	char		*from;
1114 
1115 	to = qstr;
1116 	for (from = str; *from; from++) {
1117 		switch (*from) {
1118 		case ';':	/* End of command */
1119 		case '(':	/* Start group */
1120 		case ')':	/* End group */
1121 		case '{':	/* Start group */
1122 		case '}':	/* End group */
1123 		case '[':	/* Reg expr - any of a set of chars */
1124 		case ']':	/* End of set of chars */
1125 		case '|':	/* Pipe or logical-or */
1126 		case '^':	/* Old-fashioned pipe */
1127 		case '&':	/* Background or logical-and */
1128 		case '<':	/* Redirect stdin */
1129 		case '>':	/* Redirect stdout */
1130 		case '*':	/* Reg expr - any sequence of chars */
1131 		case '?':	/* Reg expr - any single char */
1132 		case '$':	/* Variable substitution */
1133 		case '\'':	/* Singe quote - turn off all magic */
1134 		case '"':	/* Double quote - span whitespace */
1135 		case '`':	/* Backquote - run a command */
1136 		case '#':	/* Comment */
1137 		case ' ':	/* Space (for MACRO=value1 value2  */
1138 		case '\\':	/* Escape char - turn off magic of next char */
1139 			*to++ = '\\';
1140 			break;
1141 
1142 		default:
1143 			break;
1144 		}
1145 		*to++ = *from;
1146 	}
1147 	*to = '\0';
1148 }
1149 
1150 static void
unquote_str(char * str,char * qstr)1151 unquote_str(char *str, char *qstr)
1152 {
1153 	char		*to;
1154 	char		*from;
1155 
1156 	to = qstr;
1157 	for (from = str; *from; from++) {
1158 		if (*from == '\\') {
1159 			from++;
1160 		}
1161 		*to++ = *from;
1162 	}
1163 	*to = '\0';
1164 }
1165 
1166 /*
1167  * Convert the MAKEFLAGS string value into a vector of char *, similar
1168  * to argv.
1169  */
1170 static void
setup_makeflags_argv()1171 setup_makeflags_argv()
1172 {
1173 	char		*cp;
1174 	char		*cp1;
1175 	char		*cp2;
1176 	char		*cp3;
1177 	char		*cp_orig;
1178 	Boolean		add_hyphen;
1179 	int		i;
1180 	char		tmp_char;
1181 
1182 	mf_argc = 1;
1183 	cp = getenv(makeflags->string_mb);
1184 	cp_orig = cp;
1185 
1186 	if (cp) {
1187 		/*
1188 		 * If new MAKEFLAGS format, no need to add hyphen.
1189 		 * If old MAKEFLAGS format, add hyphen before flags.
1190 		 */
1191 
1192 		if ((strchr(cp, (int) hyphen_char) != NULL) ||
1193 		    (strchr(cp, (int) equal_char) != NULL)) {
1194 
1195 			/* New MAKEFLAGS format */
1196 
1197 			add_hyphen = false;
1198 
1199 			/* Check if MAKEFLAGS value begins with multiple
1200 			 * hyphen characters, and remove all duplicates.
1201 			 * Usually it happens when the next command is
1202 			 * used: $(MAKE) -$(MAKEFLAGS)
1203 			 *
1204 			 * This was a workaround for BugID 5060758, but
1205 			 * appears to have survived as a fix in make.
1206 			 */
1207 			while (*cp) {
1208 				if (*cp != (int) hyphen_char) {
1209 					break;
1210 				}
1211 				cp++;
1212 				if (*cp == (int) hyphen_char) {
1213 					/* There are two hyphens. Skip one */
1214 					cp_orig = cp;
1215 					cp++;
1216 				}
1217 				if (!(*cp)) {
1218 					/* There are hyphens only. Skip all */
1219 					cp_orig = cp;
1220 					break;
1221 				}
1222 			}
1223 		} else {
1224 
1225 			/* Old MAKEFLAGS format */
1226 
1227 			add_hyphen = true;
1228 		}
1229 	}
1230 
1231 	/* Find the number of arguments in MAKEFLAGS */
1232 	while (cp && *cp) {
1233 		/* Skip white spaces */
1234 		while (cp && *cp && isspace(*cp)) {
1235 			cp++;
1236 		}
1237 		if (cp && *cp) {
1238 			/* Increment arg count */
1239 			mf_argc++;
1240 			/* Go to next white space */
1241 			while (cp && *cp && !isspace(*cp)) {
1242 				if(*cp == (int) backslash_char) {
1243 					cp++;
1244 				}
1245 				cp++;
1246 			}
1247 		}
1248 	}
1249 	/* Allocate memory for the new MAKEFLAGS argv */
1250 	mf_argv = (char **) malloc((mf_argc + 1) * sizeof(char *));
1251 	mf_argv[0] = (char *)"MAKEFLAGS";
1252 	/*
1253 	 * Convert the MAKEFLAGS string value into a vector of char *,
1254 	 * similar to argv.
1255 	 */
1256 	cp = cp_orig;
1257 	for (i = 1; i < mf_argc; i++) {
1258 		/* Skip white spaces */
1259 		while (cp && *cp && isspace(*cp)) {
1260 			cp++;
1261 		}
1262 		if (cp && *cp) {
1263 			cp_orig = cp;
1264 			/* Go to next white space */
1265 			while (cp && *cp && !isspace(*cp)) {
1266 				if(*cp == (int) backslash_char) {
1267 					cp++;
1268 				}
1269 				cp++;
1270 			}
1271 			tmp_char = *cp;
1272 			*cp = (int) nul_char;
1273 			if (add_hyphen) {
1274 				mf_argv[i] = getmem(2 + strlen(cp_orig));
1275 				mf_argv[i][0] = '\0';
1276 				(void) strcat(mf_argv[i], "-");
1277 				// (void) strcat(mf_argv[i], cp_orig);
1278 				unquote_str(cp_orig, mf_argv[i]+1);
1279 			} else {
1280 				mf_argv[i] = getmem(2 + strlen(cp_orig));
1281 				//mf_argv[i] = strdup(cp_orig);
1282 				unquote_str(cp_orig, mf_argv[i]);
1283 			}
1284 			*cp = tmp_char;
1285 		}
1286 	}
1287 	mf_argv[i] = NULL;
1288 }
1289 
1290 /*
1291  *	parse_command_option(ch)
1292  *
1293  *	Parse make command line options.
1294  *
1295  *	Return value:
1296  *				Indicates if any -f -c or -M were seen
1297  *
1298  *	Parameters:
1299  *		ch		The character to parse
1300  *
1301  *	Static variables used:
1302  *		dmake_group_specified	Set for make -g
1303  *		dmake_max_jobs_specified	Set for make -j
1304  *		dmake_mode_specified	Set for make -m
1305  *		dmake_add_mode_specified	Set for make -x
1306  *		dmake_compat_mode_specified	Set for make -x SUN_MAKE_COMPAT_MODE=
1307  *		dmake_output_mode_specified	Set for make -x DMAKE_OUTPUT_MODE=
1308  *		dmake_odir_specified	Set for make -o
1309  *		dmake_rcfile_specified	Set for make -c
1310  *		env_wins		Set for make -e
1311  *		ignore_default_mk	Set for make -r
1312  *		trace_status		Set for make -p
1313  *
1314  *	Global variables used:
1315  *		.make.state path & name set for make -K
1316  *		continue_after_error	Set for make -k
1317  *		debug_level		Set for make -d
1318  *		do_not_exec_rule	Set for make -n
1319  *		filter_stderr		Set for make -X
1320  *		ignore_errors_all	Set for make -i
1321  *		no_parallel		Set for make -R
1322  *		quest			Set for make -q
1323  *		read_trace_level	Set for make -D
1324  *		report_dependencies	Set for make -P
1325  *		silent_all		Set for make -s
1326  *		touch			Set for make -t
1327  */
1328 static int
parse_command_option(char ch)1329 parse_command_option(char ch)
1330 {
1331 	static int		invert_next = 0;
1332 	int			invert_this = invert_next;
1333 
1334 	invert_next = 0;
1335 	switch (ch) {
1336 	case '-':			 /* Ignore "--" */
1337 		return 0;
1338 	case '~':			 /* Invert next option */
1339 		invert_next = 1;
1340 		return 0;
1341 	case 'B':			 /* Obsolete */
1342 		return 0;
1343 	case 'b':			 /* Obsolete */
1344 		return 0;
1345 	case 'c':			 /* Read alternative dmakerc file */
1346 		if (invert_this) {
1347 			dmake_rcfile_specified = false;
1348 		} else {
1349 			dmake_rcfile_specified = true;
1350 		}
1351 		return 2;
1352 	case 'C':			/* Change directory */
1353 		return 2048;
1354 	case 'D':			 /* Show lines read */
1355 		if (invert_this) {
1356 			read_trace_level--;
1357 		} else {
1358 			read_trace_level++;
1359 		}
1360 		return 0;
1361 	case 'd':			 /* Debug flag */
1362 		if (invert_this) {
1363 			debug_level--;
1364 		} else {
1365 			debug_level++;
1366 		}
1367 		return 0;
1368 	case 'e':			 /* Environment override flag */
1369 		if (invert_this) {
1370 			env_wins = false;
1371 		} else {
1372 			env_wins = true;
1373 		}
1374 		return 0;
1375 	case 'f':			 /* Read alternative makefile(s) */
1376 		return 1;
1377 	case 'g':			 /* Use alternative DMake group */
1378 		if (invert_this) {
1379 			dmake_group_specified = false;
1380 		} else {
1381 			dmake_group_specified = true;
1382 		}
1383 		return 4;
1384 	case 'i':			 /* Ignore errors */
1385 		if (invert_this) {
1386 			ignore_errors_all = false;
1387 		} else {
1388 			ignore_errors_all = true;
1389 		}
1390 		return 0;
1391 	case 'j':			 /* Use alternative DMake max jobs */
1392 		if (invert_this) {
1393 			dmake_max_jobs_specified = false;
1394 		} else {
1395 			dmake_mode_type = parallel_mode;
1396 			no_parallel = false;
1397 			dmake_max_jobs_specified = true;
1398 		}
1399 		return 8;
1400 	case 'K':			 /* Read alternative .make.state */
1401 		return 256;
1402 	case 'k':			 /* Keep making even after errors */
1403 		if (invert_this) {
1404 			continue_after_error = false;
1405 		} else {
1406 			continue_after_error = true;
1407 			continue_after_error_ever_seen = true;
1408 		}
1409 		return 0;
1410 	case 'M':			 /* Read alternative make.machines file */
1411 		if (invert_this) {
1412 			pmake_machinesfile_specified = false;
1413 		} else {
1414 			pmake_machinesfile_specified = true;
1415 			dmake_mode_type = parallel_mode;
1416 			no_parallel = false;
1417 		}
1418 		return 16;
1419 	case 'm':			 /* Use alternative DMake build mode */
1420 		if (invert_this) {
1421 			dmake_mode_specified = false;
1422 		} else {
1423 			dmake_mode_specified = true;
1424 		}
1425 		return 32;
1426 	case 'x':			 /* Use alternative DMake mode */
1427 		if (invert_this) {
1428 			dmake_add_mode_specified = false;
1429 		} else {
1430 			dmake_add_mode_specified = true;
1431 		}
1432 		return 1024;
1433 	case 'N':			 /* Reverse -n */
1434 		if (invert_this) {
1435 			do_not_exec_rule = true;
1436 		} else {
1437 			do_not_exec_rule = false;
1438 		}
1439 		return 0;
1440 	case 'n':			 /* Print, not exec commands */
1441 		if (invert_this) {
1442 			do_not_exec_rule = false;
1443 		} else {
1444 			do_not_exec_rule = true;
1445 		}
1446 		return 0;
1447 	case 'O':			 /* Integrate with maketool, obsolete */
1448 		return 0;
1449 	case 'o':			 /* Use alternative dmake output dir */
1450 		if (invert_this) {
1451 			dmake_odir_specified = false;
1452 		} else {
1453 			dmake_odir_specified = true;
1454 		}
1455 		return 512;
1456 	case 'P':			 /* Print for selected targets */
1457 		if (invert_this) {
1458 			report_dependencies_level--;
1459 		} else {
1460 			report_dependencies_level++;
1461 		}
1462 		return 0;
1463 	case 'p':			 /* Print description */
1464 		if (invert_this) {
1465 			trace_status = false;
1466 			do_not_exec_rule = false;
1467 		} else {
1468 			trace_status = true;
1469 			do_not_exec_rule = true;
1470 		}
1471 		return 0;
1472 	case 'q':			 /* Question flag */
1473 		if (invert_this) {
1474 			quest = false;
1475 		} else {
1476 			quest = true;
1477 		}
1478 		return 0;
1479 	case 'R':			 /* Don't run in parallel */
1480 		if (invert_this) {
1481 			pmake_cap_r_specified = false;
1482 			no_parallel = false;
1483 		} else {
1484 			pmake_cap_r_specified = true;
1485 			dmake_mode_type = serial_mode;
1486 			no_parallel = true;
1487 		}
1488 		return 0;
1489 	case 'r':			 /* Turn off internal rules */
1490 		if (invert_this) {
1491 			ignore_default_mk = false;
1492 		} else {
1493 			ignore_default_mk = true;
1494 		}
1495 		return 0;
1496 	case 'S':			 /* Reverse -k */
1497 		if (invert_this) {
1498 			continue_after_error = true;
1499 		} else {
1500 			continue_after_error = false;
1501 			stop_after_error_ever_seen = true;
1502 		}
1503 		return 0;
1504 	case 's':			 /* Silent flag */
1505 		if (invert_this) {
1506 			silent_all = false;
1507 		} else {
1508 			silent_all = true;
1509 		}
1510 		return 0;
1511 	case 'T':			 /* Print target list */
1512 		if (invert_this) {
1513 			list_all_targets = false;
1514 			do_not_exec_rule = false;
1515 		} else {
1516 			list_all_targets = true;
1517 			do_not_exec_rule = true;
1518 		}
1519 		return 0;
1520 	case 't':			 /* Touch flag */
1521 		if (invert_this) {
1522 			touch = false;
1523 		} else {
1524 			touch = true;
1525 		}
1526 		return 0;
1527 	case 'u':			 /* Unconditional flag */
1528 		if (invert_this) {
1529 			build_unconditional = false;
1530 		} else {
1531 			build_unconditional = true;
1532 		}
1533 		return 0;
1534 	case 'V':			/* SVR4 mode */
1535 		svr4 = true;
1536 		return 0;
1537 	case 'v':			/* Version flag */
1538 		if (invert_this) {
1539 		} else {
1540 			fprintf(stdout, "%s: %s\n", getprogname(), verstring);
1541 			exit_status = 0;
1542 			exit(0);
1543 		}
1544 		return 0;
1545 	case 'w':			 /* Unconditional flag */
1546 		if (invert_this) {
1547 			report_cwd = false;
1548 		} else {
1549 			report_cwd = true;
1550 		}
1551 		return 0;
1552 #if 0
1553 	case 'X':			/* Filter stdout */
1554 		if (invert_this) {
1555 			filter_stderr = false;
1556 		} else {
1557 			filter_stderr = true;
1558 		}
1559 		return 0;
1560 #endif
1561 	default:
1562 		break;
1563 	}
1564 	return 0;
1565 }
1566 
1567 /*
1568  *	setup_for_projectdir()
1569  *
1570  *	Read the PROJECTDIR variable, if defined, and set the sccs path
1571  *
1572  *	Parameters:
1573  *
1574  *	Global variables used:
1575  *		sccs_dir_path	Set to point to SCCS dir to use
1576  */
1577 static void
setup_for_projectdir(void)1578 setup_for_projectdir(void)
1579 {
1580 static char	path[MAXPATHLEN];
1581 char		cwdpath[MAXPATHLEN];
1582 uid_t uid;
1583 int   done=0;
1584 
1585 	/* Check if we should use PROJECTDIR when reading the SCCS dir. */
1586 	sccs_dir_path = getenv("PROJECTDIR");
1587 	if ((sccs_dir_path != NULL) &&
1588 	    (sccs_dir_path[0] != (int) slash_char)) {
1589 		struct passwd *pwent;
1590 
1591 	     {
1592 		uid = getuid();
1593 		pwent = getpwuid(uid);
1594 		if (pwent == NULL) {
1595 		   fatal(gettext("Bogus USERID "));
1596 		}
1597 		if ((pwent = getpwnam(sccs_dir_path)) == NULL) {
1598 			/*empty block : it'll go & check cwd  */
1599 		}
1600 		else {
1601 		  (void) sprintf(path, "%s/src", pwent->pw_dir);
1602 		  if (access(path, F_OK) == 0) {
1603 			sccs_dir_path = path;
1604 			done = 1;
1605 		  } else {
1606 			(void) sprintf(path, "%s/source", pwent->pw_dir);
1607 			if (access(path, F_OK) == 0) {
1608 				sccs_dir_path = path;
1609 				done = 1;
1610 			}
1611 		     }
1612 		}
1613 		if (!done) {
1614 		    if (getcwd(cwdpath, MAXPATHLEN - 1 )) {
1615 
1616 		       (void) sprintf(path, "%s/%s", cwdpath,sccs_dir_path);
1617 		       if (access(path, F_OK) == 0) {
1618 				sccs_dir_path = path;
1619 				done = 1;
1620 		        } else {
1621 				fatal(gettext("Bogus PROJECTDIR '%s'"), sccs_dir_path);
1622 		        }
1623 		    }
1624 		}
1625 	   }
1626 	}
1627 }
1628 
1629 char *
make_install_prefix(void)1630 make_install_prefix(void)
1631 {
1632 	int ret;
1633 	char origin[PATH_MAX];
1634 	char *dir;
1635 
1636 	if ((ret = readlink("/proc/self/path/a.out", origin,
1637 	    PATH_MAX - 1)) < 0)
1638 		fatal("failed to read origin from /proc\n");
1639 
1640 
1641 	origin[ret] = '\0';
1642 	return strdup(dirname(origin));
1643 }
1644 
1645 static char *
add_to_env(const char * var,const char * value,const char * fallback)1646 add_to_env(const char *var, const char *value, const char *fallback)
1647 {
1648 	const char *oldpath;
1649 	char *newpath;
1650 
1651 	oldpath = getenv(var);
1652 	if (oldpath == NULL) {
1653 		if (value != NULL) {
1654 			asprintf(&newpath, "%s=%s",
1655 			    var, value);
1656 		} else {
1657 			asprintf(&newpath, "%s=%s",
1658 			    var, fallback);
1659 		}
1660 	} else {
1661 		if (value != NULL) {
1662 			asprintf(&newpath, "%s=%s:%s",
1663 			    var, oldpath, value);
1664 		} else {
1665 			asprintf(&newpath, "%s=%s:%s",
1666 			    var, oldpath, fallback);
1667 		}
1668 	}
1669 
1670 	return (newpath);
1671 }
1672 
1673 /*
1674  *	set_sgs_support()
1675  *
1676  *	Add the libmakestate.so.1 lib to the env var SGS_SUPPORT
1677  *	  if it's not already in there.
1678  *	The SGS_SUPPORT env var and libmakestate.so.1 is used by
1679  *	  the linker ld to report .make.state info back to make.
1680  *
1681  * In the new world we always will set the 32-bit and 64-bit versions of this
1682  * variable explicitly so that we can take into account the correct isa and our
1683  * prefix. So say that the prefix was /opt/local. Then we would want to search
1684  * /opt/local/lib/libmakestate.so.1:libmakestate.so.1. We still want to search
1685  * the original location just as a safety measure.
1686  */
1687 static void
set_sgs_support()1688 set_sgs_support()
1689 {
1690 	int		len;
1691 	char		*newpath, *newpath64;
1692 	char		*lib32, *lib64;
1693 	static char	*prev_path, *prev_path64;
1694 	char		*origin = make_install_prefix();
1695 	struct stat st;
1696 
1697 	asprintf(&lib32, "%s/%s/%s", origin, "../lib",
1698 	    LD_SUPPORT_MAKE_LIB);
1699 
1700 	if (stat(lib32, &st) != 0) {
1701 		free(lib32);
1702 		// Try the tools path
1703 		asprintf(&lib32, "%s/%s/%s/%s", origin, "../../lib/",
1704 		    LD_SUPPORT_MAKE_ARCH, LD_SUPPORT_MAKE_LIB);
1705 
1706 		if (stat(lib32, &st) != 0) {
1707 			free(lib32);
1708 			lib32 = NULL;
1709 		}
1710 	}
1711 
1712 	asprintf(&lib64, "%s/%s/64/%s", origin, "../lib",
1713 	    LD_SUPPORT_MAKE_LIB);
1714 
1715 	if (stat(lib64, &st) != 0) {
1716 		free(lib64);
1717 		// Try the tools path
1718 		asprintf(&lib64, "%s/%s/%s/64/%s", origin, "../../lib/",
1719 		    LD_SUPPORT_MAKE_ARCH, LD_SUPPORT_MAKE_LIB);
1720 
1721 		if (stat(lib64, &st) != 0) {
1722 			free(lib64);
1723 			lib64 = NULL;
1724 		}
1725 	}
1726 
1727 	newpath = add_to_env(LD_SUPPORT_ENV_VAR_32, lib32, LD_SUPPORT_MAKE_LIB);
1728 	newpath64 = add_to_env(LD_SUPPORT_ENV_VAR_64, lib64, LD_SUPPORT_MAKE_LIB);
1729 
1730 	putenv(newpath);
1731 	if (prev_path) {
1732 		free(prev_path);
1733 	}
1734 	prev_path = newpath;
1735 
1736 	putenv(newpath64);
1737 	if (prev_path64) {
1738 		free(prev_path64);
1739 	}
1740 	prev_path64 = newpath64;
1741 	free(lib32);
1742 	free(lib64);
1743 	free(origin);
1744 }
1745 
1746 /*
1747  *	read_files_and_state(argc, argv)
1748  *
1749  *	Read the makefiles we care about and the environment
1750  *	Also read the = style command line options
1751  *
1752  *	Parameters:
1753  *		argc		You know what this is
1754  *		argv		You know what this is
1755  *
1756  *	Static variables used:
1757  *		env_wins	make -e, determines if env vars are RO
1758  *		ignore_default_mk make -r, determines if make.rules is read
1759  *		not_auto_depen	dwight
1760  *
1761  *	Global variables used:
1762  *		default_target_to_build	Set to first proper target from file
1763  *		do_not_exec_rule Set to false when makfile is made
1764  *		dot		The Name ".", used to read current dir
1765  *		empty_name	The Name "", use as macro value
1766  *		keep_state	Set if KEEP_STATE is in environment
1767  *		make_state	The Name ".make.state", used to read file
1768  *		makefile_type	Set to type of file being read
1769  *		makeflags	The Name "MAKEFLAGS", used to set macro value
1770  *		not_auto	dwight
1771  *		read_trace_level Checked to se if the reader should trace
1772  *		report_dependencies If -P is on we do not read .make.state
1773  *		trace_reader	Set if reader should trace
1774  *		virtual_root	The Name "VIRTUAL_ROOT", used to check value
1775  */
1776 static void
read_files_and_state(int argc,char ** argv)1777 read_files_and_state(int argc, char **argv)
1778 {
1779 	wchar_t			buffer[1000];
1780 	wchar_t			buffer_posix[1000];
1781 	char		ch;
1782 	char		*cp;
1783 	Property		def_make_macro = NULL;
1784 	Name			def_make_name;
1785 	Name			default_makefile;
1786 	String_rec		dest;
1787 	wchar_t			destbuffer[STRING_BUFFER_LENGTH];
1788 	int		i;
1789 	int		j;
1790 	Name			keep_state_name;
1791 	int			length;
1792 	Name			Makefile;
1793 	Property	macro;
1794 	struct stat		make_state_stat;
1795 	Name			makefile_name;
1796         int		makefile_next = 0;
1797 	Boolean	makefile_read = false;
1798 	String_rec		makeflags_string;
1799 	String_rec		makeflags_string_posix;
1800 	String_rec *		makeflags_string_current;
1801 	Name			makeflags_value_saved;
1802 	Name		name;
1803 	Name			new_make_value;
1804 	Boolean			save_do_not_exec_rule;
1805 	static wchar_t		state_file_str;
1806 	static char		state_file_str_mb[MAXPATHLEN];
1807 	static struct _Name	state_filename;
1808 	Boolean			temp;
1809 	char			tmp_char;
1810 	wchar_t			*tmp_wcs_buffer;
1811 	Name		value;
1812 	ASCII_Dyn_Array		makeflags_and_macro;
1813 	Boolean			is_xpg4;
1814 
1815 /*
1816  *	Remember current mode. It may be changed after reading makefile
1817  *	and we will have to correct MAKEFLAGS variable.
1818  */
1819 	is_xpg4 = posix;
1820 
1821 	MBSTOWCS(wcs_buffer, "KEEP_STATE");
1822 	keep_state_name = GETNAME(wcs_buffer, FIND_LENGTH);
1823 	MBSTOWCS(wcs_buffer, "Makefile");
1824 	Makefile = GETNAME(wcs_buffer, FIND_LENGTH);
1825 	MBSTOWCS(wcs_buffer, "makefile");
1826 	makefile_name = GETNAME(wcs_buffer, FIND_LENGTH);
1827 
1828 /*
1829  *	initialize global dependency entry for .NOT_AUTO
1830  */
1831 	not_auto_depen->next = NULL;
1832 	not_auto_depen->name = not_auto;
1833 	not_auto_depen->automatic = not_auto_depen->stale = false;
1834 
1835 /*
1836  *	Read internal definitions and rules.
1837  */
1838 	if (read_trace_level > 1) {
1839 		trace_reader = true;
1840 	}
1841 	if (!ignore_default_mk) {
1842 		if (svr4) {
1843 			MBSTOWCS(wcs_buffer, "svr4.make.rules");
1844 			default_makefile = GETNAME(wcs_buffer, FIND_LENGTH);
1845 		} else {
1846 			MBSTOWCS(wcs_buffer, "make.rules");
1847 			default_makefile = GETNAME(wcs_buffer, FIND_LENGTH);
1848 		}
1849 		default_makefile->stat.is_file = true;
1850 
1851 		(void) read_makefile(default_makefile,
1852 				     true,
1853 				     false,
1854 				     true);
1855 	}
1856 
1857 	/*
1858 	 * If the user did not redefine the MAKE macro in the
1859 	 * default makefile (make.rules), then we'd like to
1860 	 * change the macro value of MAKE to be some form
1861 	 * of argv[0] for recursive MAKE builds.
1862 	 */
1863 	MBSTOWCS(wcs_buffer, "MAKE");
1864 	def_make_name = GETNAME(wcs_buffer, wcslen(wcs_buffer));
1865 	def_make_macro = get_prop(def_make_name->prop, macro_prop);
1866 	if ((def_make_macro != NULL) &&
1867 	    (IS_EQUAL(def_make_macro->body.macro.value->string_mb,
1868 	              "make"))) {
1869 		MBSTOWCS(wcs_buffer, argv_zero_string);
1870 		new_make_value = GETNAME(wcs_buffer, wcslen(wcs_buffer));
1871 		(void) SETVAR(def_make_name,
1872 		              new_make_value,
1873 		              false);
1874 	}
1875 
1876 	default_target_to_build = NULL;
1877 	trace_reader = false;
1878 
1879 /*
1880  *	Read environment args. Let file args which follow override unless
1881  *	-e option seen. If -e option is not mentioned.
1882  */
1883 	read_environment(env_wins);
1884 	if (getvar(virtual_root)->hash.length == 0) {
1885 		maybe_append_prop(virtual_root, macro_prop)
1886 		  ->body.macro.exported = true;
1887 		MBSTOWCS(wcs_buffer, "/");
1888 		(void) SETVAR(virtual_root,
1889 			      GETNAME(wcs_buffer, FIND_LENGTH),
1890 			      false);
1891 	}
1892 
1893 /*
1894  * We now scan mf_argv and argv to see if we need to set
1895  * any of the DMake-added options/variables in MAKEFLAGS.
1896  */
1897 
1898 	makeflags_and_macro.start = 0;
1899 	makeflags_and_macro.size = 0;
1900 	enter_argv_values(mf_argc, mf_argv, &makeflags_and_macro);
1901 	enter_argv_values(argc, argv, &makeflags_and_macro);
1902 
1903 /*
1904  *	Set MFLAGS and MAKEFLAGS
1905  *
1906  *	Before reading makefile we do not know exactly which mode
1907  *	(posix or not) is used. So prepare two MAKEFLAGS strings
1908  *	for both posix and solaris modes because they are different.
1909  *
1910  *	Note: cw depends on short flags with no arguments appearing
1911  *	first in MAKEFLAGS. If this behavior changes, cw will need to
1912  *	be updated.
1913  */
1914 	INIT_STRING_FROM_STACK(makeflags_string, buffer);
1915 	INIT_STRING_FROM_STACK(makeflags_string_posix, buffer_posix);
1916 	append_char((int) hyphen_char, &makeflags_string);
1917 	append_char((int) hyphen_char, &makeflags_string_posix);
1918 
1919 	switch (read_trace_level) {
1920 	case 2:
1921 		append_char('D', &makeflags_string);
1922 		append_char('D', &makeflags_string_posix);
1923 		/* FALLTHROUGH */
1924 	case 1:
1925 		append_char('D', &makeflags_string);
1926 		append_char('D', &makeflags_string_posix);
1927 	}
1928 	switch (debug_level) {
1929 	case 2:
1930 		append_char('d', &makeflags_string);
1931 		append_char('d', &makeflags_string_posix);
1932 		/* FALLTHROUGH */
1933 	case 1:
1934 		append_char('d', &makeflags_string);
1935 		append_char('d', &makeflags_string_posix);
1936 	}
1937 	if (env_wins) {
1938 		append_char('e', &makeflags_string);
1939 		append_char('e', &makeflags_string_posix);
1940 	}
1941 	if (ignore_errors_all) {
1942 		append_char('i', &makeflags_string);
1943 		append_char('i', &makeflags_string_posix);
1944 	}
1945 	if (continue_after_error) {
1946 		if (stop_after_error_ever_seen) {
1947 			append_char('S', &makeflags_string_posix);
1948 			append_char((int) space_char, &makeflags_string_posix);
1949 			append_char((int) hyphen_char, &makeflags_string_posix);
1950 		}
1951 		append_char('k', &makeflags_string);
1952 		append_char('k', &makeflags_string_posix);
1953 	} else {
1954 		if (stop_after_error_ever_seen
1955 		    && continue_after_error_ever_seen) {
1956 			append_char('k', &makeflags_string_posix);
1957 			append_char((int) space_char, &makeflags_string_posix);
1958 			append_char((int) hyphen_char, &makeflags_string_posix);
1959 			append_char('S', &makeflags_string_posix);
1960 		}
1961 	}
1962 	if (do_not_exec_rule) {
1963 		append_char('n', &makeflags_string);
1964 		append_char('n', &makeflags_string_posix);
1965 	}
1966 	switch (report_dependencies_level) {
1967 	case 4:
1968 		append_char('P', &makeflags_string);
1969 		append_char('P', &makeflags_string_posix);
1970 		/* FALLTHROUGH */
1971 	case 3:
1972 		append_char('P', &makeflags_string);
1973 		append_char('P', &makeflags_string_posix);
1974 		/* FALLTHROUGH */
1975 	case 2:
1976 		append_char('P', &makeflags_string);
1977 		append_char('P', &makeflags_string_posix);
1978 		/* FALLTHROUGH */
1979 	case 1:
1980 		append_char('P', &makeflags_string);
1981 		append_char('P', &makeflags_string_posix);
1982 	}
1983 	if (trace_status) {
1984 		append_char('p', &makeflags_string);
1985 		append_char('p', &makeflags_string_posix);
1986 	}
1987 	if (quest) {
1988 		append_char('q', &makeflags_string);
1989 		append_char('q', &makeflags_string_posix);
1990 	}
1991 	if (silent_all) {
1992 		append_char('s', &makeflags_string);
1993 		append_char('s', &makeflags_string_posix);
1994 	}
1995 	if (touch) {
1996 		append_char('t', &makeflags_string);
1997 		append_char('t', &makeflags_string_posix);
1998 	}
1999 	if (build_unconditional) {
2000 		append_char('u', &makeflags_string);
2001 		append_char('u', &makeflags_string_posix);
2002 	}
2003 	if (report_cwd) {
2004 		append_char('w', &makeflags_string);
2005 		append_char('w', &makeflags_string_posix);
2006 	}
2007 	/* -c dmake_rcfile */
2008 	if (dmake_rcfile_specified) {
2009 		MBSTOWCS(wcs_buffer, "DMAKE_RCFILE");
2010 		dmake_rcfile = GETNAME(wcs_buffer, FIND_LENGTH);
2011 		append_makeflags_string(dmake_rcfile, &makeflags_string);
2012 		append_makeflags_string(dmake_rcfile, &makeflags_string_posix);
2013 	}
2014 	/* -g dmake_group */
2015 	if (dmake_group_specified) {
2016 		MBSTOWCS(wcs_buffer, "DMAKE_GROUP");
2017 		dmake_group = GETNAME(wcs_buffer, FIND_LENGTH);
2018 		append_makeflags_string(dmake_group, &makeflags_string);
2019 		append_makeflags_string(dmake_group, &makeflags_string_posix);
2020 	}
2021 	/* -j dmake_max_jobs */
2022 	if (dmake_max_jobs_specified) {
2023 		MBSTOWCS(wcs_buffer, "DMAKE_MAX_JOBS");
2024 		dmake_max_jobs = GETNAME(wcs_buffer, FIND_LENGTH);
2025 		append_makeflags_string(dmake_max_jobs, &makeflags_string);
2026 		append_makeflags_string(dmake_max_jobs, &makeflags_string_posix);
2027 	}
2028 	/* -m dmake_mode */
2029 	if (dmake_mode_specified) {
2030 		MBSTOWCS(wcs_buffer, "DMAKE_MODE");
2031 		dmake_mode = GETNAME(wcs_buffer, FIND_LENGTH);
2032 		append_makeflags_string(dmake_mode, &makeflags_string);
2033 		append_makeflags_string(dmake_mode, &makeflags_string_posix);
2034 	}
2035 	/* -x dmake_compat_mode */
2036 //	if (dmake_compat_mode_specified) {
2037 //		MBSTOWCS(wcs_buffer, "SUN_MAKE_COMPAT_MODE");
2038 //		dmake_compat_mode = GETNAME(wcs_buffer, FIND_LENGTH);
2039 //		append_makeflags_string(dmake_compat_mode, &makeflags_string);
2040 //		append_makeflags_string(dmake_compat_mode, &makeflags_string_posix);
2041 //	}
2042 	/* -x dmake_output_mode */
2043 	if (dmake_output_mode_specified) {
2044 		MBSTOWCS(wcs_buffer, "DMAKE_OUTPUT_MODE");
2045 		dmake_output_mode = GETNAME(wcs_buffer, FIND_LENGTH);
2046 		append_makeflags_string(dmake_output_mode, &makeflags_string);
2047 		append_makeflags_string(dmake_output_mode, &makeflags_string_posix);
2048 	}
2049 	/* -o dmake_odir */
2050 	if (dmake_odir_specified) {
2051 		MBSTOWCS(wcs_buffer, "DMAKE_ODIR");
2052 		dmake_odir = GETNAME(wcs_buffer, FIND_LENGTH);
2053 		append_makeflags_string(dmake_odir, &makeflags_string);
2054 		append_makeflags_string(dmake_odir, &makeflags_string_posix);
2055 	}
2056 	/* -M pmake_machinesfile */
2057 	if (pmake_machinesfile_specified) {
2058 		MBSTOWCS(wcs_buffer, "PMAKE_MACHINESFILE");
2059 		pmake_machinesfile = GETNAME(wcs_buffer, FIND_LENGTH);
2060 		append_makeflags_string(pmake_machinesfile, &makeflags_string);
2061 		append_makeflags_string(pmake_machinesfile, &makeflags_string_posix);
2062 	}
2063 	/* -R */
2064 	if (pmake_cap_r_specified) {
2065 		append_char((int) space_char, &makeflags_string);
2066 		append_char((int) hyphen_char, &makeflags_string);
2067 		append_char('R', &makeflags_string);
2068 		append_char((int) space_char, &makeflags_string_posix);
2069 		append_char((int) hyphen_char, &makeflags_string_posix);
2070 		append_char('R', &makeflags_string_posix);
2071 	}
2072 
2073 /*
2074  *	Make sure MAKEFLAGS is exported
2075  */
2076 	maybe_append_prop(makeflags, macro_prop)->
2077 	  body.macro.exported = true;
2078 
2079 	if (makeflags_string.buffer.start[1] != (int) nul_char) {
2080 		if (makeflags_string.buffer.start[1] != (int) space_char) {
2081 			MBSTOWCS(wcs_buffer, "MFLAGS");
2082 			(void) SETVAR(GETNAME(wcs_buffer, FIND_LENGTH),
2083 				      GETNAME(makeflags_string.buffer.start,
2084 					      FIND_LENGTH),
2085 				      false);
2086 		} else {
2087 			MBSTOWCS(wcs_buffer, "MFLAGS");
2088 			(void) SETVAR(GETNAME(wcs_buffer, FIND_LENGTH),
2089 				      GETNAME(makeflags_string.buffer.start + 2,
2090 					      FIND_LENGTH),
2091 				      false);
2092 		}
2093 	}
2094 
2095 /*
2096  *	Add command line macro to POSIX makeflags_string
2097  */
2098 	if (makeflags_and_macro.start) {
2099 		tmp_char = (char) space_char;
2100 		cp = makeflags_and_macro.start;
2101 		do {
2102 			append_char(tmp_char, &makeflags_string_posix);
2103 		} while ( tmp_char = *cp++ );
2104 		retmem_mb(makeflags_and_macro.start);
2105 	}
2106 
2107 /*
2108  *	Now set the value of MAKEFLAGS macro in accordance
2109  *	with current mode.
2110  */
2111 	macro = maybe_append_prop(makeflags, macro_prop);
2112 	temp = (Boolean) macro->body.macro.read_only;
2113 	macro->body.macro.read_only = false;
2114 	if(posix || gnu_style) {
2115 		makeflags_string_current = &makeflags_string_posix;
2116 	} else {
2117 		makeflags_string_current = &makeflags_string;
2118 	}
2119 	if (makeflags_string_current->buffer.start[1] == (int) nul_char) {
2120 		makeflags_value_saved =
2121 			GETNAME( makeflags_string_current->buffer.start + 1
2122 			       , FIND_LENGTH
2123 			       );
2124 	} else {
2125 		if (makeflags_string_current->buffer.start[1] != (int) space_char) {
2126 			makeflags_value_saved =
2127 				GETNAME( makeflags_string_current->buffer.start
2128 				       , FIND_LENGTH
2129 				       );
2130 		} else {
2131 			makeflags_value_saved =
2132 				GETNAME( makeflags_string_current->buffer.start + 2
2133 				       , FIND_LENGTH
2134 				       );
2135 		}
2136 	}
2137 	(void) SETVAR( makeflags
2138 	             , makeflags_value_saved
2139 	             , false
2140 	             );
2141 	macro->body.macro.read_only = temp;
2142 
2143 /*
2144  *	Read command line "-f" arguments and ignore -c, g, j, K, M, m, O and o args.
2145  */
2146 	save_do_not_exec_rule = do_not_exec_rule;
2147 	do_not_exec_rule = false;
2148 	if (read_trace_level > 0) {
2149 		trace_reader = true;
2150 	}
2151 
2152 	for (i = 1; i < argc; i++) {
2153 		if (argv[i] &&
2154 		    (argv[i][0] == (int) hyphen_char) &&
2155 		    (argv[i][1] == 'f') &&
2156 		    (argv[i][2] == (int) nul_char)) {
2157 			argv[i] = NULL;		/* Remove -f */
2158 			if (i >= argc - 1) {
2159 				fatal(gettext("No filename argument after -f flag"));
2160 			}
2161 			MBSTOWCS(wcs_buffer, argv[++i]);
2162 			primary_makefile = GETNAME(wcs_buffer, FIND_LENGTH);
2163 			(void) read_makefile(primary_makefile, true, true, true);
2164 			argv[i] = NULL;		/* Remove filename */
2165 			makefile_read = true;
2166 		} else if (argv[i] &&
2167 			   (argv[i][0] == (int) hyphen_char) &&
2168 			   (argv[i][1] == 'c' ||
2169 			    argv[i][1] == 'g' ||
2170 			    argv[i][1] == 'j' ||
2171 			    argv[i][1] == 'K' ||
2172 			    argv[i][1] == 'M' ||
2173 			    argv[i][1] == 'm' ||
2174 			    argv[i][1] == 'O' ||
2175 			    argv[i][1] == 'o') &&
2176 			   (argv[i][2] == (int) nul_char)) {
2177 			argv[i] = NULL;
2178 			argv[++i] = NULL;
2179 		}
2180 	}
2181 
2182 /*
2183  *	If no command line "-f" args then look for "makefile", and then for
2184  *	"Makefile" if "makefile" isn't found.
2185  */
2186 	if (!makefile_read) {
2187 		(void) read_dir(dot,
2188 				(wchar_t *) NULL,
2189 				(Property) NULL,
2190 				(wchar_t *) NULL);
2191 	    if (!posix) {
2192 		if (makefile_name->stat.is_file) {
2193 			if (Makefile->stat.is_file) {
2194 				warning(gettext("Both `makefile' and `Makefile' exist"));
2195 			}
2196 			primary_makefile = makefile_name;
2197 			makefile_read = read_makefile(makefile_name,
2198 						      false,
2199 						      false,
2200 						      true);
2201 		}
2202 		if (!makefile_read &&
2203 		    Makefile->stat.is_file) {
2204 			primary_makefile = Makefile;
2205 			makefile_read = read_makefile(Makefile,
2206 						      false,
2207 						      false,
2208 						      true);
2209 		}
2210 	    } else {
2211 
2212 		enum sccs_stat save_m_has_sccs = NO_SCCS;
2213 		enum sccs_stat save_M_has_sccs = NO_SCCS;
2214 
2215 		if (makefile_name->stat.is_file) {
2216 			if (Makefile->stat.is_file) {
2217 				warning(gettext("Both `makefile' and `Makefile' exist"));
2218 			}
2219 		}
2220 		if (makefile_name->stat.is_file) {
2221 			if (makefile_name->stat.has_sccs == NO_SCCS) {
2222 			   primary_makefile = makefile_name;
2223 			   makefile_read = read_makefile(makefile_name,
2224 						      false,
2225 						      false,
2226 						      true);
2227 			} else {
2228 			  save_m_has_sccs = makefile_name->stat.has_sccs;
2229 			  makefile_name->stat.has_sccs = NO_SCCS;
2230 			  primary_makefile = makefile_name;
2231 			  makefile_read = read_makefile(makefile_name,
2232 						      false,
2233 						      false,
2234 						      true);
2235 			}
2236 		}
2237 		if (!makefile_read &&
2238 		    Makefile->stat.is_file) {
2239 			if (Makefile->stat.has_sccs == NO_SCCS) {
2240 			   primary_makefile = Makefile;
2241 			   makefile_read = read_makefile(Makefile,
2242 						      false,
2243 						      false,
2244 						      true);
2245 			} else {
2246 			  save_M_has_sccs = Makefile->stat.has_sccs;
2247 			  Makefile->stat.has_sccs = NO_SCCS;
2248 			  primary_makefile = Makefile;
2249 			  makefile_read = read_makefile(Makefile,
2250 						      false,
2251 						      false,
2252 						      true);
2253 			}
2254 		}
2255 		if (!makefile_read &&
2256 		        makefile_name->stat.is_file) {
2257 			   makefile_name->stat.has_sccs = save_m_has_sccs;
2258 			   primary_makefile = makefile_name;
2259 			   makefile_read = read_makefile(makefile_name,
2260 						      false,
2261 						      false,
2262 						      true);
2263 		}
2264 		if (!makefile_read &&
2265 		    Makefile->stat.is_file) {
2266 			   Makefile->stat.has_sccs = save_M_has_sccs;
2267 			   primary_makefile = Makefile;
2268 			   makefile_read = read_makefile(Makefile,
2269 						      false,
2270 						      false,
2271 						      true);
2272 		}
2273 	    }
2274 	}
2275 	do_not_exec_rule = save_do_not_exec_rule;
2276 	allrules_read = makefile_read;
2277 	trace_reader = false;
2278 
2279 /*
2280  *	Now get current value of MAKEFLAGS and compare it with
2281  *	the saved value we set before reading makefile.
2282  *	If they are different then MAKEFLAGS is subsequently set by
2283  *	makefile, just leave it there. Otherwise, if make mode
2284  *	is changed by using .POSIX target in makefile we need
2285  *	to correct MAKEFLAGS value.
2286  */
2287 	Name mf_val = getvar(makeflags);
2288 	if( (posix != is_xpg4)
2289 	 && (!strcmp(mf_val->string_mb, makeflags_value_saved->string_mb)))
2290 	{
2291 		if (makeflags_string_posix.buffer.start[1] == (int) nul_char) {
2292 			(void) SETVAR(makeflags,
2293 				      GETNAME(makeflags_string_posix.buffer.start + 1,
2294 					      FIND_LENGTH),
2295 				      false);
2296 		} else {
2297 			if (makeflags_string_posix.buffer.start[1] != (int) space_char) {
2298 				(void) SETVAR(makeflags,
2299 					      GETNAME(makeflags_string_posix.buffer.start,
2300 						      FIND_LENGTH),
2301 					      false);
2302 			} else {
2303 				(void) SETVAR(makeflags,
2304 					      GETNAME(makeflags_string_posix.buffer.start + 2,
2305 						      FIND_LENGTH),
2306 					      false);
2307 			}
2308 		}
2309 	}
2310 
2311 	if (makeflags_string.free_after_use) {
2312 		retmem(makeflags_string.buffer.start);
2313 	}
2314 	if (makeflags_string_posix.free_after_use) {
2315 		retmem(makeflags_string_posix.buffer.start);
2316 	}
2317 	makeflags_string.buffer.start = NULL;
2318 	makeflags_string_posix.buffer.start = NULL;
2319 
2320 	if (posix) {
2321 		/*
2322 		 * If the user did not redefine the ARFLAGS macro in the
2323 		 * default makefile (make.rules), then we'd like to
2324 		 * change the macro value of ARFLAGS to be in accordance
2325 		 * with "POSIX" requirements.
2326 		 */
2327 		MBSTOWCS(wcs_buffer, "ARFLAGS");
2328 		name = GETNAME(wcs_buffer, wcslen(wcs_buffer));
2329 		macro = get_prop(name->prop, macro_prop);
2330 		if ((macro != NULL) && /* Maybe (macro == NULL) || ? */
2331 		    (IS_EQUAL(macro->body.macro.value->string_mb,
2332 		              "rv"))) {
2333 			MBSTOWCS(wcs_buffer, "-rv");
2334 			value = GETNAME(wcs_buffer, wcslen(wcs_buffer));
2335 			(void) SETVAR(name,
2336 			              value,
2337 			              false);
2338 		}
2339 	}
2340 
2341 	if (!posix && !svr4) {
2342 		set_sgs_support();
2343 	}
2344 
2345 
2346 /*
2347  *	Make sure KEEP_STATE is in the environment if KEEP_STATE is on.
2348  */
2349 	macro = get_prop(keep_state_name->prop, macro_prop);
2350 	if ((macro != NULL) &&
2351 	    macro->body.macro.exported) {
2352 		keep_state = true;
2353 	}
2354 	if (keep_state) {
2355 		if (macro == NULL) {
2356 			macro = maybe_append_prop(keep_state_name,
2357 						  macro_prop);
2358 		}
2359 		macro->body.macro.exported = true;
2360 		(void) SETVAR(keep_state_name,
2361 			      empty_name,
2362 			      false);
2363 
2364 		/*
2365 		 *	Read state file
2366 		 */
2367 
2368 		/* Before we read state, let's make sure we have
2369 		** right state file.
2370 		*/
2371 		/* just in case macro references are used in make_state file
2372 		** name, we better expand them at this stage using expand_value.
2373 		*/
2374 		INIT_STRING_FROM_STACK(dest, destbuffer);
2375 		expand_value(make_state, &dest, false);
2376 
2377 		make_state = GETNAME(dest.buffer.start, FIND_LENGTH);
2378 
2379 		if(!stat(make_state->string_mb, &make_state_stat)) {
2380 		   if(!(make_state_stat.st_mode & S_IFREG) ) {
2381 			/* copy the make_state structure to the other
2382 			** and then let make_state point to the new
2383 			** one.
2384 			*/
2385 		      memcpy(&state_filename, make_state,sizeof(state_filename));
2386 		      state_filename.string_mb = state_file_str_mb;
2387 		/* Just a kludge to avoid two slashes back to back */
2388 		      if((make_state->hash.length == 1)&&
2389 			        (make_state->string_mb[0] == '/')) {
2390 			 make_state->hash.length = 0;
2391 			 make_state->string_mb[0] = '\0';
2392 		      }
2393 		      sprintf(state_file_str_mb,"%s%s",
2394 		       make_state->string_mb,"/.make.state");
2395 		      make_state = &state_filename;
2396 			/* adjust the length to reflect the appended string */
2397 		      make_state->hash.length += 12;
2398 		   }
2399 		} else { /* the file doesn't exist or no permission */
2400 		   char tmp_path[MAXPATHLEN];
2401 		   char *slashp;
2402 
2403 		   if (slashp = strrchr(make_state->string_mb, '/')) {
2404 		      strncpy(tmp_path, make_state->string_mb,
2405 				(slashp - make_state->string_mb));
2406 			tmp_path[slashp - make_state->string_mb]=0;
2407 		      if(strlen(tmp_path)) {
2408 		        if(stat(tmp_path, &make_state_stat)) {
2409 			  warning(gettext("directory %s for .KEEP_STATE_FILE does not exist"),tmp_path);
2410 		        }
2411 		        if (access(tmp_path, F_OK) != 0) {
2412 			  warning(gettext("can't access dir %s"),tmp_path);
2413 		        }
2414 		      }
2415 		   }
2416 		}
2417 		if (report_dependencies_level != 1) {
2418 			Makefile_type	makefile_type_temp = makefile_type;
2419 			makefile_type = reading_statefile;
2420 			if (read_trace_level > 1) {
2421 				trace_reader = true;
2422 			}
2423 			(void) read_simple_file(make_state,
2424 						false,
2425 						false,
2426 						false,
2427 						false,
2428 						false,
2429 						true);
2430 			trace_reader = false;
2431 			makefile_type = makefile_type_temp;
2432 		}
2433 	}
2434 }
2435 
2436 /*
2437  * Scan the argv for options and "=" type args and make them readonly.
2438  */
2439 static void
enter_argv_values(int argc,char * argv[],ASCII_Dyn_Array * makeflags_and_macro)2440 enter_argv_values(int argc, char *argv[], ASCII_Dyn_Array *makeflags_and_macro)
2441 {
2442 	char		*cp;
2443 	int		i;
2444 	int			length;
2445 	Name		name;
2446 	int			opt_separator = argc;
2447 	char			tmp_char;
2448 	wchar_t			*tmp_wcs_buffer;
2449 	Name		value;
2450 	Boolean			append = false;
2451 	Property		macro;
2452 	struct stat		statbuf;
2453 
2454 
2455 	/* Read argv options and "=" type args and make them readonly. */
2456 	makefile_type = reading_nothing;
2457 	for (i = 1; i < argc; ++i) {
2458 		append = false;
2459 		if (argv[i] == NULL) {
2460 			continue;
2461 		} else if (((argv[i][0] == '-') && (argv[i][1] == '-')) ||
2462 			   ((argv[i][0] == (int) ' ') &&
2463 			    (argv[i][1] == (int) '-') &&
2464 			    (argv[i][2] == (int) ' ') &&
2465 			    (argv[i][3] == (int) '-'))) {
2466 			argv[i] = NULL;
2467 			opt_separator = i;
2468 			continue;
2469 		} else if ((i < opt_separator) && (argv[i][0] == (int) hyphen_char)) {
2470 			switch (parse_command_option(argv[i][1])) {
2471 			case 1:	/* -f seen */
2472 				++i;
2473 				continue;
2474 			case 2:	/* -c seen */
2475 				if (argv[i+1] == NULL) {
2476 					fatal(gettext("No dmake rcfile argument after -c flag"));
2477 				}
2478 				MBSTOWCS(wcs_buffer, "DMAKE_RCFILE");
2479 				name = GETNAME(wcs_buffer, FIND_LENGTH);
2480 				break;
2481 			case 4:	/* -g seen */
2482 				if (argv[i+1] == NULL) {
2483 					fatal(gettext("No dmake group argument after -g flag"));
2484 				}
2485 				MBSTOWCS(wcs_buffer, "DMAKE_GROUP");
2486 				name = GETNAME(wcs_buffer, FIND_LENGTH);
2487 				break;
2488 			case 8:	/* -j seen */
2489 				if (argv[i+1] == NULL) {
2490 					fatal(gettext("No dmake max jobs argument after -j flag"));
2491 				}
2492 				MBSTOWCS(wcs_buffer, "DMAKE_MAX_JOBS");
2493 				name = GETNAME(wcs_buffer, FIND_LENGTH);
2494 				break;
2495 			case 16: /* -M seen */
2496 				if (argv[i+1] == NULL) {
2497 					fatal(gettext("No pmake machinesfile argument after -M flag"));
2498 				}
2499 				MBSTOWCS(wcs_buffer, "PMAKE_MACHINESFILE");
2500 				name = GETNAME(wcs_buffer, FIND_LENGTH);
2501 				break;
2502 			case 32: /* -m seen */
2503 				if (argv[i+1] == NULL) {
2504 					fatal(gettext("No dmake mode argument after -m flag"));
2505 				}
2506 				MBSTOWCS(wcs_buffer, "DMAKE_MODE");
2507 				name = GETNAME(wcs_buffer, FIND_LENGTH);
2508 				break;
2509 			case 256: /* -K seen */
2510 				if (argv[i+1] == NULL) {
2511 					fatal(gettext("No makestate filename argument after -K flag"));
2512 				}
2513 				MBSTOWCS(wcs_buffer, argv[i+1]);
2514 				make_state = GETNAME(wcs_buffer, FIND_LENGTH);
2515 				keep_state = true;
2516 				argv[i] = NULL;
2517 				argv[i+1] = NULL;
2518 				continue;
2519 			case 512:	/* -o seen */
2520 				if (argv[i+1] == NULL) {
2521 					fatal(gettext("No dmake output dir argument after -o flag"));
2522 				}
2523 				MBSTOWCS(wcs_buffer, "DMAKE_ODIR");
2524 				name = GETNAME(wcs_buffer, FIND_LENGTH);
2525 				break;
2526 			case 1024: /* -x seen */
2527 				if (argv[i+1] == NULL) {
2528 					fatal(gettext("No argument after -x flag"));
2529 				}
2530 				length = strlen( "SUN_MAKE_COMPAT_MODE=");
2531 				if (strncmp(argv[i+1], "SUN_MAKE_COMPAT_MODE=", length) == 0) {
2532 					argv[i+1] = &argv[i+1][length];
2533 					MBSTOWCS(wcs_buffer, "SUN_MAKE_COMPAT_MODE");
2534 					name = GETNAME(wcs_buffer, FIND_LENGTH);
2535 					dmake_compat_mode_specified = dmake_add_mode_specified;
2536 					break;
2537 				}
2538 				length = strlen( "DMAKE_OUTPUT_MODE=");
2539 				if (strncmp(argv[i+1], "DMAKE_OUTPUT_MODE=", length) == 0) {
2540 					argv[i+1] = &argv[i+1][length];
2541 					MBSTOWCS(wcs_buffer, "DMAKE_OUTPUT_MODE");
2542 					name = GETNAME(wcs_buffer, FIND_LENGTH);
2543 					dmake_output_mode_specified = dmake_add_mode_specified;
2544 				} else {
2545 					warning(gettext("Unknown argument `%s' after -x flag (ignored)"),
2546 					      argv[i+1]);
2547 					argv[i] = argv[i + 1] = NULL;
2548 					continue;
2549 				}
2550 				break;
2551 			case 2048: /* -C seen */
2552 				/*
2553 				 * The chdir() will have been performed
2554 				 * in read_command_options().
2555 				 * Just set DMAKE_CDIR here.
2556 				 */
2557 				if (argv[i + 1] == NULL) {
2558 					fatal(gettext(
2559 					    "No argument after -C flag"));
2560 				}
2561 				MBSTOWCS(wcs_buffer, "DMAKE_CDIR");
2562 				name = GETNAME(wcs_buffer, FIND_LENGTH);
2563 				break;
2564 			default: /* Shouldn't reach here */
2565 				argv[i] = NULL;
2566 				continue;
2567 			}
2568 			argv[i] = NULL;
2569 			if (i == (argc - 1)) {
2570 				break;
2571 			}
2572 			if ((length = strlen(argv[i+1])) >= MAXPATHLEN) {
2573 				tmp_wcs_buffer = ALLOC_WC(length + 1);
2574 				(void) mbstowcs(tmp_wcs_buffer, argv[i+1], length + 1);
2575 				value = GETNAME(tmp_wcs_buffer, FIND_LENGTH);
2576 				retmem(tmp_wcs_buffer);
2577 			} else {
2578 				MBSTOWCS(wcs_buffer, argv[i+1]);
2579 				value = GETNAME(wcs_buffer, FIND_LENGTH);
2580 			}
2581 			argv[i+1] = NULL;
2582 		} else if ((cp = strchr(argv[i], (int) equal_char)) != NULL) {
2583 /*
2584  * Combine all macro in dynamic array
2585  */
2586 			if(*(cp-1) == (int) plus_char)
2587 			{
2588 				if(isspace(*(cp-2))) {
2589 					append = true;
2590 					cp--;
2591 				}
2592 			}
2593 			if(!append)
2594 				append_or_replace_macro_in_dyn_array(makeflags_and_macro, argv[i]);
2595 
2596 			while (isspace(*(cp-1))) {
2597 				cp--;
2598 			}
2599 			tmp_char = *cp;
2600 			*cp = (int) nul_char;
2601 			MBSTOWCS(wcs_buffer, argv[i]);
2602 			*cp = tmp_char;
2603 			name = GETNAME(wcs_buffer, wcslen(wcs_buffer));
2604 			while (*cp != (int) equal_char) {
2605 				cp++;
2606 			}
2607 			cp++;
2608 			while (isspace(*cp) && (*cp != (int) nul_char)) {
2609 				cp++;
2610 			}
2611 			if ((length = strlen(cp)) >= MAXPATHLEN) {
2612 				tmp_wcs_buffer = ALLOC_WC(length + 1);
2613 				(void) mbstowcs(tmp_wcs_buffer, cp, length + 1);
2614 				value = GETNAME(tmp_wcs_buffer, FIND_LENGTH);
2615 				retmem(tmp_wcs_buffer);
2616 			} else {
2617 				MBSTOWCS(wcs_buffer, cp);
2618 				value = GETNAME(wcs_buffer, FIND_LENGTH);
2619 			}
2620 			argv[i] = NULL;
2621 		} else {
2622 			/* Illegal MAKEFLAGS argument */
2623 			continue;
2624 		}
2625 		if(append) {
2626 			setvar_append(name, value);
2627 			append = false;
2628 		} else {
2629 			macro = maybe_append_prop(name, macro_prop);
2630 			macro->body.macro.exported = true;
2631 			SETVAR(name, value, false)->body.macro.read_only = true;
2632 		}
2633 	}
2634 }
2635 
2636 /*
2637  * Append the DMake option and value to the MAKEFLAGS string.
2638  */
2639 static void
append_makeflags_string(Name name,String makeflags_string)2640 append_makeflags_string(Name name, String makeflags_string)
2641 {
2642 	const char	*option;
2643 
2644 	if (strcmp(name->string_mb, "DMAKE_GROUP") == 0) {
2645 		option = " -g ";
2646 	} else if (strcmp(name->string_mb, "DMAKE_MAX_JOBS") == 0) {
2647 		option = " -j ";
2648 	} else if (strcmp(name->string_mb, "DMAKE_MODE") == 0) {
2649 		option = " -m ";
2650 	} else if (strcmp(name->string_mb, "DMAKE_ODIR") == 0) {
2651 		option = " -o ";
2652 	} else if (strcmp(name->string_mb, "DMAKE_RCFILE") == 0) {
2653 		option = " -c ";
2654 	} else if (strcmp(name->string_mb, "PMAKE_MACHINESFILE") == 0) {
2655 		option = " -M ";
2656 	} else if (strcmp(name->string_mb, "DMAKE_OUTPUT_MODE") == 0) {
2657 		option = " -x DMAKE_OUTPUT_MODE=";
2658 	} else if (strcmp(name->string_mb, "SUN_MAKE_COMPAT_MODE") == 0) {
2659 		option = " -x SUN_MAKE_COMPAT_MODE=";
2660 	} else {
2661 		fatal(gettext("Internal error: name not recognized in append_makeflags_string()"));
2662 	}
2663 	Property prop = maybe_append_prop(name, macro_prop);
2664 	if( prop == 0 || prop->body.macro.value == 0 ||
2665 	    prop->body.macro.value->string_mb == 0 ) {
2666 		return;
2667 	}
2668 	char mbs_value[MAXPATHLEN + 100];
2669 	strcpy(mbs_value, option);
2670 	strcat(mbs_value, prop->body.macro.value->string_mb);
2671 	MBSTOWCS(wcs_buffer, mbs_value);
2672 	append_string(wcs_buffer, makeflags_string, FIND_LENGTH);
2673 }
2674 
2675 /*
2676  *	read_environment(read_only)
2677  *
2678  *	This routine reads the process environment when make starts and enters
2679  *	it as make macros. The environment variable SHELL is ignored.
2680  *
2681  *	Parameters:
2682  *		read_only	Should we make env vars read only?
2683  *
2684  *	Global variables used:
2685  *		report_pwd	Set if this make was started by other make
2686  */
2687 static void
read_environment(Boolean read_only)2688 read_environment(Boolean read_only)
2689 {
2690 	char		**environment;
2691 	int			length;
2692 	wchar_t			*tmp_wcs_buffer;
2693 	Boolean			alloced_tmp_wcs_buffer = false;
2694 	wchar_t	*name;
2695 	wchar_t	*value;
2696 	Name		macro;
2697 	Property		val;
2698 	Boolean			read_only_saved;
2699 
2700 	reading_environment = true;
2701 	environment = environ;
2702 	for (; *environment; environment++) {
2703 		read_only_saved = read_only;
2704 		if ((length = strlen(*environment)) >= MAXPATHLEN) {
2705 			tmp_wcs_buffer = ALLOC_WC(length + 1);
2706 			alloced_tmp_wcs_buffer = true;
2707 			(void) mbstowcs(tmp_wcs_buffer, *environment, length + 1);
2708 			name = tmp_wcs_buffer;
2709 		} else {
2710 			MBSTOWCS(wcs_buffer, *environment);
2711 			name = wcs_buffer;
2712 		}
2713 		value = (wchar_t *) wcschr(name, (int) equal_char);
2714 
2715 		/*
2716 		 * Looks like there's a bug in the system, but sometimes
2717 		 * you can get blank lines in *environment.
2718 		 */
2719 		if (!value) {
2720 			continue;
2721 		}
2722 		MBSTOWCS(wcs_buffer2, "SHELL=");
2723 		if (IS_WEQUALN(name, wcs_buffer2, wcslen(wcs_buffer2))) {
2724 			continue;
2725 		}
2726 		MBSTOWCS(wcs_buffer2, "MAKEFLAGS=");
2727 		if (IS_WEQUALN(name, wcs_buffer2, wcslen(wcs_buffer2))) {
2728 			report_pwd = true;
2729 			/*
2730 			 * In POSIX mode we do not want MAKEFLAGS to be readonly.
2731 			 * If the MAKEFLAGS macro is subsequently set by the makefile,
2732 			 * it replaces the MAKEFLAGS variable currently found in the
2733 			 * environment.
2734 			 * See Assertion 50 in section 6.2.5.3 of standard P1003.3.2/D8.
2735 			 */
2736 			if(posix) {
2737 				read_only_saved = false;
2738 			}
2739 		}
2740 
2741 		/*
2742 		 * We ignore SUNPRO_DEPENDENCIES. This environment variable is
2743 		 * set by make and read by cpp which then writes info to
2744 		 * .make.dependency.xxx.  When make is invoked by another make
2745 		 * (recursive make), we don't want to read this because then
2746 		 * the child make will end up writing to the parent
2747 		 * directory's .make.state and clobbering them.
2748 		 */
2749 		MBSTOWCS(wcs_buffer2, "SUNPRO_DEPENDENCIES");
2750 		if (IS_WEQUALN(name, wcs_buffer2, wcslen(wcs_buffer2))) {
2751 			continue;
2752 		}
2753 
2754 		macro = GETNAME(name, value - name);
2755 		maybe_append_prop(macro, macro_prop)->body.macro.exported =
2756 		  true;
2757 		if ((value == NULL) || ((value + 1)[0] == (int) nul_char)) {
2758 			val = setvar_daemon(macro,
2759 					    (Name) NULL,
2760 					    false, no_daemon, false, debug_level);
2761 		} else {
2762 			val = setvar_daemon(macro,
2763 					    GETNAME(value + 1, FIND_LENGTH),
2764 					    false, no_daemon, false, debug_level);
2765 		}
2766 		val->body.macro.read_only = read_only_saved;
2767 		if (alloced_tmp_wcs_buffer) {
2768 			retmem(tmp_wcs_buffer);
2769 			alloced_tmp_wcs_buffer = false;
2770 		}
2771 	}
2772 	reading_environment = false;
2773 }
2774 
2775 /*
2776  *	read_makefile(makefile, complain, must_exist, report_file)
2777  *
2778  *	Read one makefile and check the result
2779  *
2780  *	Return value:
2781  *				false is the read failed
2782  *
2783  *	Parameters:
2784  *		makefile	The file to read
2785  *		complain	Passed thru to read_simple_file()
2786  *		must_exist	Passed thru to read_simple_file()
2787  *		report_file	Passed thru to read_simple_file()
2788  *
2789  *	Global variables used:
2790  *		makefile_type	Set to indicate we are reading main file
2791  *		recursion_level	Initialized
2792  */
2793 static Boolean
read_makefile(Name makefile,Boolean complain,Boolean must_exist,Boolean report_file)2794 read_makefile(Name makefile, Boolean complain, Boolean must_exist, Boolean report_file)
2795 {
2796 	Boolean			b;
2797 
2798 	makefile_type = reading_makefile;
2799 	recursion_level = 0;
2800 	reading_dependencies = true;
2801 	b = read_simple_file(makefile, true, true, complain,
2802 			     must_exist, report_file, false);
2803 	reading_dependencies = false;
2804 	return b;
2805 }
2806 
2807 /*
2808  *	make_targets(argc, argv, parallel_flag)
2809  *
2810  *	Call doname on the specified targets
2811  *
2812  *	Parameters:
2813  *		argc		You know what this is
2814  *		argv		You know what this is
2815  *		parallel_flag	True if building in parallel
2816  *
2817  *	Global variables used:
2818  *		build_failed_seen Used to generated message after failed -k
2819  *		commands_done	Used to generate message "Up to date"
2820  *		default_target_to_build	First proper target in makefile
2821  *		init		The Name ".INIT", use to run command
2822  *		parallel	Global parallel building flag
2823  *		quest		make -q, suppresses messages
2824  *		recursion_level	Initialized, used for tracing
2825  *		report_dependencies make -P, regroves whole process
2826  */
2827 static void
make_targets(int argc,char ** argv,Boolean parallel_flag)2828 make_targets(int argc, char **argv, Boolean parallel_flag)
2829 {
2830 	int			i;
2831 	char			*cp;
2832 	Doname			result;
2833 	Boolean	target_to_make_found = false;
2834 
2835 	(void) doname(init, true, true);
2836 	recursion_level = 1;
2837 	parallel = parallel_flag;
2838 /*
2839  *	make remaining args
2840  */
2841 /*
2842 	if ((report_dependencies_level == 0) && parallel) {
2843  */
2844 	if (parallel) {
2845 		/*
2846 		 * If building targets in parallel, start all of the
2847 		 * remaining args to build in parallel.
2848 		 */
2849 		for (i = 1; i < argc; i++) {
2850 			if ((cp = argv[i]) != NULL) {
2851 				commands_done = false;
2852 				if ((cp[0] == (int) period_char) &&
2853 				    (cp[1] == (int) slash_char)) {
2854 					cp += 2;
2855 				}
2856 				 if((cp[0] == (int) ' ') &&
2857 				    (cp[1] == (int) '-') &&
2858 				    (cp[2] == (int) ' ') &&
2859 				    (cp[3] == (int) '-')) {
2860 			            argv[i] = NULL;
2861 					continue;
2862 				}
2863 				MBSTOWCS(wcs_buffer, cp);
2864 				//default_target_to_build = GETNAME(wcs_buffer,
2865 				//				  FIND_LENGTH);
2866 				default_target_to_build = normalize_name(wcs_buffer,
2867 								  wcslen(wcs_buffer));
2868 				if (default_target_to_build == wait_name) {
2869 					if (parallel_process_cnt > 0) {
2870 						finish_running();
2871 					}
2872 					continue;
2873 				}
2874 				top_level_target = get_wstring(default_target_to_build->string_mb);
2875 				/*
2876 				 * If we can't execute the current target in
2877 				 * parallel, hold off the target processing
2878 				 * to preserve the order of the targets as they appeared
2879 				 * in command line.
2880 				 */
2881 				if (!parallel_ok(default_target_to_build, false)
2882 						&& parallel_process_cnt > 0) {
2883 					finish_running();
2884 				}
2885 				result = doname_check(default_target_to_build,
2886 						      true,
2887 						      false,
2888 						      false);
2889 				gather_recursive_deps();
2890 				if (/* !commands_done && */
2891 				    (result == build_ok) &&
2892 				    !quest &&
2893 				    (report_dependencies_level == 0) /*  &&
2894 				    (exists(default_target_to_build) > file_doesnt_exist)  */) {
2895 					if (posix) {
2896 						if (!commands_done) {
2897 							(void) printf(gettext("`%s' is updated.\n"),
2898 								      default_target_to_build->string_mb);
2899 						} else {
2900 							if (no_action_was_taken) {
2901 								(void) printf(gettext("`%s': no action was taken.\n"),
2902 									      default_target_to_build->string_mb);
2903 							}
2904 						}
2905 					} else {
2906 						default_target_to_build->stat.time = file_no_time;
2907 						if (!commands_done &&
2908 						    (exists(default_target_to_build) > file_doesnt_exist)) {
2909 							(void) printf(gettext("`%s' is up to date.\n"),
2910 								      default_target_to_build->string_mb);
2911 						}
2912 					}
2913 				}
2914 			}
2915 		}
2916 		/* Now wait for all of the targets to finish running */
2917 		finish_running();
2918 		//		setjmp(jmpbuffer);
2919 
2920 	}
2921 	for (i = 1; i < argc; i++) {
2922 		if ((cp = argv[i]) != NULL) {
2923 			target_to_make_found = true;
2924 			if ((cp[0] == (int) period_char) &&
2925 			    (cp[1] == (int) slash_char)) {
2926 				cp += 2;
2927 			}
2928 				 if((cp[0] == (int) ' ') &&
2929 				    (cp[1] == (int) '-') &&
2930 				    (cp[2] == (int) ' ') &&
2931 				    (cp[3] == (int) '-')) {
2932 			            argv[i] = NULL;
2933 					continue;
2934 				}
2935 			MBSTOWCS(wcs_buffer, cp);
2936 			default_target_to_build = normalize_name(wcs_buffer, wcslen(wcs_buffer));
2937 			top_level_target = get_wstring(default_target_to_build->string_mb);
2938 			report_recursion(default_target_to_build);
2939 			commands_done = false;
2940 			if (parallel) {
2941 				result = (Doname) default_target_to_build->state;
2942 			} else {
2943 				result = doname_check(default_target_to_build,
2944 						      true,
2945 						      false,
2946 						      false);
2947 			}
2948 			gather_recursive_deps();
2949 			if (build_failed_seen) {
2950 				build_failed_ever_seen = true;
2951 				warning(gettext("Target `%s' not remade because of errors"),
2952 					default_target_to_build->string_mb);
2953 			}
2954 			build_failed_seen = false;
2955 			if (report_dependencies_level > 0) {
2956 				print_dependencies(default_target_to_build,
2957 						   get_prop(default_target_to_build->prop,
2958 							    line_prop));
2959 			}
2960 			default_target_to_build->stat.time =
2961 			  file_no_time;
2962 			if (default_target_to_build->colon_splits > 0) {
2963 				default_target_to_build->state =
2964 				  build_dont_know;
2965 			}
2966 			if (!parallel &&
2967 			    /* !commands_done && */
2968 			    (result == build_ok) &&
2969 			    !quest &&
2970 			    (report_dependencies_level == 0) /*  &&
2971 			    (exists(default_target_to_build) > file_doesnt_exist)  */) {
2972 				if (posix) {
2973 					if (!commands_done) {
2974 						(void) printf(gettext("`%s' is updated.\n"),
2975 							      default_target_to_build->string_mb);
2976 					} else {
2977 						if (no_action_was_taken) {
2978 							(void) printf(gettext("`%s': no action was taken.\n"),
2979 								      default_target_to_build->string_mb);
2980 						}
2981 					}
2982 				} else {
2983 					if (!commands_done &&
2984 					    (exists(default_target_to_build) > file_doesnt_exist)) {
2985 						(void) printf(gettext("`%s' is up to date.\n"),
2986 							      default_target_to_build->string_mb);
2987 					}
2988 				}
2989 			}
2990 		}
2991 	}
2992 
2993 /*
2994  *	If no file arguments have been encountered,
2995  *	make the first name encountered that doesnt start with a dot
2996  */
2997 	if (!target_to_make_found) {
2998 		if (default_target_to_build == NULL) {
2999 			fatal(gettext("No arguments to build"));
3000 		}
3001 		commands_done = false;
3002 		top_level_target = get_wstring(default_target_to_build->string_mb);
3003 		report_recursion(default_target_to_build);
3004 
3005 
3006 		if (getenv("SPRO_EXPAND_ERRORS")){
3007 			(void) printf("::(%s)\n",
3008 				      default_target_to_build->string_mb);
3009 		}
3010 
3011 
3012 		result = doname_parallel(default_target_to_build, true, false);
3013 		gather_recursive_deps();
3014 		if (build_failed_seen) {
3015 			build_failed_ever_seen = true;
3016 			warning(gettext("Target `%s' not remade because of errors"),
3017 				default_target_to_build->string_mb);
3018 		}
3019 		build_failed_seen = false;
3020 		if (report_dependencies_level > 0) {
3021 			print_dependencies(default_target_to_build,
3022 					   get_prop(default_target_to_build->
3023 						    prop,
3024 						    line_prop));
3025 		}
3026 		default_target_to_build->stat.time = file_no_time;
3027 		if (default_target_to_build->colon_splits > 0) {
3028 			default_target_to_build->state = build_dont_know;
3029 		}
3030 		if (/* !commands_done && */
3031 		    (result == build_ok) &&
3032 		    !quest &&
3033 		    (report_dependencies_level == 0) /*  &&
3034 		    (exists(default_target_to_build) > file_doesnt_exist)  */) {
3035 			if (posix) {
3036 				if (!commands_done) {
3037 					(void) printf(gettext("`%s' is updated.\n"),
3038 						      default_target_to_build->string_mb);
3039 				} else {
3040 					if (no_action_was_taken) {
3041 						(void) printf(gettext("`%s': no action was taken.\n"),
3042 							      default_target_to_build->string_mb);
3043 					}
3044 				}
3045 			} else {
3046 				if (!commands_done &&
3047 				    (exists(default_target_to_build) > file_doesnt_exist)) {
3048 					(void) printf(gettext("`%s' is up to date.\n"),
3049 						      default_target_to_build->string_mb);
3050 				}
3051 			}
3052 		}
3053 	}
3054 }
3055 
3056 /*
3057  *	report_recursion(target)
3058  *
3059  *	If this is a recursive make and the parent make has KEEP_STATE on
3060  *	this routine reports the dependency to the parent make
3061  *
3062  *	Parameters:
3063  *		target		Target to report
3064  *
3065  *	Global variables used:
3066  *		makefiles_used		List of makefiles read
3067  *		recursive_name		The Name ".RECURSIVE", printed
3068  *		report_dependency	dwight
3069  */
3070 static void
report_recursion(Name target)3071 report_recursion(Name target)
3072 {
3073 	FILE		*report_file = get_report_file();
3074 
3075 	if ((report_file == NULL) || (report_file == (FILE*)-1)) {
3076 		return;
3077 	}
3078 	if (primary_makefile == NULL) {
3079 		/*
3080 		 * This can happen when there is no makefile and
3081 		 * only implicit rules are being used.
3082 		 */
3083 		return;
3084 	}
3085 	(void) fprintf(report_file,
3086 		       "%s: %s ",
3087 		       get_target_being_reported_for(),
3088 		       recursive_name->string_mb);
3089 	report_dependency(get_current_path());
3090 	report_dependency(target->string_mb);
3091 	report_dependency(primary_makefile->string_mb);
3092 	(void) fprintf(report_file, "\n");
3093 }
3094 
3095 /* Next function "append_or_replace_macro_in_dyn_array" must be in "misc.cc". */
3096 /* NIKMOL */
3097 extern void
append_or_replace_macro_in_dyn_array(ASCII_Dyn_Array * Ar,char * macro)3098 append_or_replace_macro_in_dyn_array(ASCII_Dyn_Array *Ar, char *macro)
3099 {
3100 	char	*cp0;	/* work pointer in macro */
3101 	char	*cp1;	/* work pointer in array */
3102 	char	*cp2;	/* work pointer in array */
3103 	char	*cp3;	/* work pointer in array */
3104 	char	*name;	/* macro name */
3105 	char	*value;	/* macro value */
3106 	int	len_array;
3107 	int	len_macro;
3108 
3109 	char * esc_value = NULL;
3110 	int esc_len;
3111 
3112 	if (!(len_macro = strlen(macro))) return;
3113 	name = macro;
3114 	while (isspace(*(name))) {
3115 		name++;
3116 	}
3117 	if (!(value = strchr(name, (int) equal_char))) {
3118 		/* no '=' in macro */
3119 		goto ERROR_MACRO;
3120 	}
3121 	cp0 = value;
3122 	value++;
3123 	while (isspace(*(value))) {
3124 		value++;
3125 	}
3126 	while (isspace(*(cp0-1))) {
3127 		cp0--;
3128 	}
3129 	if (cp0 <= name) goto ERROR_MACRO; /* no name */
3130 	if (!(Ar->size)) goto ALLOC_ARRAY;
3131 	cp1 = Ar->start;
3132 
3133 LOOK_FOR_NAME:
3134 	if (!(cp1 = strchr(cp1, name[0]))) goto APPEND_MACRO;
3135 	if (!(cp2 = strchr(cp1, (int) equal_char))) goto APPEND_MACRO;
3136 	if (strncmp(cp1, name, (size_t)(cp0-name))) {
3137 		/* another name */
3138 		cp1++;
3139 		goto LOOK_FOR_NAME;
3140 	}
3141 	if (cp1 != Ar->start) {
3142 		if (!isspace(*(cp1-1))) {
3143 			/* another name */
3144 			cp1++;
3145 			goto LOOK_FOR_NAME;
3146 		}
3147 	}
3148 	for (cp3 = cp1 + (cp0-name); cp3 < cp2; cp3++) {
3149 		if (isspace(*cp3)) continue;
3150 		/* else: another name */
3151 		cp1++;
3152 		goto LOOK_FOR_NAME;
3153 	}
3154 	/* Look for the next macro name in array */
3155 	cp3 = cp2+1;
3156 	if (*cp3 != (int) doublequote_char) {
3157 		/* internal error */
3158 		goto ERROR_MACRO;
3159 	}
3160 	if (!(cp3 = strchr(cp3+1, (int) doublequote_char))) {
3161 		/* internal error */
3162 		goto ERROR_MACRO;
3163 	}
3164 	cp3++;
3165 	while (isspace(*cp3)) {
3166 		cp3++;
3167 	}
3168 
3169 	cp2 = cp1;  /* remove old macro */
3170 	if ((*cp3) && (cp3 < Ar->start + Ar->size)) {
3171 		for (; cp3 < Ar->start + Ar->size; cp3++) {
3172 			*cp2++ = *cp3;
3173 		}
3174 	}
3175 	for (; cp2 < Ar->start + Ar->size; cp2++) {
3176 		*cp2 = 0;
3177 	}
3178 	if (*cp1) {
3179 		/* check next name */
3180 		goto LOOK_FOR_NAME;
3181 	}
3182 	goto APPEND_MACRO;
3183 
3184 ALLOC_ARRAY:
3185 	if (Ar->size) {
3186 		cp1 = Ar->start;
3187 	} else {
3188 		cp1 = 0;
3189 	}
3190 	Ar->size += 128;
3191 	Ar->start = getmem(Ar->size);
3192 	for (len_array=0; len_array < Ar->size; len_array++) {
3193 		Ar->start[len_array] = 0;
3194 	}
3195 	if (cp1) {
3196 		strcpy(Ar->start, cp1);
3197 		retmem((wchar_t *) cp1);
3198 	}
3199 
3200 APPEND_MACRO:
3201 	len_array = strlen(Ar->start);
3202 	esc_value = (char*)malloc(strlen(value)*2 + 1);
3203 	quote_str(value, esc_value);
3204 	esc_len = strlen(esc_value) - strlen(value);
3205 	if (len_array + len_macro + esc_len + 5 >= Ar->size) goto  ALLOC_ARRAY;
3206 	strcat(Ar->start, " ");
3207 	strncat(Ar->start, name, cp0-name);
3208 	strcat(Ar->start, "=");
3209 	strncat(Ar->start, esc_value, strlen(esc_value));
3210 	free(esc_value);
3211 	return;
3212 ERROR_MACRO:
3213 	/* Macro without '=' or with invalid left/right part */
3214 	return;
3215 }
3216 
3217 static void
report_dir_enter_leave(Boolean entering)3218 report_dir_enter_leave(Boolean entering)
3219 {
3220 	char	rcwd[MAXPATHLEN];
3221 static	char *	mlev = NULL;
3222 	char *	make_level_str = NULL;
3223 	int	make_level_val = 0;
3224 
3225 	make_level_str = getenv("MAKELEVEL");
3226 	if(make_level_str) {
3227 		make_level_val = atoi(make_level_str);
3228 	}
3229 	if(mlev == NULL) {
3230 		mlev = (char*) malloc(MAXPATHLEN);
3231 	}
3232 	if(entering) {
3233 		sprintf(mlev, "MAKELEVEL=%d", make_level_val + 1);
3234 	} else {
3235 		make_level_val--;
3236 		sprintf(mlev, "MAKELEVEL=%d", make_level_val);
3237 	}
3238 	putenv(mlev);
3239 
3240 	if(report_cwd) {
3241 		if(make_level_val <= 0) {
3242 			if(entering) {
3243 				sprintf(rcwd,
3244 				    gettext("%s: Entering directory `%s'\n"),
3245 				    getprogname(),
3246 				    get_current_path());
3247 			} else {
3248 				sprintf(rcwd,
3249 				    gettext("%s: Leaving directory `%s'\n"),
3250 				    getprogname(),
3251 				    get_current_path());
3252 			}
3253 		} else {
3254 			if(entering) {
3255 				sprintf(rcwd,
3256 				    gettext("%s[%d]: Entering directory `%s'\n"),
3257 				    getprogname(),
3258 				    make_level_val, get_current_path());
3259 			} else {
3260 				sprintf(rcwd,
3261 				    gettext("%s[%d]: Leaving directory `%s'\n"),
3262 				    getprogname(),
3263 				    make_level_val, get_current_path());
3264 			}
3265 		}
3266 		printf("%s", rcwd);
3267 	}
3268 }
3269