]> git.pld-linux.org Git - packages/util-linux.git/blame - util-linux-2.12-01-nfs.dif
- init var
[packages/util-linux.git] / util-linux-2.12-01-nfs.dif
CommitLineData
a5f7e223
AM
1
2Miscellaneous nfs mount changes from Trond.
3
4---
5
6 util-linux-2.12-bfields/mount/Makefile | 4
7 util-linux-2.12-bfields/mount/nfsmount.c | 1235 +++++++++++++++++++------------
8 util-linux-2.12-bfields/mount/sundries.h | 1
9 util-linux-2.12-bfields/mount/umount.c | 4
10 4 files changed, 794 insertions(+), 450 deletions(-)
11
12diff -puN mount/Makefile~nfs mount/Makefile
13--- util-linux-2.12/mount/Makefile~nfs 2004-10-13 13:51:44.000000000 -0400
14+++ util-linux-2.12-bfields/mount/Makefile 2004-10-13 14:13:30.000000000 -0400
15@@ -31,7 +31,7 @@
16
17 LO_OBJS = lomount.o $(LIB)/xstrncpy.o
18 CRYPT_OBJS = cryptsetup.o -lcryptsetup
19-NFS_OBJS = nfsmount.o nfsmount_xdr.o nfsmount_clnt.o
20+NFS_OBJS = nfsmount.o nfsmount_xdr.o
21 GEN_FILES = nfsmount.h nfsmount_xdr.c nfsmount_clnt.c
22
23 all: $(PROGS)
24@@ -55,7 +55,7 @@
25
26 umount: umount.o fstab.o sundries.o xmalloc.o realpath.o mntent.o \
27 getusername.o get_label_uuid.o mount_by_label.o mount_blkid.o \
28- version.o $(LIB)/env.o $(LO_OBJS) $(CRYPT_OBJS)
29+ version.o $(LIB)/env.o $(NFS_OBJS) $(LO_OBJS) $(CRYPT_OBJS)
30 $(LINK) $^ -o $@ $(BLKID_LIB)
31
32 swapon: swapon.o version.o xmalloc.o \
33diff -puN mount/nfsmount.c~nfs mount/nfsmount.c
34--- util-linux-2.12/mount/nfsmount.c~nfs 2004-10-13 13:51:44.000000000 -0400
35+++ util-linux-2.12-bfields/mount/nfsmount.c 2004-10-13 14:13:30.000000000 -0400
36@@ -34,6 +34,7 @@
37
38 #include "../defines.h" /* for HAVE_rpcsvc_nfs_prot_h and HAVE_inet_aton */
39
40+#include <ctype.h>
41 #include <unistd.h>
42 #include <stdio.h>
43 #include <string.h>
44@@ -72,11 +73,100 @@
45 #define NFS_FHSIZE 32
46 #endif
47
48+#define MNT_SENDBUFSIZE ((u_int)2048)
49+#define MNT_RECVBUFSIZE ((u_int)1024)
50+
51 static char *nfs_strerror(int stat);
52
53 #define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
54
55 #define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
56+#define MAX_MNTPROT ((nfs_mount_version >= 4) ? 3 : 2)
57+#define HAVE_RELIABLE_TCP (nfs_mount_version >= 4)
58+
59+#ifndef HAVE_inet_aton
60+#define inet_aton(a,b) (0)
61+#endif
62+
63+typedef dirpath mnt2arg_t;
64+typedef dirpath mnt3arg_t;
65+typedef dirpath mntarg_t;
66+
67+typedef struct fhstatus mnt2res_t;
68+typedef struct mountres3 mnt3res_t;
69+typedef union {
70+ mnt2res_t nfsv2;
71+ mnt3res_t nfsv3;
72+} mntres_t;
73+
74+typedef struct {
75+ char **hostname;
76+ struct sockaddr_in saddr;
77+ struct pmap pmap;
78+} clnt_addr_t;
79+
80+/* RPC call timeout values */
81+static const struct timeval TIMEOUT = { 20, 0 };
82+static const struct timeval RETRY_TIMEOUT = { 3, 0 };
83+
84+/* Define the order in which to probe for UDP/TCP services */
85+static const u_int *
86+proto_probelist(const int use_tcp)
87+{
88+ static const u_int probe_both[] = { IPPROTO_TCP, IPPROTO_UDP, 0 };
89+ static const u_int probe_udponly[] = { IPPROTO_UDP, 0 };
90+ if (use_tcp)
91+ return probe_both;
92+ return probe_udponly;
93+}
94+
95+/* Define the order in which NFS versions are probed on portmapper */
96+static const u_long *
97+nfs_probelist(const int vers)
98+{
99+ static const u_long nfs2_probe[] = { 2, 0};
100+ static const u_long nfs3_probe[] = { 3, 2, 0};
101+ switch (vers) {
102+ case 3:
103+ return nfs3_probe;
104+ default:
105+ return nfs2_probe;
106+ }
107+}
108+
109+/* Define the order in which Mountd versions are probed on portmapper */
110+static const u_long *
111+mnt_probelist(const int vers)
112+{
113+ static const u_long mnt1_probe[] = { 1, 2, 0 };
114+ static const u_long mnt3_probe[] = { 3, 1, 2, 0 };
115+ switch (vers) {
116+ case 3:
117+ return mnt3_probe;
118+ default:
119+ return mnt1_probe;
120+ }
121+}
122+
123+/* Map an NFS version into the corresponding Mountd version */
124+static u_long
125+nfsvers_to_mnt(const u_long vers)
126+{
127+ static const u_long nfs_to_mnt[] = { 0, 0, 1, 3 };
128+ if (vers <= 3)
129+ return nfs_to_mnt[vers];
130+ return 0;
131+}
132+
133+/* Map a Mountd version into the corresponding NFS version */
134+static u_long
135+mntvers_to_nfs(const u_long vers)
136+{
137+ static const u_long mnt_to_nfs[] = { 0, 2, 2, 3 };
138+ if (vers <= 3)
139+ return mnt_to_nfs[vers];
140+ return 0;
141+}
142
143 static int
144 linux_version_code(void) {
145@@ -102,123 +192,558 @@ linux_version_code(void) {
146 * NFS_MOUNT_VERSION: these nfsmount sources at compile time
147 * nfs_mount_version: version this source and running kernel can handle
148 */
149+static int nfs_mount_version = NFS_MOUNT_VERSION;
150+
151 static int
152 find_kernel_nfs_mount_version(void) {
153 static int kernel_version = -1;
154- int nfs_mount_version = NFS_MOUNT_VERSION;
155+ int mnt_version = NFS_MOUNT_VERSION;
156
157 if (kernel_version == -1)
158 kernel_version = linux_version_code();
159
160 if (kernel_version) {
161 if (kernel_version < MAKE_VERSION(2,1,32))
162- nfs_mount_version = 1;
163+ mnt_version = 1;
164 else if (kernel_version < MAKE_VERSION(2,2,18))
165- nfs_mount_version = 3;
166+ mnt_version = 3;
167 else if (kernel_version < MAKE_VERSION(2,3,0))
168- nfs_mount_version = 4; /* since 2.2.18pre9 */
169+ mnt_version = 4; /* since 2.2.18pre9 */
170 else if (kernel_version < MAKE_VERSION(2,3,99))
171- nfs_mount_version = 3;
172+ mnt_version = 3;
173 else
174- nfs_mount_version = 4; /* since 2.3.99pre4 */
175+ mnt_version = 4; /* since 2.3.99pre4 */
176 }
177- if (nfs_mount_version > NFS_MOUNT_VERSION)
178- nfs_mount_version = NFS_MOUNT_VERSION;
179- return nfs_mount_version;
180-}
181-
182-static struct pmap *
183-get_mountport(struct sockaddr_in *server_addr,
184- long unsigned prog,
185- long unsigned version,
186- long unsigned proto,
187- long unsigned port,
188- int nfs_mount_version)
189-{
190- struct pmaplist *pmap;
191- static struct pmap p = {0, 0, 0, 0};
192-
193- if (version > MAX_NFSPROT)
194- version = MAX_NFSPROT;
195- if (!prog)
196- prog = MOUNTPROG;
197- p.pm_prog = prog;
198- p.pm_vers = version;
199- p.pm_prot = proto;
200- p.pm_port = port;
201-
202- server_addr->sin_port = PMAPPORT;
203- pmap = pmap_getmaps(server_addr);
204-
205- while (pmap) {
206- if (pmap->pml_map.pm_prog != prog)
207- goto next;
208- if (!version && p.pm_vers > pmap->pml_map.pm_vers)
209- goto next;
210- if (version > 2 && pmap->pml_map.pm_vers != version)
211- goto next;
212- if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
213- goto next;
214- if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
215- (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) ||
216- (port && pmap->pml_map.pm_port != port))
217- goto next;
218- memcpy(&p, &pmap->pml_map, sizeof(p));
219- next:
220- pmap = pmap->pml_next;
221- }
222- if (!p.pm_vers)
223- p.pm_vers = MOUNTVERS;
224- if (!p.pm_prot)
225- p.pm_prot = IPPROTO_TCP;
226-#if 0
227- if (!p.pm_port) {
228- p.pm_port = pmap_getport(server_addr, p.pm_prog, p.pm_vers,
229- p.pm_prot);
230+ if (mnt_version > NFS_MOUNT_VERSION)
231+ mnt_version = NFS_MOUNT_VERSION;
232+ return mnt_version;
233+}
234+
235+static int
236+nfs_gethostbyname(const char *hostname, struct sockaddr_in *saddr)
237+{
238+ struct hostent *hp;
239+
240+ saddr->sin_family = AF_INET;
241+ if (!inet_aton(hostname, &saddr->sin_addr)) {
242+ if ((hp = gethostbyname(hostname)) == NULL) {
243+ fprintf(stderr, _("mount: can't get address for %s\n"),
244+ hostname);
245+ return 0;
246+ } else {
247+ if (hp->h_length > sizeof(*saddr)) {
248+ fprintf(stderr,
249+ _("mount: got bad hp->h_length\n"));
250+ hp->h_length = sizeof(*saddr);
251+ }
252+ memcpy(&saddr->sin_addr, hp->h_addr, hp->h_length);
253+ }
254+ }
255+ return 1;
256+}
257+
258+/*
259+ * Sigh... pmap_getport() doesn't actually check the version number.
260+ * In order to make sure that the server actually supports the service
261+ * we're requesting, we open and RPC client, and fire off a NULL
262+ * RPC call.
263+ */
264+static int
265+clnt_ping(struct sockaddr_in *saddr, const u_long prog, const u_long vers,
266+ const u_int prot)
267+{
268+ CLIENT *clnt;
269+ int sock, stat;
270+ static char clnt_res;
271+
272+ sock = RPC_ANYSOCK;
273+ switch(prot) {
274+ case IPPROTO_UDP:
275+ clnt = clntudp_bufcreate(saddr, prog, vers,
276+ RETRY_TIMEOUT, &sock,
277+ RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
278+ break;
279+ case IPPROTO_TCP:
280+ clnt = clnttcp_create(saddr, prog, vers, &sock,
281+ RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
282+ break;
283+ default:
284+ goto out_bad;
285+ }
286+ if (!clnt)
287+ goto out_bad;
288+ memset(&clnt_res, 0, sizeof(clnt_res));
289+ stat = clnt_call(clnt, NULLPROC,
290+ (xdrproc_t)xdr_void, (caddr_t)NULL,
291+ (xdrproc_t)xdr_void, (caddr_t)&clnt_res,
292+ TIMEOUT);
293+ clnt_destroy(clnt);
294+ close(sock);
295+ if (stat != RPC_PROGVERSMISMATCH)
296+ return 1;
297+ out_bad:
298+ return 0;
299+}
300+
301+/*
302+ * Use the portmapper to discover whether or not the service we want is
303+ * available. The lists 'versions' and 'protos' define ordered sequences
304+ * of service versions and udp/tcp protocols to probe for.
305+ */
306+static int
307+probe_port(clnt_addr_t *server,
308+ const u_long *versions,
309+ const u_int *protos)
310+{
311+ struct sockaddr_in *saddr = &server->saddr;
312+ struct pmap *pmap = &server->pmap;
313+ const u_long prog = pmap->pm_prog,
314+ vers = pmap->pm_vers,
315+ *p_vers;
316+ const u_int prot = (u_int)pmap->pm_prot,
317+ *p_prot;
318+ const u_short port = (u_short) pmap->pm_port;
319+ u_short p_port;
320+
321+ p_prot = prot ? &prot : protos;
322+ p_vers = vers ? &vers : versions;
323+ for (;;) {
324+ saddr->sin_port = htons(PMAPPORT);
325+ p_port = pmap_getport(saddr, prog, *p_vers, *p_prot);
326+ if (p_port) {
327+ if (!port || port == p_port) {
328+ saddr->sin_port = htons(port);
329+ if (clnt_ping(saddr, prog, *p_vers, *p_prot))
330+ goto out_ok;
331+ }
332+ } else if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED)
333+ break;
334+ if (!prot) {
335+ if (*++p_prot)
336+ continue;
337+ p_prot = protos;
338+ }
339+ if (vers || !*++p_vers)
340+ break;
341+ }
342+ return 0;
343+ out_ok:
344+ if (!vers)
345+ pmap->pm_vers = *p_vers;
346+ if (!prot)
347+ pmap->pm_prot = *p_prot;
348+ if (!port)
349+ pmap->pm_port = p_port;
350+ return 1;
351+}
352+
353+static int
354+probe_nfsport(clnt_addr_t *nfs_server)
355+{
356+ const struct pmap *pmap = &nfs_server->pmap;
357+ const u_long *probe_vers;
358+ const u_int *probe_prot;
359+
360+ if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
361+ return 1;
362+ probe_vers = nfs_probelist(MAX_NFSPROT);
363+ probe_prot = proto_probelist(HAVE_RELIABLE_TCP);
364+ return probe_port(nfs_server, probe_vers, probe_prot);
365+}
366+
367+static int
368+probe_mntport(clnt_addr_t *mnt_server)
369+{
370+ const struct pmap *pmap = &mnt_server->pmap;
371+ const u_long *probe_vers;
372+ const u_int *probe_prot;
373+
374+ if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
375+ return 1;
376+ probe_vers = mnt_probelist(MAX_MNTPROT);
377+ probe_prot = proto_probelist(HAVE_RELIABLE_TCP);
378+ return probe_port(mnt_server, probe_vers, probe_prot);
379+}
380+
381+static int
382+probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server)
383+{
384+ struct pmap *nfs_pmap = &nfs_server->pmap;
385+ struct pmap *mnt_pmap = &mnt_server->pmap;
386+ struct pmap save_nfs, save_mnt;
387+ int res;
388+ const u_long *probe_vers;
389+
390+ if (mnt_pmap->pm_vers && !nfs_pmap->pm_vers)
391+ nfs_pmap->pm_vers = mntvers_to_nfs(mnt_pmap->pm_vers);
392+ else if (nfs_pmap->pm_vers && !mnt_pmap->pm_vers)
393+ mnt_pmap->pm_vers = nfsvers_to_mnt(nfs_pmap->pm_vers);
394+ if (nfs_pmap->pm_vers)
395+ goto version_fixed;
396+ memcpy(&save_nfs, nfs_pmap, sizeof(save_nfs));
397+ memcpy(&save_mnt, mnt_pmap, sizeof(save_mnt));
398+ for (probe_vers = mnt_probelist(MAX_MNTPROT); *probe_vers; probe_vers++) {
399+ nfs_pmap->pm_vers = mntvers_to_nfs(*probe_vers);
400+ if ((res = probe_nfsport(nfs_server) != 0)) {
401+ mnt_pmap->pm_vers = *probe_vers;
402+ if ((res = probe_mntport(mnt_server)) != 0)
403+ return 1;
404+ memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap));
405+ }
406+ memcpy(nfs_pmap, &save_nfs, sizeof(*nfs_pmap));
407 }
408+ out_bad:
409+ return 0;
410+ version_fixed:
411+ if (!probe_nfsport(nfs_server))
412+ goto out_bad;
413+ return probe_mntport(mnt_server);
414+}
415+
416+static CLIENT *
417+mnt_openclnt(clnt_addr_t *mnt_server, int *msock, const int report_errs)
418+{
419+ struct sockaddr_in *mnt_saddr = &mnt_server->saddr;
420+ struct pmap *mnt_pmap = &mnt_server->pmap;
421+ CLIENT *clnt;
422+
423+ /* contact the mount daemon via TCP */
424+ mnt_saddr->sin_port = htons((u_short)mnt_pmap->pm_port);
425+ *msock = RPC_ANYSOCK;
426+
427+ switch (mnt_pmap->pm_prot) {
428+ case IPPROTO_UDP:
429+ clnt = clntudp_bufcreate(mnt_saddr,
430+ mnt_pmap->pm_prog, mnt_pmap->pm_vers,
431+ RETRY_TIMEOUT, msock,
432+ MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
433+ break;
434+ case IPPROTO_TCP:
435+ clnt = clnttcp_create(mnt_saddr,
436+ mnt_pmap->pm_prog, mnt_pmap->pm_vers,
437+ msock,
438+ MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
439+ break;
440+ default:
441+ goto out_bad;
442+ }
443+ if (!clnt)
444+ goto report_err;
445+ /* try to mount hostname:dirname */
446+ clnt->cl_auth = authunix_create_default();
447+ return clnt;
448+ report_err:
449+ if (report_errs)
450+ clnt_pcreateerror("mount");
451+ out_bad:
452+ return NULL;
453+}
454+
455+static inline void
456+mnt_closeclnt(CLIENT *clnt, int msock)
457+{
458+ auth_destroy(clnt->cl_auth);
459+ clnt_destroy(clnt);
460+ close(msock);
461+}
462+
463+static inline enum clnt_stat
464+nfs3_mount(CLIENT *clnt, mnt3arg_t *mnt3arg, mnt3res_t *mnt3res)
465+{
466+ return clnt_call(clnt, MOUNTPROC3_MNT,
467+ (xdrproc_t) xdr_dirpath, (caddr_t) mnt3arg,
468+ (xdrproc_t) xdr_mountres3, (caddr_t) mnt3res,
469+ TIMEOUT);
470+}
471+
472+static inline enum clnt_stat
473+nfs2_mount(CLIENT *clnt, mnt2arg_t *mnt2arg, mnt2res_t *mnt2res)
474+{
475+ return clnt_call(clnt, MOUNTPROC_MNT,
476+ (xdrproc_t) xdr_dirpath, (caddr_t) mnt2arg,
477+ (xdrproc_t) xdr_fhstatus, (caddr_t) mnt2res,
478+ TIMEOUT);
479+}
480+
481+static int
482+nfs_call_mount(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server,
483+ mntarg_t *mntarg, mntres_t *mntres, const int report_errs)
484+{
485+ CLIENT *clnt;
486+ enum clnt_stat stat;
487+ int msock;
488+
489+
490+ if (!probe_bothports(mnt_server, nfs_server)) {
491+ if (report_errs)
492+ fprintf(stderr,_("mount: failed to probe ports on NFS server %s\n"),
493+ *nfs_server->hostname);
494+ goto out_bad;
495+ }
496+
497+ clnt = mnt_openclnt(mnt_server, &msock, report_errs);
498+ if (!clnt)
499+ goto out_bad;
500+ /* make pointers in xdr_mountres3 NULL so
501+ * that xdr_array allocates memory for us
502+ */
503+ memset(mntres, 0, sizeof(*mntres));
504+ switch (mnt_server->pmap.pm_vers) {
505+ case 3:
506+ stat = nfs3_mount(clnt, mntarg, &mntres->nfsv3);
507+ break;
508+ case 2:
509+ case 1:
510+ stat = nfs2_mount(clnt, mntarg, &mntres->nfsv2);
511+ break;
512+ default:
513+ goto out_bad;
514+ }
515+ if (stat != RPC_SUCCESS && report_errs)
516+ clnt_perror(clnt, "mount");
517+ mnt_closeclnt(clnt, msock);
518+ if (stat == RPC_SUCCESS)
519+ return 1;
520+ out_bad:
521+ return 0;
522+}
523+
524+static int
525+parse_options(char *old_opts, struct nfs_mount_data *data,
526+ int *bg, int *retry, clnt_addr_t *mnt_server,
527+ clnt_addr_t *nfs_server, char *new_opts, const int opt_size)
528+{
529+ struct sockaddr_in *mnt_saddr = &mnt_server->saddr;
530+ struct pmap *mnt_pmap = &mnt_server->pmap;
531+ struct pmap *nfs_pmap = &nfs_server->pmap;
532+ int len;
533+ char *opt, *opteq;
534+ char *mounthost = NULL;
535+ char cbuf[128];
536+
537+ data->flags = 0;
538+ *bg = 0;
539+
540+ len = strlen(new_opts);
541+ for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
542+ if (strlen(opt) >= sizeof(cbuf))
543+ goto bad_parameter;
544+ if ((opteq = strchr(opt, '=')) && isdigit(opteq[1])) {
545+ int val = atoi(opteq + 1);
546+ *opteq = '\0';
547+ if (!strcmp(opt, "rsize"))
548+ data->rsize = val;
549+ else if (!strcmp(opt, "wsize"))
550+ data->wsize = val;
551+ else if (!strcmp(opt, "timeo"))
552+ data->timeo = val;
553+ else if (!strcmp(opt, "retrans"))
554+ data->retrans = val;
555+ else if (!strcmp(opt, "acregmin"))
556+ data->acregmin = val;
557+ else if (!strcmp(opt, "acregmax"))
558+ data->acregmax = val;
559+ else if (!strcmp(opt, "acdirmin"))
560+ data->acdirmin = val;
561+ else if (!strcmp(opt, "acdirmax"))
562+ data->acdirmax = val;
563+ else if (!strcmp(opt, "actimeo")) {
564+ data->acregmin = val;
565+ data->acregmax = val;
566+ data->acdirmin = val;
567+ data->acdirmax = val;
568+ }
569+ else if (!strcmp(opt, "retry"))
570+ *retry = val;
571+ else if (!strcmp(opt, "port"))
572+ nfs_pmap->pm_port = val;
573+ else if (!strcmp(opt, "mountport"))
574+ mnt_pmap->pm_port = val;
575+ else if (!strcmp(opt, "mountprog"))
576+ mnt_pmap->pm_prog = val;
577+ else if (!strcmp(opt, "mountvers"))
578+ mnt_pmap->pm_vers = val;
579+ else if (!strcmp(opt, "nfsprog"))
580+ nfs_pmap->pm_prog = val;
581+ else if (!strcmp(opt, "nfsvers") ||
582+ !strcmp(opt, "vers")) {
583+ nfs_pmap->pm_vers = val;
584+ opt = "nfsvers";
585+#if NFS_MOUNT_VERSION >= 2
586+ } else if (!strcmp(opt, "namlen")) {
587+ if (nfs_mount_version >= 2)
588+ data->namlen = val;
589+ else if (!sloppy)
590+ goto bad_parameter;
591 #endif
592-#if 0
593-#define MOUNTPORT 635
594- /* HJLu wants to remove all traces of the old default port.
595- Are there still people running a mount RPC service on this
596- port without having a portmapper? */
597- if (!p.pm_port)
598- p.pm_port = MOUNTPORT;
599-#endif
600- return &p;
601+ } else if (!strcmp(opt, "addr")) {
602+ /* ignore */;
603+ continue;
604+ } else if (!sloppy)
605+ goto bad_parameter;
606+ sprintf(cbuf, "%s=%s,", opt, opteq+1);
607+ } else if (opteq) {
608+ *opteq = '\0';
609+ if (!strcmp(opt, "proto")) {
610+ if (!strcmp(opteq+1, "udp")) {
611+ nfs_pmap->pm_prot = IPPROTO_UDP;
612+#if NFS_MOUNT_VERSION >= 2
613+ data->flags &= ~NFS_MOUNT_TCP;
614+ } else if (!strcmp(opteq+1, "tcp") &&
615+ nfs_mount_version >= 2) {
616+ nfs_pmap->pm_prot = IPPROTO_TCP;
617+ data->flags |= NFS_MOUNT_TCP;
618+#endif
619+ } else if (!sloppy)
620+ goto bad_parameter;
621+ } else if (!strcmp(opt, "mounthost"))
622+ mounthost=xstrndup(opteq+1,
623+ strcspn(opteq+1," \t\n\r,"));
624+ else
625+ goto bad_parameter;
626+ sprintf(cbuf, "%s=%s,", opt, opteq+1);
627+ } else {
628+ int val = 1;
629+ if (!strncmp(opt, "no", 2)) {
630+ val = 0;
631+ opt += 2;
632+ }
633+ if (!strcmp(opt, "bg"))
634+ *bg = val;
635+ else if (!strcmp(opt, "fg"))
636+ *bg = !val;
637+ else if (!strcmp(opt, "soft")) {
638+ data->flags &= ~NFS_MOUNT_SOFT;
639+ if (val)
640+ data->flags |= NFS_MOUNT_SOFT;
641+ } else if (!strcmp(opt, "hard")) {
642+ data->flags &= ~NFS_MOUNT_SOFT;
643+ if (!val)
644+ data->flags |= NFS_MOUNT_SOFT;
645+ } else if (!strcmp(opt, "intr")) {
646+ data->flags &= ~NFS_MOUNT_INTR;
647+ if (val)
648+ data->flags |= NFS_MOUNT_INTR;
649+ } else if (!strcmp(opt, "posix")) {
650+ data->flags &= ~NFS_MOUNT_POSIX;
651+ if (val)
652+ data->flags |= NFS_MOUNT_POSIX;
653+ } else if (!strcmp(opt, "cto")) {
654+ data->flags &= ~NFS_MOUNT_NOCTO;
655+ if (!val)
656+ data->flags |= NFS_MOUNT_NOCTO;
657+ } else if (!strcmp(opt, "ac")) {
658+ data->flags &= ~NFS_MOUNT_NOAC;
659+ if (!val)
660+ data->flags |= NFS_MOUNT_NOAC;
661+#if NFS_MOUNT_VERSION >= 2
662+ } else if (!strcmp(opt, "tcp")) {
663+ data->flags &= ~NFS_MOUNT_TCP;
664+ if (val) {
665+ if (nfs_mount_version < 2)
666+ goto bad_option;
667+ nfs_pmap->pm_prot = IPPROTO_TCP;
668+ data->flags |= NFS_MOUNT_TCP;
669+ } else
670+ nfs_pmap->pm_prot = IPPROTO_UDP;
671+ } else if (!strcmp(opt, "udp")) {
672+ data->flags &= ~NFS_MOUNT_TCP;
673+ if (!val) {
674+ if (nfs_mount_version < 2)
675+ goto bad_option;
676+ nfs_pmap->pm_prot = IPPROTO_TCP;
677+ data->flags |= NFS_MOUNT_TCP;
678+ } else
679+ nfs_pmap->pm_prot = IPPROTO_UDP;
680+#endif
681+#if NFS_MOUNT_VERSION >= 3
682+ } else if (!strcmp(opt, "lock")) {
683+ data->flags &= ~NFS_MOUNT_NONLM;
684+ if (!val) {
685+ if (nfs_mount_version < 3)
686+ goto bad_option;
687+ data->flags |= NFS_MOUNT_NONLM;
688+ }
689+#endif
690+#if NFS_MOUNT_VERSION >= 4
691+ } else if (!strcmp(opt, "broken_suid")) {
692+ data->flags &= ~NFS_MOUNT_BROKEN_SUID;
693+ if (val) {
694+ if (nfs_mount_version < 4)
695+ goto bad_option;
696+ data->flags |= NFS_MOUNT_BROKEN_SUID;
697+ }
698+#endif
699+ } else {
700+ bad_option:
701+ printf(_("Unsupported nfs mount option: "
702+ "%s%s\n"), val ? "" : "no", opt);
703+ goto out_bad;
704+ }
705+ sprintf(cbuf, val ? "%s,":"no%s,", opt);
706+ }
707+ len += strlen(cbuf);
708+ if (len >= opt_size) {
709+ printf(_("mount: excessively long option argument\n"));
710+ goto out_bad;
711+ }
712+ strcat(new_opts, cbuf);
713+ }
714+ /* See if the nfs host = mount host. */
715+ if (mounthost) {
716+ if (!nfs_gethostbyname(mounthost, mnt_saddr))
717+ goto out_bad;
718+ *mnt_server->hostname = mounthost;
719+ }
720+ return 1;
721+ bad_parameter:
722+ printf(_("Bad nfs mount parameter: %s\n"), opt);
723+ out_bad:
724+ return 0;
725+}
726+
727+static inline int
728+nfsmnt_check_compat(const struct pmap *nfs_pmap, const struct pmap *mnt_pmap)
729+{
730+ if (nfs_pmap->pm_vers > MAX_NFSPROT) {
731+ fprintf(stderr, _("NFSv%ld not supported!\n"), nfs_pmap->pm_vers);
732+ goto out_bad;
733+ }
734+ if (mnt_pmap->pm_vers > MAX_MNTPROT) {
735+ fprintf(stderr, _("NFS mount v%ld not supported!\n"), mnt_pmap->pm_vers);
736+ goto out_bad;
737+ }
738+ return 1;
739+ out_bad:
740+ return 0;
741 }
742
743-int nfsmount(const char *spec, const char *node, int *flags,
744- char **extra_opts, char **mount_opts, int *nfs_mount_vers,
745- int running_bg)
746+int
747+nfsmount(const char *spec, const char *node, int *flags,
748+ char **extra_opts, char **mount_opts, int *nfs_mount_vers,
749+ int running_bg)
750 {
751 static char *prev_bg_host;
752 char hostdir[1024];
753- CLIENT *mclient;
754 char *hostname, *dirname, *old_opts, *mounthost = NULL;
755- char new_opts[1024];
756- struct timeval total_timeout;
757- enum clnt_stat clnt_stat;
758+ char new_opts[1024], cbuf[20];
759 static struct nfs_mount_data data;
760- char *opt, *opteq;
761- int nfs_mount_version;
762 int val;
763- struct hostent *hp;
764- struct sockaddr_in server_addr;
765- struct sockaddr_in mount_server_addr;
766- struct pmap *pm_mnt;
767- int msock, fsock;
768- struct timeval retry_timeout;
769- union {
770- struct fhstatus nfsv2;
771- struct mountres3 nfsv3;
772- } status;
773+
774+ clnt_addr_t mnt_server = { &mounthost, };
775+ clnt_addr_t nfs_server = { &hostname, };
776+ struct sockaddr_in *nfs_saddr = &nfs_server.saddr;
777+ struct pmap *mnt_pmap = &mnt_server.pmap,
778+ *nfs_pmap = &nfs_server.pmap;
779+ struct pmap save_mnt, save_nfs;
780+
781+ int fsock;
782+
783+ mntres_t mntres;
784+
785 struct stat statbuf;
786- char *s;
787- int port, mountport, proto, bg, soft, intr;
788- int posix, nocto, noac, nolock, broken_suid;
789- int retry, tcp;
790- int mountprog, mountvers, nfsprog, nfsvers;
791+ char *s, *p;
792+ int bg, retry;
793 int retval;
794 time_t t;
795 time_t prevt;
796@@ -231,8 +756,7 @@ int nfsmount(const char *spec, const cha
797 nfs_mount_version = *nfs_mount_vers;
798
799 retval = EX_FAIL;
800- msock = fsock = -1;
801- mclient = NULL;
802+ fsock = -1;
803 if (strlen(spec) >= sizeof(hostdir)) {
804 fprintf(stderr, _("mount: "
805 "excessively long host:dir argument\n"));
806@@ -258,49 +782,23 @@ int nfsmount(const char *spec, const cha
807 goto fail;
808 }
809
810- server_addr.sin_family = AF_INET;
811-#ifdef HAVE_inet_aton
812- if (!inet_aton(hostname, &server_addr.sin_addr))
813-#endif
814- {
815- if ((hp = gethostbyname(hostname)) == NULL) {
816- fprintf(stderr, _("mount: can't get address for %s\n"),
817- hostname);
818- goto fail;
819- } else {
820- if (hp->h_length > sizeof(struct in_addr)) {
821- fprintf(stderr,
822- _("mount: got bad hp->h_length\n"));
823- hp->h_length = sizeof(struct in_addr);
824- }
825- memcpy(&server_addr.sin_addr,
826- hp->h_addr, hp->h_length);
827- }
828- }
829-
830- memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr));
831+ if (!nfs_gethostbyname(hostname, nfs_saddr))
832+ goto fail;
833+ mounthost = hostname;
834+ memcpy (&mnt_server.saddr, nfs_saddr, sizeof (mnt_server.saddr));
835
836 /* add IP address to mtab options for use when unmounting */
837
838- s = inet_ntoa(server_addr.sin_addr);
839+ s = inet_ntoa(nfs_saddr->sin_addr);
840 old_opts = *extra_opts;
841 if (!old_opts)
842 old_opts = "";
843- if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
844- fprintf(stderr, _("mount: "
845- "excessively long option argument\n"));
846- goto fail;
847- }
848- sprintf(new_opts, "%s%saddr=%s",
849- old_opts, *old_opts ? "," : "", s);
850- *extra_opts = xstrdup(new_opts);
851
852 /* Set default options.
853 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
854 * let the kernel decide.
855 * timeo is filled in after we know whether it'll be TCP or UDP. */
856 memset(&data, 0, sizeof(data));
857- data.retrans = 3;
858 data.acregmin = 3;
859 data.acregmax = 60;
860 data.acdirmin = 30;
861@@ -310,167 +808,21 @@ int nfsmount(const char *spec, const cha
862 #endif
863
864 bg = 0;
865- soft = 0;
866- intr = 0;
867- posix = 0;
868- nocto = 0;
869- nolock = 0;
870- broken_suid = 0;
871- noac = 0;
872 retry = 10000; /* 10000 minutes ~ 1 week */
873- tcp = 0;
874
875- mountprog = MOUNTPROG;
876- mountvers = 0;
877- port = 0;
878- mountport = 0;
879- nfsprog = NFS_PROGRAM;
880- nfsvers = 0;
881+ memset(mnt_pmap, 0, sizeof(*mnt_pmap));
882+ mnt_pmap->pm_prog = MOUNTPROG;
883+ memset(nfs_pmap, 0, sizeof(*nfs_pmap));
884+ nfs_pmap->pm_prog = NFS_PROGRAM;
885
886 /* parse options */
887+ new_opts[0] = 0;
888+ if (!parse_options(old_opts, &data, &bg, &retry, &mnt_server, &nfs_server,
889+ new_opts, sizeof(new_opts)))
890+ goto fail;
891+ if (!nfsmnt_check_compat(nfs_pmap, mnt_pmap))
892+ goto fail;
893
894- for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
895- if ((opteq = strchr(opt, '='))) {
896- val = atoi(opteq + 1);
897- *opteq = '\0';
898- if (!strcmp(opt, "rsize"))
899- data.rsize = val;
900- else if (!strcmp(opt, "wsize"))
901- data.wsize = val;
902- else if (!strcmp(opt, "timeo"))
903- data.timeo = val;
904- else if (!strcmp(opt, "retrans"))
905- data.retrans = val;
906- else if (!strcmp(opt, "acregmin"))
907- data.acregmin = val;
908- else if (!strcmp(opt, "acregmax"))
909- data.acregmax = val;
910- else if (!strcmp(opt, "acdirmin"))
911- data.acdirmin = val;
912- else if (!strcmp(opt, "acdirmax"))
913- data.acdirmax = val;
914- else if (!strcmp(opt, "actimeo")) {
915- data.acregmin = val;
916- data.acregmax = val;
917- data.acdirmin = val;
918- data.acdirmax = val;
919- }
920- else if (!strcmp(opt, "retry"))
921- retry = val;
922- else if (!strcmp(opt, "port"))
923- port = val;
924- else if (!strcmp(opt, "mountport"))
925- mountport = val;
926- else if (!strcmp(opt, "mounthost"))
927- mounthost=xstrndup(opteq+1,
928- strcspn(opteq+1," \t\n\r,"));
929- else if (!strcmp(opt, "mountprog"))
930- mountprog = val;
931- else if (!strcmp(opt, "mountvers"))
932- mountvers = val;
933- else if (!strcmp(opt, "nfsprog"))
934- nfsprog = val;
935- else if (!strcmp(opt, "nfsvers") ||
936- !strcmp(opt, "vers"))
937- nfsvers = val;
938- else if (!strcmp(opt, "proto")) {
939- if (!strncmp(opteq+1, "tcp", 3))
940- tcp = 1;
941- else if (!strncmp(opteq+1, "udp", 3))
942- tcp = 0;
943- else
944- printf(_("Warning: Unrecognized proto= option.\n"));
945- } else if (!strcmp(opt, "namlen")) {
946-#if NFS_MOUNT_VERSION >= 2
947- if (nfs_mount_version >= 2)
948- data.namlen = val;
949- else
950-#endif
951- printf(_("Warning: Option namlen is not supported.\n"));
952- } else if (!strcmp(opt, "addr")) {
953- /* ignore */;
954- } else {
955- printf(_("unknown nfs mount parameter: "
956- "%s=%d\n"), opt, val);
957- goto fail;
958- }
959- } else {
960- val = 1;
961- if (!strncmp(opt, "no", 2)) {
962- val = 0;
963- opt += 2;
964- }
965- if (!strcmp(opt, "bg"))
966- bg = val;
967- else if (!strcmp(opt, "fg"))
968- bg = !val;
969- else if (!strcmp(opt, "soft"))
970- soft = val;
971- else if (!strcmp(opt, "hard"))
972- soft = !val;
973- else if (!strcmp(opt, "intr"))
974- intr = val;
975- else if (!strcmp(opt, "posix"))
976- posix = val;
977- else if (!strcmp(opt, "cto"))
978- nocto = !val;
979- else if (!strcmp(opt, "ac"))
980- noac = !val;
981- else if (!strcmp(opt, "tcp"))
982- tcp = val;
983- else if (!strcmp(opt, "udp"))
984- tcp = !val;
985- else if (!strcmp(opt, "lock")) {
986- if (nfs_mount_version >= 3)
987- nolock = !val;
988- else
989- printf(_("Warning: option nolock is not supported.\n"));
990- } else if (!strcmp(opt, "broken_suid")) {
991- broken_suid = val;
992- } else {
993- if (!sloppy) {
994- printf(_("unknown nfs mount option: "
995- "%s%s\n"), val ? "" : "no", opt);
996- goto fail;
997- }
998- }
999- }
1000- }
1001- proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
1002-
1003- data.flags = (soft ? NFS_MOUNT_SOFT : 0)
1004- | (intr ? NFS_MOUNT_INTR : 0)
1005- | (posix ? NFS_MOUNT_POSIX : 0)
1006- | (nocto ? NFS_MOUNT_NOCTO : 0)
1007- | (noac ? NFS_MOUNT_NOAC : 0);
1008-#if NFS_MOUNT_VERSION >= 2
1009- if (nfs_mount_version >= 2)
1010- data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
1011-#endif
1012-#if NFS_MOUNT_VERSION >= 3
1013- if (nfs_mount_version >= 3)
1014- data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
1015-#endif
1016-#if NFS_MOUNT_VERSION >= 4
1017- if (nfs_mount_version >= 4)
1018- data.flags |= (broken_suid ? NFS_MOUNT_BROKEN_SUID : 0);
1019-#endif
1020- if (nfsvers > MAX_NFSPROT) {
1021- fprintf(stderr, "NFSv%d not supported!\n", nfsvers);
1022- return 0;
1023- }
1024- if (mountvers > MAX_NFSPROT) {
1025- fprintf(stderr, "NFSv%d not supported!\n", nfsvers);
1026- return 0;
1027- }
1028- if (nfsvers && !mountvers)
1029- mountvers = (nfsvers < 3) ? 1 : nfsvers;
1030- if (nfsvers && nfsvers < mountvers)
1031- mountvers = nfsvers;
1032-
1033- /* Adjust options if none specified */
1034- if (!data.timeo)
1035- data.timeo = tcp ? 70 : 7;
1036
1037 #ifdef NFS_MOUNT_DEBUG
1038 printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
1039@@ -478,9 +830,10 @@ int nfsmount(const char *spec, const cha
1040 printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
1041 data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
1042 printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
1043- port, bg, retry, data.flags);
1044+ nfs_pmap->pm_port, bg, retry, data.flags);
1045 printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n",
1046- mountprog, mountvers, nfsprog, nfsvers);
1047+ mnt_pmap->pm_prog, mnt_pmap->pm_vers,
1048+ nfs_pmap->pm_prog, nfs_pmap->pm_vers);
1049 printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",
1050 (data.flags & NFS_MOUNT_SOFT) != 0,
1051 (data.flags & NFS_MOUNT_INTR) != 0,
1052@@ -497,7 +850,7 @@ int nfsmount(const char *spec, const cha
1053 *mount_opts = (char *) &data;
1054
1055 if (*flags & MS_REMOUNT)
1056- return 0;
1057+ goto out_ok;
1058
1059 /*
1060 * If the previous mount operation on the same host was
1061@@ -512,28 +865,6 @@ int nfsmount(const char *spec, const cha
1062 }
1063
1064 /* create mount deamon client */
1065- /* See if the nfs host = mount host. */
1066- if (mounthost) {
1067- if (mounthost[0] >= '0' && mounthost[0] <= '9') {
1068- mount_server_addr.sin_family = AF_INET;
1069- mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
1070- } else {
1071- if ((hp = gethostbyname(mounthost)) == NULL) {
1072- fprintf(stderr, _("mount: can't get address for %s\n"),
1073- mounthost);
1074- goto fail;
1075- } else {
1076- if (hp->h_length > sizeof(struct in_addr)) {
1077- fprintf(stderr,
1078- _("mount: got bad hp->h_length?\n"));
1079- hp->h_length = sizeof(struct in_addr);
1080- }
1081- mount_server_addr.sin_family = AF_INET;
1082- memcpy(&mount_server_addr.sin_addr,
1083- hp->h_addr, hp->h_length);
1084- }
1085- }
1086- }
1087
1088 /*
1089 * The following loop implements the mount retries. On the first
1090@@ -551,15 +882,13 @@ int nfsmount(const char *spec, const cha
1091 *
1092 * Only the first error message will be displayed.
1093 */
1094- retry_timeout.tv_sec = 3;
1095- retry_timeout.tv_usec = 0;
1096- total_timeout.tv_sec = 20;
1097- total_timeout.tv_usec = 0;
1098 timeout = time(NULL) + 60 * retry;
1099 prevt = 0;
1100 t = 30;
1101 val = 1;
1102
1103+ memcpy(&save_nfs, nfs_pmap, sizeof(save_nfs));
1104+ memcpy(&save_mnt, mnt_pmap, sizeof(save_mnt));
1105 for (;;) {
1106 if (bg && stat(node, &statbuf) == -1) {
1107 /* no mount point yet - sleep */
1108@@ -570,89 +899,18 @@ int nfsmount(const char *spec, const cha
1109 val = 30;
1110 }
1111 } else {
1112+ int stat;
1113 /* be careful not to use too many CPU cycles */
1114 if (t - prevt < 30)
1115 sleep(30);
1116
1117- pm_mnt = get_mountport(&mount_server_addr,
1118- mountprog,
1119- mountvers,
1120- proto,
1121- mountport,
1122- nfs_mount_version);
1123-
1124- /* contact the mount daemon via TCP */
1125- mount_server_addr.sin_port = htons(pm_mnt->pm_port);
1126- msock = RPC_ANYSOCK;
1127-
1128- switch (pm_mnt->pm_prot) {
1129- case IPPROTO_UDP:
1130- mclient = clntudp_create(&mount_server_addr,
1131- pm_mnt->pm_prog,
1132- pm_mnt->pm_vers,
1133- retry_timeout,
1134- &msock);
1135- if (mclient)
1136- break;
1137- mount_server_addr.sin_port =
1138- htons(pm_mnt->pm_port);
1139- msock = RPC_ANYSOCK;
1140- case IPPROTO_TCP:
1141- mclient = clnttcp_create(&mount_server_addr,
1142- pm_mnt->pm_prog,
1143- pm_mnt->pm_vers,
1144- &msock, 0, 0);
1145+ stat = nfs_call_mount(&mnt_server, &nfs_server,
1146+ &dirname, &mntres,
1147+ !running_bg && prevt == 0);
1148+ if (stat)
1149 break;
1150- default:
1151- mclient = 0;
1152- }
1153-
1154- if (mclient) {
1155- /* try to mount hostname:dirname */
1156- mclient->cl_auth = authunix_create_default();
1157-
1158- /* make pointers in xdr_mountres3 NULL so
1159- * that xdr_array allocates memory for us
1160- */
1161- memset(&status, 0, sizeof(status));
1162-
1163- if (pm_mnt->pm_vers == 3)
1164- clnt_stat = clnt_call(mclient,
1165- MOUNTPROC3_MNT,
1166- (xdrproc_t) xdr_dirpath,
1167- (caddr_t) &dirname,
1168- (xdrproc_t) xdr_mountres3,
1169- (caddr_t) &status,
1170- total_timeout);
1171- else
1172- clnt_stat = clnt_call(mclient,
1173- MOUNTPROC_MNT,
1174- (xdrproc_t) xdr_dirpath,
1175- (caddr_t) &dirname,
1176- (xdrproc_t) xdr_fhstatus,
1177- (caddr_t) &status,
1178- total_timeout);
1179-
1180- if (clnt_stat == RPC_SUCCESS)
1181- break; /* we're done */
1182-#if 0
1183- /* errno? who sets errno? */
1184- /* this fragment breaks bg mounting */
1185- if (errno != ECONNREFUSED) {
1186- clnt_perror(mclient, "mount");
1187- goto fail; /* don't retry */
1188- }
1189-#endif
1190- if (!running_bg && prevt == 0)
1191- clnt_perror(mclient, "mount");
1192- auth_destroy(mclient->cl_auth);
1193- clnt_destroy(mclient);
1194- mclient = 0;
1195- close(msock);
1196- } else {
1197- if (!running_bg && prevt == 0)
1198- clnt_pcreateerror("mount");
1199- }
1200+ memcpy(nfs_pmap, &save_nfs, sizeof(*nfs_pmap));
1201+ memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap));
1202 prevt = t;
1203 }
1204
1205@@ -668,36 +926,35 @@ int nfsmount(const char *spec, const cha
1206 if (t >= timeout)
1207 goto fail;
1208 }
1209- nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;
1210
1211- if (nfsvers == 2) {
1212- if (status.nfsv2.fhs_status != 0) {
1213+ if (nfs_pmap->pm_vers == 2) {
1214+ if (mntres.nfsv2.fhs_status != 0) {
1215 fprintf(stderr,
1216- "mount: %s:%s failed, reason given by server: %s\n",
1217+ _("mount: %s:%s failed, reason given by server: %s\n"),
1218 hostname, dirname,
1219- nfs_strerror(status.nfsv2.fhs_status));
1220+ nfs_strerror(mntres.nfsv2.fhs_status));
1221 goto fail;
1222 }
1223 memcpy(data.root.data,
1224- (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1225+ (char *) mntres.nfsv2.fhstatus_u.fhs_fhandle,
1226 NFS_FHSIZE);
1227 #if NFS_MOUNT_VERSION >= 4
1228 data.root.size = NFS_FHSIZE;
1229 memcpy(data.old_root.data,
1230- (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1231+ (char *) mntres.nfsv2.fhstatus_u.fhs_fhandle,
1232 NFS_FHSIZE);
1233 #endif
1234 } else {
1235 #if NFS_MOUNT_VERSION >= 4
1236 fhandle3 *fhandle;
1237- if (status.nfsv3.fhs_status != 0) {
1238+ if (mntres.nfsv3.fhs_status != 0) {
1239 fprintf(stderr,
1240- "mount: %s:%s failed, reason given by server: %s\n",
1241+ _("mount: %s:%s failed, reason given by server: %s\n"),
1242 hostname, dirname,
1243- nfs_strerror(status.nfsv3.fhs_status));
1244+ nfs_strerror(mntres.nfsv3.fhs_status));
1245 goto fail;
1246 }
1247- fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
1248+ fhandle = &mntres.nfsv3.mountres3_u.mountinfo.fhandle;
1249 memset(data.old_root.data, 0, NFS_FHSIZE);
1250 memset(&data.root, 0, sizeof(data.root));
1251 data.root.size = fhandle->fhandle3_len;
1252@@ -711,13 +968,9 @@ int nfsmount(const char *spec, const cha
1253
1254 /* create nfs socket for kernel */
1255
1256- if (tcp) {
1257- if (nfs_mount_version < 3) {
1258- printf(_("NFS over TCP is not supported.\n"));
1259- goto fail;
1260- }
1261+ if (nfs_pmap->pm_prot == IPPROTO_TCP)
1262 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1263- } else
1264+ else
1265 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1266 if (fsock < 0) {
1267 perror(_("nfs socket"));
1268@@ -727,72 +980,162 @@ int nfsmount(const char *spec, const cha
1269 perror(_("nfs bindresvport"));
1270 goto fail;
1271 }
1272- if (port == 0) {
1273- server_addr.sin_port = PMAPPORT;
1274- port = pmap_getport(&server_addr, nfsprog, nfsvers,
1275- tcp ? IPPROTO_TCP : IPPROTO_UDP);
1276-#if 1
1277- /* Here we check to see if user is mounting with the
1278- * tcp option. If so, and if the portmap returns a
1279- * '0' for port (service unavailable), we then exit,
1280- * notifying the user, rather than hanging up mount.
1281- */
1282- if (port == 0 && tcp == 1) {
1283- perror(_("nfs server reported service unavailable"));
1284- goto fail;
1285- }
1286-#endif
1287-
1288- if (port == 0)
1289- port = NFS_PORT;
1290 #ifdef NFS_MOUNT_DEBUG
1291- else
1292- printf(_("used portmapper to find NFS port\n"));
1293+ printf(_("using port %d for nfs deamon\n"), nfs_pmap->pm_port);
1294 #endif
1295- }
1296-#ifdef NFS_MOUNT_DEBUG
1297- printf(_("using port %d for nfs deamon\n"), port);
1298-#endif
1299- server_addr.sin_port = htons(port);
1300+ nfs_saddr->sin_port = htons(nfs_pmap->pm_port);
1301 /*
1302 * connect() the socket for kernels 1.3.10 and below only,
1303 * to avoid problems with multihomed hosts.
1304 * --Swen
1305 */
1306 if (linux_version_code() <= 66314
1307- && connect(fsock, (struct sockaddr *) &server_addr,
1308- sizeof (server_addr)) < 0) {
1309+ && connect(fsock, (struct sockaddr *) nfs_saddr,
1310+ sizeof (*nfs_saddr)) < 0) {
1311 perror(_("nfs connect"));
1312 goto fail;
1313 }
1314
1315+#if NFS_MOUNT_VERSION >= 2
1316+ if (nfs_pmap->pm_prot == IPPROTO_TCP)
1317+ data.flags |= NFS_MOUNT_TCP;
1318+ else
1319+ data.flags &= ~NFS_MOUNT_TCP;
1320+#endif
1321+
1322 /* prepare data structure for kernel */
1323
1324 data.fd = fsock;
1325- memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
1326+ memcpy((char *) &data.addr, (char *) nfs_saddr, sizeof(data.addr));
1327 strncpy(data.hostname, hostname, sizeof(data.hostname));
1328
1329- /* clean up */
1330+ out_ok:
1331+ /* Ensure we have enough padding for the following strcat()s */
1332+ if (strlen(new_opts) + strlen(s) + 30 >= sizeof(new_opts)) {
1333+ fprintf(stderr, _("mount: "
1334+ "excessively long option argument\n"));
1335+ goto fail;
1336+ }
1337
1338- auth_destroy(mclient->cl_auth);
1339- clnt_destroy(mclient);
1340- close(msock);
1341+ sprintf(cbuf, "addr=%s", s);
1342+ strcat(new_opts, cbuf);
1343+
1344+ *extra_opts = xstrdup(new_opts);
1345 return 0;
1346
1347 /* abort */
1348-
1349 fail:
1350- if (msock != -1) {
1351- if (mclient) {
1352- auth_destroy(mclient->cl_auth);
1353- clnt_destroy(mclient);
1354- }
1355- close(msock);
1356- }
1357 if (fsock != -1)
1358 close(fsock);
1359 return retval;
1360-}
1361+}
1362+
1363+static inline enum clnt_stat
1364+nfs3_umount(dirpath *argp, CLIENT *clnt)
1365+{
1366+ static char clnt_res;
1367+ memset (&clnt_res, 0, sizeof(clnt_res));
1368+ return clnt_call(clnt, MOUNTPROC_UMNT,
1369+ (xdrproc_t) xdr_dirpath, (caddr_t)argp,
1370+ (xdrproc_t) xdr_void, (caddr_t) &clnt_res,
1371+ TIMEOUT);
1372+}
1373+
1374+static inline enum clnt_stat
1375+nfs2_umount(dirpath *argp, CLIENT *clnt)
1376+{
1377+ static char clnt_res;
1378+ memset (&clnt_res, 0, sizeof(clnt_res));
1379+ return clnt_call(clnt, MOUNTPROC_UMNT,
1380+ (xdrproc_t) xdr_dirpath, (caddr_t)argp,
1381+ (xdrproc_t) xdr_void, (caddr_t) &clnt_res,
1382+ TIMEOUT);
1383+}
1384+
1385+static int
1386+nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp)
1387+{
1388+ CLIENT *clnt;
1389+ enum clnt_stat res = 0;
1390+ int msock;
1391+
1392+ clnt = mnt_openclnt(mnt_server, &msock, 1);
1393+ if (!clnt)
1394+ goto out_bad;
1395+ switch (mnt_server->pmap.pm_vers) {
1396+ case 3:
1397+ res = nfs3_umount(argp, clnt);
1398+ break;
1399+ case 2:
1400+ case 1:
1401+ res = nfs2_umount(argp, clnt);
1402+ break;
1403+ default:
1404+ }
1405+ mnt_closeclnt(clnt, msock);
1406+ if (res == RPC_SUCCESS)
1407+ return 1;
1408+ out_bad:
1409+ return 0;
1410+}
1411+
1412+int
1413+nfsumount(const char *spec, const char *opts)
1414+{
1415+ char *hostname;
1416+ char *dirname;
1417+ clnt_addr_t mnt_server = { &hostname, };
1418+ struct pmap *pmap = &mnt_server.pmap;
1419+ char *p;
1420+
1421+ nfs_mount_version = find_kernel_nfs_mount_version();
1422+ if (spec == NULL || (p = strchr(spec,':')) == NULL)
1423+ goto out_bad;
1424+ hostname = xstrndup(spec, p-spec);
1425+ dirname = xstrdup(p+1);
1426+#ifdef NFS_MOUNT_DEBUG
1427+ printf(_("host: %s, directory: %s\n"), hostname, dirname);
1428+#endif
1429+
1430+ if (opts && (p = strstr(opts, "addr="))) {
1431+ char *q;
1432+
1433+ free(hostname);
1434+ p += 5;
1435+ q = p;
1436+ while (*q && *q != ',') q++;
1437+ hostname = xstrndup(p,q-p);
1438+ }
1439+
1440+ if (opts && (p = strstr(opts, "mounthost="))) {
1441+ char *q;
1442+
1443+ free(hostname);
1444+ p += 10;
1445+ q = p;
1446+ while (*q && *q != ',') q++;
1447+ hostname = xstrndup(p,q-p);
1448+ }
1449+
1450+ pmap->pm_prog = MOUNTPROG;
1451+ pmap->pm_vers = MOUNTVERS;
1452+ if (opts && (p = strstr(opts, "mountprog=")) && isdigit(*(p+10)))
1453+ pmap->pm_prog = atoi(p+10);
1454+ if (opts && (p = strstr(opts, "mountport=")) && isdigit(*(p+10)))
1455+ pmap->pm_port = atoi(p+10);
1456+ if (opts && (p = strstr(opts, "nfsvers=")) && isdigit(*(p+8)))
1457+ pmap->pm_vers = nfsvers_to_mnt(atoi(p+8));
1458+ if (opts && (p = strstr(opts, "mountvers=")) && isdigit(*(p+10)))
1459+ pmap->pm_vers = atoi(p+10);
1460+
1461+ if (!nfs_gethostbyname(hostname, &mnt_server.saddr))
1462+ goto out_bad;
1463+ if (!probe_mntport(&mnt_server))
1464+ goto out_bad;
1465+ return nfs_call_umount(&mnt_server, &dirname);
1466+ out_bad:
1467+ return 0;
1468+}
1469
1470 /*
1471 * We need to translate between nfs status return values and
1472diff -puN mount/sundries.h~nfs mount/sundries.h
1473--- util-linux-2.12/mount/sundries.h~nfs 2004-10-13 13:51:44.000000000 -0400
1474+++ util-linux-2.12-bfields/mount/sundries.h 2004-10-13 14:13:30.000000000 -0400
1475@@ -37,6 +37,7 @@ void die (int errcode, const char *fmt,
1476 #ifdef HAVE_NFS
1477 int nfsmount (const char *spec, const char *node, int *flags,
1478 char **orig_opts, char **opt_args, int *version, int running_bg);
1479+int nfsumount(const char *spec, const char *opts);
1480 #endif
1481
1482 /* exit status - bits below are ORed */
1483diff -puN mount/umount.c~nfs mount/umount.c
1484--- util-linux-2.12/mount/umount.c~nfs 2004-10-13 13:51:44.000000000 -0400
1485+++ util-linux-2.12-bfields/mount/umount.c 2004-10-13 14:13:30.000000000 -0400
1486@@ -122,7 +122,7 @@ check_special_umountprog() {
1487 }
1488 #endif
1489
1490-#ifdef HAVE_NFS
1491+#if 0
1492 static int xdr_dir(XDR *xdrsp, char *dirp)
1493 {
1494 return (xdr_string(xdrsp, &dirp, MNTPATHLEN));
1495@@ -265,7 +265,7 @@ umount_one (const char *spec, const char
1496 /* Ignore any RPC errors, so that you can umount the filesystem
1497 if the server is down. */
1498 if (strcasecmp(type, "nfs") == 0)
1499- nfs_umount_rpc_call(spec, opts);
1500+ nfsumount(spec, opts);
1501 #endif
1502
1503 umnt_err = umnt_err2 = 0;
1504_
This page took 0.483246 seconds and 4 git commands to generate.