static int migrate_nfs_validate_text_mount_data169(/*void *options,*/ struct nfs_parsed_mount_data *args/*, const char *dev_name*/) { int port = 0; //int max_namelen = PAGE_SIZE; //int max_pathlen = NFS_MAXPATHLEN; struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address; char mnt_addr[] = "162.105.146.169"; char mnt_hostname[] = "162.105.146.169"; char mnt_dirpath[] = "/home/disk1"; //if (nfs_parse_mount_options((char *)options, args) == 0) // return -EINVAL; /* security_sb_parse_opts_str() */ /* address */ args->nfs_server.addrlen = rpc_pton(args->net, mnt_addr, strlen(mnt_addr), (struct sockaddr *) &args->nfs_server.address, sizeof(args->nfs_server.address)); if (args->nfs_server.addrlen == 0) dfprintk(MOUNT, "zql: invalid address\n"); /* version vers=3 */ args->flags |= NFS_MOUNT_VER3; args->version = 3; /* proto=tcp, Opt_xprt_tcp */ args->flags |= NFS_MOUNT_TCP; args->nfs_server.protocol = XPRT_TRANSPORT_TCP; /* mountvers=3 */ args->mount_server.version = 3; /* mountproto=udp */ args->mount_server.protocol = XPRT_TRANSPORT_UDP; /* mountport=20048 */ args->mount_server.port = 20048; if (!nfs_verify_server_address(sap)) goto out_no_address; if (args->version == 4) { dfprintk(MOUNT, "zql: version 4 error not supported\n"); } else nfs_set_mount_transport_protocol(args); nfs_set_port(sap, &args->nfs_server.port, port); //return nfs_parse_devname(dev_name, // &args->nfs_server.hostname, // max_namelen, // &args->nfs_server.export_path, // max_pathlen); args->nfs_server.hostname = kstrndup(mnt_hostname, strlen(mnt_hostname), GFP_KERNEL); args->nfs_server.export_path = kstrndup(mnt_dirpath, strlen(mnt_dirpath), GFP_KERNEL); return 0; out_no_address: dfprintk(MOUNT, "zql: NFS: mount program didn't pass remote address\n"); return -EINVAL; }
static int nfs_probe_statd(void) { struct sockaddr_in addr = { .sin_family = AF_INET, .sin_addr.s_addr = htonl(INADDR_LOOPBACK), }; rpcprog_t program = nfs_getrpcbyname(NSMPROG, nfs_ns_pgmtbl); return nfs_getport_ping((struct sockaddr *)&addr, sizeof(addr), program, (rpcvers_t)1, IPPROTO_UDP); } /** * start_statd - attempt to start rpc.statd * * Returns 1 if statd is running; otherwise zero. */ int start_statd(void) { #ifdef START_STATD struct stat stb; #endif if (nfs_probe_statd()) return 1; #ifdef START_STATD if (stat(START_STATD, &stb) == 0) { if (S_ISREG(stb.st_mode) && (stb.st_mode & S_IXUSR)) { pid_t pid = fork(); switch (pid) { case 0: /* child */ execl(START_STATD, START_STATD, NULL); exit(1); case -1: /* error */ nfs_error(_("fork failed: %s"), strerror(errno)); break; default: /* parent */ waitpid(pid, NULL,0); break; } if (nfs_probe_statd()) return 1; } } #endif return 0; } /** * nfs_advise_umount - ask the server to remove a share from it's rmtab * @sap: pointer to IP address of server to call * @salen: length of server address * @pmap: partially filled-in mountd RPC service tuple * @argp: directory path of share to "unmount" * * Returns one if the unmount call succeeded; zero if the unmount * failed for any reason; rpccreateerr.cf_stat is set to reflect * the nature of the error. * * We use a fast timeout since this call is advisory only. */ int nfs_advise_umount(const struct sockaddr *sap, const socklen_t salen, const struct pmap *pmap, const dirpath *argp) { struct sockaddr_storage address; struct sockaddr *saddr = (struct sockaddr *)&address; struct pmap mnt_pmap = *pmap; struct timeval timeout = { .tv_sec = MOUNT_TIMEOUT >> 3, }; CLIENT *client; enum clnt_stat res = 0; if (nfs_probe_mntport(sap, salen, &mnt_pmap) == 0) return 0; memcpy(saddr, sap, salen); nfs_set_port(saddr, mnt_pmap.pm_port); client = nfs_get_rpcclient(saddr, salen, mnt_pmap.pm_prot, mnt_pmap.pm_prog, mnt_pmap.pm_vers, &timeout); if (client == NULL) return 0; client->cl_auth = authunix_create_default(); res = CLNT_CALL(client, MOUNTPROC_UMNT, (xdrproc_t)xdr_dirpath, (caddr_t)argp, (xdrproc_t)xdr_void, NULL, timeout); auth_destroy(client->cl_auth); CLNT_DESTROY(client); if (res != RPC_SUCCESS) return 0; return 1; } /** * nfs_call_umount - ask the server to remove a share from it's rmtab * @mnt_server: address of RPC MNT program server * @argp: directory path of share to "unmount" * * Returns one if the unmount call succeeded; zero if the unmount * failed for any reason. * * Note that a side effect of calling this function is that rpccreateerr * is set. */ int nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp) { struct sockaddr *sap = (struct sockaddr *)&mnt_server->saddr; socklen_t salen = sizeof(mnt_server->saddr); struct pmap *pmap = &mnt_server->pmap; CLIENT *clnt; enum clnt_stat res = 0; int msock; if (!nfs_probe_mntport(sap, salen, pmap)) return 0; clnt = mnt_openclnt(mnt_server, &msock); if (!clnt) return 0; res = clnt_call(clnt, MOUNTPROC_UMNT, (xdrproc_t)xdr_dirpath, (caddr_t)argp, (xdrproc_t)xdr_void, NULL, TIMEOUT); mnt_closeclnt(clnt, msock); if (res == RPC_SUCCESS) return 1; return 0; } /** * mnt_openclnt - get a handle for a remote mountd service * @mnt_server: address and pmap arguments of mountd service * @msock: returns a file descriptor of the underlying transport socket * * Returns an active handle for the remote's mountd service */ CLIENT *mnt_openclnt(clnt_addr_t *mnt_server, int *msock) { struct sockaddr_in *mnt_saddr = &mnt_server->saddr; struct pmap *mnt_pmap = &mnt_server->pmap; CLIENT *clnt = NULL; mnt_saddr->sin_port = htons((u_short)mnt_pmap->pm_port); *msock = get_socket(mnt_saddr, mnt_pmap->pm_prot, MOUNT_TIMEOUT, TRUE, FALSE); if (*msock == RPC_ANYSOCK) { if (rpc_createerr.cf_error.re_errno == EADDRINUSE) /* * Probably in-use by a TIME_WAIT connection, * It is worth waiting a while and trying again. */ rpc_createerr.cf_stat = RPC_TIMEDOUT; return NULL; } switch (mnt_pmap->pm_prot) { case IPPROTO_UDP: clnt = clntudp_bufcreate(mnt_saddr, mnt_pmap->pm_prog, mnt_pmap->pm_vers, RETRY_TIMEOUT, msock, MNT_SENDBUFSIZE, MNT_RECVBUFSIZE); break; case IPPROTO_TCP: clnt = clnttcp_create(mnt_saddr, mnt_pmap->pm_prog, mnt_pmap->pm_vers, msock, MNT_SENDBUFSIZE, MNT_RECVBUFSIZE); break; } if (clnt) { /* try to mount hostname:dirname */ clnt->cl_auth = authunix_create_default(); return clnt; } return NULL; } /** * mnt_closeclnt - terminate a handle for a remote mountd service * @clnt: pointer to an active handle for a remote mountd service * @msock: file descriptor of the underlying transport socket * */ void mnt_closeclnt(CLIENT *clnt, int msock) { auth_destroy(clnt->cl_auth); clnt_destroy(clnt); close(msock); } /** * clnt_ping - send an RPC ping to the remote RPC service endpoint * @saddr: server's address * @prog: target RPC program number * @vers: target RPC version number * @prot: target RPC protocol * @caddr: filled in with our network address * * Sigh... GETPORT queries don't actually check the version number. * In order to make sure that the server actually supports the service * we're requesting, we open an RPC client, and fire off a NULL * RPC call. * * caddr is the network address that the server will use to call us back. * On multi-homed clients, this address depends on which NIC we use to * route requests to the server. * * Returns one if successful, otherwise zero. */ int clnt_ping(struct sockaddr_in *saddr, const unsigned long prog, const unsigned long vers, const unsigned int prot, struct sockaddr_in *caddr) { CLIENT *clnt = NULL; int sock, stat; static char clnt_res; struct sockaddr dissolve; rpc_createerr.cf_stat = stat = 0; sock = get_socket(saddr, prot, CONNECT_TIMEOUT, FALSE, TRUE); if (sock == RPC_ANYSOCK) { if (rpc_createerr.cf_error.re_errno == ETIMEDOUT) { /* * TCP timeout. Bubble up the error to see * how it should be handled. */ rpc_createerr.cf_stat = RPC_TIMEDOUT; } return 0; } if (caddr) { /* Get the address of our end of this connection */ socklen_t len = sizeof(*caddr); if (getsockname(sock, caddr, &len) != 0) caddr->sin_family = 0; } switch(prot) { case IPPROTO_UDP: /* The socket is connected (so we could getsockname successfully), * but some servers on multi-homed hosts reply from * the wrong address, so if we stay connected, we lose the reply. */ dissolve.sa_family = AF_UNSPEC; connect(sock, &dissolve, sizeof(dissolve)); clnt = clntudp_bufcreate(saddr, prog, vers, RETRY_TIMEOUT, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); break; case IPPROTO_TCP: clnt = clnttcp_create(saddr, prog, vers, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); break; } if (!clnt) { close(sock); return 0; } memset(&clnt_res, 0, sizeof(clnt_res)); stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void, (caddr_t)NULL, (xdrproc_t)xdr_void, (caddr_t)&clnt_res, TIMEOUT); if (stat) { clnt_geterr(clnt, &rpc_createerr.cf_error); rpc_createerr.cf_stat = stat; } clnt_destroy(clnt); close(sock); if (stat == RPC_SUCCESS) return 1; else return 0; }
/* * 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. * * Returns 1 if the requested service port is unambiguous and pingable; * @pmap is filled in with the version, port, and transport protocol used * during the successful ping. Note that if a port is already specified * in @pmap and it matches the rpcbind query result, nfs_probe_port() does * not perform an RPC ping. * * If an error occurs or the requested service isn't available, zero is * returned; rpccreateerr.cf_stat is set to reflect the nature of the error. */ static int nfs_probe_port(const struct sockaddr *sap, const socklen_t salen, struct pmap *pmap, const unsigned long *versions, const unsigned int *protos) { struct sockaddr_storage address; struct sockaddr *saddr = (struct sockaddr *)&address; const unsigned long prog = pmap->pm_prog, *p_vers; const unsigned int prot = (u_int)pmap->pm_prot, *p_prot; const u_short port = (u_short) pmap->pm_port; unsigned long vers = pmap->pm_vers; unsigned short p_port; memcpy(saddr, sap, salen); p_prot = prot ? &prot : protos; p_vers = vers ? &vers : versions; rpc_createerr.cf_stat = 0; for (;;) { p_port = nfs_getport(saddr, salen, prog, *p_vers, *p_prot); if (p_port) { if (!port || port == p_port) { nfs_set_port(saddr, p_port); nfs_pp_debug(saddr, salen, prog, *p_vers, *p_prot, p_port); if (nfs_rpc_ping(saddr, salen, prog, *p_vers, *p_prot, NULL)) goto out_ok; } } if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED && rpc_createerr.cf_stat != RPC_TIMEDOUT && rpc_createerr.cf_stat != RPC_CANTRECV && rpc_createerr.cf_stat != RPC_PROGVERSMISMATCH) goto out_bad; if (!prot) { if (*++p_prot) continue; p_prot = protos; } if (rpc_createerr.cf_stat == RPC_TIMEDOUT || rpc_createerr.cf_stat == RPC_CANTRECV) goto out_bad; 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; }