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
2021-02-01 14:28:00 +03:00
/* This file intentionally does not link to libvirt/glib */
# define VIR_NO_GLIB_STDIO
# define cleanup(T, F) __attribute__((cleanup(F))) T
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 {
2021-02-01 14:27:59 +03:00
int * readfds ;
2021-02-01 14:27:51 +03:00
int numreadfds ;
bool daemonize_check ;
bool close_stdin ;
} ;
2021-02-01 14:28:00 +03:00
static void cleanupArguments ( struct Arguments * * ptr )
{
struct Arguments * args = * ptr ;
if ( args )
free ( args - > readfds ) ;
free ( args ) ;
}
2021-02-01 14:28:03 +03:00
static void cleanupStringList ( char * * * ptr )
{
char * * strings = * ptr ;
if ( strings ) {
char * * str ;
for ( str = strings ; * str ; str + + )
free ( * str ) ;
}
free ( strings ) ;
}
2021-02-01 14:28:04 +03:00
static void cleanupFile ( FILE * * ptr )
{
FILE * file = * ptr ;
fclose ( file ) ;
}
2021-02-01 14:28:01 +03:00
static void cleanupGeneric ( void * ptr )
{
void * * ptrptr = ptr ;
free ( * ptrptr ) ;
}
2021-02-01 14:27:51 +03:00
static struct Arguments * parseArguments ( int argc , char * * argv )
{
2021-02-01 14:28:00 +03:00
cleanup ( struct Arguments * , cleanupArguments ) args = NULL ;
struct Arguments * ret ;
2021-02-01 14:27:51 +03:00
size_t i ;
if ( ! ( args = calloc ( 1 , sizeof ( * args ) ) ) )
2021-02-01 14:28:00 +03:00
return NULL ;
2021-02-01 14:27:51 +03:00
2021-02-01 14:27:59 +03:00
if ( ! ( args - > readfds = calloc ( 1 , sizeof ( * args - > readfds ) ) ) )
2021-02-01 14:28:00 +03:00
return NULL ;
2021-02-01 14:27:59 +03:00
2021-02-01 14:27:51 +03:00
args - > numreadfds = 1 ;
args - > readfds [ 0 ] = STDIN_FILENO ;
for ( i = 1 ; i < argc ; i + + ) {
if ( STREQ ( argv [ i - 1 ] , " --readfd " ) ) {
char c ;
2021-02-01 14:27:59 +03:00
args - > readfds = realloc ( args - > readfds ,
( args - > numreadfds + 1 ) *
sizeof ( * args - > readfds ) ) ;
if ( ! args - > readfds )
2021-02-01 14:28:00 +03:00
return NULL ;
2021-02-01 14:27:59 +03:00
2021-02-01 14:27:51 +03:00
if ( 1 ! = sscanf ( argv [ i ] , " %u%c " ,
& args - > readfds [ args - > numreadfds + + ] , & c ) ) {
printf ( " Could not parse fd %s \n " , argv [ i ] ) ;
2021-02-01 14:28:00 +03:00
return NULL ;
2021-02-01 14:27:51 +03:00
}
} else if ( STREQ ( argv [ i ] , " --check-daemonize " ) ) {
args - > daemonize_check = true ;
} else if ( STREQ ( argv [ i ] , " --close-stdin " ) ) {
args - > close_stdin = true ;
}
}
2021-02-01 14:28:00 +03:00
ret = args ;
args = NULL ;
return ret ;
2021-02-01 14:27:51 +03:00
}
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 )
{
2021-02-01 14:28:01 +03:00
cleanup ( char * * , cleanupGeneric ) newenv = NULL ;
2021-02-01 14:27:53 +03:00
size_t length ;
size_t i ;
for ( length = 0 ; environ [ length ] ; length + + ) {
}
2021-02-01 15:42:05 +03:00
if ( length = = 0 )
return 0 ;
2021-02-01 14:27:53 +03:00
if ( ! ( newenv = malloc ( sizeof ( * newenv ) * length ) ) )
2021-02-01 14:28:01 +03:00
return - 1 ;
2021-02-01 14:27:53 +03:00
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 ] ) ;
}
2021-02-01 14:28:01 +03:00
return 0 ;
2021-02-01 14:27:53 +03:00
}
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 " ) ;
}
2021-02-01 14:27:56 +03:00
static int printCwd ( FILE * log )
{
2021-02-01 14:28:02 +03:00
cleanup ( char * , cleanupGeneric ) cwd = NULL ;
2021-02-01 14:27:56 +03:00
char * display ;
if ( ! ( cwd = getcwd ( NULL , 0 ) ) )
return - 1 ;
if ( ( strlen ( cwd ) > strlen ( " .../commanddata " ) ) & &
( STREQ ( cwd + strlen ( cwd ) - strlen ( " /commanddata " ) , " /commanddata " ) ) ) {
strcpy ( cwd , " .../commanddata " ) ;
}
display = cwd ;
# ifdef __APPLE__
if ( strstr ( cwd , " /private " ) )
display = cwd + strlen ( " /private " ) ;
# endif
fprintf ( log , " CWD:%s \n " , display ) ;
return 0 ;
}
2021-02-01 14:27:57 +03:00
static int printInput ( struct Arguments * args )
{
char buf [ 1024 ] ;
2021-02-01 14:28:03 +03:00
cleanup ( struct pollfd * , cleanupGeneric ) fds = NULL ;
cleanup ( char * * , cleanupStringList ) buffers = NULL ;
cleanup ( size_t * , cleanupGeneric ) buflen = NULL ;
2021-02-01 14:27:57 +03:00
size_t i ;
2020-08-03 18:27:58 +03:00
ssize_t got ;
2010-05-25 15:14:06 +04:00
2021-02-01 14:27:58 +03:00
if ( ! ( fds = calloc ( args - > numreadfds , sizeof ( * fds ) ) ) )
2021-02-01 14:28:03 +03:00
return - 1 ;
2021-02-01 14:27:58 +03:00
/* plus one NULL terminator */
if ( ! ( buffers = calloc ( args - > numreadfds + 1 , sizeof ( * buffers ) ) ) )
2021-02-01 14:28:03 +03:00
return - 1 ;
2021-02-01 14:27:58 +03:00
if ( ! ( buflen = calloc ( args - > numreadfds , sizeof ( * buflen ) ) ) )
2021-02-01 14:28:03 +03:00
return - 1 ;
2021-02-01 14:27:58 +03:00
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 )
2021-02-01 14:28:03 +03:00
return - 1 ;
2021-02-01 14:27:57 +03:00
usleep ( 100 * 1000 ) ;
2012-06-01 01:50:07 +04:00
}
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 ) ) ;
2021-02-01 14:28:03 +03:00
return - 1 ;
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 )
2021-02-01 14:28:03 +03:00
return - 1 ;
2019-07-25 21:22:10 +03:00
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 " ) ;
2021-02-01 14:28:03 +03:00
return - 1 ;
2019-07-25 21:22:10 +03:00
}
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 ] )
2021-02-01 14:28:03 +03:00
return - 1 ;
2020-09-21 20:32:29 +03:00
if ( fwrite ( buffers [ i ] , 1 , buflen [ i ] , stderr ) ! = buflen [ i ] )
2021-02-01 14:28:03 +03:00
return - 1 ;
2010-05-25 15:14:06 +04:00
}
fprintf ( stdout , " END STDOUT \n " ) ;
fflush ( stdout ) ;
fprintf ( stderr , " END STDERR \n " ) ;
fflush ( stderr ) ;
2021-02-01 14:28:03 +03:00
return 0 ;
2021-02-01 14:27:57 +03:00
}
int main ( int argc , char * * argv ) {
2021-02-01 14:28:04 +03:00
cleanup ( struct Arguments * , cleanupArguments ) args = NULL ;
cleanup ( FILE * , cleanupFile ) log = NULL ;
2021-02-01 14:27:57 +03:00
2021-02-01 14:28:04 +03:00
if ( ! ( log = fopen ( abs_builddir " /commandhelper.log " , " w " ) ) )
return EXIT_FAILURE ;
if ( ! ( args = parseArguments ( argc , argv ) ) )
return EXIT_FAILURE ;
2021-02-01 14:27:57 +03:00
printArguments ( log , argc , argv ) ;
if ( printEnvironment ( log ) ! = 0 )
2021-02-01 14:28:04 +03:00
return EXIT_FAILURE ;
2021-02-01 14:27:57 +03:00
if ( printFds ( log ) ! = 0 )
2021-02-01 14:28:04 +03:00
return EXIT_FAILURE ;
2021-02-01 14:27:57 +03:00
printDaemonization ( log , args ) ;
if ( printCwd ( log ) ! = 0 )
2021-02-01 14:28:04 +03:00
return EXIT_FAILURE ;
2021-02-01 14:27:57 +03:00
fprintf ( log , " UMASK:%04o \n " , umask ( 0 ) ) ;
if ( printInput ( args ) ! = 0 )
2021-02-01 14:28:04 +03:00
return EXIT_FAILURE ;
2021-02-01 14:27:57 +03:00
2021-02-01 14:28:04 +03:00
return EXIT_SUCCESS ;
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