#!/bin/ksh # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # bos720 src/bos/usr/sbin/snap/snapcore.sh 1.6.5.4 # # Licensed Materials - Property of IBM # # Restricted Materials of IBM # # COPYRIGHT International Business Machines Corp. 2000,2011 # All Rights Reserved # # US Government Users Restricted Rights - Use, duplication or # disclosure restricted by GSA ADP Schedule Contract with IBM Corp. # # IBM_PROLOG_END_TAG # @(#)43 1.6.5.4 src/bos/usr/sbin/snap/snapcore.sh, cmdsnap, bos720 7/14/11 19:42:36 # COMPONENT_NAME: (cmdsnap) # # FUNCTIONS: snapcore.sh # # ORIGINS: 27 # # (C) COPYRIGHT International Business Machines Corp. 1991, 1994 # All Rights Reserved # Licensed Materials - Property of IBM # # US Government Users Restricted Rights - Use, duplication or # disclosure restricted by GSA ADP Schedule Contract with IBM Corp. # ## [End of PROLOG] # This program gathers all the information required to analyse # core file sucessfully on any machine. ################################################################################ # Algorithm: # 1. Verify core file and exceutable file name passed exists # 2. Make sure specified core file is created by specified # executable # 3. Gather all the libraries used by the program. # 5. Gather information about installed filesets # 6. Calculate the space required # 7. Archive all the files collected using pax command # 8. Compress the archive ############################################################################### # prepend to PATH to prevent unexpected aliasing of commands export PATH="/usr/bin:/etc:/usr/sbin:$PATH" #global variables map_sz=0 # module information list size fileset_sz=0 # fileset list size core_sz=0 # size in bytes of core file exe_sz=0 # size in bytes of exe lib_sz=0 # module sizes total_sz=0 # total working space required errpt_sz=0 # errlog entries for CORE_DUMP doclean="n" dirname="/tmp/snapcore" #location of archive exename="" corename="" l_libs="" #********************************************************************** # GENERAL UTILITY FUNCTIONS * #********************************************************************** Usage () { echo "Usage:\n" echo "snapcore [-dDir] [-r] [< binary name >]\n" } Error() { echo "snapcore cannot continue. Exiting.\n" cleanUp } #follow link until it ends in a file or dir follow_link() { tmp=$1 while [ -h $tmp ];do src=`ls -al $tmp |awk '{print $11}'` path=$(cd `dirname $tmp`; cd `dirname $src`;echo $PWD) [ $? -ne 0 ] && return 1 base=`basename $src` full=$path/$base tmp=$full done l_source=$tmp return 0 } #go one level down -- /a/b/c -> /a/b and track it in var down down1() { p1=`dirname $1` down="$down/.." } # #go one level up -- /a/b/c -> /a/b/c/d and track it in var up down2() { up="/`basename $1`$up" p2=`dirname $1` } #find the no of levels in the path given #eg. /a/b/c has 3, / has 0 # level() { lev=0 d=$1 while [ "$d" != "/" ];do d="`dirname $d`" lev=$((lev+1)) done } #find the relative path of dir2 wrt dir1 #for eg., to go from /a/b/c -> /a/b/d/e - ../d/e # to go from /a/b/c to /a/b/c/d/e - ./d/e #first find the common path by traversing down each path and comparing #then go up the extra dirs if any or .. to go backwards #dir1 and dir2 have to exist # abs2rel() { if [ $# -ne 2 ];then exit 1 fi dir1=$1 dir2=$2 down="." up="" abs_rel="" if [ ! -d $dir1 ];then exit 1 fi if [ ! -d $dir2 ];then exit 1 fi dir1=$(cd $dir1;echo $PWD) dir2=$(cd $dir2;echo $PWD) #get no of levels level $dir1 n1=$lev level $dir2 n2=$lev p1=$dir1 p2=$dir2 if [ $n1 -gt $n2 ];then count=$((n1-n2)) while [ $count -ne 0 ];do down1 $p1 count=$((count-1)) done elif [ $n1 -lt $n2 ];then count=$((n2-n1)) while [ $count -ne 0 ];do down2 $p2 count=$((count-1)) done fi #now find the common dir while true; do if [ "$p1" = "$p2" ];then break fi down1 $p1 down2 $p2 done abs_rel=$down$up return } # Check available space checkSpace () { freespace=`df -k $dirname` freespace=`echo $freespace | awk '{print $11}'` if [ $freespace -lt $total_sz ] then echo "\t\tAvailable space is $freespace kbytes.\n" echo "ERROR: Not enough space Increase the file system size.\n" exit 4; fi echo "\t\tAvailable space is $freespace kbytes\n" } #calculate space required for libraries and executable libSize () { count=`wc -l $mapfile | awk '{print $1}'` if [ $? != 0 ] then echo "Error executing command wc" exit 3; fi let libcount=$count-1 l_libs=`head -$libcount $mapfile` if [ $? != 0 ] then echo "Error executin command head:" exit 3; fi for a in $l_libs do a_sz=`ls -alL $a | awk '{print $5}'` let lib_sz=$lib_sz+$a_sz done # update the map file wih full pathnames and link files echo $l_libs > $mapfile #resolve links and include destination file in the list to archive for a in $l_libs $exename do if [ -h $a ] then follow_link $a if [ $? -ne 0 ];then echo "error when following link for $a" exit 3 fi echo $l_source >> $mapfile fi done # get updated list of libraries and exe l_libs=`cat $mapfile` # get executable file size exe_sz=`ls -alL $exename | awk '{print $5}'` } # remove all temporary files cleanUp () { rm -f $mapfile rm -f $fileset rm -f $readme rm -f $errpt rm -fr $dummydir } # compute space required pass1 () { echo "pass1() in progress .... \n" # parse snapcore_$pid.map and calculate total library sizes echo "\t\tCalculating space required . \n" libSize fileset_sz=`lslpp -l | wc -c | awk '{print $1}'` errpt_sz=`errpt -aJ CORE_DUMP | wc -c | awk '{print $1}'` core_sz=`ls -alL $corename | awk '{print $5}'` let total_sz=$lib_sz+$fileset_sz+$core_sz+$exe_sz+$errpt_sz let total_sz=$total_sz/1024 #size in KB echo "\t\tTotal space required is $total_sz kbytes .. \n" echo "\t\tChecking for available space ...\n" checkSpace echo "pass1 complete.\n" } #collect all the information pass2() { echo "pass2() in progress ....\n" echo "\t\tCollecting fileset information . \n" #collect fileset info in to snapcore_$pid.lvl lslpp -l > $fileset if [ $? != 0 ] then echo " Warning: Could not collect fileset information." fi echo "\t\tCollecting error report of CORE_DUMP errors ..\n" errpt -aJ CORE_DUMP > $errpt if [ $? != 0 ] then echo " Warning: Can't collect error report." fi echo "\t\tCreating readme file .. \n" #create a README file in to snapcore_$pid.read createReadme echo "\t\tCreating archive file ...\n" #create actual archive createArchive echo "pass2 completed.\n" } # General instructions on extracting archive createReadme() { cat << END >$readme General Instructions: The archive generated by snapcore contains all the libraries, including libc.a! It is therefore necessary for the machine where the core file is to be analyzed to be at the same level as the machine where the core file was generated. If, for example, you replace your libc.a with a libc.a that doesn't match your kernel, your machine will not boot! You may wish to examine the snapcore archive before restoring it, and only restore selected files from it. You will need to be the super-user, root, to replace most libraries. END } #create Archive createArchive() { #Refer defect 751630 #fix to make the pax one shot. flist="" slist="" #Add core file to the archive abspath=$(cd `dirname $corename`;echo $PWD); src=`basename $corename` abssrc=$abspath/$src if [ `echo $abspath | grep ^$PWD` ];then #file in or below current dir flist="$flist $corename" else #file is above current dir flist="$flist $corename" slist="$slist -s?$corename?.$corename?" fi #Add README file flist="$flist $readme" slist="$slist -s?$readme?README?" #Add fileset info flist="$flist $fileset" slist="$slist -s?$fileset?lslpp.out?" #Add fileset info flist="$flist $errpt" slist="$slist -s?$errpt?errpt.out?" count=0 #Add executable and libraries listed in map file for a in $exename $l_libs do base_name=`basename $a` if [ -h $a ];then follow_link $a if [ $? -ne 0 ];then echo "error when following link for $a" exit 2 fi abspath=`dirname $l_source` src=`basename $l_source` abssrc=$abspath/$src abslpath=$(cd `dirname $a`;echo $PWD) abslink=$abslpath/`basename $a` dummydir=$dirname/dummy_$$ if [ ! -f $abssrc ] ;then echo "source for link $a ($abssrc) is not a file " cleanUp exit 1 fi [ ! -d $dummydir ] && mkdir $dummydir if [ `echo $abspath | grep ^$PWD` ];then #src at or below current dir abs2rel $PWD $abspath newspath=$abs_rel else #src above current dir newspath=.$abspath fi if [ `echo $abslpath | grep ^$PWD` ];then #link below current dir abs2rel $PWD $abslpath newlpath=$abs_rel else #link is above currnet dir newlpath=.$abslpath fi curdir=$PWD cd $dummydir [ "$newspath" != "." ] && mkdir -p $newspath touch $newspath/$src [ "$newlpath" != "." ] && mkdir -p $newlpath abs2rel $newlpath $newspath cd $newlpath ln -s $abs_rel/$src ./$base_name cd - >/dev/null flist="$flist $dummydir/$newlpath/$base_name" slist="$slist -s?$dummydir/$newlpath/$base_name?$newlpath/$base_name?" cd $curdir else #not a link absdir=`dirname $a` abspath=$(cd $absdir;echo $PWD) abssrc=$abspath/`basename $a` if [ `echo $abspath | grep ^$PWD` ];then #file below current dir abs2rel $PWD $abspath relsrc=$abs_rel/`basename $a` flist="$flist $a" slist="$slist -s?$a?$relsrc?" else flist="$flist $a" slist="$slist -s?$a?.$abssrc?" fi fi done # pax all the files from the list using flist and slist pax -xpax $slist -wf $snapcore $flist if [ $? != 0 ] then echo "Problem encountered while creating archive \n" Error exit 5 fi echo "\t\tCompressing archive file ....\n" #compress the archive compress $snapcore if [ $? != 0 ] then echo "Problem encountered while compressing $snapcore." fi } #parse Arguments, do clean up if -r specified parseArgs () { set -- `getopt rd: $*` if [ "$?" != 0 ] then Usage Error exit 1 fi while [ "$1" != -- ] do case $1 in -r ) doclean=y shift;; -d ) dirname=$2 shift;shift;; * ) echo "Error: Invalid argument" ; Usage; Error;exit 1; esac done shift #skip -- # Do the cleanup first. It might free some space if [ "$doclean" = "y" ] then echo "\nCleaning up in progress .. \n" rm $dirname/snapcore_* 2>/dev/null fi if [ $# = 0 ] && [ "$doclean" = "y" ] then echo "snapcore completed successfully.\n" exit 0 else if [ $# = 0 ] && [ "$doclean" = "n" ] then Usage Error exit 1 fi fi corename=$1 #initialize core file name if [ ! -f $corename ] then echo "Specifiled core file ($corename) does not exist.\n" Usage Error exit 1 fi if [ $# -lt 2 ] #initiliaze executable name then exename="" else exename=$2 fi # creating destination directory if [ ! -d $dirname ] then echo "Creating directory $dirname ...\n" mkdir -p $dirname if [ $? != 0 ] then echo "Cannot create directory $dirname\n" exit 1; fi fi #get full path of snap output dir dirname=$(cd $dirname;echo $PWD) #intialize archive filenames snapcore=$dirname/snapcore_$pid.pax #end Archive #initialize temporary filenames mapfile=$dirname/snapcore_$pid.map # library list fileset=$dirname/snapcore_$pid.lvl # lslpp output readme=$dirname/snapcore_$pid.readme # general instructions errpt=$dirname/snapcore_$pid.errpt # CORE_DUMP errors # Read core file info in to $mapfile /usr/lib/ras/check_core $corename > $mapfile 2>/dev/null # validate core and binary if [ $? != 0 ] then echo "Invalid core file name specified." Usage Error exit 1; fi if [ ! -s $mapfile ] then echo "Could not write data in to $mapfile. Check for filesystem space." Error exit 1; fi # last line in the module list is exe name tmp_exename=`tail -1 $mapfile` if [ $? != 0 ] then echo "Invalid core file." Usage Error exit 1; fi echo "\nCore file \"$corename\" created by \"$tmp_exename\"\n" #locate the program name if [ "$exename" != "" ] then base_exename=`basename $exename` else exename=`which $tmp_exename` base_exename=$tmp_exename fi # make sure specified program and the name contained in core are same. if [ $tmp_exename != $base_exename ] || [ ! -f $exename ] then echo "Specified program file($exename) is not valid.\n" Usage Error exit 1; fi } #main routine # set LANG nvironment export LC_MESSAGES=C # CDPATH environment variable is unset, because it was counter-productive here. unset CDPATH # parse arguments, do cleanup and collect core file information. pid=$$ #parse arguments and initialization parseArgs $@ #calculate space required pass1 #Gather all information pass2 #remove temporary file cleanUp echo "Snapcore completed successfully. Archive created in $dirname.\n" exit 0