]>
Commit | Line | Data |
---|---|---|
a5f7e223 AM |
1 | |
2 | Miscellaneous nfs mount changes from Trond. | |
3 | ||
4 | --- | |
5 | ||
6 | util-linux-2.12-bfields/mount/Makefile | 4 | |
7 | util-linux-2.12-bfields/mount/nfsmount.c | 1235 +++++++++++++++++++------------ | |
8 | util-linux-2.12-bfields/mount/sundries.h | 1 | |
9 | util-linux-2.12-bfields/mount/umount.c | 4 | |
10 | 4 files changed, 794 insertions(+), 450 deletions(-) | |
11 | ||
12 | diff -puN mount/Makefile~nfs mount/Makefile | |
13 | --- util-linux-2.12/mount/Makefile~nfs 2004-10-13 13:51:44.000000000 -0400 | |
14 | +++ util-linux-2.12-bfields/mount/Makefile 2004-10-13 14:13:30.000000000 -0400 | |
15 | @@ -31,7 +31,7 @@ | |
16 | ||
17 | LO_OBJS = lomount.o $(LIB)/xstrncpy.o | |
18 | CRYPT_OBJS = cryptsetup.o -lcryptsetup | |
19 | -NFS_OBJS = nfsmount.o nfsmount_xdr.o nfsmount_clnt.o | |
20 | +NFS_OBJS = nfsmount.o nfsmount_xdr.o | |
21 | GEN_FILES = nfsmount.h nfsmount_xdr.c nfsmount_clnt.c | |
22 | ||
23 | all: $(PROGS) | |
24 | @@ -55,7 +55,7 @@ | |
25 | ||
26 | umount: umount.o fstab.o sundries.o xmalloc.o realpath.o mntent.o \ | |
27 | getusername.o get_label_uuid.o mount_by_label.o mount_blkid.o \ | |
28 | - version.o $(LIB)/env.o $(LO_OBJS) $(CRYPT_OBJS) | |
29 | + version.o $(LIB)/env.o $(NFS_OBJS) $(LO_OBJS) $(CRYPT_OBJS) | |
30 | $(LINK) $^ -o $@ $(BLKID_LIB) | |
31 | ||
32 | swapon: swapon.o version.o xmalloc.o \ | |
33 | diff -puN mount/nfsmount.c~nfs mount/nfsmount.c | |
34 | --- util-linux-2.12/mount/nfsmount.c~nfs 2004-10-13 13:51:44.000000000 -0400 | |
35 | +++ util-linux-2.12-bfields/mount/nfsmount.c 2004-10-13 14:13:30.000000000 -0400 | |
36 | @@ -34,6 +34,7 @@ | |
37 | ||
38 | #include "../defines.h" /* for HAVE_rpcsvc_nfs_prot_h and HAVE_inet_aton */ | |
39 | ||
40 | +#include <ctype.h> | |
41 | #include <unistd.h> | |
42 | #include <stdio.h> | |
43 | #include <string.h> | |
44 | @@ -72,11 +73,100 @@ | |
45 | #define NFS_FHSIZE 32 | |
46 | #endif | |
47 | ||
48 | +#define MNT_SENDBUFSIZE ((u_int)2048) | |
49 | +#define MNT_RECVBUFSIZE ((u_int)1024) | |
50 | + | |
51 | static char *nfs_strerror(int stat); | |
52 | ||
53 | #define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r)) | |
54 | ||
55 | #define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2) | |
56 | +#define MAX_MNTPROT ((nfs_mount_version >= 4) ? 3 : 2) | |
57 | +#define HAVE_RELIABLE_TCP (nfs_mount_version >= 4) | |
58 | + | |
59 | +#ifndef HAVE_inet_aton | |
60 | +#define inet_aton(a,b) (0) | |
61 | +#endif | |
62 | + | |
63 | +typedef dirpath mnt2arg_t; | |
64 | +typedef dirpath mnt3arg_t; | |
65 | +typedef dirpath mntarg_t; | |
66 | + | |
67 | +typedef struct fhstatus mnt2res_t; | |
68 | +typedef struct mountres3 mnt3res_t; | |
69 | +typedef union { | |
70 | + mnt2res_t nfsv2; | |
71 | + mnt3res_t nfsv3; | |
72 | +} mntres_t; | |
73 | + | |
74 | +typedef struct { | |
75 | + char **hostname; | |
76 | + struct sockaddr_in saddr; | |
77 | + struct pmap pmap; | |
78 | +} clnt_addr_t; | |
79 | + | |
80 | +/* RPC call timeout values */ | |
81 | +static const struct timeval TIMEOUT = { 20, 0 }; | |
82 | +static const struct timeval RETRY_TIMEOUT = { 3, 0 }; | |
83 | + | |
84 | +/* Define the order in which to probe for UDP/TCP services */ | |
85 | +static const u_int * | |
86 | +proto_probelist(const int use_tcp) | |
87 | +{ | |
88 | + static const u_int probe_both[] = { IPPROTO_TCP, IPPROTO_UDP, 0 }; | |
89 | + static const u_int probe_udponly[] = { IPPROTO_UDP, 0 }; | |
90 | + if (use_tcp) | |
91 | + return probe_both; | |
92 | + return probe_udponly; | |
93 | +} | |
94 | + | |
95 | +/* Define the order in which NFS versions are probed on portmapper */ | |
96 | +static const u_long * | |
97 | +nfs_probelist(const int vers) | |
98 | +{ | |
99 | + static const u_long nfs2_probe[] = { 2, 0}; | |
100 | + static const u_long nfs3_probe[] = { 3, 2, 0}; | |
101 | + switch (vers) { | |
102 | + case 3: | |
103 | + return nfs3_probe; | |
104 | + default: | |
105 | + return nfs2_probe; | |
106 | + } | |
107 | +} | |
108 | + | |
109 | +/* Define the order in which Mountd versions are probed on portmapper */ | |
110 | +static const u_long * | |
111 | +mnt_probelist(const int vers) | |
112 | +{ | |
113 | + static const u_long mnt1_probe[] = { 1, 2, 0 }; | |
114 | + static const u_long mnt3_probe[] = { 3, 1, 2, 0 }; | |
115 | + switch (vers) { | |
116 | + case 3: | |
117 | + return mnt3_probe; | |
118 | + default: | |
119 | + return mnt1_probe; | |
120 | + } | |
121 | +} | |
122 | + | |
123 | +/* Map an NFS version into the corresponding Mountd version */ | |
124 | +static u_long | |
125 | +nfsvers_to_mnt(const u_long vers) | |
126 | +{ | |
127 | + static const u_long nfs_to_mnt[] = { 0, 0, 1, 3 }; | |
128 | + if (vers <= 3) | |
129 | + return nfs_to_mnt[vers]; | |
130 | + return 0; | |
131 | +} | |
132 | + | |
133 | +/* Map a Mountd version into the corresponding NFS version */ | |
134 | +static u_long | |
135 | +mntvers_to_nfs(const u_long vers) | |
136 | +{ | |
137 | + static const u_long mnt_to_nfs[] = { 0, 2, 2, 3 }; | |
138 | + if (vers <= 3) | |
139 | + return mnt_to_nfs[vers]; | |
140 | + return 0; | |
141 | +} | |
142 | ||
143 | static int | |
144 | linux_version_code(void) { | |
145 | @@ -102,123 +192,558 @@ linux_version_code(void) { | |
146 | * NFS_MOUNT_VERSION: these nfsmount sources at compile time | |
147 | * nfs_mount_version: version this source and running kernel can handle | |
148 | */ | |
149 | +static int nfs_mount_version = NFS_MOUNT_VERSION; | |
150 | + | |
151 | static int | |
152 | find_kernel_nfs_mount_version(void) { | |
153 | static int kernel_version = -1; | |
154 | - int nfs_mount_version = NFS_MOUNT_VERSION; | |
155 | + int mnt_version = NFS_MOUNT_VERSION; | |
156 | ||
157 | if (kernel_version == -1) | |
158 | kernel_version = linux_version_code(); | |
159 | ||
160 | if (kernel_version) { | |
161 | if (kernel_version < MAKE_VERSION(2,1,32)) | |
162 | - nfs_mount_version = 1; | |
163 | + mnt_version = 1; | |
164 | else if (kernel_version < MAKE_VERSION(2,2,18)) | |
165 | - nfs_mount_version = 3; | |
166 | + mnt_version = 3; | |
167 | else if (kernel_version < MAKE_VERSION(2,3,0)) | |
168 | - nfs_mount_version = 4; /* since 2.2.18pre9 */ | |
169 | + mnt_version = 4; /* since 2.2.18pre9 */ | |
170 | else if (kernel_version < MAKE_VERSION(2,3,99)) | |
171 | - nfs_mount_version = 3; | |
172 | + mnt_version = 3; | |
173 | else | |
174 | - nfs_mount_version = 4; /* since 2.3.99pre4 */ | |
175 | + mnt_version = 4; /* since 2.3.99pre4 */ | |
176 | } | |
177 | - if (nfs_mount_version > NFS_MOUNT_VERSION) | |
178 | - nfs_mount_version = NFS_MOUNT_VERSION; | |
179 | - return nfs_mount_version; | |
180 | -} | |
181 | - | |
182 | -static struct pmap * | |
183 | -get_mountport(struct sockaddr_in *server_addr, | |
184 | - long unsigned prog, | |
185 | - long unsigned version, | |
186 | - long unsigned proto, | |
187 | - long unsigned port, | |
188 | - int nfs_mount_version) | |
189 | -{ | |
190 | - struct pmaplist *pmap; | |
191 | - static struct pmap p = {0, 0, 0, 0}; | |
192 | - | |
193 | - if (version > MAX_NFSPROT) | |
194 | - version = MAX_NFSPROT; | |
195 | - if (!prog) | |
196 | - prog = MOUNTPROG; | |
197 | - p.pm_prog = prog; | |
198 | - p.pm_vers = version; | |
199 | - p.pm_prot = proto; | |
200 | - p.pm_port = port; | |
201 | - | |
202 | - server_addr->sin_port = PMAPPORT; | |
203 | - pmap = pmap_getmaps(server_addr); | |
204 | - | |
205 | - while (pmap) { | |
206 | - if (pmap->pml_map.pm_prog != prog) | |
207 | - goto next; | |
208 | - if (!version && p.pm_vers > pmap->pml_map.pm_vers) | |
209 | - goto next; | |
210 | - if (version > 2 && pmap->pml_map.pm_vers != version) | |
211 | - goto next; | |
212 | - if (version && version <= 2 && pmap->pml_map.pm_vers > 2) | |
213 | - goto next; | |
214 | - if (pmap->pml_map.pm_vers > MAX_NFSPROT || | |
215 | - (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) || | |
216 | - (port && pmap->pml_map.pm_port != port)) | |
217 | - goto next; | |
218 | - memcpy(&p, &pmap->pml_map, sizeof(p)); | |
219 | - next: | |
220 | - pmap = pmap->pml_next; | |
221 | - } | |
222 | - if (!p.pm_vers) | |
223 | - p.pm_vers = MOUNTVERS; | |
224 | - if (!p.pm_prot) | |
225 | - p.pm_prot = IPPROTO_TCP; | |
226 | -#if 0 | |
227 | - if (!p.pm_port) { | |
228 | - p.pm_port = pmap_getport(server_addr, p.pm_prog, p.pm_vers, | |
229 | - p.pm_prot); | |
230 | + if (mnt_version > NFS_MOUNT_VERSION) | |
231 | + mnt_version = NFS_MOUNT_VERSION; | |
232 | + return mnt_version; | |
233 | +} | |
234 | + | |
235 | +static int | |
236 | +nfs_gethostbyname(const char *hostname, struct sockaddr_in *saddr) | |
237 | +{ | |
238 | + struct hostent *hp; | |
239 | + | |
240 | + saddr->sin_family = AF_INET; | |
241 | + if (!inet_aton(hostname, &saddr->sin_addr)) { | |
242 | + if ((hp = gethostbyname(hostname)) == NULL) { | |
243 | + fprintf(stderr, _("mount: can't get address for %s\n"), | |
244 | + hostname); | |
245 | + return 0; | |
246 | + } else { | |
247 | + if (hp->h_length > sizeof(*saddr)) { | |
248 | + fprintf(stderr, | |
249 | + _("mount: got bad hp->h_length\n")); | |
250 | + hp->h_length = sizeof(*saddr); | |
251 | + } | |
252 | + memcpy(&saddr->sin_addr, hp->h_addr, hp->h_length); | |
253 | + } | |
254 | + } | |
255 | + return 1; | |
256 | +} | |
257 | + | |
258 | +/* | |
259 | + * Sigh... pmap_getport() doesn't actually check the version number. | |
260 | + * In order to make sure that the server actually supports the service | |
261 | + * we're requesting, we open and RPC client, and fire off a NULL | |
262 | + * RPC call. | |
263 | + */ | |
264 | +static int | |
265 | +clnt_ping(struct sockaddr_in *saddr, const u_long prog, const u_long vers, | |
266 | + const u_int prot) | |
267 | +{ | |
268 | + CLIENT *clnt; | |
269 | + int sock, stat; | |
270 | + static char clnt_res; | |
271 | + | |
272 | + sock = RPC_ANYSOCK; | |
273 | + switch(prot) { | |
274 | + case IPPROTO_UDP: | |
275 | + clnt = clntudp_bufcreate(saddr, prog, vers, | |
276 | + RETRY_TIMEOUT, &sock, | |
277 | + RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); | |
278 | + break; | |
279 | + case IPPROTO_TCP: | |
280 | + clnt = clnttcp_create(saddr, prog, vers, &sock, | |
281 | + RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); | |
282 | + break; | |
283 | + default: | |
284 | + goto out_bad; | |
285 | + } | |
286 | + if (!clnt) | |
287 | + goto out_bad; | |
288 | + memset(&clnt_res, 0, sizeof(clnt_res)); | |
289 | + stat = clnt_call(clnt, NULLPROC, | |
290 | + (xdrproc_t)xdr_void, (caddr_t)NULL, | |
291 | + (xdrproc_t)xdr_void, (caddr_t)&clnt_res, | |
292 | + TIMEOUT); | |
293 | + clnt_destroy(clnt); | |
294 | + close(sock); | |
295 | + if (stat != RPC_PROGVERSMISMATCH) | |
296 | + return 1; | |
297 | + out_bad: | |
298 | + return 0; | |
299 | +} | |
300 | + | |
301 | +/* | |
302 | + * Use the portmapper to discover whether or not the service we want is | |
303 | + * available. The lists 'versions' and 'protos' define ordered sequences | |
304 | + * of service versions and udp/tcp protocols to probe for. | |
305 | + */ | |
306 | +static int | |
307 | +probe_port(clnt_addr_t *server, | |
308 | + const u_long *versions, | |
309 | + const u_int *protos) | |
310 | +{ | |
311 | + struct sockaddr_in *saddr = &server->saddr; | |
312 | + struct pmap *pmap = &server->pmap; | |
313 | + const u_long prog = pmap->pm_prog, | |
314 | + vers = pmap->pm_vers, | |
315 | + *p_vers; | |
316 | + const u_int prot = (u_int)pmap->pm_prot, | |
317 | + *p_prot; | |
318 | + const u_short port = (u_short) pmap->pm_port; | |
319 | + u_short p_port; | |
320 | + | |
321 | + p_prot = prot ? &prot : protos; | |
322 | + p_vers = vers ? &vers : versions; | |
323 | + for (;;) { | |
324 | + saddr->sin_port = htons(PMAPPORT); | |
325 | + p_port = pmap_getport(saddr, prog, *p_vers, *p_prot); | |
326 | + if (p_port) { | |
327 | + if (!port || port == p_port) { | |
328 | + saddr->sin_port = htons(port); | |
329 | + if (clnt_ping(saddr, prog, *p_vers, *p_prot)) | |
330 | + goto out_ok; | |
331 | + } | |
332 | + } else if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED) | |
333 | + break; | |
334 | + if (!prot) { | |
335 | + if (*++p_prot) | |
336 | + continue; | |
337 | + p_prot = protos; | |
338 | + } | |
339 | + if (vers || !*++p_vers) | |
340 | + break; | |
341 | + } | |
342 | + return 0; | |
343 | + out_ok: | |
344 | + if (!vers) | |
345 | + pmap->pm_vers = *p_vers; | |
346 | + if (!prot) | |
347 | + pmap->pm_prot = *p_prot; | |
348 | + if (!port) | |
349 | + pmap->pm_port = p_port; | |
350 | + return 1; | |
351 | +} | |
352 | + | |
353 | +static int | |
354 | +probe_nfsport(clnt_addr_t *nfs_server) | |
355 | +{ | |
356 | + const struct pmap *pmap = &nfs_server->pmap; | |
357 | + const u_long *probe_vers; | |
358 | + const u_int *probe_prot; | |
359 | + | |
360 | + if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port) | |
361 | + return 1; | |
362 | + probe_vers = nfs_probelist(MAX_NFSPROT); | |
363 | + probe_prot = proto_probelist(HAVE_RELIABLE_TCP); | |
364 | + return probe_port(nfs_server, probe_vers, probe_prot); | |
365 | +} | |
366 | + | |
367 | +static int | |
368 | +probe_mntport(clnt_addr_t *mnt_server) | |
369 | +{ | |
370 | + const struct pmap *pmap = &mnt_server->pmap; | |
371 | + const u_long *probe_vers; | |
372 | + const u_int *probe_prot; | |
373 | + | |
374 | + if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port) | |
375 | + return 1; | |
376 | + probe_vers = mnt_probelist(MAX_MNTPROT); | |
377 | + probe_prot = proto_probelist(HAVE_RELIABLE_TCP); | |
378 | + return probe_port(mnt_server, probe_vers, probe_prot); | |
379 | +} | |
380 | + | |
381 | +static int | |
382 | +probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server) | |
383 | +{ | |
384 | + struct pmap *nfs_pmap = &nfs_server->pmap; | |
385 | + struct pmap *mnt_pmap = &mnt_server->pmap; | |
386 | + struct pmap save_nfs, save_mnt; | |
387 | + int res; | |
388 | + const u_long *probe_vers; | |
389 | + | |
390 | + if (mnt_pmap->pm_vers && !nfs_pmap->pm_vers) | |
391 | + nfs_pmap->pm_vers = mntvers_to_nfs(mnt_pmap->pm_vers); | |
392 | + else if (nfs_pmap->pm_vers && !mnt_pmap->pm_vers) | |
393 | + mnt_pmap->pm_vers = nfsvers_to_mnt(nfs_pmap->pm_vers); | |
394 | + if (nfs_pmap->pm_vers) | |
395 | + goto version_fixed; | |
396 | + memcpy(&save_nfs, nfs_pmap, sizeof(save_nfs)); | |
397 | + memcpy(&save_mnt, mnt_pmap, sizeof(save_mnt)); | |
398 | + for (probe_vers = mnt_probelist(MAX_MNTPROT); *probe_vers; probe_vers++) { | |
399 | + nfs_pmap->pm_vers = mntvers_to_nfs(*probe_vers); | |
400 | + if ((res = probe_nfsport(nfs_server) != 0)) { | |
401 | + mnt_pmap->pm_vers = *probe_vers; | |
402 | + if ((res = probe_mntport(mnt_server)) != 0) | |
403 | + return 1; | |
404 | + memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap)); | |
405 | + } | |
406 | + memcpy(nfs_pmap, &save_nfs, sizeof(*nfs_pmap)); | |
407 | } | |
408 | + out_bad: | |
409 | + return 0; | |
410 | + version_fixed: | |
411 | + if (!probe_nfsport(nfs_server)) | |
412 | + goto out_bad; | |
413 | + return probe_mntport(mnt_server); | |
414 | +} | |
415 | + | |
416 | +static CLIENT * | |
417 | +mnt_openclnt(clnt_addr_t *mnt_server, int *msock, const int report_errs) | |
418 | +{ | |
419 | + struct sockaddr_in *mnt_saddr = &mnt_server->saddr; | |
420 | + struct pmap *mnt_pmap = &mnt_server->pmap; | |
421 | + CLIENT *clnt; | |
422 | + | |
423 | + /* contact the mount daemon via TCP */ | |
424 | + mnt_saddr->sin_port = htons((u_short)mnt_pmap->pm_port); | |
425 | + *msock = RPC_ANYSOCK; | |
426 | + | |
427 | + switch (mnt_pmap->pm_prot) { | |
428 | + case IPPROTO_UDP: | |
429 | + clnt = clntudp_bufcreate(mnt_saddr, | |
430 | + mnt_pmap->pm_prog, mnt_pmap->pm_vers, | |
431 | + RETRY_TIMEOUT, msock, | |
432 | + MNT_SENDBUFSIZE, MNT_RECVBUFSIZE); | |
433 | + break; | |
434 | + case IPPROTO_TCP: | |
435 | + clnt = clnttcp_create(mnt_saddr, | |
436 | + mnt_pmap->pm_prog, mnt_pmap->pm_vers, | |
437 | + msock, | |
438 | + MNT_SENDBUFSIZE, MNT_RECVBUFSIZE); | |
439 | + break; | |
440 | + default: | |
441 | + goto out_bad; | |
442 | + } | |
443 | + if (!clnt) | |
444 | + goto report_err; | |
445 | + /* try to mount hostname:dirname */ | |
446 | + clnt->cl_auth = authunix_create_default(); | |
447 | + return clnt; | |
448 | + report_err: | |
449 | + if (report_errs) | |
450 | + clnt_pcreateerror("mount"); | |
451 | + out_bad: | |
452 | + return NULL; | |
453 | +} | |
454 | + | |
455 | +static inline void | |
456 | +mnt_closeclnt(CLIENT *clnt, int msock) | |
457 | +{ | |
458 | + auth_destroy(clnt->cl_auth); | |
459 | + clnt_destroy(clnt); | |
460 | + close(msock); | |
461 | +} | |
462 | + | |
463 | +static inline enum clnt_stat | |
464 | +nfs3_mount(CLIENT *clnt, mnt3arg_t *mnt3arg, mnt3res_t *mnt3res) | |
465 | +{ | |
466 | + return clnt_call(clnt, MOUNTPROC3_MNT, | |
467 | + (xdrproc_t) xdr_dirpath, (caddr_t) mnt3arg, | |
468 | + (xdrproc_t) xdr_mountres3, (caddr_t) mnt3res, | |
469 | + TIMEOUT); | |
470 | +} | |
471 | + | |
472 | +static inline enum clnt_stat | |
473 | +nfs2_mount(CLIENT *clnt, mnt2arg_t *mnt2arg, mnt2res_t *mnt2res) | |
474 | +{ | |
475 | + return clnt_call(clnt, MOUNTPROC_MNT, | |
476 | + (xdrproc_t) xdr_dirpath, (caddr_t) mnt2arg, | |
477 | + (xdrproc_t) xdr_fhstatus, (caddr_t) mnt2res, | |
478 | + TIMEOUT); | |
479 | +} | |
480 | + | |
481 | +static int | |
482 | +nfs_call_mount(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server, | |
483 | + mntarg_t *mntarg, mntres_t *mntres, const int report_errs) | |
484 | +{ | |
485 | + CLIENT *clnt; | |
486 | + enum clnt_stat stat; | |
487 | + int msock; | |
488 | + | |
489 | + | |
490 | + if (!probe_bothports(mnt_server, nfs_server)) { | |
491 | + if (report_errs) | |
492 | + fprintf(stderr,_("mount: failed to probe ports on NFS server %s\n"), | |
493 | + *nfs_server->hostname); | |
494 | + goto out_bad; | |
495 | + } | |
496 | + | |
497 | + clnt = mnt_openclnt(mnt_server, &msock, report_errs); | |
498 | + if (!clnt) | |
499 | + goto out_bad; | |
500 | + /* make pointers in xdr_mountres3 NULL so | |
501 | + * that xdr_array allocates memory for us | |
502 | + */ | |
503 | + memset(mntres, 0, sizeof(*mntres)); | |
504 | + switch (mnt_server->pmap.pm_vers) { | |
505 | + case 3: | |
506 | + stat = nfs3_mount(clnt, mntarg, &mntres->nfsv3); | |
507 | + break; | |
508 | + case 2: | |
509 | + case 1: | |
510 | + stat = nfs2_mount(clnt, mntarg, &mntres->nfsv2); | |
511 | + break; | |
512 | + default: | |
513 | + goto out_bad; | |
514 | + } | |
515 | + if (stat != RPC_SUCCESS && report_errs) | |
516 | + clnt_perror(clnt, "mount"); | |
517 | + mnt_closeclnt(clnt, msock); | |
518 | + if (stat == RPC_SUCCESS) | |
519 | + return 1; | |
520 | + out_bad: | |
521 | + return 0; | |
522 | +} | |
523 | + | |
524 | +static int | |
525 | +parse_options(char *old_opts, struct nfs_mount_data *data, | |
526 | + int *bg, int *retry, clnt_addr_t *mnt_server, | |
527 | + clnt_addr_t *nfs_server, char *new_opts, const int opt_size) | |
528 | +{ | |
529 | + struct sockaddr_in *mnt_saddr = &mnt_server->saddr; | |
530 | + struct pmap *mnt_pmap = &mnt_server->pmap; | |
531 | + struct pmap *nfs_pmap = &nfs_server->pmap; | |
532 | + int len; | |
533 | + char *opt, *opteq; | |
534 | + char *mounthost = NULL; | |
535 | + char cbuf[128]; | |
536 | + | |
537 | + data->flags = 0; | |
538 | + *bg = 0; | |
539 | + | |
540 | + len = strlen(new_opts); | |
541 | + for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) { | |
542 | + if (strlen(opt) >= sizeof(cbuf)) | |
543 | + goto bad_parameter; | |
544 | + if ((opteq = strchr(opt, '=')) && isdigit(opteq[1])) { | |
545 | + int val = atoi(opteq + 1); | |
546 | + *opteq = '\0'; | |
547 | + if (!strcmp(opt, "rsize")) | |
548 | + data->rsize = val; | |
549 | + else if (!strcmp(opt, "wsize")) | |
550 | + data->wsize = val; | |
551 | + else if (!strcmp(opt, "timeo")) | |
552 | + data->timeo = val; | |
553 | + else if (!strcmp(opt, "retrans")) | |
554 | + data->retrans = val; | |
555 | + else if (!strcmp(opt, "acregmin")) | |
556 | + data->acregmin = val; | |
557 | + else if (!strcmp(opt, "acregmax")) | |
558 | + data->acregmax = val; | |
559 | + else if (!strcmp(opt, "acdirmin")) | |
560 | + data->acdirmin = val; | |
561 | + else if (!strcmp(opt, "acdirmax")) | |
562 | + data->acdirmax = val; | |
563 | + else if (!strcmp(opt, "actimeo")) { | |
564 | + data->acregmin = val; | |
565 | + data->acregmax = val; | |
566 | + data->acdirmin = val; | |
567 | + data->acdirmax = val; | |
568 | + } | |
569 | + else if (!strcmp(opt, "retry")) | |
570 | + *retry = val; | |
571 | + else if (!strcmp(opt, "port")) | |
572 | + nfs_pmap->pm_port = val; | |
573 | + else if (!strcmp(opt, "mountport")) | |
574 | + mnt_pmap->pm_port = val; | |
575 | + else if (!strcmp(opt, "mountprog")) | |
576 | + mnt_pmap->pm_prog = val; | |
577 | + else if (!strcmp(opt, "mountvers")) | |
578 | + mnt_pmap->pm_vers = val; | |
579 | + else if (!strcmp(opt, "nfsprog")) | |
580 | + nfs_pmap->pm_prog = val; | |
581 | + else if (!strcmp(opt, "nfsvers") || | |
582 | + !strcmp(opt, "vers")) { | |
583 | + nfs_pmap->pm_vers = val; | |
584 | + opt = "nfsvers"; | |
585 | +#if NFS_MOUNT_VERSION >= 2 | |
586 | + } else if (!strcmp(opt, "namlen")) { | |
587 | + if (nfs_mount_version >= 2) | |
588 | + data->namlen = val; | |
589 | + else if (!sloppy) | |
590 | + goto bad_parameter; | |
591 | #endif | |
592 | -#if 0 | |
593 | -#define MOUNTPORT 635 | |
594 | - /* HJLu wants to remove all traces of the old default port. | |
595 | - Are there still people running a mount RPC service on this | |
596 | - port without having a portmapper? */ | |
597 | - if (!p.pm_port) | |
598 | - p.pm_port = MOUNTPORT; | |
599 | -#endif | |
600 | - return &p; | |
601 | + } else if (!strcmp(opt, "addr")) { | |
602 | + /* ignore */; | |
603 | + continue; | |
604 | + } else if (!sloppy) | |
605 | + goto bad_parameter; | |
606 | + sprintf(cbuf, "%s=%s,", opt, opteq+1); | |
607 | + } else if (opteq) { | |
608 | + *opteq = '\0'; | |
609 | + if (!strcmp(opt, "proto")) { | |
610 | + if (!strcmp(opteq+1, "udp")) { | |
611 | + nfs_pmap->pm_prot = IPPROTO_UDP; | |
612 | +#if NFS_MOUNT_VERSION >= 2 | |
613 | + data->flags &= ~NFS_MOUNT_TCP; | |
614 | + } else if (!strcmp(opteq+1, "tcp") && | |
615 | + nfs_mount_version >= 2) { | |
616 | + nfs_pmap->pm_prot = IPPROTO_TCP; | |
617 | + data->flags |= NFS_MOUNT_TCP; | |
618 | +#endif | |
619 | + } else if (!sloppy) | |
620 | + goto bad_parameter; | |
621 | + } else if (!strcmp(opt, "mounthost")) | |
622 | + mounthost=xstrndup(opteq+1, | |
623 | + strcspn(opteq+1," \t\n\r,")); | |
624 | + else | |
625 | + goto bad_parameter; | |
626 | + sprintf(cbuf, "%s=%s,", opt, opteq+1); | |
627 | + } else { | |
628 | + int val = 1; | |
629 | + if (!strncmp(opt, "no", 2)) { | |
630 | + val = 0; | |
631 | + opt += 2; | |
632 | + } | |
633 | + if (!strcmp(opt, "bg")) | |
634 | + *bg = val; | |
635 | + else if (!strcmp(opt, "fg")) | |
636 | + *bg = !val; | |
637 | + else if (!strcmp(opt, "soft")) { | |
638 | + data->flags &= ~NFS_MOUNT_SOFT; | |
639 | + if (val) | |
640 | + data->flags |= NFS_MOUNT_SOFT; | |
641 | + } else if (!strcmp(opt, "hard")) { | |
642 | + data->flags &= ~NFS_MOUNT_SOFT; | |
643 | + if (!val) | |
644 | + data->flags |= NFS_MOUNT_SOFT; | |
645 | + } else if (!strcmp(opt, "intr")) { | |
646 | + data->flags &= ~NFS_MOUNT_INTR; | |
647 | + if (val) | |
648 | + data->flags |= NFS_MOUNT_INTR; | |
649 | + } else if (!strcmp(opt, "posix")) { | |
650 | + data->flags &= ~NFS_MOUNT_POSIX; | |
651 | + if (val) | |
652 | + data->flags |= NFS_MOUNT_POSIX; | |
653 | + } else if (!strcmp(opt, "cto")) { | |
654 | + data->flags &= ~NFS_MOUNT_NOCTO; | |
655 | + if (!val) | |
656 | + data->flags |= NFS_MOUNT_NOCTO; | |
657 | + } else if (!strcmp(opt, "ac")) { | |
658 | + data->flags &= ~NFS_MOUNT_NOAC; | |
659 | + if (!val) | |
660 | + data->flags |= NFS_MOUNT_NOAC; | |
661 | +#if NFS_MOUNT_VERSION >= 2 | |
662 | + } else if (!strcmp(opt, "tcp")) { | |
663 | + data->flags &= ~NFS_MOUNT_TCP; | |
664 | + if (val) { | |
665 | + if (nfs_mount_version < 2) | |
666 | + goto bad_option; | |
667 | + nfs_pmap->pm_prot = IPPROTO_TCP; | |
668 | + data->flags |= NFS_MOUNT_TCP; | |
669 | + } else | |
670 | + nfs_pmap->pm_prot = IPPROTO_UDP; | |
671 | + } else if (!strcmp(opt, "udp")) { | |
672 | + data->flags &= ~NFS_MOUNT_TCP; | |
673 | + if (!val) { | |
674 | + if (nfs_mount_version < 2) | |
675 | + goto bad_option; | |
676 | + nfs_pmap->pm_prot = IPPROTO_TCP; | |
677 | + data->flags |= NFS_MOUNT_TCP; | |
678 | + } else | |
679 | + nfs_pmap->pm_prot = IPPROTO_UDP; | |
680 | +#endif | |
681 | +#if NFS_MOUNT_VERSION >= 3 | |
682 | + } else if (!strcmp(opt, "lock")) { | |
683 | + data->flags &= ~NFS_MOUNT_NONLM; | |
684 | + if (!val) { | |
685 | + if (nfs_mount_version < 3) | |
686 | + goto bad_option; | |
687 | + data->flags |= NFS_MOUNT_NONLM; | |
688 | + } | |
689 | +#endif | |
690 | +#if NFS_MOUNT_VERSION >= 4 | |
691 | + } else if (!strcmp(opt, "broken_suid")) { | |
692 | + data->flags &= ~NFS_MOUNT_BROKEN_SUID; | |
693 | + if (val) { | |
694 | + if (nfs_mount_version < 4) | |
695 | + goto bad_option; | |
696 | + data->flags |= NFS_MOUNT_BROKEN_SUID; | |
697 | + } | |
698 | +#endif | |
699 | + } else { | |
700 | + bad_option: | |
701 | + printf(_("Unsupported nfs mount option: " | |
702 | + "%s%s\n"), val ? "" : "no", opt); | |
703 | + goto out_bad; | |
704 | + } | |
705 | + sprintf(cbuf, val ? "%s,":"no%s,", opt); | |
706 | + } | |
707 | + len += strlen(cbuf); | |
708 | + if (len >= opt_size) { | |
709 | + printf(_("mount: excessively long option argument\n")); | |
710 | + goto out_bad; | |
711 | + } | |
712 | + strcat(new_opts, cbuf); | |
713 | + } | |
714 | + /* See if the nfs host = mount host. */ | |
715 | + if (mounthost) { | |
716 | + if (!nfs_gethostbyname(mounthost, mnt_saddr)) | |
717 | + goto out_bad; | |
718 | + *mnt_server->hostname = mounthost; | |
719 | + } | |
720 | + return 1; | |
721 | + bad_parameter: | |
722 | + printf(_("Bad nfs mount parameter: %s\n"), opt); | |
723 | + out_bad: | |
724 | + return 0; | |
725 | +} | |
726 | + | |
727 | +static inline int | |
728 | +nfsmnt_check_compat(const struct pmap *nfs_pmap, const struct pmap *mnt_pmap) | |
729 | +{ | |
730 | + if (nfs_pmap->pm_vers > MAX_NFSPROT) { | |
731 | + fprintf(stderr, _("NFSv%ld not supported!\n"), nfs_pmap->pm_vers); | |
732 | + goto out_bad; | |
733 | + } | |
734 | + if (mnt_pmap->pm_vers > MAX_MNTPROT) { | |
735 | + fprintf(stderr, _("NFS mount v%ld not supported!\n"), mnt_pmap->pm_vers); | |
736 | + goto out_bad; | |
737 | + } | |
738 | + return 1; | |
739 | + out_bad: | |
740 | + return 0; | |
741 | } | |
742 | ||
743 | -int nfsmount(const char *spec, const char *node, int *flags, | |
744 | - char **extra_opts, char **mount_opts, int *nfs_mount_vers, | |
745 | - int running_bg) | |
746 | +int | |
747 | +nfsmount(const char *spec, const char *node, int *flags, | |
748 | + char **extra_opts, char **mount_opts, int *nfs_mount_vers, | |
749 | + int running_bg) | |
750 | { | |
751 | static char *prev_bg_host; | |
752 | char hostdir[1024]; | |
753 | - CLIENT *mclient; | |
754 | char *hostname, *dirname, *old_opts, *mounthost = NULL; | |
755 | - char new_opts[1024]; | |
756 | - struct timeval total_timeout; | |
757 | - enum clnt_stat clnt_stat; | |
758 | + char new_opts[1024], cbuf[20]; | |
759 | static struct nfs_mount_data data; | |
760 | - char *opt, *opteq; | |
761 | - int nfs_mount_version; | |
762 | int val; | |
763 | - struct hostent *hp; | |
764 | - struct sockaddr_in server_addr; | |
765 | - struct sockaddr_in mount_server_addr; | |
766 | - struct pmap *pm_mnt; | |
767 | - int msock, fsock; | |
768 | - struct timeval retry_timeout; | |
769 | - union { | |
770 | - struct fhstatus nfsv2; | |
771 | - struct mountres3 nfsv3; | |
772 | - } status; | |
773 | + | |
774 | + clnt_addr_t mnt_server = { &mounthost, }; | |
775 | + clnt_addr_t nfs_server = { &hostname, }; | |
776 | + struct sockaddr_in *nfs_saddr = &nfs_server.saddr; | |
777 | + struct pmap *mnt_pmap = &mnt_server.pmap, | |
778 | + *nfs_pmap = &nfs_server.pmap; | |
779 | + struct pmap save_mnt, save_nfs; | |
780 | + | |
781 | + int fsock; | |
782 | + | |
783 | + mntres_t mntres; | |
784 | + | |
785 | struct stat statbuf; | |
786 | - char *s; | |
787 | - int port, mountport, proto, bg, soft, intr; | |
788 | - int posix, nocto, noac, nolock, broken_suid; | |
789 | - int retry, tcp; | |
790 | - int mountprog, mountvers, nfsprog, nfsvers; | |
791 | + char *s, *p; | |
792 | + int bg, retry; | |
793 | int retval; | |
794 | time_t t; | |
795 | time_t prevt; | |
796 | @@ -231,8 +756,7 @@ int nfsmount(const char *spec, const cha | |
797 | nfs_mount_version = *nfs_mount_vers; | |
798 | ||
799 | retval = EX_FAIL; | |
800 | - msock = fsock = -1; | |
801 | - mclient = NULL; | |
802 | + fsock = -1; | |
803 | if (strlen(spec) >= sizeof(hostdir)) { | |
804 | fprintf(stderr, _("mount: " | |
805 | "excessively long host:dir argument\n")); | |
806 | @@ -258,49 +782,23 @@ int nfsmount(const char *spec, const cha | |
807 | goto fail; | |
808 | } | |
809 | ||
810 | - server_addr.sin_family = AF_INET; | |
811 | -#ifdef HAVE_inet_aton | |
812 | - if (!inet_aton(hostname, &server_addr.sin_addr)) | |
813 | -#endif | |
814 | - { | |
815 | - if ((hp = gethostbyname(hostname)) == NULL) { | |
816 | - fprintf(stderr, _("mount: can't get address for %s\n"), | |
817 | - hostname); | |
818 | - goto fail; | |
819 | - } else { | |
820 | - if (hp->h_length > sizeof(struct in_addr)) { | |
821 | - fprintf(stderr, | |
822 | - _("mount: got bad hp->h_length\n")); | |
823 | - hp->h_length = sizeof(struct in_addr); | |
824 | - } | |
825 | - memcpy(&server_addr.sin_addr, | |
826 | - hp->h_addr, hp->h_length); | |
827 | - } | |
828 | - } | |
829 | - | |
830 | - memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr)); | |
831 | + if (!nfs_gethostbyname(hostname, nfs_saddr)) | |
832 | + goto fail; | |
833 | + mounthost = hostname; | |
834 | + memcpy (&mnt_server.saddr, nfs_saddr, sizeof (mnt_server.saddr)); | |
835 | ||
836 | /* add IP address to mtab options for use when unmounting */ | |
837 | ||
838 | - s = inet_ntoa(server_addr.sin_addr); | |
839 | + s = inet_ntoa(nfs_saddr->sin_addr); | |
840 | old_opts = *extra_opts; | |
841 | if (!old_opts) | |
842 | old_opts = ""; | |
843 | - if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) { | |
844 | - fprintf(stderr, _("mount: " | |
845 | - "excessively long option argument\n")); | |
846 | - goto fail; | |
847 | - } | |
848 | - sprintf(new_opts, "%s%saddr=%s", | |
849 | - old_opts, *old_opts ? "," : "", s); | |
850 | - *extra_opts = xstrdup(new_opts); | |
851 | ||
852 | /* Set default options. | |
853 | * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to | |
854 | * let the kernel decide. | |
855 | * timeo is filled in after we know whether it'll be TCP or UDP. */ | |
856 | memset(&data, 0, sizeof(data)); | |
857 | - data.retrans = 3; | |
858 | data.acregmin = 3; | |
859 | data.acregmax = 60; | |
860 | data.acdirmin = 30; | |
861 | @@ -310,167 +808,21 @@ int nfsmount(const char *spec, const cha | |
862 | #endif | |
863 | ||
864 | bg = 0; | |
865 | - soft = 0; | |
866 | - intr = 0; | |
867 | - posix = 0; | |
868 | - nocto = 0; | |
869 | - nolock = 0; | |
870 | - broken_suid = 0; | |
871 | - noac = 0; | |
872 | retry = 10000; /* 10000 minutes ~ 1 week */ | |
873 | - tcp = 0; | |
874 | ||
875 | - mountprog = MOUNTPROG; | |
876 | - mountvers = 0; | |
877 | - port = 0; | |
878 | - mountport = 0; | |
879 | - nfsprog = NFS_PROGRAM; | |
880 | - nfsvers = 0; | |
881 | + memset(mnt_pmap, 0, sizeof(*mnt_pmap)); | |
882 | + mnt_pmap->pm_prog = MOUNTPROG; | |
883 | + memset(nfs_pmap, 0, sizeof(*nfs_pmap)); | |
884 | + nfs_pmap->pm_prog = NFS_PROGRAM; | |
885 | ||
886 | /* parse options */ | |
887 | + new_opts[0] = 0; | |
888 | + if (!parse_options(old_opts, &data, &bg, &retry, &mnt_server, &nfs_server, | |
889 | + new_opts, sizeof(new_opts))) | |
890 | + goto fail; | |
891 | + if (!nfsmnt_check_compat(nfs_pmap, mnt_pmap)) | |
892 | + goto fail; | |
893 | ||
894 | - for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) { | |
895 | - if ((opteq = strchr(opt, '='))) { | |
896 | - val = atoi(opteq + 1); | |
897 | - *opteq = '\0'; | |
898 | - if (!strcmp(opt, "rsize")) | |
899 | - data.rsize = val; | |
900 | - else if (!strcmp(opt, "wsize")) | |
901 | - data.wsize = val; | |
902 | - else if (!strcmp(opt, "timeo")) | |
903 | - data.timeo = val; | |
904 | - else if (!strcmp(opt, "retrans")) | |
905 | - data.retrans = val; | |
906 | - else if (!strcmp(opt, "acregmin")) | |
907 | - data.acregmin = val; | |
908 | - else if (!strcmp(opt, "acregmax")) | |
909 | - data.acregmax = val; | |
910 | - else if (!strcmp(opt, "acdirmin")) | |
911 | - data.acdirmin = val; | |
912 | - else if (!strcmp(opt, "acdirmax")) | |
913 | - data.acdirmax = val; | |
914 | - else if (!strcmp(opt, "actimeo")) { | |
915 | - data.acregmin = val; | |
916 | - data.acregmax = val; | |
917 | - data.acdirmin = val; | |
918 | - data.acdirmax = val; | |
919 | - } | |
920 | - else if (!strcmp(opt, "retry")) | |
921 | - retry = val; | |
922 | - else if (!strcmp(opt, "port")) | |
923 | - port = val; | |
924 | - else if (!strcmp(opt, "mountport")) | |
925 | - mountport = val; | |
926 | - else if (!strcmp(opt, "mounthost")) | |
927 | - mounthost=xstrndup(opteq+1, | |
928 | - strcspn(opteq+1," \t\n\r,")); | |
929 | - else if (!strcmp(opt, "mountprog")) | |
930 | - mountprog = val; | |
931 | - else if (!strcmp(opt, "mountvers")) | |
932 | - mountvers = val; | |
933 | - else if (!strcmp(opt, "nfsprog")) | |
934 | - nfsprog = val; | |
935 | - else if (!strcmp(opt, "nfsvers") || | |
936 | - !strcmp(opt, "vers")) | |
937 | - nfsvers = val; | |
938 | - else if (!strcmp(opt, "proto")) { | |
939 | - if (!strncmp(opteq+1, "tcp", 3)) | |
940 | - tcp = 1; | |
941 | - else if (!strncmp(opteq+1, "udp", 3)) | |
942 | - tcp = 0; | |
943 | - else | |
944 | - printf(_("Warning: Unrecognized proto= option.\n")); | |
945 | - } else if (!strcmp(opt, "namlen")) { | |
946 | -#if NFS_MOUNT_VERSION >= 2 | |
947 | - if (nfs_mount_version >= 2) | |
948 | - data.namlen = val; | |
949 | - else | |
950 | -#endif | |
951 | - printf(_("Warning: Option namlen is not supported.\n")); | |
952 | - } else if (!strcmp(opt, "addr")) { | |
953 | - /* ignore */; | |
954 | - } else { | |
955 | - printf(_("unknown nfs mount parameter: " | |
956 | - "%s=%d\n"), opt, val); | |
957 | - goto fail; | |
958 | - } | |
959 | - } else { | |
960 | - val = 1; | |
961 | - if (!strncmp(opt, "no", 2)) { | |
962 | - val = 0; | |
963 | - opt += 2; | |
964 | - } | |
965 | - if (!strcmp(opt, "bg")) | |
966 | - bg = val; | |
967 | - else if (!strcmp(opt, "fg")) | |
968 | - bg = !val; | |
969 | - else if (!strcmp(opt, "soft")) | |
970 | - soft = val; | |
971 | - else if (!strcmp(opt, "hard")) | |
972 | - soft = !val; | |
973 | - else if (!strcmp(opt, "intr")) | |
974 | - intr = val; | |
975 | - else if (!strcmp(opt, "posix")) | |
976 | - posix = val; | |
977 | - else if (!strcmp(opt, "cto")) | |
978 | - nocto = !val; | |
979 | - else if (!strcmp(opt, "ac")) | |
980 | - noac = !val; | |
981 | - else if (!strcmp(opt, "tcp")) | |
982 | - tcp = val; | |
983 | - else if (!strcmp(opt, "udp")) | |
984 | - tcp = !val; | |
985 | - else if (!strcmp(opt, "lock")) { | |
986 | - if (nfs_mount_version >= 3) | |
987 | - nolock = !val; | |
988 | - else | |
989 | - printf(_("Warning: option nolock is not supported.\n")); | |
990 | - } else if (!strcmp(opt, "broken_suid")) { | |
991 | - broken_suid = val; | |
992 | - } else { | |
993 | - if (!sloppy) { | |
994 | - printf(_("unknown nfs mount option: " | |
995 | - "%s%s\n"), val ? "" : "no", opt); | |
996 | - goto fail; | |
997 | - } | |
998 | - } | |
999 | - } | |
1000 | - } | |
1001 | - proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP; | |
1002 | - | |
1003 | - data.flags = (soft ? NFS_MOUNT_SOFT : 0) | |
1004 | - | (intr ? NFS_MOUNT_INTR : 0) | |
1005 | - | (posix ? NFS_MOUNT_POSIX : 0) | |
1006 | - | (nocto ? NFS_MOUNT_NOCTO : 0) | |
1007 | - | (noac ? NFS_MOUNT_NOAC : 0); | |
1008 | -#if NFS_MOUNT_VERSION >= 2 | |
1009 | - if (nfs_mount_version >= 2) | |
1010 | - data.flags |= (tcp ? NFS_MOUNT_TCP : 0); | |
1011 | -#endif | |
1012 | -#if NFS_MOUNT_VERSION >= 3 | |
1013 | - if (nfs_mount_version >= 3) | |
1014 | - data.flags |= (nolock ? NFS_MOUNT_NONLM : 0); | |
1015 | -#endif | |
1016 | -#if NFS_MOUNT_VERSION >= 4 | |
1017 | - if (nfs_mount_version >= 4) | |
1018 | - data.flags |= (broken_suid ? NFS_MOUNT_BROKEN_SUID : 0); | |
1019 | -#endif | |
1020 | - if (nfsvers > MAX_NFSPROT) { | |
1021 | - fprintf(stderr, "NFSv%d not supported!\n", nfsvers); | |
1022 | - return 0; | |
1023 | - } | |
1024 | - if (mountvers > MAX_NFSPROT) { | |
1025 | - fprintf(stderr, "NFSv%d not supported!\n", nfsvers); | |
1026 | - return 0; | |
1027 | - } | |
1028 | - if (nfsvers && !mountvers) | |
1029 | - mountvers = (nfsvers < 3) ? 1 : nfsvers; | |
1030 | - if (nfsvers && nfsvers < mountvers) | |
1031 | - mountvers = nfsvers; | |
1032 | - | |
1033 | - /* Adjust options if none specified */ | |
1034 | - if (!data.timeo) | |
1035 | - data.timeo = tcp ? 70 : 7; | |
1036 | ||
1037 | #ifdef NFS_MOUNT_DEBUG | |
1038 | printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n", | |
1039 | @@ -478,9 +830,10 @@ int nfsmount(const char *spec, const cha | |
1040 | printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n", | |
1041 | data.acregmin, data.acregmax, data.acdirmin, data.acdirmax); | |
1042 | printf("port = %d, bg = %d, retry = %d, flags = %.8x\n", | |
1043 | - port, bg, retry, data.flags); | |
1044 | + nfs_pmap->pm_port, bg, retry, data.flags); | |
1045 | printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n", | |
1046 | - mountprog, mountvers, nfsprog, nfsvers); | |
1047 | + mnt_pmap->pm_prog, mnt_pmap->pm_vers, | |
1048 | + nfs_pmap->pm_prog, nfs_pmap->pm_vers); | |
1049 | printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n", | |
1050 | (data.flags & NFS_MOUNT_SOFT) != 0, | |
1051 | (data.flags & NFS_MOUNT_INTR) != 0, | |
1052 | @@ -497,7 +850,7 @@ int nfsmount(const char *spec, const cha | |
1053 | *mount_opts = (char *) &data; | |
1054 | ||
1055 | if (*flags & MS_REMOUNT) | |
1056 | - return 0; | |
1057 | + goto out_ok; | |
1058 | ||
1059 | /* | |
1060 | * If the previous mount operation on the same host was | |
1061 | @@ -512,28 +865,6 @@ int nfsmount(const char *spec, const cha | |
1062 | } | |
1063 | ||
1064 | /* create mount deamon client */ | |
1065 | - /* See if the nfs host = mount host. */ | |
1066 | - if (mounthost) { | |
1067 | - if (mounthost[0] >= '0' && mounthost[0] <= '9') { | |
1068 | - mount_server_addr.sin_family = AF_INET; | |
1069 | - mount_server_addr.sin_addr.s_addr = inet_addr(hostname); | |
1070 | - } else { | |
1071 | - if ((hp = gethostbyname(mounthost)) == NULL) { | |
1072 | - fprintf(stderr, _("mount: can't get address for %s\n"), | |
1073 | - mounthost); | |
1074 | - goto fail; | |
1075 | - } else { | |
1076 | - if (hp->h_length > sizeof(struct in_addr)) { | |
1077 | - fprintf(stderr, | |
1078 | - _("mount: got bad hp->h_length?\n")); | |
1079 | - hp->h_length = sizeof(struct in_addr); | |
1080 | - } | |
1081 | - mount_server_addr.sin_family = AF_INET; | |
1082 | - memcpy(&mount_server_addr.sin_addr, | |
1083 | - hp->h_addr, hp->h_length); | |
1084 | - } | |
1085 | - } | |
1086 | - } | |
1087 | ||
1088 | /* | |
1089 | * The following loop implements the mount retries. On the first | |
1090 | @@ -551,15 +882,13 @@ int nfsmount(const char *spec, const cha | |
1091 | * | |
1092 | * Only the first error message will be displayed. | |
1093 | */ | |
1094 | - retry_timeout.tv_sec = 3; | |
1095 | - retry_timeout.tv_usec = 0; | |
1096 | - total_timeout.tv_sec = 20; | |
1097 | - total_timeout.tv_usec = 0; | |
1098 | timeout = time(NULL) + 60 * retry; | |
1099 | prevt = 0; | |
1100 | t = 30; | |
1101 | val = 1; | |
1102 | ||
1103 | + memcpy(&save_nfs, nfs_pmap, sizeof(save_nfs)); | |
1104 | + memcpy(&save_mnt, mnt_pmap, sizeof(save_mnt)); | |
1105 | for (;;) { | |
1106 | if (bg && stat(node, &statbuf) == -1) { | |
1107 | /* no mount point yet - sleep */ | |
1108 | @@ -570,89 +899,18 @@ int nfsmount(const char *spec, const cha | |
1109 | val = 30; | |
1110 | } | |
1111 | } else { | |
1112 | + int stat; | |
1113 | /* be careful not to use too many CPU cycles */ | |
1114 | if (t - prevt < 30) | |
1115 | sleep(30); | |
1116 | ||
1117 | - pm_mnt = get_mountport(&mount_server_addr, | |
1118 | - mountprog, | |
1119 | - mountvers, | |
1120 | - proto, | |
1121 | - mountport, | |
1122 | - nfs_mount_version); | |
1123 | - | |
1124 | - /* contact the mount daemon via TCP */ | |
1125 | - mount_server_addr.sin_port = htons(pm_mnt->pm_port); | |
1126 | - msock = RPC_ANYSOCK; | |
1127 | - | |
1128 | - switch (pm_mnt->pm_prot) { | |
1129 | - case IPPROTO_UDP: | |
1130 | - mclient = clntudp_create(&mount_server_addr, | |
1131 | - pm_mnt->pm_prog, | |
1132 | - pm_mnt->pm_vers, | |
1133 | - retry_timeout, | |
1134 | - &msock); | |
1135 | - if (mclient) | |
1136 | - break; | |
1137 | - mount_server_addr.sin_port = | |
1138 | - htons(pm_mnt->pm_port); | |
1139 | - msock = RPC_ANYSOCK; | |
1140 | - case IPPROTO_TCP: | |
1141 | - mclient = clnttcp_create(&mount_server_addr, | |
1142 | - pm_mnt->pm_prog, | |
1143 | - pm_mnt->pm_vers, | |
1144 | - &msock, 0, 0); | |
1145 | + stat = nfs_call_mount(&mnt_server, &nfs_server, | |
1146 | + &dirname, &mntres, | |
1147 | + !running_bg && prevt == 0); | |
1148 | + if (stat) | |
1149 | break; | |
1150 | - default: | |
1151 | - mclient = 0; | |
1152 | - } | |
1153 | - | |
1154 | - if (mclient) { | |
1155 | - /* try to mount hostname:dirname */ | |
1156 | - mclient->cl_auth = authunix_create_default(); | |
1157 | - | |
1158 | - /* make pointers in xdr_mountres3 NULL so | |
1159 | - * that xdr_array allocates memory for us | |
1160 | - */ | |
1161 | - memset(&status, 0, sizeof(status)); | |
1162 | - | |
1163 | - if (pm_mnt->pm_vers == 3) | |
1164 | - clnt_stat = clnt_call(mclient, | |
1165 | - MOUNTPROC3_MNT, | |
1166 | - (xdrproc_t) xdr_dirpath, | |
1167 | - (caddr_t) &dirname, | |
1168 | - (xdrproc_t) xdr_mountres3, | |
1169 | - (caddr_t) &status, | |
1170 | - total_timeout); | |
1171 | - else | |
1172 | - clnt_stat = clnt_call(mclient, | |
1173 | - MOUNTPROC_MNT, | |
1174 | - (xdrproc_t) xdr_dirpath, | |
1175 | - (caddr_t) &dirname, | |
1176 | - (xdrproc_t) xdr_fhstatus, | |
1177 | - (caddr_t) &status, | |
1178 | - total_timeout); | |
1179 | - | |
1180 | - if (clnt_stat == RPC_SUCCESS) | |
1181 | - break; /* we're done */ | |
1182 | -#if 0 | |
1183 | - /* errno? who sets errno? */ | |
1184 | - /* this fragment breaks bg mounting */ | |
1185 | - if (errno != ECONNREFUSED) { | |
1186 | - clnt_perror(mclient, "mount"); | |
1187 | - goto fail; /* don't retry */ | |
1188 | - } | |
1189 | -#endif | |
1190 | - if (!running_bg && prevt == 0) | |
1191 | - clnt_perror(mclient, "mount"); | |
1192 | - auth_destroy(mclient->cl_auth); | |
1193 | - clnt_destroy(mclient); | |
1194 | - mclient = 0; | |
1195 | - close(msock); | |
1196 | - } else { | |
1197 | - if (!running_bg && prevt == 0) | |
1198 | - clnt_pcreateerror("mount"); | |
1199 | - } | |
1200 | + memcpy(nfs_pmap, &save_nfs, sizeof(*nfs_pmap)); | |
1201 | + memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap)); | |
1202 | prevt = t; | |
1203 | } | |
1204 | ||
1205 | @@ -668,36 +926,35 @@ int nfsmount(const char *spec, const cha | |
1206 | if (t >= timeout) | |
1207 | goto fail; | |
1208 | } | |
1209 | - nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers; | |
1210 | ||
1211 | - if (nfsvers == 2) { | |
1212 | - if (status.nfsv2.fhs_status != 0) { | |
1213 | + if (nfs_pmap->pm_vers == 2) { | |
1214 | + if (mntres.nfsv2.fhs_status != 0) { | |
1215 | fprintf(stderr, | |
1216 | - "mount: %s:%s failed, reason given by server: %s\n", | |
1217 | + _("mount: %s:%s failed, reason given by server: %s\n"), | |
1218 | hostname, dirname, | |
1219 | - nfs_strerror(status.nfsv2.fhs_status)); | |
1220 | + nfs_strerror(mntres.nfsv2.fhs_status)); | |
1221 | goto fail; | |
1222 | } | |
1223 | memcpy(data.root.data, | |
1224 | - (char *) status.nfsv2.fhstatus_u.fhs_fhandle, | |
1225 | + (char *) mntres.nfsv2.fhstatus_u.fhs_fhandle, | |
1226 | NFS_FHSIZE); | |
1227 | #if NFS_MOUNT_VERSION >= 4 | |
1228 | data.root.size = NFS_FHSIZE; | |
1229 | memcpy(data.old_root.data, | |
1230 | - (char *) status.nfsv2.fhstatus_u.fhs_fhandle, | |
1231 | + (char *) mntres.nfsv2.fhstatus_u.fhs_fhandle, | |
1232 | NFS_FHSIZE); | |
1233 | #endif | |
1234 | } else { | |
1235 | #if NFS_MOUNT_VERSION >= 4 | |
1236 | fhandle3 *fhandle; | |
1237 | - if (status.nfsv3.fhs_status != 0) { | |
1238 | + if (mntres.nfsv3.fhs_status != 0) { | |
1239 | fprintf(stderr, | |
1240 | - "mount: %s:%s failed, reason given by server: %s\n", | |
1241 | + _("mount: %s:%s failed, reason given by server: %s\n"), | |
1242 | hostname, dirname, | |
1243 | - nfs_strerror(status.nfsv3.fhs_status)); | |
1244 | + nfs_strerror(mntres.nfsv3.fhs_status)); | |
1245 | goto fail; | |
1246 | } | |
1247 | - fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle; | |
1248 | + fhandle = &mntres.nfsv3.mountres3_u.mountinfo.fhandle; | |
1249 | memset(data.old_root.data, 0, NFS_FHSIZE); | |
1250 | memset(&data.root, 0, sizeof(data.root)); | |
1251 | data.root.size = fhandle->fhandle3_len; | |
1252 | @@ -711,13 +968,9 @@ int nfsmount(const char *spec, const cha | |
1253 | ||
1254 | /* create nfs socket for kernel */ | |
1255 | ||
1256 | - if (tcp) { | |
1257 | - if (nfs_mount_version < 3) { | |
1258 | - printf(_("NFS over TCP is not supported.\n")); | |
1259 | - goto fail; | |
1260 | - } | |
1261 | + if (nfs_pmap->pm_prot == IPPROTO_TCP) | |
1262 | fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); | |
1263 | - } else | |
1264 | + else | |
1265 | fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); | |
1266 | if (fsock < 0) { | |
1267 | perror(_("nfs socket")); | |
1268 | @@ -727,72 +980,162 @@ int nfsmount(const char *spec, const cha | |
1269 | perror(_("nfs bindresvport")); | |
1270 | goto fail; | |
1271 | } | |
1272 | - if (port == 0) { | |
1273 | - server_addr.sin_port = PMAPPORT; | |
1274 | - port = pmap_getport(&server_addr, nfsprog, nfsvers, | |
1275 | - tcp ? IPPROTO_TCP : IPPROTO_UDP); | |
1276 | -#if 1 | |
1277 | - /* Here we check to see if user is mounting with the | |
1278 | - * tcp option. If so, and if the portmap returns a | |
1279 | - * '0' for port (service unavailable), we then exit, | |
1280 | - * notifying the user, rather than hanging up mount. | |
1281 | - */ | |
1282 | - if (port == 0 && tcp == 1) { | |
1283 | - perror(_("nfs server reported service unavailable")); | |
1284 | - goto fail; | |
1285 | - } | |
1286 | -#endif | |
1287 | - | |
1288 | - if (port == 0) | |
1289 | - port = NFS_PORT; | |
1290 | #ifdef NFS_MOUNT_DEBUG | |
1291 | - else | |
1292 | - printf(_("used portmapper to find NFS port\n")); | |
1293 | + printf(_("using port %d for nfs deamon\n"), nfs_pmap->pm_port); | |
1294 | #endif | |
1295 | - } | |
1296 | -#ifdef NFS_MOUNT_DEBUG | |
1297 | - printf(_("using port %d for nfs deamon\n"), port); | |
1298 | -#endif | |
1299 | - server_addr.sin_port = htons(port); | |
1300 | + nfs_saddr->sin_port = htons(nfs_pmap->pm_port); | |
1301 | /* | |
1302 | * connect() the socket for kernels 1.3.10 and below only, | |
1303 | * to avoid problems with multihomed hosts. | |
1304 | * --Swen | |
1305 | */ | |
1306 | if (linux_version_code() <= 66314 | |
1307 | - && connect(fsock, (struct sockaddr *) &server_addr, | |
1308 | - sizeof (server_addr)) < 0) { | |
1309 | + && connect(fsock, (struct sockaddr *) nfs_saddr, | |
1310 | + sizeof (*nfs_saddr)) < 0) { | |
1311 | perror(_("nfs connect")); | |
1312 | goto fail; | |
1313 | } | |
1314 | ||
1315 | +#if NFS_MOUNT_VERSION >= 2 | |
1316 | + if (nfs_pmap->pm_prot == IPPROTO_TCP) | |
1317 | + data.flags |= NFS_MOUNT_TCP; | |
1318 | + else | |
1319 | + data.flags &= ~NFS_MOUNT_TCP; | |
1320 | +#endif | |
1321 | + | |
1322 | /* prepare data structure for kernel */ | |
1323 | ||
1324 | data.fd = fsock; | |
1325 | - memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr)); | |
1326 | + memcpy((char *) &data.addr, (char *) nfs_saddr, sizeof(data.addr)); | |
1327 | strncpy(data.hostname, hostname, sizeof(data.hostname)); | |
1328 | ||
1329 | - /* clean up */ | |
1330 | + out_ok: | |
1331 | + /* Ensure we have enough padding for the following strcat()s */ | |
1332 | + if (strlen(new_opts) + strlen(s) + 30 >= sizeof(new_opts)) { | |
1333 | + fprintf(stderr, _("mount: " | |
1334 | + "excessively long option argument\n")); | |
1335 | + goto fail; | |
1336 | + } | |
1337 | ||
1338 | - auth_destroy(mclient->cl_auth); | |
1339 | - clnt_destroy(mclient); | |
1340 | - close(msock); | |
1341 | + sprintf(cbuf, "addr=%s", s); | |
1342 | + strcat(new_opts, cbuf); | |
1343 | + | |
1344 | + *extra_opts = xstrdup(new_opts); | |
1345 | return 0; | |
1346 | ||
1347 | /* abort */ | |
1348 | - | |
1349 | fail: | |
1350 | - if (msock != -1) { | |
1351 | - if (mclient) { | |
1352 | - auth_destroy(mclient->cl_auth); | |
1353 | - clnt_destroy(mclient); | |
1354 | - } | |
1355 | - close(msock); | |
1356 | - } | |
1357 | if (fsock != -1) | |
1358 | close(fsock); | |
1359 | return retval; | |
1360 | -} | |
1361 | +} | |
1362 | + | |
1363 | +static inline enum clnt_stat | |
1364 | +nfs3_umount(dirpath *argp, CLIENT *clnt) | |
1365 | +{ | |
1366 | + static char clnt_res; | |
1367 | + memset (&clnt_res, 0, sizeof(clnt_res)); | |
1368 | + return clnt_call(clnt, MOUNTPROC_UMNT, | |
1369 | + (xdrproc_t) xdr_dirpath, (caddr_t)argp, | |
1370 | + (xdrproc_t) xdr_void, (caddr_t) &clnt_res, | |
1371 | + TIMEOUT); | |
1372 | +} | |
1373 | + | |
1374 | +static inline enum clnt_stat | |
1375 | +nfs2_umount(dirpath *argp, CLIENT *clnt) | |
1376 | +{ | |
1377 | + static char clnt_res; | |
1378 | + memset (&clnt_res, 0, sizeof(clnt_res)); | |
1379 | + return clnt_call(clnt, MOUNTPROC_UMNT, | |
1380 | + (xdrproc_t) xdr_dirpath, (caddr_t)argp, | |
1381 | + (xdrproc_t) xdr_void, (caddr_t) &clnt_res, | |
1382 | + TIMEOUT); | |
1383 | +} | |
1384 | + | |
1385 | +static int | |
1386 | +nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp) | |
1387 | +{ | |
1388 | + CLIENT *clnt; | |
1389 | + enum clnt_stat res = 0; | |
1390 | + int msock; | |
1391 | + | |
1392 | + clnt = mnt_openclnt(mnt_server, &msock, 1); | |
1393 | + if (!clnt) | |
1394 | + goto out_bad; | |
1395 | + switch (mnt_server->pmap.pm_vers) { | |
1396 | + case 3: | |
1397 | + res = nfs3_umount(argp, clnt); | |
1398 | + break; | |
1399 | + case 2: | |
1400 | + case 1: | |
1401 | + res = nfs2_umount(argp, clnt); | |
1402 | + break; | |
1403 | + default: | |
1404 | + } | |
1405 | + mnt_closeclnt(clnt, msock); | |
1406 | + if (res == RPC_SUCCESS) | |
1407 | + return 1; | |
1408 | + out_bad: | |
1409 | + return 0; | |
1410 | +} | |
1411 | + | |
1412 | +int | |
1413 | +nfsumount(const char *spec, const char *opts) | |
1414 | +{ | |
1415 | + char *hostname; | |
1416 | + char *dirname; | |
1417 | + clnt_addr_t mnt_server = { &hostname, }; | |
1418 | + struct pmap *pmap = &mnt_server.pmap; | |
1419 | + char *p; | |
1420 | + | |
1421 | + nfs_mount_version = find_kernel_nfs_mount_version(); | |
1422 | + if (spec == NULL || (p = strchr(spec,':')) == NULL) | |
1423 | + goto out_bad; | |
1424 | + hostname = xstrndup(spec, p-spec); | |
1425 | + dirname = xstrdup(p+1); | |
1426 | +#ifdef NFS_MOUNT_DEBUG | |
1427 | + printf(_("host: %s, directory: %s\n"), hostname, dirname); | |
1428 | +#endif | |
1429 | + | |
1430 | + if (opts && (p = strstr(opts, "addr="))) { | |
1431 | + char *q; | |
1432 | + | |
1433 | + free(hostname); | |
1434 | + p += 5; | |
1435 | + q = p; | |
1436 | + while (*q && *q != ',') q++; | |
1437 | + hostname = xstrndup(p,q-p); | |
1438 | + } | |
1439 | + | |
1440 | + if (opts && (p = strstr(opts, "mounthost="))) { | |
1441 | + char *q; | |
1442 | + | |
1443 | + free(hostname); | |
1444 | + p += 10; | |
1445 | + q = p; | |
1446 | + while (*q && *q != ',') q++; | |
1447 | + hostname = xstrndup(p,q-p); | |
1448 | + } | |
1449 | + | |
1450 | + pmap->pm_prog = MOUNTPROG; | |
1451 | + pmap->pm_vers = MOUNTVERS; | |
1452 | + if (opts && (p = strstr(opts, "mountprog=")) && isdigit(*(p+10))) | |
1453 | + pmap->pm_prog = atoi(p+10); | |
1454 | + if (opts && (p = strstr(opts, "mountport=")) && isdigit(*(p+10))) | |
1455 | + pmap->pm_port = atoi(p+10); | |
1456 | + if (opts && (p = strstr(opts, "nfsvers=")) && isdigit(*(p+8))) | |
1457 | + pmap->pm_vers = nfsvers_to_mnt(atoi(p+8)); | |
1458 | + if (opts && (p = strstr(opts, "mountvers=")) && isdigit(*(p+10))) | |
1459 | + pmap->pm_vers = atoi(p+10); | |
1460 | + | |
1461 | + if (!nfs_gethostbyname(hostname, &mnt_server.saddr)) | |
1462 | + goto out_bad; | |
1463 | + if (!probe_mntport(&mnt_server)) | |
1464 | + goto out_bad; | |
1465 | + return nfs_call_umount(&mnt_server, &dirname); | |
1466 | + out_bad: | |
1467 | + return 0; | |
1468 | +} | |
1469 | ||
1470 | /* | |
1471 | * We need to translate between nfs status return values and | |
1472 | diff -puN mount/sundries.h~nfs mount/sundries.h | |
1473 | --- util-linux-2.12/mount/sundries.h~nfs 2004-10-13 13:51:44.000000000 -0400 | |
1474 | +++ util-linux-2.12-bfields/mount/sundries.h 2004-10-13 14:13:30.000000000 -0400 | |
1475 | @@ -37,6 +37,7 @@ void die (int errcode, const char *fmt, | |
1476 | #ifdef HAVE_NFS | |
1477 | int nfsmount (const char *spec, const char *node, int *flags, | |
1478 | char **orig_opts, char **opt_args, int *version, int running_bg); | |
1479 | +int nfsumount(const char *spec, const char *opts); | |
1480 | #endif | |
1481 | ||
1482 | /* exit status - bits below are ORed */ | |
1483 | diff -puN mount/umount.c~nfs mount/umount.c | |
1484 | --- util-linux-2.12/mount/umount.c~nfs 2004-10-13 13:51:44.000000000 -0400 | |
1485 | +++ util-linux-2.12-bfields/mount/umount.c 2004-10-13 14:13:30.000000000 -0400 | |
1486 | @@ -122,7 +122,7 @@ check_special_umountprog() { | |
1487 | } | |
1488 | #endif | |
1489 | ||
1490 | -#ifdef HAVE_NFS | |
1491 | +#if 0 | |
1492 | static int xdr_dir(XDR *xdrsp, char *dirp) | |
1493 | { | |
1494 | return (xdr_string(xdrsp, &dirp, MNTPATHLEN)); | |
1495 | @@ -265,7 +265,7 @@ umount_one (const char *spec, const char | |
1496 | /* Ignore any RPC errors, so that you can umount the filesystem | |
1497 | if the server is down. */ | |
1498 | if (strcasecmp(type, "nfs") == 0) | |
1499 | - nfs_umount_rpc_call(spec, opts); | |
1500 | + nfsumount(spec, opts); | |
1501 | #endif | |
1502 | ||
1503 | umnt_err = umnt_err2 = 0; | |
1504 | _ |