Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 815 - (hide annotations) (download)
Fri Apr 24 18:32:46 2009 UTC (15 years ago) by niro
File MIME type: text/plain
File size: 7991 byte(s)
-updated to klibc-1.5.15
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     static int get_ports(uint32_t server, const struct nfs_mount_data *data)
48     {
49     uint32_t nfs_ver, mount_ver;
50     uint32_t proto;
51    
52     if (data->flags & NFS_MOUNT_VER3) {
53     nfs_ver = NFS3_VERSION;
54     mount_ver = NFS_MNT3_VERSION;
55     } else {
56     nfs_ver = NFS2_VERSION;
57     mount_ver = NFS_MNT_VERSION;
58     }
59    
60     proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
61    
62     if (nfs_port == 0) {
63     nfs_port = portmap(server, NFS_PROGRAM, nfs_ver, proto);
64     if (nfs_port == 0) {
65     if (proto == IPPROTO_TCP) {
66     struct in_addr addr = { server };
67     fprintf(stderr, "NFS over TCP not "
68     "available from %s\n", inet_ntoa(addr));
69     return -1;
70     }
71     nfs_port = NFS_PORT;
72     }
73     }
74    
75     if (mount_port == 0) {
76     mount_port = portmap(server, NFS_MNT_PROGRAM, mount_ver, proto);
77     if (mount_port == 0)
78     mount_port = MOUNT_PORT;
79     }
80     return 0;
81     }
82    
83     static inline int pad_len(int len)
84     {
85     return (len + 3) & ~3;
86     }
87    
88     static inline void dump_params(uint32_t server,
89     const char *path,
90     const struct nfs_mount_data *data)
91     {
92     (void)server;
93     (void)path;
94     (void)data;
95    
96     #ifdef NFS_DEBUG
97     struct in_addr addr = { server };
98    
99     printf("NFS params:\n");
100     printf(" server = %s, path = \"%s\", ", inet_ntoa(addr), path);
101     printf("version = %d, proto = %s\n",
102     data->flags & NFS_MOUNT_VER3 ? 3 : 2,
103     (data->flags & NFS_MOUNT_TCP) ? "tcp" : "udp");
104     printf(" mount_port = %d, nfs_port = %d, flags = %08x\n",
105     mount_port, nfs_port, data->flags);
106     printf(" rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
107     data->rsize, data->wsize, data->timeo, data->retrans);
108     printf(" acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
109     data->acregmin, data->acregmax, data->acdirmin, data->acdirmax);
110     printf(" soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",
111     (data->flags & NFS_MOUNT_SOFT) != 0,
112     (data->flags & NFS_MOUNT_INTR) != 0,
113     (data->flags & NFS_MOUNT_POSIX) != 0,
114     (data->flags & NFS_MOUNT_NOCTO) != 0,
115     (data->flags & NFS_MOUNT_NOAC) != 0);
116     #endif
117     }
118    
119     static inline void dump_fh(const char *data, int len)
120     {
121     (void)data;
122     (void)len;
123    
124     #ifdef NFS_DEBUG
125     int i = 0;
126     int max = len - (len % 8);
127    
128     printf("Root file handle: %d bytes\n", NFS2_FHSIZE);
129    
130     while (i < max) {
131     int j;
132    
133     printf(" %4d: ", i);
134     for (j = 0; j < 4; j++) {
135     printf("%02x %02x %02x %02x ",
136     data[i] & 0xff, data[i + 1] & 0xff,
137     data[i + 2] & 0xff, data[i + 3] & 0xff);
138     }
139     i += j;
140     printf("\n");
141     }
142     #endif
143     }
144    
145     static struct mount_reply mnt_reply;
146    
147     static int mount_call(uint32_t proc, uint32_t version,
148     const char *path, struct client *clnt)
149     {
150     struct mount_call *mnt_call = NULL;
151     size_t path_len, call_len;
152     struct rpc rpc;
153     int ret = 0;
154    
155     path_len = strlen(path);
156     call_len = sizeof(*mnt_call) + pad_len(path_len);
157    
158     if ((mnt_call = malloc(call_len)) == NULL) {
159     perror("malloc");
160     goto bail;
161     }
162    
163     memset(mnt_call, 0, sizeof(*mnt_call));
164    
165     mnt_call->rpc.program = htonl(NFS_MNT_PROGRAM);
166     mnt_call->rpc.prog_vers = htonl(version);
167     mnt_call->rpc.proc = htonl(proc);
168     mnt_call->path_len = htonl(path_len);
169     memcpy(mnt_call->path, path, path_len);
170    
171     rpc.call = (struct rpc_call *)mnt_call;
172     rpc.call_len = call_len;
173     rpc.reply = (struct rpc_reply *)&mnt_reply;
174     rpc.reply_len = sizeof(mnt_reply);
175    
176     if (rpc_call(clnt, &rpc) < 0)
177     goto bail;
178    
179     if (proc != MNTPROC_MNT) {
180     goto done;
181     }
182    
183     if (rpc.reply_len < MNT_REPLY_MINSIZE) {
184     fprintf(stderr, "incomplete reply: %zu < %zu\n",
185     rpc.reply_len, MNT_REPLY_MINSIZE);
186     goto bail;
187     }
188    
189     if (mnt_reply.status != 0) {
190 niro 815 fprintf(stderr, "mount call failed - server replied: %s.\n",
191     strerror(ntohl(mnt_reply.status)));
192 niro 532 goto bail;
193     }
194    
195     goto done;
196    
197     bail:
198     ret = -1;
199    
200     done:
201     if (mnt_call) {
202     free(mnt_call);
203     }
204    
205     return ret;
206     }
207    
208     static int mount_v2(const char *path,
209     struct nfs_mount_data *data, struct client *clnt)
210     {
211     int ret = mount_call(MNTPROC_MNT, NFS_MNT_VERSION, path, clnt);
212    
213     if (ret == 0) {
214     dump_fh((const char *)&mnt_reply.fh, NFS2_FHSIZE);
215    
216     data->root.size = NFS_FHSIZE;
217     memcpy(data->root.data, &mnt_reply.fh, NFS_FHSIZE);
218     memcpy(data->old_root.data, &mnt_reply.fh, NFS_FHSIZE);
219     }
220    
221     return ret;
222     }
223    
224     static inline int umount_v2(const char *path, struct client *clnt)
225     {
226     return mount_call(MNTPROC_UMNT, NFS_MNT_VERSION, path, clnt);
227     }
228    
229     static int mount_v3(const char *path,
230     struct nfs_mount_data *data, struct client *clnt)
231     {
232     int ret = mount_call(MNTPROC_MNT, NFS_MNT3_VERSION, path, clnt);
233    
234     if (ret == 0) {
235     size_t fhsize = ntohl(mnt_reply.fh.size);
236    
237     dump_fh((const char *)&mnt_reply.fh.data, fhsize);
238    
239     memset(data->old_root.data, 0, NFS_FHSIZE);
240     memset(&data->root, 0, sizeof(data->root));
241     data->root.size = fhsize;
242     memcpy(&data->root.data, mnt_reply.fh.data, fhsize);
243     data->flags |= NFS_MOUNT_VER3;
244     }
245    
246     return ret;
247     }
248    
249     static inline int umount_v3(const char *path, struct client *clnt)
250     {
251     return mount_call(MNTPROC_UMNT, NFS_MNT3_VERSION, path, clnt);
252     }
253    
254     int nfs_mount(const char *pathname, const char *hostname,
255     uint32_t server, const char *rem_path, const char *path,
256     struct nfs_mount_data *data)
257     {
258     struct client *clnt = NULL;
259     struct sockaddr_in addr;
260     char mounted = 0;
261     int sock = -1;
262     int ret = 0;
263     int mountflags;
264    
265     if (get_ports(server, data) != 0) {
266     goto bail;
267     }
268    
269     dump_params(server, rem_path, data);
270    
271     if (data->flags & NFS_MOUNT_TCP) {
272     clnt = tcp_client(server, mount_port, CLI_RESVPORT);
273     } else {
274     clnt = udp_client(server, mount_port, CLI_RESVPORT);
275     }
276    
277     if (clnt == NULL) {
278     goto bail;
279     }
280    
281     if (data->flags & NFS_MOUNT_VER3) {
282     ret = mount_v3(rem_path, data, clnt);
283     } else {
284     ret = mount_v2(rem_path, data, clnt);
285     }
286    
287     if (ret == -1) {
288     goto bail;
289     }
290     mounted = 1;
291    
292     if (data->flags & NFS_MOUNT_TCP) {
293     sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
294     } else {
295     sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
296     }
297    
298     if (sock == -1) {
299     perror("socket");
300     goto bail;
301     }
302    
303     if (bindresvport(sock, 0) == -1) {
304     perror("bindresvport");
305     goto bail;
306     }
307    
308     addr.sin_family = AF_INET;
309     addr.sin_addr.s_addr = server;
310     addr.sin_port = htons(nfs_port);
311     memcpy(&data->addr, &addr, sizeof(data->addr));
312    
313     strncpy(data->hostname, hostname, sizeof(data->hostname));
314    
315     data->fd = sock;
316    
317     mountflags = (data->flags & NFS_MOUNT_KLIBC_RONLY) ? MS_RDONLY : 0;
318     data->flags = data->flags & NFS_MOUNT_FLAGMASK;
319     ret = mount(pathname, path, "nfs", mountflags, data);
320    
321     if (ret == -1) {
322     if (errno == ENODEV) {
323     fprintf(stderr, "mount: the kernel lacks NFS v%d "
324     "support\n",
325     (data->flags & NFS_MOUNT_VER3) ? 3 : 2);
326     } else {
327     perror("mount");
328     }
329     goto bail;
330     }
331    
332     DEBUG(("Mounted %s on %s\n", pathname, path));
333    
334     goto done;
335    
336     bail:
337     if (mounted) {
338     if (data->flags & NFS_MOUNT_VER3) {
339     umount_v3(path, clnt);
340     } else {
341     umount_v2(path, clnt);
342     }
343     }
344    
345     ret = -1;
346    
347     done:
348     if (clnt) {
349     client_free(clnt);
350     }
351    
352     if (sock != -1) {
353     close(sock);
354     }
355    
356     return ret;
357     }