# $HeadURL$ $LastChangedRevision$ # Name of this module package MINIADE; ######################################################################## # # Modules # ######################################################################## use Sys::Syslog qw(:standard :macros); use experimental 'smartmatch'; ######################################################################## # # Characteristics of this module # ######################################################################## # Declare exports BEGIN { use base qw( Exporter ); # This list was generated by trimming: egrep '^(our|sub [^_])' MINIADE.pm #our @EXPORT_OK = qw($OK $FAIL main set_messaging_parameters register_error_types display_error_stack internal error warning info debug encode_z decode_z extract_version show_help show_bad_usage show_version show_paths ask_question get_absolute_path check_readable check_writable create_uuid read_uuid write_uuid validate_uuid open_compressed_file_for_reading open_compressed_file_for_writing get_md5sum register_options process_options manage_rolling_status manage_cache fork_multi evaler register_exit_function deregister_exit_function register_temp_file deregister_temp_file execute_sql select_sql select_sql_count execute_sql_qm select_sql_qm select_sql_count_qm begin_sql_transaction end_sql_transaction assert_inside_sql_transaction assert_outside_sql_transaction connect_sqlite initialise_sqlite validate_sql_schema_version get_sql_schema_version set_sql_schema_version edit_sqlite upgrade_database lock unlock move_compressed_file get_progname get_simulate get_verboselevel set_progname set_simulate set_verboselevel set_callbacks blank_sql_null close_filehandle create_filehandle disconnect_sqlite filter funcname_to_funcref get_free_filehandle get_my_group global inherit lower_case open_string_for_reading show_sql_transaction split_string start_coproc upper_case validate_command write_sql); our @EXPORT_OK = qw(info process_options); } END { } ######################################################################## # # Public functions # ######################################################################## ######################################################################## # # Public functions: entry point related # ######################################################################## # (none) ######################################################################## # # Public functions: error stack related # ######################################################################## # (none) ######################################################################## # # Public functions: string/stream manipulation functions # ######################################################################## sub is_valid_regexp { my($regexp) = @_; return(defined scalar eval { 'junk' =~ /$regexp/ }); } ######################################################################## # # Public functions: messaging functions # ######################################################################## #DIFFSYNC: internal sub internal { my($text) = @_; _display_message("INTERNAL ERROR: $text", 0, 'crit'); exit 2; } #DIFFSYNC: error sub error { my($text) = @_; _display_message("ERROR: $text", 1, 'err'); exit 1; } #DIFFSYNC: warning sub warning { my($text) = @_; _display_message("WARNING: $text", 2, 'warning'); } #DIFFSYNC: info sub info { my($text) = @_; _display_message("INFO: $text", 3, 'info'); } #DIFFSYNC: debug sub debug { my($level, $text) = @_; ($level =~ /^[1-9][0-9]*$/) or internal("miniade_debug: $level: invalid level"); _display_message("DEBUG[$level]: $text", $level, 'debug'); } #DIFFSYNC: bad_usage sub bad_usage { my($progname); $progname = get_progname(); print STDERR "$progname: ERROR: type '$progname --help' for correct usage.\n"; exit 1; } ######################################################################## # # Public functions: filename manipulation functions # ######################################################################## # (none) ######################################################################## # # Public functions: file handle manipulation functions # ######################################################################## # (none) ######################################################################## # # Public functions: UUID-related # ######################################################################## # (none) ######################################################################## # # Public functions: file content manipulation functions # ######################################################################## # (none) ######################################################################## # # Public functions: option processing # ######################################################################## #DIFFSYNC: process_options sub process_options { my($special_options_handler, $help_handler) = @_; my($version_handler, $list_paths_handler, $standard_options_enabled, $unknown_options_enabled); #def process_options(special_options_handler=None, help_handler=None): #global _verboselevel, _simulate # Defaults for options $help_handler = \&_help_fallback if (not defined $help_handler); $version_handler = \&_version_fallback; $list_paths_handler = \&_paths_fallback; $special_options_handler = \&_special_options_fallback if (not defined $special_options_handler); $standard_options_enabled = 1; $unknown_options_enabled = 0; # Process options (to the process_options() call, not # to the program itself). # (not applicable to function with parameters) # Process arguments # (no arguments 'cos perl function can manipulate @ARGV, unlike in bash) # Sanity checks and derivations # Guts # Process each option on the *calling script's* command line. while (1) { last if ($#ARGV+1 == 0); # Standard options if ($standard_options_enabled and $ARGV[0] =~ /^--debug=(0|[1-9][0-9]*)$/) { $_verboselevel = int $1; } elsif ($standard_options_enabled and $ARGV[0] eq '-d' and $#ARGV+1 >= 2 and $ARGV[1] =~ /^(0|[1-9][0-9]*)$/) { $_verboselevel = int $1; shift @ARGV; } elsif ($standard_options_enabled and $ARGV[0] ~~ ['-n','--simulate']) { $_simulate = 1; } elsif ($ARGV[0] eq '--simulate=true') { $_simulate = 1; } elsif ($ARGV[0] eq '--simulate=false') { $_simulate = 0; } elsif ($standard_options_enabled and $ARGV[0] ~~ ['-v','--verbose']) { $_verboselevel = 3; } elsif ($standard_options_enabled and $ARGV[0] ~~ ['-V','--version']) { &$version_handler(); } elsif ($standard_options_enabled and $ARGV[0] ~~ ['-p','--paths']) { &$list_paths_handler(); } elsif ($ARGV[0] ~~ ['-h','--help']) { &$help_handler(); } elsif ($ARGV[0] eq '--') { shift @ARGV; last; # '-' may be an *argument* indicating to use stdin. } elsif ($ARGV[0] eq '-') { last; # For all non-standard options ... } elsif ($ARGV[0] =~ /^-/) { # ... if special options handler also didn't recognise it ... if (&$special_options_handler() != 0) { # ... if we allow such options (typically when delegated to sub-main-like # function) then just break out of loop, without shifting off ... if ($unknown_options_enabled) { break # ... otherwise error ... } else { bad_usage(); } } # ... and if the special options handler *did* recognise it then # no action needed (the special option handler will have done # any extra shifts itself). # For all non-option-like things just break out of loop so as to # pass them on to *argument* processing. } else { last; } # Shift off the option itself. shift @ARGV; } return 0; } ######################################################################## # # Public functions: special functions # ######################################################################## # (none) ######################################################################## # # Public functions: user related # ######################################################################## # (none) ######################################################################## # # Public functions: process management functions # ######################################################################## #DIFFSYNC: evaler ######################################################################## # # Public functions: temporary file related functions # ######################################################################## # (none) ######################################################################## # # Public functions: database related functions # ######################################################################## # (none) ######################################################################## # # Public functions: variable related functions # ######################################################################## # (none) ######################################################################## # # Public functions: locking related functions # ######################################################################## #DIFFSYNC: lock sub lock { my($lock_file) = @_; my($tmp_lock_file, $fp); $tmp_lock_file = $lock_file . ".$$"; # Create a uniquely named temporary lock file debug(10, 'lock: creating temporary lock file ...'); open $fp, '>', $tmp_lock_file; print $fp "$$\n"; close $fp; # If can easily lock, return debug(10, 'lock: sliding temporary lock into place ...'); if (link $tmp_lock_file, $lock_file) { unlink $tmp_lock_file; return 0; } # If lock is fresh, return debug(10, 'lock: presumable lock file exists; checking if fresh ...'); if (lock_is_fresh($lock_file)) { unlink $tmp_lock_file; return 1; } # Remove empty or stale lock file warning("$lock_file: empty or stale; removing ..."); unlink $lock_file; # If can easily lock, return debug(10, 'lock: again trying sliding temporary lock into place ...'); if (link $tmp_lock_file, $lock_file) { unlink $tmp_lock_file; return 0; } # If we get this far then something when wrong internal("lock: can't lock (hint: try manually running: ln $tmp_lock_file, $lock_file)"); } #DIFFSYNC: unlock sub unlock { my($lock_file) = @_; unlink $lock_file; } #DIFFSYNC: lock_is_fresh sub lock_is_fresh { my($lock_file) = @_; # If lock file not empty and not stale; return if (! -f $lock_file) { debug(10, 'lock_is_fresh: not a file; returning 1 ...'); return 1; } open $fp, '<', $lock_file; $pid = <$fp>; close $fp; if (! -d "/proc/$pid") { return 1 } # If got to here then lock is fresh. return 0; } ######################################################################## # # Public functions: directory content management functions # ######################################################################## # (none) ######################################################################## # # Public functions: miscellaneous # ######################################################################## #DIFFSYNC: check_ssh_ok #DIFFSYNC: validate_command ######################################################################## # # Public functions: access module-private variable # ######################################################################## #DIFFSYNC: get_verboselevel #DIFFSYNC: set_verboselevel #DIFFSYNC: get_simulate #DIFFSYNC: set_simulate #DIFFSYNC: get_progname sub get_progname { #global _progname return $_progname; } #DIFFSYNC: set_progname ######################################################################## # # Module-private functions # ######################################################################## #DIFFSYNC: _display_message sub _display_message { my($text, $level, $syslog_level) = @_; my($writerfunc_ref); #global _display_callback_refs foreach $writerfunc_ref (@_display_callback_refs) { &$writerfunc_ref($text, $level, $syslog_level); } } #DIFFSYNC: _display_message_stderr sub _display_message_stderr { my($text, $level, $syslog_level) = @_; #global _progname, _verboselevel return if ($_verboselevel < $level); print STDERR "$_progname: $text\n" if (-t STDERR); } #DIFFSYNC: _display_message_syslog #DIFFSYNC: _display_message_log_file #DIFFSYNC: _display_message_dev_null #DIFFSYNC: _replace_function #DIFFSYNC: _help_fallback #DIFFSYNC: _version_fallback sub _version_fallback { my($progname); $progname = get_progname(); print "$progname version 0\n"; exit 0; } #DIFFSYNC: _paths_fallback sub _paths_fallback { exit 0; } #DIFFSYNC: _special_options_fallback #DIFFSYNC: _initialise ######################################################################## # # Public variables # ######################################################################## # (none - and keep it that way!) ######################################################################## # # Module-private variables with public access functions # ######################################################################## ($_progname) = ($0 =~ /([^\/]+)$/); $_verboselevel = 2; $_simulate = 0; @_display_callback_refs = ( \&_display_message_stderr ); ######################################################################## # # Other module-private variables # ######################################################################## #_syslog_opened_flag = False ######################################################################## # # Actual code # ######################################################################## #_initialise() # Non-zero module exit code 1;