Magellan Linux

Annotation of /trunk/mkinitrd-magellan/klibc/usr/kinit/nfsmount/mount.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1297 - (hide annotations) (download)
Fri May 27 15:12:11 2011 UTC (12 years, 11 months ago) by niro
File MIME type: text/plain
File size: 8078 byte(s)
-updated to klibc-1.5.22 with mntproc definitions patch included
1 niro 532 #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     #include <errno.h>
11    
12     #include "nfsmount.h"
13     #include "sunrpc.h"
14    
15     static uint32_t mount_port;
16    
17     struct mount_call {
18     struct rpc_call rpc;
19     uint32_t path_len;
20     char path[0];
21     };
22    
23     /*
24     * The following structure is the NFS v3 on-the-wire file handle,
25     * as defined in rfc1813.
26     * This differs from the structure used by the kernel,
27     * defined in <linux/nfh3.h>: rfc has a long in network order,
28     * kernel has a short in native order.
29     * Both kernel and rfc use the name nfs_fh; kernel name is
30     * visible to user apps in some versions of libc.
31     * Use different name to avoid clashes.
32     */
33     #define NFS_MAXFHSIZE_WIRE 64
34     struct nfs_fh_wire {
35     uint32_t size;
36     char data[NFS_MAXFHSIZE_WIRE];
37     } __attribute__ ((packed));
38    
39     struct mount_reply {
40     struct rpc_reply reply;
41     uint32_t status;
42     struct nfs_fh_wire fh;
43     } __attribute__ ((packed));
44    
45     #define MNT_REPLY_MINSIZE (sizeof(struct rpc_reply) + sizeof(uint32_t))
46    
47 niro 1297 #ifndef MNTPROC_MNT
48     # define MNTPROC_MNT 1
49     # define MNTPROC_UMNT 3
50     #endif /* MNTPROC_MNT */
51    
52 niro 532 static int get_ports(uint32_t server, const struct nfs_mount_data *data)
53     {
54     uint32_t nfs_ver, mount_ver;
55     uint32_t proto;
56    
57     if (data->flags & NFS_MOUNT_VER3) {
58     nfs_ver = NFS3_VERSION;
59     mount_ver = NFS_MNT3_VERSION;
60     } else {
61     nfs_ver = NFS2_VERSION;
62     mount_ver = NFS_MNT_VERSION;
63     }
64    
65     proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
66    
67     if (nfs_port == 0) {
68     nfs_port = portmap(server, NFS_PROGRAM, nfs_ver, 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", inet_ntoa(addr));
74     return -1;
75     }
76     nfs_port = NFS_PORT;
77     }
78     }
79    
80     if (mount_port == 0) {
81     mount_port = portmap(server, NFS_MNT_PROGRAM, mount_ver, proto);
82     if (mount_port == 0)
83     mount_port = MOUNT_PORT;
84     }
85     return 0;
86     }
87    
88     static inline int pad_len(int len)
89     {
90     return (len + 3) & ~3;
91     }
92    
93     static inline void dump_params(uint32_t server,
94     const char *path,
95     const struct nfs_mount_data *data)
96     {
97     (void)server;
98     (void)path;
99     (void)data;
100    
101 niro 1122 #ifdef DEBUG
102 niro 532 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;
127     (void)len;
128    
129 niro 1122 #ifdef DEBUG
130 niro 532 int i = 0;
131     int max = len - (len % 8);
132    
133     printf("Root file handle: %d bytes\n", NFS2_FHSIZE);
134    
135     while (i < max) {
136     int j;
137    
138     printf(" %4d: ", i);
139     for (j = 0; j < 4; j++) {
140     printf("%02x %02x %02x %02x ",
141     data[i] & 0xff, data[i + 1] & 0xff,
142     data[i + 2] & 0xff, data[i + 3] & 0xff);
143     }
144     i += j;
145     printf("\n");
146     }
147     #endif
148     }
149    
150     static struct mount_reply mnt_reply;
151    
152     static int mount_call(uint32_t proc, uint32_t version,
153     const char *path, 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 niro 815 fprintf(stderr, "mount call failed - server replied: %s.\n",
196     strerror(ntohl(mnt_reply.status)));
197 niro 532 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, struct client *clnt)
215     {
216     int ret = mount_call(MNTPROC_MNT, NFS_MNT_VERSION, path, clnt);
217    
218     if (ret == 0) {
219     dump_fh((const char *)&mnt_reply.fh, NFS2_FHSIZE);
220    
221     data->root.size = NFS_FHSIZE;
222     memcpy(data->root.data, &mnt_reply.fh, NFS_FHSIZE);
223     memcpy(data->old_root.data, &mnt_reply.fh, NFS_FHSIZE);
224     }
225    
226     return ret;
227     }
228    
229     static inline int umount_v2(const char *path, struct client *clnt)
230     {
231     return mount_call(MNTPROC_UMNT, NFS_MNT_VERSION, path, clnt);
232     }
233    
234     static int mount_v3(const char *path,
235     struct nfs_mount_data *data, struct client *clnt)
236     {
237     int ret = mount_call(MNTPROC_MNT, NFS_MNT3_VERSION, path, clnt);
238    
239     if (ret == 0) {
240     size_t fhsize = ntohl(mnt_reply.fh.size);
241    
242     dump_fh((const char *)&mnt_reply.fh.data, fhsize);
243    
244     memset(data->old_root.data, 0, NFS_FHSIZE);
245     memset(&data->root, 0, sizeof(data->root));
246     data->root.size = fhsize;
247     memcpy(&data->root.data, mnt_reply.fh.data, fhsize);
248     data->flags |= NFS_MOUNT_VER3;
249     }
250    
251     return ret;
252     }
253    
254     static inline int umount_v3(const char *path, struct client *clnt)
255     {
256     return mount_call(MNTPROC_UMNT, NFS_MNT3_VERSION, path, clnt);
257     }
258    
259     int nfs_mount(const char *pathname, const char *hostname,
260     uint32_t server, const char *rem_path, const char *path,
261     struct nfs_mount_data *data)
262     {
263     struct client *clnt = NULL;
264     struct sockaddr_in addr;
265     char mounted = 0;
266     int sock = -1;
267     int ret = 0;
268     int mountflags;
269    
270     if (get_ports(server, data) != 0) {
271     goto bail;
272     }
273    
274     dump_params(server, rem_path, data);
275    
276     if (data->flags & NFS_MOUNT_TCP) {
277     clnt = tcp_client(server, mount_port, CLI_RESVPORT);
278     } else {
279     clnt = udp_client(server, mount_port, CLI_RESVPORT);
280     }
281    
282     if (clnt == NULL) {
283     goto bail;
284     }
285    
286     if (data->flags & NFS_MOUNT_VER3) {
287     ret = mount_v3(rem_path, data, clnt);
288     } else {
289     ret = mount_v2(rem_path, data, clnt);
290     }
291    
292     if (ret == -1) {
293     goto bail;
294     }
295     mounted = 1;
296    
297     if (data->flags & NFS_MOUNT_TCP) {
298     sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
299     } else {
300     sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
301     }
302    
303     if (sock == -1) {
304     perror("socket");
305     goto bail;
306     }
307    
308     if (bindresvport(sock, 0) == -1) {
309     perror("bindresvport");
310     goto bail;
311     }
312    
313     addr.sin_family = AF_INET;
314     addr.sin_addr.s_addr = server;
315     addr.sin_port = htons(nfs_port);
316     memcpy(&data->addr, &addr, sizeof(data->addr));
317    
318     strncpy(data->hostname, hostname, sizeof(data->hostname));
319    
320     data->fd = sock;
321    
322     mountflags = (data->flags & NFS_MOUNT_KLIBC_RONLY) ? MS_RDONLY : 0;
323     data->flags = data->flags & NFS_MOUNT_FLAGMASK;
324     ret = mount(pathname, path, "nfs", mountflags, data);
325    
326     if (ret == -1) {
327     if (errno == ENODEV) {
328     fprintf(stderr, "mount: the kernel lacks NFS v%d "
329     "support\n",
330     (data->flags & NFS_MOUNT_VER3) ? 3 : 2);
331     } else {
332     perror("mount");
333     }
334     goto bail;
335     }
336    
337 niro 1122 dprintf("Mounted %s on %s\n", pathname, path);
338 niro 532
339     goto done;
340    
341     bail:
342     if (mounted) {
343     if (data->flags & NFS_MOUNT_VER3) {
344     umount_v3(path, clnt);
345     } else {
346     umount_v2(path, clnt);
347     }
348     }
349    
350     ret = -1;
351    
352     done:
353     if (clnt) {
354     client_free(clnt);
355     }
356    
357     if (sock != -1) {
358     close(sock);
359     }
360    
361     return ret;
362     }