mirror of
https://github.com/mirror/make.git
synced 2024-12-27 13:20:34 +08:00
Support the -Orecurse option properly.
In this mode we still collect all the output from a given target and dump it at once. However we don't treat recursive lines any differently from non-recursive lines. Also we don't print enter/leave messages after every dump. However we do ensure that we always print them once to stdout, so the parent make will collect it properly.
This commit is contained in:
parent
deff9dacc9
commit
c5bfa40044
16
ChangeLog
16
ChangeLog
@ -1,3 +1,19 @@
|
|||||||
|
2013-09-14 Paul Smith <psmith@gnu.org>
|
||||||
|
|
||||||
|
* misc.c (set_append_mode, open_tmpfd, open_tmpfile): Move to output.c.
|
||||||
|
* misc.h: Ditto.
|
||||||
|
* output.h: Ditto.
|
||||||
|
* main.c (main): Move stdio init into output.c:output_init().
|
||||||
|
Change open_tmpfile() to output_tmpfile().
|
||||||
|
* output.c: Rename open_*() to output_*(). set_append_mode() and
|
||||||
|
open_tmpfd() are static.
|
||||||
|
(_outputs, log_working_directory): Accept a struct output and
|
||||||
|
print to that rather than the global context.
|
||||||
|
(output_dump): In recurse mode print enter/leave once for the
|
||||||
|
whole makefile.
|
||||||
|
(output_init): Initialize this processes stdio as well as child's.
|
||||||
|
* vmsjobs.c: Reformat to be closer to convention.
|
||||||
|
|
||||||
2013-09-12 Paul Smith <psmith@gnu.org>
|
2013-09-12 Paul Smith <psmith@gnu.org>
|
||||||
|
|
||||||
Rework output to handle synchronization and directory logging more
|
Rework output to handle synchronization and directory logging more
|
||||||
|
@ -1846,7 +1846,7 @@ func_shell_base (char *o, char **argv, int trim_newlines)
|
|||||||
return o;
|
return o;
|
||||||
|
|
||||||
/* Note the mktemp() is a security hole, but this only runs on Amiga.
|
/* Note the mktemp() is a security hole, but this only runs on Amiga.
|
||||||
Ideally we would use main.c:open_tmpfile(), but this uses a special
|
Ideally we would use output_tmpfile(), but this uses a special
|
||||||
Open(), not fopen(), and I'm not familiar enough with the code to mess
|
Open(), not fopen(), and I'm not familiar enough with the code to mess
|
||||||
with it. */
|
with it. */
|
||||||
strcpy (tmp_output, "t:MakeshXXXXXXXX");
|
strcpy (tmp_output, "t:MakeshXXXXXXXX");
|
||||||
|
4
job.c
4
job.c
@ -1738,7 +1738,7 @@ new_job (struct file *file)
|
|||||||
'struct child', and add that to the chain. */
|
'struct child', and add that to the chain. */
|
||||||
|
|
||||||
c = xcalloc (sizeof (struct child));
|
c = xcalloc (sizeof (struct child));
|
||||||
output_init (&c->output, output_sync);
|
output_init (&c->output);
|
||||||
|
|
||||||
c->file = file;
|
c->file = file;
|
||||||
c->sh_batch_file = NULL;
|
c->sh_batch_file = NULL;
|
||||||
@ -2588,7 +2588,7 @@ construct_command_argv_internal (char *line, char **restp, char *shell,
|
|||||||
"date", "del", "dir", "echo", "echo.",
|
"date", "del", "dir", "echo", "echo.",
|
||||||
"endlocal", "erase", "exit", "for", "ftype",
|
"endlocal", "erase", "exit", "for", "ftype",
|
||||||
"goto", "if", "if", "md", "mkdir", "move",
|
"goto", "if", "if", "md", "mkdir", "move",
|
||||||
"path", "pause", "prompt", "rd", "rem", "ren",
|
"path", "pause", "prompt", "rd", "rem", "ren",
|
||||||
"rename", "rmdir", "set", "setlocal",
|
"rename", "rmdir", "set", "setlocal",
|
||||||
"shift", "time", "title", "type", "ver",
|
"shift", "time", "title", "type", "ver",
|
||||||
"verify", "vol", ":", 0 };
|
"verify", "vol", ":", 0 };
|
||||||
|
55
main.c
55
main.c
@ -954,7 +954,7 @@ find_and_set_default_shell (const char *token)
|
|||||||
{
|
{
|
||||||
*ep = '\0';
|
*ep = '\0';
|
||||||
|
|
||||||
sprintf (sh_path, "%s/%s", p, search_token);
|
sprintf (sh_path, "%s/%s", p, search_token);
|
||||||
if (_access (sh_path, 0) == 0)
|
if (_access (sh_path, 0) == 0)
|
||||||
{
|
{
|
||||||
default_shell = xstrdup (w32ify (sh_path, 0));
|
default_shell = xstrdup (w32ify (sh_path, 0));
|
||||||
@ -974,15 +974,15 @@ find_and_set_default_shell (const char *token)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* be sure to check last element of Path */
|
/* be sure to check last element of Path */
|
||||||
if (p && *p)
|
if (p && *p)
|
||||||
{
|
{
|
||||||
sprintf (sh_path, "%s/%s", p, search_token);
|
sprintf (sh_path, "%s/%s", p, search_token);
|
||||||
if (_access (sh_path, 0) == 0)
|
if (_access (sh_path, 0) == 0)
|
||||||
{
|
{
|
||||||
default_shell = xstrdup (w32ify (sh_path, 0));
|
default_shell = xstrdup (w32ify (sh_path, 0));
|
||||||
sh_found = 1;
|
sh_found = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sh_found)
|
if (sh_found)
|
||||||
DB (DB_VERBOSE,
|
DB (DB_VERBOSE,
|
||||||
@ -1154,24 +1154,7 @@ main (int argc, char **argv, char **envp)
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Make sure stdout is line-buffered. */
|
output_init (NULL);
|
||||||
|
|
||||||
#ifdef HAVE_SETVBUF
|
|
||||||
# ifdef SETVBUF_REVERSED
|
|
||||||
setvbuf (stdout, _IOLBF, xmalloc (BUFSIZ), BUFSIZ);
|
|
||||||
# else /* setvbuf not reversed. */
|
|
||||||
/* Some buggy systems lose if we pass 0 instead of allocating ourselves. */
|
|
||||||
setvbuf (stdout, 0, _IOLBF, BUFSIZ);
|
|
||||||
# endif /* setvbuf reversed. */
|
|
||||||
#elif HAVE_SETLINEBUF
|
|
||||||
setlinebuf (stdout);
|
|
||||||
#endif /* setlinebuf missing. */
|
|
||||||
|
|
||||||
/* Configure stdout/stderr to be in append mode.
|
|
||||||
This keeps parallel jobs from losing output due to overlapping writes. */
|
|
||||||
|
|
||||||
set_append_mode (fileno (stdout));
|
|
||||||
set_append_mode (fileno (stderr));
|
|
||||||
|
|
||||||
/* Figure out where this program lives. */
|
/* Figure out where this program lives. */
|
||||||
|
|
||||||
@ -1418,16 +1401,16 @@ main (int argc, char **argv, char **envp)
|
|||||||
/* Set always_make_flag if -B was given and we've not restarted already. */
|
/* Set always_make_flag if -B was given and we've not restarted already. */
|
||||||
always_make_flag = always_make_set && (restarts == 0);
|
always_make_flag = always_make_set && (restarts == 0);
|
||||||
|
|
||||||
/* Print version information. */
|
/* Print version information, and exit. */
|
||||||
if (print_version_flag || ISDB (DB_BASIC))
|
if (print_version_flag)
|
||||||
{
|
{
|
||||||
print_version ();
|
print_version ();
|
||||||
|
die (0);
|
||||||
/* 'make --version' is supposed to just print the version and exit. */
|
|
||||||
if (print_version_flag)
|
|
||||||
die (0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ISDB (DB_BASIC))
|
||||||
|
print_version ();
|
||||||
|
|
||||||
#ifndef VMS
|
#ifndef VMS
|
||||||
/* Set the "MAKE_COMMAND" variable to the name we were invoked with.
|
/* Set the "MAKE_COMMAND" variable to the name we were invoked with.
|
||||||
(If it is a relative pathname with a slash, prepend our directory name
|
(If it is a relative pathname with a slash, prepend our directory name
|
||||||
@ -1670,7 +1653,7 @@ main (int argc, char **argv, char **envp)
|
|||||||
#endif /* !HAVE_DOS_PATHS */
|
#endif /* !HAVE_DOS_PATHS */
|
||||||
|
|
||||||
strcat (template, DEFAULT_TMPFILE);
|
strcat (template, DEFAULT_TMPFILE);
|
||||||
outfile = open_tmpfile (&stdin_nm, template);
|
outfile = output_tmpfile (&stdin_nm, template);
|
||||||
if (outfile == 0)
|
if (outfile == 0)
|
||||||
pfatal_with_name (_("fopen (temporary file)"));
|
pfatal_with_name (_("fopen (temporary file)"));
|
||||||
while (!feof (stdin) && ! ferror (stdin))
|
while (!feof (stdin) && ! ferror (stdin))
|
||||||
@ -1945,7 +1928,7 @@ main (int argc, char **argv, char **envp)
|
|||||||
|
|
||||||
#ifdef WINDOWS32
|
#ifdef WINDOWS32
|
||||||
/* sub_proc.c cannot wait for more than MAXIMUM_WAIT_OBJECTS objects
|
/* sub_proc.c cannot wait for more than MAXIMUM_WAIT_OBJECTS objects
|
||||||
* and one of them is the job-server semaphore object. Limit the
|
* and one of them is the job-server semaphore object. Limit the
|
||||||
* number of available job slots to (MAXIMUM_WAIT_OBJECTS - 1). */
|
* number of available job slots to (MAXIMUM_WAIT_OBJECTS - 1). */
|
||||||
|
|
||||||
if (job_slots >= MAXIMUM_WAIT_OBJECTS)
|
if (job_slots >= MAXIMUM_WAIT_OBJECTS)
|
||||||
|
@ -449,9 +449,6 @@ int alpha_compare (const void *, const void *);
|
|||||||
void print_spaces (unsigned int);
|
void print_spaces (unsigned int);
|
||||||
char *find_percent (char *);
|
char *find_percent (char *);
|
||||||
const char *find_percent_cached (const char **);
|
const char *find_percent_cached (const char **);
|
||||||
void set_append_mode (int);
|
|
||||||
int open_tmpfd (void);
|
|
||||||
FILE *open_tmpfile (char **, const char *);
|
|
||||||
|
|
||||||
#ifndef NO_ARCHIVES
|
#ifndef NO_ARCHIVES
|
||||||
int ar_name (const char *);
|
int ar_name (const char *);
|
||||||
|
96
misc.c
96
misc.c
@ -704,7 +704,7 @@ child_access (void)
|
|||||||
|
|
||||||
#endif /* GETLOADAVG_PRIVILEGED */
|
#endif /* GETLOADAVG_PRIVILEGED */
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef NEED_GET_PATH_MAX
|
#ifdef NEED_GET_PATH_MAX
|
||||||
unsigned int
|
unsigned int
|
||||||
get_path_max (void)
|
get_path_max (void)
|
||||||
@ -725,100 +725,6 @@ get_path_max (void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Set a file descriptor to be in O_APPEND mode.
|
|
||||||
If it fails, just ignore it. */
|
|
||||||
|
|
||||||
void
|
|
||||||
set_append_mode (int fd)
|
|
||||||
{
|
|
||||||
#if defined(F_GETFL) && defined(F_SETFL) && defined(O_APPEND)
|
|
||||||
int flags = fcntl (fd, F_GETFL, 0);
|
|
||||||
if (flags >= 0)
|
|
||||||
fcntl (fd, F_SETFL, flags | O_APPEND);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Provide support for temporary files. */
|
|
||||||
|
|
||||||
#ifndef HAVE_STDLIB_H
|
|
||||||
# ifdef HAVE_MKSTEMP
|
|
||||||
int mkstemp (char *template);
|
|
||||||
# else
|
|
||||||
char *mktemp (char *template);
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* This is only used by output-sync, and it may not be portable. */
|
|
||||||
#ifdef OUTPUT_SYNC
|
|
||||||
|
|
||||||
/* Returns a file descriptor to a temporary file. The file is automatically
|
|
||||||
closed/deleted on exit. Don't use a FILE* stream. */
|
|
||||||
int
|
|
||||||
open_tmpfd ()
|
|
||||||
{
|
|
||||||
int fd = -1;
|
|
||||||
FILE *tfile = tmpfile ();
|
|
||||||
|
|
||||||
if (! tfile)
|
|
||||||
pfatal_with_name ("tmpfile");
|
|
||||||
|
|
||||||
/* Create a duplicate so we can close the stream. */
|
|
||||||
fd = dup (fileno (tfile));
|
|
||||||
if (fd < 0)
|
|
||||||
pfatal_with_name ("dup");
|
|
||||||
|
|
||||||
fclose (tfile);
|
|
||||||
|
|
||||||
set_append_mode (fd);
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
FILE *
|
|
||||||
open_tmpfile (char **name, const char *template)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_FDOPEN
|
|
||||||
int fd;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined HAVE_MKSTEMP || defined HAVE_MKTEMP
|
|
||||||
# define TEMPLATE_LEN strlen (template)
|
|
||||||
#else
|
|
||||||
# define TEMPLATE_LEN L_tmpnam
|
|
||||||
#endif
|
|
||||||
*name = xmalloc (TEMPLATE_LEN + 1);
|
|
||||||
strcpy (*name, template);
|
|
||||||
|
|
||||||
#if defined HAVE_MKSTEMP && defined HAVE_FDOPEN
|
|
||||||
/* It's safest to use mkstemp(), if we can. */
|
|
||||||
fd = mkstemp (*name);
|
|
||||||
if (fd == -1)
|
|
||||||
return 0;
|
|
||||||
return fdopen (fd, "w");
|
|
||||||
#else
|
|
||||||
# ifdef HAVE_MKTEMP
|
|
||||||
(void) mktemp (*name);
|
|
||||||
# else
|
|
||||||
(void) tmpnam (*name);
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# ifdef HAVE_FDOPEN
|
|
||||||
/* Can't use mkstemp(), but guard against a race condition. */
|
|
||||||
fd = open (*name, O_CREAT|O_EXCL|O_WRONLY, 0600);
|
|
||||||
if (fd == -1)
|
|
||||||
return 0;
|
|
||||||
return fdopen (fd, "w");
|
|
||||||
# else
|
|
||||||
/* Not secure, but what can we do? */
|
|
||||||
return fopen (*name, "w");
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* This code is stolen from gnulib.
|
/* This code is stolen from gnulib.
|
||||||
If/when we abandon the requirement to work with K&R compilers, we can
|
If/when we abandon the requirement to work with K&R compilers, we can
|
||||||
remove this (and perhaps other parts of GNU make!) and migrate to using
|
remove this (and perhaps other parts of GNU make!) and migrate to using
|
||||||
|
274
output.c
274
output.c
@ -45,7 +45,7 @@ static unsigned int stdio_traced = 0;
|
|||||||
#define va_copy(_d, _s) ((_d) = (_s))
|
#define va_copy(_d, _s) ((_d) = (_s))
|
||||||
#define snprintf msc_vsnprintf
|
#define snprintf msc_vsnprintf
|
||||||
static int
|
static int
|
||||||
msc_vsnprintf(char *str, size_t size, const char *format, va_list ap)
|
msc_vsnprintf (char *str, size_t size, const char *format, va_list ap)
|
||||||
{
|
{
|
||||||
int len = -1;
|
int len = -1;
|
||||||
|
|
||||||
@ -60,9 +60,9 @@ msc_vsnprintf(char *str, size_t size, const char *format, va_list ap)
|
|||||||
|
|
||||||
/* Write a string to the current STDOUT or STDERR. */
|
/* Write a string to the current STDOUT or STDERR. */
|
||||||
static void
|
static void
|
||||||
_outputs (int is_err, const char *msg)
|
_outputs (struct output *out, int is_err, const char *msg)
|
||||||
{
|
{
|
||||||
if (! output_context || ! output_context->syncout)
|
if (! out || ! out->syncout)
|
||||||
{
|
{
|
||||||
FILE *f = is_err ? stderr : stdout;
|
FILE *f = is_err ? stderr : stdout;
|
||||||
fputs (msg, f);
|
fputs (msg, f);
|
||||||
@ -70,7 +70,7 @@ _outputs (int is_err, const char *msg)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int fd = is_err ? output_context->err : output_context->out;
|
int fd = is_err ? out->err : out->out;
|
||||||
int len = strlen (msg);
|
int len = strlen (msg);
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ _outputs (int is_err, const char *msg)
|
|||||||
left (according to ENTERING) the current directory. */
|
left (according to ENTERING) the current directory. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
log_working_directory (int entering)
|
log_working_directory (struct output *out, int entering)
|
||||||
{
|
{
|
||||||
static char *buf = NULL;
|
static char *buf = NULL;
|
||||||
static unsigned int len = 0;
|
static unsigned int len = 0;
|
||||||
@ -100,10 +100,6 @@ log_working_directory (int entering)
|
|||||||
const char *fmt;
|
const char *fmt;
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
/* Only print if directory logging is enabled. */
|
|
||||||
if (entering && ! print_directory_flag)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Get enough space for the longest possible output. */
|
/* Get enough space for the longest possible output. */
|
||||||
need = strlen (program) + INTEGER_LENGTH + 2 + 1;
|
need = strlen (program) + INTEGER_LENGTH + 2 + 1;
|
||||||
if (starting_directory)
|
if (starting_directory)
|
||||||
@ -158,10 +154,23 @@ log_working_directory (int entering)
|
|||||||
else
|
else
|
||||||
sprintf (p, fmt, program, makelevel, starting_directory);
|
sprintf (p, fmt, program, makelevel, starting_directory);
|
||||||
|
|
||||||
_outputs (0, buf);
|
_outputs (out, 0, buf);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set a file descriptor to be in O_APPEND mode.
|
||||||
|
If it fails, just ignore it. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_append_mode (int fd)
|
||||||
|
{
|
||||||
|
#if defined(F_GETFL) && defined(F_SETFL) && defined(O_APPEND)
|
||||||
|
int flags = fcntl (fd, F_GETFL, 0);
|
||||||
|
if (flags >= 0)
|
||||||
|
fcntl (fd, F_SETFL, flags | O_APPEND);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef OUTPUT_SYNC
|
#ifdef OUTPUT_SYNC
|
||||||
@ -277,6 +286,73 @@ release_semaphore (void *sem)
|
|||||||
perror ("fcntl()");
|
perror ("fcntl()");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns a file descriptor to a temporary file. The file is automatically
|
||||||
|
closed/deleted on exit. Don't use a FILE* stream. */
|
||||||
|
int
|
||||||
|
output_tmpfd ()
|
||||||
|
{
|
||||||
|
int fd = -1;
|
||||||
|
FILE *tfile = tmpfile ();
|
||||||
|
|
||||||
|
if (! tfile)
|
||||||
|
pfatal_with_name ("tmpfile");
|
||||||
|
|
||||||
|
/* Create a duplicate so we can close the stream. */
|
||||||
|
fd = dup (fileno (tfile));
|
||||||
|
if (fd < 0)
|
||||||
|
pfatal_with_name ("dup");
|
||||||
|
|
||||||
|
fclose (tfile);
|
||||||
|
|
||||||
|
set_append_mode (fd);
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adds file descriptors to the child structure to support output_sync; one
|
||||||
|
for stdout and one for stderr as long as they are open. If stdout and
|
||||||
|
stderr share a device they can share a temp file too.
|
||||||
|
Will reset output_sync on error. */
|
||||||
|
static void
|
||||||
|
setup_tmpfile (struct output *out)
|
||||||
|
{
|
||||||
|
/* Is make's stdout going to the same place as stderr? */
|
||||||
|
static int combined_output = -1;
|
||||||
|
|
||||||
|
if (combined_output < 0)
|
||||||
|
combined_output = sync_init ();
|
||||||
|
|
||||||
|
if (STREAM_OK (stdout))
|
||||||
|
{
|
||||||
|
int fd = output_tmpfd ();
|
||||||
|
if (fd < 0)
|
||||||
|
goto error;
|
||||||
|
CLOSE_ON_EXEC (fd);
|
||||||
|
out->out = fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (STREAM_OK (stderr))
|
||||||
|
{
|
||||||
|
if (out->out != OUTPUT_NONE && combined_output)
|
||||||
|
out->err = out->out;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int fd = output_tmpfd ();
|
||||||
|
if (fd < 0)
|
||||||
|
goto error;
|
||||||
|
CLOSE_ON_EXEC (fd);
|
||||||
|
out->err = fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* If we failed to create a temp file, disable output sync going forward. */
|
||||||
|
error:
|
||||||
|
output_close (out);
|
||||||
|
output_sync = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Synchronize the output of jobs in -j mode to keep the results of
|
/* Synchronize the output of jobs in -j mode to keep the results of
|
||||||
each job together. This is done by holding the results in temp files,
|
each job together. This is done by holding the results in temp files,
|
||||||
one for stdout and potentially another for stderr, and only releasing
|
one for stdout and potentially another for stderr, and only releasing
|
||||||
@ -290,15 +366,15 @@ output_dump (struct output *out)
|
|||||||
|
|
||||||
if (outfd_not_empty || errfd_not_empty)
|
if (outfd_not_empty || errfd_not_empty)
|
||||||
{
|
{
|
||||||
int logged = 0;
|
int traced = 0;
|
||||||
|
|
||||||
/* Try to acquire the semaphore. If it fails, dump the output
|
/* Try to acquire the semaphore. If it fails, dump the output
|
||||||
unsynchronized; still better than silently discarding it. */
|
unsynchronized; still better than silently discarding it. */
|
||||||
void *sem = acquire_semaphore ();
|
void *sem = acquire_semaphore ();
|
||||||
|
|
||||||
/* Log the working directory, if we need to. */
|
/* Log the working directory for this dump. */
|
||||||
if (out->syncout)
|
if (print_directory_flag && output_sync != OUTPUT_SYNC_RECURSE)
|
||||||
logged = log_working_directory (1);
|
traced = log_working_directory (output_context, 1);
|
||||||
|
|
||||||
/* We've entered the "critical section" during which a lock is held. We
|
/* We've entered the "critical section" during which a lock is held. We
|
||||||
want to keep it as short as possible. */
|
want to keep it as short as possible. */
|
||||||
@ -307,8 +383,8 @@ output_dump (struct output *out)
|
|||||||
if (errfd_not_empty && out->err != out->out)
|
if (errfd_not_empty && out->err != out->out)
|
||||||
pump_from_tmp (out->err, stderr);
|
pump_from_tmp (out->err, stderr);
|
||||||
|
|
||||||
if (logged)
|
if (traced)
|
||||||
log_working_directory (0);
|
log_working_directory (output_context, 0);
|
||||||
|
|
||||||
/* Exit the critical section. */
|
/* Exit the critical section. */
|
||||||
if (sem)
|
if (sem)
|
||||||
@ -329,58 +405,88 @@ output_dump (struct output *out)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adds file descriptors to the child structure to support output_sync; one
|
|
||||||
for stdout and one for stderr as long as they are open. If stdout and
|
|
||||||
stderr share a device they can share a temp file too.
|
|
||||||
Will reset output_sync on error. */
|
|
||||||
static void
|
|
||||||
setup_tmpfile (struct output *out)
|
|
||||||
{
|
|
||||||
/* Is make's stdout going to the same place as stderr? */
|
|
||||||
static int combined_output = -1;
|
|
||||||
|
|
||||||
if (combined_output < 0)
|
|
||||||
combined_output = sync_init ();
|
|
||||||
|
|
||||||
if (STREAM_OK (stdout))
|
|
||||||
{
|
|
||||||
int fd = open_tmpfd ();
|
|
||||||
if (fd < 0)
|
|
||||||
goto error;
|
|
||||||
CLOSE_ON_EXEC (fd);
|
|
||||||
out->out = fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (STREAM_OK (stderr))
|
|
||||||
{
|
|
||||||
if (out->out != OUTPUT_NONE && combined_output)
|
|
||||||
out->err = out->out;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int fd = open_tmpfd ();
|
|
||||||
if (fd < 0)
|
|
||||||
goto error;
|
|
||||||
CLOSE_ON_EXEC (fd);
|
|
||||||
out->err = fd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* If we failed to create a temp file, disable output sync going forward. */
|
|
||||||
error:
|
|
||||||
output_close (out);
|
|
||||||
output_sync = 0;
|
|
||||||
}
|
|
||||||
#endif /* OUTPUT_SYNC */
|
#endif /* OUTPUT_SYNC */
|
||||||
|
|
||||||
|
|
||||||
void
|
/* Provide support for temporary files. */
|
||||||
output_init (struct output *out, unsigned int syncout)
|
|
||||||
|
#ifndef HAVE_STDLIB_H
|
||||||
|
# ifdef HAVE_MKSTEMP
|
||||||
|
int mkstemp (char *template);
|
||||||
|
# else
|
||||||
|
char *mktemp (char *template);
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FILE *
|
||||||
|
output_tmpfile (char **name, const char *template)
|
||||||
{
|
{
|
||||||
out->out = out->err = OUTPUT_NONE;
|
#ifdef HAVE_FDOPEN
|
||||||
out->syncout = !!syncout;
|
int fd;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined HAVE_MKSTEMP || defined HAVE_MKTEMP
|
||||||
|
# define TEMPLATE_LEN strlen (template)
|
||||||
|
#else
|
||||||
|
# define TEMPLATE_LEN L_tmpnam
|
||||||
|
#endif
|
||||||
|
*name = xmalloc (TEMPLATE_LEN + 1);
|
||||||
|
strcpy (*name, template);
|
||||||
|
|
||||||
|
#if defined HAVE_MKSTEMP && defined HAVE_FDOPEN
|
||||||
|
/* It's safest to use mkstemp(), if we can. */
|
||||||
|
fd = mkstemp (*name);
|
||||||
|
if (fd == -1)
|
||||||
|
return 0;
|
||||||
|
return fdopen (fd, "w");
|
||||||
|
#else
|
||||||
|
# ifdef HAVE_MKTEMP
|
||||||
|
(void) mktemp (*name);
|
||||||
|
# else
|
||||||
|
(void) tmpnam (*name);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifdef HAVE_FDOPEN
|
||||||
|
/* Can't use mkstemp(), but guard against a race condition. */
|
||||||
|
fd = open (*name, O_CREAT|O_EXCL|O_WRONLY, 0600);
|
||||||
|
if (fd == -1)
|
||||||
|
return 0;
|
||||||
|
return fdopen (fd, "w");
|
||||||
|
# else
|
||||||
|
/* Not secure, but what can we do? */
|
||||||
|
return fopen (*name, "w");
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
output_init (struct output *out)
|
||||||
|
{
|
||||||
|
if (out)
|
||||||
|
{
|
||||||
|
out->out = out->err = OUTPUT_NONE;
|
||||||
|
out->syncout = !!output_sync;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configure this instance of make. Be sure stdout is line-buffered. */
|
||||||
|
|
||||||
|
#ifdef HAVE_SETVBUF
|
||||||
|
# ifdef SETVBUF_REVERSED
|
||||||
|
setvbuf (stdout, _IOLBF, xmalloc (BUFSIZ), BUFSIZ);
|
||||||
|
# else /* setvbuf not reversed. */
|
||||||
|
/* Some buggy systems lose if we pass 0 instead of allocating ourselves. */
|
||||||
|
setvbuf (stdout, 0, _IOLBF, BUFSIZ);
|
||||||
|
# endif /* setvbuf reversed. */
|
||||||
|
#elif HAVE_SETLINEBUF
|
||||||
|
setlinebuf (stdout);
|
||||||
|
#endif /* setlinebuf missing. */
|
||||||
|
|
||||||
|
/* Force stdout/stderr into append mode. This ensures parallel jobs won't
|
||||||
|
lose output due to overlapping writes. */
|
||||||
|
set_append_mode (fileno (stdout));
|
||||||
|
set_append_mode (fileno (stderr));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -389,7 +495,7 @@ output_close (struct output *out)
|
|||||||
if (! out)
|
if (! out)
|
||||||
{
|
{
|
||||||
if (stdio_traced)
|
if (stdio_traced)
|
||||||
log_working_directory (0);
|
log_working_directory (NULL, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,46 +508,34 @@ output_close (struct output *out)
|
|||||||
if (out->err >= 0 && out->err != out->out)
|
if (out->err >= 0 && out->err != out->out)
|
||||||
close (out->err);
|
close (out->err);
|
||||||
|
|
||||||
output_init (out, 0);
|
output_init (out);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We're about to run a sub-process so ensure we've got our output set up. */
|
/* We're about to generate output: be sure it's set up. */
|
||||||
void
|
void
|
||||||
output_start ()
|
output_start ()
|
||||||
{
|
{
|
||||||
if (! output_context)
|
|
||||||
{
|
|
||||||
if (! stdio_traced)
|
|
||||||
stdio_traced = log_working_directory (1);
|
|
||||||
}
|
|
||||||
#ifdef OUTPUT_SYNC
|
#ifdef OUTPUT_SYNC
|
||||||
else if (output_context->syncout && ! OUTPUT_ISSET(output_context))
|
if (output_context && output_context->syncout && ! OUTPUT_ISSET(output_context))
|
||||||
setup_tmpfile (output_context);
|
setup_tmpfile (output_context);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (! output_context || output_sync == OUTPUT_SYNC_RECURSE)
|
||||||
|
{
|
||||||
|
if (! stdio_traced && print_directory_flag)
|
||||||
|
stdio_traced = log_working_directory (NULL, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
outputs (int is_err, const char *msg)
|
outputs (int is_err, const char *msg)
|
||||||
{
|
{
|
||||||
/* For stdio, an empty msg means we're about to invoke a shell command,
|
|
||||||
which may or may not generate output, so log the directory. */
|
|
||||||
if (! output_context && ! stdio_traced)
|
|
||||||
stdio_traced = log_working_directory (1);
|
|
||||||
|
|
||||||
/* Don't bother to do anything with empty strings. */
|
|
||||||
if (! msg || *msg == '\0')
|
if (! msg || *msg == '\0')
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#ifdef OUTPUT_SYNC
|
output_start ();
|
||||||
if (output_context)
|
|
||||||
{
|
|
||||||
/* Create a temporary file to write to, if necessary. */
|
|
||||||
if (output_context->syncout && ! OUTPUT_ISSET(output_context))
|
|
||||||
setup_tmpfile (output_context);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_outputs (is_err, msg);
|
_outputs (output_context, is_err, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -465,7 +559,7 @@ vfmtconcat (const char *fmt, va_list args)
|
|||||||
int tot;
|
int tot;
|
||||||
int unused = fmtbuf.size - fmtbuf.len;
|
int unused = fmtbuf.size - fmtbuf.len;
|
||||||
|
|
||||||
va_copy(vcopy, args);
|
va_copy (vcopy, args);
|
||||||
|
|
||||||
tot = vsnprintf (&fmtbuf.buffer[fmtbuf.len], unused, fmt, args);
|
tot = vsnprintf (&fmtbuf.buffer[fmtbuf.len], unused, fmt, args);
|
||||||
assert (tot >= 0);
|
assert (tot >= 0);
|
||||||
@ -479,7 +573,7 @@ vfmtconcat (const char *fmt, va_list args)
|
|||||||
tot = vsnprintf (&fmtbuf.buffer[fmtbuf.len], unused, fmt, vcopy);
|
tot = vsnprintf (&fmtbuf.buffer[fmtbuf.len], unused, fmt, vcopy);
|
||||||
}
|
}
|
||||||
|
|
||||||
va_end(vcopy);
|
va_end (vcopy);
|
||||||
|
|
||||||
fmtbuf.len += tot;
|
fmtbuf.len += tot;
|
||||||
|
|
||||||
|
12
output.h
12
output.h
@ -26,12 +26,22 @@ extern struct output *output_context;
|
|||||||
#define OUTPUT_SET(_new) do{ if ((_new)->syncout) output_context = (_new); }while(0)
|
#define OUTPUT_SET(_new) do{ if ((_new)->syncout) output_context = (_new); }while(0)
|
||||||
#define OUTPUT_UNSET() do{ output_context = NULL; }while(0)
|
#define OUTPUT_UNSET() do{ output_context = NULL; }while(0)
|
||||||
|
|
||||||
void output_init (struct output *out, unsigned int syncout);
|
FILE *output_tmpfile (char **, const char *);
|
||||||
|
|
||||||
|
/* Initialize and close a child output structure: if NULL do this program's
|
||||||
|
output (this should only be done once). */
|
||||||
|
void output_init (struct output *out);
|
||||||
void output_close (struct output *out);
|
void output_close (struct output *out);
|
||||||
|
|
||||||
|
/* In situations where output may be about to be displayed but we're not
|
||||||
|
sure if we've set it up yet, call this. */
|
||||||
void output_start (void);
|
void output_start (void);
|
||||||
|
|
||||||
|
/* Show a message on stdout or stderr. Will start the output if needed. */
|
||||||
void outputs (int is_err, const char *msg);
|
void outputs (int is_err, const char *msg);
|
||||||
|
|
||||||
#ifdef OUTPUT_SYNC
|
#ifdef OUTPUT_SYNC
|
||||||
|
int output_tmpfd (void);
|
||||||
|
/* Dump any child output content to stdout, and reset it. */
|
||||||
void output_dump (struct output *out);
|
void output_dump (struct output *out);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
2013-09-14 Paul Smith <psmith@gnu.org>
|
||||||
|
|
||||||
|
* scripts/features/output-sync: Verify -Orecurse properly.
|
||||||
|
|
||||||
2013-09-12 Paul Smith <psmith@gnu.org>
|
2013-09-12 Paul Smith <psmith@gnu.org>
|
||||||
|
|
||||||
* scripts/features/output-sync: Modify for output sync behavior.
|
* scripts/features/output-sync: Modify for output sync behavior.
|
||||||
|
@ -135,8 +135,6 @@ foo: end
|
|||||||
#MAKE#[1]: Entering directory '#PWD#/bar'
|
#MAKE#[1]: Entering directory '#PWD#/bar'
|
||||||
bar: start
|
bar: start
|
||||||
bar: end
|
bar: end
|
||||||
#MAKE#[1]: Leaving directory '#PWD#/bar'
|
|
||||||
#MAKE#[1]: Entering directory '#PWD#/bar'
|
|
||||||
baz: start
|
baz: start
|
||||||
baz: end
|
baz: end
|
||||||
#MAKE#[1]: Leaving directory '#PWD#/bar'\n", 0, 6);
|
#MAKE#[1]: Leaving directory '#PWD#/bar'\n", 0, 6);
|
||||||
|
713
vmsjobs.c
713
vmsjobs.c
@ -31,10 +31,10 @@ vmsWaitForChildren(int *status)
|
|||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if (!vms_jobsefnmask)
|
if (!vms_jobsefnmask)
|
||||||
{
|
{
|
||||||
*status = 0;
|
*status = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
*status = sys$wflor (32, vms_jobsefnmask);
|
*status = sys$wflor (32, vms_jobsefnmask);
|
||||||
}
|
}
|
||||||
@ -59,9 +59,9 @@ vms_redirect (struct dsc$descriptor_s *desc, char *fname, char *ibuf)
|
|||||||
{
|
{
|
||||||
strcpy (fname, vmsify (fptr, 0));
|
strcpy (fname, vmsify (fptr, 0));
|
||||||
if (strchr (fname, '.') == 0)
|
if (strchr (fname, '.') == 0)
|
||||||
strcat (fname, ".");
|
strcat (fname, ".");
|
||||||
}
|
}
|
||||||
desc->dsc$w_length = strlen(fname);
|
desc->dsc$w_length = strlen (fname);
|
||||||
desc->dsc$a_pointer = fname;
|
desc->dsc$a_pointer = fname;
|
||||||
desc->dsc$b_dtype = DSC$K_DTYPE_T;
|
desc->dsc$b_dtype = DSC$K_DTYPE_T;
|
||||||
desc->dsc$b_class = DSC$K_CLASS_S;
|
desc->dsc$b_class = DSC$K_CLASS_S;
|
||||||
@ -74,7 +74,7 @@ vms_redirect (struct dsc$descriptor_s *desc, char *fname, char *ibuf)
|
|||||||
|
|
||||||
/* found apostrophe at (p-1)
|
/* found apostrophe at (p-1)
|
||||||
inc p until after closing apostrophe.
|
inc p until after closing apostrophe.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
char *
|
char *
|
||||||
vms_handle_apos (char *p)
|
vms_handle_apos (char *p)
|
||||||
@ -86,25 +86,21 @@ vms_handle_apos (char *p)
|
|||||||
alast = 0;
|
alast = 0;
|
||||||
|
|
||||||
while (*p != 0)
|
while (*p != 0)
|
||||||
{
|
if (*p == '"')
|
||||||
if (*p == '"')
|
if (alast)
|
||||||
{
|
{
|
||||||
if (alast)
|
alast = 0;
|
||||||
{
|
p++;
|
||||||
alast = 0;
|
}
|
||||||
p++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
p++;
|
|
||||||
if (strchr (SEPCHARS, *p))
|
|
||||||
break;
|
|
||||||
alast = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
p++;
|
{
|
||||||
}
|
p++;
|
||||||
|
if (strchr (SEPCHARS, *p))
|
||||||
|
break;
|
||||||
|
alast = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
p++;
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@ -118,100 +114,99 @@ static int ctrlYPressed= 0;
|
|||||||
int
|
int
|
||||||
vmsHandleChildTerm(struct child *child)
|
vmsHandleChildTerm(struct child *child)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
register struct child *lastc, *c;
|
register struct child *lastc, *c;
|
||||||
int child_failed;
|
int child_failed;
|
||||||
|
|
||||||
vms_jobsefnmask &= ~(1 << (child->efn - 32));
|
vms_jobsefnmask &= ~(1 << (child->efn - 32));
|
||||||
|
|
||||||
lib$free_ef(&child->efn);
|
lib$free_ef (&child->efn);
|
||||||
if (child->comname)
|
if (child->comname)
|
||||||
{
|
{
|
||||||
if (!ISDB (DB_JOBS)&&!ctrlYPressed)
|
if (!ISDB (DB_JOBS) && !ctrlYPressed)
|
||||||
unlink (child->comname);
|
unlink (child->comname);
|
||||||
free (child->comname);
|
free (child->comname);
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) sigblock (fatal_signal_mask);
|
(void) sigblock (fatal_signal_mask);
|
||||||
|
|
||||||
child_failed = !(child->cstatus & 1 || ((child->cstatus & 7) == 0));
|
child_failed = !(child->cstatus & 1 || ((child->cstatus & 7) == 0));
|
||||||
|
|
||||||
/* Search for a child matching the deceased one. */
|
/* Search for a child matching the deceased one. */
|
||||||
lastc = 0;
|
lastc = 0;
|
||||||
#if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */
|
#if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */
|
||||||
for (c = children; c != 0 && c != child; lastc = c, c = c->next)
|
for (c = children; c != 0 && c != child; lastc = c, c = c->next)
|
||||||
;
|
;
|
||||||
#else
|
#else
|
||||||
c = child;
|
c = child;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (child_failed && !c->noerror && !ignore_errors_flag)
|
if (child_failed && !c->noerror && !ignore_errors_flag)
|
||||||
{
|
{
|
||||||
/* The commands failed. Write an error message,
|
/* The commands failed. Write an error message,
|
||||||
delete non-precious targets, and abort. */
|
delete non-precious targets, and abort. */
|
||||||
child_error (c, c->cstatus, 0, 0, 0);
|
child_error (c, c->cstatus, 0, 0, 0);
|
||||||
c->file->update_status = us_failed;
|
c->file->update_status = us_failed;
|
||||||
delete_child_targets (c);
|
delete_child_targets (c);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (child_failed)
|
if (child_failed)
|
||||||
{
|
{
|
||||||
/* The commands failed, but we don't care. */
|
/* The commands failed, but we don't care. */
|
||||||
child_error (c, c->cstatus, 0, 0, 1);
|
child_error (c, c->cstatus, 0, 0, 1);
|
||||||
child_failed = 0;
|
child_failed = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */
|
#if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */
|
||||||
/* If there are more commands to run, try to start them. */
|
/* If there are more commands to run, try to start them. */
|
||||||
start_job (c);
|
start_job (c);
|
||||||
|
|
||||||
switch (c->file->command_state)
|
switch (c->file->command_state)
|
||||||
{
|
{
|
||||||
case cs_running:
|
case cs_running:
|
||||||
/* Successfully started. */
|
/* Successfully started. */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case cs_finished:
|
case cs_finished:
|
||||||
if (c->file->update_status != us_success) {
|
if (c->file->update_status != us_success)
|
||||||
/* We failed to start the commands. */
|
/* We failed to start the commands. */
|
||||||
delete_child_targets (c);
|
delete_child_targets (c);
|
||||||
}
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
error (NILF, _("internal error: '%s' command_state"),
|
error (NILF, _("internal error: '%s' command_state"),
|
||||||
c->file->name);
|
c->file->name);
|
||||||
abort ();
|
abort ();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif /* RECURSIVEJOBS */
|
#endif /* RECURSIVEJOBS */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the state flag to say the commands have finished. */
|
/* Set the state flag to say the commands have finished. */
|
||||||
c->file->command_state = cs_finished;
|
c->file->command_state = cs_finished;
|
||||||
notice_finished_file (c->file);
|
notice_finished_file (c->file);
|
||||||
|
|
||||||
#if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */
|
#if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */
|
||||||
/* Remove the child from the chain and free it. */
|
/* Remove the child from the chain and free it. */
|
||||||
if (lastc == 0)
|
if (lastc == 0)
|
||||||
children = c->next;
|
children = c->next;
|
||||||
else
|
else
|
||||||
lastc->next = c->next;
|
lastc->next = c->next;
|
||||||
free_child (c);
|
free_child (c);
|
||||||
#endif /* RECURSIVEJOBS */
|
#endif /* RECURSIVEJOBS */
|
||||||
|
|
||||||
/* There is now another slot open. */
|
/* There is now another slot open. */
|
||||||
if (job_slots_used > 0)
|
if (job_slots_used > 0)
|
||||||
--job_slots_used;
|
--job_slots_used;
|
||||||
|
|
||||||
/* If the job failed, and the -k flag was not given, die. */
|
/* If the job failed, and the -k flag was not given, die. */
|
||||||
if (child_failed && !keep_going_flag)
|
if (child_failed && !keep_going_flag)
|
||||||
die (EXIT_FAILURE);
|
die (EXIT_FAILURE);
|
||||||
|
|
||||||
(void) sigsetmask (sigblock (0) & ~(fatal_signal_mask));
|
(void) sigsetmask (sigblock (0) & ~(fatal_signal_mask));
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* VMS:
|
/* VMS:
|
||||||
@ -232,67 +227,71 @@ static unsigned short int chan= 0;
|
|||||||
static void
|
static void
|
||||||
reEnableAst(void)
|
reEnableAst(void)
|
||||||
{
|
{
|
||||||
lib$enable_ctrl (&oldCtrlMask,0);
|
lib$enable_ctrl (&oldCtrlMask,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
astYHandler (void)
|
astYHandler (void)
|
||||||
{
|
{
|
||||||
struct child *c;
|
struct child *c;
|
||||||
for (c = children; c != 0; c = c->next)
|
for (c = children; c != 0; c = c->next)
|
||||||
sys$delprc (&c->pid, 0, 0);
|
sys$delprc (&c->pid, 0, 0);
|
||||||
ctrlYPressed= 1;
|
ctrlYPressed= 1;
|
||||||
kill (getpid(),SIGQUIT);
|
kill (getpid(),SIGQUIT);
|
||||||
return SS$_NORMAL;
|
return SS$_NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
tryToSetupYAst(void)
|
tryToSetupYAst(void)
|
||||||
{
|
{
|
||||||
$DESCRIPTOR(inputDsc,"SYS$COMMAND");
|
$DESCRIPTOR(inputDsc,"SYS$COMMAND");
|
||||||
int status;
|
int status;
|
||||||
struct {
|
struct {
|
||||||
short int status, count;
|
short int status, count;
|
||||||
int dvi;
|
int dvi;
|
||||||
} iosb;
|
} iosb;
|
||||||
unsigned short int loc_chan;
|
unsigned short int loc_chan;
|
||||||
|
|
||||||
setupYAstTried++;
|
setupYAstTried++;
|
||||||
|
|
||||||
if (chan)
|
if (chan)
|
||||||
loc_chan= chan;
|
loc_chan= chan;
|
||||||
else {
|
else
|
||||||
status= sys$assign(&inputDsc,&loc_chan,0,0);
|
{
|
||||||
if (!(status&SS$_NORMAL)) {
|
status= sys$assign(&inputDsc,&loc_chan,0,0);
|
||||||
lib$signal(status);
|
if (!(status&SS$_NORMAL))
|
||||||
return;
|
{
|
||||||
}
|
lib$signal(status);
|
||||||
}
|
return;
|
||||||
status= sys$qiow (0, loc_chan, IO$_SETMODE|IO$M_CTRLYAST,&iosb,0,0,
|
}
|
||||||
astYHandler,0,0,0,0,0);
|
}
|
||||||
if (status==SS$_NORMAL)
|
status= sys$qiow (0, loc_chan, IO$_SETMODE|IO$M_CTRLYAST,&iosb,0,0,
|
||||||
status= iosb.status;
|
astYHandler,0,0,0,0,0);
|
||||||
if (status!=SS$_NORMAL) {
|
if (status==SS$_NORMAL)
|
||||||
if (!chan)
|
status= iosb.status;
|
||||||
sys$dassgn(loc_chan);
|
if (status!=SS$_NORMAL)
|
||||||
if (status!=SS$_ILLIOFUNC && status!=SS$_NOPRIV)
|
{
|
||||||
lib$signal(status);
|
if (!chan)
|
||||||
return;
|
sys$dassgn(loc_chan);
|
||||||
}
|
if (status!=SS$_ILLIOFUNC && status!=SS$_NOPRIV)
|
||||||
|
lib$signal(status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* called from AST handler ? */
|
/* called from AST handler ? */
|
||||||
if (setupYAstTried>1)
|
if (setupYAstTried>1)
|
||||||
return;
|
return;
|
||||||
if (atexit(reEnableAst))
|
if (atexit(reEnableAst))
|
||||||
fprintf (stderr,
|
fprintf (stderr,
|
||||||
_("-warning, you may have to re-enable CTRL-Y handling from DCL.\n"));
|
_("-warning, you may have to re-enable CTRL-Y handling from DCL.\n"));
|
||||||
status= lib$disable_ctrl (&ctrlMask, &oldCtrlMask);
|
status= lib$disable_ctrl (&ctrlMask, &oldCtrlMask);
|
||||||
if (!(status&SS$_NORMAL)) {
|
if (!(status&SS$_NORMAL))
|
||||||
lib$signal(status);
|
{
|
||||||
return;
|
lib$signal(status);
|
||||||
}
|
return;
|
||||||
if (!chan)
|
}
|
||||||
chan = loc_chan;
|
if (!chan)
|
||||||
|
chan = loc_chan;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -349,63 +348,61 @@ child_execute_job (char *argv, struct child *child)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
switch (*p)
|
switch (*p)
|
||||||
{
|
{
|
||||||
case '#':
|
case '#':
|
||||||
*p-- = 0;
|
*p-- = 0;
|
||||||
*q-- = 0;
|
*q-- = 0;
|
||||||
break;
|
break;
|
||||||
case '\\':
|
case '\\':
|
||||||
p++;
|
p++;
|
||||||
if (*p == '\n')
|
if (*p == '\n')
|
||||||
p++;
|
p++;
|
||||||
if (isspace ((unsigned char)*p))
|
if (isspace ((unsigned char)*p))
|
||||||
{
|
{
|
||||||
do { p++; } while (isspace ((unsigned char)*p));
|
do { p++; } while (isspace ((unsigned char)*p));
|
||||||
p--;
|
p--;
|
||||||
}
|
}
|
||||||
*q = *p;
|
*q = *p;
|
||||||
break;
|
break;
|
||||||
case '<':
|
case '<':
|
||||||
p = vms_redirect (&ifiledsc, ifile, p);
|
p = vms_redirect (&ifiledsc, ifile, p);
|
||||||
*q = ' ';
|
*q = ' ';
|
||||||
have_redirection = 1;
|
have_redirection = 1;
|
||||||
break;
|
break;
|
||||||
case '>':
|
case '>':
|
||||||
have_redirection = 1;
|
have_redirection = 1;
|
||||||
if (*(p-1) == '2')
|
if (*(p-1) == '2')
|
||||||
{
|
{
|
||||||
q--;
|
q--;
|
||||||
if (strncmp (p, ">&1", 3) == 0)
|
if (strncmp (p, ">&1", 3) == 0)
|
||||||
{
|
{
|
||||||
p += 3;
|
p += 3;
|
||||||
strcpy (efile, "sys$output");
|
strcpy (efile, "sys$output");
|
||||||
efiledsc.dsc$w_length = strlen(efile);
|
efiledsc.dsc$w_length = strlen(efile);
|
||||||
efiledsc.dsc$a_pointer = efile;
|
efiledsc.dsc$a_pointer = efile;
|
||||||
efiledsc.dsc$b_dtype = DSC$K_DTYPE_T;
|
efiledsc.dsc$b_dtype = DSC$K_DTYPE_T;
|
||||||
efiledsc.dsc$b_class = DSC$K_CLASS_S;
|
efiledsc.dsc$b_class = DSC$K_CLASS_S;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
p = vms_redirect (&efiledsc, efile, p);
|
||||||
p = vms_redirect (&efiledsc, efile, p);
|
}
|
||||||
}
|
else
|
||||||
}
|
{
|
||||||
else
|
if (*(p+1) == '>')
|
||||||
{
|
{
|
||||||
if (*(p+1) == '>')
|
have_append = 1;
|
||||||
{
|
p += 1;
|
||||||
have_append = 1;
|
}
|
||||||
p += 1;
|
p = vms_redirect (&ofiledsc, ofile, p);
|
||||||
}
|
}
|
||||||
p = vms_redirect (&ofiledsc, ofile, p);
|
*q = ' ';
|
||||||
}
|
break;
|
||||||
*q = ' ';
|
case '\n':
|
||||||
break;
|
have_newline = 1;
|
||||||
case '\n':
|
default:
|
||||||
have_newline = 1;
|
*q = *p;
|
||||||
default:
|
break;
|
||||||
*q = *p;
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
*q = *p;
|
*q = *p;
|
||||||
while (isspace ((unsigned char)*--q))
|
while (isspace ((unsigned char)*--q))
|
||||||
@ -422,55 +419,55 @@ child_execute_job (char *argv, struct child *child)
|
|||||||
p = cmd + 8;
|
p = cmd + 8;
|
||||||
|
|
||||||
if ((*(p) == 'c')
|
if ((*(p) == 'c')
|
||||||
&& (*(p+1) == 'd')
|
&& (*(p+1) == 'd')
|
||||||
&& ((*(p+2) == ' ') || (*(p+2) == '\t')))
|
&& ((*(p+2) == ' ') || (*(p+2) == '\t')))
|
||||||
{
|
{
|
||||||
p += 3;
|
p += 3;
|
||||||
while ((*p == ' ') || (*p == '\t'))
|
while ((*p == ' ') || (*p == '\t'))
|
||||||
p++;
|
p++;
|
||||||
DB (DB_JOBS, (_("BUILTIN CD %s\n"), p));
|
DB (DB_JOBS, (_("BUILTIN CD %s\n"), p));
|
||||||
if (chdir (p))
|
if (chdir (p))
|
||||||
return 0;
|
return 0;
|
||||||
else
|
else
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else if ((*(p) == 'r')
|
else if ((*(p) == 'r')
|
||||||
&& (*(p+1) == 'm')
|
&& (*(p+1) == 'm')
|
||||||
&& ((*(p+2) == ' ') || (*(p+2) == '\t')))
|
&& ((*(p+2) == ' ') || (*(p+2) == '\t')))
|
||||||
{
|
{
|
||||||
int in_arg;
|
int in_arg;
|
||||||
|
|
||||||
/* rm */
|
/* rm */
|
||||||
p += 3;
|
p += 3;
|
||||||
while ((*p == ' ') || (*p == '\t'))
|
while ((*p == ' ') || (*p == '\t'))
|
||||||
p++;
|
p++;
|
||||||
in_arg = 1;
|
in_arg = 1;
|
||||||
|
|
||||||
DB (DB_JOBS, (_("BUILTIN RM %s\n"), p));
|
DB (DB_JOBS, (_("BUILTIN RM %s\n"), p));
|
||||||
while (*p)
|
while (*p)
|
||||||
{
|
{
|
||||||
switch (*p)
|
switch (*p)
|
||||||
{
|
{
|
||||||
case ' ':
|
case ' ':
|
||||||
case '\t':
|
case '\t':
|
||||||
if (in_arg)
|
if (in_arg)
|
||||||
{
|
{
|
||||||
*p++ = ';';
|
*p++ = ';';
|
||||||
in_arg = 0;
|
in_arg = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf(_("Unknown builtin command '%s'\n"), cmd);
|
printf (_("Unknown builtin command '%s'\n"), cmd);
|
||||||
fflush(stdout);
|
fflush (stdout);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a *.com file if either the command is too long for
|
/* Create a *.com file if either the command is too long for
|
||||||
@ -485,56 +482,54 @@ child_execute_job (char *argv, struct child *child)
|
|||||||
FILE *outfile;
|
FILE *outfile;
|
||||||
char c;
|
char c;
|
||||||
char *sep;
|
char *sep;
|
||||||
int alevel = 0; /* apostrophe level */
|
int alevel = 0; /* apostrophe level */
|
||||||
|
|
||||||
if (strlen (cmd) == 0)
|
if (strlen (cmd) == 0)
|
||||||
{
|
{
|
||||||
printf (_("Error, empty command\n"));
|
printf (_("Error, empty command\n"));
|
||||||
fflush (stdout);
|
fflush (stdout);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
outfile = open_tmpfile (&child->comname, "sys$scratch:CMDXXXXXX.COM");
|
outfile = output_tmpfile (&child->comname, "sys$scratch:CMDXXXXXX.COM");
|
||||||
if (outfile == 0)
|
if (outfile == 0)
|
||||||
pfatal_with_name (_("fopen (temporary file)"));
|
pfatal_with_name (_("fopen (temporary file)"));
|
||||||
comnamelen = strlen (child->comname);
|
comnamelen = strlen (child->comname);
|
||||||
|
|
||||||
if (ifile[0])
|
if (ifile[0])
|
||||||
{
|
{
|
||||||
fprintf (outfile, "$ assign/user %s sys$input\n", ifile);
|
fprintf (outfile, "$ assign/user %s sys$input\n", ifile);
|
||||||
DB (DB_JOBS, (_("Redirected input from %s\n"), ifile));
|
DB (DB_JOBS, (_("Redirected input from %s\n"), ifile));
|
||||||
ifiledsc.dsc$w_length = 0;
|
ifiledsc.dsc$w_length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (efile[0])
|
if (efile[0])
|
||||||
{
|
{
|
||||||
fprintf (outfile, "$ define sys$error %s\n", efile);
|
fprintf (outfile, "$ define sys$error %s\n", efile);
|
||||||
DB (DB_JOBS, (_("Redirected error to %s\n"), efile));
|
DB (DB_JOBS, (_("Redirected error to %s\n"), efile));
|
||||||
efiledsc.dsc$w_length = 0;
|
efiledsc.dsc$w_length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ofile[0])
|
if (ofile[0])
|
||||||
{
|
if (have_append)
|
||||||
if (have_append)
|
{
|
||||||
{
|
fprintf (outfile, "$ set noon\n");
|
||||||
fprintf (outfile, "$ set noon\n");
|
fprintf (outfile, "$ define sys$output %.*s\n", comnamelen-3, child->comname);
|
||||||
fprintf (outfile, "$ define sys$output %.*s\n", comnamelen-3, child->comname);
|
DB (DB_JOBS, (_("Append output to %s\n"), ofile));
|
||||||
DB (DB_JOBS, (_("Append output to %s\n"), ofile));
|
ofiledsc.dsc$w_length = 0;
|
||||||
ofiledsc.dsc$w_length = 0;
|
}
|
||||||
}
|
else
|
||||||
else
|
{
|
||||||
{
|
fprintf (outfile, "$ define sys$output %s\n", ofile);
|
||||||
fprintf (outfile, "$ define sys$output %s\n", ofile);
|
DB (DB_JOBS, (_("Redirected output to %s\n"), ofile));
|
||||||
DB (DB_JOBS, (_("Redirected output to %s\n"), ofile));
|
ofiledsc.dsc$w_length = 0;
|
||||||
ofiledsc.dsc$w_length = 0;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
p = sep = q = cmd;
|
p = sep = q = cmd;
|
||||||
for (c = '\n'; c; c = *q++)
|
for (c = '\n'; c; c = *q++)
|
||||||
{
|
{
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
case '\n':
|
case '\n':
|
||||||
/* At a newline, skip any whitespace around a leading $
|
/* At a newline, skip any whitespace around a leading $
|
||||||
from the command and issue exactly one $ into the DCL. */
|
from the command and issue exactly one $ into the DCL. */
|
||||||
@ -551,8 +546,8 @@ child_execute_job (char *argv, struct child *child)
|
|||||||
p = sep = q;
|
p = sep = q;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Nice places for line breaks are after strings, after
|
/* Nice places for line breaks are after strings, after
|
||||||
comma or space and before slash. */
|
comma or space and before slash. */
|
||||||
case '"':
|
case '"':
|
||||||
q = vms_handle_apos (q);
|
q = vms_handle_apos (q);
|
||||||
sep = q;
|
sep = q;
|
||||||
@ -567,25 +562,25 @@ child_execute_job (char *argv, struct child *child)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (sep - p > 78)
|
if (sep - p > 78)
|
||||||
{
|
{
|
||||||
/* Enough stuff for a line. */
|
/* Enough stuff for a line. */
|
||||||
fwrite (p, 1, sep - p, outfile);
|
fwrite (p, 1, sep - p, outfile);
|
||||||
p = sep;
|
p = sep;
|
||||||
if (*sep)
|
if (*sep)
|
||||||
{
|
{
|
||||||
/* The command continues. */
|
/* The command continues. */
|
||||||
fputc ('-', outfile);
|
fputc ('-', outfile);
|
||||||
}
|
}
|
||||||
fputc ('\n', outfile);
|
fputc ('\n', outfile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*p)
|
if (*p)
|
||||||
{
|
{
|
||||||
fwrite (p, 1, --q - p, outfile);
|
fwrite (p, 1, --q - p, outfile);
|
||||||
fputc ('\n', outfile);
|
fputc ('\n', outfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (have_append)
|
if (have_append)
|
||||||
@ -630,66 +625,66 @@ child_execute_job (char *argv, struct child *child)
|
|||||||
|
|
||||||
vms_jobsefnmask |= (1 << (child->efn - 32));
|
vms_jobsefnmask |= (1 << (child->efn - 32));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
LIB$SPAWN [command-string]
|
LIB$SPAWN [command-string]
|
||||||
[,input-file]
|
[,input-file]
|
||||||
[,output-file]
|
[,output-file]
|
||||||
[,flags]
|
[,flags]
|
||||||
[,process-name]
|
[,process-name]
|
||||||
[,process-id] [,completion-status-address] [,byte-integer-event-flag-num]
|
[,process-id] [,completion-status-address] [,byte-integer-event-flag-num]
|
||||||
[,AST-address] [,varying-AST-argument]
|
[,AST-address] [,varying-AST-argument]
|
||||||
[,prompt-string] [,cli] [,table]
|
[,prompt-string] [,cli] [,table]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef DONTWAITFORCHILD
|
#ifndef DONTWAITFORCHILD
|
||||||
/*
|
/*
|
||||||
* Code to make ctrl+c and ctrl+y working.
|
* Code to make ctrl+c and ctrl+y working.
|
||||||
* The problem starts with the synchronous case where after lib$spawn is
|
* The problem starts with the synchronous case where after lib$spawn is
|
||||||
* called any input will go to the child. But with input re-directed,
|
* called any input will go to the child. But with input re-directed,
|
||||||
* both control characters won't make it to any of the programs, neither
|
* both control characters won't make it to any of the programs, neither
|
||||||
* the spawning nor to the spawned one. Hence the caller needs to spawn
|
* the spawning nor to the spawned one. Hence the caller needs to spawn
|
||||||
* with CLI$M_NOWAIT to NOT give up the input focus. A sys$waitfr
|
* with CLI$M_NOWAIT to NOT give up the input focus. A sys$waitfr
|
||||||
* has to follow to simulate the wanted synchronous behaviour.
|
* has to follow to simulate the wanted synchronous behaviour.
|
||||||
* The next problem is ctrl+y which isn't caught by the crtl and
|
* The next problem is ctrl+y which isn't caught by the crtl and
|
||||||
* therefore isn't converted to SIGQUIT (for a signal handler which is
|
* therefore isn't converted to SIGQUIT (for a signal handler which is
|
||||||
* already established). The only way to catch ctrl+y, is an AST
|
* already established). The only way to catch ctrl+y, is an AST
|
||||||
* assigned to the input channel. But ctrl+y handling of DCL needs to be
|
* assigned to the input channel. But ctrl+y handling of DCL needs to be
|
||||||
* disabled, otherwise it will handle it. Not to mention the previous
|
* disabled, otherwise it will handle it. Not to mention the previous
|
||||||
* ctrl+y handling of DCL needs to be re-established before make exits.
|
* ctrl+y handling of DCL needs to be re-established before make exits.
|
||||||
* One more: At the time of LIB$SPAWN signals are blocked. SIGQUIT will
|
* One more: At the time of LIB$SPAWN signals are blocked. SIGQUIT will
|
||||||
* make it to the signal handler after the child "normally" terminates.
|
* make it to the signal handler after the child "normally" terminates.
|
||||||
* This isn't enough. It seems reasonable for simple command lines like
|
* This isn't enough. It seems reasonable for simple command lines like
|
||||||
* a 'cc foobar.c' spawned in a subprocess but it is unacceptable for
|
* a 'cc foobar.c' spawned in a subprocess but it is unacceptable for
|
||||||
* spawning make. Therefore we need to abort the process in the AST.
|
* spawning make. Therefore we need to abort the process in the AST.
|
||||||
*
|
*
|
||||||
* Prior to the spawn it is checked if an AST is already set up for
|
* Prior to the spawn it is checked if an AST is already set up for
|
||||||
* ctrl+y, if not one is set up for a channel to SYS$COMMAND. In general
|
* ctrl+y, if not one is set up for a channel to SYS$COMMAND. In general
|
||||||
* this will work except if make is run in a batch environment, but there
|
* this will work except if make is run in a batch environment, but there
|
||||||
* nobody can press ctrl+y. During the setup the DCL handling of ctrl+y
|
* nobody can press ctrl+y. During the setup the DCL handling of ctrl+y
|
||||||
* is disabled and an exit handler is established to re-enable it.
|
* is disabled and an exit handler is established to re-enable it.
|
||||||
* If the user interrupts with ctrl+y, the assigned AST will fire, force
|
* If the user interrupts with ctrl+y, the assigned AST will fire, force
|
||||||
* an abort to the subprocess and signal SIGQUIT, which will be caught by
|
* an abort to the subprocess and signal SIGQUIT, which will be caught by
|
||||||
* the already established handler and will bring us back to common code.
|
* the already established handler and will bring us back to common code.
|
||||||
* After the spawn (now /nowait) a sys$waitfr simulates the /wait and
|
* After the spawn (now /nowait) a sys$waitfr simulates the /wait and
|
||||||
* enables the ctrl+y be delivered to this code. And the ctrl+c too,
|
* enables the ctrl+y be delivered to this code. And the ctrl+c too,
|
||||||
* which the crtl converts to SIGINT and which is caught by the common
|
* which the crtl converts to SIGINT and which is caught by the common
|
||||||
* signal handler. Because signals were blocked before entering this code
|
* signal handler. Because signals were blocked before entering this code
|
||||||
* sys$waitfr will always complete and the SIGQUIT will be processed after
|
* sys$waitfr will always complete and the SIGQUIT will be processed after
|
||||||
* it (after termination of the current block, somewhere in common code).
|
* it (after termination of the current block, somewhere in common code).
|
||||||
* And SIGINT too will be delayed. That is ctrl+c can only abort when the
|
* And SIGINT too will be delayed. That is ctrl+c can only abort when the
|
||||||
* current command completes. Anyway it's better than nothing :-)
|
* current command completes. Anyway it's better than nothing :-)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!setupYAstTried)
|
if (!setupYAstTried)
|
||||||
tryToSetupYAst();
|
tryToSetupYAst();
|
||||||
status = lib$spawn (&cmddsc, /* cmd-string */
|
status = lib$spawn (&cmddsc, /* cmd-string */
|
||||||
(ifiledsc.dsc$w_length == 0)?0:&ifiledsc, /* input-file */
|
(ifiledsc.dsc$w_length == 0)?0:&ifiledsc, /* input-file */
|
||||||
(ofiledsc.dsc$w_length == 0)?0:&ofiledsc, /* output-file */
|
(ofiledsc.dsc$w_length == 0)?0:&ofiledsc, /* output-file */
|
||||||
&spflags, /* flags */
|
&spflags, /* flags */
|
||||||
&pnamedsc, /* proc name */
|
&pnamedsc, /* proc name */
|
||||||
&child->pid, &child->cstatus, &child->efn,
|
&child->pid, &child->cstatus, &child->efn,
|
||||||
0, 0,
|
0, 0,
|
||||||
0, 0, 0);
|
0, 0, 0);
|
||||||
if (status & 1)
|
if (status & 1)
|
||||||
{
|
{
|
||||||
status= sys$waitfr (child->efn);
|
status= sys$waitfr (child->efn);
|
||||||
@ -697,13 +692,13 @@ child_execute_job (char *argv, struct child *child)
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
status = lib$spawn (&cmddsc,
|
status = lib$spawn (&cmddsc,
|
||||||
(ifiledsc.dsc$w_length == 0)?0:&ifiledsc,
|
(ifiledsc.dsc$w_length == 0)?0:&ifiledsc,
|
||||||
(ofiledsc.dsc$w_length == 0)?0:&ofiledsc,
|
(ofiledsc.dsc$w_length == 0)?0:&ofiledsc,
|
||||||
&spflags,
|
&spflags,
|
||||||
&pnamedsc,
|
&pnamedsc,
|
||||||
&child->pid, &child->cstatus, &child->efn,
|
&child->pid, &child->cstatus, &child->efn,
|
||||||
vmsHandleChildTerm, child,
|
vmsHandleChildTerm, child,
|
||||||
0, 0, 0);
|
0, 0, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!(status & 1))
|
if (!(status & 1))
|
||||||
|
Loading…
Reference in New Issue
Block a user