]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/mount/network.c
e6511676b0a58cf895c18306464ece1c3792cf54
[nfs-utils.git] / utils / mount / network.c
1 /*
2  * network.c -- Provide common network functions for NFS mount/umount
3  *
4  * Copyright (C) 2007 Oracle.  All rights reserved.
5  * Copyright (C) 2007 Chuck Lever <chuck.lever@oracle.com>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public
18  * License along with this program; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 021110-1307, USA.
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <ctype.h>
29 #include <unistd.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <errno.h>
34 #include <netdb.h>
35 #include <time.h>
36
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <sys/wait.h>
40 #include <netinet/in.h>
41 #include <rpc/rpc.h>
42 #include <rpc/pmap_prot.h>
43 #include <rpc/pmap_clnt.h>
44
45 #include "xcommon.h"
46 #include "mount.h"
47 #include "nls.h"
48 #include "nfs_mount.h"
49 #include "mount_constants.h"
50 #include "nfsrpc.h"
51 #include "parse_opt.h"
52 #include "network.h"
53 #include "conffile.h"
54
55 #define PMAP_TIMEOUT    (10)
56 #define CONNECT_TIMEOUT (20)
57 #define MOUNT_TIMEOUT   (30)
58
59 #if SIZEOF_SOCKLEN_T - 0 == 0
60 #define socklen_t unsigned int
61 #endif
62
63 extern int nfs_mount_data_version;
64 extern char *progname;
65 extern int verbose;
66
67 static const char *nfs_ns_pgmtbl[] = {
68         "status",
69         NULL,
70 };
71
72 static const char *nfs_mnt_pgmtbl[] = {
73         "mount",
74         "mountd",
75         NULL,
76 };
77
78 static const char *nfs_nfs_pgmtbl[] = {
79         "nfs",
80         "nfsprog",
81         NULL,
82 };
83
84 static const char *nfs_transport_opttbl[] = {
85         "udp",
86         "tcp",
87         "proto",
88         NULL,
89 };
90
91 static const char *nfs_version_opttbl[] = {
92         "v2",
93         "v3",
94         "v4",
95         "vers",
96         "nfsvers",
97         NULL,
98 };
99
100 static const unsigned long nfs_to_mnt[] = {
101         0,
102         0,
103         1,
104         3,
105 };
106
107 static const unsigned long mnt_to_nfs[] = {
108         0,
109         2,
110         2,
111         3,
112 };
113
114 /*
115  * Map an NFS version into the corresponding Mountd version
116  */
117 unsigned long nfsvers_to_mnt(const unsigned long vers)
118 {
119         if (vers <= 3)
120                 return nfs_to_mnt[vers];
121         return 0;
122 }
123
124 /*
125  * Map a Mountd version into the corresponding NFS version
126  */
127 static unsigned long mntvers_to_nfs(const unsigned long vers)
128 {
129         if (vers <= 3)
130                 return mnt_to_nfs[vers];
131         return 0;
132 }
133
134 static const unsigned int probe_udp_only[] = {
135         IPPROTO_UDP,
136         0,
137 };
138
139 static const unsigned int probe_udp_first[] = {
140         IPPROTO_UDP,
141         IPPROTO_TCP,
142         0,
143 };
144
145 static const unsigned int probe_tcp_first[] = {
146         IPPROTO_TCP,
147         IPPROTO_UDP,
148         0,
149 };
150
151 static const unsigned long probe_nfs2_only[] = {
152         2,
153         0,
154 };
155
156 static const unsigned long probe_nfs3_first[] = {
157         3,
158         2,
159         0,
160 };
161
162 static const unsigned long probe_mnt1_first[] = {
163         1,
164         2,
165         0,
166 };
167
168 static const unsigned long probe_mnt3_first[] = {
169         3,
170         1,
171         2,
172         0,
173 };
174
175 static int nfs_lookup(const char *hostname, const sa_family_t family,
176                       struct sockaddr *sap, socklen_t *salen)
177 {
178         struct addrinfo *gai_results;
179         struct addrinfo gai_hint = {
180 #ifdef HAVE_DECL_AI_ADDRCONFIG
181                 .ai_flags       = AI_ADDRCONFIG,
182 #endif  /* HAVE_DECL_AI_ADDRCONFIG */
183                 .ai_family      = family,
184         };
185         socklen_t len = *salen;
186         int error, ret = 0;
187
188         *salen = 0;
189
190         error = getaddrinfo(hostname, NULL, &gai_hint, &gai_results);
191         switch (error) {
192         case 0:
193                 break;
194         case EAI_SYSTEM:
195                 nfs_error(_("%s: DNS resolution failed for %s: %s"),
196                         progname, hostname, strerror(errno));
197                 return ret;
198         default:
199                 nfs_error(_("%s: DNS resolution failed for %s: %s"),
200                         progname, hostname, gai_strerror(error));
201                 return ret;
202         }
203
204         switch (gai_results->ai_addr->sa_family) {
205         case AF_INET:
206         case AF_INET6:
207                 if (len >= gai_results->ai_addrlen) {
208                         *salen = gai_results->ai_addrlen;
209                         memcpy(sap, gai_results->ai_addr, *salen);
210                         ret = 1;
211                 }
212                 break;
213         default:
214                 /* things are really broken if we get here, so warn */
215                 nfs_error(_("%s: unrecognized DNS resolution results for %s"),
216                                 progname, hostname);
217                 break;
218         }
219
220         freeaddrinfo(gai_results);
221         return ret;
222 }
223
224 /**
225  * nfs_name_to_address - resolve hostname to an IPv4 or IPv6 socket address
226  * @hostname: pointer to C string containing DNS hostname to resolve
227  * @sap: pointer to buffer to fill with socket address
228  * @len: IN: size of buffer to fill; OUT: size of socket address
229  *
230  * Returns 1 and places a socket address at @sap if successful;
231  * otherwise zero.
232  */
233 int nfs_name_to_address(const char *hostname,
234                         struct sockaddr *sap, socklen_t *salen)
235 {
236 #ifdef IPV6_SUPPORTED
237         return nfs_lookup(hostname, AF_UNSPEC, sap, salen);
238 #else   /* !IPV6_SUPPORTED */
239         return nfs_lookup(hostname, AF_INET, sap, salen);
240 #endif  /* !IPV6_SUPPORTED */
241 }
242
243 /**
244  * nfs_gethostbyname - resolve a hostname to an IPv4 address
245  * @hostname: pointer to a C string containing a DNS hostname
246  * @sin: returns an IPv4 address 
247  *
248  * Returns 1 if successful, otherwise zero.
249  */
250 int nfs_gethostbyname(const char *hostname, struct sockaddr_in *sin)
251 {
252         socklen_t len = sizeof(*sin);
253
254         return nfs_lookup(hostname, AF_INET, (struct sockaddr *)sin, &len);
255 }
256
257 /**
258  * nfs_string_to_sockaddr - convert string address to sockaddr
259  * @address:    pointer to presentation format address to convert
260  * @sap:        pointer to socket address buffer to fill in
261  * @salen:      IN: length of address buffer
262  *              OUT: length of converted socket address
263  *
264  * Convert a presentation format address string to a socket address.
265  * Similar to nfs_name_to_address(), but the DNS query is squelched,
266  * and won't make any noise if the getaddrinfo() call fails.
267  *
268  * Returns 1 and fills in @sap and @salen if successful; otherwise zero.
269  *
270  * See RFC 4038 section 5.1 or RFC 3513 section 2.2 for more details
271  * on presenting IPv6 addresses as text strings.
272  */
273 int nfs_string_to_sockaddr(const char *address, struct sockaddr *sap,
274                            socklen_t *salen)
275 {
276         struct addrinfo *gai_results;
277         struct addrinfo gai_hint = {
278                 .ai_flags       = AI_NUMERICHOST,
279         };
280         socklen_t len = *salen;
281         int ret = 0;
282
283         *salen = 0;
284
285         if (getaddrinfo(address, NULL, &gai_hint, &gai_results) == 0) {
286                 switch (gai_results->ai_addr->sa_family) {
287                 case AF_INET:
288                 case AF_INET6:
289                         if (len >= gai_results->ai_addrlen) {
290                                 *salen = gai_results->ai_addrlen;
291                                 memcpy(sap, gai_results->ai_addr, *salen);
292                                 ret = 1;
293                         }
294                         break;
295                 }
296                 freeaddrinfo(gai_results);
297         }
298
299         return ret;
300 }
301
302 /**
303  * nfs_present_sockaddr - convert sockaddr to string
304  * @sap: pointer to socket address to convert
305  * @salen: length of socket address
306  * @buf: pointer to buffer to fill in
307  * @buflen: length of buffer
308  *
309  * Convert the passed-in sockaddr-style address to presentation format.
310  * The presentation format address is placed in @buf and is
311  * '\0'-terminated.
312  *
313  * Returns 1 if successful; otherwise zero.
314  *
315  * See RFC 4038 section 5.1 or RFC 3513 section 2.2 for more details
316  * on presenting IPv6 addresses as text strings.
317  */
318 int nfs_present_sockaddr(const struct sockaddr *sap, const socklen_t salen,
319                          char *buf, const size_t buflen)
320 {
321 #ifdef HAVE_GETNAMEINFO
322         int result;
323
324         result = getnameinfo(sap, salen, buf, buflen,
325                                         NULL, 0, NI_NUMERICHOST);
326         if (!result)
327                 return 1;
328
329         nfs_error(_("%s: invalid server address: %s"), progname,
330                         gai_strerror(result));
331         return 0;
332 #else   /* HAVE_GETNAMEINFO */
333         char *addr;
334
335         if (sap->sa_family == AF_INET) {
336                 addr = inet_ntoa(((struct sockaddr_in *)sap)->sin_addr);
337                 if (addr && strlen(addr) < buflen) {
338                         strcpy(buf, addr);
339                         return 1;
340                 }
341         }
342
343         nfs_error(_("%s: invalid server address"), progname);
344         return 0;
345 #endif  /* HAVE_GETNAMEINFO */
346 }
347
348 /*
349  * Attempt to connect a socket, but time out after "timeout" seconds.
350  *
351  * On error return, caller closes the socket.
352  */
353 static int connect_to(int fd, struct sockaddr *addr,
354                         socklen_t addrlen, int timeout)
355 {
356         int ret, saved;
357         fd_set rset, wset;
358         struct timeval tv = {
359                 .tv_sec = timeout,
360         };
361
362         saved = fcntl(fd, F_GETFL, 0);
363         fcntl(fd, F_SETFL, saved | O_NONBLOCK);
364
365         ret = connect(fd, addr, addrlen);
366         if (ret < 0 && errno != EINPROGRESS)
367                 return -1;
368         if (ret == 0)
369                 goto out;
370
371         FD_ZERO(&rset);
372         FD_SET(fd, &rset);
373         wset = rset;
374         ret = select(fd + 1, &rset, &wset, NULL, &tv);
375         if (ret == 0) {
376                 errno = ETIMEDOUT;
377                 return -1;
378         }
379         if (FD_ISSET(fd, &rset) || FD_ISSET(fd, &wset)) {
380                 int error;
381                 socklen_t len = sizeof(error);
382                 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
383                         return -1;
384                 if (error) {
385                         errno = error;
386                         return -1;
387                 }
388         } else
389                 return -1;
390
391 out:
392         fcntl(fd, F_SETFL, saved);
393         return 0;
394 }
395
396 /*
397  * Create a socket that is locally bound to a reserved or non-reserved port.
398  *
399  * The caller should check rpc_createerr to determine the cause of any error.
400  */
401 static int get_socket(struct sockaddr_in *saddr, unsigned int p_prot,
402                         unsigned int timeout, int resvp, int conn)
403 {
404         int so, cc, type;
405         struct sockaddr_in laddr;
406         socklen_t namelen = sizeof(laddr);
407
408         type = (p_prot == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM);
409         if ((so = socket (AF_INET, type, p_prot)) < 0)
410                 goto err_socket;
411
412         laddr.sin_family = AF_INET;
413         laddr.sin_port = 0;
414         laddr.sin_addr.s_addr = htonl(INADDR_ANY);
415         if (resvp) {
416                 if (bindresvport(so, &laddr) < 0)
417                         goto err_bindresvport;
418         } else {
419                 cc = bind(so, (struct sockaddr *)&laddr, namelen);
420                 if (cc < 0)
421                         goto err_bind;
422         }
423         if (type == SOCK_STREAM || (conn && type == SOCK_DGRAM)) {
424                 cc = connect_to(so, (struct sockaddr *)saddr, namelen,
425                                 timeout);
426                 if (cc < 0)
427                         goto err_connect;
428         }
429         return so;
430
431 err_socket:
432         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
433         rpc_createerr.cf_error.re_errno = errno;
434         if (verbose) {
435                 nfs_error(_("%s: Unable to create %s socket: errno %d (%s)\n"),
436                         progname, p_prot == IPPROTO_UDP ? _("UDP") : _("TCP"),
437                         errno, strerror(errno));
438         }
439         return RPC_ANYSOCK;
440
441 err_bindresvport:
442         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
443         rpc_createerr.cf_error.re_errno = errno;
444         if (verbose) {
445                 nfs_error(_("%s: Unable to bindresvport %s socket: errno %d"
446                                 " (%s)\n"),
447                         progname, p_prot == IPPROTO_UDP ? _("UDP") : _("TCP"),
448                         errno, strerror(errno));
449         }
450         close(so);
451         return RPC_ANYSOCK;
452
453 err_bind:
454         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
455         rpc_createerr.cf_error.re_errno = errno;
456         if (verbose) {
457                 nfs_error(_("%s: Unable to bind to %s socket: errno %d (%s)\n"),
458                         progname, p_prot == IPPROTO_UDP ? _("UDP") : _("TCP"),
459                         errno, strerror(errno));
460         }
461         close(so);
462         return RPC_ANYSOCK;
463
464 err_connect:
465         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
466         rpc_createerr.cf_error.re_errno = errno;
467         if (verbose) {
468                 nfs_error(_("%s: Unable to connect to %s:%d, errno %d (%s)\n"),
469                         progname, inet_ntoa(saddr->sin_addr),
470                         ntohs(saddr->sin_port), errno, strerror(errno));
471         }
472         close(so);
473         return RPC_ANYSOCK;
474 }
475
476 static void nfs_pp_debug(const struct sockaddr *sap, const socklen_t salen,
477                          const rpcprog_t program, const rpcvers_t version,
478                          const unsigned short protocol,
479                          const unsigned short port)
480 {
481         char buf[NI_MAXHOST];
482
483         if (!verbose)
484                 return;
485
486         if (nfs_present_sockaddr(sap, salen, buf, sizeof(buf)) == 0) {
487                 buf[0] = '\0';
488                 strcat(buf, "unknown host");
489         }
490
491         fprintf(stderr, _("%s: trying %s prog %lu vers %lu prot %s port %d\n"),
492                         progname, buf, (unsigned long)program,
493                         (unsigned long)version,
494                         (protocol == IPPROTO_UDP ? _("UDP") : _("TCP")),
495                         port);
496 }
497
498 static void nfs_pp_debug2(const char *str)
499 {
500         if (!verbose)
501                 return;
502
503         if (rpc_createerr.cf_error.re_status == RPC_CANTRECV ||
504             rpc_createerr.cf_error.re_status == RPC_CANTSEND)
505                 nfs_error(_("%s: portmap query %s%s - %s"),
506                                 progname, str, clnt_spcreateerror(""),
507                                 strerror(rpc_createerr.cf_error.re_errno));
508         else
509                 nfs_error(_("%s: portmap query %s%s"),
510                                 progname, str, clnt_spcreateerror(""));
511 }
512
513 /*
514  * Use the portmapper to discover whether or not the service we want is
515  * available. The lists 'versions' and 'protos' define ordered sequences
516  * of service versions and udp/tcp protocols to probe for.
517  *
518  * Returns 1 if the requested service port is unambiguous and pingable;
519  * @pmap is filled in with the version, port, and transport protocol used
520  * during the successful ping.  Note that if a port is already specified
521  * in @pmap and it matches the rpcbind query result, nfs_probe_port() does
522  * not perform an RPC ping.
523  * 
524  * If an error occurs or the requested service isn't available, zero is
525  * returned; rpccreateerr.cf_stat is set to reflect the nature of the error.
526  */
527 static int nfs_probe_port(const struct sockaddr *sap, const socklen_t salen,
528                           struct pmap *pmap, const unsigned long *versions,
529                           const unsigned int *protos)
530 {
531         struct sockaddr_storage address;
532         struct sockaddr *saddr = (struct sockaddr *)&address;
533         const unsigned long prog = pmap->pm_prog, *p_vers;
534         const unsigned int prot = (u_int)pmap->pm_prot, *p_prot;
535         const u_short port = (u_short) pmap->pm_port;
536         unsigned long vers = pmap->pm_vers;
537         unsigned short p_port;
538
539         memcpy(saddr, sap, salen);
540         p_prot = prot ? &prot : protos;
541         p_vers = vers ? &vers : versions;
542
543         for (;;) {
544                 if (verbose)
545                         printf(_("%s: prog %lu, trying vers=%lu, prot=%u\n"),
546                                 progname, prog, *p_vers, *p_prot);
547                 p_port = nfs_getport(saddr, salen, prog, *p_vers, *p_prot);
548                 if (p_port) {
549                         if (!port || port == p_port) {
550                                 nfs_set_port(saddr, p_port);
551                                 nfs_pp_debug(saddr, salen, prog, *p_vers,
552                                                 *p_prot, p_port);
553                                 if (nfs_rpc_ping(saddr, salen, prog,
554                                                         *p_vers, *p_prot, NULL))
555                                         goto out_ok;
556                         } else
557                                 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
558                 }
559                 if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED &&
560                     rpc_createerr.cf_stat != RPC_TIMEDOUT &&
561                     rpc_createerr.cf_stat != RPC_CANTRECV &&
562                     rpc_createerr.cf_stat != RPC_PROGVERSMISMATCH)
563                         break;
564
565                 if (!prot) {
566                         if (*++p_prot) {
567                                 nfs_pp_debug2("retrying");
568                                 continue;
569                         }
570                         p_prot = protos;
571                 }
572                 if (rpc_createerr.cf_stat == RPC_TIMEDOUT ||
573                     rpc_createerr.cf_stat == RPC_CANTRECV)
574                         break;
575
576                 if (vers || !*++p_vers)
577                         break;
578         }
579
580         nfs_pp_debug2("failed");
581         return 0;
582
583 out_ok:
584         if (!vers)
585                 pmap->pm_vers = *p_vers;
586         if (!prot)
587                 pmap->pm_prot = *p_prot;
588         if (!port)
589                 pmap->pm_port = p_port;
590         nfs_clear_rpc_createerr();
591         return 1;
592 }
593
594 /*
595  * Probe a server's NFS service to determine which versions and
596  * transport protocols are supported.
597  *
598  * Returns 1 if the requested service port is unambiguous and pingable;
599  * @pmap is filled in with the version, port, and transport protocol used
600  * during the successful ping.  If all three are already specified, simply
601  * return success without an rpcbind query or RPC ping (we may be trying
602  * to mount an NFS service that is not advertised via rpcbind).
603  *
604  * If an error occurs or the requested service isn't available, zero is
605  * returned; rpccreateerr.cf_stat is set to reflect the nature of the error.
606  */
607 static int nfs_probe_nfsport(const struct sockaddr *sap, const socklen_t salen,
608                                 struct pmap *pmap)
609 {
610         if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
611                 return 1;
612
613         if (nfs_mount_data_version >= 4) {
614                 const unsigned int *probe_proto = probe_tcp_first;
615
616                 /*
617                  * If the default proto has been set and 
618                  * its not TCP, start with UDP
619                  */
620                 if (config_default_proto && config_default_proto != IPPROTO_TCP)
621                         probe_proto =  probe_udp_first;
622
623                 return nfs_probe_port(sap, salen, pmap,
624                                         probe_nfs3_first, probe_proto);
625         } else
626                 return nfs_probe_port(sap, salen, pmap,
627                                         probe_nfs2_only, probe_udp_only);
628 }
629
630 /*
631  * Probe a server's mountd service to determine which versions and
632  * transport protocols are supported.
633  *
634  * Returns 1 if the requested service port is unambiguous and pingable;
635  * @pmap is filled in with the version, port, and transport protocol used
636  * during the successful ping.  If all three are already specified, simply
637  * return success without an rpcbind query or RPC ping (we may be trying
638  * to mount an NFS service that is not advertised via rpcbind).
639  * 
640  * If an error occurs or the requested service isn't available, zero is
641  * returned; rpccreateerr.cf_stat is set to reflect the nature of the error.
642  */
643 static int nfs_probe_mntport(const struct sockaddr *sap, const socklen_t salen,
644                                 struct pmap *pmap)
645 {
646         if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
647                 return 1;
648
649         if (nfs_mount_data_version >= 4)
650                 return nfs_probe_port(sap, salen, pmap,
651                                         probe_mnt3_first, probe_udp_first);
652         else
653                 return nfs_probe_port(sap, salen, pmap,
654                                         probe_mnt1_first, probe_udp_only);
655 }
656
657 /*
658  * Probe a server's mountd service to determine which versions and
659  * transport protocols are supported.  Invoked when the protocol
660  * version is already known for both the NFS and mountd service.
661  *
662  * Returns 1 and fills in both @pmap structs if the requested service
663  * ports are unambiguous and pingable.  Otherwise zero is returned;
664  * rpccreateerr.cf_stat is set to reflect the nature of the error.
665  */
666 static int nfs_probe_version_fixed(const struct sockaddr *mnt_saddr,
667                         const socklen_t mnt_salen,
668                         struct pmap *mnt_pmap,
669                         const struct sockaddr *nfs_saddr,
670                         const socklen_t nfs_salen,
671                         struct pmap *nfs_pmap)
672 {
673         if (!nfs_probe_nfsport(nfs_saddr, nfs_salen, nfs_pmap))
674                 return 0;
675         return nfs_probe_mntport(mnt_saddr, mnt_salen, mnt_pmap);
676 }
677
678 /**
679  * nfs_probe_bothports - discover the RPC endpoints of mountd and NFS server
680  * @mnt_saddr:  pointer to socket address of mountd server
681  * @mnt_salen:  length of mountd server's address
682  * @mnt_pmap:   IN: partially filled-in mountd RPC service tuple;
683  *              OUT: fully filled-in mountd RPC service tuple
684  * @nfs_saddr:  pointer to socket address of NFS server
685  * @nfs_salen:  length of NFS server's address
686  * @nfs_pmap:   IN: partially filled-in NFS RPC service tuple;
687  *              OUT: fully filled-in NFS RPC service tuple
688  *
689  * Returns 1 and fills in both @pmap structs if the requested service
690  * ports are unambiguous and pingable.  Otherwise zero is returned;
691  * rpccreateerr.cf_stat is set to reflect the nature of the error.
692  */
693 int nfs_probe_bothports(const struct sockaddr *mnt_saddr,
694                         const socklen_t mnt_salen,
695                         struct pmap *mnt_pmap,
696                         const struct sockaddr *nfs_saddr,
697                         const socklen_t nfs_salen,
698                         struct pmap *nfs_pmap)
699 {
700         struct pmap save_nfs, save_mnt;
701         const unsigned long *probe_vers;
702
703         if (mnt_pmap->pm_vers && !nfs_pmap->pm_vers)
704                 nfs_pmap->pm_vers = mntvers_to_nfs(mnt_pmap->pm_vers);
705         else if (nfs_pmap->pm_vers && !mnt_pmap->pm_vers)
706                 mnt_pmap->pm_vers = nfsvers_to_mnt(nfs_pmap->pm_vers);
707
708         if (nfs_pmap->pm_vers)
709                 return nfs_probe_version_fixed(mnt_saddr, mnt_salen, mnt_pmap,
710                                                nfs_saddr, nfs_salen, nfs_pmap);
711
712         memcpy(&save_nfs, nfs_pmap, sizeof(save_nfs));
713         memcpy(&save_mnt, mnt_pmap, sizeof(save_mnt));
714         probe_vers = (nfs_mount_data_version >= 4) ?
715                         probe_mnt3_first : probe_mnt1_first;
716
717         for (; *probe_vers; probe_vers++) {
718                 nfs_pmap->pm_vers = mntvers_to_nfs(*probe_vers);
719                 if (nfs_probe_nfsport(nfs_saddr, nfs_salen, nfs_pmap) != 0) {
720                         mnt_pmap->pm_vers = *probe_vers;
721                         if (nfs_probe_mntport(mnt_saddr, mnt_salen, mnt_pmap) != 0)
722                                 return 1;
723                         memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap));
724                 }
725                 switch (rpc_createerr.cf_stat) {
726                 case RPC_PROGVERSMISMATCH:
727                 case RPC_PROGNOTREGISTERED:
728                         break;
729                 default:
730                         return 0;
731                 }
732                 memcpy(nfs_pmap, &save_nfs, sizeof(*nfs_pmap));
733         }
734
735         return 0;
736 }
737
738 /**
739  * probe_bothports - discover the RPC endpoints of mountd and NFS server
740  * @mnt_server: pointer to address and pmap argument for mountd results
741  * @nfs_server: pointer to address and pmap argument for NFS server
742  *
743  * This is the legacy API that takes "clnt_addr_t" for both servers,
744  * but supports only AF_INET addresses.
745  *
746  * Returns 1 and fills in the pmap field in both clnt_addr_t structs
747  * if the requested service ports are unambiguous and pingable.
748  * Otherwise zero is returned; rpccreateerr.cf_stat is set to reflect
749  * the nature of the error.
750  */
751 int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server)
752 {
753         return nfs_probe_bothports((struct sockaddr *)&mnt_server->saddr,
754                                         sizeof(mnt_server->saddr),
755                                         &mnt_server->pmap,
756                                         (struct sockaddr *)&nfs_server->saddr,
757                                         sizeof(nfs_server->saddr),
758                                         &nfs_server->pmap);
759 }
760
761 static int nfs_probe_statd(void)
762 {
763         struct sockaddr_in addr = {
764                 .sin_family             = AF_INET,
765                 .sin_addr.s_addr        = htonl(INADDR_LOOPBACK),
766         };
767         rpcprog_t program = nfs_getrpcbyname(NSMPROG, nfs_ns_pgmtbl);
768
769         return nfs_getport_ping((struct sockaddr *)&addr, sizeof(addr),
770                                 program, (rpcvers_t)1, IPPROTO_UDP);
771 }
772
773 /**
774  * start_statd - attempt to start rpc.statd
775  *
776  * Returns 1 if statd is running; otherwise zero.
777  */
778 int start_statd(void)
779 {
780 #ifdef START_STATD
781         struct stat stb;
782 #endif
783
784         if (nfs_probe_statd())
785                 return 1;
786
787 #ifdef START_STATD
788         if (stat(START_STATD, &stb) == 0) {
789                 if (S_ISREG(stb.st_mode) && (stb.st_mode & S_IXUSR)) {
790                         pid_t pid = fork();
791                         switch (pid) {
792                         case 0: /* child */
793                                 execl(START_STATD, START_STATD, NULL);
794                                 exit(1);
795                         case -1: /* error */
796                                 nfs_error(_("%s: fork failed: %s"),
797                                                 progname, strerror(errno));
798                                 break;
799                         default: /* parent */
800                                 waitpid(pid, NULL,0);
801                                 break;
802                         }
803                         if (nfs_probe_statd())
804                                 return 1;
805                 }
806         }
807 #endif
808
809         return 0;
810 }
811
812 /**
813  * nfs_advise_umount - ask the server to remove a share from it's rmtab
814  * @sap: pointer to IP address of server to call
815  * @salen: length of server address
816  * @pmap: partially filled-in mountd RPC service tuple
817  * @argp: directory path of share to "unmount"
818  *
819  * Returns one if the unmount call succeeded; zero if the unmount
820  * failed for any reason;  rpccreateerr.cf_stat is set to reflect
821  * the nature of the error.
822  *
823  * We use a fast timeout since this call is advisory only.
824  */
825 int nfs_advise_umount(const struct sockaddr *sap, const socklen_t salen,
826                       const struct pmap *pmap, const dirpath *argp)
827 {
828         struct sockaddr_storage address;
829         struct sockaddr *saddr = (struct sockaddr *)&address;
830         struct pmap mnt_pmap = *pmap;
831         struct timeval timeout = {
832                 .tv_sec         = MOUNT_TIMEOUT >> 3,
833         };
834         CLIENT *client;
835         enum clnt_stat res = 0;
836
837         memcpy(saddr, sap, salen);
838         if (nfs_probe_mntport(saddr, salen, &mnt_pmap) == 0) {
839                 if (verbose)
840                         nfs_error(_("%s: Failed to discover mountd port%s"),
841                                 progname, clnt_spcreateerror(""));
842                 return 0;
843         }
844         nfs_set_port(saddr, mnt_pmap.pm_port);
845
846         client = nfs_get_priv_rpcclient(saddr, salen, mnt_pmap.pm_prot,
847                                         mnt_pmap.pm_prog, mnt_pmap.pm_vers,
848                                         &timeout);
849         if (client == NULL) {
850                 if (verbose)
851                         nfs_error(_("%s: Failed to create RPC client%s"),
852                                 progname, clnt_spcreateerror(""));
853                 return 0;
854         }
855
856         client->cl_auth = authunix_create_default();
857
858         res = CLNT_CALL(client, MOUNTPROC_UMNT,
859                         (xdrproc_t)xdr_dirpath, (caddr_t)argp,
860                         (xdrproc_t)xdr_void, NULL,
861                         timeout);
862         if (res != RPC_SUCCESS) {
863                 rpc_createerr.cf_stat = res;
864                 CLNT_GETERR(client, &rpc_createerr.cf_error);
865                 if (verbose)
866                         nfs_error(_("%s: UMNT call failed: %s"),
867                                 progname, clnt_sperrno(res));
868
869         }
870         auth_destroy(client->cl_auth);
871         CLNT_DESTROY(client);
872
873         if (res != RPC_SUCCESS)
874                 return 0;
875         return 1;
876 }
877
878 /**
879  * nfs_call_umount - ask the server to remove a share from it's rmtab
880  * @mnt_server: address of RPC MNT program server
881  * @argp: directory path of share to "unmount"
882  *
883  * Returns one if the unmount call succeeded; zero if the unmount
884  * failed for any reason.
885  *
886  * Note that a side effect of calling this function is that rpccreateerr
887  * is set.
888  */
889 int nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp)
890 {
891         struct sockaddr *sap = (struct sockaddr *)&mnt_server->saddr;
892         socklen_t salen = sizeof(mnt_server->saddr);
893         struct pmap *pmap = &mnt_server->pmap;
894         CLIENT *clnt;
895         enum clnt_stat res = 0;
896         int msock;
897
898         if (!nfs_probe_mntport(sap, salen, pmap))
899                 return 0;
900         clnt = mnt_openclnt(mnt_server, &msock);
901         if (!clnt)
902                 return 0;
903         res = clnt_call(clnt, MOUNTPROC_UMNT,
904                         (xdrproc_t)xdr_dirpath, (caddr_t)argp,
905                         (xdrproc_t)xdr_void, NULL,
906                         TIMEOUT);
907         mnt_closeclnt(clnt, msock);
908
909         if (res == RPC_SUCCESS)
910                 return 1;
911         return 0;
912 }
913
914 /**
915  * mnt_openclnt - get a handle for a remote mountd service
916  * @mnt_server: address and pmap arguments of mountd service
917  * @msock: returns a file descriptor of the underlying transport socket
918  *
919  * Returns an active handle for the remote's mountd service
920  */
921 CLIENT *mnt_openclnt(clnt_addr_t *mnt_server, int *msock)
922 {
923         struct sockaddr_in *mnt_saddr = &mnt_server->saddr;
924         struct pmap *mnt_pmap = &mnt_server->pmap;
925         CLIENT *clnt = NULL;
926
927         mnt_saddr->sin_port = htons((u_short)mnt_pmap->pm_port);
928         *msock = get_socket(mnt_saddr, mnt_pmap->pm_prot, MOUNT_TIMEOUT,
929                                 TRUE, FALSE);
930         if (*msock == RPC_ANYSOCK) {
931                 if (rpc_createerr.cf_error.re_errno == EADDRINUSE)
932                         /*
933                          * Probably in-use by a TIME_WAIT connection,
934                          * It is worth waiting a while and trying again.
935                          */
936                         rpc_createerr.cf_stat = RPC_TIMEDOUT;
937                 return NULL;
938         }
939
940         switch (mnt_pmap->pm_prot) {
941         case IPPROTO_UDP:
942                 clnt = clntudp_bufcreate(mnt_saddr,
943                                          mnt_pmap->pm_prog, mnt_pmap->pm_vers,
944                                          RETRY_TIMEOUT, msock,
945                                          MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
946                 break;
947         case IPPROTO_TCP:
948                 clnt = clnttcp_create(mnt_saddr,
949                                       mnt_pmap->pm_prog, mnt_pmap->pm_vers,
950                                       msock,
951                                       MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
952                 break;
953         }
954         if (clnt) {
955                 /* try to mount hostname:dirname */
956                 clnt->cl_auth = authunix_create_default();
957                 return clnt;
958         }
959         return NULL;
960 }
961
962 /**
963  * mnt_closeclnt - terminate a handle for a remote mountd service
964  * @clnt: pointer to an active handle for a remote mountd service
965  * @msock: file descriptor of the underlying transport socket
966  *
967  */
968 void mnt_closeclnt(CLIENT *clnt, int msock)
969 {
970         auth_destroy(clnt->cl_auth);
971         clnt_destroy(clnt);
972         close(msock);
973 }
974
975 /**
976  * clnt_ping - send an RPC ping to the remote RPC service endpoint
977  * @saddr: server's address
978  * @prog: target RPC program number
979  * @vers: target RPC version number
980  * @prot: target RPC protocol
981  * @caddr: filled in with our network address
982  *
983  * Sigh... GETPORT queries don't actually check the version number.
984  * In order to make sure that the server actually supports the service
985  * we're requesting, we open an RPC client, and fire off a NULL
986  * RPC call.
987  *
988  * caddr is the network address that the server will use to call us back.
989  * On multi-homed clients, this address depends on which NIC we use to
990  * route requests to the server.
991  *
992  * Returns one if successful, otherwise zero.
993  */
994 int clnt_ping(struct sockaddr_in *saddr, const unsigned long prog,
995                 const unsigned long vers, const unsigned int prot,
996                 struct sockaddr_in *caddr)
997 {
998         CLIENT *clnt = NULL;
999         int sock, stat;
1000         static char clnt_res;
1001         struct sockaddr dissolve;
1002
1003         rpc_createerr.cf_stat = stat = 0;
1004         sock = get_socket(saddr, prot, CONNECT_TIMEOUT, FALSE, TRUE);
1005         if (sock == RPC_ANYSOCK) {
1006                 if (rpc_createerr.cf_error.re_errno == ETIMEDOUT) {
1007                         /*
1008                          * TCP timeout. Bubble up the error to see 
1009                          * how it should be handled.
1010                          */
1011                         rpc_createerr.cf_stat = RPC_TIMEDOUT;
1012                 }
1013                 return 0;
1014         }
1015
1016         if (caddr) {
1017                 /* Get the address of our end of this connection */
1018                 socklen_t len = sizeof(*caddr);
1019                 if (getsockname(sock, caddr, &len) != 0)
1020                         caddr->sin_family = 0;
1021         }
1022
1023         switch(prot) {
1024         case IPPROTO_UDP:
1025                 /* The socket is connected (so we could getsockname successfully),
1026                  * but some servers on multi-homed hosts reply from
1027                  * the wrong address, so if we stay connected, we lose the reply.
1028                  */
1029                 dissolve.sa_family = AF_UNSPEC;
1030                 connect(sock, &dissolve, sizeof(dissolve));
1031
1032                 clnt = clntudp_bufcreate(saddr, prog, vers,
1033                                          RETRY_TIMEOUT, &sock,
1034                                          RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
1035                 break;
1036         case IPPROTO_TCP:
1037                 clnt = clnttcp_create(saddr, prog, vers, &sock,
1038                                       RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
1039                 break;
1040         }
1041         if (!clnt) {
1042                 close(sock);
1043                 return 0;
1044         }
1045         memset(&clnt_res, 0, sizeof(clnt_res));
1046         stat = clnt_call(clnt, NULLPROC,
1047                          (xdrproc_t)xdr_void, (caddr_t)NULL,
1048                          (xdrproc_t)xdr_void, (caddr_t)&clnt_res,
1049                          TIMEOUT);
1050         if (stat) {
1051                 clnt_geterr(clnt, &rpc_createerr.cf_error);
1052                 rpc_createerr.cf_stat = stat;
1053         }
1054         clnt_destroy(clnt);
1055         close(sock);
1056
1057         if (stat == RPC_SUCCESS)
1058                 return 1;
1059         else
1060                 return 0;
1061 }
1062
1063 /*
1064  * Try a getsockname() on a connected datagram socket.
1065  *
1066  * Returns 1 and fills in @buf if successful; otherwise, zero.
1067  *
1068  * A connected datagram socket prevents leaving a socket in TIME_WAIT.
1069  * This conserves the ephemeral port number space, helping reduce failed
1070  * socket binds during mount storms.
1071  */
1072 static int nfs_ca_sockname(const struct sockaddr *sap, const socklen_t salen,
1073                            struct sockaddr *buf, socklen_t *buflen)
1074 {
1075         struct sockaddr_in sin = {
1076                 .sin_family             = AF_INET,
1077                 .sin_addr.s_addr        = htonl(INADDR_ANY),
1078         };
1079         struct sockaddr_in6 sin6 = {
1080                 .sin6_family            = AF_INET6,
1081                 .sin6_addr              = IN6ADDR_ANY_INIT,
1082         };
1083         int sock;
1084
1085         sock = socket(sap->sa_family, SOCK_DGRAM, IPPROTO_UDP);
1086         if (sock < 0)
1087                 return 0;
1088
1089         switch (sap->sa_family) {
1090         case AF_INET:
1091                 if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
1092                         close(sock);
1093                         return 0;
1094                 }
1095                 break;
1096         case AF_INET6:
1097                 if (bind(sock, (struct sockaddr *)&sin6, sizeof(sin6)) < 0) {
1098                         close(sock);
1099                         return 0;
1100                 }
1101                 break;
1102         default:
1103                 errno = EAFNOSUPPORT;
1104                 return 0;
1105         }
1106
1107         if (connect(sock, sap, salen) < 0) {
1108                 close(sock);
1109                 return 0;
1110         }
1111
1112         return !getsockname(sock, buf, buflen);
1113 }
1114
1115 /*
1116  * Try to generate an address that prevents the server from calling us.
1117  *
1118  * Returns 1 and fills in @buf if successful; otherwise, zero.
1119  */
1120 static int nfs_ca_gai(const struct sockaddr *sap,
1121                       struct sockaddr *buf, socklen_t *buflen)
1122 {
1123         struct addrinfo *gai_results;
1124         struct addrinfo gai_hint = {
1125                 .ai_family      = sap->sa_family,
1126                 .ai_flags       = AI_PASSIVE,   /* ANYADDR */
1127         };
1128
1129         if (getaddrinfo(NULL, "", &gai_hint, &gai_results))
1130                 return 0;
1131
1132         *buflen = gai_results->ai_addrlen;
1133         memcpy(buf, gai_results->ai_addr, *buflen);
1134
1135         freeaddrinfo(gai_results);
1136
1137         return 1;
1138 }
1139
1140 /**
1141  * nfs_callback_address - acquire our local network address
1142  * @sap: pointer to address of remote
1143  * @sap_len: length of address
1144  * @buf: pointer to buffer to be filled in with local network address
1145  * @buflen: IN: length of buffer to fill in; OUT: length of filled-in address
1146  *
1147  * Discover a network address that an NFSv4 server can use to call us back.
1148  * On multi-homed clients, this address depends on which NIC we use to
1149  * route requests to the server.
1150  *
1151  * Returns 1 and fills in @buf if an unambiguous local address is
1152  * available; returns 1 and fills in an appropriate ANYADDR address
1153  * if a local address isn't available; otherwise, returns zero.
1154  */
1155 int nfs_callback_address(const struct sockaddr *sap, const socklen_t salen,
1156                          struct sockaddr *buf, socklen_t *buflen)
1157 {
1158         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)buf;
1159
1160         if (nfs_ca_sockname(sap, salen, buf, buflen) == 0)
1161                 if (nfs_ca_gai(sap, buf, buflen) == 0)
1162                         goto out_failed;
1163
1164         /*
1165          * The server can't use an interface ID that was generated
1166          * here on the client, so always clear sin6_scope_id.
1167          */
1168         if (sin6->sin6_family == AF_INET6)
1169                 sin6->sin6_scope_id = 0;
1170
1171         return 1;
1172
1173 out_failed:
1174         *buflen = 0;
1175         if (verbose)
1176                 nfs_error(_("%s: failed to construct callback address"),
1177                                 progname);
1178         return 0;
1179 }
1180
1181 /*
1182  * "nfsprog" is supported only by the legacy mount command.  The
1183  * kernel mount client does not support this option.
1184  *
1185  * Returns TRUE if @program contains a valid value for this option,
1186  * or FALSE if the option was specified with an invalid value.
1187  */
1188 static int
1189 nfs_nfs_program(struct mount_options *options, unsigned long *program)
1190 {
1191         long tmp;
1192
1193         switch (po_get_numeric(options, "nfsprog", &tmp)) {
1194         case PO_NOT_FOUND:
1195                 break;
1196         case PO_FOUND:
1197                 if (tmp > 0) {
1198                         *program = tmp;
1199                         return 1;
1200                 }
1201         case PO_BAD_VALUE:
1202                 return 0;
1203         }
1204
1205         /*
1206          * NFS RPC program wasn't specified.  The RPC program
1207          * cannot be determined via an rpcbind query.
1208          */
1209         *program = nfs_getrpcbyname(NFSPROG, nfs_nfs_pgmtbl);
1210         return 1;
1211 }
1212
1213 /*
1214  * Returns TRUE if @version contains a valid value for this option,
1215  * or FALSE if the option was specified with an invalid value.
1216  */
1217 int
1218 nfs_nfs_version(struct mount_options *options, unsigned long *version)
1219 {
1220         long tmp;
1221
1222         switch (po_rightmost(options, nfs_version_opttbl)) {
1223         case 0: /* v2 */
1224                 *version = 2;
1225                 return 1;
1226         case 1: /* v3 */
1227                 *version = 3;
1228                 return 1;
1229         case 2: /* v4 */
1230                 *version = 4;
1231                 return 1;
1232         case 3: /* vers */
1233                 switch (po_get_numeric(options, "vers", &tmp)) {
1234                 case PO_FOUND:
1235                         if (tmp >= 2 && tmp <= 4) {
1236                                 *version = tmp;
1237                                 return 1;
1238                         }
1239                         return 0;
1240                 case PO_NOT_FOUND:
1241                         nfs_error(_("%s: option parsing error\n"),
1242                                         progname);
1243                 case PO_BAD_VALUE:
1244                         return 0;
1245                 }
1246         case 4: /* nfsvers */
1247                 switch (po_get_numeric(options, "nfsvers", &tmp)) {
1248                 case PO_FOUND:
1249                         if (tmp >= 2 && tmp <= 4) {
1250                                 *version = tmp;
1251                                 return 1;
1252                         }
1253                         return 0;
1254                 case PO_NOT_FOUND:
1255                         nfs_error(_("%s: option parsing error\n"),
1256                                         progname);
1257                 case PO_BAD_VALUE:
1258                         return 0;
1259                 }
1260         }
1261
1262         /*
1263          * NFS version wasn't specified.  The pmap version value
1264          * will be filled in later by an rpcbind query in this case.
1265          */
1266         *version = 0;
1267         return 1;
1268 }
1269
1270 /*
1271  * Returns TRUE if @protocol contains a valid value for this option,
1272  * or FALSE if the option was specified with an invalid value.
1273  */
1274 int
1275 nfs_nfs_protocol(struct mount_options *options, unsigned long *protocol)
1276 {
1277         char *option;
1278
1279         switch (po_rightmost(options, nfs_transport_opttbl)) {
1280         case 0: /* udp */
1281                 *protocol = IPPROTO_UDP;
1282                 return 1;
1283         case 1: /* tcp */
1284                 *protocol = IPPROTO_TCP;
1285                 return 1;
1286         case 2: /* proto */
1287                 option = po_get(options, "proto");
1288                 if (option) {
1289                         if (strcmp(option, "tcp") == 0) {
1290                                 *protocol = IPPROTO_TCP;
1291                                 return 1;
1292                         }
1293                         if (strcmp(option, "udp") == 0) {
1294                                 *protocol = IPPROTO_UDP;
1295                                 return 1;
1296                         }
1297                         return 0;
1298                 }
1299         }
1300
1301         /*
1302          * NFS transport protocol wasn't specified.  The pmap
1303          * protocol value will be filled in later by an rpcbind
1304          * query in this case.
1305          */
1306         *protocol = 0;
1307         return 1;
1308 }
1309
1310 /*
1311  * Returns TRUE if @port contains a valid value for this option,
1312  * or FALSE if the option was specified with an invalid value.
1313  */
1314 static int
1315 nfs_nfs_port(struct mount_options *options, unsigned long *port)
1316 {
1317         long tmp;
1318
1319         switch (po_get_numeric(options, "port", &tmp)) {
1320         case PO_NOT_FOUND:
1321                 break;
1322         case PO_FOUND:
1323                 if (tmp >= 1 && tmp <= 65535) {
1324                         *port = tmp;
1325                         return 1;
1326                 }
1327         case PO_BAD_VALUE:
1328                 return 0;
1329         }
1330
1331         /*
1332          * NFS service port wasn't specified.  The pmap port value
1333          * will be filled in later by an rpcbind query in this case.
1334          */
1335         *port = 0;
1336         return 1;
1337 }
1338
1339 /*
1340  * "mountprog" is supported only by the legacy mount command.  The
1341  * kernel mount client does not support this option.
1342  *
1343  * Returns TRUE if @program contains a valid value for this option,
1344  * or FALSE if the option was specified with an invalid value.
1345  */
1346 static int
1347 nfs_mount_program(struct mount_options *options, unsigned long *program)
1348 {
1349         long tmp;
1350
1351         switch (po_get_numeric(options, "mountprog", &tmp)) {
1352         case PO_NOT_FOUND:
1353                 break;
1354         case PO_FOUND:
1355                 if (tmp > 0) {
1356                         *program = tmp;
1357                         return 1;
1358                 }
1359         case PO_BAD_VALUE:
1360                 return 0;
1361         }
1362
1363         /*
1364          * MNT RPC program wasn't specified.  The RPC program
1365          * cannot be determined via an rpcbind query.
1366          */
1367         *program = nfs_getrpcbyname(MOUNTPROG, nfs_mnt_pgmtbl);
1368         return 1;
1369 }
1370
1371 /*
1372  * Returns TRUE if @version contains a valid value for this option,
1373  * or FALSE if the option was specified with an invalid value.
1374  */
1375 static int
1376 nfs_mount_version(struct mount_options *options, unsigned long *version)
1377 {
1378         long tmp;
1379
1380         switch (po_get_numeric(options, "mountvers", &tmp)) {
1381         case PO_NOT_FOUND:
1382                 break;
1383         case PO_FOUND:
1384                 if (tmp >= 1 && tmp <= 4) {
1385                         *version = tmp;
1386                         return 1;
1387                 }
1388         case PO_BAD_VALUE:
1389                 return 0;
1390         }
1391
1392         /*
1393          * MNT version wasn't specified.  The pmap version value
1394          * will be filled in later by an rpcbind query in this case.
1395          */
1396         *version = 0;
1397         return 1;
1398 }
1399
1400 /*
1401  * Returns TRUE if @protocol contains a valid value for this option,
1402  * or FALSE if the option was specified with an invalid value.
1403  */
1404 static int
1405 nfs_mount_protocol(struct mount_options *options, unsigned long *protocol)
1406 {
1407         char *option;
1408
1409         option = po_get(options, "mountproto");
1410         if (option) {
1411                 if (strcmp(option, "tcp") == 0) {
1412                         *protocol = IPPROTO_TCP;
1413                         return 1;
1414                 }
1415                 if (strcmp(option, "udp") == 0) {
1416                         *protocol = IPPROTO_UDP;
1417                         return 1;
1418                 }
1419                 return 0;
1420         }
1421
1422         /*
1423          * MNT transport protocol wasn't specified.  If the NFS
1424          * transport protocol was specified, use that; otherwise
1425          * set @protocol to zero.  The pmap protocol value will
1426          * be filled in later by an rpcbind query in this case.
1427          */
1428         return nfs_nfs_protocol(options, protocol);
1429 }
1430
1431 /*
1432  * Returns TRUE if @port contains a valid value for this option,
1433  * or FALSE if the option was specified with an invalid value.
1434  */
1435 static int
1436 nfs_mount_port(struct mount_options *options, unsigned long *port)
1437 {
1438         long tmp;
1439
1440         switch (po_get_numeric(options, "mountport", &tmp)) {
1441         case PO_NOT_FOUND:
1442                 break;
1443         case PO_FOUND:
1444                 if (tmp >= 1 && tmp <= 65535) {
1445                         *port = tmp;
1446                         return 1;
1447                 }
1448         case PO_BAD_VALUE:
1449                 return 0;
1450         }
1451
1452         /*
1453          * MNT service port wasn't specified.  The pmap port value
1454          * will be filled in later by an rpcbind query in this case.
1455          */
1456         *port = 0;
1457         return 1;
1458 }
1459
1460 /**
1461  * nfs_options2pmap - set up pmap structs based on mount options
1462  * @options: pointer to mount options
1463  * @nfs_pmap: OUT: pointer to pmap arguments for NFS server
1464  * @mnt_pmap: OUT: pointer to pmap arguments for mountd server
1465  *
1466  * Returns TRUE if the pmap options specified in @options have valid
1467  * values; otherwise FALSE is returned.
1468  */
1469 int nfs_options2pmap(struct mount_options *options,
1470                      struct pmap *nfs_pmap, struct pmap *mnt_pmap)
1471 {
1472         if (!nfs_nfs_program(options, &nfs_pmap->pm_prog))
1473                 return 0;
1474         if (!nfs_nfs_version(options, &nfs_pmap->pm_vers))
1475                 return 0;
1476         if (!nfs_nfs_protocol(options, &nfs_pmap->pm_prot))
1477                 return 0;
1478         if (!nfs_nfs_port(options, &nfs_pmap->pm_port))
1479                 return 0;
1480
1481         if (!nfs_mount_program(options, &mnt_pmap->pm_prog))
1482                 return 0;
1483         if (!nfs_mount_version(options, &mnt_pmap->pm_vers))
1484                 return 0;
1485         if (!nfs_mount_protocol(options, &mnt_pmap->pm_prot))
1486                 return 0;
1487         if (!nfs_mount_port(options, &mnt_pmap->pm_port))
1488                 return 0;
1489
1490         return 1;
1491 }