mountclient.py revision 9e80d6f12512803532aed39a0335e6346b77abf4
1# Mount RPC client -- RFC 1094 (NFS), Appendix A 2 3# This module demonstrates how to write your own RPC client in Python. 4# Since there is no RPC compiler for Python (yet), you must first 5# create classes derived from Packer and Unpacker to handle the data 6# types for the server you want to interface to. You then write the 7# client class. If you want to support both the TCP and the UDP 8# version of a protocol, use multiple inheritance as shown below. 9 10 11import rpc 12from rpc import Packer, Unpacker, TCPClient, UDPClient 13 14 15# Program number and version for the mount protocol 16MOUNTPROG = 100005 17MOUNTVERS = 1 18 19# Size of the 'fhandle' opaque structure 20FHSIZE = 32 21 22 23# Packer derived class for Mount protocol clients. 24# The only thing we need to pack beyond basic types is an 'fhandle' 25 26class MountPacker(Packer): 27 28 def pack_fhandle(self, fhandle): 29 self.pack_fopaque(FHSIZE, fhandle) 30 31 32# Unpacker derived class for Mount protocol clients. 33# The important types we need to unpack are fhandle, fhstatus, 34# mountlist and exportlist; mountstruct, exportstruct and groups are 35# used to unpack components of mountlist and exportlist and the 36# corresponding functions are passed as function argument to the 37# generic unpack_list function. 38 39class MountUnpacker(Unpacker): 40 41 def unpack_fhandle(self): 42 return self.unpack_fopaque(FHSIZE) 43 44 def unpack_fhstatus(self): 45 status = self.unpack_uint() 46 if status == 0: 47 fh = self.unpack_fhandle() 48 else: 49 fh = None 50 return status, fh 51 52 def unpack_mountlist(self): 53 return self.unpack_list(self.unpack_mountstruct) 54 55 def unpack_mountstruct(self): 56 hostname = self.unpack_string() 57 directory = self.unpack_string() 58 return (hostname, directory) 59 60 def unpack_exportlist(self): 61 return self.unpack_list(self.unpack_exportstruct) 62 63 def unpack_exportstruct(self): 64 filesys = self.unpack_string() 65 groups = self.unpack_groups() 66 return (filesys, groups) 67 68 def unpack_groups(self): 69 return self.unpack_list(self.unpack_string) 70 71 72# These are the procedures specific to the Mount client class. 73# Think of this as a derived class of either TCPClient or UDPClient. 74 75class PartialMountClient: 76 77 # This method is called by Client.__init__ to initialize 78 # self.packer and self.unpacker 79 def addpackers(self): 80 self.packer = MountPacker() 81 self.unpacker = MountUnpacker('') 82 83 # This method is called by Client.__init__ to bind the socket 84 # to a particular network interface and port. We use the 85 # default network interface, but if we're running as root, 86 # we want to bind to a reserved port 87 def bindsocket(self): 88 import os 89 try: 90 uid = os.getuid() 91 except AttributeError: 92 uid = 1 93 if uid == 0: 94 port = rpc.bindresvport(self.sock, '') 95 # 'port' is not used 96 else: 97 self.sock.bind(('', 0)) 98 99 # This function is called to cough up a suitable 100 # authentication object for a call to procedure 'proc'. 101 def mkcred(self): 102 if self.cred == None: 103 self.cred = rpc.AUTH_UNIX, rpc.make_auth_unix_default() 104 return self.cred 105 106 # The methods Mnt, Dump etc. each implement one Remote 107 # Procedure Call. This is done by calling self.make_call() 108 # with as arguments: 109 # 110 # - the procedure number 111 # - the arguments (or None) 112 # - the "packer" function for the arguments (or None) 113 # - the "unpacker" function for the return value (or None) 114 # 115 # The packer and unpacker function, if not None, *must* be 116 # methods of self.packer and self.unpacker, respectively. 117 # A value of None means that there are no arguments or is no 118 # return value, respectively. 119 # 120 # The return value from make_call() is the return value from 121 # the remote procedure call, as unpacked by the "unpacker" 122 # function, or None if the unpacker function is None. 123 # 124 # (Even if you expect a result of None, you should still 125 # return the return value from make_call(), since this may be 126 # needed by a broadcasting version of the class.) 127 # 128 # If the call fails, make_call() raises an exception 129 # (this includes time-outs and invalid results). 130 # 131 # Note that (at least with the UDP protocol) there is no 132 # guarantee that a call is executed at most once. When you do 133 # get a reply, you know it has been executed at least once; 134 # when you don't get a reply, you know nothing. 135 136 def Mnt(self, directory): 137 return self.make_call(1, directory, \ 138 self.packer.pack_string, \ 139 self.unpacker.unpack_fhstatus) 140 141 def Dump(self): 142 return self.make_call(2, None, \ 143 None, self.unpacker.unpack_mountlist) 144 145 def Umnt(self, directory): 146 return self.make_call(3, directory, \ 147 self.packer.pack_string, None) 148 149 def Umntall(self): 150 return self.make_call(4, None, None, None) 151 152 def Export(self): 153 return self.make_call(5, None, \ 154 None, self.unpacker.unpack_exportlist) 155 156 157# We turn the partial Mount client into a full one for either protocol 158# by use of multiple inheritance. (In general, when class C has base 159# classes B1...Bn, if x is an instance of class C, methods of x are 160# searched first in C, then in B1, then in B2, ..., finally in Bn.) 161 162class TCPMountClient(PartialMountClient, TCPClient): 163 164 def __init__(self, host): 165 TCPClient.__init__(self, host, MOUNTPROG, MOUNTVERS) 166 167 168class UDPMountClient(PartialMountClient, UDPClient): 169 170 def __init__(self, host): 171 UDPClient.__init__(self, host, MOUNTPROG, MOUNTVERS) 172 173 174# A little test program for the Mount client. This takes a host as 175# command line argument (default the local machine), prints its export 176# list, and attempts to mount and unmount each exported files system. 177# An optional first argument of -t or -u specifies the protocol to use 178# (TCP or UDP), default is UDP. 179 180def test(): 181 import sys 182 if sys.argv[1:] and sys.argv[1] == '-t': 183 C = TCPMountClient 184 del sys.argv[1] 185 elif sys.argv[1:] and sys.argv[1] == '-u': 186 C = UDPMountClient 187 del sys.argv[1] 188 else: 189 C = UDPMountClient 190 if sys.argv[1:]: host = sys.argv[1] 191 else: host = '' 192 mcl = C(host) 193 list = mcl.Export() 194 for item in list: 195 print item 196 try: 197 mcl.Mnt(item[0]) 198 except: 199 print 'Sorry' 200 continue 201 mcl.Umnt(item[0]) 202