#include <string.h>
#include <descrip.h>
#include <clidef.h>
extern char *vmsify PARAMS ((char *name, int type));
static int vms_jobsefnmask = 0;
static void
vmsWaitForChildren(int *status)
{
while (1)
{
if (!vms_jobsefnmask)
{
*status = 0;
return;
}
*status = sys$wflor (32, vms_jobsefnmask);
}
return;
}
char *
vms_redirect (struct dsc$descriptor_s *desc, char *fname, char *ibuf)
{
char *fptr;
ibuf++;
while (isspace ((unsigned char)*ibuf))
ibuf++;
fptr = ibuf;
while (*ibuf && !isspace ((unsigned char)*ibuf))
ibuf++;
*ibuf = 0;
if (strcmp (fptr, "/dev/null") != 0)
{
strcpy (fname, vmsify (fptr, 0));
if (strchr (fname, '.') == 0)
strcat (fname, ".");
}
desc->dsc$w_length = strlen(fname);
desc->dsc$a_pointer = fname;
desc->dsc$b_dtype = DSC$K_DTYPE_T;
desc->dsc$b_class = DSC$K_CLASS_S;
if (*fname == 0)
printf (_("Warning: Empty redirection\n"));
return ibuf;
}
char *
vms_handle_apos (char *p)
{
int alast;
#define SEPCHARS ",/()= "
alast = 0;
while (*p != 0)
{
if (*p == '"')
{
if (alast)
{
alast = 0;
p++;
}
else
{
p++;
if (strchr (SEPCHARS, *p))
break;
alast = 1;
}
}
else
p++;
}
return p;
}
int
vmsHandleChildTerm(struct child *child)
{
int status;
register struct child *lastc, *c;
int child_failed;
vms_jobsefnmask &= ~(1 << (child->efn - 32));
lib$free_ef(&child->efn);
(void) sigblock (fatal_signal_mask);
child_failed = !(child->cstatus & 1 || ((child->cstatus & 7) == 0));
lastc = 0;
#if defined(RECURSIVEJOBS)
for (c = children; c != 0 && c != child; lastc = c, c = c->next)
;
#else
c = child;
#endif
if (child_failed && !c->noerror && !ignore_errors_flag)
{
child_error (c->file->name, c->cstatus, 0, 0, 0);
c->file->update_status = 1;
delete_child_targets (c);
}
else
{
if (child_failed)
{
child_error (c->file->name, c->cstatus, 0, 0, 1);
child_failed = 0;
}
#if defined(RECURSIVEJOBS)
start_job (c);
switch (c->file->command_state)
{
case cs_running:
break;
case cs_finished:
if (c->file->update_status != 0) {
delete_child_targets (c);
}
break;
default:
error (NILF, _("internal error: `%s' command_state"),
c->file->name);
abort ();
break;
}
#endif
}
c->file->command_state = cs_finished;
notice_finished_file (c->file);
#if defined(RECURSIVEJOBS)
if (lastc == 0)
children = c->next;
else
lastc->next = c->next;
free_child (c);
#endif
if (job_slots_used > 0)
--job_slots_used;
if (child_failed && !keep_going_flag)
die (EXIT_FAILURE);
(void) sigsetmask (sigblock (0) & ~(fatal_signal_mask));
return 1;
}
#define MAXCMDLEN 200
#include <iodef.h>
#include <libclidef.h>
#include <ssdef.h>
static int ctrlMask= LIB$M_CLI_CTRLY;
static int oldCtrlMask;
static int setupYAstTried= 0;
static int pidToAbort= 0;
static int chan= 0;
static void
reEnableAst(void)
{
lib$enable_ctrl (&oldCtrlMask,0);
}
static void
astHandler (void)
{
if (pidToAbort) {
sys$forcex (&pidToAbort, 0, SS$_ABORT);
pidToAbort= 0;
}
kill (getpid(),SIGQUIT);
}
static void
tryToSetupYAst(void)
{
$DESCRIPTOR(inputDsc,"SYS$COMMAND");
int status;
struct {
short int status, count;
int dvi;
} iosb;
setupYAstTried++;
if (!chan) {
status= sys$assign(&inputDsc,&chan,0,0);
if (!(status&SS$_NORMAL)) {
lib$signal(status);
return;
}
}
status= sys$qiow (0, chan, IO$_SETMODE|IO$M_CTRLYAST,&iosb,0,0,
astHandler,0,0,0,0,0);
if (status==SS$_NORMAL)
status= iosb.status;
if (status==SS$_ILLIOFUNC || status==SS$_NOPRIV) {
sys$dassgn(chan);
#ifdef CTRLY_ENABLED_ANYWAY
fprintf (stderr,
_("-warning, CTRL-Y will leave sub-process(es) around.\n"));
#else
return;
#endif
}
else if (!(status&SS$_NORMAL)) {
sys$dassgn(chan);
lib$signal(status);
return;
}
if (setupYAstTried>1)
return;
if (atexit(reEnableAst))
fprintf (stderr,
_("-warning, you may have to re-enable CTRL-Y handling from DCL.\n"));
status= lib$disable_ctrl (&ctrlMask, &oldCtrlMask);
if (!(status&SS$_NORMAL)) {
lib$signal(status);
return;
}
}
int
child_execute_job (char *argv, struct child *child)
{
int i;
static struct dsc$descriptor_s cmddsc;
static struct dsc$descriptor_s pnamedsc;
static struct dsc$descriptor_s ifiledsc;
static struct dsc$descriptor_s ofiledsc;
static struct dsc$descriptor_s efiledsc;
int have_redirection = 0;
int have_newline = 0;
int spflags = CLI$M_NOWAIT;
int status;
char *cmd = alloca (strlen (argv) + 512), *p, *q;
char ifile[256], ofile[256], efile[256];
char *comname = 0;
char procname[100];
int in_string;
ifile[0] = 0;
ofile[0] = 0;
efile[0] = 0;
DB (DB_JOBS, ("child_execute_job (%s)\n", argv));
while (isspace ((unsigned char)*argv))
argv++;
if (*argv == 0)
return 0;
sprintf (procname, "GMAKE_%05x", getpid () & 0xfffff);
pnamedsc.dsc$w_length = strlen(procname);
pnamedsc.dsc$a_pointer = procname;
pnamedsc.dsc$b_dtype = DSC$K_DTYPE_T;
pnamedsc.dsc$b_class = DSC$K_CLASS_S;
in_string = 0;
for (p = argv, q = cmd; *p; p++, q++)
{
if (*p == '"')
in_string = !in_string;
if (in_string)
{
*q = *p;
continue;
}
switch (*p)
{
case '#':
*p-- = 0;
*q-- = 0;
break;
case '\\':
p++;
if (*p == '\n')
p++;
if (isspace ((unsigned char)*p))
{
do { p++; } while (isspace ((unsigned char)*p));
p--;
}
*q = *p;
break;
case '<':
p = vms_redirect (&ifiledsc, ifile, p);
*q = ' ';
have_redirection = 1;
break;
case '>':
have_redirection = 1;
if (*(p-1) == '2')
{
q--;
if (strncmp (p, ">&1", 3) == 0)
{
p += 3;
strcpy (efile, "sys$output");
efiledsc.dsc$w_length = strlen(efile);
efiledsc.dsc$a_pointer = efile;
efiledsc.dsc$b_dtype = DSC$K_DTYPE_T;
efiledsc.dsc$b_class = DSC$K_CLASS_S;
}
else
{
p = vms_redirect (&efiledsc, efile, p);
}
}
else
{
p = vms_redirect (&ofiledsc, ofile, p);
}
*q = ' ';
break;
case '\n':
have_newline = 1;
default:
*q = *p;
break;
}
}
*q = *p;
while (isspace ((unsigned char)*--q))
*q = '\0';
if (strncmp (cmd, "builtin_", 8) == 0)
{
child->pid = 270163;
child->efn = 0;
child->cstatus = 1;
DB (DB_JOBS, (_("BUILTIN [%s][%s]\n"), cmd, cmd+8));
p = cmd + 8;
if ((*(p) == 'c')
&& (*(p+1) == 'd')
&& ((*(p+2) == ' ') || (*(p+2) == '\t')))
{
p += 3;
while ((*p == ' ') || (*p == '\t'))
p++;
DB (DB_JOBS, (_("BUILTIN CD %s\n"), p));
if (chdir (p))
return 0;
else
return 1;
}
else if ((*(p) == 'r')
&& (*(p+1) == 'm')
&& ((*(p+2) == ' ') || (*(p+2) == '\t')))
{
int in_arg;
p += 3;
while ((*p == ' ') || (*p == '\t'))
p++;
in_arg = 1;
DB (DB_JOBS, (_("BUILTIN RM %s\n"), p));
while (*p)
{
switch (*p)
{
case ' ':
case '\t':
if (in_arg)
{
*p++ = ';';
in_arg = 0;
}
break;
default:
break;
}
p++;
}
}
else
{
printf(_("Unknown builtin command '%s'\n"), cmd);
fflush(stdout);
return 0;
}
}
if (strlen (cmd) > MAXCMDLEN
|| (have_redirection != 0)
|| (have_newline != 0))
{
FILE *outfile;
char c;
char *sep;
int alevel = 0;
if (strlen (cmd) == 0)
{
printf (_("Error, empty command\n"));
fflush (stdout);
return 0;
}
outfile = open_tmpfile (&comname, "sys$scratch:CMDXXXXXX.COM");
if (outfile == 0)
pfatal_with_name (_("fopen (temporary file)"));
if (ifile[0])
{
fprintf (outfile, "$ assign/user %s sys$input\n", ifile);
DB (DB_JOBS, (_("Redirected input from %s\n"), ifile));
ifiledsc.dsc$w_length = 0;
}
if (efile[0])
{
fprintf (outfile, "$ define sys$error %s\n", efile);
DB (DB_JOBS, (_("Redirected error to %s\n"), efile));
efiledsc.dsc$w_length = 0;
}
if (ofile[0])
{
fprintf (outfile, "$ define sys$output %s\n", ofile);
DB (DB_JOBS, (_("Redirected output to %s\n"), ofile));
ofiledsc.dsc$w_length = 0;
}
p = sep = q = cmd;
for (c = '\n'; c; c = *q++)
{
switch (c)
{
case '\n':
while (isspace ((unsigned char)*p))
p++;
if (*p == '$')
p++;
while (isspace ((unsigned char)*p))
p++;
fwrite (p, 1, q - p, outfile);
fputc ('$', outfile);
fputc (' ', outfile);
p = sep = q;
break;
case '"':
q = vms_handle_apos (q);
sep = q;
break;
case ',':
case ' ':
sep = q;
break;
case '/':
case '\0':
sep = q - 1;
break;
default:
break;
}
if (sep - p > 78)
{
fwrite (p, 1, sep - p, outfile);
p = sep;
if (*sep)
{
fputc ('-', outfile);
}
fputc ('\n', outfile);
}
}
fwrite (p, 1, q - p, outfile);
fputc ('\n', outfile);
fclose (outfile);
sprintf (cmd, "$ @%s", comname);
DB (DB_JOBS, (_("Executing %s instead\n"), cmd));
}
cmddsc.dsc$w_length = strlen(cmd);
cmddsc.dsc$a_pointer = cmd;
cmddsc.dsc$b_dtype = DSC$K_DTYPE_T;
cmddsc.dsc$b_class = DSC$K_CLASS_S;
child->efn = 0;
while (child->efn < 32 || child->efn > 63)
{
status = lib$get_ef ((unsigned long *)&child->efn);
if (!(status & 1))
return 0;
}
sys$clref (child->efn);
vms_jobsefnmask |= (1 << (child->efn - 32));
#ifndef DONTWAITFORCHILD
if (!setupYAstTried)
tryToSetupYAst();
status = lib$spawn (&cmddsc,
(ifiledsc.dsc$w_length == 0)?0:&ifiledsc,
(ofiledsc.dsc$w_length == 0)?0:&ofiledsc,
&spflags,
&pnamedsc,
&child->pid, &child->cstatus, &child->efn,
0, 0,
0, 0, 0);
if (status & 1)
{
pidToAbort= child->pid;
status= sys$waitfr (child->efn);
pidToAbort= 0;
vmsHandleChildTerm(child);
}
#else
status = lib$spawn (&cmddsc,
(ifiledsc.dsc$w_length == 0)?0:&ifiledsc,
(ofiledsc.dsc$w_length == 0)?0:&ofiledsc,
&spflags,
&pnamedsc,
&child->pid, &child->cstatus, &child->efn,
vmsHandleChildTerm, child,
0, 0, 0);
#endif
if (!(status & 1))
{
printf (_("Error spawning, %d\n") ,status);
fflush (stdout);
switch (status)
{
case 0x1c:
errno = EPROCLIM;
break;
default:
errno = EFAIL;
}
}
if (comname && !ISDB (DB_JOBS))
unlink (comname);
return (status & 1);
}