gparted/src/FileSystem.cc

266 lines
9.7 KiB
C++
Raw Normal View History

/* Copyright (C) 2004 Bart
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "../include/FileSystem.h"
#include "../include/GParted_Core.h"
#include <cerrno>
#include <iostream>
#include <gtkmm/main.h>
#include <signal.h>
#include <fcntl.h>
#include <sigc++/slot.h>
namespace GParted
{
FileSystem::FileSystem()
{
}
const Glib::ustring FileSystem::get_custom_text( CUSTOM_TEXT ttype, int index ) const
{
return get_generic_text( ttype, index ) ;
}
const Glib::ustring FileSystem::get_generic_text( CUSTOM_TEXT ttype, int index )
{
/*TO TRANSLATORS: these labels will be used in the partition menu */
static const Glib::ustring activate_text = _( "_Mount" ) ;
static const Glib::ustring deactivate_text = _( "_Unmount" ) ;
switch ( ttype ) {
case CTEXT_ACTIVATE_FILESYSTEM :
return index == 0 ? activate_text : "" ;
case CTEXT_DEACTIVATE_FILESYSTEM :
return index == 0 ? deactivate_text : "" ;
default :
return "" ;
}
}
void FileSystem::store_exit_status( GPid pid, int status )
{
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
2015-09-06 07:39:07 -06:00
exit_status = Utils::decode_wait_status( status );
running = false;
if (pipecount == 0) // pipes finished first
Gtk::Main::quit();
Glib::spawn_close_pid( pid );
}
//Callback passing the latest partial output from the external command
// to operation detail for updating in the UI
static void update_command_output( OperationDetail *operationdetail, Glib::ustring *str )
{
operationdetail->set_description( *str, FONT_ITALIC );
}
static void cancel_command( bool force, Glib::Pid pid, bool cancel_safe )
{
if( force || cancel_safe )
kill( -pid, SIGINT );
}
static void setup_child()
{
setpgrp();
}
int FileSystem::execute_command( const Glib::ustring & command, OperationDetail & operationdetail,
Connect timed progress tracking callbacks inside execute_command() (#760709) The timed progress tracking callback for execution of xfs copy follows this pattern: sigc::connection c; ... c = Glib::signal_timeout().connect( ... sigc::mem_fun( *this, &xfs::copy_progress ) ..., 500 /*ms*/ ); ... execute_command( ... ); c.disconnect(); As with output progress tracking callbacks for ext2/3/4 and ntfs file system specific commands, pass the callback slot and a flag into execute_command() and connect the timed callback inside. This simplified the pattern to: ... execute_command( ...|EXEC_PROGRESS_TIMED, static_cast<TimedSlot>( sigc::mem_fun( *this, &xfs::copy_progress ) ) ); NOTE: The type of sigc::mem_fun() doesn't allow the compiler to choose between the two overloaded variants of execute_command() with the fourth parameter of either (full types without typedefs of StreamSlot and TimedSlot respectively): sigc::slot<void, OperationDetail *> stream_progress_slot sigc::slot<bool, OperationDetail *> timed_progress_slot Therefore have to cast the result of all callback slots to the relevant type. Hence: static_cast<StreamSlot>( sigc::mem_fun( *this, &{CLASS}::{NAME}_progress ) ) static_cast<TimedSlot>( sigc::mem_fun( *this, &xfs::copy_progress ) ) References: * [sigc] Functor not resolving between overloaded methods with different slot types https://mail.gnome.org/archives/libsigc-list/2016-February/msg00000.html * Bug 306705 - Can't overload methods based on different slot<> parameters. https://bugzilla.gnome.org/show_bug.cgi?id=306705 Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific copy methods
2016-02-03 14:17:30 -07:00
ExecFlags flags )
{
StreamSlot empty_stream_slot;
TimedSlot empty_timed_slot;
return execute_command_internal( command, operationdetail, flags, empty_stream_slot, empty_timed_slot );
}
int FileSystem::execute_command( const Glib::ustring & command, OperationDetail & operationdetail,
ExecFlags flags,
StreamSlot stream_progress_slot )
{
TimedSlot empty_timed_slot;
return execute_command_internal( command, operationdetail, flags, stream_progress_slot, empty_timed_slot );
}
int FileSystem::execute_command( const Glib::ustring & command, OperationDetail & operationdetail,
ExecFlags flags,
TimedSlot timed_progress_slot )
{
StreamSlot empty_stream_slot;
return execute_command_internal( command, operationdetail, flags, empty_stream_slot, timed_progress_slot );
}
int FileSystem::execute_command_internal( const Glib::ustring & command, OperationDetail & operationdetail,
ExecFlags flags,
StreamSlot stream_progress_slot,
TimedSlot timed_progress_slot )
{
Time and check nearly all file system action commands (#754684) There has been an undocumented rule that external commands displayed in the operation details, as part of file system manipulations, only get a time and check mark displayed when multiple commands are needed, and not otherwise. (GParted checks whether all commands are successful or not regardless of whether a check mark is displayed in the operation details or not). EXCEPTION 1: btrfs resize Since the following commit [1] from 2013-02-22, GParted stopped displaying the timing for the btrfs resize command in the operation details. It being part of a multi-command sequence to perform the step. This is because FileSystem::execute_command() since the commit can only check the exit status for zero / non-zero while timing and checking the command status but btrfs resize needs to consider some non-zero statuses as successful. [1] 52a2a9b00a32996921ace055e71d0e09fb33c5fe Reduce threading (#685740) EXCEPTION 2: ext2/3/4 move and copy using e2image When use of e2image was added [2] the single command steps were timed and check. [2] 86111fe12a26d23d9fc2a9e2d19281290ecaf985 Use e2image to move/copy ext[234] file systems (#721516) EXCEPTION 3: fat16/32 write label and UUID Uses Utils::execute_command() rather than FileSystem::execute_command() so can be separately changed. See the following commit for resolution of the final commands not yet timed and check mark displayed. CHANGE: Lets make a simpler rule of always displaying the time and a check mark for all external commands displayed in the operation details. However this makes several of the other single command actions need special exit status handling because zero success, non-zero failure is not correct for every case. Specifically affects resizing of reiserfs and check repair of ext2/3/4, fat16/32, jfs and reiserfs. After this change all external commands run as file system actions must follow one of these two patterns of using the EXEC_CHECK_STATUS flag or separately calling FileSystem::set_status() to register success or failure of the command: exit_status = execute_command(cmd, od, EXEC_CHECK_STATUS...); or: exit_status = execute_command(cmd, od, ...); bool success = (exit_status == 0 || exit_status == OTHER_SUCCESS_VALUE...); set_status(od, success ); Bug 754684 - Updates to FileSystem:: and Utils::execute_command() functions
2015-09-05 02:31:16 -06:00
operationdetail.add_child( OperationDetail( command, STATUS_EXECUTE, FONT_BOLD_ITALIC ) );
Leave commands with progress bars shown in the applying dialog (#760709) For non-progress tracked external commands the command being executed is displayed in the Apply pending operations dialog, just below the top pulsing progress bar. However for progress tracked external commands the description of the parent operation detail is displayed instead. Example 1: non-progress tracked xfs check repair: TreePath Check and repair file system (xfs) on /dev/sdc1 0 + calibrate /dev/sdc1 0:0 + check file system on /dev/sdc1 for errors and (if po... 0:1 + xfs_repair -v /dev/sdc1 0:1:0 + [empty stdout] 0:1:0:0 + [stderr]Phase 1 - find and verify superblock... 0:1:0:1 "xfs_repair -v /dev/sdc1" (TreePath 0:1:0) is shown because it is the latest updated operation detail which is timed (set to status executing). Example 2: progress tracked ext4 copy using e2image: TreePath Copy /dev/sdc2 to /dev/sdc3 0 + calibrate /dev/sdc2 0:0 + check file system on /dev/sdc2 for errors and (if po... 0:1 + set partition type on /dev/sdc3 0:2 + copy file system of /dev/sdc2 to /dev/sdc3 0:3 + e2image -ra -p /dev/sdc2 /dev/sdc3 0:3:0 + [stdout]Scanning inodes... 0:3:0:0 + [stderr]e2image 1.42.9 (28-Dec-2013)... 0:3:0:1 "copy file system of /dev/sdc2 to /dev/sdc3" (TreePath 0:3) is shown because that operation detail is also timed and it is being constantly updated by the progress bar updates via it. Change execute_command() to update the progress bar via the operation detail it creates to hold the command being executed, instead of the parent operation detail, to resolve the above. Also replaces calling operationdetail.get_last_child() throughout the method. Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific copy methods
2016-02-08 13:02:42 -07:00
OperationDetail & cmd_operationdetail = operationdetail.get_last_child();
Glib::Pid pid;
// set up pipes for capture
int out, err;
// spawn external process
running = true;
try {
Glib::spawn_async_with_pipes(
std::string( "." ),
Glib::shell_parse_argv( command ),
Glib::SPAWN_DO_NOT_REAP_CHILD | Glib::SPAWN_SEARCH_PATH,
sigc::ptr_fun(setup_child),
&pid,
0,
&out,
&err );
} catch (Glib::SpawnError &e) {
std::cerr << e.what() << std::endl;
Leave commands with progress bars shown in the applying dialog (#760709) For non-progress tracked external commands the command being executed is displayed in the Apply pending operations dialog, just below the top pulsing progress bar. However for progress tracked external commands the description of the parent operation detail is displayed instead. Example 1: non-progress tracked xfs check repair: TreePath Check and repair file system (xfs) on /dev/sdc1 0 + calibrate /dev/sdc1 0:0 + check file system on /dev/sdc1 for errors and (if po... 0:1 + xfs_repair -v /dev/sdc1 0:1:0 + [empty stdout] 0:1:0:0 + [stderr]Phase 1 - find and verify superblock... 0:1:0:1 "xfs_repair -v /dev/sdc1" (TreePath 0:1:0) is shown because it is the latest updated operation detail which is timed (set to status executing). Example 2: progress tracked ext4 copy using e2image: TreePath Copy /dev/sdc2 to /dev/sdc3 0 + calibrate /dev/sdc2 0:0 + check file system on /dev/sdc2 for errors and (if po... 0:1 + set partition type on /dev/sdc3 0:2 + copy file system of /dev/sdc2 to /dev/sdc3 0:3 + e2image -ra -p /dev/sdc2 /dev/sdc3 0:3:0 + [stdout]Scanning inodes... 0:3:0:0 + [stderr]e2image 1.42.9 (28-Dec-2013)... 0:3:0:1 "copy file system of /dev/sdc2 to /dev/sdc3" (TreePath 0:3) is shown because that operation detail is also timed and it is being constantly updated by the progress bar updates via it. Change execute_command() to update the progress bar via the operation detail it creates to hold the command being executed, instead of the parent operation detail, to resolve the above. Also replaces calling operationdetail.get_last_child() throughout the method. Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific copy methods
2016-02-08 13:02:42 -07:00
cmd_operationdetail.add_child( OperationDetail( e.what(), STATUS_ERROR, FONT_ITALIC ) );
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
2015-09-06 07:39:07 -06:00
return Utils::get_failure_status( e );
}
fcntl( out, F_SETFL, O_NONBLOCK );
fcntl( err, F_SETFL, O_NONBLOCK );
Glib::signal_child_watch().connect( sigc::mem_fun( *this, &FileSystem::store_exit_status ), pid );
output.clear();
error.clear();
pipecount = 2;
PipeCapture outputcapture( out, output );
PipeCapture errorcapture( err, error );
outputcapture.signal_eof.connect( sigc::mem_fun( *this, &FileSystem::execute_command_eof ) );
errorcapture.signal_eof.connect( sigc::mem_fun( *this, &FileSystem::execute_command_eof ) );
Leave commands with progress bars shown in the applying dialog (#760709) For non-progress tracked external commands the command being executed is displayed in the Apply pending operations dialog, just below the top pulsing progress bar. However for progress tracked external commands the description of the parent operation detail is displayed instead. Example 1: non-progress tracked xfs check repair: TreePath Check and repair file system (xfs) on /dev/sdc1 0 + calibrate /dev/sdc1 0:0 + check file system on /dev/sdc1 for errors and (if po... 0:1 + xfs_repair -v /dev/sdc1 0:1:0 + [empty stdout] 0:1:0:0 + [stderr]Phase 1 - find and verify superblock... 0:1:0:1 "xfs_repair -v /dev/sdc1" (TreePath 0:1:0) is shown because it is the latest updated operation detail which is timed (set to status executing). Example 2: progress tracked ext4 copy using e2image: TreePath Copy /dev/sdc2 to /dev/sdc3 0 + calibrate /dev/sdc2 0:0 + check file system on /dev/sdc2 for errors and (if po... 0:1 + set partition type on /dev/sdc3 0:2 + copy file system of /dev/sdc2 to /dev/sdc3 0:3 + e2image -ra -p /dev/sdc2 /dev/sdc3 0:3:0 + [stdout]Scanning inodes... 0:3:0:0 + [stderr]e2image 1.42.9 (28-Dec-2013)... 0:3:0:1 "copy file system of /dev/sdc2 to /dev/sdc3" (TreePath 0:3) is shown because that operation detail is also timed and it is being constantly updated by the progress bar updates via it. Change execute_command() to update the progress bar via the operation detail it creates to hold the command being executed, instead of the parent operation detail, to resolve the above. Also replaces calling operationdetail.get_last_child() throughout the method. Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific copy methods
2016-02-08 13:02:42 -07:00
cmd_operationdetail.add_child( OperationDetail( output, STATUS_NONE, FONT_ITALIC ) );
cmd_operationdetail.add_child( OperationDetail( error, STATUS_NONE, FONT_ITALIC ) );
std::vector<OperationDetail*> &children = cmd_operationdetail.get_childs();
outputcapture.signal_update.connect( sigc::bind( sigc::ptr_fun( update_command_output ),
children[children.size() - 2],
&output ) );
errorcapture.signal_update.connect( sigc::bind( sigc::ptr_fun( update_command_output ),
children[children.size() - 1],
&error ) );
Connect timed progress tracking callbacks inside execute_command() (#760709) The timed progress tracking callback for execution of xfs copy follows this pattern: sigc::connection c; ... c = Glib::signal_timeout().connect( ... sigc::mem_fun( *this, &xfs::copy_progress ) ..., 500 /*ms*/ ); ... execute_command( ... ); c.disconnect(); As with output progress tracking callbacks for ext2/3/4 and ntfs file system specific commands, pass the callback slot and a flag into execute_command() and connect the timed callback inside. This simplified the pattern to: ... execute_command( ...|EXEC_PROGRESS_TIMED, static_cast<TimedSlot>( sigc::mem_fun( *this, &xfs::copy_progress ) ) ); NOTE: The type of sigc::mem_fun() doesn't allow the compiler to choose between the two overloaded variants of execute_command() with the fourth parameter of either (full types without typedefs of StreamSlot and TimedSlot respectively): sigc::slot<void, OperationDetail *> stream_progress_slot sigc::slot<bool, OperationDetail *> timed_progress_slot Therefore have to cast the result of all callback slots to the relevant type. Hence: static_cast<StreamSlot>( sigc::mem_fun( *this, &{CLASS}::{NAME}_progress ) ) static_cast<TimedSlot>( sigc::mem_fun( *this, &xfs::copy_progress ) ) References: * [sigc] Functor not resolving between overloaded methods with different slot types https://mail.gnome.org/archives/libsigc-list/2016-February/msg00000.html * Bug 306705 - Can't overload methods based on different slot<> parameters. https://bugzilla.gnome.org/show_bug.cgi?id=306705 Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific copy methods
2016-02-03 14:17:30 -07:00
sigc::connection timed_conn;
if ( flags & EXEC_PROGRESS_STDOUT && ! stream_progress_slot.empty() )
// Call progress tracking callback when stdout updates
Leave commands with progress bars shown in the applying dialog (#760709) For non-progress tracked external commands the command being executed is displayed in the Apply pending operations dialog, just below the top pulsing progress bar. However for progress tracked external commands the description of the parent operation detail is displayed instead. Example 1: non-progress tracked xfs check repair: TreePath Check and repair file system (xfs) on /dev/sdc1 0 + calibrate /dev/sdc1 0:0 + check file system on /dev/sdc1 for errors and (if po... 0:1 + xfs_repair -v /dev/sdc1 0:1:0 + [empty stdout] 0:1:0:0 + [stderr]Phase 1 - find and verify superblock... 0:1:0:1 "xfs_repair -v /dev/sdc1" (TreePath 0:1:0) is shown because it is the latest updated operation detail which is timed (set to status executing). Example 2: progress tracked ext4 copy using e2image: TreePath Copy /dev/sdc2 to /dev/sdc3 0 + calibrate /dev/sdc2 0:0 + check file system on /dev/sdc2 for errors and (if po... 0:1 + set partition type on /dev/sdc3 0:2 + copy file system of /dev/sdc2 to /dev/sdc3 0:3 + e2image -ra -p /dev/sdc2 /dev/sdc3 0:3:0 + [stdout]Scanning inodes... 0:3:0:0 + [stderr]e2image 1.42.9 (28-Dec-2013)... 0:3:0:1 "copy file system of /dev/sdc2 to /dev/sdc3" (TreePath 0:3) is shown because that operation detail is also timed and it is being constantly updated by the progress bar updates via it. Change execute_command() to update the progress bar via the operation detail it creates to hold the command being executed, instead of the parent operation detail, to resolve the above. Also replaces calling operationdetail.get_last_child() throughout the method. Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific copy methods
2016-02-08 13:02:42 -07:00
outputcapture.signal_update.connect( sigc::bind( stream_progress_slot, &cmd_operationdetail ) );
else if ( flags & EXEC_PROGRESS_STDERR && ! stream_progress_slot.empty() )
// Call progress tracking callback when stderr updates
Leave commands with progress bars shown in the applying dialog (#760709) For non-progress tracked external commands the command being executed is displayed in the Apply pending operations dialog, just below the top pulsing progress bar. However for progress tracked external commands the description of the parent operation detail is displayed instead. Example 1: non-progress tracked xfs check repair: TreePath Check and repair file system (xfs) on /dev/sdc1 0 + calibrate /dev/sdc1 0:0 + check file system on /dev/sdc1 for errors and (if po... 0:1 + xfs_repair -v /dev/sdc1 0:1:0 + [empty stdout] 0:1:0:0 + [stderr]Phase 1 - find and verify superblock... 0:1:0:1 "xfs_repair -v /dev/sdc1" (TreePath 0:1:0) is shown because it is the latest updated operation detail which is timed (set to status executing). Example 2: progress tracked ext4 copy using e2image: TreePath Copy /dev/sdc2 to /dev/sdc3 0 + calibrate /dev/sdc2 0:0 + check file system on /dev/sdc2 for errors and (if po... 0:1 + set partition type on /dev/sdc3 0:2 + copy file system of /dev/sdc2 to /dev/sdc3 0:3 + e2image -ra -p /dev/sdc2 /dev/sdc3 0:3:0 + [stdout]Scanning inodes... 0:3:0:0 + [stderr]e2image 1.42.9 (28-Dec-2013)... 0:3:0:1 "copy file system of /dev/sdc2 to /dev/sdc3" (TreePath 0:3) is shown because that operation detail is also timed and it is being constantly updated by the progress bar updates via it. Change execute_command() to update the progress bar via the operation detail it creates to hold the command being executed, instead of the parent operation detail, to resolve the above. Also replaces calling operationdetail.get_last_child() throughout the method. Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific copy methods
2016-02-08 13:02:42 -07:00
errorcapture.signal_update.connect( sigc::bind( stream_progress_slot, &cmd_operationdetail ) );
Connect timed progress tracking callbacks inside execute_command() (#760709) The timed progress tracking callback for execution of xfs copy follows this pattern: sigc::connection c; ... c = Glib::signal_timeout().connect( ... sigc::mem_fun( *this, &xfs::copy_progress ) ..., 500 /*ms*/ ); ... execute_command( ... ); c.disconnect(); As with output progress tracking callbacks for ext2/3/4 and ntfs file system specific commands, pass the callback slot and a flag into execute_command() and connect the timed callback inside. This simplified the pattern to: ... execute_command( ...|EXEC_PROGRESS_TIMED, static_cast<TimedSlot>( sigc::mem_fun( *this, &xfs::copy_progress ) ) ); NOTE: The type of sigc::mem_fun() doesn't allow the compiler to choose between the two overloaded variants of execute_command() with the fourth parameter of either (full types without typedefs of StreamSlot and TimedSlot respectively): sigc::slot<void, OperationDetail *> stream_progress_slot sigc::slot<bool, OperationDetail *> timed_progress_slot Therefore have to cast the result of all callback slots to the relevant type. Hence: static_cast<StreamSlot>( sigc::mem_fun( *this, &{CLASS}::{NAME}_progress ) ) static_cast<TimedSlot>( sigc::mem_fun( *this, &xfs::copy_progress ) ) References: * [sigc] Functor not resolving between overloaded methods with different slot types https://mail.gnome.org/archives/libsigc-list/2016-February/msg00000.html * Bug 306705 - Can't overload methods based on different slot<> parameters. https://bugzilla.gnome.org/show_bug.cgi?id=306705 Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific copy methods
2016-02-03 14:17:30 -07:00
else if ( flags & EXEC_PROGRESS_TIMED && ! timed_progress_slot.empty() )
// Call progress tracking callback every 500 ms
Leave commands with progress bars shown in the applying dialog (#760709) For non-progress tracked external commands the command being executed is displayed in the Apply pending operations dialog, just below the top pulsing progress bar. However for progress tracked external commands the description of the parent operation detail is displayed instead. Example 1: non-progress tracked xfs check repair: TreePath Check and repair file system (xfs) on /dev/sdc1 0 + calibrate /dev/sdc1 0:0 + check file system on /dev/sdc1 for errors and (if po... 0:1 + xfs_repair -v /dev/sdc1 0:1:0 + [empty stdout] 0:1:0:0 + [stderr]Phase 1 - find and verify superblock... 0:1:0:1 "xfs_repair -v /dev/sdc1" (TreePath 0:1:0) is shown because it is the latest updated operation detail which is timed (set to status executing). Example 2: progress tracked ext4 copy using e2image: TreePath Copy /dev/sdc2 to /dev/sdc3 0 + calibrate /dev/sdc2 0:0 + check file system on /dev/sdc2 for errors and (if po... 0:1 + set partition type on /dev/sdc3 0:2 + copy file system of /dev/sdc2 to /dev/sdc3 0:3 + e2image -ra -p /dev/sdc2 /dev/sdc3 0:3:0 + [stdout]Scanning inodes... 0:3:0:0 + [stderr]e2image 1.42.9 (28-Dec-2013)... 0:3:0:1 "copy file system of /dev/sdc2 to /dev/sdc3" (TreePath 0:3) is shown because that operation detail is also timed and it is being constantly updated by the progress bar updates via it. Change execute_command() to update the progress bar via the operation detail it creates to hold the command being executed, instead of the parent operation detail, to resolve the above. Also replaces calling operationdetail.get_last_child() throughout the method. Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific copy methods
2016-02-08 13:02:42 -07:00
timed_conn = Glib::signal_timeout().connect( sigc::bind( timed_progress_slot, &cmd_operationdetail ), 500 );
outputcapture.connect_signal();
errorcapture.connect_signal();
Leave commands with progress bars shown in the applying dialog (#760709) For non-progress tracked external commands the command being executed is displayed in the Apply pending operations dialog, just below the top pulsing progress bar. However for progress tracked external commands the description of the parent operation detail is displayed instead. Example 1: non-progress tracked xfs check repair: TreePath Check and repair file system (xfs) on /dev/sdc1 0 + calibrate /dev/sdc1 0:0 + check file system on /dev/sdc1 for errors and (if po... 0:1 + xfs_repair -v /dev/sdc1 0:1:0 + [empty stdout] 0:1:0:0 + [stderr]Phase 1 - find and verify superblock... 0:1:0:1 "xfs_repair -v /dev/sdc1" (TreePath 0:1:0) is shown because it is the latest updated operation detail which is timed (set to status executing). Example 2: progress tracked ext4 copy using e2image: TreePath Copy /dev/sdc2 to /dev/sdc3 0 + calibrate /dev/sdc2 0:0 + check file system on /dev/sdc2 for errors and (if po... 0:1 + set partition type on /dev/sdc3 0:2 + copy file system of /dev/sdc2 to /dev/sdc3 0:3 + e2image -ra -p /dev/sdc2 /dev/sdc3 0:3:0 + [stdout]Scanning inodes... 0:3:0:0 + [stderr]e2image 1.42.9 (28-Dec-2013)... 0:3:0:1 "copy file system of /dev/sdc2 to /dev/sdc3" (TreePath 0:3) is shown because that operation detail is also timed and it is being constantly updated by the progress bar updates via it. Change execute_command() to update the progress bar via the operation detail it creates to hold the command being executed, instead of the parent operation detail, to resolve the above. Also replaces calling operationdetail.get_last_child() throughout the method. Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific copy methods
2016-02-08 13:02:42 -07:00
cmd_operationdetail.signal_cancel.connect(
sigc::bind(
sigc::ptr_fun( cancel_command ),
pid,
flags & EXEC_CANCEL_SAFE ) );
Gtk::Main::run();
if ( flags & EXEC_CHECK_STATUS )
{
if ( !exit_status )
Leave commands with progress bars shown in the applying dialog (#760709) For non-progress tracked external commands the command being executed is displayed in the Apply pending operations dialog, just below the top pulsing progress bar. However for progress tracked external commands the description of the parent operation detail is displayed instead. Example 1: non-progress tracked xfs check repair: TreePath Check and repair file system (xfs) on /dev/sdc1 0 + calibrate /dev/sdc1 0:0 + check file system on /dev/sdc1 for errors and (if po... 0:1 + xfs_repair -v /dev/sdc1 0:1:0 + [empty stdout] 0:1:0:0 + [stderr]Phase 1 - find and verify superblock... 0:1:0:1 "xfs_repair -v /dev/sdc1" (TreePath 0:1:0) is shown because it is the latest updated operation detail which is timed (set to status executing). Example 2: progress tracked ext4 copy using e2image: TreePath Copy /dev/sdc2 to /dev/sdc3 0 + calibrate /dev/sdc2 0:0 + check file system on /dev/sdc2 for errors and (if po... 0:1 + set partition type on /dev/sdc3 0:2 + copy file system of /dev/sdc2 to /dev/sdc3 0:3 + e2image -ra -p /dev/sdc2 /dev/sdc3 0:3:0 + [stdout]Scanning inodes... 0:3:0:0 + [stderr]e2image 1.42.9 (28-Dec-2013)... 0:3:0:1 "copy file system of /dev/sdc2 to /dev/sdc3" (TreePath 0:3) is shown because that operation detail is also timed and it is being constantly updated by the progress bar updates via it. Change execute_command() to update the progress bar via the operation detail it creates to hold the command being executed, instead of the parent operation detail, to resolve the above. Also replaces calling operationdetail.get_last_child() throughout the method. Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific copy methods
2016-02-08 13:02:42 -07:00
cmd_operationdetail.set_status( STATUS_SUCCES );
else
Leave commands with progress bars shown in the applying dialog (#760709) For non-progress tracked external commands the command being executed is displayed in the Apply pending operations dialog, just below the top pulsing progress bar. However for progress tracked external commands the description of the parent operation detail is displayed instead. Example 1: non-progress tracked xfs check repair: TreePath Check and repair file system (xfs) on /dev/sdc1 0 + calibrate /dev/sdc1 0:0 + check file system on /dev/sdc1 for errors and (if po... 0:1 + xfs_repair -v /dev/sdc1 0:1:0 + [empty stdout] 0:1:0:0 + [stderr]Phase 1 - find and verify superblock... 0:1:0:1 "xfs_repair -v /dev/sdc1" (TreePath 0:1:0) is shown because it is the latest updated operation detail which is timed (set to status executing). Example 2: progress tracked ext4 copy using e2image: TreePath Copy /dev/sdc2 to /dev/sdc3 0 + calibrate /dev/sdc2 0:0 + check file system on /dev/sdc2 for errors and (if po... 0:1 + set partition type on /dev/sdc3 0:2 + copy file system of /dev/sdc2 to /dev/sdc3 0:3 + e2image -ra -p /dev/sdc2 /dev/sdc3 0:3:0 + [stdout]Scanning inodes... 0:3:0:0 + [stderr]e2image 1.42.9 (28-Dec-2013)... 0:3:0:1 "copy file system of /dev/sdc2 to /dev/sdc3" (TreePath 0:3) is shown because that operation detail is also timed and it is being constantly updated by the progress bar updates via it. Change execute_command() to update the progress bar via the operation detail it creates to hold the command being executed, instead of the parent operation detail, to resolve the above. Also replaces calling operationdetail.get_last_child() throughout the method. Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific copy methods
2016-02-08 13:02:42 -07:00
cmd_operationdetail.set_status( STATUS_ERROR );
}
close( out );
close( err );
Connect timed progress tracking callbacks inside execute_command() (#760709) The timed progress tracking callback for execution of xfs copy follows this pattern: sigc::connection c; ... c = Glib::signal_timeout().connect( ... sigc::mem_fun( *this, &xfs::copy_progress ) ..., 500 /*ms*/ ); ... execute_command( ... ); c.disconnect(); As with output progress tracking callbacks for ext2/3/4 and ntfs file system specific commands, pass the callback slot and a flag into execute_command() and connect the timed callback inside. This simplified the pattern to: ... execute_command( ...|EXEC_PROGRESS_TIMED, static_cast<TimedSlot>( sigc::mem_fun( *this, &xfs::copy_progress ) ) ); NOTE: The type of sigc::mem_fun() doesn't allow the compiler to choose between the two overloaded variants of execute_command() with the fourth parameter of either (full types without typedefs of StreamSlot and TimedSlot respectively): sigc::slot<void, OperationDetail *> stream_progress_slot sigc::slot<bool, OperationDetail *> timed_progress_slot Therefore have to cast the result of all callback slots to the relevant type. Hence: static_cast<StreamSlot>( sigc::mem_fun( *this, &{CLASS}::{NAME}_progress ) ) static_cast<TimedSlot>( sigc::mem_fun( *this, &xfs::copy_progress ) ) References: * [sigc] Functor not resolving between overloaded methods with different slot types https://mail.gnome.org/archives/libsigc-list/2016-February/msg00000.html * Bug 306705 - Can't overload methods based on different slot<> parameters. https://bugzilla.gnome.org/show_bug.cgi?id=306705 Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific copy methods
2016-02-03 14:17:30 -07:00
if ( timed_conn.connected() )
timed_conn.disconnect();
Leave commands with progress bars shown in the applying dialog (#760709) For non-progress tracked external commands the command being executed is displayed in the Apply pending operations dialog, just below the top pulsing progress bar. However for progress tracked external commands the description of the parent operation detail is displayed instead. Example 1: non-progress tracked xfs check repair: TreePath Check and repair file system (xfs) on /dev/sdc1 0 + calibrate /dev/sdc1 0:0 + check file system on /dev/sdc1 for errors and (if po... 0:1 + xfs_repair -v /dev/sdc1 0:1:0 + [empty stdout] 0:1:0:0 + [stderr]Phase 1 - find and verify superblock... 0:1:0:1 "xfs_repair -v /dev/sdc1" (TreePath 0:1:0) is shown because it is the latest updated operation detail which is timed (set to status executing). Example 2: progress tracked ext4 copy using e2image: TreePath Copy /dev/sdc2 to /dev/sdc3 0 + calibrate /dev/sdc2 0:0 + check file system on /dev/sdc2 for errors and (if po... 0:1 + set partition type on /dev/sdc3 0:2 + copy file system of /dev/sdc2 to /dev/sdc3 0:3 + e2image -ra -p /dev/sdc2 /dev/sdc3 0:3:0 + [stdout]Scanning inodes... 0:3:0:0 + [stderr]e2image 1.42.9 (28-Dec-2013)... 0:3:0:1 "copy file system of /dev/sdc2 to /dev/sdc3" (TreePath 0:3) is shown because that operation detail is also timed and it is being constantly updated by the progress bar updates via it. Change execute_command() to update the progress bar via the operation detail it creates to hold the command being executed, instead of the parent operation detail, to resolve the above. Also replaces calling operationdetail.get_last_child() throughout the method. Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific copy methods
2016-02-08 13:02:42 -07:00
cmd_operationdetail.stop_progressbar();
return exit_status;
}
Time and check nearly all file system action commands (#754684) There has been an undocumented rule that external commands displayed in the operation details, as part of file system manipulations, only get a time and check mark displayed when multiple commands are needed, and not otherwise. (GParted checks whether all commands are successful or not regardless of whether a check mark is displayed in the operation details or not). EXCEPTION 1: btrfs resize Since the following commit [1] from 2013-02-22, GParted stopped displaying the timing for the btrfs resize command in the operation details. It being part of a multi-command sequence to perform the step. This is because FileSystem::execute_command() since the commit can only check the exit status for zero / non-zero while timing and checking the command status but btrfs resize needs to consider some non-zero statuses as successful. [1] 52a2a9b00a32996921ace055e71d0e09fb33c5fe Reduce threading (#685740) EXCEPTION 2: ext2/3/4 move and copy using e2image When use of e2image was added [2] the single command steps were timed and check. [2] 86111fe12a26d23d9fc2a9e2d19281290ecaf985 Use e2image to move/copy ext[234] file systems (#721516) EXCEPTION 3: fat16/32 write label and UUID Uses Utils::execute_command() rather than FileSystem::execute_command() so can be separately changed. See the following commit for resolution of the final commands not yet timed and check mark displayed. CHANGE: Lets make a simpler rule of always displaying the time and a check mark for all external commands displayed in the operation details. However this makes several of the other single command actions need special exit status handling because zero success, non-zero failure is not correct for every case. Specifically affects resizing of reiserfs and check repair of ext2/3/4, fat16/32, jfs and reiserfs. After this change all external commands run as file system actions must follow one of these two patterns of using the EXEC_CHECK_STATUS flag or separately calling FileSystem::set_status() to register success or failure of the command: exit_status = execute_command(cmd, od, EXEC_CHECK_STATUS...); or: exit_status = execute_command(cmd, od, ...); bool success = (exit_status == 0 || exit_status == OTHER_SUCCESS_VALUE...); set_status(od, success ); Bug 754684 - Updates to FileSystem:: and Utils::execute_command() functions
2015-09-05 02:31:16 -06:00
void FileSystem::set_status( OperationDetail & operationdetail, bool success )
{
operationdetail.get_last_child().set_status( success ? STATUS_SUCCES : STATUS_ERROR );
}
void FileSystem::execute_command_eof()
{
if (--pipecount)
return; // wait for second pipe to eof
if ( !running ) // already got exit status
Gtk::Main::quit();
}
//Create uniquely named temporary directory and add results to operation detail
Glib::ustring FileSystem::mk_temp_dir( const Glib::ustring & infix, OperationDetail & operationdetail )
{
// Construct template like "$TMPDIR/gparted-XXXXXX" or "$TMPDIR/gparted-INFIX-XXXXXX"
Glib::ustring dir_template = Glib::get_tmp_dir() + "/gparted-" ;
if ( ! infix .empty() )
dir_template += infix + "-" ;
dir_template += "XXXXXX" ;
//Secure Programming for Linux and Unix HOWTO, Chapter 6. Avoid Buffer Overflow
// http://tldp.org/HOWTO/Secure-Programs-HOWTO/library-c.html
char dir_buf[4096+1];
sprintf( dir_buf, "%.*s", (int) sizeof(dir_buf)-1, dir_template .c_str() ) ;
//Looks like "mkdir -v" command was run to the user
operationdetail .add_child( OperationDetail(
Glib::ustring( "mkdir -v " ) + dir_buf, STATUS_EXECUTE, FONT_BOLD_ITALIC ) ) ;
const char * dir_name = mkdtemp( dir_buf ) ;
if ( NULL == dir_name )
{
int e = errno ;
operationdetail .get_last_child() .set_status( STATUS_ERROR ) ;
operationdetail .get_last_child() .add_child( OperationDetail(
String::ucompose( "mkdtemp(%1): %2", dir_buf, Glib::strerror( e ) ), STATUS_NONE ) ) ;
dir_name = "" ;
}
else
{
//Update command with actually created temporary directory
operationdetail .get_last_child() .set_description(
Glib::ustring( "mkdir -v " ) + dir_name, FONT_BOLD_ITALIC ) ;
operationdetail .get_last_child() .set_status( STATUS_SUCCES ) ;
operationdetail .get_last_child() .add_child( OperationDetail(
/*TO TRANSLATORS: looks like Created directory /tmp/gparted-CEzvSp */
String::ucompose( _("Created directory %1"), dir_name ), STATUS_NONE ) ) ;
}
return Glib::ustring( dir_name ) ;
}
//Remove directory and add results to operation detail
void FileSystem::rm_temp_dir( const Glib::ustring dir_name, OperationDetail & operationdetail )
{
//Looks like "rmdir -v" command was run to the user
operationdetail .add_child( OperationDetail( Glib::ustring( "rmdir -v " ) + dir_name,
STATUS_EXECUTE, FONT_BOLD_ITALIC ) ) ;
if ( rmdir( dir_name .c_str() ) )
{
//Don't mark operation as errored just because rmdir
// failed. Set to Warning (N/A) instead.
int e = errno ;
operationdetail .get_last_child() .set_status( STATUS_SUCCES ) ; //Stop timer
operationdetail .get_last_child() .set_status( STATUS_N_A ) ;
operationdetail .get_last_child() .add_child( OperationDetail(
String::ucompose( "rmdir(%1): ", dir_name ) + Glib::strerror( e ), STATUS_NONE ) ) ;
}
else
{
operationdetail .get_last_child() .set_status( STATUS_SUCCES ) ;
operationdetail .get_last_child() .add_child( OperationDetail(
/*TO TRANSLATORS: looks like Removed directory /tmp/gparted-CEzvSp */
String::ucompose( _("Removed directory %1"), dir_name ), STATUS_NONE ) ) ;
}
}
} //GParted