diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
commit | fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch) | |
tree | bdda434976bc09c864f2e4fa6f16ba1952b1e555 /unix/os/zoscmd.c | |
download | iraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz |
Initial commit
Diffstat (limited to 'unix/os/zoscmd.c')
-rw-r--r-- | unix/os/zoscmd.c | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/unix/os/zoscmd.c b/unix/os/zoscmd.c new file mode 100644 index 00000000..63b1c894 --- /dev/null +++ b/unix/os/zoscmd.c @@ -0,0 +1,219 @@ +/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + */ + +#include <stdio.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/time.h> +#include <sys/resource.h> + +#define import_kernel +#define import_knames +#define import_error +#define import_spp +#include <iraf.h> + +#ifdef LINUX +#define USE_SIGACTION +#endif + +static int lastsig; +extern int pr_onint(); + +#ifdef SYSV +#define vfork fork +#else +# ifdef sun +# include <vfork.h> +# endif +#endif + +extern void pr_enter (int pid, int inchan, int outchan); +extern int pr_wait (int pid); + + + +/* ZOSCMD -- Send a (machine dependent) command to the host operating + * system. If nonnull stdout or stderr filenames are given, try to spool + * the output in these files. + */ +int +ZOSCMD ( + PKCHAR *oscmd, + PKCHAR *stdin_file, + PKCHAR *stdout_file, + PKCHAR *stderr_file, + XINT *status +) +{ + char *shell, *sh = "/bin/sh"; + char *sin, *sout, *serr, *cmd; + struct rlimit rlim; + int maxfd, fd, pid; + char *getenv(); +#ifdef USE_SIGACTION + struct sigaction oldact; +#else + SIGFUNC old_sigint; +#endif + + extern int _u_fmode(); + + + cmd = (char *)oscmd; + sin = (char *)stdin_file; + sout = (char *)stdout_file; + serr = (char *)stderr_file; + + /* The Bourne shell SH is used if the first character of the cmd + * is '!' or if the user does not have SHELL defined in their + * environment. + */ + if (*cmd == '!') { + shell = sh; + cmd++; + } else if ((shell = getenv ("SHELL")) == NULL) + shell = sh; + +#ifdef USE_SIGACTION + sigaction (SIGINT, NULL, &oldact); +#else + old_sigint = (SIGFUNC) signal (SIGINT, SIG_IGN); +#endif + + /* Vfork is faster if we can use it. + */ + if (*sin == EOS && *sout == EOS && *serr == EOS) { + while ((pid = vfork()) == ERR) + sleep (2); + } else { + while ((pid = fork()) == ERR) + sleep (2); + } + + if (pid == 0) { + /* Child. + */ + + /* Run the system call. Let child inherit the parents standard + * input unless redirected by nonnull stdin_file. Set standard + * output and error output streams if filenames given, else write + * to same files (i.e., terminal) as parent. + */ + if (*sin != EOS) { /* stdin */ + fd = open (sin, 0); + if (fd == ERR) { + fprintf (stderr, "cannot open `%s'\n", sin); + _exit (1); + } + close (0); dup (fd); close (fd); + } + + if (*sout != EOS) { /* stdout */ + fd = creat (sout, _u_fmode(FILE_MODEBITS)); + if (fd == ERR) + fprintf (stderr, "cannot create `%s'\n", sout); + else { + close (1); dup (fd); close (fd); + } + } + + if (*serr != EOS) { /* stderr */ + /* If stdout and stderr are to go to the same file, + * dup stdout file descriptor as stderr. + */ + if (strcmp (sout, serr) == 0) { + close (2); dup (1); + } else { + fd = creat (serr, _u_fmode(FILE_MODEBITS)); + if (fd == ERR) + fprintf (stderr, "cannot create `%s'\n", serr); + else { + close (2); dup (fd); close (fd); + } + } + } + + if (getrlimit (RLIMIT_NOFILE, &rlim)) + maxfd = MAXOFILES; + else + maxfd = rlim.rlim_cur; + + /* Arrange for the local file descriptors of the parent to be closed + * in the child if the exec succeeds. If this is not done the child + * may run out of file descriptors. + */ + for (fd=3; fd < min(MAXOFILES,maxfd); fd++) + fcntl (fd, F_SETFD, 1); + + /* Spawn a shell to execute the command. + */ + + /* Setting old_sigint here doesn't make sense if we will be + * execl-ing a different process. Use SIG_DFL instead. + signal (SIGINT, old_sigint); + */ + signal (SIGINT, SIG_DFL); + + execl (shell, shell, "-c", cmd, (char *) 0); + + /* NOTREACHED (unless execl fails) */ + _exit (1); + } + + /* Parent: wait for child to finish up. Parent process should ignore + * interrupts; OS process will handle interrupts and return at the + * proper time. The parent is out of the picture while the OS process + * is running (except for the pr_onint interrupt handler, below). + */ + pr_enter (pid, 0, 0); + lastsig = 0; + +#ifndef SYSV + /* This doesn't appear to work on SysV systems, I suspect that wait() + * is not being reentered after the signal handler below. This could + * probably be fixed by modifying the signal handling but I am not + * sure the parent needs to intercept errors in any case, so lets + * try really ignoring errors in the parent instead, on SYSV systems. + */ + if (old_sigint != SIG_IGN) + signal (SIGINT, (SIGFUNC) pr_onint); +#endif + + *status = pr_wait (pid); + + /* If the OS command was interrupted, ignore its exit status and return + * the interrupt exception code to the calling program. Do not return + * the interrupt code unless an interrupt occurs. + */ + if (*status == SYS_XINT) + *status = 1; + if (lastsig == SIGINT) + *status = SYS_XINT; + +#ifdef USE_SIGACTION + sigaction (SIGINT, &oldact, NULL); +#else + signal (SIGINT, old_sigint); +#endif + + return (XOK); +} + + +/* PR_ONINT -- Special interrupt handler for ZOSCMD. If the OS command is + * interrupted, post a flag to indicate this to ZOSCMD when the pr_wait() + * returns. + */ +int +pr_onint ( + int usig, /* SIGINT, SIGFPE, etc. */ + int *hwcode, /* not used */ + int *scp /* not used */ +) +{ + lastsig = usig; + /* return to wait() */ + + return (XOK); +} |