/* @(#)subproc.c 17.1.1.1 (ESO-IPG) 01/25/02 17:26:44 */ /*--------------------------------------------------------------------- * $Date: 93/07/12 19:00:38 $ $Revision: 2.9.6.1 $ *--------------------------------------------------------------------- * Copyright (c) 1992, Visual Edge Software Ltd. * * ALL RIGHTS RESERVED. Permission to use, copy, modify, and * distribute this software and its documentation for any purpose * and without fee is hereby granted, provided that the above * copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Visual Edge Software not be * used in advertising or publicity pertaining to distribution of * the software without specific, written prior permission. The year * included in the notice is the year of the creation of the work. *--------------------------------------------------------------------- * File_Description_Section *--------------------------------------------------------------------*/ /*--- include files ---*/ #include "uxproto.h" #include "version.h" #include "subproc.h" #include "sp_spmd.h" #include "sp_pty.h" /*--- macro symbolic constants ---*/ /*--- macro functions ---*/ /*--- types ---*/ /*--- external functions ---*/ /*--- external variables ---*/ /*--- global variables ---*/ SubprocInfo_t *UxSpArray[MAX_SUBPROC]; SubprocMgr_t UxSubprocMgr; /*--- file global variables ---*/ M_FILE_VERSION("$Header") /*--- forward declaration of static functions ---*/ /*---------------------------------------------------------------------- * NAME: * DESCRIPTION: * PARAMETERS: handle h - handle to subproc * void (*fnt)() - exit callback function * RETURN: ERROR or NO_ERROR * EXT REFS: UxSpArray * EXT EFFECTS: UxSpArray * ASSUMPTIONS: * REVISIONS: 05/01/93 fix3810 clean-up dd/mm/yy fix# fix_description *--------------------------------------------------------------------*/ int UxSetSubprocExitCallback(h, fnt) handle h; void (*fnt)(); { SubprocInfo_t *sp; if(UxCheckIndex(h) == ERROR) return(ERROR); sp = UxSpArray[h]; sp->exit_cb = fnt; return(NO_ERROR); } /*---------------------------------------------------------------------- * NAME: * DESCRIPTION: * PARAMETERS: handle index - index into array of subprocs * RETURN: ERROR or NO_ERROR * EXT REFS: UxSpArray * EXT EFFECTS: UxSpArray * ASSUMPTIONS: * REVISIONS: 05/01/93 fix3810 clean-up 02/04/93 fix4074 don't execute if subproc exiting dd/mm/yy fix# fix_description *--------------------------------------------------------------------*/ int UxDeleteSubproc(index) handle index; { if (UxSpArray[index] == (SubprocInfo_t *) 0) { return ERROR; } if (UxSpArray[index]->subprocStatus != EXITING) { if (UxCheckIndex(index) == ERROR) { return ERROR; } /* Exit the process if running and close tty/pty * remove the XInput fd */ UxExitSubproc(index); if(UxSpArray[index]->process) UxFree(UxSpArray[index]->process); if(UxSpArray[index]->defarg) UxFree(UxSpArray[index]->defarg); UxFree(UxSpArray[index]); UxSpArray[index] = (SubprocInfo_t *) 0; } else { error_msg(CGETS(MS_MISC1_PROCESS_EXITING, DS_MS_MISC1_PROCESS_EXITING)); } return NO_ERROR; } /*---------------------------------------------------------------------- * NAME: * DESCRIPTION: * PARAMETERS: handle thisHandle - index into array of subprocs * RETURN: void * EXT REFS: * EXT EFFECTS: * ASSUMPTIONS: * REVISIONS: 29/04/93 - created dd/mm/yy fix# fix_description *--------------------------------------------------------------------*/ int UxDelayedDeleteSubproc (thisHandle) handle thisHandle; { static handle lastHandle = -1; /*----------------------------------------------------- * Safety check. Allow a value of -1 for handles. It'll * be used to force the previous delete. *-----------------------------------------------------*/ if ((thisHandle != -1) && (UxCheckIndex (thisHandle) == ERROR)) { return(ERROR); } /*----------------------------------------------------- * If we're already in a DELAYED_EXIT, just return * Otherwise, the next time UxDelayedDeleteSubproc is * called it'll try to delete an already deleted handle. *-----------------------------------------------------*/ if ((thisHandle == -1) || (UxSpArray[thisHandle]->subprocStatus != DELAYED_EXIT)) { /*----------------------------------------------------- * The user might have called UxDeleteSubproc after * calling UxDelayedDeleteSubproc on the same handle. * In that case, UxSpArray[lastHandle] is NULL. *-----------------------------------------------------*/ if (lastHandle != -1) { UxDeleteSubproc (lastHandle); } lastHandle = thisHandle; if (thisHandle != -1) { UxSpArray[thisHandle]->subprocStatus = DELAYED_EXIT; } } return NO_ERROR; } /*---------------------------------------------------------------------- * NAME: * DESCRIPTION: * PARAMETERS: char *process - subprocess to be created *defarg - default argument to the subprocess - overridden by argument passed to UxRunSubproc void (*fnt)() - output function caused when output present from subproc * RETURN: subprocess handle = index into subproc arrray * EXT REFS: UxSpArray * EXT EFFECTS: UxSpArray * ASSUMPTIONS: * REVISIONS: 05/01/93 fix3810 clean-up dd/mm/yy fix# fix_description *--------------------------------------------------------------------*/ handle UxCreateSubproc(process, defarg, fnt) char *process, *defarg; void (*fnt)(); { SubprocInfo_t *sp; int index, i; static int initialized = 0; int putenv(); if (!process || !*process) { UxInternalError( __FILE__, __LINE__, CGETS( MS_MISC1_NULL_PROC_ERR, DS_MS_MISC1_NULL_PROC_ERR)); return ERROR; } if(!initialized) { for(i = 0; i < MAX_SUBPROC; i++) { UxSpArray[i] = (SubprocInfo_t *)0; } putenv("TERM=uimx"); initialized = 1; } if( (index = UxGetSp()) == ERROR) return ERROR; sp = UxSpArray[index]; if(! (sp->process = UxMalloc(strlen(process) + 1)) ) { UxInternalError( __FILE__, __LINE__, CGETS( MS_MISC_MALLOC_ERR, DS_MS_MISC_MALLOC_ERR)); UxFree( (char *) sp); UxSpArray[index] = (SubprocInfo_t *)0; return ERROR; } strcpy(sp->process, process); if(!defarg || (defarg[0] == '\0')) sp->defarg = (char *)0; else if(! (sp->defarg = UxMalloc(strlen(defarg) + 1)) ) { UxInternalError( __FILE__, __LINE__, CGETS( MS_MISC_MALLOC_ERR, DS_MS_MISC_MALLOC_ERR)); UxFree(sp->process); UxFree( (char *) sp); UxSpArray[index] = (SubprocInfo_t *)0; return ERROR; } if(defarg && (defarg[0] != '\0')) strcpy(sp->defarg, defarg); sp->output_fnt = fnt; sp->exit_cb = 0; sp->echo= 0; #ifdef DEBUG fprintf(stderr, ">>(%d) [UxCreateSubproc] handle=%d\n", getpid(), index); #endif /* DEBUG */ return(index); } /*---------------------------------------------------------------------- * NAME: * DESCRIPTION: * PARAMETERS: handle sp_h - process handle int echo - do we want echo ? * RETURN: ERROR/NO_ERROR * EXT REFS: UxSpArray * EXT EFFECTS: UxSpArray * ASSUMPTIONS: * REVISIONS: 05/01/93 fix3810 clean-up dd/mm/yy fix# fix_description *--------------------------------------------------------------------*/ int UxSetSubprocEcho(sp_h, echo) handle sp_h; int echo; { SubprocInfo_t *sp; if(UxCheckIndex(sp_h) == ERROR) return(ERROR); sp = UxSpArray[sp_h]; sp->echo= echo; return NO_ERROR; } /*---------------------------------------------------------------------- * NAME: * DESCRIPTION: * PARAMETERS: int flag -close-on-exec flag * RETURN: NONE * EXT REFS: globals_used * EXT EFFECTS: globals or other things altered * ASSUMPTIONS: * REVISIONS: 14/11/91 creation 04/01/92 fix3384 05/01/93 fix3810 cleanup 07/07/93 fix4339 dg port dd/mm/yy fix# fix_description *--------------------------------------------------------------------*/ void UxMarkFileCloseOnExec(flag) int flag; { int i; /* For dg88, we do not want the SYSV code because in design time uimx hangs and we have to do Ctrl-C to unhang it. It works fine with the 'else' code. */ #if defined(SYSV) && !defined(dg88) for (i = 3; i < _NFILE; i++) (void) fcntl(i, F_SETFD, flag); #else /* SYSV */ for (i = getdtablesize(); i > 2; i--) (void) fcntl(i, F_SETFD, flag); #endif /* SYSV */ } /*---------------------------------------------------------------------- * NAME: * DESCRIPTION: * PARAMETERS: handle sp_vh -- handle indicating the process char *cmd_line -- arguments to the process * RETURN: ERROR / NO_ERROR * EXT REFS: UxSpArray * EXT EFFECTS: globals or other things altered * ASSUMPTIONS: * REVISIONS: 05/01/93 fix3810 clean-up dd/mm/yy fix# fix_description *--------------------------------------------------------------------*/ int UxRunSubproc(sp_vh, cmd_line) handle sp_vh; char *cmd_line; { char *cmd; SubprocInfo_t *sp; if(UxCheckIndex(sp_vh) == ERROR) { return(ERROR); } if (UxSpArray[sp_vh]->subprocStatus == DELAYED_EXIT) { UxError( CGETS( MS_MISC_HNDL_DELAYED_EXIT, DS_MS_MISC_HNDL_DELAYED_EXIT)); return(ERROR); } sp = UxSpArray[sp_vh]; if(sp->pid > 0) { error_msg(CGETS( MS_MISC_SUBPROC_RUNNIN, DS_MS_MISC_SUBPROC_RUNNIN)); return(ERROR); } if(cmd_line && (cmd_line[0] != '\0')) cmd = cmd_line; else cmd = sp->defarg; if (UxExecSubprocess(sp, cmd) == ERROR) { return(ERROR); } return(NO_ERROR); } /*---------------------------------------------------------------------- * NAME: * DESCRIPTION: * PARAMETERS: handle sp_vh -- handle indicating the process char *cmd_line -- arguments to the process * RETURN: ERROR / NO_ERROR * EXT REFS: globals_used * EXT EFFECTS: globals or other things altered * ASSUMPTIONS: * REVISIONS: 05/01/93 fix3810 clean-up dd/mm/yy fix# fix_description *--------------------------------------------------------------------*/ int UxExecSubproc(sp_vh, cmd_line) handle sp_vh; char *cmd_line; { if(UxExitSubproc(sp_vh) == ERROR) return(ERROR); if(UxRunSubproc(sp_vh, cmd_line) == ERROR) return(ERROR); return(NO_ERROR); } /*---------------------------------------------------------------------- * NAME: < int UxExitSubproc(sp_vh)> * DESCRIPTION: * PARAMETERS: handle sp_vh -- object handle * RETURN: ERROR / NO_ERROR * EXT REFS: UxSpArray * EXT EFFECTS: UxSpArray * ASSUMPTIONS: * REVISIONS: 05/01/93 fix3810 clean-up dd/mm/yy fix# fix_description *--------------------------------------------------------------------*/ int UxExitSubproc(sp_vh) handle sp_vh; { SubprocInfo_t *sp; if (UxCheckIndex(sp_vh) == ERROR) { return ERROR; } sp = UxSpArray[sp_vh]; if(sp->pid > 0) { kill(sp->pid, SIGKILL); UxSpExit (sp); } return(NO_ERROR); } /*---------------------------------------------------------------------- * NAME: < int UxGetSubprocPid(sp_vh)> * DESCRIPTION: * PARAMETERS: handle sp_vh -- object handle * RETURN: ERROR -1 if the subprocess object does not exist 0 if the process is dead pid if the process is running * EXT REFS: UxSpArray * EXT EFFECTS: UxSpArray * ASSUMPTIONS: * REVISIONS: 19/12/91 fix3288 05/01/93 fix3810 clean-up dd/mm/yy fix# fix_description *--------------------------------------------------------------------*/ int UxGetSubprocPid(sp_vh) handle sp_vh; { SubprocInfo_t *sp; if(UxCheckIndex(sp_vh) == ERROR) return(ERROR); sp = UxSpArray[sp_vh]; if(sp->pid == -1){ error_msg(CGETS( MS_MISC_SUBPROC_NOACT, DS_MS_MISC_SUBPROC_NOACT)); return(ERROR); } /** if there is a process id */ if(sp->pid > 0) { /* and the process is dead -- reset the pid entry -- close the pty/tty and reset the entries -- remove the input source for X */ if ((kill(sp->pid, 0) == -1) && (errno != EPERM)) { sp->pid = -1; /* UxSpExit (sp); */ } } return(sp->pid); } /*---------------------------------------------------------------------- * NAME: * DESCRIPTION: * PARAMETERS handle *sp_vh - process handle char *tex - string to pass to process * RETURN: ERROR /NO_ERROR * EXT REFS: globals_used * EXT EFFECTS: globals or other things altered * ASSUMPTIONS: * REVISIONS: 05/01/93 fix3810 clean-up dd/mm/yy fix# fix_description *--------------------------------------------------------------------*/ int UxSendSubproc(sp_vh, tex) handle sp_vh; char *tex; { char *tbuff; int ret; if(UxCheckIndex(sp_vh) == ERROR) return(ERROR); if (UxSpArray[sp_vh]->subprocStatus == DELAYED_EXIT) { UxError( CGETS( MS_MISC_HNDL_DELAYED_EXIT, DS_MS_MISC_HNDL_DELAYED_EXIT)); return(ERROR); } if(tex == NULL) { tex = ""; } tbuff = (char *) UxMalloc((strlen(tex) + 2)*sizeof(char)); strcpy(tbuff, tex); strcat(tbuff, "\n"); ret = UxSendSubprocNoCR(sp_vh, tbuff); UxFree(tbuff); return ret; } /*---------------------------------------------------------------------- * NAME: * DESCRIPTION: * PARAMETERS: handle sp_vh - process handle char *tex - text string * RETURN: ERROR/NO_ERROR * EXT REFS: UxSpArray * EXT EFFECTS: globals or other things altered * ASSUMPTIONS: * REVISIONS: 05/01/93 fix3810 clean-up 05/04/93 fix4074 message for errno = EAGAIN dd/mm/yy fix# fix_description *--------------------------------------------------------------------*/ int UxSendSubprocNoCR(sp_vh, tex) handle sp_vh; char *tex; { register int len; SubprocInfo_t *sp; spmd_input_t msg; /* viewed as input to subprocess */ if(tex == NULL) { tex = ""; } if(UxCheckIndex(sp_vh) == ERROR) return(ERROR); if (UxSpArray[sp_vh]->subprocStatus == DELAYED_EXIT) { UxError( CGETS( MS_MISC_HNDL_DELAYED_EXIT, DS_MS_MISC_HNDL_DELAYED_EXIT)); return(ERROR); } sp = UxSpArray[sp_vh]; UxSpCheck(sp); /* sp_check() sets pid to -1 if process isn't there */ if(sp->pid == -1) { error_msg(CGETS( MS_MISC_SUBPROC_NOACT, DS_MS_MISC_SUBPROC_NOACT)); return(ERROR); } len = strlen(tex); msg.mtype = SPMD_INPUT; /* input from subprocess perspective */ msg.pid = sp->pid; ASSERT (len < sizeof(msg.input)); /* Could use more messages.. */ strcpy (msg.input, tex); if (msgsnd(UxSpmd.spmd_pc_msqid, &msg, len+sizeof(msg.pid), IPC_NOWAIT) == -1) { if (errno == EAGAIN) { error_msg(CGETS(MS_MISC1_MSG_NOT_SENT, DS_MS_MISC1_MSG_NOT_SENT)); } else { UxInternalError(__FILE__, __LINE__, CGETS( MS_MISC_W_SUBPROC_ERR, DS_MS_MISC_W_SUBPROC_ERR)); UxSpCheck(sp); } return(ERROR); } return(NO_ERROR); } /*---------------------------------------------------------------------- * NAME: * DESCRIPTION: * PARAMETERS: int fd - not used int *status - returns 1 if there is more data * RETURN: char * - pointer to data transferred * EXT REFS: UxSpmd * EXT EFFECTS: UxSpmd * ASSUMPTIONS: * REVISIONS: 05/01/93 fix3810 clean-up 08/01/93 fix3818 to remove r's at end for HP/IBM 25/03/93 fix4037 deal with multibyte *--------------------------------------------------------------------*/ char * UxTransferToBuffer(fd, status) int fd, *status; { int len; int max_read = SIZEOFTEXTMSG - 1; static char text_buff[SIZEOFTEXTMSG]; if ((UxSpmd.spmd_rmsgrp == NULL) || (UxSpmd.spmd_rmsgsiz <= 0)) { return (NULL); /* sanity checking failed */ } /* * Copying could be avoided by returning a pointer into * UxSpmd.spmd_rmsgrp directly. */ len = UxSpmd.spmd_rmsgsiz; strncpy (text_buff, UxSpmd.spmd_rmsgrp, len); text_buff[len] = '\0'; UxSpmd.spmd_rmsgsiz -= len; /* decrement remainder count */ UxSpmd.spmd_rmsgrp = NULL; *status = 0; return(text_buff); } /*---------------------------------------------------------------------- * NAME: * DESCRIPTION: * PARAMETERS: int fd - not used Widget tw - widget to output data to * RETURN: void * EXT REFS: globals_used * EXT EFFECTS: globals or other things altered * ASSUMPTIONS: * REVISIONS: 05/01/93 fix3810 clean-up dd/mm/yy fix# fix_description *--------------------------------------------------------------------*/ void UxAppendTo(fd, tw) int fd; Widget tw; { char *text; int more; while( (text = UxTransferToBuffer(fd, &more)) ) { if(tw) UxTextAppend(tw, text); else fprintf(stdout, "%s",text); if(!more) break; } } /*---------------------------------------------------------------------- * NAME: * DESCRIPTION: * PARAMETERS: handle sp_vh - handle to subproc char *data - data passed to the subprocess function * RETURN: ERROR/NO_ERROR * EXT REFS: UxSpArray * EXT EFFECTS: UxSpArray * ASSUMPTIONS: * REVISIONS: 05/01/93 fix3810 clean-up dd/mm/yy fix# fix_description *--------------------------------------------------------------------*/ int UxSetSubprocClosure(sp_vh, data) handle sp_vh; char *data; { SubprocInfo_t *sp; if(UxCheckIndex(sp_vh) == ERROR) return(ERROR); sp = UxSpArray[sp_vh]; sp->user_data = data; return(NO_ERROR); } /*---------------------------------------------------------------------- * NAME: * DESCRIPTION: * PARAMETERS: handle sp_vh - handle to subproc void (*fnt)() - output function * RETURN: ERROR/NO_ERROR * EXT REFS: UxSpArray * EXT EFFECTS: UxSpArray * ASSUMPTIONS: * REVISIONS: 05/01/93 fix3810 clean-up dd/mm/yy fix# fix_description *--------------------------------------------------------------------*/ int UxSetSubprocFunction(sp_vh, fnt) handle sp_vh; void (*fnt)(); { SubprocInfo_t *sp; if (UxCheckIndex(sp_vh) == ERROR) return(ERROR); sp = UxSpArray[sp_vh]; sp->output_fnt = fnt; return(NO_ERROR); }