コード例 #1
0
ファイル: pty.c プロジェクト: slapin/cdesktopenv
/*----------------------------------------------------------------------+*/
SPC_Channel_Ptr open_pty_channel_object(SPC_Channel_Ptr channel,
					int iomode,
					XeString hostname)
/*----------------------------------------------------------------------+*/
{

  Wire *tmpwire, *newwire;
  SPC_Channel_Ptr result;
  
  call_parent_method(channel, open, (channel, iomode, hostname), result);

  if(result==SPC_ERROR)
    return(SPC_ERROR);

  /* We know that we are going to use one of STDIN, STDOUT, or STDERR
     (or else we would be a NOIO channel), so allocate at least one
     pty pair */

  if(!(tmpwire=getpty(NULL)))
    return(SPC_ERROR);

  if (IS_SPCIO_STDIN(iomode)) {
    channel->wires[STDIN]=tmpwire;
  }
  
  if (IS_SPCIO_STDOUT(iomode)) {
    channel->wires[STDOUT]=tmpwire;
  }
  
  if (IS_SPCIO_SEPARATE(iomode)) {
    if(!(newwire=getpty(tmpwire))) {
      spc_close(tmpwire->fd[MASTER_SIDE]);
      free_wire(tmpwire);
      return(SPC_ERROR);
    } else
      tmpwire=newwire;
  }
  
  if (IS_SPCIO_STDERR(iomode)) {
    channel->wires[STDERR]=tmpwire;
  }
  
  channel->wire_list=tmpwire;
  
  /* set up the channel file descriptors */

  channel->file_descs[STDIN]  = (channel->wires[STDIN]) ->fd[MASTER_SIDE];
  channel->file_descs[STDOUT] = (channel->wires[STDOUT])->fd[MASTER_SIDE];
  channel->file_descs[STDERR] = (channel->wires[STDERR])->fd[MASTER_SIDE];

  for(tmpwire=channel->wire_list; tmpwire; tmpwire=tmpwire->next) {
    init_termio(&tmpwire->master_termio);
    init_termio(&tmpwire->slave_termio);
  }
  
  return(channel);

}
コード例 #2
0
ファイル: spc-xt.c プロジェクト: idunham/cdesktop
/*-----------------------------------------------------------------------+*/
int SPC_Wait_For_Termination(SPC_Channel_Ptr channel)
/*-----------------------------------------------------------------------+*/
{
  int result;
  
  call_parent_method(channel, wait_for_termination, (channel), result);
  
  if(result==SPC_ERROR) return(SPC_ERROR);

  do {

    if(SPC_Select() == SPC_ERROR)
      return(SPC_ERROR);
    
  } while(IS_ACTIVE(channel));
  
  return(TRUE);
  
}
コード例 #3
0
/*----------------------------------------------------------------------+*/
int exec_proc_local_channel_object(SPC_Channel_Ptr channel)
/*----------------------------------------------------------------------+*/
{
    sigset_t newsigmask, oldsigmask;
    pid_t pid;
    int result;
    XeString *envp;
    XeString dir = XeString_NULL;
    int retval;
    int i, reuse_pid = 0;
    
    call_parent_method(channel, exec_proc, (channel), result);
    
    if(result==SPC_ERROR)
	return(SPC_ERROR);

    /* Check to see if the channel pathname points to a valid executable.
       We do this by using the _path_search function.  If the channel
       has a PATH variable set in its local environment, use it,
       otherwise use the "global" environment.  We can accomplish this
       by using the spc_getenv call in the _path_search call.  If the
       channel doesn't have a PATH variable, then spc_getenv will
       return NULL, which indicates use of the global environment.
   */

    if(!_path_search(SPC_Getenv("PATH", channel->envp),
		    channel->path,
		    executable_predicate)) {
      SPC_Error(SPC_Cannot_Exec, channel->path);
      return(SPC_ERROR);
    }
       
    /* If we were passed a host:dir to cd to, make sure it exists. */
    /* We want to do this before we fork the child.                */

    if((channel->context_dir) && (channel->context_dir[0])) {
	struct stat	stat_info;
	Boolean ok = FALSE;
	
	_DtSvcProcessLock();
	if (SPC_client_version_number < SPC_PROTOCOL_VERSION_CDE_BASE)
	   dir = get_path_from_context(channel->context_dir);
	else {
	   /*
	    * context_dir is actually a "netfile" so it needs to
	    * be converted to a "real" path.
	    */
	   dir = (char *) tt_netfile_file (channel->context_dir);
	   if (tt_ptr_error (dir) != TT_OK) 
	      dir = NULL;
	}
	_DtSvcProcessUnlock();

	if (dir == NULL)
	    /* can't make connection ... */;
	else if (stat(dir,&stat_info) != 0)	
	    /* directory not there */;

	else if ((stat_info.st_mode & S_IFDIR) == 0)
	    /* path is not a directory ... */;
	else
	    ok = TRUE;
	
	if (!ok && IS_SPCIO_FORCE_CONTEXT(channel->IOMode)) {
	    if (dir != NULL && (strcmp (dir, channel->context_dir) != 0))
	       SPC_Error(SPC_cannot_Chdir, dir);
	    SPC_Error(SPC_cannot_Chdir, channel->context_dir);
	    XeFree(dir);
	    dir = XeString_NULL;
	    return(SPC_ERROR);
	}
    }

    if(mempf0(channel, pre_fork)==SPC_ERROR)
	return(SPC_ERROR);
    
    /* When using HP NLIO (xj0input) we have a problem.  Namely,  */
    /* the xj0 processs uses signal() to deal with SIGCLD which   */	
    /* is incompatible with sigaction/sigprogmask/etc.  Even      */
    /* though xj0 resets the signal handler, since the signal     */
    /* routines are incompatible, our original handler gets lost. */
    /* Hence, we need to reset it.  We do it here everytime we    */
    /* fork a child just to be on the safe side.                  */

    SPC_ResetTerminator();
    
    sigemptyset(&newsigmask);
    sigemptyset(&oldsigmask);
    sigaddset(&newsigmask, SIGCHLD);
    
    if (sigprocmask(SIG_BLOCK, &newsigmask, &oldsigmask) == ERROR)
	return(SPC_ERROR);
    
    pid = channel->pid = fork();
    
    /*
     * Must save this pid so that when the daemon's timer goes off,
     * if there has been no activity and there are no sub-processes
     * running, the daemon can exit.
     */
    i = 0;
    _DtSvcProcessLock();
    if (SPC_pid_list == NULL)
      /*
       * Create the first block plus the NULL terminator.
       */
      SPC_pid_list = (pid_t *) malloc (2 * sizeof (pid_t));
    else {
      /*
       * If a dead pid entry exists, reuse it; otherwise, must create 
       * room for the new pid.
       */
      for (i = 0; SPC_pid_list[i] != NULL; i++)
        if (SPC_pid_list[i] == SPCD_DEAD_PROCESS) {
	  SPC_pid_list[i] = pid;
	  reuse_pid = 1;
	  break;
	}
      if (!reuse_pid)
	SPC_pid_list = (pid_t *) realloc (SPC_pid_list, 
					   (i+2) * sizeof (pid_t));
    }
    if (!reuse_pid) {
      SPC_pid_list[i] = pid;
      SPC_pid_list[i+1] = NULL;
    }
    _DtSvcProcessUnlock();

    if (pid) {
	XeFree(dir);
	
	/* Did we really fork? */
	if (pid == ERROR) {
	  SPC_Error(SPC_Cannot_Fork);
	  retval = SPC_ERROR;
	} else {
	  /* Do any set up for the parent process here */
	  mempf1(channel, post_fork, pid);
	  retval = TRUE;
	}
	
	/* Reinstate the old signal mask (unblock SIGCLD). */
	
	sigprocmask(SIG_SETMASK, &oldsigmask, (sigset_t *)NULL);
	return(retval);
    }
    else {
	/* Child process: connect wires, make environment and exec sub-process */
	
	sigprocmask(SIG_SETMASK, &oldsigmask, (sigset_t *)NULL);
	
	/* Make sure the child is the process group leader.  In the case of
	   ptys, we also want to break the current terminal affiliation.
	   We want to be the process group leader so XeSPCKillProcess (which
	   does a kill(-pid, 9)) will kill all processes associated with us.
	   
	   For PTY's, we need to break the terminal affiliation so the next
	   open (which will be a pty) will cause us to become affiliated with
	   the pty.  We do this so when the parent process closes the master
	   side of the pty, the slave side processes get SIGHUP.  If they
	   ignore SIGHUP, they will never die.  So it goes...
	   */

	if(IS_SPCIO_PTY(channel->IOMode))
	    setsid();
	else {
	    pid_t tmppid = getpid();
	    if(setpgid(tmppid, tmppid) == -1) 
		fprintf(stderr, (XeString)"setpgid failed, errno: %d\n", errno);
	}
	
	/* Connect wires to sub-process standard files */
	result=mempf1(channel, post_fork, pid);
	
	if(result!=SPC_ERROR) {
	    int		indx = -1;
	    int		i;
	    char	**ppch;

	    /*
	     * Before adding in the list of environment variables 
	     * from the environment variable files, must search 
	     * the list for LANG definitions.  If found, the
	     * last definition must be putenv'ed to assure the 
	     * multi-byte parsing code is using the correct locale.
	     */
	    for (i = 0, ppch = channel->envp; *ppch; *ppch++, i++)
	       if (!strncmp (*ppch, "LANG=", 5))
		  indx = i;

	    if (indx != -1)
	       resolve_variable_reference (&channel->envp[indx]);

	    _DtSvcProcessLock();
	    if (!setlocale (LC_CTYPE, ""))
	       /*
		* setlocale failed - log a message but execute 
		* the command anyway.
		*/ 
	       if (SPC_Print_Protocol != NULL)
		  (void) fprintf(SPC_Print_Protocol,
		      "+++> Failed to 'setlocale'; LANG = %s\n",
		      getenv("LANG"));
	    /* Mix in the stashed environment */
	    
	    for(envp=channel->envp; *envp; envp++)
		resolve_variable_reference(&*envp);

	    if (SPC_mount_point_env_var != NULL)
		/*
		 * The mount point environment variable was 
		 * inherited by the daemon or was given to the
		 * daemon via the command line.  In either case
		 * this subprocess must inherit the daemon's
		 * value.
		 */
		(void) putenv (SPC_mount_point_env_var);
	    _DtSvcProcessUnlock();

	    /* Connect to the context directory */
	    /* We have already validated this guy exists */

	    if(dir) 
		Xechdir(dir);
	}
	
	XeFree(dir);

	if(result!=SPC_ERROR) {
	    /* Execute */
	    /* Compiler barfs without cast ? */
#if defined(__hpux_8_0) || defined(__aix)
            result=execvp(channel->path, channel->argv);
#else
	    result=execvp(channel->path, channel->argv);
#endif
	    /* If we return from exec, it failed */
	    SPC_Error(SPC_Cannot_Exec, channel->path);
	}
	
	/* We want to get rid of this child image (carefully) */
	_exit(42);
	
    }
}
コード例 #4
0
ファイル: pty.c プロジェクト: slapin/cdesktopenv
/*----------------------------------------------------------------------+*/
int read_pty_channel_object(SPC_Channel_Ptr channel,
			    int connector,           /* STDOUT or STDERR */
			    XeString buffer,
			    int nbytes)
/*----------------------------------------------------------------------+*/
#ifdef __hpux_pty
{
  
  int result, select_value;
  struct fd_set read_mask, except_mask;
  int fd=channel->file_descs[connector];
  struct request_info req_info;
  struct timeval timeout, *timeptr;
  int i;
 
  call_parent_method(channel,
		     read,
		     (channel, connector, buffer, nbytes),
		     result);
  
  if(result==SPC_ERROR)
    return(SPC_ERROR);

  if(!IS_SPCIO_DATA(channel->wires[connector]->flags))
    return(0);

  FD_ZERO(&read_mask);
  FD_ZERO(&except_mask);

  FD_SET(fd, &read_mask);
  FD_SET(fd, &except_mask);
  
  if(channel->close_timeout) {
    timeout.tv_sec=channel->close_timeout;
    timeout.tv_usec=0;
    timeptr = (&timeout);
  } else
    timeptr=NULL;

  do
    select_value=select(fd+1, &read_mask, NULL, &except_mask, timeptr);
  while(select_value==ERROR && errno==EINTR);
  
  if(select_value==ERROR) {
    SPC_Error(SPC_Bad_Select);
    return(SPC_ERROR);
  }

  /* If there is anything to read, read it & return */
  IS_FD_SET(&read_mask, result);
  if(result) {
    do {
      result = read(fd, buffer, nbytes);
    } while (result<0 && errno == EINTR);
    if(result==ERROR) {
      SPC_Error(SPC_Reading);
      return(SPC_ERROR);
    }
    return(result);
  }
  
  /* Nothing to read.  We either timed out or got an exception. */
  
  if(select_value != 0) {

    /* We got an exception */
    ioctl(fd, TIOCREQGET, &req_info);
    
    /* Clear the request (Not really necessary in the case of a close,
       but do it anyway) */
    
    ioctl(fd, TIOCREQSET, &req_info);
  }

  if((select_value == 0) || (req_info.request == TIOCCLOSE)) {

    /* Close, disable trapping on this fd & return EOF.  We regard
       a timeout as being the same as a close. */

    SPC_Disable_Trapping(fd);
    SPC_Change_State(channel, connector, 0, -1);
    return(0);

  } else

    /* Otherwise (open or IOCTL), return -1 */

    return(EXCEPT_FLAG);
}