Changeset 280 for branches/GNU/src/gmake/job.c
- Timestamp:
- May 16, 2005, 6:54:02 PM (20 years ago)
- Location:
- branches/GNU/src/gmake
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/GNU/src/gmake
- Property svn:ignore
-
old new 34 34 README.DOS 35 35 README.W32 36 README.OS2 36 37 aclocal.m4 37 38 autom4te.cache
-
- Property svn:ignore
-
branches/GNU/src/gmake/job.c
r153 r280 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 … … 61 62 62 63 # include <descrip.h> 64 char default_shell[] = ""; 65 int batch_mode_shell = 0; 66 67 #elif defined (__riscos__) 68 63 69 char default_shell[] = ""; 64 70 int batch_mode_shell = 0; … … 168 174 #endif /* Don't have `union wait'. */ 169 175 170 #ifdef VMS171 static int vms_jobsefnmask = 0;172 #endif /* !VMS */173 174 176 #ifndef HAVE_UNISTD_H 175 177 extern int dup2 (); … … 199 201 static int job_next_command PARAMS ((struct child *)); 200 202 static int start_waiting_job PARAMS ((struct child *)); 201 #ifdef VMS202 static void vmsWaitForChildren PARAMS ((int *));203 #endif204 203 205 204 … … 228 227 unsigned long job_counter = 0; 229 228 229 /* Number of jobserver tokens this instance is currently using. */ 230 231 unsigned int jobserver_tokens = 0; 230 232 231 233 … … 237 239 w32_kill(int pid, int sig) 238 240 { 239 return ((process_kill(pid, sig) == TRUE) ? 0 : -1); 241 return ((process_kill((HANDLE)pid, sig) == TRUE) ? 0 : -1); 242 } 243 244 /* This function creates a temporary file name with the given extension 245 * the unixy param controls both the extension and the path separator 246 * return an xmalloc'ed string of a newly created temp file or die. */ 247 static char * 248 create_batch_filename(char const *base, int unixy) 249 { 250 const char *const ext = unixy ? "sh" : "bat"; 251 const char *error = NULL; 252 char temp_path[MAXPATHLEN]; /* need to know its length */ 253 unsigned path_size = GetTempPath(sizeof temp_path, temp_path); 254 int path_is_dot = 0; 255 unsigned uniq = 1; 256 const unsigned sizemax = strlen (base) + strlen (ext) + 10; 257 258 if (path_size == 0) 259 { 260 path_size = GetCurrentDirectory (sizeof temp_path, temp_path); 261 path_is_dot = 1; 262 } 263 264 while (path_size > 0 && 265 path_size + sizemax < sizeof temp_path && 266 uniq < 0x10000) 267 { 268 unsigned size = sprintf (temp_path + path_size, 269 "%s%s-%x.%s", 270 temp_path[path_size - 1] == '\\' ? "" : "\\", 271 base, uniq, ext); 272 HANDLE h = CreateFile (temp_path, /* file name */ 273 GENERIC_READ | GENERIC_WRITE, /* desired access */ 274 0, /* no share mode */ 275 NULL, /* default security attributes */ 276 CREATE_NEW, /* creation disposition */ 277 FILE_ATTRIBUTE_NORMAL | /* flags and attributes */ 278 FILE_ATTRIBUTE_TEMPORARY, /* we'll delete it */ 279 NULL); /* no template file */ 280 281 if (h == INVALID_HANDLE_VALUE) 282 { 283 const DWORD er = GetLastError(); 284 285 if (er == ERROR_FILE_EXISTS || er == ERROR_ALREADY_EXISTS) 286 ++uniq; 287 288 /* the temporary path is not guaranteed to exist */ 289 else if (path_is_dot == 0) 290 { 291 path_size = GetCurrentDirectory (sizeof temp_path, temp_path); 292 path_is_dot = 1; 293 } 294 295 else 296 { 297 error = map_windows32_error_to_string (er); 298 break; 299 } 300 } 301 else 302 { 303 const unsigned final_size = path_size + size + 1; 304 char *const path = (char *) xmalloc (final_size); 305 memcpy (path, temp_path, final_size); 306 CloseHandle (h); 307 if (unixy) 308 { 309 char *p; 310 int ch; 311 for (p = path; (ch = *p) != 0; ++p) 312 if (ch == '\\') 313 *p = '/'; 314 } 315 return path; /* good return */ 316 } 317 } 318 319 if (error == NULL) 320 error = _("Cannot create a temporary file\n"); 321 fatal (NILF, error); 322 323 /* not reached */ 324 return NULL; 240 325 } 241 326 #endif /* WINDOWS32 */ … … 317 402 318 403 319 #ifdef VMS320 /* Wait for nchildren children to terminate */321 static void322 vmsWaitForChildren(int *status)323 {324 while (1)325 {326 if (!vms_jobsefnmask)327 {328 *status = 0;329 return;330 }331 332 *status = sys$wflor (32, vms_jobsefnmask);333 }334 return;335 }336 337 /* Set up IO redirection. */338 339 char *340 vms_redirect (struct dsc$descriptor_s *desc, char *fname, char *ibuf)341 {342 char *fptr;343 extern char *vmsify ();344 345 ibuf++;346 while (isspace ((unsigned char)*ibuf))347 ibuf++;348 fptr = ibuf;349 while (*ibuf && !isspace ((unsigned char)*ibuf))350 ibuf++;351 *ibuf = 0;352 if (strcmp (fptr, "/dev/null") != 0)353 {354 strcpy (fname, vmsify (fptr, 0));355 if (strchr (fname, '.') == 0)356 strcat (fname, ".");357 }358 desc->dsc$w_length = strlen(fname);359 desc->dsc$a_pointer = fname;360 desc->dsc$b_dtype = DSC$K_DTYPE_T;361 desc->dsc$b_class = DSC$K_CLASS_S;362 363 if (*fname == 0)364 printf (_("Warning: Empty redirection\n"));365 return ibuf;366 }367 368 369 /* found apostrophe at (p-1)370 inc p until after closing apostrophe.371 */372 373 static char *374 vms_handle_apos (char *p)375 {376 int alast;377 378 #define SEPCHARS ",/()= "379 380 alast = 0;381 382 while (*p != 0)383 {384 if (*p == '"')385 {386 if (alast)387 {388 alast = 0;389 p++;390 }391 else392 {393 p++;394 if (strchr (SEPCHARS, *p))395 break;396 alast = 1;397 }398 }399 else400 p++;401 }402 403 return p;404 }405 406 #endif407 408 404 409 405 /* Handle a dead child. This handler may or may not ever be installed. … … 474 470 { 475 471 int remote = 0; 476 register int pid;472 pid_t pid; 477 473 int exit_code, exit_sig, coredump; 478 474 register struct child *lastc, *c; … … 543 539 { 544 540 #ifdef VMS 541 static void vmsWaitForChildren PARAMS ((int *)); 545 542 vmsWaitForChildren (&status); 546 543 pid = c->pid; … … 616 613 HANDLE hPID; 617 614 int err; 615 exit_code = 0; 616 exit_sig = 0; 617 coredump = 0; 618 618 619 619 /* wait for anything to finish */ 620 if (hPID = process_wait_for_any()) { 621 622 /* was an error found on this process? */ 623 err = process_last_err(hPID); 624 625 /* get exit data */ 626 exit_code = process_exit_code(hPID); 627 628 if (err) 629 fprintf(stderr, "make (e=%d): %s", 630 exit_code, map_windows32_error_to_string(exit_code)); 631 632 /* signal */ 633 exit_sig = process_signal(hPID); 634 635 /* cleanup process */ 636 process_cleanup(hPID); 637 638 coredump = 0; 639 } 640 pid = (int) hPID; 620 hPID = process_wait_for_any(); 621 if (hPID) 622 { 623 624 /* was an error found on this process? */ 625 err = process_last_err(hPID); 626 627 /* get exit data */ 628 exit_code = process_exit_code(hPID); 629 630 if (err) 631 fprintf(stderr, "make (e=%d): %s", 632 exit_code, map_windows32_error_to_string(exit_code)); 633 634 /* signal */ 635 exit_sig = process_signal(hPID); 636 637 /* cleanup process */ 638 process_cleanup(hPID); 639 640 coredump = 0; 641 } 642 pid = (pid_t) hPID; 641 643 } 642 644 #endif /* WINDOWS32 */ … … 812 814 free_child (struct child *child) 813 815 { 814 /* If this child is the only one it was our "free" job, so don't put a 815 token back for it. This child has already been removed from the list, 816 so if there any left this wasn't the last one. */ 817 818 if (job_fds[1] >= 0 && children) 816 if (!jobserver_tokens) 817 fatal (NILF, "INTERNAL: Freeing child 0x%08lx (%s) but no tokens left!\n", 818 (unsigned long int) child, child->file->name); 819 820 /* If we're using the jobserver and this child is not the only outstanding 821 job, put a token back into the pipe for it. */ 822 823 if (job_fds[1] >= 0 && jobserver_tokens > 1) 819 824 { 820 825 char token = '+'; … … 830 835 (unsigned long int) child, child->file->name)); 831 836 } 837 838 --jobserver_tokens; 832 839 833 840 if (handling_fatal_signal) /* Don't bother free'ing if about to die. */ … … 870 877 } 871 878 872 #ifdef 879 #ifdef POSIX 873 880 void 874 881 unblock_sigs (void) … … 881 888 882 889 #ifdef MAKE_JOBSERVER 890 RETSIGTYPE 891 job_noop (int sig UNUSED) 892 { 893 } 883 894 /* Set the child handler action flags to FLAGS. */ 884 895 static void 885 set_child_handler_action_flags (int flags)896 set_child_handler_action_flags (int set_handler, int set_alarm) 886 897 { 887 898 struct sigaction sa; 899 900 #ifdef __EMX__ 901 /* The child handler must be turned off here. */ 902 signal (SIGCHLD, SIG_DFL); 903 #endif 904 888 905 bzero ((char *) &sa, sizeof sa); 889 906 sa.sa_handler = child_handler; 890 sa.sa_flags = flags;907 sa.sa_flags = set_handler ? 0 : SA_RESTART; 891 908 #if defined SIGCHLD 892 909 sigaction (SIGCHLD, &sa, NULL); … … 894 911 #if defined SIGCLD && SIGCLD != SIGCHLD 895 912 sigaction (SIGCLD, &sa, NULL); 913 #endif 914 #if defined SIGALRM 915 if (set_alarm) 916 { 917 /* If we're about to enter the read(), set an alarm to wake up in a 918 second so we can check if the load has dropped and we can start more 919 work. On the way out, turn off the alarm and set SIG_DFL. */ 920 alarm (set_handler ? 1 : 0); 921 sa.sa_handler = set_handler ? job_noop : SIG_DFL; 922 sa.sa_flags = 0; 923 sigaction (SIGALRM, &sa, NULL); 924 } 896 925 #endif 897 926 } … … 1158 1187 1159 1188 #ifdef VMS 1160 1161 1189 if (!child_execute_job (argv, child)) { 1162 1190 /* Fork failed! */ … … 1582 1610 1583 1611 /* If we don't already have a job started, use our "free" token. */ 1584 if (! children)1612 if (!jobserver_tokens) 1585 1613 break; 1586 1614 … … 1617 1645 reap_children (0, 0); 1618 1646 1619 /* If our "free" token has become available, use it. */ 1647 /* Kick off any jobs we have waiting for an opportunity that 1648 can run now (ie waiting for load). */ 1649 start_waiting_jobs (); 1650 1651 /* If our "free" slot has become available, use it; we don't need an 1652 actual token. */ 1653 if (!jobserver_tokens) 1654 break; 1655 1656 /* There must be at least one child already, or we have no business 1657 waiting for a token. */ 1620 1658 if (!children) 1621 break;1659 fatal (NILF, "INTERNAL: no children as we go to sleep on read\n"); 1622 1660 1623 1661 /* Set interruptible system calls, and read() for a job token. */ 1624 set_child_handler_action_flags ( 0);1662 set_child_handler_action_flags (1, waiting_jobs != NULL); 1625 1663 got_token = read (job_rfd, &token, 1); 1626 1664 saved_errno = errno; 1627 #ifdef __EMX__ 1628 /* The child handler must be turned off here. */ 1629 signal (SIGCHLD, SIG_DFL); 1630 #endif 1631 set_child_handler_action_flags (SA_RESTART); 1665 set_child_handler_action_flags (0, waiting_jobs != NULL); 1632 1666 1633 1667 /* If we got one, we're done here. */ … … 1648 1682 } 1649 1683 #endif 1684 1685 ++jobserver_tokens; 1650 1686 1651 1687 /* The job is now primed. Start it running. … … 1728 1764 load_too_high (void) 1729 1765 { 1730 #if defined(__MSDOS__) || defined(VMS) || defined(_AMIGA) 1766 #if defined(__MSDOS__) || defined(VMS) || defined(_AMIGA) || defined(__riscos__) 1731 1767 return 1; 1732 1768 #else … … 1812 1848 1813 1849 #ifndef WINDOWS32 1814 #ifdef VMS1815 #include <descrip.h>1816 #include <clidef.h>1817 1818 /* This is called as an AST when a child process dies (it won't get1819 interrupted by anything except a higher level AST).1820 */1821 int vmsHandleChildTerm(struct child *child)1822 {1823 int status;1824 register struct child *lastc, *c;1825 int child_failed;1826 1827 vms_jobsefnmask &= ~(1 << (child->efn - 32));1828 1829 lib$free_ef(&child->efn);1830 1831 (void) sigblock (fatal_signal_mask);1832 1833 child_failed = !(child->cstatus & 1 || ((child->cstatus & 7) == 0));1834 1835 /* Search for a child matching the deceased one. */1836 lastc = 0;1837 #if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */1838 for (c = children; c != 0 && c != child; lastc = c, c = c->next);1839 #else1840 c = child;1841 #endif1842 1843 if (child_failed && !c->noerror && !ignore_errors_flag)1844 {1845 /* The commands failed. Write an error message,1846 delete non-precious targets, and abort. */1847 child_error (c->file->name, c->cstatus, 0, 0, 0);1848 c->file->update_status = 1;1849 delete_child_targets (c);1850 }1851 else1852 {1853 if (child_failed)1854 {1855 /* The commands failed, but we don't care. */1856 child_error (c->file->name, c->cstatus, 0, 0, 1);1857 child_failed = 0;1858 }1859 1860 #if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */1861 /* If there are more commands to run, try to start them. */1862 start_job (c);1863 1864 switch (c->file->command_state)1865 {1866 case cs_running:1867 /* Successfully started. */1868 break;1869 1870 case cs_finished:1871 if (c->file->update_status != 0) {1872 /* We failed to start the commands. */1873 delete_child_targets (c);1874 }1875 break;1876 1877 default:1878 error (NILF, _("internal error: `%s' command_state"),1879 c->file->name);1880 abort ();1881 break;1882 }1883 #endif /* RECURSIVEJOBS */1884 }1885 1886 /* Set the state flag to say the commands have finished. */1887 c->file->command_state = cs_finished;1888 notice_finished_file (c->file);1889 1890 #if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */1891 /* Remove the child from the chain and free it. */1892 if (lastc == 0)1893 children = c->next;1894 else1895 lastc->next = c->next;1896 free_child (c);1897 #endif /* RECURSIVEJOBS */1898 1899 /* There is now another slot open. */1900 if (job_slots_used > 0)1901 --job_slots_used;1902 1903 /* If the job failed, and the -k flag was not given, die. */1904 if (child_failed && !keep_going_flag)1905 die (EXIT_FAILURE);1906 1907 (void) sigsetmask (sigblock (0) & ~(fatal_signal_mask));1908 1909 return 1;1910 }1911 1912 /* VMS:1913 Spawn a process executing the command in ARGV and return its pid. */1914 1915 #define MAXCMDLEN 2001916 1917 /* local helpers to make ctrl+c and ctrl+y working, see below */1918 #include <iodef.h>1919 #include <libclidef.h>1920 #include <ssdef.h>1921 1922 static int ctrlMask= LIB$M_CLI_CTRLY;1923 static int oldCtrlMask;1924 static int setupYAstTried= 0;1925 static int pidToAbort= 0;1926 static int chan= 0;1927 1928 static void reEnableAst(void) {1929 lib$enable_ctrl (&oldCtrlMask,0);1930 }1931 1932 static astHandler (void) {1933 if (pidToAbort) {1934 sys$forcex (&pidToAbort, 0, SS$_ABORT);1935 pidToAbort= 0;1936 }1937 kill (getpid(),SIGQUIT);1938 }1939 1940 static void tryToSetupYAst(void) {1941 $DESCRIPTOR(inputDsc,"SYS$COMMAND");1942 int status;1943 struct {1944 short int status, count;1945 int dvi;1946 } iosb;1947 1948 setupYAstTried++;1949 1950 if (!chan) {1951 status= sys$assign(&inputDsc,&chan,0,0);1952 if (!(status&SS$_NORMAL)) {1953 lib$signal(status);1954 return;1955 }1956 }1957 status= sys$qiow (0, chan, IO$_SETMODE|IO$M_CTRLYAST,&iosb,0,0,1958 astHandler,0,0,0,0,0);1959 if (status==SS$_ILLIOFUNC) {1960 sys$dassgn(chan);1961 #ifdef CTRLY_ENABLED_ANYWAY1962 fprintf (stderr,1963 _("-warning, CTRL-Y will leave sub-process(es) around.\n"));1964 #else1965 return;1966 #endif1967 }1968 if (status==SS$_NORMAL)1969 status= iosb.status;1970 if (!(status&SS$_NORMAL)) {1971 lib$signal(status);1972 return;1973 }1974 1975 /* called from AST handler ? */1976 if (setupYAstTried>1)1977 return;1978 if (atexit(reEnableAst))1979 fprintf (stderr,1980 _("-warning, you may have to re-enable CTRL-Y handling from DCL.\n"));1981 status= lib$disable_ctrl (&ctrlMask, &oldCtrlMask);1982 if (!(status&SS$_NORMAL)) {1983 lib$signal(status);1984 return;1985 }1986 }1987 int1988 child_execute_job (char *argv, struct child *child)1989 {1990 int i;1991 static struct dsc$descriptor_s cmddsc;1992 static struct dsc$descriptor_s pnamedsc;1993 static struct dsc$descriptor_s ifiledsc;1994 static struct dsc$descriptor_s ofiledsc;1995 static struct dsc$descriptor_s efiledsc;1996 int have_redirection = 0;1997 int have_newline = 0;1998 1999 int spflags = CLI$M_NOWAIT;2000 int status;2001 char *cmd = alloca (strlen (argv) + 512), *p, *q;2002 char ifile[256], ofile[256], efile[256];2003 char *comname = 0;2004 char procname[100];2005 2006 /* Parse IO redirection. */2007 2008 ifile[0] = 0;2009 ofile[0] = 0;2010 efile[0] = 0;2011 2012 DB (DB_JOBS, ("child_execute_job (%s)\n", argv));2013 2014 while (isspace ((unsigned char)*argv))2015 argv++;2016 2017 if (*argv == 0)2018 return 0;2019 2020 sprintf (procname, "GMAKE_%05x", getpid () & 0xfffff);2021 pnamedsc.dsc$w_length = strlen(procname);2022 pnamedsc.dsc$a_pointer = procname;2023 pnamedsc.dsc$b_dtype = DSC$K_DTYPE_T;2024 pnamedsc.dsc$b_class = DSC$K_CLASS_S;2025 2026 /* Handle comments and redirection. */2027 for (p = argv, q = cmd; *p; p++, q++)2028 {2029 switch (*p)2030 {2031 case '#':2032 *p-- = 0;2033 *q-- = 0;2034 break;2035 case '\\':2036 p++;2037 if (*p == '\n')2038 p++;2039 if (isspace ((unsigned char)*p))2040 {2041 do { p++; } while (isspace ((unsigned char)*p));2042 p--;2043 }2044 *q = *p;2045 break;2046 case '<':2047 p = vms_redirect (&ifiledsc, ifile, p);2048 *q = ' ';2049 have_redirection = 1;2050 break;2051 case '>':2052 have_redirection = 1;2053 if (*(p-1) == '2')2054 {2055 q--;2056 if (strncmp (p, ">&1", 3) == 0)2057 {2058 p += 3;2059 strcpy (efile, "sys$output");2060 efiledsc.dsc$w_length = strlen(efile);2061 efiledsc.dsc$a_pointer = efile;2062 efiledsc.dsc$b_dtype = DSC$K_DTYPE_T;2063 efiledsc.dsc$b_class = DSC$K_CLASS_S;2064 }2065 else2066 {2067 p = vms_redirect (&efiledsc, efile, p);2068 }2069 }2070 else2071 {2072 p = vms_redirect (&ofiledsc, ofile, p);2073 }2074 *q = ' ';2075 break;2076 case '\n':2077 have_newline = 1;2078 default:2079 *q = *p;2080 break;2081 }2082 }2083 *q = *p;2084 2085 if (strncmp (cmd, "builtin_", 8) == 0)2086 {2087 child->pid = 270163;2088 child->efn = 0;2089 child->cstatus = 1;2090 2091 DB (DB_JOBS, (_("BUILTIN [%s][%s]\n"), cmd, cmd+8));2092 2093 p = cmd + 8;2094 2095 if ((*(p) == 'c')2096 && (*(p+1) == 'd')2097 && ((*(p+2) == ' ') || (*(p+2) == '\t')))2098 {2099 p += 3;2100 while ((*p == ' ') || (*p == '\t'))2101 p++;2102 DB (DB_JOBS, (_("BUILTIN CD %s\n"), p));2103 if (chdir (p))2104 return 0;2105 else2106 return 1;2107 }2108 else if ((*(p) == 'r')2109 && (*(p+1) == 'm')2110 && ((*(p+2) == ' ') || (*(p+2) == '\t')))2111 {2112 int in_arg;2113 2114 /* rm */2115 p += 3;2116 while ((*p == ' ') || (*p == '\t'))2117 p++;2118 in_arg = 1;2119 2120 DB (DB_JOBS, (_("BUILTIN RM %s\n"), p));2121 while (*p)2122 {2123 switch (*p)2124 {2125 case ' ':2126 case '\t':2127 if (in_arg)2128 {2129 *p++ = ';';2130 in_arg = 0;2131 }2132 break;2133 default:2134 break;2135 }2136 p++;2137 }2138 }2139 else2140 {2141 printf(_("Unknown builtin command '%s'\n"), cmd);2142 fflush(stdout);2143 return 0;2144 }2145 }2146 2147 /* Create a *.com file if either the command is too long for2148 lib$spawn, or the command contains a newline, or if redirection2149 is desired. Forcing commands with newlines into DCLs allows to2150 store search lists on user mode logicals. */2151 2152 if (strlen (cmd) > MAXCMDLEN2153 || (have_redirection != 0)2154 || (have_newline != 0))2155 {2156 FILE *outfile;2157 char c;2158 char *sep;2159 int alevel = 0; /* apostrophe level */2160 2161 if (strlen (cmd) == 0)2162 {2163 printf (_("Error, empty command\n"));2164 fflush (stdout);2165 return 0;2166 }2167 2168 outfile = open_tmpfile (&comname, "sys$scratch:CMDXXXXXX.COM");2169 if (outfile == 0)2170 pfatal_with_name (_("fopen (temporary file)"));2171 2172 if (ifile[0])2173 {2174 fprintf (outfile, "$ assign/user %s sys$input\n", ifile);2175 DB (DB_JOBS, (_("Redirected input from %s\n"), ifile));2176 ifiledsc.dsc$w_length = 0;2177 }2178 2179 if (efile[0])2180 {2181 fprintf (outfile, "$ define sys$error %s\n", efile);2182 DB (DB_JOBS, (_("Redirected error to %s\n"), efile));2183 efiledsc.dsc$w_length = 0;2184 }2185 2186 if (ofile[0])2187 {2188 fprintf (outfile, "$ define sys$output %s\n", ofile);2189 DB (DB_JOBS, (_("Redirected output to %s\n"), ofile));2190 ofiledsc.dsc$w_length = 0;2191 }2192 2193 p = sep = q = cmd;2194 for (c = '\n'; c; c = *q++)2195 {2196 switch (c)2197 {2198 case '\n':2199 /* At a newline, skip any whitespace around a leading $2200 from the command and issue exactly one $ into the DCL. */2201 while (isspace ((unsigned char)*p))2202 p++;2203 if (*p == '$')2204 p++;2205 while (isspace ((unsigned char)*p))2206 p++;2207 fwrite (p, 1, q - p, outfile);2208 fputc ('$', outfile);2209 fputc (' ', outfile);2210 /* Reset variables. */2211 p = sep = q;2212 break;2213 2214 /* Nice places for line breaks are after strings, after2215 comma or space and before slash. */2216 case '"':2217 q = vms_handle_apos (q);2218 sep = q;2219 break;2220 case ',':2221 case ' ':2222 sep = q;2223 break;2224 case '/':2225 case '\0':2226 sep = q - 1;2227 break;2228 default:2229 break;2230 }2231 if (sep - p > 78)2232 {2233 /* Enough stuff for a line. */2234 fwrite (p, 1, sep - p, outfile);2235 p = sep;2236 if (*sep)2237 {2238 /* The command continues. */2239 fputc ('-', outfile);2240 }2241 fputc ('\n', outfile);2242 }2243 }2244 2245 fwrite (p, 1, q - p, outfile);2246 fputc ('\n', outfile);2247 2248 fclose (outfile);2249 2250 sprintf (cmd, "$ @%s", comname);2251 2252 DB (DB_JOBS, (_("Executing %s instead\n"), cmd));2253 }2254 2255 cmddsc.dsc$w_length = strlen(cmd);2256 cmddsc.dsc$a_pointer = cmd;2257 cmddsc.dsc$b_dtype = DSC$K_DTYPE_T;2258 cmddsc.dsc$b_class = DSC$K_CLASS_S;2259 2260 child->efn = 0;2261 while (child->efn < 32 || child->efn > 63)2262 {2263 status = lib$get_ef ((unsigned long *)&child->efn);2264 if (!(status & 1))2265 return 0;2266 }2267 2268 sys$clref (child->efn);2269 2270 vms_jobsefnmask |= (1 << (child->efn - 32));2271 2272 /*2273 LIB$SPAWN [command-string]2274 [,input-file]2275 [,output-file]2276 [,flags]2277 [,process-name]2278 [,process-id] [,completion-status-address] [,byte-integer-event-flag-num]2279 [,AST-address] [,varying-AST-argument]2280 [,prompt-string] [,cli] [,table]2281 */2282 2283 #ifndef DONTWAITFORCHILD2284 /*2285 * Code to make ctrl+c and ctrl+y working.2286 * The problem starts with the synchronous case where after lib$spawn is2287 * called any input will go to the child. But with input re-directed,2288 * both control characters won't make it to any of the programs, neither2289 * the spawning nor to the spawned one. Hence the caller needs to spawn2290 * with CLI$M_NOWAIT to NOT give up the input focus. A sys$waitfr2291 * has to follow to simulate the wanted synchronous behaviour.2292 * The next problem is ctrl+y which isn't caught by the crtl and2293 * therefore isn't converted to SIGQUIT (for a signal handler which is2294 * already established). The only way to catch ctrl+y, is an AST2295 * assigned to the input channel. But ctrl+y handling of DCL needs to be2296 * disabled, otherwise it will handle it. Not to mention the previous2297 * ctrl+y handling of DCL needs to be re-established before make exits.2298 * One more: At the time of LIB$SPAWN signals are blocked. SIGQUIT will2299 * make it to the signal handler after the child "normally" terminates.2300 * This isn't enough. It seems reasonable for simple command lines like2301 * a 'cc foobar.c' spawned in a subprocess but it is unacceptable for2302 * spawning make. Therefore we need to abort the process in the AST.2303 *2304 * Prior to the spawn it is checked if an AST is already set up for2305 * ctrl+y, if not one is set up for a channel to SYS$COMMAND. In general2306 * this will work except if make is run in a batch environment, but there2307 * nobody can press ctrl+y. During the setup the DCL handling of ctrl+y2308 * is disabled and an exit handler is established to re-enable it.2309 * If the user interrupts with ctrl+y, the assigned AST will fire, force2310 * an abort to the subprocess and signal SIGQUIT, which will be caught by2311 * the already established handler and will bring us back to common code.2312 * After the spawn (now /nowait) a sys$waitfr simulates the /wait and2313 * enables the ctrl+y be delivered to this code. And the ctrl+c too,2314 * which the crtl converts to SIGINT and which is caught by the common2315 * signal handler. Because signals were blocked before entering this code2316 * sys$waitfr will always complete and the SIGQUIT will be processed after2317 * it (after termination of the current block, somewhere in common code).2318 * And SIGINT too will be delayed. That is ctrl+c can only abort when the2319 * current command completes. Anyway it's better than nothing :-)2320 */2321 2322 if (!setupYAstTried)2323 tryToSetupYAst();2324 status = lib$spawn (&cmddsc, /* cmd-string */2325 (ifiledsc.dsc$w_length == 0)?0:&ifiledsc, /* input-file */2326 (ofiledsc.dsc$w_length == 0)?0:&ofiledsc, /* output-file */2327 &spflags, /* flags */2328 &pnamedsc, /* proc name */2329 &child->pid, &child->cstatus, &child->efn,2330 0, 0,2331 0, 0, 0);2332 if (status & 1)2333 {2334 pidToAbort= child->pid;2335 status= sys$waitfr (child->efn);2336 pidToAbort= 0;2337 vmsHandleChildTerm(child);2338 }2339 #else2340 status = lib$spawn (&cmddsc,2341 (ifiledsc.dsc$w_length == 0)?0:&ifiledsc,2342 (ofiledsc.dsc$w_length == 0)?0:&ofiledsc,2343 &spflags,2344 &pnamedsc,2345 &child->pid, &child->cstatus, &child->efn,2346 vmsHandleChildTerm, child,2347 0, 0, 0);2348 #endif2349 2350 if (!(status & 1))2351 {2352 printf (_("Error spawning, %d\n") ,status);2353 fflush (stdout);2354 switch (status)2355 {2356 case 0x1c:2357 errno = EPROCLIM;2358 break;2359 default:2360 errno = EFAIL;2361 }2362 }2363 2364 if (comname && !ISDB (DB_JOBS))2365 unlink (comname);2366 2367 return (status & 1);2368 }2369 2370 #else /* !VMS */2371 1850 2372 1851 /* EMX: Start a child process. This function returns the new pid. */ 2373 # if defined __MSDOS__ || 1852 # if defined __MSDOS__ || defined __EMX__ 2374 1853 int 2375 1854 child_execute_job (int stdin_fd, int stdout_fd, char **argv, char **envp) … … 2409 1888 pid = exec_command (argv, envp); 2410 1889 2411 /* Restore stdout/stdin of the parent process. */ 2412 if (stdin_fd != 0 && dup2 (save_stdin, 0) != 0) 2413 fatal (NILF, _("restoring of stdin failed\n")); 2414 if (stdout_fd != 1 && dup2 (save_stdout, 1) != 1) 2415 fatal (NILF, _("restoring of stdout failed\n")); 1890 /* Restore stdout/stdin of the parent and close temporary FDs. */ 1891 if (stdin_fd != 0) 1892 { 1893 if (dup2 (save_stdin, 0) != 0) 1894 fatal (NILF, _("Could not restore stdin\n")); 1895 else 1896 close (save_stdin); 1897 } 1898 1899 if (stdout_fd != 1) 1900 { 1901 if (dup2 (save_stdout, 1) != 1) 1902 fatal (NILF, _("Could not restore stdout\n")); 1903 else 1904 close (save_stdout); 1905 } 2416 1906 2417 1907 return pid; … … 2440 1930 } 2441 1931 #endif /* !AMIGA && !__MSDOS__ */ 2442 #endif /* !VMS */2443 1932 #endif /* !WINDOWS32 */ 2444 1933 … … 2452 1941 int 2453 1942 # else 2454 1943 void 2455 1944 # endif 2456 1945 exec_command (char **argv, char **envp) … … 2492 1981 2493 1982 /* wait and reap last child */ 2494 while (hWaitPID = process_wait_for_any()) 1983 hWaitPID = process_wait_for_any(); 1984 while (hWaitPID) 2495 1985 { 2496 1986 /* was an error found on this process? */ … … 2560 2050 char **new_argv; 2561 2051 int argc; 2052 int i=1; 2562 2053 2563 2054 # ifdef __EMX__ … … 2578 2069 ++argc; 2579 2070 2071 # ifdef __EMX__ 2072 if (!unixy_shell) 2073 ++argc; 2074 # endif 2075 2580 2076 new_argv = (char **) alloca ((1 + argc + 1) * sizeof (char *)); 2581 2077 new_argv[0] = shell; 2582 new_argv[1] = argv[0]; 2078 2079 # ifdef __EMX__ 2080 if (!unixy_shell) 2081 { 2082 new_argv[1] = "/c"; 2083 ++i; 2084 --argc; 2085 } 2086 # endif 2087 2088 new_argv[i] = argv[0]; 2583 2089 while (argc > 0) 2584 2090 { 2585 new_argv[ 1+ argc] = argv[argc];2091 new_argv[i + argc] = argv[argc]; 2586 2092 --argc; 2587 2093 } … … 2751 2257 char* sh_chars; 2752 2258 char** sh_cmds; 2259 #elif defined(__riscos__) 2260 static char sh_chars[] = ""; 2261 static char *sh_cmds[] = { 0 }; 2753 2262 #else /* must be UNIX-ish */ 2754 2263 static char sh_chars[] = "#;\"*?[]&|<>(){}$`^~!"; … … 3021 2530 register int j; 3022 2531 for (j = 0; sh_cmds[j] != 0; ++j) 3023 if (streq (sh_cmds[j], new_argv[0])) 3024 goto slow; 2532 { 2533 if (streq (sh_cmds[j], new_argv[0])) 2534 goto slow; 2535 # ifdef __EMX__ 2536 /* Non-Unix shells are case insensitive. */ 2537 if (!unixy_shell 2538 && strcasecmp (sh_cmds[j], new_argv[0]) == 0) 2539 goto slow; 2540 # endif 2541 } 3025 2542 } 3026 2543 … … 3060 2577 /* Line was empty. */ 3061 2578 return 0; 3062 else 3063 2579 2580 return new_argv; 3064 2581 3065 2582 slow:; … … 3210 2727 int id = GetCurrentProcessId(); 3211 2728 PATH_VAR(fbuf); 3212 char* fname = NULL;3213 2729 3214 2730 /* create a file name */ 3215 2731 sprintf(fbuf, "make%d", id); 3216 fname = tempnam(".", fbuf); 3217 3218 /* create batch file name */ 3219 *batch_filename_ptr = xmalloc(strlen(fname) + 5); 3220 strcpy(*batch_filename_ptr, fname); 3221 3222 /* make sure path name is in DOS backslash format */ 3223 if (!unixy_shell) { 3224 fname = *batch_filename_ptr; 3225 for (i = 0; fname[i] != '\0'; ++i) 3226 if (fname[i] == '/') 3227 fname[i] = '\\'; 3228 strcat(*batch_filename_ptr, ".bat"); 3229 } else { 3230 strcat(*batch_filename_ptr, ".sh"); 3231 } 2732 *batch_filename_ptr = create_batch_filename (fbuf, unixy_shell); 3232 2733 3233 2734 DB (DB_JOBS, (_("Creating temporary batch file %s\n"), … … 3258 2759 (char *) 0, (char *) 0, 3259 2760 (char **) 0); 3260 # 2761 #ifdef __EMX__ 3261 2762 else if (!unixy_shell) 3262 2763 { 3263 /* new_line is local, must not be freed therefore */ 3264 char *p, *q; 3265 int quote; 3266 size_t index; 3267 size_t len; 3268 3269 /* handle quotes 3270 We have to remove all double quotes and to split the line 3271 into distinct arguments because of the strange handling 3272 of builtin commands by cmd: 'echo "bla"' prints "bla" 3273 (with quotes) while 'c:\bin\echo.exe "bla"' prints bla 3274 (without quotes). Some programs like autoconf rely 3275 on the second behaviour. */ 3276 3277 len = strlen (new_line) + 1; 3278 3279 /* More than 1 arg per character is impossible. */ 3280 new_argv = (char **) xmalloc (len * sizeof (char *)); 3281 3282 /* All the args can fit in a buffer as big as new_line is. */ 3283 new_argv[0] = (char *) xmalloc (len); 3284 3285 index = 0; 3286 quote = 0; 3287 q = new_line; 3288 p = new_argv[index]; 3289 while(*q != '\0') 3290 { 3291 /* searching for closing quote */ 3292 if (quote) 3293 { 3294 if (*q == quote) 3295 { 3296 /* remove the quote */ 3297 q++; 3298 quote = 0; 3299 } 3300 else /* normal character: copy it */ 3301 *p++ = *q++; 3302 } 3303 3304 /* searching for opening quote */ 3305 else if (*q == '\"' 3306 # ifndef NO_CMD_DEFAULT 3307 || *q == '\'' 3308 # endif 3309 ) 3310 { 3311 /* remove opening quote */ 3312 quote = *q; 3313 q++; 3314 } 3315 3316 /* spaces outside of a quoted string: remove them 3317 and start a new argument */ 3318 else if (*q == ' ' || *q == '\t') 3319 { 3320 *p++ = '\0'; /* trailing '\0' for last argument */ 3321 3322 /* remove all successive spaces */ 3323 do 3324 { 3325 q++; 3326 } 3327 while(*q == ' ' || *q == '\t'); 3328 3329 /* start new argument */ 3330 index++; 3331 new_argv[index] = p; 3332 } 3333 3334 /* normal character (no space) outside a quoted string*/ 3335 else 3336 *p++ = *q++; 3337 } /* end while() */ 3338 3339 *p = '\0'; /* trailing '\0' for the last argument */ 3340 new_argv[index + 1] = NULL; 3341 3342 # ifndef NO_CMD_DEFAULT 3343 /* special case: echo x="y" 3344 (e.g. autoconf uses this to determine whether make works) 3345 this is pure idioty but cmd works this way: 3346 if 'echo' and 'x="y"' are two different arguments cmd 3347 will print '"x="y""' but if they are only one argument 3348 cmd will print 'bla="blurb"' as it should be 3349 note: if we do not allow cmd to be the default shell 3350 we do not need this kind of voodoo */ 3351 if (index == 3 && strcasecmp(new_argv[2], "echo") == 0) 3352 { 3353 new_argv[2][4] = ' '; 3354 new_argv[3] = NULL; 3355 } 3356 # endif 2764 /* new_line is local, must not be freed therefore 2765 We use line here instead of new_line because we run the shell 2766 manually. */ 2767 size_t line_len = strlen (line); 2768 char *p = new_line; 2769 char *q = new_line; 2770 memcpy (new_line, line, line_len + 1); 2771 /* replace all backslash-newline combination and also following tabs */ 2772 while (*q != '\0') 2773 { 2774 if (q[0] == '\\' && q[1] == '\n') 2775 { 2776 q += 2; /* remove '\\' and '\n' */ 2777 if (q[0] == '\t') 2778 q++; /* remove 1st tab in the next line */ 2779 } 2780 else 2781 *p++ = *q++; 2782 } 2783 *p = '\0'; 2784 2785 # ifndef NO_CMD_DEFAULT 2786 if (strnicmp (new_line, "echo", 4) == 0 2787 && (new_line[4] == ' ' || new_line[4] == '\t')) 2788 { 2789 /* the builtin echo command: handle it separately */ 2790 size_t echo_len = line_len - 5; 2791 char *echo_line = new_line + 5; 2792 2793 /* special case: echo 'x="y"' 2794 cmd works this way: a string is printed as is, i.e., no quotes 2795 are removed. But autoconf uses a command like echo 'x="y"' to 2796 determine whether make works. autoconf expects the output x="y" 2797 so we will do exactly that. 2798 Note: if we do not allow cmd to be the default shell 2799 we do not need this kind of voodoo */ 2800 if (echo_line[0] == '\'' 2801 && echo_line[echo_len - 1] == '\'' 2802 && strncmp (echo_line + 1, "ac_maketemp=", 2803 strlen ("ac_maketemp=")) == 0) 2804 { 2805 /* remove the enclosing quotes */ 2806 memmove (echo_line, echo_line + 1, echo_len - 2); 2807 echo_line[echo_len - 2] = '\0'; 2808 } 2809 } 2810 # endif 2811 2812 { 2813 /* Let the shell decide what to do. Put the command line into the 2814 2nd command line argument and hope for the best ;-) */ 2815 size_t sh_len = strlen (shell); 2816 2817 /* exactly 3 arguments + NULL */ 2818 new_argv = (char **) xmalloc (4 * sizeof (char *)); 2819 /* Exactly strlen(shell) + strlen("/c") + strlen(line) + 3 times 2820 the trailing '\0' */ 2821 new_argv[0] = (char *) malloc (sh_len + line_len + 5); 2822 memcpy (new_argv[0], shell, sh_len + 1); 2823 new_argv[1] = new_argv[0] + sh_len + 1; 2824 memcpy (new_argv[1], "/c", 3); 2825 new_argv[2] = new_argv[1] + 3; 2826 memcpy (new_argv[2], new_line, line_len + 1); 2827 new_argv[3] = NULL; 2828 } 3357 2829 } 3358 2830 #elif defined(__MSDOS__) … … 3535 3007 } 3536 3008 #endif /* !HAPE_DUP2 && !_AMIGA */ 3009 3010 /* On VMS systems, include special VMS functions. */ 3011 3012 #ifdef VMS 3013 #include "vmsjobs.c" 3014 #endif
Note:
See TracChangeset
for help on using the changeset viewer.