Subject: [PATCH] [BZ 99930] dbginfo.sh: enhancements for script execution and man page
From: Wolfgang Taphorn <taphorn@de.ibm.com>

Description:  dbginfo.sh: enhancements for script execution and man page
Symptom:      The result of the data collection does not provide all required
              information which is required to finally analyze the situation.
Problem:      The execution of the script has the following issues
              * The script does not verify if it is running for user root
              * The script does not post any messages into syslog during
                runtime. This makes it quite difficulty to verify, when the
                data collection started and ended.
              * The script does not run in a dedicated locale. The output of
                various tools can include messages in the language which has
                been set by the administrator.
              * Some Linux on System z specific tools are not yet processed
                during data collection, such as lsmem and lschp.
              * Some important configuration files are still not collected,
                such as openssl.conf and openssl.cnf.
              * Some parts in the man page might not be shown properly
Solution:     The following changes are implemented:
              * Added verification if the script is executed for user root
              * Added logging mechanism to print messages into syslog.
              * Added statement for LC_ALL to set the "C" 'standard' locale
              * Added lsmem and lschp for commands being executed
              * Added openssl.conf and openssl.cnf to be collected as
                configuration files
              * Corrected some parts in the man page
Reproduction: Some information how to reproduce the issues
              * Run the script as 'non-root' user. The output will not contain
                all the important information.
              * Run the script and verify if something is stated in syslog,
                when the script is executed.
              * Run the script on a system, where the locale is set to
                'non-en' locale. Some out put of important commands will be
                printed in the non-en locale.
              * Run the data collection and verify that the output of lsmem,
                and lschp and that the config files openssl.conf, and
                openssl.cnf are not collected. 
Upstream-ID:  -
Problem-ID:   99930

Signed-off-by: Wolfgang Taphorn <taphorn@de.ibm.com>
---
 scripts/dbginfo.sh |  167 +++++++++++++++++++++++++++++++----------------------
 1 file changed, 100 insertions(+), 67 deletions(-)

--- a/scripts/dbginfo.sh
+++ b/scripts/dbginfo.sh
@@ -28,6 +28,9 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 ###############################################################################
 
+# Switching to neutral locale
+export LC_ALL=C
+
 # The kernel release version as delivered from uname -r
 readonly KERNEL_RELEASE_VERSION="`uname -r 2>/dev/null`"
 
@@ -44,6 +47,9 @@ readonly TERMINAL="`tty 2>/dev/null`"
 # The processor ID for the first processor
 readonly PROCESSORID=`grep -E ".*processor 0:.*" /proc/cpuinfo | sed 's/.*identification[[:space:]]*\=[[:space:]]*\([[:alnum:]]*\).*/\1/g'`
 
+# The processor version for the first processor
+readonly PROCESSORVERSION=`grep -E ".*processor 0:.*" /proc/cpuinfo | sed 's/.*version[[:space:]]*\=[[:space:]]*\([[:alnum:]]*\).*/\1/g'`
+
 # The current date
 readonly DATETIME=`date +%Y-%m-%d-%H-%M-%S 2>/dev/null`
 
@@ -111,13 +117,13 @@ else
     readonly LINUX_SUPPORT_SYSFSDBF=0
 fi
 
-# Is this Linux on System z under z/VM (0=yes, 1=no)
-if grep -q 'z/VM' /proc/sysinfo 2>/dev/null; then
-    readonly LINUX_ON_ZVM=0
+if test "x${PROCESSORVERSION}" = "xFF" || test "x${PROCESSORVERSION}" = "xff"; then
+    readonly RUNTIME_ENVIRONMENT=`grep -E "VM00.*Control Program.*" /proc/sysinfo| sed 's/.*:[[:space:]]*\([[:graph:]]*\).*/\1/g'`;
 else
-    readonly LINUX_ON_ZVM=1
+    readonly RUNTIME_ENVIRONMENT="LPAR"
 fi
 
+
 ########################################
 
 # Collection of proc fs entries
@@ -178,8 +184,8 @@ fi
 if test ${LINUX_SUPPORT_SYSFSDBF} -eq 1; then
     if test -e /proc/s390dbf; then
 	PROCFILES="${PROCFILES}\
-	  `find /proc/s390dbf -type f -not -path \"*/raw\" -not -path \"*/flush\" 2>/dev/null`\
-	  "
+          `find /proc/s390dbf -type f -not -path \"*/raw\" -not -path \"*/flush\" 2>/dev/null`\
+          "
     fi
 fi
 
@@ -228,10 +234,12 @@ CONFIGFILES="\
   /etc/pam.d\
   /etc/profile\
   /etc/profile.d\
+  /etc/pki/tls/openssl.cnf\
   /etc/rc.d\
   /etc/rc.local\
   /etc/resolv.*\
   /etc/rsyslog.d\
+  /etc/ssl/openssl.conf\
   /etc/sysconfig\
   /etc/sysctl.d\
   /etc/syslog*\
@@ -272,7 +280,9 @@ CMDS="uname -a\
   :multipath -d\
   :multipath -t\
   :lsqeth\
+  :lschp\
   :lscss\
+  :lsmem\
   :lsdasd\
   :ziorep_config -ADM\
   :lsmod\
@@ -370,7 +380,7 @@ collect_cmdsout() {
     local cmd
     local ifs_orig="${IFS}"
 
-    pr_log_stdout " 1 of ${COLLECTION_COUNT}: Collecting command output"
+    pr_syslog_stdout "1 of ${COLLECTION_COUNT}: Collecting command output"
 
     IFS=:
     for cmd in ${CMDS}; do
@@ -391,8 +401,8 @@ collect_vmcmdsout() {
     local module_loaded=1
     local ifs_orig="${IFS}"
 
-    if test ${LINUX_ON_ZVM} -eq 0; then
-	pr_log_stdout " 2 of ${COLLECTION_COUNT}: Collecting z/VM command output"
+    if echo "${RUNTIME_ENVIRONMENT}" | grep -qi "z/VM" >/dev/null 2>&1; then
+	pr_syslog_stdout "2 of ${COLLECTION_COUNT}: Collecting z/VM command output"
 
 	if type vmcp >/dev/null 2>&1; then
 	    cp_command="vmcp"
@@ -406,8 +416,8 @@ collect_vmcmdsout() {
 	    fi
 	else
 	    pr_log_stdout " "
-	    pr_log_stdout "  WARNING: No program found to communicate to z/VM CP"
-	    pr_log_stdout "  WARNING: Skipping the collection of z/VM command output"
+	    pr_log_stdout "WARNING: No program found to communicate to z/VM CP"
+	    pr_log_stdout "WARNING: Skipping the collection of z/VM command output"
 	    pr_log_stdout " "
 	    return 1
 	fi
@@ -437,7 +447,7 @@ collect_vmcmdsout() {
 	    rmmod vmcp
 	fi
     else
-	pr_log_stdout " 2 of ${COLLECTION_COUNT}: Running in LPAR, no z/VM command output collected"
+	pr_syslog_stdout "2 of ${COLLECTION_COUNT}: Collecting z/VM command output skipped - no z/VM environment"
     fi
 
     pr_log_stdout " "
@@ -448,7 +458,7 @@ collect_vmcmdsout() {
 collect_procfs() {
     local file_name
 
-    pr_log_stdout " 3 of ${COLLECTION_COUNT}: Collecting procfs"
+    pr_syslog_stdout "3 of ${COLLECTION_COUNT}: Collecting procfs"
 
     for file_name in ${PROCFILES}; do
 	call_collect_file "${file_name}"
@@ -467,7 +477,7 @@ collect_sysfs() {
 
     # Requires kernel version newer then 2.4
     if test ${LINUX_SUPPORT_SYSFS} -eq 0; then
-	pr_log_stdout " 4 of ${COLLECTION_COUNT}: Collecting sysfs"
+	pr_syslog_stdout "4 of ${COLLECTION_COUNT}: Collecting sysfs"
 	# Requires kernel version of 2.6.13 or newer
 	if test ${LINUX_SUPPORT_SYSFSDBF} -eq 0; then
 	    if ! grep -qE "${MOUNT_POINT_DEBUGFS}.*debugfs" /proc/mounts 2>/dev/null; then
@@ -475,7 +485,7 @@ collect_sysfs() {
 		    sleep 2
 		    debugfs_mounted=1;
 		else
-		    pr_log_stdout "  WARNING: \"Unable to mount debugfs ${MOUNT_POINT_DEBUGFS}\""
+		    pr_log_stdout "WARNING: \"Unable to mount debugfs ${MOUNT_POINT_DEBUGFS}\""
 		fi
 	    fi
 	fi
@@ -487,7 +497,7 @@ collect_sysfs() {
 	done
 
 	find /sys -noleaf -type f -perm /444 2>/dev/null | while IFS= read -r file_name; do
-	    echo "  ${file_name}"
+	    echo " ${file_name}"
 	    dd if="${file_name}" iflag=nonblock of="${WORKPATH}${file_name}"
 	done
 
@@ -495,7 +505,7 @@ collect_sysfs() {
 	    umount "${MOUNT_POINT_DEBUGFS}"
 	fi
     else
-	pr_log_stdout " 4 of ${COLLECTION_COUNT}: Collecting sysfs skipped. Kernel `uname -r` must be newer than 2.4"
+	pr_syslog_stdout "4 of ${COLLECTION_COUNT}: Collecting sysfs skipped. Kernel `uname -r` must be newer than 2.4"
     fi
 
     pr_log_stdout " "
@@ -506,7 +516,7 @@ collect_sysfs() {
 collect_logfiles() {
     local file_name
 
-    pr_log_stdout " 5 of ${COLLECTION_COUNT}: Collecting log files"
+    pr_syslog_stdout "5 of ${COLLECTION_COUNT}: Collecting log files"
 
     for file_name in ${LOGFILES}; do
 	call_collect_file "${file_name}"
@@ -515,11 +525,12 @@ collect_logfiles() {
     pr_log_stdout " "
 }
 
+
 ########################################
 collect_configfiles() {
     local file_name
 
-    pr_log_stdout " 6 of ${COLLECTION_COUNT}: Collecting config files"
+    pr_syslog_stdout "6 of ${COLLECTION_COUNT}: Collecting config files"
 
     for file_name in ${CONFIGFILES}; do
 	call_collect_file "${file_name}"
@@ -536,16 +547,16 @@ collect_osaoat() {
 
     if which qethqoat >/dev/null 2>&1; then
 	if test -n "${network_devices}"; then
-	    pr_log_stdout " 7 of ${COLLECTION_COUNT}: Collecting osa oat output"
+	    pr_syslog_stdout "7 of ${COLLECTION_COUNT}: Collecting osa oat output"
 	    for network_device in "${network_devices}"; do
 		call_run_command "qethqoat ${network_device}" "${OUTPUT_FILE_OSAOAT}.out" &&
 		call_run_command "qethqoat -r ${network_device}" "${OUTPUT_FILE_OSAOAT}_${network_device}.raw"
 	    done
 	else
-	    pr_log_stdout " 7 of ${COLLECTION_COUNT}: Collecting osa oat output skipped - no devices"
+	    pr_syslog_stdout "7 of ${COLLECTION_COUNT}: Collecting osa oat output skipped - no devices"
 	fi
     else
-	pr_log_stdout " 7 of ${COLLECTION_COUNT}: Collecting osa oat output skipped - not available"
+	pr_syslog_stdout "7 of ${COLLECTION_COUNT}: Collecting osa oat output skipped - not available"
     fi
 
     pr_log_stdout " "
@@ -565,16 +576,16 @@ call_run_command() {
 
     # check if command exists
     if ! which "${raw_cmd}" >/dev/null 2>&1; then
-	# check if command is a builtin
+        # check if command is a builtin
 	if ! command -v "${raw_cmd}" >/dev/null 2>&1; then
-	    echo "  WARNING: Command \"${raw_cmd}\" not available" >> "${logfile}"
+	    echo "WARNING: Command \"${raw_cmd}\" not available" >> "${logfile}"
 	    echo >> "${logfile}"
 	    return 1;
 	fi
     fi
 
     if ! eval "${cmd}" >> "${logfile}" 2>&1; then
-	echo "  WARNING: Command \"${cmd}\" failed" >> "${logfile}"
+	echo "WARNING: Command \"${cmd}\" failed" >> "${logfile}"
 	echo >> "${logfile}"
 	return 1
     else
@@ -589,7 +600,7 @@ call_collect_file() {
     local directory_name
     local file_name="${1}"
 
-    echo "  ${file_name}"
+    echo " ${file_name}"
 
     directory_name="`dirname \"${file_name}\" 2>/dev/null`"
     if test ! -e "${WORKPATH}${directory_name}"; then
@@ -610,8 +621,8 @@ call_collect_file() {
 # print version info
 print_version() {
     cat <<EOF
- ${SCRIPTNAME}: Debug information script version %S390_TOOLS_VERSION%
- Copyright IBM Corp. 2002, 2013
+${SCRIPTNAME}: Debug information script version %S390_TOOLS_VERSION%
+Copyright IBM Corp. 2002, 2013
 EOF
 }
 
@@ -625,30 +636,30 @@ print_usage()
     cat <<EOF
 
 
- Usage: ${SCRIPTNAME} [OPTIONS]
+Usage: ${SCRIPTNAME} [OPTIONS]
 
- This script collects runtime, configuration and trace information about
- your Linux on System z installation for debugging purposes.
+This script collects runtime, configuration and trace information about
+your Linux on System z installation for debugging purposes.
 
- It also traces information about z/VM if the Linux runs under z/VM.
+It also traces information about z/VM if the Linux runs under z/VM.
 
 
- The collected information is written to a TAR archive named
+The collected information is written to a TAR archive named
 
-     /tmp/DBGINFO-[date]-[time]-[hostname]-[processorid].tgz
+    /tmp/DBGINFO-[date]-[time]-[hostname]-[processorid].tgz
 
- where [date] and [time] are the date and time when debug data is collected.
- [hostname] indicates the hostname of the system the data was collected from.
- The [processorid] is taken from the processor 0 and indicates the processor
- identification.
+where [date] and [time] are the date and time when debug data is collected.
+[hostname] indicates the hostname of the system the data was collected from.
+The [processorid] is taken from the processor 0 and indicates the processor
+identification.
 
- Options:
+Options:
 
         -h|--help          print this help
         -v|--version       print version information
 
 
- Please report bugs to: linux390@de.ibm.com
+Please report bugs to: linux390@de.ibm.com
 
 EOF
 }
@@ -662,9 +673,9 @@ print_alreadyrunning() {
     cat <<EOF
 
 
- Please check the system if another instance of ${SCRIPTNAME} is already
- running. If this is not the case, please remove the lock file
- '${WORKDIR_BASE}${SCRIPTNAME}.lock'.
+Please check the system if another instance of ${SCRIPTNAME} is already
+running. If this is not the case, please remove the lock file
+'${WORKDIR_BASE}${SCRIPTNAME}.lock'.
 EOF
 }
 
@@ -683,15 +694,15 @@ commandline_parse()
 	    print_version
 	else
 	    echo
-	    echo " ${SCRIPTNAME}: invalid option ${cmdline_arg1}"
-	    echo " Try '${SCRIPTNAME} --help' for more information"
+	    echo "${SCRIPTNAME}: invalid option ${cmdline_arg1}"
+	    echo "Try '${SCRIPTNAME} --help' for more information"
 	    echo
 	    exit 1
 	fi
 	exit 0
     elif test ${cmdline_count} -ge 1; then
 	echo
-	echo " ERROR: Invalid number of arguments!"
+	echo "ERROR: Invalid number of arguments!"
 	echo
 	print_usage
 	exit 1
@@ -706,21 +717,21 @@ environment_setup()
     if test ! -e "${WORKDIR_BASE}"; then
 	mkdir -p "${WORKDIR_BASE}"
     elif test ! -d "${WORKDIR_BASE}"; then
-	echo " ERROR: ${WORKDIR_BASE} exists but this is a file!"
-	echo "        Please make sure ${WORKDIR_BASE} is a directory."
+	echo "ERROR: ${WORKDIR_BASE} exists but this is a file!"
+	echo "       Please make sure ${WORKDIR_BASE} is a directory."
 	exit 1
     fi
 
     if test -e "${WORKDIR_BASE}${SCRIPTNAME}".lock; then
 	print_alreadyrunning
-	exit 1
+        exit 1
     else
 	touch "${WORKDIR_BASE}${SCRIPTNAME}".lock
     fi
 
     if ! mkdir "${WORKPATH}" 2>/dev/null; then
-	echo " ERROR: Target directory ${WORKPATH} already exists or"
-	echo "        ${WORKDIR_BASE} does not exist!"
+	echo "ERROR: Target directory ${WORKPATH} already exists or"
+	echo "       ${WORKDIR_BASE} does not exist!"
 	exit 1
     fi
 }
@@ -730,18 +741,18 @@ environment_setup()
 # create gzip-ped tar file
 create_package()
 {
-    pr_stdout " Finalizing: Creating archive with collected data"
+    pr_stdout "Finalizing: Creating archive with collected data"
     cd "${WORKDIR_BASE}"
 
     if ! tar -czf "${WORKARCHIVE}" "${WORKDIR_CURRENT}"; then
 	pr_stdout " "
-	pr_stdout " ERROR: Collection of data failed!"
-	pr_stdout "        The creation of ${WORKARCHIVE} was not successful."
-	pr_stdout "        Please check the directory ${WORKDIR_BASE}"
-	pr_stdout "        to provide enough free available space."
+	pr_stdout "ERROR: Collection of data failed!"
+	pr_stdout "       The creation of ${WORKARCHIVE} was not successful."
+	pr_stdout "       Please check the directory ${WORKDIR_BASE}"
+	pr_stdout "       to provide enough free available space."
     else
 	pr_stdout " "
-	pr_stdout " Collected data was saved to:"
+	pr_stdout "Collected data was saved to:"
 	pr_stdout " >>  ${WORKARCHIVE}  <<"
     fi
 
@@ -755,14 +766,14 @@ environment_cleanup()
 {
     if ! rm -rf "${WORKPATH}" 2>/dev/null; then
 	pr_stdout " "
-	pr_stdout " WARNING: Deletion of ${WORKPATH} failed"
-	pr_stdout " Please remove the directory manually"
+	pr_stdout "WARNING: Deletion of ${WORKPATH} failed"
+	pr_stdout "Please remove the directory manually"
 	pr_stdout " "
     fi
     if ! rm -f "${WORKDIR_BASE}${SCRIPTNAME}".lock 2>/dev/null; then
 	pr_stdout " "
-	pr_stdout " WARNING: Deletion of ${WORKDIR_BASE}${SCRIPTNAME} failed"
-	pr_stdout " Please remove the file manually"
+	pr_stdout "WARNING: Deletion of ${WORKDIR_BASE}${SCRIPTNAME} failed"
+	pr_stdout "Please remove the file manually"
 	pr_stdout " "
     fi
 }
@@ -773,12 +784,13 @@ environment_cleanup()
 emergency_exit()
 {
     pr_stdout " "
-    pr_stdout " INFO: Data collection has been interrupted"
-    pr_stdout " INFO: Cleanup of temporary collected data"
+    pr_stdout "INFO: Data collection has been interrupted"
+    pr_stdout "INFO: Cleanup of temporary collected data"
     environment_cleanup
-    pr_stdout " INFO: Emergency exit processed"
+    pr_stdout "INFO: Emergency exit processed"
 
     pr_stdout " "
+    logger -t "${SCRIPTNAME}" "Data collection interrupted"
     exit;
 }
 
@@ -800,10 +812,27 @@ pr_log_stdout()
 }
 
 
+########################################
+# Function to print to stdout and into log file when rediretion is active
+pr_syslog_stdout()
+{
+    echo "$@"
+    echo "$@" >&8
+    logger -t ${SCRIPTNAME} "$@"
+}
+
+
 ###############################################################################
 # Running the script
 
 commandline_parse ${*}
+
+# Verification to run as root
+if test `/usr/bin/id -u 2>/dev/null` -ne 0; then
+    echo "ERROR: You must be user root to run ${SCRIPTNAME}!"
+    exit 1
+fi
+
 environment_setup
 print_version
 
@@ -814,11 +843,13 @@ exec 8>&1 9>&2 >${LOGFILE} 2>&1
 trap emergency_exit 1 2 15
 
 pr_log_stdout ""
-pr_log_stdout " Hardware platform     = `uname -i`"
-pr_log_stdout " Kernel version        = ${KERNEL_VERSION}.${KERNEL_MAJOR_REVISION}.${KERNEL_MINOR_REVISION} (`uname -r 2>/dev/null`)"
-pr_log_stdout " Runtime environment   = `test ${LINUX_ON_ZVM} -eq 0 && echo 'z/VM' || echo 'LPAR'`"
+pr_log_stdout "Hardware platform     = `uname -i`"
+pr_log_stdout "Kernel version        = ${KERNEL_VERSION}.${KERNEL_MAJOR_REVISION}.${KERNEL_MINOR_REVISION} (`uname -r 2>/dev/null`)"
+pr_log_stdout "Runtime environment   = ${RUNTIME_ENVIRONMENT}"
 pr_log_stdout ""
 
+logger -t "${SCRIPTNAME}" "Starting data collection"
+
 collect_cmdsout
 
 collect_vmcmdsout
@@ -839,6 +870,8 @@ create_package
 
 environment_cleanup
 
+logger -t "${SCRIPTNAME}" "Data collection completed"
+
 exec 1>&8 2>&9 8>&- 9>&-
 
 #EOF
