Implement shell style exit status decoding (#754684)
Command exit status is a 1 byte value between 0 and 255. [1][2] However at the Unix API level the value is encoded as documented in the waitpid(2) manual page. This is true for the Glib API too. [3] This is why, for example, the comment in ext2::check_repair() reported receiving undocumented exit status 256. It was actually receiving exit status 1 encoded as per the waitpid(2) method. Add shell style exit status decoding [2] to execution of all external commands. Return value from Utils::execute_command() and FileSystem::execute_command() functions are now: 0 - 125 - Exit status from the command 126 - Error executing the command 127 - Command not found 128+N - Command terminated by signal N 255 - Unexpected waitpid(2) condition Also adjust checking of the returned statuses as necessary. [1] Advanced Bash-Scripting Guide: Appendix D. Exit Codes With Special Meanings http://www.linuxtopia.org/online_books/advanced_bash_scripting_guide/exitcodes.html [2] Quote from the bash(1) manual page: EXIT STATUS ... Exit statuses fall between 0 and 255, though as explained below, the shell may use values above 125 specially. ... ... When a command terminates on a fatal signal N, bash uses the value of 128+N as the exit status. If a command is not found, the child process created to execute it returns a status of 127. If a command is found but is not executable, the return status is 126. [3] Quote from the Glib Reference Manual, Spawning Processes section, for function g_spawn_check_exit_status(): https://developer.gnome.org/glib/stable/glib-Spawning-Processes.html#g-spawn-check-exit-status The g_spawn_sync() and g_child_watch_add() family of APIs return an exit status for subprocesses encoded in a platform-specific way. On Unix, this is guaranteed to be in the same format waitpid() returns, ... Bug 754684 - Updates to FileSystem:: and Utils::execute_command() functions
This commit is contained in:
parent
a202b4569a
commit
2b57229fc2
|
@ -190,6 +190,8 @@ public:
|
||||||
Glib::ustring & output,
|
Glib::ustring & output,
|
||||||
Glib::ustring & error,
|
Glib::ustring & error,
|
||||||
bool use_C_locale = false ) ;
|
bool use_C_locale = false ) ;
|
||||||
|
static int get_failure_status( Glib::SpawnError & e );
|
||||||
|
static int decode_wait_status( int wait_status );
|
||||||
static Glib::ustring regexp_label( const Glib::ustring & text
|
static Glib::ustring regexp_label( const Glib::ustring & text
|
||||||
, const Glib::ustring & pattern
|
, const Glib::ustring & pattern
|
||||||
) ;
|
) ;
|
||||||
|
|
|
@ -54,7 +54,7 @@ const Glib::ustring FileSystem::get_generic_text( CUSTOM_TEXT ttype, int index )
|
||||||
|
|
||||||
void FileSystem::store_exit_status( GPid pid, int status )
|
void FileSystem::store_exit_status( GPid pid, int status )
|
||||||
{
|
{
|
||||||
exit_status = status;
|
exit_status = Utils::decode_wait_status( status );
|
||||||
running = false;
|
running = false;
|
||||||
if (pipecount == 0) // pipes finished first
|
if (pipecount == 0) // pipes finished first
|
||||||
Gtk::Main::quit();
|
Gtk::Main::quit();
|
||||||
|
@ -102,7 +102,7 @@ int FileSystem::execute_command( const Glib::ustring & command, OperationDetail
|
||||||
std::cerr << e.what() << std::endl;
|
std::cerr << e.what() << std::endl;
|
||||||
operationdetail.get_last_child().add_child(
|
operationdetail.get_last_child().add_child(
|
||||||
OperationDetail( e.what(), STATUS_ERROR, FONT_ITALIC ) );
|
OperationDetail( e.what(), STATUS_ERROR, FONT_ITALIC ) );
|
||||||
return 1;
|
return Utils::get_failure_status( e );
|
||||||
}
|
}
|
||||||
fcntl( out, F_SETFL, O_NONBLOCK );
|
fcntl( out, F_SETFL, O_NONBLOCK );
|
||||||
fcntl( err, F_SETFL, O_NONBLOCK );
|
fcntl( err, F_SETFL, O_NONBLOCK );
|
||||||
|
|
34
src/Utils.cc
34
src/Utils.cc
|
@ -33,6 +33,8 @@
|
||||||
#include <sys/statvfs.h>
|
#include <sys/statvfs.h>
|
||||||
#include <gtkmm/main.h>
|
#include <gtkmm/main.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
namespace GParted
|
namespace GParted
|
||||||
{
|
{
|
||||||
|
@ -529,7 +531,7 @@ public:
|
||||||
|
|
||||||
void CommandStatus::store_exit_status( GPid pid, int status )
|
void CommandStatus::store_exit_status( GPid pid, int status )
|
||||||
{
|
{
|
||||||
exit_status = status;
|
exit_status = Utils::decode_wait_status( status );
|
||||||
running = false;
|
running = false;
|
||||||
if (pipecount == 0) // pipes finished first
|
if (pipecount == 0) // pipes finished first
|
||||||
{
|
{
|
||||||
|
@ -596,7 +598,7 @@ int Utils::execute_command( const Glib::ustring & command,
|
||||||
&err );
|
&err );
|
||||||
} catch (Glib::SpawnError &e) {
|
} catch (Glib::SpawnError &e) {
|
||||||
std::cerr << e.what() << std::endl;
|
std::cerr << e.what() << std::endl;
|
||||||
return 1;
|
return Utils::get_failure_status( e );
|
||||||
}
|
}
|
||||||
fcntl( out, F_SETFL, O_NONBLOCK );
|
fcntl( out, F_SETFL, O_NONBLOCK );
|
||||||
fcntl( err, F_SETFL, O_NONBLOCK );
|
fcntl( err, F_SETFL, O_NONBLOCK );
|
||||||
|
@ -625,6 +627,34 @@ int Utils::execute_command( const Glib::ustring & command,
|
||||||
return status.exit_status;
|
return status.exit_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return shell style exit status when failing to execute a command. 127 for command not
|
||||||
|
// found and 126 otherwise.
|
||||||
|
// NOTE:
|
||||||
|
// Together get_failure_status() and decode_wait_status() provide complete shell style
|
||||||
|
// exit status handling. See bash(1) manual page, EXIT STATUS section for details.
|
||||||
|
int Utils::get_failure_status( Glib::SpawnError & e )
|
||||||
|
{
|
||||||
|
if ( e.code() == Glib::SpawnError::NOENT )
|
||||||
|
return 127;
|
||||||
|
return 126;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return shell style decoding of waitpid(2) encoded exit statuses. Return command exit
|
||||||
|
// status or 128 + signal number when terminated by a signal.
|
||||||
|
int Utils::decode_wait_status( int wait_status )
|
||||||
|
{
|
||||||
|
if ( WIFEXITED( wait_status ) )
|
||||||
|
return WEXITSTATUS( wait_status );
|
||||||
|
else if ( WIFSIGNALED( wait_status ) )
|
||||||
|
return 128 + WTERMSIG( wait_status );
|
||||||
|
|
||||||
|
// Other cases of WIFSTOPPED() and WIFCONTINUED() occur when the process is
|
||||||
|
// stopped or resumed by signals. Should be impossible as this function is only
|
||||||
|
// called after the process has exited.
|
||||||
|
std::cerr << "Unexpected wait status " << wait_status << std::endl;
|
||||||
|
return 255;
|
||||||
|
}
|
||||||
|
|
||||||
Glib::ustring Utils::regexp_label( const Glib::ustring & text
|
Glib::ustring Utils::regexp_label( const Glib::ustring & text
|
||||||
, const Glib::ustring & pattern
|
, const Glib::ustring & pattern
|
||||||
)
|
)
|
||||||
|
|
|
@ -356,8 +356,8 @@ bool btrfs::resize( const Partition & partition_new, OperationDetail & operation
|
||||||
// but not ignoring them will cause resizing to the
|
// but not ignoring them will cause resizing to the
|
||||||
// same size as part of check operation to fail.
|
// same size as part of check operation to fail.
|
||||||
resize_succeeded = ( exit_status == 0
|
resize_succeeded = ( exit_status == 0
|
||||||
|| ( btrfs_found && exit_status == 30<<8 )
|
|| ( btrfs_found && exit_status == 30 )
|
||||||
|| ( ! btrfs_found && exit_status == 1<<8 )
|
|| ( ! btrfs_found && exit_status == 1 )
|
||||||
) ;
|
) ;
|
||||||
}
|
}
|
||||||
set_status( operationdetail, resize_succeeded );
|
set_status( operationdetail, resize_succeeded );
|
||||||
|
|
|
@ -240,10 +240,7 @@ bool ext2::check_repair( const Partition & partition, OperationDetail & operatio
|
||||||
{
|
{
|
||||||
exit_status = execute_command( fsck_cmd + " -f -y -v -C 0 " + partition.get_path(), operationdetail,
|
exit_status = execute_command( fsck_cmd + " -f -y -v -C 0 " + partition.get_path(), operationdetail,
|
||||||
EXEC_CANCEL_SAFE );
|
EXEC_CANCEL_SAFE );
|
||||||
|
bool success = ( exit_status == 0 || exit_status == 1 || exit_status == 2 );
|
||||||
//exitstatus 256 isn't documented, but it's returned when the 'FILE SYSTEM IS MODIFIED'
|
|
||||||
//this is quite normal (especially after a copy) so we let the function return true...
|
|
||||||
bool success = ( exit_status == 0 || exit_status == 1 || exit_status == 2 || exit_status == 256 );
|
|
||||||
set_status( operationdetail, success );
|
set_status( operationdetail, success );
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,7 +128,7 @@ FS fat16::get_filesystem_support()
|
||||||
void fat16::set_used_sectors( Partition & partition )
|
void fat16::set_used_sectors( Partition & partition )
|
||||||
{
|
{
|
||||||
exit_status = Utils::execute_command( check_cmd + " -n -v " + partition .get_path(), output, error, true ) ;
|
exit_status = Utils::execute_command( check_cmd + " -n -v " + partition .get_path(), output, error, true ) ;
|
||||||
if ( exit_status == 0 || exit_status == 1 || exit_status == 256 )
|
if ( exit_status == 0 || exit_status == 1 )
|
||||||
{
|
{
|
||||||
//total file system size in logical sectors
|
//total file system size in logical sectors
|
||||||
index = output .rfind( "\n", output .find( "sectors total" ) ) +1 ;
|
index = output .rfind( "\n", output .find( "sectors total" ) ) +1 ;
|
||||||
|
@ -239,7 +239,7 @@ bool fat16::check_repair( const Partition & partition, OperationDetail & operati
|
||||||
{
|
{
|
||||||
exit_status = execute_command( check_cmd + " -a -w -v " + partition .get_path(), operationdetail,
|
exit_status = execute_command( check_cmd + " -a -w -v " + partition .get_path(), operationdetail,
|
||||||
EXEC_CANCEL_SAFE );
|
EXEC_CANCEL_SAFE );
|
||||||
bool success = ( exit_status == 0 || exit_status == 1 || exit_status == 256 );
|
bool success = ( exit_status == 0 || exit_status == 1 );
|
||||||
set_status( operationdetail, success );
|
set_status( operationdetail, success );
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,7 +121,7 @@ void ntfs::set_used_sectors( Partition & partition )
|
||||||
{
|
{
|
||||||
exit_status = Utils::execute_command(
|
exit_status = Utils::execute_command(
|
||||||
"ntfsresize --info --force --no-progress-bar " + partition .get_path(), output, error, true ) ;
|
"ntfsresize --info --force --no-progress-bar " + partition .get_path(), output, error, true ) ;
|
||||||
if ( exit_status == 0 || exit_status == 1<<8 )
|
if ( exit_status == 0 || exit_status == 1 )
|
||||||
{
|
{
|
||||||
index = output .find( "Current volume size:" ) ;
|
index = output .find( "Current volume size:" ) ;
|
||||||
if ( index >= output .length() ||
|
if ( index >= output .length() ||
|
||||||
|
|
|
@ -176,7 +176,12 @@ bool reiserfs::resize( const Partition & partition_new, OperationDetail & operat
|
||||||
Glib::ustring cmd = "sh -c 'echo y | resize_reiserfs" + size + " " + partition_new .get_path() + "'" ;
|
Glib::ustring cmd = "sh -c 'echo y | resize_reiserfs" + size + " " + partition_new .get_path() + "'" ;
|
||||||
|
|
||||||
exit_status = execute_command( cmd, operationdetail ) ;
|
exit_status = execute_command( cmd, operationdetail ) ;
|
||||||
bool success = ( exit_status == 0 || exit_status == 256 );
|
// NOTE: Neither resize_reiserfs manual page nor the following commit, which first
|
||||||
|
// added this check, indicate why exit status 1 also indicates success. Commit
|
||||||
|
// from 2006-05-23:
|
||||||
|
// 7bb7e8a84f164cd913384509a6adc3739a9d8b78
|
||||||
|
// Use ped_device_read and ped_device_write instead of 'dd' to copy
|
||||||
|
bool success = ( exit_status == 0 || exit_status == 1 );
|
||||||
set_status( operationdetail, success );
|
set_status( operationdetail, success );
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
@ -185,7 +190,7 @@ bool reiserfs::check_repair( const Partition & partition, OperationDetail & oper
|
||||||
{
|
{
|
||||||
exit_status = execute_command( "reiserfsck --yes --fix-fixable --quiet " + partition.get_path(),
|
exit_status = execute_command( "reiserfsck --yes --fix-fixable --quiet " + partition.get_path(),
|
||||||
operationdetail, EXEC_CANCEL_SAFE );
|
operationdetail, EXEC_CANCEL_SAFE );
|
||||||
bool success = ( exit_status == 0 || exit_status == 1 || exit_status == 256 );
|
bool success = ( exit_status == 0 || exit_status == 1 );
|
||||||
set_status( operationdetail, success );
|
set_status( operationdetail, success );
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue