4 * Copyright (c) 1997-2009 Erez Zadok
5 * Copyright (c) 1990 Jan-Simon Pendry
6 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
7 * Copyright (c) 1990 The Regents of the University of California.
10 * This code is derived from software contributed to Berkeley by
11 * Jan-Simon Pendry at Imperial College, London.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgment:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * File: am-utils/conf/transp/transp_tli.c
44 * TLI specific utilities.
45 * -Erez Zadok <ezk@cs.columbia.edu>
50 #endif /* HAVE_CONFIG_H */
54 struct netconfig
*nfsncp
;
58 * find the IP address that can be used to connect to the local host
61 amu_get_myaddress(struct in_addr
*iap
, const char *preferred_localhost
)
65 struct netconfig
*ncp
;
66 struct nd_addrlist
*addrs
= (struct nd_addrlist
*) NULL
;
67 struct nd_hostserv service
;
69 handlep
= setnetconfig();
70 ncp
= getnetconfig(handlep
);
71 service
.h_host
= (preferred_localhost
? (char *) preferred_localhost
: HOST_SELF_CONNECT
);
72 service
.h_serv
= (char *) NULL
;
74 ret
= netdir_getbyname(ncp
, &service
, &addrs
);
76 if (ret
|| !addrs
|| addrs
->n_cnt
< 1) {
77 plog(XLOG_FATAL
, "cannot get local host address. using 127.0.0.1");
78 iap
->s_addr
= htonl(INADDR_LOOPBACK
);
81 * XXX: there may be more more than one address for this local
82 * host. Maybe something can be done with those.
84 struct sockaddr_in
*sinp
= (struct sockaddr_in
*) addrs
->n_addrs
[0].buf
;
86 if (preferred_localhost
)
87 plog(XLOG_INFO
, "localhost_address \"%s\" requested, using %s",
88 preferred_localhost
, inet_dquad(dq
, sizeof(dq
), iap
->s_addr
));
89 iap
->s_addr
= sinp
->sin_addr
.s_addr
; /* XXX: used to be htonl() */
92 endnetconfig(handlep
); /* free's up internal resources too */
93 netdir_free((voidp
) addrs
, ND_ADDRLIST
);
98 * How to bind to reserved ports.
99 * TLI handle (socket) and port version.
102 bind_resv_port(int td
, u_short
*pp
)
105 struct t_bind
*treq
, *tret
;
106 struct sockaddr_in
*sin
;
108 treq
= (struct t_bind
*) t_alloc(td
, T_BIND
, T_ADDR
);
110 plog(XLOG_ERROR
, "t_alloc req");
113 tret
= (struct t_bind
*) t_alloc(td
, T_BIND
, T_ADDR
);
115 t_free((char *) treq
, T_BIND
);
116 plog(XLOG_ERROR
, "t_alloc ret");
119 memset((char *) treq
->addr
.buf
, 0, treq
->addr
.len
);
120 sin
= (struct sockaddr_in
*) treq
->addr
.buf
;
121 sin
->sin_family
= AF_INET
;
122 treq
->qlen
= 64; /* 0 is ok for udp, for tcp you need qlen>0 */
123 treq
->addr
.len
= treq
->addr
.maxlen
;
125 port
= IPPORT_RESERVED
;
129 sin
->sin_port
= htons(port
);
130 rc
= t_bind(td
, treq
, tret
);
132 plog(XLOG_ERROR
, "t_bind");
134 if (memcmp(treq
->addr
.buf
, tret
->addr
.buf
, tret
->addr
.len
) == 0)
139 } while ((rc
< 0 || errno
== EADDRINUSE
) && (int) port
> IPPORT_RESERVED
/ 2);
145 plog(XLOG_ERROR
, "could not t_bind to any reserved port");
147 t_free((char *) tret
, T_BIND
);
148 t_free((char *) treq
, T_BIND
);
156 * close a descriptor, TLI style
166 * Create an rpc client attached to the mount daemon.
169 get_mount_client(char *host
, struct sockaddr_in
*unused_sin
, struct timeval
*tv
, int *sock
, u_long mnt_version
)
173 struct netconfig
*nc
= NULL
;
174 struct sockaddr_in sin
;
176 nb
.maxlen
= sizeof(sin
);
177 nb
.buf
= (char *) &sin
;
180 * First try a TCP handler
184 * Find mountd address on TCP
186 if ((nc
= getnetconfigent(NC_TCP
)) == NULL
) {
187 plog(XLOG_ERROR
, "getnetconfig for tcp failed: %s", nc_sperror());
190 if (!rpcb_getaddr(MOUNTPROG
, mnt_version
, nc
, &nb
, host
)) {
192 * don't print error messages here, since mountd might legitimately
198 * Create privileged TCP socket
200 *sock
= t_open(nc
->nc_device
, O_RDWR
, 0);
203 plog(XLOG_ERROR
, "t_open %s: %m", nc
->nc_device
);
206 if (bind_resv_port(*sock
, (u_short
*) NULL
) < 0)
207 plog(XLOG_ERROR
, "couldn't bind mountd socket to privileged port");
209 if ((client
= clnt_vc_create(*sock
, &nb
, MOUNTPROG
, mnt_version
, 0, 0))
210 == (CLIENT
*) NULL
) {
211 plog(XLOG_ERROR
, "clnt_vc_create failed");
216 dlog("get_mount_client: using tcp, port %d", sin
.sin_port
);
218 freenetconfigent(nc
);
222 /* first free possibly previously allocated netconfig entry */
224 freenetconfigent(nc
);
227 * TCP failed so try UDP
231 * Find mountd address on UDP
233 if ((nc
= getnetconfigent(NC_UDP
)) == NULL
) {
234 plog(XLOG_ERROR
, "getnetconfig for udp failed: %s", nc_sperror());
237 if (!rpcb_getaddr(MOUNTPROG
, mnt_version
, nc
, &nb
, host
)) {
238 plog(XLOG_ERROR
, "%s",
239 clnt_spcreateerror("couldn't get mountd address on udp"));
243 * Create privileged UDP socket
245 *sock
= t_open(nc
->nc_device
, O_RDWR
, 0);
248 plog(XLOG_ERROR
, "t_open %s: %m", nc
->nc_device
);
249 goto badout
; /* neither tcp not udp succeeded */
251 if (bind_resv_port(*sock
, (u_short
*) NULL
) < 0)
252 plog(XLOG_ERROR
, "couldn't bind mountd socket to privileged port");
254 if ((client
= clnt_dg_create(*sock
, &nb
, MOUNTPROG
, mnt_version
, 0, 0))
255 == (CLIENT
*) NULL
) {
256 plog(XLOG_ERROR
, "clnt_dg_create failed");
258 goto badout
; /* neither tcp not udp succeeded */
260 if (clnt_control(client
, CLSET_RETRY_TIMEOUT
, (char *) tv
) == FALSE
) {
261 plog(XLOG_ERROR
, "clnt_control CLSET_RETRY_TIMEOUT for udp failed");
262 clnt_destroy(client
);
263 goto badout
; /* neither tcp not udp succeeded */
266 dlog("get_mount_client: using udp, port %d", sin
.sin_port
);
272 freenetconfigent(nc
);
277 #ifdef NOT_NEEDED_ON_TLI_SYSTEMS
279 * find the address of the caller of an RPC procedure.
282 amu_svc_getcaller(SVCXPRT
*xprt
)
285 * On TLI systems we don't use an INET network type, but a "ticlts" (see
286 * /etc/netconfig). This means that packets could only come from the
287 * loopback interface, and we don't need to check them and filter possibly
288 * spoofed packets. Therefore we simply return NULL here, and the caller
289 * will ignore the result.
291 return NULL
; /* tell called to ignore check */
293 #endif /* NOT_NEEDED_ON_TLI_SYSTEMS */
297 * Register an RPC server:
298 * return 1 on success, 0 otherwise.
301 amu_svc_register(SVCXPRT
*xprt
, u_long prognum
, u_long versnum
,
302 void (*dispatch
)(struct svc_req
*rqstp
, SVCXPRT
*xprt
),
303 u_long protocol
, struct netconfig
*ncp
)
305 /* on TLI: svc_reg returns 1 on success, 0 otherwise */
306 return svc_reg(xprt
, prognum
, versnum
, dispatch
, ncp
);
311 * Bind to reserved UDP port, for NFS service only.
315 bind_resv_port_only_udp(u_short
*pp
)
317 int td
, rc
= -1, port
;
318 struct t_bind
*treq
, *tret
;
319 struct sockaddr_in
*sin
;
320 extern char *t_errlist
[];
322 struct netconfig
*nc
= (struct netconfig
*) NULL
;
325 if ((nc_handle
= setnetconfig()) == (voidp
) NULL
) {
326 plog(XLOG_ERROR
, "Cannot rewind netconfig: %s", nc_sperror());
330 * Search the netconfig table for INET/UDP.
331 * This loop will terminate if there was an error in the /etc/netconfig
332 * file or if you reached the end of the file without finding the udp
333 * device. Either way your machine has probably far more problems (for
334 * example, you cannot have nfs v2 w/o UDP).
337 if ((nc
= getnetconfig(nc_handle
)) == (struct netconfig
*) NULL
) {
338 plog(XLOG_ERROR
, "Error accessing getnetconfig: %s", nc_sperror());
339 endnetconfig(nc_handle
);
342 if (STREQ(nc
->nc_protofmly
, NC_INET
) &&
343 STREQ(nc
->nc_proto
, NC_UDP
))
348 * This is the primary reason for the getnetconfig code above: to get the
349 * correct device name to udp, and t_open a descriptor to be used in
352 td
= t_open(nc
->nc_device
, O_RDWR
, (struct t_info
*) NULL
);
353 endnetconfig(nc_handle
);
356 plog(XLOG_ERROR
, "t_open failed: %d: %s", t_errno
, t_errlist
[t_errno
]);
359 treq
= (struct t_bind
*) t_alloc(td
, T_BIND
, T_ADDR
);
361 plog(XLOG_ERROR
, "t_alloc req");
364 tret
= (struct t_bind
*) t_alloc(td
, T_BIND
, T_ADDR
);
366 t_free((char *) treq
, T_BIND
);
367 plog(XLOG_ERROR
, "t_alloc ret");
370 memset((char *) treq
->addr
.buf
, 0, treq
->addr
.len
);
371 sin
= (struct sockaddr_in
*) treq
->addr
.buf
;
372 sin
->sin_family
= AF_INET
;
373 treq
->qlen
= 64; /* 0 is ok for udp, for tcp you need qlen>0 */
374 treq
->addr
.len
= treq
->addr
.maxlen
;
378 sin
->sin_port
= htons(*pp
);
379 rc
= t_bind(td
, treq
, tret
);
381 port
= IPPORT_RESERVED
;
385 sin
->sin_port
= htons(port
);
386 rc
= t_bind(td
, treq
, tret
);
388 plog(XLOG_ERROR
, "t_bind for port %d: %s", port
, t_errlist
[t_errno
]);
390 if (memcmp(treq
->addr
.buf
, tret
->addr
.buf
, tret
->addr
.len
) == 0)
395 } while ((rc
< 0 || errno
== EADDRINUSE
) && (int) port
> IPPORT_RESERVED
/ 2);
401 t_free((char *) tret
, T_BIND
);
402 t_free((char *) treq
, T_BIND
);
408 * Bind NFS to a reserved port.
411 bind_nfs_port(int unused_so
, u_short
*nfs_portp
)
414 int error
= bind_resv_port_only_udp(&port
);
423 * Create the nfs service for amd
424 * return 0 (TRUE) if OK, 1 (FALSE) if failed.
427 create_nfs_service(int *soNFSp
, u_short
*nfs_portp
, SVCXPRT
**nfs_xprtp
, void (*dispatch_fxn
)(struct svc_req
*rqstp
, SVCXPRT
*transp
))
429 char *nettype
= "ticlts";
431 nfsncp
= getnetconfigent(nettype
);
432 if (nfsncp
== NULL
) {
433 plog(XLOG_ERROR
, "cannot getnetconfigent for %s", nettype
);
434 /* failed with ticlts, try plain udp (hpux11) */
436 nfsncp
= getnetconfigent(nettype
);
437 if (nfsncp
== NULL
) {
438 plog(XLOG_ERROR
, "cannot getnetconfigent for %s", nettype
);
442 *nfs_xprtp
= svc_tli_create(RPC_ANYFD
, nfsncp
, NULL
, 0, 0);
443 if (*nfs_xprtp
== NULL
) {
444 plog(XLOG_ERROR
, "cannot create nfs tli service for amd");
449 * Get the service file descriptor and check its number to see if
450 * the t_open failed. If it succeeded, then go on to binding to a
453 *soNFSp
= (*nfs_xprtp
)->xp_fd
;
454 if (*soNFSp
< 0 || bind_nfs_port(*soNFSp
, nfs_portp
) < 0) {
455 plog(XLOG_ERROR
, "Can't create privileged nfs port (TLI)");
456 svc_destroy(*nfs_xprtp
);
459 if (svc_reg(*nfs_xprtp
, NFS_PROGRAM
, NFS_VERSION
, dispatch_fxn
, NULL
) != 1) {
460 plog(XLOG_ERROR
, "could not register amd NFS service");
461 svc_destroy(*nfs_xprtp
);
465 return 0; /* all is well */
470 * Bind to preferred AMQ port.
473 bind_preferred_amq_port(u_short pref_port
,
474 const struct netconfig
*ncp
,
475 struct t_bind
**tretpp
)
477 int td
= -1, rc
= -1;
479 struct sockaddr_in
*sin
, *sin2
;
480 extern char *t_errlist
[];
484 plog(XLOG_ERROR
, "null ncp");
488 td
= t_open(ncp
->nc_device
, O_RDWR
, (struct t_info
*) NULL
);
490 plog(XLOG_ERROR
, "t_open failed: %d: %s", t_errno
, t_errlist
[t_errno
]);
493 treq
= (struct t_bind
*) t_alloc(td
, T_BIND
, T_ADDR
);
495 plog(XLOG_ERROR
, "t_alloc req");
498 *tretpp
= (struct t_bind
*) t_alloc(td
, T_BIND
, T_ADDR
);
500 t_free((char *) treq
, T_BIND
);
501 plog(XLOG_ERROR
, "t_alloc tretpp");
504 memset((char *) treq
->addr
.buf
, 0, treq
->addr
.len
);
505 sin
= (struct sockaddr_in
*) treq
->addr
.buf
;
506 sin
->sin_family
= AF_INET
;
507 treq
->qlen
= 64; /* must be greater than 0 to work for TCP connections */
508 treq
->addr
.len
= treq
->addr
.maxlen
;
511 sin
->sin_port
= htons(pref_port
);
512 sin
->sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
); /* XXX: may not be needed */
513 rc
= t_bind(td
, treq
, *tretpp
);
515 plog(XLOG_ERROR
, "t_bind return err %d", rc
);
518 /* check if we got the port we asked for */
519 sin2
= (struct sockaddr_in
*) (*tretpp
)->addr
.buf
;
520 if (sin
->sin_port
!= sin2
->sin_port
) {
521 plog(XLOG_ERROR
, "asked for port %d, got different one (%d)",
522 ntohs(sin
->sin_port
), ntohs(sin2
->sin_port
));
523 t_errno
= TNOADDR
; /* XXX: is this correct? */
527 if (sin
->sin_addr
.s_addr
!= sin2
->sin_addr
.s_addr
) {
528 plog(XLOG_ERROR
, "asked for address %x, got different one (%x)",
529 (int) ntohl(sin
->sin_addr
.s_addr
), (int) ntohl(sin2
->sin_addr
.s_addr
));
530 t_errno
= TNOADDR
; /* XXX: is this correct? */
536 t_free((char *) treq
, T_BIND
);
537 return (rc
< 0 ? rc
: td
);
542 * Create the amq service for amd (both TCP and UDP)
545 create_amq_service(int *udp_soAMQp
,
547 struct netconfig
**udp_amqncpp
,
550 struct netconfig
**tcp_amqncpp
,
551 u_short preferred_amq_port
)
554 * (partially) create the amq service for amd
555 * to be completed further in by caller.
556 * XXX: is this "partially" still true?! See amd/nfs_start.c. -Erez
559 /* first create the TCP service */
561 if ((*tcp_amqncpp
= getnetconfigent(NC_TCP
)) == NULL
) {
562 plog(XLOG_ERROR
, "cannot getnetconfigent for %s", NC_TCP
);
567 if (preferred_amq_port
> 0) {
568 struct t_bind
*tbp
= NULL
;
571 plog(XLOG_INFO
, "requesting preferred amq TCP port %d", preferred_amq_port
);
572 sock
= bind_preferred_amq_port(preferred_amq_port
, *tcp_amqncpp
, &tbp
);
574 plog(XLOG_ERROR
, "bind_preferred_amq_port failed for TCP port %d: %s",
575 preferred_amq_port
, t_errlist
[t_errno
]);
578 *tcp_amqpp
= svc_tli_create(sock
, *tcp_amqncpp
, tbp
, 0, 0);
579 if (*tcp_amqpp
!= NULL
)
580 plog(XLOG_INFO
, "amq service bound to TCP port %d", preferred_amq_port
);
581 t_free((char *) tbp
, T_BIND
);
583 /* select any port */
584 *tcp_amqpp
= svc_tli_create(RPC_ANYFD
, *tcp_amqncpp
, NULL
, 0, 0);
586 if (*tcp_amqpp
== NULL
) {
587 plog(XLOG_ERROR
, "cannot create (tcp) tli service for amq");
591 if (tcp_soAMQp
&& tcp_amqpp
)
592 *tcp_soAMQp
= (*tcp_amqpp
)->xp_fd
;
594 /* next create the UDP service */
596 if ((*udp_amqncpp
= getnetconfigent(NC_UDP
)) == NULL
) {
597 plog(XLOG_ERROR
, "cannot getnetconfigent for %s", NC_UDP
);
601 if (preferred_amq_port
> 0) {
602 struct t_bind
*tbp
= NULL
;
605 plog(XLOG_INFO
, "requesting preferred amq UDP port %d", preferred_amq_port
);
606 sock
= bind_preferred_amq_port(preferred_amq_port
, *udp_amqncpp
, &tbp
);
608 plog(XLOG_ERROR
, "bind_preferred_amq_port failed for UDP port %d: %s",
609 preferred_amq_port
, t_errlist
[t_errno
]);
612 *udp_amqpp
= svc_tli_create(sock
, *udp_amqncpp
, tbp
, 0, 0);
613 if (*udp_amqpp
!= NULL
)
614 plog(XLOG_INFO
, "amq service bound to UDP port %d", preferred_amq_port
);
615 t_free((char *) tbp
, T_BIND
);
617 /* select any port */
618 *udp_amqpp
= svc_tli_create(RPC_ANYFD
, *udp_amqncpp
, NULL
, 0, 0);
620 if (*udp_amqpp
== NULL
) {
621 plog(XLOG_ERROR
, "cannot create (udp) tli service for amq");
625 if (udp_soAMQp
&& udp_amqpp
)
626 *udp_soAMQp
= (*udp_amqpp
)->xp_fd
;
628 return 0; /* all is well */
633 * Find netconfig info for TCP/UDP device, and fill in the knetconfig
634 * structure. If in_ncp is not NULL, use that instead of defaulting
635 * to a TCP/UDP service. If in_ncp is NULL, then use the service type
636 * specified in nc_protoname (which may be either "tcp" or "udp"). If
637 * nc_protoname is NULL, default to UDP.
640 get_knetconfig(struct knetconfig
**kncpp
, struct netconfig
*in_ncp
, char *nc_protoname
)
642 struct netconfig
*ncp
= NULL
;
649 ncp
= getnetconfigent(nc_protoname
);
651 ncp
= getnetconfigent(NC_UDP
);
656 *kncpp
= (struct knetconfig
*) xzalloc(sizeof(struct knetconfig
));
657 if (*kncpp
== (struct knetconfig
*) NULL
) {
659 freenetconfigent(ncp
);
662 (*kncpp
)->knc_semantics
= ncp
->nc_semantics
;
663 (*kncpp
)->knc_protofmly
= strdup(ncp
->nc_protofmly
);
664 (*kncpp
)->knc_proto
= strdup(ncp
->nc_proto
);
666 if (stat(ncp
->nc_device
, &statbuf
) < 0) {
667 plog(XLOG_ERROR
, "could not stat() %s: %m", ncp
->nc_device
);
671 freenetconfigent(ncp
);
672 return -3; /* amd will end (free not needed) */
674 (*kncpp
)->knc_rdev
= (dev_t
) statbuf
.st_rdev
;
675 if (!in_ncp
) { /* free only if argument not passed */
676 freenetconfigent(ncp
);
684 * Free a previously allocated knetconfig structure.
687 free_knetconfig(struct knetconfig
*kncp
)
690 if (kncp
->knc_protofmly
)
691 XFREE(kncp
->knc_protofmly
);
693 XFREE(kncp
->knc_proto
);
695 kncp
= (struct knetconfig
*) NULL
;
701 * Check if the portmapper is running and reachable: 0==down, 1==up
703 int check_pmap_up(char *host
, struct sockaddr_in
* sin
)
706 enum clnt_stat clnt_stat
= RPC_TIMEDOUT
; /* assume failure */
707 int socket
= RPC_ANYSOCK
;
708 struct timeval timeout
;
712 sin
->sin_port
= htons(PMAPPORT
);
713 client
= clntudp_create(sin
, PMAPPROG
, PMAPVERS
, timeout
, &socket
);
714 if (client
== (CLIENT
*) NULL
) {
716 "check_pmap_up: cannot create connection to contact portmapper on host \"%s\"%s",
717 host
, clnt_spcreateerror(""));
722 /* Ping the portmapper on a remote system by calling the nullproc */
723 clnt_stat
= clnt_call(client
,
725 (XDRPROC_T_TYPE
) xdr_void
,
727 (XDRPROC_T_TYPE
) xdr_void
,
730 clnt_destroy(client
);
734 if (clnt_stat
== RPC_TIMEDOUT
) {
736 "check_pmap_up: failed to contact portmapper on host \"%s\": %s",
737 host
, clnt_sperrno(clnt_stat
));
745 * Find the best NFS version for a host.
748 get_nfs_version(char *host
, struct sockaddr_in
*sin
, u_long nfs_version
, const char *proto
)
755 * If not set or set wrong, then try from NFS_VERS_MAX on down. If
756 * set, then try from nfs_version on down.
758 if (nfs_version
<= 0 || nfs_version
> NFS_VERS_MAX
) {
759 nfs_version
= NFS_VERS_MAX
;
762 if (nfs_version
== NFS_VERSION
) {
763 dlog("get_nfs_version trying NFS(%d,%s) for %s",
764 (int) nfs_version
, proto
, host
);
766 dlog("get_nfs_version trying NFS(%d-%d,%s) for %s",
767 (int) NFS_VERSION
, (int) nfs_version
, proto
, host
);
770 /* 3 seconds is more than enough for a LAN */
771 memset(&tv
, 0, sizeof(tv
));
775 #ifdef HAVE_CLNT_CREATE_VERS_TIMED
776 clnt
= clnt_create_vers_timed(host
, NFS_PROGRAM
, &versout
, NFS_VERSION
, nfs_version
, proto
, &tv
);
777 #else /* not HAVE_CLNT_CREATE_VERS_TIMED */
778 clnt
= clnt_create_vers(host
, NFS_PROGRAM
, &versout
, NFS_VERSION
, nfs_version
, proto
);
779 #endif /* not HAVE_CLNT_CREATE_VERS_TIMED */
782 if (nfs_version
== NFS_VERSION
)
783 plog(XLOG_INFO
, "get_nfs_version NFS(%d,%s) failed for %s: %s",
784 (int) nfs_version
, proto
, host
, clnt_spcreateerror(""));
786 plog(XLOG_INFO
, "get_nfs_version NFS(%d-%d,%s) failed for %s: %s",
787 (int) NFS_VERSION
, (int) nfs_version
, proto
, host
, clnt_spcreateerror(""));
796 #if defined(HAVE_FS_AUTOFS) && defined(AUTOFS_PROG)
798 * find the IP address that can be used to connect autofs service to.
801 get_autofs_address(struct netconfig
*ncp
, struct t_bind
*tbp
)
804 struct nd_addrlist
*addrs
= (struct nd_addrlist
*) NULL
;
805 struct nd_hostserv service
;
807 service
.h_host
= HOST_SELF_CONNECT
;
808 service
.h_serv
= "autofs";
810 ret
= netdir_getbyname(ncp
, &service
, &addrs
);
813 plog(XLOG_FATAL
, "get_autofs_address: cannot get local host address: %s", netdir_sperror());
818 * XXX: there may be more more than one address for this local
819 * host. Maybe something can be done with those.
821 tbp
->addr
.len
= addrs
->n_addrs
->len
;
822 tbp
->addr
.maxlen
= addrs
->n_addrs
->len
;
823 memcpy(tbp
->addr
.buf
, addrs
->n_addrs
->buf
, addrs
->n_addrs
->len
);
825 * qlen should not be zero for TCP connections. It's not clear what it
826 * should be for UDP connections, but setting it to something like 64 seems
827 * to be the safe value that works.
832 netdir_free((voidp
) addrs
, ND_ADDRLIST
);
840 * Register the autofs service for amd
843 register_autofs_service(char *autofs_conftype
,
844 void (*autofs_dispatch
)(struct svc_req
*rqstp
, SVCXPRT
*xprt
))
846 struct t_bind
*tbp
= NULL
;
847 struct netconfig
*autofs_ncp
;
848 SVCXPRT
*autofs_xprt
= NULL
;
849 int fd
= -1, err
= 1; /* assume failed */
851 plog(XLOG_INFO
, "registering autofs service: %s", autofs_conftype
);
852 autofs_ncp
= getnetconfigent(autofs_conftype
);
853 if (autofs_ncp
== NULL
) {
854 plog(XLOG_ERROR
, "register_autofs_service: cannot getnetconfigent for %s", autofs_conftype
);
858 fd
= t_open(autofs_ncp
->nc_device
, O_RDWR
, NULL
);
860 plog(XLOG_ERROR
, "register_autofs_service: t_open failed (%s)",
865 tbp
= (struct t_bind
*) t_alloc(fd
, T_BIND
, T_ADDR
);
867 plog(XLOG_ERROR
, "register_autofs_service: t_alloc failed");
871 if (get_autofs_address(autofs_ncp
, tbp
) != 0) {
872 plog(XLOG_ERROR
, "register_autofs_service: get_autofs_address failed");
876 autofs_xprt
= svc_tli_create(fd
, autofs_ncp
, tbp
, 0, 0);
877 if (autofs_xprt
== NULL
) {
878 plog(XLOG_ERROR
, "cannot create autofs tli service for amd");
882 rpcb_unset(AUTOFS_PROG
, AUTOFS_VERS
, autofs_ncp
);
883 if (svc_reg(autofs_xprt
, AUTOFS_PROG
, AUTOFS_VERS
, autofs_dispatch
, autofs_ncp
) == FALSE
) {
884 plog(XLOG_ERROR
, "could not register amd AUTOFS service");
892 freenetconfigent(autofs_ncp
);
894 SVC_DESTROY(autofs_xprt
);
902 t_free((char *) tbp
, T_BIND
);
904 dlog("register_autofs_service: returning %d\n", err
);
910 unregister_autofs_service(char *autofs_conftype
)
912 struct netconfig
*autofs_ncp
;
915 plog(XLOG_INFO
, "unregistering autofs service listener: %s", autofs_conftype
);
917 autofs_ncp
= getnetconfigent(autofs_conftype
);
918 if (autofs_ncp
== NULL
) {
919 plog(XLOG_ERROR
, "destroy_autofs_service: cannot getnetconfigent for %s", autofs_conftype
);
924 rpcb_unset(AUTOFS_PROG
, AUTOFS_VERS
, autofs_ncp
);
927 #endif /* HAVE_FS_AUTOFS && AUTOFS_PROG */