Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 906 - (show annotations) (download)
Fri Oct 16 11:37:14 2009 UTC (14 years, 6 months ago) by niro
File MIME type: text/plain
File size: 8086 byte(s)
-fixed missing mntproc definitions with newer kernels (>= 2.6.31)
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 #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 #ifndef MNTPROC_MNT
48 # define MNTPROC_MNT 1
49 # define MNTPROC_UMNT 3
50 #endif /* MNTPROC_MNT */
51
52 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 #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;
127 (void)len;
128
129 #ifdef NFS_DEBUG
130 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 fprintf(stderr, "mount call failed - server replied: %s.\n",
196 strerror(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, 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 DEBUG(("Mounted %s on %s\n", pathname, path));
338
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 }