1077 lines
26 KiB
Bash
Executable File
1077 lines
26 KiB
Bash
Executable File
#! /bin/dash
|
|
|
|
# tape_admin
|
|
# https://github.com/rzerres/dsnap-sync
|
|
# Copyright (C) 2017, 2018 Ralf Zerres
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
|
|
# You should have received a copy of the GNU General Public License along
|
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
# -------------------------------------------------------------------------
|
|
|
|
# Helper routines for tape handling
|
|
|
|
progname="${0##*/}"
|
|
version="0.0.1"
|
|
|
|
# global variables
|
|
color=0
|
|
date_cmd="date -u +%Y%M%d%H%M%S"
|
|
default_changer_device="/dev/changer"
|
|
dryrun=0
|
|
ltfs_mountpoint="/media/tape"
|
|
ltfs_devname="/dev/sg9"
|
|
mediapools_json="/etc/dsnap-sync/MediaPools.json"
|
|
mediapool_name=""
|
|
use_mtx=0
|
|
verbose=0
|
|
volume_name=""
|
|
|
|
#
|
|
MTX=mtx
|
|
JQ=jq
|
|
LTFS=ltfs
|
|
LTFSCK=ltfsck
|
|
MKLTFS=mkltfs
|
|
|
|
# ascii color
|
|
BLUE=
|
|
GREEN=
|
|
MAGENTA=
|
|
RED=
|
|
YELLOW=
|
|
NO_COLOR=
|
|
|
|
###
|
|
# functions
|
|
###
|
|
|
|
check_prerequisites () {
|
|
# requested binaries:
|
|
which ${MTX} >/dev/null 2>&1 || { printf "'%s' is not installed.\n" ${MTX} && exit 1; }
|
|
which ${LTFS} >/dev/null 2>&1 || { printf "'%s' is not installed.\n" ${LTFS} && exit 1; }
|
|
which ${MKLTFS} >/dev/null 2>&1 || { printf "'%s' is not installed.\n" ${MKLTFS} && exit 1; }
|
|
|
|
which ${JQ} >/dev/null 2>&1 || { printf "'%s' is not installed.\n" ${JQ} && exit 1; }
|
|
|
|
}
|
|
|
|
compare_date () {
|
|
local date1=${1}
|
|
local date2=${2}
|
|
|
|
if [ $date1 -eq $date2 ]; then
|
|
if [ $verbose -ge 2 ]; then
|
|
printf "${MAGENTA}date1 ${GREEN}'%s'${MAGENTA} is equal to date2 ${GREEN}'%s'${NO_COLOR}\n" \
|
|
"$date1" "$date2"
|
|
fi
|
|
return 0
|
|
elif [ $date1 -lt $date2 ]; then
|
|
if [ $verbose -ge 2 ]; then
|
|
printf "${MAGENTA}date1 ${GREEN}'%s'${MAGENTA} is lower then date2 ${GREEN}'%s'${NO_COLOR}\n" \
|
|
"$date1" "$date2"
|
|
fi
|
|
return 1
|
|
elif [ $date1 -gt $date2 ]; then
|
|
if [ $verbose -ge 2 ]; then
|
|
printf "${MAGENTA}date1 ${GREEN}'%s'${MAGENTA} is greater then date2 ${GREEN}'%s'${NO_COLOR}\n" \
|
|
"$date1" "$date2"
|
|
fi
|
|
return 2
|
|
fi
|
|
}
|
|
|
|
die () {
|
|
error "$@"
|
|
exit 1
|
|
}
|
|
|
|
error () {
|
|
printf "\n==> ERROR: %s\n" "$@"
|
|
notify_error 'Error' 'Check journal for more information.'
|
|
} >&2
|
|
|
|
get_mediapolicy () {
|
|
local mediapools_json=${mediapools:-$mediapools_json}
|
|
local mediapool_name=${1}
|
|
local volume_name=${2}
|
|
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${BLUE}get_mediapolicy...${NO_COLOR}\n"
|
|
fi
|
|
|
|
if test ! -r ${mediapools_json}; then
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${RED}Error:${MAGENTA} media-pool file ${GREEN}'%s'${MAGENTA} can't be opend!${NO_COLOR}}\n" \
|
|
"$mediapools_json"
|
|
fi
|
|
exit 1
|
|
fi
|
|
|
|
cmd="jq --monochrome-output --ascii-output ' .MediaPool[] \
|
|
| select(.Name == \"${mediapool_name}\") \
|
|
| .Member[] \
|
|
| select(.VolumeName == \"${volume_name}\") \
|
|
| .MediaPolicy ' \
|
|
${mediapools_json}"
|
|
volume_mediapolicy=$(eval $cmd)
|
|
|
|
if [ $verbose -ge 3 ]; then
|
|
printf "${MAGENTA}MediaPolicy for volume_name ${GREEN}'%s'${MAGENTA} in media-pool ${GREEN}'%s'${MAGENTA}: ${NO_COLOR}%s${NO_COLOR}\n" \
|
|
"$volume_name" "$mediapool_name" "$volume_mediapolicy"
|
|
fi
|
|
}
|
|
|
|
get_poolmember () {
|
|
# return: 0-> volume_name match; 1 -> volume_name does not match
|
|
local mediapools_json=${mediapools:-$mediapools_json}
|
|
local mediapool_name=${1}
|
|
local volume_name=${2:-any}
|
|
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${BLUE}get_poolmember...${NO_COLOR}\n"
|
|
fi
|
|
|
|
if test ! -r ${mediapools_json}; then
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${RED}Error:${MAGENTA} media-pool file ${GREEN}'%s'${MAGENTA} can't be opend!${NO_COLOR}}\n" \
|
|
"$mediapools_json"
|
|
fi
|
|
exit 1
|
|
fi
|
|
|
|
#cmd="jq --monochrome-output --join-output --ascii-output '.MediaPool[] \
|
|
cmd="jq --monochrome-output --ascii-output '.MediaPool[] \
|
|
| select(.Name == \"${mediapool_name}\") \
|
|
| .Member[].VolumeName' \
|
|
${mediapools_json}"
|
|
poolmember=$(eval $cmd)
|
|
|
|
if [ $verbose -ge 2 ]; then
|
|
printf "${MAGENTA}poolmembers for media-pool ${GREEN}'%s'${MAGENTA} are:\n${NO_COLOR}%s${NO_COLOR}\n" \
|
|
"$mediapool_name" "$poolmember"
|
|
fi
|
|
|
|
for i in $poolmember ; do
|
|
if test "$i" = "\"${volume_name}\""; then
|
|
if [ $verbose -ge 3 ]; then
|
|
printf "${MAGENTA}volume_name ${GREEN}'%s'${MAGENTA} is member of media-pool ${GREEN}'%s'${NO_COLOR}}\n" \
|
|
"$i" "$mediapool_name"
|
|
fi
|
|
return 0
|
|
break
|
|
fi
|
|
done
|
|
return 1
|
|
}
|
|
|
|
get_poolmember_next () {
|
|
local mediapools_json=${mediapools:-$mediapools_json}
|
|
local mediapool_name=${1}
|
|
local volume_name=${2}
|
|
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${BLUE}get_poolmember_next...${NO_COLOR}\n"
|
|
fi
|
|
|
|
if test ! -r ${mediapools_json}; then
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${RED}Error:${MAGENTA} media-pool file ${GREEN}'%s'${MAGENTA} can't be opend!${NO_COLOR}}\n" \
|
|
"$mediapools_json"
|
|
fi
|
|
exit 1
|
|
fi
|
|
|
|
cmd="jq --monochrome-output --ascii-output ' .MediaPool[] \
|
|
| select(.Name == \"${mediapool_name}\") \
|
|
| .Member[] \
|
|
| .VolumeName ' \
|
|
${mediapools_json}"
|
|
volume_poolmember=$(eval $cmd)
|
|
|
|
i=0
|
|
volume_index=-1
|
|
for member in $volume_poolmember; do
|
|
if [ $i -eq 0 ]; then
|
|
volume_name_next=$(echo $member | sed -e 's/"//g')
|
|
fi
|
|
if [ $i -eq $volume_index ]; then
|
|
if [ ${#member} -ge 1 ]; then
|
|
volume_name_next=$(echo $member | sed -e 's/"//g')
|
|
break;
|
|
fi
|
|
fi
|
|
if [ $member = \"$volume_name\" ]; then
|
|
volume_index=$(($i+1))
|
|
fi
|
|
i=$(($i + 1))
|
|
done
|
|
|
|
if [ $verbose -ge 3 ]; then
|
|
printf "${MAGENTA}poolmember_next for media-pool ${GREEN}'%s'${MAGENTA} is: ${NO_COLOR}%s${NO_COLOR}\n" \
|
|
"$mediapool_name" "$volume_name_next"
|
|
fi
|
|
}
|
|
|
|
get_slot () {
|
|
local mediapools_json=${mediapools:-$mediapools_json}
|
|
local mediapool_name=${1}
|
|
local volume_name=${2}
|
|
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${BLUE}get_slot...${NO_COLOR}\n"
|
|
fi
|
|
|
|
if test ! -r ${mediapools_json}; then
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${RED}Error:${MAGENTA} media-pool file ${GREEN}'%s'${MAGENTA} can't be opend!${NO_COLOR}}\n" \
|
|
"$mediapools_json"
|
|
fi
|
|
exit 1
|
|
fi
|
|
|
|
cmd="jq --monochrome-output --ascii-output ' .MediaPool[] \
|
|
| select(.Name == \"${mediapool_name}\") \
|
|
| .Member[] \
|
|
| select(.VolumeName == \"${volume_name}\") \
|
|
| .Slot ' \
|
|
${mediapools_json}"
|
|
volume_slot=$(eval $cmd)
|
|
volume_slot=$(echo $volume_slot | sed -e 's/"//g')
|
|
|
|
if [ $verbose -ge 3 ]; then
|
|
printf "${MAGENTA}Slot for volume_name ${GREEN}'%s'${MAGENTA} from media-pool ${GREEN}'%s'${MAGENTA}: ${NO_COLOR}%s${NO_COLOR}\n" \
|
|
"$volume_name" "$mediapool_name" "$volume_slot"
|
|
fi
|
|
}
|
|
|
|
get_retensiondate () {
|
|
local mediapools_json=${mediapools:-$mediapools_json}
|
|
local mediapool_name=${1}
|
|
local volume_name=${2}
|
|
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${BLUE}get_retensiondate...${NO_COLOR}\n"
|
|
fi
|
|
|
|
if test ! -r ${mediapools_json}; then
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${RED}Error:${MAGENTA} media-pool file ${GREEN}'%s'${MAGENTA} can't be opend!${NO_COLOR}}\n" \
|
|
"$mediapools_json"
|
|
fi
|
|
exit 1
|
|
fi
|
|
|
|
cmd="jq --monochrome-output --ascii-output ' .MediaPool[] \
|
|
| select(.Name == \"${mediapool_name}\") \
|
|
| .Member[] \
|
|
| select(.VolumeName == \"${volume_name}\") \
|
|
| .RetensionDate ' \
|
|
${mediapools_json}"
|
|
volume_retensiondate=$(eval $cmd)
|
|
|
|
if [ $verbose -ge 3 ]; then
|
|
printf "${MAGENTA}RetensionDate for volume_name ${GREEN}'%s'${MAGENTA} in media-pool ${GREEN}'%s'${MAGENTA}: ${NO_COLOR}%s${NO_COLOR}\n" \
|
|
"$volume_name" "$mediapool_name" "$volume_retensiondate"
|
|
fi
|
|
}
|
|
|
|
ltfs_format () {
|
|
local ltfs_devname=${ltfs_devname}
|
|
local volume_name=${1}
|
|
local tape_id=${2}
|
|
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${BLUE}ltfs_format...${NO_COLOR}\n"
|
|
fi
|
|
|
|
make_err_file
|
|
${MKLTFS} --device=$ltfs_devname --volume-name=${volume_name} --tape-serial=${tape_id} 2>${ERRFILE}
|
|
RET=$?
|
|
}
|
|
|
|
ltfs_is_mounted () {
|
|
local ltfs_devname
|
|
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${BLUE}ltfs_is_mounted...${NO_COLOR}\n"
|
|
fi
|
|
|
|
ltfs_devname=$(findmnt -n -T $ltfs_mountpoint -o source | awk -F ':' '{print $2}')
|
|
if [ ${#ltfs_devname} -gt 1 ]; then
|
|
if [ $verbose -ge 2 ]; then
|
|
printf "${MAGENTA}LTFS tape mounted via ${GREEN}'%s'${MAGENTA} at ${GREEN}'%s'${NO_COLOR}\n" \
|
|
"$ltfs_devname" "$ltfs_mountpoint"
|
|
fi
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
ltfs_mount () {
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${BLUE}ltfs_mount...${NO_COLOR}\n"
|
|
fi
|
|
|
|
ltfs_is_mounted
|
|
if [ $? -eq 1 ]; then
|
|
if [ ! -d $ltfs_mountpoint ]; then
|
|
mkdir -p $ltfs_mountpoint
|
|
fi
|
|
if [ $verbose -ge 2 ]; then
|
|
printf "${MAGENTA}LTFS mounting tape ${GREEN}'%s'${MAGENTA} to ${GREEN}'%s'${NO_COLOR}\n" \
|
|
"$ltfs_devname" "$ltfs_mountpoint"
|
|
${LTFS} -o devname=$ltfs_devname -o verbose=$verbose $ltfs_mountpoint
|
|
else
|
|
${LTFS} -o devname=$ltfs_devname -o verbose=0 $ltfs_mountpoint
|
|
fi
|
|
if [ $? -eq 0 ]; then
|
|
return 0
|
|
else
|
|
return $?
|
|
fi
|
|
fi
|
|
}
|
|
|
|
ltfs_umount () {
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${BLUE}ltfs_unmount...${NO_COLOR}\n"
|
|
|
|
fi
|
|
|
|
ltfs_is_mounted
|
|
if [ $? -eq 0 ]; then
|
|
ret=$(umount $ltfs_mountpoint 2>/dev/null)
|
|
if [ $? -eq 0 ]; then
|
|
if [ $verbose -ge 2 ]; then
|
|
printf "${MAGENTA}LTFS tape ${GREEN}'%s'${MAGENTA} unmounted.${NO_COLOR}\n" \
|
|
"$ltfs_devname"
|
|
fi
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
ltfs_wipe () {
|
|
local ltfs_devname=${ltfs_devname}
|
|
local volume_name=${1}
|
|
local tape_id=${2}
|
|
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${BLUE}ltfs_wipe...${NO_COLOR}\n"
|
|
fi
|
|
|
|
rm -rf $ltfs_mountpoint/*
|
|
}
|
|
|
|
make_err_file() {
|
|
ERRFILE=`mktemp $XDG_RUNTIME_DIR/mtx.err.XXXXXXXXXX`
|
|
if test x${ERRFILE} = x; then
|
|
ERRFILE="$XDG_RUNTIME_DIR/mtx.err.$$"
|
|
if test -f ${ERRFILE}; then
|
|
echo "ERROR: Temp file security problem on: ${ERRFILE}"
|
|
exit 1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
make_temp_file() {
|
|
TMPFILE=`mktemp $XDG_RUNTIME_DIR/mtx.XXXXXXXXXX`
|
|
if test x${TMPFILE} = x; then
|
|
TMPFILE="$XDG_RUNTIME_DIR/mtx.$$"
|
|
if test -f ${TMPFILE}; then
|
|
echo "ERROR: Temp file security problem on: ${TMPFILE}"
|
|
exit 1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
mtx_exchange () {
|
|
local changer_device=${changer_device:-$default_changer_device}
|
|
#export changer_device
|
|
local slot_source=${1}
|
|
local slot_target=${2}
|
|
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${BLUE}mtx_exchange...${NO_COLOR}\n"
|
|
fi
|
|
|
|
make_err_file
|
|
${MTX} -f $changer_device exchange $slot_source $slot_target 2>${ERRFILE}
|
|
RET=$?
|
|
}
|
|
|
|
mtx_getlabel () {
|
|
local changer_device=${changer_device:-$default_changer_device}
|
|
local slot_source=${slot_source:-99}
|
|
export slot_source
|
|
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${BLUE}Tape get-label...${NO_COLOR}\n"
|
|
fi
|
|
|
|
make_temp_file
|
|
${MTX} -f $changer_device status >${TMPFILE}
|
|
RET=$?
|
|
|
|
case ${slot_source} in
|
|
0)
|
|
if [ $verbose -ge 2 ]; then
|
|
printf "Calling: ${GREEN}%s${MAGENTA} -f ${GREEN}%s${MAGENTA} %s${NO_COLOR}\n" \
|
|
"${MTX}" "${changer_device}" "${slot_source}"
|
|
fi
|
|
volume_name=$(perl -ne '
|
|
/Data Transfer Element (\d+):Full \(Storage Element (\d+) Loaded\)(:VolumeTag =\s*(.+))?/ && print "$4\n";' ${TMPFILE})
|
|
#/Data Transfer Element (\d+):Full \(Storage Element (\d+) Loaded\)(:VolumeTag =\s*(.+))?/ && print "Drive:$1:Slot:$2:$4\n";' ${TMPFILE}
|
|
;;
|
|
[0-9][0-8] | [0-9])
|
|
if [ $verbose -ge 2 ]; then
|
|
printf "Calling: ${GREEN}%s${MAGENTA} -f ${GREEN}%s${MAGENTA} %s${NO_COLOR}\n" \
|
|
"${MTX}" "${changer_device}" "${slot_source}"
|
|
fi
|
|
perl -ne '
|
|
/Storage Element ($ENV{"slot_source"}):Full( :VolumeTag=(.+))?/ && print "$3\n";' ${TMPFILE}
|
|
;;
|
|
*)
|
|
if [ $verbose -ge 2 ]; then
|
|
printf "Calling: ${GREEN}%s${MAGENTA} -f ${GREEN}%s${MAGENTA} -- to list all slots${NO_COLOR}\n" \
|
|
"${MTX}" "${changer_device}"
|
|
fi
|
|
# can be converted to awk+sed+cut, see below
|
|
perl -ne '
|
|
/Data Transfer Element (\d+):Empty/ && print "Drive:$1:empty\n";
|
|
/Data Transfer Element (\d+):Full \(Storage Element (\d+) Loaded\)(:VolumeTag =\s*(.+))?/ && print "Drive:$1:Slot:$2:$4\n";
|
|
/Storage Element (\d+):Empty/ && print "Slot:$1:empty\n";
|
|
/Storage Element (\d+):Full( :VolumeTag=(.+))?/ && print "Slot:$1:$3\n";
|
|
/Storage Element (\d+) IMPORT.EXPORT:Empty/ && print "Import:$1:empty\n";
|
|
/Storage Element (\d+) IMPORT.EXPORT:Full( :VolumeTag=(.+))?/ && print "Import:$1:$3\n";' ${TMPFILE}
|
|
;;
|
|
esac
|
|
# If perl isn't installed, you can use by those commands
|
|
#cat ${TMPFILE} | grep "Data Transfer Element" | awk "{print \"D:\"\$4 \$7 \$9 \$10}" | sed "s/=/:/" | sed "s/Full/F:/" | sed "s/Empty/E/"
|
|
#cat ${TMPFILE} | grep -v "Data Transfer Element" | grep "Storage Element" | grep -v "IMPORT/EXPORT" | awk "{print \"S:\"\$3 \$4 \$5}" | sed "s/IMPORT\/EXPORT//" | sed "s/Full *:VolumeTag=/F:/" | sed "s/Empty/E/"
|
|
#cat ${TMPFILE} | grep -v "Data Transfer Element" | grep "Storage Element" | grep "IMPORT/EXPORT" | awk "{print \"I:\"\$3 \$4 \$5}" | sed "s/IMPORT\/EXPORT//" | sed "s/Full *:VolumeTag=/F:/" | sed "s/Empty/E/"
|
|
|
|
rm -f ${TMPFILE} >/dev/null 2>&1
|
|
return $RET
|
|
}
|
|
|
|
mtx_inventory () {
|
|
local changer_device=${changer_device:-$default_changer_device}
|
|
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${BLUE}mtx_inventory...${NO_COLOR}\n"
|
|
fi
|
|
|
|
${MTX} -f $changer_device inventory
|
|
RET=$?
|
|
}
|
|
|
|
mtx_load () {
|
|
local changer_device=${changer_device:-$default_changer_device}
|
|
local slot_source=${1}
|
|
local drive=${2}
|
|
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${BLUE}mtx_load...${NO_COLOR}\n"
|
|
fi
|
|
|
|
make_err_file
|
|
${MTX} -f $changer_device load $slot_source $drive 2>${ERRFILE}
|
|
RET=$?
|
|
}
|
|
|
|
mtx_status () {
|
|
local changer_device=${changer_device:-$default_changer_device}
|
|
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${BLUE}Tape status...${NO_COLOR}\n"
|
|
fi
|
|
|
|
${MTX} -f $changer_device status
|
|
}
|
|
|
|
mtx_transfer () {
|
|
local changer_device=${changer_device:-$default_changer_device}
|
|
#export changer_device
|
|
local slot_source=${1##slot_source=}
|
|
local slot_target=${2##slot_target=}
|
|
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${BLUE}Tape transfer...${NO_COLOR}\n"
|
|
fi
|
|
|
|
make_err_file
|
|
${MTX} -f $changer_device transfer $slot_source $slot_target 2>${ERRFILE}
|
|
RET=$?
|
|
}
|
|
|
|
mtx_unload () {
|
|
local changer_device=${changer_device:-$default_changer_device}
|
|
local slot_source=${1}
|
|
local drive=${2}
|
|
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${BLUE}Tape unload...${NO_COLOR}\n"
|
|
fi
|
|
|
|
make_err_file
|
|
for i in 1 2 3 4 5 ; do
|
|
${MTX} -f $changer_device unload $slot_source $drive 2>${ERRFILE}
|
|
RET=$?
|
|
if test $RET -eq 0; then
|
|
break
|
|
fi
|
|
grep "Error Code=" ${ERRFILE} 2>/dev/null 1>/dev/null
|
|
if test $? -ne 0 ; then
|
|
break
|
|
fi
|
|
sleep $i
|
|
done
|
|
cat ${ERRFILE}
|
|
rm -f ${ERRFILE} >/dev/null 2>&1
|
|
if test $RET -ne 0 ; then
|
|
if [ $verbose -ge 2 ]; then
|
|
printf "${RED}Fail: %s -f %s unload slot=%s drive=%s${NOCOLOR}\n" \
|
|
"${MTX}" "${changer_device}" "${slot_source}" "${drive}"
|
|
fi
|
|
fi
|
|
exit $RET
|
|
|
|
|
|
}
|
|
|
|
parse_params () {
|
|
#printf "\n${BLUE}Parse arguments...${NO_COLOR}\n"
|
|
|
|
# Evaluate given call parameters
|
|
while [ $# -gt 0 ]; do
|
|
key="$1"
|
|
case $key in
|
|
-h | --help | \-\? | --usage)
|
|
# Call usage() function.
|
|
usage
|
|
;;
|
|
--dry-run|--dryrun)
|
|
dryrun=1
|
|
shift 1
|
|
;;
|
|
--get-retensiondate)
|
|
shift 1
|
|
pool_params=${*}
|
|
pool_params="${pool_params%% -*}"
|
|
params=$*
|
|
set -- $pool_params
|
|
count=$#
|
|
test $count -ge 1 && mediapool_name="$1"
|
|
test $count -ge 2 && volume_name="$2"
|
|
set -- $params
|
|
shift $count
|
|
cmd=get-retensiondate
|
|
;;
|
|
--get-poolmember)
|
|
shift 1
|
|
pool_params=${*}
|
|
pool_params="${pool_params%% -*}"
|
|
params=$*
|
|
set -- $pool_params
|
|
count=$#
|
|
test $count -ge 1 && mediapool_name="$1"
|
|
test $count -ge 2 && volume_name="$2"
|
|
set -- $params
|
|
shift $count
|
|
cmd=get-poolmember
|
|
;;
|
|
--get-poolmember-next)
|
|
shift 1
|
|
pool_params=${*}
|
|
pool_params="${pool_params%% -*}"
|
|
params=$*
|
|
set -- $pool_params
|
|
count=$#
|
|
test $count -ge 1 && mediapool_name="$1"
|
|
test $count -ge 2 && volume_name="$2"
|
|
set -- $params
|
|
shift $count
|
|
cmd=get-poolmember-next
|
|
;;
|
|
--get-slot)
|
|
shift 1
|
|
pool_params=${*}
|
|
pool_params="${pool_params%% -*}"
|
|
params=$*
|
|
set -- $pool_params
|
|
count=$#
|
|
test $count -ge 1 && mediapool_name="$1"
|
|
test $count -ge 2 && volume_name="$2"
|
|
set -- $params
|
|
shift $count
|
|
cmd=get-slot
|
|
;;
|
|
--mount-tape)
|
|
shift 1
|
|
tape_params=${*}
|
|
tape_params="${tape_params%% -*}"
|
|
params=$*
|
|
set -- $tape_params
|
|
count=$#
|
|
test $count -lt 2 && usage
|
|
test $count -ge 1 && mediapool_name="$1"
|
|
test $count -ge 2 && volume_name="$2"
|
|
set -- $params
|
|
shift $count
|
|
cmd=mount-tape
|
|
;;
|
|
-p|--port)
|
|
port=$2
|
|
shift 2
|
|
;;
|
|
--remote)
|
|
remote=$2
|
|
shift 2
|
|
;;
|
|
--use-mtx)
|
|
use_mtx=1
|
|
shift 1
|
|
;;
|
|
--ltfs-devname)
|
|
ltfs_devname="$2"
|
|
shift 2
|
|
;;
|
|
--ltfs-format)
|
|
shift 1
|
|
ltfs_params=${*}
|
|
ltfs_params="${ltfs_params%% -*}"
|
|
params=$*
|
|
set -- $ltfs_params
|
|
count=$#
|
|
test $count -ge 1 && volume_name="$1"
|
|
test $count -ge 2 && tape_id="$2"
|
|
set -- $params
|
|
shift $count
|
|
cmd=ltfs-format
|
|
;;
|
|
--ltfs-is-mounted)
|
|
shift 1
|
|
cmd=ltfs-is-mounted
|
|
;;
|
|
--ltfs-mount)
|
|
shift 1
|
|
cmd=ltfs-mount
|
|
;;
|
|
--ltfs-mountpoint)
|
|
ltfs_mountpoint="$2"
|
|
shift 2
|
|
;;
|
|
--ltfs-umount)
|
|
shift 1
|
|
cmd=ltfs-umount
|
|
;;
|
|
--mtx-exchange)
|
|
shift
|
|
slots=${*}
|
|
slots="${slots%% -*}"
|
|
params=$*
|
|
set -- $slots
|
|
count=$#
|
|
test $count -lt 2 && usage
|
|
slot_source="$1"
|
|
slot_target="$2"
|
|
set -- $params
|
|
shift $count
|
|
cmd=mtx-exchange
|
|
;;
|
|
--mtx-getlabel)
|
|
shift
|
|
slots=${*}
|
|
slots="${slots%% -*}"
|
|
params=$*
|
|
set -- $slots
|
|
count=$#
|
|
test $count -eq 1 && slot_source="$1"
|
|
set -- $params
|
|
shift $count
|
|
slot_getlabel=1
|
|
cmd=mtx-getlabel
|
|
;;
|
|
--mtx-inventory|mtx-inquiry)
|
|
shift
|
|
cmd=mtx-inventory
|
|
;;
|
|
--mtx-load)
|
|
shift
|
|
slots=${*}
|
|
slots="${slots%% -*}"
|
|
params=$*
|
|
set -- $slots
|
|
count=$#
|
|
test $count -lt 1 && usage
|
|
slot_source="$1"
|
|
test $count -eq 2 && drive="$2"
|
|
set -- $params
|
|
shift $count
|
|
cmd=mtx-load
|
|
;;
|
|
--mtx-transfer)
|
|
shift
|
|
slots=${*}
|
|
slots="${slots%% -*}"
|
|
params=$*
|
|
set -- $slots
|
|
count=$#
|
|
test $count -lt 2 && usage
|
|
slot_source="${1}"
|
|
slot_target="${2}"
|
|
set -- $params
|
|
shift $count
|
|
cmd=mtx-transfer
|
|
;;
|
|
--mtx-unload)
|
|
shift
|
|
slots=${*}
|
|
slots="${slots%% -*}"
|
|
params=$*
|
|
set -- $slots
|
|
count=$#
|
|
test $count -lt 1 && usage
|
|
slot_source="$1"
|
|
test $count -eq 2 && drive="$2"
|
|
set -- $params
|
|
shift $count
|
|
cmd=mtx-unload
|
|
;;
|
|
-v|--verbose)
|
|
verbose=$(($verbose + 1))
|
|
shift 1
|
|
;;
|
|
--version)
|
|
printf "%s v%s\n" "$progname" "$version"
|
|
exit 0
|
|
;;
|
|
--ltfs-devname=*)
|
|
ltfs_devname="${1#*=}"
|
|
shift
|
|
;;
|
|
--ltfs-mountpoint=*)
|
|
ltfs_mountpoint="${1#*=}"
|
|
shift
|
|
;;
|
|
--color=*)
|
|
case ${1#*=} in
|
|
yes | Yes | True | true)
|
|
color=1;
|
|
;;
|
|
*)
|
|
;;
|
|
esac
|
|
shift
|
|
;;
|
|
--remote=*)
|
|
remote=${1#*=}
|
|
shift
|
|
;;
|
|
--v=* | --verbose=*)
|
|
verbose=${1#*=}
|
|
shift
|
|
;;
|
|
--) # End of all options
|
|
shift
|
|
break
|
|
;;
|
|
-*)
|
|
printf "WARN: Unknown option (ignored): $1" >&2
|
|
die "Unknown option"
|
|
;;
|
|
*)
|
|
printf "Unknown option: %s\nRun '%s -h' for valid options.\n" $key $progname
|
|
die "Unknown option"
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [ -z "$remote" ]; then
|
|
ssh=""
|
|
else
|
|
ssh="ssh -T $remote"
|
|
if [ ! -z "$port" ]; then
|
|
ssh="$ssh -p $port"
|
|
fi
|
|
fi
|
|
|
|
if [ "$color" ]; then
|
|
# ascii color
|
|
BLUE='\033[0;34m'
|
|
GREEN='\033[0;32m'
|
|
MAGENTA='\033[0;35m'
|
|
RED='\033[0;31m'
|
|
YELLOW='\033[0;33m'
|
|
NO_COLOR='\033[0m'
|
|
fi
|
|
|
|
if [ $verbose -ge 2 ]; then
|
|
printf "${BLUE}$progname (runtime arguments)...${NO_COLOR}\n"
|
|
printf "LTFS Settings\n"
|
|
printf " ltfs device-name: '%s'\n" "$ltfs_devname"
|
|
printf " ltfs mount-point: '%s'\n" "$ltfs_mountpoint"
|
|
printf "MTX Settings\n"
|
|
printf " def changer-name: '%s'\n" "$default_changer_device"
|
|
|
|
if [ $verbose -ge 1 ]; then tape_options="verbose_level=$verbose"; fi
|
|
if [ $dryrun -eq 1 ]; then tape_options="${tape_options} dry-run=true"; fi
|
|
if [ $color -eq 1 ]; then tape_options="${tape_options} color=true"; fi
|
|
if [ $use_mtx -eq 1 ]; then tape_options="${tape_options} use-mtx=true"; fi
|
|
printf "Options: '%s'\n\n" "${tape_options}"
|
|
fi
|
|
}
|
|
|
|
mount_tape () {
|
|
local mediapool_name=${1}
|
|
local volume_name=${2}
|
|
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${BLUE}mount_tape...${NO_COLOR}\n"
|
|
fi
|
|
|
|
ltfs_is_mounted
|
|
if test $? -eq 0; then
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${MAGENTA}LTFS Tape is-mounted: ${GREEN}%d${NO_COLOR}\n" \
|
|
"$?"
|
|
fi
|
|
# get label from tape in given drive slot
|
|
mtx_getlabel 0
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${MAGENTA}Tape Label: ${GREEN}%s${NO_COLOR}\n" \
|
|
"${volume_name}"
|
|
fi
|
|
# check if given tape is poolmember of selected pool
|
|
get_poolmember ${mediapool_name} ${volume_name}
|
|
if [ $? -eq 0 ]; then
|
|
# volume_name match
|
|
get_mediapolicy ${mediapool_name} ${volume_name}
|
|
if [ ${#volume_mediapolicy} -gt 0 ]; then
|
|
if [ ${volume_mediapolicy} = "append" ] || [ ${volume_mediapolicy} = "overwrite" ] ; then
|
|
return 0
|
|
fi
|
|
if [ ${volume_mediapolicy} = "overwrite" ] ; then
|
|
volume_retensiondate="20180101000000"
|
|
get_retensiondate ${mediapool_name} ${volume_name}
|
|
date_now=$($date_cmd)
|
|
compare_date $date_now $volume_retensiondate
|
|
if [ $? -eq 2 ]; then
|
|
# retensiondate has exposed: wipe given tape
|
|
ltfs_wipe
|
|
return 0
|
|
fi
|
|
if [ $? -eq 1 ]; then
|
|
# respect active retensiondate: unload given tape
|
|
ltfs_unmount
|
|
mtx_unload
|
|
# use next volume_name from pool
|
|
get_poolmember_next ${mediapool_name} ${volume_name}
|
|
get_slot ${mediapool_name} ${volume_name_next}
|
|
mtx_load ${volume_slot}
|
|
ltfs_mount
|
|
return 0
|
|
fi
|
|
fi
|
|
fi
|
|
else
|
|
# volume_name does not match
|
|
ltfs_umount
|
|
mtx_unload 0
|
|
# TODO
|
|
get_poolmember
|
|
get_poolmember_next ${mediapool_name} ${volume_name}
|
|
#mtx load ${volume_name_next}
|
|
fi
|
|
else
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${MAGENTA}No LTFS Tape mounted...${NO_COLOR}\n"
|
|
fi
|
|
get_slot ${mediapool_name} ${volume_name}
|
|
mtx_load ${volume_slot}
|
|
ltfs_mount
|
|
return 0
|
|
fi
|
|
}
|
|
|
|
traperror () {
|
|
printf "Exited due to error on line %s.\n" $1
|
|
printf "exit status: %s\n" "$2"
|
|
#printf "command: %s\n" "$3"
|
|
#printf "bash line: %s\n" "$4"
|
|
#printf "function name: %s\n" "$5"
|
|
exit 1
|
|
}
|
|
|
|
trapkill () {
|
|
printf "Exited due to user intervention.\n"
|
|
#run_cleanup
|
|
exit 0
|
|
}
|
|
|
|
usage () {
|
|
cat <<EOF
|
|
$progname $version
|
|
Usage: $progname [options]
|
|
|
|
Options:
|
|
--use-mtx use mtx loader handling
|
|
--color Enable colored output messages
|
|
-r, --remote <address> Send the snapshot backup to a remote machine. The snapshot will be sent via ssh.
|
|
You should specify the remote machine's hostname or ip address. The 'root' user
|
|
must be permitted to login on the remote machine.
|
|
-p, --port <port> The remote port.
|
|
--dry-run perform a trial run where no changes are made.
|
|
-v, --verbose Be verbose on what's going on (min: --verbose=1, max: --verbose=3)
|
|
--version show program version
|
|
EOF
|
|
|
|
exit 0
|
|
}
|
|
|
|
###
|
|
# Main
|
|
###
|
|
|
|
cwd=`pwd`
|
|
|
|
# can't be ported to dash (ERR is not supported)
|
|
trap trapkill TERM INT
|
|
|
|
check_prerequisites
|
|
|
|
# validate commandline options, set resonable defaults
|
|
parse_params $@
|
|
|
|
case $cmd in
|
|
get-mediapolicy)
|
|
get_mediapolicy "${mediapool_name}" "${volume_name}"
|
|
if test $? -eq 0; then
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${MAGENTA}MediaPolicy for ${GREEN}'%s'${MAGENTA} is:${NO_COLOR} %s.\n" \
|
|
"${volume_name}" "${volume_mediapolicy}"
|
|
fi
|
|
fi
|
|
;;
|
|
get-poolmember)
|
|
valid_member=0
|
|
get_poolmember "${mediapool_name}" "${volume_name}"
|
|
if test $? -eq 0; then
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${MAGENTA}Volume-Name ${GREEN}'%s'${MAGENTA} is a valid mediapool member.${NO_COLOR}\n" \
|
|
"${volume_name}"
|
|
fi
|
|
valid_member=1
|
|
fi
|
|
;;
|
|
get-poolmember-next)
|
|
valid_member=0
|
|
get_poolmember_next "${mediapool_name}" "${volume_name}"
|
|
if test $? -eq 0; then
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${MAGENTA}Next Volume-Name from media-pool ${GREEN}'%s'${MAGENTA} is: ${NO_COLOR}'%s'\n" \
|
|
"${mediapool_name}" "${volume_name_next}"
|
|
fi
|
|
fi
|
|
;;
|
|
get-retensiondate)
|
|
get_retensiondate "${mediapool_name}" "${volume_name}"
|
|
if test $? -eq 0; then
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${MAGENTA}RetensionDate for ${GREEN}'%s'${MAGENTA} is:${NO_COLOR} %s.\n" \
|
|
"${volume_name}" "${volume_retensiondate}"
|
|
fi
|
|
fi
|
|
;;
|
|
get-slot)
|
|
get_slot "${mediapool_name}" "${volume_name}"
|
|
if test $? -eq 0; then
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${MAGENTA}Slot location for ${GREEN}'%s'${MAGENTA} is:${NO_COLOR} %s.\n" \
|
|
"${volume_name}" "${volume_slot}"
|
|
fi
|
|
fi
|
|
;;
|
|
ltfs-format)
|
|
ltfs_format "${volume_name}" "${tape_id}"
|
|
;;
|
|
ltfs-is-mounted)
|
|
ltfs_is_mounted
|
|
if test $? -eq 0; then
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${MAGENTA}LTFS Tape is-mounted: ${GREEN}%d${NO_COLOR}\n" \
|
|
"$?"
|
|
fi
|
|
fi
|
|
;;
|
|
ltfs-mount)
|
|
ltfs_mount
|
|
if test $? -eq 0; then
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${MAGENTA}LTFS Tape mount: ${GREEN}%d${NO_COLOR}\n" \
|
|
"$?"
|
|
fi
|
|
fi
|
|
;;
|
|
ltfs-umount)
|
|
ltfs_umount
|
|
if test $? -eq 0; then
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${MAGENTA}LTFS Tape unmount: ${GREEN}%d${NO_COLOR}\n" \
|
|
"$?"
|
|
fi
|
|
fi
|
|
;;
|
|
mtx-exchange)
|
|
mtx_exchange "${slot_source}" "${slot_target}"
|
|
;;
|
|
mtx-getlabel)
|
|
mtx_getlabel $slot_source
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${MAGENTA}Tape Label: ${GREEN}%s${NO_COLOR}\n" \
|
|
"${volume_name}"
|
|
fi
|
|
;;
|
|
mtx-inventory)
|
|
mtx_inventory
|
|
;;
|
|
mtx-load)
|
|
mtx_load "${slot_source}" "${drive}"
|
|
;;
|
|
mtx-transfer)
|
|
mtx_transfer "${slot_source}" "${slot_target}"
|
|
;;
|
|
mtx-unload)
|
|
mtx_unload "${slot_source}" "${drive}"
|
|
;;
|
|
mount-tape)
|
|
mount_tape "${mediapool_name}" "${volume_name}"
|
|
if test $? -eq 0; then
|
|
if [ $verbose -ge 1 ]; then
|
|
printf "${MAGENTA}mount tape ${GREEN}'%s'${MAGENTA} for ${GREEN}'%s'${MAGENTA}:${NO_COLOR} %s.\n" \
|
|
"${volume_name}" "${mediapool_name}" "$?"
|
|
fi
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
# return: 0 = equal, 1 = lower, 2 = greater
|
|
#compare_date "20180824090000" "20180824090000"
|
|
|
|
exit 0
|