# vim: filetype=sh
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
# $FreeBSD$
#
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "@(#)logapi.kshlib 1.2 07/03/14 SMI"
#
#
# This is a ksh function library. It is intended to be sourced into
# other ksh scripts and not executed directly.
#
. ${STF_SUITE}/include/stf.shlib
#
# Send a debug message to stderr, if $STF_DEBUG set.
#
function log_debug
{
[ -z "$STF_DEBUG" ] && return
echo "$*" >&2
}
# Output an assertion
#
# $@ - assertion text
function log_assert
{
_printline ASSERTION: "$@"
}
# Output a comment
#
# $@ - comment text
function log_note
{
_printline NOTE: "$@"
}
# Execute a positive test and exit $STF_FAIL is test fails
#
# $@ - command to execute
function log_must
{
log_pos "$@"
(( $? != 0 )) && log_fail
}
# Execute a command that must exit $1
#
# $@ - command to execute
function log_mustbe
{
typeset exitcode_wanted=$1
shift
log_cmd "$@"
(( $? != $exitcode_wanted )) && log_fail
}
# Execute a negative test and exit $STF_FAIL if test passes
#
# $@ - command to execute
function log_mustnot
{
log_neg "$@"
(( $? != 0 )) && log_fail
}
# Execute a command that should only be logged if it fails.
#
# $@ - command to execute
function log_onfail
{
eval $@
typeset status=$?
[ $status -eq 0 ] && return
_printerror "$@" "unexpectedly exited $status"
}
# Execute and print command with status where success equals non-zero result
# or output includes expected keyword
#
# $2-$@ - command to execute
#
# Summary: execute $@. Return 1 if any of the following hold:
# 1) The command exited 0, 127, 138, or 139
# 2) The command's stderr included "internal error" or
# "assertion failed"
#
# return 0 if command fails, or the output contains the keyword expected,
# return 1 otherwise
function log_neg
{
typeset out=""
typeset logfile="$TMPDIR/log.$$"
typeset ret=1
while [[ -e $logfile ]]; do
logfile="$logfile.$$"
done
"$@" 2>$logfile
typeset status=$?
out="/bin/cat $logfile"
# unexpected status
if (( $status == 0 )); then
print -u2 $($out)
_printerror "$@" "unexpectedly exited $status"
# missing binary
elif (( $status == 127 )); then
print -u2 $($out)
_printerror "$@" "unexpectedly exited $status (File not found)"
# bus error - core dump
elif (( $status == 138 )); then
print -u2 $($out)
_printerror "$@" "unexpectedly exited $status (Bus Error)"
# segmentation violation - core dump
elif (( $status == 139 )); then
print -u2 $($out)
_printerror "$@" "unexpectedly exited $status (SEGV)"
else
$out | /usr/bin/egrep -i "internal error|assertion failed" \
> /dev/null 2>&1
# internal error or assertion failed
if (( $? == 0 )); then
print -u2 $($out)
_printerror "$@" "internal error or assertion failure" \
" exited $status"
else
ret=0
fi
if (( $ret == 0 )); then
[[ -n $LOGAPI_DEBUG ]] && print $($out)
_printsuccess "$@" "exited $status"
fi
fi
_recursive_output $logfile "false"
return $ret
}
# Execute and print command; unconditionally return its exit code.
# Useful for code that needs to do more specialized exit status filtering.
function log_cmd
{
typeset logfile="$TMPDIR/log.$$"
while [[ -e $logfile ]]; do
logfile="$logfile.$$"
done
"$@" 2>$logfile
typeset status=$?
_printline "EXECUTED (exited $status): $@"
_recursive_output $logfile "false"
return $status
}
# Execute and print command with status where success equals zero result
#
# $@ command to execute
#
# Summary: run $@. return 1 if its exit status was nonzero or if it printed
# "internal error" or "assertion failed" to stderr.
# print stderr on failure or if LOGAPI_DEBUG is set.
#
# return command exit status
function log_pos
{
typeset out=""
typeset logfile="$TMPDIR/log.$$"
while [[ -e $logfile ]]; do
logfile="$logfile.$$"
done
"$@" 2>$logfile
typeset status=$?
out="/bin/cat $logfile"
if (( $status != 0 )) ; then
print -u2 $($out)
_printerror "$@" "exited $status"
else
$out | /usr/bin/egrep -i "internal error|assertion failed" \
> /dev/null 2>&1
# internal error or assertion failed
if [[ $? -eq 0 ]]; then
print -u2 $($out)
_printerror "$@" "internal error or assertion failure" \
" exited $status"
status=1
else
[[ -n $LOGAPI_DEBUG ]] && print $($out)
_printsuccess "$@"
fi
fi
_recursive_output $logfile "false"
return $status
}
# Set an exit handler
#
# $@ - function(s) to perform on exit
function log_onexit
{
_CLEANUP="$@"
}
#
# Exit functions
#
# Perform cleanup and exit $STF_PASS
#
# $@ - message text
function log_pass
{
_endlog $STF_PASS "$@"
}
# Perform cleanup and exit $STF_FAIL
#
# $@ - message text
function log_fail
{
_endlog $STF_FAIL "$@"
}
# Perform cleanup and exit $STF_UNRESOLVED
#
# $@ - message text
function log_unresolved
{
_endlog $STF_UNRESOLVED "$@"
}
# Perform cleanup and exit $STF_NOTINUSE
#
# $@ - message text
function log_notinuse
{
_endlog $STF_NOTINUSE "$@"
}
# Perform cleanup and exit $STF_UNSUPPORTED
#
# $@ - message text
function log_unsupported
{
_endlog $STF_UNSUPPORTED "$@"
}
# Perform cleanup and exit $STF_UNTESTED
#
# $@ - message text
function log_untested
{
_endlog $STF_UNTESTED "$@"
}
# Perform cleanup and exit $STF_UNINITIATED
#
# $@ - message text
function log_uninitiated
{
_endlog $STF_UNINITIATED "$@"
}
# Perform cleanup and exit $STF_NORESULT
#
# $@ - message text
function log_noresult
{
_endlog $STF_NORESULT "$@"
}
# Perform cleanup and exit $STF_WARNING
#
# $@ - message text
function log_warning
{
_endlog $STF_WARNING "$@"
}
# Perform cleanup and exit $STF_TIMED_OUT
#
# $@ - message text
function log_timed_out
{
_endlog $STF_TIMED_OUT "$@"
}
# Perform cleanup and exit $STF_OTHER
#
# $@ - message text
function log_other
{
_endlog $STF_OTHER "$@"
}
#
# Internal functions
#
# Perform cleanup and exit
#
# Summary: Runs any cleanup routine registered with log_onexit. Prints a
# message and exits $1. Note: the _recursive_output does
# nothing, because the rest of this api guarantees that the
# logfile will not exist.
# $1 - stf exit code
# $2-$n - message text
function _endlog
{
typeset logfile="$TMPDIR/log.$$"
_recursive_output $logfile
export STF_EXITCODE=$1
shift
(( ${#@} > 0 )) && _printline "$@"
if [[ -n $_CLEANUP ]] ; then
typeset cleanup=$_CLEANUP
log_onexit ""
log_note "Performing local cleanup via log_onexit ($cleanup)"
$cleanup
fi
exit $STF_EXITCODE
}
# Output a formatted line
#
# $@ - message text
function _printline
{
print `/bin/date +%H:%M:%S` "$@"
}
# Output an error message
#
# $@ - message text
function _printerror
{
_printline ERROR: "$@"
}
# Output a success message
#
# $@ - message text
function _printsuccess
{
_printline SUCCESS: "$@"
}
# Output logfiles recursively
#
# $1 - start file
# $2 - indicate whether output the start file itself, default as yes.
function _recursive_output #logfile
{
typeset logfile=$1
while [[ -e $logfile ]]; do
if [[ -z $2 || $logfile != $1 ]]; then
/bin/cat $logfile
fi
/bin/rm -f $logfile
logfile="$logfile.$$"
done
}