#!/bin/sh -efu

if [ -z "${__included_bacula_sh_functions:-}" ]; then
__included_bacula_sh_functions=1

. shell-var
. shell-quote

# definitions
bacula_daemon_list='dir fd sd'
bacula_magic_string='#generated by bacula-sh-functions'
bacula_db_name=bacula
bacula_default_job_name="DefaultJob"
bacula_console_timeout=15

# directories
bacula_sysconf_dir=/etc/bacula
bacula_mount_dir=/mnt/bacula
bacula_localstate_dir=/var/lib/bacula
bacula_filelist_dir="$bacula_sysconf_dir/filelist"
bacula_fileset_dir="$bacula_sysconf_dir/fileset"
bacula_client_dir="$bacula_sysconf_dir/client"
bacula_schedule_dir="$bacula_sysconf_dir/schedule"
bacula_job_dir="$bacula_sysconf_dir/job"
bacula_pool_dir="$bacula_sysconf_dir/pool"

# subdirectory for file storages
# note: we use an additional subdirectory under file storage to setup appropriate access rights
#       and hide backup data from everyone except administrator
bacula_backup_subdir="backup"

# files
bacula_db_file="$bacula_localstate_dir/$bacula_db_name.db"
bacula_sql_file="$bacula_localstate_dir/$bacula_db_name.sql"

bacula_dir_file="$bacula_sysconf_dir/bacula-dir.conf"
bacula_fd_file="$bacula_sysconf_dir/bacula-fd.conf"
bacula_fd_password_file="$bacula_sysconf_dir/bacula-fd-password.conf"
bacula_sd_file="$bacula_sysconf_dir/bacula-sd.conf"
bacula_console_file="$bacula_sysconf_dir/bconsole.conf"
bacula_storage_file="$bacula_sysconf_dir/storage/file.conf"

bacula_device_file="$bacula_sysconf_dir/device/filestorage.conf"

# catalog
bacula_catalog_name="MyCatalog"
bacula_catalog_schedule_file="$bacula_sysconf_dir/schedule/weeklycycleafterbackup.conf"
bacula_catalog_schedule_name="WeeklyCycleAfterBackup"
bacula_catalog_job_file="$bacula_sysconf_dir/job/backupcatalog.conf"
bacula_catalog_bsr_file="BackupCatalog.bsr"
bacula_catalog_job_name='BackupCatalog'

# groups
backupadmin_group='backupadmin'

### simple config processing

__section_range()
{
    local section
    quote_sed_regexp_variable section "$1"
    echo "/^[[:space:]]*$section[[:space:]]*{[[:space:]]*\(#.*\)\?\$/,/^[[:space:]]*}[[:space:]]*\$/"
}

# simple config file reading
# usage: bacula_config_get file section name
bacula_config_get()
{
    local file="$1";shift
    local section="$1";shift
    local name="$1";shift

    local qname
    quote_sed_regexp_variable qname "$name"

    sed \
        -n \
	-e "$(__section_range "$section") s/^[[:space:]]*$qname[[:space:]]*=[[:space:]]*\"\?\([^\"]\+\)\"\?[[:space:]]*$/\1/p" \
	"$file"
}

# simple config file writing
# usage: bacula_config_get <file> <section> <name> <value> [quote]
# note: bacula cannot understand some values in quote mode, default value of quote is 1
bacula_config_set()
{
    local file="$1";shift
    local section="$1";shift
    local name="$1";shift
    local value="$1";shift
    local quote="${1:-1}"

    [ "$quote" = "0" ] || value="\"$value\""

    local qname qvalue
    quote_sed_regexp_variable qname "$name"
    quote_sed_regexp_variable qvalue "$value"

    sed \
	-e "$(__section_range "$section") s/^#\?\([[:space:]]*$qname[[:space:]]*=[[:space:]]*\).*/\1$qvalue/" \
	-i "$file"
}


# comment variable in section
# usage: bacula_config_get file section name
bacula_config_comment()
{
    local file="$1";shift
    local section="$1";shift
    local name="$1";shift

    local qname
    quote_sed_regexp_variable qname "$name"

    sed \
	-e "$(__section_range "$section") s/^\([[:space:]]*$qname[[:space:]]*=[[:space:]]*.*\)/#\1/" \
	-i "$file"
}



# uncomment variable in section
# usage: bacula_config_get file section name
bacula_config_uncomment()
{
    local file="$1";shift
    local section="$1";shift
    local name="$1";shift

    local qname
    quote_sed_regexp_variable qname "$name"

    sed \
	-e "$(__section_range "$section") s/^#\([[:space:]]*$qname[[:space:]]*=[[:space:]]*.*\)/\1/" \
	-i "$file"
}

### simple console sql requests

# helper, grep sql table cells from bconsole output
__grep_row()
{
    sed -n -e '/^|/!d; x; /^$/!{x;s/^|[[:space:]]*//;s/[[:space:]]*|$//;s/[[:space:]]\+|[[:space:]]\+/\t/g;p}'
}

bacula_console_query_sql()
{
    /sbin/service bacula-dir status >/dev/null || return 0

    (bconsole -c "$bacula_console_file" <<EOF
sqlquery
$1
.
EOF
)|__grep_row
}

bacula_console_query_cmd()
{
    /sbin/service bacula-dir status >/dev/null || return 0

    bconsole -c "$bacula_console_file" -u "$bacula_console_timeout"
}

bacula_console_set_director()
{
    bacula_config_set "$bacula_console_file" Director Name "$1"
}

### support include/exclude in bacula-dir config file
__director_include_add()
{
    grep -wqs "@$1" "$bacula_dir_file" ||
	printf '@%s\n' "$1" >>"$bacula_dir_file"
    cat >"$1"
}

__director_include_del()
{
    sed "/^@$(quote_sed_regexp "$1")\$/d" -i "$bacula_dir_file"
    rm -f -- "$1"
}

### common work with filesets
### fileset constists from two parts: bacula config and file list

# add file to filelist
# usage: bacula_filelist_add <fileset> <file>
bacula_filelist_add()
{
    fgrep -wqs "$2" "$1" || echo "$2" >> "$1"
}

# remove file from filelist
# usage: bacula_filelist_add <fileset> <file>
bacula_filelist_del()
{
    sed "/^$(quote_sed_regexp "$2")\$/d" -i "$1"
}

### common daemon work

bacula_daemon_status()
{
    local IFS=' '
    local runlevel="$(/sbin/runlevel | cut -c3)"
    for i in $bacula_daemon_list; do
	LANG=C LC_ALL=C /sbin/chkconfig --list bacula-$i|grep -qs "${runlevel}:on" || return 1
	/sbin/service bacula-$i status >/dev/null || return 1
    done
    return 0
}

bacula_daemon_on()
{
    bacula_daemon_status ||
	for i in $bacula_daemon_list; do
	    /sbin/chkconfig bacula-$i on
	    /sbin/service bacula-$i start >&2 || return 1
	done
}

bacula_daemon_off()
{
    for i in $bacula_daemon_list; do
	/sbin/service bacula-$i stop >&2
	/sbin/chkconfig bacula-$i off
    done
}

### jobs

# purge jobs for specified client
# note: don't use purge jobs client= to avoid autoselecting feature
bacula_job_del_by_name()
{
    bacula_console_query_sql "select jobId from Job where Name='$1';"|
	while read jobid; do
	    printf 'delete job jobid="%s"\n' "$jobid"|bacula_console_query_cmd
	done
}

bacula_job_list_active()
{
    bacula_console_query_sql "select jobId from Job where jobStatus='R' or jobStatus='C';"
}

__parse_jobid()
{
    tee /dev/stderr|
	sed -n 's/Job queued.*JobId=\([^[:space:]]\+\).*/\1/p'
}

bacula_job_run()
{
    printf 'run %s yes\n' "$1"|
	bacula_console_query_cmd|
	__parse_jobid
}

bacula_job_enable()
{
    printf 'enable job=%s' "$1"|bacula_console_query_cmd
}

bacula_job_disable()
{
    printf 'disable job=%s' "$1"|bacula_console_query_cmd
}

bacula_job_cancel()
{
    local name="$1";shift
    printf 'cancel job=%s\n' "$name"|bacula_console_query_cmd
}

bacula_job_status()
{
    local jobid="$1";shift
    bacula_console_query_sql "select jobStatus from Job where jobId='$jobid';"
}

### various restore jobs

__mark_path()
{
    local dir="${1%/*}"
    local base="${1##*/}"

    [ "$dir" != "$1" ] || return 0

    local IFS='/'
    for i in $dir; do
	[ -n "$i" ] || continue
	printf 'cd "%s"\n' "$i"
    done

    printf 'mark "%s"\n' "$base"
}

bacula_restore_file()
{
    local client="$1";shift
    local fileset="$1";shift
    local date="$1";shift
    local file="$1";shift
    local restoreclient="$1";shift
    local restorepath="$1";shift

    [ -n "$restorepath" ] || restorepath="/"

    ( bacula_console_query_cmd<<EOF
restore client="$client" fileset="$fileset" restoreclient="$restoreclient" where="$restorepath" before="$date 23:59:00" select yes
$(__mark_path "$file")
done
EOF
)|__parse_jobid
}

bacula_restore_all()
{
    local client="$1";shift
    local fileset="$1";shift
    local date="$1";shift
    local target_dir="$1";shift

    local next_date="$(date +'%F %T' --date="$date 1 min")"

    printf 'restore client="%s" fileset="%s" before="%s" select all done where="%s" yes\n' \
	"$client" "$fileset" "$next_date" "$target_dir"|
	bacula_console_query_cmd|
	__parse_jobid
}

### storage setup

# read storage device usage in percent
# usage: bacula_storage_get_usage <path>
bacula_storage_get_usage()
{
    local storage_dir="$(readlink -e "$1")/$bacula_backup_subdir"
    df -lhP |
	sed 1d |
	sort -r -k 6,6 |
	while read fs total use avail percent mpoint; do
	    [ -z "${storage_dir##$mpoint*}" ] || continue
	    echo "$percent"
	    break
	done
}

bacula_storage_status_last()
{
    printf '.status storage last\n'|
	bacula_console_query_cmd|
	sed -n 's/.*[[:space:]]JobStatus=\([^[:space:]]\+\)[[:space:]].*/\1/p'
}

bacula_storage_status_current()
{
    printf '.status storage current\n'|
	bacula_console_query_cmd|
	sed -n 's/.*[[:space:]]JobStatus=\([^[:space:]]\+\)[[:space:]].*/\1/p'
}

bacula_storage_status_running()
{
    printf 'gui on\n.status storage=File running\n'|
	bacula_console_query_cmd|
	    sed '1,5d'
}


# setup storage device path
bacula_storage_set_path()
{
    local backup_dir="$1/$bacula_backup_subdir";shift
    # set correct access rights
    install -d  -m2750 --owner bacula --group "$backupadmin_group" "$backup_dir"
    find "$backup_dir" -type f|xargs -r chown bacula:"$backupadmin_group"

    # update device settings
    # note: don't use bacula_config_set, becaulse, bacula-local-backup backend3 needs magic string here
    cat>"$bacula_device_file"<<EOF
$bacula_magic_string
Device {
  Name = FileStorage
  Media Type = File
  Archive Device = "$backup_dir"
  LabelMedia = yes;
  Random Access = Yes;
  AutomaticMount = yes;
  RemovableMedia = no;
  AlwaysOpen = no;
}
EOF

    # catalog's bootstrap lives in backup directory too
    bacula_catalog_set_bsr "$backup_dir/$bacula_catalog_bsr_file"
}

# read storage device path
bacula_storage_get_path()
{
    local v="$(bacula_config_get "$bacula_device_file" Device "Archive Device")"
    echo "${v%/$bacula_backup_subdir}"
}

# read official public storage address
bacula_storage_get_address()
{
    bacula_config_get "$bacula_storage_file" Storage Address|
	sed \
	    -e 's/#.*$//' \
	    -e 's/[[:space:]]*$//'
}

# setup official public storage address
bacula_storage_set_address()
{
    bacula_config_set "$bacula_storage_file" Storage Address "$1"
}

bacula_storage_probe_path()
{
    [ -e "$1/$bacula_backup_subdir/$bacula_catalog_bsr_file" ] && echo "$1"
}

# update accepted director name
bacula_storage_set_director()
{
    local name="$1";shift

    local qname
    quote_sed_regexp_variable qname "$name"

    # update Messages
    local v="$(bacula_config_get "$bacula_fd_file" Messages director)"
    v="$(echo "$v"|sed "s/^[[:space:]]*[^[:space:]]\+\([[:space:]]*=.*\)/$qname\1/")" #"
    bacula_config_set "$bacula_sd_file" Messages director "$v" 0

    # update Director
    bacula_config_set "$bacula_sd_file" Director Name "$name"
}

### catalog setup

bacula_catalog_restore()
{
    local source_dir="$1/$bacula_backup_subdir";shift
    local dest_dir="$1";shift
    local bsr_file="$source_dir/$bacula_catalog_bsr_file"

    install -dpm 770 --owner root --group bacula "$dest_dir/$bacula_localstate_dir"

    [ -e "$bsr_file" ] || return 1

    #extract sql file using low level utility
    local include_file=`mktemp -t bextract.XXXXXX` || return 1
    printf "%s\n" "$bacula_sql_file" >"$include_file"

    local rc=0
    /usr/sbin/bextract -i "$include_file" -b "$bsr_file" "$source_dir" "$dest_dir" || rc=1

    rm -f -- "$include_file"

    [ "$rc" = "0" ] || return 1

    #regenerate sql database (FIXME: for sqlite3 only!)
    rm -f -- "$dest_dir/$bacula_db_file"
    cat "$dest_dir/$bacula_sql_file" | sqlite3 "$dest_dir/$bacula_db_file" ||
	return 1

    chmod 640 "$dest_dir/$bacula_db_file"
    chown bacula:bacula "$dest_dir/$bacula_db_file"
}

bacula_catalog_set_path()
{
    local path
    quote_sed_regexp_variable path "$1"
    sed "s/\(^[[:space:]]*WorkingDirectory[[:space:]]*=[[:space:]]*\).*/\1\"$path\"/" \
	-i "$bacula_dir_file"
}

bacula_catalog_set_bsr()
{
    local path
    quote_sed_regexp_variable path "$1"

    sed "s/\(^[[:space:]]*Write[[:space:]]\+Bootstrap[[:space:]]*=[[:space:]]*\).*/\1\"$path\"/" \
	-i "$bacula_catalog_job_file"
}

# schedule catalog backup after main backup

# special schedule for catalog (database) backup
# usage: bacula_catalog_set_time schedule-time
bacula_catalog_set_time()
{
    local catalog_time="$(date +'%H:%M' --date="$1 1min")";shift

    __director_include_add "$bacula_catalog_schedule_file"<<EOF
$bacula_magic_string
Schedule {
  Name = "$bacula_catalog_schedule_name"
  Run = Full sun-sat at $catalog_time
}
EOF
}


### schedule setup

# setup weekly schedule period
# usage: bacula_schedule_set_time schedule-file schedule-name schedule-time
bacula_schedule_set_time()
{
    local schedfile="$1";shift
    local schedname="$1";shift
    local schedtime="${1%:*}";shift

    __director_include_add "$schedfile"<<EOF
$bacula_magic_string
Schedule {
  Name = "$schedname"
  Run = Full 1st sun at $schedtime
  Run = Differential 2nd-5th sun at $schedtime
  Run = Incremental mon-sat at $schedtime
}
EOF

}

# read schedule time
# note: will work correctly only in pair with bacula_schedule_set_time() function
# usage: bacula_schedule_get_time schefile-file
bacula_schedule_get_time()
{
    bacula_config_get "$1" Schedule Run|
	sed -n -e 's/.*[[:space:]]\+at[[:space:]]\+\([^[:space:]]\+\)[[:space:]]*$/\1:00/p;T;q'
}

### physical device setup

__read_var()
{
    local line="$1";shift
    local name="$1";shift
    local v="${line#* $name=\"}"
    echo "${v%%\"*}"
}

__read_priority()
{
    local dev_name="$1";shift
    if [ -d "/sys/class/block/$dev_name/md" ];then
	echo "2"
    elif [ -d "/sys/devices/virtual/block/$dev_name" ];then
	echo "1"
    else
	echo "0"
    fi
}

__list_partitions()
{
    local line= fs_uuid= fs_type=
    local dev_major_minor= dev_name= dev_priority=
    blkid -c /dev/null|
    while read line; do
	    dev_name="${line%%:*}"
	    dev_name="${dev_name##*/}"
	    dev_major_minor="$(cat /sys/class/block/$dev_name/dev)"

	    fs_uuid="$(__read_var "$line" UUID)"
	    fs_type="$(__read_var "$line" TYPE)"

	    case "$fs_type" in
		ext2|ext3|ext4|xfs|ntfs) ;;
		*) continue ;;
	    esac

	    dev_priority="$(__read_priority "$dev_name")"

	    printf '%s\t%s\t%s\t%s\t%s\n' \
		"$dev_major_minor" \
		"$fs_uuid" "$dev_name" "$dev_priority" \
		"$fs_type"
	done|
	sort -k1,1
}

__read_major_minor()
{
    local data="$(stat -L -c '%t:%T' "$1")"
    local major="${data%:*}"
    local minor="${data#*:}"

    printf '%s:%s' "$((0x$major))" "$((0x$minor))"
}

__list_mpoints()
{
    local device= mpoint= line= uuid= tags=
    while read device mpoint line; do
	[ -b "$device" ] || continue

	printf '%s\t%s\n' "$(__read_major_minor "$device")" "$mpoint"
    done </proc/mounts|
    sort -k1,1
}

bacula_device_list()
{
    local tempfile="$(mktemp -t scan-partitions.XXXX)"

    __list_mpoints >"$tempfile"
    __list_partitions|
	join -a1 -j1 -  "$tempfile"|
	awk '
{ id=$2;
  dv=$3;
  pr=$4;
  fs=$5;
  mp=$6;

  if (mp) pr+=4;
  if (pr >= pr_list[id]) { pr_list[id]=pr; mp_list[id]=mp; fs_list[id]=fs; dv_list[id]=dv } 
}
END { for (i in dv_list) { printf "%s\t%s\t%s\t%s\n",i,dv_list[i],fs_list[i],mp_list[i]; } }
'
    rm -f -- "$tempfile"
}

bacula_device_probe()
{
    local name="$1";shift
    local fs="$1";shift
    local mpoint="$1";shift

    if [ -n "$mpoint" ] ;then
	bacula_storage_probe_path "$mpoint"
    else
	mpoint="$bacula_mount_dir"
	mkdir -p -- "$mpoint"
	[ "$fs" != "ntfs" ] || fs="ntfs-3g"

	mount -t "$fs" /dev/$name "$mpoint" >&2 || mount -t "$fs" /dev/mapper/$name "$mpoint" >&2 || return 1
	if ! bacula_storage_probe_path "$mpoint"; then
	    umount "$mpoint" >&2
	    return 1;
	fi
    fi
}

bacula_device_find_path()
{
    local notify="$1";shift
    local mpoint=
    bacula_device_list|
    while read dev_uid dev_name dev_fs dev_mpoint; do
	"$notify" "$dev_name"
	if mpoint="$(bacula_device_probe "$dev_name" "$dev_fs" "$dev_mpoint")";then
	    echo "$mpoint"
	fi
    done
}

### pool management

# create new pool
# usage: bacula_pool_add <name>
bacula_pool_add()
{
    local name="$1"

    __director_include_add "$bacula_pool_dir/$name.conf"<<EOF
$bacula_magic_string
Pool {
  Name = "$name"
  Pool Type = Backup
  Recycle = yes
  AutoPrune = yes
  Volume Use Duration = 23 hours
  Volume Retention = 7 days
  LabelFormat = "$name-"
}
EOF
}

# clear pool and pool's files
# usage: bacula_pool_clear <pool-name> [<volume-dir>]
# if volume dir is specified, appropriate files will be removed
bacula_pool_clear()
{
    local poolname="$1";shift
    local volume_dir="${1:-}"
    local volume

    # files cleanup
    if [ -n "$volume_dir" ];then
	local volname="$(bacula_console_query_sql "select LabelFormat from Pool  where Name = '$poolname' limit 1;")"
	local qvolname
	quote_sed_regexp_variable qvolname "$volname"

	find "$volume_dir/$bacula_backup_subdir" -regextype posix-basic  -type f -regex "$volume_dir/$bacula_backup_subdir/$qvolname[0-9]\+" -delete
    fi

    # database cleanup
    bacula_console_query_sql "select M.VolumeName from Media M , Pool P  where M.PoolId = P.PoolId and P.Name = '$poolname' and M.VolStatus != 'Purged';"|
	while read volume; do
	    printf 'purge volume="%s"\n' "$volume"|bacula_console_query_cmd
	done

}

# remove pool and pool's files
# usage: bacula_pool_del <name> <storage-dir>
bacula_pool_del()
{
    local poolname="$1";shift
    local volume_dir="$1";shift
    local volume

    # files cleanup
    local volname="$(bacula_console_query_sql "select LabelFormat from Pool  where Name = '$poolname' limit 1;")"
    local qvolname
    quote_sed_regexp_variable qvolname "$volname"

    find "$volume_dir/$bacula_backup_subdir" -regextype posix-basic  -type f -regex "$volume_dir/$bacula_backup_subdir/$qvolname[0-9]\+" -delete

    # database cleanup
    bacula_console_query_sql "select M.VolumeName from Media M , Pool P  where M.PoolId = P.PoolId and P.Name = '$poolname';"|
	while read volume; do
	    printf 'delete volume="%s" yes\n' "${volume##*/}"|bacula_console_query_cmd
	done
    #note: bacula doesn't understand yes here
    printf 'delete pool="%s"\nyes\n' "$poolname"|bacula_console_query_cmd

    __director_include_del "$bacula_pool_dir/$poolname.conf"
}

# read pool's volume retention
# usage: bacula_pool_get_retention <filename>
bacula_pool_get_retention()
{
    bacula_config_get "$1" Pool "Volume Retention"|sed 's/[[:space:]]\+days[[:space:]]*$//'
}

# update pool's volume retention
# usage: bacula_pool_set_retention <filename> <value>
bacula_pool_set_retention()
{
    bacula_config_set "$1" Pool "Volume Retention" "$2 days" 0
}

### file daemon setup

# update accepted director name
bacula_file_set_director()
{
    local name="$1";shift

    local qname
    quote_sed_regexp_variable qname "$name"

    # update Messages
    local v="$(bacula_config_get "$bacula_fd_file" Messages director)"
    v="$(echo "$v"|sed "s/^[[:space:]]*[^[:space:]]\+\([[:space:]]*=.*\)/$qname\1/")" #"
    bacula_config_set "$bacula_fd_file" Messages director "$v" 0

    # update Director
    bacula_config_set "$bacula_fd_file" Director Name "$name"
}

# update file daemon's password
bacula_file_set_password()
{
    local value
    quote_sed_regexp_variable value "$1"
    sed \
	-e "s/\(^[[:space:]]*Password[[:space:]]*=[[:space:]]*\).*/\1\"$value\"/" \
	-i "$bacula_fd_password_file"
}

bacula_get_include_from_section()
{
	local file="$1";shift
	local section="$1";shift
#	sed "/^@$(quote_sed_regexp "$1")\$/d" -i "$bacula_dir_file"
	sed \
		-n \
		-e "$(__section_range "$section") s/^@//p" \
		"$file"
}

bacula_file_get_password()
{
	name=Password
	local qname
	quote_sed_regexp_variable qname "$name"
	local file="$(bacula_get_include_from_section "$bacula_fd_file" Director)"
	sed \
		-n \
		-e "s/^[[:space:]]*$qname[[:space:]]*=[[:space:]]*\"\?\([^\"]\+\)\"\?[[:space:]]*$/\1/p" \
		"$file"

}

bacula_fdfile_get_password()
{
	bacula_config_get "$bacula_fd_file" Director Password
}

bacula_file_get_director()
{
	bacula_config_get "$bacula_fd_file" Director Name
}

# read current processing file
bacula_file_get_progress()
{
    printf 'status client="%s"\n' "$1"|
	bacula_console_query_cmd|
	sed -n 's/^[[:space:]]\+Processing file:[[:space:]]\+//p'
}

### director setup

# read director's name
bacula_director_get_name()
{
    bacula_config_get "$bacula_dir_file" Director Name
}

# update director's name
bacula_director_set_name()
{
    bacula_config_set "$bacula_dir_file" Director Name "$1"
}

# update catalog password
bacula_director_set_catalog_password()
{
    bacula_config_set "$bacula_dir_file" Catalog password "$1"
}

bacula_director_status_last()
{
    printf '.status dir last\n'|
	bacula_console_query_cmd|
	sed -n 's/.*[[:space:]]JobStatus=\([^[:space:]]\+\)[[:space:]].*/\1/p'
}

bacula_director_status_current()
{
    printf '.status dir current\n'|
	bacula_console_query_cmd|
	sed -n 's/.*[[:space:]]JobStatus=\([^[:space:]]\+\)[[:space:]].*/\1/p'|
	head -n1
}

bacula_director_status_running()
{
    printf '.status dir running\n'|
	bacula_console_query_cmd|
	sed -n '/==/,/==/ {/==/!p}'
}

fi #__included_bacula_sh_functions
