Changeset 287 for trunk/src/gmake/job.c
- Timestamp:
- May 17, 2005, 1:34:55 AM (20 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/gmake/job.c
r232 r287 1 1 /* Job execution and handling for GNU Make. 2 Copyright (C) 1988,89,90,91,92,93,94,95,96,97,99 Free Software Foundation, Inc. 2 Copyright (C) 1988,1989,1990,1991,1992,1993,1994,1995,1996,1997,1999, 3 2000,2001,2002,2003,2004,2005 Free Software Foundation, Inc. 3 4 This file is part of GNU Make. 4 5 … … 69 70 70 71 # include <descrip.h> 72 char default_shell[] = ""; 73 int batch_mode_shell = 0; 74 75 #elif defined (__riscos__) 76 71 77 char default_shell[] = ""; 72 78 int batch_mode_shell = 0; … … 176 182 #endif /* Don't have `union wait'. */ 177 183 178 #ifdef VMS179 static int vms_jobsefnmask = 0;180 #endif /* !VMS */181 182 184 #ifndef HAVE_UNISTD_H 183 185 extern int dup2 (); … … 207 209 static int job_next_command PARAMS ((struct child *)); 208 210 static int start_waiting_job PARAMS ((struct child *)); 209 #ifdef VMS210 static void vmsWaitForChildren PARAMS ((int *));211 #endif212 211 #ifdef MAKE_DLLSHELL 213 212 static int spawn_command PARAMS ((char **argv, char **envp, struct child *child)); … … 239 238 unsigned long job_counter = 0; 240 239 240 /* Number of jobserver tokens this instance is currently using. */ 241 242 unsigned int jobserver_tokens = 0; 241 243 242 244 … … 248 250 w32_kill(int pid, int sig) 249 251 { 250 return ((process_kill(pid, sig) == TRUE) ? 0 : -1); 252 return ((process_kill((HANDLE)pid, sig) == TRUE) ? 0 : -1); 253 } 254 255 /* This function creates a temporary file name with the given extension 256 * the unixy param controls both the extension and the path separator 257 * return an xmalloc'ed string of a newly created temp file or die. */ 258 static char * 259 create_batch_filename(char const *base, int unixy) 260 { 261 const char *const ext = unixy ? "sh" : "bat"; 262 const char *error = NULL; 263 char temp_path[MAXPATHLEN]; /* need to know its length */ 264 unsigned path_size = GetTempPath(sizeof temp_path, temp_path); 265 int path_is_dot = 0; 266 unsigned uniq = 1; 267 const unsigned sizemax = strlen (base) + strlen (ext) + 10; 268 269 if (path_size == 0) 270 { 271 path_size = GetCurrentDirectory (sizeof temp_path, temp_path); 272 path_is_dot = 1; 273 } 274 275 while (path_size > 0 && 276 path_size + sizemax < sizeof temp_path && 277 uniq < 0x10000) 278 { 279 unsigned size = sprintf (temp_path + path_size, 280 "%s%s-%x.%s", 281 temp_path[path_size - 1] == '\\' ? "" : "\\", 282 base, uniq, ext); 283 HANDLE h = CreateFile (temp_path, /* file name */ 284 GENERIC_READ | GENERIC_WRITE, /* desired access */ 285 0, /* no share mode */ 286 NULL, /* default security attributes */ 287 CREATE_NEW, /* creation disposition */ 288 FILE_ATTRIBUTE_NORMAL | /* flags and attributes */ 289 FILE_ATTRIBUTE_TEMPORARY, /* we'll delete it */ 290 NULL); /* no template file */ 291 292 if (h == INVALID_HANDLE_VALUE) 293 { 294 const DWORD er = GetLastError(); 295 296 if (er == ERROR_FILE_EXISTS || er == ERROR_ALREADY_EXISTS) 297 ++uniq; 298 299 /* the temporary path is not guaranteed to exist */ 300 else if (path_is_dot == 0) 301 { 302 path_size = GetCurrentDirectory (sizeof temp_path, temp_path); 303 path_is_dot = 1; 304 } 305 306 else 307 { 308 error = map_windows32_error_to_string (er); 309 break; 310 } 311 } 312 else 313 { 314 const unsigned final_size = path_size + size + 1; 315 char *const path = (char *) xmalloc (final_size); 316 memcpy (path, temp_path, final_size); 317 CloseHandle (h); 318 if (unixy) 319 { 320 char *p; 321 int ch; 322 for (p = path; (ch = *p) != 0; ++p) 323 if (ch == '\\') 324 *p = '/'; 325 } 326 return path; /* good return */ 327 } 328 } 329 330 if (error == NULL) 331 error = _("Cannot create a temporary file\n"); 332 fatal (NILF, error); 333 334 /* not reached */ 335 return NULL; 251 336 } 252 337 #endif /* WINDOWS32 */ … … 328 413 329 414 330 #ifdef VMS331 /* Wait for nchildren children to terminate */332 static void333 vmsWaitForChildren(int *status)334 {335 while (1)336 {337 if (!vms_jobsefnmask)338 {339 *status = 0;340 return;341 }342 343 *status = sys$wflor (32, vms_jobsefnmask);344 }345 return;346 }347 348 /* Set up IO redirection. */349 350 char *351 vms_redirect (struct dsc$descriptor_s *desc, char *fname, char *ibuf)352 {353 char *fptr;354 extern char *vmsify ();355 356 ibuf++;357 while (isspace ((unsigned char)*ibuf))358 ibuf++;359 fptr = ibuf;360 while (*ibuf && !isspace ((unsigned char)*ibuf))361 ibuf++;362 *ibuf = 0;363 if (strcmp (fptr, "/dev/null") != 0)364 {365 strcpy (fname, vmsify (fptr, 0));366 if (strchr (fname, '.') == 0)367 strcat (fname, ".");368 }369 desc->dsc$w_length = strlen(fname);370 desc->dsc$a_pointer = fname;371 desc->dsc$b_dtype = DSC$K_DTYPE_T;372 desc->dsc$b_class = DSC$K_CLASS_S;373 374 if (*fname == 0)375 printf (_("Warning: Empty redirection\n"));376 return ibuf;377 }378 379 380 /* found apostrophe at (p-1)381 inc p until after closing apostrophe.382 */383 384 static char *385 vms_handle_apos (char *p)386 {387 int alast;388 389 #define SEPCHARS ",/()= "390 391 alast = 0;392 393 while (*p != 0)394 {395 if (*p == '"')396 {397 if (alast)398 {399 alast = 0;400 p++;401 }402 else403 {404 p++;405 if (strchr (SEPCHARS, *p))406 break;407 alast = 1;408 }409 }410 else411 p++;412 }413 414 return p;415 }416 417 #endif418 419 415 420 416 /* Handle a dead child. This handler may or may not ever be installed. … … 485 481 { 486 482 int remote = 0; 487 register int pid;483 pid_t pid; 488 484 int exit_code, exit_sig, coredump; 489 485 register struct child *lastc, *c; … … 569 565 { 570 566 #ifdef VMS 567 static void vmsWaitForChildren PARAMS ((int *)); 571 568 vmsWaitForChildren (&status); 572 569 pid = c->pid; … … 644 641 HANDLE hPID; 645 642 int err; 643 exit_code = 0; 644 exit_sig = 0; 645 coredump = 0; 646 646 647 647 /* wait for anything to finish */ 648 if (hPID = process_wait_for_any()) { 649 650 /* was an error found on this process? */ 651 err = process_last_err(hPID); 652 653 /* get exit data */ 654 exit_code = process_exit_code(hPID); 655 656 if (err) 657 fprintf(stderr, "make (e=%d): %s", 658 exit_code, map_windows32_error_to_string(exit_code)); 659 660 /* signal */ 661 exit_sig = process_signal(hPID); 662 663 /* cleanup process */ 664 process_cleanup(hPID); 665 666 coredump = 0; 667 } 668 pid = (int) hPID; 648 hPID = process_wait_for_any(); 649 if (hPID) 650 { 651 652 /* was an error found on this process? */ 653 err = process_last_err(hPID); 654 655 /* get exit data */ 656 exit_code = process_exit_code(hPID); 657 658 if (err) 659 fprintf(stderr, "make (e=%d): %s", 660 exit_code, map_windows32_error_to_string(exit_code)); 661 662 /* signal */ 663 exit_sig = process_signal(hPID); 664 665 /* cleanup process */ 666 process_cleanup(hPID); 667 668 coredump = 0; 669 } 670 pid = (pid_t) hPID; 669 671 } 670 672 #endif /* WINDOWS32 */ … … 840 842 free_child (struct child *child) 841 843 { 842 /* If this child is the only one it was our "free" job, so don't put a 843 token back for it. This child has already been removed from the list, 844 so if there any left this wasn't the last one. */ 845 846 if (job_fds[1] >= 0 && children) 844 if (!jobserver_tokens) 845 fatal (NILF, "INTERNAL: Freeing child 0x%08lx (%s) but no tokens left!\n", 846 (unsigned long int) child, child->file->name); 847 848 /* If we're using the jobserver and this child is not the only outstanding 849 job, put a token back into the pipe for it. */ 850 851 if (job_fds[1] >= 0 && jobserver_tokens > 1) 847 852 { 848 853 char token = '+'; … … 858 863 (unsigned long int) child, child->file->name)); 859 864 } 865 866 --jobserver_tokens; 860 867 861 868 if (handling_fatal_signal) /* Don't bother free'ing if about to die. */ … … 898 905 } 899 906 900 #ifdef 907 #ifdef POSIX 901 908 void 902 909 unblock_sigs (void) … … 909 916 910 917 #ifdef MAKE_JOBSERVER 918 RETSIGTYPE 919 job_noop (int sig UNUSED) 920 { 921 } 911 922 /* Set the child handler action flags to FLAGS. */ 912 923 static void 913 set_child_handler_action_flags (int flags)924 set_child_handler_action_flags (int set_handler, int set_alarm) 914 925 { 915 926 struct sigaction sa; 927 928 #ifdef __EMX__ 929 /* The child handler must be turned off here. */ 930 signal (SIGCHLD, SIG_DFL); 931 #endif 932 916 933 bzero ((char *) &sa, sizeof sa); 917 934 sa.sa_handler = child_handler; 918 sa.sa_flags = flags;935 sa.sa_flags = set_handler ? 0 : SA_RESTART; 919 936 #if defined SIGCHLD 920 937 sigaction (SIGCHLD, &sa, NULL); … … 922 939 #if defined SIGCLD && SIGCLD != SIGCHLD 923 940 sigaction (SIGCLD, &sa, NULL); 941 #endif 942 #if defined SIGALRM 943 if (set_alarm) 944 { 945 /* If we're about to enter the read(), set an alarm to wake up in a 946 second so we can check if the load has dropped and we can start more 947 work. On the way out, turn off the alarm and set SIG_DFL. */ 948 alarm (set_handler ? 1 : 0); 949 sa.sa_handler = set_handler ? job_noop : SIG_DFL; 950 sa.sa_flags = 0; 951 sigaction (SIGALRM, &sa, NULL); 952 } 924 953 #endif 925 954 } … … 1226 1255 1227 1256 #ifdef VMS 1228 1229 1257 if (!child_execute_job (argv, child)) { 1230 1258 /* Fork failed! */ … … 1670 1698 1671 1699 /* If we don't already have a job started, use our "free" token. */ 1672 if (! children)1700 if (!jobserver_tokens) 1673 1701 break; 1674 1702 … … 1705 1733 reap_children (0, 0); 1706 1734 1707 /* If our "free" token has become available, use it. */ 1735 /* Kick off any jobs we have waiting for an opportunity that 1736 can run now (ie waiting for load). */ 1737 start_waiting_jobs (); 1738 1739 /* If our "free" slot has become available, use it; we don't need an 1740 actual token. */ 1741 if (!jobserver_tokens) 1742 break; 1743 1744 /* There must be at least one child already, or we have no business 1745 waiting for a token. */ 1708 1746 if (!children) 1709 break;1747 fatal (NILF, "INTERNAL: no children as we go to sleep on read\n"); 1710 1748 1711 1749 /* Set interruptible system calls, and read() for a job token. */ 1712 set_child_handler_action_flags ( 0);1750 set_child_handler_action_flags (1, waiting_jobs != NULL); 1713 1751 got_token = read (job_rfd, &token, 1); 1714 1752 saved_errno = errno; 1715 #if defined(__EMX__) && !defined(__INNOTEK_LIBC__) 1716 /* The child handler must be turned off here. */ 1717 signal (SIGCHLD, SIG_DFL); 1718 #endif 1719 set_child_handler_action_flags (SA_RESTART); 1753 set_child_handler_action_flags (0, waiting_jobs != NULL); 1720 1754 1721 1755 /* If we got one, we're done here. */ … … 1736 1770 } 1737 1771 #endif 1772 1773 ++jobserver_tokens; 1738 1774 1739 1775 /* The job is now primed. Start it running. … … 1816 1852 load_too_high (void) 1817 1853 { 1818 #if defined(__MSDOS__) || defined(VMS) || defined(_AMIGA) 1854 #if defined(__MSDOS__) || defined(VMS) || defined(_AMIGA) || defined(__riscos__) 1819 1855 return 1; 1820 1856 #else … … 1900 1936 1901 1937 #ifndef WINDOWS32 1902 #ifdef VMS1903 #include <descrip.h>1904 #include <clidef.h>1905 1906 /* This is called as an AST when a child process dies (it won't get1907 interrupted by anything except a higher level AST).1908 */1909 int vmsHandleChildTerm(struct child *child)1910 {1911 int status;1912 register struct child *lastc, *c;1913 int child_failed;1914 1915 vms_jobsefnmask &= ~(1 << (child->efn - 32));1916 1917 lib$free_ef(&child->efn);1918 1919 (void) sigblock (fatal_signal_mask);1920 1921 child_failed = !(child->cstatus & 1 || ((child->cstatus & 7) == 0));1922 1923 /* Search for a child matching the deceased one. */1924 lastc = 0;1925 #if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */1926 for (c = children; c != 0 && c != child; lastc = c, c = c->next);1927 #else1928 c = child;1929 #endif1930 1931 if (child_failed && !c->noerror && !ignore_errors_flag)1932 {1933 /* The commands failed. Write an error message,1934 delete non-precious targets, and abort. */1935 child_error (c->file->name, c->cstatus, 0, 0, 0);1936 c->file->update_status = 1;1937 delete_child_targets (c);1938 }1939 else1940 {1941 if (child_failed)1942 {1943 /* The commands failed, but we don't care. */1944 child_error (c->file->name, c->cstatus, 0, 0, 1);1945 child_failed = 0;1946 }1947 1948 #if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */1949 /* If there are more commands to run, try to start them. */1950 start_job (c);1951 1952 switch (c->file->command_state)1953 {1954 case cs_running:1955 /* Successfully started. */1956 break;1957 1958 case cs_finished:1959 if (c->file->update_status != 0) {1960 /* We failed to start the commands. */1961 delete_child_targets (c);1962 }1963 break;1964 1965 default:1966 error (NILF, _("internal error: `%s' command_state"),1967 c->file->name);1968 abort ();1969 break;1970 }1971 #endif /* RECURSIVEJOBS */1972 }1973 1974 /* Set the state flag to say the commands have finished. */1975 c->file->command_state = cs_finished;1976 notice_finished_file (c->file);1977 1978 #if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */1979 /* Remove the child from the chain and free it. */1980 if (lastc == 0)1981 children = c->next;1982 else1983 lastc->next = c->next;1984 free_child (c);1985 #endif /* RECURSIVEJOBS */1986 1987 /* There is now another slot open. */1988 if (job_slots_used > 0)1989 --job_slots_used;1990 1991 /* If the job failed, and the -k flag was not given, die. */1992 if (child_failed && !keep_going_flag)1993 die (EXIT_FAILURE);1994 1995 (void) sigsetmask (sigblock (0) & ~(fatal_signal_mask));1996 1997 return 1;1998 }1999 2000 /* VMS:2001 Spawn a process executing the command in ARGV and return its pid. */2002 2003 #define MAXCMDLEN 2002004 2005 /* local helpers to make ctrl+c and ctrl+y working, see below */2006 #include <iodef.h>2007 #include <libclidef.h>2008 #include <ssdef.h>2009 2010 static int ctrlMask= LIB$M_CLI_CTRLY;2011 static int oldCtrlMask;2012 static int setupYAstTried= 0;2013 static int pidToAbort= 0;2014 static int chan= 0;2015 2016 static void reEnableAst(void) {2017 lib$enable_ctrl (&oldCtrlMask,0);2018 }2019 2020 static astHandler (void) {2021 if (pidToAbort) {2022 sys$forcex (&pidToAbort, 0, SS$_ABORT);2023 pidToAbort= 0;2024 }2025 kill (getpid(),SIGQUIT);2026 }2027 2028 static void tryToSetupYAst(void) {2029 $DESCRIPTOR(inputDsc,"SYS$COMMAND");2030 int status;2031 struct {2032 short int status, count;2033 int dvi;2034 } iosb;2035 2036 setupYAstTried++;2037 2038 if (!chan) {2039 status= sys$assign(&inputDsc,&chan,0,0);2040 if (!(status&SS$_NORMAL)) {2041 lib$signal(status);2042 return;2043 }2044 }2045 status= sys$qiow (0, chan, IO$_SETMODE|IO$M_CTRLYAST,&iosb,0,0,2046 astHandler,0,0,0,0,0);2047 if (status==SS$_ILLIOFUNC) {2048 sys$dassgn(chan);2049 #ifdef CTRLY_ENABLED_ANYWAY2050 fprintf (stderr,2051 _("-warning, CTRL-Y will leave sub-process(es) around.\n"));2052 #else2053 return;2054 #endif2055 }2056 if (status==SS$_NORMAL)2057 status= iosb.status;2058 if (!(status&SS$_NORMAL)) {2059 lib$signal(status);2060 return;2061 }2062 2063 /* called from AST handler ? */2064 if (setupYAstTried>1)2065 return;2066 if (atexit(reEnableAst))2067 fprintf (stderr,2068 _("-warning, you may have to re-enable CTRL-Y handling from DCL.\n"));2069 status= lib$disable_ctrl (&ctrlMask, &oldCtrlMask);2070 if (!(status&SS$_NORMAL)) {2071 lib$signal(status);2072 return;2073 }2074 }2075 int2076 child_execute_job (char *argv, struct child *child)2077 {2078 int i;2079 static struct dsc$descriptor_s cmddsc;2080 static struct dsc$descriptor_s pnamedsc;2081 static struct dsc$descriptor_s ifiledsc;2082 static struct dsc$descriptor_s ofiledsc;2083 static struct dsc$descriptor_s efiledsc;2084 int have_redirection = 0;2085 int have_newline = 0;2086 2087 int spflags = CLI$M_NOWAIT;2088 int status;2089 char *cmd = alloca (strlen (argv) + 512), *p, *q;2090 char ifile[256], ofile[256], efile[256];2091 char *comname = 0;2092 char procname[100];2093 2094 /* Parse IO redirection. */2095 2096 ifile[0] = 0;2097 ofile[0] = 0;2098 efile[0] = 0;2099 2100 DB (DB_JOBS, ("child_execute_job (%s)\n", argv));2101 2102 while (isspace ((unsigned char)*argv))2103 argv++;2104 2105 if (*argv == 0)2106 return 0;2107 2108 sprintf (procname, "GMAKE_%05x", getpid () & 0xfffff);2109 pnamedsc.dsc$w_length = strlen(procname);2110 pnamedsc.dsc$a_pointer = procname;2111 pnamedsc.dsc$b_dtype = DSC$K_DTYPE_T;2112 pnamedsc.dsc$b_class = DSC$K_CLASS_S;2113 2114 /* Handle comments and redirection. */2115 for (p = argv, q = cmd; *p; p++, q++)2116 {2117 switch (*p)2118 {2119 case '#':2120 *p-- = 0;2121 *q-- = 0;2122 break;2123 case '\\':2124 p++;2125 if (*p == '\n')2126 p++;2127 if (isspace ((unsigned char)*p))2128 {2129 do { p++; } while (isspace ((unsigned char)*p));2130 p--;2131 }2132 *q = *p;2133 break;2134 case '<':2135 p = vms_redirect (&ifiledsc, ifile, p);2136 *q = ' ';2137 have_redirection = 1;2138 break;2139 case '>':2140 have_redirection = 1;2141 if (*(p-1) == '2')2142 {2143 q--;2144 if (strncmp (p, ">&1", 3) == 0)2145 {2146 p += 3;2147 strcpy (efile, "sys$output");2148 efiledsc.dsc$w_length = strlen(efile);2149 efiledsc.dsc$a_pointer = efile;2150 efiledsc.dsc$b_dtype = DSC$K_DTYPE_T;2151 efiledsc.dsc$b_class = DSC$K_CLASS_S;2152 }2153 else2154 {2155 p = vms_redirect (&efiledsc, efile, p);2156 }2157 }2158 else2159 {2160 p = vms_redirect (&ofiledsc, ofile, p);2161 }2162 *q = ' ';2163 break;2164 case '\n':2165 have_newline = 1;2166 default:2167 *q = *p;2168 break;2169 }2170 }2171 *q = *p;2172 2173 if (strncmp (cmd, "builtin_", 8) == 0)2174 {2175 child->pid = 270163;2176 child->efn = 0;2177 child->cstatus = 1;2178 2179 DB (DB_JOBS, (_("BUILTIN [%s][%s]\n"), cmd, cmd+8));2180 2181 p = cmd + 8;2182 2183 if ((*(p) == 'c')2184 && (*(p+1) == 'd')2185 && ((*(p+2) == ' ') || (*(p+2) == '\t')))2186 {2187 p += 3;2188 while ((*p == ' ') || (*p == '\t'))2189 p++;2190 DB (DB_JOBS, (_("BUILTIN CD %s\n"), p));2191 if (chdir (p))2192 return 0;2193 else2194 return 1;2195 }2196 else if ((*(p) == 'r')2197 && (*(p+1) == 'm')2198 && ((*(p+2) == ' ') || (*(p+2) == '\t')))2199 {2200 int in_arg;2201 2202 /* rm */2203 p += 3;2204 while ((*p == ' ') || (*p == '\t'))2205 p++;2206 in_arg = 1;2207 2208 DB (DB_JOBS, (_("BUILTIN RM %s\n"), p));2209 while (*p)2210 {2211 switch (*p)2212 {2213 case ' ':2214 case '\t':2215 if (in_arg)2216 {2217 *p++ = ';';2218 in_arg = 0;2219 }2220 break;2221 default:2222 break;2223 }2224 p++;2225 }2226 }2227 else2228 {2229 printf(_("Unknown builtin command '%s'\n"), cmd);2230 fflush(stdout);2231 return 0;2232 }2233 }2234 2235 /* Create a *.com file if either the command is too long for2236 lib$spawn, or the command contains a newline, or if redirection2237 is desired. Forcing commands with newlines into DCLs allows to2238 store search lists on user mode logicals. */2239 2240 if (strlen (cmd) > MAXCMDLEN2241 || (have_redirection != 0)2242 || (have_newline != 0))2243 {2244 FILE *outfile;2245 char c;2246 char *sep;2247 int alevel = 0; /* apostrophe level */2248 2249 if (strlen (cmd) == 0)2250 {2251 printf (_("Error, empty command\n"));2252 fflush (stdout);2253 return 0;2254 }2255 2256 outfile = open_tmpfile (&comname, "sys$scratch:CMDXXXXXX.COM");2257 if (outfile == 0)2258 pfatal_with_name (_("fopen (temporary file)"));2259 2260 if (ifile[0])2261 {2262 fprintf (outfile, "$ assign/user %s sys$input\n", ifile);2263 DB (DB_JOBS, (_("Redirected input from %s\n"), ifile));2264 ifiledsc.dsc$w_length = 0;2265 }2266 2267 if (efile[0])2268 {2269 fprintf (outfile, "$ define sys$error %s\n", efile);2270 DB (DB_JOBS, (_("Redirected error to %s\n"), efile));2271 efiledsc.dsc$w_length = 0;2272 }2273 2274 if (ofile[0])2275 {2276 fprintf (outfile, "$ define sys$output %s\n", ofile);2277 DB (DB_JOBS, (_("Redirected output to %s\n"), ofile));2278 ofiledsc.dsc$w_length = 0;2279 }2280 2281 p = sep = q = cmd;2282 for (c = '\n'; c; c = *q++)2283 {2284 switch (c)2285 {2286 case '\n':2287 /* At a newline, skip any whitespace around a leading $2288 from the command and issue exactly one $ into the DCL. */2289 while (isspace ((unsigned char)*p))2290 p++;2291 if (*p == '$')2292 p++;2293 while (isspace ((unsigned char)*p))2294 p++;2295 fwrite (p, 1, q - p, outfile);2296 fputc ('$', outfile);2297 fputc (' ', outfile);2298 /* Reset variables. */2299 p = sep = q;2300 break;2301 2302 /* Nice places for line breaks are after strings, after2303 comma or space and before slash. */2304 case '"':2305 q = vms_handle_apos (q);2306 sep = q;2307 break;2308 case ',':2309 case ' ':2310 sep = q;2311 break;2312 case '/':2313 case '\0':2314 sep = q - 1;2315 break;2316 default:2317 break;2318 }2319 if (sep - p > 78)2320 {2321 /* Enough stuff for a line. */2322 fwrite (p, 1, sep - p, outfile);2323 p = sep;2324 if (*sep)2325 {2326 /* The command continues. */2327 fputc ('-', outfile);2328 }2329 fputc ('\n', outfile);2330 }2331 }2332 2333 fwrite (p, 1, q - p, outfile);2334 fputc ('\n', outfile);2335 2336 fclose (outfile);2337 2338 sprintf (cmd, "$ @%s", comname);2339 2340 DB (DB_JOBS, (_("Executing %s instead\n"), cmd));2341 }2342 2343 cmddsc.dsc$w_length = strlen(cmd);2344 cmddsc.dsc$a_pointer = cmd;2345 cmddsc.dsc$b_dtype = DSC$K_DTYPE_T;2346 cmddsc.dsc$b_class = DSC$K_CLASS_S;2347 2348 child->efn = 0;2349 while (child->efn < 32 || child->efn > 63)2350 {2351 status = lib$get_ef ((unsigned long *)&child->efn);2352 if (!(status & 1))2353 return 0;2354 }2355 2356 sys$clref (child->efn);2357 2358 vms_jobsefnmask |= (1 << (child->efn - 32));2359 2360 /*2361 LIB$SPAWN [command-string]2362 [,input-file]2363 [,output-file]2364 [,flags]2365 [,process-name]2366 [,process-id] [,completion-status-address] [,byte-integer-event-flag-num]2367 [,AST-address] [,varying-AST-argument]2368 [,prompt-string] [,cli] [,table]2369 */2370 2371 #ifndef DONTWAITFORCHILD2372 /*2373 * Code to make ctrl+c and ctrl+y working.2374 * The problem starts with the synchronous case where after lib$spawn is2375 * called any input will go to the child. But with input re-directed,2376 * both control characters won't make it to any of the programs, neither2377 * the spawning nor to the spawned one. Hence the caller needs to spawn2378 * with CLI$M_NOWAIT to NOT give up the input focus. A sys$waitfr2379 * has to follow to simulate the wanted synchronous behaviour.2380 * The next problem is ctrl+y which isn't caught by the crtl and2381 * therefore isn't converted to SIGQUIT (for a signal handler which is2382 * already established). The only way to catch ctrl+y, is an AST2383 * assigned to the input channel. But ctrl+y handling of DCL needs to be2384 * disabled, otherwise it will handle it. Not to mention the previous2385 * ctrl+y handling of DCL needs to be re-established before make exits.2386 * One more: At the time of LIB$SPAWN signals are blocked. SIGQUIT will2387 * make it to the signal handler after the child "normally" terminates.2388 * This isn't enough. It seems reasonable for simple command lines like2389 * a 'cc foobar.c' spawned in a subprocess but it is unacceptable for2390 * spawning make. Therefore we need to abort the process in the AST.2391 *2392 * Prior to the spawn it is checked if an AST is already set up for2393 * ctrl+y, if not one is set up for a channel to SYS$COMMAND. In general2394 * this will work except if make is run in a batch environment, but there2395 * nobody can press ctrl+y. During the setup the DCL handling of ctrl+y2396 * is disabled and an exit handler is established to re-enable it.2397 * If the user interrupts with ctrl+y, the assigned AST will fire, force2398 * an abort to the subprocess and signal SIGQUIT, which will be caught by2399 * the already established handler and will bring us back to common code.2400 * After the spawn (now /nowait) a sys$waitfr simulates the /wait and2401 * enables the ctrl+y be delivered to this code. And the ctrl+c too,2402 * which the crtl converts to SIGINT and which is caught by the common2403 * signal handler. Because signals were blocked before entering this code2404 * sys$waitfr will always complete and the SIGQUIT will be processed after2405 * it (after termination of the current block, somewhere in common code).2406 * And SIGINT too will be delayed. That is ctrl+c can only abort when the2407 * current command completes. Anyway it's better than nothing :-)2408 */2409 2410 if (!setupYAstTried)2411 tryToSetupYAst();2412 status = lib$spawn (&cmddsc, /* cmd-string */2413 (ifiledsc.dsc$w_length == 0)?0:&ifiledsc, /* input-file */2414 (ofiledsc.dsc$w_length == 0)?0:&ofiledsc, /* output-file */2415 &spflags, /* flags */2416 &pnamedsc, /* proc name */2417 &child->pid, &child->cstatus, &child->efn,2418 0, 0,2419 0, 0, 0);2420 if (status & 1)2421 {2422 pidToAbort= child->pid;2423 status= sys$waitfr (child->efn);2424 pidToAbort= 0;2425 vmsHandleChildTerm(child);2426 }2427 #else2428 status = lib$spawn (&cmddsc,2429 (ifiledsc.dsc$w_length == 0)?0:&ifiledsc,2430 (ofiledsc.dsc$w_length == 0)?0:&ofiledsc,2431 &spflags,2432 &pnamedsc,2433 &child->pid, &child->cstatus, &child->efn,2434 vmsHandleChildTerm, child,2435 0, 0, 0);2436 #endif2437 2438 if (!(status & 1))2439 {2440 printf (_("Error spawning, %d\n") ,status);2441 fflush (stdout);2442 switch (status)2443 {2444 case 0x1c:2445 errno = EPROCLIM;2446 break;2447 default:2448 errno = EFAIL;2449 }2450 }2451 2452 if (comname && !ISDB (DB_JOBS))2453 unlink (comname);2454 2455 return (status & 1);2456 }2457 2458 #else /* !VMS */2459 1938 2460 1939 /* EMX: Start a child process. This function returns the new pid. */ 2461 # if defined __MSDOS__ || defined __EMX__2462 1940 /* The child argument can be NULL (that's why we return the pid), if it is 2463 1941 and the shell is a dllshell:// a child structure is created and inserted … … 2466 1944 BTW. the name of this function in this port is very misleading, spawn_job 2467 1945 would perhaps be more appropriate. */ 2468 1946 # if defined __MSDOS__ || defined __EMX__ 2469 1947 int 2470 1948 child_execute_job (int stdin_fd, int stdout_fd, char **argv, char **envp, … … 2509 1987 #endif 2510 1988 2511 /* Restore stdout/stdin of the parent process. */ 2512 if (stdin_fd != 0 && dup2 (save_stdin, 0) != 0) 2513 fatal (NILF, _("restoring of stdin failed\n")); 2514 if (stdout_fd != 1 && dup2 (save_stdout, 1) != 1) 2515 fatal (NILF, _("restoring of stdout failed\n")); 2516 2517 /* Cleanup handles */ 1989 /* Restore stdout/stdin of the parent and close temporary FDs. */ 2518 1990 if (stdin_fd != 0) 2519 close (save_stdin); 1991 { 1992 if (dup2 (save_stdin, 0) != 0) 1993 fatal (NILF, _("Could not restore stdin\n")); 1994 else 1995 close (save_stdin); 1996 } 1997 2520 1998 if (stdout_fd != 1) 2521 close (save_stdout); 1999 { 2000 if (dup2 (save_stdout, 1) != 1) 2001 fatal (NILF, _("Could not restore stdout\n")); 2002 else 2003 close (save_stdout); 2004 } 2522 2005 2523 2006 return pid; … … 2546 2029 } 2547 2030 #endif /* !AMIGA && !__MSDOS__ */ 2548 #endif /* !VMS */2549 2031 #endif /* !WINDOWS32 */ 2550 2032 … … 2678 2160 int 2679 2161 # else 2680 2162 void 2681 2163 # endif 2682 2164 exec_command (char **argv, char **envp) … … 2718 2200 2719 2201 /* wait and reap last child */ 2720 while (hWaitPID = process_wait_for_any()) 2202 hWaitPID = process_wait_for_any(); 2203 while (hWaitPID) 2721 2204 { 2722 2205 /* was an error found on this process? */ … … 2786 2269 char **new_argv; 2787 2270 int argc; 2271 int i=1; 2788 2272 2789 2273 # ifdef __EMX__ … … 2804 2288 ++argc; 2805 2289 2290 # ifdef __EMX__ 2291 if (!unixy_shell) 2292 ++argc; 2293 # endif 2294 2806 2295 new_argv = (char **) alloca ((1 + argc + 1) * sizeof (char *)); 2807 2296 new_argv[0] = shell; 2808 new_argv[1] = argv[0]; 2297 2298 # ifdef __EMX__ 2299 if (!unixy_shell) 2300 { 2301 new_argv[1] = "/c"; 2302 ++i; 2303 --argc; 2304 } 2305 # endif 2306 2307 new_argv[i] = argv[0]; 2809 2308 while (argc > 0) 2810 2309 { 2811 new_argv[ 1+ argc] = argv[argc];2310 new_argv[i + argc] = argv[argc]; 2812 2311 --argc; 2813 2312 } … … 2977 2476 char* sh_chars; 2978 2477 char** sh_cmds; 2478 #elif defined(__riscos__) 2479 static char sh_chars[] = ""; 2480 static char *sh_cmds[] = { 0 }; 2979 2481 #else /* must be UNIX-ish */ 2980 2482 static char sh_chars[] = "#;\"*?[]&|<>(){}$`^~!"; … … 3254 2756 register int j; 3255 2757 for (j = 0; sh_cmds[j] != 0; ++j) 3256 if (streq (sh_cmds[j], new_argv[0])) 3257 goto slow; 2758 { 2759 if (streq (sh_cmds[j], new_argv[0])) 2760 goto slow; 2761 # ifdef __EMX__ 2762 /* Non-Unix shells are case insensitive. */ 2763 if (!unixy_shell 2764 && strcasecmp (sh_cmds[j], new_argv[0]) == 0) 2765 goto slow; 2766 # endif 2767 } 3258 2768 } 3259 2769 … … 3293 2803 /* Line was empty. */ 3294 2804 return 0; 3295 else 3296 2805 2806 return new_argv; 3297 2807 3298 2808 slow:; … … 3443 2953 int id = GetCurrentProcessId(); 3444 2954 PATH_VAR(fbuf); 3445 char* fname = NULL;3446 2955 3447 2956 /* create a file name */ 3448 2957 sprintf(fbuf, "make%d", id); 3449 fname = tempnam(".", fbuf); 3450 3451 /* create batch file name */ 3452 *batch_filename_ptr = xmalloc(strlen(fname) + 5); 3453 strcpy(*batch_filename_ptr, fname); 3454 3455 /* make sure path name is in DOS backslash format */ 3456 if (!unixy_shell) { 3457 fname = *batch_filename_ptr; 3458 for (i = 0; fname[i] != '\0'; ++i) 3459 if (fname[i] == '/') 3460 fname[i] = '\\'; 3461 strcat(*batch_filename_ptr, ".bat"); 3462 } else { 3463 strcat(*batch_filename_ptr, ".sh"); 3464 } 2958 *batch_filename_ptr = create_batch_filename (fbuf, unixy_shell); 3465 2959 3466 2960 DB (DB_JOBS, (_("Creating temporary batch file %s\n"), … … 3491 2985 (char *) 0, (char *) 0, 3492 2986 (char **) 0); 3493 # 2987 #ifdef __EMX__ 3494 2988 else if (!unixy_shell) 3495 2989 { 3496 /* new_line is local, must not be freed therefore */ 3497 char *p, *q; 3498 int quote; 3499 size_t index; 3500 size_t len; 3501 3502 /* handle quotes 3503 We have to remove all double quotes and to split the line 3504 into distinct arguments because of the strange handling 3505 of builtin commands by cmd: 'echo "bla"' prints "bla" 3506 (with quotes) while 'c:\bin\echo.exe "bla"' prints bla 3507 (without quotes). Some programs like autoconf rely 3508 on the second behaviour. */ 3509 3510 len = strlen (new_line) + 1; 3511 3512 /* More than 1 arg per character is impossible. */ 3513 new_argv = (char **) xmalloc (len * sizeof (char *)); 3514 3515 /* All the args can fit in a buffer as big as new_line is. */ 3516 new_argv[0] = (char *) xmalloc (len); 3517 3518 index = 0; 3519 quote = 0; 3520 q = new_line; 3521 p = new_argv[index]; 3522 while(*q != '\0') 3523 { 3524 /* searching for closing quote */ 3525 if (quote) 3526 { 3527 if (*q == quote) 3528 { 3529 /* remove the quote */ 3530 q++; 3531 quote = 0; 3532 } 3533 else /* normal character: copy it */ 3534 *p++ = *q++; 3535 } 3536 3537 /* searching for opening quote */ 3538 else if (*q == '\"' 3539 # ifndef NO_CMD_DEFAULT 3540 || *q == '\'' 3541 # endif 3542 ) 3543 { 3544 /* remove opening quote */ 3545 quote = *q; 3546 q++; 3547 } 3548 3549 /* spaces outside of a quoted string: remove them 3550 and start a new argument */ 3551 else if (*q == ' ' || *q == '\t') 3552 { 3553 *p++ = '\0'; /* trailing '\0' for last argument */ 3554 3555 /* remove all successive spaces */ 3556 do 3557 { 3558 q++; 3559 } 3560 while(*q == ' ' || *q == '\t'); 3561 3562 /* start new argument */ 3563 index++; 3564 new_argv[index] = p; 3565 } 3566 3567 /* normal character (no space) outside a quoted string*/ 3568 else 3569 *p++ = *q++; 3570 } /* end while() */ 3571 3572 *p = '\0'; /* trailing '\0' for the last argument */ 3573 new_argv[index + 1] = NULL; 3574 3575 # ifndef NO_CMD_DEFAULT 3576 /* special case: echo x="y" 3577 (e.g. autoconf uses this to determine whether make works) 3578 this is pure idioty but cmd works this way: 3579 if 'echo' and 'x="y"' are two different arguments cmd 3580 will print '"x="y""' but if they are only one argument 3581 cmd will print 'bla="blurb"' as it should be 3582 note: if we do not allow cmd to be the default shell 3583 we do not need this kind of voodoo */ 3584 if (index == 3 && strcasecmp(new_argv[2], "echo") == 0) 3585 { 3586 new_argv[2][4] = ' '; 3587 new_argv[3] = NULL; 3588 } 3589 # endif 2990 /* new_line is local, must not be freed therefore 2991 We use line here instead of new_line because we run the shell 2992 manually. */ 2993 size_t line_len = strlen (line); 2994 char *p = new_line; 2995 char *q = new_line; 2996 memcpy (new_line, line, line_len + 1); 2997 /* replace all backslash-newline combination and also following tabs */ 2998 while (*q != '\0') 2999 { 3000 if (q[0] == '\\' && q[1] == '\n') 3001 { 3002 q += 2; /* remove '\\' and '\n' */ 3003 if (q[0] == '\t') 3004 q++; /* remove 1st tab in the next line */ 3005 } 3006 else 3007 *p++ = *q++; 3008 } 3009 *p = '\0'; 3010 3011 # ifndef NO_CMD_DEFAULT 3012 if (strnicmp (new_line, "echo", 4) == 0 3013 && (new_line[4] == ' ' || new_line[4] == '\t')) 3014 { 3015 /* the builtin echo command: handle it separately */ 3016 size_t echo_len = line_len - 5; 3017 char *echo_line = new_line + 5; 3018 3019 /* special case: echo 'x="y"' 3020 cmd works this way: a string is printed as is, i.e., no quotes 3021 are removed. But autoconf uses a command like echo 'x="y"' to 3022 determine whether make works. autoconf expects the output x="y" 3023 so we will do exactly that. 3024 Note: if we do not allow cmd to be the default shell 3025 we do not need this kind of voodoo */ 3026 if (echo_line[0] == '\'' 3027 && echo_line[echo_len - 1] == '\'' 3028 && strncmp (echo_line + 1, "ac_maketemp=", 3029 strlen ("ac_maketemp=")) == 0) 3030 { 3031 /* remove the enclosing quotes */ 3032 memmove (echo_line, echo_line + 1, echo_len - 2); 3033 echo_line[echo_len - 2] = '\0'; 3034 } 3035 } 3036 # endif 3037 3038 { 3039 /* Let the shell decide what to do. Put the command line into the 3040 2nd command line argument and hope for the best ;-) */ 3041 size_t sh_len = strlen (shell); 3042 3043 /* exactly 3 arguments + NULL */ 3044 new_argv = (char **) xmalloc (4 * sizeof (char *)); 3045 /* Exactly strlen(shell) + strlen("/c") + strlen(line) + 3 times 3046 the trailing '\0' */ 3047 new_argv[0] = (char *) malloc (sh_len + line_len + 5); 3048 memcpy (new_argv[0], shell, sh_len + 1); 3049 new_argv[1] = new_argv[0] + sh_len + 1; 3050 memcpy (new_argv[1], "/c", 3); 3051 new_argv[2] = new_argv[1] + 3; 3052 memcpy (new_argv[2], new_line, line_len + 1); 3053 new_argv[3] = NULL; 3054 } 3590 3055 } 3591 3056 #elif defined(__MSDOS__) … … 3768 3233 } 3769 3234 #endif /* !HAPE_DUP2 && !_AMIGA */ 3235 3236 /* On VMS systems, include special VMS functions. */ 3237 3238 #ifdef VMS 3239 #include "vmsjobs.c" 3240 #endif
Note:
See TracChangeset
for help on using the changeset viewer.