-/* Convert RPC errors into strings */
-int rpc_strerror(int);
-int rpc_strerror(int spos)
-{
- int cf_stat = rpc_createerr.cf_stat;
- int pos=0, cf_errno = rpc_createerr.cf_error.re_errno;
- char *ptr, *estr = clnt_sperrno(cf_stat);
- char *tmp;
-
- if (estr) {
- if ((ptr = index(estr, ':')))
- estr = ++ptr;
-
- tmp = &errbuf[spos];
- if (cf_stat == RPC_SYSTEMERROR)
- pos = snprintf(tmp, (erreob - tmp),
- "System Error: %s", strerror(cf_errno));
- else
- pos = snprintf(tmp, (erreob - tmp), "RPC Error:%s", estr);
- }
- return (pos);
-}
-void mount_errors(char *, int, int);
-void mount_errors(char *server, int will_retry, int bg)
-{
- int pos = 0;
- char *tmp;
- static int onlyonce = 0;
-
- tmp = &errbuf[pos];
- if (bg)
- pos = snprintf(tmp, (erreob - tmp),
- "mount to NFS server '%s' failed: ", server);
- else
- pos = snprintf(tmp, (erreob - tmp),
- "mount: mount to NFS server '%s' failed: ", server);
-
- tmp = &errbuf[pos];
- if (rpc_createerr.cf_stat == RPC_TIMEDOUT) {
- pos = snprintf(tmp, (erreob - tmp), "timed out %s",
- will_retry ? "(retrying)" : "(giving up)");
- } else {
- pos += rpc_strerror(pos);
- tmp = &errbuf[pos];
- if (bg) {
- pos = snprintf(tmp, (erreob - tmp), " %s",
- will_retry ? "(retrying)" : "(giving up)");
- }
- }
- if (bg) {
- if (onlyonce++ < 1)
- openlog("mount", LOG_CONS|LOG_PID, LOG_AUTH);
- syslog(LOG_ERR, "%s.", errbuf);
- } else
- fprintf(stderr, "%s.\n", errbuf);
-}
-
-/* Define the order in which to probe for UDP/TCP services */
-enum plist {
- use_tcp = 0,
- udp_tcp,
- udp_only,
-};
-static const u_int *
-proto_probelist(enum plist list)
-{
- static const u_int probe_udp_tcp[] = { IPPROTO_UDP, IPPROTO_TCP, 0 };
- static const u_int probe_both[] = { IPPROTO_TCP, IPPROTO_UDP, 0 };
- static const u_int probe_udponly[] = { IPPROTO_UDP, 0 };
-
- if (list == use_tcp)
- return probe_both;
- if (list == udp_tcp)
- return probe_udp_tcp;
- return probe_udponly;
-}
-
-/* Define the order in which NFS versions are probed on portmapper */
-static const u_long *
-nfs_probelist(const int vers)
-{
- static const u_long nfs2_probe[] = { 2, 0};
- static const u_long nfs3_probe[] = { 3, 2, 0};
- switch (vers) {
- case 3:
- return nfs3_probe;
- default:
- return nfs2_probe;
- }
-}
-
-/* Define the order in which Mountd versions are probed on portmapper */
-static const u_long *
-mnt_probelist(const int vers)
-{
- static const u_long mnt1_probe[] = { 1, 2, 0 };
- static const u_long mnt3_probe[] = { 3, 1, 2, 0 };
- switch (vers) {
- case 3:
- return mnt3_probe;
- default:
- return mnt1_probe;
- }
-}
-
-static int
-linux_version_code(void) {
- struct utsname my_utsname;
- int p, q, r;
-
- if (uname(&my_utsname) == 0) {
- p = atoi(strtok(my_utsname.release, "."));
- q = atoi(strtok(NULL, "."));
- r = atoi(strtok(NULL, "."));
- return MAKE_VERSION(p,q,r);
- }
- return 0;
-}
-
-/*
- * Unfortunately, the kernel prints annoying console messages
- * in case of an unexpected nfs mount version (instead of
- * just returning some error). Therefore we'll have to try
- * and figure out what version the kernel expects.
- *
- * Variables:
- * NFS_MOUNT_VERSION: these nfsmount sources at compile time
- * nfs_mount_version: version this source and running kernel can handle
- */
-int nfs_mount_version = NFS_MOUNT_VERSION;
-
-int
-find_kernel_nfs_mount_version(void) {
- static int kernel_version = -1;
- int mnt_version = NFS_MOUNT_VERSION;
-
- if (kernel_version == -1)
- kernel_version = linux_version_code();
-
- if (kernel_version) {
- if (kernel_version < MAKE_VERSION(2,1,32))
- mnt_version = 1;
- else if (kernel_version < MAKE_VERSION(2,2,18))
- mnt_version = 3;
- else if (kernel_version < MAKE_VERSION(2,3,0))
- mnt_version = 4; /* since 2.2.18pre9 */
- else if (kernel_version < MAKE_VERSION(2,3,99))
- mnt_version = 3;
- else if (kernel_version < MAKE_VERSION(2,6,3))
- mnt_version = 4;
- else
- mnt_version = 6;
- }
- if (mnt_version > NFS_MOUNT_VERSION)
- mnt_version = NFS_MOUNT_VERSION;
- return mnt_version;
-}
-
-int nfs_gethostbyname(const char *, struct sockaddr_in *);
-int nfs_gethostbyname(const char *hostname, struct sockaddr_in *saddr)
-{
- struct hostent *hp;
-
- saddr->sin_family = AF_INET;
- if (!inet_aton(hostname, &saddr->sin_addr)) {
- if ((hp = gethostbyname(hostname)) == NULL) {
- fprintf(stderr, _("mount: can't get address for %s\n"),
- hostname);
- return 0;
- } else {
- if (hp->h_length > sizeof(*saddr)) {
- fprintf(stderr,
- _("mount: got bad hp->h_length\n"));
- hp->h_length = sizeof(*saddr);
- }
- memcpy(&saddr->sin_addr, hp->h_addr, hp->h_length);
- }
- }
- return 1;
-}
-
-/*
- * getport() is very similar to pmap_getport() with
- * the exception this version uses a non-reserve ports
- * instead of reserve ports since reserve ports
- * are not needed for pmap requests.
- */
-u_short
-getport(
- struct sockaddr_in *saddr,
- u_long prog,
- u_long vers,
- u_int prot)
-{
- u_short port = 0;
- int socket;
- CLIENT *clnt = NULL;
- struct pmap parms;
- enum clnt_stat stat;
-
- saddr->sin_port = htons (PMAPPORT);
- socket = get_socket(saddr, prot, FALSE, FALSE);
-
- switch (prot) {
- case IPPROTO_UDP:
- clnt = clntudp_bufcreate(saddr,
- PMAPPROG, PMAPVERS, TIMEOUT, &socket,
- UDPMSGSIZE, UDPMSGSIZE);
- break;
- case IPPROTO_TCP:
- clnt = clnttcp_create(saddr,
- PMAPPROG, PMAPVERS, &socket, 50, 500);
- break;
- }
- if (clnt != NULL) {
- parms.pm_prog = prog;
- parms.pm_vers = vers;
- parms.pm_prot = prot;
- parms.pm_port = 0; /* not needed or used */
-
- stat = clnt_call(clnt, PMAPPROC_GETPORT, (xdrproc_t)xdr_pmap,
- (caddr_t)&parms, (xdrproc_t)xdr_u_short, (caddr_t)&port, TIMEOUT);
- if (stat) {
- clnt_geterr(clnt, &rpc_createerr.cf_error);
- rpc_createerr.cf_stat = stat;
- }
- clnt_destroy(clnt);
- if (stat != RPC_SUCCESS)
- port = 0;
- else if (port == 0)
- rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
- }
- if (socket != 1)
- close(socket);
-
- return port;
-}
-
-/*
- * Use the portmapper to discover whether or not the service we want is
- * available. The lists 'versions' and 'protos' define ordered sequences
- * of service versions and udp/tcp protocols to probe for.
- */
-static int
-probe_port(clnt_addr_t *server,
- const u_long *versions,
- const u_int *protos)
-{
- struct sockaddr_in *saddr = &server->saddr;
- struct pmap *pmap = &server->pmap;
- const u_long prog = pmap->pm_prog, *p_vers;
- const u_int prot = (u_int)pmap->pm_prot,
- *p_prot;
- const u_short port = (u_short) pmap->pm_port;
- u_long vers = pmap->pm_vers;
- u_short p_port;
- p_prot = prot ? &prot : protos;
- p_vers = vers ? &vers : versions;
- rpc_createerr.cf_stat = 0;
- for (;;) {
- saddr->sin_port = htons(PMAPPORT);
- p_port = getport(saddr, prog, *p_vers, *p_prot);
- if (p_port) {
- if (!port || port == p_port) {
- saddr->sin_port = htons(p_port);
- if (verbose) {
- fprintf(stderr,
- "mount: trying %s prog %ld vers %ld prot %s port %d\n",
- inet_ntoa(saddr->sin_addr), prog, *p_vers,
- *p_prot == IPPROTO_UDP ? "udp" : "tcp", p_port);
- }
- if (clnt_ping(saddr, prog, *p_vers, *p_prot, NULL))
- goto out_ok;
- if (rpc_createerr.cf_stat == RPC_TIMEDOUT)
- goto out_bad;
- }
- }
- if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED)
- goto out_bad;
-
- if (!prot) {
- if (*++p_prot)
- continue;
- p_prot = protos;
- }
- if (vers == pmap->pm_vers) {
- p_vers = versions;
- vers = 0;
- }
- if (vers || !*++p_vers)
- break;
- }
-out_bad:
- return 0;
-
- out_ok:
- if (!vers)
- pmap->pm_vers = *p_vers;
- if (!prot)
- pmap->pm_prot = *p_prot;
- if (!port)
- pmap->pm_port = p_port;
- rpc_createerr.cf_stat = 0;
- return 1;
-}
-
-static int
-probe_nfsport(clnt_addr_t *nfs_server)
-{
- const struct pmap *pmap = &nfs_server->pmap;
- const u_long *probe_vers;
- const u_int *probe_prot;
-
- if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
- return 1;
- probe_vers = nfs_probelist(MAX_NFSPROT);
- probe_prot = proto_probelist(HAVE_RELIABLE_TCP ? use_tcp : udp_only);
- return probe_port(nfs_server, probe_vers, probe_prot);
-}
-
-int probe_mntport(clnt_addr_t *mnt_server)
-{
- const struct pmap *pmap = &mnt_server->pmap;
- const u_long *probe_vers;
- const u_int *probe_prot;
-
- if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
- return 1;
- probe_vers = mnt_probelist(MAX_MNTPROT);
- probe_prot = proto_probelist(HAVE_RELIABLE_TCP ? udp_tcp : udp_only);
- return probe_port(mnt_server, probe_vers, probe_prot);
-}
-
-static int
-probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server)
-{
- struct pmap *nfs_pmap = &nfs_server->pmap;
- struct pmap *mnt_pmap = &mnt_server->pmap;
- struct pmap save_nfs, save_mnt;
- int res;
- const u_long *probe_vers;
-
- if (mnt_pmap->pm_vers && !nfs_pmap->pm_vers)
- nfs_pmap->pm_vers = mntvers_to_nfs(mnt_pmap->pm_vers);
- else if (nfs_pmap->pm_vers && !mnt_pmap->pm_vers)
- mnt_pmap->pm_vers = nfsvers_to_mnt(nfs_pmap->pm_vers);
- if (nfs_pmap->pm_vers)
- goto version_fixed;
- memcpy(&save_nfs, nfs_pmap, sizeof(save_nfs));
- memcpy(&save_mnt, mnt_pmap, sizeof(save_mnt));
- for (probe_vers = mnt_probelist(MAX_MNTPROT); *probe_vers; probe_vers++) {
- nfs_pmap->pm_vers = mntvers_to_nfs(*probe_vers);
- if ((res = probe_nfsport(nfs_server) != 0)) {
- mnt_pmap->pm_vers = nfsvers_to_mnt(nfs_pmap->pm_vers);
- if ((res = probe_mntport(mnt_server)) != 0)
- return 1;
- memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap));
- }
- switch (rpc_createerr.cf_stat) {
- case RPC_PROGVERSMISMATCH:
- case RPC_PROGNOTREGISTERED:
- break;
- default:
- goto out_bad;
- }
- memcpy(nfs_pmap, &save_nfs, sizeof(*nfs_pmap));
- }
- out_bad:
- return 0;
- version_fixed:
- if (!probe_nfsport(nfs_server))
- goto out_bad;
- return probe_mntport(mnt_server);
-}
-