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
26 /*
27 * doname.c
28 *
29 * Figure out which targets are out of date and rebuild them
30 */
31
32 /*
33 * Included files
34 */
35 #include <alloca.h> /* alloca() */
36
37 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
38 # include <avo/strings.h> /* AVO_STRDUP() */
39 # include <dm/Avo_MToolJobResultMsg.h>
40 # include <dm/Avo_MToolJobStartMsg.h>
41 # include <dm/Avo_MToolRsrcInfoMsg.h>
42 # include <dm/Avo_macro_defs.h> /* AVO_BLOCK_INTERUPTS & AVO_UNBLOCK_INTERUPTS */
43 # include <dmthread/Avo_ServerState.h>
44 # include <rw/pstream.h>
45 # include <rw/xdrstrea.h>
46 #endif
47
48 #include <fcntl.h>
49 #include <mk/defs.h>
50 #include <mksh/i18n.h> /* get_char_semantics_value() */
51 #include <mksh/macro.h> /* getvar(), expand_value() */
52 #include <mksh/misc.h> /* getmem() */
53 #include <poll.h>
54
55
56 #include <signal.h>
57
58 # include <stropts.h>
59
60 #include <sys/errno.h>
61 #include <sys/stat.h>
62 #include <sys/types.h>
63 #include <sys/utsname.h> /* uname() */
64 #include <sys/wait.h>
65 #include <unistd.h> /* close() */
66
67 /*
68 * Defined macros
69 */
70 # define LOCALHOST "localhost"
71
72 #define MAXRULES 100
73
74 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
75 #define SEND_MTOOL_MSG(cmds) \
76 if (send_mtool_msgs) { \
77 cmds \
78 }
79 #else
80 #define SEND_MTOOL_MSG(cmds)
81 #endif
82
83 // Sleep for .1 seconds between stat()'s
84 const int STAT_RETRY_SLEEP_TIME = 100000;
85
86 /*
87 * typedefs & structs
88 */
89
90 /*
91 * Static variables
92 */
93 static char hostName[MAXNAMELEN] = "";
94 static char userName[MAXNAMELEN] = "";
95
96 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
97 static FILE *mtool_msgs_fp;
98 static XDR xdrs;
99 static int sent_rsrc_info_msg = 0;
100 #endif
101
102 static int second_pass = 0;
103
104 /*
105 * File table of contents
106 */
107 extern Doname doname_check(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic);
108 extern Doname doname(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic);
109 static Boolean check_dependencies(Doname *result, Property line, Boolean do_get, Name target, Name true_target, Boolean doing_subtree, Chain *out_of_date_tail, Property old_locals, Boolean implicit, Property *command, Name less, Boolean rechecking_target, Boolean recheck_conditionals);
110 void dynamic_dependencies(Name target);
111 static Doname run_command(register Property line, Boolean print_machine);
112 extern Doname execute_serial(Property line);
113 extern Name vpath_translation(register Name cmd);
114 extern void check_state(Name temp_file_name);
115 static void read_dependency_file(register Name filename);
116 static void check_read_state_file(void);
117 static void do_assign(register Name line, register Name target);
118 static void build_command_strings(Name target, register Property line);
119 static Doname touch_command(register Property line, register Name target, Doname result);
120 extern void update_target(Property line, Doname result);
121 static Doname sccs_get(register Name target, register Property *command);
122 extern void read_directory_of_file(register Name file);
123 static void add_pattern_conditionals(register Name target);
124 extern void set_locals(register Name target, register Property old_locals);
125 extern void reset_locals(register Name target, register Property old_locals, register Property conditional, register int index);
126 extern Boolean check_auto_dependencies(Name target, int auto_count, Name *automatics);
127 static void delete_query_chain(Chain ch);
128
129 // From read2.cc
130 extern Name normalize_name(register wchar_t *name_string, register int length);
131
132
133 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
134 static void append_job_result_msg(Avo_MToolJobResultMsg *job_result_msg);
135 static int pollResults(char *outFn, char *errFn, char *hostNm);
136 static void pollResultsAction(char *outFn, char *errFn);
137 static void rxmGetNextResultsBlock(int fd);
138 static int us_sleep(unsigned int nusecs);
139 extern "C" void Avo_PollResultsAction_Sigusr1Handler(int foo);
140 #endif
141
142 /*
143 * DONE.
144 *
145 * doname_check(target, do_get, implicit, automatic)
146 *
147 * Will call doname() and then inspect the return value
148 *
149 * Return value:
150 * Indication if the build failed or not
151 *
152 * Parameters:
153 * target The target to build
154 * do_get Passed thru to doname()
155 * implicit Passed thru to doname()
156 * automatic Are we building a hidden dependency?
157 *
158 * Global variables used:
159 * build_failed_seen Set if -k is on and error occurs
160 * continue_after_error Indicates that -k is on
1002 dependency != NULL;
1003 dependency = dependency->next) {
1004 Boolean this_dependency_changed = false;
1005
1006 if (!dependency->automatic &&
1007 (rechecking_target || target->rechecking_target)) {
1008 /*
1009 * We only bother with the autos when rechecking
1010 */
1011 continue;
1012 }
1013
1014 if (dependency->name == wait_name) {
1015 /*
1016 * The special target .WAIT means finish all of
1017 * the prior dependencies before continuing.
1018 */
1019 if (dependencies_running) {
1020 break;
1021 }
1022 #ifdef DISTRIBUTED
1023 } else if ((!parallel_ok(dependency->name, false)) &&
1024 (dependencies_running)) {
1025 /*
1026 * If we can't execute the current dependency in
1027 * parallel, hold off the dependency processing
1028 * to preserve the order of the dependencies.
1029 */
1030 break;
1031 #endif
1032 } else {
1033 timestruc_t depe_time = file_doesnt_exist;
1034
1035
1036 if (true_target->is_member) {
1037 depe_time = exists(dependency->name);
1038 }
1039 if (dependency->built ||
1040 (dependency->name->state == build_failed)) {
1041 dep_result = (Doname) dependency->name->state;
1042 } else {
1043 dep_result = doname_check(dependency->name,
1044 do_get,
1045 false,
1046 (Boolean) dependency->automatic);
1047 }
1048 if (true_target->is_member || dependency->name->is_member) {
1049 /* should compare only secs, cause lib members does not have nsec time resolution */
1050 if (depe_time.tv_sec != dependency->name->stat.time.tv_sec) {
1051 this_dependency_changed =
1827 * Return value:
1828 * The result of the command build
1829 *
1830 * Parameters:
1831 * line The command to execute
1832 *
1833 * Static variables used:
1834 *
1835 * Global variables used:
1836 * continue_after_error -k flag
1837 * do_not_exec_rule -n flag
1838 * report_dependencies -P flag
1839 * silent Don't echo commands before executing
1840 * temp_file_name Temp file for auto dependencies
1841 * vpath_defined If true, translate path for command
1842 */
1843 Doname
1844 execute_serial(Property line)
1845 {
1846 int child_pid = 0;
1847 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
1848 Avo_MToolJobResultMsg *job_result_msg;
1849 RWCollectable *xdr_msg;
1850 #endif
1851 Boolean printed_serial;
1852 Doname result = build_ok;
1853 Cmd_line rule, cmd_tail, command = NULL;
1854 char mbstring[MAXPATHLEN];
1855 int filed;
1856 Name target = line->body.line.target;
1857
1858 SEND_MTOOL_MSG(
1859 if (!sent_rsrc_info_msg) {
1860 if (userName[0] == '\0') {
1861 avo_get_user(userName, NULL);
1862 }
1863 if (hostName[0] == '\0') {
1864 strcpy(hostName, avo_hostname());
1865 }
1866 send_rsrc_info_msg(1, hostName, userName);
1867 sent_rsrc_info_msg = 1;
1868 }
1869 send_job_start_msg(line);
1870 job_result_msg = new Avo_MToolJobResultMsg();
1913 getpid(),
1914 file_number++);
1915
1916 int tmp_fd = mkstemp(mbstring);
1917 if(tmp_fd) {
1918 (void) close(tmp_fd);
1919 }
1920
1921 stdout_file = strdup(mbstring);
1922 stderr_file = NULL;
1923 child_pid = pollResults(stdout_file,
1924 (char *)NULL,
1925 (char *)NULL);
1926 );
1927 /* Do assignment if command line prefixed with "=" */
1928 if (rule->assign) {
1929 result = build_ok;
1930 do_assign(rule->command_line, target);
1931 } else if (report_dependencies_level == 0) {
1932 /* Execute command line. */
1933 #ifdef DISTRIBUTED
1934 setvar_envvar((Avo_DoJobMsg *)NULL);
1935 #else
1936 setvar_envvar();
1937 #endif
1938 result = dosys(rule->command_line,
1939 (Boolean) rule->ignore_error,
1940 (Boolean) rule->make_refd,
1941 /* ds 98.04.23 bug #4085164. make should always show error messages */
1942 false,
1943 /* BOOLEAN(rule->silent &&
1944 rule->ignore_error), */
1945 (Boolean) rule->always_exec,
1946 target,
1947 send_mtool_msgs);
1948 check_state(temp_file_name);
1949 }
1950 SEND_MTOOL_MSG(
1951 append_job_result_msg(job_result_msg);
1952 if (child_pid > 0) {
1953 kill(child_pid, SIGUSR1);
1954 while (!((waitpid(child_pid, 0, 0) == -1)
1955 && (errno == ECHILD)));
1956 }
1957 child_pid = 0;
2021 spro->body.macro.value = NULL;
2022 }
2023 }
2024 spro = get_prop(sunpro_dependencies->prop, env_mem_prop);
2025 if(spro) {
2026 char *val = spro->body.env_mem.value;
2027 if(val != NULL) {
2028 /*
2029 * Do not return memory allocated for SUNPRO_DEPENDENCIES
2030 * It will be returned in setvar_daemon() in macro.cc
2031 */
2032 // retmem_mb(val);
2033 spro->body.env_mem.value = NULL;
2034 }
2035 }
2036
2037 return result;
2038 }
2039
2040
2041 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
2042
2043 /*
2044 * Create and send an Avo_MToolRsrcInfoMsg.
2045 */
2046 void
2047 send_rsrc_info_msg(int max_jobs, char *hostname, char *username)
2048 {
2049 static int first = 1;
2050 Avo_MToolRsrcInfoMsg *msg;
2051 RWSlistCollectables server_list;
2052 Avo_ServerState *server_state;
2053 RWCollectable *xdr_msg;
2054
2055 if (!first) {
2056 return;
2057 }
2058 first = 0;
2059
2060 create_xdrs_ptr();
2061
2062 server_state = new Avo_ServerState(max_jobs, hostname, username);
2063 server_list.append(server_state);
2064 msg = new Avo_MToolRsrcInfoMsg(&server_list);
2065
2066 xdr_msg = (RWCollectable *)msg;
2067 xdr(get_xdrs_ptr(), xdr_msg);
2068 (void) fflush(get_mtool_msgs_fp());
2069
2070 delete server_state;
2071 delete msg;
2072 }
2073
2074 /*
2075 * Create and send an Avo_MToolJobStartMsg.
2076 */
2077 void
2078 send_job_start_msg(Property line)
2079 {
2080 int cmd_options = 0;
2081 Avo_MToolJobStartMsg *msg;
2082 Cmd_line rule;
2083 Name target = line->body.line.target;
2084 RWCollectable *xdr_msg;
2085
2086 if (userName[0] == '\0') {
2087 avo_get_user(userName, NULL);
2088 }
2089 if (hostName[0] == '\0') {
2090 strcpy(hostName, avo_hostname());
2091 }
2092
2093 msg = new Avo_MToolJobStartMsg();
2094 msg->setJobId(++job_msg_id);
2095 msg->setTarget(AVO_STRDUP(target->string_mb));
2096 msg->setHost(AVO_STRDUP(hostName));
2097 msg->setUser(AVO_STRDUP(userName));
2098
2099 for (rule = line->body.line.command_used;
2100 rule != NULL;
2101 rule = rule->next) {
2102 if (posix && (touch || quest) && !rule->always_exec) {
2103 continue;
2104 }
2105 if (vpath_defined) {
2106 rule->command_line =
2107 vpath_translation(rule->command_line);
2108 }
2109 cmd_options = 0;
2110 if (rule->ignore_error || ignore_errors) {
2111 cmd_options |= ignore_mask;
2112 }
2113 if (rule->silent || silent) {
2114 cmd_options |= silent_mask;
2115 }
2116 if (rule->command_line->meta) {
2117 cmd_options |= meta_mask;
2118 }
2119 if (!touch && (rule->command_line->hash.length > 0)) {
2120 msg->appendCmd(new Avo_DmakeCommand(rule->command_line->string_mb, cmd_options));
2121 }
2122 }
2123
2124 xdr_msg = (RWCollectable*) msg;
2125 xdr(&xdrs, xdr_msg);
2126 (void) fflush(mtool_msgs_fp);
2127
2128 /* tolik, 08/39/2002.
2129 I commented out this code because it causes using unallocated memory.
2130 delete msg;
2131 */
2132 }
2133
2134 /*
2135 * Append the stdout/err to Avo_MToolJobResultMsg.
2136 */
2137 static void
2138 append_job_result_msg(Avo_MToolJobResultMsg *job_result_msg)
2139 {
2140 FILE *fp;
2141 char line[MAXPATHLEN];
2142 char stdout_file2[MAXPATHLEN];
2143
2144 if (stdout_file != NULL) {
2145 fp = fopen(stdout_file, "r");
2146 if (fp == NULL) {
2147 /* Hmmm... what should we do here? */
2148 warning(catgets(catd, 1, 326, "fopen() of stdout_file failed. Output may be lost"));
2149 return;
2150 }
2151 while (fgets(line, MAXPATHLEN, fp) != NULL) {
2152 if (line[strlen(line) - 1] == '\n') {
2153 line[strlen(line) - 1] = '\0';
2154 }
2155 job_result_msg->appendOutput(AVO_STRDUP(line));
2156 }
2157 (void) fclose(fp);
2158 us_sleep(STAT_RETRY_SLEEP_TIME);
2159 } else {
2160 /* Hmmm... stdout_file shouldn't be NULL */
2161 warning(catgets(catd, 1, 327, "Internal stdout_file variable shouldn't be NULL. Output may be lost"));
2162 }
2163 }
2164 #endif /* TEAMWARE_MAKE_CMN */
2165
2166 /*
2167 * vpath_translation(cmd)
2168 *
2169 * Translates one command line by
2170 * checking each word. If the word has an alias it is translated.
2171 *
2172 * Return value:
2173 * The translated command
2174 *
2175 * Parameters:
2176 * cmd Command to translate
2177 *
2178 * Global variables used:
2179 */
2180 Name
2181 vpath_translation(register Name cmd)
2182 {
2183 wchar_t buffer[STRING_BUFFER_LENGTH];
2184 String_rec new_cmd;
2776 *
2777 * Parameters:
2778 * line The command line to update
2779 * target The target we are touching
2780 * result Initial value for the result we return
2781 *
2782 * Global variables used:
2783 * do_not_exec_rule Indicates that -n is on
2784 * silent Do not echo commands
2785 */
2786 static Doname
2787 touch_command(register Property line, register Name target, Doname result)
2788 {
2789 Name name;
2790 register Chain target_group;
2791 String_rec touch_string;
2792 wchar_t buffer[MAXPATHLEN];
2793 Name touch_cmd;
2794 Cmd_line rule;
2795
2796 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
2797 Avo_MToolJobResultMsg *job_result_msg;
2798 RWCollectable *xdr_msg;
2799 int child_pid = 0;
2800 wchar_t string[MAXPATHLEN];
2801 char mbstring[MAXPATHLEN];
2802 int filed;
2803 #endif
2804
2805 SEND_MTOOL_MSG(
2806 if (!sent_rsrc_info_msg) {
2807 if (userName[0] == '\0') {
2808 avo_get_user(userName, NULL);
2809 }
2810 if (hostName[0] == '\0') {
2811 strcpy(hostName, avo_hostname());
2812 }
2813 send_rsrc_info_msg(1, hostName, userName);
2814 sent_rsrc_info_msg = 1;
2815 }
2816 send_job_start_msg(line);
2817 job_result_msg = new Avo_MToolJobResultMsg();
2818 );
2819 for (name = target, target_group = NULL; name != NULL;) {
2820 if (!name->is_member) {
2821 /*
2822 * Build a touch command that can be passed
2823 * to dosys(). If KEEP_STATE is on, "make -t"
3443 if (*p++ == dependency->name) {
3444 /* If we can find it on the */
3445 /* saved list of autos we */
3446 /* are OK */
3447 goto not_new;
3448 }
3449 }
3450 /* But if we scan over the old list */
3451 /* of auto. without finding it it is */
3452 /* new and we must check it */
3453 return true;
3454 }
3455 not_new:;
3456 }
3457 return false;
3458 } else {
3459 return false;
3460 }
3461 }
3462
3463 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
3464 void
3465 create_xdrs_ptr(void)
3466 {
3467 static int xdrs_init = 0;
3468
3469 if (!xdrs_init) {
3470 xdrs_init = 1;
3471 mtool_msgs_fp = fdopen(mtool_msgs_fd, "a");
3472 xdrstdio_create(&xdrs,
3473 mtool_msgs_fp,
3474 XDR_ENCODE);
3475 }
3476 }
3477
3478 XDR *
3479 get_xdrs_ptr(void)
3480 {
3481 return &xdrs;
3482 }
3483
3484 FILE *
3485 get_mtool_msgs_fp(void)
3486 {
3487 return mtool_msgs_fp;
3488 }
3489
3490 int
3491 get_job_msg_id(void)
3492 {
3493 return job_msg_id;
3494 }
3495
3496 // Continuously poll and show the results of remotely executing a job,
3497 // i.e., output the stdout and stderr files.
3498
3499 static int
3500 pollResults(char *outFn, char *errFn, char *hostNm)
3501 {
3502 int child;
3503
3504 child = fork();
3505 switch (child) {
3506 case -1:
3507 break;
3508 case 0:
3509 enable_interrupt((void (*) (int))SIG_DFL);
3510 (void) sigset(SIGUSR1, Avo_PollResultsAction_Sigusr1Handler);
3511 pollResultsAction(outFn, errFn);
3512
3513 exit(0);
3514 break;
3515 default:
3516 break;
3517 }
3518 return child;
3519 }
3520
3521 // This is the PollResultsAction SIGUSR1 handler.
3522
3523 static bool_t pollResultsActionTimeToFinish = FALSE;
3524
3525 extern "C" void
3526 Avo_PollResultsAction_Sigusr1Handler(int foo)
3527 {
3528 pollResultsActionTimeToFinish = TRUE;
3529 }
3530
3531 static void
3532 pollResultsAction(char *outFn, char *errFn)
3533 {
3534 int fd;
3535 time_t file_time = 0;
3536 long file_time_nsec = 0;
3537 struct stat statbuf;
3538 int stat_rc;
3539
3540 // Keep stat'ing until file exists.
3541 while (((stat_rc = stat(outFn, &statbuf)) != 0) &&
3542 (errno == ENOENT) &&
3543 !pollResultsActionTimeToFinish) {
3544 us_sleep(STAT_RETRY_SLEEP_TIME);
3545 }
3546 // The previous stat() could be failed due to EINTR
3547 // So one more try is needed
3548 if (stat_rc != 0 && stat(outFn, &statbuf) != 0) {
3549 // stat() failed
3550 warning(NOCATGETS("Internal error: stat(\"%s\", ...) failed: %s\n"),
3551 outFn, strerror(errno));
3552 exit(1);
3553 }
3554
3555 if ((fd = open(outFn, O_RDONLY)) < 0
3556 && (errno != EINTR || (fd = open(outFn, O_RDONLY)) < 0)) {
3557 // open() failed
3558 warning(NOCATGETS("Internal error: open(\"%s\", O_RDONLY) failed: %s\n"),
3559 outFn, strerror(errno));
3560 exit(1);
3561 }
3562
3563 while (!pollResultsActionTimeToFinish && stat(outFn, &statbuf) == 0) {
3564 if ((statbuf.st_mtim.tv_sec > file_time) ||
3565 ((statbuf.st_mtim.tv_sec == file_time) &&
3566 (statbuf.st_mtim.tv_nsec > file_time_nsec))
3567 ) {
3568 file_time = statbuf.st_mtim.tv_sec;
3569 file_time_nsec = statbuf.st_mtim.tv_nsec;
3570 rxmGetNextResultsBlock(fd);
3571 }
3572 us_sleep(STAT_RETRY_SLEEP_TIME);
3573 }
3574 // Check for the rest of output
3575 rxmGetNextResultsBlock(fd);
3576
3577 (void) close(fd);
3578 }
3579
3580 static void
3581 rxmGetNextResultsBlock(int fd)
3582 {
3583 size_t to_read = 8 * 1024;
3584 ssize_t bytes_read;
3585 ssize_t bytes_written;
3586 char results_buf[8 * 1024];
3587 sigset_t newset;
3588 sigset_t oldset;
3589
3590 // Read some more from the output/results file.
3591 // Hopefully the kernel managed to prefetch the stuff.
3592 bytes_read = read(fd, results_buf, to_read);
3593 while (bytes_read > 0) {
3594 AVO_BLOCK_INTERUPTS;
3595 bytes_written = write(1, results_buf, bytes_read);
3596 AVO_UNBLOCK_INTERUPTS;
3597 if (bytes_written != bytes_read) {
3598 // write() failed
3599 warning(NOCATGETS("Internal error: write(1, ...) failed: %s\n"),
3600 strerror(errno));
3601 exit(1);
3602 }
3603 bytes_read = read(fd, results_buf, to_read);
3604 }
3605 }
3606
3607 // Generic, interruptable microsecond resolution sleep member function.
3608
3609 static int
3610 us_sleep(unsigned int nusecs)
3611 {
3612 struct pollfd dummy;
3613 int timeout;
3614
3615 if ((timeout = nusecs/1000) <= 0) {
3616 timeout = 1;
3617 }
3618 return poll(&dummy, 0, timeout);
3619 }
3620 #endif /* TEAMWARE_MAKE_CMN */
3621
3622 // Recursively delete each of the Chain struct on the chain.
3623
3624 static void
3625 delete_query_chain(Chain ch)
3626 {
3627 if (ch == NULL) {
3628 return;
3629 } else {
3630 delete_query_chain(ch->next);
3631 retmem_mb((char *) ch);
3632 }
3633 }
3634
3635 Doname
3636 target_can_be_built(register Name target) {
3637 Doname result = build_dont_know;
3638 Name true_target = target;
3639 Property line;
3640
|
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
26 /*
27 * doname.c
28 *
29 * Figure out which targets are out of date and rebuild them
30 */
31
32 /*
33 * Included files
34 */
35 #include <alloca.h> /* alloca() */
36
37
38 #include <fcntl.h>
39 #include <mk/defs.h>
40 #include <mksh/i18n.h> /* get_char_semantics_value() */
41 #include <mksh/macro.h> /* getvar(), expand_value() */
42 #include <mksh/misc.h> /* getmem() */
43 #include <poll.h>
44
45
46 #include <signal.h>
47
48 # include <stropts.h>
49
50 #include <sys/errno.h>
51 #include <sys/stat.h>
52 #include <sys/types.h>
53 #include <sys/utsname.h> /* uname() */
54 #include <sys/wait.h>
55 #include <unistd.h> /* close() */
56
57 /*
58 * Defined macros
59 */
60 # define LOCALHOST "localhost"
61
62 #define MAXRULES 100
63
64 #define SEND_MTOOL_MSG(cmds)
65
66 // Sleep for .1 seconds between stat()'s
67 const int STAT_RETRY_SLEEP_TIME = 100000;
68
69 /*
70 * typedefs & structs
71 */
72
73 /*
74 * Static variables
75 */
76 static char hostName[MAXNAMELEN] = "";
77 static char userName[MAXNAMELEN] = "";
78
79
80 static int second_pass = 0;
81
82 /*
83 * File table of contents
84 */
85 extern Doname doname_check(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic);
86 extern Doname doname(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic);
87 static Boolean check_dependencies(Doname *result, Property line, Boolean do_get, Name target, Name true_target, Boolean doing_subtree, Chain *out_of_date_tail, Property old_locals, Boolean implicit, Property *command, Name less, Boolean rechecking_target, Boolean recheck_conditionals);
88 void dynamic_dependencies(Name target);
89 static Doname run_command(register Property line, Boolean print_machine);
90 extern Doname execute_serial(Property line);
91 extern Name vpath_translation(register Name cmd);
92 extern void check_state(Name temp_file_name);
93 static void read_dependency_file(register Name filename);
94 static void check_read_state_file(void);
95 static void do_assign(register Name line, register Name target);
96 static void build_command_strings(Name target, register Property line);
97 static Doname touch_command(register Property line, register Name target, Doname result);
98 extern void update_target(Property line, Doname result);
99 static Doname sccs_get(register Name target, register Property *command);
100 extern void read_directory_of_file(register Name file);
101 static void add_pattern_conditionals(register Name target);
102 extern void set_locals(register Name target, register Property old_locals);
103 extern void reset_locals(register Name target, register Property old_locals, register Property conditional, register int index);
104 extern Boolean check_auto_dependencies(Name target, int auto_count, Name *automatics);
105 static void delete_query_chain(Chain ch);
106
107 // From read2.cc
108 extern Name normalize_name(register wchar_t *name_string, register int length);
109
110
111
112 /*
113 * DONE.
114 *
115 * doname_check(target, do_get, implicit, automatic)
116 *
117 * Will call doname() and then inspect the return value
118 *
119 * Return value:
120 * Indication if the build failed or not
121 *
122 * Parameters:
123 * target The target to build
124 * do_get Passed thru to doname()
125 * implicit Passed thru to doname()
126 * automatic Are we building a hidden dependency?
127 *
128 * Global variables used:
129 * build_failed_seen Set if -k is on and error occurs
130 * continue_after_error Indicates that -k is on
972 dependency != NULL;
973 dependency = dependency->next) {
974 Boolean this_dependency_changed = false;
975
976 if (!dependency->automatic &&
977 (rechecking_target || target->rechecking_target)) {
978 /*
979 * We only bother with the autos when rechecking
980 */
981 continue;
982 }
983
984 if (dependency->name == wait_name) {
985 /*
986 * The special target .WAIT means finish all of
987 * the prior dependencies before continuing.
988 */
989 if (dependencies_running) {
990 break;
991 }
992 } else {
993 timestruc_t depe_time = file_doesnt_exist;
994
995
996 if (true_target->is_member) {
997 depe_time = exists(dependency->name);
998 }
999 if (dependency->built ||
1000 (dependency->name->state == build_failed)) {
1001 dep_result = (Doname) dependency->name->state;
1002 } else {
1003 dep_result = doname_check(dependency->name,
1004 do_get,
1005 false,
1006 (Boolean) dependency->automatic);
1007 }
1008 if (true_target->is_member || dependency->name->is_member) {
1009 /* should compare only secs, cause lib members does not have nsec time resolution */
1010 if (depe_time.tv_sec != dependency->name->stat.time.tv_sec) {
1011 this_dependency_changed =
1787 * Return value:
1788 * The result of the command build
1789 *
1790 * Parameters:
1791 * line The command to execute
1792 *
1793 * Static variables used:
1794 *
1795 * Global variables used:
1796 * continue_after_error -k flag
1797 * do_not_exec_rule -n flag
1798 * report_dependencies -P flag
1799 * silent Don't echo commands before executing
1800 * temp_file_name Temp file for auto dependencies
1801 * vpath_defined If true, translate path for command
1802 */
1803 Doname
1804 execute_serial(Property line)
1805 {
1806 int child_pid = 0;
1807 Boolean printed_serial;
1808 Doname result = build_ok;
1809 Cmd_line rule, cmd_tail, command = NULL;
1810 char mbstring[MAXPATHLEN];
1811 int filed;
1812 Name target = line->body.line.target;
1813
1814 SEND_MTOOL_MSG(
1815 if (!sent_rsrc_info_msg) {
1816 if (userName[0] == '\0') {
1817 avo_get_user(userName, NULL);
1818 }
1819 if (hostName[0] == '\0') {
1820 strcpy(hostName, avo_hostname());
1821 }
1822 send_rsrc_info_msg(1, hostName, userName);
1823 sent_rsrc_info_msg = 1;
1824 }
1825 send_job_start_msg(line);
1826 job_result_msg = new Avo_MToolJobResultMsg();
1869 getpid(),
1870 file_number++);
1871
1872 int tmp_fd = mkstemp(mbstring);
1873 if(tmp_fd) {
1874 (void) close(tmp_fd);
1875 }
1876
1877 stdout_file = strdup(mbstring);
1878 stderr_file = NULL;
1879 child_pid = pollResults(stdout_file,
1880 (char *)NULL,
1881 (char *)NULL);
1882 );
1883 /* Do assignment if command line prefixed with "=" */
1884 if (rule->assign) {
1885 result = build_ok;
1886 do_assign(rule->command_line, target);
1887 } else if (report_dependencies_level == 0) {
1888 /* Execute command line. */
1889 setvar_envvar();
1890 result = dosys(rule->command_line,
1891 (Boolean) rule->ignore_error,
1892 (Boolean) rule->make_refd,
1893 /* ds 98.04.23 bug #4085164. make should always show error messages */
1894 false,
1895 /* BOOLEAN(rule->silent &&
1896 rule->ignore_error), */
1897 (Boolean) rule->always_exec,
1898 target,
1899 send_mtool_msgs);
1900 check_state(temp_file_name);
1901 }
1902 SEND_MTOOL_MSG(
1903 append_job_result_msg(job_result_msg);
1904 if (child_pid > 0) {
1905 kill(child_pid, SIGUSR1);
1906 while (!((waitpid(child_pid, 0, 0) == -1)
1907 && (errno == ECHILD)));
1908 }
1909 child_pid = 0;
1973 spro->body.macro.value = NULL;
1974 }
1975 }
1976 spro = get_prop(sunpro_dependencies->prop, env_mem_prop);
1977 if(spro) {
1978 char *val = spro->body.env_mem.value;
1979 if(val != NULL) {
1980 /*
1981 * Do not return memory allocated for SUNPRO_DEPENDENCIES
1982 * It will be returned in setvar_daemon() in macro.cc
1983 */
1984 // retmem_mb(val);
1985 spro->body.env_mem.value = NULL;
1986 }
1987 }
1988
1989 return result;
1990 }
1991
1992
1993
1994 /*
1995 * vpath_translation(cmd)
1996 *
1997 * Translates one command line by
1998 * checking each word. If the word has an alias it is translated.
1999 *
2000 * Return value:
2001 * The translated command
2002 *
2003 * Parameters:
2004 * cmd Command to translate
2005 *
2006 * Global variables used:
2007 */
2008 Name
2009 vpath_translation(register Name cmd)
2010 {
2011 wchar_t buffer[STRING_BUFFER_LENGTH];
2012 String_rec new_cmd;
2604 *
2605 * Parameters:
2606 * line The command line to update
2607 * target The target we are touching
2608 * result Initial value for the result we return
2609 *
2610 * Global variables used:
2611 * do_not_exec_rule Indicates that -n is on
2612 * silent Do not echo commands
2613 */
2614 static Doname
2615 touch_command(register Property line, register Name target, Doname result)
2616 {
2617 Name name;
2618 register Chain target_group;
2619 String_rec touch_string;
2620 wchar_t buffer[MAXPATHLEN];
2621 Name touch_cmd;
2622 Cmd_line rule;
2623
2624
2625 SEND_MTOOL_MSG(
2626 if (!sent_rsrc_info_msg) {
2627 if (userName[0] == '\0') {
2628 avo_get_user(userName, NULL);
2629 }
2630 if (hostName[0] == '\0') {
2631 strcpy(hostName, avo_hostname());
2632 }
2633 send_rsrc_info_msg(1, hostName, userName);
2634 sent_rsrc_info_msg = 1;
2635 }
2636 send_job_start_msg(line);
2637 job_result_msg = new Avo_MToolJobResultMsg();
2638 );
2639 for (name = target, target_group = NULL; name != NULL;) {
2640 if (!name->is_member) {
2641 /*
2642 * Build a touch command that can be passed
2643 * to dosys(). If KEEP_STATE is on, "make -t"
3263 if (*p++ == dependency->name) {
3264 /* If we can find it on the */
3265 /* saved list of autos we */
3266 /* are OK */
3267 goto not_new;
3268 }
3269 }
3270 /* But if we scan over the old list */
3271 /* of auto. without finding it it is */
3272 /* new and we must check it */
3273 return true;
3274 }
3275 not_new:;
3276 }
3277 return false;
3278 } else {
3279 return false;
3280 }
3281 }
3282
3283
3284 // Recursively delete each of the Chain struct on the chain.
3285
3286 static void
3287 delete_query_chain(Chain ch)
3288 {
3289 if (ch == NULL) {
3290 return;
3291 } else {
3292 delete_query_chain(ch->next);
3293 retmem_mb((char *) ch);
3294 }
3295 }
3296
3297 Doname
3298 target_can_be_built(register Name target) {
3299 Doname result = build_dont_know;
3300 Name true_target = target;
3301 Property line;
3302
|