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 = ¬_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