~ubuntu-branches/ubuntu/hardy/klibc/hardy-updates

« back to all changes in this revision

Viewing changes to nfsmount/mount.c

  • Committer: Bazaar Package Importer
  • Author(s): Jeff Bailey
  • Date: 2006-01-04 20:24:52 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20060104202452-ec4v3n829rymukuv
Tags: 1.1.15-0ubuntu1
* New upstream version.

* Patch to fix compilation on parisc64 kernels.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#include <sys/mount.h>
2
 
#include <sys/types.h>
3
 
#include <sys/socket.h>
4
 
#include <arpa/inet.h>
5
 
#include <netinet/in.h>
6
 
#include <linux/nfs.h>
7
 
#include <stdio.h>
8
 
#include <stdlib.h>
9
 
#include <string.h>
10
 
 
11
 
#include "nfsmount.h"
12
 
#include "sunrpc.h"
13
 
 
14
 
static __u32 mount_port;
15
 
 
16
 
struct mount_call
17
 
{
18
 
        struct rpc_call rpc;
19
 
        __u32 path_len;
20
 
        char path[0];
21
 
};
22
 
 
23
 
 
24
 
/*
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.
33
 
 */
34
 
#define NFS_MAXFHSIZE_WIRE 64
35
 
struct nfs_fh_wire
36
 
{
37
 
        __u32 size;
38
 
        char data[NFS_MAXFHSIZE_WIRE];
39
 
} __attribute__((packed));
40
 
 
41
 
 
42
 
struct mount_reply
43
 
{
44
 
        struct rpc_reply reply;
45
 
        __u32 status;
46
 
        struct nfs_fh_wire fh;
47
 
} __attribute__((packed));
48
 
 
49
 
#define MNT_REPLY_MINSIZE (sizeof(struct rpc_reply) + sizeof(__u32))
50
 
 
51
 
static int get_ports(__u32 server, const struct nfs_mount_data *data)
52
 
{
53
 
        __u32 nfs_ver, mount_ver;
54
 
        __u32 proto;
55
 
 
56
 
        if (data->flags & NFS_MOUNT_VER3) {
57
 
                nfs_ver = NFS3_VERSION;
58
 
                mount_ver = NFS_MNT3_VERSION;
59
 
        } else {
60
 
                nfs_ver = NFS2_VERSION;
61
 
                mount_ver = NFS_MNT_VERSION;
62
 
        }
63
 
 
64
 
        proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
65
 
 
66
 
        if (nfs_port == 0) {
67
 
                nfs_port = portmap(server, NFS_PROGRAM, nfs_ver,
68
 
                                   proto);
69
 
                if (nfs_port == 0) {
70
 
                        if (proto == IPPROTO_TCP) {
71
 
                                struct in_addr addr = { server };
72
 
                                fprintf(stderr, "NFS over TCP not "
73
 
                                        "available from %s\n",
74
 
                                        inet_ntoa(addr));
75
 
                                return -1;
76
 
                        }
77
 
                        nfs_port = NFS_PORT;
78
 
                }
79
 
        }
80
 
 
81
 
        if (mount_port == 0) {
82
 
                mount_port = portmap(server, NFS_MNT_PROGRAM, mount_ver,
83
 
                                     proto);
84
 
                if (mount_port == 0)
85
 
                        mount_port = MOUNT_PORT;
86
 
        }
87
 
        return 0;
88
 
}
89
 
 
90
 
static inline int pad_len(int len)
91
 
{
92
 
        return (len + 3) & ~3;
93
 
}
94
 
 
95
 
static inline void dump_params(__u32 server,
96
 
                               const char *path,
97
 
                               const struct nfs_mount_data *data)
98
 
{
99
 
        (void)server; (void)path; (void)data;
100
 
 
101
 
#ifdef NFS_DEBUG
102
 
        struct in_addr addr = { server };
103
 
 
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);
121
 
#endif
122
 
}
123
 
 
124
 
static inline void dump_fh(const char *data, int len)
125
 
{
126
 
        (void)data; (void)len;
127
 
 
128
 
#ifdef NFS_DEBUG
129
 
        int i = 0;
130
 
        int max = len - (len % 8);
131
 
 
132
 
        printf("Root file handle: %d bytes\n", NFS2_FHSIZE);
133
 
 
134
 
        while (i < max) {
135
 
                int j;
136
 
 
137
 
                printf("  %4d:  ", i);
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);
142
 
                }
143
 
                i += j;
144
 
                printf("\n");
145
 
        }
146
 
#endif
147
 
}
148
 
 
149
 
static struct mount_reply mnt_reply;
150
 
 
151
 
static int mount_call(__u32 proc, __u32 version,
152
 
                      const char *path,
153
 
                      struct client *clnt)
154
 
{
155
 
        struct mount_call *mnt_call = NULL;
156
 
        size_t path_len, call_len;
157
 
        struct rpc rpc;
158
 
        int ret = 0;
159
 
 
160
 
        path_len = strlen(path);
161
 
        call_len = sizeof(*mnt_call) + pad_len(path_len);
162
 
 
163
 
        if ((mnt_call = malloc(call_len)) == NULL) {
164
 
                perror("malloc");
165
 
                goto bail;
166
 
        }
167
 
 
168
 
        memset(mnt_call, 0, sizeof(*mnt_call));
169
 
 
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);
175
 
 
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);
180
 
 
181
 
        if (rpc_call(clnt, &rpc) < 0)
182
 
                goto bail;
183
 
 
184
 
        if (proc != MNTPROC_MNT) {
185
 
                goto done;
186
 
        }
187
 
 
188
 
        if (rpc.reply_len < MNT_REPLY_MINSIZE) {
189
 
                fprintf(stderr, "incomplete reply: %zu < %zu\n",
190
 
                        rpc.reply_len, MNT_REPLY_MINSIZE);
191
 
                goto bail;
192
 
        }
193
 
 
194
 
        if (mnt_reply.status != 0) {
195
 
                fprintf(stderr, "mount call failed: %d\n",
196
 
                        ntohl(mnt_reply.status));
197
 
                goto bail;
198
 
        }
199
 
 
200
 
        goto done;
201
 
 
202
 
 bail:
203
 
        ret = -1;
204
 
 
205
 
 done:
206
 
        if (mnt_call) {
207
 
                free(mnt_call);
208
 
        }
209
 
 
210
 
        return ret;
211
 
}
212
 
 
213
 
static int mount_v2(const char *path,
214
 
                    struct nfs_mount_data *data,
215
 
                    struct client *clnt)
216
 
{
217
 
        int ret = mount_call(MNTPROC_MNT, NFS_MNT_VERSION, path, clnt);
218
 
 
219
 
        if (ret == 0) {
220
 
                dump_fh((const char *) &mnt_reply.fh, NFS2_FHSIZE);
221
 
 
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);
225
 
        }
226
 
 
227
 
        return ret;
228
 
}
229
 
 
230
 
static inline int umount_v2(const char *path, struct client *clnt)
231
 
{
232
 
        return mount_call(MNTPROC_UMNT, NFS_MNT_VERSION, path, clnt);
233
 
}
234
 
 
235
 
static int mount_v3(const char *path,
236
 
                    struct nfs_mount_data *data,
237
 
                    struct client *clnt)
238
 
{
239
 
        int ret = mount_call(MNTPROC_MNT, NFS_MNT3_VERSION, path, clnt);
240
 
 
241
 
        if (ret == 0) {
242
 
                size_t fhsize = ntohl(mnt_reply.fh.size);
243
 
 
244
 
                dump_fh((const char *) &mnt_reply.fh.data, fhsize);
245
 
 
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;
251
 
        }
252
 
 
253
 
        return ret;
254
 
}
255
 
 
256
 
static inline int umount_v3(const char *path, struct client *clnt)
257
 
{
258
 
        return mount_call(MNTPROC_UMNT, NFS_MNT3_VERSION, path, clnt);
259
 
}
260
 
 
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)
264
 
{
265
 
        struct client *clnt = NULL;
266
 
        struct sockaddr_in addr;
267
 
        char mounted = 0;
268
 
        int sock = -1;
269
 
        int ret = 0;
270
 
        int mountflags;
271
 
 
272
 
        if (get_ports(server, data) != 0) {
273
 
                goto bail;
274
 
        }
275
 
 
276
 
        dump_params(server, path, data);
277
 
 
278
 
        if (data->flags & NFS_MOUNT_TCP) {
279
 
                clnt = tcp_client(server, mount_port, CLI_RESVPORT);
280
 
        } else {
281
 
                clnt = udp_client(server, mount_port, CLI_RESVPORT);
282
 
        }
283
 
 
284
 
        if (clnt == NULL) {
285
 
                goto bail;
286
 
        }
287
 
 
288
 
        if (data->flags & NFS_MOUNT_VER3) {
289
 
                ret = mount_v3(rem_path, data, clnt);
290
 
        } else {
291
 
                ret = mount_v2(rem_path, data, clnt);
292
 
        }
293
 
 
294
 
        if (ret == -1) {
295
 
                goto bail;
296
 
        }
297
 
        mounted = 1;
298
 
 
299
 
        if (data->flags & NFS_MOUNT_TCP) {
300
 
                sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
301
 
        } else {
302
 
                sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
303
 
        }
304
 
 
305
 
        if (sock == -1) {
306
 
                perror("socket");
307
 
                goto bail;
308
 
        }
309
 
 
310
 
        if (bindresvport(sock, 0) == -1) {
311
 
                perror("bindresvport");
312
 
                goto bail;
313
 
        }
314
 
 
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));
319
 
 
320
 
        strncpy(data->hostname, hostname, sizeof(data->hostname));
321
 
 
322
 
        data->fd = sock;
323
 
 
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);
327
 
 
328
 
        if (ret == -1) {
329
 
                perror("mount");
330
 
                goto bail;
331
 
        }
332
 
 
333
 
        DEBUG(("Mounted %s on %s\n", pathname, path));
334
 
 
335
 
        goto done;
336
 
 
337
 
 bail:
338
 
        if (mounted) {
339
 
                if (data->flags & NFS_MOUNT_VER3) {
340
 
                        umount_v3(path, clnt);
341
 
                } else {
342
 
                        umount_v2(path, clnt);
343
 
                }
344
 
        }
345
 
 
346
 
        ret = -1;
347
 
 
348
 
 done:
349
 
        if (clnt) {
350
 
                client_free(clnt);
351
 
        }
352
 
 
353
 
        if (sock != -1) {
354
 
                close(sock);
355
 
        }
356
 
 
357
 
        return ret;
358
 
}
359