From 91a5dd8e4acde7938ec8603673d47098070ccc35 Mon Sep 17 00:00:00 2001 From: Ruud van der Pas Date: Fri, 22 Jul 2022 06:15:12 -0700 Subject: gprofng: fix bug 29356 - Execution fails if gprofng is not included in PATH gprofng/Changelog: 2022-07-22 Ruud van der Pas PR gprofng/29356 * gp-display-html/gp-display-html.in: fixed a problem to execute gp-display-text in case gprofng is not included in the search path. --- gprofng/gp-display-html/gp-display-html.in | 307 ++++++++++++++++++++++++++--- 1 file changed, 284 insertions(+), 23 deletions(-) (limited to 'gprofng') diff --git a/gprofng/gp-display-html/gp-display-html.in b/gprofng/gp-display-html/gp-display-html.in index 774dbd5..ab21dbb 100644 --- a/gprofng/gp-display-html/gp-display-html.in +++ b/gprofng/gp-display-html/gp-display-html.in @@ -54,8 +54,16 @@ INIT my $TRUE = 1; my $FALSE = 0; +#------------------------------------------------------------------------------ +# Used to ensure correct alignment of columns. +#------------------------------------------------------------------------------ my $g_max_length_first_metric; +#------------------------------------------------------------------------------ +# This variable contains the path used to execute $GP_DISPAY_TEXT. +#------------------------------------------------------------------------------ +my $g_path_to_tools; + #------------------------------------------------------------------------------- # Code debugging flag #------------------------------------------------------------------------------- @@ -282,9 +290,16 @@ sub main #------------------------------------------------------------------------------ # OS commands executed and search paths. #------------------------------------------------------------------------------ - my @selected_os_cmds = qw (rm mv cat hostname locale which printenv ls + my @selected_os_cmds = qw (rm mv cat hostname locale which printenv ls uname readelf mkdir); - my @search_paths_os_cmds = qw (/usr/bin /bin); + my @search_paths_os_cmds = qw ( + /usr/bin + /bin + /usr/local/bin + /usr/local/sbin + /usr/sbin + /sbin + ); #------------------------------------------------------------------------------ # TBD: Eliminate these. @@ -411,6 +426,11 @@ sub main #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ +# Store the absolute path of the command executed. +#------------------------------------------------------------------------------ + my $location_gp_command = $0; + +#------------------------------------------------------------------------------ # The very first thing to do is to quickly determine if the user has enabled # one of the following options and take action accordingly: # --version, --verbose, --debug, --quiet @@ -695,10 +715,30 @@ sub main gp_message ("debug", $subr_name, "base_va_executable = $base_va_executable"); #------------------------------------------------------------------------------ -# The gp-display-text tool is critical and has to be available in order to proceed. +# The $GP_DISPLAY_TEXT tool is critical and has to be available in order +# to proceed. +# This subroutine only returns a value if the tool can be found." #------------------------------------------------------------------------------ - $ignore_value = check_availability_tool (); + $g_path_to_tools = ${ check_availability_tool (\$location_gp_command)}; + + $GP_DISPLAY_TEXT = $g_path_to_tools . $GP_DISPLAY_TEXT; + gp_message ("debug", $subr_name, "updated GP_DISPLAY_TEXT = $GP_DISPLAY_TEXT"); + +#------------------------------------------------------------------------------ +# Check if $GP_DISPLAY_TEXT is executable for user, group, and other. +# If not, print a warning only, since this may not be fatal but could +# potentially lead to issues later on. +#------------------------------------------------------------------------------ + if (not is_file_executable ($GP_DISPLAY_TEXT)) + { + my $msg = "file $GP_DISPLAY_TEXT is not executable for user, group, and other"; + gp_message ("warning", $subr_name, $msg); + } + +#------------------------------------------------------------------------------ +# Find out what the decimal separator is, as set by the user. +#------------------------------------------------------------------------------ ($return_code, $decimal_separator, $convert_to_dot) = determine_decimal_separator (); @@ -711,7 +751,7 @@ sub main } else { - my $msg = "the decimal separator can not be determined - set to $decimal_separator"; + my $msg = "the decimal separator cannot be determined - set to $decimal_separator"; gp_message ("warning", $subr_name, $msg); } @@ -1275,10 +1315,11 @@ sub calculate_target_hex_address } #-- End of subroutine calculate_target_hex_address #------------------------------------------------------------------------------ -# This subroutine sets the absolute path to all commands in array @cmds. The -# commands and their respective paths are stored in hash "g_mapped_cmds". +# Sets the absolute path to all commands in array @cmds. The commands and +# their respective paths are stored in hash "g_mapped_cmds". # -# It is a fatal error if such a path can't be found. +# If no such mapping is found, a warning is issued, but execution continues. +# The warning(s) may help with troubleshooting, should a failure occur later. #------------------------------------------------------------------------------ sub check_and_define_cmds { @@ -1311,7 +1352,7 @@ sub check_and_define_cmds $found_match = $FALSE; for my $path (@search_path) { - $target_cmd = $path."/".$cmd; + $target_cmd = $path . "/" . $cmd; if (-x $target_cmd) { $found_match = $TRUE; @@ -1335,9 +1376,12 @@ sub check_and_define_cmds { if ($mapped eq "road_to_nowhere") { - gp_message ("error", $subr_name, "cannot find a path for command $cmd"); + my $msg = "cannot find a path for command $cmd - " . + "assume this will still work without a path"; + gp_message ("warning", $subr_name, $msg); $no_of_failed_mappings++; $failed_cmds .= $cmd; + $g_mapped_cmds{$cmd} = $cmd; } else { @@ -1346,8 +1390,8 @@ sub check_and_define_cmds } if ($no_of_failed_mappings != 0) { - gp_message ("error", $subr_name, "failed to find a mapping for $failed_cmds"); - gp_message ("error", $subr_name, "a total of $no_of_failed_mappings mapping failures"); + gp_message ("debug", $subr_name, "failed to find a mapping for $failed_cmds"); + gp_message ("debug", $subr_name, "a total of $no_of_failed_mappings mapping failures"); } return ($no_of_failed_mappings); @@ -1552,29 +1596,93 @@ sub check_and_proc_dis_func_call # Check for the $GP_DISPLAY_TEXT tool to be available. This is a critical tool # needed to provide the information. If it can not be found, execution is # terminated. +# +# We first search foe this tool in the current execution directory. If it +# cannot be found there, use $PATH to try to locate it. #------------------------------------------------------------------------------ sub check_availability_tool { my $subr_name = get_my_name (); - my $target_cmd; - my $output_which_gp_display_text; + my ($location_gp_command_ref) = @_; + my $error_code; + my $error_occurred; + my $msg; + my $output_which_gp_display_text; + my $return_value; + my $target_cmd; - $target_cmd = $g_mapped_cmds{"which"} . " $GP_DISPLAY_TEXT 2>&1"; +#------------------------------------------------------------------------------ +# Get the path to gp-display-text. +#------------------------------------------------------------------------------ + my ($error_occurred_ref, $return_value_ref) = find_path_to_gp_display_text ( + $location_gp_command_ref + ); + $error_occurred = ${ $error_occurred_ref}; + $return_value = ${ $return_value_ref}; - ($error_code, $output_which_gp_display_text) = execute_system_cmd ($target_cmd); - - if ($error_code == 0) + $msg = "error_occurred = $error_occurred return_value = $return_value"; + gp_message ("debugXL", $subr_name, $msg); + + if (not $error_occurred) +#------------------------------------------------------------------------------ +# All is well and gp-display-text has been located. +#------------------------------------------------------------------------------ { - gp_message ("debug", $subr_name, "tool $GP_DISPLAY_TEXT is in the search path"); - } + $g_path_to_tools = $return_value; + + $msg = "located $GP_DISPLAY_TEXT in execution directory"; + gp_message ("debug", $subr_name, $msg); + $msg = "g_path_to_tools = $g_path_to_tools"; + gp_message ("debug", $subr_name, $msg); + } else +#------------------------------------------------------------------------------ +# Something went wrong, but perhaps we can still continue. Try to find +# $GP_DISPLAY_TEXT through the search path. +#------------------------------------------------------------------------------ { - gp_message ("abort", $subr_name, "fatal error executing command $target_cmd"); - } + $msg = "error accessing $GP_DISPLAY_TEXT: $return_value - " . + "run time behaviour may be undefined"; + gp_message ("warning", $subr_name, $msg); + +#------------------------------------------------------------------------------ +# Check if we can find $GP_DISPLAY_TEXT in the search path. +#------------------------------------------------------------------------------ + $msg = "check for $GP_DISPLAY_TEXT in search path"; + gp_message ("debug", $subr_name, $msg); - return (0); + $target_cmd = $g_mapped_cmds{"which"} . " $GP_DISPLAY_TEXT 2>&1"; + + ($error_code, $output_which_gp_display_text) = + execute_system_cmd ($target_cmd); + + if ($error_code == 0) + { + my ($gp_file_name, $gp_path, $suffix_not_used) = + fileparse ($output_which_gp_display_text); + $g_path_to_tools = $gp_path; + + $msg = "using $GP_DISPLAY_TEXT in $g_path_to_tools instead"; + gp_message ("warning", $subr_name, $msg); + + $msg = "the $GP_DISPLAY_TEXT tool is in the search path"; + gp_message ("debug", $subr_name, $msg); + $msg = "g_path_to_tools = $g_path_to_tools"; + gp_message ("debug", $subr_name, $msg); + } + else + { + $msg = "failure to find $GP_DISPLAY_TEXT in the search path"; + gp_message ("debug", $subr_name, $msg); + + $msg = "fatal error executing command $target_cmd"; + gp_message ("abort", $subr_name, $msg); + } + } + + return (\$g_path_to_tools); } #-- End of subroutine check_availability_tool @@ -3875,6 +3983,58 @@ sub find_keyword_in_string } #-- End of subroutine find_keyword_in_string #------------------------------------------------------------------------------ +# Retrieve the absolute path that was used to execute the command. This path +# is used to execute gp-display-text later on. +#------------------------------------------------------------------------------ +sub find_path_to_gp_display_text +{ + my $subr_name = get_my_name (); + + my ($full_command_ref) = @_; + + my $full_command = ${ $full_command_ref }; + + my $error_occurred = $TRUE; + my $return_value; + +#------------------------------------------------------------------------------ +# Get the path name. +#------------------------------------------------------------------------------ + my ($gp_file_name, $gp_path, $suffix_not_used) = fileparse ($full_command); + + gp_message ("debug", $subr_name, "full_command = $full_command"); + gp_message ("debug", $subr_name, "gp_path = $gp_path"); + + my $gp_display_text_instance = $gp_path . $GP_DISPLAY_TEXT; + +#------------------------------------------------------------------------------ +# Check if $GP_DISPLAY_TEXT exists, is not empty, and executable. +#------------------------------------------------------------------------------ + if (not -e $gp_display_text_instance) + { + $return_value = "file not found"; + } + else + { + if (is_file_empty ($gp_display_text_instance)) + { + $return_value = "file is empty"; + } + else + { +#------------------------------------------------------------------------------ +# All is well. Capture the path. +#------------------------------------------------------------------------------ + $error_occurred = $FALSE; + $return_value = $gp_path; + } + } + + return (\$error_occurred, \$return_value); + +} #-- End of subroutine find_path_to_gp_display_text + +#------------------------------------------------------------------------------ # Scan the command line to see if the specified option is present. # # Two types of options are supported: options without a value (e.g. --help) or @@ -9272,6 +9432,107 @@ sub is_file_empty } #-- End of subroutine is_file_empty +#------------------------------------------------------------------------------ +# Check if a file is executable and return $TRUE or $FALSE. +#------------------------------------------------------------------------------ +sub is_file_executable +{ + my $subr_name = get_my_name (); + + my ($filename) = @_; + + my $file_permissions; + my $index_offset; + my $is_executable; + my $mode; + my $number_of_bytes; + my @permission_settings = (); + my %permission_values = (); + + chomp ($filename); + + gp_message ("debug", $subr_name, "check if filename = $filename is executable"); + + if (not -e $filename) + { +#------------------------------------------------------------------------------ +# The return value is used in the caller. This is why we return the empty +# string in case the file does not exist. +#------------------------------------------------------------------------------ + gp_message ("debug", $subr_name, "filename = $filename not found"); + $is_executable = $FALSE; + } + else + { + $mode = stat ($filename)->mode; + + gp_message ("debugXL", $subr_name, "mode = $mode"); +#------------------------------------------------------------------------------ +# Get username. We currently do not do anything with this though and the +# code is commented out. +# +# my $my_name = getlogin () || getpwuid($<) || "Kilroy";; +# gp_message ("debug", $subr_name, "my_name = $my_name"); +#------------------------------------------------------------------------------ + +#------------------------------------------------------------------------------ +# Convert file permissions to octal, split the individual numbers and store +# the values for the respective users. +#------------------------------------------------------------------------------ + $file_permissions = sprintf("%o", $mode & 07777); + + @permission_settings = split (//, $file_permissions); + + $number_of_bytes = scalar (@permission_settings); + + gp_message ("debugXL", $subr_name, "file_permissions = $file_permissions"); + gp_message ("debugXL", $subr_name, "permission_settings = @permission_settings"); + gp_message ("debugXL", $subr_name, "number_of_settings = $number_of_bytes"); + + if ($number_of_bytes == 4) + { + $index_offset = 1; + } + elsif ($number_of_bytes == 3) + { + $index_offset = 0; + } + else + { + my $msg = "unexpected number of $number_of_bytes bytes " . + "in permission settings: @permission_settings"; + gp_message ("assertion", $subr_name, $msg); + } + + $permission_values{user} = $permission_settings[$index_offset++]; + $permission_values{group} = $permission_settings[$index_offset++]; + $permission_values{other} = $permission_settings[$index_offset]; + +#------------------------------------------------------------------------------ +# The executable bit should be set for user, group and other. If this fails +# we mark the file as not executable. Note that this is gprofng specific. +#------------------------------------------------------------------------------ + $is_executable = $TRUE; + for my $k (keys %permission_values) + { + my $msg = "permission_values{" . $k . "} = " . + $permission_values{$k}; + gp_message ("debugXL", $subr_name, $msg); + + if ($permission_values{$k} % 2 == 0) + { + $is_executable = $FALSE; + last; + } + } + } + + gp_message ("debug", $subr_name, "is_executable = $is_executable"); + + return ($is_executable); + +} #-- End of subroutine is_file_executable + #------------------------------------------------------------------------------- # TBD. #------------------------------------------------------------------------------- -- cgit v1.1