@ -1545,6 +1545,65 @@ out:
return ret ;
}
static void pmutils_suspend ( int suspend_mode , Error * * errp )
{
Error * local_err = NULL ;
const char * pmutils_bin ;
char * pmutils_path ;
pid_t pid ;
int status ;
switch ( suspend_mode ) {
case SUSPEND_MODE_DISK :
pmutils_bin = " pm-hibernate " ;
break ;
case SUSPEND_MODE_RAM :
pmutils_bin = " pm-suspend " ;
break ;
case SUSPEND_MODE_HYBRID :
pmutils_bin = " pm-suspend-hybrid " ;
break ;
default :
error_setg ( errp , " unknown guest suspend mode " ) ;
return ;
}
pmutils_path = g_find_program_in_path ( pmutils_bin ) ;
if ( ! pmutils_path ) {
error_setg ( errp , " the helper program '%s' was not found " , pmutils_bin ) ;
return ;
}
pid = fork ( ) ;
if ( ! pid ) {
setsid ( ) ;
execle ( pmutils_path , pmutils_bin , NULL , environ ) ;
/*
* If we get here execle ( ) has failed .
*/
_exit ( EXIT_FAILURE ) ;
} else if ( pid < 0 ) {
error_setg_errno ( errp , errno , " failed to create child process " ) ;
goto out ;
}
ga_wait_child ( pid , & status , & local_err ) ;
if ( local_err ) {
error_propagate ( errp , local_err ) ;
goto out ;
}
if ( WEXITSTATUS ( status ) ) {
error_setg ( errp ,
" the helper program '%s' returned an unexpected exit status "
" code (%d) " , pmutils_path , WEXITSTATUS ( status ) ) ;
}
out :
g_free ( pmutils_path ) ;
}
static bool linux_sys_state_supports_mode ( int suspend_mode , Error * * errp )
{
const char * sysfile_str ;
@ -1581,64 +1640,28 @@ static bool linux_sys_state_supports_mode(int suspend_mode, Error **errp)
return false ;
}
static void bios_supports_mode ( int suspend_mode , Error * * errp )
{
Error * local_err = NULL ;
bool ret ;
ret = pmutils_supports_mode ( suspend_mode , & local_err ) ;
if ( ret ) {
return ;
}
if ( local_err ) {
error_propagate ( errp , local_err ) ;
return ;
}
ret = linux_sys_state_supports_mode ( suspend_mode , errp ) ;
if ( ! ret ) {
error_setg ( errp ,
" the requested suspend mode is not supported by the guest " ) ;
return ;
}
}
static void guest_suspend ( int suspend_mode , Error * * errp )
static void linux_sys_state_suspend ( int suspend_mode , Error * * errp )
{
Error * local_err = NULL ;
const char * pmutils_bin , * sysfile_str ;
char * pmutils_path ;
const char * sysfile_str ;
pid_t pid ;
int status ;
bios_supports_mode ( suspend_mode , & local_err ) ;
if ( local_err ) {
error_propagate ( errp , local_err ) ;
return ;
}
switch ( suspend_mode ) {
case SUSPEND_MODE_DISK :
pmutils_bin = " pm-hibernate " ;
sysfile_str = " disk " ;
break ;
case SUSPEND_MODE_RAM :
pmutils_bin = " pm-suspend " ;
sysfile_str = " mem " ;
break ;
case SUSPEND_MODE_HYBRID :
pmutils_bin = " pm-suspend-hybrid " ;
sysfile_str = NULL ;
break ;
default :
error_setg ( errp , " unknown guest suspend mode " ) ;
return ;
}
pmutils_path = g_find_program_in_path ( pmutils_bin ) ;
pid = fork ( ) ;
if ( pid = = 0 ) {
if ( ! pid ) {
/* child */
int fd ;
@ -1647,19 +1670,6 @@ static void guest_suspend(int suspend_mode, Error **errp)
reopen_fd_to_null ( 1 ) ;
reopen_fd_to_null ( 2 ) ;
if ( pmutils_path ) {
execle ( pmutils_path , pmutils_bin , NULL , environ ) ;
}
/*
* If we get here either pm - utils is not installed or execle ( ) has
* failed . Let ' s try the manual method if the caller wants it .
*/
if ( ! sysfile_str ) {
_exit ( EXIT_FAILURE ) ;
}
fd = open ( LINUX_SYS_STATE_FILE , O_WRONLY ) ;
if ( fd < 0 ) {
_exit ( EXIT_FAILURE ) ;
@ -1672,27 +1682,63 @@ static void guest_suspend(int suspend_mode, Error **errp)
_exit ( EXIT_SUCCESS ) ;
} else if ( pid < 0 ) {
error_setg_errno ( errp , errno , " failed to create child process " ) ;
goto out ;
return ;
}
ga_wait_child ( pid , & status , & local_err ) ;
if ( local_err ) {
error_propagate ( errp , local_err ) ;
goto out ;
}
if ( ! WIFEXITED ( status ) ) {
error_setg ( errp , " child process has terminated abnormally " ) ;
goto out ;
return ;
}
if ( WEXITSTATUS ( status ) ) {
error_setg ( errp , " child process has failed to suspend " ) ;
goto out ;
}
out :
g_free ( pmutils_path ) ;
}
static void bios_supports_mode ( int suspend_mode , Error * * errp )
{
Error * local_err = NULL ;
bool ret ;
ret = pmutils_supports_mode ( suspend_mode , & local_err ) ;
if ( ret ) {
return ;
}
if ( local_err ) {
error_propagate ( errp , local_err ) ;
return ;
}
ret = linux_sys_state_supports_mode ( suspend_mode , errp ) ;
if ( ! ret ) {
error_setg ( errp ,
" the requested suspend mode is not supported by the guest " ) ;
return ;
}
}
static void guest_suspend ( int suspend_mode , Error * * errp )
{
Error * local_err = NULL ;
bios_supports_mode ( suspend_mode , & local_err ) ;
if ( local_err ) {
error_propagate ( errp , local_err ) ;
return ;
}
pmutils_suspend ( suspend_mode , & local_err ) ;
if ( ! local_err ) {
return ;
}
error_free ( local_err ) ;
linux_sys_state_suspend ( suspend_mode , & local_err ) ;
if ( local_err ) {
error_propagate ( errp , local_err ) ;
}
}
void qmp_guest_suspend_disk ( Error * * errp )