summaryrefslogtreecommitdiff
path: root/vmsjobs.c
diff options
context:
space:
mode:
authorJohn Malmberg <wb8tyw@qsl.net>2014-09-13 20:20:22 -0500
committerPaul Smith <psmith@gnu.org>2014-10-20 01:28:46 -0400
commit894ee7f6c8b96ed89d4672da6cde4105c15cbf31 (patch)
tree1d10c4e86225e29358467266a4eb8b8e9a9ade1a /vmsjobs.c
parente75662bc6a96571f041bdad799eb557ff580135c (diff)
downloadgunmake-894ee7f6c8b96ed89d4672da6cde4105c15cbf31.tar.gz
[SV 42447]: VMS simulate exporting symbols
This also includes fixing the most of the exit handling code for VMS. Self tests: Previously about 94 Tests in 36 categories fail. Now about 45 tests in 22 categories fail. Because some tests do not properly clean up, the number of tests that fail can vary by one or two test cases between consecutive runs. * Makefile.am: Add new VMS files. * job.c: add prototype for vms_strsignal(). * job.c: (child_error): Remove VMS specific code as no longer needed. * job.c: (reap_children): The VMS specific code was setting the status to 0 instead of setting it to the proper exit status. * job.h: Add vms_launch_status to struct child. * main.c: (main): Use environment variables for options to use MCR * instead of a foreign command, and to always use command files for subprocesses. For VMS use (set_program_name) routine which is common to ports of other GNU packages to VMS to set the program name used internally. Use (vms_putenv_symbol) to set up symbols to be visible in child programs, including recursive make launched by execve() Start of Bash shell detection code for VMS. * makefile.com: Need nested_include=none for building on VMS search lists. Add vms_progname, vms_exit, and vms_export_symbol. * makefile.vms: Need nested_include=none for building on VMS search lists. Add vms_progname, vms_exit, vms_export_symbol. * makeint.h: Make sure non-standard "VMS" macro is defined. Add prototypes for new VMS routines. Remove VMS-specific failure codes. * vmsjobs.c: Add VMS POSIX exit code constants. (_is_unixy_shell): Detect Bash shell. (vms_strsignal): simulate strsignal() on VMS. (vmsHandleChildTerm): fix to properly report failed LIB$SPAWN() exit status codes. Remove code that duplicated code in job.c. (child_execute_job): Export environment symbols before spawning a child and restore afterward unless option to use command files for subprocesses is set. Improve handling of UNIX null commands ":". * vms_exit.c: Provides vms_exit() to detect if an exit code is UNIX or VMS, and converts the UNIX code into a VMS exit code. * vms_export_symbol.c: Routines to create DCL symbols that work like shell aliases or exported shell symbols and clean them up on exit. * vms_export_symbol_test.com: Unit test for vms_export_symbol.c * vms_progname.c: New file: VMS specific replace for progname.c that is used in some GNU projects.
Diffstat (limited to 'vmsjobs.c')
-rw-r--r--vmsjobs.c210
1 files changed, 120 insertions, 90 deletions
diff --git a/vmsjobs.c b/vmsjobs.c
index b11bca1..df93a4d 100644
--- a/vmsjobs.c
+++ b/vmsjobs.c
@@ -20,13 +20,67 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include <descrip.h>
#include <clidef.h>
+/* TODO - VMS specific header file conditionally included in makeint.h */
+
+#include <stsdef.h>
+#include <ssdef.h>
+void
+decc$exit (int status);
+
+/* Lowest legal non-success VMS exit code is 8 */
+/* GNU make only defines codes 0, 1, 2 */
+/* So assume any exit code > 8 is a VMS exit code */
+
+#ifndef MAX_EXPECTED_EXIT_CODE
+# define MAX_EXPECTED_EXIT_CODE 7
+#endif
+
+
+#if __CRTL_VER >= 70302000 && !defined(__VAX)
+# define MAX_DCL_LINE_LENGTH 4095
+#else
+# define MAX_DCL_LINE_LENGTH 1023
+#endif
+
char *vmsify (char *name, int type);
static int vms_jobsefnmask = 0;
+/* returns whether path is assumed to be a unix like shell. */
+int
+_is_unixy_shell (const char *path)
+{
+ if (path == NULL)
+ return 0;
+
+ /* When in doubt assume a unix like shell */
+ return 1;
+}
+
+#define VMS_GETMSG_MAX 256
+static char vms_strsignal_text[VMS_GETMSG_MAX + 2];
+
+char *
+vms_strsignal (int status)
+{
+ if (status <= MAX_EXPECTED_EXIT_CODE)
+ sprintf (vms_strsignal_text, "lib$spawn returned %x", status);
+ else
+ {
+ int vms_status;
+ unsigned short * msg_len;
+ unsigned char out[4];
+ vms_status = SYS$GETMSG (status, &msg_len,
+ vms_strsignal_text, 7, *out);
+ }
+
+ return vms_strsignal_text;
+}
+
+
/* Wait for nchildren children to terminate */
static void
-vmsWaitForChildren(int *status)
+vmsWaitForChildren (int *status)
{
while (1)
{
@@ -132,9 +186,19 @@ vmsHandleChildTerm(struct child *child)
(void) sigblock (fatal_signal_mask);
- child_failed = !(child->cstatus & 1);
- if (child_failed)
- exit_code = child->cstatus;
+ /* First check to see if this is a POSIX exit status and handle */
+ if ((child->cstatus & VMS_POSIX_EXIT_MASK) == VMS_POSIX_EXIT_MASK)
+ {
+ exit_code = (child->cstatus >> 3) & 255;
+ if (exit_code != MAKE_SUCCESS)
+ child_failed = 1;
+ }
+ else
+ {
+ child_failed = !$VMS_STATUS_SUCCESS (child->cstatus);
+ if (child_failed)
+ exit_code = child->cstatus;
+ }
/* Search for a child matching the deceased one. */
lastc = 0;
@@ -145,69 +209,16 @@ vmsHandleChildTerm(struct child *child)
c = child;
#endif
- if (child_failed && !c->noerror && !ignore_errors_flag)
+ if ($VMS_STATUS_SUCCESS (child->vms_launch_status))
{
- /* The commands failed. Write an error message,
- delete non-precious targets, and abort. */
- child_error (c, c->cstatus, 0, 0, 0);
- c->file->update_status = us_failed;
- delete_child_targets (c);
- }
- else
- {
- if (child_failed)
- {
- /* The commands failed, but we don't care. */
- child_error (c, c->cstatus, 0, 0, 1);
- child_failed = 0;
- }
-
-#if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */
- /* If there are more commands to run, try to start them. */
- start_job (c);
-
- switch (c->file->command_state)
- {
- case cs_running:
- /* Successfully started. */
- break;
-
- case cs_finished:
- if (c->file->update_status != us_success)
- /* We failed to start the commands. */
- delete_child_targets (c);
- break;
-
- default:
- OS (error, NILF,
- _("internal error: '%s' command_state"), c->file->name);
- abort ();
- break;
- }
-#endif /* RECURSIVEJOBS */
+ /* Convert VMS success status to 0 for UNIX code to be happy */
+ child->vms_launch_status = 0;
}
/* Set the state flag to say the commands have finished. */
c->file->command_state = cs_finished;
notice_finished_file (c->file);
-#if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */
- /* Remove the child from the chain and free it. */
- if (lastc == 0)
- children = c->next;
- else
- lastc->next = c->next;
- free_child (c);
-#endif /* RECURSIVEJOBS */
-
- /* There is now another slot open. */
- if (job_slots_used > 0)
- --job_slots_used;
-
- /* If the job failed, and the -k flag was not given, die. */
- if (child_failed && !keep_going_flag)
- die (exit_code);
-
(void) sigsetmask (sigblock (0) & ~(fatal_signal_mask));
return 1;
@@ -216,8 +227,6 @@ vmsHandleChildTerm(struct child *child)
/* VMS:
Spawn a process executing the command in ARGV and return its pid. */
-#define MAXCMDLEN 200
-
/* local helpers to make ctrl+c and ctrl+y working, see below */
#include <iodef.h>
#include <libclidef.h>
@@ -508,10 +517,8 @@ child_execute_job (char *argv, struct child *child)
}
}
/* expand ':' aka 'do nothing' builtin for bash and friends */
- else if (cmd[0]==':' && cmd[1]=='\0')
- {
- cmd = "continue";
- }
+ else if (cmd[0]==':')
+ cmd[0] = '!';
}
else
{
@@ -614,23 +621,23 @@ child_execute_job (char *argv, struct child *child)
cmd = tmp_cmd;
}
-#ifdef USE_DCL_COM_FILE
- /* Enforce the creation of a command file.
+ /* Enforce the creation of a command file if "vms_always_use_cmd_file" is
+ non-zero.
Then all the make environment variables are written as DCL symbol
assignments into the command file as well, so that they are visible
in the sub-process but do not affect the current process.
Further, this way DCL reads the input stream and therefore does
'forced' symbol substitution, which it doesn't do for one-liners when
they are 'lib$spawn'ed. */
-#else
+
+ /* Otherwise the behavior is: */
/* Create a *.com file if either the command is too long for
lib$spawn, or the command contains a newline, or if redirection
is desired. Forcing commands with newlines into DCLs allows to
store search lists on user mode logicals. */
- if (strlen (cmd) > MAXCMDLEN
+ if (vms_always_use_cmd_file || strlen (cmd) > (MAX_DCL_LINE_LENGTH - 30)
|| (have_redirection != 0)
|| (have_newline != 0))
-#endif
{
FILE *outfile;
char c;
@@ -696,9 +703,9 @@ child_execute_job (char *argv, struct child *child)
DB (DB_JOBS, (_("Redirected output to %s\n"), ofile));
ofiledsc.dsc$w_length = 0;
}
-#ifdef USE_DCL_COM_FILE
+
/* Export the child environment into DCL symbols */
- if (child->environment != 0)
+ if (vms_always_use_cmd_file || (child->environment != 0))
{
char **ep = child->environment;
char *valstr;
@@ -712,7 +719,7 @@ child_execute_job (char *argv, struct child *child)
ep++;
}
}
-#endif
+
fprintf (outfile, "$ %.*s_ = f$verify(%.*s_1)\n", tmpstrlen, tmpstr, tmpstrlen, tmpstr);
/* TODO: give 78 a name! Whether 78 is a good number is another question.
@@ -834,6 +841,17 @@ child_execute_job (char *argv, struct child *child)
vms_jobsefnmask |= (1 << (child->efn - 32));
+ /* Export the child environment into DCL symbols */
+ if (!vms_always_use_cmd_file && child->environment != 0)
+ {
+ char **ep = child->environment;
+ while (*ep != 0)
+ {
+ vms_putenv_symbol (*ep);
+ *ep++;
+ }
+ }
+
/*
LIB$SPAWN [command-string]
[,input-file]
@@ -886,21 +904,23 @@ child_execute_job (char *argv, struct child *child)
if (!setupYAstTried)
tryToSetupYAst();
- status = lib$spawn (&cmddsc, /* cmd-string */
- (ifiledsc.dsc$w_length == 0)?0:&ifiledsc, /* input-file */
- (ofiledsc.dsc$w_length == 0)?0:&ofiledsc, /* output-file */
- &spflags, /* flags */
- &pnamedsc, /* proc name */
- &child->pid, &child->cstatus, &child->efn,
- 0, 0,
- 0, 0, 0);
- if (status & 1)
+ child->vms_launch_status = lib$spawn (&cmddsc, /* cmd-string */
+ (ifiledsc.dsc$w_length == 0)?0:&ifiledsc, /* input-file */
+ (ofiledsc.dsc$w_length == 0)?0:&ofiledsc, /* output-file */
+ &spflags, /* flags */
+ &pnamedsc, /* proc name */
+ &child->pid, &child->cstatus, &child->efn,
+ 0, 0,
+ 0, 0, 0);
+
+ status = child->vms_launch_status;
+ if ($VMS_STATUS_SUCCESS (status))
{
- status= sys$waitfr (child->efn);
- vmsHandleChildTerm(child);
+ status = sys$waitfr (child->efn);
+ vmsHandleChildTerm (child);
}
#else
- status = lib$spawn (&cmddsc,
+ child->vms_launch_status = lib$spawn (&cmddsc,
(ifiledsc.dsc$w_length == 0)?0:&ifiledsc,
(ofiledsc.dsc$w_length == 0)?0:&ofiledsc,
&spflags,
@@ -908,15 +928,14 @@ child_execute_job (char *argv, struct child *child)
&child->pid, &child->cstatus, &child->efn,
vmsHandleChildTerm, child,
0, 0, 0);
+ status = child->vms_launch_status;
#endif
- if (!(status & 1))
+ if (!$VMS_STATUS_SUCCESS (status))
{
- printf (_("Error spawning, %d\n") ,status);
- fflush (stdout);
switch (status)
{
- case 0x1c:
+ case SS$_EXQUOTA:
errno = EPROCLIM;
break;
default:
@@ -924,5 +943,16 @@ child_execute_job (char *argv, struct child *child)
}
}
+ /* Restore the VMS symbols that were changed */
+ if (!vms_always_use_cmd_file && child->environment != 0)
+ {
+ char **ep = child->environment;
+ while (*ep != 0)
+ {
+ vms_restore_symbol (*ep);
+ *ep++;
+ }
+ }
+
return (status & 1);
}