]> git.pld-linux.org Git - packages/util-linux.git/blob - util-linux-2.12-01-nfs.dif
- init var
[packages/util-linux.git] / util-linux-2.12-01-nfs.dif
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 _
This page took 0.310623 seconds and 3 git commands to generate.