2010-05-25 15:14:06 +04:00
/*
* commandtest . c : Test the libCommand API
*
2014-02-19 05:06:50 +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 <signal.h>
# include <sys/stat.h>
2020-01-16 14:38:18 +03:00
# ifndef WIN32
# include <sys / wait.h>
# endif
2010-05-25 15:14:06 +04:00
# include <fcntl.h>
# include "testutils.h"
# include "internal.h"
2012-12-12 22:06:53 +04:00
# include "viralloc.h"
2012-12-12 20:27:01 +04:00
# include "vircommand.h"
2011-07-19 22:32:58 +04:00
# include "virfile.h"
2011-08-13 01:54:49 +04:00
# include "virpidfile.h"
2012-12-13 22:21:53 +04:00
# include "virerror.h"
2013-01-16 14:58:00 +04:00
# include "virthread.h"
2013-04-03 14:36:23 +04:00
# include "virstring.h"
2014-02-20 07:04:40 +04:00
# include "virprocess.h"
2020-02-17 00:59:28 +03:00
# include "virutil.h"
2012-06-01 01:50:07 +04:00
# define VIR_FROM_THIS VIR_FROM_NONE
2010-05-25 15:14:06 +04:00
# ifdef WIN32
2011-07-28 19:48:12 +04:00
int
main ( void )
2010-05-25 15:14:06 +04:00
{
2011-07-28 19:48:12 +04:00
return EXIT_AM_SKIP ;
2010-05-25 15:14:06 +04:00
}
# else
2020-01-07 19:16:19 +03:00
/* Some UNIX lack it in headers & it doesn't hurt to redeclare */
extern char * * environ ;
2014-07-16 18:19:28 +04:00
static int checkoutput ( const char * testname ,
char * prefix )
2010-12-06 13:51:41 +03:00
{
2010-05-25 15:14:06 +04:00
int ret = - 1 ;
char * expectname = NULL ;
char * expectlog = NULL ;
char * actualname = NULL ;
char * actuallog = NULL ;
2019-10-22 16:26:14 +03:00
expectname = g_strdup_printf ( " %s/commanddata/%s.log " , abs_srcdir , testname ) ;
actualname = g_strdup_printf ( " %s/commandhelper.log " , abs_builddir ) ;
2010-05-25 15:14:06 +04:00
if ( virFileReadAll ( expectname , 1024 * 64 , & expectlog ) < 0 ) {
fprintf ( stderr , " cannot read %s \n " , expectname ) ;
goto cleanup ;
}
if ( virFileReadAll ( actualname , 1024 * 64 , & actuallog ) < 0 ) {
fprintf ( stderr , " cannot read %s \n " , actualname ) ;
goto cleanup ;
}
2014-07-16 18:19:28 +04:00
if ( prefix ) {
char * tmp = NULL ;
2019-10-22 16:26:14 +03:00
tmp = g_strdup_printf ( " %s%s " , prefix , expectlog ) ;
2014-07-16 18:19:28 +04:00
VIR_FREE ( expectlog ) ;
expectlog = tmp ;
}
2010-05-25 15:14:06 +04:00
if ( STRNEQ ( expectlog , actuallog ) ) {
2016-05-26 18:01:51 +03:00
virTestDifference ( stderr , expectlog , actuallog ) ;
2010-05-25 15:14:06 +04:00
goto cleanup ;
}
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2011-05-03 20:37:13 +04:00
if ( actualname )
unlink ( actualname ) ;
2010-05-25 15:14:06 +04:00
VIR_FREE ( actuallog ) ;
VIR_FREE ( actualname ) ;
VIR_FREE ( expectlog ) ;
VIR_FREE ( expectname ) ;
return ret ;
}
/*
* Run program , no args , inherit all ENV , keep CWD .
* Only stdin / out / err open
* No slot for return status must log error .
*/
2019-10-14 15:45:03 +03:00
static int test0 ( const void * unused G_GNUC_UNUSED )
2010-12-06 13:51:41 +03:00
{
2010-05-25 15:14:06 +04:00
virCommandPtr cmd ;
int ret = - 1 ;
cmd = virCommandNew ( abs_builddir " /commandhelper-doesnotexist " ) ;
if ( virCommandRun ( cmd , NULL ) = = 0 )
goto cleanup ;
2010-12-06 14:58:56 +03:00
2018-05-05 15:04:21 +03:00
if ( virGetLastErrorCode ( ) = = VIR_ERR_OK )
2010-05-25 15:14:06 +04:00
goto cleanup ;
2010-12-06 14:58:56 +03:00
2010-05-25 15:14:06 +04:00
virResetLastError ( ) ;
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2010-05-25 15:14:06 +04:00
virCommandFree ( cmd ) ;
return ret ;
}
/*
* Run program , no args , inherit all ENV , keep CWD .
* Only stdin / out / err open
* Capturing return status must not log error .
*/
2019-10-14 15:45:03 +03:00
static int test1 ( const void * unused G_GNUC_UNUSED )
2010-12-06 13:51:41 +03:00
{
2010-05-25 15:14:06 +04:00
virCommandPtr cmd ;
int ret = - 1 ;
int status ;
cmd = virCommandNew ( abs_builddir " /commandhelper-doesnotexist " ) ;
2014-02-20 04:32:19 +04:00
if ( virCommandRun ( cmd , & status ) < 0 )
goto cleanup ;
if ( status ! = EXIT_ENOENT )
goto cleanup ;
virCommandRawStatus ( cmd ) ;
2010-05-25 15:14:06 +04:00
if ( virCommandRun ( cmd , & status ) < 0 )
goto cleanup ;
2014-02-19 05:06:50 +04:00
if ( ! WIFEXITED ( status ) | | WEXITSTATUS ( status ) ! = EXIT_ENOENT )
2010-05-25 15:14:06 +04:00
goto cleanup ;
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2010-05-25 15:14:06 +04:00
virCommandFree ( cmd ) ;
return ret ;
}
/*
* Run program ( twice ) , no args , inherit all ENV , keep CWD .
* Only stdin / out / err open
*/
2019-10-14 15:45:03 +03:00
static int test2 ( const void * unused G_GNUC_UNUSED )
2010-12-06 13:51:41 +03:00
{
2010-05-25 15:14:06 +04:00
virCommandPtr cmd = virCommandNew ( abs_builddir " /commandhelper " ) ;
int ret ;
if ( virCommandRun ( cmd , NULL ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2010-12-07 00:48:11 +03:00
virCommandFree ( cmd ) ;
2010-05-25 15:14:06 +04:00
return - 1 ;
}
2014-07-16 18:19:28 +04:00
if ( ( ret = checkoutput ( " test2 " , NULL ) ) ! = 0 ) {
2010-05-25 15:14:06 +04:00
virCommandFree ( cmd ) ;
return ret ;
}
if ( virCommandRun ( cmd , NULL ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2010-12-07 00:48:11 +03:00
virCommandFree ( cmd ) ;
2010-05-25 15:14:06 +04:00
return - 1 ;
}
virCommandFree ( cmd ) ;
2014-07-16 18:19:28 +04:00
return checkoutput ( " test2 " , NULL ) ;
2010-05-25 15:14:06 +04:00
}
/*
* Run program , no args , inherit all ENV , keep CWD .
* stdin / out / err + two extra FD open
*/
2019-10-14 15:45:03 +03:00
static int test3 ( const void * unused G_GNUC_UNUSED )
2010-12-06 13:51:41 +03:00
{
2010-05-25 15:14:06 +04:00
virCommandPtr cmd = virCommandNew ( abs_builddir " /commandhelper " ) ;
int newfd1 = dup ( STDERR_FILENO ) ;
int newfd2 = dup ( STDERR_FILENO ) ;
int newfd3 = dup ( STDERR_FILENO ) ;
2020-01-17 13:52:46 +03:00
struct stat before , after ;
2010-12-07 00:48:11 +03:00
int ret = - 1 ;
2010-05-25 15:14:06 +04:00
2020-01-17 13:52:46 +03:00
if ( fstat ( newfd3 , & before ) < 0 ) {
perror ( " fstat " ) ;
goto cleanup ;
}
2013-07-11 14:31:56 +04:00
virCommandPassFD ( cmd , newfd1 , 0 ) ;
virCommandPassFD ( cmd , newfd3 ,
VIR_COMMAND_PASS_FD_CLOSE_PARENT ) ;
2010-05-25 15:14:06 +04:00
if ( virCommandRun ( cmd , NULL ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2010-12-07 00:48:11 +03:00
goto cleanup ;
2010-05-25 15:14:06 +04:00
}
if ( fcntl ( newfd1 , F_GETFL ) < 0 | |
2020-01-17 13:52:46 +03:00
fcntl ( newfd2 , F_GETFL ) < 0 ) {
puts ( " fds 1/2 were not open " ) ;
2010-12-07 00:48:11 +03:00
goto cleanup ;
2010-05-25 15:14:06 +04:00
}
2020-01-17 13:52:46 +03:00
/* We expect newfd3 to be closed, but the
* fd might have already been reused by
* the event loop . So if it is open , we
* check if it matches the stat info we
* got earlier
*/
if ( fcntl ( newfd3 , F_GETFL ) > = 0 & &
fstat ( newfd3 , & after ) > = 0 ) {
if ( before . st_ino = = after . st_ino & &
before . st_dev = = after . st_dev & &
before . st_mode = = after . st_mode ) {
puts ( " fd 3 should not be open " ) ;
goto cleanup ;
}
}
2014-07-16 18:19:28 +04:00
ret = checkoutput ( " test3 " , NULL ) ;
2010-12-07 00:48:11 +03:00
2014-03-25 10:53:44 +04:00
cleanup :
2010-05-25 15:14:06 +04:00
virCommandFree ( cmd ) ;
2014-01-13 19:50:00 +04:00
/* coverity[double_close] */
2010-05-25 15:14:06 +04:00
VIR_FORCE_CLOSE ( newfd1 ) ;
VIR_FORCE_CLOSE ( newfd2 ) ;
2010-12-07 00:48:11 +03:00
return ret ;
2010-05-25 15:14:06 +04:00
}
/*
* Run program , no args , inherit all ENV , CWD is /
* Only stdin / out / err open .
* Daemonized
*/
2019-10-14 15:45:03 +03:00
static int test4 ( const void * unused G_GNUC_UNUSED )
2010-12-06 13:51:41 +03:00
{
2010-05-25 15:14:06 +04:00
virCommandPtr cmd = virCommandNew ( abs_builddir " /commandhelper " ) ;
2011-08-13 01:54:49 +04:00
char * pidfile = virPidFileBuildPath ( abs_builddir , " commandhelper " ) ;
2010-12-07 00:48:11 +03:00
pid_t pid ;
int ret = - 1 ;
if ( ! pidfile )
goto cleanup ;
2010-05-25 15:14:06 +04:00
virCommandSetPidFile ( cmd , pidfile ) ;
virCommandDaemonize ( cmd ) ;
if ( virCommandRun ( cmd , NULL ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2010-12-07 00:48:11 +03:00
goto cleanup ;
2010-05-25 15:14:06 +04:00
}
2011-08-13 01:54:49 +04:00
if ( virPidFileRead ( abs_builddir , " commandhelper " , & pid ) < 0 ) {
2010-05-25 15:14:06 +04:00
printf ( " cannot read pidfile \n " ) ;
2010-12-07 00:48:11 +03:00
goto cleanup ;
2010-05-25 15:14:06 +04:00
}
while ( kill ( pid , 0 ) ! = - 1 )
2019-10-02 20:01:11 +03:00
g_usleep ( 100 * 1000 ) ;
2010-05-25 15:14:06 +04:00
2014-07-16 18:19:28 +04:00
ret = checkoutput ( " test4 " , NULL ) ;
2010-05-25 15:14:06 +04:00
2014-03-25 10:53:44 +04:00
cleanup :
2010-12-07 00:48:11 +03:00
virCommandFree ( cmd ) ;
2011-05-03 20:37:13 +04:00
if ( pidfile )
unlink ( pidfile ) ;
2010-05-25 15:14:06 +04:00
VIR_FREE ( pidfile ) ;
2010-12-07 00:48:11 +03:00
return ret ;
2010-05-25 15:14:06 +04:00
}
/*
* Run program , no args , inherit filtered ENV , keep CWD .
* Only stdin / out / err open
*/
2019-10-14 15:45:03 +03:00
static int test5 ( const void * unused G_GNUC_UNUSED )
2010-12-06 13:51:41 +03:00
{
2010-05-25 15:14:06 +04:00
virCommandPtr cmd = virCommandNew ( abs_builddir " /commandhelper " ) ;
virCommandAddEnvPassCommon ( cmd ) ;
if ( virCommandRun ( cmd , NULL ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2010-12-07 00:48:11 +03:00
virCommandFree ( cmd ) ;
2010-05-25 15:14:06 +04:00
return - 1 ;
}
virCommandFree ( cmd ) ;
2014-07-16 18:19:28 +04:00
return checkoutput ( " test5 " , NULL ) ;
2010-05-25 15:14:06 +04:00
}
/*
* Run program , no args , inherit filtered ENV , keep CWD .
* Only stdin / out / err open
*/
2019-10-14 15:45:03 +03:00
static int test6 ( const void * unused G_GNUC_UNUSED )
2010-12-06 13:51:41 +03:00
{
2010-05-25 15:14:06 +04:00
virCommandPtr cmd = virCommandNew ( abs_builddir " /commandhelper " ) ;
2019-08-01 15:52:00 +03:00
virCommandAddEnvPass ( cmd , " DISPLAY " ) ;
virCommandAddEnvPass ( cmd , " DOESNOTEXIST " ) ;
2010-05-25 15:14:06 +04:00
if ( virCommandRun ( cmd , NULL ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2010-12-07 00:48:11 +03:00
virCommandFree ( cmd ) ;
2010-05-25 15:14:06 +04:00
return - 1 ;
}
virCommandFree ( cmd ) ;
2014-07-16 18:19:28 +04:00
return checkoutput ( " test6 " , NULL ) ;
2010-05-25 15:14:06 +04:00
}
/*
* Run program , no args , inherit filtered ENV , keep CWD .
* Only stdin / out / err open
*/
2019-10-14 15:45:03 +03:00
static int test7 ( const void * unused G_GNUC_UNUSED )
2010-12-06 13:51:41 +03:00
{
2010-05-25 15:14:06 +04:00
virCommandPtr cmd = virCommandNew ( abs_builddir " /commandhelper " ) ;
virCommandAddEnvPassCommon ( cmd ) ;
2019-08-01 15:52:00 +03:00
virCommandAddEnvPass ( cmd , " DISPLAY " ) ;
virCommandAddEnvPass ( cmd , " DOESNOTEXIST " ) ;
2010-05-25 15:14:06 +04:00
if ( virCommandRun ( cmd , NULL ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2010-12-07 00:48:11 +03:00
virCommandFree ( cmd ) ;
2010-05-25 15:14:06 +04:00
return - 1 ;
}
virCommandFree ( cmd ) ;
2014-07-16 18:19:28 +04:00
return checkoutput ( " test7 " , NULL ) ;
2010-05-25 15:14:06 +04:00
}
/*
* Run program , no args , inherit filtered ENV , keep CWD .
* Only stdin / out / err open
*/
2019-10-14 15:45:03 +03:00
static int test8 ( const void * unused G_GNUC_UNUSED )
2010-12-06 13:51:41 +03:00
{
2010-05-25 15:14:06 +04:00
virCommandPtr cmd = virCommandNew ( abs_builddir " /commandhelper " ) ;
2012-09-25 03:04:46 +04:00
virCommandAddEnvString ( cmd , " USER=bogus " ) ;
2010-05-25 15:14:06 +04:00
virCommandAddEnvString ( cmd , " LANG=C " ) ;
2012-09-25 03:04:46 +04:00
virCommandAddEnvPair ( cmd , " USER " , " also bogus " ) ;
2010-05-25 15:14:06 +04:00
virCommandAddEnvPair ( cmd , " USER " , " test " ) ;
if ( virCommandRun ( cmd , NULL ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2010-12-07 00:48:11 +03:00
virCommandFree ( cmd ) ;
2010-05-25 15:14:06 +04:00
return - 1 ;
}
virCommandFree ( cmd ) ;
2014-07-16 18:19:28 +04:00
return checkoutput ( " test8 " , NULL ) ;
2010-05-25 15:14:06 +04:00
}
/*
* Run program , some args , inherit all ENV , keep CWD .
* Only stdin / out / err open
*/
2019-10-14 15:45:03 +03:00
static int test9 ( const void * unused G_GNUC_UNUSED )
2010-12-06 13:51:41 +03:00
{
2010-05-25 15:14:06 +04:00
virCommandPtr cmd = virCommandNew ( abs_builddir " /commandhelper " ) ;
const char * const args [ ] = { " arg1 " , " arg2 " , NULL } ;
2011-11-10 04:19:33 +04:00
virBuffer buf = VIR_BUFFER_INITIALIZER ;
2010-05-25 15:14:06 +04:00
virCommandAddArg ( cmd , " -version " ) ;
virCommandAddArgPair ( cmd , " -log " , " bar.log " ) ;
virCommandAddArgSet ( cmd , args ) ;
2011-11-10 04:19:33 +04:00
virCommandAddArgBuffer ( cmd , & buf ) ;
virBufferAddLit ( & buf , " arg4 " ) ;
virCommandAddArgBuffer ( cmd , & buf ) ;
virCommandAddArgList ( cmd , " arg5 " , " arg6 " , NULL ) ;
if ( virBufferUse ( & buf ) ) {
printf ( " Buffer not transferred \n " ) ;
virBufferFreeAndReset ( & buf ) ;
virCommandFree ( cmd ) ;
return - 1 ;
}
2010-05-25 15:14:06 +04:00
if ( virCommandRun ( cmd , NULL ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2010-12-07 00:48:11 +03:00
virCommandFree ( cmd ) ;
2010-05-25 15:14:06 +04:00
return - 1 ;
}
virCommandFree ( cmd ) ;
2014-07-16 18:19:28 +04:00
return checkoutput ( " test9 " , NULL ) ;
2010-05-25 15:14:06 +04:00
}
/*
* Run program , some args , inherit all ENV , keep CWD .
* Only stdin / out / err open
*/
2019-10-14 15:45:03 +03:00
static int test10 ( const void * unused G_GNUC_UNUSED )
2010-12-06 13:51:41 +03:00
{
2010-05-25 15:14:06 +04:00
virCommandPtr cmd = virCommandNew ( abs_builddir " /commandhelper " ) ;
const char * const args [ ] = {
" -version " , " -log=bar.log " , NULL ,
} ;
virCommandAddArgSet ( cmd , args ) ;
if ( virCommandRun ( cmd , NULL ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2010-12-07 00:48:11 +03:00
virCommandFree ( cmd ) ;
2010-05-25 15:14:06 +04:00
return - 1 ;
}
virCommandFree ( cmd ) ;
2014-07-16 18:19:28 +04:00
return checkoutput ( " test10 " , NULL ) ;
2010-05-25 15:14:06 +04:00
}
/*
* Run program , some args , inherit all ENV , keep CWD .
* Only stdin / out / err open
*/
2019-10-14 15:45:03 +03:00
static int test11 ( const void * unused G_GNUC_UNUSED )
2010-12-06 13:51:41 +03:00
{
2010-05-25 15:14:06 +04:00
const char * args [ ] = {
abs_builddir " /commandhelper " ,
" -version " , " -log=bar.log " , NULL ,
} ;
virCommandPtr cmd = virCommandNewArgs ( args ) ;
if ( virCommandRun ( cmd , NULL ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2010-12-07 00:48:11 +03:00
virCommandFree ( cmd ) ;
2010-05-25 15:14:06 +04:00
return - 1 ;
}
virCommandFree ( cmd ) ;
2014-07-16 18:19:28 +04:00
return checkoutput ( " test11 " , NULL ) ;
2010-05-25 15:14:06 +04:00
}
/*
* Run program , no args , inherit all ENV , keep CWD .
* Only stdin / out / err open . Set stdin data
*/
2019-10-14 15:45:03 +03:00
static int test12 ( const void * unused G_GNUC_UNUSED )
2010-12-06 13:51:41 +03:00
{
2010-05-25 15:14:06 +04:00
virCommandPtr cmd = virCommandNew ( abs_builddir " /commandhelper " ) ;
virCommandSetInputBuffer ( cmd , " Hello World \n " ) ;
if ( virCommandRun ( cmd , NULL ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2010-12-07 00:48:11 +03:00
virCommandFree ( cmd ) ;
2010-05-25 15:14:06 +04:00
return - 1 ;
}
virCommandFree ( cmd ) ;
2014-07-16 18:19:28 +04:00
return checkoutput ( " test12 " , NULL ) ;
2010-05-25 15:14:06 +04:00
}
/*
* Run program , no args , inherit all ENV , keep CWD .
* Only stdin / out / err open . Set stdin data
*/
2019-10-14 15:45:03 +03:00
static int test13 ( const void * unused G_GNUC_UNUSED )
2010-12-06 13:51:41 +03:00
{
2010-05-25 15:14:06 +04:00
virCommandPtr cmd = virCommandNew ( abs_builddir " /commandhelper " ) ;
char * outactual = NULL ;
const char * outexpect = " BEGIN STDOUT \n "
" Hello World \n "
" END STDOUT \n " ;
int ret = - 1 ;
virCommandSetInputBuffer ( cmd , " Hello World \n " ) ;
virCommandSetOutputBuffer ( cmd , & outactual ) ;
if ( virCommandRun ( cmd , NULL ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2010-12-07 00:48:11 +03:00
goto cleanup ;
2010-05-25 15:14:06 +04:00
}
2010-12-07 00:48:11 +03:00
if ( ! outactual )
goto cleanup ;
2010-05-25 15:14:06 +04:00
virCommandFree ( cmd ) ;
2010-12-07 00:48:11 +03:00
cmd = NULL ;
2010-05-25 15:14:06 +04:00
2015-10-20 19:15:12 +03:00
if ( STRNEQ ( outactual , outexpect ) ) {
2016-05-26 18:01:51 +03:00
virTestDifference ( stderr , outexpect , outactual ) ;
2010-05-25 15:14:06 +04:00
goto cleanup ;
}
2014-07-16 18:19:28 +04:00
ret = checkoutput ( " test13 " , NULL ) ;
2010-05-25 15:14:06 +04:00
2014-03-25 10:53:44 +04:00
cleanup :
2010-12-07 00:48:11 +03:00
virCommandFree ( cmd ) ;
2010-05-25 15:14:06 +04:00
VIR_FREE ( outactual ) ;
return ret ;
}
/*
* Run program , no args , inherit all ENV , keep CWD .
* Only stdin / out / err open . Set stdin data
*/
2019-10-14 15:45:03 +03:00
static int test14 ( const void * unused G_GNUC_UNUSED )
2010-12-06 13:51:41 +03:00
{
2010-05-25 15:14:06 +04:00
virCommandPtr cmd = virCommandNew ( abs_builddir " /commandhelper " ) ;
char * outactual = NULL ;
const char * outexpect = " BEGIN STDOUT \n "
" Hello World \n "
" END STDOUT \n " ;
char * erractual = NULL ;
const char * errexpect = " BEGIN STDERR \n "
" Hello World \n "
" END STDERR \n " ;
2012-01-28 02:40:20 +04:00
char * jointactual = NULL ;
const char * jointexpect = " BEGIN STDOUT \n "
" BEGIN STDERR \n "
" Hello World \n "
" Hello World \n "
" END STDOUT \n "
" END STDERR \n " ;
2010-05-25 15:14:06 +04:00
int ret = - 1 ;
virCommandSetInputBuffer ( cmd , " Hello World \n " ) ;
virCommandSetOutputBuffer ( cmd , & outactual ) ;
virCommandSetErrorBuffer ( cmd , & erractual ) ;
if ( virCommandRun ( cmd , NULL ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2010-12-07 00:48:11 +03:00
goto cleanup ;
2010-05-25 15:14:06 +04:00
}
2010-12-07 00:48:11 +03:00
if ( ! outactual | | ! erractual )
goto cleanup ;
2010-05-25 15:14:06 +04:00
virCommandFree ( cmd ) ;
2012-01-28 02:40:20 +04:00
cmd = virCommandNew ( abs_builddir " /commandhelper " ) ;
virCommandSetInputBuffer ( cmd , " Hello World \n " ) ;
virCommandSetOutputBuffer ( cmd , & jointactual ) ;
virCommandSetErrorBuffer ( cmd , & jointactual ) ;
if ( virCommandRun ( cmd , NULL ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2012-01-28 02:40:20 +04:00
goto cleanup ;
}
if ( ! jointactual )
goto cleanup ;
2010-05-25 15:14:06 +04:00
2015-10-20 19:15:12 +03:00
if ( STRNEQ ( outactual , outexpect ) ) {
2016-05-26 18:01:51 +03:00
virTestDifference ( stderr , outexpect , outactual ) ;
2010-05-25 15:14:06 +04:00
goto cleanup ;
}
2015-10-20 19:15:12 +03:00
if ( STRNEQ ( erractual , errexpect ) ) {
2016-05-26 18:01:51 +03:00
virTestDifference ( stderr , errexpect , erractual ) ;
2010-05-25 15:14:06 +04:00
goto cleanup ;
}
2015-10-20 19:15:12 +03:00
if ( STRNEQ ( jointactual , jointexpect ) ) {
2016-05-26 18:01:51 +03:00
virTestDifference ( stderr , jointexpect , jointactual ) ;
2012-01-28 02:40:20 +04:00
goto cleanup ;
}
2010-05-25 15:14:06 +04:00
2014-07-16 18:19:28 +04:00
ret = checkoutput ( " test14 " , NULL ) ;
2010-05-25 15:14:06 +04:00
2014-03-25 10:53:44 +04:00
cleanup :
2010-12-07 00:48:11 +03:00
virCommandFree ( cmd ) ;
2010-05-25 15:14:06 +04:00
VIR_FREE ( outactual ) ;
VIR_FREE ( erractual ) ;
2012-01-28 02:40:20 +04:00
VIR_FREE ( jointactual ) ;
2010-05-25 15:14:06 +04:00
return ret ;
}
/*
* Run program , no args , inherit all ENV , change CWD .
* Only stdin / out / err open
*/
2019-10-14 15:45:03 +03:00
static int test15 ( const void * unused G_GNUC_UNUSED )
2010-12-06 13:51:41 +03:00
{
2010-05-25 15:14:06 +04:00
virCommandPtr cmd = virCommandNew ( abs_builddir " /commandhelper " ) ;
2010-12-06 15:03:26 +03:00
char * cwd = NULL ;
int ret = - 1 ;
2010-05-25 15:14:06 +04:00
2019-10-22 16:26:14 +03:00
cwd = g_strdup_printf ( " %s/commanddata " , abs_srcdir ) ;
2010-12-06 15:03:26 +03:00
virCommandSetWorkingDirectory ( cmd , cwd ) ;
2014-09-03 19:13:21 +04:00
virCommandSetUmask ( cmd , 002 ) ;
2010-05-25 15:14:06 +04:00
if ( virCommandRun ( cmd , NULL ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2010-12-06 15:03:26 +03:00
goto cleanup ;
2010-05-25 15:14:06 +04:00
}
2014-07-16 18:19:28 +04:00
ret = checkoutput ( " test15 " , NULL ) ;
2010-12-06 15:03:26 +03:00
2014-03-25 10:53:44 +04:00
cleanup :
2010-12-06 15:03:26 +03:00
VIR_FREE ( cwd ) ;
2010-05-25 15:14:06 +04:00
virCommandFree ( cmd ) ;
2010-12-06 15:03:26 +03:00
return ret ;
2010-05-25 15:14:06 +04:00
}
/*
* Don ' t run program ; rather , log what would be run .
*/
2019-10-14 15:45:03 +03:00
static int test16 ( const void * unused G_GNUC_UNUSED )
2010-12-06 13:51:41 +03:00
{
2011-07-28 19:51:26 +04:00
virCommandPtr cmd = virCommandNew ( " true " ) ;
2010-05-25 15:14:06 +04:00
char * outactual = NULL ;
2012-08-28 22:11:45 +04:00
const char * outexpect = " A=B C='D E' true F 'G H' " ;
2010-05-25 15:14:06 +04:00
int ret = - 1 ;
int fd = - 1 ;
virCommandAddEnvPair ( cmd , " A " , " B " ) ;
2012-08-28 22:11:45 +04:00
virCommandAddEnvPair ( cmd , " C " , " D E " ) ;
virCommandAddArg ( cmd , " F " ) ;
virCommandAddArg ( cmd , " G H " ) ;
2010-05-25 15:14:06 +04:00
qemu: use line breaks in command line args written to log
The QEMU command line arguments are very long and currently all written
on a single line to /var/log/libvirt/qemu/$GUEST.log. This introduces
logic to add line breaks after every env variable and "-" optional
argument, and every positional argument. This will create a clearer log
file, which will in turn present better in bug reports when people cut +
paste from the log into a bug comment.
An example log file entry now looks like this:
2018-12-14 12:57:03.677+0000: starting up libvirt version: 5.0.0, qemu version: 3.0.0qemu-3.0.0-1.fc29, kernel: 4.19.5-300.fc29.x86_64, hostname: localhost.localdomain
LC_ALL=C \
PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin \
HOME=/home/berrange \
USER=berrange \
LOGNAME=berrange \
QEMU_AUDIO_DRV=none \
/usr/bin/qemu-system-ppc64 \
-name guest=guest,debug-threads=on \
-S \
-object secret,id=masterKey0,format=raw,file=/home/berrange/.config/libvirt/qemu/lib/domain-33-guest/master-key.aes \
-machine pseries-2.10,accel=tcg,usb=off,dump-guest-core=off \
-m 1024 \
-realtime mlock=off \
-smp 1,sockets=1,cores=1,threads=1 \
-uuid c8a74977-ab18-41d0-ae3b-4041c7fffbcd \
-display none \
-no-user-config \
-nodefaults \
-chardev socket,id=charmonitor,fd=23,server,nowait \
-mon chardev=charmonitor,id=monitor,mode=control \
-rtc base=utc \
-no-shutdown \
-boot strict=on \
-device qemu-xhci,id=usb,bus=pci.0,addr=0x1 \
-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x2 \
-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \
-msg timestamp=on
2018-12-14 12:57:03.730+0000: shutting down, reason=failed
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
2018-12-14 15:07:08 +03:00
if ( ( outactual = virCommandToString ( cmd , false ) ) = = NULL ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot convert to string: %s \n " , virGetLastErrorMessage ( ) ) ;
2010-12-07 00:48:11 +03:00
goto cleanup ;
2010-05-25 15:14:06 +04:00
}
if ( ( fd = open ( abs_builddir " /commandhelper.log " ,
O_CREAT | O_TRUNC | O_WRONLY , 0600 ) ) < 0 ) {
2019-10-02 18:30:36 +03:00
printf ( " Cannot open log file: %s \n " , g_strerror ( errno ) ) ;
2010-05-25 15:14:06 +04:00
goto cleanup ;
}
virCommandWriteArgLog ( cmd , fd ) ;
if ( VIR_CLOSE ( fd ) < 0 ) {
2019-10-02 18:30:36 +03:00
printf ( " Cannot close log file: %s \n " , g_strerror ( errno ) ) ;
2010-05-25 15:14:06 +04:00
goto cleanup ;
}
2015-10-20 19:15:12 +03:00
if ( STRNEQ ( outactual , outexpect ) ) {
2016-05-26 18:01:51 +03:00
virTestDifference ( stderr , outexpect , outactual ) ;
2010-05-25 15:14:06 +04:00
goto cleanup ;
}
2010-12-07 00:48:11 +03:00
2014-07-16 18:19:28 +04:00
ret = checkoutput ( " test16 " , NULL ) ;
2010-05-25 15:14:06 +04:00
2014-03-25 10:53:44 +04:00
cleanup :
2010-12-07 00:48:11 +03:00
virCommandFree ( cmd ) ;
2010-05-25 15:14:06 +04:00
VIR_FORCE_CLOSE ( fd ) ;
VIR_FREE ( outactual ) ;
return ret ;
}
2010-12-04 00:14:16 +03:00
/*
* Test string handling when no output is present .
*/
2019-10-14 15:45:03 +03:00
static int test17 ( const void * unused G_GNUC_UNUSED )
2010-12-04 00:14:16 +03:00
{
2011-07-28 19:51:26 +04:00
virCommandPtr cmd = virCommandNew ( " true " ) ;
2010-12-04 00:14:16 +03:00
int ret = - 1 ;
char * outbuf ;
2013-01-22 18:15:42 +04:00
char * errbuf = NULL ;
2010-12-04 00:14:16 +03:00
virCommandSetOutputBuffer ( cmd , & outbuf ) ;
if ( outbuf ! = NULL ) {
puts ( " buffer not sanitized at registration " ) ;
goto cleanup ;
}
if ( virCommandRun ( cmd , NULL ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2010-12-04 00:14:16 +03:00
goto cleanup ;
}
2014-03-25 21:03:19 +04:00
sa_assert ( outbuf ) ;
2013-01-14 19:35:45 +04:00
if ( * outbuf ) {
2010-12-04 00:14:16 +03:00
puts ( " output buffer is not an allocated empty string " ) ;
goto cleanup ;
}
VIR_FREE ( outbuf ) ;
2019-10-20 14:49:46 +03:00
outbuf = g_strdup ( " should not be leaked " ) ;
2010-12-04 00:14:16 +03:00
virCommandSetErrorBuffer ( cmd , & errbuf ) ;
if ( errbuf ! = NULL ) {
puts ( " buffer not sanitized at registration " ) ;
goto cleanup ;
}
if ( virCommandRun ( cmd , NULL ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2010-12-04 00:14:16 +03:00
goto cleanup ;
}
2013-01-14 19:35:45 +04:00
if ( * outbuf | | * errbuf ) {
2010-12-04 00:14:16 +03:00
puts ( " output buffers are not allocated empty strings " ) ;
goto cleanup ;
}
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2010-12-04 00:14:16 +03:00
virCommandFree ( cmd ) ;
VIR_FREE ( outbuf ) ;
VIR_FREE ( errbuf ) ;
return ret ;
}
2010-12-21 21:49:49 +03:00
/*
* Run long - running daemon , to ensure no hang .
*/
2019-10-14 15:45:03 +03:00
static int test18 ( const void * unused G_GNUC_UNUSED )
2010-12-21 21:49:49 +03:00
{
virCommandPtr cmd = virCommandNewArgList ( " sleep " , " 100 " , NULL ) ;
2011-08-13 01:54:49 +04:00
char * pidfile = virPidFileBuildPath ( abs_builddir , " commandhelper " ) ;
2010-12-21 21:49:49 +03:00
pid_t pid ;
int ret = - 1 ;
if ( ! pidfile )
goto cleanup ;
virCommandSetPidFile ( cmd , pidfile ) ;
virCommandDaemonize ( cmd ) ;
alarm ( 5 ) ;
if ( virCommandRun ( cmd , NULL ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2010-12-21 21:49:49 +03:00
goto cleanup ;
}
alarm ( 0 ) ;
2011-08-13 01:54:49 +04:00
if ( virPidFileRead ( abs_builddir , " commandhelper " , & pid ) < 0 ) {
2010-12-21 21:49:49 +03:00
printf ( " cannot read pidfile \n " ) ;
goto cleanup ;
}
2011-03-23 01:22:37 +03:00
virCommandFree ( cmd ) ;
cmd = NULL ;
if ( kill ( pid , 0 ) ! = 0 ) {
printf ( " daemon should still be running \n " ) ;
goto cleanup ;
}
2010-12-21 21:49:49 +03:00
while ( kill ( pid , SIGINT ) ! = - 1 )
2019-10-02 20:01:11 +03:00
g_usleep ( 100 * 1000 ) ;
2010-12-21 21:49:49 +03:00
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2010-12-21 21:49:49 +03:00
virCommandFree ( cmd ) ;
2011-05-03 20:37:13 +04:00
if ( pidfile )
unlink ( pidfile ) ;
2010-12-21 21:49:49 +03:00
VIR_FREE ( pidfile ) ;
return ret ;
}
2011-03-23 01:22:37 +03:00
/*
* Asynchronously run long - running daemon , to ensure no hang .
*/
2019-10-14 15:45:03 +03:00
static int test19 ( const void * unused G_GNUC_UNUSED )
2011-03-23 01:22:37 +03:00
{
virCommandPtr cmd = virCommandNewArgList ( " sleep " , " 100 " , NULL ) ;
pid_t pid ;
int ret = - 1 ;
alarm ( 5 ) ;
if ( virCommandRunAsync ( cmd , & pid ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2011-03-23 01:22:37 +03:00
goto cleanup ;
}
if ( kill ( pid , 0 ) ! = 0 ) {
printf ( " Child should still be running " ) ;
goto cleanup ;
}
virCommandAbort ( cmd ) ;
if ( kill ( pid , 0 ) = = 0 ) {
printf ( " Child should be aborted " ) ;
goto cleanup ;
}
alarm ( 0 ) ;
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2011-03-23 01:22:37 +03:00
virCommandFree ( cmd ) ;
return ret ;
}
2010-12-21 21:49:49 +03:00
2012-06-01 01:50:07 +04:00
/*
* Run program , no args , inherit all ENV , keep CWD .
* Ignore huge stdin data , to provoke SIGPIPE or EPIPE in parent .
*/
2019-10-14 15:45:03 +03:00
static int test20 ( const void * unused G_GNUC_UNUSED )
2012-06-01 01:50:07 +04:00
{
virCommandPtr cmd = virCommandNewArgList ( abs_builddir " /commandhelper " ,
" --close-stdin " , NULL ) ;
char * buf ;
int ret = - 1 ;
struct sigaction sig_action ;
sig_action . sa_handler = SIG_IGN ;
sig_action . sa_flags = 0 ;
sigemptyset ( & sig_action . sa_mask ) ;
sigaction ( SIGPIPE , & sig_action , NULL ) ;
2019-10-22 16:26:14 +03:00
buf = g_strdup_printf ( " 1 \n %100000d \n " , 2 ) ;
2012-06-01 01:50:07 +04:00
virCommandSetInputBuffer ( cmd , buf ) ;
if ( virCommandRun ( cmd , NULL ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2012-06-01 01:50:07 +04:00
goto cleanup ;
}
2014-07-16 18:19:28 +04:00
ret = checkoutput ( " test20 " , NULL ) ;
2014-03-25 10:53:44 +04:00
cleanup :
2012-06-01 01:50:07 +04:00
virCommandFree ( cmd ) ;
VIR_FREE ( buf ) ;
return ret ;
}
2011-05-11 19:51:30 +04:00
static const char * const newenv [ ] = {
" PATH=/usr/bin:/bin " ,
" HOSTNAME=test " ,
" LANG=C " ,
" HOME=/home/test " ,
" USER=test " ,
2017-11-17 16:17:38 +03:00
" LOGNAME=test " ,
2011-05-11 19:51:30 +04:00
" TMPDIR=/tmp " ,
" DISPLAY=:0.0 " ,
NULL
} ;
2019-10-14 15:45:03 +03:00
static int test21 ( const void * unused G_GNUC_UNUSED )
2013-01-16 21:55:06 +04:00
{
virCommandPtr cmd = virCommandNew ( abs_builddir " /commandhelper " ) ;
int ret = - 1 ;
const char * wrbuf = " Hello world \n " ;
char * outbuf = NULL , * errbuf = NULL ;
2014-01-20 15:27:29 +04:00
const char * outbufExpected = " BEGIN STDOUT \n "
2013-01-16 21:55:06 +04:00
" Hello world \n "
" END STDOUT \n " ;
2014-01-20 15:27:29 +04:00
const char * errbufExpected = " BEGIN STDERR \n "
2013-01-16 21:55:06 +04:00
" Hello world \n "
" END STDERR \n " ;
virCommandSetInputBuffer ( cmd , wrbuf ) ;
virCommandSetOutputBuffer ( cmd , & outbuf ) ;
virCommandSetErrorBuffer ( cmd , & errbuf ) ;
virCommandDoAsyncIO ( cmd ) ;
if ( virCommandRunAsync ( cmd , NULL ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2013-01-16 21:55:06 +04:00
goto cleanup ;
}
if ( virCommandWait ( cmd , NULL ) < 0 )
goto cleanup ;
if ( virTestGetVerbose ( ) )
printf ( " STDOUT:%s \n STDERR:%s \n " , NULLSTR ( outbuf ) , NULLSTR ( errbuf ) ) ;
2018-09-28 02:54:05 +03:00
if ( STRNEQ_NULLABLE ( outbuf , outbufExpected ) ) {
2016-05-26 18:01:51 +03:00
virTestDifference ( stderr , outbufExpected , outbuf ) ;
2013-01-16 21:55:06 +04:00
goto cleanup ;
}
2018-09-28 02:54:05 +03:00
if ( STRNEQ_NULLABLE ( errbuf , errbufExpected ) ) {
2016-05-26 18:01:51 +03:00
virTestDifference ( stderr , errbufExpected , errbuf ) ;
2013-01-16 21:55:06 +04:00
goto cleanup ;
}
2014-07-16 18:19:28 +04:00
ret = checkoutput ( " test21 " , NULL ) ;
2014-03-25 10:53:44 +04:00
cleanup :
2013-01-16 21:55:06 +04:00
VIR_FREE ( outbuf ) ;
VIR_FREE ( errbuf ) ;
virCommandFree ( cmd ) ;
return ret ;
}
2014-02-19 05:06:50 +04:00
static int
2019-10-14 15:45:03 +03:00
test22 ( const void * unused G_GNUC_UNUSED )
2014-02-19 05:06:50 +04:00
{
int ret = - 1 ;
virCommandPtr cmd ;
int status = - 1 ;
cmd = virCommandNewArgList ( " /bin/sh " , " -c " , " exit 3 " , NULL ) ;
2014-02-20 04:32:19 +04:00
if ( virCommandRun ( cmd , & status ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2014-02-20 04:32:19 +04:00
goto cleanup ;
}
if ( status ! = 3 ) {
printf ( " Unexpected status %d \n " , status ) ;
goto cleanup ;
}
virCommandRawStatus ( cmd ) ;
2014-02-19 05:06:50 +04:00
if ( virCommandRun ( cmd , & status ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2014-02-19 05:06:50 +04:00
goto cleanup ;
}
if ( ! WIFEXITED ( status ) | | WEXITSTATUS ( status ) ! = 3 ) {
printf ( " Unexpected status %d \n " , status ) ;
goto cleanup ;
}
virCommandFree ( cmd ) ;
cmd = virCommandNewArgList ( " /bin/sh " , " -c " , " kill -9 $$ " , NULL ) ;
2014-02-20 04:32:19 +04:00
if ( virCommandRun ( cmd , & status ) = = 0 ) {
printf ( " Death by signal not detected, status %d \n " , status ) ;
goto cleanup ;
}
virCommandRawStatus ( cmd ) ;
2014-02-19 05:06:50 +04:00
if ( virCommandRun ( cmd , & status ) < 0 ) {
2016-05-19 22:10:18 +03:00
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
2014-02-19 05:06:50 +04:00
goto cleanup ;
}
if ( ! WIFSIGNALED ( status ) | | WTERMSIG ( status ) ! = SIGKILL ) {
printf ( " Unexpected status %d \n " , status ) ;
goto cleanup ;
}
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2014-02-19 05:06:50 +04:00
virCommandFree ( cmd ) ;
return ret ;
}
2014-02-20 07:04:40 +04:00
static int
2019-10-14 15:45:03 +03:00
test23 ( const void * unused G_GNUC_UNUSED )
2014-02-20 07:04:40 +04:00
{
/* Not strictly a virCommand test, but this is the easiest place
* to test this lower - level interface . It takes a double fork to
* test virProcessExitWithStatus . */
int status = - 1 ;
pid_t pid ;
virFork: simplify semantics
The old semantics of virFork() violates the priciple of good
usability: it requires the caller to check the pid argument
after use, *even when virFork returned -1*, in order to properly
abort a child process that failed setup done immediately after
fork() - that is, the caller must call _exit() in the child.
While uses in virfile.c did this correctly, uses in 'virsh
lxc-enter-namespace' and 'virt-login-shell' would happily return
from the calling function in both the child and the parent,
leading to very confusing results. [Thankfully, I found the
problem by inspection, and can't actually trigger the double
return on error without an LD_PRELOAD library.]
It is much better if the semantics of virFork are impossible
to abuse. Looking at virFork(), the parent could only ever
return -1 with a non-negative pid if it misused pthread_sigmask,
but this never happens. Up until this patch series, the child
could return -1 with non-negative pid if it fails to set up
signals correctly, but we recently fixed that to make the child
call _exit() at that point instead of forcing the caller to do
it. Thus, the return value and contents of the pid argument are
now redundant (a -1 return now happens only for failure to fork,
a child 0 return only happens for a successful 0 pid, and a
parent 0 return only happens for a successful non-zero pid),
so we might as well return the pid directly rather than an
integer of whether it succeeded or failed; this is also good
from the interface design perspective as users are already
familiar with fork() semantics.
One last change in this patch: before returning the pid directly,
I found cases where using virProcessWait unconditionally on a
cleanup path of a virFork's -1 pid return would be nicer if there
were a way to avoid it overwriting an earlier message. While
such paths are a bit harder to come by with my change to a direct
pid return, I decided to keep the virProcessWait change in this
patch.
* src/util/vircommand.h (virFork): Change signature.
* src/util/vircommand.c (virFork): Guarantee that child will only
return on success, to simplify callers. Return pid rather than
status, now that the situations are always the same.
(virExec): Adjust caller, also avoid open-coding process death.
* src/util/virprocess.c (virProcessWait): Tweak semantics when pid
is -1.
(virProcessRunInMountNamespace): Adjust caller.
* src/util/virfile.c (virFileAccessibleAs, virFileOpenForked)
(virDirCreate): Likewise.
* tools/virt-login-shell.c (main): Likewise.
* tools/virsh-domain.c (cmdLxcEnterNamespace): Likewise.
* tests/commandtest.c (test23): Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-12-22 04:54:33 +04:00
if ( ( pid = virFork ( ) ) < 0 )
2019-11-12 23:46:29 +03:00
return - 1 ;
2014-02-20 07:04:40 +04:00
if ( pid = = 0 ) {
virFork: simplify semantics
The old semantics of virFork() violates the priciple of good
usability: it requires the caller to check the pid argument
after use, *even when virFork returned -1*, in order to properly
abort a child process that failed setup done immediately after
fork() - that is, the caller must call _exit() in the child.
While uses in virfile.c did this correctly, uses in 'virsh
lxc-enter-namespace' and 'virt-login-shell' would happily return
from the calling function in both the child and the parent,
leading to very confusing results. [Thankfully, I found the
problem by inspection, and can't actually trigger the double
return on error without an LD_PRELOAD library.]
It is much better if the semantics of virFork are impossible
to abuse. Looking at virFork(), the parent could only ever
return -1 with a non-negative pid if it misused pthread_sigmask,
but this never happens. Up until this patch series, the child
could return -1 with non-negative pid if it fails to set up
signals correctly, but we recently fixed that to make the child
call _exit() at that point instead of forcing the caller to do
it. Thus, the return value and contents of the pid argument are
now redundant (a -1 return now happens only for failure to fork,
a child 0 return only happens for a successful 0 pid, and a
parent 0 return only happens for a successful non-zero pid),
so we might as well return the pid directly rather than an
integer of whether it succeeded or failed; this is also good
from the interface design perspective as users are already
familiar with fork() semantics.
One last change in this patch: before returning the pid directly,
I found cases where using virProcessWait unconditionally on a
cleanup path of a virFork's -1 pid return would be nicer if there
were a way to avoid it overwriting an earlier message. While
such paths are a bit harder to come by with my change to a direct
pid return, I decided to keep the virProcessWait change in this
patch.
* src/util/vircommand.h (virFork): Change signature.
* src/util/vircommand.c (virFork): Guarantee that child will only
return on success, to simplify callers. Return pid rather than
status, now that the situations are always the same.
(virExec): Adjust caller, also avoid open-coding process death.
* src/util/virprocess.c (virProcessWait): Tweak semantics when pid
is -1.
(virProcessRunInMountNamespace): Adjust caller.
* src/util/virfile.c (virFileAccessibleAs, virFileOpenForked)
(virDirCreate): Likewise.
* tools/virt-login-shell.c (main): Likewise.
* tools/virsh-domain.c (cmdLxcEnterNamespace): Likewise.
* tests/commandtest.c (test23): Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-12-22 04:54:33 +04:00
if ( ( pid = virFork ( ) ) < 0 )
2014-02-20 07:04:40 +04:00
_exit ( EXIT_FAILURE ) ;
if ( pid = = 0 )
_exit ( 42 ) ;
2014-02-20 07:23:44 +04:00
if ( virProcessWait ( pid , & status , true ) < 0 )
2014-02-20 07:04:40 +04:00
_exit ( EXIT_FAILURE ) ;
virProcessExitWithStatus ( status ) ;
_exit ( EXIT_FAILURE ) ;
}
2014-02-20 07:23:44 +04:00
if ( virProcessWait ( pid , & status , true ) < 0 )
2019-11-12 23:46:29 +03:00
return - 1 ;
2014-02-20 07:04:40 +04:00
if ( ! WIFEXITED ( status ) | | WEXITSTATUS ( status ) ! = 42 ) {
printf ( " Unexpected status %d \n " , status ) ;
2019-11-12 23:46:29 +03:00
return - 1 ;
2014-02-20 07:04:40 +04:00
}
virFork: simplify semantics
The old semantics of virFork() violates the priciple of good
usability: it requires the caller to check the pid argument
after use, *even when virFork returned -1*, in order to properly
abort a child process that failed setup done immediately after
fork() - that is, the caller must call _exit() in the child.
While uses in virfile.c did this correctly, uses in 'virsh
lxc-enter-namespace' and 'virt-login-shell' would happily return
from the calling function in both the child and the parent,
leading to very confusing results. [Thankfully, I found the
problem by inspection, and can't actually trigger the double
return on error without an LD_PRELOAD library.]
It is much better if the semantics of virFork are impossible
to abuse. Looking at virFork(), the parent could only ever
return -1 with a non-negative pid if it misused pthread_sigmask,
but this never happens. Up until this patch series, the child
could return -1 with non-negative pid if it fails to set up
signals correctly, but we recently fixed that to make the child
call _exit() at that point instead of forcing the caller to do
it. Thus, the return value and contents of the pid argument are
now redundant (a -1 return now happens only for failure to fork,
a child 0 return only happens for a successful 0 pid, and a
parent 0 return only happens for a successful non-zero pid),
so we might as well return the pid directly rather than an
integer of whether it succeeded or failed; this is also good
from the interface design perspective as users are already
familiar with fork() semantics.
One last change in this patch: before returning the pid directly,
I found cases where using virProcessWait unconditionally on a
cleanup path of a virFork's -1 pid return would be nicer if there
were a way to avoid it overwriting an earlier message. While
such paths are a bit harder to come by with my change to a direct
pid return, I decided to keep the virProcessWait change in this
patch.
* src/util/vircommand.h (virFork): Change signature.
* src/util/vircommand.c (virFork): Guarantee that child will only
return on success, to simplify callers. Return pid rather than
status, now that the situations are always the same.
(virExec): Adjust caller, also avoid open-coding process death.
* src/util/virprocess.c (virProcessWait): Tweak semantics when pid
is -1.
(virProcessRunInMountNamespace): Adjust caller.
* src/util/virfile.c (virFileAccessibleAs, virFileOpenForked)
(virDirCreate): Likewise.
* tools/virt-login-shell.c (main): Likewise.
* tools/virsh-domain.c (cmdLxcEnterNamespace): Likewise.
* tests/commandtest.c (test23): Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-12-22 04:54:33 +04:00
if ( ( pid = virFork ( ) ) < 0 )
2019-11-12 23:46:29 +03:00
return - 1 ;
2014-02-20 07:04:40 +04:00
if ( pid = = 0 ) {
virFork: simplify semantics
The old semantics of virFork() violates the priciple of good
usability: it requires the caller to check the pid argument
after use, *even when virFork returned -1*, in order to properly
abort a child process that failed setup done immediately after
fork() - that is, the caller must call _exit() in the child.
While uses in virfile.c did this correctly, uses in 'virsh
lxc-enter-namespace' and 'virt-login-shell' would happily return
from the calling function in both the child and the parent,
leading to very confusing results. [Thankfully, I found the
problem by inspection, and can't actually trigger the double
return on error without an LD_PRELOAD library.]
It is much better if the semantics of virFork are impossible
to abuse. Looking at virFork(), the parent could only ever
return -1 with a non-negative pid if it misused pthread_sigmask,
but this never happens. Up until this patch series, the child
could return -1 with non-negative pid if it fails to set up
signals correctly, but we recently fixed that to make the child
call _exit() at that point instead of forcing the caller to do
it. Thus, the return value and contents of the pid argument are
now redundant (a -1 return now happens only for failure to fork,
a child 0 return only happens for a successful 0 pid, and a
parent 0 return only happens for a successful non-zero pid),
so we might as well return the pid directly rather than an
integer of whether it succeeded or failed; this is also good
from the interface design perspective as users are already
familiar with fork() semantics.
One last change in this patch: before returning the pid directly,
I found cases where using virProcessWait unconditionally on a
cleanup path of a virFork's -1 pid return would be nicer if there
were a way to avoid it overwriting an earlier message. While
such paths are a bit harder to come by with my change to a direct
pid return, I decided to keep the virProcessWait change in this
patch.
* src/util/vircommand.h (virFork): Change signature.
* src/util/vircommand.c (virFork): Guarantee that child will only
return on success, to simplify callers. Return pid rather than
status, now that the situations are always the same.
(virExec): Adjust caller, also avoid open-coding process death.
* src/util/virprocess.c (virProcessWait): Tweak semantics when pid
is -1.
(virProcessRunInMountNamespace): Adjust caller.
* src/util/virfile.c (virFileAccessibleAs, virFileOpenForked)
(virDirCreate): Likewise.
* tools/virt-login-shell.c (main): Likewise.
* tools/virsh-domain.c (cmdLxcEnterNamespace): Likewise.
* tests/commandtest.c (test23): Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-12-22 04:54:33 +04:00
if ( ( pid = virFork ( ) ) < 0 )
2014-02-20 07:04:40 +04:00
_exit ( EXIT_FAILURE ) ;
if ( pid = = 0 ) {
raise ( SIGKILL ) ;
_exit ( EXIT_FAILURE ) ;
}
2014-02-20 07:23:44 +04:00
if ( virProcessWait ( pid , & status , true ) < 0 )
2014-02-20 07:04:40 +04:00
_exit ( EXIT_FAILURE ) ;
virProcessExitWithStatus ( status ) ;
_exit ( EXIT_FAILURE ) ;
}
2014-02-20 07:23:44 +04:00
if ( virProcessWait ( pid , & status , true ) < 0 )
2019-11-12 23:46:29 +03:00
return - 1 ;
2014-02-20 07:04:40 +04:00
if ( ! WIFSIGNALED ( status ) | | WTERMSIG ( status ) ! = SIGKILL ) {
printf ( " Unexpected status %d \n " , status ) ;
2019-11-12 23:46:29 +03:00
return - 1 ;
2014-02-20 07:04:40 +04:00
}
2019-11-12 23:46:29 +03:00
return 0 ;
2014-02-20 07:04:40 +04:00
}
2019-10-14 15:45:03 +03:00
static int test25 ( const void * unused G_GNUC_UNUSED )
2016-07-11 17:03:34 +03:00
{
int ret = - 1 ;
int pipeFD [ 2 ] = { - 1 , - 1 } ;
2016-07-13 19:53:22 +03:00
int rv = 0 ;
2016-07-11 17:03:34 +03:00
ssize_t tries = 100 ;
pid_t pid ;
2017-10-09 22:14:56 +03:00
gid_t * groups = NULL ;
int ngroups ;
virCommandPtr cmd = virCommandNew ( " some/nonexistent/binary " ) ;
2016-07-11 17:03:34 +03:00
2020-01-24 18:22:12 +03:00
if ( virPipeQuiet ( pipeFD ) < 0 ) {
2016-07-11 17:03:34 +03:00
fprintf ( stderr , " Unable to create pipe \n " ) ;
goto cleanup ;
}
if ( virSetNonBlock ( pipeFD [ 0 ] ) < 0 ) {
fprintf ( stderr , " Unable to make read end of pipe nonblocking \n " ) ;
goto cleanup ;
}
2017-10-09 22:14:56 +03:00
if ( ( ngroups = virGetGroupList ( virCommandGetUID ( cmd ) , virCommandGetGID ( cmd ) ,
& groups ) ) < 0 )
goto cleanup ;
2016-07-11 17:03:34 +03:00
/* Now, fork and try to exec a nonexistent binary. */
pid = virFork ( ) ;
if ( pid < 0 ) {
fprintf ( stderr , " Unable to spawn child \n " ) ;
goto cleanup ;
}
if ( pid = = 0 ) {
/* Child */
2017-10-09 22:14:56 +03:00
rv = virCommandExec ( cmd , groups , ngroups ) ;
2017-04-09 14:28:07 +03:00
2016-07-11 17:03:34 +03:00
if ( safewrite ( pipeFD [ 1 ] , & rv , sizeof ( rv ) ) < 0 )
fprintf ( stderr , " Unable to write to pipe \n " ) ;
_exit ( EXIT_FAILURE ) ;
}
/* Parent */
while ( - - tries ) {
if ( saferead ( pipeFD [ 0 ] , & rv , sizeof ( rv ) ) < 0 ) {
if ( errno ! = EWOULDBLOCK ) {
fprintf ( stderr , " Unable to read from pipe \n " ) ;
goto cleanup ;
}
2019-10-02 20:01:11 +03:00
g_usleep ( 10 * 1000 ) ;
2016-07-11 17:03:34 +03:00
} else {
break ;
}
}
if ( ! tries ) {
fprintf ( stderr , " Child hasn't returned anything \n " ) ;
goto cleanup ;
}
if ( rv > = 0 ) {
fprintf ( stderr , " Child should have returned an error \n " ) ;
goto cleanup ;
}
ret = 0 ;
cleanup :
VIR_FORCE_CLOSE ( pipeFD [ 0 ] ) ;
VIR_FORCE_CLOSE ( pipeFD [ 1 ] ) ;
2017-10-09 22:14:56 +03:00
VIR_FREE ( groups ) ;
virCommandFree ( cmd ) ;
2016-07-11 17:03:34 +03:00
return ret ;
}
qemu: use line breaks in command line args written to log
The QEMU command line arguments are very long and currently all written
on a single line to /var/log/libvirt/qemu/$GUEST.log. This introduces
logic to add line breaks after every env variable and "-" optional
argument, and every positional argument. This will create a clearer log
file, which will in turn present better in bug reports when people cut +
paste from the log into a bug comment.
An example log file entry now looks like this:
2018-12-14 12:57:03.677+0000: starting up libvirt version: 5.0.0, qemu version: 3.0.0qemu-3.0.0-1.fc29, kernel: 4.19.5-300.fc29.x86_64, hostname: localhost.localdomain
LC_ALL=C \
PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin \
HOME=/home/berrange \
USER=berrange \
LOGNAME=berrange \
QEMU_AUDIO_DRV=none \
/usr/bin/qemu-system-ppc64 \
-name guest=guest,debug-threads=on \
-S \
-object secret,id=masterKey0,format=raw,file=/home/berrange/.config/libvirt/qemu/lib/domain-33-guest/master-key.aes \
-machine pseries-2.10,accel=tcg,usb=off,dump-guest-core=off \
-m 1024 \
-realtime mlock=off \
-smp 1,sockets=1,cores=1,threads=1 \
-uuid c8a74977-ab18-41d0-ae3b-4041c7fffbcd \
-display none \
-no-user-config \
-nodefaults \
-chardev socket,id=charmonitor,fd=23,server,nowait \
-mon chardev=charmonitor,id=monitor,mode=control \
-rtc base=utc \
-no-shutdown \
-boot strict=on \
-device qemu-xhci,id=usb,bus=pci.0,addr=0x1 \
-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x2 \
-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \
-msg timestamp=on
2018-12-14 12:57:03.730+0000: shutting down, reason=failed
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
2018-12-14 15:07:08 +03:00
/*
* Don ' t run program ; rather , log what would be run .
*/
2019-10-14 15:45:03 +03:00
static int test26 ( const void * unused G_GNUC_UNUSED )
qemu: use line breaks in command line args written to log
The QEMU command line arguments are very long and currently all written
on a single line to /var/log/libvirt/qemu/$GUEST.log. This introduces
logic to add line breaks after every env variable and "-" optional
argument, and every positional argument. This will create a clearer log
file, which will in turn present better in bug reports when people cut +
paste from the log into a bug comment.
An example log file entry now looks like this:
2018-12-14 12:57:03.677+0000: starting up libvirt version: 5.0.0, qemu version: 3.0.0qemu-3.0.0-1.fc29, kernel: 4.19.5-300.fc29.x86_64, hostname: localhost.localdomain
LC_ALL=C \
PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin \
HOME=/home/berrange \
USER=berrange \
LOGNAME=berrange \
QEMU_AUDIO_DRV=none \
/usr/bin/qemu-system-ppc64 \
-name guest=guest,debug-threads=on \
-S \
-object secret,id=masterKey0,format=raw,file=/home/berrange/.config/libvirt/qemu/lib/domain-33-guest/master-key.aes \
-machine pseries-2.10,accel=tcg,usb=off,dump-guest-core=off \
-m 1024 \
-realtime mlock=off \
-smp 1,sockets=1,cores=1,threads=1 \
-uuid c8a74977-ab18-41d0-ae3b-4041c7fffbcd \
-display none \
-no-user-config \
-nodefaults \
-chardev socket,id=charmonitor,fd=23,server,nowait \
-mon chardev=charmonitor,id=monitor,mode=control \
-rtc base=utc \
-no-shutdown \
-boot strict=on \
-device qemu-xhci,id=usb,bus=pci.0,addr=0x1 \
-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x2 \
-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \
-msg timestamp=on
2018-12-14 12:57:03.730+0000: shutting down, reason=failed
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
2018-12-14 15:07:08 +03:00
{
virCommandPtr cmd = virCommandNew ( " true " ) ;
char * outactual = NULL ;
const char * outexpect =
" A=B \\ \n "
" C='D E' \\ \n "
" true \\ \n "
" --foo bar \\ \n "
" --oooh \\ \n "
" -f \\ \n "
" --wizz 'eek eek' \\ \n "
" -w \\ \n "
" -z \\ \n "
" -l \\ \n "
" --mmm flash \\ \n "
" bang \\ \n "
" wallop " ;
int ret = - 1 ;
int fd = - 1 ;
virCommandAddEnvPair ( cmd , " A " , " B " ) ;
virCommandAddEnvPair ( cmd , " C " , " D E " ) ;
virCommandAddArgList ( cmd , " --foo " , " bar " , " --oooh " , " -f " ,
" --wizz " , " eek eek " , " -w " , " -z " , " -l " ,
" --mmm " , " flash " , " bang " , " wallop " ,
NULL ) ;
if ( ( outactual = virCommandToString ( cmd , true ) ) = = NULL ) {
printf ( " Cannot convert to string: %s \n " , virGetLastErrorMessage ( ) ) ;
goto cleanup ;
}
if ( ( fd = open ( abs_builddir " /commandhelper.log " ,
O_CREAT | O_TRUNC | O_WRONLY , 0600 ) ) < 0 ) {
2019-10-02 18:30:36 +03:00
printf ( " Cannot open log file: %s \n " , g_strerror ( errno ) ) ;
qemu: use line breaks in command line args written to log
The QEMU command line arguments are very long and currently all written
on a single line to /var/log/libvirt/qemu/$GUEST.log. This introduces
logic to add line breaks after every env variable and "-" optional
argument, and every positional argument. This will create a clearer log
file, which will in turn present better in bug reports when people cut +
paste from the log into a bug comment.
An example log file entry now looks like this:
2018-12-14 12:57:03.677+0000: starting up libvirt version: 5.0.0, qemu version: 3.0.0qemu-3.0.0-1.fc29, kernel: 4.19.5-300.fc29.x86_64, hostname: localhost.localdomain
LC_ALL=C \
PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin \
HOME=/home/berrange \
USER=berrange \
LOGNAME=berrange \
QEMU_AUDIO_DRV=none \
/usr/bin/qemu-system-ppc64 \
-name guest=guest,debug-threads=on \
-S \
-object secret,id=masterKey0,format=raw,file=/home/berrange/.config/libvirt/qemu/lib/domain-33-guest/master-key.aes \
-machine pseries-2.10,accel=tcg,usb=off,dump-guest-core=off \
-m 1024 \
-realtime mlock=off \
-smp 1,sockets=1,cores=1,threads=1 \
-uuid c8a74977-ab18-41d0-ae3b-4041c7fffbcd \
-display none \
-no-user-config \
-nodefaults \
-chardev socket,id=charmonitor,fd=23,server,nowait \
-mon chardev=charmonitor,id=monitor,mode=control \
-rtc base=utc \
-no-shutdown \
-boot strict=on \
-device qemu-xhci,id=usb,bus=pci.0,addr=0x1 \
-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x2 \
-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \
-msg timestamp=on
2018-12-14 12:57:03.730+0000: shutting down, reason=failed
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
2018-12-14 15:07:08 +03:00
goto cleanup ;
}
virCommandWriteArgLog ( cmd , fd ) ;
if ( VIR_CLOSE ( fd ) < 0 ) {
2019-10-02 18:30:36 +03:00
printf ( " Cannot close log file: %s \n " , g_strerror ( errno ) ) ;
qemu: use line breaks in command line args written to log
The QEMU command line arguments are very long and currently all written
on a single line to /var/log/libvirt/qemu/$GUEST.log. This introduces
logic to add line breaks after every env variable and "-" optional
argument, and every positional argument. This will create a clearer log
file, which will in turn present better in bug reports when people cut +
paste from the log into a bug comment.
An example log file entry now looks like this:
2018-12-14 12:57:03.677+0000: starting up libvirt version: 5.0.0, qemu version: 3.0.0qemu-3.0.0-1.fc29, kernel: 4.19.5-300.fc29.x86_64, hostname: localhost.localdomain
LC_ALL=C \
PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin \
HOME=/home/berrange \
USER=berrange \
LOGNAME=berrange \
QEMU_AUDIO_DRV=none \
/usr/bin/qemu-system-ppc64 \
-name guest=guest,debug-threads=on \
-S \
-object secret,id=masterKey0,format=raw,file=/home/berrange/.config/libvirt/qemu/lib/domain-33-guest/master-key.aes \
-machine pseries-2.10,accel=tcg,usb=off,dump-guest-core=off \
-m 1024 \
-realtime mlock=off \
-smp 1,sockets=1,cores=1,threads=1 \
-uuid c8a74977-ab18-41d0-ae3b-4041c7fffbcd \
-display none \
-no-user-config \
-nodefaults \
-chardev socket,id=charmonitor,fd=23,server,nowait \
-mon chardev=charmonitor,id=monitor,mode=control \
-rtc base=utc \
-no-shutdown \
-boot strict=on \
-device qemu-xhci,id=usb,bus=pci.0,addr=0x1 \
-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x2 \
-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \
-msg timestamp=on
2018-12-14 12:57:03.730+0000: shutting down, reason=failed
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
2018-12-14 15:07:08 +03:00
goto cleanup ;
}
if ( STRNEQ ( outactual , outexpect ) ) {
virTestDifference ( stderr , outexpect , outactual ) ;
goto cleanup ;
}
ret = checkoutput ( " test26 " , NULL ) ;
cleanup :
virCommandFree ( cmd ) ;
VIR_FORCE_CLOSE ( fd ) ;
VIR_FREE ( outactual ) ;
return ret ;
}
2019-10-14 15:45:03 +03:00
static int test27 ( const void * unused G_GNUC_UNUSED )
2019-07-25 21:22:10 +03:00
{
virCommandPtr cmd = virCommandNew ( abs_builddir " /commandhelper " ) ;
int pipe1 [ 2 ] ;
int pipe2 [ 2 ] ;
int ret = - 1 ;
size_t buflen = 1024 * 128 ;
char * buffer0 = NULL ;
char * buffer1 = NULL ;
char * buffer2 = NULL ;
char * outactual = NULL ;
char * erractual = NULL ;
char * outexpect = NULL ;
# define TEST27_OUTEXPECT_TEMP "BEGIN STDOUT\n" \
" %s%s%s " \
" END STDOUT \n "
char * errexpect = NULL ;
# define TEST27_ERREXPECT_TEMP "BEGIN STDERR\n" \
" %s%s%s " \
" END STDERR \n "
if ( VIR_ALLOC_N ( buffer0 , buflen ) < 0 | |
VIR_ALLOC_N ( buffer1 , buflen ) < 0 | |
VIR_ALLOC_N ( buffer2 , buflen ) < 0 )
goto cleanup ;
memset ( buffer0 , ' H ' , buflen - 2 ) ;
buffer0 [ buflen - 2 ] = ' \n ' ;
buffer0 [ buflen - 1 ] = 0 ;
memset ( buffer1 , ' 1 ' , buflen - 2 ) ;
buffer1 [ buflen - 2 ] = ' \n ' ;
buffer1 [ buflen - 1 ] = 0 ;
memset ( buffer2 , ' 2 ' , buflen - 2 ) ;
buffer2 [ buflen - 2 ] = ' \n ' ;
buffer2 [ buflen - 1 ] = 0 ;
2019-10-22 16:26:14 +03:00
outexpect = g_strdup_printf ( TEST27_OUTEXPECT_TEMP ,
buffer0 , buffer1 , buffer2 ) ;
errexpect = g_strdup_printf ( TEST27_ERREXPECT_TEMP ,
buffer0 , buffer1 , buffer2 ) ;
2019-07-25 21:22:10 +03:00
2020-01-24 18:22:12 +03:00
if ( virPipeQuiet ( pipe1 ) < 0 | | virPipeQuiet ( pipe2 ) < 0 ) {
2019-10-02 18:30:36 +03:00
printf ( " Could not create pipe: %s \n " , g_strerror ( errno ) ) ;
2019-07-25 21:22:10 +03:00
goto cleanup ;
}
if ( virCommandSetSendBuffer ( cmd , pipe1 [ 1 ] ,
( unsigned char * ) buffer1 , buflen - 1 ) < 0 | |
virCommandSetSendBuffer ( cmd , pipe2 [ 1 ] ,
( unsigned char * ) buffer2 , buflen - 1 ) < 0 ) {
printf ( " Could not set send buffers \n " ) ;
goto cleanup ;
}
pipe1 [ 1 ] = 0 ;
pipe2 [ 1 ] = 0 ;
buffer1 = NULL ;
buffer2 = NULL ;
virCommandAddArg ( cmd , " --readfd " ) ;
virCommandAddArgFormat ( cmd , " %d " , pipe1 [ 0 ] ) ;
virCommandPassFD ( cmd , pipe1 [ 0 ] , 0 ) ;
virCommandAddArg ( cmd , " --readfd " ) ;
virCommandAddArgFormat ( cmd , " %d " , pipe2 [ 0 ] ) ;
virCommandPassFD ( cmd , pipe2 [ 0 ] , 0 ) ;
virCommandSetInputBuffer ( cmd , buffer0 ) ;
virCommandSetOutputBuffer ( cmd , & outactual ) ;
virCommandSetErrorBuffer ( cmd , & erractual ) ;
if ( virCommandRun ( cmd , NULL ) < 0 ) {
printf ( " Cannot run child %s \n " , virGetLastErrorMessage ( ) ) ;
goto cleanup ;
}
if ( ! outactual | | ! erractual )
goto cleanup ;
if ( STRNEQ ( outactual , outexpect ) ) {
virTestDifference ( stderr , outexpect , outactual ) ;
goto cleanup ;
}
if ( STRNEQ ( erractual , errexpect ) ) {
virTestDifference ( stderr , errexpect , erractual ) ;
goto cleanup ;
}
2019-07-29 17:11:29 +03:00
if ( checkoutput ( " test27 " , NULL ) < 0 )
goto cleanup ;
2019-07-25 21:22:10 +03:00
ret = 0 ;
cleanup :
2019-07-26 23:56:31 +03:00
virCommandFree ( cmd ) ;
2019-07-25 21:22:10 +03:00
VIR_FORCE_CLOSE ( pipe1 [ 0 ] ) ;
VIR_FORCE_CLOSE ( pipe2 [ 0 ] ) ;
VIR_FORCE_CLOSE ( pipe1 [ 1 ] ) ;
VIR_FORCE_CLOSE ( pipe2 [ 1 ] ) ;
VIR_FREE ( buffer0 ) ;
VIR_FREE ( buffer1 ) ;
VIR_FREE ( buffer2 ) ;
VIR_FREE ( outactual ) ;
VIR_FREE ( erractual ) ;
VIR_FREE ( outexpect ) ;
VIR_FREE ( errexpect ) ;
return ret ;
}
2013-01-16 14:58:00 +04:00
2020-03-18 14:59:08 +03:00
static int
test28Callback ( pid_t pid G_GNUC_UNUSED ,
void * opaque G_GNUC_UNUSED )
{
virReportSystemError ( ENODATA , " %s " , " some error message " ) ;
return - 1 ;
}
static int
test28 ( const void * unused G_GNUC_UNUSED )
{
/* Not strictly a virCommand test, but this is the easiest place
* to test this lower - level interface . */
virErrorPtr err ;
2020-03-24 15:48:58 +03:00
g_autofree char * msg = g_strdup_printf ( " some error message: %s " , g_strerror ( ENODATA ) ) ;
2020-03-18 14:59:08 +03:00
if ( virProcessRunInFork ( test28Callback , NULL ) ! = - 1 ) {
fprintf ( stderr , " virProcessRunInFork did not fail \n " ) ;
return - 1 ;
}
if ( ! ( err = virGetLastError ( ) ) ) {
fprintf ( stderr , " Expected error but got nothing \n " ) ;
return - 1 ;
}
if ( ! ( err - > code = = VIR_ERR_SYSTEM_ERROR & &
err - > domain = = 0 & &
2020-03-24 15:48:58 +03:00
STREQ ( err - > message , msg ) & &
2020-03-18 14:59:08 +03:00
err - > level = = VIR_ERR_ERROR & &
STREQ ( err - > str1 , " %s " ) & &
2020-03-24 15:48:58 +03:00
STREQ ( err - > str2 , msg ) & &
2020-03-18 14:59:08 +03:00
err - > int1 = = ENODATA & &
err - > int2 = = - 1 ) ) {
fprintf ( stderr , " Unexpected error object \n " ) ;
return - 1 ;
}
return 0 ;
}
2010-05-25 15:14:06 +04:00
static int
2011-04-29 20:21:20 +04:00
mymain ( void )
2010-05-25 15:14:06 +04:00
{
int ret = 0 ;
2011-01-29 00:22:39 +03:00
int fd ;
2013-01-14 19:35:45 +04:00
int virinitret ;
2013-01-16 14:58:00 +04:00
2010-05-25 15:14:06 +04:00
if ( chdir ( " /tmp " ) < 0 )
2012-03-22 15:33:35 +04:00
return EXIT_FAILURE ;
2010-05-25 15:14:06 +04:00
2014-09-03 19:13:21 +04:00
umask ( 022 ) ;
2011-02-24 15:12:27 +03:00
setpgid ( 0 , 0 ) ;
2012-04-28 01:25:35 +04:00
ignore_value ( setsid ( ) ) ;
2011-02-24 15:12:27 +03:00
2012-01-07 01:07:23 +04:00
/* Our test expects particular fd values; to get that, we must not
* leak fds that we inherited from a lazy parent . At the same
* time , virInitialize may open some fds ( perhaps via third - party
* libraries that it uses ) , and we must not kill off an fd that
* this process opens as it might break expectations of a
* pthread_atfork handler , as well as interfering with our tests
* trying to ensure we aren ' t leaking to our children . The
* solution is to do things in two phases - reserve the fds we
* want by overwriting any externally inherited fds , then
* initialize , then clear the slots for testing . */
if ( ( fd = open ( " /dev/null " , O_RDONLY ) ) < 0 | |
dup2 ( fd , 3 ) < 0 | |
dup2 ( fd , 4 ) < 0 | |
dup2 ( fd , 5 ) < 0 | |
2013-02-05 20:15:20 +04:00
dup2 ( fd , 6 ) < 0 | |
dup2 ( fd , 7 ) < 0 | |
dup2 ( fd , 8 ) < 0 | |
2013-01-14 19:35:45 +04:00
( fd > 8 & & VIR_CLOSE ( fd ) < 0 ) ) {
VIR_FORCE_CLOSE ( fd ) ;
2012-01-07 01:07:23 +04:00
return EXIT_FAILURE ;
2013-01-14 19:35:45 +04:00
}
2011-08-25 15:05:54 +04:00
/* Prime the debug/verbose settings from the env vars,
* since we ' re about to reset ' environ ' */
2012-04-28 01:25:35 +04:00
ignore_value ( virTestGetDebug ( ) ) ;
ignore_value ( virTestGetVerbose ( ) ) ;
2011-08-25 15:05:54 +04:00
2013-01-14 19:35:45 +04:00
/* Make sure to not leak fd's */
virinitret = virInitialize ( ) ;
2012-01-07 01:07:23 +04:00
/* Phase two of killing interfering fds; see above. */
2013-01-14 19:35:45 +04:00
/* coverity[overwrite_var] - silence the obvious */
2011-01-29 00:22:39 +03:00
fd = 3 ;
VIR_FORCE_CLOSE ( fd ) ;
fd = 4 ;
VIR_FORCE_CLOSE ( fd ) ;
fd = 5 ;
VIR_FORCE_CLOSE ( fd ) ;
2013-02-05 20:15:20 +04:00
fd = 6 ;
VIR_FORCE_CLOSE ( fd ) ;
fd = 7 ;
VIR_FORCE_CLOSE ( fd ) ;
fd = 8 ;
VIR_FORCE_CLOSE ( fd ) ;
2010-12-11 01:30:56 +03:00
2013-01-14 19:35:45 +04:00
if ( virinitret < 0 )
return EXIT_FAILURE ;
2010-05-25 15:14:06 +04:00
environ = ( char * * ) newenv ;
2017-11-03 15:09:47 +03:00
# define DO_TEST(NAME) \
if ( virTestRun ( " Command Exec " # NAME " test " , \
NAME , NULL ) < 0 ) \
2010-05-25 15:14:06 +04:00
ret = - 1
DO_TEST ( test0 ) ;
DO_TEST ( test1 ) ;
DO_TEST ( test2 ) ;
DO_TEST ( test3 ) ;
DO_TEST ( test4 ) ;
DO_TEST ( test5 ) ;
DO_TEST ( test6 ) ;
DO_TEST ( test7 ) ;
DO_TEST ( test8 ) ;
DO_TEST ( test9 ) ;
DO_TEST ( test10 ) ;
DO_TEST ( test11 ) ;
DO_TEST ( test12 ) ;
DO_TEST ( test13 ) ;
DO_TEST ( test14 ) ;
DO_TEST ( test15 ) ;
DO_TEST ( test16 ) ;
2010-12-04 00:14:16 +03:00
DO_TEST ( test17 ) ;
2010-12-21 21:49:49 +03:00
DO_TEST ( test18 ) ;
2011-03-23 01:22:37 +03:00
DO_TEST ( test19 ) ;
2012-06-01 01:50:07 +04:00
DO_TEST ( test20 ) ;
2013-01-16 21:55:06 +04:00
DO_TEST ( test21 ) ;
2014-02-19 05:06:50 +04:00
DO_TEST ( test22 ) ;
2014-02-20 07:04:40 +04:00
DO_TEST ( test23 ) ;
2016-07-11 17:03:34 +03:00
DO_TEST ( test25 ) ;
qemu: use line breaks in command line args written to log
The QEMU command line arguments are very long and currently all written
on a single line to /var/log/libvirt/qemu/$GUEST.log. This introduces
logic to add line breaks after every env variable and "-" optional
argument, and every positional argument. This will create a clearer log
file, which will in turn present better in bug reports when people cut +
paste from the log into a bug comment.
An example log file entry now looks like this:
2018-12-14 12:57:03.677+0000: starting up libvirt version: 5.0.0, qemu version: 3.0.0qemu-3.0.0-1.fc29, kernel: 4.19.5-300.fc29.x86_64, hostname: localhost.localdomain
LC_ALL=C \
PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin \
HOME=/home/berrange \
USER=berrange \
LOGNAME=berrange \
QEMU_AUDIO_DRV=none \
/usr/bin/qemu-system-ppc64 \
-name guest=guest,debug-threads=on \
-S \
-object secret,id=masterKey0,format=raw,file=/home/berrange/.config/libvirt/qemu/lib/domain-33-guest/master-key.aes \
-machine pseries-2.10,accel=tcg,usb=off,dump-guest-core=off \
-m 1024 \
-realtime mlock=off \
-smp 1,sockets=1,cores=1,threads=1 \
-uuid c8a74977-ab18-41d0-ae3b-4041c7fffbcd \
-display none \
-no-user-config \
-nodefaults \
-chardev socket,id=charmonitor,fd=23,server,nowait \
-mon chardev=charmonitor,id=monitor,mode=control \
-rtc base=utc \
-no-shutdown \
-boot strict=on \
-device qemu-xhci,id=usb,bus=pci.0,addr=0x1 \
-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x2 \
-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \
-msg timestamp=on
2018-12-14 12:57:03.730+0000: shutting down, reason=failed
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
2018-12-14 15:07:08 +03:00
DO_TEST ( test26 ) ;
2019-07-25 21:22:10 +03:00
DO_TEST ( test27 ) ;
2020-03-18 14:59:08 +03:00
DO_TEST ( test28 ) ;
2010-05-25 15:14:06 +04:00
2014-03-17 13:38:38 +04:00
return ret = = 0 ? EXIT_SUCCESS : EXIT_FAILURE ;
2010-05-25 15:14:06 +04:00
}
2017-03-29 17:45:42 +03:00
VIR_TEST_MAIN ( mymain )
2011-07-28 19:48:12 +04:00
# endif /* !WIN32 */