improve bash completions and related delivery mechanism
[debian/mtx] / contrib / mtx.py
1 # Copyright 2000 Enhanced Software Technologies Inc.
2 # Released under Free Software Foundation's General Public License,
3 # Version 2 or above
4 #
5 # This is an example of how to parse the 'mtx' output from a scripting
6 # language. 
7 #
8 # Routine to call 'mtx' and read status, or
9 # whatever.
10 #
11 # We do this here rather than creating a Python "C" module because:
12 #  1) Reduces complexity of compile environment
13 #  2) Easier debugging.
14 #  3) More in keeping with the Unix philosophy of things.
15 #  4) Easier to add new functionality. 
16 #
17 #
18
19 import string
20 import os
21 import time # we can do some waiting here...
22
23 def readpipe(command):
24     result=""
25     
26     infile=os.popen(command,"r")
27
28     try:
29         s=infile.read()
30     except:
31         s=""
32         pass
33     if not s:
34         return None  # didn't get anything :-(. 
35     result=result+s
36     return result
37
38
39
40
41 # these are returned by the mtx.status routine:
42 class slotstatus:
43     def __init__(self,slotnum,middle,barcode=None):
44         middle=string.strip(middle)
45         try:
46             left,right=string.split(middle," ")
47         except:
48             left=middle
49             right=None
50             pass
51         # Note: We will not be able to test this at the moment since the
52         # 220 has no import/export port!
53         if right=="IMPORT/EXPORT":
54             self.importexport=1
55         else:
56             self.importexport=0
57             pass
58         self.slotnum=int(slotnum) # make sure it's an integer...
59         if left=="Full":
60             self.full=1
61         else:
62             self.full=None
63             pass
64         if not barcode:
65             self.voltag=None
66         else:
67             l=string.split(barcode,"=",1)
68             self.voltag=l[1]
69             pass
70         return
71     pass
72
73 # Drive status lines have this format:
74 #Data Transfer Element 0:Full (Storage Element 10 Loaded):VolumeTag = B0000009H
75 #Data Transfer Element 1:Empty
76
77 class drivestatus:
78     def __init__(self,slotnum,middle,barcode=None):
79         self.slotnum=slotnum
80         if middle=="Empty":
81             self.full=None
82             self.origin=None
83             self.voltag=None
84             return
85         else:
86             self.full=1
87             pass
88
89         # okay, we know we have a tape in the drive. 
90         # split and find out our origin: we will always have
91         # an origin, even if the #$@% mtx program had to dig one
92         # out of the air:
93
94         l=string.split(middle," ")
95         self.origin=int(l[3])
96
97         if not barcode:
98             self.voltag=None # barcode of this element.
99         else:
100             l=string.split(barcode," ")
101             self.voltag=string.strip(l[2])
102             pass
103         return
104     pass
105
106 # This is the return value for mtx.status. 
107 class mtxstatus:
108     def __init__(self):
109         self.numdrives=None
110         self.numslots=None
111         self.numexport=None
112         self.drives=[]  # a list of drivestatus instances.
113         self.slots=[]   # a list of slotstatus instances
114         self.export=[]  # another list of slotstatus instances
115         return
116     pass
117
118 # call 'mtx' and get barcode info, if possible:
119 # okay, we now have a string that consists of a number of lines.
120 # we want to explode this string into its component parts.
121 # Example format:
122 # Storage Changer /dev/sgd:2 Drives, 21 Slots
123 # Data Transfer Element 0:Full (Storage Element '5' Loaded) 
124 # Data Transfer Element 1:Empty
125 # Storage Element 1:Full :VolumeTag=CLNA0001
126 # Storage Element 2:Full :VolumeTag=B0000009
127 # Storage Element 3:Full :VolumeTag=B0000010
128 # ....
129 # What we want to do, then, is:
130 # 1) Turn it into lines by doing a string.split on newline.
131 # 2) Split the 1st line on ":" to get left and right.
132 # 3) Split the right half on space to get #drives "Drives," #slots
133 # 4) process the drives (Full,Empty, etc.)
134 # 5) For each of the remaining lines: Split on ':'
135 # 6) Full/Empty status is in 2)
136 #
137 configdir="/opt/brupro/bin"  # sigh. 
138
139 def status(device):
140     retval=mtxstatus()
141     command="%s/mtx -f %s status" % (configdir,device)
142     result=readpipe(command)
143     if not result:
144         return None  # sorry! 
145     # now to parse:
146
147     try:
148         lines=string.split(result,"\n")
149     except:
150         return None # sorry, no status!
151     
152     # print "DEBUG:lines=",lines
153
154     try:
155         l=string.split(lines[0],":")
156     except:
157         return None # sorry, no status!
158     
159     # print "DEBUG:l=",l
160     leftside=l[0]
161     rightside=l[1]
162     if len(l) > 2:
163         barcode=l[3]
164     else:
165         barcode=None
166         pass
167     t=string.split(rightside)
168     retval.numdrives=int(t[0])
169     retval.numslots=int(t[2])
170     
171     for s in lines[1:]:
172         if not s:
173             continue # skip blank lines!
174         #print "DEBUG:s=",s
175         parts=string.split(s,":")
176         leftpart=string.split(parts[0])
177         rightpart=parts[1]
178         try:
179             barcode=parts[2]
180         except:
181             barcode=None
182             pass
183         #print "DEBUG:leftpart=",leftpart
184         if leftpart[0]=="Data" and leftpart[1]=="Transfer":
185             retval.drives.append(drivestatus(leftpart[3],rightpart,barcode))
186             pass
187         if leftpart[0]=="Storage" and leftpart[1]=="Element":
188             element=slotstatus(leftpart[2],rightpart,barcode)
189             if element.importexport:
190                 retval.export.append(element)
191             else:
192                 retval.slots.append(element)
193                 pass
194             pass
195         continue
196
197     return retval
198
199 # Output of a mtx inquiry looks like:
200 #
201 #Product Type: Medium Changer
202 #Vendor ID: 'EXABYTE '
203 #Product ID: 'Exabyte EZ17    '
204 #Revision: '1.07'
205 #Attached Changer: No
206 #
207 # We simply return a hash table with these values { left:right } format. 
208
209 def mtxinquiry(device):
210     command="%s/mtx -f %s inquiry" % (configdir,device)
211     str=readpipe(command) # calls the command, returns all its data.
212
213     str=string.strip(str)
214     lines=string.split(str,"\n")
215     retval={}
216     for l in lines:
217         # DEBUG #
218         l=string.strip(l)
219         print "splitting line: '",l,"'"
220         idx,val=string.split(l,':',1)
221         val=string.strip(val)
222         if val[0]=="'":
223             val=val[1:-1] # strip off single quotes, sigh. 
224             pass 
225         retval[idx]=val
226         continue
227     return retval
228
229 # Now for the easy part:
230
231 def load(device,slot,drive=0):
232     command="%s/mtx -f %s load %s %s >/dev/null " % (configdir,device,slot,drive)
233     status=os.system(command)
234     return status
235
236 def unload(device,slot,drive=0):
237     command="%s/mtx -f %s unload %s %s >/dev/null " % (configdir,device,slot,drive)
238     return os.system(command)
239
240 def inventory(device):
241     command="%s/mtx -f %s inventory >/dev/null " % (configdir,device)
242     return os.system(command)
243
244 def wait_for_inventory(device):
245     # loop while we have an error return...
246     errcount=0
247     while inventory(device):
248         if errcount==0:
249             print "Waiting for loader '%s'" % device
250             pass
251         time.sleep(1)
252         try:
253             s=status(device)
254         except:
255             s=None
256             pass
257         if s:
258             return 0 # well, whatever we're doing, we're inventoried :-(
259         errcount=errcount+1
260         if errcount==600:   # we've been waiting for 10 minutes :-(
261             return 1 # sorry!
262         continue
263     return 0  # we succeeded!
264
265 # RCS REVISION LOG:
266 # $Log$
267 # Revision 1.1  2001/06/05 17:10:51  elgreen
268 # Initial revision
269 #
270 # Revision 1.2  2000/12/22 14:17:19  eric
271 # mtx 1.2.11pre1
272 #
273 # Revision 1.14  2000/11/12 20:35:29  eric
274 # do string.strip on the voltag
275 #
276 # Revision 1.13  2000/11/04 00:33:38  eric
277 # if we can get an inventory on the loader after we send it 'mtx inventory',
278 # then obviously we managed to do SOMETHING.
279 #
280 # Revision 1.12  2000/10/28 00:04:34  eric
281 # added wait_for_inventory command
282 #
283 # Revision 1.11  2000/10/27 23:27:58  eric
284 # Added inventory command...
285 #
286 # Revision 1.10  2000/10/01 01:06:29  eric
287 # evening checkin
288 #
289 # Revision 1.9  2000/09/29 02:49:29  eric
290 # evening checkin
291 #
292 # Revision 1.8  2000/09/02 01:05:33  eric
293 # Evening Checkin
294 #
295 # Revision 1.7  2000/09/01 00:08:11  eric
296 # strip lines in mtxinquiry
297 #
298 # Revision 1.6  2000/09/01 00:05:33  eric
299 # debugging
300 #
301 # Revision 1.5  2000/08/31 23:46:01  eric
302 # fix def:
303 #
304 # Revision 1.4  2000/08/31 23:44:06  eric
305 # =->==
306 #