2010-05-25 15:14:06 +04:00
/*
* commandhelper . c : Auxiliary program for commandtest
*
2014-03-18 12:13:43 +04:00
* Copyright ( C ) 2010 - 2014 Red Hat , Inc .
2010-05-25 15:14:06 +04:00
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library 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
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
2012-09-21 02:30:55 +04:00
* License along with this library . If not , see
2012-07-21 14:06:23 +04:00
* < http : //www.gnu.org/licenses/>.
2010-05-25 15:14:06 +04:00
*/
# include <config.h>
# include <unistd.h>
# include <fcntl.h>
2014-09-03 19:13:21 +04:00
# include <sys/stat.h>
2010-05-25 15:14:06 +04:00
2020-01-27 15:52:23 +03:00
# define VIR_NO_GLIB_STDIO /* This file intentionally does not link to libvirt/glib */
2017-09-21 10:55:07 +03:00
# include "testutils.h"
2012-03-29 13:50:00 +04:00
# ifndef WIN32
2020-01-17 14:19:13 +03:00
# include <poll.h>
2010-05-25 15:14:06 +04:00
2020-01-07 19:16:19 +03:00
/* Some UNIX lack it in headers & it doesn't hurt to redeclare */
extern char * * environ ;
2013-06-07 12:37:25 +04:00
# define VIR_FROM_THIS VIR_FROM_NONE
2010-05-25 15:14:06 +04:00
2021-02-01 14:27:51 +03:00
struct Arguments {
int readfds [ 3 ] ;
int numreadfds ;
bool daemonize_check ;
bool close_stdin ;
} ;
static struct Arguments * parseArguments ( int argc , char * * argv )
{
struct Arguments * args = NULL ;
int ret = - 1 ;
size_t i ;
if ( ! ( args = calloc ( 1 , sizeof ( * args ) ) ) )
goto cleanup ;
args - > numreadfds = 1 ;
args - > readfds [ 0 ] = STDIN_FILENO ;
for ( i = 1 ; i < argc ; i + + ) {
if ( STREQ ( argv [ i - 1 ] , " --readfd " ) ) {
char c ;
if ( 1 ! = sscanf ( argv [ i ] , " %u%c " ,
& args - > readfds [ args - > numreadfds + + ] , & c ) ) {
printf ( " Could not parse fd %s \n " , argv [ i ] ) ;
goto cleanup ;
}
} else if ( STREQ ( argv [ i ] , " --check-daemonize " ) ) {
args - > daemonize_check = true ;
} else if ( STREQ ( argv [ i ] , " --close-stdin " ) ) {
args - > close_stdin = true ;
}
}
ret = 0 ;
cleanup :
if ( ret = = 0 )
return args ;
free ( args ) ;
return NULL ;
}
2021-02-01 14:27:52 +03:00
static void printArguments ( FILE * log , int argc , char * * argv )
{
size_t i ;
for ( i = 1 ; i < argc ; i + + ) {
fprintf ( log , " ARG:%s \n " , argv [ i ] ) ;
}
}
2014-03-18 12:13:43 +04:00
static int envsort ( const void * a , const void * b )
{
2021-02-01 14:27:47 +03:00
const char * astr = * ( const char * * ) a ;
const char * bstr = * ( const char * * ) b ;
2013-05-03 16:52:21 +04:00
2021-02-01 14:27:47 +03:00
while ( true ) {
char achar = ( * astr = = ' = ' ) ? ' \0 ' : * astr ;
char bchar = ( * bstr = = ' = ' ) ? ' \0 ' : * bstr ;
if ( ( achar = = ' \0 ' ) | | ( achar ! = bchar ) )
return achar - bchar ;
astr + + ;
bstr + + ;
}
2010-05-25 15:14:06 +04:00
}
2021-02-01 14:27:53 +03:00
static int printEnvironment ( FILE * log )
{
char * * newenv ;
size_t length ;
size_t i ;
int ret = - 1 ;
for ( length = 0 ; environ [ length ] ; length + + ) {
}
if ( ! ( newenv = malloc ( sizeof ( * newenv ) * length ) ) )
goto cleanup ;
for ( i = 0 ; i < length ; i + + ) {
newenv [ i ] = environ [ i ] ;
}
qsort ( newenv , length , sizeof ( newenv [ 0 ] ) , envsort ) ;
for ( i = 0 ; i < length ; i + + ) {
/* Ignore the variables used to instruct the loader into
* behaving differently , as they could throw the tests off . */
if ( ! STRPREFIX ( newenv [ i ] , " LD_ " ) )
fprintf ( log , " ENV:%s \n " , newenv [ i ] ) ;
}
ret = 0 ;
cleanup :
if ( newenv )
free ( newenv ) ;
return ret ;
}
2021-02-01 14:27:54 +03:00
static int printFds ( FILE * log )
{
long int open_max = sysconf ( _SC_OPEN_MAX ) ;
size_t i ;
if ( open_max < 0 )
return - 1 ;
for ( i = 0 ; i < open_max ; i + + ) {
int ignore ;
if ( i = = fileno ( log ) )
continue ;
if ( fcntl ( i , F_GETFD , & ignore ) = = - 1 & & errno = = EBADF )
continue ;
fprintf ( log , " FD:%zu \n " , i ) ;
}
return 0 ;
}
2021-02-01 14:27:55 +03:00
static void printDaemonization ( FILE * log , struct Arguments * args )
{
int retries = 3 ;
if ( args - > daemonize_check ) {
while ( ( getpgrp ( ) = = getppid ( ) ) & & ( retries - - > 0 ) ) {
usleep ( 100 * 1000 ) ;
}
}
fprintf ( log , " DAEMON:%s \n " , getpgrp ( ) ! = getppid ( ) ? " yes " : " no " ) ;
}
2010-05-25 15:14:06 +04:00
int main ( int argc , char * * argv ) {
2021-02-01 14:27:51 +03:00
struct Arguments * args = parseArguments ( argc , argv ) ;
2021-02-01 14:27:53 +03:00
size_t i ;
2011-04-29 21:14:23 +04:00
char * cwd ;
2010-05-25 15:14:06 +04:00
FILE * log = fopen ( abs_builddir " /commandhelper.log " , " w " ) ;
2014-09-03 22:59:31 +04:00
int ret = EXIT_FAILURE ;
2019-07-25 21:22:10 +03:00
struct pollfd fds [ 3 ] ;
char * buffers [ 3 ] = { NULL , NULL , NULL } ;
size_t buflen [ 3 ] = { 0 , 0 , 0 } ;
2020-08-03 18:27:58 +03:00
char buf [ 1024 ] ;
ssize_t got ;
2010-05-25 15:14:06 +04:00
2021-02-01 14:27:51 +03:00
if ( ! log | | ! args )
2021-02-01 14:27:48 +03:00
goto cleanup ;
2010-05-25 15:14:06 +04:00
2021-02-01 14:27:52 +03:00
printArguments ( log , argc , argv ) ;
2021-02-01 14:27:50 +03:00
2021-02-01 14:27:53 +03:00
if ( printEnvironment ( log ) ! = 0 )
2021-02-01 14:27:48 +03:00
goto cleanup ;
2010-05-25 15:14:06 +04:00
2021-02-01 14:27:54 +03:00
if ( printFds ( log ) ! = 0 )
2014-09-03 22:59:31 +04:00
goto cleanup ;
2010-05-25 15:14:06 +04:00
2021-02-01 14:27:55 +03:00
printDaemonization ( log , args ) ;
2020-07-21 13:32:10 +03:00
2011-04-29 21:14:23 +04:00
if ( ! ( cwd = getcwd ( NULL , 0 ) ) )
2014-09-03 22:59:31 +04:00
goto cleanup ;
2011-04-29 21:14:23 +04:00
if ( strlen ( cwd ) > strlen ( " .../commanddata " ) & &
2010-05-25 15:14:06 +04:00
STREQ ( cwd + strlen ( cwd ) - strlen ( " /commanddata " ) , " /commanddata " ) )
strcpy ( cwd , " .../commanddata " ) ;
2019-08-21 19:13:18 +03:00
# ifdef __APPLE__
char * noprivateprefix = NULL ;
if ( strstr ( cwd , " /private " ) )
noprivateprefix = cwd + strlen ( " /private " ) ;
else
noprivateprefix = cwd ;
fprintf ( log , " CWD:%s \n " , noprivateprefix ) ;
# else
2010-05-25 15:14:06 +04:00
fprintf ( log , " CWD:%s \n " , cwd ) ;
2019-08-21 19:13:18 +03:00
# endif
2017-09-20 14:03:47 +03:00
free ( cwd ) ;
2010-05-25 15:14:06 +04:00
2014-09-03 19:13:21 +04:00
fprintf ( log , " UMASK:%04o \n " , umask ( 0 ) ) ;
2021-02-01 14:27:51 +03:00
if ( args - > close_stdin ) {
2012-06-01 01:50:07 +04:00
if ( freopen ( " /dev/null " , " r " , stdin ) ! = stdin )
2014-09-03 22:59:31 +04:00
goto cleanup ;
2012-06-01 01:50:07 +04:00
usleep ( 100 * 1000 ) ;
}
2010-05-25 15:14:06 +04:00
fprintf ( stdout , " BEGIN STDOUT \n " ) ;
fflush ( stdout ) ;
fprintf ( stderr , " BEGIN STDERR \n " ) ;
fflush ( stderr ) ;
2021-02-01 14:27:51 +03:00
for ( i = 0 ; i < args - > numreadfds ; i + + ) {
fds [ i ] . fd = args - > readfds [ i ] ;
2021-02-01 14:27:46 +03:00
fds [ i ] . events = POLLIN ;
fds [ i ] . revents = 0 ;
2019-07-25 21:22:10 +03:00
}
2010-05-25 15:14:06 +04:00
for ( ; ; ) {
2019-07-25 21:22:10 +03:00
unsigned ctr = 0 ;
2021-02-01 14:27:51 +03:00
if ( poll ( fds , args - > numreadfds , - 1 ) < 0 ) {
2019-07-25 21:22:10 +03:00
printf ( " poll failed: %s \n " , strerror ( errno ) ) ;
2014-09-03 22:59:31 +04:00
goto cleanup ;
2019-07-25 21:22:10 +03:00
}
2021-02-01 14:27:51 +03:00
for ( i = 0 ; i < args - > numreadfds ; i + + ) {
2020-10-08 17:02:08 +03:00
short revents = POLLIN | POLLHUP | POLLERR ;
# ifdef __APPLE__
/*
* poll ( ) on / dev / null will return POLLNVAL
* Apple - Feedback : FB8785208
*/
revents | = POLLNVAL ;
# endif
if ( fds [ i ] . revents & revents ) {
2019-07-25 21:22:10 +03:00
fds [ i ] . revents = 0 ;
got = read ( fds [ i ] . fd , buf , sizeof ( buf ) ) ;
if ( got < 0 )
goto cleanup ;
if ( got = = 0 ) {
/* do not want to hear from this fd anymore */
fds [ i ] . events = 0 ;
} else {
buffers [ i ] = realloc ( buffers [ i ] , buflen [ i ] + got ) ;
if ( ! buf [ i ] ) {
fprintf ( stdout , " Out of memory! \n " ) ;
goto cleanup ;
}
memcpy ( buffers [ i ] + buflen [ i ] , buf , got ) ;
buflen [ i ] + = got ;
}
}
}
2021-02-01 14:27:51 +03:00
for ( i = 0 ; i < args - > numreadfds ; i + + ) {
2019-07-25 21:22:10 +03:00
if ( fds [ i ] . events ) {
ctr + + ;
break ;
}
}
if ( ctr = = 0 )
2010-05-25 15:14:06 +04:00
break ;
2019-07-25 21:22:10 +03:00
}
2021-02-01 14:27:51 +03:00
for ( i = 0 ; i < args - > numreadfds ; i + + ) {
2020-09-21 20:32:29 +03:00
if ( fwrite ( buffers [ i ] , 1 , buflen [ i ] , stdout ) ! = buflen [ i ] )
2014-09-03 22:59:31 +04:00
goto cleanup ;
2020-09-21 20:32:29 +03:00
if ( fwrite ( buffers [ i ] , 1 , buflen [ i ] , stderr ) ! = buflen [ i ] )
2014-09-03 22:59:31 +04:00
goto cleanup ;
2010-05-25 15:14:06 +04:00
}
fprintf ( stdout , " END STDOUT \n " ) ;
fflush ( stdout ) ;
fprintf ( stderr , " END STDERR \n " ) ;
fflush ( stderr ) ;
2014-09-03 22:59:31 +04:00
ret = EXIT_SUCCESS ;
2010-05-25 15:14:06 +04:00
2014-09-03 22:59:31 +04:00
cleanup :
2019-10-15 14:55:26 +03:00
for ( i = 0 ; i < G_N_ELEMENTS ( buffers ) ; i + + )
2019-07-25 21:22:10 +03:00
free ( buffers [ i ] ) ;
2021-02-01 14:27:51 +03:00
if ( args )
free ( args ) ;
2021-02-01 14:27:48 +03:00
if ( log )
fclose ( log ) ;
2014-09-03 22:59:31 +04:00
return ret ;
2010-05-25 15:14:06 +04:00
}
2012-03-29 13:50:00 +04:00
# else
int
main ( void )
{
return EXIT_AM_SKIP ;
}
# endif