1 /* --------------- Moved here from job.c ---------------
2 This file must be #included in job.c, as it accesses static functions.
4 Copyright (C) 1996-2013 Free Software Foundation, Inc.
5 This file is part of GNU Make.
7 GNU Make is free software; you can redistribute it and/or modify it under the
8 terms of the GNU General Public License as published by the Free Software
9 Foundation; either version 3 of the License, or (at your option) any later
12 GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License along with
17 this program. If not, see <http://www.gnu.org/licenses/>. */
23 char *vmsify (char *name, int type);
25 static int vms_jobsefnmask = 0;
27 /* Wait for nchildren children to terminate */
29 vmsWaitForChildren(int *status)
39 *status = sys$wflor (32, vms_jobsefnmask);
44 /* Set up IO redirection. */
47 vms_redirect (struct dsc$descriptor_s *desc, char *fname, char *ibuf)
52 while (isspace ((unsigned char)*ibuf))
55 while (*ibuf && !isspace ((unsigned char)*ibuf))
58 if (strcmp (fptr, "/dev/null") != 0)
60 strcpy (fname, vmsify (fptr, 0));
61 if (strchr (fname, '.') == 0)
64 desc->dsc$w_length = strlen (fname);
65 desc->dsc$a_pointer = fname;
66 desc->dsc$b_dtype = DSC$K_DTYPE_T;
67 desc->dsc$b_class = DSC$K_CLASS_S;
70 printf (_("Warning: Empty redirection\n"));
75 /* found apostrophe at (p-1)
76 inc p until after closing apostrophe.
80 vms_handle_apos (char *p)
84 #define SEPCHARS ",/()= "
98 if (strchr (SEPCHARS, *p))
108 static int ctrlYPressed= 0;
109 /* This is called at main or AST level. It is at AST level for DONTWAITFORCHILD
110 and at main level otherwise. In any case it is called when a child process
111 terminated. At AST level it won't get interrupted by anything except a
112 inner mode level AST.
115 vmsHandleChildTerm(struct child *child)
118 register struct child *lastc, *c;
121 vms_jobsefnmask &= ~(1 << (child->efn - 32));
123 lib$free_ef (&child->efn);
126 if (!ISDB (DB_JOBS) && !ctrlYPressed)
127 unlink (child->comname);
128 free (child->comname);
131 (void) sigblock (fatal_signal_mask);
133 child_failed = !(child->cstatus & 1 || ((child->cstatus & 7) == 0));
135 /* Search for a child matching the deceased one. */
137 #if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */
138 for (c = children; c != 0 && c != child; lastc = c, c = c->next)
144 if (child_failed && !c->noerror && !ignore_errors_flag)
146 /* The commands failed. Write an error message,
147 delete non-precious targets, and abort. */
148 child_error (c, c->cstatus, 0, 0, 0);
149 c->file->update_status = us_failed;
150 delete_child_targets (c);
156 /* The commands failed, but we don't care. */
157 child_error (c, c->cstatus, 0, 0, 1);
161 #if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */
162 /* If there are more commands to run, try to start them. */
165 switch (c->file->command_state)
168 /* Successfully started. */
172 if (c->file->update_status != us_success)
173 /* We failed to start the commands. */
174 delete_child_targets (c);
178 error (NILF, _("internal error: '%s' command_state"),
183 #endif /* RECURSIVEJOBS */
186 /* Set the state flag to say the commands have finished. */
187 c->file->command_state = cs_finished;
188 notice_finished_file (c->file);
190 #if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */
191 /* Remove the child from the chain and free it. */
195 lastc->next = c->next;
197 #endif /* RECURSIVEJOBS */
199 /* There is now another slot open. */
200 if (job_slots_used > 0)
203 /* If the job failed, and the -k flag was not given, die. */
204 if (child_failed && !keep_going_flag)
207 (void) sigsetmask (sigblock (0) & ~(fatal_signal_mask));
213 Spawn a process executing the command in ARGV and return its pid. */
215 #define MAXCMDLEN 200
217 /* local helpers to make ctrl+c and ctrl+y working, see below */
219 #include <libclidef.h>
222 static int ctrlMask= LIB$M_CLI_CTRLY;
223 static int oldCtrlMask;
224 static int setupYAstTried= 0;
225 static unsigned short int chan= 0;
230 lib$enable_ctrl (&oldCtrlMask,0);
237 for (c = children; c != 0; c = c->next)
238 sys$delprc (&c->pid, 0, 0);
240 kill (getpid(),SIGQUIT);
247 $DESCRIPTOR(inputDsc,"SYS$COMMAND");
250 short int status, count;
253 unsigned short int loc_chan;
261 status= sys$assign(&inputDsc,&loc_chan,0,0);
262 if (!(status&SS$_NORMAL))
268 status= sys$qiow (0, loc_chan, IO$_SETMODE|IO$M_CTRLYAST,&iosb,0,0,
269 astYHandler,0,0,0,0,0);
270 if (status==SS$_NORMAL)
272 if (status!=SS$_NORMAL)
275 sys$dassgn(loc_chan);
276 if (status!=SS$_ILLIOFUNC && status!=SS$_NOPRIV)
281 /* called from AST handler ? */
282 if (setupYAstTried>1)
284 if (atexit(reEnableAst))
286 _("-warning, you may have to re-enable CTRL-Y handling from DCL.\n"));
287 status= lib$disable_ctrl (&ctrlMask, &oldCtrlMask);
288 if (!(status&SS$_NORMAL))
298 child_execute_job (char *argv, struct child *child)
301 static struct dsc$descriptor_s cmddsc;
302 static struct dsc$descriptor_s pnamedsc;
303 static struct dsc$descriptor_s ifiledsc;
304 static struct dsc$descriptor_s ofiledsc;
305 static struct dsc$descriptor_s efiledsc;
306 int have_redirection = 0;
308 int have_newline = 0;
310 int spflags = CLI$M_NOWAIT;
312 char *cmd = alloca (strlen (argv) + 512), *p, *q;
313 char ifile[256], ofile[256], efile[256];
318 /* Parse IO redirection. */
323 child->comname = NULL;
325 DB (DB_JOBS, ("child_execute_job (%s)\n", argv));
327 while (isspace ((unsigned char)*argv))
333 sprintf (procname, "GMAKE_%05x", getpid () & 0xfffff);
334 pnamedsc.dsc$w_length = strlen(procname);
335 pnamedsc.dsc$a_pointer = procname;
336 pnamedsc.dsc$b_dtype = DSC$K_DTYPE_T;
337 pnamedsc.dsc$b_class = DSC$K_CLASS_S;
340 /* Handle comments and redirection. */
341 for (p = argv, q = cmd; *p; p++, q++)
344 in_string = !in_string;
360 if (isspace ((unsigned char)*p))
362 do { p++; } while (isspace ((unsigned char)*p));
368 p = vms_redirect (&ifiledsc, ifile, p);
370 have_redirection = 1;
373 have_redirection = 1;
377 if (strncmp (p, ">&1", 3) == 0)
380 strcpy (efile, "sys$output");
381 efiledsc.dsc$w_length = strlen(efile);
382 efiledsc.dsc$a_pointer = efile;
383 efiledsc.dsc$b_dtype = DSC$K_DTYPE_T;
384 efiledsc.dsc$b_class = DSC$K_CLASS_S;
387 p = vms_redirect (&efiledsc, efile, p);
396 p = vms_redirect (&ofiledsc, ofile, p);
408 while (isspace ((unsigned char)*--q))
411 if (strncmp (cmd, "builtin_", 8) == 0)
417 DB (DB_JOBS, (_("BUILTIN [%s][%s]\n"), cmd, cmd+8));
423 && ((*(p+2) == ' ') || (*(p+2) == '\t')))
426 while ((*p == ' ') || (*p == '\t'))
428 DB (DB_JOBS, (_("BUILTIN CD %s\n"), p));
434 else if ((*(p) == 'r')
436 && ((*(p+2) == ' ') || (*(p+2) == '\t')))
442 while ((*p == ' ') || (*p == '\t'))
446 DB (DB_JOBS, (_("BUILTIN RM %s\n"), p));
467 printf (_("Unknown builtin command '%s'\n"), cmd);
473 /* Create a *.com file if either the command is too long for
474 lib$spawn, or the command contains a newline, or if redirection
475 is desired. Forcing commands with newlines into DCLs allows to
476 store search lists on user mode logicals. */
478 if (strlen (cmd) > MAXCMDLEN
479 || (have_redirection != 0)
480 || (have_newline != 0))
485 int alevel = 0; /* apostrophe level */
487 if (strlen (cmd) == 0)
489 printf (_("Error, empty command\n"));
494 outfile = output_tmpfile (&child->comname, "sys$scratch:CMDXXXXXX.COM");
496 pfatal_with_name (_("fopen (temporary file)"));
497 comnamelen = strlen (child->comname);
501 fprintf (outfile, "$ assign/user %s sys$input\n", ifile);
502 DB (DB_JOBS, (_("Redirected input from %s\n"), ifile));
503 ifiledsc.dsc$w_length = 0;
508 fprintf (outfile, "$ define sys$error %s\n", efile);
509 DB (DB_JOBS, (_("Redirected error to %s\n"), efile));
510 efiledsc.dsc$w_length = 0;
516 fprintf (outfile, "$ set noon\n");
517 fprintf (outfile, "$ define sys$output %.*s\n", comnamelen-3, child->comname);
518 DB (DB_JOBS, (_("Append output to %s\n"), ofile));
519 ofiledsc.dsc$w_length = 0;
523 fprintf (outfile, "$ define sys$output %s\n", ofile);
524 DB (DB_JOBS, (_("Redirected output to %s\n"), ofile));
525 ofiledsc.dsc$w_length = 0;
529 for (c = '\n'; c; c = *q++)
534 /* At a newline, skip any whitespace around a leading $
535 from the command and issue exactly one $ into the DCL. */
536 while (isspace ((unsigned char)*p))
540 while (isspace ((unsigned char)*p))
542 fwrite (p, 1, q - p, outfile);
543 fputc ('$', outfile);
544 fputc (' ', outfile);
545 /* Reset variables. */
549 /* Nice places for line breaks are after strings, after
550 comma or space and before slash. */
552 q = vms_handle_apos (q);
568 /* Enough stuff for a line. */
569 fwrite (p, 1, sep - p, outfile);
573 /* The command continues. */
574 fputc ('-', outfile);
576 fputc ('\n', outfile);
582 fwrite (p, 1, --q - p, outfile);
583 fputc ('\n', outfile);
588 fprintf (outfile, "$ deassign sys$output ! 'f$verify(0)\n");
589 fprintf (outfile, "$ append:=append\n");
590 fprintf (outfile, "$ delete:=delete\n");
591 fprintf (outfile, "$ append/new %.*s %s\n", comnamelen-3, child->comname, ofile);
592 fprintf (outfile, "$ delete %.*s;*\n", comnamelen-3, child->comname);
593 DB (DB_JOBS, (_("Append %.*s and cleanup\n"), comnamelen-3, child->comname));
598 sprintf (cmd, "$ @%s", child->comname);
600 DB (DB_JOBS, (_("Executing %s instead\n"), cmd));
603 cmddsc.dsc$w_length = strlen(cmd);
604 cmddsc.dsc$a_pointer = cmd;
605 cmddsc.dsc$b_dtype = DSC$K_DTYPE_T;
606 cmddsc.dsc$b_class = DSC$K_CLASS_S;
609 while (child->efn < 32 || child->efn > 63)
611 status = lib$get_ef ((unsigned long *)&child->efn);
617 unlink (child->comname);
618 free (child->comname);
624 sys$clref (child->efn);
626 vms_jobsefnmask |= (1 << (child->efn - 32));
629 LIB$SPAWN [command-string]
634 [,process-id] [,completion-status-address] [,byte-integer-event-flag-num]
635 [,AST-address] [,varying-AST-argument]
636 [,prompt-string] [,cli] [,table]
639 #ifndef DONTWAITFORCHILD
641 * Code to make ctrl+c and ctrl+y working.
642 * The problem starts with the synchronous case where after lib$spawn is
643 * called any input will go to the child. But with input re-directed,
644 * both control characters won't make it to any of the programs, neither
645 * the spawning nor to the spawned one. Hence the caller needs to spawn
646 * with CLI$M_NOWAIT to NOT give up the input focus. A sys$waitfr
647 * has to follow to simulate the wanted synchronous behaviour.
648 * The next problem is ctrl+y which isn't caught by the crtl and
649 * therefore isn't converted to SIGQUIT (for a signal handler which is
650 * already established). The only way to catch ctrl+y, is an AST
651 * assigned to the input channel. But ctrl+y handling of DCL needs to be
652 * disabled, otherwise it will handle it. Not to mention the previous
653 * ctrl+y handling of DCL needs to be re-established before make exits.
654 * One more: At the time of LIB$SPAWN signals are blocked. SIGQUIT will
655 * make it to the signal handler after the child "normally" terminates.
656 * This isn't enough. It seems reasonable for simple command lines like
657 * a 'cc foobar.c' spawned in a subprocess but it is unacceptable for
658 * spawning make. Therefore we need to abort the process in the AST.
660 * Prior to the spawn it is checked if an AST is already set up for
661 * ctrl+y, if not one is set up for a channel to SYS$COMMAND. In general
662 * this will work except if make is run in a batch environment, but there
663 * nobody can press ctrl+y. During the setup the DCL handling of ctrl+y
664 * is disabled and an exit handler is established to re-enable it.
665 * If the user interrupts with ctrl+y, the assigned AST will fire, force
666 * an abort to the subprocess and signal SIGQUIT, which will be caught by
667 * the already established handler and will bring us back to common code.
668 * After the spawn (now /nowait) a sys$waitfr simulates the /wait and
669 * enables the ctrl+y be delivered to this code. And the ctrl+c too,
670 * which the crtl converts to SIGINT and which is caught by the common
671 * signal handler. Because signals were blocked before entering this code
672 * sys$waitfr will always complete and the SIGQUIT will be processed after
673 * it (after termination of the current block, somewhere in common code).
674 * And SIGINT too will be delayed. That is ctrl+c can only abort when the
675 * current command completes. Anyway it's better than nothing :-)
680 status = lib$spawn (&cmddsc, /* cmd-string */
681 (ifiledsc.dsc$w_length == 0)?0:&ifiledsc, /* input-file */
682 (ofiledsc.dsc$w_length == 0)?0:&ofiledsc, /* output-file */
683 &spflags, /* flags */
684 &pnamedsc, /* proc name */
685 &child->pid, &child->cstatus, &child->efn,
690 status= sys$waitfr (child->efn);
691 vmsHandleChildTerm(child);
694 status = lib$spawn (&cmddsc,
695 (ifiledsc.dsc$w_length == 0)?0:&ifiledsc,
696 (ofiledsc.dsc$w_length == 0)?0:&ofiledsc,
699 &child->pid, &child->cstatus, &child->efn,
700 vmsHandleChildTerm, child,
706 printf (_("Error spawning, %d\n") ,status);