diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 06:03:02 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 06:03:02 +0000 |
commit | 4897093455a2bf08f3db3a1132cc2f6f5484d77c (patch) | |
tree | 9e6373544263f003139431fb4b08f9766e1ed530 /support/nfs/rpcmisc.c | |
parent | Initial commit. (diff) | |
download | nfs-utils-upstream.tar.xz nfs-utils-upstream.zip |
Adding upstream version 1:2.6.4.upstream/1%2.6.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'support/nfs/rpcmisc.c')
-rw-r--r-- | support/nfs/rpcmisc.c | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/support/nfs/rpcmisc.c b/support/nfs/rpcmisc.c new file mode 100644 index 0000000..d84c04f --- /dev/null +++ b/support/nfs/rpcmisc.c @@ -0,0 +1,213 @@ +/* + * Miscellaneous functions for RPC service startup and shutdown. + * + * This code is partially snarfed from rpcgen -s tcp -s udp, + * partly written by Mark Shand, Donald Becker, and Rick + * Sladkey. It was tweaked slightly by Olaf Kirch to be + * usable by both unfsd and mountd. + * + * This software may be used for any purpose provided + * the above copyright notice is retained. It is supplied + * as is, with no warranty expressed or implied. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <rpc/rpc.h> +#include <rpc/pmap_clnt.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <fcntl.h> +#include <memory.h> +#include <errno.h> +#include <unistd.h> +#include <time.h> +#include "nfslib.h" +#include "rpcmisc.h" + +#if SIZEOF_SOCKLEN_T - 0 == 0 +#define socklen_t int +#endif + +#define _RPCSVC_CLOSEDOWN 120 +int _rpcpmstart = 0; +unsigned int _rpcprotobits = (NFSCTL_UDPBIT|NFSCTL_TCPBIT); +int _rpcsvcdirty = 0; + +static void +closedown(int sig) +{ + (void) signal(sig, closedown); + + if (_rpcsvcdirty == 0) { + static int size; + int i, openfd; + + if (NFSCTL_TCPISSET(_rpcprotobits) == 0) + exit(0); + + if (size == 0) + size = getdtablesize(); + + for (i = 0, openfd = 0; i < size && openfd < 2; i++) + if (FD_ISSET(i, &svc_fdset)) + openfd++; + if (openfd <= 1) + exit(0); + } + + (void) alarm(_RPCSVC_CLOSEDOWN); +} + +/* + * Create listener socket for a given port + * + * Return an open network socket on success; otherwise return -1 + * if some error occurs. + */ +static int +makesock(int port, int proto) +{ + struct sockaddr_in sin; + int sock, sock_type, val; + + sock_type = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM; + sock = socket(AF_INET, sock_type, proto); + if (sock < 0) { + xlog(L_FATAL, "Could not make a socket: %s", + strerror(errno)); + return -1; + } + memset((char *) &sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = htonl(INADDR_ANY); + sin.sin_port = htons(port); + + val = 1; + if (proto == IPPROTO_TCP) + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, + &val, sizeof(val)) < 0) + xlog(L_ERROR, "setsockopt failed: %s", + strerror(errno)); + + if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) == -1) { + xlog(L_FATAL, "Could not bind name to socket: %s", + strerror(errno)); + close(sock); + return -1; + } + + return svcsock_nonblock(sock); +} + +void +rpc_init(char *name, int prog, int vers, + void (*dispatch)(struct svc_req *, register SVCXPRT *), + int defport) +{ + struct sockaddr_in saddr; + SVCXPRT *transp; + int sock; + socklen_t asize; + + asize = sizeof(saddr); + sock = 0; + if (getsockname(0, (struct sockaddr *) &saddr, &asize) == 0 + && saddr.sin_family == AF_INET) { + socklen_t ssize = sizeof(int); + int fdtype = 0; + if (getsockopt(0, SOL_SOCKET, SO_TYPE, + (char *)&fdtype, &ssize) == -1) + xlog(L_FATAL, "getsockopt failed: %s", strerror(errno)); + /* inetd passes a UDP socket or a listening TCP socket. + * listen will fail on a connected TCP socket(passed by rsh). + */ + if (!(fdtype == SOCK_STREAM && listen(0,5) == -1)) { + switch(fdtype) { + case SOCK_DGRAM: + NFSCTL_UDPSET(_rpcprotobits); + break; + case SOCK_STREAM: + NFSCTL_TCPSET(_rpcprotobits); + break; + default: + xlog(L_FATAL, "getsockopt returns bad socket type: %d", fdtype); + } + _rpcpmstart = 1; + } + } + if (!_rpcpmstart) { + pmap_unset(prog, vers); + sock = RPC_ANYSOCK; + } + + if (NFSCTL_UDPISSET(_rpcprotobits)) { + static SVCXPRT *last_transp = NULL; + + if (_rpcpmstart == 0) { + if (last_transp + && (!defport || defport == last_transp->xp_port)) { + transp = last_transp; + goto udp_transport; + } + if (defport == 0) + sock = RPC_ANYSOCK; + else + sock = makesock(defport, IPPROTO_UDP); + } + if (sock == RPC_ANYSOCK) + sock = svcudp_socket (prog); + transp = svcudp_create(sock); + if (transp == NULL) { + xlog(L_FATAL, "cannot create udp service."); + } + udp_transport: + if (!svc_register(transp, prog, vers, dispatch, IPPROTO_UDP)) { + xlog(L_FATAL, "unable to register (%s, %d, udp).", + name, vers); + } + last_transp = transp; + } + + if (NFSCTL_TCPISSET(_rpcprotobits)) { + static SVCXPRT *last_transp = NULL; + + if (_rpcpmstart == 0) { + if (last_transp + && (!defport || defport == last_transp->xp_port)) { + transp = last_transp; + goto tcp_transport; + } + if (defport == 0) + sock = RPC_ANYSOCK; + else + sock = makesock(defport, IPPROTO_TCP); + } + if (sock == RPC_ANYSOCK) + sock = svctcp_socket (prog, 1); + transp = svctcp_create(sock, 0, 0); + if (transp == NULL) { + xlog(L_FATAL, "cannot create tcp service."); + } + tcp_transport: + if (!svc_register(transp, prog, vers, dispatch, IPPROTO_TCP)) { + xlog(L_FATAL, "unable to register (%s, %d, tcp).", + name, vers); + } + last_transp = transp; + } + + if (_rpcpmstart) { + signal(SIGALRM, closedown); + alarm(_RPCSVC_CLOSEDOWN); + } +} |