#!/usr/bin/bash -p
# ^ -p protects us from shellshock

realdir ()
{
    # print the canonical path of a directory, resolving symlinks in
    # the way. On files, it will just echo back the argument.
    if [ -d "$1" ]; then
        ( cd "$1" && pwd -P )
    else
        echo "$1"
        return 1
    fi
}

check_cert()
{
    CERT=$1
    echo "***** Certificate: $CERT"
    if [ -r $CERT ]; then
        openssl x509 -in $CERT -text -noout
    else
        echo "Can't read $CERT"
    fi
    echo ""
}

tail_log()
{
    LOG=$1
    LINES=$2
    if [ -r $LOG ]; then
        echo "***** $LOG (last $LINES lines)"
        tail --lines=$LINES $LOG
    else
        echo "***** $LOG (doesn't exist)"
    fi
    echo ""
}

dump_file()
{
    FILE=$1
    if [ -r $FILE ]; then
        echo "***** $FILE"
        cat $FILE
    else
        echo "***** $FILE (doesn't exist)"
    fi
    echo ""
}

dump_files_that_exist()
{
    local FILENAME
    for FILENAME in "$@"; do
        if [[ -f $FILENAME ]]; then
            dump_file "$FILENAME"
        fi
    done
}

dump_files_in_dir()
{
    DIR=$1
    echo "***** Files in $DIR"
    if [ -L $DIR ]; then
        REAL_DIR=$(realdir "$DIR")
        echo "(symbolic link to $REAL_DIR)"
    else
        REAL_DIR=$DIR
    fi

    if [ -d $REAL_DIR ]; then
        find $REAL_DIR \
            ! -name 'osg-profile.txt*' \
            -type f -print0 | sort -z | xargs -0 bash -c '
                for X in "$@"; do
                    echo "File: $X"; cat "$X"; echo
                done' -
    else
        echo "$REAL_DIR can't be read as a directory"
    fi
    echo ""
}

list_directory()
{
    DIR=$1
    echo "***** Contents of $DIR"
    if [ -L $DIR ]; then
        REAL_DIR=$(realdir "$DIR")
        echo "(symbolic link to $REAL_DIR)"
    else
        REAL_DIR=$DIR
    fi

    if [ -d $REAL_DIR ]; then
        ls -laF $REAL_DIR
    else
        echo $REAL_DIR
    fi
    echo ""
}

run_cmd()
{
    CMD=$1
    shift
    OPTIONS=$@

    echo "***** Running: $CMD $OPTIONS"
    which $CMD > /dev/null 2>&1
    if [ $? -eq 0 ]; then
        $CMD $OPTIONS
    else
        echo $?
        echo "Cannot find $CMD."
    fi
    echo ""
}

message() {
    echo "$@" >&3
}

python_info () {
    local python=$1
    $python -c "import sys; print('Version: ' + sys.version)"
    $python -c "import sys; print('Executable: ' + sys.executable)"
    $python -c "import sys; print('Prefix: ' + sys.prefix)"
    $python -c 'import platform; print("Architecture: " + str(platform.architecture()))'
    $python -c "import sys; print('Search paths: ' + str(sys.path))"
    echo "------"
}


cconfig_dump_systemd () {
    local instance="$1"
    local executable="$2"

    local service="${executable}@${instance}.service"
    local servicep="${executable}-privileged@${instance}.service"
    local active
    local activep
    local enabled
    local enabledp

    [[ $(systemctl is-active "$service")   == active  ]] && active=1
    [[ $(systemctl is-active "$servicep")  == active  ]] && activep=1
    [[ $(systemctl is-enabled "$service")  == enabled ]] && enabled=1
    [[ $(systemctl is-enabled "$servicep") == enabled ]] && enabledp=1

    if [[ ! ( $active || $activep || $enabled || $enabledp ) ]]; then
        # This service is neither enabled nor active. Skip it; we don't care
        return 0
    fi

    echo -n "***** XRootD cconfig for executable $executable, instance $instance ("
    if [[ $activep ]]; then
        echo -n "active (privileged)"
    elif [[ $active ]]; then
        echo -n "active"
    else
        echo -n "inactive"
    fi
    echo -n ", "
    if [[ $enabledp ]]; then
        echo -n "enabled (privileged)"
    elif [[ $enabled ]]; then
        echo -n "enabled"
    else
        echo -n "disabled"
    fi
    echo ")"

    if [[ $enabled && $enabledp ]]; then
        echo "WARNING! Both $service and $servicep are enabled; this may result in conflicts"
    fi
    if [[ $active && $activep ]]; then
        echo "WARNING! Both $service and $servicep are active; this may result in conflicts"
    fi

    cconfig -x "$executable" -h "$(hostname -f)" -n "$instance" -c "/etc/xrootd/xrootd-${instance}.cfg" 2>&1 \
        | grep -v "^Config continuing with file "
    echo
}


dir=`pwd`

if [ ! -w $dir ]; then
    echo "I'm sorry, I don't have permission to create osg-profile.txt"
    echo "in the current directory. Please change into a directory where"
    echo "you have permission, or switch to a user that does have permission"
    exit 1
fi

tmpd=$(mktemp -d)
trap 'rm -rf "$tmpd"' EXIT

tmplog=$tmpd/osg-profile.txt

# Redirect remaining output to $tmplog; send any status messages (via the
# message function) to console (stdout)
exec 3>&2 > "$tmplog" 2>&1

# Determine whether we are profiling a tarball install or an rpm install
# based on whether or not $OSG_LOCATION is defined.

# XXX This will falsely identify an OSG 1.2 install as a tarball install
tarball_install=false
rpm_install=true
if [[ -n $OSG_LOCATION ]]; then
    tarball_install=true
    rpm_install=false
fi

message "OSG System Profiler"
if $tarball_install; then
    message "Analyzing tarball install with OSG_LOCATION=$OSG_LOCATION..."
    echo "OSG System Profile (tarball OSG_LOCATION=$OSG_LOCATION)"
elif $rpm_install; then
    message "Analyzing RPM install..."
    echo "OSG System Profile (RPM)"
fi

echo Created at `date`
echo ""

run_cmd hostname -f
run_cmd uname -a

dump_file "/etc/redhat-release"
dump_file "/etc/nsswitch.conf"
dump_file "/etc/hosts"

run_cmd df --human-readable --print-type
run_cmd free


if which update-crypto-policies &>/dev/null; then
    echo "***** Crypto Policy"
    update-crypto-policies --show 2>&1
else
    echo "***** Crypto Binary not found..."
fi

dump_file "/proc/cpuinfo"

run_cmd netstat -i

if [ root = `whoami` ]; then
    run_cmd /sbin/iptables -vL
else
    echo "***** No iptables info (user was not root)"
fi

dump_file "/etc/selinux/config"
dump_file "/selinux/enforce"


if which selinuxenabled &>/dev/null && selinuxenabled; then
    echo "***** SELinux audit log"
    # Change the section marker of the sealert output to avoid clashing with
    # our section markers.
    sealert -a /var/log/audit/audit.log | sed -e 's/^[*][*][*][*][*]/******/'
fi


if $rpm_install; then
    rpm -qa | grep "^osg" | sort | xargs --no-run-if-empty -n 1 rpm -q
    echo ""

    tail_log /var/log/osg/osg-configure.log 200
    dump_files_in_dir "/etc/osg/config.d"
fi

# XRootD cconfig dumps for available instances
if command -v cconfig &>/dev/null; then
    for file in /etc/xrootd/xrootd-*.cfg
    do
        instance=${file#/etc/xrootd/xrootd-}
        instance=${instance%.cfg}

        cconfig_dump_systemd "$instance" "xrootd"
        cconfig_dump_systemd "$instance" "cmsd"
    done
fi
echo "***** Xrootd information:"
for file in /etc/xrootd/xrootd-*.cfg
do
    dump_file $file
done
dump_files_in_dir "/etc/xrootd/config.d"

echo "***** Showing processes owned by the user xrootd"
ps -u xrootd u
echo ""

echo "***** Python information:"

for python in "$(command -v python)" "$(command -v python2)" "$(command -v python3)" "/usr/libexec/platform-python"; do
    if [[ -n $python && -x $python ]]; then
        python_info "$python"
    fi
done

run_cmd openssl version

if $tarball_install; then
    dump_file $OSG_LOCATION/setup.sh
    dump_file $OSG_LOCATION/setup.csh
fi

echo "***** Running: /usr/bin/env | sort"
/usr/bin/env | sort
echo ""

list_directory "${OSG_LOCATION-}/etc/grid-security"
if $rpm_install; then
    check_cert "/etc/grid-security/hostcert.pem"
    check_cert "/etc/grid-security/rsv/rsvcert.pem"
    check_cert "/etc/grid-security/voms/vomscert.pem"

    run_cmd rpm -q --whatprovides grid-certificates
fi

list_directory "${OSG_LOCATION-}/etc/grid-security/certificates"

echo "***** Enabled gratia probe cronjobs"
if [[ -x /etc/cron.d ]]; then
    perl -n - /etc/cron.d/* <<"__END__"
BEGIN {
    our $pattern = qr{(?xm) ^ \s* [^#] .* gratia/ (?:probe/)? ([^/]+) /};
    our $found = 0;
    our $output = sprintf("%-20s %s\n", 'Probe', 'In File');
}

if ( $_ =~ $pattern ) {
    $found = 1;
    my $probename = $1;
    my $shortfilename = $ARGV;
    $shortfilename =~ s{^/etc/cron.d/}{};
    $output .= sprintf("%-20s %s\n", $probename, $shortfilename);
}

END {
    if ($found) {
        print $output;
    } else {
        print "None\n"
    }
}
__END__
else
    echo "Could not look in /etc/cron.d"
fi


if $rpm_install; then
    PATH=$PATH:/usr/libexec/osg-system-profiler
    if type -f gratia-pbs-lsf-config-check &>/dev/null && rpm -q gratia-probe-pbs-lsf &>/dev/null; then
        echo "***** Gratia PBS/LSF config check"
        gratia-pbs-lsf-config-check
    fi

    dump_file "/etc/grid-security/gsi-authz.conf"
    dump_file "/etc/lcmaps.db"

    dump_file "/etc/yum.conf"

    dump_files_in_dir "/etc/yum.repos.d/"

    dump_files_in_dir "/etc/globus/"

    tail_log /var/log/gridftp.log 200
    tail_log /var/log/gridftp-auth.log 200

    # List all RPMs and verify them. Put the listing and the verification in
    # separate sections.  Verification only lists modified RPMs.
    message "Verifying RPMs. This may take a while."

    all_rpms_log=$(mktemp $dir/allrpmslog.XXXXXX)
    rpm_verify_log=$(mktemp $dir/rpmverifylog.XXXXXX)

    width=$(( ${COLUMNS:-80} - 1 ))
    rpm -qa | grep -v kernel-devel | sort -u | while read rpm_to_verify; do
        if [[ -t 3 ]]; then
            printf "%-${width}s\r" "$rpm_to_verify" >&3
        else
            message -n .
        fi
        echo $rpm_to_verify >> $all_rpms_log

        # This awk trick prints out the header iff rpm --verify actually produces output
        rpm --verify $rpm_to_verify 2> /dev/null | awk '
            NR==1 { print "***** rpm --verify '$rpm_to_verify'" }
            { print }' >> $rpm_verify_log
    done
    message ""
    echo "***** All RPMs"
    cat $all_rpms_log
    echo ""
    cat $rpm_verify_log

    rm -f $all_rpms_log $rpm_verify_log
fi

if $tarball_install; then
    dump_file "$OSG_LOCATION"/etc/fetch-crl*.conf
fi

log=$dir/"osg-profile.txt"
if [ -e $log ]; then
    message "Backing up old $log to $log.bak"
    mv -f "$log" "$log.bak"
fi
mv -f "$tmplog" "$log"

message ""
message "Your system profile is located in:"
message "  $log"
message ""
message "If you are having problems with your installation, please create a"
message "ticket by sending email to help@osg-htc.org."
message ""
message "You should attach $log to the ticket."
message ""
message "You may also follow one of the other methods for getting help"
message "listed at:"
message "  https://osg-htc.org/docs/common/help/"
message ""

echo Finished at `date`

exit 0
