#!/bin/bash # $Id: diskusage,v 1.11 2005-08-03 19:41:34 jlarsen Exp $ # Copyright 2004 John R Larsen - theClaw56@larsen-family.us # Free for personal use. Contact author for commercial use. # # Description: bash script used to capture disk usage and update a webpage or # send email with the results. Use "diskusage -h" for help. # #------------------------------------------------------------------------------- # get_version. Function that parses script version and date info from the RCS Id line. function get_version () { SCRIPT_VER="v`echo '$Id: diskusage,v 1.11 2005-08-03 19:41:34 jlarsen Exp $' | awk '{print $3}'`" SCRIPT_DATE="`echo '$Id: diskusage,v 1.11 2005-08-03 19:41:34 jlarsen Exp $' | awk '{print $4}'`" } # get_version #------------------------------------------------------------------------------ # display_debug_help: Function to display debug help. function display_debug_help () { local func_name=display_debug_help if [ $(($D & 0x1)) -ne 0 ]; then echo "[$LINENO]$func_name:$$> Inside display_debug_help";fi cat << EOF | more ----- Debug Help ($SCRIPT_VER) --------------------------------------- Debug is enabled in one of three ways in decending order of precedence: "-d 0xNNNN" on command line DISKUSAGE_DEBUG_FLAGS environment variable "debug_flags" file in same directory as diskusage Debug output can be changed "on the fly" by changing the contents of "debug_flags", which is read each time pt goes through its while loop. Each debug line is qualified with a construct like the following: if [ \$((\$D & 0x1)) -ne 0 ]; then echo "[\$LINENO]\$func_name:\$\$> Debug message or action";fi The expression on the left of -ne is a bash construct. The $((expr)) gets evaluated and returns a value. The expression I'm using is "$D & 0xNN". The & performs a bitwise AND and returns the result. If it is zero (no matching bits) then the debug line is skipped. If it is non zero then the debug line is performed. Each debug line can have multiple bits that turn it on or just a single bit. The pattern "0xNN" is the collection of bits that turn the debug on. The action of each bit is defined below. 00000000 - No debug 00000001 - Enable all the "Inside function name" debug lines 00000002 - process_command_line verbose output 00000004 - 00000008 - 00000010 - main: Display environment when starting up 80000000 - Don't output the "Debug flags changed" messages in "set_debug_level" EOF } # display_debug_help #------------------------------------------------------------------------------ # set_debug_level: Function that sets the $D variable based on a file, an #environment variable, or a command line variable. See display_debug_help. function set_debug_level () { local func_name=set_debug_level # Note: Command line -d overrides environment variable DISKUSAGE_DEBUG_FLAGS if it exists, # which overrides debug_flags file if it exists. # Check one time if DISKUSAGE_DEBUG_FLAGS env variable exists and use it if it does if [ "${ENV_VAR_TESTED:=FALSE}" = "FALSE" ]; then ENV_VAR_TESTED=TRUE D=${DISKUSAGE_DEBUG_FLAGS:-0} if [ "$D" != "0" ] && [ $(($D & 0x80000000)) -eq 0 ]; then echo "[$LINENO]$$> ${func_name:-startup}: set_debug_level: Debug flags changed to: $D"; fi fi # Check the existence of a file named "debug_flags" and use it if conditions are right if [ -e debug_flags ]; then if [ "${DEBUG_FLAGS_FILE:=FIRST_READ}" = "FIRST_READ" ]; then # Getting here means the debug_flags file has never been read. DEBUG_FLAGS_FILE=`cat -s debug_flags` if [ "$D" = "0" ]; then # Getting here means $D was zero and the debug_flags contents should be used instead since env variable doesn't exist or has value of 0 D=$DEBUG_FLAGS_FILE if [ "$D" != "0" ] && [ $(($D & 0x80000000)) -eq 0 ]; then echo "[$LINENO]$$> ${func_name:-startup}: set_debug_level: Debug flags changed to: $D"; fi fi else # Read debug_flags file and update $D if the file has changed NEW_DEBUG_FLAGS_FILE=`cat -s debug_flags` if [ $NEW_DEBUG_FLAGS_FILE != $DEBUG_FLAGS_FILE ]; then DEBUG_FLAGS_FILE=$NEW_DEBUG_FLAGS_FILE D=$DEBUG_FLAGS_FILE if [ $(($D & 0x80000000)) -eq 0 ]; then echo "[$LINENO]$$> ${func_name:-startup}: set_debug_level: Debug flags changed to: $D" fi fi fi fi } # set_debug_level #------------------------------------------------------------------------------- # setup_env. Function that determines what OS the script is running on and # setups environment variables accordingly. function setup_env () { local func_name=setup_env if [ $(($D & 0x1)) -ne 0 ]; then echo "[$LINENO]$func_name:$$> Inside setup_env";fi # Figure out which OS you're running on and setup program paths accordingly OS_TYPE=`uname -a | awk '{print $3}'` case $OS_TYPE in 5.8*) # Solaris 8 export DF="/usr/ucb/df" export DU="/usr/bin/du" export HOST=`/usr/ucb/hostname` export LS=/bin/ls export MAIL=/usr/ucb/mail export SCP=/opt/bin/scp export TEE=/usr/bin/tee ;; 2.4*) # Mandrake Linux 8.x and 9.x, Redhat Linux Work Station Enterprise 3 export DF="/bin/df -k" export DU="/usr/bin/du" export HOST=`/bin/hostname` export LS=/bin/ls export MAIL=/bin/mail export SCP=/usr/bin/scp export TEE=/usr/bin/tee ;; 2.6*) # Mandrake Linux 10.x export DF="/bin/df -k" export DU="/usr/bin/du" export HOST=`/bin/hostname` export LS=/bin/ls export MAIL=/bin/mail export SCP=/usr/bin/scp export TEE=/usr/bin/tee ;; 1.5*) # cygwin export TEE=/usr/bin/tee # Base cygwin doesn't include many packages required for backup to work. # Check that these packages have been installed in their default locations. # Make sure the openssh package has been installed if [ -e /usr/bin/scp ]; then export SCP=/usr/bin/scp else echo "ERROR [$LINENO]$func_name> Missing scp. Install the openssh package." exit 1 fi # Make sure the email package has been installed if [ -e /usr/bin/email ]; then MAIL=/usr/bin/email else echo "ERROR [$LINENO]$func_name> Missing email. Install the email package." exit 1 fi export DF="/usr/bin/df -k" export DU="/usr/bin/du" export HOST=`/usr/bin/hostname` export LS=/usr/bin/ls ;; *) # Unknown OS echo "ERROR [$LINENO]$func_name> Unknown OS" exit 1 ;; esac # Set the default values of all environment variables here NUM_REPORTS=10 export WORKING_DIR=`pwd` export CURRENT_DATA=$WORKING_DIR/current_data export HTML_FILE=$WORKING_DIR/diskusage.html # The default for EMAIL_ADDRESS can be overwritten using the -e command line option EMAIL_ADDRESS="" YES=1 NO=0 TRUE=1 FALSE=0 } # setup_env #------------------------------------------------------------------------------ # display_env # Function to display the values of environment variables function display_env () { local func_name=display_env if [ $(($D & 0x1)) -ne 0 ]; then echo "[$LINENO]$func_name:$$> Inside display_env";fi echo "----- CURRENT ENVIRONMENT VARIABLE VALUES -----------------" echo "HOST: $HOST" echo "EMAIL_ADDRESS: $EMAIL_ADDRESS" echo "WORKING_DIR: $WORKING_DIR" echo "CURRENT_DATA: $CURRENT_DATA" echo "HTML_FILE: $HTML_FILE" echo "NUM_REPORTS $NUM_REPORTS" echo "-----------------------------------------------------------" return 0 } # display_env #------------------------------------------------------------------------------ # display_help: Function to display the help screen function display_help () { local func_name=display_help if [ $(($D & 0x1)) -ne 0 ]; then echo "[$LINENO]$func_name:$$> Inside display_help";fi cat << EOF ----- diskusage ($SCRIPT_VER $SCRIPT_DATE) -------------------------------------------- usage: diskusage [ options ] Options: -d 0xN Debug flags value. Use the "-hd" option to see how to use them. -e adr Email address (Default is none) (Separate multiple email addresses with commas and no spaces) -h Help screen -hd Help Debug. This describes how the builtin debugging works. -hs Help setup. This gives detailed operating and setup instructions. -n num Number of previous reports to include (Default: $NUM_REPORTS) You MUST modify these scripts for your situation! -mdf Make template diskusage.df script -mw Make template diskusage.webpage script EOF } # display_help #------------------------------------------------------------------------------ # display_setup_help: Function to display the setup help screen function display_setup_help () { local func_name=display_setup_help if [ $(($D & 0x1)) -ne 0 ]; then echo "[$LINENO]$func_name:$$> Inside display_setup_help";fi cat << EOF DESCRIPTION: This script captures the disk usage and reports it via email or by updating a webpage. EMAIL: "diskusage" sends email to email addresses defined on the command line using the -e option. Multiple email addresses can be used by separating them with a comma and no space. WEBPAGE UPDATE: "diskusage" can update a webpage. If the file "diskusage.webpage" exists in the same directory as the diskusage script, it is used to perform the update. Use "diskusage -mw" to create a template of diskusage.webpage that can be edited for your situation. Complete instructions are included in the file. If this file exists, it is used to updated the webpage each time diskusage runs. DISK USAGE: "diskusage" reports the current disk usage. diskusage uses the "df" command unless it finds the file "diskusage.df" in the same directory as the diskusage script. In a situation with lots of auto mounted drives, the output of "df" can be very lengthy. You can use diskusage.df to perform df only on the drives that you're interested in. Use "diskusage -mdf" to create a template version of this file that you can edit for your situation. CRON OPERATION: It is intended that diskusage be run as a cron task. A typical crontab line is shown below. 01 03 * * * /root/diskusage/diskusage -e theClaw56@comcast.net SUPPORTED PLATFORMS: This script has been used successfully on the following systems: Solaris 8 using bash v2.03.0(1) Mandrake Linux 9.1 using bash v2.05b.0(1) Copyright: 2004 by John R Larsen Free for personal use. Contact the author for commercial use. http://larsen-family.us theClaw56@larsen-family.us EOF } # display_setup_help #------------------------------------------------------------------------------ # process_command_line function process_command_line () { local func_name=process_command_line if [ $(($D & 0x1)) -ne 0 ]; then echo "[$LINENO]$func_name:$$> Inside process_command_line";fi while [ $# -ne 0 ] do case $1 in -d) #debug mode # Command line -d overrides environment variable DISKUSAGE_DEBUG_FLAGS if it exists, which overrides debug_flags file if it exists D=$2 if [ "$D" != "0" ] && [ $(($D & 0x80000000)) -eq 0 ]; then echo "[$LINENO]$func_name:$$> Debug flags changed to: $D"; fi if [ $(($D & 0x200000)) -ne 0 ]; then echo "[$LINENO]$func_name:$$> In case -d"; fi shift ;; -e) #email address if [ $(($D & 0x2)) -ne 0 ]; then echo "[$LINENO]$func_name:$$> In case -e"; fi EMAIL_ADDRESS=$2 shift ;; -h) #show help if [ $(($D & 0x2)) -ne 0 ]; then echo "[$LINENO]$func_name:$$> In case -h"; fi display_help exit;; -hd) #show debug help if [ $(($D & 0x2)) -ne 0 ]; then echo "[$LINENO]$func_name:$$> In case -hd"; fi display_debug_help exit;; -hs) #show setup help if [ $(($D & 0x2)) -ne 0 ]; then echo "[$LINENO]$func_name:$$> In case -hs"; fi display_help >| /tmp/$$.tmp display_setup_help >> /tmp/$$.tmp cat /tmp/$$.tmp | more rm -f /tmp/$$.tmp exit;; -mdf) #make template diskusage.df script if [ $(($D & 0x2)) -ne 0 ]; then echo "[$LINENO]$func_name:$$> In case -mdf"; fi make_template_df echo "Making template diskusage.df script. You MUST modify this for your use." exit;; -mw) #make template diskusage.webpage script if [ $(($D & 0x2)) -ne 0 ]; then echo "[$LINENO]$func_name:$$> In case -mw"; fi make_template_webpage echo "Making template diskusage.webpage script. You MUST modify this for your use." exit;; -n) #number of previous reports to keep if [ $(($D & 0x2)) -ne 0 ]; then echo "[$LINENO]$func_name:$$> In case -n"; fi NUM_REPORTS=$2 shift ;; *) # Unrecognized option display_help echo "ERROR[$LINENO]$func_name> Unrecognized command line option: $1" exit ;; esac # Don't shift command line if processing at last argument if [ $# -ne 0 ]; then shift fi done } # process_command_line #------------------------------------------------------------------------------ # web_page. Function that creates a web page and copies it somewhere periodically. # If the file diskusage.webpage exists then the web page is created and diskusage.webpage # is called with the name of the web page in $1. The diskusage.webpage file is unique # and must be self contained to copy the file where it needs to be. This can # be to another drive on the LAN or could be using scp. Use "diskusage -mw" to make # a template that can be modified for your needs. function web_page () { local func_name=web_page if [ $(($D & 0x1)) -ne 0 ]; then echo "[$LINENO]$func_name:$$> Inside web_page";fi # Check if diskusage.webpage exists and exit if it doesn't if [ ! -e $WORKING_DIR/diskusage.webpage ]; then return; fi # Getting here means diskusage.webpage exists # Build the web page cat << EOF >| $HTML_FILE
EOF cat $CURRENT_DATA >> $HTML_FILE echo "" >> $HTML_FILE # Append previous reports if they exist let count=1 while [ $count -le $NUM_REPORTS ]; do if [ -e previous_data.$count ]; then echo "
" >> $HTML_FILE cat previous_data.$count >> $HTML_FILE echo "" >> $HTML_FILE fi let count=count+1 done echo " " >> $HTML_FILE # Use the diskusage.webpage script in the back ground to transfer the web page where it needs to go. $WORKING_DIR/diskusage.webpage $HTML_FILE & } # web_page #------------------------------------------------------------------------------ # make_template_df: Function to create a template diskusage.df script function make_template_df () { local func_name=make_template_df if [ $(($D & 0x1)) -ne 0 ]; then echo "[$LINENO]$func_name:$$> Inside make_template_df";fi cat << EOF >| diskusage.df #!/bin/bash # Copyright 2004 John R Larsen - theClaw56@larsen-family.us #----- diskusage ($SCRIPT_VER $SCRIPT_DATE) -------------------------------------------- # This is the diskusage.df script called by "diskusage" to get a listing of disk usage. # You don't need this script if the normal output of df is acceptable. If this script # doesn't exist then "diskusage" will use df and capture its output. If you want to limit # the output of df to a few specific directories then use this script. # # Note that you can actually put any commands in this script for which you want to capture # the output. For example, you could also put in the "w" command to get a current listing # of users and machine state. # # The following environment variables are exported by diskusage and can be used in this script: # DF The full path to the df program on the host where the diskusage is running # DU The full path to the du program on the host where the diskusage is running # \$DF EOF # Set execute permissions chmod 755 diskusage.df } # make_template_df #------------------------------------------------------------------------------ # make_template_copy: Function to create a template diskusage.webpage script function make_template_webpage () { local func_name=make_template_webpage if [ $(($D & 0x1)) -ne 0 ]; then echo "[$LINENO]$func_name:$$> Inside make_template_webpage";fi cat << EOF >| diskusage.webpage #!/bin/bash # Copyright 2004 John R Larsen - theClaw56@larsen-family.us #----- diskusage ($SCRIPT_VER $SCRIPT_DATE) -------------------------------------------- # This is the diskusage.webpage script called by "diskusage" to update the website. The # name of the html file is passed in \$1 so that it can be renamed as needed. This is # required if multiple sites are reporting diskusage and all the web pages are in the same # directory on the webserver. # # The following environment variables are exported by diskusage and can be used in this script: # HOST Name of the host performing the diskusage # SCP The full path to the scp program on the host where the script is running # # The copying method will vary depending on how to access the web server. If it # is on the same LAN as the machine running the script, then a simple "cp" command # might work. If the webserver is on a remote machine then it may be necessary # to use "scp" to do the copy using already established public/private RSA key # access. Examples of both are given below. # LAN copy. This simple line copies the file to the correct webserver directory. #cp -f \$1 /var/www/html/diskusage/\${HOST}_diskusage.html # SCP copy. Use this line if transferring the file to a remote webserver. The "-F" option # tells scp to use the named ssh configuration file. Below are the settings that might # be in such a file. See manpage for ssh_config(5) for complete descriptions: # # Host loader # HostName linux-beast # Port = 2222 # UserKnownHostsFile = /home/jlarsen/ssh_tunnel/linux-beast/known_hosts # User = jlarsen # IdentityFile = /home/jlarsen/ssh_tunnel/linux-beast/id_rsa.fhc-beast # # Using the settings above and the private key (with no pass phrase) the transfer can be # done by a cron job. #\$SCP -F /path/to/ssh/config/file \$1 loader:/path/to/webserver/directory/\${HOST}_diskusage.html 2>/dev/null EOF # Set execute permissions chmod 755 diskusage.webpage } # make_template_copy #------------------------------------------------------------------------------ # set_working_dir: Function that sets the WORKING_DIR based on $0 function set_working_dir () { # Configure working directory WORKING_DIR=`dirname $0` if [ "$WORKING_DIR" = "." ]; then WORKING_DIR=`pwd` fi cd $WORKING_DIR } # set_working_dir #------------------------------------------------------------------------------ # main function main () { local func_name=main if [ $(($D & 0x1)) -ne 0 ]; then echo "[$LINENO]$func_name:$$> Inside main";fi setup_env process_command_line $* # Show environment variable values if verbose level is high enough if [ $(($D & 0x10)) -ne 0 ]; then display_env fi # Bump all the previous reports by one let count=$NUM_REPORTS-1 new_num=$NUM_REPORTS while [ $count -gt 0 ]; do if [ -e previous_data.$count ]; then mv previous_data.$count previous_data.$new_num fi let count=count-1 let new_num=new_num-1 done # Save the previous report if it exists if [ -e $CURRENT_DATA ]; then mv $CURRENT_DATA previous_data.1 fi # Capture current disk usage echo "------------------------------- diskusage $SCRIPT_VER $SCRIPT_DATE --------" >| $CURRENT_DATA echo "Disk usage report generated by $HOST" >> $CURRENT_DATA echo "Email sent to: $EMAIL_ADDRESS " >> $CURRENT_DATA echo "Script started at: `date +%Y\-%b\-%d\ %H\:%M\:%S\ %a`" >> $CURRENT_DATA echo "----------------------------------------------------------------" >> $CURRENT_DATA echo "Disk usage:" >> $CURRENT_DATA if [ -e $WORKING_DIR/diskusage.df ]; then source $WORKING_DIR/diskusage.df >> $CURRENT_DATA else echo "`$DF`" >> $CURRENT_DATA fi # Return to the starting directory cd $WORKING_DIR # Send the email if EMAIL_ADDRESS isn't null if [ "$EMAIL_ADDRESS" != "" ]; then # Create the body of the email from current data and previous data echo "CURRENT DISK USAGE:" >| diskusage.email cat $CURRENT_DATA >> diskusage.email # Append previous reports if they exist let count=1 while [ $count -le $NUM_REPORTS ]; do if [ -e previous_data.$count ]; then echo "" >> diskusage.email echo "" >> diskusage.email echo "PREVIOUS DISK USAGE REPORT $count:" >> diskusage.email cat previous_data.$count >> diskusage.email fi let count=count+1 done # Send the email cat diskusage.email | $MAIL -s "diskusage: generated by $HOST" $EMAIL_ADDRESS fi # Copy the webpage over if enabled web_page } # main set_working_dir set_debug_level get_version main $*