2016-02-16 17:58:52 +03:00
/*
* Unix SMB / CIFS implementation .
* Samba system utilities
* Copyright ( C ) Jeremy Allison 2000
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "replace.h"
# include "system/wait.h"
# include "system/filesys.h"
# include <talloc.h>
2018-12-27 12:18:28 +03:00
# include "lib/util/sys_popen.h"
2016-02-16 17:58:52 +03:00
# include "lib/util/debug.h"
/**************************************************************************
Wrapper for popen . Safer as it doesn ' t search a path .
Modified from the glibc sources .
modified by tridge to return a file descriptor . We must kick our FILE * habit
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
typedef struct _popen_list
{
int fd ;
pid_t child_pid ;
struct _popen_list * next ;
} popen_list ;
static popen_list * popen_chain ;
2019-05-17 07:45:21 +03:00
int sys_popenv ( char * const argl [ ] )
2016-02-16 17:58:52 +03:00
{
int parent_end , child_end ;
int pipe_fds [ 2 ] ;
popen_list * entry = NULL ;
2019-05-17 07:45:21 +03:00
const char * command = argl [ 0 ] ;
2016-02-16 17:58:52 +03:00
int ret ;
2019-05-17 07:45:21 +03:00
if ( argl = = NULL ) {
errno = EINVAL ;
return - 1 ;
}
2016-02-16 17:58:52 +03:00
if ( ! * command ) {
errno = EINVAL ;
return - 1 ;
}
ret = pipe ( pipe_fds ) ;
if ( ret < 0 ) {
2019-05-17 07:45:21 +03:00
DBG_ERR ( " error opening pipe: %s \n " ,
strerror ( errno ) ) ;
2016-02-16 17:58:52 +03:00
return - 1 ;
}
parent_end = pipe_fds [ 0 ] ;
child_end = pipe_fds [ 1 ] ;
entry = talloc_zero ( NULL , popen_list ) ;
if ( entry = = NULL ) {
2019-05-17 07:45:21 +03:00
DBG_ERR ( " talloc failed \n " ) ;
2016-02-16 17:58:52 +03:00
goto err_exit ;
}
entry - > child_pid = fork ( ) ;
if ( entry - > child_pid = = - 1 ) {
2019-05-17 07:45:21 +03:00
DBG_ERR ( " fork failed: %s \n " , strerror ( errno ) ) ;
2016-02-16 17:58:52 +03:00
goto err_exit ;
}
if ( entry - > child_pid = = 0 ) {
/*
* Child !
*/
int child_std_end = STDOUT_FILENO ;
popen_list * p ;
close ( parent_end ) ;
if ( child_end ! = child_std_end ) {
dup2 ( child_end , child_std_end ) ;
close ( child_end ) ;
}
/*
* POSIX .2 : " popen() shall ensure that any streams from previous
* popen ( ) calls that remain open in the parent process are closed
* in the new child process . "
*/
for ( p = popen_chain ; p ; p = p - > next )
close ( p - > fd ) ;
ret = execv ( argl [ 0 ] , argl ) ;
if ( ret = = - 1 ) {
2019-05-17 07:45:21 +03:00
DBG_ERR ( " ERROR executing command "
" '%s': %s \n " , command , strerror ( errno ) ) ;
2016-02-16 17:58:52 +03:00
}
_exit ( 127 ) ;
}
/*
* Parent .
*/
close ( child_end ) ;
/* Link into popen_chain. */
entry - > next = popen_chain ;
popen_chain = entry ;
entry - > fd = parent_end ;
return entry - > fd ;
err_exit :
TALLOC_FREE ( entry ) ;
close ( pipe_fds [ 0 ] ) ;
close ( pipe_fds [ 1 ] ) ;
return - 1 ;
}
/**************************************************************************
Wrapper for pclose . Modified from the glibc sources .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int sys_pclose ( int fd )
{
int wstatus ;
popen_list * * ptr = & popen_chain ;
popen_list * entry = NULL ;
pid_t wait_pid ;
int status = - 1 ;
/* Unlink from popen_chain. */
for ( ; * ptr ! = NULL ; ptr = & ( * ptr ) - > next ) {
if ( ( * ptr ) - > fd = = fd ) {
entry = * ptr ;
* ptr = ( * ptr ) - > next ;
status = 0 ;
break ;
}
}
if ( status < 0 | | close ( entry - > fd ) < 0 )
return - 1 ;
/*
* As Samba is catching and eating child process
* exits we don ' t really care about the child exit
* code , a - 1 with errno = ECHILD will do fine for us .
*/
do {
wait_pid = waitpid ( entry - > child_pid , & wstatus , 0 ) ;
} while ( wait_pid = = - 1 & & errno = = EINTR ) ;
TALLOC_FREE ( entry ) ;
if ( wait_pid = = - 1 )
return - 1 ;
return wstatus ;
}