/* @(#)osp.c 17.1.1.1 (ES0-DMD) 01/25/02 17:35:09 */ /*=========================================================================== Copyright (C) 1995 European Southern Observatory (ESO) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Massachusetss Ave, Cambridge, MA 02139, USA. Corresponding concerning ESO-MIDAS should be addressed as follows: Internet e-mail: midas@eso.org Postal address: European Southern Observatory Data Management Division Karl-Schwarzschild-Strasse 2 D 85748 Garching bei Muenchen GERMANY ===========================================================================*/ /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .TYPE Module .NAME osp .LANGUAGE C .AUTHOR IPG-ESO Garching .CATEGORY Host operating system interfaces, Process control. .COMMENTS These routines give the basic capabilitites for controlling processes. Processes are addressed by an integer number called process identifier. The process activation function defines the file with the executable code (possibly in a remote node) and the process name, the routine returns the process identification number to be used in further references. Processes can be activated or aborted, also the process logical name associated to it can be changed. At process creation, one can redirect the standard input and/or output of the newly created process. Each process has some status information associated to it. The status information is defined as a data structure (tag prstatus) consisting of a process id (pid field), background/foreground flag (bflg field) and name (procname field) for checking the status of the child process. Functions in this module allow to define and retrieve this status information. The routines return always a non-negative integer number on successful return. Otherwise, a value of -1 is set to indicate an error condition and the variable ``oserror'' contains the symbolic error code. .VERSION [0.0] 25-Aug-1986 Definition B. Pirenne .VERSION [1.0] 10-Nov-1986 Programmation BP .VERSION [1.5] 26-Jun-1987 Add child process termination control BP .VERSION [1.6] 07-Jul-1987 Allow redefin. of stdin and/or stdout of child .VERSION [1.7] 04-Nov-1987 fix construction of process name in ospcreate K. Banse .VERSION [1.8] 01-Dec-1987 Add child status in proc. struct in private memory I.Suisalu. .VERSION [1.9] 25-May-1988 Cosmetic changes C. Guirao .VERSION [1.10]14-OCT-1988 The child signal SIGCLD get SIG_DFL C.G. .VERSION [1.11]19-Oct-1989 Conceal interal subroutines .VERSION [1.12]25-Apr-1991 Added signal.h include + VOID .REMARK =================== System V version ================ .REMARK On the management and information retrieval of the processes: In order to be able to retrieve information on the processes and in order to give a name to it, a special structure was built(see "osparms.h"). Array of this structures are hold in private memory of the calling program. .VERSION [1.13]20-Jan-1992 CG. SHELL variable is used to spawn processes .VERSION [1.14]14-Apr-1992 CG. Change 1.14 is removed. The Bourne-Shell is the only one that do change the environment .VERSION [2.0]13-Jul-1992 CG. chcatch is VOID. CG .VERSION [2.1]14-Jul-1992 VOID is now called VOIDSIG. CG. -------------------------------------------------------------------------*/ /* * Define _POSIX_SOURCE to indicate * that this is a POSIX program */ #define _POSIX_SOURCE 1 #include /* ANSI-C prototyping */ #include #include #include #include #include #include #include #ifdef OSERROR_D /* oserror already defined (Silicon G)*/ #define oserror midaserror #endif static int pid; extern char *oserrmsg; extern int oserror; #ifdef __STDC__ static void alarm_handler(int sig) #else static void alarm_handler(sig) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE dummy routine to catch SIGALRM avoiding killing the process -----------------------------------------------------------*/ int sig; #endif { kill (pid, SIGKILL); } int ospcreate(phname, procname, backgrd, stin, stout, time_out) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Activates a specified process whose name is phname and logical process name is procname. (this last name can be modify using osprename) Enviroment pointer also passed to the process. One argument (backgrd) defines if the process will run in background/foreground. Allows redirection of the process' standard input and/or output to specified files if the corresponding file descriptors returned from a previous open (osd-, osa-, osx-, ...) statement are given as last parameters to this call. .RETURNS Upon successful completion the .RETURNS process identification is returned, otherwise -1. .REMARKS System dependencies: -- UNIX: fork(2), execl(2),open(2), close(2), getuid(2), close(2), dup(2), ------------------------------------------------------------*/ char *phname; /* IN : physical filename with executable code */ char *procname; /* IN : process logical name . OBSOLETE*/ int backgrd; /* Put backgound or not */ int stin; /* IN : file descr. of the new child's std. input */ int stout; /* IN : file descr. of the new child's std. output */ unsigned int time_out; /* IN : amount of seconds for timeout */ { int chstat; struct sigaction ignore, saveintr, savequit; char *ptr_bgr; ignore.sa_handler = SIG_IGN; sigemptyset(&ignore.sa_mask); ignore.sa_flags = 0; if (sigaction(SIGINT,&ignore,&saveintr) != 0) { oserror=errno; return(-1); }; if (sigaction(SIGQUIT,&ignore,&savequit) != 0) { oserror=errno; return(-1); }; /* * In the parent process, fork returns the * process number of the child. In the * child process, 0 is returned. */ switch (pid = fork()) { case -1: oserror =errno; return(-1); case 0: /* In child process */ /* Restore signals for child process */ (void) sigaction(SIGINT, &saveintr, (struct sigaction *)NULL); (void) sigaction(SIGQUIT, &savequit, (struct sigaction *)NULL); if (stin != 0) { /* redirected input of child process */ (void) close (0); /* close old standard input */ (void) dup(stin); /* duplicate file descriptor */ (void) close(stin); /* close unnecessary old file descr. */ } if (stout != 1) { /* redirected output of child process */ (void) close (1); /* close old standard output */ (void) dup(stout); /* duplicate file descriptor */ (void) close(stout); /* close unnecessary old file descr. */ } if (*phname == '$') { /* system command */ phname ++; /* if background, ignore SIGINT and SIGQUIT */ if ( (ptr_bgr = strrchr(phname,'&')) != NULL) { ptr_bgr++; for ( ; *ptr_bgr && *ptr_bgr == ' '; ptr_bgr++) ; if (!*ptr_bgr) { sigaction(SIGINT,&ignore,&saveintr); sigaction(SIGQUIT,&ignore,&savequit); } } (void) execl("/bin/sh","sh","-c",phname,(char *)0); } else { /* Execute the process */ if (strchr(phname,' ') == (char *)0) (void)execl(phname,phname,(char *)0); else { /* the phname contains arguments */ char *arg[9]; char *log_name, *blank_ptr; int i; log_name = malloc (strlen(phname)+1); strcpy(log_name,phname); arg[0]=log_name; for (i=0; i < 8 ; i++) { if ( !(blank_ptr = strchr(arg[i],' '))) { arg[i+1] = (char *)0; break; } while ( *blank_ptr == ' ' ) *blank_ptr++ = '\0'; arg[i+1] = blank_ptr; } (void)execl(arg[0],arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],arg[7],arg[8],(char *)0); } } /* exit with the errno code + eight bit set, to be recognized by chstat */ /* Do not print the error. The application could then try in midwork */ /* printf("ERROR IN CHILD, errno = %d\n",errno); */ exit(0x80 | errno); /* suppress the fork */; default: /* In father process */ if(!backgrd) { struct sigaction act, oalrm; if (time_out != 0) { /* Catch the signal ALRM to avoid proccess to terminate */ act.sa_handler = alarm_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGALRM,&act,&oalrm); /* Set alarm to time_out */ (void) alarm(time_out); } oserror = 0; while (waitpid(pid, &chstat, 0) != pid) { if (errno != EINTR) { oserror= errno; break; } } if (time_out != 0) { (void) alarm(0); sigaction(SIGALRM,&oalrm,&act); } /* If the execl failed */ if ( (chstat & 0x8000) == 0x8000 ) oserror = ( (chstat >> 8 ) & 0x7f ); if (!oserror) { if ( WIFEXITED(chstat) ) oserror = WEXITSTATUS(chstat); if ( WIFSIGNALED(chstat) ) { int int_signal; char errmsg[80]; int_signal = WTERMSIG(chstat); sprintf(errmsg,"Child killed by signal %d",int_signal); oserrmsg = errmsg; oserror = -1; } } } /* restore previous signal actions */ sigaction(SIGINT,&saveintr,(struct sigaction *)NULL); sigaction(SIGQUIT,&savequit,(struct sigaction *)NULL); if (oserror) pid = -1; } return(pid); } void ospexit(stat) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Normal termination of a process. .RETURNS Nothing .REMARKS System dependencies: -- UNIX: exit(2) ------------------------------------------------------------*/ int stat; { exit(stat); /* Terminates the process. */ } int ospwait(time) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Delays the execution of a process for a time interval. Resolution of time interval is in seconds. .RETURNS Always 0 .REMARKS System dependencies: -- UNIX: sleep(2) ------------------------------------------------------------*/ unsigned int time; /* IN : time delay in seconds */ { sleep(time); return(0); } /* CG. I favor to removed this, and use getpid directly * Currently used by gui applications: XSpectra XFilter XEchelle & stella */ int osppid() /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Obtains current process identification. .RETURNS The process identification as a integer. -------------------------------------------------------------*/ { return(getpid()); }