1 # Mount RPC client -- RFC 1094 (NFS), Appendix A
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.
12 from rpc
import Packer
, Unpacker
, TCPClient
, UDPClient
15 # Program number and version for the mount protocol
19 # Size of the 'fhandle' opaque structure
23 # Packer derived class for Mount protocol clients.
24 # The only thing we need to pack beyond basic types is an 'fhandle'
26 class MountPacker(Packer
):
28 def pack_fhandle(self
, fhandle
):
29 self
.pack_fopaque(FHSIZE
, fhandle
)
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.
39 class MountUnpacker(Unpacker
):
41 def unpack_fhandle(self
):
42 return self
.unpack_fopaque(FHSIZE
)
44 def unpack_fhstatus(self
):
45 status
= self
.unpack_uint()
47 fh
= self
.unpack_fhandle()
52 def unpack_mountlist(self
):
53 return self
.unpack_list(self
.unpack_mountstruct
)
55 def unpack_mountstruct(self
):
56 hostname
= self
.unpack_string()
57 directory
= self
.unpack_string()
58 return (hostname
, directory
)
60 def unpack_exportlist(self
):
61 return self
.unpack_list(self
.unpack_exportstruct
)
63 def unpack_exportstruct(self
):
64 filesys
= self
.unpack_string()
65 groups
= self
.unpack_groups()
66 return (filesys
, groups
)
68 def unpack_groups(self
):
69 return self
.unpack_list(self
.unpack_string
)
72 # These are the procedures specific to the Mount client class.
73 # Think of this as a derived class of either TCPClient or UDPClient.
75 class PartialMountClient
:
77 # This method is called by Client.__init__ to initialize
78 # self.packer and self.unpacker
80 self
.packer
= MountPacker()
81 self
.unpacker
= MountUnpacker('')
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
91 except AttributeError:
94 port
= rpc
.bindresvport(self
.sock
, '')
97 self
.sock
.bind(('', 0))
99 # This function is called to cough up a suitable
100 # authentication object for a call to procedure 'proc'.
102 if self
.cred
== None:
103 self
.cred
= rpc
.AUTH_UNIX
, rpc
.make_auth_unix_default()
106 # The methods Mnt, Dump etc. each implement one Remote
107 # Procedure Call. This is done by calling self.make_call()
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)
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.
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.
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.)
128 # If the call fails, make_call() raises an exception
129 # (this includes time-outs and invalid results).
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.
136 def Mnt(self
, directory
):
137 return self
.make_call(1, directory
, \
138 self
.packer
.pack_string
, \
139 self
.unpacker
.unpack_fhstatus
)
142 return self
.make_call(2, None, \
143 None, self
.unpacker
.unpack_mountlist
)
145 def Umnt(self
, directory
):
146 return self
.make_call(3, directory
, \
147 self
.packer
.pack_string
, None)
150 return self
.make_call(4, None, None, None)
153 return self
.make_call(5, None, \
154 None, self
.unpacker
.unpack_exportlist
)
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.)
162 class TCPMountClient(PartialMountClient
, TCPClient
):
164 def __init__(self
, host
):
165 TCPClient
.__init
__(self
, host
, MOUNTPROG
, MOUNTVERS
)
168 class UDPMountClient(PartialMountClient
, UDPClient
):
170 def __init__(self
, host
):
171 UDPClient
.__init
__(self
, host
, MOUNTPROG
, MOUNTVERS
)
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.
182 if sys
.argv
[1:] and sys
.argv
[1] == '-t':
185 elif sys
.argv
[1:] and sys
.argv
[1] == '-u':
190 if sys
.argv
[1:]: host
= sys
.argv
[1]