#!/bin/sh

# -----------------------------------------------------------------------------
print_usage_and_exit() {
    echo
    echo "Usage: $this_script <exec-name> <pid> <timestamp>"
    echo
    echo -e "\tThis script will accept a core file on stdin and save it in"
    echo -e "\tgzip format to $CORE_FINAL_PATH."
    echo
    exit 1
}

# - MAIN ----------------------------------------------------------------------

# pick up some helper functions
source /ciena/scripts/fault.sh

# Take note of our name as invoked
this_script=$(basename $0)

# Fill variables such as $CORE_FINAL_PATH
#get_core_paths
CORE_INITIAL_PATH=/tmp
CORE_FINAL_PATH=/tmp/corefiles
TMP_STDERR=/tmp/$$.stderr

# Errors should be sent to syslog, as there is no guarantee that stdout or
# stderr will be connected to anything when this script is invoked.
SYSLOG="logger -t $this_script"

# Add appfs to our path so that artamir platforms can find gzip
export PATH=$PATH:/mnt/apps/usr/bin

# check for various help incarnations
case "$1" in
    "-h"|"--help"|"-?") print_usage_and_exit ;;
esac

# Verify that the correct number of parameters were provided
if [ "$#" -ne 3 ] ; then
    echo
    echo "ERROR: missing parameters"
    $SYSLOG "missing parameters"
    print_usage_and_exit
fi

# Grab the parameters provided by the kernel.  These are defined by the
# parameters included in /proc/sys/kernel/core_pattern.
#
thread_name=$1
pid=$2
timestamp=$3

# Use the exe entry in proc to determine the real name of the binary.  This
# allows the correct name to be attached to commands that soft link to a
# binary or change their name using prctl().
#
real_name=$(readlink /proc/$pid/exe)
if [ "$?" -eq "0" ] ; then
    real_name=$(basename $real_name)
else
    real_name=$thread_name
fi

core_initial_file=$CORE_INITIAL_PATH/core.$pid
core_lock_file=$CORE_INITIAL_PATH/core.in.progress
core_final_file=$CORE_FINAL_PATH/core-$real_name-$pid-$timestamp.gz

source /ciena/scripts/krn getenv
family=$(cat /family)
if [ "$KRN_MODE" != "debug" ]; then
    case "$family" in
        "artamir")  NCORES=2 ;;
        "brego")    NCORES=5 ;;
        "caliondo") NCORES=5 ;;
    esac
else
    NCORES=5
fi

# We now make the core file in its final place (flash) so as to reduce
# the temporary RAM needs while coring.  (The original architecture
# kept all cores in RAM disk, and the two-stage process kept
# incomplete cores from being processed too early.)  Core-making is
# slightly faster this way, but you'll have to figure out whether
# they're done yet on your own.  (As a hint, owner-read permission
# will be withheld until the core is completed.)

# First advertise to the world that we're trying to make a core.
# Processes can know that if there is a core file in $CORE_INITIAL_PATH
# that it's not finished yet, and they can react accordingly.  We try to
# mimic the 6.3 core behavior to minimize compatibility problems.

touch $core_initial_file

# Serialize the making of core files.  Eliminates situations where
# flash fills up and _all_ paralleled core files end up truncated and
# thus corrupt.  Done this way all that will fit intact will be so,
# and only the extras are truncated/corrupt.  (We keep them anyway
# because a truncated core file still has useful information in it.)
# The hard-link is used as an atomic test-and-set mutex, this is
# standard Unix script practice for the last thirty years.

waitcount=180	# Three minutes.
while ! ln $core_initial_file $core_lock_file 2>/dev/null; do
    sleep 1
    waitcount=$(expr $waitcount - 1)
    if [ $waitcount -eq 0 ]; then
	$SYSLOG "Too busy, can't make core file $core_final_file"
	rm -f $core_initial_file
	exit
    fi
done

# Do not use nice on the gzip call below if associated corefile is from a 
# SAOS server process crash.  Use of nice on SAOS server crash in the first
# minute of operation was found to result in >10mins to gzip corefile,
# resulting in watchdog expiry and reboot.  This defeats config revert-to-
# defaults defense mechanism.
unset NICE SPID
FIFO=/tmp/fifo/leos/LEOS_IPC_PID

if [ -r "$FIFO" ]; then
    SPID=`cat $FIFO`
fi

if [ "$SPID" -ne $2 ]; then
    NICE=nice
fi

zipcount=$(ls -1 $CORE_FINAL_PATH/core-* 2>/dev/null | wc -l)
if [ "$zipcount" -lt $NCORES ]; then

    echo "Core file for $pid ($(xargs -0 </proc/$pid/cmdline)) being generated..." >/dev/console
    # Make the final file with the special 'incomplete' access permissions.
    mkdir -p -m 0775 $CORE_FINAL_PATH
    umask u-r

    # Run gzip with input from stdin, and send the output to $core_final_file.
    # We choose speed rather than compression density; the size
    # difference is small but the speed difference is immense.
    $NICE gzip -1fc > $core_final_file 2> $TMP_STDERR
    if [ "$?" -ne "0" ] ; then
	$SYSLOG $(cat $TMP_STDERR)
	$SYSLOG "Error making $core_final_file, it may be corrupt."
        write_error=" (core file may have errors)"
    fi
    rm -rf $TMP_STDERR

    # Ensure group accessibility, and mark as 'complete'.
    chmod u+r,g=u $core_final_file
    umask u+r

else
    $SYSLOG "maximum number of core files reached ($NCORES)"
fi

# Finished, release interlocks.
rm -f $core_initial_file $core_lock_file

generate_core_log $real_name $pid $timestamp $core_final_file $thread_name "$write_error"
