blob: a0de94b93d07501a1de6d7855c35f02b61418444 [file] [log] [blame]
Guido van Rossume3cafbe1992-12-14 23:25:04 +00001# 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
Guido van Rossum20f99601992-12-15 20:53:17 +000011import rpc
Guido van Rossume3cafbe1992-12-14 23:25:04 +000012from rpc import Packer, Unpacker, TCPClient, UDPClient
13
14MOUNTPROG = 100005
15MOUNTVERS = 1
16
17FHSIZE = 32
18
19
20# Packer derived class for Mount protocol clients.
21# The only thing we need to pack beyond basic types is an 'fhandle'
22
23class MountPacker(Packer):
24
25 def pack_fhandle(self, fhandle):
26 self.pack_fopaque(FHSIZE, fhandle)
27
28
29# Unpacker derived class for Mount protocol clients.
30# The important types we need to unpack are fhandle, fhstatus,
31# mountlist and exportlist; mountstruct, exportstruct and groups are
32# used to unpack components of mountlist and exportlist and the
33# corresponding functions are passed as function argument to the
34# generic unpack_list function.
35
36class MountUnpacker(Unpacker):
37
38 def unpack_fhandle(self):
39 return self.unpack_fopaque(FHSIZE)
40
41 def unpack_fhstatus(self):
42 status = self.unpack_uint()
43 if status == 0:
44 fh = self.unpack_fhandle()
45 else:
46 fh = None
47 return status, fh
48
49 def unpack_mountlist(self):
50 return self.unpack_list(self.unpack_mountstruct)
51
52 def unpack_mountstruct(self):
53 hostname = self.unpack_string()
54 directory = self.unpack_string()
55 return (hostname, directory)
56
57 def unpack_exportlist(self):
58 return self.unpack_list(self.unpack_exportstruct)
59
60 def unpack_exportstruct(self):
61 filesys = self.unpack_string()
62 groups = self.unpack_groups()
63 return (filesys, groups)
64
65 def unpack_groups(self):
66 return self.unpack_list(self.unpack_string)
67
68
69# These are the procedures specific to the Mount client class.
70# Think of this as a derived class of either TCPClient or UDPClient.
71
72class PartialMountClient:
73
74 # This method is called by Client.init to initialize
75 # self.packer and self.unpacker
76 def addpackers(self):
77 self.packer = MountPacker().init()
78 self.unpacker = MountUnpacker().init('')
79
Guido van Rossum20f99601992-12-15 20:53:17 +000080 # This function is called to gobble up a suitable
81 # authentication object for a call to procedure 'proc'.
82 # (Experiments suggest that for Mnt/Unmnt, Unix authentication
83 # is necessary, while the other calls require no
84 # authentication.)
85 def mkcred(self, proc):
86 if proc not in (1, 3, 4): # not Mnt/Unmnt/Unmntall
87 return rpc.AUTH_NULL, ''
88 if self.cred == None:
89 self.cred = rpc.AUTH_UNIX, rpc.make_auth_unix_default()
90 return self.cred
91
Guido van Rossume3cafbe1992-12-14 23:25:04 +000092 # The methods Mnt, Dump etc. each implement one Remote
93 # Procedure Call. Their general structure is
94 # self.start_call(<procedure-number>)
95 # <pack arguments using self.packer>
96 # self.do_call() # This does the actual message exchange
97 # <unpack reply using self.unpacker>
98 # self.end_call()
99 # return <reply>
100 # If the call fails, an exception is raised by do_call().
101 # If the reply does not match what you unpack, an exception is
102 # raised either during unpacking (if you overrun the buffer)
103 # or by end_call() (if you leave values in the buffer).
104 # Calling packer methods with invalid arguments (e.g. if
105 # invalid arguments were passed from outside) will also result
106 # in exceptions during packing.
107
108 def Mnt(self, directory):
109 self.start_call(1)
110 self.packer.pack_string(directory)
111 self.do_call()
112 stat = self.unpacker.unpack_fhstatus()
113 self.end_call()
114 return stat
115
116 def Dump(self):
117 self.start_call(2)
118 self.do_call()
119 list = self.unpacker.unpack_mountlist()
120 self.end_call()
121 return list
122
123 def Umnt(self, directory):
124 self.start_call(3)
125 self.packer.pack_string(directory)
126 self.do_call()
127 self.end_call()
128
129 def Umntall(self):
130 self.start_call(4)
131 self.do_call()
132 self.end_call()
133
134 def Export(self):
135 self.start_call(5)
136 self.do_call()
137 list = self.unpacker.unpack_exportlist()
138 self.end_call()
139 return list
140
141
142# We turn the partial Mount client into a full one for either protocol
143# by use of multiple inheritance. (In general, when class C has base
144# classes B1...Bn, if x is an instance of class C, methods of x are
145# searched first in C, then in B1, then in B2, ..., finally in Bn.)
146
147class TCPMountClient(PartialMountClient, TCPClient):
148
149 def init(self, host):
150 return TCPClient.init(self, host, MOUNTPROG, MOUNTVERS)
151
152
153class UDPMountClient(PartialMountClient, UDPClient):
154
155 def init(self, host):
156 return UDPClient.init(self, host, MOUNTPROG, MOUNTVERS)
157
158
159# A little test program for the Mount client. This takes a host as
160# command line argument (default the local machine), prints its export
161# list, and attempt to mount and unmount each exported files system.
162
163def test():
164 import sys
165 if sys.argv[1:]: host = sys.argv[1]
166 else: host = ''
167 mcl = UDPMountClient().init(host)
168 list = mcl.Export()
169 for item in list:
170 print item
171 try:
172 mcl.Mnt(item[0])
173 except:
174 print 'Sorry'
175 continue
176 mcl.Umnt(item[0])
177 return
178
179#test()