NAME
App::USBKeyCopyCon - GUI console for bulk copying of USB keys
SYNOPSIS
To launch the GUI application that this module implements, simply run the supplied wrapper script:
sudo usb-key-copy-con
DESCRIPTION
This module implements an application for bulk copying USB flash drives (storage devices). The application was developed to run on Linux and is probably not particularly portable to other platforms.
From a user's perspective the operation is simple:
insert a 'master' USB key when prompted - the contents of the key will be copied into a temporary directory on the hard drive, after which the key can be removed
insert blank keys into all available USB ports - the app will detect when each new key is inserted, start the copy process and alert the user on completion
repeat step 2 as required
The program can write to multiple keys in parallel. It can also use filtering on device parameters to only overwrite devices which match the vendor name and storage capacity specified - other devices will be ignored.
The specifics of reading the master key, preparing a blank key (formatting parameters etc) are implemented in short 'profile' scripts (a reader and a writer). You can supply your own profile scripts if your requirements differ from those provided.
DEVELOPER INFORMATION
The remainder of the documentation is targetted at developers who wish to modify or customise the application.
The application uses the Gtk2 GUI toolkit. The wrapper script instantiates a single application object like this:
use App::USBKeyCopyCon;
App::USBKeyCopyCon->new->run;
The constructor is responsible for building the user interface and the run
method invokes the Gtk2 event loop. UI events are dispatched as method calls on the application object.
ATTRIBUTES
The application object has the following attributes (with correspondingly named accessor methods):
- app_win
-
The main Gtk2::Window object.
- capacity_combo
-
The Gtk2::ComboBox object for the device filter 'Capacity' drop-down menu.
- capacity_entry
-
The Gtk2::Entry object for the device filter 'Capacity' text entry box.
- console
-
The Gtk2::TextView object used for writing output messages.
- current_keys
-
A hash for tracking which (non-master) keys are currently inserted and what stage each copy process is at. The hash key is the device 'UDI' and the value is a hash of device dtails .
- current_state
-
Used to control which mode the application is in:
MASTER-WAIT waiting for the user to insert the master key MASTER-COPYING waiting for the master key 'reader' script to complete MASTER-COPIED waiting for the user to remove the master key COPYING waiting for the user to insert blank keys
- exit_status
-
Used by a SIGCHLD handler to track the exit status of the copy scripts. The key is a process ID and the value is the exist status returned by
wait
. - hal
-
The DBus object ('org.freedesktop.Hal.Manager') from which device add/remove events are received.
- key_rack
-
The Gtk2::HBox object containing the widgets representing currently inserted keys.
- master_info
-
A hash of device details for the 'master' USB key.
- master_root
-
The path to the temp directory containing the copy of the master key.
- mount_dir
-
The path to the temp directory containing temporary mount points.
The volume label read from the master key and to be applied to the copies.
- reader_script
-
The path to the profile script used to read the master key.
- selected_sound
-
Pathname of the currently selected sound file, to be played when copying is complete.
- temp_root
-
The temp directory selected by the user. The application will create a subdirectory for the copy of the master key and for temporary mount points.
- vendor_combo
-
The Gtk2::ComboBox object for the device filter 'Vendor' drop-down menu.
- vendor_entry
-
The Gtk2::Entry object for the device filter 'Vendor' text entry box.
- volume_label
- writer_script
-
The path to the profile script used to write to the blank keys.
PROFILES
The tasks of reading a master key and writing to a blank key are delegated to 'reader' and 'writer' scripts. A pair of reader/writer scripts is supplied but the application is designed to support using different scripts as dictated by a user selection. The supplied script assume file-by-file copying and format the blank keys with a VFAT filesystem. An alternate profile might use dd
to write a complete filesystem in a single operation.
A pair of scripts is referred to as a copying 'profile'. The select_profile
method can be used to instruct the application to use a specific pair of scripts.
The supplied scripts are called:
copyfiles-reader.sh
copyfiles-writer.sh
The default constructor selects this profile with the call:
$self->select_profile('copyfiles');
The reader/writer scripts do not have to be shell scripts - they merely need to be executable. The application ignores the file extension if it is present.
METHODS
Constructor
The new
method is used to create an application object. It in turn calls BUILD
to create and populate the application window and hook into HAL (the Hardware Abstraction Layer) via DBus to get notifications of devices been added/removed.
add_key_to_rack ( key_info )
Called from hal_device_added
if the newly added device matches the current device filter settings. The key_info
parameter supplied is a hashref of device properties as returned by hal_device_properties
. A GUI widget representing the new USB key is added to the user interface and a data structure to track the copying process is created.
build_console ( )
Called from the constructor to create the scrolled text window for displaying progress messages.
build_filters ( )
Called from the constructor to create the toolbar of drop-down menus and text entries for the device filter settings.
build_key_rack ( )
Called from the constructor to create the container widget to house the per-key status indicators.
build_menu ( )
Called from the constructor to create the application menu and hook the menu items up to handler methods.
clean_temp_dir ( )
Called from the run
method immediately before the application exits. This method is responsible for removing the temporary directories containing the master copy of the files and the mount points for the blank keys.
confirm_master_dialog ( key_info )
This method is called each time a USB key is inserted when the application is in the MASTER-WAIT
state. The key_info
parameter supplied is a hashref of device properties as returned by hal_device_properties
. this method displays a dialog box to allow the user to confirm that the device should be used as the master key.
If the user selects 'Cancel', no further action is taken and the application goes back to waiting for a master key to be inserted.
If the user confirms the device should be used as the master, then control is passed to the start_master_read
method.
copy_finished ( exit_status )
Called when a 'writer' process exits. Checks the exit status and updates the icon in the key rack (0 = success, non-zero = failure).
disable_filter_inputs ( )
This method is called from require_master_key
to disable the menu and text entry widgets on the device filter toolbar.
enable_filter_inputs ( )
This method is called from require_master_key
to enable the menu and text entry widgets on the device filter toolbar.
fork_copier ( key_info )
Called from add_key_to_rack
. Forks a 'writer' process and collects its STDOUT+STDERR via a pipe.
get_volume_label ( device )
Called from confirm_master_dialog
when collecting information about the key which was just inserted. Current implementation simply runs the dosfslabel
command.
hal_device_added ( udi )
Called to handle a 'DeviceAdded' event from HAL via DBus. Delegates to start_master_read
if the app is waiting for a master key. Otherwise checks whether the new device parameters match the current filter settings and delegates to add_key_to_rack
if they do.
hal_device_properties ( udi )
Called from hal_device_added
to query HAL. Returns a hash(ref) of device details. The global variable %hal_device_added
defines which attributes returned from HAL will appear in the hash and which keys they will be mapped to.
hal_device_removed ( udi )
Called to handle a 'DeviceRemoved' event from HAL via DBus. Delegates to remove_key_from_rack
if the application is in the COPYING
state.
init_dbus_watcher ( )
Called from the constructor to hook up device-add events to the hal_device_added
method and device-remove events to hal_device_removed
.
master_copy_finished ( exit_status )
Called when the 'reader' process exits. Checks the exit status and updates the application state to <MASTER-COPIED> on success or MASTER-WAIT
on failure.
match_device_filter ( key_info )
Called from hal_device_added
and returns true if the device matches the current filter parameters, or false otherwise.
on_copier_pipe_read ( fileno, condition, udi )
Handler for data received from a 'writer' process. Updates the status icon for the device to indicate progress.
on_master_pipe_read ( fileno, condition, udi )
Handler for data received from the master key 'reader' process. Copies output from the process to the console widget.
on_menu_edit_preferences ( )
Handler for the Edit > Preferences menu item - not currently implemented.
on_menu_file_new ( )
Handler for the File > New menu item. Resets the application state via require_master_key
.
on_menu_file_quit ( )
Handler for the File > Quit menu item. Exits the Gtk event loop, which returns control to the run
method.
on_menu_help_about ( )
Handler for the Help > About menu item. Displays 'About' dialog.
play_sound_file ( sound_file )
This method takes a pathname to a sound file (e.g.: a .wav) and plays it. The current implementation simply runs the the SOX play
command - it should probably use GStreamer
remove_key_from_rack ( udi )
Called from hal_device_removed
to remove the indicator widget corresponding to the USB key which has just been removed.
require_master_key ( )
Called from the constructor to put the app in the MASTER-WAIT
mode (waiting for the master key to be inserted). Can also be called from the on_menu_file_new
menu event handler.
run ( )
This method is called from the wrapper script. It's job is to run the Gtk event loop and when that exits, to call clean_temp_dir
and then return.
say ( message )
Appends a message to the console widget. (Note, the caller is responsible for supplying the newline characters).
select_profile ( profile_name )
This method is used to select which reader/writer scripts will be used. At present there is one hard-coded call to this method in the constructor. Ideally, the user would select from all available profile scripts in the 'confirm master' dialog.
set_temp_root ( pathname )
Called from confirm_master_dialog
based on the temp directory selected by the user.
start_master_read ( key_info )
Called from hal_device_added
to fork off a 'reader' process to slurp in the contents of the master key.
tick ( )
This timer event handler is used to take the child process exit status values collected by the SIGCHLD handler and pass them to master_copy_finished
or copy_finished
as appropriate.
update_key_progress ( udi, status )
Called from on_copier_pipe_read
to update the status icon for a specified USB key device. The progress parameter is a number in the range 0-10 for copies in progress; -1 for a copy that has failed (non-zero exit status from the 'writer' process); or -2 to indicate a device which did not match the filter settings and is being ignored.
AUTHOR
Grant McLean, <grantm at cpan.org>
BUGS
Please report any bugs or feature requests to bug-app-usbkeycopycon at rt.cpan.org
, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=App-USBKeyCopyCon. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
SUPPORT
You can find documentation for this module with the perldoc command.
perldoc App::USBKeyCopyCon
You can also look for information at:
github: source code repository
RT: CPAN's request tracker
AnnoCPAN: Annotated CPAN documentation
CPAN Ratings
Search CPAN
COPYRIGHT & LICENSE
Copyright 2009 Grant McLean, all rights reserved.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.