Changeset 5c2c0b8b36f6c5c53b7e922f115248b884648f30

Show
Ignore:
Timestamp:
24/03/07 12:08:46 (2 years ago)
Author:
Rémi Denis-Courmont <rem@videolan.org>
git-committer:
Rémi Denis-Courmont <rem@videolan.org> 1174734526 +0000
git-parent:

[7e784b4dbac0381217f11a58519346a043a582d1]

git-author:
Rémi Denis-Courmont <rem@videolan.org> 1174734526 +0000
Message:

- Fix various error handling bugs in vlc_execve.
- Use a single pipe rather two pairs

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • src/extras/libc.c

    r3ac440c r5c2c0b8  
    2626 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. 
    2727 *****************************************************************************/ 
     28#include <vlc/vlc.h> 
     29 
    2830#include <string.h>                                              /* strdup() */ 
    2931#include <stdlib.h> 
    3032#include <ctype.h> 
    3133 
    32 #include <vlc/vlc.h> 
    3334 
    3435#undef iconv_t 
     
    5051#   include <errno.h> 
    5152#   include <sys/wait.h> 
     53#   include <fcntl.h> 
     54#   include <sys/socket.h> 
     55#   include <sys/poll.h> 
    5256#endif 
    5357 
     
    915919 * wait until it finishes and return its standard output 
    916920 *************************************************************************/ 
    917 int __vlc_execve( vlc_object_t *p_object, int i_argc, char **ppsz_argv, 
    918                   char **ppsz_env, char *psz_cwd, char *p_in, int i_in, 
    919                   char **pp_data, int *pi_data ) 
     921int __vlc_execve( vlc_object_t *p_object, int i_argc, char *const *ppsz_argv, 
     922                  char *const *ppsz_env, const char *psz_cwd, 
     923                  const char *p_in, size_t i_in, 
     924                  char **pp_data, size_t *pi_data ) 
    920925{ 
    921926#ifdef HAVE_FORK 
    922     int pi_stdin[2]; 
    923     int pi_stdout[2]; 
    924     pid_t i_child_pid; 
    925  
    926     pipe( pi_stdin ); 
    927     pipe( pi_stdout ); 
    928  
    929     if ( (i_child_pid = fork()) == -1 ) 
    930     { 
    931         msg_Err( p_object, "unable to fork (%s)", strerror(errno) ); 
     927# define BUFSIZE 1024 
     928    int fds[2], i_status; 
     929 
     930    if (socketpair (AF_LOCAL, SOCK_STREAM, 0, fds)) 
    932931        return -1; 
    933     } 
    934  
    935     if ( i_child_pid == 0 ) 
    936     { 
    937         close(0); 
    938         dup(pi_stdin[1]); 
    939         close(pi_stdin[0]); 
    940  
    941         close(1); 
    942         dup(pi_stdout[1]); 
    943         close(pi_stdout[0]); 
    944  
    945         close(2); 
    946  
    947         if ( psz_cwd != NULL ) 
    948             chdir( psz_cwd ); 
    949         execve( ppsz_argv[0], ppsz_argv, ppsz_env ); 
    950         exit(1); 
    951     } 
    952  
    953     close(pi_stdin[1]); 
    954     close(pi_stdout[1]); 
    955     if ( !i_in ) 
    956         close( pi_stdin[0] ); 
     932 
     933    pid_t pid = -1; 
     934    if ((fds[0] > 2) && (fds[1] > 2)) 
     935        pid = fork (); 
     936 
     937    switch (pid) 
     938    { 
     939        case -1: 
     940            msg_Err (p_object, "unable to fork (%s)", strerror (errno)); 
     941            close (fds[0]); 
     942            close (fds[1]); 
     943            return -1; 
     944 
     945        case 0: 
     946            /* NOTE: 
     947             * Like it or not, close can fail (and not only with EBADF) 
     948             */ 
     949            if ((close (0) == 0) && (close (1) == 0) && (close (2) == 0) 
     950             && (dup (fds[1]) == 0) && (dup (fds[1]) == 1) 
     951             && (open ("/dev/null", O_RDONLY) == 2) 
     952             && ((psz_cwd == NULL) || (chdir (psz_cwd) == 0))) 
     953                execve (ppsz_argv[0], ppsz_argv, ppsz_env); 
     954 
     955            exit (1); 
     956    } 
     957 
     958    close (fds[1]); 
    957959 
    958960    *pi_data = 0; 
    959     if( *pp_data
    960         free( *pp_data ); 
     961    if (*pp_data
     962        free (*pp_data); 
    961963    *pp_data = NULL; 
    962     *pp_data = malloc( 1025 );  /* +1 for \0 */ 
    963     if( !*pp_data ) 
    964         return -1; 
    965  
    966     while ( !p_object->b_die ) 
    967     { 
    968         int i_ret, i_status; 
    969         fd_set readfds, writefds; 
    970         struct timeval tv; 
    971  
    972         FD_ZERO( &readfds ); 
    973         FD_ZERO( &writefds ); 
    974         FD_SET( pi_stdout[0], &readfds ); 
    975         if ( i_in ) 
    976             FD_SET( pi_stdin[0], &writefds ); 
    977  
    978         tv.tv_sec = 0; 
    979         tv.tv_usec = 10000; 
    980  
    981         i_ret = select( pi_stdin[0] > pi_stdout[0] ? pi_stdin[0] + 1 : 
    982                         pi_stdout[0] + 1, &readfds, &writefds, NULL, &tv ); 
    983         if ( i_ret > 0 ) 
    984         { 
    985             if ( FD_ISSET( pi_stdout[0], &readfds ) ) 
     964 
     965    if (i_in == 0) 
     966        shutdown (fds[0], SHUT_WR); 
     967 
     968    while (!p_object->b_die) 
     969    { 
     970        struct pollfd ufd[1]; 
     971        memset (ufd, 0, sizeof (ufd)); 
     972        ufd[0].fd = fds[0]; 
     973        ufd[0].events = POLLIN; 
     974 
     975        if (i_in > 0) 
     976            ufd[0].events |= POLLOUT; 
     977 
     978        if (poll (ufd, 1, 10) <= 0) 
     979            continue; 
     980 
     981        if (ufd[0].revents & ~POLLOUT) 
     982        { 
     983            char *ptr = realloc (*pp_data, *pi_data + BUFSIZE + 1); 
     984            if (ptr == NULL) 
     985                break; /* safely abort */ 
     986 
     987            *pp_data = ptr; 
     988 
     989            ssize_t val = read (fds[0], ptr + *pi_data, BUFSIZE); 
     990            switch (val) 
    986991            { 
    987                 ssize_t i_read = read( pi_stdout[0], &(*pp_data)[*pi_data], 
    988                                        1024 ); 
    989                 if ( i_read > 0 ) 
    990                 { 
    991                     *pi_data += i_read; 
    992                     *pp_data = realloc( *pp_data, *pi_data + 1025 ); 
    993                 } 
     992                case -1: 
     993                case 0: 
     994                    shutdown (fds[0], SHUT_RD); 
     995                    break; 
     996 
     997                default: 
     998                    *pi_data += val; 
    994999            } 
    995             if ( FD_ISSET( pi_stdin[0], &writefds ) ) 
     1000        } 
     1001 
     1002        if (ufd[0].revents & POLLOUT) 
     1003        { 
     1004            ssize_t val = write (fds[0], p_in, i_in); 
     1005            switch (val) 
    9961006            { 
    997                 ssize_t i_write = write( pi_stdin[0], p_in, __MIN(i_in, 1024) ); 
    998  
    999                 if ( i_write > 0 ) 
    1000                 { 
    1001                     p_in += i_write
    1002                     i_in -= i_write; 
    1003                 } 
    1004                 if ( !i_in ) 
    1005                     close( pi_stdin[0] )
     1007                case -1: 
     1008                case 0: 
     1009                    i_in = 0; 
     1010                    shutdown (fds[0], SHUT_WR); 
     1011                    break
     1012 
     1013                default: 
     1014                    i_in -= val; 
     1015                    p_in += val
    10061016            } 
    10071017        } 
    1008  
    1009         if ( waitpid( i_child_pid, &i_status, WNOHANG ) == i_child_pid ) 
    1010         { 
    1011             if ( WIFEXITED( i_status ) ) 
    1012             { 
    1013                 if ( WEXITSTATUS( i_status ) ) 
    1014                 { 
    1015                     msg_Warn( p_object, 
    1016                               "child %s returned with error code %d", 
    1017                               ppsz_argv[0], WEXITSTATUS( i_status ) ); 
    1018                 } 
    1019             } 
    1020             else 
    1021             { 
    1022                 if ( WIFSIGNALED( i_status ) ) 
    1023                 { 
    1024                     msg_Warn( p_object, 
    1025                               "child %s quit on signal %d", ppsz_argv[0], 
    1026                               WTERMSIG( i_status ) ); 
    1027                 } 
    1028             } 
    1029             if ( i_in ) 
    1030                 close( pi_stdin[0] ); 
    1031             close( pi_stdout[0] ); 
    1032             break; 
    1033         } 
    1034  
    1035         if ( i_ret < 0 && errno != EINTR ) 
    1036         { 
    1037             msg_Warn( p_object, "select failed (%s)", strerror(errno) ); 
    1038         } 
     1018    } 
     1019 
     1020    close (fds[0]); 
     1021 
     1022    while (waitpid (pid, &i_status, 0) == -1); 
     1023 
     1024    if (WIFEXITED (i_status)) 
     1025    { 
     1026        i_status = WEXITSTATUS (i_status); 
     1027        if (i_status) 
     1028            msg_Warn (p_object,  "child %s (PID %d) exited with error code %d", 
     1029                      ppsz_argv[0], (int)pid, i_status); 
     1030    } 
     1031    else 
     1032    if (WIFSIGNALED (i_status)) // <-- this should be redumdant a check 
     1033    { 
     1034        i_status = WTERMSIG (i_status); 
     1035        msg_Warn (p_object, "child %s (PID %d) exited on signal %d (%s)", 
     1036                  ppsz_argv[0], (int)pid, i_status, strsignal (i_status)); 
    10391037    } 
    10401038 
     
    12111209#endif 
    12121210 
     1211    if (*pp_data == NULL) 
     1212        return -1; 
     1213 
    12131214    (*pp_data)[*pi_data] = '\0'; 
    12141215    return 0;