Beispiel #1
0
/**
   Set up a childs io redirections. Should only be called by
   setup_child_process(). Does the following: First it closes any open
   file descriptors not related to the child by calling
   close_unused_internal_pipes() and closing the universal variable
   server file descriptor. It then goes on to perform all the
   redirections described by \c io.

   \param io the list of IO redirections for the child

   \return 0 on sucess, -1 on failiure
*/
static int handle_child_io( io_data_t *io )
{

	close_unused_internal_pipes( io );

	for( ; io; io=io->next )
	{
		int tmp;

		if( io->io_mode == IO_FD && io->fd == io->param1.old_fd )
		{
			continue;
		}

		if( io->fd > 2 )
		{
			/*
			  Make sure the fd used by this redirection is not used by e.g. a pipe. 
			*/
			free_fd( io, io->fd );
		}
				
		switch( io->io_mode )
		{
			case IO_CLOSE:
			{
				if( close(io->fd) )
				{
					debug( 0, _(L"Failed to close file descriptor %d"), io->fd );
					wperror( L"close" );
				}
				break;
			}

			case IO_FILE:
			{
				if( (tmp=wopen( io->param1.filename,
						io->param2.flags, OPEN_MASK ) )==-1 )
				{
					if( ( io->param2.flags & O_EXCL ) &&
					    ( errno ==EEXIST ) )
					{
						debug( 1, 
						       NOCLOB_ERROR,
						       io->param1.filename );
					}
					else
					{
						debug( 1, 
						       FILE_ERROR,
						       io->param1.filename );
										
						wperror( L"open" );
					}
					
					return -1;
				}
				else if( tmp != io->fd)
				{
					/*
					  This call will sometimes fail, but that is ok,
					  this is just a precausion.
					*/
					close(io->fd);
							
					if(dup2( tmp, io->fd ) == -1 )
					{
						debug( 1, 
							   FD_ERROR,
							   io->fd );
						wperror( L"dup2" );
						return -1;
					}
					exec_close( tmp );
				}				
				break;
			}
			
			case IO_FD:
			{
				/*
				  This call will sometimes fail, but that is ok,
				  this is just a precausion.
				*/
				close(io->fd);

				if( dup2( io->param1.old_fd, io->fd ) == -1 )
				{
					debug( 1, 
						   FD_ERROR,
						   io->fd );
					wperror( L"dup2" );
					return -1;
				}
				break;
			}
			
			case IO_BUFFER:
			case IO_PIPE:
			{
				int write_pipe;
				
				write_pipe = !io->is_input;
/*
				debug( 0,
					   L"%ls %ls on fd %d (%d %d)", 
					   write_pipe?L"write":L"read", 
					   (io->io_mode == IO_BUFFER)?L"buffer":L"pipe",
					   io->fd,
					   io->param1.pipe_fd[0],
					   io->param1.pipe_fd[1]);
*/
				if( dup2( io->param1.pipe_fd[write_pipe], io->fd ) != io->fd )
				{
					debug( 1, PIPE_ERROR );
					wperror( L"dup2" );
					return -1;
				}

				if( write_pipe ) 
				{
					exec_close( io->param1.pipe_fd[0]);
					exec_close( io->param1.pipe_fd[1]);
				}
				else
				{
					exec_close( io->param1.pipe_fd[0] );
				}
				break;
			}
			
		}
	}

	return 0;
	
}
Beispiel #2
0
/**
   Set up a childs io redirections. Should only be called by
   setup_child_process(). Does the following: First it closes any open
   file descriptors not related to the child by calling
   close_unused_internal_pipes() and closing the universal variable
   server file descriptor. It then goes on to perform all the
   redirections described by \c io.

   \param io the list of IO redirections for the child

   \return 0 on sucess, -1 on failiure
*/
static int handle_child_io(const io_chain_t &io_chain)
{
    //fprintf(stderr, "child IO for %d\n", getpid());
    close_unused_internal_pipes(io_chain);
    free_redirected_fds_from_pipes(io_chain);
    for (size_t idx = 0; idx < io_chain.size(); idx++)
    {
        io_data_t *io = io_chain.at(idx).get();
        int tmp;

        if (io->io_mode == IO_FD && io->fd == static_cast<io_fd_t*>(io)->old_fd)
        {
            continue;
        }

        switch (io->io_mode)
        {
            case IO_CLOSE:
            {
                if (log_redirections) fprintf(stderr, "%d: close %d\n", getpid(), io->fd);
                if (close(io->fd))
                {
                    debug_safe_int(0, "Failed to close file descriptor %s", io->fd);
                    safe_perror("close");
                }
                break;
            }

            case IO_FILE:
            {
                // Here we definitely do not want to set CLO_EXEC because our child needs access
                CAST_INIT(io_file_t *, io_file, io);
                if ((tmp=open(io_file->filename_cstr,
                              io_file->flags, OPEN_MASK))==-1)
                {
                    if ((io_file->flags & O_EXCL) &&
                            (errno ==EEXIST))
                    {
                        debug_safe(1, NOCLOB_ERROR, io_file->filename_cstr);
                    }
                    else
                    {
                        debug_safe(1, FILE_ERROR, io_file->filename_cstr);
                        safe_perror("open");
                    }

                    return -1;
                }
                else if (tmp != io->fd)
                {
                    /*
                      This call will sometimes fail, but that is ok,
                      this is just a precausion.
                    */
                    close(io->fd);

                    if (dup2(tmp, io->fd) == -1)
                    {
                        debug_safe_int(1,  FD_ERROR, io->fd);
                        safe_perror("dup2");
                        return -1;
                    }
                    exec_close(tmp);
                }
                break;
            }

            case IO_FD:
            {
                int old_fd = static_cast<const io_fd_t *>(io)->old_fd;
                if (log_redirections) fprintf(stderr, "%d: fd dup %d to %d\n", getpid(), old_fd, io->fd);

                /*
                  This call will sometimes fail, but that is ok,
                  this is just a precausion.
                */
                close(io->fd);


                if (dup2(old_fd, io->fd) == -1)
                {
                    debug_safe_int(1, FD_ERROR, io->fd);
                    safe_perror("dup2");
                    return -1;
                }
                break;
            }

            case IO_BUFFER:
            case IO_PIPE:
            {
                CAST_INIT(io_pipe_t *, io_pipe, io);
                /* If write_pipe_idx is 0, it means we're connecting to the read end (first pipe fd). If it's 1, we're connecting to the write end (second pipe fd). */
                unsigned int write_pipe_idx = (io_pipe->is_input ? 0 : 1);
                /*
                        debug( 0,
                             L"%ls %ls on fd %d (%d %d)",
                             write_pipe?L"write":L"read",
                             (io->io_mode == IO_BUFFER)?L"buffer":L"pipe",
                             io->fd,
                             io->pipe_fd[0],
                             io->pipe_fd[1]);
                */
                if (log_redirections) fprintf(stderr, "%d: %s dup %d to %d\n", getpid(), io->io_mode == IO_BUFFER ? "buffer" : "pipe", io_pipe->pipe_fd[write_pipe_idx], io->fd);
                if (dup2(io_pipe->pipe_fd[write_pipe_idx], io->fd) != io->fd)
                {
                    debug_safe(1, LOCAL_PIPE_ERROR);
                    safe_perror("dup2");
                    return -1;
                }

                if (io_pipe->pipe_fd[0] >= 0)
                    exec_close(io_pipe->pipe_fd[0]);
                if (io_pipe->pipe_fd[1] >= 0)
                    exec_close(io_pipe->pipe_fd[1]);
                break;
            }

        }
    }

    return 0;

}