Changeset 5c2c0b8b36f6c5c53b7e922f115248b884648f30
- 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
| r3ac440c |
r5c2c0b8 |
|
| 26 | 26 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
|---|
| 27 | 27 | *****************************************************************************/ |
|---|
| | 28 | #include <vlc/vlc.h> |
|---|
| | 29 | |
|---|
| 28 | 30 | #include <string.h> /* strdup() */ |
|---|
| 29 | 31 | #include <stdlib.h> |
|---|
| 30 | 32 | #include <ctype.h> |
|---|
| 31 | 33 | |
|---|
| 32 | | #include <vlc/vlc.h> |
|---|
| 33 | 34 | |
|---|
| 34 | 35 | #undef iconv_t |
|---|
| … | … | |
| 50 | 51 | # include <errno.h> |
|---|
| 51 | 52 | # include <sys/wait.h> |
|---|
| | 53 | # include <fcntl.h> |
|---|
| | 54 | # include <sys/socket.h> |
|---|
| | 55 | # include <sys/poll.h> |
|---|
| 52 | 56 | #endif |
|---|
| 53 | 57 | |
|---|
| … | … | |
| 915 | 919 | * wait until it finishes and return its standard output |
|---|
| 916 | 920 | *************************************************************************/ |
|---|
| 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 ) |
|---|
| | 921 | int __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 ) |
|---|
| 920 | 925 | { |
|---|
| 921 | 926 | #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)) |
|---|
| 932 | 931 | 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]); |
|---|
| 957 | 959 | |
|---|
| 958 | 960 | *pi_data = 0; |
|---|
| 959 | | if( *pp_data ) |
|---|
| 960 | | free( *pp_data ); |
|---|
| | 961 | if (*pp_data) |
|---|
| | 962 | free (*pp_data); |
|---|
| 961 | 963 | *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) |
|---|
| 986 | 991 | { |
|---|
| 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; |
|---|
| 994 | 999 | } |
|---|
| 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) |
|---|
| 996 | 1006 | { |
|---|
| 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; |
|---|
| 1006 | 1016 | } |
|---|
| 1007 | 1017 | } |
|---|
| 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)); |
|---|
| 1039 | 1037 | } |
|---|
| 1040 | 1038 | |
|---|
| … | … | |
| 1211 | 1209 | #endif |
|---|
| 1212 | 1210 | |
|---|
| | 1211 | if (*pp_data == NULL) |
|---|
| | 1212 | return -1; |
|---|
| | 1213 | |
|---|
| 1213 | 1214 | (*pp_data)[*pi_data] = '\0'; |
|---|
| 1214 | 1215 | return 0; |
|---|