3
#include <sys/socket.h>
5
#include <netinet/in.h>
14
static __u32 mount_port;
25
* The following structure is the NFS v3 on-the-wire file handle,
26
* as defined in rfc1813.
27
* This differs from the structure used by the kernel,
28
* defined in <linux/nfh3.h>: rfc has a long in network order,
29
* kernel has a short in native order.
30
* Both kernel and rfc use the name nfs_fh; kernel name is
31
* visible to user apps in some versions of libc.
32
* Use different name to avoid clashes.
34
#define NFS_MAXFHSIZE_WIRE 64
38
char data[NFS_MAXFHSIZE_WIRE];
39
} __attribute__((packed));
44
struct rpc_reply reply;
46
struct nfs_fh_wire fh;
47
} __attribute__((packed));
49
#define MNT_REPLY_MINSIZE (sizeof(struct rpc_reply) + sizeof(__u32))
51
static int get_ports(__u32 server, const struct nfs_mount_data *data)
53
__u32 nfs_ver, mount_ver;
56
if (data->flags & NFS_MOUNT_VER3) {
57
nfs_ver = NFS3_VERSION;
58
mount_ver = NFS_MNT3_VERSION;
60
nfs_ver = NFS2_VERSION;
61
mount_ver = NFS_MNT_VERSION;
64
proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
67
nfs_port = portmap(server, NFS_PROGRAM, nfs_ver,
70
if (proto == IPPROTO_TCP) {
71
struct in_addr addr = { server };
72
fprintf(stderr, "NFS over TCP not "
73
"available from %s\n",
81
if (mount_port == 0) {
82
mount_port = portmap(server, NFS_MNT_PROGRAM, mount_ver,
85
mount_port = MOUNT_PORT;
90
static inline int pad_len(int len)
92
return (len + 3) & ~3;
95
static inline void dump_params(__u32 server,
97
const struct nfs_mount_data *data)
99
(void)server; (void)path; (void)data;
102
struct in_addr addr = { server };
104
printf("NFS params:\n");
105
printf(" server = %s, path = \"%s\", ", inet_ntoa(addr), path);
106
printf("version = %d, proto = %s\n",
107
data->flags & NFS_MOUNT_VER3 ? 3 : 2,
108
(data->flags & NFS_MOUNT_TCP) ? "tcp" : "udp");
109
printf(" mount_port = %d, nfs_port = %d, flags = %08x\n",
110
mount_port, nfs_port, data->flags);
111
printf(" rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
112
data->rsize, data->wsize, data->timeo, data->retrans);
113
printf(" acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
114
data->acregmin, data->acregmax, data->acdirmin, data->acdirmax);
115
printf(" soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",
116
(data->flags & NFS_MOUNT_SOFT) != 0,
117
(data->flags & NFS_MOUNT_INTR) != 0,
118
(data->flags & NFS_MOUNT_POSIX) != 0,
119
(data->flags & NFS_MOUNT_NOCTO) != 0,
120
(data->flags & NFS_MOUNT_NOAC) != 0);
124
static inline void dump_fh(const char *data, int len)
126
(void)data; (void)len;
130
int max = len - (len % 8);
132
printf("Root file handle: %d bytes\n", NFS2_FHSIZE);
138
for (j = 0; j < 4; j++) {
139
printf("%02x %02x %02x %02x ",
140
data[i] & 0xff, data[i + 1] & 0xff,
141
data[i + 2] & 0xff, data[i + 3] & 0xff);
149
static struct mount_reply mnt_reply;
151
static int mount_call(__u32 proc, __u32 version,
155
struct mount_call *mnt_call = NULL;
156
size_t path_len, call_len;
160
path_len = strlen(path);
161
call_len = sizeof(*mnt_call) + pad_len(path_len);
163
if ((mnt_call = malloc(call_len)) == NULL) {
168
memset(mnt_call, 0, sizeof(*mnt_call));
170
mnt_call->rpc.program = htonl(NFS_MNT_PROGRAM);
171
mnt_call->rpc.prog_vers = htonl(version);
172
mnt_call->rpc.proc = htonl(proc);
173
mnt_call->path_len = htonl(path_len);
174
memcpy(mnt_call->path, path, path_len);
176
rpc.call = (struct rpc_call *) mnt_call;
177
rpc.call_len = call_len;
178
rpc.reply = (struct rpc_reply *) &mnt_reply;
179
rpc.reply_len = sizeof(mnt_reply);
181
if (rpc_call(clnt, &rpc) < 0)
184
if (proc != MNTPROC_MNT) {
188
if (rpc.reply_len < MNT_REPLY_MINSIZE) {
189
fprintf(stderr, "incomplete reply: %zu < %zu\n",
190
rpc.reply_len, MNT_REPLY_MINSIZE);
194
if (mnt_reply.status != 0) {
195
fprintf(stderr, "mount call failed: %d\n",
196
ntohl(mnt_reply.status));
213
static int mount_v2(const char *path,
214
struct nfs_mount_data *data,
217
int ret = mount_call(MNTPROC_MNT, NFS_MNT_VERSION, path, clnt);
220
dump_fh((const char *) &mnt_reply.fh, NFS2_FHSIZE);
222
data->root.size = NFS_FHSIZE;
223
memcpy(data->root.data, &mnt_reply.fh, NFS_FHSIZE);
224
memcpy(data->old_root.data, &mnt_reply.fh, NFS_FHSIZE);
230
static inline int umount_v2(const char *path, struct client *clnt)
232
return mount_call(MNTPROC_UMNT, NFS_MNT_VERSION, path, clnt);
235
static int mount_v3(const char *path,
236
struct nfs_mount_data *data,
239
int ret = mount_call(MNTPROC_MNT, NFS_MNT3_VERSION, path, clnt);
242
size_t fhsize = ntohl(mnt_reply.fh.size);
244
dump_fh((const char *) &mnt_reply.fh.data, fhsize);
246
memset(data->old_root.data, 0, NFS_FHSIZE);
247
memset(&data->root, 0, sizeof(data->root));
248
data->root.size = fhsize;
249
memcpy(&data->root.data, mnt_reply.fh.data, fhsize);
250
data->flags |= NFS_MOUNT_VER3;
256
static inline int umount_v3(const char *path, struct client *clnt)
258
return mount_call(MNTPROC_UMNT, NFS_MNT3_VERSION, path, clnt);
261
int nfs_mount(const char *pathname, const char *hostname,
262
__u32 server, const char *rem_path, const char *path,
263
struct nfs_mount_data *data)
265
struct client *clnt = NULL;
266
struct sockaddr_in addr;
272
if (get_ports(server, data) != 0) {
276
dump_params(server, path, data);
278
if (data->flags & NFS_MOUNT_TCP) {
279
clnt = tcp_client(server, mount_port, CLI_RESVPORT);
281
clnt = udp_client(server, mount_port, CLI_RESVPORT);
288
if (data->flags & NFS_MOUNT_VER3) {
289
ret = mount_v3(rem_path, data, clnt);
291
ret = mount_v2(rem_path, data, clnt);
299
if (data->flags & NFS_MOUNT_TCP) {
300
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
302
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
310
if (bindresvport(sock, 0) == -1) {
311
perror("bindresvport");
315
addr.sin_family = AF_INET;
316
addr.sin_addr.s_addr = server;
317
addr.sin_port = htons(nfs_port);
318
memcpy(&data->addr, &addr, sizeof(data->addr));
320
strncpy(data->hostname, hostname, sizeof(data->hostname));
324
mountflags = (data->flags & NFS_MOUNT_KLIBC_RONLY) ? MS_RDONLY : 0;
325
data->flags = data->flags & NFS_MOUNT_FLAGMASK;
326
ret = mount(pathname, path, "nfs", mountflags, data);
333
DEBUG(("Mounted %s on %s\n", pathname, path));
339
if (data->flags & NFS_MOUNT_VER3) {
340
umount_v3(path, clnt);
342
umount_v2(path, clnt);