]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
update baculabackupreport script
authorEric Bollengier <eric@baculasystems.com>
Fri, 26 Mar 2021 15:08:07 +0000 (16:08 +0100)
committerEric Bollengier <eric@baculasystems.com>
Fri, 26 Mar 2021 15:34:25 +0000 (16:34 +0100)
bacula/scripts/baculabackupreport.in [changed mode: 0755->0644]

old mode 100755 (executable)
new mode 100644 (file)
index e9a4f0e..fe9996d
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/dash
 #
 # baculabackupreport.sh
 #
 server="@hostname@"
 admin="@job_email@"
 bcbin="@sbindir@/bconsole"
-sendmail="/usr/sbin/sendmail"
+sendmail="/usr/bin/sendmail"
 bcconfig="@sysconfdir@/bconsole.conf"
+baculafd="" # Wildcard client(s) to report on - default is any/all clients
+hist="24"   # Default history in hours if not specified on command line
 
 # Database variables
 # ------------------
-dbtype="@DEFAULT_DB_TYPE@"                          # Supported options are pgsql/postgresql, mysql, mariadb
-db="@db_name@"
-dbuser="@db_user@"
-dbbindir="/usr/bin"
-# dbpass="-p@db_password@"   # Uncomment and set db password if one is used
+dbtype="@DEFAULT_DB_TYPE@"                                                     # Supported options are sqlite, mysql, pgsql, mariadb
+# dbfile="/catalog/bacula.db" # Uncomment and set to Bacula sqlite3 catalog database file
+db="@db_name@"                                                                 # Not needed for sqlite
+dbuser="@db_user@"                                                     # Not needed for sqlite
+dbbin="/usr/bin/psql"
+# dbpass="-p@db_password@"                             # Uncomment and set db password if one is used. Also not needed for sqlite
 
 # Formatting variables
 # --------------------
-html="yes"                                                                              # Generate HTML emails instead of plain text emails?
-boldstatus="yes"                                                        # Set <b> tag on Status field (only if html="yes")
-colorstatusbg="yes"                                             # Colorize the Status cell's background? (only if html="yes")
-
-jobtableheadercolor="#b0b0b0"   # Background color for the HTML table's header
-jobtablejobcolor="#f4f4f4"              # Background color for the job rows in the HTML table
-runningjobcolor="#4d79ff"                       # Background color of the Status cell for "Running" jobs
-goodjobcolor="#00f000"                          # Background color of the Status cell for "OK" jobs
-warnjobcolor="#ffff00"                          # Background color of the Status cell for "OK" jobs (with warnings - well, actually with 'joberrors')
-badjobcolor="#cc3300"                                   # Background color of the Status cell for "bad" jobs
-goodjobwitherrcolor="#cccc00"   # Background color of the Status cell for "OK" jobs (with errors) - Not implemented due to request
-
-fontfamily="Verdana, Arial, Helvetica, sans-serif"      # Set the font family to use for HTML emails
-fontsize="16px"                                                         # Set the font size to use for email title and print summaries
-fontsizejobinfo="12px"                          # Set the font size to use for job information inside of table
-fontsizesumlog="10px"                                   # Set the font size of bad logs and job summaries
-
-printsummary="yes"                                              # Print a short summary after the job list table? (Total Jobs, Files & Bytes)
-emailsummaries="no"                                             # Email all job summaries. Be careful with this, it can generate very large emails
-emailbadlogs="yes"                                              # Email logs of bad jobs or jobs with JobErrors -ne 0. Be careful, this can generate very large emails.
-addsubjecticon="yes"                                    # Prepend the email Subject with UTF-8 icons (a 'checkmark', 'circle with slash', or a bold 'x')
-nojobsicon="=?utf-8?Q?=E2=8A=98?="              # utf-8 subject icon when no jobs have been run
-goodjobsicon="=?utf-8?Q?=E2=9C=94?="    # utf-8 subject icon when all jobs were "OK"
-badjobsicon="=?utf-8?Q?=E2=9C=96?="             # utf-8 subject icon when there are jobs with errors etc
-starbadjobids="yes"                                             # Prepend an asterisk "*" to jobids of "bad" jobs
-sortfield="EndTime"                                             # Which catalog db field to sort on? Multiple,fields,work,here
-sortorder="DESC"                                                        # Which direction to sort?
-emailtitle="Jobs Run On ${server} in the Past ${1} Hours"       # This is prepended at the top of the email, before the jobs table
+# Toggles and other miscellaneous settings
+# ----------------------------------------
+html="yes"                                                                             # Generate HTML emails instead of plain text emails?
+boldjobname="yes"                                                      # Bold the Job Name in HTML emails?
+centerjobname="yes"                                            # Center the Job Name in HTML emails?
+boldstatus="yes"                                                       # Set <b> tag on Status field (only if html="yes")
+colorstatusbg="yes"                                            # Colorize the Status cell's background? (only if html="yes")
+printsummary="yes"                                             # Print a short summary after the job list table? (Total Jobs, Files & Bytes)
+emailsummaries="no"                                            # Email all job summaries. Be careful with this, it can generate very large emails
+emailbadlogs="no"                                                      # Email logs of bad jobs or jobs with JobErrors -ne 0. Be careful, this can generate very large emails.
+addsubjecticon="yes"                                   # Prepend the email Subject with UTF-8 icons (a 'checkmark', 'circle with slash', or a bold 'x')
+addsubjectrunningorcreated="yes"                       # Append "(## jobs still runnning/queued)" to Subject if > running or queued job > 0
+nojobsicon="=?utf-8?Q?=E2=8A=98?="             # utf-8 subject icon when no jobs have been run
+# goodjobsicon="=?utf-8?Q?=E2=9C=94?=" # utf-8 subject icon when all jobs were "OK"
+# goodjobsicon="=?UTF-8?Q?=E2=9C=94=EF=B8=8F?="        # Alternate (better) utf-8 subject icon when all jobs were "OK"
+goodjobsicon="=?UTF-8?Q?=E2=9C=85?="   # Alternate (better) utf-8 subject icon when all jobs were "OK"
+badjobsicon="=?utf-8?Q?=E2=9C=96?="            # utf-8 subject icon when there are jobs with errors etc
+starbadjobids="yes"                                            # Prepend an asterisk "*" to jobids of "bad" jobs
+sortfield="JobId"                                                      # Which catalog db field to sort on? Multiple,fields,work,here
+sortorder="DESC"                                                       # Which direction to sort?
+emailtitle="Jobs run on ${server} in the past ${1} hours"      # This is prepended at the top of the email, before the jobs table
+
+# HTML colors
+# -----------
+jobtableheadercolor="#b0b0b0"  # Background color for the HTML table's header
+jobtablejobcolor="#f4f4f4"             # Background color for the job rows in the HTML table
+runningjobcolor="#4d79ff"                      # Background color of the Status cell for "Running" jobs
+createdjobcolor="#add8e6"                      # Background color of the Status cell for "Created, but not yet running" jobs
+goodjobcolor="#00f000"                         # Background color of the Status cell for "OK" jobs
+# warnjobcolor="#ffff00"                               # (yellow) background color of the Status cell for "OK" jobs (with warnings - well, actually with 'joberrors')
+warnjobcolor="#ffc800"                         # Alternate (orange) background color of the Status cell for "OK" jobs (with warnings - well, actually with 'joberrors')
+badjobcolor="#cc3300"                                  # Background color of the Status cell for "bad" jobs
+errorjobcolor="#cc3300"                                # Background color of the Status cell for jobs with errors
+goodjobwitherrcolor="#cccc00"  # Background color of the Status cell for "OK" jobs (with errors) - Not implemented due to request
+
+# HTML fonts
+# ----------
+fontfamily="Verdana, Arial, Helvetica, sans-serif"     # Set the font family to use for HTML emails
+fontsize="16px"                                                                # Set the font size to use for email title and print summaries
+fontsizejobinfo="12px"                         # Set the font size to use for job information inside of table
+fontsizesumlog="10px"                                  # Set the font size of bad logs and job summaries
 
 
 # --------------------------------------------------
@@ -93,616 +109,905 @@ emailtitle="Jobs Run On ${server} in the Past ${1} Hours"       # This is prepen
 # --------------------------------------------------
 
 
-hist=${1}
-if [ -z ${hist} ]; then
-        echo -e "\nUSE:\n$0 <history in hours>\n"
-        exit 1
+# Check to see if there are command line variables,
+# and if there are, attempt to assign  them to
+# baculafd, admin (email), and hist  variables
+# -------------------------------------------------
+if [ $# -eq 3 ]; then
+       admin=${3}
+       baculafd=${2}
+       hist=${1}
+       elif [ $# -eq 2 ]; then
+       baculafd=${2}
+       hist=${1}
+       elif [ $# -eq 1 ]; then
+       hist=${1}
+fi
+
+
+# A simple test to make sure
+# the hist variable is a number
+# -----------------------------
+# Short and sweet, but a non-POSIX bashism :(
+# if [ -z ${hist} ] || ! [[ ${hist} =~ ^[0-9]+$ ]]; then
+# so, instead, we do a POSIX-compaitble version:
+# -------------------------------------------------------
+histisnum=$(echo ${hist} | grep -E '^[0-9]+$')
+if [ -z ${hist} ] || [ -z ${histisnum} ]; then
+       echo
+       echo "USE: $0 [history in hours] [Bacula Client] [Admin Email]"
+       echo
+       exit 1
 fi
 
+
+# Test the rest of the binaries, and configuration files
+# ------------------------------------------------------
 if [ ! -e ${bcconfig} ]; then
-        echo -e "\nThe bconsole configuration file does not seem to be '${bcconfig}'."
-        echo -e "Please check the setting for the variable 'bcconfig'.\n"
-        exit 1
+       echo
+       echo "The bconsole configuration file does not seem to be '${bcconfig}'."
+       echo "Please check the setting for the variable 'bcconfig'."
+       echo
+       exit 1
 fi
 
 if [ ! -x ${bcbin} ]; then
-        echo -e "\nThe bconsole binary does not seem to be '${bcbin}', or it is not executable."
-        echo -e "Please check the setting for the variable 'bcbin'.\n"
-        exit 1
+       echo
+       echo "The bconsole binary does not seem to be '${bcbin}', or it is not executable."
+       echo "Please check the setting for the variable 'bcbin'."
+       echo
+       exit 1
 fi
 
-if [ ! -x ${dbbin} ]; then
-        echo -e "\nThe database client binary does not seem to be '${dbbin}', or it is not executable."
-        echo -e "Please check the setting for the variable 'dbbin'.\n"
-        exit 1
+if [ ! -x ${sendmail} ]; then
+       echo
+       echo "The sendmail binary does not seem to be '${sendmail}', or it is not executable."
+       echo "Please check the setting for the variable 'sendmail'."
+       echo
+       exit 1
 fi
 
-if [ ! -x ${sendmail} ]; then
-        echo -e "\nThe sendmail binary does not seem to be '${sendmail}', or it is not executable."
-        echo -e "Please check the setting for the variable 'sendmail'.\n"
-        exit 1
+if [ ! -x ${dbbin} ]; then
+       echo
+       echo "The database client binary does not seem to be '${dbbin}', or it is not executable."
+       echo "Please check the setting for the variable 'dbbin'."
+       echo
+       exit 1
 fi
 
 
 # Build query based on dbtype. Good thing we have "standards" Sigh...
 # -------------------------------------------------------------------
 case ${dbtype} in
-        mysql )
-                queryresult=$(echo "SELECT JobId, Name, StartTime, EndTime, Type, Level, JobStatus, JobFiles, JobBytes, \
-                TIMEDIFF (EndTime,StartTime) as RunTime, JobErrors \
-                FROM Job \
-                WHERE (RealEndTime >= DATE_ADD(NOW(), INTERVAL -${hist} HOUR) OR JobStatus='R') \
-                ORDER BY ${sortfield} ${sortorder};" \
-                | ${dbbindir}/mysql -u ${dbuser} ${dbpass} ${db} \
-                | sed '/^JobId/d' )
-                ;;
-
-        pgsql|postgresql )
-                queryresult=$(echo "SELECT JobId, Name, StartTime, EndTime, Type, Level, JobStatus, JobFiles, JobBytes, \
-                AGE(EndTime, StartTime) as RunTime, JobErrors \
-                FROM Job \
-                WHERE (RealEndTime >= CURRENT_TIMESTAMP(2) - cast('${hist} HOUR' as INTERVAL) OR JobStatus='R') \
-                ORDER BY ${sortfield} ${sortorder};" \
-                | ${dbbindir}/psql -U ${dbuser} ${dbpass} ${db} -0t \
-                | sed -e 's/|//g' -e '/^$/d' )
-                ;;
-
-        mariadb )
-                queryresult=$(echo "SELECT JobId, Name, StartTime, EndTime, Type, Level, JobStatus, JobFiles, JobBytes, \
-                TIMEDIFF (EndTime,StartTime) as RunTime, JobErrors \
-                FROM Job \
-                WHERE (RealEndTime >= DATE_ADD(NOW(), INTERVAL -${hist} HOUR) OR JobStatus='R') \
-                ORDER BY ${sortfield} ${sortorder};" \
-                | ${dbbindir}/mysql -u ${dbuser} -p${dbpass} ${db} -s -N )
-                ;;
-
-        * )
-                echo "dbtype of '${dbtype}' is invalid. Please set dbtype variable to 'mysql', 'pgsql', or 'mariadb'"
-                exit 1
-                ;;
+
+       sqlite )
+               # waa - 20171215 - sqlite3 query is a work in progress!
+               # -----------------------------------------------------
+               sqlitetries=4
+               sqlitetrydelay=10
+               while test ${sqlitetries} -gt 0; do
+                       queryresult=$(echo "SELECT JobId, REPLACE(Name,' ','_'), JobStatus, \
+                       JobErrors, Type, Level, JobFiles, JobBytes, StartTime, EndTime, \
+                       time((strftime('%s',EndTime) - strftime('%s',StartTime)), 'unixepoch') as RunTime \
+                       FROM Job WHERE (RealEndTime >= datetime('now', 'localtime', '-${hist} hours') OR (JobStatus='R' OR JobStatus='C')) \
+                       ORDER BY ${sortfield} ${sortorder};" \
+                       | ${dbbin} -noheader -column ${dbfile})
+
+#                      if [ ! -z $(echo ${queryresult} | grep "database is locked") ]; then
+                               let sqlitetries-=1
+#                              echo "Pfffff!  Someone using sqlite...."
+#                              exit 1
+#                      fi
+               done
+               ;;
+
+       mysql )
+               queryresult=$(echo "SELECT JobId, REPLACE(Name,' ','_'), JobStatus, \
+               JobErrors, Type, Level, JobFiles, JobBytes, StartTime, EndTime, \
+               TIMEDIFF (EndTime,StartTime) as RunTime \
+               FROM Job \
+               WHERE (RealEndTime >= DATE_ADD(NOW(), INTERVAL -${hist} HOUR) OR (JobStatus='R' OR JobStatus='C')) \
+               ORDER BY ${sortfield} ${sortorder};" \
+               | ${dbbin} -u ${dbuser} ${dbpass} ${db} \
+               | sed '/^JobId/d' )
+               ;;
+
+       pgsql )
+               queryresult=$(echo "SELECT Job.JobId, REPLACE(Job.Name,' ','_'), Job.JobStatus, \
+               Job.JobErrors, Job.Type, Job.Level, Job.JobFiles, Job.JobBytes, Job.StartTime, Job.EndTime, \
+               AGE(Job.EndTime, Job.StartTime) as RunTime, Client.Name \
+               FROM Job \
+               INNER JOIN Client on Job.ClientID=Client.ClientID \
+               WHERE (Job.RealEndTime >= CURRENT_TIMESTAMP(2) - cast('${hist} HOUR' as INTERVAL) OR (Job.JobStatus='R' OR Job.JobStatus='C')) \
+               AND Client.Name LIKE '%${baculafd}%' \
+               ORDER BY Job.${sortfield} ${sortorder};" \
+               | ${dbbin} -U ${dbuser} ${dbpass} ${db} -0t \
+               | sed -e 's/|//g' -e '/^$/d' )
+               ;;
+
+       mariadb )
+               queryresult=$(echo "SELECT JobId, REPLACE(Name,' ','_'), JobStatus, \
+               JobErrors, Type, Level, JobFiles, JobBytes, StartTime, EndTime, \
+               TIMEDIFF (EndTime,StartTime) as RunTime \
+               FROM Job \
+               WHERE (RealEndTime >= DATE_ADD(NOW(), INTERVAL -${hist} HOUR) OR (JobStatus='R' OR JobStatus='C')) \
+               ORDER BY ${sortfield} ${sortorder};" \
+               | ${dbbin} -u ${dbuser} -p${dbpass} ${db} -s -N )
+               ;;
+
+       * )
+               echo "dbtype of '${dbtype}' is invalid. Please set dbtype variable to 'sqlite', 'mysql', 'pgsql', or 'mariadb'"
+               exit 1
+               ;;
 esac
 
 
+# Let's check for Running or "Created, but not yet running" jobs
+# to append a nice comment to end of email Subject
+# --------------------------------------------------------------
+runningorcreated=$(echo "${queryresult}" | awk '{print $3}' | grep -c "R\|C")
+
+
 # If we have no jobs to report on, then
 # we need to skip the entire awk script
 # and some bash stuff and jump all the
-# way to about line 673
+# way to about line 851
 # -------------------------------------
 if [ -z "${queryresult}" ]; then
-        results="0"
-        else
-                results="1"
+       results="0"
+       else
+               results="1"
+               totaljobs=$(echo "${queryresult}" | wc -l)
+
+
+# Since exit codes can only be 0-255, we can not exit the awk script
+# with the number of Jobs with errors as it will not be correct once
+# the number of bad jobs is greater than 255. Instead we will write
+# this number to a temp file, then read it from bash and delete it
+# once the awk script exits.
+# ------------------------------------------------------------------
+awkerrfile=$(mktemp -t XXXXXX) 
 
 
 # Now for some fun with awk
 # -------------------------
-IFS=" "
-msg=$(echo ${queryresult} | \
+msg=$(echo "${queryresult}" | \
 LC_ALL=en_US.UTF-8 \
 awk \
 -v html="${html}" \
+-v awkerrfile="${awkerrfile}" \
+-v totaljobs="${totaljobs}" \
+-v boldjobname="${boldjobname}" \
+-v centerjobname="${centerjobname}" \
 -v boldstatus="${boldstatus}" \
 -v colorstatusbg="${colorstatusbg}" \
 -v jobtableheadercolor="${jobtableheadercolor}" \
 -v jobtablejobcolor="${jobtablejobcolor}" \
 -v runningjobcolor="${runningjobcolor}" \
+-v createdjobcolor="${createdjobcolor}" \
 -v goodjobcolor="${goodjobcolor}" \
+-v errorjobcolor="${errorjobcolor}" \
 -v goodjobwitherrcolor="${goodjobwitherrcolor}" \
 -v warnjobcolor="${warnjobcolor}" \
 -v badjobcolor="${badjobcolor}" \
 -v printsummary="${printsummary}" \
 -v starbadjobids="${starbadjobids}" \
-'BEGIN { awkerr = 0 }
-{star = " " }
-
-
-                                                # List of possible jobstatus codes
-                                                # --------------------------------
-                                                # Enter SQL query: SELECT * FROM status;
-                                                # +-----------+---------------------------------+----------+
-                                                # | jobstatus | jobstatuslong                   | severity |
-                                                # +-----------+---------------------------------+----------+
-                                                # | C         | Created, not yet running        |       15 |
-                                                # | R         | Running                         |       15 |
-                                                # | B         | Blocked                         |       15 |
-                                                # | T         | Completed successfully          |       10 |
-                                                # | E         | Terminated with errors          |       25 |
-                                                # | e         | Non-fatal error                 |       20 |
-                                                # | f         | Fatal error                     |      100 |
-                                                # | D         | Verify found differences        |       15 |
-                                                # | A         | Canceled by user                |       90 |
-                                                # | F         | Waiting for Client              |       15 |
-                                                # | S         | Waiting for Storage daemon      |       15 |
-                                                # | m         | Waiting for new media           |          |
-                                                # | M         | Waiting for media mount         |       15 |
-                                                # | s         | Waiting for storage resource    |       15 |
-                                                # | j         | Waiting for job resource        |       15 |
-                                                # | c         | Waiting for client resource     |       15 |
-                                                # | d         | Waiting on maximum jobs         |       15 |
-                                                # | t         | Waiting on start time           |       15 |
-                                                # | p         | Waiting on higher priority jobs |       15 |
-                                                # | a         | SD despooling attributes        |       15 |
-                                                # | i         | Doing batch insert file records |       15 |
-                                                # | I         | Incomplete Job                  |       25 |
-                                                # +-----------+---------------------------------+----------+
-
-
-                                                # Is this job still running?
-                                                # If a job is still running, then there will be no "Stop Time"
-                                                # fields, so $9 (jobstatus) will be shifted left two columns
-                                                # to $7, and we will need to test and then reassign these variables
-                                                # Note, this seems to be required for PostgreSQL, but MariaDB and
-                                                # MySQL return all zeros for the date and time for running jobs
-                                                # -----------------------------------------------------------------
-                                                { if ($7 == "R" && $8 ~ /^[0-9]+/)
-                                                        {
-                                                                $13 = $10
-                                                                $11 = $9
-                                                                $10 = $8
-                                                                $9  = $7
-                                                                $8  = $6
-                                                                $7  = $5
-                                                                $5  = "--=Still Running=--"
-                                                                $6  = ""
-                                                        }
-                                                }
-
-
-                                                # Assign words to job status code characters
-                                                # ------------------------------------------
-                                                # First, check to see if we need to generate an HTML email
-                                                { if (html == "yes")
-                                                                {
-                                                                        # Set default opening and closing tags for status cell
-                                                                        # ----------------------------------------------------
-                                                                        tdo = "<td align=\"center\">"
-                                                                        tdc = "</td>"
-
-                                                                        # Check to see if the job is "OK" then assign
-                                                                        # the "goodjobcolor" to the cell background
-                                                                        # -------------------------------------------
-                                                                        if ($9 ~ /[T]/ && $13 == 0)
-                                                                                {
-                                                                                        if (colorstatusbg == "yes")
-                                                                                                # Assign jobs that are OK or Running the goodjobcolor
-                                                                                                # ---------------------------------------------------
-                                                                                                {
-                                                                                                        tdo = "<td align=\"center\" bgcolor=\"" goodjobcolor "\">"
-                                                                                                }
-
-                                                                                # Should the status be bolded?
-                                                                                # ----------------------------
-                                                                                if (boldstatus == "yes")
-                                                                                        {
-                                                                                                tdo=tdo"<b>"
-                                                                                                tdc="</b>"tdc
-                                                                                        }
-                                                                                status["T"]=tdo"-OK-"tdc
-
-                                                                                # If it is a good job, but with errors or warnings
-                                                                                # then we will assign the warnjobcolor
-                                                                                # ------------------------------------------------
-                                                                                } else if ($9 == "T" && $13 != 0)
-                                                                                        {
-                                                                                                if (colorstatusbg == "yes")
-                                                                                                        # Assign OK jobs with errors the warnjobcolor
-                                                                                                        # -------------------------------------------
-                                                                                                        {
-                                                                                                                tdo = "<td align=\"center\" bgcolor=\"" warnjobcolor "\">"
-                                                                                                        }
-
-                                                                                                # Should the status be bolded?
-                                                                                                # ----------------------------
-                                                                                                if (boldstatus == "yes")
-                                                                                                        {
-                                                                                                                tdo=tdo"<b>"
-                                                                                                                tdc="</b>"tdc
-                                                                                                        }
-                                                                                                # Since the "W" jobstatus never appears in the DB, we manually
-                                                                                                # assign it here so it can be recognized later on in the script
-                                                                                                # -------------------------------------------------------------
-                                                                                                $9 = "W"
-                                                                                                status["W"]=tdo"OK/Warnings"tdc
-
-                                                                                # If the job is still running we will
-                                                                                # assign it the runningjobcolor
-                                                                                # -----------------------------------
-                                                                                } else if ($9 == "R")
-                                                                                        {
-                                                                                                if (colorstatusbg == "yes")
-                                                                                                        # Assign running jobs the runningjobcolor
-                                                                                                        # ---------------------------------------
-                                                                                                        {
-                                                                                                                tdo = "<td align=\"center\" bgcolor=\"" runningjobcolor "\">"
-                                                                                                        }
-
-                                                                                                # Should the status be bolded?
-                                                                                                # ----------------------------
-                                                                                                if (boldstatus == "yes")
-                                                                                                        {
-                                                                                                                tdo=tdo"<b>"
-                                                                                                                tdc="</b>"tdc
-                                                                                                        }
-                                                                                                status["R"]=tdo"Running"tdc
-
-                                                                                # If it is a bad job, then
-                                                                                # we assign the badjobcolor
-                                                                                # -------------------------
-                                                                                } else if ($9 ~ /[ABDef]/)
-                                                                                        {
-                                                                                                if (colorstatusbg == "yes")
-                                                                                                        # Assign bad jobs the badjobcolor
-                                                                                                        # -------------------------------
-                                                                                                        {
-                                                                                                                tdo = "<td align=\"center\" bgcolor=\"" badjobcolor "\">"
-                                                                                                        }
-
-                                                                                                # Should the status be bolded?
-                                                                                                # ----------------------------
-                                                                                                if (boldstatus == "yes")
-                                                                                                        {
-                                                                                                                tdo=tdo"<b>"
-                                                                                                                tdc="</b>"tdc
-                                                                                                        }
-                                                                                                status["A"]=tdo"Aborted"tdc
-                                                                                                status["D"]=tdo"Verify Diffs"tdc
-                                                                                                status["f"]=tdo"Failed"tdc
-
-                                                                                # If it is a job with warnings or errors, assign the job the warnjobcolor
-                                                                                # I have never seen a "W" status in the db. Jobs that are "OK -- with warnings"
-                                                                                # still have a "T" jobstatus, but the joberrors field is incremented in the db
-                                                                                # -----------------------------------------------------------------------------
-                                                                                } else if ($9 ~ /[EI]/)
-                                                                                        {
-                                                                                                if (colorstatusbg == "yes")
-                                                                                                        # Assign job the warnjobcolor
-                                                                                                        # ---------------------------
-                                                                                                        {
-                                                                                                                tdo = "<td align=\"center\" bgcolor=\"" warnjobcolor "\">"
-                                                                                                        }
-
-                                                                                                # Should the status be bolded?
-                                                                                                # ----------------------------
-                                                                                                if (boldstatus == "yes")
-                                                                                                        {
-                                                                                                                tdo=tdo"<b>"
-                                                                                                                tdc="</b>"tdc
-                                                                                                        }
-                                                                                                status["E"]=tdo"OK, w/Errors"tdc
-                                                                                                status["I"]=tdo"Incomplete"tdc
-                                                                                        }
-                                                                } else
-                                                                # $html is not "yes" so statuses will be normal text
-                                                                # --------------------------------------------------
-                                                                        {
-                                                                                status["A"]="     Aborted   "
-                                                                                status["D"]="  Verify Diffs "
-                                                                                status["E"]="  OK, w/Errors "
-                                                                                status["f"]="     Failed    "
-                                                                                status["I"]="   Incomplete  "
-                                                                                status["R"]="     Running   "
-                                                                                status["T"]="      -OK-     "
-                                                                                # Since the "W" jobstatus never appears in the DB, we manually
-                                                                                # assign it here so it can be recognized later on in the script
-                                                                                # -------------------------------------------------------------
-                                                                                if ($9 == "T" && $13 != 0)
-                                                                                        { $9 = "W"
-                                                                                                status["W"]="   OK/Warnings "
-                                                                                        }
-                                                                        }
-                                                }
-
-
-                                                # These status characters seem to only
-                                                # be Director "in memory" statuses. They
-                                                # do not get entered into the DB ever so we
-                                                # cannot catch them with the db query we use
-                                                # I might have to query the DIR as well as
-                                                # the DB to be able to capture these
-                                                # ------------------------------------------
-                                                {
-                                                        status["C"]="     Created   "
-                                                        status["B"]="     Blocked   "
-                                                        status["F"]="     Wait FD   "
-                                                        status["S"]="     Wait SD   "
-                                                        status["m"]=" Wait New Media"
-                                                        status["M"]="   Wait Mount  "
-                                                        status["s"]="   Wait Storage"
-                                                        status["j"]="    Wait Job   "
-                                                        status["c"]="   Wait Client "
-                                                        status["d"]="  Wait Max Jobs"
-                                                        status["t"]="Wait Start Time"
-                                                        status["p"]="  Wait Priority"
-                                                        status["a"]="  Despool Attrs"
-                                                        status["i"]="  Batch Insert "
-                                                        status["L"]="Spool Last Data"
-                                                }
-
-
-                                                # Assign words to job type code characters
-                                                # ----------------------------------------
-                                                {
-                                                        jobtype["D"]="Admin"
-                                                        jobtype["B"]="Backup"
-                                                        jobtype["C"]="Copy"
-                                                        jobtype["c"]="Control"
-                                                        jobtype["R"]="Restore"
-                                                        jobtype["V"]="Verify"
-                                                }
-
-
-                                                # Assign words to job level code characters
-                                                # -----------------------------------------
-                                                {
-                                                        level["F"]="Full"
-                                                        level["I"]="Incr"
-                                                        level["D"]="Diff"
-                                                        level["f"]="VFul"
-                                                        level["-"]="----"
-                                                }
-
-
-                                                # Assign words to Verify job level code characters
-                                                # ------------------------------------------------
-                                                {
-                                                        level["A"]="VVol"
-                                                        level["C"]="VCat"
-                                                        level["V"]="Init"
-                                                        level["O"]="VV2C"
-                                                        level["d"]="VD2C"
-                                                }
-
-
-                                                # Check to see if the job did not "T"erminate OK then increment $awkerr,
-                                                # and prepend the JobId with an asterisk for quick visual identification
-                                                # of problem jobs.
-
-                                                # Need to choose between a positive or negative test of the job status code
-                                                # -------------------------------------------------------------------------
-                                                # Negative check - testing for non existence of all "good" status codes
-                                                # $9 !~ /[TRCFSMmsjcdtpai]/ { awkerr++; $1 = "* "$1 }
-                                                # Positive check - testing the existence of all "bad" status codes
-                                                # good { if ($9 ~ /[ABDEIWef]/ || $13 != 0) { awkerr++; if (starbadjobids == "yes") { star  = "*" } } }
-                                                { if ($9 ~ /[ABDEIef]/) { awkerr++; if (starbadjobids == "yes") { star  = "*" } } }
-
-
-                                                # If the job is an Admin, Copy, Control,
-                                                # Restore, or Migration job it will have
-                                                # no real "Level", so we set it to "----"
-                                                # ---------------------------------------
-                                                { if ($7 ~ /[CcDRm]/) { $8 = "-" } }
-
-
-                                                # Print out each job, formatted with the following fields:
-                                                # JobId Name Status Errors Type Level Files Bytes StartTime EndTime RunTime
-                                                # -------------------------------------------------------------------------
-                                                { if (html == "yes")
-                                                        { printf("<tr bgcolor=\"%s\"> \
-                                                                <td align=\"center\">%s%s%s</td> \
-                                                                <td>%s</td> \
-                                                                %s \
-                                                                <td align=\"right\">%'"'"'d</td> \
-                                                                <td align=\"center\">%s</td> \
-                                                                <td align=\"center\">%s</td> \
-                                                                <td align=\"right\">%'"'"'d</td> \
-                                                                <td align=\"right\">%'"'"'9.2f GB</td> \
-                                                                <td align=\"center\">%s %s</td> \
-                                                                <td align=\"center\">%s %s</td> \
-                                                                <td align=\"center\">%s</td> \
-                                                                </tr>\n", \
-                                                                jobtablejobcolor, star, $1, star, $2, status[$9], $13, jobtype[$7], level[$8], $10, $11/(1024*1024*1024), $3, $4, $5, $6, $12);
-                                                        } else
-                                                                { printf("%s %-7s %-14s %16s %'"'"'12d %8s %6s %'"'"'9d %'"'"'9.2f GB %11s %-9s %-10s %-9s %-9s\n", \
-                                                                        star, $1, $2, status[$9], $13, jobtype[$7], level[$8], $10, $11/(1024*1024*1024), $3, $4, $5, $6, $12);
-                                                                }
-                                                }
-
-
-                                                # Count the number of jobs
-                                                # ------------------------
-                                                { totaljobs++ }
-
-
-                                                # Count the number of files and bytes from all jobs
-                                                # -------------------------------------------------
-                                                { files += $10 }
-                                                { bytes += $11 }
+'BEGIN {awkerr = 0}
+{star = " "}
+
+                                               # List of possible jobstatus codes
+                                               # --------------------------------
+                                               # Enter SQL query: SELECT * FROM status;
+                                               # +-----------+---------------------------------+----------+
+                                               # | jobstatus | jobstatuslong                   | severity |
+                                               # +-----------+---------------------------------+----------+
+                                               # | C         | Created, not yet running        |       15 |
+                                               # | R         | Running                         |       15 |
+                                               # | B         | Blocked                         |       15 |
+                                               # | T         | Completed successfully          |       10 |
+                                               # | E         | Terminated with errors          |       25 |
+                                               # | e         | Non-fatal error                 |       20 |
+                                               # | f         | Fatal error                     |      100 |
+                                               # | D         | Verify found differences        |       15 |
+                                               # | A         | Canceled by user                |       90 |
+                                               # | F         | Waiting for Client              |       15 |
+                                               # | S         | Waiting for Storage daemon      |       15 |
+                                               # | m         | Waiting for new media           |          |
+                                               # | M         | Waiting for media mount         |       15 |
+                                               # | s         | Waiting for storage resource    |       15 |
+                                               # | j         | Waiting for job resource        |       15 |
+                                               # | c         | Waiting for client resource     |       15 |
+                                               # | d         | Waiting on maximum jobs         |       15 |
+                                               # | t         | Waiting on start time           |       15 |
+                                               # | p         | Waiting on higher priority jobs |       15 |
+                                               # | a         | SD despooling attributes        |       15 |
+                                               # | i         | Doing batch insert file records |       15 |
+                                               # | I         | Incomplete Job                  |       25 |
+                                               # +-----------+---------------------------------+----------+
+
+
+# If an ADMIN type job does not have a "Level" set anywhere in the Job, or
+# overriden in a schedule, or specified on the command line it will have a NULL
+# "Level". This shifts the columns we receive from the SQL query left
+# by one, starting at the sixth column. Here we move everything right by one to
+# mitigate this issue.
+# This does not cover failed Control/Migration jobs with no start time due to
+# the SQl query returning 0 jobs to copy or migrate. See below.
+# -----------------------------------------------------------------------------
+{ if ($3 != "R" && $5 != "c" && $5 != "m" && NF != 14)
+       {
+               $14 = $13
+               $13 = $12
+               $12 = $11
+               $11 = $10
+               $10 = $9
+               $9  = $8
+               $8  = $7
+               $7  = $6
+       }
+}
+
+# If the job is running, and it is an ADMIN type job, and the fifth
+# field is not "Full", "Incr", or "Diff" then there was no level
+# set for this ADMIN job, and the "Level" field will be NULL and we
+# will have a fewer fields to shift right.
+# -----------------------------------------------------------------
+{ if ($3 == "R" && $5 == "D" && $6 !~ /[FID]/)
+       {
+               $14 = $13
+               $13 = $12
+               $12 = $11
+               $11 = $10
+               $10 = $9
+               $9  = $8
+               $8  = $7
+       }
+}
+
+# If the job is still running, there is no EndTime, so we shift the
+# RunTime two fields to the right and manually set the Endtime
+# Additionally, we need to set shift the client name from $11 to $14
+# and then we need to set $11 to the "Still Running" string
+# ------------------------------------------------------------------
+{ if ($3 == "R")
+       {
+               $14 = $11
+               if (html == "yes")
+                       {
+                               $11 = "Still Running"
+                               $13 = "<hr width=\"50%\">"
+                       } else {
+                               $11 = "  =Still"
+                               $12 = "Running= "
+                               $13 = "--------"
+                       }
+       }
+}
+
+# If the job is Created but not yet running, there is no EndTime,
+# so we shift the RunTime two fields to the right and manually set
+# the Endtime
+# -----------------------------------------------------------------
+{ if ($3 == "C")
+       {
+               if (html == "yes")
+                       {
+                               $9 = "Created, not yet running"
+                               $11 = "<hr width=\"55%\">"
+                               $13 = "<hr width=\"50%\">"
+                       } else {
+                               $9 = "=Created="
+                               $10 = ""
+                               $11 = "----------"
+                               $12 = "--------"
+                               $13 = "--------"
+                       }
+       }
+}
+
+# If the job is a failed copy control job, and there is no StartTime
+# and no RunTime, these last three fields are shifted two to the left
+# -------------------------------------------------------------------
+{ if ($3 == "f" && $5 ~ /[cm]/ && $9 == "")
+       {
+               if (html == "yes")
+                       {
+                               $9 = "Never Started"
+                               $10 = ""
+                               $11 = "<hr width=\"55%\">"
+                               $13 = "<hr width=\"50%\">"
+                               } else {
+                                       $12 = $10
+                                       $11 = $9
+                                       $13 = "--------"
+                                       $9 = "      Never"
+                                       $10 = "Started "
+                       }
+       }
+}
+
+# Assign words to job status code characters
+# ------------------------------------------
+# First, check to see if we need to generate an HTML email
+{ if (html == "yes")
+       {
+                       # Set default opening and closing tags for status cell
+                       # ----------------------------------------------------
+                       tdo = "<td align=\"center\">"
+                       tdc = "</td>"
+
+                       # Check to see if the job is "OK" then assign
+                       # the "goodjobcolor" to the cell background
+                       # -------------------------------------------
+                       if ($3 ~ /[T]/ && $4 == 0)
+                               {
+                                       if (colorstatusbg == "yes")
+                                               # Assign jobs that are OK or Running the goodjobcolor
+                                               # ---------------------------------------------------
+                                               {
+                                                       tdo = "<td align=\"center\" bgcolor=\"" goodjobcolor "\">"
+                                               }
+
+                               # Should the status be bolded?
+                               # ----------------------------
+                               if (boldstatus == "yes")
+                                       {
+                                               tdo=tdo"<b>"
+                                               tdc="</b>"tdc
+                                       }
+                               status["T"]=tdo"-OK-"tdc
+
+                               # If it is a good job, but with errors or warnings
+                               # then we will assign the warnjobcolor
+                               # ------------------------------------------------
+                               } else if ($3 == "T" && $4 != 0)
+                                       {
+                                               if (colorstatusbg == "yes")
+                                                       # Assign OK jobs with errors the warnjobcolor
+                                                       # -------------------------------------------
+                                                       {
+                                                               tdo = "<td align=\"center\" bgcolor=\"" warnjobcolor "\">"
+                                                       }
+
+                                               # Should the status be bolded?
+                                               # ----------------------------
+                                               if (boldstatus == "yes")
+                                                       {
+                                                               tdo=tdo"<b>"
+                                                               tdc="</b>"tdc
+                                                       }
+                                               # Since the "W" jobstatus never appears in the DB, we manually
+                                               # assign it here so it can be recognized later on in the script
+                                               # -------------------------------------------------------------
+                                               $3 = "W"
+                                               status["W"]=tdo"OK/Warnings"tdc
+
+                               # If the job is still running we will
+                               # assign it the runningjobcolor
+                               # -----------------------------------
+                               } else if ($3 == "R")
+                                       {
+                                               if (colorstatusbg == "yes")
+                                                       # Assign running jobs the runningjobcolor
+                                                       # ---------------------------------------
+                                                       {
+                                                               tdo = "<td align=\"center\" bgcolor=\"" runningjobcolor "\">"
+                                                       }
+
+                                               # Should the status be bolded?
+                                               # ----------------------------
+                                               if (boldstatus == "yes")
+                                                       {
+                                                               tdo=tdo"<b>"
+                                                               tdc="</b>"tdc
+                                                       }
+                                               status["R"]=tdo"Running"tdc
+
+                               # If the job is created but not yet
+                               # running we will assign it the
+                               # createdjobcolor
+                               # ---------------------------------
+                               } else if ($3 == "C")
+                                       {
+                                               if (colorstatusbg == "yes")
+                                                       # Assign running jobs the createdjobcolor
+                                                       # ---------------------------------------
+                                                       {
+                                                               tdo = "<td align=\"center\" bgcolor=\"" createdjobcolor "\">"
+                                                       }
+
+                                               # Should the status be bolded?
+                                               # ----------------------------
+                                               if (boldstatus == "yes")
+                                                       {
+                                                               tdo=tdo"<b>"
+                                                               tdc="</b>"tdc
+                                                       }
+                                               status["C"]=tdo"Created"tdc
+
+                               # If it is a bad job, then
+                               # we assign the badjobcolor
+                               # -------------------------
+                               } else if ($3 ~ /[ABDef]/)
+                                       {
+                                               if (colorstatusbg == "yes")
+                                                       # Assign bad jobs the badjobcolor
+                                                       # -------------------------------
+                                                       {
+                                                               tdo = "<td align=\"center\" bgcolor=\"" badjobcolor "\">"
+                                                       }
+
+                                               # Should the status be bolded?
+                                               # ----------------------------
+                                               if (boldstatus == "yes")
+                                                       {
+                                                               tdo=tdo"<b>"
+                                                               tdc="</b>"tdc
+                                                       }
+                                               status["A"]=tdo"Aborted"tdc
+                                               status["D"]=tdo"Verify Diffs"tdc
+                                               status["f"]=tdo"Failed"tdc
+
+                               # If the job terminated "E", assign the job the errorjobcolor
+                               # -----------------------------------------------------------
+                               } else if ($3 == "E")
+                                       {
+                                               if (colorstatusbg == "yes")
+                                                       # Assign job the errorjobcolor
+                                                       # ----------------------------
+                                                       {
+                                                               tdo = "<td align=\"center\" bgcolor=\"" errorjobcolor "\">"
+                                                       }
+
+                                               # Should the status be bolded?
+                                               # ----------------------------
+                                               if (boldstatus == "yes")
+                                                       {
+                                                               tdo=tdo"<b>"
+                                                               tdc="</b>"tdc
+                                                       }
+                                               status["E"]=tdo"Errors"tdc
+                                       
+
+                               # If the job terminated "I" (Incomplete), assign the job the warnjobcolor
+                               # -----------------------------------------------------------------------
+                               } else if ($3 == "I")
+                                       {
+                                               if (colorstatusbg == "yes")
+                                                       # Assign job the warnjobcolor
+                                                       # ---------------------------
+                                                       {
+                                                               tdo = "<td align=\"center\" bgcolor=\"" warnjobcolor "\">"
+                                                       }
+
+                                               # Should the status be bolded?
+                                               # ----------------------------
+                                               if (boldstatus == "yes")
+                                                       {
+                                                               tdo=tdo"<b>"
+                                                               tdc="</b>"tdc
+                                                       }
+                                               status["I"]=tdo"Incomplete"tdc
+                                       }
+               } else
+               # $html is not "yes" so statuses will be normal text
+               # --------------------------------------------------
+                       {
+                               status["A"]="     Aborted   "
+                               status["C"]="     Created   "
+                               status["D"]="  Verify Diffs "
+                               status["E"]="     Errors    "
+                               status["f"]="     Failed    "
+                               status["I"]="   Incomplete  "
+                               status["R"]="     Running   "
+                               status["T"]="      -OK-     "
+                               # Since the "W" jobstatus never appears in the DB, we manually
+                               # assign it here so it can be recognized later on in the script
+                               # -------------------------------------------------------------
+                               if ($3 == "T" && $4 != 0)
+                                       { $3 = "W"
+                                               status["W"]="   OK/Warnings "
+                                       }
+                       }
+}
+
+
+# These status characters seem to only
+# be Director "in memory" statuses. They
+# do not get entered into the DB ever so we
+# cannot catch them with the db query we use
+# I might have to query the DIR as well as
+# the DB to be able to capture these
+# ------------------------------------------
+{
+       status["B"]="     Blocked   "
+       status["F"]="     Wait FD   "
+       status["S"]="     Wait SD   "
+       status["m"]=" Wait New Media"
+       status["M"]="   Wait Mount  "
+       status["s"]="   Wait Storage"
+       status["j"]="    Wait Job   "
+       status["c"]="   Wait Client "
+       status["d"]="  Wait Max Jobs"
+       status["t"]="Wait Start Time"
+       status["p"]="  Wait Priority"
+       status["a"]="  Despool Attrs"
+       status["i"]="  Batch Insert "
+       status["L"]="Spool Last Data"
+}
+
+
+# Assign words to job type code characters
+# ----------------------------------------
+{
+       jobtype["D"]="Admin"
+       jobtype["B"]="Backup"
+       jobtype["C"]="Copy"
+       jobtype["c"]="Control"
+       jobtype["R"]="Restore"
+       jobtype["V"]="Verify"
+       jobtype["M"]="Migrated"
+       jobtype["m"]="Migration"
+}
+
+
+# Assign words to job level code characters
+# -----------------------------------------
+{
+       level["F"]="Full"
+       level["I"]="Incr"
+       level["D"]="Diff"
+       level["f"]="VFul"
+       level["-"]="Base"
+       if (html == "yes")
+               {
+                       level["-"]="<hr width=\"50%\">"
+               } else {
+                       level["-"]="----"
+               }
+}
+
+
+# Assign words to Verify job level code characters
+# ------------------------------------------------
+{
+       level["A"]="VVol"
+       level["C"]="VCat"
+       level["V"]="Init"
+       level["O"]="VV2C"
+       level["d"]="VD2C"
+}
+
+
+# Check to see if the job did not "T"erminate OK then increment $awkerr,
+# and prepend the JobId with an asterisk for quick visual identification
+# of problem jobs.
+# -------------------------------------------------------------------------
+{ if ($3 ~ /[ABDEIef]/) { awkerr++; if (starbadjobids == "yes") { star  = "*" } } }
+
+
+# If the job is an Admin, Control,
+# or Migration job it will have
+# no real "Level", so we set it to "----"
+# Also need to set it for Client ($14) on
+# Admin jobs
+# -------------------------------------------
+{ if ($5 ~ /[cDm]/)
+       { $6 = "-"
+        if (html == "yes")
+               {
+                       $14 = "<hr width=\"50%\">"
+               } else {
+                       $14 = "-"
+               }
+       }
+}
+
+# Print out each job, formatted with the following fields:
+# JobId Name Status Errors Type Level Files Bytes StartTime EndTime RunTime
+# -------------------------------------------------------------------------
+{ if (html == "yes")
+       {
+               # Check to see if we center or bold the JobName
+               # ---------------------------------------------
+               { if (boldjobname == "yes" && centerjobname == "yes")
+                       { $2 = "<td align=\"center\"><b>"$2"</b></td>" }
+                       else if (boldjobname == "yes")
+                               { $2 = "<td><b>"$2"</b></td>" }
+                               else if (centerjobname == "yes")
+                                       { $2 = "<td align=\"center\">"$2"</td>" }
+                                               else { $2 = "<td>"$2"</td>" }
+               }
+
+               printf("<tr bgcolor=\"%s\"> \
+               <td align=\"center\">%s%s%s</td> \
+               %s \
+               <td align=\"center\">%s</td> \
+               %s \
+               <td align=\"right\">%'"'"'d</td> \
+               <td align=\"center\">%s</td> \
+               <td align=\"center\">%s</td> \
+               <td align=\"right\">%'"'"'d</td> \
+               <td align=\"right\">%'"'"'9.2f GB</td> \
+               <td align=\"center\">%s %s</td> \
+               <td align=\"center\">%s %s</td> \
+               <td align=\"center\">%s</td> \
+               </tr>\n", \
+               jobtablejobcolor, star, $1, star, $2, $14, status[$3], $4, jobtype[$5], level[$6], $7, $8/(1024*1024*1024), $9, $10, $11, $12, $13);
+       } else
+               { printf("%s %-9s %-10s     %-14s %16s %'"'"'12d %8s %6s %'"'"'9d %'"'"'9.2f GB %11s %-9s %-10s %-9s %-9s\n", \
+                       star, $1, $2, $14, status[$3], $4, jobtype[$5], level[$6], $7, $8/(1024*1024*1024), $9, $10, $11, $12, $13);
+               }
+}
+
+
+# Increment the job counter
+# -------------------------
+{ totaljobs++ }
+
 
+# Count the files and bytes from all Backup jobs
+# ----------------------------------------------
+{ if ($5 == "B")
+               {
+                       backupfiles += $7
+                       backupbytes += $8
+               }
+}
 
+
+# Count the files and bytes from all
+# Restore, Copy or Migration jobs. Not
+# sure if I like this idea yet. Sticking
+# to only counting Restore jobs for now.
+# --------------------------------------
+# { if ($5 == "R" || $5 == "C" || $5 == "M")
+{ if ($5 == "R")
+               {
+                       restorefiles += $7
+                       restorebytes += $8
+               }
+}
+
+
+END {
 # Finally, print out the summaries
 # --------------------------------
-END {
 if (printsummary == "yes")
-        { if (html == "yes")
-                {
-                        printf("</table>")
-                        printf("<br>\
-                        <hr align=\"left\" width=\"25%\">\
-                        <table width=\"25%\">\
-                                <tr><td><b>Total Jobs</b></td><td  align=\"center\"><b>:</b></td> <td align=\"right\"><b>%'"'"'15d</b></td></tr>\
-                                <tr><td><b>Total Files</b></td><td align=\"center\"><b>:</b></td> <td align=\"right\"><b>%'"'"'15d</b></td></tr>\
-                                <tr><td><b>Total Bytes</b></td><td align=\"center\"><b>:</b></td> <td align=\"right\"><b>%'"'"'15.2f GB</b></td></tr>\
-                        </table>\
-                        <hr align=\"left\" width=\"25%\">",\
-                        totaljobs, files, bytes/(1024*1024*1024));
-                } else
+       { if (html == "yes")
+               {
+                       printf("</table>")
+                       printf("<br>\
+                       <hr align=\"left\" width=\"25%\">\
+                       <table width=\"25%\">\
+                               <tr><td><b>Total Jobs</b></td><td align=\"center\"><b>:</b></td> <td align=\"right\"><b>%'"'"'15d</b></td></tr>\
+                               <tr><td><b>Bad Jobs</b></td><td align=\"center\"><b>:</b></td> <td align=\"right\"><b>%'"'"'15d</b></td></tr>\
+                               <tr><td><b>Total Backup Files</b></td><td align=\"center\"><b>:</b></td> <td align=\"right\"><b>%'"'"'15d</b></td></tr>\
+                               <tr><td><b>Total Backup Bytes</b></td><td align=\"center\"><b>:</b></td> <td align=\"right\"><b>%'"'"'15.2f GB</b></td></tr>\
+                               <tr><td><b>Total Restore Files</b></td><td align=\"center\"><b>:</b></td> <td align=\"right\"><b>%'"'"'15d</b></td></tr>\
+                               <tr><td><b>Total Restore Bytes</b></td><td align=\"center\"><b>:</b></td> <td align=\"right\"><b>%'"'"'15.2f GB</b></td></tr>\
+                       </table>\
+                       <hr align=\"left\" width=\"25%\">",\
+                       totaljobs, awkerr, backupfiles, backupbytes/(1024*1024*1024), restorefiles, restorebytes/(1024*1024*1024));
+               } else
 printf("\
   =================================\n\
-  Total Jobs  : %'"'"'15d\n\
-  Total Files : %'"'"'15d\n\
-  Total Bytes : %'"'"'15.2f GB\n\
+  Total Jobs  : %'"'"'19d\n\
+  Bad Jobs    : %'"'"'19d\n\
+  Total Backup Files : %'"'"'12d\n\
+  Total Backup Bytes : %'"'"'9.2f GB\n\
+  Total Restore Files : %'"'"'11d\n\
+  Total Restore Bytes : %'"'"'8.2f GB\n\
   =================================\n",\
-totaljobs, files, bytes/(1024*1024*1024));
-} exit awkerr }
+totaljobs, awkerr, backupfiles, backupbytes/(1024*1024*1024), restorefiles, restorebytes/(1024*1024*1024));
+print awkerr > awkerrfile;
+} exit }
 ')
 
 
-# Any failed jobs, or jobs with errors?
-# -------------------------------------
-numbadjobs=$?
+# Any failed jobs, or non "OK" jobs with errors?
+# ----------------------------------------------
+numbadjobs=$(cat $awkerrfile)
+rm -f $awkerrfile
 
 
 # Do we email the job summaries?
 # ------------------------------
-if [ ${emailsummaries} == "yes" ]; then
-        # Get all of the jobids from the query results, but
-        # skip any running jobs because they will not have
-        # a summary in the DB until the job has terminated
-        # -------------------------------------------------
-        alljobids=$(echo "${queryresult}" \
-        | awk '{ if ($7 != "R") printf("%s ", $1) }')
-
-
-        # If no jobids were returned, skip creating
-        # the header and looping through zero records
-        # -------------------------------------------
-        if [ ! -z "${alljobids}" ]; then
-                # Generate the header
-                # -------------------
-                msg="${msg}"$(
-                if [ ${html} == "yes" ]; then
-                        echo "<pre>====================================="
-                                else
-                                        echo -e "\n\n\n====================================="
-                fi
-                        echo "Job Summaries of All Terminated Jobs:"
-                        echo "====================================="
-                )
-
-
-                # Get the job logs from all jobs and just grep for the summary
-                # ------------------------------------------------------------
-                for jobid in ${alljobids}; do
-                        msg="${msg}"$(
-                                echo -e "\n--------------"
-                                echo "JobId: ${jobid}"
-                                echo "--------------"
-                                echo "llist joblog jobid=${jobid}" | ${bcbin} -c ${bcconfig} | grep -A31 "^  Build OS:"
-                                echo "======================================================================"
-                        )
-                done
-                if [ ${html} == "yes" ]; then
-                        msg=${msg}$(echo "</pre>")
-                fi
-        fi
+if [ ${emailsummaries} = "yes" ]; then
+       # Get all of the jobids from the query results, but
+       # skip any running or "created, but not yet running"
+       # jobs because they will not have a summary in the
+       # catalog DB until the job has terminated.
+       # --------------------------------------------------
+       alljobids=$(echo "${queryresult}" \
+       | awk '{ if ($3 !~ /[RC]/) printf("%s ", $1) }')
+
+
+       # If no jobids were returned, skip creating
+       # the header and looping through zero records
+       # -------------------------------------------
+       if [ ! -z "${alljobids}" ]; then
+               # Generate the header
+               # -------------------
+               msg="${msg}"$(
+               if [ ${html} = "yes" ]; then
+                       echo "<pre>===================================="
+                               else
+                                       echo
+                                       echo
+                                       echo
+                                       echo "===================================="
+               fi
+                       echo "Job Summaries of All Terminated Jobs"
+                       echo "===================================="
+               )
+
+
+               # Get the job logs from all jobs and just awk for the summary
+               # -----------------------------------------------------------
+               for jobid in ${alljobids}; do
+                       msg="${msg}"$(
+                               echo
+                               echo "------------"
+                               echo "JobId: ${jobid}"
+                               echo "------------"
+                               echo "llist joblog jobid=${jobid}" | ${bcbin} -c ${bcconfig} \
+                                                       | sed 's/^  //' \
+                                                       | awk "BEGIN {IGNORECASE=0} /^Build OS:.*/ || /^Build:.*/,/^Termination:/ {print}"
+                               echo "======================================================================"
+                       )
+               done
+               if [ ${html} = "yes" ]; then
+                       msg=${msg}$(echo "</pre>")
+               fi
+       fi
 fi
 
 
 # Do we email the bad job logs with the report?
 # ---------------------------------------------
-if [ ${emailbadlogs} == "yes" ]; then
-        # Get the badjobs, or the good jobs with
-        # JobErrors != 0 from the query results
-        # --------------------------------------
-        badjobids=$(echo "${queryresult}" \
-        | awk '{ if ($9 ~ /[ABDEIef]/ || ($9 == "T" && $13 != 0)) printf("%s ", $1) }')
-
-
-        # If no jobids were returned, skip creating
-        # the header and looping through zero records
-        # -------------------------------------------
-        if [ ! -z "${badjobids}" ]; then
-                # Generate the header
-                # -------------------
-                msg="${msg}"$(
-                if [ ${html} == "yes" ]; then
-                        echo "<pre>=========================================================="
-                                else
-                                        echo -e "\n\n\n=========================================================="
-                fi
-                        echo "Job logs of failed jobs, or good jobs with JobErrors != 0:"
-                        echo "=========================================================="
-                )
-
-
-                # Get the bad job's log from the Director via bconsole
-                # ----------------------------------------------------
-                for jobid in ${badjobids}; do
-                        msg="${msg}"$(
-                                echo -e "\n--------------"
-                                echo "JobId: ${jobid}"
-                                echo "--------------"
-                                echo "llist joblog jobid=${jobid}" | ${bcbin} -c ${bcconfig}
-                                echo "======================================================================"
-                        )
-                done
-                if [ ${html} == "yes" ]; then
-                        msg=${msg}$(echo "</pre>")
-                fi
-        fi
+if [ ${emailbadlogs} = "yes" ]; then
+       # Get the badjobs, or the good jobs with
+       # JobErrors != 0 from the query results
+       # --------------------------------------
+       badjobids=$(echo "${queryresult}" \
+       | awk '{ if ($3 ~ /[ABDEIef]/ || ($3 == "T" && $4 != 0)) printf("%s ", $1) }')
+
+
+       # If no jobids were returned, skip creating
+       # the header and looping through zero records
+       # -------------------------------------------
+       if [ ! -z "${badjobids}" ]; then
+               # Generate the header
+               # -------------------
+               msg="${msg}"$(
+               if [ ${html} = "yes" ]; then
+                       echo "<pre>===================================================="
+                               else
+                                       echo
+                                       echo
+                                       echo
+                                       echo "===================================================="
+               fi
+                       echo "Job logs of failed jobs, or good jobs with JobErrors"
+                       echo "===================================================="
+               )
+
+
+               # Get the bad job logs from the Director via bconsole
+               # ---------------------------------------------------
+               for jobid in ${badjobids}; do
+                       msg="${msg}"$(
+                               echo
+                               echo "------------"
+                               echo "JobId: ${jobid}"
+                               echo "------------"
+                               echo "llist joblog jobid=${jobid}" | ${bcbin} -c ${bcconfig}
+                               echo "======================================================================"
+                       )
+               done
+               if [ ${html} = "yes" ]; then
+                       msg=${msg}$(echo "</pre>")
+               fi
+       fi
 fi
 
 
 # Prepend the header to the $msg output
 # -------------------------------------
-if [ ${html} == "yes" ]; then
-        msg="<html>
-        <head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">
-                <style>
-                        body {font-family:$fontfamily; font-size:$fontsize;} td {font-size:$fontsizejobinfo;} pre {font-size:$fontsizesumlog;}
-                </style>
-        </head>
-        <body>
-                <p><u><b>${emailtitle}</b></u></p>
-                <table width=\"98%\" align=\"center\" border=\"1\" cellpadding=\"2\" cellspacing=\"0\">
-                        <tr bgcolor=\"${jobtableheadercolor}\">
-                        <td align=\"center\"><b>Job ID</b></td>
-                        <td align=\"center\"><b>Job Name</b></td>
-                        <td align=\"center\"><b>Status</b></td>
-                        <td align=\"center\"><b>Errors</b></td>
-                        <td align=\"center\"><b>Type</b></td>
-                        <td align=\"center\"><b>Level</b></td>
-                        <td align=\"center\"><b>Files</b></td>
-                        <td align=\"center\"><b>Bytes</b></td>
-                        <td align=\"center\"><b>Start Time</b></td>
-                        <td align=\"center\"><b>End Time</b></td>
-                        <td align=\"center\"><b>Run Time</b></td>
-                </tr>
+if [ ${html} = "yes" ]; then
+       msg="<html>
+       <head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">
+               <style>
+                       body {font-family:$fontfamily; font-size:$fontsize;} td {font-size:$fontsizejobinfo;} pre {font-size:$fontsizesumlog;}
+               </style>
+       </head>
+       <body>
+               <p><u><b>${totaljobs} ${emailtitle}</b></u></p>
+               <table width=\"98%\" align=\"center\" border=\"1\" cellpadding=\"2\" cellspacing=\"0\">
+                       <tr bgcolor=\"${jobtableheadercolor}\">
+                       <td align=\"center\"><b>Job ID</b></td>
+                       <td align=\"center\"><b>Job Name</b></td>
+                       <td align=\"center\"><b>Client Name</b></td>
+                       <td align=\"center\"><b>Status</b></td>
+                       <td align=\"center\"><b>Errors</b></td>
+                       <td align=\"center\"><b>Type</b></td>
+                       <td align=\"center\"><b>Level</b></td>
+                       <td align=\"center\"><b>Files</b></td>
+                       <td align=\"center\"><b>Bytes</b></td>
+                       <td align=\"center\"><b>Start Time</b></td>
+                       <td align=\"center\"><b>End Time</b></td>
+                       <td align=\"center\"><b>Run Time</b></td>
+               </tr>
 ${msg}
 </body></html>"
-        else
-                msg="
-  ${emailtitle}
-  ------------------------------------------
+       else
+               msg="
+  ${totaljobs} ${emailtitle}
+  -------------------------------------------------
 
-  JobId      Job Name          Status         Errors     Type    Level   Files       Bytes         Start Time            End Time        Run Time
-  -----   --------------   ---------------  ----------  -------  -----  --------  -----------  -------------------  -------------------  --------
+  JobId     Job Name        Client Name         Status         Errors     Type    Level   Files       Bytes         Start Time            End Time        Run Time
+  -----   -------------    --------------   ---------------  ----------  -------  -----  --------  -----------  -------------------  -------------------  --------
 ${msg}"
 fi
 
-fi      # If there were zero results returned from the
-                # SQL the query, we skip the entire awk script,
-                # and a lot of other bash stuff that generates
-                # the email body and we end up here
-# -------------------------------------------------
+fi
+
+
+# If there were zero results returned from the
+# SQL the query, we skip the entire awk script,
+# and a lot of other bash stuff that generates
+# the email body and we end up here.
+# ---------------------------------------------
 if [ ${results} -eq 0 ]; then
-        status="No Jobs Have Been Run"
-        subjecticon="${nojobsicon}"
-        msg="Nothing to see here..."
-        else
-                # Totally unnecessary, but, well...  OCD... :)
-                # --------------------------------------------
-                if [ ${numbadjobs} -ne 0 ]; then
-                        if [ ${numbadjobs} -eq 1 ]; then
-                                job="Job"
-                                        else
-                                                job="Jobs"
-                        fi
-                        status="(${numbadjobs}) ${job} with Errors"
-                        subjecticon="${badjobsicon}"
-                                else
-                                        status="All Jobs OK"
-                                        subjecticon="${goodjobsicon}"
-                fi
+       status="No Jobs Have Been Run"
+       subjecticon="${nojobsicon}"
+       msg="These are not the droids you are looking for..."
+       else
+               # Totally unnecessary, but, well...  OCD... :)
+               # --------------------------------------------
+               if [ ${numbadjobs} -ne 0 ]; then
+                       if [ ${numbadjobs} -eq 1 ]; then
+                               job="Job"
+                               else
+                                       job="Jobs"
+                       fi
+                       status="(${numbadjobs}) ${job} with Errors"
+                       subjecticon="${badjobsicon}"
+                       else
+                               if [ ${totaljobs} -eq 1 ]; then
+                                       job="Job"
+                                       else
+                                               job="Jobs"
+                               fi
+                               status="All ${totaljobs} ${job} OK"
+                               subjecticon="${goodjobsicon}"
+               fi
 fi
 
 
 # More silliness
 # --------------
 if [ ${hist} -eq 1 ]; then
-        hour="Hour"
-        else
-                hour="Hours"
+       hour="Hour"
+       else
+               hour="Hours"
+fi
+
+
+# Touch up the Running or created message to append to Subject
+# ------------------------------------------------------------
+if [ ${addsubjectrunningorcreated} = "yes" ]; then
+       if [ ${runningorcreated} -ne 0 ]; then
+               if [ ${runningorcreated} -eq 1 ]; then
+                       job="job"
+                       else
+                               job="jobs"
+               fi
+               runningorcreatedsubject="(${runningorcreated} ${job} still queued/running)"
+               else
+                       runningorcreatedsubject=""
+       fi
 fi
 
 
@@ -710,19 +1015,21 @@ fi
 # ----------------
 (
 echo "To: ${admin}"
-echo "From: ${admin}"
-if [ ${addsubjecticon} == "yes" ]; then
-        echo "Subject: ${subjecticon} ${server} - ${status} in the Past ${hist} ${hour}"
-                else
-                        echo "Subject: ${server} - ${status} in the Past ${hist} ${hour}"
+echo "From: ${server} <${admin}>"
+if [ ${addsubjecticon} = "yes" ]; then
+       echo "Subject: ${subjecticon} ${server} - ${status} in the Past ${hist} ${hour} ${runningorcreatedsubject}"
+       else
+               echo "Subject: ${server} - ${status} in the Past ${hist} ${hour} ${runningorcreatedsubject}"
 fi
-if [ ${html} == "yes" ]  &&  [ ${results} -ne 0 ]; then
+if [ ${html} = "yes" ]  &&  [ ${results} -ne 0 ]; then
  echo "Content-Type: text/html"
  echo "MIME-Version: 1.0"
 fi
-echo ""
+echo
 echo "${msg}"
-) | /usr/sbin/sendmail -t
+) | ${sendmail} -t
+
+
 # -------------
 # End of script
 # -------------
@@ -810,7 +1117,7 @@ echo "${msg}"
 #          - Thanks to Chris Couture for the idea of adding RunTime
 #            to the email output.
 #          - Thanks to Chris Couture for the idea of using some unicode
-#            characters (a 'checkmark'or a bold 'x') in the Subject:
+#            characters (a 'checkmark' or a bold 'x') in the Subject:
 #            to quickly see if everything ran OK.
 #              - Added $addsubjecticon variable to enable/disable the
 #                prepending of this icon to the Subject.
@@ -822,20 +1129,20 @@ echo "${msg}"
 #            Chris Courture again for this nice idea.
 #          - Added $jobtableheadercolor, $jobtablejobcolor, $goodjobcolor,
 #            $goodjobwitherrcolor, $runningjobcolor, $warnjobcolor, and
-#            $badjobcolor variables to colorize HTML emails
-#          - Added $emailtitle variable for the title at the top
+#            $badjobcolor variables to colorize HTML emails.
+#          - Added $emailtitle variable for the title at the top.
 #          - Added $fontfamily, $fontsize, $fontsizejobinfo, and $fontsizesumlog
-#            variables to allow styling of the HTML output (Thanks again Chris)
+#            variables to allow styling of the HTML output. (Thanks again Chris)
 #          - Added $nojobsicon, $goodjobsicon, and $badjobsicon variables to
-#            allow setting the prepended utf-8 subject icon character
+#            allow setting the prepended utf-8 subject icon character.
 #          - Reformatted things so that if there are no jobs returned by the
-#            SQL query, the email message sent is nice and short
+#            SQL query, the email message sent is nice and short.
 #          - Modified the license to allow for inclusion into Bacula Community,
-#            and possibly the Enterprise Edition releases
+#            and possibly the Enterprise Edition releases.
 #
-# 20170430 - Modified the order of the fields to make more sense
+# 20170430 - Modified the order of the fields to make more sense.
 #          - Re-aligned the text email so that when an asterisk is pre-pended it
-#            does not shift the whole line
+#            does not shift the whole line.
 #
 # 20170508 - Re-worked some of the logic so that good jobs (JobStatus="T") which
 #            have errors will have their status listed as "OK/Warnings", and it
@@ -846,13 +1153,85 @@ echo "${msg}"
 #            db in the future.
 #          - Added an "Errors" column to the table to show "JobErrors" from the
 #            db.
-#          - Some minor variable name changes and other minor changes
+#          - Some minor variable name changes and other minor changes.
 #
-# 20170511 - Minor adjustments to the alignment formatting of the text email
-#          - Minor 'case' changes to a couple levels (Init & VCat)
+# 20170511 - Minor adjustments to the alignment formatting of the text email.
+#          - Minor 'case' changes to a couple levels (Init & VCat).
 #
-# ------------------------------------------------------------------------------
+# 20170517 - Rewrote the SQL queries so that the order of the fields returned
+#            matched the order of the colums in the email output. This allowed
+#            easier fixing of a strange issue where Bacula Enterprise does not
+#            set a "Level" for ADMIN type jobs that are started by the scheduler.
+#            This also forced modifications to all of the printf() output order,
+#            and allowed for easier shifting of variables in situations where
+#            some columns were null, causing the rest of the columns to shift
+#            left.
+#
+# 20170922 - Added a check for "Created, not yet running" jobs. (JobStatus="C").
+#            Added $createdjobcolor variable to display using their own color.
+#            Set any blank fields to "----"
+#
+# 20170926 - Fixed several bugs including a missing "Incomplete" status, and
+#            some incorrect placement of curly brackets in the awk script.
+#          - Added missing JobTypes for Copy/Control, Migration/Migrated.
+#          - Used "<hr>" in html output for blank fields.
+#          - Fixed an issue where a copy or migration job fails but does not
+#            have a start time. It has an end time, so this shifts everything
+#            two fields to the left. This is caused when the copy or the
+#            migration job is started, but the selection of jobs to copy/migrate
+#            returns an errror. (e.g.: the SQL Selection query returns an error)
+#
+# 20171002 - Fixed alignment problems with the text version of the report. Made
+#            modifications to some of the wording and filled blank fields with
+#            "-" characters.
+#          - Fixed the job summary output so that it properly prints all summary
+#            lines from the "Build OS:" line until the "Termination:" line and
+#            nothing else. For example, Verify job summaries are shorter than
+#            backup job summaries, and Copy/Migration jobs summaries are longer.
+#          - Added the number of "Bad Jobs", "Total Restore Files" and
+#            "Total Restore Bytes" to the Job Summary section.
+#
+# 20171005 - Added small change that someone submitted to my website which
+#            replaces any spaces in Job names with underscores. This keeps all of
+#            the columns in order for awk to work with. Thank you anonymous. :)
+#
+# 20171007 - Minor fix for failed Copy control jobs output (check for null $9)
+#
+# 20171201 - Removed all 'bashisms' to make this script as POSIX compliant as
+#            possible.
+#          - So, no more '[[ some test ]]' and no more 'echo -e'
+#          - Tested with 'dash' which is a strictly POSIX compliant shell,
+#            so this should be very portable now.
+#          - Minor reorganization of the variables at the top.
+#
+# 20171202 - Added $boldjobname and $centerjobname variables to allow the jobname
+#            in HTML emails to be bolded and/or centered.
+#
+# 20171215 - Began to implement sqlite3 support
+#
+# 20200811 - Set 24 hours as a default number of hist hours. Now, no command line
+#            parameters are required.
+#          - Added 'hist', 'baculafd', and 'admin' variable command line overrides.
+#          - Added the ability to report on one Client or multiple Clients based
+#            on second command line parameter and a SQL "LIKE" query.
+#          - Now, one (hist), two (hist Client), or three (hist client admin_email)
+#            command line parameters may be supplied. If you want to specify admin
+#            email on command line *and* you want to report on all clients, then
+#            just set the second parameter to "".
+#          - Keep in mind: Admin, Copy Control, and Migration jobs do not have a
+#            a Client. When filtering by Client, these jobs cannot be included in
+#            the report.
+#
+# 20200820 - Write the number of Jobs with errors (awkerr varable) to a temporary
+#            file instead of exiting the main awk script with the awkerr variable.
+#            This solves the issue of "wrap around" when this number exceeds 255
+#            because POSIX exit result codes are only 0-255 (8-bit number)
+#          - Added the total number of jobs to the "All Jobs OK..." email subject
+#          - Added the total number of jobs to the top of the email body
+#
+# 20200925 - Swap the Job Name and Client columns so that the Job Name is first
+# ---------------------------------------------------------------------------------
 
 
-# I like small tabs. Use  :set list in vim to see tabbing etc
-# vim: set tabstop=2:softtabstop=2:shiftwidth=2 #
+# I like small tabs. Use :set list in vim to see tabbing etc
+# vim: tabstop=2 softtabstop=2 shiftwidth=2