[Asterisk-code-review] ast_coredumper: Refactor to better find things (asterisk[16])
George Joseph
asteriskteam at digium.com
Fri Oct 22 14:12:28 CDT 2021
George Joseph has uploaded this change for review. ( https://gerrit.asterisk.org/c/asterisk/+/16628 )
Change subject: ast_coredumper: Refactor to better find things
......................................................................
ast_coredumper: Refactor to better find things
The search for a running asterisk when --running is used
has been greatly simplified and in the event it doesn't
work, you can now specify a pid to use on the command
line with --pid.
The search for asterisk modules when --tarball-coredumps
is used has been enhanced to have a better chance of finding
them and in the event it doesn't work, you can now specify
--libdir on the command line to indicate the library directory
where they were installed.
Several confusing and conflicting options were removed:
--append-coredumps
--conffile
--no-default-search
The script was re-structured to make it easier for follow.
Change-Id: I674be64bdde3ef310b6a551d4911c3b600ffee59
---
M contrib/scripts/ast_coredumper
1 file changed, 449 insertions(+), 453 deletions(-)
git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/28/16628/1
diff --git a/contrib/scripts/ast_coredumper b/contrib/scripts/ast_coredumper
index 9d9f8bc..9d4b4af 100755
--- a/contrib/scripts/ast_coredumper
+++ b/contrib/scripts/ast_coredumper
@@ -1,46 +1,431 @@
#!/usr/bin/env bash
# Turn on extended globbing
shopt -s extglob
+shopt -s nullglob
# Bail on any error
set -e
prog=$(basename $0)
+# NOTE: <(cmd) is a bash construct that returns a temporary file name
+# from which the command output can be read. In this case, we're
+# extracting the block of text delimited by '#@@@FUNCSSTART@@@'
+# and '#@@@FUNCSEND@@@' from this file and 'source'ing it to
+# get some functions.
+source <(sed -n -r -e "/^#@@@FUNCSSTART@@@/,\${p;/^#@@@FUNCSEND@@@/q}" $0 | sed '1d;$d')
+
+# The "!(*.txt)" is a bash construct that excludes files ending with .txt
+# from the glob match.
+declare -a COREDUMPS=( /tmp/core[-._]asterisk!(*.txt) /tmp/core[-._]$(hostname)!(*.txt) )
+
+# A line starting with ': ' is a bash construct that makes the shell
+# perform the operation but ignore the result. This is an alternative to
+# having to do RUNNING=${RUNNING:=false} to set defaults.
+
+: ${ASTERISK_BIN:=$(which asterisk)}
+: ${DATEFORMAT='date -u +%FT%H-%M-%S%z'}
+: ${DELETE_COREDUMPS_AFTER:=false}
+: ${DELETE_RESULTS_AFTER:=false}
+: ${DRY_RUN:=false}
+: ${GDB:=$(which gdb)}
+: ${HELP:=false}
+: ${LATEST:=false}
+: ${OUTPUTDIR:=/tmp}
+: ${PROMPT:=true}
+: ${RUNNING:=false}
+: ${TARBALL_CONFIG:=false}
+: ${TARBALL_COREDUMPS:=false}
+: ${TARBALL_RESULTS:=false}
+
+COMMANDLINE_COREDUMPS=false
+
+# Read config files from most important to least important.
+# Variables set on the command line or environment always take precedence.
+[ -f ./ast_debug_tools.conf ] && source ./ast_debug_tools.conf
+[ -f ~/ast_debug_tools.conf ] && source ~/ast_debug_tools.conf
+[ -f /etc/asterisk/ast_debug_tools.conf ] && source /etc/asterisk/ast_debug_tools.conf
+
+for a in "$@" ; do
+ if [[ $a == "--RUNNING" ]] ; then
+ RUNNING=true
+ PROMPT=false
+ elif [[ $a =~ --no-([^=]+)$ ]] ; then
+ var=${BASH_REMATCH[1]//-/_}
+ eval ${var^^}="false"
+ elif [[ $a =~ --([^=]+)$ ]] ; then
+ var=${BASH_REMATCH[1]//-/_}
+ eval ${var^^}="true"
+ elif [[ $a =~ --([^=]+)=(.+)$ ]] ; then
+ var=${BASH_REMATCH[1]//-/_}
+ eval ${var^^}=${BASH_REMATCH[2]}
+ else
+ if ! $COMMANDLINE_COREDUMPS ; then
+ COMMANDLINE_COREDUMPS=true
+ COREDUMPS=()
+ fi
+ COREDUMPS+=( "$a" )
+ fi
+done
+
+if $HELP ; then
+ print_help
+ exit 0
+fi
+
+check_gdb
+
+if [ -z "${ASTERISK_BIN}" -o ! -x "${ASTERISK_BIN}" ] ; then
+ die -2 <<-EOF
+ The asterisk binary specified (${ASTERISK_BIN})
+ was not found or is not executable. Use the '--asterisk-binary'
+ option to specify a valid binary.
+ EOF
+fi
+
+if [ $EUID -ne 0 ] ; then
+ die -13 "You must be root to use $prog."
+fi
+
+if [ -z "${OUTPUTDIR}" -o ! -d "${OUTPUTDIR}" ] ; then
+ die -20 "OUTPUTDIR ${OUTPUTDIR} doesn't exists or is not a directory"
+fi
+
+# Timestamp to use for output files
+df=${tarball_uniqueid:-$(${DATEFORMAT})}
+
+if $RUNNING ; then
+ MAIN_PID=$(find_pid)
+ # If find_pid returns an error, the shell will automatically exit.
+
+ # We only want to process the coredump from the running process.
+ COREDUMPS=( )
+
+ msg "Found a single asterisk instance running as process $MAIN_PID"
+
+ if $PROMPT ; then
+ read -p "WARNING: Taking a core dump of the running asterisk instance will suspend call processing while the dump is saved. Do you wish to continue? (y/N) " answer
+ else
+ answer=Y
+ fi
+
+ if [[ "$answer" =~ ^[Yy] ]] ; then
+ cf="${OUTPUTDIR}/core-asterisk-running-$df"
+ echo $(S_COR ${DRY_RUN} "Simulating dumping" "Dumping") " running asterisk process to $cf"
+ if ${DRY_RUN} ; then
+ echo Simulating ${GDB} ${ASTERISK_BIN} -p $MAIN_PID -q --batch --ex "gcore $cf"
+ else
+ ${GDB} ${ASTERISK_BIN} -p $MAIN_PID -q --batch --ex "gcore $cf" >/dev/null 2>&1
+ fi
+ COREDUMPS=( "$cf" )
+ else
+ die -125 "Aborting dump of running process"
+ fi
+else
+
+ # At this point, all glob entries that match files should be expanded.
+ # Any entries that don't exist are probably globs that didn't match anything
+ # and need to be pruned. Any non coredumps are also pruned.
+
+ for i in ${!COREDUMPS[@]} ; do
+ if [ ! -f "${COREDUMPS[$i]}" ] ; then
+ unset COREDUMPS[$i]
+ continue
+ fi
+ # Some versions of 'file' don't allow only the first n bytes of the
+ # file to be processed so we use dd to grab just the first 32 bytes.
+ mimetype=$(dd if="${COREDUMPS[$i]}" bs=32 count=1 2>/dev/null | file -bi -)
+ if [[ ! "$mimetype" =~ coredump ]] ; then
+ unset COREDUMPS[$i]
+ continue
+ fi
+ done
+
+ # Sort and weed out any dups
+ COREDUMPS=( $(ls -t "${COREDUMPS[@]}" 2>/dev/null | uniq ) )
+
+ if [ ${#COREDUMPS[@]} -eq 0 ] ; then
+ die -2 "No coredumps found"
+ fi
+
+ if $LATEST ; then
+ COREDUMPS=( "${COREDUMPS[0]}" )
+ fi
+fi
+
+if [ ${#COREDUMPS[@]} -eq 0 ] ; then
+ die -2 "No coredumps found"
+fi
+
+# Extract the gdb scripts from the end of this script
+# and save them to /tmp/.gdbinit, then add a trap to
+# clean it up.
+gdbinit=${OUTPUTDIR}/.ast_coredumper.gdbinit
+trap "rm $gdbinit" EXIT
+ss=`egrep -n "^#@@@SCRIPTSTART@@@" $0 |cut -f1 -d:`
+tail -n +${ss} $0 >$gdbinit
+
+# Now iterate over the coredumps and dump the debugging info
+for i in "${!COREDUMPS[@]}" ; do
+ cf=$(realpath -e ${COREDUMPS[$i]} || : )
+ if [ -z "$cf" ] ; then
+ continue
+ fi
+ echo "Processing $cf"
+
+ cfname=`basename ${cf}`
+
+ # Produce all the output files
+ ${GDB} -n --batch -q --ex "source $gdbinit" "${ASTERISK_BIN}" "$cf" 2>/dev/null | (
+ of=/dev/null
+ while IFS= read line ; do
+ if [[ "$line" =~ !@!@!@!\ ([^\ ]+)\ !@!@!@! ]] ; then
+ of=${OUTPUTDIR}/${cfname}-${BASH_REMATCH[1]}
+ of=${of//:/-}
+ rm -f "$of"
+ echo "Creating $of"
+ fi
+ echo -e $"$line" >> "$of"
+ done
+ )
+
+ if $TARBALL_COREDUMPS ; then
+ # We need to change occurrences of ':' to '-' because
+ # Jira won't let you attach a file with colons in the name.
+ cfname=${cfname//:/-}
+ tf=${OUTPUTDIR}/${cfname}.tar.gz
+ echo "Creating ${tf}"
+
+ dest=${OUTPUTDIR}/${cfname}.output
+ rm -rf ${dest} 2>/dev/null || :
+
+ libdir=""
+
+ if [ -n "${LIBDIR}" ] ; then
+ LIBDIR=$(realpath "${LIBDIR}")
+ if [ ! -d "${LIBDIR}/asterisk/modules" ] ; then
+ die -2 <<-EOF
+ ${LIBDIR}/asterisk/modules does not exist.
+ The library specified by --libdir or LIBDIR ${LIBDIR})
+ either does not exist or does not contain an "asterisk/modules" directory.
+ EOF
+ fi
+ libdir=${LIBDIR}
+ else
+ abits=$(file -b ${ASTERISK_BIN} | sed -n -r -e "s/.*(32|64)-bit.*/\1/p")
+ declare -a searchorder
+ if [ $abits -eq 32 ] ; then
+ searchorder=( /lib /usr/lib /usr/lib32 /usr/local/lib )
+ else
+ searchorder=( /usr/lib64 /usr/local/lib64 /usr/lib /usr/local/lib /lib )
+ fi
+ for d in ${searchorder[@]} ; do
+ testmod="${d}/asterisk/modules/bridge_simple.so"
+ if [ -e "${testmod}" ] ; then
+ lbits=$(file -b ${ASTERISK_BIN} | sed -n -r -e "s/.*(32|64)-bit.*/\1/p")
+ if [ $lbits -eq $abits ] ; then
+ libdir=$d
+ break;
+ fi
+ fi
+ done
+
+ if [ -z "${libdir}" ] ; then
+ die -2 <<-EOF
+ No standard systemlibrary directory contained asterisk modules.
+ Please specify the correct system library directory
+ with the --libdir option or the LIBDIR variable.
+ ${LIBDIR}/asterisk/modules must exist.
+ EOF
+ fi
+ fi
+
+ mkdir -p ${dest}/tmp ${dest}/${libdir}/asterisk ${dest}/etc ${dest}/usr/sbin
+
+ ln -s ${cf} ${dest}/tmp/${cfname}
+ cp ${OUTPUTDIR}/${cfname}*.txt ${dest}/tmp/
+ [ -f /etc/os-release ] && cp /etc/os-release ${dest}/etc/
+ if $TARBALL_CONFIG ; then
+ cp -a /etc/asterisk ${dest}/etc/
+ fi
+ cp -a /${libdir}/libasterisk* ${dest}/${libdir}/
+ cp -a /${libdir}/asterisk/* ${dest}/${libdir}/asterisk/
+ cp -a /usr/sbin/asterisk ${dest}/usr/sbin
+ rm -rf ${tf}
+ tar -chzf ${tf} --transform="s/^[.]/${cfname}.output/" -C ${dest} .
+ sleep 3
+ rm -rf ${dest}
+ echo "Created $tf"
+ elif $TARBALL_RESULTS ; then
+ cfname=${cfname//:/-}
+ tf=${OUTPUTDIR}/${cfname}.tar.gz
+ echo "Creating ${tf}"
+
+ dest=${OUTPUTDIR}/${cfname}.output
+ rm -rf ${dest} 2>/dev/null || :
+ mkdir -p ${dest}
+ cp ${OUTPUTDIR}/${cfname}*.txt ${dest}/
+ if $TARBALL_CONFIG ; then
+ mkdir -p ${dest}/etc
+ cp -a /etc/asterisk ${dest}/etc/
+ fi
+ tar -chzf ${tf} --transform="s/^[.]/${cfname}/" -C ${dest} .
+ rm -rf ${dest}
+ echo "Created $tf"
+ fi
+
+ if $DELETE_COREDUMPS_AFTER ; then
+ rm -rf "${cf}"
+ fi
+
+ if $DELETE_RESULTS_AFTER ; then
+ rm -rf "${cf//:/-}"-{brief,full,thread1,locks,info}.txt
+ fi
+done
+
+exit
+# @formatter:off
+
+#@@@FUNCSSTART@@@
print_help() {
-cat <<EOF
+ sed -n -r -e "/^#@@@HELPSTART@@@/,\${p;/^#@@@HELPEND@@@/q}" $0 | sed '1d;$d'
+ exit 1
+}
+
+die() {
+ if [[ $1 =~ ^-([0-9]+) ]] ; then
+ RC=${BASH_REMATCH[1]}
+ shift
+ fi
+ if [ -z "$1" ] ; then
+ cat >&2
+ else
+ echo $1 >&2
+ fi
+ exit ${RC:-1}
+}
+
+msg() {
+ if [ -z "$1" ] ; then
+ cat
+ else
+ echo $1
+ fi
+ return 0
+}
+
+S_COR() {
+ if $1 ; then
+ echo -n "$2"
+ else
+ echo -n "$3"
+ fi
+}
+
+check_gdb() {
+ if [ -z "${GDB}" -o ! -x "${GDB}" ] ; then
+ die -2 <<-EOF
+ ${GDB} seems to not be installed.
+ Please install gdb or use the '--gdb' option to
+ point to a valid executable.
+ EOF
+ fi
+
+ result=$($GDB --batch --ex "python print('hello')" 2>/dev/null || : )
+ if [[ ! "$result" =~ ^hello$ ]] ; then
+ die -2 <<-EOF
+ $GDB does not support python.
+ Use the '--gdb' option to point to one that does.
+ EOF
+ fi
+}
+
+find_pid() {
+ if [ -n "$PID" ] ; then
+ echo $PID
+ return 0
+ fi
+
+ # Some versions of pgrep can't display the program arguments
+ # so we'll just get the pids that exactly match a program
+ # name of "asterisk".
+ pids=$( pgrep -d ',' -x "asterisk")
+ if [ -z ${pids} ] ; then
+ die -3 <<-EOF
+ No running asterisk instances detected.
+ If you know the pid of the process you want to dump,
+ supply it on the command line with --pid=<pid>.
+ EOF
+ fi
+
+ # Now that we have the pids, let's get the command and
+ # its args. We'll add them to an array indexed by pid.
+ declare -a candidates
+ while read LINE ; do
+ [[ $LINE =~ ([0-9]+)[\ ]+([^\ ]+)[\ ]+(.*) ]] || continue
+ pid=${BASH_REMATCH[1]}
+ prog=${BASH_REMATCH[2]}
+ args=${BASH_REMATCH[3]}
+ # If you run "asterisk -(rRx)", pgrep will find the process (which we
+ # really don't want) but thankfully, asterisk.c resets argv[0] to
+ # "rasterisk" so the output of ps will show that. This is an easy
+ # filter to weed out remote consoles.
+ [[ "$prog" == "rasterisk" ]] && continue;
+ candidates[$pid]="${prog}^${args}"
+ done < <(ps -o pid= -o command= -p $pids)
+
+ if [ ${#candidates[@]} -eq 0 ] ; then
+ die -3 <<-EOF
+ No running asterisk instances detected.
+ If you know the pid of the process you want to dump,
+ supply it on the command line with --pid=<pid>.
+ EOF
+ fi
+
+ if [ ${#candidates[@]} -gt 1 ] ; then
+ die -22 <<-EOF
+ Detected more than one asterisk process running.
+ $(printf "%8s %s\n" "PID" "COMMAND")
+ $(for p in ${!candidates[@]} ; do printf "%8s %s\n" $p "${candidates[$p]//^/ }" ; done )
+ If you know the pid of the process you want to dump,
+ supply it on the command line with --pid=<pid>.
+ EOF
+ fi
+
+ echo ${!candidates[@]}
+ return 0
+}
+#@@@FUNCSEND@@@
+
+#@@@HELPSTART@@@
NAME
$prog - Dump and/or format asterisk coredump files
SYNOPSIS
- $prog [ --help ] [ --running | --RUNNING ] [ --latest ]
+ $prog [ --help ] [ --running | --RUNNING ] [ --pid="pid" ]
+ [ --latest ] [ --OUTPUTDIR="path" ]
+ [ --libdir="path" ] [ --asterisk-bin="path" ]
+ [ --gdb="path" ]
[ --tarball-coredumps ] [ --delete-coredumps-after ]
[ --tarball-results ] [ --delete-results-after ]
[ --tarball-config ] [ --tarball-uniqueid="<uniqueid>" ]
- [ --no-default-search ] [ --append-coredumps ]
- [ --asterisk-bin="path" ]
[ <coredump> | <pattern> ... ]
DESCRIPTION
Extracts backtraces and lock tables from Asterisk coredump files.
- For each coredump found, 4 new result files are created:
- - <coredump>.brief.txt: The output of "thread apply all bt".
+ For each coredump found, 5 new result files are created:
+ - <coredump>-brief.txt: The output of "thread apply all bt".
- - <coredump>.thread1.txt: The output of "thread apply 1 bt full".
+ - <coredump>-full.txt: The output of "thread apply all bt full".
- - <coredump>.full.txt: The output of "thread apply all bt full".
+ - <coredump>-info.txt: State info like taskprocessors, channels, etc
- - <coredump>.locks.txt: If asterisk was compiled with
+ - <coredump>-locks.txt: If asterisk was compiled with
"DEBUG_THREADS", this file will contain a dump of the locks
table similar to doing a "core show locks" from the asterisk
CLI.
- Optional features:
- - The running asterisk process can be suspended and dumped.
- - The coredumps can be merged into a tarball.
- - The coredumps can be deleted after processing.
- - The results files can be merged into a tarball.
- - The results files can be deleted after processing.
+ - <coredump>-thread1.txt: The output of "thread apply 1 bt full".
Options:
@@ -49,27 +434,48 @@
--running
Create a coredump from the running asterisk instance and
- process it along with any other coredumps found (if any).
+ process it.
WARNING: This WILL interrupt call processing. You will be
- asked to confirm. The coredump will be written to /tmp if
- $OUTPUTDIR is not defined.
+ asked to confirm.
--RUNNING
Same as --running but without the confirmation prompt.
DANGEROUS!!
+ --pid=<asterisk main process pid>
+ If you are trying to get a dump of the running asterisk
+ instance, specifying its pid on the command line will
+ bypass the complex logic used to figure it out.
+
--latest
Process only the latest coredump from those specified (based
- on last-modified time). If a dump of the running process was
- requested, it is always included in addition to the latest
- from the existing coredumps.
+ on last-modified time). Only needed when --running was not
+ specified and there is more that one coredump matched.
+
+ --outputdir=<output directory>
+ The directory into which output products will be saved.
+ Default: same directory as coredump
+
+ --libdir=<shared libs directory>
+ The directory where the libasterisk* shared libraries and
+ the asterisk/modules directory are located. The common
+ directories like /usr/lib, /usr/lib64, etc are automatically
+ searches so oonly use this option if your asterisk install
+ is non-standard.
+
+ --asterisk-bin=<asterisk binary>
+ Path to the asterisk binary.
+ Default: look for asterisk in the PATH.
+
+ --gdb=<path_to_gdb>
+ gdb must have python support built-in. Most do.
+ Default: /usr/bin/gdb
--tarball-coredumps
Creates a gzipped tarball of coredumps processed, their
- results txt files and copies of /etc/os-release,
- /usr/sbin/asterisk, /usr/lib(64)/libasterisk* and
- /usr/lib(64)/asterisk as those files are needed to properly
- examine the coredump. The file will be named
+ results txt files, a copy of /etc/os-release, the
+ asterisk binary, and all modules.
+ The file will be named
$OUTPUTDIR/asterisk.<timestamp>.coredumps.tar.gz or
$OUTPUTDIR/asterisk-<uniqueid>.coredumps.tar.gz if
--tarball-uniqueid was specified.
@@ -88,7 +494,7 @@
--delete-results-after
Deletes all processed results regardless of whether
- a tarball was created. It probably doesn't make sense
+ a tarball was created. It probably does not make sense
to use this option unless you have also specified
--tarball-results.
@@ -101,45 +507,28 @@
but you can use your own unique id in the tarball names
such as the Jira issue id.
- --no-default-search
- Ignore COREDUMPS from the config files and process only
- coredumps listed on the command line (if any) and/or
- the running asterisk instance (if requested).
-
- --append-coredumps
- Append any coredumps specified on the command line to the
- config file specified ones instead of overriding them.
-
- --asterisk-binary
- Path to the asterisk binary. Default: look for asterisk
- in the PATH.
-
<coredump> | <pattern>
- A list of coredumps or coredump search patterns. Unless
- --append-coredumps was specified, these entries will override
- those specified in the config files.
+ A list of coredumps or coredump search patterns. These
+ will override the default and those specified in the config files.
- Any resulting file that isn't actually a coredump is silently
- ignored. If your patterns contains spaces be sure to only
- quote the portion of the pattern that DOESN'T contain wildcard
- expressions. If you quote the whole pattern, it won't be
- expanded.
-
- If --no-default-search is specified and no files are specified
- on the command line, then the only the running asterisk process
- will be dumped (if requested). Otherwise if no files are
- specified on the command line the value of COREDUMPS from
- ast_debug_tools.conf will be used. Failing that, the following
- patterns will be used:
+ The default patterns are:
/tmp/core[-._]asterisk!(*.txt)
/tmp/core[-._]\$(hostname)!(*.txt)
+ The "!(*.txt)" tells bash to ignore any files that match
+ the base pattern and end in ".txt"
+
NOTES
You must be root to use $prog.
- $OUTPUTDIR can be read from the current environment or from the
- ast_debug_tools.conf file described below. If not specified,
- work products are placed in the same directory as the core file.
+ All options except "running", "RUNNING" and "pid" can be
+ specified in the environment or ast_debug_tools.conf file.
+ Option names must be translated to upper case and their '-'
+ characters replaced by '_'. Boolean options must be set to
+ 'true' or 'false' (lower case, without the quotes).
+ Examples:
+ TARBALL_RESULTS=true
+ ASTERISK_BIN=/usr/sbin/asterisk
The script relies on not only bash, but also recent GNU date and
gdb with python support. *BSD operating systems may require
@@ -155,403 +544,10 @@
~/ast_debug_tools.conf
./ast_debug_tools.conf
- #
- # This file is used by the Asterisk debug tools.
- # Unlike other Asterisk config files, this one is
- # "sourced" by bash and must adhere to bash semantics.
- #
+ See the configs/samples/ast_debug_tools.conf file in the asterisk
+ source tree for more info.
- # A list of coredumps and/or coredump search patterns.
- # Bash extended globs are enabled and any resulting files
- # that aren't actually coredumps are silently ignored
- # so you can be liberal with the globs.
- #
- # If your patterns contains spaces be sure to only quote
- # the portion of the pattern that DOESN'T contain wildcard
- # expressions. If you quote the whole pattern, it won't
- # be expanded and the glob characters will be treated as
- # literals.
- #
- # The exclusion of files ending ".txt" is just for
- # demonstration purposes as non-coredumps will be ignored
- # anyway.
- COREDUMPS=(/tmp/core[-._]asterisk!(*.txt) /tmp/core[-._]\$(hostname)!(*.txt))
-
- # The directory to contain output files and work directories.
- # For output from existing core files, the default is the
- # directory that the core file is found in. For core files
- # produced from a running process, the default is /tmp.
- OUTPUTDIR=/some/directory
-
- # Date command for the "running" coredump and tarballs.
- # DATEFORMAT will be executed to get the timestamp.
- # Don't put quotes around the format string or they'll be
- # treated as literal characters. Also be aware of colons
- # in the output as you can't upload files with colons in
- # the name to Jira.
- #
- # Unix timestamp
- #DATEFORMAT='date +%s.%N'
- #
- # *BSD/MacOS doesn't support %N but after installing GNU
- # coreutils...
- #DATEFORMAT='gdate +%s.%N'
- #
- # Readable GMT
- #DATEFORMAT='date -u +%FT%H-%M-%S%z'
- #
- # Readable Local time
- DATEFORMAT='date +%FT%H-%M-%S%z'
-
-EOF
- exit 1
-}
-
-if [ $EUID -ne 0 ] ; then
- echo "You must be root to use $prog."
- exit 1
-fi
-
-running=false
-RUNNING=false
-latest=false
-tarball_coredumps=false
-tarball_config=false
-delete_coredumps_after=false
-tarball_results=false
-delete_results_after=false
-append_coredumps=false
-
-declare -a COREDUMPS
-declare -a ARGS_COREDUMPS
-
-# readconf reads a bash-sourceable file and sets variables
-# that havn't already been set. This allows variables set
-# on the command line or that are already in the environment
-# to take precedence over those read from the file.
-#
-# Setting the values can't be done in a subshell so you can't
-# just pipe the output of sed into the while.
-
-readconf() {
- while read line ; do
- v=${line%%=*}
- [ -z "${!v}" ] && eval $line || :
- done <<EOF
-$( sed -r -e "/\s*#/d" -e "/^\s*$/d" $1 )
-EOF
-}
-
-# Read config files from most important to least important.
-# Variable set on the command line or environment always take precedence.
-[ -f ./ast_debug_tools.conf ] && readconf ./ast_debug_tools.conf
-[ -f ~/ast_debug_tools.conf ] && readconf ~/ast_debug_tools.conf
-[ -f /etc/asterisk/ast_debug_tools.conf ] && readconf /etc/asterisk/ast_debug_tools.conf
-
-# For *BSD, the preferred gdb may be in /usr/local/bin so we
-# need to search for one that supports python.
-for g in $(which -a gdb) ; do
- result=$($g --batch --ex "python print('hello')" 2>/dev/null || : )
- if [[ "$result" =~ ^hello$ ]] ; then
- GDB=$g
- break
- fi
-done
-
-if [ -z "$GDB" ] ; then
- echo "No suitable gdb was found in $PATH"
- exit 1
-fi
-
-if [ -n "$OUTPUTDIR" ] ; then
- if [ ! -d "$OUTPUTDIR" ] ; then
- echo "OUTPUTDIR $OUTPUTDIR doesn't exists or is not a directory"
- exit 1
- fi
-fi
-
-if [ ${#COREDUMPS[@]} -eq 0 ] ; then
- COREDUMPS+=(/tmp/core[-._]asterisk!(*.txt) /tmp/core[-._]$(hostname)!(*.txt))
-fi
-
-DATEFORMAT=${DATEFORMAT:-'date +%FT%H-%M-%S%z'}
-
-# Use "$@" (with the quotes) so spaces in patterns or
-# file names are preserved.
-# Later on when we have to iterate over COREDUMPS, we always
-# use the indexes rather than trying to expand the values of COREDUMPS
-# just in case.
-
-for a in "$@" ; do
- case "$a" in
- --running)
- running=true
- ;;
- --RUNNING)
- RUNNING=true
- ;;
- --no-default-search)
- # Clean out COREDUMPS from config files
- COREDUMPS=()
- ;;
- --latest)
- latest=true
- ;;
- --tarball-coredumps)
- tarball_coredumps=true
- ;;
- --tarball-config)
- tarball_config=true
- ;;
- --delete-coredumps-after)
- delete_coredumps_after=true
- ;;
- --tarball-results)
- tarball_results=true
- ;;
- --delete-results-after)
- delete_results_after=true
- ;;
- --append-coredumps)
- append_coredumps=true
- ;;
- --tarball-uniqueid=*)
- tarball_uniqueid=${a#*=}
- ;;
- --asterisk-bin=*)
- asterisk_bin=${a#*=}
- ;;
- --help|-*)
- print_help
- ;;
- *)
- ARGS_COREDUMPS+=("$a")
- # If any files are specified on the command line, ignore those
- # specified in the config files unless append-coredumps was specified.
- if ! $append_coredumps ; then
- COREDUMPS=()
- fi
- esac
-done
-
-# append coredumps/patterns specified as command line arguments to COREDUMPS.
-for i in ${!ARGS_COREDUMPS[@]} ; do
- COREDUMPS+=("${ARGS_COREDUMPS[$i]}")
-done
-
-# At this point, all glob entries that match files should be expanded.
-# Any entries that don't exist are probably globs that didn't match anything
-# and need to be pruned. Any non coredumps are also pruned.
-
-for i in ${!COREDUMPS[@]} ; do
- if [ ! -f "${COREDUMPS[$i]}" ] ; then
- unset COREDUMPS[$i]
- continue
- fi
- # Some versions of 'file' don't allow only the first n bytes of the
- # file to be processed so we use dd to grab just the first 32 bytes.
- mimetype=$(dd if="${COREDUMPS[$i]}" bs=32 count=1 2>/dev/null | file -bi -)
- if [[ ! "$mimetype" =~ coredump ]] ; then
- unset COREDUMPS[$i]
- continue
- fi
-done
-
-# Sort and weed out any dups
-IFS=$'\x0a'
-readarray -t COREDUMPS < <(echo -n "${COREDUMPS[*]}" | sort -u )
-unset IFS
-
-# If --latest, get the last modified timestamp of each file,
-# sort them, then return the latest.
-if [ ${#COREDUMPS[@]} -gt 0 ] && $latest ; then
- lf=$(find "${COREDUMPS[@]}" -printf '%T@ %p\n' | sort -n | tail -1)
- COREDUMPS=("${lf#* }")
-fi
-
-# Timestamp to use for output files
-df=${tarball_uniqueid:-$(${DATEFORMAT})}
-
-if [ x"$asterisk_bin" = x ]; then
- asterisk_bin=$(which asterisk)
-fi
-
-if $running || $RUNNING ; then
- # We need to go through some gyrations to find the pid of the running
- # MAIN asterisk process and not someone or something running asterisk -r.
-
- unset pid
-
- # Simplest case first...
- pids=$(pgrep -f "$asterisk_bin" || : )
- pidcount=$(echo $pids | wc -w)
-
- # Single process, great.
- if [ $pidcount -eq 1 ] ; then
- pid=$pids
- echo "Found a single asterisk instance running as process $pid"
- fi
-
- # More than 1 asterisk process running
- if [ x"$pid" = x ] ; then
- # More than 1 process running, let's try asking asterisk for it's
- # pidfile
- pidfile=$("$asterisk_bin" -rx "core show settings" 2>/dev/null | sed -n -r -e "s/^\s*pid file:\s+(.*)/\1/gpi")
- # We found it
- if [ x"$pidfile" != x -a -f "$pidfile" ] ; then
- pid=$(cat "$pidfile")
- echo "Found pidfile $pidfile with process $pid"
- fi
- fi
-
- # It's possible that asterisk was started with the -C option which means the
- # control socket and pidfile might not be where we expect. We're going to
- # have to parse the process arguments to see if -C was specified.
- # The first process that has a -C argument determines which config
- # file to use to find the pidfile of the main process.
- # NOTE: The ps command doesn't quote command line arguments that it
- # displays so we need to look in /proc/<pid>/cmdline.
-
- if [ x"$pid" = x ] ; then
- # BSDs might not mount /proc by default :(
- mounted_proc=0
- if uname -o | grep -qi "bsd" ; then
- if ! mount | grep -qi "/proc" ; then
- echo "Temporarily mounting /proc"
- mounted_proc=1
- mount -t procfs proc /proc
- fi
- fi
-
- for p in $pids ; do
- # Fields in cmdline are delimited by NULLs
- astetcconf=$(sed -n -r -e "s/.*\x00-C\x00([^\x00]+).*/\1/gp" /proc/$p/cmdline)
- if [ x"$astetcconf" != x ] ; then
- pidfile=$("$asterisk_bin" -C "$astetcconf" -rx "core show settings" 2>/dev/null | sed -n -r -e "s/^\s*pid file:\s+(.*)/\1/gpi")
- if [ x"$pidfile" != x -a -f "$pidfile" ] ; then
- pid=$(cat "$pidfile")
- echo "Found pidfile $pidfile the hard way with process $pid"
- break
- fi
- fi
- done
- if [ $mounted_proc -eq 1 ] ; then
- echo "Unmounting /proc"
- umount /proc
- fi
- fi
-
- if [ x"$pid" = x ] ; then
- >&2 echo "Can't determine pid of the running asterisk instance"
- exit 1
- fi
-
- if $RUNNING ; then
- answer=Y
- else
- read -p "WARNING: Taking a core dump of the running asterisk instance will suspend call processing while the dump is saved. Do you wish to continue? (y/N) " answer
- fi
- if [[ "$answer" =~ ^[Yy] ]] ; then
- cf="${OUTPUTDIR:-/tmp}/core-asterisk-running-$df"
- echo "Dumping running asterisk process to $cf"
- ${GDB} ${asterisk_bin} -p $pid -q --batch --ex "gcore $cf" >/dev/null 2>&1
- COREDUMPS+=("$cf")
- else
- echo "Skipping dump of running process"
- fi
-fi
-
-if [ "${#COREDUMPS[@]}" -eq 0 ] ; then
- echo "No coredumps found"
- print_help
-fi
-
-# Extract the gdb scripts from the end of this script
-# and save them to /tmp/.gdbinit
-
-gdbinit=${OUTPUTDIR:-/tmp}/.ast_coredumper.gdbinit
-
-trap "rm $gdbinit" EXIT
-
-ss=`egrep -n "^#@@@SCRIPTSTART@@@" $0 |cut -f1 -d:`
-tail -n +${ss} $0 >$gdbinit
-
-# Now iterate over the coredumps and dump the debugging info
-for i in ${!COREDUMPS[@]} ; do
- cf=$(readlink -ne ${COREDUMPS[$i]})
- echo "Processing $cf"
-
- cfdir=`dirname ${cf}`
- cfname=`basename ${cf}`
- outputdir=${OUTPUTDIR:-${cfdir}}
-
- ${GDB} -n --batch -q --ex "source $gdbinit" "$asterisk_bin" "$cf" 2>/dev/null | (
- of=/dev/null
- while IFS= read line ; do
- if [[ "$line" =~ !@!@!@!\ ([^\ ]+)\ !@!@!@! ]] ; then
- of=${outputdir}/${cfname}-${BASH_REMATCH[1]}
- of=${of//:/-}
- rm -f "$of"
- echo "Creating $of"
- fi
- echo -e $"$line" >> "$of"
- done
- )
-
- if $tarball_coredumps ; then
- cfname=${cfname//:/-}
- tf=${outputdir}/${cfname}.tar.gz
- echo "Creating ${tf}"
-
- dest=${outputdir}/${cfname}.output
- rm -rf ${dest} 2>/dev/null || :
-
- libdir=usr/lib
- [ -d /usr/lib64 ] && libdir+=64
- mkdir -p ${dest}/tmp ${dest}/${libdir}/asterisk ${dest}/etc ${dest}/usr/sbin
-
- ln -s ${cf} ${dest}/tmp/${cfname}
- cp ${outputdir}/${cfname}*.txt ${dest}/tmp/
- [ -f /etc/os-release ] && cp /etc/os-release ${dest}/etc/
- if $tarball_config ; then
- cp -a /etc/asterisk ${dest}/etc/
- fi
- cp -a /${libdir}/libasterisk* ${dest}/${libdir}/
- cp -a /${libdir}/asterisk/* ${dest}/${libdir}/asterisk/
- cp -a /usr/sbin/asterisk ${dest}/usr/sbin
- rm -rf ${tf}
- tar -chzf ${tf} --transform="s/^[.]/${cfname}.output/" -C ${dest} .
- sleep 3
- rm -rf ${dest}
- echo "Created $tf"
- elif $tarball_results ; then
- cfname=${cfname//:/-}
- tf=${outputdir}/${cfname}.tar.gz
- echo "Creating ${tf}"
-
- dest=${outputdir}/${cfname}.output
- rm -rf ${dest} 2>/dev/null || :
- mkdir -p ${dest}
- cp ${outputdir}/${cfname}*.txt ${dest}/
- if $tarball_config ; then
- mkdir -p ${dest}/etc
- cp -a /etc/asterisk ${dest}/etc/
- fi
- tar -chzf ${tf} --transform="s/^[.]/${cfname}/" -C ${dest} .
- rm -rf ${dest}
- echo "Created $tf"
- fi
-
-if $delete_coredumps_after ; then
- rm -rf "${cf}"
- fi
-
- if $delete_results_after ; then
- rm -rf "${cf//:/-}"-{brief,full,thread1,locks,info}.txt
- fi
-done
-
-exit
+#@@@HELPEND@@@
# Be careful editng the inline scripts.
# They're space-indented.
--
To view, visit https://gerrit.asterisk.org/c/asterisk/+/16628
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings
Gerrit-Project: asterisk
Gerrit-Branch: 16
Gerrit-Change-Id: I674be64bdde3ef310b6a551d4911c3b600ffee59
Gerrit-Change-Number: 16628
Gerrit-PatchSet: 1
Gerrit-Owner: George Joseph <gjoseph at digium.com>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20211022/129a6a94/attachment-0001.html>
More information about the asterisk-code-review
mailing list