mtx-changer 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. #!/bin/sh
  2. #
  3. # Bacula interface to mtx autoloader
  4. #
  5. # If you set in your Device resource
  6. #
  7. # Changer Command = "path-to-this-script/mtx-changer %c %o %S %a %d"
  8. # you will have the following input to this script:
  9. #
  10. # So Bacula will always call with all the following arguments, even though
  11. # in come cases, not all are used.
  12. #
  13. # mtx-changer "changer-device" "command" "slot" "archive-device" "drive-index"
  14. # $1 $2 $3 $4 $5
  15. #
  16. # for example:
  17. #
  18. # mtx-changer /dev/sg0 load 1 /dev/nst0 0 (on a Linux system)
  19. #
  20. # will request to load the first cartidge into drive 0, where
  21. # the SCSI control channel is /dev/sg0, and the read/write device
  22. # is /dev/nst0.
  23. #
  24. # The commands are:
  25. # Command Function
  26. # unload unload a given slot
  27. # load load a given slot
  28. # loaded which slot is loaded?
  29. # list list Volume names (requires barcode reader)
  30. # slots how many slots total?
  31. # listall list all info
  32. # transfer
  33. #
  34. # Slots are numbered from 1 ...
  35. # Drives are numbered from 0 ...
  36. #
  37. #
  38. # If you need to an offline, refer to the drive as $4
  39. # e.g. mt -f $4 offline
  40. #
  41. # Many changers need an offline after the unload. Also many
  42. # changers need a sleep 60 after the mtx load.
  43. #
  44. # N.B. If you change the script, take care to return either
  45. # the mtx exit code or a 0. If the script exits with a non-zero
  46. # exit code, Bacula will assume the request failed.
  47. #
  48. # source our conf file
  49. if test ! -f /etc/bacula/scripts/mtx-changer.conf ; then
  50. echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
  51. echo "ERROR: /etc/bacula/scripts/mtx-changer.conf file not found!!!!"
  52. echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
  53. exit 1
  54. fi
  55. . /etc/bacula/scripts/mtx-changer.conf
  56. MTX=/usr/sbin/mtx
  57. if test ${debug_log} -ne 0 ; then
  58. touch /var/lib/bacula/mtx.log
  59. fi
  60. dbgfile="/var/lib/bacula/mtx.log"
  61. debug() {
  62. if test -f $dbgfile; then
  63. echo "`date +\"%Y%m%d-%H:%M:%S\"` $*" >> $dbgfile
  64. fi
  65. }
  66. #
  67. # Create a temporary file
  68. #
  69. make_temp_file() {
  70. TMPFILE=`mktemp /var/lib/bacula/mtx.XXXXXXXXXX`
  71. if test x${TMPFILE} = x; then
  72. TMPFILE="/var/lib/bacula/mtx.$$"
  73. if test -f ${TMPFILE}; then
  74. echo "ERROR: Temp file security problem on: ${TMPFILE}"
  75. exit 1
  76. fi
  77. fi
  78. }
  79. #
  80. # The purpose of this function to wait a maximum
  81. # time for the drive. It will
  82. # return as soon as the drive is ready, or after
  83. # waiting a maximum of 300 seconds.
  84. # Note, this is very system dependent, so if you are
  85. # not running on Linux, you will probably need to
  86. # re-write it, or at least change the grep target.
  87. # We've attempted to get the appropriate OS grep targets
  88. # in the code at the top of this script.
  89. #
  90. wait_for_drive() {
  91. i=0
  92. while [ $i -le 300 ]; do # Wait max 300 seconds
  93. if mt -f $1 status 2>&1 | grep "${ready}" >/dev/null 2>&1; then
  94. break
  95. fi
  96. debug "Device $1 - not ready, retrying..."
  97. sleep 1
  98. i=`expr $i + 1`
  99. done
  100. }
  101. # check parameter count on commandline
  102. #
  103. check_parm_count() {
  104. pCount=$1
  105. pCountNeed=$2
  106. if test $pCount -lt $pCountNeed; then
  107. echo "ERROR: usage: mtx-changer ctl-device command [slot archive-device drive-index]"
  108. echo " Insufficient number of arguments given."
  109. if test $pCount -lt 2; then
  110. echo " Mimimum usage is first two arguments ..."
  111. else
  112. echo " Command expected $pCountNeed arguments"
  113. fi
  114. exit 1
  115. fi
  116. }
  117. # Check for special cases where only 2 arguments are needed,
  118. # all others are a minimum of 5
  119. #
  120. case $2 in
  121. list|listall)
  122. check_parm_count $# 2
  123. ;;
  124. slots)
  125. check_parm_count $# 2
  126. ;;
  127. transfer)
  128. check_parm_count $# 4
  129. ;;
  130. *)
  131. check_parm_count $# 5
  132. ;;
  133. esac
  134. # Setup arguments
  135. ctl=$1
  136. cmd="$2"
  137. slot=$3
  138. device=$4
  139. drive=$5
  140. debug "Parms: $ctl $cmd $slot $device $drive"
  141. case $cmd in
  142. unload)
  143. debug "Doing mtx -f $ctl unload $slot $drive"
  144. if test ${offline} -eq 1 ; then
  145. mt -f $device offline
  146. fi
  147. if test ${offline_sleep} -ne 0 ; then
  148. sleep ${offline_sleep}
  149. fi
  150. ${MTX} -f $ctl unload $slot $drive
  151. ;;
  152. load)
  153. debug "Doing mtx -f $ctl load $slot $drive"
  154. ${MTX} -f $ctl load $slot $drive
  155. rtn=$?
  156. if test ${load_sleep} -ne 0 ; then
  157. sleep ${load_sleep}
  158. fi
  159. wait_for_drive $device
  160. exit $rtn
  161. ;;
  162. list)
  163. debug "Doing mtx -f $ctl -- to list volumes"
  164. make_temp_file
  165. if test ${inventory} -ne 0 ; then
  166. ${MTX} -f $ctl inventory
  167. fi
  168. ${MTX} -f $ctl status >${TMPFILE}
  169. rtn=$?
  170. if test ${vxa_packetloader} -ne 0 ; then
  171. cat ${TMPFILE} | grep " *Storage Element [0-9]*:.*Full" | sed "s/ Storage Element //" | sed "s/Full :VolumeTag=//"
  172. else
  173. cat ${TMPFILE} | grep " Storage Element [0-9]*:.*Full" | awk "{print \$3 \$4}" | sed "s/Full *\(:VolumeTag=\)*//"
  174. fi
  175. cat ${TMPFILE} | grep "^Data Transfer Element [0-9]*:Full (Storage Element [0-9]" | awk '{printf "%s:%s\n",$7,$10}'
  176. rm -f ${TMPFILE} >/dev/null 2>&1
  177. exit $rtn
  178. ;;
  179. listall)
  180. # Drive content: D:Drive num:F:Slot loaded:Volume Name
  181. # D:0:F:2:vol2 or D:Drive num:E
  182. # D:1:F:42:vol42
  183. # D:3:E
  184. #
  185. # Slot content:
  186. # S:1:F:vol1 S:Slot num:F:Volume Name
  187. # S:2:E or S:Slot num:E
  188. # S:3:F:vol4
  189. #
  190. # Import/Export tray slots:
  191. # I:10:F:vol10 I:Slot num:F:Volume Name
  192. # I:11:E or I:Slot num:E
  193. # I:12:F:vol40
  194. debug "Doing mtx -f $ctl -- to list all"
  195. make_temp_file
  196. if test ${inventory} -ne 0 ; then
  197. ${MTX} -f $ctl inventory
  198. fi
  199. ${MTX} -f $ctl status >${TMPFILE}
  200. rtn=$?
  201. # can be converted to awk+sed+cut, see below
  202. perl -ne '
  203. /Data Transfer Element (\d+):Empty/ && print "D:$1:E\n";
  204. /Data Transfer Element (\d+):Full \(Storage Element (\d+) Loaded\)(:VolumeTag =\s*(.+))?/ && print "D:$1:F:$2:$4\n";
  205. /Storage Element (\d+):Empty/ && print "S:$1:E\n";
  206. /Storage Element (\d+):Full( :VolumeTag=(.+))?/ && print "S:$1:F:$3\n";
  207. /Storage Element (\d+) IMPORT.EXPORT:Empty/ && print "I:$1:E\n";
  208. /Storage Element (\d+) IMPORT.EXPORT:Full( :VolumeTag=(.+))?/ && print "I:$1:F:$3\n";' ${TMPFILE}
  209. # If perl isn't installed, you can use by those commands
  210. #cat ${TMPFILE} | grep "Data Transfer Element" | awk "{print \"D:\"\$4 \$7 \$9 \$10}" | sed "s/=/:/" | sed "s/Full/F:/" | sed "s/Empty/E/"
  211. #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/"
  212. #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/"
  213. rm -f ${TMPFILE} >/dev/null 2>&1
  214. exit $rtn
  215. ;;
  216. transfer)
  217. slotdest=$device
  218. debug "Doing transfer from $slot to $slotdest"
  219. ${MTX} -f $ctl transfer $slot $slotdest
  220. rtn=$?
  221. exit $rtn
  222. ;;
  223. loaded)
  224. debug "Doing mtx -f $ctl $drive -- to find what is loaded"
  225. make_temp_file
  226. ${MTX} -f $ctl status >${TMPFILE}
  227. rtn=$?
  228. cat ${TMPFILE} | grep "^Data Transfer Element $drive:Full" | awk "{print \$7}"
  229. cat ${TMPFILE} | grep "^Data Transfer Element $drive:Empty" | awk "{print 0}"
  230. rm -f ${TMPFILE} >/dev/null 2>&1
  231. exit $rtn
  232. ;;
  233. slots)
  234. debug "Doing mtx -f $ctl -- to get count of slots"
  235. ${MTX} -f $ctl status | grep " *Storage Changer" | awk "{print \$5}"
  236. ;;
  237. esac