int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir, const char *name, const char *path, struct nfs_sattr *sattr) { int *p, *p0; int status; int ruid = 0; PRINTK("NFS call symlink %s -> %s\n", name, path); if (!(p0 = nfs_rpc_alloc())) return -EIO; retry: p = nfs_rpc_header(p0, NFSPROC_SYMLINK, ruid); p = xdr_encode_fhandle(p, dir); p = xdr_encode_string(p, name); p = xdr_encode_string(p, path); p = xdr_encode_sattr(p, sattr); if ((status = nfs_rpc_call(server, p0, p)) < 0) { nfs_rpc_free(p0); return status; } if (!(p = nfs_rpc_verify(p0))) status = NFSERR_IO; else if ((status = ntohl(*p++)) == NFS_OK) { PRINTK("NFS reply symlink\n"); } else { if (!ruid && current->euid == 0 && current->uid != 0) { ruid = 1; goto retry; } PRINTK("NFS reply symlink failed = %d\n", status); } nfs_rpc_free(p0); return -nfs_stat_to_errno(status); }
/* * Encode a lock as part of an NLM call */ static __be32 * nlm4_encode_lock(__be32 *p, struct nlm_lock *lock) { struct file_lock *fl = &lock->fl; __s64 start, len; if (!(p = xdr_encode_string(p, lock->caller)) || !(p = nlm4_encode_fh(p, &lock->fh)) || !(p = nlm4_encode_oh(p, &lock->oh))) return NULL; if (fl->fl_start > NLM4_OFFSET_MAX || (fl->fl_end > NLM4_OFFSET_MAX && fl->fl_end != OFFSET_MAX)) return NULL; *p++ = htonl(lock->svid); start = loff_t_to_s64(fl->fl_start); if (fl->fl_end == OFFSET_MAX) len = 0; else len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1); p = xdr_encode_hyper(p, start); p = xdr_encode_hyper(p, len); return p; }
static int *nfs_rpc_header(int *p, int procedure, int ruid) { int *p1, *p2; int i; static int xid = 0; unsigned char *sys = (unsigned char *) system_utsname.nodename; if (xid == 0) { xid = CURRENT_TIME; xid ^= (sys[3]<<24) | (sys[2]<<16) | (sys[1]<<8) | sys[0]; } *p++ = htonl(++xid); *p++ = htonl(RPC_CALL); *p++ = htonl(RPC_VERSION); *p++ = htonl(NFS_PROGRAM); *p++ = htonl(NFS_VERSION); *p++ = htonl(procedure); *p++ = htonl(RPC_AUTH_UNIX); p1 = p++; *p++ = htonl(CURRENT_TIME); /* traditional, could be anything */ p = xdr_encode_string(p, (char *) sys); *p++ = htonl(ruid ? current->uid : current->fsuid); *p++ = htonl(current->egid); p2 = p++; for (i = 0; i < 16 && i < NGROUPS && current->groups[i] != NOGROUP; i++) *p++ = htonl(current->groups[i]); *p2 = htonl(i); *p1 = htonl((p - (p1 + 1)) << 2); *p++ = htonl(RPC_AUTH_NULL); *p++ = htonl(0); return p; }
int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *name) { int *p, *p0; int status; int ruid = 0; PRINTK("NFS call rmdir %s\n", name); if (!(p0 = nfs_rpc_alloc(server->wsize))) return -EIO; retry: p = nfs_rpc_header(p0, NFSPROC_RMDIR, ruid); p = xdr_encode_fhandle(p, dir); p = xdr_encode_string(p, name); if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) { nfs_rpc_free(p0); return status; } if (!(p = nfs_rpc_verify(p0))) status = -errno_NFSERR_IO; else if ((status = ntohl(*p++)) == NFS_OK) { PRINTK("NFS reply rmdir\n"); /* status = 0; */ } else { if (!ruid && current->fsuid == 0 && current->uid != 0) { ruid = 1; goto retry; } PRINTK("NFS reply rmdir failed = %d\n", status); status = -nfs_stat_to_errno(status); } nfs_rpc_free(p0); return status; }
int mnt_proc_mnt(struct generic_server *server, char *directory, struct nfs_fh *fhandle) { int *p, *p0; int status; DPRINTF(CLUHELP2_LEVEL,("MNT call MNT\n")); if (!(p0 = overhead_rpc_alloc(server->rsize))) return -EIO; p = mnt_rpc_header(p0,MNTPROC_MNT,0); p = xdr_encode_string(p,directory); if ((status = generic_rpc_call(server, p0, p)) < 0) { overhead_rpc_free(p0); return status; } if (!(p = generic_rpc_verify(p0))) {status = -1;} else { status = ntohl(*p++); if (status == 0) { xdr_decode_fhandle(p, fhandle); fhandle->server = server; DPRINTF(CLUHELP2_LEVEL,("MNTPROC_MNT call good\n")); } } DPRINTF(CLUHELP2_LEVEL,("pmap proc getmap status: %d\n",status)); overhead_rpc_free(p0); return(status); }
static int xdr_encode_dirpath(struct rpc_rqst *req, u32 *p, const char *path) { p = xdr_encode_string(p, path); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); return 0; }
static u32 * xdr_encode_common(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp) { char buffer[20]; /* * Use the dotted-quad IP address of the remote host as * identifier. Linux statd always looks up the canonical * hostname first for whatever remote hostname it receives, * so this works alright. */ sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(argp->addr)); if (!(p = xdr_encode_string(p, buffer)) || !(p = xdr_encode_string(p, system_utsname.nodename))) return ERR_PTR(-EIO); *p++ = htonl(argp->prog); *p++ = htonl(argp->vers); *p++ = htonl(argp->proc); return p; }
int nfs_proc_rename(struct nfs_server *server, struct nfs_fh *old_dir, const char *old_name, struct nfs_fh *new_dir, const char *new_name) { int *p, *p0; int status; int ruid = 0; PRINTK("NFS call rename %s -> %s\n", old_name, new_name); if (!(p0 = nfs_rpc_alloc())) return -EIO; retry: p = nfs_rpc_header(p0, NFSPROC_RENAME, ruid); p = xdr_encode_fhandle(p, old_dir); p = xdr_encode_string(p, old_name); p = xdr_encode_fhandle(p, new_dir); p = xdr_encode_string(p, new_name); if ((status = nfs_rpc_call(server, p0, p)) < 0) { nfs_rpc_free(p0); return status; } if (!(p = nfs_rpc_verify(p0))) status = NFSERR_IO; else if ((status = ntohl(*p++)) == NFS_OK) { PRINTK("NFS reply rename\n"); } else { if (!ruid && current->euid == 0 && current->uid != 0) { ruid = 1; goto retry; } PRINTK("NFS reply rename failed = %d\n", status); } nfs_rpc_free(p0); return -nfs_stat_to_errno(status); }
static int xdr_encode_mon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp) { char buffer[20]; u32 addr = ntohl(argp->addr); dprintk("nsm: xdr_encode_mon(%08x, %d, %d, %d)\n", htonl(argp->addr), htonl(argp->proc), htonl(argp->vers), htonl(argp->proc)); /* * Use the dotted-quad IP address of the remote host as * identifier. Linux statd always looks up the canonical * hostname first for whatever remote hostname it receives, * so this works alright. */ sprintf(buffer, "%d.%d.%d.%d", (addr>>24) & 0xff, (addr>>16) & 0xff, (addr>>8) & 0xff, (addr) & 0xff); if (!(p = xdr_encode_string(p, buffer)) || !(p = xdr_encode_string(p, system_utsname.nodename))) return -EIO; *p++ = htonl(argp->prog); *p++ = htonl(argp->vers); *p++ = htonl(argp->proc); /* This is the private part. Needed only for SM_MON call */ if (rqstp->rq_task->tk_proc == SM_MON) { *p++ = argp->addr; *p++ = 0; *p++ = 0; *p++ = 0; } rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); return 0; }
int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, const char *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { int *p, *p0; int status; int ruid = 0; PRINTK("NFS call lookup %s\n", name); #ifdef NFS_PROC_DEBUG if (!strcmp(name, "xyzzy")) proc_debug = 1 - proc_debug; #endif if (!(p0 = nfs_rpc_alloc(server->rsize))) return -EIO; retry: p = nfs_rpc_header(p0, NFSPROC_LOOKUP, ruid); p = xdr_encode_fhandle(p, dir); p = xdr_encode_string(p, name); if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) { nfs_rpc_free(p0); return status; } if (!(p = nfs_rpc_verify(p0))) status = -errno_NFSERR_IO; else if ((status = ntohl(*p++)) == NFS_OK) { p = xdr_decode_fhandle(p, fhandle); p = xdr_decode_fattr(p, fattr); PRINTK("NFS reply lookup\n"); /* status = 0; */ } else { if (!ruid && current->fsuid == 0 && current->uid != 0) { ruid = 1; goto retry; } PRINTK("NFS reply lookup failed = %d\n", status); status = -nfs_stat_to_errno(status); } nfs_rpc_free(p0); return status; }
int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir, const char *name, struct nfs_sattr *sattr, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { int *p, *p0; int status; int ruid = 0; PRINTK("NFS call create %s\n", name); if (!(p0 = nfs_rpc_alloc())) return -EIO; retry: p = nfs_rpc_header(p0, NFSPROC_CREATE, ruid); p = xdr_encode_fhandle(p, dir); p = xdr_encode_string(p, name); p = xdr_encode_sattr(p, sattr); if ((status = nfs_rpc_call(server, p0, p)) < 0) { nfs_rpc_free(p0); return status; } if (!(p = nfs_rpc_verify(p0))) status = NFSERR_IO; else if ((status = ntohl(*p++)) == NFS_OK) { p = xdr_decode_fhandle(p, fhandle); p = xdr_decode_fattr(p, fattr); PRINTK("NFS reply create\n"); } else { if (!ruid && current->euid == 0 && current->uid != 0) { ruid = 1; goto retry; } PRINTK("NFS reply create failed = %d\n", status); } nfs_rpc_free(p0); return -nfs_stat_to_errno(status); }
int mnt_proc_umnt(struct generic_server *server, const char *dirname) { int *p, *p0; int status; DPRINTF(CLUHELP2_LEVEL,("MNT call UMNT\n")); if (!(p0 = overhead_rpc_alloc(server->rsize))) return -EIO; p = mnt_rpc_header(p0,MNTPROC_UMNT,0); p = xdr_encode_string(p,dirname); if ((status = generic_rpc_call(server, p0, p)) < 0) { overhead_rpc_free(p0); return status; } if (!(p = generic_rpc_verify(p0))) {status = 0;} else { status = 1; DPRINTF(CLUHELP2_LEVEL,("MNTPROC_UMNT good\n")); } overhead_rpc_free(p0); return(status); }
/** * rpcb_register - set or unset a port registration with the local rpcbind svc * @prog: RPC program number to bind * @vers: RPC version number to bind * @prot: transport protocol to use to make this request * @port: port value to register * @okay: result code * * port == 0 means unregister, port != 0 means register. * * This routine supports only rpcbind version 2. */ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) { struct sockaddr_in sin = { .sin_family = AF_INET, .sin_addr.s_addr = htonl(INADDR_LOOPBACK), }; struct rpcbind_args map = { .r_prog = prog, .r_vers = vers, .r_prot = prot, .r_port = port, }; struct rpc_message msg = { .rpc_proc = &rpcb_procedures2[port ? RPCBPROC_SET : RPCBPROC_UNSET], .rpc_argp = &map, .rpc_resp = okay, }; struct rpc_clnt *rpcb_clnt; int error = 0; dprintk("RPC: %sregistering (%u, %u, %d, %u) with local " "rpcbind\n", (port ? "" : "un"), prog, vers, prot, port); rpcb_clnt = rpcb_create("localhost", (struct sockaddr *) &sin, sizeof(sin), XPRT_TRANSPORT_UDP, 2, 1); if (IS_ERR(rpcb_clnt)) return PTR_ERR(rpcb_clnt); error = rpc_call_sync(rpcb_clnt, &msg, 0); rpc_shutdown_client(rpcb_clnt); if (error < 0) printk(KERN_WARNING "RPC: failed to contact local rpcbind " "server (errno %d).\n", -error); dprintk("RPC: registration status %d/%d\n", error, *okay); return error; } /** * rpcb_getport_sync - obtain the port for an RPC service on a given host * @sin: address of remote peer * @prog: RPC program number to bind * @vers: RPC version number to bind * @prot: transport protocol to use to make this request * * Return value is the requested advertised port number, * or a negative errno value. * * Called from outside the RPC client in a synchronous task context. * Uses default timeout parameters specified by underlying transport. * * XXX: Needs to support IPv6 */ int rpcb_getport_sync(struct sockaddr_in *sin, u32 prog, u32 vers, int prot) { struct rpcbind_args map = { .r_prog = prog, .r_vers = vers, .r_prot = prot, .r_port = 0, }; struct rpc_message msg = { .rpc_proc = &rpcb_procedures2[RPCBPROC_GETPORT], .rpc_argp = &map, .rpc_resp = &map.r_port, }; struct rpc_clnt *rpcb_clnt; int status; dprintk("RPC: %s(" NIPQUAD_FMT ", %u, %u, %d)\n", __FUNCTION__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot); rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin, sizeof(*sin), prot, 2, 0); if (IS_ERR(rpcb_clnt)) return PTR_ERR(rpcb_clnt); status = rpc_call_sync(rpcb_clnt, &msg, 0); rpc_shutdown_client(rpcb_clnt); if (status >= 0) { if (map.r_port != 0) return map.r_port; status = -EACCES; } return status; } EXPORT_SYMBOL_GPL(rpcb_getport_sync); static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbind_args *map, int version) { struct rpc_message msg = { .rpc_proc = rpcb_next_version[version].rpc_proc, .rpc_argp = map, .rpc_resp = &map->r_port, }; struct rpc_task_setup task_setup_data = { .rpc_client = rpcb_clnt, .rpc_message = &msg, .callback_ops = &rpcb_getport_ops, .callback_data = map, .flags = RPC_TASK_ASYNC, }; return rpc_run_task(&task_setup_data); } /** * rpcb_getport_async - obtain the port for a given RPC service on a given host * @task: task that is waiting for portmapper request * * This one can be called for an ongoing RPC request, and can be used in * an async (rpciod) context. */ void rpcb_getport_async(struct rpc_task *task) { struct rpc_clnt *clnt = task->tk_client; u32 bind_version; struct rpc_xprt *xprt = task->tk_xprt; struct rpc_clnt *rpcb_clnt; static struct rpcbind_args *map; struct rpc_task *child; struct sockaddr_storage addr; struct sockaddr *sap = (struct sockaddr *)&addr; size_t salen; int status; struct rpcb_info *info; dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", task->tk_pid, __FUNCTION__, clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot); /* Autobind on cloned rpc clients is discouraged */ BUG_ON(clnt->cl_parent != clnt); if (xprt_test_and_set_binding(xprt)) { status = -EAGAIN; /* tell caller to check again */ dprintk("RPC: %5u %s: waiting for another binder\n", task->tk_pid, __FUNCTION__); goto bailout_nowake; } /* Put self on queue before sending rpcbind request, in case * rpcb_getport_done completes before we return from rpc_run_task */ rpc_sleep_on(&xprt->binding, task, NULL, NULL); /* Someone else may have bound if we slept */ if (xprt_bound(xprt)) { status = 0; dprintk("RPC: %5u %s: already bound\n", task->tk_pid, __FUNCTION__); goto bailout_nofree; } salen = rpc_peeraddr(clnt, sap, sizeof(addr)); /* Don't ever use rpcbind v2 for AF_INET6 requests */ switch (sap->sa_family) { case AF_INET: info = rpcb_next_version; break; case AF_INET6: info = rpcb_next_version6; break; default: status = -EAFNOSUPPORT; dprintk("RPC: %5u %s: bad address family\n", task->tk_pid, __FUNCTION__); goto bailout_nofree; } if (info[xprt->bind_index].rpc_proc == NULL) { xprt->bind_index = 0; status = -EPFNOSUPPORT; dprintk("RPC: %5u %s: no more getport versions available\n", task->tk_pid, __FUNCTION__); goto bailout_nofree; } bind_version = info[xprt->bind_index].rpc_vers; dprintk("RPC: %5u %s: trying rpcbind version %u\n", task->tk_pid, __FUNCTION__, bind_version); rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot, bind_version, 0); if (IS_ERR(rpcb_clnt)) { status = PTR_ERR(rpcb_clnt); dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n", task->tk_pid, __FUNCTION__, PTR_ERR(rpcb_clnt)); goto bailout_nofree; } map = kzalloc(sizeof(struct rpcbind_args), GFP_ATOMIC); if (!map) { status = -ENOMEM; dprintk("RPC: %5u %s: no memory available\n", task->tk_pid, __FUNCTION__); goto bailout_nofree; } map->r_prog = clnt->cl_prog; map->r_vers = clnt->cl_vers; map->r_prot = xprt->prot; map->r_port = 0; map->r_xprt = xprt_get(xprt); map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID); map->r_addr = rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR); map->r_owner = RPCB_OWNER_STRING; /* ignored for GETADDR */ child = rpcb_call_async(rpcb_clnt, map, xprt->bind_index); rpc_release_client(rpcb_clnt); if (IS_ERR(child)) { status = -EIO; dprintk("RPC: %5u %s: rpc_run_task failed\n", task->tk_pid, __FUNCTION__); goto bailout; } rpc_put_task(child); task->tk_xprt->stat.bind_count++; return; bailout: kfree(map); xprt_put(xprt); bailout_nofree: rpcb_wake_rpcbind_waiters(xprt, status); bailout_nowake: task->tk_status = status; } EXPORT_SYMBOL_GPL(rpcb_getport_async); /* * Rpcbind child task calls this callback via tk_exit. */ static void rpcb_getport_done(struct rpc_task *child, void *data) { struct rpcbind_args *map = data; struct rpc_xprt *xprt = map->r_xprt; int status = child->tk_status; /* Garbage reply: retry with a lesser rpcbind version */ if (status == -EIO) status = -EPROTONOSUPPORT; /* rpcbind server doesn't support this rpcbind protocol version */ if (status == -EPROTONOSUPPORT) xprt->bind_index++; if (status < 0) { /* rpcbind server not available on remote host? */ xprt->ops->set_port(xprt, 0); } else if (map->r_port == 0) { /* Requested RPC service wasn't registered on remote host */ xprt->ops->set_port(xprt, 0); status = -EACCES; } else { /* Succeeded */ xprt->ops->set_port(xprt, map->r_port); xprt_set_bound(xprt); status = 0; } dprintk("RPC: %5u rpcb_getport_done(status %d, port %u)\n", child->tk_pid, status, map->r_port); rpcb_wake_rpcbind_waiters(xprt, status); } static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p, struct rpcbind_args *rpcb) { dprintk("RPC: rpcb_encode_mapping(%u, %u, %d, %u)\n", rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port); *p++ = htonl(rpcb->r_prog); *p++ = htonl(rpcb->r_vers); *p++ = htonl(rpcb->r_prot); *p++ = htonl(rpcb->r_port); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); return 0; } static int rpcb_decode_getport(struct rpc_rqst *req, __be32 *p, unsigned short *portp) { *portp = (unsigned short) ntohl(*p++); dprintk("RPC: rpcb_decode_getport result %u\n", *portp); return 0; } static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p, unsigned int *boolp) { *boolp = (unsigned int) ntohl(*p++); dprintk("RPC: rpcb_decode_set result %u\n", *boolp); return 0; } static int rpcb_encode_getaddr(struct rpc_rqst *req, __be32 *p, struct rpcbind_args *rpcb) { dprintk("RPC: rpcb_encode_getaddr(%u, %u, %s)\n", rpcb->r_prog, rpcb->r_vers, rpcb->r_addr); *p++ = htonl(rpcb->r_prog); *p++ = htonl(rpcb->r_vers); p = xdr_encode_string(p, rpcb->r_netid); p = xdr_encode_string(p, rpcb->r_addr); p = xdr_encode_string(p, rpcb->r_owner); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); return 0; }
/* Using the mount protocol, lookup NAME at host HOST. Return a node for it or null for an error. If an error occurs, a message is automatically sent to stderr. */ struct node * mount_root (char *name, char *host) { struct sockaddr_in addr; struct hostent *h; int *p; void *rpcbuf; int port; error_t err; struct node *np; short pmapport; /* Lookup the portmapper port number */ if (pmap_service_name) { struct servent *s; /* XXX This will always fail! pmap_service_name will always be "sunrpc" What should pmap_service_name really be? By definition the second argument is either "tcp" or "udp" Thus, is this backwards (as service_name suggests)? If so, should it read: s = getservbyname (pmap_service_name, "udp"); or is there something I am missing here? */ s = getservbyname ("sunrpc", pmap_service_name); if (s) pmapport = s->s_port; else pmapport = htons (pmap_service_number); } else pmapport = htons (pmap_service_number); /* Lookup the host */ h = gethostbyname (host); if (!h) { herror (host); return 0; } addr.sin_family = h->h_addrtype; memcpy (&addr.sin_addr, h->h_addr_list[0], h->h_length); addr.sin_port = pmapport; if (mount_port_override) addr.sin_port = htons (mount_port); else { /* Formulate and send a PMAPPROC_GETPORT request to lookup the mount program on the server. */ if (connect (main_udp_socket, (struct sockaddr *)&addr, sizeof (struct sockaddr_in)) == -1) { error (0, errno, "server mount program"); return 0; } p = pmap_initialize_rpc (PMAPPROC_GETPORT, &rpcbuf); if (! p) { error (0, errno, "creating rpc packet"); return 0; } *(p++) = htonl (MOUNTPROG); *(p++) = htonl (MOUNTVERS); *(p++) = htonl (IPPROTO_UDP); *(p++) = htonl (0); err = conduct_rpc (&rpcbuf, &p); if (!err) { port = ntohl (*p); p++; addr.sin_port = htons (port); } else if (mount_port) addr.sin_port = htons (mount_port); else { error (0, err, "portmap of mount"); goto error_with_rpcbuf; } free (rpcbuf); } /* Now, talking to the mount program, fetch a file handle for the root. */ if (connect (main_udp_socket, (struct sockaddr *) &addr, sizeof (struct sockaddr_in)) == -1) { error (0, errno, "connect"); goto error_with_rpcbuf; } p = mount_initialize_rpc (MOUNTPROC_MNT, &rpcbuf); if (! p) { error (0, errno, "rpc"); goto error_with_rpcbuf; } p = xdr_encode_string (p, name); err = conduct_rpc (&rpcbuf, &p); if (err) { error (0, err, "%s", name); goto error_with_rpcbuf; } /* XXX Protocol spec says this should be a "unix error code"; we'll pretend that an NFS error code is what's meant; the numbers match anyhow. */ err = nfs_error_trans (htonl (*p)); p++; if (err) { error (0, err, "%s", name); goto error_with_rpcbuf; } /* Create the node for root */ xdr_decode_fhandle (p, &np); free (rpcbuf); pthread_mutex_unlock (&np->lock); if (nfs_port_override) port = nfs_port; else { /* Send another PMAPPROC_GETPORT request to lookup the nfs server. */ addr.sin_port = pmapport; if (connect (main_udp_socket, (struct sockaddr *) &addr, sizeof (struct sockaddr_in)) == -1) { error (0, errno, "connect"); return 0; } p = pmap_initialize_rpc (PMAPPROC_GETPORT, &rpcbuf); if (! p) { error (0, errno, "rpc"); goto error_with_rpcbuf; } *(p++) = htonl (NFS_PROGRAM); *(p++) = htonl (NFS_VERSION); *(p++) = htonl (IPPROTO_UDP); *(p++) = htonl (0); err = conduct_rpc (&rpcbuf, &p); if (!err) { port = ntohl (*p); p++; } else if (nfs_port) port = nfs_port; else { error (0, err, "portmap of nfs server"); goto error_with_rpcbuf; } free (rpcbuf); } addr.sin_port = htons (port); if (connect (main_udp_socket, (struct sockaddr *) &addr, sizeof (struct sockaddr_in)) == -1) { error (0, errno, "connect"); return 0; } mounted_hostname = host; mounted_nfs_port = port; return np; error_with_rpcbuf: free (rpcbuf); return 0; }
/* * Create NSM client for the local host */ static struct rpc_clnt * nsm_create(void) { struct sockaddr_in sin = { .sin_family = AF_INET, .sin_addr.s_addr = htonl(INADDR_LOOPBACK), .sin_port = 0, }; struct rpc_create_args args = { .protocol = IPPROTO_UDP, .address = (struct sockaddr *)&sin, .addrsize = sizeof(sin), .servername = "localhost", .program = &nsm_program, .version = SM_VERSION, .authflavor = RPC_AUTH_NULL, .flags = (RPC_CLNT_CREATE_ONESHOT), }; return rpc_create(&args); } /* * XDR functions for NSM. */ static __be32 * xdr_encode_common(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) { char buffer[20], *name; /* * Use the dotted-quad IP address of the remote host as * identifier. Linux statd always looks up the canonical * hostname first for whatever remote hostname it receives, * so this works alright. */ if (nsm_use_hostnames) { name = argp->mon_name; } else { sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(argp->addr)); name = buffer; } if (!(p = xdr_encode_string(p, name)) || !(p = xdr_encode_string(p, utsname()->nodename))) return ERR_PTR(-EIO); *p++ = htonl(argp->prog); *p++ = htonl(argp->vers); *p++ = htonl(argp->proc); return p; } static int xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) { p = xdr_encode_common(rqstp, p, argp); if (IS_ERR(p)) return PTR_ERR(p); /* Surprise - there may even be room for an IPv6 address now */ *p++ = argp->addr; *p++ = 0; *p++ = 0; *p++ = 0; rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); return 0; }