2 Miscellaneous nfs mount changes from Trond.
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(-)
12 diff -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
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
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)
32 swapon: swapon.o version.o xmalloc.o \
33 diff -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
38 #include "../defines.h" /* for HAVE_rpcsvc_nfs_prot_h and HAVE_inet_aton */
48 +#define MNT_SENDBUFSIZE ((u_int)2048)
49 +#define MNT_RECVBUFSIZE ((u_int)1024)
51 static char *nfs_strerror(int stat);
53 #define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
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)
59 +#ifndef HAVE_inet_aton
60 +#define inet_aton(a,b) (0)
63 +typedef dirpath mnt2arg_t;
64 +typedef dirpath mnt3arg_t;
65 +typedef dirpath mntarg_t;
67 +typedef struct fhstatus mnt2res_t;
68 +typedef struct mountres3 mnt3res_t;
76 + struct sockaddr_in saddr;
80 +/* RPC call timeout values */
81 +static const struct timeval TIMEOUT = { 20, 0 };
82 +static const struct timeval RETRY_TIMEOUT = { 3, 0 };
84 +/* Define the order in which to probe for UDP/TCP services */
86 +proto_probelist(const int use_tcp)
88 + static const u_int probe_both[] = { IPPROTO_TCP, IPPROTO_UDP, 0 };
89 + static const u_int probe_udponly[] = { IPPROTO_UDP, 0 };
92 + return probe_udponly;
95 +/* Define the order in which NFS versions are probed on portmapper */
96 +static const u_long *
97 +nfs_probelist(const int vers)
99 + static const u_long nfs2_probe[] = { 2, 0};
100 + static const u_long nfs3_probe[] = { 3, 2, 0};
109 +/* Define the order in which Mountd versions are probed on portmapper */
110 +static const u_long *
111 +mnt_probelist(const int vers)
113 + static const u_long mnt1_probe[] = { 1, 2, 0 };
114 + static const u_long mnt3_probe[] = { 3, 1, 2, 0 };
123 +/* Map an NFS version into the corresponding Mountd version */
125 +nfsvers_to_mnt(const u_long vers)
127 + static const u_long nfs_to_mnt[] = { 0, 0, 1, 3 };
129 + return nfs_to_mnt[vers];
133 +/* Map a Mountd version into the corresponding NFS version */
135 +mntvers_to_nfs(const u_long vers)
137 + static const u_long mnt_to_nfs[] = { 0, 2, 2, 3 };
139 + return mnt_to_nfs[vers];
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
149 +static int nfs_mount_version = NFS_MOUNT_VERSION;
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;
157 if (kernel_version == -1)
158 kernel_version = linux_version_code();
160 if (kernel_version) {
161 if (kernel_version < MAKE_VERSION(2,1,32))
162 - nfs_mount_version = 1;
164 else if (kernel_version < MAKE_VERSION(2,2,18))
165 - nfs_mount_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;
174 - nfs_mount_version = 4; /* since 2.3.99pre4 */
175 + mnt_version = 4; /* since 2.3.99pre4 */
177 - if (nfs_mount_version > NFS_MOUNT_VERSION)
178 - nfs_mount_version = NFS_MOUNT_VERSION;
179 - return nfs_mount_version;
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)
190 - struct pmaplist *pmap;
191 - static struct pmap p = {0, 0, 0, 0};
193 - if (version > MAX_NFSPROT)
194 - version = MAX_NFSPROT;
198 - p.pm_vers = version;
202 - server_addr->sin_port = PMAPPORT;
203 - pmap = pmap_getmaps(server_addr);
206 - if (pmap->pml_map.pm_prog != prog)
208 - if (!version && p.pm_vers > pmap->pml_map.pm_vers)
210 - if (version > 2 && pmap->pml_map.pm_vers != version)
212 - if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
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))
218 - memcpy(&p, &pmap->pml_map, sizeof(p));
220 - pmap = pmap->pml_next;
223 - p.pm_vers = MOUNTVERS;
225 - p.pm_prot = IPPROTO_TCP;
228 - p.pm_port = pmap_getport(server_addr, p.pm_prog, p.pm_vers,
230 + if (mnt_version > NFS_MOUNT_VERSION)
231 + mnt_version = NFS_MOUNT_VERSION;
232 + return mnt_version;
236 +nfs_gethostbyname(const char *hostname, struct sockaddr_in *saddr)
238 + struct hostent *hp;
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"),
247 + if (hp->h_length > sizeof(*saddr)) {
249 + _("mount: got bad hp->h_length\n"));
250 + hp->h_length = sizeof(*saddr);
252 + memcpy(&saddr->sin_addr, hp->h_addr, hp->h_length);
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
265 +clnt_ping(struct sockaddr_in *saddr, const u_long prog, const u_long vers,
270 + static char clnt_res;
272 + sock = RPC_ANYSOCK;
275 + clnt = clntudp_bufcreate(saddr, prog, vers,
276 + RETRY_TIMEOUT, &sock,
277 + RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
280 + clnt = clnttcp_create(saddr, prog, vers, &sock,
281 + RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
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,
293 + clnt_destroy(clnt);
295 + if (stat != RPC_PROGVERSMISMATCH)
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.
307 +probe_port(clnt_addr_t *server,
308 + const u_long *versions,
309 + const u_int *protos)
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,
316 + const u_int prot = (u_int)pmap->pm_prot,
318 + const u_short port = (u_short) pmap->pm_port;
321 + p_prot = prot ? &prot : protos;
322 + p_vers = vers ? &vers : versions;
324 + saddr->sin_port = htons(PMAPPORT);
325 + p_port = pmap_getport(saddr, prog, *p_vers, *p_prot);
327 + if (!port || port == p_port) {
328 + saddr->sin_port = htons(port);
329 + if (clnt_ping(saddr, prog, *p_vers, *p_prot))
332 + } else if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED)
339 + if (vers || !*++p_vers)
345 + pmap->pm_vers = *p_vers;
347 + pmap->pm_prot = *p_prot;
349 + pmap->pm_port = p_port;
354 +probe_nfsport(clnt_addr_t *nfs_server)
356 + const struct pmap *pmap = &nfs_server->pmap;
357 + const u_long *probe_vers;
358 + const u_int *probe_prot;
360 + if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
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);
368 +probe_mntport(clnt_addr_t *mnt_server)
370 + const struct pmap *pmap = &mnt_server->pmap;
371 + const u_long *probe_vers;
372 + const u_int *probe_prot;
374 + if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
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);
382 +probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server)
384 + struct pmap *nfs_pmap = &nfs_server->pmap;
385 + struct pmap *mnt_pmap = &mnt_server->pmap;
386 + struct pmap save_nfs, save_mnt;
388 + const u_long *probe_vers;
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)
404 + memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap));
406 + memcpy(nfs_pmap, &save_nfs, sizeof(*nfs_pmap));
411 + if (!probe_nfsport(nfs_server))
413 + return probe_mntport(mnt_server);
417 +mnt_openclnt(clnt_addr_t *mnt_server, int *msock, const int report_errs)
419 + struct sockaddr_in *mnt_saddr = &mnt_server->saddr;
420 + struct pmap *mnt_pmap = &mnt_server->pmap;
423 + /* contact the mount daemon via TCP */
424 + mnt_saddr->sin_port = htons((u_short)mnt_pmap->pm_port);
425 + *msock = RPC_ANYSOCK;
427 + switch (mnt_pmap->pm_prot) {
429 + clnt = clntudp_bufcreate(mnt_saddr,
430 + mnt_pmap->pm_prog, mnt_pmap->pm_vers,
431 + RETRY_TIMEOUT, msock,
432 + MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
435 + clnt = clnttcp_create(mnt_saddr,
436 + mnt_pmap->pm_prog, mnt_pmap->pm_vers,
438 + MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
445 + /* try to mount hostname:dirname */
446 + clnt->cl_auth = authunix_create_default();
450 + clnt_pcreateerror("mount");
456 +mnt_closeclnt(CLIENT *clnt, int msock)
458 + auth_destroy(clnt->cl_auth);
459 + clnt_destroy(clnt);
463 +static inline enum clnt_stat
464 +nfs3_mount(CLIENT *clnt, mnt3arg_t *mnt3arg, mnt3res_t *mnt3res)
466 + return clnt_call(clnt, MOUNTPROC3_MNT,
467 + (xdrproc_t) xdr_dirpath, (caddr_t) mnt3arg,
468 + (xdrproc_t) xdr_mountres3, (caddr_t) mnt3res,
472 +static inline enum clnt_stat
473 +nfs2_mount(CLIENT *clnt, mnt2arg_t *mnt2arg, mnt2res_t *mnt2res)
475 + return clnt_call(clnt, MOUNTPROC_MNT,
476 + (xdrproc_t) xdr_dirpath, (caddr_t) mnt2arg,
477 + (xdrproc_t) xdr_fhstatus, (caddr_t) mnt2res,
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)
486 + enum clnt_stat stat;
490 + if (!probe_bothports(mnt_server, nfs_server)) {
492 + fprintf(stderr,_("mount: failed to probe ports on NFS server %s\n"),
493 + *nfs_server->hostname);
497 + clnt = mnt_openclnt(mnt_server, &msock, report_errs);
500 + /* make pointers in xdr_mountres3 NULL so
501 + * that xdr_array allocates memory for us
503 + memset(mntres, 0, sizeof(*mntres));
504 + switch (mnt_server->pmap.pm_vers) {
506 + stat = nfs3_mount(clnt, mntarg, &mntres->nfsv3);
510 + stat = nfs2_mount(clnt, mntarg, &mntres->nfsv2);
515 + if (stat != RPC_SUCCESS && report_errs)
516 + clnt_perror(clnt, "mount");
517 + mnt_closeclnt(clnt, msock);
518 + if (stat == RPC_SUCCESS)
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)
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;
534 + char *mounthost = NULL;
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);
547 + if (!strcmp(opt, "rsize"))
549 + else if (!strcmp(opt, "wsize"))
551 + else if (!strcmp(opt, "timeo"))
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;
569 + else if (!strcmp(opt, "retry"))
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;
585 +#if NFS_MOUNT_VERSION >= 2
586 + } else if (!strcmp(opt, "namlen")) {
587 + if (nfs_mount_version >= 2)
588 + data->namlen = val;
590 + goto bad_parameter;
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? */
598 - p.pm_port = MOUNTPORT;
601 + } else if (!strcmp(opt, "addr")) {
604 + } else if (!sloppy)
605 + goto bad_parameter;
606 + sprintf(cbuf, "%s=%s,", opt, opteq+1);
607 + } else if (opteq) {
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;
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,"));
625 + goto bad_parameter;
626 + sprintf(cbuf, "%s=%s,", opt, opteq+1);
629 + if (!strncmp(opt, "no", 2)) {
633 + if (!strcmp(opt, "bg"))
635 + else if (!strcmp(opt, "fg"))
637 + else if (!strcmp(opt, "soft")) {
638 + data->flags &= ~NFS_MOUNT_SOFT;
640 + data->flags |= NFS_MOUNT_SOFT;
641 + } else if (!strcmp(opt, "hard")) {
642 + data->flags &= ~NFS_MOUNT_SOFT;
644 + data->flags |= NFS_MOUNT_SOFT;
645 + } else if (!strcmp(opt, "intr")) {
646 + data->flags &= ~NFS_MOUNT_INTR;
648 + data->flags |= NFS_MOUNT_INTR;
649 + } else if (!strcmp(opt, "posix")) {
650 + data->flags &= ~NFS_MOUNT_POSIX;
652 + data->flags |= NFS_MOUNT_POSIX;
653 + } else if (!strcmp(opt, "cto")) {
654 + data->flags &= ~NFS_MOUNT_NOCTO;
656 + data->flags |= NFS_MOUNT_NOCTO;
657 + } else if (!strcmp(opt, "ac")) {
658 + data->flags &= ~NFS_MOUNT_NOAC;
660 + data->flags |= NFS_MOUNT_NOAC;
661 +#if NFS_MOUNT_VERSION >= 2
662 + } else if (!strcmp(opt, "tcp")) {
663 + data->flags &= ~NFS_MOUNT_TCP;
665 + if (nfs_mount_version < 2)
667 + nfs_pmap->pm_prot = IPPROTO_TCP;
668 + data->flags |= NFS_MOUNT_TCP;
670 + nfs_pmap->pm_prot = IPPROTO_UDP;
671 + } else if (!strcmp(opt, "udp")) {
672 + data->flags &= ~NFS_MOUNT_TCP;
674 + if (nfs_mount_version < 2)
676 + nfs_pmap->pm_prot = IPPROTO_TCP;
677 + data->flags |= NFS_MOUNT_TCP;
679 + nfs_pmap->pm_prot = IPPROTO_UDP;
681 +#if NFS_MOUNT_VERSION >= 3
682 + } else if (!strcmp(opt, "lock")) {
683 + data->flags &= ~NFS_MOUNT_NONLM;
685 + if (nfs_mount_version < 3)
687 + data->flags |= NFS_MOUNT_NONLM;
690 +#if NFS_MOUNT_VERSION >= 4
691 + } else if (!strcmp(opt, "broken_suid")) {
692 + data->flags &= ~NFS_MOUNT_BROKEN_SUID;
694 + if (nfs_mount_version < 4)
696 + data->flags |= NFS_MOUNT_BROKEN_SUID;
701 + printf(_("Unsupported nfs mount option: "
702 + "%s%s\n"), val ? "" : "no", opt);
705 + sprintf(cbuf, val ? "%s,":"no%s,", opt);
707 + len += strlen(cbuf);
708 + if (len >= opt_size) {
709 + printf(_("mount: excessively long option argument\n"));
712 + strcat(new_opts, cbuf);
714 + /* See if the nfs host = mount host. */
716 + if (!nfs_gethostbyname(mounthost, mnt_saddr))
718 + *mnt_server->hostname = mounthost;
722 + printf(_("Bad nfs mount parameter: %s\n"), opt);
728 +nfsmnt_check_compat(const struct pmap *nfs_pmap, const struct pmap *mnt_pmap)
730 + if (nfs_pmap->pm_vers > MAX_NFSPROT) {
731 + fprintf(stderr, _("NFSv%ld not supported!\n"), nfs_pmap->pm_vers);
734 + if (mnt_pmap->pm_vers > MAX_MNTPROT) {
735 + fprintf(stderr, _("NFS mount v%ld not supported!\n"), mnt_pmap->pm_vers);
743 -int nfsmount(const char *spec, const char *node, int *flags,
744 - char **extra_opts, char **mount_opts, int *nfs_mount_vers,
747 +nfsmount(const char *spec, const char *node, int *flags,
748 + char **extra_opts, char **mount_opts, int *nfs_mount_vers,
751 static char *prev_bg_host;
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;
761 - int nfs_mount_version;
763 - struct hostent *hp;
764 - struct sockaddr_in server_addr;
765 - struct sockaddr_in mount_server_addr;
766 - struct pmap *pm_mnt;
768 - struct timeval retry_timeout;
770 - struct fhstatus nfsv2;
771 - struct mountres3 nfsv3;
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;
787 - int port, mountport, proto, bg, soft, intr;
788 - int posix, nocto, noac, nolock, broken_suid;
790 - int mountprog, mountvers, nfsprog, nfsvers;
796 @@ -231,8 +756,7 @@ int nfsmount(const char *spec, const cha
797 nfs_mount_version = *nfs_mount_vers;
800 - msock = 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
810 - server_addr.sin_family = AF_INET;
811 -#ifdef HAVE_inet_aton
812 - if (!inet_aton(hostname, &server_addr.sin_addr))
815 - if ((hp = gethostbyname(hostname)) == NULL) {
816 - fprintf(stderr, _("mount: can't get address for %s\n"),
820 - if (hp->h_length > sizeof(struct in_addr)) {
822 - _("mount: got bad hp->h_length\n"));
823 - hp->h_length = sizeof(struct in_addr);
825 - memcpy(&server_addr.sin_addr,
826 - hp->h_addr, hp->h_length);
830 - memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr));
831 + if (!nfs_gethostbyname(hostname, nfs_saddr))
833 + mounthost = hostname;
834 + memcpy (&mnt_server.saddr, nfs_saddr, sizeof (mnt_server.saddr));
836 /* add IP address to mtab options for use when unmounting */
838 - s = inet_ntoa(server_addr.sin_addr);
839 + s = inet_ntoa(nfs_saddr->sin_addr);
840 old_opts = *extra_opts;
843 - if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
844 - fprintf(stderr, _("mount: "
845 - "excessively long option argument\n"));
848 - sprintf(new_opts, "%s%saddr=%s",
849 - old_opts, *old_opts ? "," : "", s);
850 - *extra_opts = xstrdup(new_opts);
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));
861 @@ -310,167 +808,21 @@ int nfsmount(const char *spec, const cha
872 retry = 10000; /* 10000 minutes ~ 1 week */
875 - mountprog = MOUNTPROG;
879 - nfsprog = NFS_PROGRAM;
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;
888 + if (!parse_options(old_opts, &data, &bg, &retry, &mnt_server, &nfs_server,
889 + new_opts, sizeof(new_opts)))
891 + if (!nfsmnt_check_compat(nfs_pmap, mnt_pmap))
894 - for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
895 - if ((opteq = strchr(opt, '='))) {
896 - val = atoi(opteq + 1);
898 - if (!strcmp(opt, "rsize"))
900 - else if (!strcmp(opt, "wsize"))
902 - else if (!strcmp(opt, "timeo"))
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;
920 - else if (!strcmp(opt, "retry"))
922 - else if (!strcmp(opt, "port"))
924 - else if (!strcmp(opt, "mountport"))
926 - else if (!strcmp(opt, "mounthost"))
927 - mounthost=xstrndup(opteq+1,
928 - strcspn(opteq+1," \t\n\r,"));
929 - else if (!strcmp(opt, "mountprog"))
931 - else if (!strcmp(opt, "mountvers"))
933 - else if (!strcmp(opt, "nfsprog"))
935 - else if (!strcmp(opt, "nfsvers") ||
936 - !strcmp(opt, "vers"))
938 - else if (!strcmp(opt, "proto")) {
939 - if (!strncmp(opteq+1, "tcp", 3))
941 - else if (!strncmp(opteq+1, "udp", 3))
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)
951 - printf(_("Warning: Option namlen is not supported.\n"));
952 - } else if (!strcmp(opt, "addr")) {
955 - printf(_("unknown nfs mount parameter: "
956 - "%s=%d\n"), opt, val);
961 - if (!strncmp(opt, "no", 2)) {
965 - if (!strcmp(opt, "bg"))
967 - else if (!strcmp(opt, "fg"))
969 - else if (!strcmp(opt, "soft"))
971 - else if (!strcmp(opt, "hard"))
973 - else if (!strcmp(opt, "intr"))
975 - else if (!strcmp(opt, "posix"))
977 - else if (!strcmp(opt, "cto"))
979 - else if (!strcmp(opt, "ac"))
981 - else if (!strcmp(opt, "tcp"))
983 - else if (!strcmp(opt, "udp"))
985 - else if (!strcmp(opt, "lock")) {
986 - if (nfs_mount_version >= 3)
989 - printf(_("Warning: option nolock is not supported.\n"));
990 - } else if (!strcmp(opt, "broken_suid")) {
994 - printf(_("unknown nfs mount option: "
995 - "%s%s\n"), val ? "" : "no", opt);
1001 - proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
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);
1012 -#if NFS_MOUNT_VERSION >= 3
1013 - if (nfs_mount_version >= 3)
1014 - data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
1016 -#if NFS_MOUNT_VERSION >= 4
1017 - if (nfs_mount_version >= 4)
1018 - data.flags |= (broken_suid ? NFS_MOUNT_BROKEN_SUID : 0);
1020 - if (nfsvers > MAX_NFSPROT) {
1021 - fprintf(stderr, "NFSv%d not supported!\n", nfsvers);
1024 - if (mountvers > MAX_NFSPROT) {
1025 - fprintf(stderr, "NFSv%d not supported!\n", nfsvers);
1028 - if (nfsvers && !mountvers)
1029 - mountvers = (nfsvers < 3) ? 1 : nfsvers;
1030 - if (nfsvers && nfsvers < mountvers)
1031 - mountvers = nfsvers;
1033 - /* Adjust options if none specified */
1035 - data.timeo = tcp ? 70 : 7;
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;
1055 if (*flags & MS_REMOUNT)
1060 * If the previous mount operation on the same host was
1061 @@ -512,28 +865,6 @@ int nfsmount(const char *spec, const cha
1064 /* create mount deamon client */
1065 - /* See if the nfs host = mount host. */
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);
1071 - if ((hp = gethostbyname(mounthost)) == NULL) {
1072 - fprintf(stderr, _("mount: can't get address for %s\n"),
1076 - if (hp->h_length > sizeof(struct in_addr)) {
1078 - _("mount: got bad hp->h_length?\n"));
1079 - hp->h_length = sizeof(struct in_addr);
1081 - mount_server_addr.sin_family = AF_INET;
1082 - memcpy(&mount_server_addr.sin_addr,
1083 - hp->h_addr, hp->h_length);
1089 * The following loop implements the mount retries. On the first
1090 @@ -551,15 +882,13 @@ int nfsmount(const char *spec, const cha
1092 * Only the first error message will be displayed.
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;
1103 + memcpy(&save_nfs, nfs_pmap, sizeof(save_nfs));
1104 + memcpy(&save_mnt, mnt_pmap, sizeof(save_mnt));
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
1113 /* be careful not to use too many CPU cycles */
1117 - pm_mnt = get_mountport(&mount_server_addr,
1122 - nfs_mount_version);
1124 - /* contact the mount daemon via TCP */
1125 - mount_server_addr.sin_port = htons(pm_mnt->pm_port);
1126 - msock = RPC_ANYSOCK;
1128 - switch (pm_mnt->pm_prot) {
1130 - mclient = clntudp_create(&mount_server_addr,
1137 - mount_server_addr.sin_port =
1138 - htons(pm_mnt->pm_port);
1139 - msock = RPC_ANYSOCK;
1141 - mclient = clnttcp_create(&mount_server_addr,
1145 + stat = nfs_call_mount(&mnt_server, &nfs_server,
1146 + &dirname, &mntres,
1147 + !running_bg && prevt == 0);
1155 - /* try to mount hostname:dirname */
1156 - mclient->cl_auth = authunix_create_default();
1158 - /* make pointers in xdr_mountres3 NULL so
1159 - * that xdr_array allocates memory for us
1161 - memset(&status, 0, sizeof(status));
1163 - if (pm_mnt->pm_vers == 3)
1164 - clnt_stat = clnt_call(mclient,
1166 - (xdrproc_t) xdr_dirpath,
1167 - (caddr_t) &dirname,
1168 - (xdrproc_t) xdr_mountres3,
1169 - (caddr_t) &status,
1172 - clnt_stat = clnt_call(mclient,
1174 - (xdrproc_t) xdr_dirpath,
1175 - (caddr_t) &dirname,
1176 - (xdrproc_t) xdr_fhstatus,
1177 - (caddr_t) &status,
1180 - if (clnt_stat == RPC_SUCCESS)
1181 - break; /* we're done */
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 */
1190 - if (!running_bg && prevt == 0)
1191 - clnt_perror(mclient, "mount");
1192 - auth_destroy(mclient->cl_auth);
1193 - clnt_destroy(mclient);
1197 - if (!running_bg && prevt == 0)
1198 - clnt_pcreateerror("mount");
1200 + memcpy(nfs_pmap, &save_nfs, sizeof(*nfs_pmap));
1201 + memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap));
1205 @@ -668,36 +926,35 @@ int nfsmount(const char *spec, const cha
1209 - nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;
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) {
1216 - "mount: %s:%s failed, reason given by server: %s\n",
1217 + _("mount: %s:%s failed, reason given by server: %s\n"),
1219 - nfs_strerror(status.nfsv2.fhs_status));
1220 + nfs_strerror(mntres.nfsv2.fhs_status));
1223 memcpy(data.root.data,
1224 - (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1225 + (char *) mntres.nfsv2.fhstatus_u.fhs_fhandle,
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,
1235 #if NFS_MOUNT_VERSION >= 4
1237 - if (status.nfsv3.fhs_status != 0) {
1238 + if (mntres.nfsv3.fhs_status != 0) {
1240 - "mount: %s:%s failed, reason given by server: %s\n",
1241 + _("mount: %s:%s failed, reason given by server: %s\n"),
1243 - nfs_strerror(status.nfsv3.fhs_status));
1244 + nfs_strerror(mntres.nfsv3.fhs_status));
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
1254 /* create nfs socket for kernel */
1257 - if (nfs_mount_version < 3) {
1258 - printf(_("NFS over TCP is not supported.\n"));
1261 + if (nfs_pmap->pm_prot == IPPROTO_TCP)
1262 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1265 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1267 perror(_("nfs socket"));
1268 @@ -727,72 +980,162 @@ int nfsmount(const char *spec, const cha
1269 perror(_("nfs bindresvport"));
1273 - server_addr.sin_port = PMAPPORT;
1274 - port = pmap_getport(&server_addr, nfsprog, nfsvers,
1275 - tcp ? IPPROTO_TCP : IPPROTO_UDP);
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.
1282 - if (port == 0 && tcp == 1) {
1283 - perror(_("nfs server reported service unavailable"));
1290 #ifdef NFS_MOUNT_DEBUG
1292 - printf(_("used portmapper to find NFS port\n"));
1293 + printf(_("using port %d for nfs deamon\n"), nfs_pmap->pm_port);
1296 -#ifdef NFS_MOUNT_DEBUG
1297 - printf(_("using port %d for nfs deamon\n"), port);
1299 - server_addr.sin_port = htons(port);
1300 + nfs_saddr->sin_port = htons(nfs_pmap->pm_port);
1302 * connect() the socket for kernels 1.3.10 and below only,
1303 * to avoid problems with multihomed hosts.
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"));
1315 +#if NFS_MOUNT_VERSION >= 2
1316 + if (nfs_pmap->pm_prot == IPPROTO_TCP)
1317 + data.flags |= NFS_MOUNT_TCP;
1319 + data.flags &= ~NFS_MOUNT_TCP;
1322 /* prepare data structure for kernel */
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));
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"));
1338 - auth_destroy(mclient->cl_auth);
1339 - clnt_destroy(mclient);
1341 + sprintf(cbuf, "addr=%s", s);
1342 + strcat(new_opts, cbuf);
1344 + *extra_opts = xstrdup(new_opts);
1350 - if (msock != -1) {
1352 - auth_destroy(mclient->cl_auth);
1353 - clnt_destroy(mclient);
1363 +static inline enum clnt_stat
1364 +nfs3_umount(dirpath *argp, CLIENT *clnt)
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,
1374 +static inline enum clnt_stat
1375 +nfs2_umount(dirpath *argp, CLIENT *clnt)
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,
1386 +nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp)
1389 + enum clnt_stat res = 0;
1392 + clnt = mnt_openclnt(mnt_server, &msock, 1);
1395 + switch (mnt_server->pmap.pm_vers) {
1397 + res = nfs3_umount(argp, clnt);
1401 + res = nfs2_umount(argp, clnt);
1405 + mnt_closeclnt(clnt, msock);
1406 + if (res == RPC_SUCCESS)
1413 +nfsumount(const char *spec, const char *opts)
1417 + clnt_addr_t mnt_server = { &hostname, };
1418 + struct pmap *pmap = &mnt_server.pmap;
1421 + nfs_mount_version = find_kernel_nfs_mount_version();
1422 + if (spec == NULL || (p = strchr(spec,':')) == NULL)
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);
1430 + if (opts && (p = strstr(opts, "addr="))) {
1436 + while (*q && *q != ',') q++;
1437 + hostname = xstrndup(p,q-p);
1440 + if (opts && (p = strstr(opts, "mounthost="))) {
1446 + while (*q && *q != ',') q++;
1447 + hostname = xstrndup(p,q-p);
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);
1461 + if (!nfs_gethostbyname(hostname, &mnt_server.saddr))
1463 + if (!probe_mntport(&mnt_server))
1465 + return nfs_call_umount(&mnt_server, &dirname);
1471 * We need to translate between nfs status return values and
1472 diff -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,
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);
1482 /* exit status - bits below are ORed */
1483 diff -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() {
1492 static int xdr_dir(XDR *xdrsp, char *dirp)
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);
1503 umnt_err = umnt_err2 = 0;