1 /* $NetBSD: getnfsargs.c,v 1.12 2008/10/15 19:06:45 pooka Exp $ */
4 * Copyright (c) 1992, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include <sys/cdefs.h>
37 __COPYRIGHT("@(#) Copyright (c) 1992, 1993, 1994\
38 The Regents of the University of California. All rights reserved.");
43 static char sccsid
[] = "@(#)mount_nfs.c 8.11 (Berkeley) 5/4/95";
45 __RCSID("$NetBSD: getnfsargs.c,v 1.12 2008/10/15 19:06:45 pooka Exp $");
49 #include <sys/param.h>
50 #include <sys/mount.h>
51 #include <sys/socket.h>
56 #include <rpc/pmap_clnt.h>
57 #include <rpc/pmap_prot.h>
60 #include <netiso/iso.h>
64 #include <nfs/rpcv2.h>
65 #include <nfs/nfsproto.h>
67 #include <nfs/nfsmount.h>
69 #include <arpa/inet.h>
82 #include "mount_nfs.h"
89 u_char nfh
[NFSX_V3FHMAX
];
92 static int xdr_dir(XDR
*, char *);
93 static int xdr_fh(XDR
*, struct nfhret
*);
96 getnfsargs(char *spec
, struct nfs_args
*nfsargsp
)
99 struct addrinfo hints
, *ai_nfs
, *ai
;
101 static struct netbuf nfs_nb
;
102 static struct sockaddr_storage nfs_ss
;
103 struct netconfig
*nconf
;
106 static struct sockaddr_iso isoaddr
;
107 struct iso_addr
*isop
;
110 struct timeval pertry
, try;
111 enum clnt_stat clnt_stat
;
112 int i
, nfsvers
, mntvers
;
114 char *hostp
, *delimp
;
115 static struct nfhret nfhret
;
116 static char nam
[MNAMELEN
+ 1];
118 strlcpy(nam
, spec
, sizeof(nam
));
119 if ((delimp
= strchr(spec
, '@')) != NULL
) {
121 } else if ((delimp
= strrchr(spec
, ':')) != NULL
) {
125 warnx("no <host>:<dirpath> or <dirpath>@<host> spec");
130 * DUMB!! Until the mount protocol works on iso transport, we must
131 * supply both an iso and an inet address for the host.
134 if (!strncmp(hostp
, "iso=", 4)) {
139 if ((delimp
= strchr(hostp
, '+')) == NULL
) {
140 warnx("no iso+inet address");
144 if ((isop
= iso_addr(hostp
)) == NULL
) {
145 warnx("bad ISO address");
148 memset(&isoaddr
, 0, sizeof (isoaddr
));
149 memcpy(&isoaddr
.siso_addr
, isop
, sizeof (struct iso_addr
));
150 isoaddr
.siso_len
= sizeof (isoaddr
);
151 isoaddr
.siso_family
= AF_ISO
;
152 isoaddr
.siso_tlen
= 2;
153 isoport
= htons(NFS_PORT
);
154 memcpy(TSEL(&isoaddr
), &isoport
, isoaddr
.siso_tlen
);
160 * Handle an internet host address.
162 memset(&hints
, 0, sizeof hints
);
163 hints
.ai_flags
= AI_NUMERICHOST
;
164 hints
.ai_socktype
= nfsargsp
->sotype
;
165 if (getaddrinfo(hostp
, "nfs", &hints
, &ai_nfs
) != 0) {
167 if ((ecode
= getaddrinfo(hostp
, "nfs", &hints
, &ai_nfs
)) != 0) {
168 warnx("can't get net id for host \"%s\": %s", hostp
,
169 gai_strerror(ecode
));
174 if ((nfsargsp
->flags
& NFSMNT_NFSV3
) != 0) {
176 mntvers
= RPCMNT_VER3
;
179 mntvers
= RPCMNT_VER1
;
181 nfhret
.stat
= EACCES
; /* Mark not yet successful */
183 for (ai
= ai_nfs
; ai
; ai
= ai
->ai_next
) {
185 * XXX. Need a generic (family, type, proto) -> nconf interface.
186 * __rpc_*2nconf exist, maybe they should be exported.
188 if (nfsargsp
->sotype
== SOCK_STREAM
) {
189 if (ai
->ai_family
== AF_INET6
)
194 if (ai
->ai_family
== AF_INET6
)
200 nconf
= getnetconfigent(netid
);
203 retryleft
= retrycnt
;
205 while (retryleft
> 0) {
206 nfs_nb
.buf
= &nfs_ss
;
207 nfs_nb
.maxlen
= sizeof nfs_ss
;
208 if (!rpcb_getaddr(RPCPROG_NFS
, nfsvers
, nconf
, &nfs_nb
, hostp
)){
209 if (rpc_createerr
.cf_stat
== RPC_SYSTEMERROR
) {
210 nfhret
.stat
= rpc_createerr
.cf_error
.re_errno
;
213 if (rpc_createerr
.cf_stat
== RPC_UNKNOWNPROTO
) {
214 nfhret
.stat
= EPROTONOSUPPORT
;
217 if ((opflags
& ISBGRND
) == 0) {
220 snprintf(buf
, sizeof(buf
),
221 "%s: rpcbind to nfs on server",
223 clnt_pcreateerror(buf
);
229 * XXX relies on clnt_tcp_create to bind to a reserved
232 clp
= clnt_tp_create(hostp
, RPCPROG_MNT
, mntvers
,
233 mnttcp_ok
? nconf
: getnetconfigent("udp"));
235 if ((opflags
& ISBGRND
) == 0) {
237 "Cannot MNT RPC (mountd)");
240 CLNT_CONTROL(clp
, CLSET_RETRY_TIMEOUT
,
242 clp
->cl_auth
= authsys_create_default();
245 nfhret
.auth
= RPCAUTH_UNIX
;
246 nfhret
.vers
= mntvers
;
247 clnt_stat
= clnt_call(clp
, RPCMNT_MOUNT
,
248 xdr_dir
, spec
, xdr_fh
, &nfhret
, try);
250 case RPC_PROGVERSMISMATCH
:
251 if (nfsvers
== NFS_VER3
&& !force3
) {
253 mntvers
= RPCMNT_VER1
;
258 errx(1, "%s", clnt_sperror(clp
,
262 auth_destroy(clp
->cl_auth
);
267 /* XXX should give up on some errors */
268 if ((opflags
& ISBGRND
) == 0)
269 warnx("%s", clnt_sperror(clp
,
275 if (--retryleft
> 0) {
276 if (opflags
& BGRND
) {
278 if ((i
= fork()) != 0) {
284 (void) close(STDIN_FILENO
);
285 (void) close(STDOUT_FILENO
);
286 (void) close(STDERR_FILENO
);
293 if (nfhret
.stat
== 0)
296 freeaddrinfo(ai_nfs
);
298 if (opflags
& ISBGRND
)
301 warnx("can't access %s: %s", spec
, strerror(nfhret
.stat
));
306 nfsargsp
->addr
= (struct sockaddr
*) &isoaddr
;
307 nfsargsp
->addrlen
= sizeof (isoaddr
);
311 nfsargsp
->addr
= (struct sockaddr
*) nfs_nb
.buf
;
312 nfsargsp
->addrlen
= nfs_nb
.len
;
314 struct sockaddr
*sa
= nfsargsp
->addr
;
315 switch (sa
->sa_family
) {
317 ((struct sockaddr_in
*)sa
)->sin_port
= port
;
321 ((struct sockaddr_in6
*)sa
)->sin6_port
= port
;
325 errx(1, "Unsupported socket family %d",
330 nfsargsp
->fh
= nfhret
.nfh
;
331 nfsargsp
->fhsize
= nfhret
.fhsize
;
332 nfsargsp
->hostname
= nam
;
337 * xdr routines for mount rpc's
340 xdr_dir(XDR
*xdrsp
, char *dirp
)
342 return (xdr_string(xdrsp
, &dirp
, RPCMNT_PATHLEN
));
346 xdr_fh(XDR
*xdrsp
, struct nfhret
*np
)
349 long auth
, authcnt
, authfnd
= 0;
351 if (!xdr_u_long(xdrsp
, &np
->stat
))
357 np
->fhsize
= NFSX_V2FH
;
358 return (xdr_opaque(xdrsp
, (caddr_t
)np
->nfh
, NFSX_V2FH
));
360 if (!xdr_long(xdrsp
, &np
->fhsize
))
362 if (np
->fhsize
<= 0 || np
->fhsize
> NFSX_V3FHMAX
)
364 if (!xdr_opaque(xdrsp
, (caddr_t
)np
->nfh
, np
->fhsize
))
366 if (!xdr_long(xdrsp
, &authcnt
))
368 for (i
= 0; i
< authcnt
; i
++) {
369 if (!xdr_long(xdrsp
, &auth
))
371 if (auth
== np
->auth
)
375 * Some servers, such as DEC's OSF/1 return a nil authenticator
376 * list to indicate RPCAUTH_UNIX.
378 if (!authfnd
&& (authcnt
> 0 || np
->auth
!= RPCAUTH_UNIX
))