From f105a525ae9c912b0b164e997d4d4dc9c9f8a823 Mon Sep 17 00:00:00 2001 From: Ralf Zerres Date: Fri, 21 Sep 2018 20:50:26 +0200 Subject: [PATCH] tape-admin: binary inclusion Signed-off-by: Ralf Zerres --- bin/tape-admin | 1737 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1737 insertions(+) create mode 100755 bin/tape-admin diff --git a/bin/tape-admin b/bin/tape-admin new file mode 100755 index 0000000..6058cc4 --- /dev/null +++ b/bin/tape-admin @@ -0,0 +1,1737 @@ +#! /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.5" + +# global variables +color=0 +date_cmd="date -u +%Y%m%d%H%M%S" # use universial time +date_iso="" +date_seconds="" +default_changer_device="/dev/changer" +dryrun=0 +ltfs_mountpoint="/media/tape" +ltfs_devname="/dev/sg9" +mediapools_json="/etc/dsnap-sync/MediaPools.json" +mediapool_name="" +timezone="Europe/Berlin" +use_mtx=0 +verbose=0 +volume_name="" +volume_name_active="" +volume_name_next="" + +# helper programms +ATTR=attr +JQ=jq +LTFS=ltfs +LTFSCK=ltfsck +MKLTFS=mkltfs +MTX=mtx +SSH=ssh + +# ascii color +BLUE= +GREEN= +MAGENTA= +RED= +YELLOW= +NO_COLOR= + +### +# functions +### + +check_prerequisites () { + # requested binaries: + which ${ATTR} >/dev/null 2>&1 || { printf "'%s' is not installed.\n" ${ATTR} && exit 1; } + 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 findmnt >/dev/null 2>&1 || { printf "'findmnt' is not installed." && 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; } + which perl >/dev/null 2>&1 || { printf "'%s' is not installed.\n" perl && exit 1; } + which awk >/dev/null 2>&1 || { printf "'%s' is not installed.\n" awk && exit 1; } + which sed >/dev/null 2>&1 || { printf "'%s' is not installed.\n" sed && 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 +} + +date_iso_to_seconds () { + local date_string=$1 + + year=$(echo $date_string | cut -c 1-4) + month=$(echo $date_string | cut -c 5-6) + day=$(echo $date_string | cut -c 7-8) + hour=$(echo $date_string | cut -c 9-10) + minute=$(echo $date_string | cut -c 11-12) + second=$(echo $date_string | cut -c 13-14) + + test ${month#0} -gt 12 && printf "${RED}Error:${NO_COLOR} Invalid argument month: '%s'\n" $month && return 1 + test ${day#0} -gt 31 && printf "${RED}Error:${NO_COLOR} Invalid argument day: '%s'\n" $day && return 1 + test ${hour#0} -gt 23 && printf "${RED}Error:${NO_COLOR} Invalid argument hour: '%s'\n" $hour && return 1 + test ${minute#0} -gt 59 && printf "${RED}Error:${NO_COLOR} Invalid argument minute: '%s'\n" $minute && return 1 + test ${second#0} -gt 50 && printf "${RED}Error:${NO_COLOR} Invalid argument second: '%s'\n" $second && return 1 + + date_iso=$(printf "%s-%s-%s %s:%s:%s\n" \ + ${year} ${month} ${day} ${hour} ${minute} ${second}) + date_seconds=$(date --date="$date_iso" +"%s") +} + +date_seconds_to_iso () { + local date_string=$1 + + date_iso=$(date --date="$date_string" +"%Y-%M-%d %H:%M:%S") +} + +date_string_to_iso () { + local date_string=$1 + + year=$(echo $date_string | cut -c 1-4) + month=$(echo $date_string | cut -c 5-6) + day=$(echo $date_string | cut -c 7-8) + hour=$(echo $date_string | cut -c 9-10) + minute=$(echo $date_string | cut -c 11-12) + second=$(echo $date_string | cut -c 13-14) + + test ${month#0} -gt 12 && printf "${RED}Error:${NO_COLOR} Invalid argument month: '%s'\n" $month && return 1 + test ${day#0} -gt 31 && printf "${RED}Error:${NO_COLOR} Invalid argument day: '%s'\n" $day && return 1 + test ${hour#0} -gt 23 && printf "${RED}Error:${NO_COLOR} Invalid argument hour: '%s'\n" $hour && return 1 + test ${minute#0} -gt 59 && printf "${RED}Error:${NO_COLOR} Invalid argument minute: '%s'\n" $minute && return 1 + test ${second#0} -gt 59 && printf "${RED}Error:${NO_COLOR} Invalid argument second: '%s'\n" $second && return 1 + + date_iso=$(printf "%s-%s-%s %s:%s:%s\n" \ + ${year} ${month} ${day} ${hour} ${minute} ${second}) +} + +die () { + error "$@" + exit 1 +} + +error () { + printf "\n==> ERROR: %s\n" "$@" + notify_error 'Error' 'Check journal for more information.' +} >&2 + +get_lastwrite () { + local mediapools_json=${mediapools:-$mediapools_json} + local mediapool_name=${1} + #local volume_name=${2} + + if [ $verbose -ge 1 ]; then + printf "${BLUE}get_lastwrite...${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 + + if [ ${#volume_name} -ge 1 ]; then + # select last write date for given volume + cmd="jq --monochrome-output --ascii-output ' .MediaPool[] \ + | select(.Name == \"${mediapool_name}\") \ + | .Member[] \ + | select(.VolumeName == \"${volume_name}\") \ + | .LastWrite ' \ + ${mediapools_json}" + else + # select volume with latest write date + cmd="jq --monochrome-output --ascii-output ' .MediaPool[] \ + | select(.Name == \"${mediapool_name}\") \ + | .Member \ + | map({ \"VolumeName\" : .VolumeName, \"LastWrite\" : ( .LastWrite | scan(\"[0-9]{14}\")) }) \ + | sort_by(.LastWrite) \ + | .[-1] \ + | .VolumeName ' \ + ${mediapools_json}" + volume_name=$(eval $cmd) + volume_name=$(echo $volume_name | sed -e 's/"//g') + cmd="jq --monochrome-output --ascii-output ' .MediaPool[] \ + | select(.Name == \"${mediapool_name}\") \ + | .Member \ + | map({ \"VolumeName\" : .VolumeName, \"LastWrite\" : ( .LastWrite | scan(\"[0-9]{14}\")) }) \ + | sort_by(.LastWrite) \ + | .[-1] \ + | .LastWrite ' \ + ${mediapools_json}" + fi + volume_lastwrite=$(eval $cmd) + if [ ${#volume_lastwrite} -gt 1 ]; then + volume_lastwrite=$(echo $volume_lastwrite | sed -e 's/"//g') + if [ $verbose -ge 3 ]; then + printf "${MAGENTA}volume_lastwrite for for volume ${GREEN}'%s'${MAGENTA} in media-pool ${GREEN}'%s'${MAGENTA} is: ${NO_COLOR}%s${NO_COLOR}\n" \ + "$volume_name" "$mediapool_name" "$volume_lastwrite" + fi + else + return 1 + fi +} + +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) + volume_mediapolicy=$(echo $volume_mediapolicy | sed -e 's/"//g') + + 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_mediapool_names () { + local mediapools_json=${mediapools:-$mediapools_json} + #local mediapool_name=${1} + + if [ $verbose -ge 1 ]; then + printf "${BLUE}get_mediapools...${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[] \ + | .Name ' \ + ${mediapools_json}" + mediapool_names=$(eval $cmd) + mediapool_names=$(echo $mediapool_names | sed -e 's/"//g') + + if [ $verbose -ge 3 ]; then + printf "${MAGENTA}Media-pool names: ${GREEN}'%s'${NO_COLOR}\n" \ + "$mediapool_names" + 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) + poolmember=$(echo $poolmember | sed -e 's/"//g') + + 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:-"none"} + + 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 \ + | map({ \"VolumeName\" : .VolumeName, \"LastWrite\" : ( .LastWrite | scan(\"[0-9]{14}\")) }) \ + | sort_by(.LastWrite) \ + | .[0] \ + | .VolumeName ' \ + ${mediapools_json}" + volume_poolmember=$(eval $cmd) + volume_poolmember=$(echo $volume_poolmember | sed -e 's/"//g') + + 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} -ge 1 ]; then + if [ $member = $volume_name ]; then + volume_index=$(($i+1)) + fi + 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 [ ${#volume_retensiondate} -gt 1 ]; then + volume_retensiondate=$(echo $volume_retensiondate | sed -e 's/"//g') + 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 + else + return 1 + fi +} + +ltfs_get_attribute () { + local ltfs_devname=${ltfs_devname} + local ltfs_attribute_name=${1:-volumeName} + + if [ $verbose -ge 1 ]; then + printf "${BLUE}ltfs_get_attribute...${NO_COLOR}\n" + fi + + make_err_file + # Reference: https://www.ibm.com/support/knowledgecenter/en/STQNYL_2.4.0/ltfs_hints_virtual_extended_attribute.html + # eg: ltfs.indexCreator + # ltfs.volumeBlocksize + # ltfs.volumeName, ltfs.volumeSerial, ltfs.volumeUUID + ltfs_attribute_value=$(${ATTR} -g ltfs.$ltfs_attribute_name $ltfs_mountpoint 2>${ERRFILE}) + rm -f ${ERRFILE} + if [ $? -eq 0 ]; then + ltfs_attribute_value=$(echo ${ltfs_attribute_value##*:} | sed -e 's/\r\n//g') + if [ $verbose -ge 2 ]; then + printf "${MAGENTA}LTFS attribute ${GREEN}'%s'${MAGENTA} is: ${GREEN}'%s'${NO_COLOR}\n" \ + "$ltfs_attribute_name" "$ltfs_attribute_value" + fi + return 0 + else + if [ $verbose -ge 2 ]; then + printf "${MAGENTA}LTFS attribute ${GREEN}'%s'${MAGENTA} isn't valid${NO_COLOR}\n" \ + "$ltfs_attribute_name" + fi + fi + return $? +} + +ltfs_format () { + local ltfs_devname=${ltfs_devname} + local volume_name=${1} + local volume_serial=${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=${volume_serial} 2>${ERRFILE} + RET=$? + rm -f ${ERRFILE} + return $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 + make_err_file + 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 2>${ERRFILE} + else + ${LTFS} -o devname=$ltfs_devname -o verbose=0 $ltfs_mountpoint 2>${ERRFILE} + fi + if [ $? -eq 0 ]; then + return 0 + else + # format tape if needed + if [ -z $volume_name_active ]; then + slot_source="0" + mtx_getlabel $slot_source + fi + need_format=$(grep "medium is not partitioned" ${ERRFILE}) + rm -f ${ERRFILE} + if [ ${#need_format} -ge 1 ]; then + tape_id=$(echo $volume_name_active | sed -e 's/\([[:alpha:]]*-\)//g') + # TODO: tape_id needs to be exactly 6 character long + volume_serial=$(printf "%0.s0" $(seq 1 $((6 - ${#tape_id})))) + volume_serial="${volume_serial}${tape_id}" + ltfs_format ${volume_name_active} ${volume_serial} + ltfs_mount + fi + return $? + fi + else + if [ $verbose -ge 2 ]; then + printf "${MAGENTA}LTFS tape ${GREEN}'%s'${MAGENTA} is mounted to ${GREEN}'%s'${NO_COLOR}\n" \ + "$ltfs_devname" "$ltfs_mountpoint" + fi + fi +} + +ltfs_umount () { + if [ $verbose -ge 1 ]; then + printf "${BLUE}ltfs_umount...${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=$? + rm -f ${ERRFILE} +} + +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_active=$(perl -ne ' + /Data Transfer Element (\d+):Full \(Storage Element (\d+) Loaded\)(:VolumeTag =\s*(.+))?/ && print "$4\n";' ${TMPFILE}) + volume_name_active=$(echo $volume_name_active | sed -e 's/ *$//g') + ;; + [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=$? + rm -f ${ERRFILE} +} + +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=$? + rm -f ${ERRFILE} +} + +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${NO_COLOR}\n" \ + "${MTX}" "${changer_device}" "${slot_source}" "${drive}" + fi + fi + return $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-lastwrite) + 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-lastwrite + ;; + --get-mediapools) + shift 1 + cmd=get-mediapools + ;; + --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-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-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) + shift 1 + tape_params=${*} + tape_params="${tape_params%% -*}" + params=$* + set -- $tape_params + count=$# + test $count -lt 1 && usage + mediapool_name="$1" + test $count -ge 2 && volume_name="$2" + set -- $params + shift $count + cmd=mount + ;; + -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-getattribute) + shift 1 + ltfs_params=${*} + ltfs_params="${ltfs_params%% -*}" + params=$* + set -- $ltfs_params + count=$# + test $count -eq 0 && ltfs_attribute_name="volumeName" + shift $count + cmd=ltfs-getattribute + ;; + --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 + ;; + --update-lastwrite) + shift 1 + pool_params=${*} + pool_params="${pool_params%% -*}" + params=$* + set -- $pool_params + count=$# + test $count -lt 2 && usage + mediapool_name="$1" + volume_name="$2" + test $count -ge 3 && date_string="$3" + set -- $params + shift $count + cmd=update-lastwrite + ;; + --update-retensiondate) + shift 1 + pool_params=${*} + pool_params="${pool_params%% -*}" + params=$* + set -- $pool_params + count=$# + test $count -lt 2 && usage + mediapool_name="$1" + volume_name="$2" + test $count -ge 3 && date_string="$3" + set -- $params + shift $count + cmd=update-retensiondate + ;; + -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.${NO_COLOR}\n" + fi + + # check that mounted tape is member of selected mediapool + mtx_getlabel 0 + if [ $? -eq 0 ]; then + get_poolmember ${mediapool_name} ${volume_name_active} + if [ $? -eq 1 ]; then + # unmount and recurse execution + ltfs_umount + if [ $? -eq 0 ]; then + mtx_unload + if [ $? -eq 0 ]; then + mount_tape "${mediapool_name}" "${volume_name}" + return 0 + else + return $? + fi + else + return $? + fi + fi + fi + # get date from last written tape in given mediapool + if [ "${#volume_name}" -eq 0 ]; then + get_lastwrite ${mediapool_name} + if [ $? != 0 ]; then + exit 1 + fi + fi + # get label from tape in given drive slot + slot_source="0" + mtx_getlabel $slot_source + if [ $verbose -ge 1 ]; then + printf "${MAGENTA}Tape Label: ${GREEN}%s${NO_COLOR}\n" \ + "${volume_name_active}" + fi + if [ "${#volume_name_active}" -ge 1 ] && [ "${volume_name_active}" != "${volume_name}" ]; then + ltfs_umount + if [ $? -eq 0 ]; then + mtx_unload + if [ $? -eq 0 ]; then + mount_tape "${mediapool_name}" "${volume_name}" + return 0 + else + return $? + fi + else + return $? + fi + fi + # check if given tape is poolmember of selected pool + get_poolmember ${mediapool_name} ${volume_name} + if [ $? -eq 0 ]; then + # volume_name is member of given mediapool + get_mediapolicy ${mediapool_name} ${volume_name} + if [ ${#volume_mediapolicy} -gt 0 ]; then + if [ ${volume_mediapolicy} = "append" ] ; then + if [ $verbose -ge 1 ]; then + printf "${MAGENTA}Valid tape mediapolicy: ${GREEN}%s${NO_COLOR}\n" \ + "${volume_mediapolicy}" + fi + volume_retensiondate="20180101000000" + get_retensiondate ${mediapool_name} ${volume_name} + if [ $? -eq 0 ]; then + date_now=$($date_cmd) + compare_date $date_now $volume_retensiondate + if [ $? -eq 2 ]; then + # retensiondate has exposed: use it + return 0 + fi + if [ $? -eq 1 ]; then + # respect active retensiondate: unload given tape + ltfs_umount + 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 + if [ $? -eq 0 ]; then + return 0 + fi + fi + 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 + if [ $? -eq 0 ]; then + return 0 + fi + fi + if [ $? -eq 1 ]; then + # respect active retensiondate: unload given tape + ltfs_umount + 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 + if [ $? -eq 0 ]; then + return 0 + fi + fi + fi + fi + fi + else + # volume_name is not member of given pool + ltfs_umount + if [ $? -eq 0 ]; then + mtx_unload + if [ $? -eq 0 ]; then + if [ "${#volume_name}" -eq 0 ]; then + get_lastwrite ${mediapool_name} + fi + get_poolmember_next ${mediapool_name} ${volume_name} + if [ $? -eq 0 ]; then + mtx load ${volume_name_next} + ltfs_mount + fi + else + return $? + fi + else + return $? + fi + fi + else + if [ $verbose -ge 1 ]; then + printf "${MAGENTA}No LTFS Tape mounted...${NO_COLOR}\n" + fi + if [ "${#volume_name}" -eq 0 ]; then + # set volume_name and last write date + get_lastwrite ${mediapool_name} + fi + # check label from tape in given drive slot + slot_source="0" + mtx_getlabel $slot_source + if [ $? -eq 0 ] && [ "${#volume_name_active}" -gt 1 ]; then + if [ $verbose -ge 1 ]; then + printf "${MAGENTA}Tape Label: ${GREEN}%s${NO_COLOR}\n" \ + "${volume_name_active}" + fi + if [ "${#volume_name_active}" -gt 1 ] && [ "${volume_name_active}" != "${volume_name}" ]; then + mtx_unload + if [ $? -eq 0 ]; then + mount_tape "${mediapool_name}" "${volume_name}" + return 0 + else + return $? + fi + fi + else + # mount new tape + get_slot ${mediapool_name} ${volume_name} + mtx_load ${volume_slot} + fi + + # volume_name is member of given mediapool + get_mediapolicy ${mediapool_name} ${volume_name} + if [ ${#volume_mediapolicy} -gt 0 ]; then + if [ ${volume_mediapolicy} = "append" ] ; then + if [ $verbose -ge 1 ]; then + printf "${MAGENTA}Valid tape mediapolicy: ${GREEN}%s${NO_COLOR}\n" \ + "${volume_mediapolicy}" + fi + 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: use it + ltfs_mount + return 0 + fi + 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_mount + if [ $? -eq 0 ]; then + ltfs_wipe + if [ $? -eq 0 ]; then + return 0 + fi + fi + fi + if [ $? -eq 1 ]; then + # respect active retensiondate: unload given tape + mtx_unload + if [ $? -eq 0 ]; then + # use next volume_name from pool + get_poolmember_next ${mediapool_name} ${volume_name} + mount_tape "${mediapool_name}" "${volume_name}" + return 0 + else + return $? + fi + fi + fi + fi + 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 +} + +update_lastwrite () { + local mediapools_json=${mediapools:-$mediapools_json} + local mediapool_name=${1:-0} + local volume_name=${2} + local date_string=${3:-now} + + if [ $verbose -ge 1 ]; then + printf "${BLUE}update_lastwrite...${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 + else + json_path=${mediapools_json%/*} + json_file=${mediapools_json##*/} + cp "$mediapools_json" $XDG_RUNTIME_DIR/$json_file + fi + + if [ ${#volume_name} -ge 1 ]; then + # update last write date for given volume (date field in utc) + if [ "${date_string}" = "now" ]; then + volume_lastwrite=$($date_cmd) + else + volume_lastwrite=$date_string + fi + + cmd="jq --monochrome-output --ascii-output '.MediaPool[] \ + | select(.Name == \"$mediapool_name\") \ + | .Member \ + | map(.VolumeName == \"$volume_name\") | index(true)' \ + ${mediapools_json}" + tape_index=$(eval $cmd) + if [ $? -eq 0 ]; then + cmd="jq --monochrome-output --ascii-output '(.MediaPool[] \ + | select(.Name == \"$mediapool_name\") \ + | .Member[$tape_index] \ + | .LastWrite) \ + |= \"$volume_lastwrite\" ' \ + ${mediapools_json} > $XDG_RUNTIME_DIR/$json_file" + $(eval $cmd) + if [ $? -eq 0 ]; then + cp "$XDG_RUNTIME_DIR/$json_file" "$mediapools_json" + else + return 1 + fi + else + return 1 + fi + + if [ $verbose -ge 3 ]; then + printf "${MAGENTA}LastWrite for for volume ${GREEN}'%s'${MAGENTA} is: ${NO_COLOR}%s${NO_COLOR}\n" \ + "$volume_name" "$volume_lastwrite" + fi + fi +} + +update_retensiondate () { + local mediapools_json=${mediapools:-$mediapools_json} + local mediapool_name=${1:-0} + local volume_name=${2} + local date_string=${3:-now} + + if [ $verbose -ge 1 ]; then + printf "${BLUE}update_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 + else + json_path=${mediapools_json%/*} + json_file=${mediapools_json##*/} + cp "$mediapools_json" $XDG_RUNTIME_DIR/$json_file + fi + + if [ ${#volume_name} -ge 1 ]; then + # update retension date for given volume (date field in utc) + if [ "${date_string}" = "now" ]; then + volume_retensiondate=$($date_cmd) + else + volume_retensiondate=$date_string + fi + + cmd="jq --monochrome-output --ascii-output '.MediaPool[] \ + | select(.Name == \"$mediapool_name\") \ + | .Member \ + | map(.VolumeName == \"$volume_name\") | index(true)' \ + ${mediapools_json}" + tape_index=$(eval $cmd) + if [ $? -eq 0 ]; then + cmd="jq --monochrome-output --ascii-output '(.MediaPool[] \ + | select(.Name == \"$mediapool_name\") \ + | .Member[$tape_index] \ + | .RetensionDate) \ + |= \"$volume_retensiondate\" ' \ + ${mediapools_json} > $XDG_RUNTIME_DIR/$json_file" + $(eval $cmd) + if [ $? -eq 0 ]; then + cp "$XDG_RUNTIME_DIR/$json_file" "$mediapools_json" + else + return 1 + fi + else + return 1 + fi + + if [ $verbose -ge 3 ]; then + printf "${MAGENTA}RetensionDate for for volume ${GREEN}'%s'${MAGENTA} is: ${NO_COLOR}%s${NO_COLOR}\n" \ + "$volume_name" "$volume_retensiondate" + fi + fi +} + + +usage () { + cat < [volume_name]) + without given volume_name, extract Pool member that was last witten to + --get-mediapools extract MediaPool names Pool configuration (JSON-File) + --get-mediapolicy extract MediaPolicy attribute from Pool configuration (JSON-File) + (input attribute: [volume_name]) + --get-poolmember extract VolumeName attribute from Pool configuration (JSON-File) + (input attribute: [volume_name]) + --get-poolmember-next extract VolumeName for next usable Pool member (JSON-File) + (input attribute: [volume_name]) + --get-retensiondate extract RetensionDate attribute from Pool configuration (JSON-File) + (input attribute: [volume_name]) + --get-slot extract Slot attribute from Pool configuration (JSON-File) + (input attribute: [volume_name]) + --ltfs-getattribute report ltfs extended attribute for mounted tape + (input attribute: ) + --ltfs-format format tape + (input attribute: ) + --ltfs-is-mounted returns true, if ltfs tape is already mounted + --ltfs-mount mount a ltfs tape (returns true on success) + --ltfs-umount unmount a ltfs tape (returns true on success) + --mtx-exchange exchange tapes in slots + (input attribute: ) + --mtx-getlabel report tape label/barcode for tape in drive + (input attribute: ) + --mtx-inventory run inquriy task for tape-changer + --mtx-load load a tape to target slot + (input attribute: ) + --mtx-status list changer slot status + --mtx-transfer transfer a tape to target slot + (input attribute: ) + --mtx-unload unload a tape + (input attribute: slot_source drive) + --mount make tape accessible for OS + (input attribute: []) + --update-lastwrite update LastWrite attribute for given TapeName in Pool (JSON-File) + (input attribute: [ ) + --update-retensiondate update RetensionDate attribute for given TapeName in Pool (JSON-File) + (input attribute: [ ) + --use-mtx use mtx loader handling. If not specified, all mtx commands will use + default device ($default_changer_device) + -v, --verbose Be verbose on what's going on (min: --verbose=1, max: --verbose=3) + --version show program version +EOF + #-r, --remote
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 The remote port. + # --dry-run perform a trial run where no changes are made. + + 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 + return $? + ;; + get-mediapools) + get_mediapool_names + if test $? -eq 0; then + if [ $verbose -ge 1 ]; then + printf "${MAGENTA}MediaPool names:${NO_COLOR} %s.\n" \ + "${mediapool_names}" + fi + fi + return $? + ;; + 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 + return $? + ;; + get-lastwrite) + valid_member=0 + get_lastwrite "${mediapool_name}" "${volume_name}" + if test $? -eq 0; then + if [ $verbose -ge 1 ]; then + date_string_to_iso ${volume_lastwrite} + if [ $? -eq 0 ]; then + volume_date=$(date --date="${date_iso}Z") + printf "${MAGENTA}Last write date for Volume ${GREEN}'%s'${MAGENTA} from media-pool ${GREEN}'%s'${MAGENTA} is :${NO_COLOR}'%s'.\n" \ + "${volume_name}" "${mediapool_name}" "${volume_date}" + fi + fi + else + return 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 + return $? + ;; + 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 + else + return 1 + 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 + return $? + ;; + ltfs-format) + ltfs_format "${volume_name}" "${tape_id}" + ;; + ltfs-getattribute) + ltfs_is_mounted + if test $? -eq 0; then + ltfs_get_attribute "${ltfs_attribute_name}" + if test $? -eq 0; then + if [ $verbose -ge 1 ]; then + printf "${MAGENTA}LTFS attribute ${GREEN}'%s'${MAGENTA} is: ${GREEN}'%s'${NO_COLOR}\n" \ + "${ltfs_attribute_name}" "${ltfs_attribute_value}" + fi + fi + fi + return $? + ;; + ltfs-is-mounted) + ltfs_is_mounted + if test $? -eq 0; then + if [ $verbose -ge 1 ]; then + printf "${MAGENTA}LTFS Tape is-mounted: ${GREEN}true${NO_COLOR}\n" + fi + fi + return $? + ;; + ltfs-mount) + ltfs_mount + if test $? -eq 0; then + if [ $verbose -ge 1 ]; then + printf "${MAGENTA}LTFS Tape mount: ${GREEN}true${NO_COLOR}\n" + fi + fi + return $? + ;; + ltfs-umount) + ltfs_umount + if test $? -eq 0; then + if [ $verbose -ge 1 ]; then + printf "${MAGENTA}LTFS Tape unmount: ${GREEN}true${NO_COLOR}\n" + fi + fi + return $? + ;; + mtx-exchange) + mtx_exchange "${slot_source}" "${slot_target}" + return $? + ;; + mtx-getlabel) + mtx_getlabel $slot_source + if [ $verbose -ge 1 ]; then + printf "${MAGENTA}Tape Label: ${GREEN}%s${NO_COLOR}\n" \ + "${volume_name_active}" + fi + return $? + ;; + mtx-inventory) + mtx_inventory + return $? + ;; + mtx-load) + mtx_load "${slot_source}" "${drive}" + return $? + ;; + mtx-transfer) + mtx_transfer "${slot_source}" "${slot_target}" + return $? + ;; + mtx-unload) + mtx_unload "${slot_source}" "${drive}" + return $? + ;; + mount) + 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}true.\n" \ + "${volume_name_active}" "${mediapool_name}" + fi + fi + return $? + ;; + update-lastwrite) + update_lastwrite "${mediapool_name}" "${volume_name}" "${date_string}" + if test $? -eq 0; then + if [ $verbose -ge 1 ]; then + date_string_to_iso "${volume_lastwrite}" + if [ $? -eq 0 ]; then + volume_date=$(date --date="${date_iso}Z") + printf "${MAGENTA}LastWrite date for ${GREEN}'%s'${MAGENTA} is: ${NO_COLOR}'%s'.\n" \ + "${volume_name}" "${volume_date}" + fi + fi + fi + return $? + ;; + update-retensiondate) + update_retensiondate "${mediapool_name}" "${volume_name}" "${date_string}" + if test $? -eq 0; then + if [ $verbose -ge 1 ]; then + date_string_to_iso "${volume_retensiondate}" + if [ $? -eq 0 ]; then + volume_date=$(date --date="${date_iso}Z") + printf "${MAGENTA}RetensionDate date for ${GREEN}'%s'${MAGENTA} is: ${NO_COLOR}'%s'.\n" \ + "${volume_name}" "${volume_date}" + fi + fi + fi + return $? + ;; +esac