#!/bin/sh # Gathers information about system state and creates an lzop # compressed rich core # This file is part of sp-rich-core # # Copyright (C) 2006-2008 Nokia Corporation. # # Contact: Eero Tamminen # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # version 2 as published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA # # Helper functions # _obtain_configuration() { # default fallback values, overruled by configuration file if one exists system_settings=/usr/share/crash-reporter-settings user_settings=/home/user INCLUDE_CORE=true INCLUDE_SYSLOG=true INCLUDE_PKGLIST=true DEFAULT_CORE_NAME="unknown" if [ -e $system_settings/crash-reporter-privacy.conf ]; then . $system_settings/crash-reporter-privacy.conf 2>/dev/null fi if [ -e $user_settings/crash-reporter-privacy.conf ]; then . $user_settings/crash-reporter-privacy.conf 2>/dev/null fi } _parse_arguments() { while [ $# -ge 1 ]; do case $1 in "--no-section-header") NO_SECTION_HEADER=true ;; "--default-name") shift DEFAULT_CORE_NAME="$1" ;; --name=*) argument_core_name=${1#--name=} ;; --pid=*) core_pid=${1#--pid=} ;; --signal=*) core_sig=${1#--signal=} ;; esac shift done } _print_header() { printf '\n[---rich-core: %s---]\n' "$@" } _print_separator() { printf '\n--- %s ---\n' "$@" } _print_file_with_header() { if [ -f $1 ]; then _print_header $1 cat $1 fi } _print_syslog_files_with_header() { _print_header $1 if [ -f /tmp/Xorg.0.log ]; then _print_separator /tmp/Xorg.0.log cat /tmp/Xorg.0.log fi if [ -x /bin/dmesg ]; then _print_separator dmesg /bin/dmesg fi if [ -f $1 ]; then _print_separator $1 cat $1 fi } _print_command_with_header() { _cmd=$1 shift if [ -x ${_cmd} ]; then _print_header ${_cmd##*/} { ${_cmd} $@ 2>&1; } fi } _free_space() { # first we cut the header line with sed # then put everything on one line with tr # (long device name may split the line) # and then pick available space with another sed # -> feel free to optimize # df -k $1 | # sed -e '1d' | # tr '\n' ' ' | # sed -e 's/^[^ ]* *[0-9]* *[0-9]* *\([0-9]*\) *.*$/\1/g' df -k $1 | awk '/\/dev\//{print $4}' } # # Information collection functions # _section_date() { _print_command_with_header /bin/date } _section_proc_fd() { _print_header fd ls -l /proc/${core_pid}/fd/ } _section_proc_smaps() { _print_file_with_header /proc/${core_pid}/smaps } _section_osso_software_version() { _print_file_with_header /tmp/osso_software_version } _section_component_version() { _print_file_with_header /proc/component_version } _section_ifconfig() { _print_command_with_header /sbin/ifconfig -a } _section_df() { _print_command_with_header /bin/df } _section_ls_proc() { _print_header ls_proc ls -l /proc/${core_pid}/ } _section_cmdline() { _print_file_with_header /proc/${core_pid}/cmdline } _section_slabinfo() { _print_file_with_header /proc/slabinfo } _section_xmeminfo() { _print_command_with_header /usr/bin/xmeminfo -d :0 } _section_proc2csv() { _print_command_with_header /usr/bin/proc2csv } _section_packagelist() { _print_header packagelist awk '/^Package:/{printf("%s ",$2)}/^Version:/{print $2}' /var/lib/dpkg/status | /bin/grep -v -e -l10n -e -dbg | sort } _section_syslog() { # as syslog has existed in two different places, try the old one first # to support older releases if [ -e /var/ftd-log/syslog ]; then _print_syslog_files_with_header /var/ftd-log/syslog else _print_syslog_files_with_header /var/log/syslog fi } _section_osso_product_info() { if [ -f /tmp/osso-product-info ]; then _print_file_with_header /tmp/osso-product-info else _print_command_with_header /usr/bin/osso-product-info fi } # # Main program # _obtain_configuration _parse_arguments $* # if dumping disabled in settings, don't bother going further if [ x"${coredumping}" = x"false" ]; then cat > /dev/null exit fi # kludge to avoid coredumps during shutdown # this flag is created by crash-reporter-daemon # when shutdown starts if [ -e /tmp/do_not_dump_rich_cores ]; then # uncomment next line to have list of those you missed by this omission # echo "`date` $argument_core_name" >> /home/user/rich-cores-skipped-during-shutdown.txt cat > /dev/null exit fi # figure out where to dump core for loc in "/media/mmc1" "/home/user/MyDocs" "/media/mmc2" ; do if [ -d $loc/core-dumps ]; then _free=`_free_space $loc/core-dumps` if [ -n "$_free" -a "$_free" -gt 20000 ]; then # more than 20MB free, check can we create a file there touch $loc/core-dumps/testfile retval=$? if [ $retval -eq 0 ]; then rm $loc/core-dumps/testfile core_location="$loc/core-dumps" break; fi fi fi done if [ x"${core_location}" = x ]; then cat > /dev/null exit fi # If invoked from command line, we won't have a valid pid, so a dummy # value is assigned instead if [ x"$NO_SECTION_HEADER" = x"true" ] && [ -z ${core_pid} ]; then core_pid=0 fi # in most cases, corename comes from argument. # if not from there, then try based on /proc/PID core_name="$argument_core_name" if [ "${core_pid}" -gt 0 ]; then # figure out the executable core_exe=`readlink -f /proc/${core_pid}/exe` core_exe_basename=${core_exe##*/} # if process is maemo-invoker, don't create a core if [ x"${core_exe_basename}" = x"maemo-invoker" ]; then cat > /dev/null exit fi if [ -z "${core_name}" ]; then core_tmp=`tr '\0' ' ' < /proc/${core_pid}/cmdline | cut -d' ' -f1` core_name=${core_tmp##*/} fi fi # if still no core name, revert to exe name or "unknown" if [ -z "${core_name}" ]; then if [ -n "${core_exe_basename}" ]; then core_name="${core_exe_basename}" else core_name="$DEFAULT_CORE_NAME" fi fi # Check whether the dump request can be discarded based # on white/blacklisting rules. if [ -e /etc/rich-core.include ]; then /bin/grep -q "${core_name}" /etc/rich-core.include if [ $? -ne 0 ]; then # Not in the whitelist; do not dump a core cat > /dev/null exit fi fi if [ -e /etc/rich-core.exclude ]; then /bin/grep -q "${core_name}" /etc/rich-core.exclude if [ $? -eq 0 ]; then # Is in the blacklist; do not dump a core cat > /dev/null exit fi fi # We will lack the value for the signal if we're invoked from the # script. Provide a dummy value in that case. if [ -z "${core_sig}" ]; then core_sig=0 fi # Make up a wannabe-unique HW ID from two last octets of WLAN MAC mac_suffix=$(ifconfig wlan0 | awk 'BEGIN {FS=":"; RS=" *\n"} {print $6$7; exit}') if [ -z ${mac_suffix} ]; then mac_suffix="xxxx"; fi # Make a naming distinction between oopslogs and rich-cores if [ -n "${IS_OOPSLOG}" ]; then timestamp=$(date +%F-%S) rcorefilename=${core_location}/oopslog-${mac_suffix}-${timestamp} else rcorefilename=${core_location}/${core_name}-${mac_suffix}-${core_sig}-${core_pid} fi # Collect process specific information first, only then system # as process may disappear while this info is collected ( if [ -z "${IS_OOPSLOG}" ] && [ "${core_pid}" -gt 0 ]; then _section_cmdline _section_ls_proc _section_proc_fd _section_proc_smaps fi _section_date _section_osso_software_version _section_component_version _section_df _section_ifconfig if [ -z "${IS_OOPSLOG}" ]; then _section_slabinfo # disable xmeminfo for now as it may hang # _section_xmeminfo _section_proc2csv fi if [ x"$INCLUDE_PKGLIST" = x"true" ]; then _section_packagelist fi if [ x"$INCLUDE_SYSLOG" = x"true" ]; then _section_syslog fi _section_osso_product_info if [ x"$NO_SECTION_HEADER" = x"true" ]; then cat elif [ -n "${IS_OOPSLOG}" ]; then _print_header oopslog cat else if [ x"$INCLUDE_CORE" = x"true" ]; then _print_header coredump cat fi fi ) | lzop > ${rcorefilename}.rcore.lzo # count cores per application if [ ! -d /var/lib/dsme/rich-cores ]; then mkdir -p /var/lib/dsme/rich-cores; fi counterfile=/var/lib/dsme/rich-cores/${core_name} echo $(($(cat $counterfile 2>/dev/null)+1)) > $counterfile