summaryrefslogtreecommitdiffstats
path: root/contrib/amd/amd
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>2007-12-05 15:48:03 +0000
committerobrien <obrien@FreeBSD.org>2007-12-05 15:48:03 +0000
commitea691ecd980d2860f0b39e9e504de4da404806fd (patch)
treefa83b3bb0660890a21b550fa1f334b151bf098f9 /contrib/amd/amd
parentc06a2e613662fc6ce10145b41762be8f8ab22ba4 (diff)
downloadFreeBSD-src-ea691ecd980d2860f0b39e9e504de4da404806fd.zip
FreeBSD-src-ea691ecd980d2860f0b39e9e504de4da404806fd.tar.gz
Virgin import of AMD (am-utils) v6.1.5
Sponsored by: Juniper Networks
Diffstat (limited to 'contrib/amd/amd')
-rw-r--r--contrib/amd/amd/am_ops.c149
-rw-r--r--contrib/amd/amd/amd.826
-rw-r--r--contrib/amd/amd/amd.c249
-rw-r--r--contrib/amd/amd/amd.h723
-rw-r--r--contrib/amd/amd/amfs_auto.c1524
-rw-r--r--contrib/amd/amd/amfs_direct.c30
-rw-r--r--contrib/amd/amd/amfs_error.c57
-rw-r--r--contrib/amd/amd/amfs_generic.c1262
-rw-r--r--contrib/amd/amd/amfs_host.c170
-rw-r--r--contrib/amd/amd/amfs_link.c78
-rw-r--r--contrib/amd/amd/amfs_linkx.c34
-rw-r--r--contrib/amd/amd/amfs_nfsl.c143
-rw-r--r--contrib/amd/amd/amfs_nfsx.c174
-rw-r--r--contrib/amd/amd/amfs_program.c64
-rw-r--r--contrib/amd/amd/amfs_root.c30
-rw-r--r--contrib/amd/amd/amfs_toplvl.c363
-rw-r--r--contrib/amd/amd/amfs_union.c50
-rw-r--r--contrib/amd/amd/amq_subr.c123
-rw-r--r--contrib/amd/amd/amq_svc.c85
-rw-r--r--contrib/amd/amd/autil.c619
-rw-r--r--contrib/amd/amd/clock.c34
-rw-r--r--contrib/amd/amd/conf.c540
-rw-r--r--contrib/amd/amd/conf_parse.y4
-rw-r--r--contrib/amd/amd/conf_tok.l4
-rw-r--r--contrib/amd/amd/get_args.c249
-rw-r--r--contrib/amd/amd/info_exec.c423
-rw-r--r--contrib/amd/amd/info_file.c40
-rw-r--r--contrib/amd/amd/info_hesiod.c26
-rw-r--r--contrib/amd/amd/info_ldap.c231
-rw-r--r--contrib/amd/amd/info_ndbm.c15
-rw-r--r--contrib/amd/amd/info_nis.c17
-rw-r--r--contrib/amd/amd/info_nisplus.c54
-rw-r--r--contrib/amd/amd/info_passwd.c17
-rw-r--r--contrib/amd/amd/info_union.c28
-rw-r--r--contrib/amd/amd/map.c716
-rw-r--r--contrib/amd/amd/mapc.c316
-rw-r--r--contrib/amd/amd/mntfs.c126
-rw-r--r--contrib/amd/amd/nfs_prot_svc.c65
-rw-r--r--contrib/amd/amd/nfs_start.c166
-rw-r--r--contrib/amd/amd/nfs_subr.c359
-rw-r--r--contrib/amd/amd/ops_TEMPLATE.c46
-rw-r--r--contrib/amd/amd/ops_cachefs.c67
-rw-r--r--contrib/amd/amd/ops_cdfs.c75
-rw-r--r--contrib/amd/amd/ops_efs.c50
-rw-r--r--contrib/amd/amd/ops_lofs.c53
-rw-r--r--contrib/amd/amd/ops_mfs.c5
-rw-r--r--contrib/amd/amd/ops_nfs.c628
-rw-r--r--contrib/amd/amd/ops_nfs3.c5
-rw-r--r--contrib/amd/amd/ops_nullfs.c5
-rw-r--r--contrib/amd/amd/ops_pcfs.c93
-rw-r--r--contrib/amd/amd/ops_tfs.c5
-rw-r--r--contrib/amd/amd/ops_tmpfs.c5
-rw-r--r--contrib/amd/amd/ops_ufs.c49
-rw-r--r--contrib/amd/amd/ops_umapfs.c5
-rw-r--r--contrib/amd/amd/ops_unionfs.c5
-rw-r--r--contrib/amd/amd/ops_xfs.c49
-rw-r--r--contrib/amd/amd/opts.c487
-rw-r--r--contrib/amd/amd/readdir.c498
-rw-r--r--contrib/amd/amd/restart.c312
-rw-r--r--contrib/amd/amd/rpc_fwd.c74
-rw-r--r--contrib/amd/amd/sched.c70
-rw-r--r--contrib/amd/amd/srvr_amfs_auto.c19
-rw-r--r--contrib/amd/amd/srvr_nfs.c588
63 files changed, 7859 insertions, 4717 deletions
diff --git a/contrib/amd/amd/am_ops.c b/contrib/amd/amd/am_ops.c
index 3097aee..5a5c336 100644
--- a/contrib/amd/amd/am_ops.c
+++ b/contrib/amd/amd/am_ops.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1989 Jan-Simon Pendry
* Copyright (c) 1989 Imperial College of Science, Technology & Medicine
* Copyright (c) 1989 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: am_ops.c,v 1.6.2.7 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/am_ops.c
*
*/
@@ -87,9 +86,6 @@ static am_ops *vops[] =
#ifdef HAVE_AMU_FS_UNION
&amfs_union_ops, /* union F/S */
#endif /* HAVE_AMU_FS_UNION */
-#ifdef HAVE_AMU_FS_INHERIT
- &amfs_inherit_ops, /* inheritance F/S */
-#endif /* HAVE_AMU_FS_INHERIT */
/*
* A few more native filesystems.
@@ -126,7 +122,7 @@ static am_ops *vops[] =
#endif /* HAVE_FS_UMAPFS */
/*
- * These 5 should be last, in the order:
+ * These 4 should be last, in the order:
* (1) amfs_auto
* (2) amfs_direct
* (3) amfs_toplvl
@@ -149,107 +145,111 @@ static am_ops *vops[] =
void
-ops_showamfstypes(char *buf)
+ops_showamfstypes(char *buf, size_t l)
{
struct am_ops **ap;
- int l = 0;
+ int linesize = 0;
buf[0] = '\0';
for (ap = vops; *ap; ap++) {
- strcat(buf, (*ap)->fs_type);
+ xstrlcat(buf, (*ap)->fs_type, l);
if (ap[1])
- strcat(buf, ", ");
- l += strlen((*ap)->fs_type) + 2;
- if (l > 62) {
- l = 0;
- strcat(buf, "\n ");
+ xstrlcat(buf, ", ", l);
+ linesize += strlen((*ap)->fs_type) + 2;
+ if (linesize > 62) {
+ linesize = 0;
+ xstrlcat(buf, "\n ", l);
}
}
}
static void
-ops_show1(char *buf, int *lp, const char *name)
+ops_show1(char *buf, size_t l, int *linesizep, const char *name)
{
- strcat(buf, name);
- strcat(buf, ", ");
- *lp += strlen(name) + 2;
- if (*lp > 60) {
- strcat(buf, "\t\n");
- *lp = 0;
+ xstrlcat(buf, name, l);
+ xstrlcat(buf, ", ", l);
+ *linesizep += strlen(name) + 2;
+ if (*linesizep > 60) {
+ xstrlcat(buf, "\t\n", l);
+ *linesizep = 0;
}
}
void
-ops_showfstypes(char *buf)
+ops_showfstypes(char *buf, size_t l)
{
- int l = 0;
+ int linesize = 0;
buf[0] = '\0';
+#ifdef MNTTAB_TYPE_AUTOFS
+ ops_show1(buf, l, &linesize, MNTTAB_TYPE_AUTOFS);
+#endif /* MNTTAB_TYPE_AUTOFS */
+
#ifdef MNTTAB_TYPE_CACHEFS
- ops_show1(buf, &l, MNTTAB_TYPE_CACHEFS);
+ ops_show1(buf, l, &linesize, MNTTAB_TYPE_CACHEFS);
#endif /* MNTTAB_TYPE_CACHEFS */
#ifdef MNTTAB_TYPE_CDFS
- ops_show1(buf, &l, MNTTAB_TYPE_CDFS);
+ ops_show1(buf, l, &linesize, MNTTAB_TYPE_CDFS);
#endif /* MNTTAB_TYPE_CDFS */
#ifdef MNTTAB_TYPE_CFS
- ops_show1(buf, &l, MNTTAB_TYPE_CFS);
+ ops_show1(buf, l, &linesize, MNTTAB_TYPE_CFS);
#endif /* MNTTAB_TYPE_CFS */
#ifdef MNTTAB_TYPE_LOFS
- ops_show1(buf, &l, MNTTAB_TYPE_LOFS);
+ ops_show1(buf, l, &linesize, MNTTAB_TYPE_LOFS);
#endif /* MNTTAB_TYPE_LOFS */
#ifdef MNTTAB_TYPE_EFS
- ops_show1(buf, &l, MNTTAB_TYPE_EFS);
+ ops_show1(buf, l, &linesize, MNTTAB_TYPE_EFS);
#endif /* MNTTAB_TYPE_EFS */
#ifdef MNTTAB_TYPE_MFS
- ops_show1(buf, &l, MNTTAB_TYPE_MFS);
+ ops_show1(buf, l, &linesize, MNTTAB_TYPE_MFS);
#endif /* MNTTAB_TYPE_MFS */
#ifdef MNTTAB_TYPE_NFS
- ops_show1(buf, &l, MNTTAB_TYPE_NFS);
+ ops_show1(buf, l, &linesize, MNTTAB_TYPE_NFS);
#endif /* MNTTAB_TYPE_NFS */
#ifdef MNTTAB_TYPE_NFS3
- ops_show1(buf, &l, "nfs3"); /* always hard-code as nfs3 */
+ ops_show1(buf, l, &linesize, "nfs3"); /* always hard-code as nfs3 */
#endif /* MNTTAB_TYPE_NFS3 */
#ifdef MNTTAB_TYPE_NULLFS
- ops_show1(buf, &l, MNTTAB_TYPE_NULLFS);
+ ops_show1(buf, l, &linesize, MNTTAB_TYPE_NULLFS);
#endif /* MNTTAB_TYPE_NULLFS */
#ifdef MNTTAB_TYPE_PCFS
- ops_show1(buf, &l, MNTTAB_TYPE_PCFS);
+ ops_show1(buf, l, &linesize, MNTTAB_TYPE_PCFS);
#endif /* MNTTAB_TYPE_PCFS */
#ifdef MNTTAB_TYPE_TFS
- ops_show1(buf, &l, MNTTAB_TYPE_TFS);
+ ops_show1(buf, l, &linesize, MNTTAB_TYPE_TFS);
#endif /* MNTTAB_TYPE_TFS */
#ifdef MNTTAB_TYPE_TMPFS
- ops_show1(buf, &l, MNTTAB_TYPE_TMPFS);
+ ops_show1(buf, l, &linesize, MNTTAB_TYPE_TMPFS);
#endif /* MNTTAB_TYPE_TMPFS */
#ifdef MNTTAB_TYPE_UFS
- ops_show1(buf, &l, MNTTAB_TYPE_UFS);
+ ops_show1(buf, l, &linesize, MNTTAB_TYPE_UFS);
#endif /* MNTTAB_TYPE_UFS */
#ifdef MNTTAB_TYPE_UMAPFS
- ops_show1(buf, &l, MNTTAB_TYPE_UMAPFS);
+ ops_show1(buf, l, &linesize, MNTTAB_TYPE_UMAPFS);
#endif /* MNTTAB_TYPE_UMAPFS */
#ifdef MNTTAB_TYPE_UNIONFS
- ops_show1(buf, &l, MNTTAB_TYPE_UNIONFS);
+ ops_show1(buf, l, &linesize, MNTTAB_TYPE_UNIONFS);
#endif /* MNTTAB_TYPE_UNIONFS */
#ifdef MNTTAB_TYPE_XFS
- ops_show1(buf, &l, MNTTAB_TYPE_XFS);
+ ops_show1(buf, l, &linesize, MNTTAB_TYPE_XFS);
#endif /* MNTTAB_TYPE_XFS */
/* terminate with a period, newline, and NULL */
@@ -257,7 +257,7 @@ ops_showfstypes(char *buf)
buf[strlen(buf) - 4] = '\0';
else
buf[strlen(buf) - 2] = '\0';
- strcat(buf, ".\n");
+ xstrlcat(buf, ".\n", l);
}
@@ -289,11 +289,11 @@ reverse_option(const char *opt)
/* check if string starts with 'no' and chop it */
if (NSTREQ(opt, "no", 2)) {
- strcpy(buf, &opt[2]);
+ xstrlcpy(buf, &opt[2], sizeof(buf));
} else {
/* finally return a string prepended with 'no' */
- strcpy(buf, "no");
- strcat(buf, opt);
+ xstrlcpy(buf, "no", sizeof(buf));
+ xstrlcat(buf, opt, sizeof(buf));
}
return buf;
}
@@ -315,7 +315,7 @@ merge_opts(const char *opts1, const char *opts2)
char *eq; /* pointer to whatever follows '=' within temp */
char oneopt[80]; /* one option w/o value if any */
char *revoneopt; /* reverse of oneopt */
- int len = strlen(opts1) + strlen(opts2) + 2; /* space for "," and NULL */
+ size_t len = strlen(opts1) + strlen(opts2) + 2; /* space for "," and NULL */
char *s1 = strdup(opts1); /* copy of opts1 to munge */
/* initialization */
@@ -327,31 +327,30 @@ merge_opts(const char *opts1, const char *opts2)
tmpstr;
tmpstr = strtok(NULL, ",")) {
/* copy option to temp buffer */
- strncpy(oneopt, tmpstr, 80);
- oneopt[79] = '\0';
+ xstrlcpy(oneopt, tmpstr, 80);
/* if option has a value such as rsize=1024, chop the value part */
if ((eq = haseq(oneopt)))
*eq = '\0';
/* find reverse option of oneopt */
revoneopt = reverse_option(oneopt);
/* if option orits reverse exist in opts2, ignore it */
- if (hasmntopt(&mnt2, oneopt) || hasmntopt(&mnt2, revoneopt))
+ if (amu_hasmntopt(&mnt2, oneopt) || amu_hasmntopt(&mnt2, revoneopt))
continue;
/* add option to returned string */
- if (newstr && newstr[0]) {
- strcat(newstr, ",");
- strcat(newstr, tmpstr);
+ if (newstr[0]) {
+ xstrlcat(newstr, ",", len);
+ xstrlcat(newstr, tmpstr, len);
} else {
- strcpy(newstr, tmpstr);
+ xstrlcpy(newstr, tmpstr, len);
}
}
/* finally, append opts2 itself */
- if (newstr && newstr[0]) {
- strcat(newstr, ",");
- strcat(newstr, opts2);
+ if (newstr[0]) {
+ xstrlcat(newstr, ",", len);
+ xstrlcat(newstr, opts2, len);
} else {
- strcpy(newstr, opts2);
+ xstrlcpy(newstr, opts2, len);
}
XFREE(s1);
@@ -360,10 +359,22 @@ merge_opts(const char *opts1, const char *opts2)
am_ops *
-ops_match(am_opts *fo, char *key, char *g_key, char *path, char *keym, char *map)
+ops_search(char *type)
{
am_ops **vp;
am_ops *rop = 0;
+ for (vp = vops; (rop = *vp); vp++)
+ if (STREQ(rop->fs_type, type))
+ break;
+ return rop;
+}
+
+
+am_ops *
+ops_match(am_opts *fo, char *key, char *g_key, char *path, char *keym, char *map)
+{
+ am_ops *rop = 0;
+ char *link_dir;
/*
* First crack the global opts and the local opts
@@ -377,9 +388,7 @@ ops_match(am_opts *fo, char *key, char *g_key, char *path, char *keym, char *map
/*
* Next find the correct filesystem type
*/
- for (vp = vops; (rop = *vp); vp++)
- if (STREQ(rop->fs_type, fo->opt_type))
- break;
+ rop = ops_search(fo->opt_type);
if (!rop) {
plog(XLOG_USER, "fs type \"%s\" not recognized", fo->opt_type);
rop = &amfs_error_ops;
@@ -434,17 +443,33 @@ ops_match(am_opts *fo, char *key, char *g_key, char *path, char *keym, char *map
}
/*
+ * Initialize opt_mount_type to "nfs", if it's not initialized already
+ */
+ if (!fo->opt_mount_type)
+ fo->opt_mount_type = "nfs";
+
+ /* Normalize the sublink and make it absolute */
+ link_dir = fo->opt_sublink;
+ if (link_dir && link_dir[0] && link_dir[0] != '/') {
+ link_dir = str3cat((char *) 0, fo->opt_fs, "/", link_dir);
+ normalize_slash(link_dir);
+ XFREE(fo->opt_sublink);
+ fo->opt_sublink = link_dir;
+ }
+
+ /*
* Check the filesystem is happy
*/
if (fo->fs_mtab)
XFREE(fo->fs_mtab);
- if ((fo->fs_mtab = (*rop->fs_match) (fo)))
+ fo->fs_mtab = rop->fs_match(fo);
+ if (fo->fs_mtab)
return rop;
/*
* Return error file system
*/
- fo->fs_mtab = (*amfs_error_ops.fs_match) (fo);
+ fo->fs_mtab = amfs_error_ops.fs_match(fo);
return &amfs_error_ops;
}
diff --git a/contrib/amd/amd/amd.8 b/contrib/amd/amd/amd.8
index a3967a6..565a550 100644
--- a/contrib/amd/amd/amd.8
+++ b/contrib/amd/amd/amd.8
@@ -1,5 +1,5 @@
.\"
-.\" Copyright (c) 1997-2004 Erez Zadok
+.\" Copyright (c) 1997-2006 Erez Zadok
.\" Copyright (c) 1989 Jan-Simon Pendry
.\" Copyright (c) 1989 Imperial College of Science, Technology & Medicine
.\" Copyright (c) 1989 The Regents of the University of California.
@@ -38,7 +38,7 @@
.\"
.\" %W% (Berkeley) %G%
.\"
-.\" $Id: amd.8,v 1.4.2.5 2004/01/06 03:15:16 ezk Exp $
+.\" $Id: amd.8,v 1.14.2.1 2006/01/02 18:48:23 ezk Exp $
.\"
.TH AMD 8 "3 November 1989"
.SH NAME
@@ -76,6 +76,8 @@ amd \- automatically mount file systems
] [
.BI \-y " YP-domain"
] [
+.BI \-A " arch"
+] [
.BI \-C " cluster-name"
] [
.BI \-D " option"
@@ -244,6 +246,11 @@ The default is the system domain name. This option is ignored if NIS
support is not available.
.TP
+.BI \-A " arch"
+Specifies the OS architecture. This is used solely to set the ${arch}
+selector.
+
+.TP
.BI \-C " cluster-name"
Specify an alternative HP-UX cluster name to use.
@@ -310,14 +317,12 @@ Map entries that are tagged with a tag other than
will not be processed.
.SH FILES
-.PD 0
.TP 5
.B /a
directory under which filesystems are dynamically mounted
.TP 5
.B /etc/amd.conf
default configuration file
-.PD
.SH CAVEATS
Some care may be required when creating a mount map.
.LP
@@ -345,12 +350,21 @@ the features.
.BR mtab (5),
.BR syslog (3).
.LP
+``am-utils''
+.BR info (1)
+entry.
+.LP
+.I "Linux NFS and Automounter Administration"
+by Erez Zadok, ISBN 0-7821-2739-8, (Sybex, 2001).
+.LP
+.I http://www.am-utils.org
+.LP
.I "Amd \- The 4.4 BSD Automounter"
.SH AUTHORS
Jan-Simon Pendry <jsp@doc.ic.ac.uk>, Department of Computing, Imperial College, London, UK.
.P
-Erez Zadok <ezk@cs.columbia.edu>, Department of Computer Science, Columbia
-University, New York, USA.
+Erez Zadok <ezk@cs.sunysb.edu>, Computer Science Department, Stony Brook
+University, Stony Brook, New York, USA.
.P
Other authors and contributors to am-utils are listed in the
.B AUTHORS
diff --git a/contrib/amd/amd/amd.c b/contrib/amd/amd/amd.c
index e2631ae..37eab5d 100644
--- a/contrib/amd/amd/amd.c
+++ b/contrib/amd/amd/amd.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1989 Jan-Simon Pendry
* Copyright (c) 1989 Imperial College of Science, Technology & Medicine
* Copyright (c) 1989 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: amd.c,v 1.8.2.6 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/amd.c
*
*/
@@ -54,9 +53,10 @@
struct amu_global_options gopt; /* where global options are stored */
-char pid_fsname[16 + MAXHOSTNAMELEN]; /* "kiska.southseas.nz:(pid%d)" */
+char pid_fsname[SIZEOF_PID_FSNAME]; /* "kiska.southseas.nz:(pid%d)" */
char *hostdomain = "unknown.domain";
-char hostd[2 * MAXHOSTNAMELEN + 1]; /* Host+domain */
+#define SIZEOF_HOSTD (2 * MAXHOSTNAMELEN + 1) /* Host+domain */
+char hostd[SIZEOF_HOSTD]; /* Host+domain */
char *endian = ARCH_ENDIAN; /* Big or Little endian */
char *cpu = HOST_CPU; /* CPU type */
char *PrimNetName; /* name of primary network */
@@ -71,6 +71,10 @@ struct amd_stats amd_stats; /* Server statistics */
struct in_addr myipaddr; /* (An) IP address of this host */
time_t do_mapc_reload = 0; /* mapc_reload() call required? */
+#ifdef HAVE_FS_AUTOFS
+int amd_use_autofs = 0;
+#endif /* HAVE_FS_AUTOFS */
+
#ifdef HAVE_SIGACTION
sigset_t masked_sigs;
#endif /* HAVE_SIGACTION */
@@ -118,10 +122,8 @@ sighup(int sig)
signal(sig, sighup);
#endif /* REINSTALL_SIGNAL_HANDLER */
-#ifdef DEBUG
if (sig != SIGHUP)
dlog("spurious call to sighup");
-#endif /* DEBUG */
/*
* Force a reload by zero'ing the timer
*/
@@ -133,7 +135,26 @@ sighup(int sig)
static RETSIGTYPE
parent_exit(int sig)
{
- exit(0);
+ /*
+ * This signal handler is called during Amd initialization. The parent
+ * forks a child to do all the hard automounting work, and waits for a
+ * SIGQUIT signal from the child. When the parent gets the signal it's
+ * supposed to call this handler and exit(3), thus completing the
+ * daemonizing process. Alas, on some systems, especially Linux 2.4/2.6
+ * with Glibc, exit(3) doesn't always terminate the parent process.
+ * Worse, the parent process now refuses to accept any more SIGQUIT
+ * signals -- they are blocked. What's really annoying is that this
+ * doesn't happen all the time, suggesting a race condition somewhere.
+ * (This happens even if I change the logic to use another signal.) I
+ * traced this to something which exit(3) does in addition to exiting the
+ * process, probably some atexit() stuff or other side-effects related to
+ * signal handling. Either way, since at this stage the parent process
+ * just needs to terminate, I'm simply calling _exit(2). Note also that
+ * the OpenGroup doesn't list exit(3) as a recommended "Base Interface"
+ * but they do list _exit(2) as one. This fix seems to work reliably all
+ * the time. -Erez (2/27/2005)
+ */
+ _exit(0);
}
@@ -145,6 +166,7 @@ daemon_mode(void)
#ifdef HAVE_SIGACTION
struct sigaction sa, osa;
+ memset(&sa, 0, sizeof(sa));
sa.sa_handler = parent_exit;
sa.sa_flags = 0;
sigemptyset(&(sa.sa_mask));
@@ -217,6 +239,7 @@ init_global_options(void)
#if defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME)
static struct utsname un;
#endif /* defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME) */
+ int i;
memset(&gopt, 0, sizeof(struct amu_global_options));
@@ -226,9 +249,15 @@ init_global_options(void)
/* automounter temp dir */
gopt.auto_dir = "/a";
+ /* toplevel attribute cache timeout */
+ gopt.auto_attrcache = 0;
+
/* cluster name */
gopt.cluster = NULL;
+ /* executable map timeout */
+ gopt.exec_map_timeout = AMFS_EXEC_MAP_TIMEOUT;
+
/*
* kernel architecture: this you must get from uname() if possible.
*/
@@ -260,11 +289,11 @@ init_global_options(void)
/* local domain */
gopt.sub_domain = NULL;
- /* NFS retransmit counter */
- gopt.amfs_auto_retrans = -1;
-
- /* NFS retry interval */
- gopt.amfs_auto_timeo = -1;
+ /* reset NFS (and toplvl) retransmit counter and retry interval */
+ for (i=0; i<AMU_TYPE_MAX; ++i) {
+ gopt.amfs_auto_retrans[i] = -1; /* -1 means "never set before" */
+ gopt.amfs_auto_timeo[i] = -1; /* -1 means "never set before" */
+ }
/* cache duration */
gopt.am_timeo = AM_TTL;
@@ -272,11 +301,13 @@ init_global_options(void)
/* dismount interval */
gopt.am_timeo_w = AM_TTL_W;
+ /* map reload intervl */
+ gopt.map_reload_interval = ONE_HOUR;
+
/*
- * various CFM_* flags.
- * by default, only the "plock" option is on (if available).
+ * various CFM_* flags that are on by default.
*/
- gopt.flags = CFM_PROCESS_LOCK;
+ gopt.flags = CFM_DEFAULT_FLAGS;
#ifdef HAVE_MAP_HESIOD
/* Hesiod rhs zone */
@@ -293,6 +324,9 @@ init_global_options(void)
/* LDAP cache */
gopt.ldap_cache_seconds = 0;
gopt.ldap_cache_maxmem = 131072;
+
+ /* LDAP protocol version */
+ gopt.ldap_proto_version = 2;
#endif /* HAVE_MAP_LDAP */
#ifdef HAVE_MAP_NIS
@@ -302,17 +336,58 @@ init_global_options(void)
}
+/*
+ * Lock process text and data segment in memory (after forking the daemon)
+ */
+static void
+do_memory_locking(void)
+{
+#if defined(HAVE_PLOCK) || defined(HAVE_MLOCKALL)
+ int locked_ok = 0;
+#else /* not HAVE_PLOCK and not HAVE_MLOCKALL */
+ plog(XLOG_WARNING, "Process memory locking not supported by the OS");
+#endif /* not HAVE_PLOCK and not HAVE_MLOCKALL */
+#ifdef HAVE_PLOCK
+# ifdef _AIX
+ /*
+ * On AIX you must lower the stack size using ulimit() before calling
+ * plock. Otherwise plock will reserve a lot of memory space based on
+ * your maximum stack size limit. Since it is not easily possible to
+ * tell what should the limit be, I print a warning before calling
+ * plock(). See the manual pages for ulimit(1,3,4) on your AIX system.
+ */
+ plog(XLOG_WARNING, "AIX: may need to lower stack size using ulimit(3) before calling plock");
+# endif /* _AIX */
+ if (!locked_ok && plock(PROCLOCK) != 0)
+ plog(XLOG_WARNING, "Couldn't lock process pages in memory using plock(): %m");
+ else
+ locked_ok = 1;
+#endif /* HAVE_PLOCK */
+#ifdef HAVE_MLOCKALL
+ if (!locked_ok && mlockall(MCL_CURRENT|MCL_FUTURE) != 0)
+ plog(XLOG_WARNING, "Couldn't lock process pages in memory using mlockall(): %m");
+ else
+ locked_ok = 1;
+#endif /* HAVE_MLOCKALL */
+#if defined(HAVE_PLOCK) || defined(HAVE_MLOCKALL)
+ if (locked_ok)
+ plog(XLOG_INFO, "Locked process pages in memory");
+#endif /* HAVE_PLOCK || HAVE_MLOCKALL */
+
+#if defined(HAVE_MADVISE) && defined(MADV_PROTECT)
+ madvise(0, 0, MADV_PROTECT); /* may be redundant of the above worked out */
+#endif /* defined(HAVE_MADVISE) && defined(MADV_PROTECT) */
+}
+
+
int
main(int argc, char *argv[])
{
- char *domdot, *verstr;
+ char *domdot, *verstr, *vertmp;
int ppid = 0;
int error;
char *progname = NULL; /* "amd" */
char hostname[MAXHOSTNAMELEN + 1] = "localhost"; /* Hostname */
-#ifdef HAVE_SIGACTION
- struct sigaction sa;
-#endif /* HAVE_SIGACTION */
/*
* Make sure some built-in assumptions are true before we start
@@ -363,11 +438,6 @@ main(int argc, char *argv[])
going_down(1);
}
-#ifdef DEBUG
- /* initialize debugging flags (Register AMQ, Enter daemon mode) */
- debug_flags = D_AMQ | D_DAEMON;
-#endif /* DEBUG */
-
/*
* Initialize global options structure.
*/
@@ -386,73 +456,31 @@ main(int argc, char *argv[])
*domdot++ = '\0';
hostdomain = domdot;
}
- strcpy(hostd, hostname);
+ xstrlcpy(hostd, hostname, sizeof(hostd));
am_set_hostname(hostname);
/*
- * Trap interrupts for shutdowns.
- */
-#ifdef HAVE_SIGACTION
- sa.sa_handler = sigterm;
- sa.sa_flags = 0;
- sigemptyset(&(sa.sa_mask));
- sigaddset(&(sa.sa_mask), SIGINT);
- sigaddset(&(sa.sa_mask), SIGTERM);
- sigaction(SIGINT, &sa, NULL);
- sigaction(SIGTERM, &sa, NULL);
-#else /* not HAVE_SIGACTION */
- (void) signal(SIGINT, sigterm);
-#endif /* not HAVE_SIGACTION */
-
- /*
- * Trap Terminate so that we can shutdown gracefully (some chance)
- */
-#ifdef HAVE_SIGACTION
- sa.sa_handler = sigterm;
- sa.sa_flags = 0;
- sigemptyset(&(sa.sa_mask));
- sigaddset(&(sa.sa_mask), SIGTERM);
- sigaction(SIGTERM, &sa, NULL);
-#else /* not HAVE_SIGACTION */
- (void) signal(SIGTERM, sigterm);
-#endif /* not HAVE_SIGACTION */
-
- /*
- * Hangups tell us to reload the cache
+ * Setup signal handlers
*/
-#ifdef HAVE_SIGACTION
- sa.sa_handler = sighup;
- sa.sa_flags = 0;
- sigemptyset(&(sa.sa_mask));
- sigaddset(&(sa.sa_mask), SIGHUP);
- sigaction(SIGHUP, &sa, NULL);
-#else /* not HAVE_SIGACTION */
- (void) signal(SIGHUP, sighup);
-#endif /* not HAVE_SIGACTION */
-
+ /* SIGINT: trap interrupts for shutdowns */
+ setup_sighandler(SIGINT, sigterm);
+ /* SIGTERM: trap terminate so we can shutdown cleanly (some chance) */
+ setup_sighandler(SIGTERM, sigterm);
+ /* SIGHUP: hangups tell us to reload the cache */
+ setup_sighandler(SIGHUP, sighup);
/*
- * Trap Death-of-a-child. These allow us to
- * pick up the exit status of backgrounded mounts.
- * See "sched.c".
+ * SIGCHLD: trap Death-of-a-child. These allow us to pick up the exit
+ * status of backgrounded mounts. See "sched.c".
*/
+ setup_sighandler(SIGCHLD, sigchld);
#ifdef HAVE_SIGACTION
- sa.sa_handler = sigchld;
- sa.sa_flags = 0;
- sigemptyset(&(sa.sa_mask));
- sigaddset(&(sa.sa_mask), SIGCHLD);
- sigaction(SIGCHLD, &sa, NULL);
-
- /*
- * construct global "masked_sigs" used in nfs_start.c
- */
+ /* construct global "masked_sigs" used in nfs_start.c */
sigemptyset(&masked_sigs);
+ sigaddset(&masked_sigs, SIGINT);
+ sigaddset(&masked_sigs, SIGTERM);
sigaddset(&masked_sigs, SIGHUP);
sigaddset(&masked_sigs, SIGCHLD);
- sigaddset(&masked_sigs, SIGTERM);
- sigaddset(&masked_sigs, SIGINT);
-#else /* not HAVE_SIGACTION */
- (void) signal(SIGCHLD, sigchld);
-#endif /* not HAVE_SIGACTION */
+#endif /* HAVE_SIGACTION */
/*
* Fix-up any umask problems. Most systems default
@@ -473,18 +501,21 @@ main(int argc, char *argv[])
/*
* Log version information.
*/
- verstr = strtok(get_version_string(), "\n");
+ vertmp = get_version_string();
+ verstr = strtok(vertmp, "\n");
plog(XLOG_INFO, "AM-UTILS VERSION INFORMATION:");
while (verstr) {
plog(XLOG_INFO, "%s", verstr);
verstr = strtok(NULL, "\n");
}
+ XFREE(vertmp);
/*
- * Get our own IP address so that we
- * can mount the automounter.
+ * Get our own IP address so that we can mount the automounter. We pass
+ * localhost_address which could be used as the default localhost
+ * name/address in amu_get_myaddress().
*/
- amu_get_myaddress(&myipaddr);
+ amu_get_myaddress(&myipaddr, gopt.localhost_address);
plog(XLOG_INFO, "My ip addr is %s", inet_ntoa(myipaddr));
/* avoid hanging on other NFS servers if started elsewhere */
@@ -499,29 +530,6 @@ main(int argc, char *argv[])
going_down(1);
}
- /*
- * Lock process text and data segment in memory.
- */
-#ifdef HAVE_PLOCK
- if (gopt.flags & CFM_PROCESS_LOCK) {
-# ifdef _AIX
- /*
- * On AIX you must lower the stack size using ulimit() before calling
- * plock. Otherwise plock will reserve a lot of memory space based on
- * your maximum stack size limit. Since it is not easily possible to
- * tell what should the limit be, I print a warning before calling
- * plock(). See the manual pages for ulimit(1,3,4) on your AIX system.
- */
- plog(XLOG_WARNING, "AIX: may need to lower stack size using ulimit(3) before calling plock");
-# endif /* _AIX */
- if (plock(PROCLOCK) != 0) {
- plog(XLOG_WARNING, "Couldn't lock process text and data segment in memory: %m");
- } else {
- plog(XLOG_INFO, "Locked process text and data segment in memory");
- }
- }
-#endif /* HAVE_PLOCK */
-
#ifdef HAVE_MAP_NIS
/*
* If the domain was specified then bind it here
@@ -534,14 +542,17 @@ main(int argc, char *argv[])
}
#endif /* HAVE_MAP_NIS */
-#ifdef DEBUG
- amuDebug(D_DAEMON)
-#endif /* DEBUG */
+ if (!amuDebug(D_DAEMON))
ppid = daemon_mode();
- sprintf(pid_fsname, "%s:(pid%ld)", am_get_hostname(), (long) am_mypid);
+ /*
+ * Lock process text and data segment in memory.
+ */
+ if (gopt.flags & CFM_PROCESS_LOCK) {
+ do_memory_locking();
+ }
- do_mapc_reload = clocktime() + ONE_HOUR;
+ do_mapc_reload = clocktime(NULL) + gopt.map_reload_interval;
/*
* Register automounter with system.
@@ -549,6 +560,16 @@ main(int argc, char *argv[])
error = mount_automounter(ppid);
if (error && ppid)
kill(ppid, SIGALRM);
+
+#ifdef HAVE_FS_AUTOFS
+ /*
+ * XXX this should be part of going_down(), but I can't move it there
+ * because it would be calling non-library code from the library... ugh
+ */
+ if (amd_use_autofs)
+ destroy_autofs_service();
+#endif /* HAVE_FS_AUTOFS */
+
going_down(error);
abort();
diff --git a/contrib/amd/amd/amd.h b/contrib/amd/amd/amd.h
index e5e4e44..0e371b7 100644
--- a/contrib/amd/amd/amd.h
+++ b/contrib/amd/amd/amd.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: amd.h,v 1.8.2.8 2004/01/21 04:04:58 ib42 Exp $
+ * File: am-utils/amd/amd.h
*
*/
@@ -50,33 +49,160 @@
* MACROS:
*/
+/*
+ * Define a default debug mtab path for systems
+ * that support mtab on file.
+ */
+#ifdef MOUNT_TABLE_ON_FILE
+# define DEBUG_MNTTAB_FILE "/tmp/mnttab"
+#endif /* MOUNT_TABLE_ON_FILE */
+
/* options for amd.conf */
-#define CFM_BROWSABLE_DIRS 0x0001
-#define CFM_MOUNT_TYPE_AUTOFS 0x0002
-#define CFM_SELECTORS_IN_DEFAULTS 0x0004
-#define CFM_NORMALIZE_HOSTNAMES 0x0008
-#define CFM_PROCESS_LOCK 0x0010
-#define CFM_PRINT_PID 0x0020
-#define CFM_RESTART_EXISTING_MOUNTS 0x0040
-#define CFM_SHOW_STATFS_ENTRIES 0x0080
-#define CFM_FULLY_QUALIFIED_HOSTS 0x0100
-#define CFM_BROWSABLE_DIRS_FULL 0x0200 /* allow '/' in readdir() */
-#define CFM_UNMOUNT_ON_EXIT 0x0400 /* when amd finishing */
-#define CFM_NFS_INSECURE_PORT 0x0800
+#define CFM_BROWSABLE_DIRS 0x00000001
+#define CFM_MOUNT_TYPE_AUTOFS 0x00000002 /* use kernel autofs support */
+#define CFM_SELECTORS_IN_DEFAULTS 0x00000004
+#define CFM_NORMALIZE_HOSTNAMES 0x00000008
+#define CFM_PROCESS_LOCK 0x00000010
+#define CFM_PRINT_PID 0x00000020
+#define CFM_RESTART_EXISTING_MOUNTS 0x00000040
+#define CFM_SHOW_STATFS_ENTRIES 0x00000080
+#define CFM_FULLY_QUALIFIED_HOSTS 0x00000100
+#define CFM_BROWSABLE_DIRS_FULL 0x00000200 /* allow '/' in readdir() */
+#define CFM_UNMOUNT_ON_EXIT 0x00000400 /* when amd finishing */
+#define CFM_USE_TCPWRAPPERS 0x00000800
+#define CFM_AUTOFS_USE_LOFS 0x00001000
+#define CFM_NFS_INSECURE_PORT 0x00002000
+#define CFM_DOMAIN_STRIP 0x00004000
+#define CFM_NORMALIZE_SLASHES 0x00008000 /* normalize slashes? */
+#define CFM_FORCED_UNMOUNTS 0x00010000 /* forced unmounts? */
+#define CFM_TRUNCATE_LOG 0x00020000 /* truncate log file? */
+#if 0
+/* XXX: reserved to sync up with am-utils-6.2 */
+#define CFM_SUN_MAP_SYNTAX 0x00040000 /* Sun map syntax? */
+#endif
+#define CFM_NFS_ANY_INTERFACE 0x00080000 /* all interfaces are acceptable */
+
+/* defaults global flags: plock, tcpwrappers, and autofs/lofs */
+#define CFM_DEFAULT_FLAGS (CFM_PROCESS_LOCK|CFM_USE_TCPWRAPPERS|CFM_AUTOFS_USE_LOFS|CFM_DOMAIN_STRIP|CFM_NORMALIZE_SLASHES)
+
+/*
+ * macro definitions for automounter vfs/vnode operations.
+ */
+#define VLOOK_CREATE 0x1
+#define VLOOK_DELETE 0x2
+#define VLOOK_LOOKUP 0x3
+
+/*
+ * macro definitions for automounter vfs capabilities
+ */
+#define FS_DIRECTORY 0x0001 /* This looks like a dir, not a link */
+#define FS_MBACKGROUND 0x0002 /* Should background this mount */
+#define FS_NOTIMEOUT 0x0004 /* Don't bother with timeouts */
+#define FS_MKMNT 0x0008 /* Need to make the mount point */
+#define FS_UBACKGROUND 0x0010 /* Unmount in background */
+#define FS_BACKGROUND (FS_MBACKGROUND|FS_UBACKGROUND)
+#define FS_DISCARD 0x0020 /* Discard immediately on last reference */
+#define FS_AMQINFO 0x0040 /* Amq is interested in this fs type */
+#define FS_AUTOFS 0x0080 /* This filesystem can be an autofs f/s */
+#define FS_DIRECT 0x0100 /* Direct mount */
+#define FS_ON_AUTOFS 0x0200 /* This filesystem can be mounted directly
+ onto an autofs mountpoint */
+
+/*
+ * macros for struct am_node (map of auto-mount points).
+ */
+#define AMF_NOTIMEOUT 0x0001 /* This node never times out */
+#define AMF_ROOT 0x0002 /* This is a root node */
+#define AMF_AUTOFS 0x0004 /* This node is part of an autofs filesystem */
+#define AMF_REMOUNT 0x0008 /* This node needs to be remounted */
+#define AMF_SOFTLOOKUP 0x0010 /* This node returns EIO if server is down */
+
+/*
+ * macros for struct mntfs (list of mounted filesystems)
+ */
+#define MFF_MOUNTED 0x0001 /* Node is mounted */
+#define MFF_MOUNTING 0x0002 /* Mount is in progress */
+#define MFF_UNMOUNTING 0x0004 /* Unmount is in progress */
+#define MFF_RESTART 0x0008 /* Restarted node */
+#define MFF_MKMNT 0x0010 /* Delete this node's am_mount */
+#define MFF_ERROR 0x0020 /* This node failed to mount */
+#define MFF_LOGDOWN 0x0040 /* Logged that this mount is down */
+#define MFF_RSTKEEP 0x0080 /* Don't timeout this filesystem - restarted */
+#define MFF_WANTTIMO 0x0100 /* Need a timeout call when not busy */
+#define MFF_NFSLINK 0x0200 /* nfsl type, and deemed a link */
+#define MFF_IS_AUTOFS 0x0400 /* this filesystem is of type autofs */
+#define MFF_NFS_SCALEDOWN 0x0800 /* the mount failed, retry with v2/UDP */
+#define MFF_ON_AUTOFS 0x1000 /* autofs has a lofs/link to this f/s */
+#define MFF_WEBNFS 0x2000 /* use public filehandle */
+
+/*
+ * macros for struct fserver.
+ */
+#define FSF_VALID 0x0001 /* Valid information available */
+#define FSF_DOWN 0x0002 /* This fileserver is thought to be down */
+#define FSF_ERROR 0x0004 /* Permanent error has occurred */
+#define FSF_WANT 0x0008 /* Want a wakeup call */
+#define FSF_PINGING 0x0010 /* Already doing pings */
+#define FSF_WEBNFS 0x0020 /* Don't try to contact portmapper */
+#define FSF_PING_UNINIT 0x0040 /* ping values have not been initilized */
+#define FSF_FORCE_UNMOUNT 0x0080 /* force umount of this fserver */
+#define FSRV_ERROR(fs) ((fs) && (((fs)->fs_flags & FSF_ERROR) == FSF_ERROR))
+#define FSRV_ISDOWN(fs) ((fs) && (((fs)->fs_flags & (FSF_DOWN|FSF_VALID)) == (FSF_DOWN|FSF_VALID)))
+#define FSRV_ISUP(fs) (!(fs) || (((fs)->fs_flags & (FSF_DOWN|FSF_VALID)) == (FSF_VALID)))
/* some systems (SunOS 4.x) neglect to define the mount null message */
#ifndef MOUNTPROC_NULL
# define MOUNTPROC_NULL ((u_long)(0))
#endif /* not MOUNTPROC_NULL */
+/*
+ * Error to return if remote host is not available.
+ * Try, in order, "host down", "host unreachable", "invalid argument".
+ */
+#ifdef EHOSTDOWN
+# define AM_ERRNO_HOST_DOWN EHOSTDOWN
+#else /* not EHOSTDOWN */
+# ifdef EHOSTUNREACH
+# define AM_ERRNO_HOST_DOWN EHOSTUNREACH
+# else /* not EHOSTUNREACH */
+# define AM_ERRNO_HOST_DOWN EINVAL
+# endif /* not EHOSTUNREACH */
+#endif /* not EHOSTDOWN */
+
/* Hash table size */
#define NKVHASH (1 << 2) /* Power of two */
+/* Max entries to return in one call */
+#define MAX_READDIR_ENTRIES 16
+
+/*
+ * default amfs_auto retrans - 1/10th seconds
+ */
+#define AMFS_AUTO_RETRANS(x) ((ALLOWED_MOUNT_TIME*10+5*gopt.amfs_auto_timeo[(x)])/gopt.amfs_auto_timeo[(x)] * 2)
+
+/*
+ * The following values can be tuned...
+ */
+#define AM_TTL (300) /* Default cache period (5 min) */
+#define AM_TTL_W (120) /* Default unmount interval (2 min) */
+#define AM_PINGER 30 /* NFS ping interval for live systems */
+#define AMFS_AUTO_TIMEO 8 /* Default amfs_auto timeout - .8s */
+#define AMFS_EXEC_MAP_TIMEOUT 10 /* default 10sec exec map timeout */
+
/* interval between forced retries of a mount */
#define RETRY_INTERVAL 2
-#define ereturn(x) { *error_return = x; return 0; }
+#ifndef ROOT_MAP
+# define ROOT_MAP "\"root\""
+#endif /* not ROOT_MAP */
+#define ereturn(x) do { *error_return = x; return 0; } while (0)
+
+#define NEVER (time_t) 0
+
+#if defined(HAVE_TCPD_H) && defined(HAVE_LIBWRAP)
+# define AMD_SERVICE_NAME "amd" /* for tcpwrappers */
+#endif /* defined(HAVE_TCPD_H) && defined(HAVE_LIBWRAP) */
/*
* TYPEDEFS:
@@ -84,6 +210,16 @@
typedef struct cf_map cf_map_t;
typedef struct kv kv;
+typedef struct am_node am_node;
+typedef struct mntfs mntfs;
+typedef struct am_opts am_opts;
+typedef struct am_ops am_ops;
+typedef struct am_stats am_stats;
+typedef struct fserver fserver;
+
+typedef voidp wchan_t;
+typedef voidp opaque_t;
+
/*
* Cache map operations
*/
@@ -93,6 +229,28 @@ typedef int mtime_fn(mnt_map *, char *, time_t *);
typedef int isup_fn(mnt_map *, char *);
typedef int reload_fn(mnt_map *, char *, add_fn *);
typedef int search_fn(mnt_map *, char *, char *, char **, time_t *);
+typedef int task_fun(opaque_t);
+typedef void cb_fun(int, int, opaque_t);
+typedef void fwd_fun(voidp, int, struct sockaddr_in *,
+ struct sockaddr_in *, opaque_t, int);
+typedef int key_fun(char *, opaque_t);
+typedef void callout_fun(opaque_t);
+
+/*
+ * automounter vfs/vnode operations.
+ */
+typedef char *(*vfs_match) (am_opts *);
+typedef int (*vfs_init) (mntfs *);
+typedef int (*vmount_fs) (am_node *, mntfs *);
+typedef int (*vumount_fs) (am_node *, mntfs *);
+typedef am_node *(*vlookup_child) (am_node *, char *, int *, int);
+typedef am_node *(*vmount_child) (am_node *, int *);
+typedef int (*vreaddir) (am_node *, nfscookie, nfsdirlist *, nfsentry *, u_int);
+typedef am_node *(*vreadlink) (am_node *, int *);
+typedef void (*vmounted) (mntfs *);
+typedef void (*vumounted) (mntfs *);
+typedef fserver *(*vffserver) (mntfs *);
+typedef wchan_t (*vget_wchan) (mntfs *);
@@ -104,6 +262,7 @@ typedef int search_fn(mnt_map *, char *, char *, char **, time_t *);
struct amu_global_options {
char *arch; /* name of current architecture */
char *auto_dir; /* automounter temp dir */
+ int auto_attrcache; /* attribute cache timeout for auto dirs */
char *cluster; /* cluster name */
char *karch; /* kernel architecture */
char *logfile; /* amd log file */
@@ -113,16 +272,33 @@ struct amu_global_options {
char *op_sys_vendor; /* name of OS vendor ${vendor} */
char *pid_file; /* PID file */
char *sub_domain; /* local domain */
+ char *localhost_address; /* localhost address (NULL means use 127.0.0.1) */
+ char *map_defaults; /* global map /default options */
char *map_options; /* global map options */
+ int map_reload_interval; /* map reload interval */
char *map_type; /* global map type */
char *search_path; /* search path for maps */
char *mount_type; /* mount type for map */
+ char *debug_mtab_file; /* path for the mtab file during debug mode */
u_int flags; /* various CFM_* flags */
- int amfs_auto_retrans; /* NFS retransmit counter */
- int amfs_auto_timeo; /* NFS retry interval */
+
+#define AMU_TYPE_NONE -1 /* for amfs_auto_{timeo,retrans,toplvl} */
+#define AMU_TYPE_UDP 0 /* for amfs_auto_{timeo,retrans,toplvl} */
+#define AMU_TYPE_TCP 1 /* for amfs_auto_{timeo,retrans,toplvl} */
+ /*
+ * Note: toplvl is only UDP, but we want to separate it from regular
+ * NFS mounts which Amd makes, because the toplvl mount is a localhost
+ * mount for which different timeo/retrans parameters may be desired.
+ */
+#define AMU_TYPE_TOPLVL 2 /* for amfs_auto_{timeo,retrans,toplvl} */
+#define AMU_TYPE_MAX 3 /* for amfs_auto_{timeo,retrans,toplvl} */
+ int amfs_auto_retrans[AMU_TYPE_MAX]; /* NFS retransmit counter */
+ int amfs_auto_timeo[AMU_TYPE_MAX]; /* NFS retry interval */
+
int am_timeo; /* cache duration */
int am_timeo_w; /* dismount interval */
- int portmap_program; /* amd RPC program number */
+ u_long portmap_program; /* amd RPC program number */
+ u_short preferred_amq_port; /* preferred amq service RPC port number (0 means "any") */
#ifdef HAVE_MAP_HESIOD
char *hesiod_base; /* Hesiod rhs */
#endif /* HAVE_MAP_HESIOD */
@@ -131,12 +307,14 @@ struct amu_global_options {
char *ldap_hostports; /* LDAP host ports */
long ldap_cache_seconds; /* LDAP internal cache - keep seconds */
long ldap_cache_maxmem; /* LDAP internal cache - max memory (bytes) */
+ long ldap_proto_version; /* LDAP protocol version */
#endif /* HAVE_MAP_LDAP */
#ifdef HAVE_MAP_NIS
char *nis_domain; /* YP domain name */
#endif /* HAVE_MAP_NIS */
char *nfs_proto; /* NFS protocol (NULL, udp, tcp) */
int nfs_vers; /* NFS version (0, 2, 3, 4) */
+ u_int exec_map_timeout; /* timeout (seconds) for executable maps */
};
/* if you add anything here, update conf.c:reset_cf_map() */
@@ -144,10 +322,12 @@ struct cf_map {
char *cfm_dir; /* /home, /u, /src */
char *cfm_name; /* amd.home, /etc/amd.home ... */
char *cfm_type; /* file, hesiod, ndbm, nis ... */
+ char *cfm_defaults; /* map /defaults options in amd.conf */
char *cfm_opts; /* -cache:=all, etc. */
char *cfm_search_path; /* /etc/local:/etc/amdmaps:/misc/yp */
char *cfm_tag; /* optional map tag for amd -T */
u_int cfm_flags; /* browsable_dirs? mount_type? */
+ struct cf_map *cfm_next; /* pointer to next in list (if any) */
};
/*
@@ -176,52 +356,173 @@ struct mnt_map {
search_fn *search; /* Function to be used for searching */
mtime_fn *mtime; /* Modify time function */
kv *kvhash[NKVHASH]; /* Cached data */
- /* options available via amd conf file */
- char *cf_map_type; /* file, hesiod, ndbm, nis, etc. */
- char *cf_search_path; /* /etc/local:/etc/amdmaps:/misc/yp */
+ cf_map_t *cfm; /* pointer to per-map amd.conf opts, if any */
void *map_data; /* Map data black box */
};
/*
- * Mounting a file system may take a significant period of time. The
- * problem is that if this is done in the main process thread then the
- * entire automounter could be blocked, possibly hanging lots of processes
- * on the system. Instead we use a continuation scheme to allow mounts to
- * be attempted in a sub-process. When the sub-process exits we pick up the
- * exit status (by convention a UN*X error number) and continue in a
- * notifier. The notifier gets handed a data structure and can then
- * determine whether the mount was successful or not. If not, it updates
- * the data structure and tries again until there are no more ways to try
- * the mount, or some other permanent error occurs. In the mean time no RPC
- * reply is sent, even after the mount is successful. We rely on the RPC
- * retry mechanism to resend the lookup request which can then be handled.
- */
-struct continuation {
- char **ivec; /* Current mount info */
- am_node *mp; /* Node we are trying to mount */
- char *key; /* Map key */
- char *info; /* Info string */
- char **xivec; /* Saved strsplit vector */
- char *auto_opts; /* Automount options */
- am_opts fs_opts; /* Filesystem options */
- char *def_opts; /* Default automount options */
- int retry; /* Try again? */
- int tried; /* Have we tried any yet? */
- time_t start; /* Time we started this mount */
- int callout; /* Callout identifier */
+ * Options
+ */
+struct am_opts {
+ char *fs_glob; /* Smashed copy of global options */
+ char *fs_local; /* Expanded copy of local options */
+ char *fs_mtab; /* Mount table entry */
+ /* Other options ... */
+ char *opt_dev;
+ char *opt_delay;
+ char *opt_dir;
+ char *opt_fs;
+ char *opt_group;
+ char *opt_mount;
+ char *opt_opts;
+ char *opt_remopts;
+ char *opt_pref;
+ char *opt_cache;
+ char *opt_rfs;
+ char *opt_rhost;
+ char *opt_sublink;
+ char *opt_type;
+ char *opt_mount_type; /* "nfs" or "autofs" */
+ char *opt_unmount;
+ char *opt_umount; /* an "alias" for opt_unmount (type:=program) */
+ char *opt_user;
+ char *opt_maptype; /* map type: file, nis, hesiod, etc. */
+ char *opt_cachedir; /* cache directory */
+ char *opt_addopts; /* options to add to opt_opts */
};
+struct am_ops {
+ char *fs_type; /* type of filesystems e.g. "nfsx" */
+ vfs_match fs_match; /* fxn: match */
+ vfs_init fs_init; /* fxn: initialization */
+ vmount_fs mount_fs; /* fxn: mount my own vnode */
+ vumount_fs umount_fs; /* fxn: unmount my own vnode */
+ vlookup_child lookup_child; /* fxn: lookup path-name */
+ vmount_child mount_child; /* fxn: mount path-name */
+ vreaddir readdir; /* fxn: read directory */
+ vreadlink readlink; /* fxn: read link */
+ vmounted mounted; /* fxn: after-mount extra actions */
+ vumounted umounted; /* fxn: after-umount extra actions */
+ vffserver ffserver; /* fxn: find a file server */
+ vget_wchan get_wchan; /* fxn: get the waiting channel */
+ int nfs_fs_flags; /* filesystem flags FS_* for nfs mounts */
+#ifdef HAVE_FS_AUTOFS
+ int autofs_fs_flags;/* filesystem flags FS_* for autofs mounts */
+#endif /* HAVE_FS_AUTOFS */
+};
+
+/*
+ * List of mounted filesystems
+ */
+struct mntfs {
+ qelem mf_q; /* List of mounted filesystems */
+ am_ops *mf_ops; /* Operations on this mountpoint */
+ am_opts *mf_fo; /* File opts */
+ char *mf_mount; /* "/a/kiska/home/kiska" */
+ char *mf_info; /* Mount info */
+ char *mf_auto; /* Automount opts */
+ char *mf_mopts; /* FS mount opts */
+ char *mf_remopts; /* Remote FS mount opts */
+ char *mf_loopdev; /* loop device name for /dev/loop mounts */
+ fserver *mf_server; /* File server */
+ int mf_fsflags; /* Flags FS_* copied from mf_ops->*_fs_flags */
+ int mf_flags; /* Flags MFF_* */
+ int mf_error; /* Error code from background mount */
+ int mf_refc; /* Number of references to this node */
+ int mf_cid; /* Callout id */
+ void (*mf_prfree) (opaque_t); /* Free private space */
+ opaque_t mf_private; /* Private - per-fs data */
+};
+
+/*
+ * List of fileservers
+ */
+struct fserver {
+ qelem fs_q; /* List of fileservers */
+ int fs_refc; /* Number of references to this server */
+ char *fs_host; /* Normalized hostname of server */
+ struct sockaddr_in *fs_ip; /* Network address of server */
+ int fs_cid; /* Callout id */
+ int fs_pinger; /* Ping (keepalive) interval */
+ int fs_flags; /* Flags */
+ char *fs_type; /* File server type */
+ u_long fs_version; /* NFS version of server (2, 3, etc.)*/
+ char *fs_proto; /* NFS protocol of server (tcp, udp, etc.) */
+ opaque_t fs_private; /* Private data */
+ void (*fs_prfree) (opaque_t); /* Free private data */
+};
+
+/*
+ * Per-mountpoint statistics
+ */
+struct am_stats {
+ time_t s_mtime; /* Mount time */
+ u_short s_uid; /* Uid of mounter */
+ int s_getattr; /* Count of getattrs */
+ int s_lookup; /* Count of lookups */
+ int s_readdir; /* Count of readdirs */
+ int s_readlink; /* Count of readlinks */
+ int s_statfs; /* Count of statfs */
+};
+
+/*
+ * System statistics
+ */
+struct amd_stats {
+ int d_drops; /* Dropped requests */
+ int d_stale; /* Stale NFS handles */
+ int d_mok; /* Successful mounts */
+ int d_merr; /* Failed mounts */
+ int d_uerr; /* Failed unmounts */
+};
+extern struct amd_stats amd_stats;
+
+/*
+ * Map of auto-mount points.
+ */
+struct am_node {
+ int am_mapno; /* Map number */
+ mntfs *am_mnt; /* Mounted filesystem */
+ mntfs **am_mfarray; /* Filesystem sources to try to mount */
+ char *am_name; /* "kiska": name of this node */
+ char *am_path; /* "/home/kiska": path of this node's mount point */
+ char *am_link; /* "/a/kiska/home/kiska/this/that": link to sub-dir */
+ am_node *am_parent; /* Parent of this node */
+ am_node *am_ysib; /* Younger sibling of this node */
+ am_node *am_osib; /* Older sibling of this node */
+ am_node *am_child; /* First child of this node */
+ nfsattrstat am_attr; /* File attributes */
+#define am_fattr am_attr.ns_u.ns_attr_u
+ int am_flags; /* Boolean flags AMF_* */
+ int am_error; /* Specific mount error */
+ time_t am_ttl; /* Time to live */
+ int am_timeo_w; /* Dismount wait interval */
+ int am_timeo; /* Cache timeout interval */
+ u_int am_gen; /* Generation number */
+ char *am_pref; /* Mount info prefix */
+ am_stats am_stats; /* Statistics gathering */
+ SVCXPRT *am_transp; /* Info for quick reply */
+ dev_t am_dev; /* Device number */
+ dev_t am_rdev; /* Remote/real device number */
+#ifdef HAVE_FS_AUTOFS
+ autofs_fh_t *am_autofs_fh;
+ time_t am_autofs_ttl; /* Time to expire autofs nodes */
+#endif /* HAVE_FS_AUTOFS */
+};
/*
* EXTERNALS:
*/
-/* Amq server global functions */
+/*
+ * Amq server global functions
+ */
extern amq_mount_info_list *amqproc_getmntfs_1_svc(voidp argp, struct svc_req *rqstp);
extern amq_mount_stats *amqproc_stats_1_svc(voidp argp, struct svc_req *rqstp);
extern amq_mount_tree_list *amqproc_export_1_svc(voidp argp, struct svc_req *rqstp);
extern amq_mount_tree_p *amqproc_mnttree_1_svc(voidp argp, struct svc_req *rqstp);
extern amq_string *amqproc_getvers_1_svc(voidp argp, struct svc_req *rqstp);
+extern amq_string *amqproc_pawd_1_svc(voidp argp, struct svc_req *rqstp);
extern int *amqproc_getpid_1_svc(voidp argp, struct svc_req *rqstp);
extern int *amqproc_mount_1_svc(voidp argp, struct svc_req *rqstp);
extern int *amqproc_setopt_1_svc(voidp argp, struct svc_req *rqstp);
@@ -229,44 +530,134 @@ extern voidp amqproc_null_1_svc(voidp argp, struct svc_req *rqstp);
extern voidp amqproc_umnt_1_svc(voidp argp, struct svc_req *rqstp);
/* other external definitions */
-extern am_nfs_fh *root_fh(char *dir);
+extern am_nfs_fh *get_root_nfs_fh(char *dir);
extern am_node *find_ap(char *);
-extern am_node *find_ap2(char *, am_node *);
+extern am_node *get_ap_child(am_node *, char *);
extern bool_t xdr_amq_mount_info_qelem(XDR *xdrs, qelem *qhead);
extern fserver *find_nfs_srvr(mntfs *mf);
-extern int auto_fmount(am_node *mp);
-extern int auto_fumount(am_node *mp);
-extern int mount_nfs_fh(am_nfs_handle_t *fhp, char *dir, char *fs_name, char *opts, mntfs *mf);
-extern int process_last_regular_map(void);
+extern int mount_nfs_fh(am_nfs_handle_t *fhp, char *mntdir, char *fs_name, mntfs *mf);
+extern int process_all_regular_maps(void);
+extern cf_map_t *find_cf_map(const char *name);
extern int set_conf_kv(const char *section, const char *k, const char *v);
-extern int try_mount(voidp mvp);
+extern int mount_node(opaque_t arg);
+extern int unmount_mp(am_node *mp);
extern int yyparse (void);
-extern nfsentry *make_entry_chain(am_node *mp, const nfsentry *current_chain, int fully_browsable);
-extern void amfs_auto_cont(int rc, int term, voidp closure);
-extern void amfs_auto_mkcacheref(mntfs *mf);
-extern void amfs_auto_retry(int rc, int term, voidp closure);
+
+extern void amfs_mkcacheref(mntfs *mf);
+extern int amfs_mount(am_node *mp, mntfs *mf, char *opts);
extern void assign_error_mntfs(am_node *mp);
-extern void flush_srvr_nfs_cache(void);
-extern void free_continuation(struct continuation *cp);
-extern void mf_mounted(mntfs *mf);
-extern void quick_reply(am_node *mp, int error);
+extern am_node *next_nonerror_node(am_node *xp);
+extern void flush_srvr_nfs_cache(fserver *fs);
+extern void am_mounted(am_node *);
+extern void mf_mounted(mntfs *mf, bool_t call_free_opts);
+extern void am_unmounted(am_node *);
+extern am_node *get_exported_ap(int index);
+extern am_node *get_first_exported_ap(int *index);
+extern am_node *get_next_exported_ap(int *index);
+extern am_node *path_to_exported_ap(char *path);
+extern am_node *exported_ap_alloc(void);
+extern am_node *find_mf(mntfs *);
+extern am_node *next_map(int *);
+extern am_ops *ops_match(am_opts *, char *, char *, char *, char *, char *);
+extern am_ops *ops_search(char *);
+extern fserver *dup_srvr(fserver *);
+extern void srvrlog(fserver *, char *);
+extern int get_mountd_port(fserver *, u_short *, wchan_t);
+extern void flush_nfs_fhandle_cache(fserver *);
+
+extern mntfs *dup_mntfs(mntfs *);
+extern mntfs *find_mntfs(am_ops *, am_opts *, char *, char *, char *, char *, char *);
+extern mntfs *locate_mntfs(am_ops *, am_opts *, char *, char *, char *, char *, char *);
+extern mntfs *new_mntfs(void);
+extern mntfs *realloc_mntfs(mntfs *, am_ops *, am_opts *, char *, char *, char *, char *, char *);
+extern void flush_mntfs(void);
+extern void free_mntfs(voidp);
+
+
+extern void amq_program_1(struct svc_req *rqstp, SVCXPRT *transp);
+extern int background(void);
+extern void deslashify(char *);
+extern void do_task_notify(void);
+extern int eval_fs_opts(am_opts *, char *, char *, char *, char *, char *);
+extern void forcibly_timeout_mp(am_node *);
+extern void free_map(am_node *);
+extern void free_opts(am_opts *);
+extern void free_srvr(fserver *);
+extern int fwd_init(void);
+extern int fwd_packet(int, char *, int, struct sockaddr_in *, struct sockaddr_in *, opaque_t, fwd_fun *);
+extern void fwd_reply(void);
+extern void get_args(int argc, char *argv[]);
+extern wchan_t get_mntfs_wchan(mntfs *mf);
+extern void host_normalize(char **);
+extern void init_map(am_node *, char *);
+extern void ins_que(qelem *, qelem *);
+extern void insert_am(am_node *, am_node *);
+extern int make_nfs_auth(void);
+extern void make_root_node(void);
+extern void map_flush_srvr(fserver *);
+extern void mapc_add_kv(mnt_map *, char *, char *);
+extern mnt_map *mapc_find(char *, char *, const char *);
+extern void mapc_free(opaque_t);
+extern int mapc_keyiter(mnt_map *, key_fun, opaque_t);
+extern void mapc_reload(void);
+extern int mapc_search(mnt_map *, char *, char **);
+extern void mapc_showtypes(char *buf, size_t l);
+extern int mapc_type_exists(const char *type);
+extern void mk_fattr(nfsfattr *, nfsftype);
+extern int mount_auto_node(char *, opaque_t);
+extern int mount_automounter(int);
+extern int mount_exported(void);
+extern void mp_to_fh(am_node *, am_nfs_fh *);
+extern void new_ttl(am_node *);
+extern void nfs_quick_reply(am_node *mp, int error);
+extern void normalize_slash(char *);
+extern void ops_showamfstypes(char *buf, size_t l);
+extern void ops_showfstypes(char *outbuf, size_t l);
+extern void rem_que(qelem *);
+extern void reschedule_timeout_mp(void);
+extern void restart(void);
+extern void restart_automounter_nodes(void);
+extern int root_keyiter(key_fun *, opaque_t);
extern void root_newmap(const char *, const char *, const char *, const cf_map_t *);
+extern void run_task(task_fun *, opaque_t, cb_fun *, opaque_t);
+extern void sched_task(cb_fun *, opaque_t, wchan_t);
+extern int softclock(void);
+extern int timeout(u_int, void (*fn)(opaque_t), opaque_t);
+extern void timeout_mp(opaque_t);
+extern void untimeout(int);
+extern void umount_exported(void);
+extern int valid_key(char *);
+extern void wakeup(wchan_t);
+extern void wakeup_srvr(fserver *);
+extern void wakeup_task(int, int, wchan_t);
+#define SIZEOF_PID_FSNAME (16 + MAXHOSTNAMELEN)
+extern char pid_fsname[SIZEOF_PID_FSNAME]; /* "kiska.southseas.nz:(pid%d)" */
+#define SIZEOF_HOSTD (2 * MAXHOSTNAMELEN + 1)
+extern char hostd[SIZEOF_HOSTD]; /* Host+domain */
+#define SIZEOF_OPTS 256 /* used for char opts[] and preopts[] */
-/* amd global variables */
+/*
+ * Global variables.
+ */
extern FILE *yyin;
-extern SVCXPRT *nfs_program_2_transp; /* For quick_reply() */
+extern SVCXPRT *current_transp; /* For nfs_quick_reply() */
extern char *conf_tag;
-extern char *opt_gid;
-extern char *opt_uid;
-extern int NumChild;
+#define SIZEOF_UID_STR 12
+#define SIZEOF_GID_STR 12
+extern char *opt_gid, gid_str[SIZEOF_GID_STR];
+extern char *opt_uid, uid_str[SIZEOF_UID_STR];
+extern int NumChildren;
extern int fwd_sock;
extern int select_intr_valid;
+extern int immediate_abort; /* Should close-down unmounts be retried */
extern int usage;
extern int use_conf_file; /* use amd configuration file */
+extern int task_notify_todo; /* Task notifier needs running */
extern jmp_buf select_intr;
extern qelem mfhead;
-extern struct am_opts fs_static; /* copy of the options to play with */
extern struct amu_global_options gopt; /* where global options are stored */
+extern time_t do_mapc_reload; /* Flush & reload mount map cache */
+extern time_t next_softclock; /* Time to call softclock() */
#ifdef HAVE_SIGACTION
extern sigset_t masked_sigs;
@@ -274,16 +665,88 @@ extern sigset_t masked_sigs;
#if defined(HAVE_AMU_FS_LINK) || defined(HAVE_AMU_FS_LINKX)
extern char *amfs_link_match(am_opts *fo);
-extern int amfs_link_fumount(mntfs *mf);
#endif /* defined(HAVE_AMU_FS_LINK) || defined(HAVE_AMU_FS_LINKX) */
-#ifdef HAVE_AMU_FS_NFSL
-extern char *nfs_match(am_opts *fo);
-#endif /* HAVE_AMU_FS_NFSL */
+#ifdef HAVE_FS_AUTOFS
+extern int amd_use_autofs;
+
+extern int autofs_get_fh(am_node *mp);
+extern void autofs_release_fh(am_node *mp);
+extern void autofs_get_mp(am_node *mp);
+extern void autofs_release_mp(am_node *mp);
+extern void autofs_add_fdset(fd_set *readfds);
+extern int autofs_handle_fdset(fd_set *readfds, int nsel);
+extern void autofs_mounted(am_node *mp);
+extern void autofs_mount_succeeded(am_node *mp);
+extern void autofs_mount_failed(am_node *mp);
+extern int autofs_umount_succeeded(am_node *mp);
+extern int autofs_umount_failed(am_node *mp);
+extern int autofs_mount_fs(am_node *mp, mntfs *mf);
+extern int autofs_umount_fs(am_node *mp, mntfs *mf);
+extern void autofs_get_opts(char *opts, size_t l, autofs_fh_t *fh);
+extern int autofs_compute_mount_flags(mntent_t *);
+extern void autofs_timeout_mp(am_node *);
+extern int create_autofs_service(void);
+extern int destroy_autofs_service(void);
+#endif /* HAVE_FS_AUTOFS */
+
+/**************************************************************************/
+/*** Generic file-system types, implemented as part of the native O/S. ***/
+/**************************************************************************/
+
+/*
+ * Loopback File System
+ * Many systems can't support this, and in any case most of the
+ * functionality is available with Symlink FS.
+ */
+#ifdef HAVE_FS_LOFS
+extern am_ops lofs_ops;
+extern int mount_lofs(char *mntdir, char *fs_name, char *opts, int on_autofs);
+#endif /* HAVE_FS_LOFS */
-#if defined(HAVE_FS_NFS3) && !defined(HAVE_XDR_MOUNTRES3)
-extern bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp);
-#endif /* defined(HAVE_FS_NFS3) && !defined(HAVE_XDR_MOUNTRES3) */
+/*
+ * CD-ROM File System (CD-ROM)
+ * (HSFS: High Sierra F/S on some machines)
+ * Many systems can't support this, and in any case most of the
+ * functionality is available with program FS.
+ */
+#ifdef HAVE_FS_CDFS
+extern am_ops cdfs_ops;
+#endif /* HAVE_FS_CDFS */
+
+/*
+ * PC File System (MS-DOS)
+ * Many systems can't support this, and in any case most of the
+ * functionality is available with program FS.
+ */
+#ifdef HAVE_FS_PCFS
+extern am_ops pcfs_ops;
+#endif /* HAVE_FS_PCFS */
+
+/*
+ * Caching File System (Solaris)
+ */
+#ifdef HAVE_FS_CACHEFS
+extern am_ops cachefs_ops;
+#endif /* HAVE_FS_CACHEFS */
+
+/*
+ * Network File System
+ * Good, slow, NFS V.2.
+ */
+#ifdef HAVE_FS_NFS
+extern am_ops nfs_ops; /* NFS */
+extern fserver *find_nfs_srvr (mntfs *);
+extern qelem nfs_srvr_list;
+#endif /* HAVE_FS_NFS */
+
+/*
+ * Un*x File System
+ * Normal local disk file system.
+ */
+#ifdef HAVE_FS_UFS
+extern am_ops ufs_ops; /* Un*x file system */
+#endif /* HAVE_FS_UFS */
/* Unix file system (irix) */
#ifdef HAVE_FS_XFS
@@ -295,4 +758,110 @@ extern am_ops xfs_ops; /* Un*x file system */
extern am_ops efs_ops; /* Un*x file system */
#endif /* HAVE_FS_EFS */
+/**************************************************************************/
+/*** Automounter file-system types, implemented by amd. ***/
+/**************************************************************************/
+
+/*
+ * Root AMD File System
+ */
+extern am_ops amfs_root_ops; /* Root file system */
+
+/*
+ * Generic amfs helper methods
+ */
+extern am_node *amfs_generic_lookup_child(am_node *mp, char *fname, int *error_return, int op);
+extern am_node *amfs_generic_mount_child(am_node *ap, int *error_return);
+extern int amfs_generic_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, u_int count);
+extern int amfs_generic_umount(am_node *mp, mntfs *mf);
+extern void amfs_generic_mounted(mntfs *mf);
+extern char *amfs_generic_match(am_opts *fo);
+extern fserver *amfs_generic_find_srvr(mntfs *);
+
+/*
+ * Automount File System
+ */
+#ifdef HAVE_AMU_FS_AUTO
+extern am_ops amfs_auto_ops; /* Automount file system (this!) */
+#endif /* HAVE_AMU_FS_AUTO */
+
+/*
+ * Toplvl Automount File System
+ */
+#ifdef HAVE_AMU_FS_TOPLVL
+extern am_ops amfs_toplvl_ops; /* Toplvl Automount file system */
+extern int amfs_toplvl_mount(am_node *mp, mntfs *mf);
+extern int amfs_toplvl_umount(am_node *mp, mntfs *mf);
+#endif /* HAVE_AMU_FS_TOPLVL */
+
+/*
+ * Direct Automount File System
+ */
+#ifdef HAVE_AMU_FS_DIRECT
+extern am_ops amfs_direct_ops; /* Direct Automount file system (this too) */
+#endif /* HAVE_AMU_FS_DIRECT */
+
+/*
+ * Error File System
+ */
+#ifdef HAVE_AMU_FS_ERROR
+extern am_ops amfs_error_ops; /* Error file system */
+extern am_node *amfs_error_lookup_child(am_node *mp, char *fname, int *error_return, int op);
+extern am_node *amfs_error_mount_child(am_node *ap, int *error_return);
+extern int amfs_error_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, u_int count);
+#endif /* HAVE_AMU_FS_ERROR */
+
+/*
+ * NFS mounts with local existence check.
+ */
+#ifdef HAVE_AMU_FS_NFSL
+extern am_ops amfs_nfsl_ops; /* NFSL */
+#endif /* HAVE_AMU_FS_NFSL */
+
+/*
+ * Multi-nfs mounts.
+ */
+#ifdef HAVE_AMU_FS_NFSX
+extern am_ops amfs_nfsx_ops; /* NFSX */
+#endif /* HAVE_AMU_FS_NFSX */
+
+/*
+ * NFS host - a whole tree.
+ */
+#ifdef HAVE_AMU_FS_HOST
+extern am_ops amfs_host_ops; /* NFS host */
+#endif /* HAVE_AMU_FS_HOST */
+
+/*
+ * Program File System
+ * This is useful for things like RVD.
+ */
+#ifdef HAVE_AMU_FS_PROGRAM
+extern am_ops amfs_program_ops; /* Program File System */
+#endif /* HAVE_AMU_FS_PROGRAM */
+
+/*
+ * Symbolic-link file system.
+ * A "filesystem" which is just a symbol link.
+ */
+#ifdef HAVE_AMU_FS_LINK
+extern am_ops amfs_link_ops; /* Symlink FS */
+#endif /* HAVE_AMU_FS_LINK */
+
+/*
+ * Symbolic-link file system, which also checks that the target of
+ * the symlink exists.
+ * A "filesystem" which is just a symbol link.
+ */
+#ifdef HAVE_AMU_FS_LINKX
+extern am_ops amfs_linkx_ops; /* Symlink FS with existence check */
+#endif /* HAVE_AMU_FS_LINKX */
+
+/*
+ * Union file system
+ */
+#ifdef HAVE_AMU_FS_UNION
+extern am_ops amfs_union_ops; /* Union FS */
+#endif /* HAVE_AMU_FS_UNION */
+
#endif /* not _AMD_H */
diff --git a/contrib/amd/amd/amfs_auto.c b/contrib/amd/amd/amfs_auto.c
index ad05393..75a451f 100644
--- a/contrib/amd/amd/amfs_auto.c
+++ b/contrib/amd/amd/amfs_auto.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: amfs_auto.c,v 1.9.2.12 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/amfs_auto.c
*
*/
@@ -55,9 +54,7 @@
/****************************************************************************
*** MACROS ***
****************************************************************************/
-#define IN_PROGRESS(cp) ((cp)->mp->am_mnt->mf_flags & MFF_MOUNTING)
-#define DOT_DOT_COOKIE (u_int) 1
/****************************************************************************
*** STRUCTURES ***
@@ -67,10 +64,7 @@
/****************************************************************************
*** FORWARD DEFINITIONS ***
****************************************************************************/
-static int amfs_auto_bgmount(struct continuation *cp, int mpe);
-static int amfs_auto_mount(am_node *mp);
-static int amfs_auto_readdir_browsable(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, int count, int fully_browsable);
-static void amfs_auto_umounted(am_node *mp);
+static int amfs_auto_mount(am_node *mp, mntfs *mf);
/****************************************************************************
@@ -79,19 +73,22 @@ static void amfs_auto_umounted(am_node *mp);
am_ops amfs_auto_ops =
{
"auto",
- amfs_auto_match,
+ amfs_generic_match,
0, /* amfs_auto_init */
amfs_auto_mount,
- 0,
- amfs_auto_umount,
- 0,
- amfs_auto_lookuppn,
- amfs_auto_readdir,
+ amfs_generic_umount,
+ amfs_generic_lookup_child,
+ amfs_generic_mount_child,
+ amfs_generic_readdir,
0, /* amfs_auto_readlink */
- 0, /* amfs_auto_mounted */
- amfs_auto_umounted,
- find_amfs_auto_srvr,
- FS_AMQINFO | FS_DIRECTORY
+ amfs_generic_mounted,
+ 0, /* amfs_auto_umounted */
+ amfs_generic_find_srvr,
+ 0, /* amfs_auto_get_wchan */
+ FS_AMQINFO | FS_DIRECTORY,
+#ifdef HAVE_FS_AUTOFS
+ AUTOFS_AUTO_FS_FLAGS,
+#endif /* HAVE_FS_AUTOFS */
};
@@ -99,65 +96,11 @@ am_ops amfs_auto_ops =
*** FUNCTIONS ***
****************************************************************************/
/*
- * AMFS_AUTO needs nothing in particular.
- */
-char *
-amfs_auto_match(am_opts *fo)
-{
- char *p = fo->opt_rfs;
-
- if (!fo->opt_rfs) {
- plog(XLOG_USER, "auto: no mount point named (rfs:=)");
- return 0;
- }
- if (!fo->opt_fs) {
- plog(XLOG_USER, "auto: no map named (fs:=)");
- return 0;
- }
-
- /*
- * Swap round fs:= and rfs:= options
- * ... historical (jsp)
- */
- fo->opt_rfs = fo->opt_fs;
- fo->opt_fs = p;
-
- /*
- * mtab entry turns out to be the name of the mount map
- */
- return strdup(fo->opt_rfs ? fo->opt_rfs : ".");
-}
-
-
-
-
-/*
- * Build a new map cache for this node, or re-use
- * an existing cache for the same map.
- */
-void
-amfs_auto_mkcacheref(mntfs *mf)
-{
- char *cache;
-
- if (mf->mf_fo && mf->mf_fo->opt_cache)
- cache = mf->mf_fo->opt_cache;
- else
- cache = "none";
- mf->mf_private = (voidp) mapc_find(mf->mf_info, cache,
- mf->mf_fo->opt_maptype);
- mf->mf_prfree = mapc_free;
-}
-
-
-/*
* Mount a sub-mount
*/
static int
-amfs_auto_mount(am_node *mp)
+amfs_auto_mount(am_node *mp, mntfs *mf)
{
- mntfs *mf = mp->am_mnt;
-
/*
* Pseudo-directories are used to provide some structure
* to the automounted directories instead
@@ -207,1432 +150,27 @@ amfs_auto_mount(am_node *mp)
mp->am_pref = str3cat((char *) 0, ppref, mp->am_name, "/");
}
- /*
- * Attach a map cache
- */
- amfs_auto_mkcacheref(mf);
-
- return 0;
-}
-
-
-
-
-/*
- * Unmount an automount sub-node
- */
-int
-amfs_auto_umount(am_node *mp)
-{
- return 0;
-}
-
-
-/*
- * Unmount an automount node
- */
-static void
-amfs_auto_umounted(am_node *mp)
-{
- /*
- * If this is a pseudo-directory then just adjust the link count
- * in the parent, otherwise call the generic unmount routine
- */
- if (mp->am_parent && mp->am_parent->am_parent)
- --mp->am_parent->am_fattr.na_nlink;
-}
-
-
-/*
- * Discard an old continuation
- */
-void
-free_continuation(struct continuation *cp)
-{
- if (cp->callout)
- untimeout(cp->callout);
- XFREE(cp->key);
- XFREE(cp->xivec);
- XFREE(cp->info);
- XFREE(cp->auto_opts);
- XFREE(cp->def_opts);
- free_opts(&cp->fs_opts);
- XFREE(cp);
-}
+#ifdef HAVE_FS_AUTOFS
+ if (mf->mf_flags & MFF_IS_AUTOFS) {
+ char opts[SIZEOF_OPTS];
+ int error;
+ autofs_get_opts(opts, sizeof(opts), mp->am_autofs_fh);
-/*
- * Discard the underlying mount point and replace
- * with a reference to an error filesystem.
- */
-void
-assign_error_mntfs(am_node *mp)
-{
- if (mp->am_error > 0) {
- /*
- * Save the old error code
- */
- int error = mp->am_error;
- if (error <= 0)
- error = mp->am_mnt->mf_error;
- /*
- * Discard the old filesystem
- */
- free_mntfs(mp->am_mnt);
- /*
- * Allocate a new error reference
- */
- mp->am_mnt = new_mntfs();
- /*
- * Put back the error code
- */
- mp->am_mnt->mf_error = error;
- mp->am_mnt->mf_flags |= MFF_ERROR;
- /*
- * Zero the error in the mount point
- */
- mp->am_error = 0;
- }
-}
-
-
-/*
- * The continuation function. This is called by
- * the task notifier when a background mount attempt
- * completes.
- */
-void
-amfs_auto_cont(int rc, int term, voidp closure)
-{
- struct continuation *cp = (struct continuation *) closure;
- mntfs *mf = cp->mp->am_mnt;
-
- /*
- * Definitely not trying to mount at the moment
- */
- mf->mf_flags &= ~MFF_MOUNTING;
-
- /*
- * While we are mounting - try to avoid race conditions
- */
- new_ttl(cp->mp);
-
- /*
- * Wakeup anything waiting for this mount
- */
- wakeup((voidp) mf);
-
- /*
- * Check for termination signal or exit status...
- */
- if (rc || term) {
- am_node *xmp;
-
- if (term) {
- /*
- * Not sure what to do for an error code.
- */
- mf->mf_error = EIO; /* XXX ? */
- mf->mf_flags |= MFF_ERROR;
- plog(XLOG_ERROR, "mount for %s got signal %d", cp->mp->am_path, term);
- } else {
- /*
- * Check for exit status...
- */
- mf->mf_error = rc;
- mf->mf_flags |= MFF_ERROR;
- errno = rc; /* XXX */
- if (!STREQ(cp->mp->am_mnt->mf_ops->fs_type, "linkx"))
- plog(XLOG_ERROR, "%s: mount (amfs_auto_cont): %m", cp->mp->am_path);
+ /* now do the mount */
+ error = amfs_mount(mp, mf, opts);
+ if (error) {
+ errno = error;
+ plog(XLOG_FATAL, "amfs_auto_mount: amfs_mount failed: %m");
+ return error;
}
-
- /*
- * If we get here then that attempt didn't work, so
- * move the info vector pointer along by one and
- * call the background mount routine again
- */
- amd_stats.d_merr++;
- cp->ivec++;
- xmp = cp->mp;
- (void) amfs_auto_bgmount(cp, 0);
- assign_error_mntfs(xmp);
- } else {
- /*
- * The mount worked.
- */
- am_mounted(cp->mp);
- free_continuation(cp);
- }
-
- reschedule_timeout_mp();
-}
-
-
-/*
- * Retry a mount
- */
-void
-amfs_auto_retry(int rc, int term, voidp closure)
-{
- struct continuation *cp = (struct continuation *) closure;
- int error = 0;
-
-#ifdef DEBUG
- dlog("Commencing retry for mount of %s", cp->mp->am_path);
-#endif /* DEBUG */
-
- new_ttl(cp->mp);
-
- if ((cp->start + ALLOWED_MOUNT_TIME) < clocktime()) {
- /*
- * The entire mount has timed out. Set the error code and skip past all
- * the info vectors so that amfs_auto_bgmount will not have any more
- * ways to try the mount, so causing an error.
- */
- plog(XLOG_INFO, "mount of \"%s\" has timed out", cp->mp->am_path);
- error = ETIMEDOUT;
- while (*cp->ivec)
- cp->ivec++;
- /* explicitly forbid further retries after timeout */
- cp->retry = FALSE;
- }
- if (error || !IN_PROGRESS(cp)) {
- (void) amfs_auto_bgmount(cp, error);
- }
- reschedule_timeout_mp();
-}
-
-
-/*
- * Try to mount a file system. Can be called
- * directly or in a sub-process by run_task.
- */
-int
-try_mount(voidp mvp)
-{
- int error = 0;
- am_node *mp = (am_node *) mvp;
- mntfs *mf = mp->am_mnt;
-
- /*
- * If the directory is not yet made and it needs to be made, then make it!
- * This may be run in a background process in which case the flag setting
- * won't be noticed later - but it is set anyway just after run_task is
- * called. It should probably go away totally...
- */
- if (!(mf->mf_flags & MFF_MKMNT) && mf->mf_ops->fs_flags & FS_MKMNT) {
- error = mkdirs(mf->mf_mount, 0555);
- if (!error)
- mf->mf_flags |= MFF_MKMNT;
- }
-
- /*
- * Mount it!
- */
- error = mount_node(mp);
-
-#ifdef DEBUG
- if (error > 0) {
- errno = error;
- dlog("amfs_auto: call to mount_node(%s) failed: %m", mp->am_path);
- }
-#endif /* DEBUG */
-
- return error;
-}
-
-
-/*
- * Pick a file system to try mounting and
- * do that in the background if necessary
- *
-For each location:
- if it is new -defaults then
- extract and process
- continue;
- fi
- if it is a cut then
- if a location has been tried then
- break;
- fi
- continue;
- fi
- parse mount location
- discard previous mount location if required
- find matching mounted filesystem
- if not applicable then
- this_error = No such file or directory
- continue
- fi
- if the filesystem failed to be mounted then
- this_error = error from filesystem
- elif the filesystem is mounting or unmounting then
- this_error = -1
- elif the fileserver is down then
- this_error = -1
- elif the filesystem is already mounted
- this_error = 0
- break
- fi
- if no error on this mount then
- this_error = initialize mount point
- fi
- if no error on this mount and mount is delayed then
- this_error = -1
- fi
- if this_error < 0 then
- retry = true
- fi
- if no error on this mount then
- make mount point if required
- fi
- if no error on this mount then
- if mount in background then
- run mount in background
- return -1
- else
- this_error = mount in foreground
- fi
- fi
- if an error occurred on this mount then
- update stats
- save error in mount point
- fi
-endfor
- */
-static int
-amfs_auto_bgmount(struct continuation *cp, int mpe)
-{
- mntfs *mf = cp->mp->am_mnt; /* Current mntfs */
- mntfs *mf_retry = 0; /* First mntfs which needed retrying */
- int this_error = -1; /* Per-mount error */
- int hard_error = -1;
- int mp_error = mpe;
-
- /*
- * Try to mount each location.
- * At the end:
- * hard_error == 0 indicates something was mounted.
- * hard_error > 0 indicates everything failed with a hard error
- * hard_error < 0 indicates nothing could be mounted now
- */
- for (; this_error && *cp->ivec; cp->ivec++) {
- am_ops *p;
- am_node *mp = cp->mp;
- char *link_dir;
- int dont_retry;
-
- if (hard_error < 0)
- hard_error = this_error;
-
- this_error = -1;
-
- if (**cp->ivec == '-') {
- /*
- * Pick up new defaults
- */
- if (cp->auto_opts && *cp->auto_opts)
- cp->def_opts = str3cat(cp->def_opts, cp->auto_opts, ";", *cp->ivec + 1);
- else
- cp->def_opts = strealloc(cp->def_opts, *cp->ivec + 1);
-#ifdef DEBUG
- dlog("Setting def_opts to \"%s\"", cp->def_opts);
-#endif /* DEBUG */
- continue;
- }
- /*
- * If a mount has been attempted, and we find
- * a cut then don't try any more locations.
- */
- if (STREQ(*cp->ivec, "/") || STREQ(*cp->ivec, "||")) {
- if (cp->tried) {
-#ifdef DEBUG
- dlog("Cut: not trying any more locations for %s",
- mp->am_path);
-#endif /* DEBUG */
- break;
- }
- continue;
- }
-
- /* match the operators */
- p = ops_match(&cp->fs_opts, *cp->ivec, cp->def_opts, mp->am_path, cp->key, mp->am_parent->am_mnt->mf_info);
-
- /*
- * Find a mounted filesystem for this node.
- */
- mp->am_mnt = mf = realloc_mntfs(mf, p, &cp->fs_opts,
- cp->fs_opts.opt_fs,
- cp->fs_opts.fs_mtab,
- cp->auto_opts,
- cp->fs_opts.opt_opts,
- cp->fs_opts.opt_remopts);
-
- p = mf->mf_ops;
-#ifdef DEBUG
- dlog("Got a hit with %s", p->fs_type);
-#endif /* DEBUG */
-
- /*
- * Note whether this is a real mount attempt
- */
- if (p == &amfs_error_ops) {
- plog(XLOG_MAP, "Map entry %s for %s did not match", *cp->ivec, mp->am_path);
- if (this_error <= 0)
- this_error = ENOENT;
- continue;
- } else {
- if (cp->fs_opts.fs_mtab) {
- plog(XLOG_MAP, "Trying mount of %s on %s fstype %s",
- cp->fs_opts.fs_mtab, mp->am_path, p->fs_type);
- }
- cp->tried = TRUE;
- }
-
- this_error = 0;
- dont_retry = FALSE;
-
- if (mp->am_link) {
- XFREE(mp->am_link);
- mp->am_link = 0;
- }
- link_dir = mf->mf_fo->opt_sublink;
-
- if (link_dir && *link_dir) {
- if (*link_dir == '/') {
- mp->am_link = strdup(link_dir);
- } else {
- /*
- * Try getting fs option from continuation, not mountpoint!
- * Don't try logging the string from mf, since it may be bad!
- */
- if (cp->fs_opts.opt_fs != mf->mf_fo->opt_fs)
- plog(XLOG_ERROR, "use %s instead of 0x%lx",
- cp->fs_opts.opt_fs, (unsigned long) mf->mf_fo->opt_fs);
-
- mp->am_link = str3cat((char *) 0,
- cp->fs_opts.opt_fs, "/", link_dir);
-
- normalize_slash(mp->am_link);
- }
- }
-
- if (mf->mf_error > 0) {
- this_error = mf->mf_error;
- } else if (mf->mf_flags & (MFF_MOUNTING | MFF_UNMOUNTING)) {
- /*
- * Still mounting - retry later
- */
-#ifdef DEBUG
- dlog("Duplicate pending mount fstype %s", p->fs_type);
-#endif /* DEBUG */
- this_error = -1;
- } else if (FSRV_ISDOWN(mf->mf_server)) {
- /*
- * Would just mount from the same place
- * as a hung mount - so give up
- */
-#ifdef DEBUG
- dlog("%s is already hung - giving up", mf->mf_mount);
-#endif /* DEBUG */
- mp_error = EWOULDBLOCK;
- dont_retry = TRUE;
- this_error = -1;
- } else if (mf->mf_flags & MFF_MOUNTED) {
-#ifdef DEBUG
- dlog("duplicate mount of \"%s\" ...", mf->mf_info);
-#endif /* DEBUG */
-
- /*
- * Just call mounted()
- */
- am_mounted(mp);
-
- this_error = 0;
- break;
- }
-
- /*
- * Will usually need to play around with the mount nodes
- * file attribute structure. This must be done here.
- * Try and get things initialized, even if the fileserver
- * is not known to be up. In the common case this will
- * progress things faster.
- */
- if (!this_error) {
- /*
- * Fill in attribute fields.
- */
- if (mf->mf_ops->fs_flags & FS_DIRECTORY)
- mk_fattr(mp, NFDIR);
- else
- mk_fattr(mp, NFLNK);
-
- if (p->fs_init)
- this_error = (*p->fs_init) (mf);
- }
-
- /*
- * Make sure the fileserver is UP before doing any more work
- */
- if (!FSRV_ISUP(mf->mf_server)) {
-#ifdef DEBUG
- dlog("waiting for server %s to become available", mf->mf_server->fs_host);
-#endif /* DEBUG */
- this_error = -1;
- }
-
- if (!this_error && mf->mf_fo->opt_delay) {
- /*
- * If there is a delay timer on the mount
- * then don't try to mount if the timer
- * has not expired.
- */
- int i = atoi(mf->mf_fo->opt_delay);
- if (i > 0 && clocktime() < (cp->start + i)) {
-#ifdef DEBUG
- dlog("Mount of %s delayed by %lds", mf->mf_mount, (long) (i - clocktime() + cp->start));
-#endif /* DEBUG */
- this_error = -1;
- }
- }
-
- if (this_error < 0 && !dont_retry) {
- if (!mf_retry)
- mf_retry = dup_mntfs(mf);
- cp->retry = TRUE;
-#ifdef DEBUG
- dlog("will retry ...\n");
-#endif /* DEBUG */
- break;
- }
-
- if (!this_error) {
- if (p->fs_flags & FS_MBACKGROUND) {
- mf->mf_flags |= MFF_MOUNTING; /* XXX */
-#ifdef DEBUG
- dlog("backgrounding mount of \"%s\"", mf->mf_mount);
-#endif /* DEBUG */
- if (cp->callout) {
- untimeout(cp->callout);
- cp->callout = 0;
- }
-
- /* actually run the task, backgrounding as necessary */
- run_task(try_mount, (voidp) mp, amfs_auto_cont, (voidp) cp);
-
- mf->mf_flags |= MFF_MKMNT; /* XXX */
- if (mf_retry)
- free_mntfs(mf_retry);
- return -1;
- } else {
-#ifdef DEBUG
- dlog("foreground mount of \"%s\" ...", mf->mf_info);
-#endif /* DEBUG */
- this_error = try_mount((voidp) mp);
- if (this_error < 0) {
- if (!mf_retry)
- mf_retry = dup_mntfs(mf);
- cp->retry = TRUE;
- }
- }
- }
-
- if (this_error >= 0) {
- if (this_error > 0) {
- amd_stats.d_merr++;
- if (mf != mf_retry) {
- mf->mf_error = this_error;
- mf->mf_flags |= MFF_ERROR;
- }
- }
-
- /*
- * Wakeup anything waiting for this mount
- */
- wakeup((voidp) mf);
- }
- }
-
- if (this_error && cp->retry) {
- free_mntfs(mf);
- mf = cp->mp->am_mnt = mf_retry;
- /*
- * Not retrying again (so far)
- */
- cp->retry = FALSE;
- cp->tried = FALSE;
- /*
- * Start at the beginning.
- * Rewind the location vector and
- * reset the default options.
- */
-#ifdef DEBUG
- dlog("(skipping rewind)\n");
-#endif /* DEBUG */
- /*
- * Arrange that amfs_auto_bgmount is called
- * after anything else happens.
- */
-#ifdef DEBUG
- dlog("Arranging to retry mount of %s", cp->mp->am_path);
-#endif /* DEBUG */
- sched_task(amfs_auto_retry, (voidp) cp, (voidp) mf);
- if (cp->callout)
- untimeout(cp->callout);
- cp->callout = timeout(RETRY_INTERVAL, wakeup, (voidp) mf);
-
- cp->mp->am_ttl = clocktime() + RETRY_INTERVAL;
-
- /*
- * Not done yet - so don't return anything
- */
- return -1;
- }
-
- if (hard_error < 0 || this_error == 0)
- hard_error = this_error;
-
- /*
- * Discard handle on duff filesystem.
- * This should never happen since it
- * should be caught by the case above.
- */
- if (mf_retry) {
- if (hard_error)
- plog(XLOG_ERROR, "discarding a retry mntfs for %s", mf_retry->mf_mount);
- free_mntfs(mf_retry);
}
+#endif /* HAVE_FS_AUTOFS */
/*
- * If we get here, then either the mount succeeded or
- * there is no more mount information available.
- */
- if (hard_error < 0 && mp_error)
- hard_error = cp->mp->am_error = mp_error;
- if (hard_error > 0) {
- /*
- * Set a small(ish) timeout on an error node if
- * the error was not a time out.
- */
- switch (hard_error) {
- case ETIMEDOUT:
- case EWOULDBLOCK:
- cp->mp->am_timeo = 17;
- break;
- default:
- cp->mp->am_timeo = 5;
- break;
- }
- new_ttl(cp->mp);
- }
-
- /*
- * Make sure that the error value in the mntfs has a
- * reasonable value.
- */
- if (mf->mf_error < 0) {
- mf->mf_error = hard_error;
- if (hard_error)
- mf->mf_flags |= MFF_ERROR;
- }
-
- /*
- * In any case we don't need the continuation any more
- */
- free_continuation(cp);
-
- return hard_error;
-}
-
-
-/*
- * Automount interface to RPC lookup routine
- * Find the corresponding entry and return
- * the file handle for it.
- */
-am_node *
-amfs_auto_lookuppn(am_node *mp, char *fname, int *error_return, int op)
-{
- am_node *ap, *new_mp, *ap_hung;
- char *info; /* Mount info - where to get the file system */
- char **ivec, **xivec; /* Split version of info */
- char *auto_opts; /* Automount options */
- int error = 0; /* Error so far */
- char path_name[MAXPATHLEN]; /* General path name buffer */
- char *pfname; /* Path for database lookup */
- struct continuation *cp; /* Continuation structure if need to mount */
- int in_progress = 0; /* # of (un)mount in progress */
- char *dflts;
- mntfs *mf;
-
-#ifdef DEBUG
- dlog("in amfs_auto_lookuppn");
-#endif /* DEBUG */
-
- /*
- * If the server is shutting down
- * then don't return information
- * about the mount point.
- */
- if (amd_state == Finishing) {
-#ifdef DEBUG
- if ((mf = mp->am_mnt) == 0 || mf->mf_ops == &amfs_direct_ops) {
- dlog("%s mount ignored - going down", fname);
- } else {
- dlog("%s/%s mount ignored - going down", mp->am_path, fname);
- }
-#endif /* DEBUG */
- ereturn(ENOENT);
- }
-
- /*
- * Handle special case of "." and ".."
- */
- if (fname[0] == '.') {
- if (fname[1] == '\0')
- return mp; /* "." is the current node */
- if (fname[1] == '.' && fname[2] == '\0') {
- if (mp->am_parent) {
-#ifdef DEBUG
- dlog(".. in %s gives %s", mp->am_path, mp->am_parent->am_path);
-#endif /* DEBUG */
- return mp->am_parent; /* ".." is the parent node */
- }
- ereturn(ESTALE);
- }
- }
-
- /*
- * Check for valid key name.
- * If it is invalid then pretend it doesn't exist.
- */
- if (!valid_key(fname)) {
- plog(XLOG_WARNING, "Key \"%s\" contains a disallowed character", fname);
- ereturn(ENOENT);
- }
-
- /*
- * Expand key name.
- * fname is now a private copy.
- */
- fname = expand_key(fname);
-
- for (ap_hung = 0, ap = mp->am_child; ap; ap = ap->am_osib) {
- /*
- * Otherwise search children of this node
- */
- if (FSTREQ(ap->am_name, fname)) {
- mf = ap->am_mnt;
- if (ap->am_error) {
- error = ap->am_error;
- continue;
- }
- /*
- * If the error code is undefined then it must be
- * in progress.
- */
- if (mf->mf_error < 0)
- goto in_progrss;
-
- /*
- * Check for a hung node
- */
- if (FSRV_ISDOWN(mf->mf_server)) {
-#ifdef DEBUG
- dlog("server hung");
-#endif /* DEBUG */
- error = ap->am_error;
- ap_hung = ap;
- continue;
- }
- /*
- * If there was a previous error with this node
- * then return that error code.
- */
- if (mf->mf_flags & MFF_ERROR) {
- error = mf->mf_error;
- continue;
- }
- if (!(mf->mf_flags & MFF_MOUNTED) || (mf->mf_flags & MFF_UNMOUNTING)) {
- in_progrss:
- /*
- * If the fs is not mounted or it is unmounting then there
- * is a background (un)mount in progress. In this case
- * we just drop the RPC request (return nil) and
- * wait for a retry, by which time the (un)mount may
- * have completed.
- */
-#ifdef DEBUG
- dlog("ignoring mount of %s in %s -- flags (%x) in progress",
- fname, mf->mf_mount, mf->mf_flags);
-#endif /* DEBUG */
- in_progress++;
- continue;
- }
-
- /*
- * Otherwise we have a hit: return the current mount point.
- */
-#ifdef DEBUG
- dlog("matched %s in %s", fname, ap->am_path);
-#endif /* DEBUG */
- XFREE(fname);
- return ap;
- }
- }
-
- if (in_progress) {
-#ifdef DEBUG
- dlog("Waiting while %d mount(s) in progress", in_progress);
-#endif /* DEBUG */
- XFREE(fname);
- ereturn(-1);
- }
-
- /*
- * If an error occurred then return it.
- */
- if (error) {
-#ifdef DEBUG
- errno = error; /* XXX */
- dlog("Returning error: %m");
-#endif /* DEBUG */
- XFREE(fname);
- ereturn(error);
- }
-
- /*
- * If doing a delete then don't create again!
- */
- switch (op) {
- case VLOOK_DELETE:
- ereturn(ENOENT);
-
- case VLOOK_CREATE:
- break;
-
- default:
- plog(XLOG_FATAL, "Unknown op to amfs_auto_lookuppn: 0x%x", op);
- ereturn(EINVAL);
- }
-
- /*
- * If the server is going down then just return,
- * don't try to mount any more file systems
- */
- if ((int) amd_state >= (int) Finishing) {
-#ifdef DEBUG
- dlog("not found - server going down anyway");
-#endif /* DEBUG */
- XFREE(fname);
- ereturn(ENOENT);
- }
-
- /*
- * If we get there then this is a reference to an,
- * as yet, unknown name so we need to search the mount
- * map for it.
- */
- if (mp->am_pref) {
- sprintf(path_name, "%s%s", mp->am_pref, fname);
- pfname = path_name;
- } else {
- pfname = fname;
- }
-
- mf = mp->am_mnt;
-
-#ifdef DEBUG
- dlog("will search map info in %s to find %s", mf->mf_info, pfname);
-#endif /* DEBUG */
- /*
- * Consult the oracle for some mount information.
- * info is malloc'ed and belongs to this routine.
- * It ends up being free'd in free_continuation().
- *
- * Note that this may return -1 indicating that information
- * is not yet available.
- */
- error = mapc_search((mnt_map *) mf->mf_private, pfname, &info);
- if (error) {
- if (error > 0)
- plog(XLOG_MAP, "No map entry for %s", pfname);
- else
- plog(XLOG_MAP, "Waiting on map entry for %s", pfname);
- XFREE(fname);
- ereturn(error);
- }
-#ifdef DEBUG
- dlog("mount info is %s", info);
-#endif /* DEBUG */
-
- /*
- * Split info into an argument vector.
- * The vector is malloc'ed and belongs to
- * this routine. It is free'd in free_continuation()
- */
- xivec = ivec = strsplit(info, ' ', '\"');
-
- /*
- * Default error code...
- */
- if (ap_hung)
- error = EWOULDBLOCK;
- else
- error = ENOENT;
-
- /*
- * Allocate a new map
- */
- new_mp = exported_ap_alloc();
- if (new_mp == 0) {
- XFREE(xivec);
- XFREE(info);
- XFREE(fname);
- ereturn(ENOSPC);
- }
- if (mf->mf_auto)
- auto_opts = mf->mf_auto;
- else
- auto_opts = "";
-
- auto_opts = strdup(auto_opts);
-
-#ifdef DEBUG
- dlog("searching for /defaults entry");
-#endif /* DEBUG */
- if (mapc_search((mnt_map *) mf->mf_private, "/defaults", &dflts) == 0) {
- char *dfl;
- char **rvec;
-#ifdef DEBUG
- dlog("/defaults gave %s", dflts);
-#endif /* DEBUG */
- if (*dflts == '-')
- dfl = dflts + 1;
- else
- dfl = dflts;
-
- /*
- * Chop the defaults up
- */
- rvec = strsplit(dfl, ' ', '\"');
-
- if (gopt.flags & CFM_SELECTORS_IN_DEFAULTS) {
- /*
- * Pick whichever first entry matched the list of selectors.
- * Strip the selectors from the string, and assign to dfl the
- * rest of the string.
- */
- if (rvec) {
- am_opts ap;
- am_ops *pt;
- char **sp = rvec;
- while (*sp) { /* loop until you find something, if any */
- memset((char *) &ap, 0, sizeof(am_opts));
- /*
- * This next routine cause many spurious "expansion of ... is"
- * messages, which are ignored, b/c all we need out of this
- * routine is to match selectors. These spurious messages may
- * be wrong, esp. if they try to expand ${key} b/c it will
- * get expanded to "/defaults"
- */
- pt = ops_match(&ap, *sp, "", mp->am_path, "/defaults",
- mp->am_parent->am_mnt->mf_info);
- free_opts(&ap); /* don't leak */
- if (pt == &amfs_error_ops) {
- plog(XLOG_MAP, "did not match defaults for \"%s\"", *sp);
- } else {
- dfl = strip_selectors(*sp, "/defaults");
- plog(XLOG_MAP, "matched default selectors \"%s\"", dfl);
- break;
- }
- ++sp;
- }
- }
- } else { /* not enable_default_selectors */
- /*
- * Extract first value
- */
- dfl = rvec[0];
- }
-
- /*
- * If there were any values at all...
- */
- if (dfl) {
- /*
- * Log error if there were other values
- */
- if (!(gopt.flags & CFM_SELECTORS_IN_DEFAULTS) && rvec[1]) {
-# ifdef DEBUG
- dlog("/defaults chopped into %s", dfl);
-# endif /* DEBUG */
- plog(XLOG_USER, "More than a single value for /defaults in %s", mf->mf_info);
- }
-
- /*
- * Prepend to existing defaults if they exist,
- * otherwise just use these defaults.
- */
- if (*auto_opts && *dfl) {
- char *nopts = (char *) xmalloc(strlen(auto_opts) + strlen(dfl) + 2);
- sprintf(nopts, "%s;%s", dfl, auto_opts);
- XFREE(auto_opts);
- auto_opts = nopts;
- } else if (*dfl) {
- auto_opts = strealloc(auto_opts, dfl);
- }
- }
- XFREE(dflts);
- /*
- * Don't need info vector any more
- */
- XFREE(rvec);
- }
-
- /*
- * Fill it in
- */
- init_map(new_mp, fname);
-
- /*
- * Put it in the table
- */
- insert_am(new_mp, mp);
-
- /*
- * Fill in some other fields,
- * path and mount point.
- *
- * bugfix: do not prepend old am_path if direct map
- * <wls@astro.umd.edu> William Sebok
- */
- new_mp->am_path = str3cat(new_mp->am_path,
- mf->mf_ops == &amfs_direct_ops ? "" : mp->am_path,
- *fname == '/' ? "" : "/", fname);
-
-#ifdef DEBUG
- dlog("setting path to %s", new_mp->am_path);
-#endif /* DEBUG */
-
- /*
- * Take private copy of pfname
- */
- pfname = strdup(pfname);
-
- /*
- * Construct a continuation
- */
- cp = ALLOC(struct continuation);
- cp->callout = 0;
- cp->mp = new_mp;
- cp->xivec = xivec;
- cp->ivec = ivec;
- cp->info = info;
- cp->key = pfname;
- cp->auto_opts = auto_opts;
- cp->retry = FALSE;
- cp->tried = FALSE;
- cp->start = clocktime();
- cp->def_opts = strdup(auto_opts);
- memset((voidp) &cp->fs_opts, 0, sizeof(cp->fs_opts));
-
- /*
- * Try and mount the file system. If this succeeds immediately (possible
- * for a ufs file system) then return the attributes, otherwise just
- * return an error.
- */
- error = amfs_auto_bgmount(cp, error);
- reschedule_timeout_mp();
- if (!error) {
- XFREE(fname);
- return new_mp;
- }
-
- /*
- * Code for quick reply. If nfs_program_2_transp is set, then
- * its the transp that's been passed down from nfs_program_2().
- * If new_mp->am_transp is not already set, set it by copying in
- * nfs_program_2_transp. Once am_transp is set, quick_reply() can
- * use it to send a reply to the client that requested this mount.
- */
- if (nfs_program_2_transp && !new_mp->am_transp) {
- new_mp->am_transp = (SVCXPRT *) xmalloc(sizeof(SVCXPRT));
- *(new_mp->am_transp) = *nfs_program_2_transp;
- }
- if (error && (new_mp->am_mnt->mf_ops == &amfs_error_ops))
- new_mp->am_error = error;
-
- assign_error_mntfs(new_mp);
-
- XFREE(fname);
-
- ereturn(error);
-}
-
-
-/*
- * Locate next node in sibling list which is mounted
- * and is not an error node.
- */
-am_node *
-next_nonerror_node(am_node *xp)
-{
- mntfs *mf;
-
- /*
- * Bug report (7/12/89) from Rein Tollevik <rein@ifi.uio.no>
- * Fixes a race condition when mounting direct automounts.
- * Also fixes a problem when doing a readdir on a directory
- * containing hung automounts.
- */
- while (xp &&
- (!(mf = xp->am_mnt) || /* No mounted filesystem */
- mf->mf_error != 0 || /* There was a mntfs error */
- xp->am_error != 0 || /* There was a mount error */
- !(mf->mf_flags & MFF_MOUNTED) || /* The fs is not mounted */
- (mf->mf_server->fs_flags & FSF_DOWN)) /* The fs may be down */
- )
- xp = xp->am_osib;
-
- return xp;
-}
-
-
-/*
- * This readdir function which call a special version of it that allows
- * browsing if browsable_dirs=yes was set on the map.
- */
-int
-amfs_auto_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, int count)
-{
- u_int gen = *(u_int *) cookie;
- am_node *xp;
- mntent_t mnt;
-#ifdef DEBUG
- nfsentry *ne;
- static int j;
-#endif /* DEBUG */
-
- dp->dl_eof = FALSE; /* assume readdir not done */
-
- /* check if map is browsable */
- if (mp->am_mnt && mp->am_mnt->mf_mopts) {
- mnt.mnt_opts = mp->am_mnt->mf_mopts;
- if (hasmntopt(&mnt, "fullybrowsable"))
- return amfs_auto_readdir_browsable(mp, cookie, dp, ep, count, TRUE);
- if (hasmntopt(&mnt, "browsable"))
- return amfs_auto_readdir_browsable(mp, cookie, dp, ep, count, FALSE);
- }
-
- /* when gen is 0, we start reading from the beginning of the directory */
- if (gen == 0) {
- /*
- * In the default instance (which is used to start a search) we return
- * "." and "..".
- *
- * This assumes that the count is big enough to allow both "." and ".."
- * to be returned in a single packet. If it isn't (which would be
- * fairly unbelievable) then tough.
- */
-#ifdef DEBUG
- dlog("amfs_auto_readdir: default search");
-#endif /* DEBUG */
- /*
- * Check for enough room. This is extremely approximate but is more
- * than enough space. Really need 2 times:
- * 4byte fileid
- * 4byte cookie
- * 4byte name length
- * 4byte name
- * plus the dirlist structure */
- if (count < (2 * (2 * (sizeof(*ep) + sizeof("..") + 4) + sizeof(*dp))))
- return EINVAL;
-
- xp = next_nonerror_node(mp->am_child);
- dp->dl_entries = ep;
-
- /* construct "." */
- ep[0].ne_fileid = mp->am_gen;
- ep[0].ne_name = ".";
- ep[0].ne_nextentry = &ep[1];
- *(u_int *) ep[0].ne_cookie = 0;
-
- /* construct ".." */
- if (mp->am_parent)
- ep[1].ne_fileid = mp->am_parent->am_gen;
- else
- ep[1].ne_fileid = mp->am_gen;
- ep[1].ne_name = "..";
- ep[1].ne_nextentry = 0;
- *(u_int *) ep[1].ne_cookie = (xp ? xp->am_gen : DOT_DOT_COOKIE);
-
- if (!xp)
- dp->dl_eof = TRUE; /* by default assume readdir done */
-
-#ifdef DEBUG
- amuDebug(D_READDIR)
- for (j=0,ne=ep; ne; ne=ne->ne_nextentry)
- plog(XLOG_DEBUG, "gen1 key %4d \"%s\" fi=%d ck=%d",
- j++, ne->ne_name, ne->ne_fileid, *(u_int *)ne->ne_cookie);
-#endif /* DEBUG */
- return 0;
- }
-#ifdef DEBUG
- dlog("amfs_auto_readdir: real child");
-#endif /* DEBUG */
-
- if (gen == DOT_DOT_COOKIE) {
-#ifdef DEBUG
- dlog("amfs_auto_readdir: End of readdir in %s", mp->am_path);
-#endif /* DEBUG */
- dp->dl_eof = TRUE;
- dp->dl_entries = 0;
-#ifdef DEBUG
- amuDebug(D_READDIR)
- plog(XLOG_DEBUG, "end of readdir eof=TRUE, dl_entries=0\n");
-#endif /* DEBUG */
- return 0;
- }
-
- /* non-browsable directories code */
- xp = mp->am_child;
- while (xp && xp->am_gen != gen)
- xp = xp->am_osib;
-
- if (xp) {
- int nbytes = count / 2; /* conservative */
- int todo = MAX_READDIR_ENTRIES;
-
- dp->dl_entries = ep;
- do {
- am_node *xp_next = next_nonerror_node(xp->am_osib);
-
- if (xp_next) {
- *(u_int *) ep->ne_cookie = xp_next->am_gen;
- } else {
- *(u_int *) ep->ne_cookie = DOT_DOT_COOKIE;
- dp->dl_eof = TRUE;
- }
-
- ep->ne_fileid = xp->am_gen;
- ep->ne_name = xp->am_name;
- nbytes -= sizeof(*ep) + 1;
- if (xp->am_name)
- nbytes -= strlen(xp->am_name);
-
- xp = xp_next;
-
- if (nbytes > 0 && !dp->dl_eof && todo > 1) {
- ep->ne_nextentry = ep + 1;
- ep++;
- --todo;
- } else {
- todo = 0;
- }
- } while (todo > 0);
-
- ep->ne_nextentry = 0;
-
-#ifdef DEBUG
- amuDebug(D_READDIR)
- for (j=0,ne=ep; ne; ne=ne->ne_nextentry)
- plog(XLOG_DEBUG, "gen2 key %4d \"%s\" fi=%d ck=%d",
- j++, ne->ne_name, ne->ne_fileid, *(u_int *)ne->ne_cookie);
-#endif /* DEBUG */
- return 0;
- }
- return ESTALE;
-}
-
-
-/* This one is called only if map is browsable */
-static int
-amfs_auto_readdir_browsable(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, int count, int fully_browsable)
-{
- u_int gen = *(u_int *) cookie;
- int chain_length, i;
- static nfsentry *te, *te_next;
-#ifdef DEBUG
- nfsentry *ne;
- static int j;
-#endif /* DEBUG */
-
- dp->dl_eof = FALSE; /* assume readdir not done */
-
-#ifdef DEBUG
- amuDebug(D_READDIR)
- plog(XLOG_DEBUG, "amfs_auto_readdir_browsable gen=%u, count=%d",
- gen, count);
-#endif /* DEBUG */
-
- if (gen == 0) {
- /*
- * In the default instance (which is used to start a search) we return
- * "." and "..".
- *
- * This assumes that the count is big enough to allow both "." and ".."
- * to be returned in a single packet. If it isn't (which would be
- * fairly unbelievable) then tough.
- */
-#ifdef DEBUG
- dlog("amfs_auto_readdir_browsable: default search");
-#endif /* DEBUG */
- /*
- * Check for enough room. This is extremely approximate but is more
- * than enough space. Really need 2 times:
- * 4byte fileid
- * 4byte cookie
- * 4byte name length
- * 4byte name
- * plus the dirlist structure */
- if (count < (2 * (2 * (sizeof(*ep) + sizeof("..") + 4) + sizeof(*dp))))
- return EINVAL;
-
- /*
- * compute # of entries to send in this chain.
- * heuristics: 128 bytes per entry.
- * This is too much probably, but it seems to work better because
- * of the re-entrant nature of nfs_readdir, and esp. on systems
- * like OpenBSD 2.2.
- */
- chain_length = count / 128;
-
- /* reset static state counters */
- te = te_next = NULL;
-
- dp->dl_entries = ep;
-
- /* construct "." */
- ep[0].ne_fileid = mp->am_gen;
- ep[0].ne_name = ".";
- ep[0].ne_nextentry = &ep[1];
- *(u_int *) ep[0].ne_cookie = 0;
-
- /* construct ".." */
- if (mp->am_parent)
- ep[1].ne_fileid = mp->am_parent->am_gen;
- else
- ep[1].ne_fileid = mp->am_gen;
-
- ep[1].ne_name = "..";
- ep[1].ne_nextentry = 0;
- *(u_int *) ep[1].ne_cookie = DOT_DOT_COOKIE;
-
- /*
- * If map is browsable, call a function make_entry_chain() to construct
- * a linked list of unmounted keys, and return it. Then link the chain
- * to the regular list. Get the chain only once, but return
- * chunks of it each time.
- */
- te = make_entry_chain(mp, dp->dl_entries, fully_browsable);
- if (!te)
- return 0;
-#ifdef DEBUG
- amuDebug(D_READDIR)
- for (j=0,ne=te; ne; ne=ne->ne_nextentry)
- plog(XLOG_DEBUG, "gen1 key %4d \"%s\"", j++, ne->ne_name);
-#endif /* DEBUG */
-
- /* return only "chain_length" entries */
- te_next = te;
- for (i=1; i<chain_length; ++i) {
- te_next = te_next->ne_nextentry;
- if (!te_next)
- break;
- }
- if (te_next) {
- nfsentry *te_saved = te_next->ne_nextentry;
- te_next->ne_nextentry = NULL; /* terminate "te" chain */
- te_next = te_saved; /* save rest of "te" for next iteration */
- dp->dl_eof = FALSE; /* tell readdir there's more */
- } else {
- dp->dl_eof = TRUE; /* tell readdir that's it */
- }
- ep[1].ne_nextentry = te; /* append this chunk of "te" chain */
-#ifdef DEBUG
- amuDebug(D_READDIR) {
- for (j=0,ne=te; ne; ne=ne->ne_nextentry)
- plog(XLOG_DEBUG, "gen2 key %4d \"%s\"", j++, ne->ne_name);
- for (j=0,ne=ep; ne; ne=ne->ne_nextentry)
- plog(XLOG_DEBUG, "gen2+ key %4d \"%s\" fi=%d ck=%d",
- j++, ne->ne_name, ne->ne_fileid, *(u_int *)ne->ne_cookie);
- plog(XLOG_DEBUG, "EOF is %d", dp->dl_eof);
- }
-#endif /* DEBUG_READDIR */
- return 0;
- } /* end of "if (gen == 0)" statement */
-
-#ifdef DEBUG
- dlog("amfs_auto_readdir_browsable: real child");
-#endif /* DEBUG */
-
- if (gen == DOT_DOT_COOKIE) {
-#ifdef DEBUG
- dlog("amfs_auto_readdir_browsable: End of readdir in %s", mp->am_path);
-#endif /* DEBUG */
- dp->dl_eof = TRUE;
- dp->dl_entries = 0;
- return 0;
- }
-
- /*
- * If browsable directories, then continue serving readdir() with another
- * chunk of entries, starting from where we left off (when gen was equal
- * to 0). Once again, assume last chunk served to readdir.
- */
- dp->dl_eof = TRUE;
- dp->dl_entries = ep;
-
- te = te_next; /* reset 'te' from last saved te_next */
- if (!te) { /* another indicator of end of readdir */
- dp->dl_entries = 0;
- return 0;
- }
- /*
- * compute # of entries to send in this chain.
- * heuristics: 128 bytes per entry.
+ * Attach a map cache
*/
- chain_length = count / 128;
+ amfs_mkcacheref(mf);
- /* return only "chain_length" entries */
- for (i=1; i<chain_length; ++i) {
- te_next = te_next->ne_nextentry;
- if (!te_next)
- break;
- }
- if (te_next) {
- nfsentry *te_saved = te_next->ne_nextentry;
- te_next->ne_nextentry = NULL; /* terminate "te" chain */
- te_next = te_saved; /* save rest of "te" for next iteration */
- dp->dl_eof = FALSE; /* tell readdir there's more */
- }
- ep = te; /* send next chunk of "te" chain */
- dp->dl_entries = ep;
-#ifdef DEBUG
- amuDebug(D_READDIR) {
- plog(XLOG_DEBUG, "dl_entries=0x%lx, te_next=0x%lx, dl_eof=%d",
- (long) dp->dl_entries, (long) te_next, dp->dl_eof);
- for (ne=te; ne; ne=ne->ne_nextentry)
- plog(XLOG_DEBUG, "gen3 key %4d \"%s\"", j++, ne->ne_name);
- }
-#endif /* DEBUG */
return 0;
}
-
-
-int
-amfs_auto_fmount(am_node *mp)
-{
- mntfs *mf = mp->am_mnt;
- return (*mf->mf_ops->fmount_fs) (mf);
-}
-
-
-int
-amfs_auto_fumount(am_node *mp)
-{
- mntfs *mf = mp->am_mnt;
- return (*mf->mf_ops->fumount_fs) (mf);
-}
diff --git a/contrib/amd/amd/amfs_direct.c b/contrib/amd/amd/amfs_direct.c
index 2ea0ae6..dbef743 100644
--- a/contrib/amd/amd/amfs_direct.c
+++ b/contrib/amd/amd/amfs_direct.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: amfs_direct.c,v 1.3.2.4 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/amfs_direct.c
*
*/
@@ -63,19 +62,22 @@ static am_node *amfs_direct_readlink(am_node *mp, int *error_return);
am_ops amfs_direct_ops =
{
"direct",
- amfs_auto_match,
+ amfs_generic_match,
0, /* amfs_direct_init */
amfs_toplvl_mount,
- 0,
amfs_toplvl_umount,
- 0,
- amfs_error_lookuppn,
+ amfs_generic_lookup_child,
+ amfs_generic_mount_child,
amfs_error_readdir,
amfs_direct_readlink,
- amfs_toplvl_mounted,
- 0, /* amfs_auto_umounted */
- find_amfs_auto_srvr,
- FS_MKMNT | FS_NOTIMEOUT | FS_BACKGROUND | FS_AMQINFO
+ amfs_generic_mounted,
+ 0, /* amfs_direct_umounted */
+ amfs_generic_find_srvr,
+ 0, /* amfs_direct_get_wchan */
+ FS_DIRECT | FS_MKMNT | FS_NOTIMEOUT | FS_BACKGROUND | FS_AMQINFO,
+#ifdef HAVE_FS_AUTOFS
+ AUTOFS_DIRECT_FS_FLAGS,
+#endif /* HAVE_FS_AUTOFS */
};
@@ -92,8 +94,10 @@ amfs_direct_readlink(am_node *mp, int *error_return)
xp = next_nonerror_node(mp->am_child);
if (!xp) {
if (!mp->am_mnt->mf_private)
- amfs_auto_mkcacheref(mp->am_mnt); /* XXX */
- xp = amfs_auto_lookuppn(mp, mp->am_path + 1, &rc, VLOOK_CREATE);
+ amfs_mkcacheref(mp->am_mnt); /* XXX */
+ xp = amfs_generic_lookup_child(mp, mp->am_path + 1, &rc, VLOOK_CREATE);
+ if (xp && rc < 0)
+ xp = amfs_generic_mount_child(xp, &rc);
}
if (xp) {
new_ttl(xp); /* (7/12/89) from Rein Tollevik */
diff --git a/contrib/amd/amd/amfs_error.c b/contrib/amd/amd/amfs_error.c
index ca62033..51bdaa6 100644
--- a/contrib/amd/amd/amfs_error.c
+++ b/contrib/amd/amd/amfs_error.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1989 Jan-Simon Pendry
* Copyright (c) 1989 Imperial College of Science, Technology & Medicine
* Copyright (c) 1989 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: amfs_error.c,v 1.3.2.5 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/amfs_error.c
*
*/
@@ -57,9 +56,8 @@
#include <amd.h>
static char *amfs_error_match(am_opts *fo);
-static int amfs_error_fmount(mntfs *mf);
-static int amfs_error_fumount(mntfs *mf);
-static void amfs_error_umounted(am_node *mp);
+static int amfs_error_mount(am_node *am, mntfs *mf);
+static int amfs_error_umount(am_node *am, mntfs *mf);
/*
@@ -70,17 +68,20 @@ am_ops amfs_error_ops =
"error",
amfs_error_match,
0, /* amfs_error_init */
- amfs_auto_fmount,
- amfs_error_fmount,
- amfs_auto_fumount,
- amfs_error_fumount,
- amfs_error_lookuppn,
+ amfs_error_mount,
+ amfs_error_umount,
+ amfs_error_lookup_child,
+ amfs_error_mount_child,
amfs_error_readdir,
0, /* amfs_error_readlink */
0, /* amfs_error_mounted */
- amfs_error_umounted,
- find_amfs_auto_srvr,
- FS_DISCARD
+ 0, /* amfs_error_umounted */
+ amfs_generic_find_srvr,
+ 0, /* amfs_error_get_wchan */
+ FS_DISCARD, /* nfs_fs_flags */
+#ifdef HAVE_FS_AUTOFS
+ AUTOFS_ERROR_FS_FLAGS,
+#endif /* HAVE_FS_AUTOFS */
};
@@ -96,14 +97,14 @@ amfs_error_match(am_opts *fo)
static int
-amfs_error_fmount(mntfs *mf)
+amfs_error_mount(am_node *am, mntfs *mf)
{
return ENOENT;
}
static int
-amfs_error_fumount(mntfs *mf)
+amfs_error_umount(am_node *am, mntfs *mf)
{
/*
* Always succeed
@@ -118,7 +119,7 @@ amfs_error_fumount(mntfs *mf)
* If we do then just give an error.
*/
am_node *
-amfs_error_lookuppn(am_node *mp, char *fname, int *error_return, int op)
+amfs_error_lookup_child(am_node *mp, char *fname, int *error_return, int op)
{
*error_return = ESTALE;
return 0;
@@ -126,25 +127,25 @@ amfs_error_lookuppn(am_node *mp, char *fname, int *error_return, int op)
/*
- * EFS interface to RPC readdir() routine.
+ * EFS interface to RPC lookup() routine.
* Should never get here in the automounter.
* If we do then just give an error.
*/
-int
-amfs_error_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, int count)
+am_node *
+amfs_error_mount_child(am_node *ap, int *error_return)
{
- return ESTALE;
+ *error_return = ESTALE;
+ return 0;
}
/*
- * umounted() callback for EFS.
- *
- * This prevents core-dumps on callbacks to error file-systems from
- * nfsx_fumount.
+ * EFS interface to RPC readdir() routine.
+ * Should never get here in the automounter.
+ * If we do then just give an error.
*/
-static void
-amfs_error_umounted(am_node *mp)
+int
+amfs_error_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, u_int count)
{
- /* nothing to do */
+ return ESTALE;
}
diff --git a/contrib/amd/amd/amfs_generic.c b/contrib/amd/amd/amfs_generic.c
new file mode 100644
index 0000000..3e7c365
--- /dev/null
+++ b/contrib/amd/amd/amfs_generic.c
@@ -0,0 +1,1262 @@
+/*
+ * Copyright (c) 1997-2006 Erez Zadok
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgment:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *
+ * File: am-utils/amd/amfs_generic.c
+ *
+ */
+
+/*
+ * generic functions used by amfs filesystems, ripped out of amfs_auto.c.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* HAVE_CONFIG_H */
+#include <am_defs.h>
+#include <amd.h>
+
+
+/****************************************************************************
+ *** MACROS ***
+ ****************************************************************************/
+#define IN_PROGRESS(cp) ((cp)->mp->am_mnt->mf_flags & MFF_MOUNTING)
+
+
+/****************************************************************************
+ *** STRUCTURES ***
+ ****************************************************************************/
+/*
+ * Mounting a file system may take a significant period of time. The
+ * problem is that if this is done in the main process thread then the
+ * entire automounter could be blocked, possibly hanging lots of processes
+ * on the system. Instead we use a continuation scheme to allow mounts to
+ * be attempted in a sub-process. When the sub-process exits we pick up the
+ * exit status (by convention a UN*X error number) and continue in a
+ * notifier. The notifier gets handed a data structure and can then
+ * determine whether the mount was successful or not. If not, it updates
+ * the data structure and tries again until there are no more ways to try
+ * the mount, or some other permanent error occurs. In the mean time no RPC
+ * reply is sent, even after the mount is successful. We rely on the RPC
+ * retry mechanism to resend the lookup request which can then be handled.
+ */
+struct continuation {
+ am_node *mp; /* Node we are trying to mount */
+ int retry; /* Try again? */
+ time_t start; /* Time we started this mount */
+ int callout; /* Callout identifier */
+ mntfs **mf; /* Current mntfs */
+};
+
+
+/****************************************************************************
+ *** FORWARD DEFINITIONS ***
+ ****************************************************************************/
+static am_node *amfs_lookup_node(am_node *mp, char *fname, int *error_return);
+static mntfs *amfs_lookup_one_mntfs(am_node *new_mp, mntfs *mf, char *ivec,
+ char *def_opts, char *pfname);
+static mntfs **amfs_lookup_mntfs(am_node *new_mp, int *error_return);
+static void amfs_cont(int rc, int term, opaque_t arg);
+static void amfs_retry(int rc, int term, opaque_t arg);
+static void free_continuation(struct continuation *cp);
+static int amfs_bgmount(struct continuation *cp);
+static char *amfs_parse_defaults(am_node *mp, mntfs *mf, char *def_opts);
+
+
+/****************************************************************************
+ *** FUNCTIONS ***
+ ****************************************************************************/
+static am_node *
+amfs_lookup_node(am_node *mp, char *fname, int *error_return)
+{
+ am_node *new_mp;
+ int error = 0; /* Error so far */
+ int in_progress = 0; /* # of (un)mount in progress */
+ mntfs *mf;
+ char *expanded_fname = 0;
+
+ dlog("in amfs_lookup_node");
+
+ /*
+ * If the server is shutting down
+ * then don't return information
+ * about the mount point.
+ */
+ if (amd_state == Finishing) {
+ if (mp->am_mnt == 0 || mp->am_mnt->mf_fsflags & FS_DIRECT) {
+ dlog("%s mount ignored - going down", fname);
+ } else {
+ dlog("%s/%s mount ignored - going down", mp->am_path, fname);
+ }
+ ereturn(ENOENT);
+ }
+
+ /*
+ * Handle special case of "." and ".."
+ */
+ if (fname[0] == '.') {
+ if (fname[1] == '\0')
+ return mp; /* "." is the current node */
+ if (fname[1] == '.' && fname[2] == '\0') {
+ if (mp->am_parent) {
+ dlog(".. in %s gives %s", mp->am_path, mp->am_parent->am_path);
+ return mp->am_parent; /* ".." is the parent node */
+ }
+ ereturn(ESTALE);
+ }
+ }
+
+ /*
+ * Check for valid key name.
+ * If it is invalid then pretend it doesn't exist.
+ */
+ if (!valid_key(fname)) {
+ plog(XLOG_WARNING, "Key \"%s\" contains a disallowed character", fname);
+ ereturn(ENOENT);
+ }
+
+ /*
+ * Expand key name.
+ * expanded_fname is now a private copy.
+ */
+ expanded_fname = expand_selectors(fname);
+
+ /*
+ * Search children of this node
+ */
+ for (new_mp = mp->am_child; new_mp; new_mp = new_mp->am_osib) {
+ if (FSTREQ(new_mp->am_name, expanded_fname)) {
+ if (new_mp->am_error) {
+ error = new_mp->am_error;
+ continue;
+ }
+
+ /*
+ * If the error code is undefined then it must be
+ * in progress.
+ */
+ mf = new_mp->am_mnt;
+ if (mf->mf_error < 0)
+ goto in_progrss;
+
+ /*
+ * If there was a previous error with this node
+ * then return that error code.
+ */
+ if (mf->mf_flags & MFF_ERROR) {
+ error = mf->mf_error;
+ continue;
+ }
+ if (!(mf->mf_flags & MFF_MOUNTED) || (mf->mf_flags & MFF_UNMOUNTING)) {
+ in_progrss:
+ /*
+ * If the fs is not mounted or it is unmounting then there
+ * is a background (un)mount in progress. In this case
+ * we just drop the RPC request (return nil) and
+ * wait for a retry, by which time the (un)mount may
+ * have completed.
+ */
+ dlog("ignoring mount of %s in %s -- %smounting in progress, flags %x",
+ expanded_fname, mf->mf_mount,
+ (mf->mf_flags & MFF_UNMOUNTING) ? "un" : "", mf->mf_flags);
+ in_progress++;
+ if (mf->mf_flags & MFF_UNMOUNTING) {
+ dlog("will remount later");
+ new_mp->am_flags |= AMF_REMOUNT;
+ }
+ continue;
+ }
+
+ /*
+ * Otherwise we have a hit: return the current mount point.
+ */
+ dlog("matched %s in %s", expanded_fname, new_mp->am_path);
+ XFREE(expanded_fname);
+ return new_mp;
+ }
+ }
+
+ if (in_progress) {
+ dlog("Waiting while %d mount(s) in progress", in_progress);
+ XFREE(expanded_fname);
+ ereturn(-1);
+ }
+
+ /*
+ * If an error occurred then return it.
+ */
+ if (error) {
+ dlog("Returning error: %s", strerror(error));
+ XFREE(expanded_fname);
+ ereturn(error);
+ }
+
+ /*
+ * If the server is going down then just return,
+ * don't try to mount any more file systems
+ */
+ if ((int) amd_state >= (int) Finishing) {
+ dlog("not found - server going down anyway");
+ ereturn(ENOENT);
+ }
+
+ /*
+ * Allocate a new map
+ */
+ new_mp = get_ap_child(mp, expanded_fname);
+ XFREE(expanded_fname);
+ if (new_mp == 0)
+ ereturn(ENOSPC);
+
+ *error_return = -1;
+ return new_mp;
+}
+
+
+
+static mntfs *
+amfs_lookup_one_mntfs(am_node *new_mp, mntfs *mf, char *ivec,
+ char *def_opts, char *pfname)
+{
+ am_ops *p;
+ am_opts *fs_opts;
+ mntfs *new_mf;
+ char *mp_dir = 0;
+#ifdef HAVE_FS_AUTOFS
+ int on_autofs = 1;
+#endif /* HAVE_FS_AUTOFS */
+
+ /* match the operators */
+ fs_opts = CALLOC(am_opts);
+ p = ops_match(fs_opts, ivec, def_opts, new_mp->am_path,
+ pfname, mf->mf_info);
+#ifdef HAVE_FS_AUTOFS
+ /* XXX: this should be factored out into an autofs-specific function */
+ if (new_mp->am_flags & AMF_AUTOFS) {
+ /* ignore user-provided fs if we're using autofs */
+ if (fs_opts->opt_sublink) {
+ /*
+ * For sublinks we need to use a hack with autofs:
+ * mount the filesystem on the original opt_fs (which is NOT an
+ * autofs mountpoint) and symlink (or lofs-mount) to it from
+ * the autofs mountpoint.
+ */
+ on_autofs = 0;
+ mp_dir = fs_opts->opt_fs;
+ } else {
+ if (p->autofs_fs_flags & FS_ON_AUTOFS) {
+ mp_dir = new_mp->am_path;
+ } else {
+ mp_dir = fs_opts->opt_fs;
+ on_autofs = 0;
+ }
+ }
+ } else
+#endif /* HAVE_FS_AUTOFS */
+ mp_dir = fs_opts->opt_fs;
+
+ /*
+ * Find or allocate a filesystem for this node.
+ */
+ new_mf = find_mntfs(p, fs_opts,
+ mp_dir,
+ fs_opts->fs_mtab,
+ def_opts,
+ fs_opts->opt_opts,
+ fs_opts->opt_remopts);
+
+ /*
+ * See whether this is a real filesystem
+ */
+ p = new_mf->mf_ops;
+ if (p == &amfs_error_ops) {
+ plog(XLOG_MAP, "Map entry %s for %s did not match", ivec, new_mp->am_path);
+ free_mntfs(new_mf);
+ return NULL;
+ }
+
+ dlog("Got a hit with %s", p->fs_type);
+
+#ifdef HAVE_FS_AUTOFS
+ if (new_mp->am_flags & AMF_AUTOFS && on_autofs) {
+ new_mf->mf_flags |= MFF_ON_AUTOFS;
+ new_mf->mf_fsflags = new_mf->mf_ops->autofs_fs_flags;
+ }
+ /*
+ * A new filesystem is an autofs filesystems if:
+ * 1. it claims it can be one (has the FS_AUTOFS flag)
+ * 2. autofs is enabled system-wide
+ * 3. either has an autofs parent,
+ * or it is explicitly requested to be autofs.
+ */
+ if (new_mf->mf_ops->autofs_fs_flags & FS_AUTOFS &&
+ amd_use_autofs &&
+ ((mf->mf_flags & MFF_IS_AUTOFS) ||
+ (new_mf->mf_fo && new_mf->mf_fo->opt_mount_type &&
+ STREQ(new_mf->mf_fo->opt_mount_type, "autofs"))))
+ new_mf->mf_flags |= MFF_IS_AUTOFS;
+#endif /* HAVE_FS_AUTOFS */
+
+ return new_mf;
+}
+
+
+static mntfs **
+amfs_lookup_mntfs(am_node *new_mp, int *error_return)
+{
+ am_node *mp;
+ char *info; /* Mount info - where to get the file system */
+ char **ivecs, **cur_ivec; /* Split version of info */
+ int num_ivecs;
+ char *orig_def_opts; /* Original Automount options */
+ char *def_opts; /* Automount options */
+ int error = 0; /* Error so far */
+ char path_name[MAXPATHLEN]; /* General path name buffer */
+ char *pfname; /* Path for database lookup */
+ mntfs *mf, **mf_array;
+ int count;
+
+ dlog("in amfs_lookup_mntfs");
+
+ mp = new_mp->am_parent;
+
+ /*
+ * If we get here then this is a reference to an,
+ * as yet, unknown name so we need to search the mount
+ * map for it.
+ */
+ if (mp->am_pref) {
+ if (strlen(mp->am_pref) + strlen(new_mp->am_name) >= sizeof(path_name))
+ ereturn(ENAMETOOLONG);
+ xsnprintf(path_name, sizeof(path_name), "%s%s", mp->am_pref, new_mp->am_name);
+ pfname = path_name;
+ } else {
+ pfname = new_mp->am_name;
+ }
+
+ mf = mp->am_mnt;
+
+ dlog("will search map info in %s to find %s", mf->mf_info, pfname);
+ /*
+ * Consult the oracle for some mount information.
+ * info is malloc'ed and belongs to this routine.
+ * It ends up being free'd in free_continuation().
+ *
+ * Note that this may return -1 indicating that information
+ * is not yet available.
+ */
+ error = mapc_search((mnt_map *) mf->mf_private, pfname, &info);
+ if (error) {
+ if (error > 0)
+ plog(XLOG_MAP, "No map entry for %s", pfname);
+ else
+ plog(XLOG_MAP, "Waiting on map entry for %s", pfname);
+ ereturn(error);
+ }
+ dlog("mount info is %s", info);
+
+ /*
+ * Split info into an argument vector.
+ * The vector is malloc'ed and belongs to
+ * this routine. It is free'd further down.
+ *
+ * Note: the vector pointers point into info, so don't free it!
+ */
+ ivecs = strsplit(info, ' ', '\"');
+
+ if (mf->mf_auto)
+ def_opts = mf->mf_auto;
+ else
+ def_opts = "";
+
+ orig_def_opts = amfs_parse_defaults(mp, mf, strdup(def_opts));
+ def_opts = strdup(orig_def_opts);
+
+ /* first build our defaults */
+ num_ivecs = 0;
+ for (cur_ivec = ivecs; *cur_ivec; cur_ivec++) {
+ if (**cur_ivec == '-') {
+ /*
+ * Pick up new defaults
+ */
+ char *new_def_opts = str3cat(NULL, def_opts, ";", *cur_ivec + 1);
+ XFREE(def_opts);
+ def_opts = new_def_opts;
+ dlog("Setting def_opts to \"%s\"", def_opts);
+ continue;
+ } else
+ num_ivecs++;
+ }
+
+ mf_array = calloc(num_ivecs + 1, sizeof(mntfs *));
+
+ /* construct the array of struct mntfs for this mount point */
+ for (count = 0, cur_ivec = ivecs; *cur_ivec; cur_ivec++) {
+ mntfs *new_mf;
+
+ if (**cur_ivec == '-') {
+ XFREE(def_opts);
+ if ((*cur_ivec)[1] == '\0') {
+ /*
+ * If we have a single dash '-' than we need to reset the
+ * default options.
+ */
+ def_opts = strdup(orig_def_opts);
+ dlog("Resetting the default options, a single dash '-' was found.");
+ } else {
+ /* append options to /default options */
+ def_opts = str3cat((char *) 0, orig_def_opts, ";", *cur_ivec + 1);
+ dlog("Resetting def_opts to \"%s\"", def_opts);
+ }
+ continue;
+ }
+
+ /*
+ * If a mntfs has already been found, and we find
+ * a cut then don't try any more locations.
+ *
+ * XXX: we do not know when the "/" was added as an equivalent for "||".
+ * It's undocumented, it might go away at any time. Caveat emptor.
+ */
+ if (STREQ(*cur_ivec, "/") || STREQ(*cur_ivec, "||")) {
+ if (count > 0) {
+ dlog("Cut: not trying any more locations for %s", mp->am_path);
+ break;
+ }
+ continue;
+ }
+
+ new_mf = amfs_lookup_one_mntfs(new_mp, mf, *cur_ivec, def_opts, pfname);
+ if (new_mf == NULL)
+ continue;
+ mf_array[count++] = new_mf;
+ }
+
+ /* We're done with ivecs */
+ XFREE(ivecs);
+ XFREE(info);
+ XFREE(orig_def_opts);
+ XFREE(def_opts);
+ if (count == 0) { /* no match */
+ XFREE(mf_array);
+ ereturn(ENOENT);
+ }
+
+ return mf_array;
+}
+
+
+/*
+ * The continuation function. This is called by
+ * the task notifier when a background mount attempt
+ * completes.
+ */
+static void
+amfs_cont(int rc, int term, opaque_t arg)
+{
+ struct continuation *cp = (struct continuation *) arg;
+ am_node *mp = cp->mp;
+ mntfs *mf = mp->am_mnt;
+
+ dlog("amfs_cont: '%s'", mp->am_path);
+
+ /*
+ * Definitely not trying to mount at the moment
+ */
+ mf->mf_flags &= ~MFF_MOUNTING;
+
+ /*
+ * While we are mounting - try to avoid race conditions
+ */
+ new_ttl(mp);
+
+ /*
+ * Wakeup anything waiting for this mount
+ */
+ wakeup(get_mntfs_wchan(mf));
+
+ /*
+ * Check for termination signal or exit status...
+ */
+ if (rc || term) {
+#ifdef HAVE_FS_AUTOFS
+ if (mf->mf_flags & MFF_IS_AUTOFS &&
+ !(mf->mf_flags & MFF_MOUNTED))
+ autofs_release_fh(mp);
+#endif /* HAVE_FS_AUTOFS */
+
+ if (term) {
+ /*
+ * Not sure what to do for an error code.
+ */
+ mf->mf_error = EIO; /* XXX ? */
+ mf->mf_flags |= MFF_ERROR;
+ plog(XLOG_ERROR, "mount for %s got signal %d", mp->am_path, term);
+ } else {
+ /*
+ * Check for exit status...
+ */
+#ifdef __linux__
+ /*
+ * HACK ALERT!
+ *
+ * On Linux (and maybe not only) it's possible to run
+ * an amd which "knows" how to mount certain combinations
+ * of nfs_proto/nfs_version which the kernel doesn't grok.
+ * So if we got an EINVAL and we have a server that's not
+ * using NFSv2/UDP, try again with NFSv2/UDP.
+ *
+ * Too bad that there is no way to dynamically determine
+ * what combinations the _client_ supports, as opposed to
+ * what the _server_ supports...
+ */
+ if (rc == EINVAL &&
+ mf->mf_server &&
+ (mf->mf_server->fs_version != 2 ||
+ !STREQ(mf->mf_server->fs_proto, "udp")))
+ mf->mf_flags |= MFF_NFS_SCALEDOWN;
+ else
+#endif /* __linux__ */
+ {
+ mf->mf_error = rc;
+ mf->mf_flags |= MFF_ERROR;
+ errno = rc; /* XXX */
+ if (!STREQ(mp->am_mnt->mf_ops->fs_type, "linkx"))
+ plog(XLOG_ERROR, "%s: mount (amfs_cont): %m", mp->am_path);
+ }
+ }
+
+ if (!(mf->mf_flags & MFF_NFS_SCALEDOWN)) {
+ /*
+ * If we get here then that attempt didn't work, so
+ * move the info vector pointer along by one and
+ * call the background mount routine again
+ */
+ amd_stats.d_merr++;
+ cp->mf++;
+ }
+ amfs_bgmount(cp);
+ if (mp->am_error > 0)
+ assign_error_mntfs(mp);
+ } else {
+ /*
+ * The mount worked.
+ */
+ dlog("Mounting %s returned success", cp->mp->am_path);
+ am_mounted(cp->mp);
+ free_continuation(cp);
+ }
+
+ reschedule_timeout_mp();
+}
+
+
+/*
+ * Retry a mount
+ */
+static void
+amfs_retry(int rc, int term, opaque_t arg)
+{
+ struct continuation *cp = (struct continuation *) arg;
+ am_node *mp = cp->mp;
+ int error = 0;
+
+ dlog("Commencing retry for mount of %s", mp->am_path);
+
+ new_ttl(mp);
+
+ if ((cp->start + ALLOWED_MOUNT_TIME) < clocktime(NULL)) {
+ /*
+ * The entire mount has timed out. Set the error code and skip past all
+ * the mntfs's so that amfs_bgmount will not have any more
+ * ways to try the mount, thus causing an error.
+ */
+ plog(XLOG_INFO, "mount of \"%s\" has timed out", mp->am_path);
+ error = ETIMEDOUT;
+ while (*cp->mf)
+ cp->mf++;
+ /* explicitly forbid further retries after timeout */
+ cp->retry = FALSE;
+ }
+ if (error || !IN_PROGRESS(cp))
+ error = amfs_bgmount(cp);
+
+ reschedule_timeout_mp();
+}
+
+
+/*
+ * Discard an old continuation
+ */
+static void
+free_continuation(struct continuation *cp)
+{
+ mntfs **mfp;
+
+ dlog("free_continuation");
+ if (cp->callout)
+ untimeout(cp->callout);
+ /*
+ * we must free the mntfs's in the list.
+ * so free all of them if there was an error,
+ * or free all but the used one, if the mount succeeded.
+ */
+ for (mfp = cp->mp->am_mfarray; *mfp; mfp++) {
+ free_mntfs(*mfp);
+ }
+ XFREE(cp->mp->am_mfarray);
+ cp->mp->am_mfarray = 0;
+ XFREE(cp);
+}
+
+
+/*
+ * Pick a file system to try mounting and
+ * do that in the background if necessary
+ *
+For each location:
+ discard previous mount location if required
+ fetch next mount location
+ if the filesystem failed to be mounted then
+ this_error = error from filesystem
+ goto failed
+ if the filesystem is mounting or unmounting then
+ goto retry;
+ if the fileserver is down then
+ this_error = EIO
+ continue;
+ if the filesystem is already mounted
+ break
+ fi
+
+ this_error = initialize mount point
+
+ if no error on this mount and mount is delayed then
+ this_error = -1
+ fi
+ if this_error < 0 then
+ retry = true
+ fi
+ if no error on this mount then
+ if mount in background then
+ run mount in background
+ return -1
+ else
+ this_error = mount in foreground
+ fi
+ fi
+ if an error occurred on this mount then
+ update stats
+ save error in mount point
+ fi
+endfor
+ */
+static int
+amfs_bgmount(struct continuation *cp)
+{
+ am_node *mp = cp->mp;
+ mntfs *mf; /* Current mntfs */
+ int this_error = -1; /* Per-mount error */
+ int hard_error = -1; /* Cumulative per-node error */
+
+ if (mp->am_mnt)
+ free_mntfs(mp->am_mnt);
+
+ /*
+ * Try to mount each location.
+ * At the end:
+ * hard_error == 0 indicates something was mounted.
+ * hard_error > 0 indicates everything failed with a hard error
+ * hard_error < 0 indicates nothing could be mounted now
+ */
+ for (mp->am_mnt = *cp->mf; *cp->mf; cp->mf++, mp->am_mnt = *cp->mf) {
+ am_ops *p;
+
+ mf = dup_mntfs(mp->am_mnt);
+ p = mf->mf_ops;
+
+ if (hard_error < 0)
+ hard_error = this_error;
+ this_error = 0;
+
+ if (mf->mf_error > 0) {
+ this_error = mf->mf_error;
+ goto failed;
+ }
+
+ if (mf->mf_flags & (MFF_MOUNTING | MFF_UNMOUNTING)) {
+ /*
+ * Still mounting - retry later
+ */
+ dlog("mount of \"%s\" already pending", mf->mf_info);
+ goto retry;
+ }
+
+ if (FSRV_ISDOWN(mf->mf_server)) {
+ /*
+ * Would just mount from the same place
+ * as a hung mount - so give up
+ */
+ dlog("%s is already hung - giving up", mf->mf_server->fs_host);
+ this_error = EIO;
+ goto failed;
+ }
+
+ if (mp->am_link) {
+ XFREE(mp->am_link);
+ mp->am_link = NULL;
+ }
+ if (mf->mf_fo && mf->mf_fo->opt_sublink)
+ mp->am_link = strdup(mf->mf_fo->opt_sublink);
+
+ /*
+ * Will usually need to play around with the mount nodes
+ * file attribute structure. This must be done here.
+ * Try and get things initialized, even if the fileserver
+ * is not known to be up. In the common case this will
+ * progress things faster.
+ */
+
+ /*
+ * Fill in attribute fields.
+ */
+ if (mf->mf_fsflags & FS_DIRECTORY)
+ mk_fattr(&mp->am_fattr, NFDIR);
+ else
+ mk_fattr(&mp->am_fattr, NFLNK);
+
+ if (mf->mf_flags & MFF_MOUNTED) {
+ dlog("duplicate mount of \"%s\" ...", mf->mf_info);
+ /*
+ * Skip initial processing of the mountpoint if already mounted.
+ * This could happen if we have multiple sublinks into the same f/s,
+ * or if we are restarting an already-mounted filesystem.
+ */
+ goto already_mounted;
+ }
+
+ if (mf->mf_fo && mf->mf_fo->fs_mtab) {
+ plog(XLOG_MAP, "Trying mount of %s on %s fstype %s mount_type %s",
+ mf->mf_fo->fs_mtab, mf->mf_mount, p->fs_type,
+ mp->am_flags & AMF_AUTOFS ? "autofs" : "non-autofs");
+ }
+
+ if (p->fs_init && !(mf->mf_flags & MFF_RESTART))
+ this_error = p->fs_init(mf);
+
+ if (this_error > 0)
+ goto failed;
+ if (this_error < 0)
+ goto retry;
+
+ if (mf->mf_fo && mf->mf_fo->opt_delay) {
+ /*
+ * If there is a delay timer on the mount
+ * then don't try to mount if the timer
+ * has not expired.
+ */
+ int i = atoi(mf->mf_fo->opt_delay);
+ time_t now = clocktime(NULL);
+ if (i > 0 && now < (cp->start + i)) {
+ dlog("Mount of %s delayed by %lds", mf->mf_mount, (long) (i - now + cp->start));
+ goto retry;
+ }
+ }
+
+ /*
+ * If the directory is not yet made and it needs to be made, then make it!
+ */
+ if (!(mf->mf_flags & MFF_MKMNT) && mf->mf_fsflags & FS_MKMNT) {
+ plog(XLOG_INFO, "creating mountpoint directory '%s'", mf->mf_mount);
+ this_error = mkdirs(mf->mf_mount, 0555);
+ if (this_error) {
+ plog(XLOG_ERROR, "mkdirs failed: %s", strerror(this_error));
+ goto failed;
+ }
+ mf->mf_flags |= MFF_MKMNT;
+ }
+
+#ifdef HAVE_FS_AUTOFS
+ if (mf->mf_flags & MFF_IS_AUTOFS)
+ if ((this_error = autofs_get_fh(mp)))
+ goto failed;
+#endif /* HAVE_FS_AUTOFS */
+
+ already_mounted:
+ mf->mf_flags |= MFF_MOUNTING;
+ if (mf->mf_fsflags & FS_MBACKGROUND) {
+ dlog("backgrounding mount of \"%s\"", mf->mf_mount);
+ if (cp->callout) {
+ untimeout(cp->callout);
+ cp->callout = 0;
+ }
+
+ /* actually run the task, backgrounding as necessary */
+ run_task(mount_node, (opaque_t) mp, amfs_cont, (opaque_t) cp);
+ return -1;
+ } else {
+ dlog("foreground mount of \"%s\" ...", mf->mf_mount);
+ this_error = mount_node((opaque_t) mp);
+ }
+
+ mf->mf_flags &= ~MFF_MOUNTING;
+ if (this_error > 0)
+ goto failed;
+ if (this_error == 0) {
+ am_mounted(mp);
+ break; /* Success */
+ }
+
+ retry:
+ if (!cp->retry)
+ continue;
+ dlog("will retry ...\n");
+
+ /*
+ * Arrange that amfs_bgmount is called
+ * after anything else happens.
+ */
+ dlog("Arranging to retry mount of %s", mp->am_path);
+ sched_task(amfs_retry, (opaque_t) cp, get_mntfs_wchan(mf));
+ if (cp->callout)
+ untimeout(cp->callout);
+ cp->callout = timeout(RETRY_INTERVAL, wakeup,
+ (opaque_t) get_mntfs_wchan(mf));
+
+ mp->am_ttl = clocktime(NULL) + RETRY_INTERVAL;
+
+ /*
+ * Not done yet - so don't return anything
+ */
+ return -1;
+
+ failed:
+ amd_stats.d_merr++;
+ mf->mf_error = this_error;
+ mf->mf_flags |= MFF_ERROR;
+#ifdef HAVE_FS_AUTOFS
+ if (mp->am_autofs_fh)
+ autofs_release_fh(mp);
+#endif /* HAVE_FS_AUTOFS */
+ if (mf->mf_flags & MFF_MKMNT) {
+ rmdirs(mf->mf_mount);
+ mf->mf_flags &= ~MFF_MKMNT;
+ }
+ /*
+ * Wakeup anything waiting for this mount
+ */
+ wakeup(get_mntfs_wchan(mf));
+ free_mntfs(mf);
+ /* continue */
+ }
+
+ /*
+ * If we get here, then either the mount succeeded or
+ * there is no more mount information available.
+ */
+ if (this_error) {
+ mp->am_mnt = mf = new_mntfs();
+
+#ifdef HAVE_FS_AUTOFS
+ if (mp->am_flags & AMF_AUTOFS)
+ autofs_mount_failed(mp);
+ else
+#endif /* HAVE_FS_AUTOFS */
+ nfs_quick_reply(mp, this_error);
+
+ if (hard_error <= 0)
+ hard_error = this_error;
+ if (hard_error < 0)
+ hard_error = ETIMEDOUT;
+
+ /*
+ * Set a small(ish) timeout on an error node if
+ * the error was not a time out.
+ */
+ switch (hard_error) {
+ case ETIMEDOUT:
+ case EWOULDBLOCK:
+ case EIO:
+ mp->am_timeo = 17;
+ break;
+ default:
+ mp->am_timeo = 5;
+ break;
+ }
+ new_ttl(mp);
+ } else {
+ mf = mp->am_mnt;
+ /*
+ * Wakeup anything waiting for this mount
+ */
+ wakeup(get_mntfs_wchan(mf));
+ hard_error = 0;
+ }
+
+ /*
+ * Make sure that the error value in the mntfs has a
+ * reasonable value.
+ */
+ if (mf->mf_error < 0) {
+ mf->mf_error = hard_error;
+ if (hard_error)
+ mf->mf_flags |= MFF_ERROR;
+ }
+
+ /*
+ * In any case we don't need the continuation any more
+ */
+ free_continuation(cp);
+
+ return hard_error;
+}
+
+
+static char *
+amfs_parse_defaults(am_node *mp, mntfs *mf, char *def_opts)
+{
+ char *dflts;
+ char *dfl;
+ char **rvec = NULL;
+ struct mnt_map *mm = (mnt_map *) mf->mf_private;
+
+ dlog("determining /defaults entry value");
+
+ /*
+ * Find out if amd.conf overrode any map-specific /defaults.
+ *
+ * HACK ALERT: there's no easy way to find out what the map mount point is
+ * at this point, so I am forced to initialize the mnt_map->cfm field here
+ * for the first time, upon the very first search for a /defaults entry in
+ * this map. This initialization is much better done in mapc_create(),
+ * but it's impossible to do that there with the current code structure.
+ */
+ if (mm->cfm == NULL) { /* then initialize it for first time */
+ mm->cfm = find_cf_map(mf->mf_mount);
+ }
+ if (mm->cfm && mm->cfm->cfm_defaults) {
+ dlog("map %s map_defaults override: %s", mf->mf_mount, mm->cfm->cfm_defaults);
+ dflts = strdup(mm->cfm->cfm_defaults);
+ } else if (mapc_search(mm, "/defaults", &dflts) == 0) {
+ dlog("/defaults gave %s", dflts);
+ } else {
+ return def_opts; /* if nothing found */
+ }
+
+ /* trim leading '-' in case thee's one */
+ if (*dflts == '-')
+ dfl = dflts + 1;
+ else
+ dfl = dflts;
+
+ /*
+ * Chop the defaults up
+ */
+ rvec = strsplit(dfl, ' ', '\"');
+
+ if (gopt.flags & CFM_SELECTORS_IN_DEFAULTS) {
+ /*
+ * Pick whichever first entry matched the list of selectors.
+ * Strip the selectors from the string, and assign to dfl the
+ * rest of the string.
+ */
+ if (rvec) {
+ am_opts ap;
+ am_ops *pt;
+ char **sp = rvec;
+ while (*sp) { /* loop until you find something, if any */
+ memset((char *) &ap, 0, sizeof(am_opts));
+ /*
+ * This next routine cause many spurious "expansion of ... is"
+ * messages, which are ignored, b/c all we need out of this
+ * routine is to match selectors. These spurious messages may
+ * be wrong, esp. if they try to expand ${key} b/c it will
+ * get expanded to "/defaults"
+ */
+ pt = ops_match(&ap, *sp, "", mp->am_path, "/defaults",
+ mp->am_parent->am_mnt->mf_info);
+ free_opts(&ap); /* don't leak */
+ if (pt == &amfs_error_ops) {
+ plog(XLOG_MAP, "did not match defaults for \"%s\"", *sp);
+ } else {
+ dfl = strip_selectors(*sp, "/defaults");
+ plog(XLOG_MAP, "matched default selectors \"%s\"", dfl);
+ break;
+ }
+ ++sp;
+ }
+ }
+ } else { /* not selectors_in_defaults */
+ /*
+ * Extract first value
+ */
+ dfl = rvec[0];
+ }
+
+ /*
+ * If there were any values at all...
+ */
+ if (dfl) {
+ /*
+ * Log error if there were other values
+ */
+ if (!(gopt.flags & CFM_SELECTORS_IN_DEFAULTS) && rvec[1]) {
+ dlog("/defaults chopped into %s", dfl);
+ plog(XLOG_USER, "More than a single value for /defaults in %s", mf->mf_info);
+ }
+
+ /*
+ * Prepend to existing defaults if they exist,
+ * otherwise just use these defaults.
+ */
+ if (*def_opts && *dfl) {
+ size_t l = strlen(def_opts) + strlen(dfl) + 2;
+ char *nopts = (char *) xmalloc(l);
+ xsnprintf(nopts, l, "%s;%s", dfl, def_opts);
+ XFREE(def_opts);
+ def_opts = nopts;
+ } else if (*dfl) {
+ def_opts = strealloc(def_opts, dfl);
+ }
+ }
+
+ XFREE(dflts);
+
+ /* don't need info vector any more */
+ if (rvec)
+ XFREE(rvec);
+
+ return def_opts;
+}
+
+
+am_node *
+amfs_generic_mount_child(am_node *new_mp, int *error_return)
+{
+ int error;
+ struct continuation *cp; /* Continuation structure if need to mount */
+
+ dlog("in amfs_generic_mount_child");
+
+ *error_return = error = 0; /* Error so far */
+
+ /* we have an errorfs attached to the am_node, free it */
+ free_mntfs(new_mp->am_mnt);
+ new_mp->am_mnt = 0;
+
+ /*
+ * Construct a continuation
+ */
+ cp = ALLOC(struct continuation);
+ cp->callout = 0;
+ cp->mp = new_mp;
+ cp->retry = TRUE;
+ cp->start = clocktime(NULL);
+ cp->mf = new_mp->am_mfarray;
+
+ /*
+ * Try and mount the file system. If this succeeds immediately (possible
+ * for a ufs file system) then return the attributes, otherwise just
+ * return an error.
+ */
+ error = amfs_bgmount(cp);
+ reschedule_timeout_mp();
+ if (!error)
+ return new_mp;
+
+ /*
+ * Code for quick reply. If current_transp is set, then it's the
+ * transp that's been passed down from nfs_program_2() or from
+ * autofs_program_[123]().
+ * If new_mp->am_transp is not already set, set it by copying in
+ * current_transp. Once am_transp is set, nfs_quick_reply() and
+ * autofs_mount_succeeded() can use it to send a reply to the
+ * client that requested this mount.
+ */
+ if (current_transp && !new_mp->am_transp) {
+ dlog("Saving RPC transport for %s", new_mp->am_path);
+ new_mp->am_transp = (SVCXPRT *) xmalloc(sizeof(SVCXPRT));
+ *(new_mp->am_transp) = *current_transp;
+ }
+ if (error && (new_mp->am_mnt->mf_ops == &amfs_error_ops))
+ new_mp->am_error = error;
+
+ if (new_mp->am_error > 0)
+ assign_error_mntfs(new_mp);
+
+ ereturn(error);
+}
+
+
+/*
+ * Automount interface to RPC lookup routine
+ * Find the corresponding entry and return
+ * the file handle for it.
+ */
+am_node *
+amfs_generic_lookup_child(am_node *mp, char *fname, int *error_return, int op)
+{
+ am_node *new_mp;
+ mntfs **mf_array;
+ int mp_error;
+
+ dlog("in amfs_generic_lookup_child");
+
+ *error_return = 0;
+ new_mp = amfs_lookup_node(mp, fname, error_return);
+
+ /* return if we got an error */
+ if (!new_mp || *error_return > 0)
+ return new_mp;
+
+ /* also return if it's already mounted and known to be up */
+ if (*error_return == 0 && FSRV_ISUP(new_mp->am_mnt->mf_server))
+ return new_mp;
+
+ switch (op) {
+ case VLOOK_DELETE:
+ /*
+ * If doing a delete then don't create again!
+ */
+ ereturn(ENOENT);
+ case VLOOK_LOOKUP:
+ return new_mp;
+ }
+
+ /* save error_return */
+ mp_error = *error_return;
+
+ mf_array = amfs_lookup_mntfs(new_mp, error_return);
+ if (!mf_array) {
+ new_mp->am_error = new_mp->am_mnt->mf_error = *error_return;
+ free_map(new_mp);
+ return NULL;
+ }
+
+ /*
+ * Already mounted but known to be down:
+ * check if we have any alternatives to mount
+ */
+ if (mp_error == 0) {
+ mntfs **mfp;
+ for (mfp = mf_array; *mfp; mfp++)
+ if (*mfp != new_mp->am_mnt)
+ break;
+ if (*mfp != NULL) {
+ /*
+ * we found an alternative, so try mounting again.
+ */
+ *error_return = -1;
+ } else {
+ for (mfp = mf_array; *mfp; mfp++)
+ free_mntfs(*mfp);
+ XFREE(mf_array);
+ if (new_mp->am_flags & AMF_SOFTLOOKUP) {
+ ereturn(EIO);
+ } else {
+ *error_return = 0;
+ return new_mp;
+ }
+ }
+ }
+
+ /* store the array inside the am_node */
+ new_mp->am_mfarray = mf_array;
+
+ /*
+ * Note: while it might seem like a good idea to prioritize
+ * the list of mntfs's we got here, it probably isn't.
+ * It would ignore the ordering of entries specified by the user,
+ * which is counterintuitive and confusing.
+ */
+ return new_mp;
+}
+
+
+void
+amfs_generic_mounted(mntfs *mf)
+{
+ amfs_mkcacheref(mf);
+}
+
+
+/*
+ * Unmount an automount sub-node
+ */
+int
+amfs_generic_umount(am_node *mp, mntfs *mf)
+{
+ int error = 0;
+
+#ifdef HAVE_FS_AUTOFS
+ int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
+ if (mf->mf_flags & MFF_IS_AUTOFS)
+ error = UMOUNT_FS(mp->am_path, mnttab_file_name, unmount_flags);
+#endif /* HAVE_FS_AUTOFS */
+
+ return error;
+}
+
+
+char *
+amfs_generic_match(am_opts *fo)
+{
+ char *p;
+
+ if (!fo->opt_rfs) {
+ plog(XLOG_USER, "amfs_generic_match: no mount point named (rfs:=)");
+ return 0;
+ }
+ if (!fo->opt_fs) {
+ plog(XLOG_USER, "amfs_generic_match: no map named (fs:=)");
+ return 0;
+ }
+
+ /*
+ * Swap round fs:= and rfs:= options
+ * ... historical (jsp)
+ */
+ p = fo->opt_rfs;
+ fo->opt_rfs = fo->opt_fs;
+ fo->opt_fs = p;
+
+ /*
+ * mtab entry turns out to be the name of the mount map
+ */
+ return strdup(fo->opt_rfs ? fo->opt_rfs : ".");
+}
diff --git a/contrib/amd/amd/amfs_host.c b/contrib/amd/amd/amfs_host.c
index ad0887c..55423c4 100644
--- a/contrib/amd/amd/amfs_host.c
+++ b/contrib/amd/amd/amfs_host.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: amfs_host.c,v 1.4.2.7 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/amfs_host.c
*
*/
@@ -57,10 +56,10 @@
#include <amd.h>
static char *amfs_host_match(am_opts *fo);
-static int amfs_host_fmount(mntfs *mf);
-static int amfs_host_fumount(mntfs *mf);
static int amfs_host_init(mntfs *mf);
-static void amfs_host_umounted(am_node *mp);
+static int amfs_host_mount(am_node *am, mntfs *mf);
+static int amfs_host_umount(am_node *am, mntfs *mf);
+static void amfs_host_umounted(mntfs *mf);
/*
* Ops structure
@@ -70,17 +69,20 @@ am_ops amfs_host_ops =
"host",
amfs_host_match,
amfs_host_init,
- amfs_auto_fmount,
- amfs_host_fmount,
- amfs_auto_fumount,
- amfs_host_fumount,
- amfs_error_lookuppn,
+ amfs_host_mount,
+ amfs_host_umount,
+ amfs_error_lookup_child,
+ amfs_error_mount_child,
amfs_error_readdir,
0, /* amfs_host_readlink */
0, /* amfs_host_mounted */
amfs_host_umounted,
find_nfs_srvr,
- FS_MKMNT | FS_BACKGROUND | FS_AMQINFO
+ 0, /* amfs_host_get_wchan */
+ FS_MKMNT | FS_BACKGROUND | FS_AMQINFO,
+#ifdef HAVE_FS_AUTOFS
+ AUTOFS_HOST_FS_FLAGS,
+#endif /* HAVE_FS_AUTOFS */
};
@@ -95,21 +97,21 @@ am_ops amfs_host_ops =
* allows the entire PC disk to be mounted.
*/
static void
-make_mntpt(char *mntpt, const exports ex, const mntfs *mf)
+make_mntpt(char *mntpt, size_t l, const exports ex, const char *mf_mount)
{
if (ex->ex_dir[0] == '/') {
if (ex->ex_dir[1] == 0)
- strcpy(mntpt, (mf)->mf_mount);
+ xstrlcpy(mntpt, mf_mount, l);
else
- sprintf(mntpt, "%s%s", mf->mf_mount, ex->ex_dir);
+ xsnprintf(mntpt, l, "%s%s", mf_mount, ex->ex_dir);
} else if (ex->ex_dir[0] >= 'a' &&
ex->ex_dir[0] <= 'z' &&
ex->ex_dir[1] == ':' &&
ex->ex_dir[2] == '/' &&
ex->ex_dir[3] == 0)
- sprintf(mntpt, "%s/%c%%", mf->mf_mount, ex->ex_dir[0]);
+ xsnprintf(mntpt, l, "%s/%c%%", mf_mount, ex->ex_dir[0]);
else
- sprintf(mntpt, "%s/%s", mf->mf_mount, ex->ex_dir);
+ xsnprintf(mntpt, l, "%s/%s", mf_mount, ex->ex_dir);
}
@@ -134,8 +136,7 @@ amfs_host_match(am_opts *fo)
static int
amfs_host_init(mntfs *mf)
{
- fserver *fs;
- u_short port;
+ u_short mountd_port;
if (strchr(mf->mf_info, ':') == 0)
return ENOENT;
@@ -152,41 +153,39 @@ amfs_host_init(mntfs *mf)
*/
/*
* First, we find the fileserver for this mntfs and then call
- * nfs_srvr_port with our mntfs passed as the wait channel.
- * nfs_srvr_port will check some things and then schedule
+ * get_mountd_port with our mntfs passed as the wait channel.
+ * get_mountd_port will check some things and then schedule
* it so that when the fileserver is ready, a wakeup is done
- * on this mntfs. amfs_auto_cont() is already sleeping on this mntfs
- * so as soon as that wakeup happens amfs_auto_cont() is called and
+ * on this mntfs. amfs_cont() is already sleeping on this mntfs
+ * so as soon as that wakeup happens amfs_cont() is called and
* this mount is retried.
*/
- if ((fs = mf->mf_server))
+ if (mf->mf_server)
/*
* We don't really care if there's an error returned.
* Since this is just to help speed things along, the
* error will get handled properly elsewhere.
*/
- (void) nfs_srvr_port(fs, &port, (voidp) mf);
+ get_mountd_port(mf->mf_server, &mountd_port, get_mntfs_wchan(mf));
return 0;
}
static int
-do_mount(am_nfs_handle_t *fhp, char *dir, char *fs_name, char *opts, mntfs *mf)
+do_mount(am_nfs_handle_t *fhp, char *mntdir, char *fs_name, mntfs *mf)
{
struct stat stb;
-#ifdef DEBUG
- dlog("amfs_host: mounting fs %s on %s\n", fs_name, dir);
-#endif /* DEBUG */
+ dlog("amfs_host: mounting fs %s on %s\n", fs_name, mntdir);
- (void) mkdirs(dir, 0555);
- if (stat(dir, &stb) < 0 || (stb.st_mode & S_IFMT) != S_IFDIR) {
- plog(XLOG_ERROR, "No mount point for %s - skipping", dir);
+ (void) mkdirs(mntdir, 0555);
+ if (stat(mntdir, &stb) < 0 || (stb.st_mode & S_IFMT) != S_IFDIR) {
+ plog(XLOG_ERROR, "No mount point for %s - skipping", mntdir);
return ENOENT;
}
- return mount_nfs_fh(fhp, dir, fs_name, opts, mf);
+ return mount_nfs_fh(fhp, mntdir, fs_name, mf);
}
@@ -208,6 +207,10 @@ fetch_fhandle(CLIENT *client, char *dir, am_nfs_handle_t *fhp, u_long nfs_versio
{
struct timeval tv;
enum clnt_stat clnt_stat;
+ struct fhstatus res;
+#ifdef HAVE_FS_NFS3
+ struct am_mountres3 res3;
+#endif /* HAVE_FS_NFS3 */
/*
* Pick a number, any number...
@@ -215,9 +218,7 @@ fetch_fhandle(CLIENT *client, char *dir, am_nfs_handle_t *fhp, u_long nfs_versio
tv.tv_sec = 20;
tv.tv_usec = 0;
-#ifdef DEBUG
dlog("Fetching fhandle for %s", dir);
-#endif /* DEBUG */
/*
* Call the mount daemon on the remote host to
@@ -227,25 +228,28 @@ fetch_fhandle(CLIENT *client, char *dir, am_nfs_handle_t *fhp, u_long nfs_versio
plog(XLOG_INFO, "fetch_fhandle: NFS version %d", (int) nfs_version);
#ifdef HAVE_FS_NFS3
if (nfs_version == NFS_VERSION3) {
- memset((char *) &fhp->v3, 0, sizeof(fhp->v3));
+ memset((char *) &res3, 0, sizeof(res3));
clnt_stat = clnt_call(client,
MOUNTPROC_MNT,
(XDRPROC_T_TYPE) xdr_dirpath,
(SVC_IN_ARG_TYPE) &dir,
- (XDRPROC_T_TYPE) xdr_mountres3,
- (SVC_IN_ARG_TYPE) &fhp->v3,
+ (XDRPROC_T_TYPE) xdr_am_mountres3,
+ (SVC_IN_ARG_TYPE) &res3,
tv);
if (clnt_stat != RPC_SUCCESS) {
plog(XLOG_ERROR, "mountd rpc failed: %s", clnt_sperrno(clnt_stat));
return EIO;
}
/* Check the status of the filehandle */
- if ((errno = fhp->v3.fhs_status)) {
-#ifdef DEBUG
+ if ((errno = res3.fhs_status)) {
dlog("fhandle fetch for mount version 3 failed: %m");
-#endif /* DEBUG */
return errno;
}
+ memset((voidp) &fhp->v3, 0, sizeof(am_nfs_fh3));
+ fhp->v3.am_fh3_length = res3.mountres3_u.mountinfo.fhandle.fhandle3_len;
+ memmove(fhp->v3.am_fh3_data,
+ res3.mountres3_u.mountinfo.fhandle.fhandle3_val,
+ fhp->v3.am_fh3_length);
} else { /* not NFS_VERSION3 mount */
#endif /* HAVE_FS_NFS3 */
clnt_stat = clnt_call(client,
@@ -253,20 +257,19 @@ fetch_fhandle(CLIENT *client, char *dir, am_nfs_handle_t *fhp, u_long nfs_versio
(XDRPROC_T_TYPE) xdr_dirpath,
(SVC_IN_ARG_TYPE) &dir,
(XDRPROC_T_TYPE) xdr_fhstatus,
- (SVC_IN_ARG_TYPE) &fhp->v2,
+ (SVC_IN_ARG_TYPE) &res,
tv);
if (clnt_stat != RPC_SUCCESS) {
plog(XLOG_ERROR, "mountd rpc failed: %s", clnt_sperrno(clnt_stat));
return EIO;
}
/* Check status of filehandle */
- if (fhp->v2.fhs_status) {
- errno = fhp->v2.fhs_status;
-#ifdef DEBUG
+ if (res.fhs_status) {
+ errno = res.fhs_status;
dlog("fhandle fetch for mount version 1 failed: %m");
-#endif /* DEBUG */
return errno;
}
+ memmove(&fhp->v2, &res.fhs_fh, NFS_FHSIZE);
#ifdef HAVE_FS_NFS3
} /* end of "if (nfs_version == NFS_VERSION3)" statement */
#endif /* HAVE_FS_NFS3 */
@@ -291,11 +294,8 @@ already_mounted(mntlist *mlist, char *dir)
}
-/*
- * Mount the export tree from a host
- */
static int
-amfs_host_fmount(mntfs *mf)
+amfs_host_mount(am_node *am, mntfs *mf)
{
struct timeval tv2;
CLIENT *client;
@@ -317,6 +317,14 @@ amfs_host_fmount(mntfs *mf)
u_long mnt_version;
/*
+ * WebNFS servers don't necessarily run mountd.
+ */
+ if (mf->mf_flags & MFF_WEBNFS) {
+ plog(XLOG_ERROR, "amfs_host_mount: cannot support WebNFS");
+ return EIO;
+ }
+
+ /*
* Read the mount list
*/
mlist = read_mtab(mf->mf_mount, mnttab_file_name);
@@ -334,10 +342,10 @@ amfs_host_fmount(mntfs *mf)
*/
host = mf->mf_server->fs_host;
sin = *mf->mf_server->fs_ip;
- plog(XLOG_INFO, "amfs_host_fmount: NFS version %d", (int) mf->mf_server->fs_version);
+ plog(XLOG_INFO, "amfs_host_mount: NFS version %d", (int) mf->mf_server->fs_version);
#ifdef HAVE_FS_NFS3
if (mf->mf_server->fs_version == NFS_VERSION3)
- mnt_version = MOUNTVERS3;
+ mnt_version = AM_MOUNTVERS3;
else
#endif /* HAVE_FS_NFS3 */
mnt_version = MOUNTVERS;
@@ -374,9 +382,7 @@ amfs_host_fmount(mntfs *mf)
}
client->cl_auth = nfs_auth;
-#ifdef DEBUG
dlog("Fetching export list from %s", host);
-#endif /* DEBUG */
/*
* Fetch the export list
@@ -392,7 +398,7 @@ amfs_host_fmount(mntfs *mf)
tv2);
if (clnt_stat != RPC_SUCCESS) {
const char *msg = clnt_sperrno(clnt_stat);
- plog(XLOG_ERROR, "host_fmount rpc failed: %s", msg);
+ plog(XLOG_ERROR, "host_mount rpc failed: %s", msg);
/* clnt_perror(client, "rpc"); */
error = EIO;
goto out;
@@ -412,7 +418,7 @@ amfs_host_fmount(mntfs *mf)
*/
ep = (exports *) xmalloc(n_export * sizeof(exports));
for (j = 0, ex = exlist; ex; ex = ex->ex_next) {
- make_mntpt(mntpt, ex, mf);
+ make_mntpt(mntpt, sizeof(mntpt), ex, mf->mf_mount);
if (already_mounted(mlist, mntpt))
/* we have at least one mounted f/s, so don't fail the mount */
ok = TRUE;
@@ -442,9 +448,7 @@ amfs_host_fmount(mntfs *mf)
for (j = k = 0; j < n_export; j++) {
/* Check and avoid a duplicated export entry */
if (j > k && ep[k] && STREQ(ep[j]->ex_dir, ep[k]->ex_dir)) {
-#ifdef DEBUG
dlog("avoiding dup fhandle requested for %s", ep[j]->ex_dir);
-#endif /* DEBUG */
ep[j] = 0;
} else {
k = j;
@@ -461,9 +465,9 @@ amfs_host_fmount(mntfs *mf)
* error code 0 at the end. If they all fail then return
* the last error code.
*/
- strncpy(fs_name, mf->mf_info, sizeof(fs_name));
+ xstrlcpy(fs_name, mf->mf_info, MAXPATHLEN);
if ((rfs_dir = strchr(fs_name, ':')) == (char *) 0) {
- plog(XLOG_FATAL, "amfs_host_fmount: mf_info has no colon");
+ plog(XLOG_FATAL, "amfs_host_mount: mf_info has no colon");
error = EINVAL;
goto out;
}
@@ -471,9 +475,15 @@ amfs_host_fmount(mntfs *mf)
for (j = 0; j < n_export; j++) {
ex = ep[j];
if (ex) {
- strcpy(rfs_dir, ex->ex_dir);
- make_mntpt(mntpt, ex, mf);
- if (do_mount(&fp[j], mntpt, fs_name, mf->mf_mopts, mf) == 0)
+ /*
+ * Note: the sizeof space left in rfs_dir is what's left in fs_name
+ * after strchr() above returned a pointer _inside_ fs_name. The
+ * calculation below also takes into account that rfs_dir was
+ * incremented by the ++ above.
+ */
+ xstrlcpy(rfs_dir, ex->ex_dir, sizeof(fs_name) - (rfs_dir - fs_name));
+ make_mntpt(mntpt, sizeof(mntpt), ex, mf->mf_mount);
+ if (do_mount(&fp[j], mntpt, fs_name, mf) == 0)
ok = TRUE;
}
}
@@ -522,9 +532,10 @@ directory_prefix(char *pref, char *dir)
* Unmount a mount tree
*/
static int
-amfs_host_fumount(mntfs *mf)
+amfs_host_umount(am_node *am, mntfs *mf)
{
mntlist *ml, *mprev;
+ int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
int xerror = 0;
/*
@@ -559,18 +570,24 @@ amfs_host_fumount(mntfs *mf)
char *dir = ml->mnt->mnt_dir;
if (directory_prefix(mf->mf_mount, dir)) {
int error;
-#ifdef DEBUG
dlog("amfs_host: unmounts %s", dir);
-#endif /* DEBUG */
/*
* Unmount "dir"
*/
- error = UMOUNT_FS(dir, mnttab_file_name);
+ error = UMOUNT_FS(dir, mnttab_file_name, unmount_flags);
/*
* Keep track of errors
*/
if (error) {
- if (!xerror)
+ /*
+ * If we have not already set xerror and error is not ENOENT,
+ * then set xerror equal to error and log it.
+ * 'xerror' is the return value for this function.
+ *
+ * We do not want to pass ENOENT as an error because if the
+ * directory does not exists our work is done anyway.
+ */
+ if (!xerror && error != ENOENT)
xerror = error;
if (error != EBUSY) {
errno = error;
@@ -591,7 +608,7 @@ amfs_host_fumount(mntfs *mf)
* Try to remount, except when we are shutting down.
*/
if (xerror && amd_state != Finishing) {
- xerror = amfs_host_fmount(mf);
+ xerror = amfs_host_mount(am, mf);
if (!xerror) {
/*
* Don't log this - it's usually too verbose
@@ -611,9 +628,8 @@ amfs_host_fumount(mntfs *mf)
* mountd protocol is badly broken anyway.
*/
static void
-amfs_host_umounted(am_node *mp)
+amfs_host_umounted(mntfs *mf)
{
- mntfs *mf = mp->am_mnt;
char *host;
CLIENT *client;
enum clnt_stat clnt_stat;
@@ -626,6 +642,14 @@ amfs_host_umounted(am_node *mp)
return;
/*
+ * WebNFS servers shouldn't ever get here.
+ */
+ if (mf->mf_flags & MFF_WEBNFS) {
+ plog(XLOG_ERROR, "amfs_host_umounted: cannot support WebNFS");
+ return;
+ }
+
+ /*
* Take a copy of the server hostname, address, and NFS version
* to mount version conversion.
*/
@@ -634,7 +658,7 @@ amfs_host_umounted(am_node *mp)
plog(XLOG_INFO, "amfs_host_umounted: NFS version %d", (int) mf->mf_server->fs_version);
#ifdef HAVE_FS_NFS3
if (mf->mf_server->fs_version == NFS_VERSION3)
- mnt_version = MOUNTVERS3;
+ mnt_version = AM_MOUNTVERS3;
else
#endif /* HAVE_FS_NFS3 */
mnt_version = MOUNTVERS;
@@ -661,9 +685,7 @@ amfs_host_umounted(am_node *mp)
}
client->cl_auth = nfs_auth;
-#ifdef DEBUG
dlog("Unmounting all from %s", host);
-#endif /* DEBUG */
clnt_stat = clnt_call(client,
MOUNTPROC_UMNTALL,
diff --git a/contrib/amd/amd/amfs_link.c b/contrib/amd/amd/amfs_link.c
index 55552ae..e75ab86 100644
--- a/contrib/amd/amd/amfs_link.c
+++ b/contrib/amd/amd/amfs_link.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: amfs_link.c,v 1.3.2.4 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/amfs_link.c
*
*/
@@ -52,6 +51,9 @@
#include <am_defs.h>
#include <amd.h>
+/* forward declarations */
+static int amfs_link_mount(am_node *mp, mntfs *mf);
+static int amfs_link_umount(am_node *mp, mntfs *mf);
/*
* Ops structures
@@ -61,17 +63,20 @@ am_ops amfs_link_ops =
"link",
amfs_link_match,
0, /* amfs_link_init */
- amfs_auto_fmount,
- amfs_link_fmount,
- amfs_auto_fumount,
- amfs_link_fumount,
- amfs_error_lookuppn,
+ amfs_link_mount,
+ amfs_link_umount,
+ amfs_error_lookup_child,
+ amfs_error_mount_child,
amfs_error_readdir,
0, /* amfs_link_readlink */
0, /* amfs_link_mounted */
0, /* amfs_link_umounted */
- find_amfs_auto_srvr,
- 0
+ amfs_generic_find_srvr,
+ 0, /* nfs_fs_flags */
+ 0, /* amfs_link_get_wchan */
+#ifdef HAVE_FS_AUTOFS
+ AUTOFS_LINK_FS_FLAGS,
+#endif /* HAVE_FS_AUTOFS */
};
@@ -88,54 +93,41 @@ amfs_link_match(am_opts *fo)
}
/*
- * Bug report (14/12/89) from Jay Plett <jay@princeton.edu>
- * If an automount point has the same name as an existing
- * link type mount Amd hits a race condition and either hangs
- * or causes a symlink loop.
+ * If the link target points to another mount point, then we could
+ * end up with an unpleasant situation, where the link f/s simply
+ * "assumes" the mntfs of that mount point.
*
- * If fs begins with a '/' change the opt_fs & opt_sublink
- * fields so that the fs option doesn't end up pointing at
- * an existing symlink.
+ * For example, if the link points to /usr, and /usr is a real ufs
+ * filesystem, then the link f/s will use the inherited ufs mntfs,
+ * and the end result will be that it will become unmountable.
*
- * If sublink is nil then set sublink to fs
- * else set sublink to fs / sublink
+ * To prevent this, we use a hack: we prepend a dot ('.') to opt_fs if
+ * its original value was an absolute path, so that it will never match
+ * any other mntfs.
*
- * Finally set fs to ".".
+ * XXX: a less hacky solution should be used...
*/
- if (*fo->opt_fs == '/') {
- char *fullpath;
- char *link = fo->opt_sublink;
- if (link) {
- if (*link == '/')
- fullpath = strdup(link);
- else
- fullpath = str3cat((char *) 0, fo->opt_fs, "/", link);
- } else {
- fullpath = strdup(fo->opt_fs);
- }
-
- if (fo->opt_sublink)
- XFREE(fo->opt_sublink);
- fo->opt_sublink = fullpath;
- fo->opt_fs = str3cat(fo->opt_fs, ".", fullpath, "");
+ if (fo->opt_fs[0] == '/') {
+ char *link_hack = str3cat(NULL, ".", fo->opt_fs, "");
+ if (!fo->opt_sublink)
+ fo->opt_sublink = strdup(fo->opt_fs);
+ XFREE(fo->opt_fs);
+ fo->opt_fs = link_hack;
}
return strdup(fo->opt_fs);
}
-int
-amfs_link_fmount(mntfs *mf)
+static int
+amfs_link_mount(am_node *mp, mntfs *mf)
{
- /*
- * Wow - this is hard to implement! :-)
- */
return 0;
}
-int
-amfs_link_fumount(mntfs *mf)
+static int
+amfs_link_umount(am_node *mp, mntfs *mf)
{
return 0;
}
diff --git a/contrib/amd/amd/amfs_linkx.c b/contrib/amd/amd/amfs_linkx.c
index c7c9b79..e306eda 100644
--- a/contrib/amd/amd/amfs_linkx.c
+++ b/contrib/amd/amd/amfs_linkx.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: amfs_linkx.c,v 1.3.2.4 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/amfs_linkx.c
*
*/
@@ -53,7 +52,8 @@
#include <amd.h>
/* forward declarations */
-static int amfs_linkx_mount(am_node *mp);
+static int amfs_linkx_mount(am_node *mp, mntfs *mf);
+static int amfs_linkx_umount(am_node *mp, mntfs *mf);
/*
* linkx operations
@@ -64,21 +64,24 @@ struct am_ops amfs_linkx_ops =
amfs_link_match,
0, /* amfs_linkx_init */
amfs_linkx_mount,
- 0,
- amfs_auto_fumount,
- amfs_link_fumount,
- amfs_error_lookuppn,
+ amfs_linkx_umount,
+ amfs_error_lookup_child,
+ amfs_error_mount_child,
amfs_error_readdir,
0, /* amfs_linkx_readlink */
0, /* amfs_linkx_mounted */
0, /* amfs_linkx_umounted */
- find_amfs_auto_srvr,
- FS_MBACKGROUND
+ amfs_generic_find_srvr,
+ 0, /* amfs_linkx_get_wchan */
+ FS_MBACKGROUND,
+#ifdef HAVE_FS_AUTOFS
+ AUTOFS_LINKX_FS_FLAGS,
+#endif /* HAVE_FS_AUTOFS */
};
static int
-amfs_linkx_mount(am_node *mp)
+amfs_linkx_mount(am_node *mp, mntfs *mf)
{
/*
* Check for existence of target.
@@ -89,7 +92,7 @@ amfs_linkx_mount(am_node *mp)
if (mp->am_link)
ln = mp->am_link;
else /* should never occur */
- ln = mp->am_mnt->mf_mount;
+ ln = mf->mf_mount;
/*
* Use lstat, not stat, since we don't
@@ -101,3 +104,10 @@ amfs_linkx_mount(am_node *mp)
return 0;
}
+
+
+static int
+amfs_linkx_umount(am_node *mp, mntfs *mf)
+{
+ return 0;
+}
diff --git a/contrib/amd/amd/amfs_nfsl.c b/contrib/amd/amd/amfs_nfsl.c
index bed6f4d..bb48f0e 100644
--- a/contrib/amd/amd/amfs_nfsl.c
+++ b/contrib/amd/amd/amfs_nfsl.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: amfs_nfsl.c,v 1.4.2.4 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/amfs_nfsl.c
*
*/
@@ -60,9 +59,9 @@
/* forward declarations */
static char *amfs_nfsl_match(am_opts *fo);
static int amfs_nfsl_init(mntfs *mf);
-static int amfs_nfsl_fmount(mntfs *mf);
-static int amfs_nfsl_fumount(mntfs *mf);
-static void amfs_nfsl_umounted(am_node *mp);
+static int amfs_nfsl_mount(am_node *mp, mntfs *mf);
+static int amfs_nfsl_umount(am_node *mp, mntfs *mf);
+static void amfs_nfsl_umounted(mntfs *mf);
static fserver *amfs_nfsl_ffserver(mntfs *mf);
/*
@@ -70,20 +69,23 @@ static fserver *amfs_nfsl_ffserver(mntfs *mf);
*/
am_ops amfs_nfsl_ops =
{
- "nfsl", /* name of file system */
- amfs_nfsl_match, /* match */
- amfs_nfsl_init, /* initialize */
- amfs_auto_fmount, /* mount vnode */
- amfs_nfsl_fmount, /* mount vfs */
- amfs_auto_fumount, /* unmount vnode */
- amfs_nfsl_fumount, /* unmount VFS */
- amfs_error_lookuppn, /* lookup path-name */
- amfs_error_readdir, /* read directory */
- 0, /* read link */
- 0, /* after-mount extra actions */
- amfs_nfsl_umounted, /* after-umount extra actions */
- amfs_nfsl_ffserver, /* find a file server */
- FS_MKMNT | FS_BACKGROUND | FS_AMQINFO /* flags */
+ "nfsl",
+ amfs_nfsl_match,
+ amfs_nfsl_init,
+ amfs_nfsl_mount,
+ amfs_nfsl_umount,
+ amfs_error_lookup_child,
+ amfs_error_mount_child,
+ amfs_error_readdir,
+ 0, /* amfs_nfsl_readlink */
+ 0, /* amfs_nfsl_mounted */
+ amfs_nfsl_umounted,
+ amfs_nfsl_ffserver,
+ 0, /* amfs_nfsl_get_wchan */
+ FS_MKMNT | FS_BACKGROUND | FS_AMQINFO, /* nfs_fs_flags */
+#ifdef HAVE_FS_AUTOFS
+ AUTOFS_NFSL_FS_FLAGS,
+#endif /* HAVE_FS_AUTOFS */
};
@@ -94,10 +96,16 @@ am_ops amfs_nfsl_ops =
static char *
amfs_nfsl_match(am_opts *fo)
{
- char *cp = fo->opt_fs;
+ char *cp;
char *ho = fo->opt_rhost;
+ char *retval;
struct stat stb;
+ if (fo->opt_sublink)
+ cp = fo->opt_sublink;
+ else
+ cp = fo->opt_fs;
+
if (!cp || !ho) {
plog(XLOG_USER, "amfs_nfsl: host $fs and $rhost must be specified");
return NULL;
@@ -105,20 +113,20 @@ amfs_nfsl_match(am_opts *fo)
/*
* If this host is not the same as $rhost, or if link does not exist,
- * perform nfs_match(), same as for type:=nfs.
- * If link value exists (or same host), then perform amfs_link_match(),
- * same as for linkx.
+ * call nfs_ops.fs_match().
+ * If link value exists (or same host), call amfs_link_ops.fs_match().
*/
if (!STRCEQ(ho, am_get_hostname())) {
plog(XLOG_INFO, "amfs_nfsl: \"%s\" is not local host, using type:=nfs", ho);
- return nfs_match(fo);
+ retval = nfs_ops.fs_match(fo);
} else if (lstat(cp, &stb) < 0) {
plog(XLOG_INFO, "amfs_nfsl: \"%s\" does not exist, using type:=nfs", cp);
- return nfs_match(fo);
+ retval = nfs_ops.fs_match(fo);
} else {
plog(XLOG_INFO, "amfs_nfsl: \"%s\" exists, using type:=link", cp);
- return amfs_link_match(fo);
+ retval = amfs_link_ops.fs_match(fo);
}
+ return retval;
}
@@ -129,15 +137,15 @@ amfs_nfsl_match(am_opts *fo)
static int
amfs_nfsl_init(mntfs *mf)
{
- /*
- * If a link, do nothing (same as type:=link).
- * If non-link, do nfs_init (same as type:=nfs).
- */
+ int ret = 0;
if (mf->mf_flags & MFF_NFSLINK) {
- return 0;
+ if (amfs_link_ops.fs_init)
+ ret = amfs_link_ops.fs_init(mf);
} else {
- return nfs_init(mf);
+ if (nfs_ops.fs_init)
+ ret = nfs_ops.fs_init(mf);
}
+ return ret;
}
@@ -146,17 +154,17 @@ amfs_nfsl_init(mntfs *mf)
* Returns: 0 if OK, non-zero (errno) if failed.
*/
static int
-amfs_nfsl_fmount(mntfs *mf)
+amfs_nfsl_mount(am_node *mp, mntfs *mf)
{
- /*
- * If a link, do run amfs_link_fmount() (same as type:=link)
- * If non-link, do nfs_fmount (same as type:=nfs).
- */
+ int ret = 0;
if (mf->mf_flags & MFF_NFSLINK) {
- return amfs_link_fmount(mf);
+ if (amfs_link_ops.mount_fs)
+ ret = amfs_link_ops.mount_fs(mp, mf);
} else {
- return nfs_fmount(mf);
+ if (nfs_ops.mount_fs)
+ ret = nfs_ops.mount_fs(mp, mf);
}
+ return ret;
}
@@ -165,17 +173,17 @@ amfs_nfsl_fmount(mntfs *mf)
* Returns: 0 if OK, non-zero (errno) if failed.
*/
static int
-amfs_nfsl_fumount(mntfs *mf)
+amfs_nfsl_umount(am_node *mp, mntfs *mf)
{
- /*
- * If a link, do run amfs_link_fumount() (same as type:=link)
- * If non-link, do nfs_fumount (same as type:=nfs).
- */
+ int ret = 0;
if (mf->mf_flags & MFF_NFSLINK) {
- return amfs_link_fumount(mf);
+ if (amfs_link_ops.umount_fs)
+ ret = amfs_link_ops.umount_fs(mp, mf);
} else {
- return nfs_fumount(mf);
+ if (nfs_ops.umount_fs)
+ ret = nfs_ops.umount_fs(mp, mf);
}
+ return ret;
}
@@ -186,27 +194,14 @@ amfs_nfsl_fumount(mntfs *mf)
* See amfs_auto_umounted(), host_umounted(), nfs_umounted().
*/
static void
-amfs_nfsl_umounted(am_node *mp)
+amfs_nfsl_umounted(mntfs *mf)
{
- mntfs *mf = mp->am_mnt;
-
- /*
- * If a link, do nothing (same as type:=link)
- * If non-link, do nfs_fumount (same as type:=nfs).
- */
if (mf->mf_flags & MFF_NFSLINK) {
- return;
+ if (amfs_link_ops.umounted)
+ amfs_link_ops.umounted(mf);
} else {
- nfs_umounted(mp);
- /*
- * MUST remove mount point directories, because if they remain
- * behind, the next nfsl access will think they are a link
- * type file system, and not NFS! (when it performs link target
- * existence test)
- */
- if (mf->mf_flags & MFF_MKMNT)
- rmdirs(mf->mf_mount);
- return;
+ if (nfs_ops.umounted)
+ nfs_ops.umounted(mf);
}
}
@@ -218,20 +213,26 @@ amfs_nfsl_umounted(am_node *mp)
static fserver *
amfs_nfsl_ffserver(mntfs *mf)
{
- char *cp = mf->mf_fo->opt_fs;
+ char *cp;
char *ho = mf->mf_fo->opt_rhost;
struct stat stb;
+ if (mf->mf_fo->opt_sublink)
+ cp = mf->mf_fo->opt_sublink;
+ else
+ cp = mf->mf_fo->opt_fs;
+
/*
* If this host is not the same as $rhost, or if link does not exist,
- * perform find_nfs_srvr(), same as for type:=nfs.
- * If link value exists (or same host), then perform
- * find_amfs_auto_srvr(), same as for linkx.
+ * call amfs_link_ops.ffserver().
+ * If link value exists (or same host), then call ops_nfs.ffserver().
*/
if (!STRCEQ(ho, am_get_hostname()) || lstat(cp, &stb) < 0) {
- return find_nfs_srvr(mf);
+ return nfs_ops.ffserver(mf);
} else {
mf->mf_flags |= MFF_NFSLINK;
- return find_amfs_auto_srvr(mf);
+ /* remove the FS_MKMNT flag, we don't want amd touching the mountpoint */
+ mf->mf_fsflags &= ~FS_MKMNT;
+ return amfs_link_ops.ffserver(mf);
}
}
diff --git a/contrib/amd/amd/amfs_nfsx.c b/contrib/amd/amd/amfs_nfsx.c
index 7d8949b..91be8af 100644
--- a/contrib/amd/amd/amfs_nfsx.c
+++ b/contrib/amd/amd/amfs_nfsx.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: amfs_nfsx.c,v 1.3.2.5 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/amfs_nfsx.c
*
*/
@@ -67,13 +66,13 @@ struct amfs_nfsx {
int nx_c; /* Number of elements in nx_v */
amfs_nfsx_mnt *nx_v; /* Underlying mounts */
amfs_nfsx_mnt *nx_try;
+ am_node *nx_mp;
};
/* forward definitions */
static char *amfs_nfsx_match(am_opts *fo);
-static int amfs_nfsx_fmount (mntfs *);
-static int amfs_nfsx_fmount(mntfs *mf);
-static int amfs_nfsx_fumount(mntfs *mf);
+static int amfs_nfsx_mount(am_node *am, mntfs *mf);
+static int amfs_nfsx_umount(am_node *am, mntfs *mf);
static int amfs_nfsx_init(mntfs *mf);
/*
@@ -84,17 +83,20 @@ am_ops amfs_nfsx_ops =
"nfsx",
amfs_nfsx_match,
amfs_nfsx_init,
- amfs_auto_fmount,
- amfs_nfsx_fmount,
- amfs_auto_fumount,
- amfs_nfsx_fumount,
- amfs_error_lookuppn,
+ amfs_nfsx_mount,
+ amfs_nfsx_umount,
+ amfs_error_lookup_child,
+ amfs_error_mount_child,
amfs_error_readdir,
0, /* amfs_nfsx_readlink */
0, /* amfs_nfsx_mounted */
0, /* amfs_nfsx_umounted */
find_nfs_srvr, /* XXX */
- /* FS_UBACKGROUND| */ FS_AMQINFO
+ 0, /* amfs_nfsx_get_wchan */
+ /* FS_UBACKGROUND| */ FS_AMQINFO, /* nfs_fs_flags */
+#ifdef HAVE_FS_AUTOFS
+ AUTOFS_NFSX_FS_FLAGS,
+#endif /* HAVE_FS_AUTOFS */
};
@@ -118,7 +120,7 @@ amfs_nfsx_match(am_opts *fo)
/* set default sublink */
if (fo->opt_sublink == 0) {
ptr = strchr(fo->opt_rfs, ',');
- if (ptr && ptr != (fo->opt_rfs + 1))
+ if (ptr && ptr > (fo->opt_rfs + 1))
fo->opt_sublink = strnsave(fo->opt_rfs + 1, ptr - fo->opt_rfs - 1);
}
@@ -148,17 +150,15 @@ amfs_nfsx_match(am_opts *fo)
* Determine magic cookie to put in mtab
*/
xmtab = str3cat((char *) 0, fo->opt_rhost, ":", fo->opt_rfs);
-#ifdef DEBUG
dlog("NFSX: mounting remote server \"%s\", remote fs \"%s\" on \"%s\"",
fo->opt_rhost, fo->opt_rfs, fo->opt_fs);
-#endif /* DEBUG */
return xmtab;
}
static void
-amfs_nfsx_prfree(voidp vp)
+amfs_nfsx_prfree(opaque_t vp)
{
struct amfs_nfsx *nx = (struct amfs_nfsx *) vp;
int i;
@@ -201,7 +201,7 @@ amfs_nfsx_init(mntfs *mf)
error = EINVAL;
goto errexit;
}
- pref = host +1;
+ pref = host + 1;
host = info;
/*
@@ -212,14 +212,16 @@ amfs_nfsx_init(mntfs *mf)
/*
* Count array size
*/
- for (i = 0; ivec[i]; i++) ;
+ for (i = 0; ivec[i]; i++)
+ /* nothing */;
nx = ALLOC(struct amfs_nfsx);
- mf->mf_private = (voidp) nx;
+ mf->mf_private = (opaque_t) nx;
mf->mf_prfree = amfs_nfsx_prfree;
nx->nx_c = i - 1; /* i-1 because we don't want the prefix */
nx->nx_v = (amfs_nfsx_mnt *) xmalloc(nx->nx_c * sizeof(amfs_nfsx_mnt));
+ nx->nx_mp = 0;
{
char *mp = 0;
char *xinfo = 0;
@@ -243,11 +245,11 @@ amfs_nfsx_init(mntfs *mf)
normalize_slash(xinfo);
if (pref[1] != '\0')
deslashify(xinfo);
-#ifdef DEBUG
dlog("amfs_nfsx: init mount for %s on %s", xinfo, mp);
-#endif /* DEBUG */
nx->nx_v[i].n_error = -1;
nx->nx_v[i].n_mnt = find_mntfs(&nfs_ops, mf->mf_fo, mp, xinfo, "", mf->mf_mopts, mf->mf_remopts);
+ /* propagate the on_autofs flag */
+ nx->nx_v[i].n_mnt->mf_flags |= mf->mf_flags & MFF_ON_AUTOFS;
}
if (rfs)
XFREE(rfs);
@@ -274,7 +276,9 @@ amfs_nfsx_init(mntfs *mf)
for (i = 0; i < nx->nx_c; i++) {
amfs_nfsx_mnt *n = &nx->nx_v[i];
mntfs *m = n->n_mnt;
- int error = (*m->mf_ops->fs_init) (m);
+ int error = 0;
+ if (m->mf_ops->fs_init && !(mf->mf_flags & MFF_RESTART))
+ error = m->mf_ops->fs_init(m);
/*
* if you just "return error" here, you will have made a failure
* in any submounts to fail the whole group. There was old unused code
@@ -287,7 +291,7 @@ amfs_nfsx_init(mntfs *mf)
glob_error = -1;
if (!asked_for_wakeup) {
asked_for_wakeup = 1;
- sched_task(wakeup_task, (voidp) mf, (voidp) m);
+ sched_task(wakeup_task, (opaque_t) mf, get_mntfs_wchan(m));
}
}
}
@@ -297,10 +301,11 @@ amfs_nfsx_init(mntfs *mf)
static void
-amfs_nfsx_cont(int rc, int term, voidp closure)
+amfs_nfsx_cont(int rc, int term, opaque_t arg)
{
- mntfs *mf = (mntfs *) closure;
+ mntfs *mf = (mntfs *) arg;
struct amfs_nfsx *nx = (struct amfs_nfsx *) mf->mf_private;
+ am_node *mp = nx->nx_mp;
amfs_nfsx_mnt *n = nx->nx_try;
n->n_mnt->mf_flags &= ~(MFF_ERROR | MFF_MOUNTING);
@@ -309,7 +314,7 @@ amfs_nfsx_cont(int rc, int term, voidp closure)
/*
* Wakeup anything waiting for this mount
*/
- wakeup((voidp) n->n_mnt);
+ wakeup(get_mntfs_wchan(n->n_mnt));
if (rc || term) {
if (term) {
@@ -334,52 +339,41 @@ amfs_nfsx_cont(int rc, int term, voidp closure)
/*
* The mount worked.
*/
- mf_mounted(n->n_mnt);
+ mf_mounted(n->n_mnt, FALSE); /* FALSE => don't free the n_mnt->am_opts */
n->n_error = 0;
}
/*
* Do the remaining bits
*/
- if (amfs_nfsx_fmount(mf) >= 0) {
- wakeup((voidp) mf);
- mf->mf_flags &= ~MFF_MOUNTING;
- mf_mounted(mf);
- }
+ if (amfs_nfsx_mount(mp, mf) >= 0)
+ wakeup(get_mntfs_wchan(mf));
}
static int
-try_amfs_nfsx_mount(voidp mv)
+try_amfs_nfsx_mount(opaque_t mv)
{
mntfs *mf = (mntfs *) mv;
+ struct amfs_nfsx *nx = (struct amfs_nfsx *) mf->mf_private;
+ am_node *mp = nx->nx_mp;
int error;
- mf->mf_flags |= MFF_MOUNTING;
- error = (*mf->mf_ops->fmount_fs) (mf);
- mf->mf_flags &= ~MFF_MOUNTING;
+ error = mf->mf_ops->mount_fs(mp, mf);
return error;
}
static int
-amfs_nfsx_remount(mntfs *mf, int fg)
+amfs_nfsx_remount(am_node *am, mntfs *mf, int fg)
{
struct amfs_nfsx *nx = (struct amfs_nfsx *) mf->mf_private;
amfs_nfsx_mnt *n;
int glob_error = -1;
- for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) {
- mntfs *m = n->n_mnt;
- if (n->n_error < 0) {
- if (!(m->mf_flags & MFF_MKMNT) && m->mf_ops->fs_flags & FS_MKMNT) {
- int error = mkdirs(m->mf_mount, 0555);
- if (!error)
- m->mf_flags |= MFF_MKMNT;
- }
- }
- }
+ /* Save the am_node pointer for later use */
+ nx->nx_mp = am;
/*
* Iterate through the mntfs's and mount each filesystem
@@ -387,40 +381,38 @@ amfs_nfsx_remount(mntfs *mf, int fg)
*/
for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) {
mntfs *m = n->n_mnt;
+
+ if (m->mf_flags & MFF_MOUNTING)
+ break;
+
+ if (m->mf_flags & MFF_MOUNTED) {
+ mf_mounted(m, FALSE); /* FALSE => don't free the m->am_opts */
+ n->n_error = glob_error = 0;
+ continue;
+ }
+
if (n->n_error < 0) {
- /*
- * Check fmount entry pt. exists
- * and then mount...
- */
- if (!m->mf_ops->fmount_fs) {
- n->n_error = EINVAL;
- } else {
-#ifdef DEBUG
- dlog("calling underlying fmount on %s", m->mf_mount);
-#endif /* DEBUG */
- if (!fg && foreground && (m->mf_ops->fs_flags & FS_MBACKGROUND)) {
- m->mf_flags |= MFF_MOUNTING; /* XXX */
-#ifdef DEBUG
- dlog("backgrounding mount of \"%s\"", m->mf_info);
-#endif /* DEBUG */
- nx->nx_try = n;
- run_task(try_amfs_nfsx_mount, (voidp) m, amfs_nfsx_cont, (voidp) mf);
- n->n_error = -1;
- return -1;
- } else {
-#ifdef DEBUG
- dlog("foreground mount of \"%s\" ...", mf->mf_info);
-#endif /* DEBUG */
- n->n_error = (*m->mf_ops->fmount_fs) (m);
- }
+ /* Create the mountpoint, if and as required */
+ if (!(m->mf_flags & MFF_MKMNT) && m->mf_fsflags & FS_MKMNT) {
+ if (!mkdirs(m->mf_mount, 0555))
+ m->mf_flags |= MFF_MKMNT;
}
-#ifdef DEBUG
- if (n->n_error > 0) {
- errno = n->n_error; /* XXX */
- dlog("underlying fmount of %s failed: %m", m->mf_mount);
+ dlog("calling underlying mount on %s", m->mf_mount);
+ if (!fg && foreground && (m->mf_fsflags & FS_MBACKGROUND)) {
+ m->mf_flags |= MFF_MOUNTING;
+ dlog("backgrounding mount of \"%s\"", m->mf_info);
+ nx->nx_try = n;
+ run_task(try_amfs_nfsx_mount, (opaque_t) m, amfs_nfsx_cont, (opaque_t) mf);
+ n->n_error = -1;
+ return -1;
+ } else {
+ dlog("foreground mount of \"%s\" ...", mf->mf_info);
+ n->n_error = m->mf_ops->mount_fs(am, m);
}
-#endif /* DEBUG */
+
+ if (n->n_error > 0)
+ dlog("underlying fmount of %s failed: %s", m->mf_mount, strerror(n->n_error));
if (n->n_error == 0) {
glob_error = 0;
@@ -435,9 +427,9 @@ amfs_nfsx_remount(mntfs *mf, int fg)
static int
-amfs_nfsx_fmount(mntfs *mf)
+amfs_nfsx_mount(am_node *am, mntfs *mf)
{
- return amfs_nfsx_remount(mf, FALSE);
+ return amfs_nfsx_remount(am, mf, FALSE);
}
@@ -447,7 +439,7 @@ amfs_nfsx_fmount(mntfs *mf)
* and so may hang under extremely rare conditions.
*/
static int
-amfs_nfsx_fumount(mntfs *mf)
+amfs_nfsx_umount(am_node *am, mntfs *mf)
{
struct amfs_nfsx *nx = (struct amfs_nfsx *) mf->mf_private;
amfs_nfsx_mnt *n;
@@ -469,10 +461,8 @@ amfs_nfsx_fumount(mntfs *mf)
* which had been successfully unmounted.
*/
if (n->n_error == 0) {
-#ifdef DEBUG
dlog("calling underlying fumount on %s", m->mf_mount);
-#endif /* DEBUG */
- n->n_error = (*m->mf_ops->fumount_fs) (m);
+ n->n_error = m->mf_ops->umount_fs(am, m);
if (n->n_error) {
glob_error = n->n_error;
n->n_error = 0;
@@ -490,7 +480,7 @@ amfs_nfsx_fumount(mntfs *mf)
* whole lot...
*/
if (glob_error) {
- glob_error = amfs_nfsx_remount(mf, TRUE);
+ glob_error = amfs_nfsx_remount(am, mf, TRUE);
if (glob_error) {
errno = glob_error; /* XXX */
plog(XLOG_USER, "amfs_nfsx: remount of %s failed: %m", mf->mf_mount);
@@ -502,22 +492,12 @@ amfs_nfsx_fumount(mntfs *mf)
*/
for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) {
mntfs *m = n->n_mnt;
- am_node am;
-
- /*
- * XXX: all the umounted handler needs is a
- * mntfs pointer, so pass an am_node with the right
- * pointer in it.
- */
- memset((voidp) &am, 0, sizeof(am));
- am.am_mnt = m;
-#ifdef DEBUG
dlog("calling underlying umounted on %s", m->mf_mount);
-#endif /* DEBUG */
- (*m->mf_ops->umounted) (&am);
+ if (m->mf_ops->umounted)
+ m->mf_ops->umounted(m);
if (n->n_error < 0) {
- if (m->mf_ops->fs_flags & FS_MKMNT) {
+ if (m->mf_fsflags & FS_MKMNT) {
(void) rmdirs(m->mf_mount);
m->mf_flags &= ~MFF_MKMNT;
}
diff --git a/contrib/amd/amd/amfs_program.c b/contrib/amd/amd/amfs_program.c
index 795c596..843e805 100644
--- a/contrib/amd/amd/amfs_program.c
+++ b/contrib/amd/amd/amfs_program.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1989 Jan-Simon Pendry
* Copyright (c) 1989 Imperial College of Science, Technology & Medicine
* Copyright (c) 1989 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: amfs_program.c,v 1.6.2.4 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/amfs_program.c
*
*/
@@ -54,8 +53,8 @@
/* forward definitions */
static char *amfs_program_match(am_opts *fo);
-static int amfs_program_fmount(mntfs *mf);
-static int amfs_program_fumount(mntfs *mf);
+static int amfs_program_mount(am_node *am, mntfs *mf);
+static int amfs_program_umount(am_node *am, mntfs *mf);
static int amfs_program_init(mntfs *mf);
/*
@@ -66,17 +65,20 @@ am_ops amfs_program_ops =
"program",
amfs_program_match,
amfs_program_init,
- amfs_auto_fmount,
- amfs_program_fmount,
- amfs_auto_fumount,
- amfs_program_fumount,
- amfs_error_lookuppn,
+ amfs_program_mount,
+ amfs_program_umount,
+ amfs_error_lookup_child,
+ amfs_error_mount_child,
amfs_error_readdir,
0, /* amfs_program_readlink */
0, /* amfs_program_mounted */
0, /* amfs_program_umounted */
- find_amfs_auto_srvr,
- FS_BACKGROUND | FS_AMQINFO
+ amfs_generic_find_srvr,
+ 0, /* amfs_program_get_wchan */
+ FS_MKMNT | FS_BACKGROUND | FS_AMQINFO, /* nfs_fs_flags */
+#ifdef HAVE_FS_AUTOFS
+ AUTOFS_PROGRAM_FS_FLAGS,
+#endif /* HAVE_FS_AUTOFS */
};
@@ -88,10 +90,19 @@ amfs_program_match(am_opts *fo)
{
char *prog;
- if (!fo->opt_mount || !fo->opt_unmount) {
- plog(XLOG_ERROR, "program: both mount and unmount must be specified");
+ if (fo->opt_unmount && fo->opt_umount) {
+ plog(XLOG_ERROR, "program: cannot specify both unmount and umount options");
return 0;
}
+ if (!fo->opt_mount) {
+ plog(XLOG_ERROR, "program: must specify mount command");
+ return 0;
+ }
+ if (!fo->opt_unmount && !fo->opt_umount) {
+ fo->opt_unmount = str3cat(NULL, UNMOUNT_PROGRAM, " umount ", fo->opt_fs);
+ plog(XLOG_INFO, "program: un/umount not specified; using default \"%s\"",
+ fo->opt_unmount);
+ }
prog = strchr(fo->opt_mount, ' ');
return strdup(prog ? prog + 1 : fo->opt_mount);
@@ -101,13 +112,16 @@ amfs_program_match(am_opts *fo)
static int
amfs_program_init(mntfs *mf)
{
- /*
- * Save unmount command
- */
- if (mf->mf_refc == 1) {
- mf->mf_private = (voidp) strdup(mf->mf_fo->opt_unmount);
- mf->mf_prfree = (void (*)(voidp)) free;
- }
+ /* check if already saved value */
+ if (mf->mf_private != NULL)
+ return 0;
+
+ /* save unmount (or umount) command */
+ if (mf->mf_fo->opt_unmount != NULL)
+ mf->mf_private = (opaque_t) strdup(mf->mf_fo->opt_unmount);
+ else
+ mf->mf_private = (opaque_t) strdup(mf->mf_fo->opt_umount);
+ mf->mf_prfree = (void (*)(opaque_t)) free;
return 0;
}
@@ -142,8 +156,7 @@ amfs_program_exec(char *info)
/*
* Try the exec
*/
-#ifdef DEBUG
- amuDebug(D_FULL) {
+ if (amuDebug(D_FULL)) {
char **cp = xivec;
plog(XLOG_DEBUG, "executing (un)mount command...");
while (*cp) {
@@ -151,7 +164,6 @@ amfs_program_exec(char *info)
cp++;
}
}
-#endif /* DEBUG */
if (xivec[0] == 0 || xivec[1] == 0) {
errno = EINVAL;
@@ -180,14 +192,14 @@ amfs_program_exec(char *info)
static int
-amfs_program_fmount(mntfs *mf)
+amfs_program_mount(am_node *am, mntfs *mf)
{
return amfs_program_exec(mf->mf_fo->opt_mount);
}
static int
-amfs_program_fumount(mntfs *mf)
+amfs_program_umount(am_node *am, mntfs *mf)
{
return amfs_program_exec((char *) mf->mf_private);
}
diff --git a/contrib/amd/amd/amfs_root.c b/contrib/amd/amd/amfs_root.c
index 9d121bb..243267e 100644
--- a/contrib/amd/amd/amfs_root.c
+++ b/contrib/amd/amd/amfs_root.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: amfs_root.c,v 1.3.2.4 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/amfs_root.c
*
*/
@@ -55,7 +54,7 @@
/****************************************************************************
*** FORWARD DEFINITIONS ***
****************************************************************************/
-static int amfs_root_mount(am_node *mp);
+static int amfs_root_mount(am_node *mp, mntfs *mf);
/****************************************************************************
*** OPS STRUCTURES ***
@@ -66,16 +65,19 @@ am_ops amfs_root_ops =
0, /* amfs_root_match */
0, /* amfs_root_init */
amfs_root_mount,
- 0,
- amfs_auto_umount,
- 0,
- amfs_auto_lookuppn,
- amfs_auto_readdir,
+ amfs_generic_umount,
+ amfs_generic_lookup_child,
+ amfs_generic_mount_child,
+ amfs_generic_readdir,
0, /* amfs_root_readlink */
0, /* amfs_root_mounted */
0, /* amfs_root_umounted */
- find_amfs_auto_srvr,
- FS_NOTIMEOUT | FS_AMQINFO | FS_DIRECTORY
+ amfs_generic_find_srvr,
+ 0, /* amfs_root_get_wchan */
+ FS_NOTIMEOUT | FS_AMQINFO | FS_DIRECTORY, /* nfs_fs_flags */
+#ifdef HAVE_FS_AUTOFS
+ AUTOFS_ROOT_FS_FLAGS,
+#endif /* HAVE_FS_AUTOFS */
};
@@ -87,12 +89,10 @@ am_ops amfs_root_ops =
* Mount the root...
*/
static int
-amfs_root_mount(am_node *mp)
+amfs_root_mount(am_node *mp, mntfs *mf)
{
- mntfs *mf = mp->am_mnt;
-
mf->mf_mount = strealloc(mf->mf_mount, pid_fsname);
- mf->mf_private = (voidp) mapc_find(mf->mf_info, "", NULL);
+ mf->mf_private = (opaque_t) mapc_find(mf->mf_info, "", NULL);
mf->mf_prfree = mapc_free;
return 0;
diff --git a/contrib/amd/amd/amfs_toplvl.c b/contrib/amd/amd/amfs_toplvl.c
index c0e7604..1b968f1 100644
--- a/contrib/amd/amd/amfs_toplvl.c
+++ b/contrib/amd/amd/amfs_toplvl.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: amfs_toplvl.c,v 1.7.2.5 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/amfs_toplvl.c
*
*/
@@ -55,7 +54,7 @@
/****************************************************************************
*** FORWARD DEFINITIONS ***
****************************************************************************/
-
+static int amfs_toplvl_init(mntfs *mf);
/****************************************************************************
*** OPS STRUCTURES ***
@@ -63,19 +62,23 @@
am_ops amfs_toplvl_ops =
{
"toplvl",
- amfs_auto_match,
- 0, /* amfs_auto_init */
+ amfs_generic_match,
+ amfs_toplvl_init, /* amfs_toplvl_init */
amfs_toplvl_mount,
- 0,
amfs_toplvl_umount,
- 0,
- amfs_auto_lookuppn,
- amfs_auto_readdir, /* browsable version of readdir() */
+ amfs_generic_lookup_child,
+ amfs_generic_mount_child,
+ amfs_generic_readdir,
0, /* amfs_toplvl_readlink */
- amfs_toplvl_mounted,
+ amfs_generic_mounted,
0, /* amfs_toplvl_umounted */
- find_amfs_auto_srvr,
- FS_MKMNT | FS_NOTIMEOUT | FS_BACKGROUND | FS_AMQINFO | FS_DIRECTORY
+ amfs_generic_find_srvr,
+ 0, /* amfs_toplvl_get_wchan */
+ FS_MKMNT | FS_NOTIMEOUT | FS_BACKGROUND |
+ FS_AMQINFO | FS_DIRECTORY, /* nfs_fs_flags */
+#ifdef HAVE_FS_AUTOFS
+ AUTOFS_TOPLVL_FS_FLAGS,
+#endif /* HAVE_FS_AUTOFS */
};
@@ -83,166 +86,79 @@ am_ops amfs_toplvl_ops =
*** FUNCTIONS ***
****************************************************************************/
-/*
- * Mount an automounter directory.
- * The automounter is connected into the system
- * as a user-level NFS server. mount_amfs_toplvl constructs
- * the necessary NFS parameters to be given to the
- * kernel so that it will talk back to us.
- *
- * NOTE: automounter mounts in themselves are using NFS Version 2.
- */
-static int
-mount_amfs_toplvl(char *dir, char *opts)
+static void
+set_auto_attrcache_timeout(char *preopts, char *opts, size_t l)
{
- char fs_hostname[MAXHOSTNAMELEN + MAXPATHLEN + 1];
- int retry, error, genflags;
- mntent_t mnt;
- nfs_args_t nfs_args;
- am_nfs_fh *fhp;
- am_nfs_handle_t anh;
- MTYPE_TYPE type = MOUNT_TYPE_NFS;
-#ifndef HAVE_TRANSPORT_TYPE_TLI
- u_short port;
- struct sockaddr_in sin;
-#endif /* not HAVE_TRANSPORT_TYPE_TLI */
-
- memset((voidp) &mnt, 0, sizeof(mnt));
- mnt.mnt_dir = dir;
- mnt.mnt_fsname = pid_fsname;
- mnt.mnt_opts = opts;
-
- /*
- * Make sure that amd's top-level NFS mounts are hidden by default
- * from df.
- * If they don't appear to support the either the "ignore" mnttab
- * option entry, or the "auto" one, set the mount type to "nfs".
- */
- mnt.mnt_type = HIDE_MOUNT_TYPE;
-
- retry = hasmntval(&mnt, MNTTAB_OPT_RETRY);
- if (retry <= 0)
- retry = 2; /* XXX */
-
- /*
- * SET MOUNT ARGS
- */
- /*
- * get fhandle of remote path for automount point
- */
- fhp = root_fh(dir);
- if (!fhp) {
- plog(XLOG_FATAL, "Can't find root file handle for %s", dir);
- return EINVAL;
- }
-#ifndef HAVE_TRANSPORT_TYPE_TLI
+#ifdef MNTTAB_OPT_NOAC
/*
- * Create sockaddr to point to the local machine. 127.0.0.1
- * is not used since that will not work in HP-UX clusters and
- * this is no more expensive.
+ * Don't cache attributes - they are changing under the kernel's feet.
+ * For example, IRIX5.2 will dispense with nfs lookup calls and hand stale
+ * filehandles to getattr unless we disable attribute caching on the
+ * automount points.
*/
- memset((voidp) &sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_addr = myipaddr;
- port = hasmntval(&mnt, MNTTAB_OPT_PORT);
- if (port) {
- sin.sin_port = htons(port);
- } else {
- plog(XLOG_ERROR, "no port number specified for %s", dir);
- return EINVAL;
+ if (gopt.auto_attrcache == 0) {
+ xsnprintf(preopts, l, ",%s", MNTTAB_OPT_NOAC);
+ xstrlcat(opts, preopts, l);
}
-#endif /* not HAVE_TRANSPORT_TYPE_TLI */
+#endif /* MNTTAB_OPT_NOAC */
/*
- * Make a ``hostname'' string for the kernel
- */
- sprintf(fs_hostname, "pid%ld@%s:%s",
- (long) (foreground ? am_mypid : getppid()),
- am_get_hostname(),
- dir);
- /*
- * Most kernels have a name length restriction (64 bytes)...
+ * XXX: note that setting these to 0 in the past resulted in an error on
+ * some systems, which is why it's better to use "noac" if possible. For
+ * now, we're setting everything possible, but if this will cause trouble,
+ * then we'll have to condition the remainder of this on OPT_NOAC.
*/
- if (strlen(fs_hostname) >= MAXHOSTNAMELEN)
- strcpy(fs_hostname + MAXHOSTNAMELEN - 3, "..");
-#ifdef HOSTNAMESZ
- /*
- * ... and some of these restrictions are 32 bytes (HOSTNAMESZ)
- * If you need to get the definition for HOSTNAMESZ found, you may
- * add the proper header file to the conf/nfs_prot/nfs_prot_*.h file.
- */
- if (strlen(fs_hostname) >= HOSTNAMESZ)
- strcpy(fs_hostname + HOSTNAMESZ - 3, "..");
-#endif /* HOSTNAMESZ */
+#ifdef MNTTAB_OPT_ACTIMEO
+ xsnprintf(preopts, l, ",%s=%d", MNTTAB_OPT_ACTIMEO, gopt.auto_attrcache);
+ xstrlcat(opts, preopts, l);
+#else /* MNTTAB_OPT_ACTIMEO */
+# ifdef MNTTAB_OPT_ACDIRMIN
+ xsnprintf(preopts, l, ",%s=%d", MNTTAB_OPT_ACTDIRMIN, gopt.auto_attrcache);
+ xstrlcat(opts, preopts, l);
+# endif /* MNTTAB_OPT_ACDIRMIN */
+# ifdef MNTTAB_OPT_ACDIRMAX
+ xsnprintf(preopts, l, ",%s=%d", MNTTAB_OPT_ACTDIRMAX, gopt.auto_attrcache);
+ xstrlcat(opts, preopts, l);
+# endif /* MNTTAB_OPT_ACDIRMAX */
+# ifdef MNTTAB_OPT_ACREGMIN
+ xsnprintf(preopts, l, ",%s=%d", MNTTAB_OPT_ACTREGMIN, gopt.auto_attrcache);
+ xstrlcat(opts, preopts, l);
+# endif /* MNTTAB_OPT_ACREGMIN */
+# ifdef MNTTAB_OPT_ACREGMAX
+ xsnprintf(preopts, l, ",%s=%d", MNTTAB_OPT_ACTREGMAX, gopt.auto_attrcache);
+ xstrlcat(opts, preopts, l);
+# endif /* MNTTAB_OPT_ACREGMAX */
+#endif /* MNTTAB_OPT_ACTIMEO */
+}
- /*
- * Finally we can compute the mount genflags set above,
- * and add any automounter specific flags.
- */
- genflags = compute_mount_flags(&mnt);
- genflags |= compute_automounter_mount_flags(&mnt);
- /* setup the many fields and flags within nfs_args */
- memmove(&anh.v2.fhs_fh, fhp, sizeof(*fhp));
-#ifdef HAVE_TRANSPORT_TYPE_TLI
- compute_nfs_args(&nfs_args,
- &mnt,
- genflags,
- nfsncp,
- NULL, /* remote host IP addr is set below */
- NFS_VERSION, /* version 2 */
- "udp",
- &anh,
- fs_hostname,
- pid_fsname);
- /*
- * IMPORTANT: set the correct IP address AFTERWARDS. It cannot
- * be done using the normal mechanism of compute_nfs_args(), because
- * that one will allocate a new address and use NFS_SA_DREF() to copy
- * parts to it, while assuming that the ip_addr passed is always
- * a "struct sockaddr_in". That assumption is incorrect on TLI systems,
- * because they define a special macro HOST_SELF which is DIFFERENT
- * than localhost (127.0.0.1)!
- */
- nfs_args.addr = &nfsxprt->xp_ltaddr;
-#else /* not HAVE_TRANSPORT_TYPE_TLI */
- compute_nfs_args(&nfs_args,
- &mnt,
- genflags,
- &sin,
- NFS_VERSION, /* version 2 */
- "udp",
- &anh,
- fs_hostname,
- pid_fsname);
-#endif /* not HAVE_TRANSPORT_TYPE_TLI */
-
- /*************************************************************************
- * NOTE: while compute_nfs_args() works ok for regular NFS mounts *
- * the toplvl one is not, and so some options must be corrected by hand *
- * more carefully, *after* compute_nfs_args() runs. *
- *************************************************************************/
- compute_automounter_nfs_args(&nfs_args, &mnt);
+/*
+ * Initialize a top-level mount. In our case, if the user asked for
+ * forced_unmounts, and the OS supports it, then we try forced/lazy unmounts
+ * on any previous toplvl mounts. This is useful if a previous Amd died and
+ * left behind toplvl mount points (this Amd will clean them up).
+ *
+ * WARNING: Don't use forced/lazy unmounts if you have another valid Amd
+ * running, because this code WILL force those valid toplvl mount points to
+ * be detached as well!
+ */
+static int
+amfs_toplvl_init(mntfs *mf)
+{
+ int error = 0;
- /* This is it! Here we try to mount amd on its mount points */
-#ifdef DEBUG
- amuDebug(D_TRACE) {
- print_nfs_args(&nfs_args, 0);
- plog(XLOG_DEBUG, "Generic mount flags 0x%x", genflags);
+#if defined(MNT2_GEN_OPT_FORCE) || defined(MNT2_GEN_OPT_DETACH)
+ if (gopt.flags & CFM_FORCED_UNMOUNTS) {
+ plog(XLOG_INFO, "amfs_toplvl_init: trying forced/lazy unmount of %s",
+ mf->mf_mount);
+ error = umount2_fs(mf->mf_mount, AMU_UMOUNT_FORCE | AMU_UMOUNT_DETACH);
+ if (error)
+ plog(XLOG_INFO, "amfs_toplvl_init: forced/lazy unmount failed: %m");
+ else
+ dlog("amfs_toplvl_init: forced/lazy unmount succeeded");
}
-#endif /* DEBUG */
- error = mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type,
- 0, NULL, mnttab_file_name);
-
-#ifdef HAVE_TRANSPORT_TYPE_TLI
- free_knetconfig(nfs_args.knconf);
- /*
- * local automounter mounts do not allocate a special address, so
- * no need to XFREE(nfs_args.addr) under TLI.
- */
-#endif /* HAVE_TRANSPORT_TYPE_TLI */
-
+#endif /* MNT2_GEN_OPT_FORCE || MNT2_GEN_OPT_DETACH */
return error;
}
@@ -251,13 +167,11 @@ mount_amfs_toplvl(char *dir, char *opts)
* Mount the top-level
*/
int
-amfs_toplvl_mount(am_node *mp)
+amfs_toplvl_mount(am_node *mp, mntfs *mf)
{
- mntfs *mf = mp->am_mnt;
struct stat stb;
- char opts[256], preopts[256];
+ char opts[SIZEOF_OPTS], preopts[SIZEOF_OPTS], toplvl_opts[40];
int error;
- char *mnttype;
/*
* Mounting the automounter.
@@ -271,16 +185,6 @@ amfs_toplvl_mount(am_node *mp)
plog(XLOG_WARNING, "%s is not a directory", mp->am_path);
return ENOTDIR;
}
- if (mf->mf_ops == &amfs_toplvl_ops)
- mnttype = "indirect";
- else if (mf->mf_ops == &amfs_direct_ops)
- mnttype = "direct";
-#ifdef HAVE_AMU_FS_UNION
- else if (mf->mf_ops == &amfs_union_ops)
- mnttype = "union";
-#endif /* HAVE_AMU_FS_UNION */
- else
- mnttype = "auto";
/*
* Construct some mount options:
@@ -288,49 +192,71 @@ amfs_toplvl_mount(am_node *mp)
* Tack on magic map=<mapname> option in mtab to emulate
* SunOS automounter behavior.
*/
- preopts[0] = '\0';
+
+#ifdef HAVE_FS_AUTOFS
+ if (mf->mf_flags & MFF_IS_AUTOFS) {
+ autofs_get_opts(opts, sizeof(opts), mp->am_autofs_fh);
+ } else
+#endif /* HAVE_FS_AUTOFS */
+ {
+ preopts[0] = '\0';
#ifdef MNTTAB_OPT_INTR
- strcat(preopts, MNTTAB_OPT_INTR);
- strcat(preopts, ",");
+ xstrlcat(preopts, MNTTAB_OPT_INTR, sizeof(preopts));
+ xstrlcat(preopts, ",", sizeof(preopts));
#endif /* MNTTAB_OPT_INTR */
#ifdef MNTTAB_OPT_IGNORE
- strcat(preopts, MNTTAB_OPT_IGNORE);
- strcat(preopts, ",");
+ xstrlcat(preopts, MNTTAB_OPT_IGNORE, sizeof(preopts));
+ xstrlcat(preopts, ",", sizeof(preopts));
#endif /* MNTTAB_OPT_IGNORE */
- sprintf(opts, "%s%s,%s=%d,%s=%d,%s=%d,%s,map=%s",
- preopts,
- MNTTAB_OPT_RW,
- MNTTAB_OPT_PORT, nfs_port,
- MNTTAB_OPT_TIMEO, gopt.amfs_auto_timeo,
- MNTTAB_OPT_RETRANS, gopt.amfs_auto_retrans,
- mnttype, mf->mf_info);
+ /* write most of the initial options + preopts */
+ xsnprintf(opts, sizeof(opts), "%s%s,%s=%d,%s,map=%s",
+ preopts,
+ MNTTAB_OPT_RW,
+ MNTTAB_OPT_PORT, nfs_port,
+ mf->mf_ops->fs_type, mf->mf_info);
+
+ /* process toplvl timeo/retrans options, if any */
+ if (gopt.amfs_auto_timeo[AMU_TYPE_TOPLVL] > 0) {
+ xsnprintf(toplvl_opts, sizeof(toplvl_opts), ",%s=%d",
+ MNTTAB_OPT_TIMEO, gopt.amfs_auto_timeo[AMU_TYPE_TOPLVL]);
+ xstrlcat(opts, toplvl_opts, sizeof(opts));
+ }
+ if (gopt.amfs_auto_retrans[AMU_TYPE_TOPLVL] > 0) {
+ xsnprintf(toplvl_opts, sizeof(toplvl_opts), ",%s=%d",
+ MNTTAB_OPT_RETRANS, gopt.amfs_auto_retrans[AMU_TYPE_TOPLVL]);
+ xstrlcat(opts, toplvl_opts, sizeof(opts));
+ }
+
+#ifdef MNTTAB_OPT_NOAC
+ if (gopt.auto_attrcache == 0) {
+ xstrlcat(opts, ",", sizeof(opts));
+ xstrlcat(opts, MNTTAB_OPT_NOAC, sizeof(opts));
+ } else
+#endif /* MNTTAB_OPT_NOAC */
+ set_auto_attrcache_timeout(preopts, opts, sizeof(preopts));
+ }
/* now do the mount */
- error = mount_amfs_toplvl(mf->mf_mount, opts);
+ error = amfs_mount(mp, mf, opts);
if (error) {
errno = error;
- plog(XLOG_FATAL, "amfs_toplvl_mount: mount_amfs_toplvl failed: %m");
+ plog(XLOG_FATAL, "amfs_toplvl_mount: amfs_mount failed: %m");
return error;
}
return 0;
}
-void
-amfs_toplvl_mounted(mntfs *mf)
-{
- amfs_auto_mkcacheref(mf);
-}
-
-
/*
* Unmount a top-level automount node
*/
int
-amfs_toplvl_umount(am_node *mp)
+amfs_toplvl_umount(am_node *mp, mntfs *mf)
{
- int error;
struct stat stb;
+ int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
+ int error;
+ int count = 0; /* how many times did we try to unmount? */
again:
/*
@@ -345,15 +271,48 @@ again:
* actually fixed the problem - so simulate an ls -ld here.
*/
if (lstat(mp->am_path, &stb) < 0) {
-#ifdef DEBUG
+ error = errno;
dlog("lstat(%s): %m", mp->am_path);
-#endif /* DEBUG */
+ goto out;
}
- error = UMOUNT_FS(mp->am_path, mnttab_file_name);
+ if ((stb.st_mode & S_IFMT) != S_IFDIR) {
+ plog(XLOG_ERROR, "amfs_toplvl_umount: %s is not a directory, aborting.", mp->am_path);
+ error = ENOTDIR;
+ goto out;
+ }
+
+ error = UMOUNT_FS(mp->am_path, mnttab_file_name, unmount_flags);
if (error == EBUSY) {
+#ifdef HAVE_FS_AUTOFS
+ /*
+ * autofs mounts are "in place", so it is possible
+ * that we can't just unmount our mount points and go away.
+ * If that's the case, just give up.
+ */
+ if (mf->mf_flags & MFF_IS_AUTOFS)
+ return error;
+#endif /* HAVE_FS_AUTOFS */
plog(XLOG_WARNING, "amfs_toplvl_unmount retrying %s in 1s", mp->am_path);
- sleep(1); /* XXX */
+ count++;
+ sleep(1);
+ /*
+ * If user wants forced/lazy unmount semantics, then set those flags,
+ * but only after we've tried normal lstat/umount a few times --
+ * otherwise forced unmounts may hang this very same Amd (by preventing
+ * it from achieving a clean unmount).
+ */
+ if (gopt.flags & CFM_FORCED_UNMOUNTS) {
+ if (count == 5) { /* after 5 seconds, try MNT_FORCE */
+ dlog("enabling forced unmounts for toplvl node %s", mp->am_path);
+ unmount_flags |= AMU_UMOUNT_FORCE;
+ }
+ if (count == 10) { /* after 10 seconds, try MNT_DETACH */
+ dlog("enabling detached unmounts for toplvl node %s", mp->am_path);
+ unmount_flags |= AMU_UMOUNT_DETACH;
+ }
+ }
goto again;
}
+out:
return error;
}
diff --git a/contrib/amd/amd/amfs_union.c b/contrib/amd/amd/amfs_union.c
index 2a74d8c..6adb5b0 100644
--- a/contrib/amd/amd/amfs_union.c
+++ b/contrib/amd/amd/amfs_union.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: amfs_union.c,v 1.3.2.5 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/amfs_union.c
*
*/
@@ -55,6 +54,7 @@
/****************************************************************************
*** FORWARD DEFINITIONS ***
****************************************************************************/
+static int create_amfs_union_node(char *dir, opaque_t arg);
static void amfs_union_mounted(mntfs *mf);
@@ -64,19 +64,22 @@ static void amfs_union_mounted(mntfs *mf);
am_ops amfs_union_ops =
{
"union",
- amfs_auto_match,
- 0, /* amfs_auto_init */
+ amfs_generic_match,
+ 0, /* amfs_union_init */
amfs_toplvl_mount,
- 0,
amfs_toplvl_umount,
- 0,
- amfs_auto_lookuppn,
- amfs_auto_readdir,
- 0, /* amfs_toplvl_readlink */
+ amfs_generic_lookup_child,
+ amfs_generic_mount_child,
+ amfs_generic_readdir,
+ 0, /* amfs_union_readlink */
amfs_union_mounted,
- 0, /* amfs_toplvl_umounted */
- find_amfs_auto_srvr,
- FS_MKMNT | FS_NOTIMEOUT | FS_BACKGROUND | FS_AMQINFO | FS_DIRECTORY
+ 0, /* amfs_union_umounted */
+ amfs_generic_find_srvr,
+ 0, /* amfs_union_get_wchan */
+ FS_MKMNT | FS_NOTIMEOUT | FS_BACKGROUND | FS_AMQINFO | FS_DIRECTORY,
+#ifdef HAVE_FS_AUTOFS
+ AUTOFS_UNION_FS_FLAGS,
+#endif /* HAVE_FS_AUTOFS */
};
@@ -85,11 +88,14 @@ am_ops amfs_union_ops =
* XXX: this function may not be used anywhere...
*/
static int
-create_amfs_union_node(char *dir, voidp arg)
+create_amfs_union_node(char *dir, opaque_t arg)
{
if (!STREQ(dir, "/defaults")) {
int error = 0;
- (void) amfs_toplvl_ops.lookuppn(arg, dir, &error, VLOOK_CREATE);
+ am_node *am;
+ am = amfs_generic_lookup_child(arg, dir, &error, VLOOK_CREATE);
+ if (am && error < 0)
+ am = amfs_generic_mount_child(am, &error);
if (error > 0) {
errno = error; /* XXX */
plog(XLOG_ERROR, "unionfs: could not mount %s: %m", dir);
@@ -103,20 +109,22 @@ create_amfs_union_node(char *dir, voidp arg)
static void
amfs_union_mounted(mntfs *mf)
{
- int i;
+ int index;
+ am_node *mp;
- amfs_auto_mkcacheref(mf);
+ amfs_mkcacheref(mf);
/*
* Having made the union mount point,
* populate all the entries...
*/
- for (i = 0; i <= last_used_map; i++) {
- am_node *mp = exported_ap[i];
- if (mp && mp->am_mnt == mf) {
+ for (mp = get_first_exported_ap(&index);
+ mp;
+ mp = get_next_exported_ap(&index)) {
+ if (mp->am_mnt == mf) {
/* return value from create_amfs_union_node is ignored by mapc_keyiter */
(void) mapc_keyiter((mnt_map *) mp->am_mnt->mf_private,
- (void (*)(char *, voidp)) create_amfs_union_node,
+ create_amfs_union_node,
mp);
break;
}
diff --git a/contrib/amd/amd/amq_subr.c b/contrib/amd/amd/amq_subr.c
index d0e49ba..79ecafc 100644
--- a/contrib/amd/amd/amq_subr.c
+++ b/contrib/amd/amd/amq_subr.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: amq_subr.c,v 1.6.2.6 2004/01/19 00:25:55 ezk Exp $
+ * File: am-utils/amd/amq_subr.c
*
*/
/*
@@ -111,8 +110,10 @@ amq_mount_tree_list *
amqproc_export_1_svc(voidp argp, struct svc_req *rqstp)
{
static amq_mount_tree_list aml;
+ static am_node *mp;
- aml.amq_mount_tree_list_val = (amq_mount_tree_p *) &exported_ap[0];
+ mp = get_exported_ap(0);
+ aml.amq_mount_tree_list_val = (amq_mount_tree_p *) ((void *) &mp);
aml.amq_mount_tree_list_len = 1; /* XXX */
return &aml;
@@ -130,16 +131,14 @@ amqproc_setopt_1_svc(voidp argp, struct svc_req *rqstp)
switch (opt->as_opt) {
case AMOPT_DEBUG:
-#ifdef DEBUG
if (debug_option(opt->as_str))
-#endif /* DEBUG */
rc = EINVAL;
break;
case AMOPT_LOGFILE:
if (gopt.logfile && opt->as_str
&& STREQ(gopt.logfile, opt->as_str)) {
- if (switch_to_logfile(opt->as_str, orig_umask))
+ if (switch_to_logfile(opt->as_str, orig_umask, 0))
rc = EINVAL;
} else {
rc = EACCES;
@@ -155,8 +154,8 @@ amqproc_setopt_1_svc(voidp argp, struct svc_req *rqstp)
if (amd_state == Run) {
plog(XLOG_INFO, "amq says flush cache");
do_mapc_reload = 0;
- flush_nfs_fhandle_cache((fserver *) 0);
- flush_srvr_nfs_cache();
+ flush_nfs_fhandle_cache((fserver *) NULL);
+ flush_srvr_nfs_cache((fserver *) NULL);
}
break;
}
@@ -168,7 +167,7 @@ amqproc_setopt_1_svc(voidp argp, struct svc_req *rqstp)
amq_mount_info_list *
amqproc_getmntfs_1_svc(voidp argp, struct svc_req *rqstp)
{
- return (amq_mount_info_list *) ((void *)&mfhead); /* XXX */
+ return (amq_mount_info_list *) ((void *)&mfhead); /* XXX */
}
@@ -194,6 +193,64 @@ amqproc_getpid_1_svc(voidp argp, struct svc_req *rqstp)
/*
+ * Process PAWD string of remote pawd tool.
+ *
+ * We repeat the resolution of the string until the resolved string resolves
+ * to itself. This ensures that we follow path resolutions through all
+ * possible Amd mount points until we reach some sort of convergence. To
+ * prevent possible infinite loops, we break out of this loop if the strings
+ * do not converge after MAX_PAWD_TRIES times.
+ */
+amq_string *
+amqproc_pawd_1_svc(voidp argp, struct svc_req *rqstp)
+{
+ static amq_string res;
+#define MAX_PAWD_TRIES 10
+ int index, len, maxagain = MAX_PAWD_TRIES;
+ am_node *mp;
+ char *mountpoint;
+ char *dir = *(char **) argp;
+ static char tmp_buf[MAXPATHLEN];
+ char prev_buf[MAXPATHLEN];
+
+ tmp_buf[0] = prev_buf[0] = '\0'; /* default is empty string: no match */
+ do {
+ for (mp = get_first_exported_ap(&index);
+ mp;
+ mp = get_next_exported_ap(&index)) {
+ if (STREQ(mp->am_mnt->mf_ops->fs_type, "toplvl"))
+ continue;
+ if (STREQ(mp->am_mnt->mf_ops->fs_type, "auto"))
+ continue;
+ mountpoint = (mp->am_link ? mp->am_link : mp->am_mnt->mf_mount);
+ len = strlen(mountpoint);
+ if (len == 0)
+ continue;
+ if (!NSTREQ(mountpoint, dir, len))
+ continue;
+ if (dir[len] != '\0' && dir[len] != '/')
+ continue;
+ xstrlcpy(tmp_buf, mp->am_path, sizeof(tmp_buf));
+ xstrlcat(tmp_buf, &dir[len], sizeof(tmp_buf));
+ break;
+ } /* end of "for" loop */
+ /* once tmp_buf and prev_buf are equal, break out of "do" loop */
+ if (STREQ(tmp_buf, prev_buf))
+ break;
+ else
+ xstrlcpy(prev_buf, tmp_buf, sizeof(prev_buf));
+ } while (--maxagain);
+ /* check if we couldn't resolve the string after MAX_PAWD_TRIES times */
+ if (maxagain <= 0)
+ plog(XLOG_WARNING, "path \"%s\" did not resolve after %d tries",
+ tmp_buf, MAX_PAWD_TRIES);
+
+ res = tmp_buf;
+ return &res;
+}
+
+
+/*
* XDR routines.
*/
@@ -201,7 +258,7 @@ amqproc_getpid_1_svc(voidp argp, struct svc_req *rqstp)
bool_t
xdr_amq_setopt(XDR *xdrs, amq_setopt *objp)
{
- if (!xdr_enum(xdrs, (enum_t *) & objp->as_opt)) {
+ if (!xdr_enum(xdrs, (enum_t *) ((voidp) &objp->as_opt))) {
return (FALSE);
}
if (!xdr_string(xdrs, &objp->as_str, AMQ_STRLEN)) {
@@ -266,10 +323,16 @@ xdr_amq_mount_subtree(XDR *xdrs, amq_mount_tree *objp)
if (!xdr_amq_mount_tree_node(xdrs, objp)) {
return (FALSE);
}
- if (!xdr_pointer(xdrs, (char **) &mp->am_osib, sizeof(amq_mount_tree), (XDRPROC_T_TYPE) xdr_amq_mount_subtree)) {
+ if (!xdr_pointer(xdrs,
+ (char **) ((voidp) &mp->am_osib),
+ sizeof(amq_mount_tree),
+ (XDRPROC_T_TYPE) xdr_amq_mount_subtree)) {
return (FALSE);
}
- if (!xdr_pointer(xdrs, (char **) &mp->am_child, sizeof(amq_mount_tree), (XDRPROC_T_TYPE) xdr_amq_mount_subtree)) {
+ if (!xdr_pointer(xdrs,
+ (char **) ((voidp) &mp->am_child),
+ sizeof(amq_mount_tree),
+ (XDRPROC_T_TYPE) xdr_amq_mount_subtree)) {
return (FALSE);
}
return (TRUE);
@@ -280,15 +343,21 @@ bool_t
xdr_amq_mount_tree(XDR *xdrs, amq_mount_tree *objp)
{
am_node *mp = (am_node *) objp;
- am_node *mnil = 0;
+ am_node *mnil = NULL;
if (!xdr_amq_mount_tree_node(xdrs, objp)) {
return (FALSE);
}
- if (!xdr_pointer(xdrs, (char **) ((void *)&mnil), sizeof(amq_mount_tree), (XDRPROC_T_TYPE) xdr_amq_mount_subtree)) {
+ if (!xdr_pointer(xdrs,
+ (char **) ((voidp) &mnil),
+ sizeof(amq_mount_tree),
+ (XDRPROC_T_TYPE) xdr_amq_mount_subtree)) {
return (FALSE);
}
- if (!xdr_pointer(xdrs, (char **) &mp->am_child, sizeof(amq_mount_tree), (XDRPROC_T_TYPE) xdr_amq_mount_subtree)) {
+ if (!xdr_pointer(xdrs,
+ (char **) ((voidp) &mp->am_child),
+ sizeof(amq_mount_tree),
+ (XDRPROC_T_TYPE) xdr_amq_mount_subtree)) {
return (FALSE);
}
return (TRUE);
@@ -332,7 +401,7 @@ bool_t
xdr_amq_mount_tree_list(XDR *xdrs, amq_mount_tree_list *objp)
{
if (!xdr_array(xdrs,
- (char **) &objp->amq_mount_tree_list_val,
+ (char **) ((voidp) &objp->amq_mount_tree_list_val),
(u_int *) &objp->amq_mount_tree_list_len,
~0,
sizeof(amq_mount_tree_p),
@@ -354,7 +423,7 @@ xdr_amq_mount_info_qelem(XDR *xdrs, qelem *qhead)
u_int len = 0;
for (mf = AM_LAST(mntfs, qhead); mf != HEAD(mntfs, qhead); mf = PREV(mntfs, mf)) {
- if (!(mf->mf_ops->fs_flags & FS_AMQINFO))
+ if (!(mf->mf_fsflags & FS_AMQINFO))
continue;
len++;
}
@@ -365,7 +434,7 @@ xdr_amq_mount_info_qelem(XDR *xdrs, qelem *qhead)
*/
for (mf = AM_LAST(mntfs, qhead); mf != HEAD(mntfs, qhead); mf = PREV(mntfs, mf)) {
int up;
- if (!(mf->mf_ops->fs_flags & FS_AMQINFO))
+ if (!(mf->mf_fsflags & FS_AMQINFO))
continue;
if (!xdr_amq_string(xdrs, &mf->mf_ops->fs_type)) {
@@ -386,20 +455,12 @@ xdr_amq_mount_info_qelem(XDR *xdrs, qelem *qhead)
if (!xdr_int(xdrs, &mf->mf_refc)) {
return (FALSE);
}
- if (mf->mf_server->fs_flags & FSF_ERROR)
+ if (FSRV_ERROR(mf->mf_server) || FSRV_ISDOWN(mf->mf_server))
up = 0;
+ else if (FSRV_ISUP(mf->mf_server))
+ up = 1;
else
- switch (mf->mf_server->fs_flags & (FSF_DOWN | FSF_VALID)) {
- case FSF_DOWN | FSF_VALID:
- up = 0;
- break;
- case FSF_VALID:
- up = 1;
- break;
- default:
- up = -1;
- break;
- }
+ up = -1;
if (!xdr_int(xdrs, &up)) {
return (FALSE);
}
diff --git a/contrib/amd/amd/amq_svc.c b/contrib/amd/amd/amq_svc.c
index 8468567..6fadb16 100644
--- a/contrib/amd/amd/amq_svc.c
+++ b/contrib/amd/amd/amq_svc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: amq_svc.c,v 1.4.2.5 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/amq_svc.c
*
*/
@@ -51,6 +50,65 @@
/* typedefs */
typedef char *(*amqsvcproc_t)(voidp, struct svc_req *);
+#if defined(HAVE_TCPD_H) && defined(HAVE_LIBWRAP)
+# ifdef NEED_LIBWRAP_SEVERITY_VARIABLES
+/*
+ * Some systems that define libwrap already define these two variables
+ * in libwrap, while others don't: so I need to know precisely iff
+ * to define these two severity variables.
+ */
+int allow_severity=0, deny_severity=0;
+# endif /* NEED_LIBWRAP_SEVERITY_VARIABLES */
+
+/*
+ * check if remote amq is authorized to access this amd.
+ * Returns: 1=allowed, 0=denied.
+ */
+static int
+amqsvc_is_client_allowed(const struct sockaddr_in *addr, char *remote)
+{
+ struct hostent *h;
+ char *name = NULL, **ad;
+ int ret = 0; /* default is 0==denied */
+
+ /* Check IP address */
+ if (hosts_ctl(AMD_SERVICE_NAME, "", remote, "")) {
+ ret = 1;
+ goto out;
+ }
+ /* Get address */
+ if (!(h = gethostbyaddr((const char *)&(addr->sin_addr),
+ sizeof(addr->sin_addr),
+ AF_INET)))
+ goto out;
+ if (!(name = strdup(h->h_name)))
+ goto out;
+ /* Paranoia check */
+ if (!(h = gethostbyname(name)))
+ goto out;
+ for (ad = h->h_addr_list; *ad; ad++)
+ if (!memcmp(*ad, &(addr->sin_addr), h->h_length))
+ break;
+ if (!*ad)
+ goto out;
+ if (hosts_ctl(AMD_SERVICE_NAME, "", h->h_name, "")) {
+ return 1;
+ goto out;
+ }
+ /* Check aliases */
+ for (ad = h->h_aliases; *ad; ad++)
+ if (hosts_ctl(AMD_SERVICE_NAME, "", *ad, "")) {
+ return 1;
+ goto out;
+ }
+
+ out:
+ if (name)
+ XFREE(name);
+ return ret;
+}
+#endif /* defined(HAVE_TCPD_H) && defined(HAVE_LIBWRAP) */
+
void
amq_program_1(struct svc_req *rqstp, SVCXPRT *transp)
@@ -64,6 +122,21 @@ amq_program_1(struct svc_req *rqstp, SVCXPRT *transp)
xdrproc_t xdr_argument, xdr_result;
amqsvcproc_t local;
+#if defined(HAVE_TCPD_H) && defined(HAVE_LIBWRAP)
+ if (gopt.flags & CFM_USE_TCPWRAPPERS) {
+ struct sockaddr_in *remote_addr = svc_getcaller(rqstp->rq_xprt);
+ char *remote_hostname = inet_ntoa(remote_addr->sin_addr);
+
+ if (!amqsvc_is_client_allowed(remote_addr, remote_hostname)) {
+ plog(XLOG_WARNING, "Amd denied remote amq service to %s", remote_hostname);
+ svcerr_auth(transp, AUTH_FAILED);
+ return;
+ } else {
+ dlog("Amd allowed remote amq service to %s", remote_hostname);
+ }
+ }
+#endif /* defined(HAVE_TCPD_H) && defined(HAVE_LIBWRAP) */
+
switch (rqstp->rq_proc) {
case AMQPROC_NULL:
@@ -120,6 +193,12 @@ amq_program_1(struct svc_req *rqstp, SVCXPRT *transp)
local = (amqsvcproc_t) amqproc_getpid_1_svc;
break;
+ case AMQPROC_PAWD:
+ xdr_argument = (xdrproc_t) xdr_amq_string;
+ xdr_result = (xdrproc_t) xdr_amq_string;
+ local = (amqsvcproc_t) amqproc_pawd_1_svc;
+ break;
+
default:
svcerr_noproc(transp);
return;
diff --git a/contrib/amd/amd/autil.c b/contrib/amd/amd/autil.c
index bb43918..a5ecd6d 100644
--- a/contrib/amd/amd/autil.c
+++ b/contrib/amd/amd/autil.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: autil.c,v 1.4.2.6 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/autil.c
*
*/
@@ -52,100 +51,49 @@
#include <am_defs.h>
#include <amd.h>
-int NumChild = 0; /* number of children of primary amd */
+int NumChildren = 0; /* number of children of primary amd */
static char invalid_keys[] = "\"'!;@ \t\n";
+/****************************************************************************
+ *** MACROS ***
+ ****************************************************************************/
+
#ifdef HAVE_TRANSPORT_TYPE_TLI
# define PARENT_USLEEP_TIME 100000 /* 0.1 seconds */
#endif /* HAVE_TRANSPORT_TYPE_TLI */
+/****************************************************************************
+ *** FORWARD DEFINITIONS ***
+ ****************************************************************************/
+static void domain_strip(char *otherdom, char *localdom);
+static int dofork(void);
+
+
+/****************************************************************************
+ *** FUNCTIONS ***
+ ****************************************************************************/
+
+/*
+ * Copy s into p, reallocating p if necessary
+ */
char *
strealloc(char *p, char *s)
{
- int len = strlen(s) + 1;
+ size_t len = strlen(s) + 1;
p = (char *) xrealloc((voidp) p, len);
- strcpy(p, s);
+ xstrlcpy(p, s, len);
#ifdef DEBUG_MEM
+# if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY)
malloc_verify();
+# endif /* not defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY) */
#endif /* DEBUG_MEM */
return p;
}
-char **
-strsplit(char *s, int ch, int qc)
-{
- char **ivec;
- int ic = 0;
- int done = 0;
-
- ivec = (char **) xmalloc((ic + 1) * sizeof(char *));
-
- while (!done) {
- char *v;
-
- /*
- * skip to split char
- */
- while (*s && (ch == ' ' ? (isascii(*s) && isspace((int)*s)) : *s == ch))
- *s++ = '\0';
-
- /*
- * End of string?
- */
- if (!*s)
- break;
-
- /*
- * remember start of string
- */
- v = s;
-
- /*
- * skip to split char
- */
- while (*s && !(ch == ' ' ? (isascii(*s) && isspace((int)*s)) : *s == ch)) {
- if (*s++ == qc) {
- /*
- * Skip past string.
- */
- s++;
- while (*s && *s != qc)
- s++;
- if (*s == qc)
- s++;
- }
- }
-
- if (!*s)
- done = 1;
- *s++ = '\0';
-
- /*
- * save string in new ivec slot
- */
- ivec[ic++] = v;
- ivec = (char **) xrealloc((voidp) ivec, (ic + 1) * sizeof(char *));
-#ifdef DEBUG
- amuDebug(D_STR)
- plog(XLOG_DEBUG, "strsplit saved \"%s\"", v);
-#endif /* DEBUG */
- }
-
-#ifdef DEBUG
- amuDebug(D_STR)
- plog(XLOG_DEBUG, "strsplit saved a total of %d strings", ic);
-#endif /* DEBUG */
-
- ivec[ic] = 0;
-
- return ivec;
-}
-
-
/*
* Strip off the trailing part of a domain
* to produce a short-form domain relative
@@ -170,7 +118,8 @@ domain_strip(char *otherdom, char *localdom)
/*
- * Normalize a host name
+ * Normalize a host name: replace cnames with real names, and decide if to
+ * strip domain name or not.
*/
void
host_normalize(char **chp)
@@ -182,20 +131,18 @@ host_normalize(char **chp)
*/
if (gopt.flags & CFM_NORMALIZE_HOSTNAMES) {
struct hostent *hp;
- clock_valid = 0;
hp = gethostbyname(*chp);
if (hp && hp->h_addrtype == AF_INET) {
-#ifdef DEBUG
dlog("Hostname %s normalized to %s", *chp, hp->h_name);
-#endif /* DEBUG */
*chp = strealloc(*chp, (char *) hp->h_name);
}
}
- domain_strip(*chp, hostd);
+ if (gopt.flags & CFM_DOMAIN_STRIP) {
+ domain_strip(*chp, hostd);
+ }
}
-
/*
* Keys are not allowed to contain " ' ! or ; to avoid
* problems with macro expansions.
@@ -226,14 +173,20 @@ forcibly_timeout_mp(am_node *mp)
} else {
plog(XLOG_INFO, "\"%s\" forcibly timed out", mp->am_path);
mp->am_flags &= ~AMF_NOTIMEOUT;
- mp->am_ttl = clocktime();
+ mp->am_ttl = clocktime(NULL);
+ /*
+ * Force mtime update of parent dir, to prevent DNLC/dcache from caching
+ * the old entry, which could result in ESTALE errors, bad symlinks, and
+ * more.
+ */
+ clocktime(&mp->am_parent->am_fattr.na_mtime);
reschedule_timeout_mp();
}
}
void
-mf_mounted(mntfs *mf)
+mf_mounted(mntfs *mf, bool_t call_free_opts)
{
int quoted;
int wasmounted = mf->mf_flags & MFF_MOUNTED;
@@ -250,10 +203,33 @@ mf_mounted(mntfs *mf)
/*
* Do mounted callback
*/
- if (mf->mf_ops->mounted) {
- (*mf->mf_ops->mounted) (mf);
+ if (mf->mf_ops->mounted)
+ mf->mf_ops->mounted(mf);
+
+ /*
+ * Be careful when calling free_ops and XFREE here. Some pseudo file
+ * systems like nfsx call this function (mf_mounted), even though it
+ * would be called by the lower-level amd file system functions. nfsx
+ * needs to call this function because of the other actions it takes.
+ * So we pass a boolean from the caller (yes, not so clean workaround)
+ * to determine if we should free or not. If we're not freeing (often
+ * because we're called from a callback function), then just to be sure,
+ * we'll zero out the am_opts structure and set the pointer to NULL.
+ * The parent mntfs node owns this memory and is going to free it with a
+ * call to mf_mounted(mntfs,TRUE) (see comment in the am_mounted code).
+ */
+ if (call_free_opts) {
+ free_opts(mf->mf_fo); /* this free is needed to prevent leaks */
+ XFREE(mf->mf_fo); /* (also this one) */
+ } else {
+ memset(mf->mf_fo, 0, sizeof(am_opts));
+ mf->mf_fo = NULL;
}
- mf->mf_fo = 0;
+ }
+
+ if (mf->mf_flags & MFF_RESTART) {
+ mf->mf_flags &= ~MFF_RESTART;
+ dlog("Restarted filesystem %s, flags 0x%x", mf->mf_mount, mf->mf_flags);
}
/*
@@ -272,40 +248,61 @@ mf_mounted(mntfs *mf)
void
am_mounted(am_node *mp)
{
+ int notimeout = 0; /* assume normal timeouts initially */
mntfs *mf = mp->am_mnt;
- mf_mounted(mf);
+ /*
+ * This is the parent mntfs which does the mf->mf_fo (am_opts type), and
+ * we're passing TRUE here to tell mf_mounted to actually free the
+ * am_opts. See a related comment in mf_mounted().
+ */
+ mf_mounted(mf, TRUE);
+
+#ifdef HAVE_FS_AUTOFS
+ if (mf->mf_flags & MFF_IS_AUTOFS)
+ autofs_mounted(mp);
+#endif /* HAVE_FS_AUTOFS */
/*
* Patch up path for direct mounts
*/
- if (mp->am_parent && mp->am_parent->am_mnt->mf_ops == &amfs_direct_ops)
+ if (mp->am_parent && mp->am_parent->am_mnt->mf_fsflags & FS_DIRECT)
mp->am_path = str3cat(mp->am_path, mp->am_parent->am_path, "/", ".");
/*
- * Check whether this mount should be cached permanently
+ * Check whether this mount should be cached permanently or not,
+ * and handle user-requested timeouts.
*/
- if (mf->mf_ops->fs_flags & FS_NOTIMEOUT) {
+ /* first check if file system was set to never timeout */
+ if (mf->mf_fsflags & FS_NOTIMEOUT)
+ notimeout = 1;
+ /* next, alter that decision by map flags */
+ if (mf->mf_mopts) {
mntent_t mnt;
mnt.mnt_opts = mf->mf_mopts;
- if (mf->mf_mopts && hasmntopt(&mnt, "unmount"))
- mp->am_flags &= ~AMF_NOTIMEOUT;
+ /* umount option: user wants to unmount this entry */
+ if (amu_hasmntopt(&mnt, "unmount") || amu_hasmntopt(&mnt, "umount"))
+ notimeout = 0;
+ /* noumount option: user does NOT want to unmount this entry */
+ if (amu_hasmntopt(&mnt, "nounmount") || amu_hasmntopt(&mnt, "noumount"))
+ notimeout = 1;
+ /* utimeout=N option: user wants to unmount this option AND set timeout */
+ if ((mp->am_timeo = hasmntval(&mnt, "utimeout")) == 0)
+ mp->am_timeo = gopt.am_timeo; /* otherwise use default timeout */
else
- mp->am_flags |= AMF_NOTIMEOUT;
- } else if (mf->mf_mount[1] == '\0' && mf->mf_mount[0] == '/') {
+ notimeout = 0;
+ /* special case: don't try to unmount "/" (it can never succeed) */
+ if (mf->mf_mount[0] == '/' && mf->mf_mount[1] == '\0')
+ notimeout = 1;
+ }
+ /* finally set actual flags */
+ if (notimeout) {
mp->am_flags |= AMF_NOTIMEOUT;
+ plog(XLOG_INFO, "%s set to never timeout", mp->am_path);
} else {
- mntent_t mnt;
- if (mf->mf_mopts) {
- mnt.mnt_opts = mf->mf_mopts;
- if (hasmntopt(&mnt, "nounmount"))
- mp->am_flags |= AMF_NOTIMEOUT;
- if (hasmntopt(&mnt, "unmount"))
- mp->am_flags &= ~AMF_NOTIMEOUT;
- if ((mp->am_timeo = hasmntval(&mnt, "utimeout")) == 0)
- mp->am_timeo = gopt.am_timeo;
- }
+ mp->am_flags &= ~AMF_NOTIMEOUT;
+ plog(XLOG_INFO, "%s set to timeout in %d seconds", mp->am_path, mp->am_timeo);
}
/*
@@ -313,25 +310,38 @@ am_mounted(am_node *mp)
* compute the length of the returned string.
*/
if (mp->am_fattr.na_type == NFLNK)
- mp->am_fattr.na_size = strlen(mp->am_link ? mp->am_link : mp->am_mnt->mf_mount);
+ mp->am_fattr.na_size = strlen(mp->am_link ? mp->am_link : mf->mf_mount);
/*
- * Record mount time
+ * Record mount time, and update am_stats at the same time.
*/
- mp->am_fattr.na_mtime.nt_seconds = mp->am_stats.s_mtime = clocktime();
+ mp->am_stats.s_mtime = clocktime(&mp->am_fattr.na_mtime);
new_ttl(mp);
/*
- * Update mtime of parent node
+ * Update mtime of parent node (copying "struct nfstime" in '=' below)
*/
if (mp->am_parent && mp->am_parent->am_mnt)
- mp->am_parent->am_fattr.na_mtime.nt_seconds = mp->am_stats.s_mtime;
+ mp->am_parent->am_fattr.na_mtime = mp->am_fattr.na_mtime;
/*
- * Now, if we can, do a reply to our NFS client here
+ * This is ugly, but essentially unavoidable
+ * Sublinks must be treated separately as type==link
+ * when the base type is different.
+ */
+ if (mp->am_link && mf->mf_ops != &amfs_link_ops)
+ amfs_link_ops.mount_fs(mp, mf);
+
+ /*
+ * Now, if we can, do a reply to our client here
* to speed things up.
*/
- quick_reply(mp, 0);
+#ifdef HAVE_FS_AUTOFS
+ if (mp->am_flags & AMF_AUTOFS)
+ autofs_mount_succeeded(mp);
+ else
+#endif /* HAVE_FS_AUTOFS */
+ nfs_quick_reply(mp, 0);
/*
* Update stats
@@ -340,21 +350,303 @@ am_mounted(am_node *mp)
}
+/*
+ * Replace mount point with a reference to an error filesystem.
+ * The mount point (struct mntfs) is NOT discarded,
+ * the caller must do it if it wants to _before_ calling this function.
+ */
+void
+assign_error_mntfs(am_node *mp)
+{
+ int error;
+ dlog("assign_error_mntfs");
+ /*
+ * Save the old error code
+ */
+ error = mp->am_error;
+ if (error <= 0)
+ error = mp->am_mnt->mf_error;
+ /*
+ * Allocate a new error reference
+ */
+ mp->am_mnt = new_mntfs();
+ /*
+ * Put back the error code
+ */
+ mp->am_mnt->mf_error = error;
+ mp->am_mnt->mf_flags |= MFF_ERROR;
+ /*
+ * Zero the error in the mount point
+ */
+ mp->am_error = 0;
+}
+
+
+/*
+ * Build a new map cache for this node, or re-use
+ * an existing cache for the same map.
+ */
+void
+amfs_mkcacheref(mntfs *mf)
+{
+ char *cache;
+
+ if (mf->mf_fo && mf->mf_fo->opt_cache)
+ cache = mf->mf_fo->opt_cache;
+ else
+ cache = "none";
+ mf->mf_private = (opaque_t) mapc_find(mf->mf_info,
+ cache,
+ (mf->mf_fo ? mf->mf_fo->opt_maptype : NULL));
+ mf->mf_prfree = mapc_free;
+}
+
+
+/*
+ * Locate next node in sibling list which is mounted
+ * and is not an error node.
+ */
+am_node *
+next_nonerror_node(am_node *xp)
+{
+ mntfs *mf;
+
+ /*
+ * Bug report (7/12/89) from Rein Tollevik <rein@ifi.uio.no>
+ * Fixes a race condition when mounting direct automounts.
+ * Also fixes a problem when doing a readdir on a directory
+ * containing hung automounts.
+ */
+ while (xp &&
+ (!(mf = xp->am_mnt) || /* No mounted filesystem */
+ mf->mf_error != 0 || /* There was a mntfs error */
+ xp->am_error != 0 || /* There was a mount error */
+ !(mf->mf_flags & MFF_MOUNTED) || /* The fs is not mounted */
+ (mf->mf_server->fs_flags & FSF_DOWN)) /* The fs may be down */
+ )
+ xp = xp->am_osib;
+
+ return xp;
+}
+
+
+/*
+ * Mount an automounter directory.
+ * The automounter is connected into the system
+ * as a user-level NFS server. amfs_mount constructs
+ * the necessary NFS parameters to be given to the
+ * kernel so that it will talk back to us.
+ *
+ * NOTE: automounter mounts in themselves are using NFS Version 2 (UDP).
+ *
+ * NEW: on certain systems, mounting can be done using the
+ * kernel-level automount (autofs) support. In that case,
+ * we don't need NFS at all here.
+ */
int
-mount_node(am_node *mp)
+amfs_mount(am_node *mp, mntfs *mf, char *opts)
{
- mntfs *mf = mp->am_mnt;
- int error = 0;
+ char fs_hostname[MAXHOSTNAMELEN + MAXPATHLEN + 1];
+ int retry, error = 0, genflags;
+ int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
+ char *dir = mf->mf_mount;
+ mntent_t mnt;
+ MTYPE_TYPE type;
+ int forced_unmount = 0; /* are we using forced unmounts? */
+
+ memset((voidp) &mnt, 0, sizeof(mnt));
+ mnt.mnt_dir = dir;
+ mnt.mnt_fsname = pid_fsname;
+ mnt.mnt_opts = opts;
+
+#ifdef HAVE_FS_AUTOFS
+ if (mf->mf_flags & MFF_IS_AUTOFS) {
+ type = MOUNT_TYPE_AUTOFS;
+ /*
+ * Make sure that amd's top-level autofs mounts are hidden by default
+ * from df.
+ * XXX: It works ok on Linux, might not work on other systems.
+ */
+ mnt.mnt_type = "autofs";
+ } else
+#endif /* HAVE_FS_AUTOFS */
+ {
+ type = MOUNT_TYPE_NFS;
+ /*
+ * Make sure that amd's top-level NFS mounts are hidden by default
+ * from df.
+ * If they don't appear to support the either the "ignore" mnttab
+ * option entry, or the "auto" one, set the mount type to "nfs".
+ */
+ mnt.mnt_type = HIDE_MOUNT_TYPE;
+ }
- mf->mf_flags |= MFF_MOUNTING;
- error = (*mf->mf_ops->mount_fs) (mp);
+ retry = hasmntval(&mnt, MNTTAB_OPT_RETRY);
+ if (retry <= 0)
+ retry = 2; /* XXX: default to 2 retries */
- mf = mp->am_mnt;
- if (error >= 0)
- mf->mf_flags &= ~MFF_MOUNTING;
- if (!error && !(mf->mf_ops->fs_flags & FS_MBACKGROUND)) {
- /* ...but see ifs_mount */
- am_mounted(mp);
+ /*
+ * SET MOUNT ARGS
+ */
+
+ /*
+ * Make a ``hostname'' string for the kernel
+ */
+ xsnprintf(fs_hostname, sizeof(fs_hostname), "pid%ld@%s:%s",
+ get_server_pid(), am_get_hostname(), dir);
+ /*
+ * Most kernels have a name length restriction (64 bytes)...
+ */
+ if (strlen(fs_hostname) >= MAXHOSTNAMELEN)
+ xstrlcpy(fs_hostname + MAXHOSTNAMELEN - 3, "..",
+ sizeof(fs_hostname) - MAXHOSTNAMELEN + 3);
+#ifdef HOSTNAMESZ
+ /*
+ * ... and some of these restrictions are 32 bytes (HOSTNAMESZ)
+ * If you need to get the definition for HOSTNAMESZ found, you may
+ * add the proper header file to the conf/nfs_prot/nfs_prot_*.h file.
+ */
+ if (strlen(fs_hostname) >= HOSTNAMESZ)
+ xstrlcpy(fs_hostname + HOSTNAMESZ - 3, "..",
+ sizeof(fs_hostname) - HOSTNAMESZ + 3);
+#endif /* HOSTNAMESZ */
+
+ /*
+ * Finally we can compute the mount genflags set above,
+ * and add any automounter specific flags.
+ */
+ genflags = compute_mount_flags(&mnt);
+#ifdef HAVE_FS_AUTOFS
+ if (on_autofs)
+ genflags |= autofs_compute_mount_flags(&mnt);
+#endif /* HAVE_FS_AUTOFS */
+ genflags |= compute_automounter_mount_flags(&mnt);
+
+again:
+ if (!(mf->mf_flags & MFF_IS_AUTOFS)) {
+ nfs_args_t nfs_args;
+ am_nfs_fh *fhp;
+ am_nfs_handle_t anh;
+#ifndef HAVE_TRANSPORT_TYPE_TLI
+ u_short port;
+ struct sockaddr_in sin;
+#endif /* not HAVE_TRANSPORT_TYPE_TLI */
+
+ /*
+ * get fhandle of remote path for automount point
+ */
+ fhp = get_root_nfs_fh(dir);
+ if (!fhp) {
+ plog(XLOG_FATAL, "Can't find root file handle for %s", dir);
+ return EINVAL;
+ }
+
+#ifndef HAVE_TRANSPORT_TYPE_TLI
+ /*
+ * Create sockaddr to point to the local machine.
+ */
+ memset((voidp) &sin, 0, sizeof(sin));
+ /* as per POSIX, sin_len need not be set (used internally by kernel) */
+ sin.sin_family = AF_INET;
+ sin.sin_addr = myipaddr;
+ port = hasmntval(&mnt, MNTTAB_OPT_PORT);
+ if (port) {
+ sin.sin_port = htons(port);
+ } else {
+ plog(XLOG_ERROR, "no port number specified for %s", dir);
+ return EINVAL;
+ }
+#endif /* not HAVE_TRANSPORT_TYPE_TLI */
+
+ /* setup the many fields and flags within nfs_args */
+ memmove(&anh.v2, fhp, sizeof(*fhp));
+#ifdef HAVE_TRANSPORT_TYPE_TLI
+ compute_nfs_args(&nfs_args,
+ &mnt,
+ genflags,
+ nfsncp,
+ NULL, /* remote host IP addr is set below */
+ NFS_VERSION, /* version 2 */
+ "udp",
+ &anh,
+ fs_hostname,
+ pid_fsname);
+ /*
+ * IMPORTANT: set the correct IP address AFTERWARDS. It cannot
+ * be done using the normal mechanism of compute_nfs_args(), because
+ * that one will allocate a new address and use NFS_SA_DREF() to copy
+ * parts to it, while assuming that the ip_addr passed is always
+ * a "struct sockaddr_in". That assumption is incorrect on TLI systems,
+ * because they define a special macro HOST_SELF which is DIFFERENT
+ * than localhost (127.0.0.1)!
+ */
+ nfs_args.addr = &nfsxprt->xp_ltaddr;
+#else /* not HAVE_TRANSPORT_TYPE_TLI */
+ compute_nfs_args(&nfs_args,
+ &mnt,
+ genflags,
+ NULL,
+ &sin,
+ NFS_VERSION, /* version 2 */
+ "udp",
+ &anh,
+ fs_hostname,
+ pid_fsname);
+#endif /* not HAVE_TRANSPORT_TYPE_TLI */
+
+ /*************************************************************************
+ * NOTE: while compute_nfs_args() works ok for regular NFS mounts *
+ * the toplvl one is not quite regular, and so some options must be *
+ * corrected by hand more carefully, *after* compute_nfs_args() runs. *
+ *************************************************************************/
+ compute_automounter_nfs_args(&nfs_args, &mnt);
+
+ if (amuDebug(D_TRACE)) {
+ print_nfs_args(&nfs_args, 0);
+ plog(XLOG_DEBUG, "Generic mount flags 0x%x", genflags);
+ }
+
+ /* This is it! Here we try to mount amd on its mount points */
+ error = mount_fs(&mnt, genflags, (caddr_t) &nfs_args,
+ retry, type, 0, NULL, mnttab_file_name, on_autofs);
+
+#ifdef HAVE_TRANSPORT_TYPE_TLI
+ free_knetconfig(nfs_args.knconf);
+ /*
+ * local automounter mounts do not allocate a special address, so
+ * no need to XFREE(nfs_args.addr) under TLI.
+ */
+#endif /* HAVE_TRANSPORT_TYPE_TLI */
+
+#ifdef HAVE_FS_AUTOFS
+ } else {
+ /* This is it! Here we try to mount amd on its mount points */
+ error = mount_fs(&mnt, genflags, (caddr_t) mp->am_autofs_fh,
+ retry, type, 0, NULL, mnttab_file_name, on_autofs);
+#endif /* HAVE_FS_AUTOFS */
+ }
+ if (error == 0 || forced_unmount)
+ return error;
+
+ /*
+ * If user wants forced/lazy unmount semantics, then try it iff the
+ * current mount failed with EIO or ESTALE.
+ */
+ if (gopt.flags & CFM_FORCED_UNMOUNTS) {
+ switch (errno) {
+ case ESTALE:
+ case EIO:
+ forced_unmount = errno;
+ plog(XLOG_WARNING, "Mount %s failed (%m); force unmount.", mp->am_path);
+ if ((error = UMOUNT_FS(mp->am_path, mnttab_file_name,
+ AMU_UMOUNT_FORCE | AMU_UMOUNT_DETACH)) < 0) {
+ plog(XLOG_WARNING, "Forced umount %s failed: %m.", mp->am_path);
+ errno = forced_unmount;
+ } else
+ goto again;
+ default:
+ break;
+ }
}
return error;
@@ -373,15 +665,79 @@ am_unmounted(am_node *mp)
* Do unmounted callback
*/
if (mf->mf_ops->umounted)
- (*mf->mf_ops->umounted) (mp);
+ mf->mf_ops->umounted(mf);
+
+ /*
+ * This is ugly, but essentially unavoidable.
+ * Sublinks must be treated separately as type==link
+ * when the base type is different.
+ */
+ if (mp->am_link && mf->mf_ops != &amfs_link_ops)
+ amfs_link_ops.umount_fs(mp, mf);
+
+#ifdef HAVE_FS_AUTOFS
+ if (mf->mf_flags & MFF_IS_AUTOFS)
+ autofs_release_fh(mp);
+ if (mp->am_flags & AMF_AUTOFS)
+ autofs_umount_succeeded(mp);
+#endif /* HAVE_FS_AUTOFS */
+
+ /*
+ * Clean up any directories that were made
+ *
+ * If we remove the mount point of a pending mount, any queued access
+ * to it will fail. So don't do it in that case.
+ * Also don't do it if the refcount is > 1.
+ */
+ if (mf->mf_flags & MFF_MKMNT &&
+ mf->mf_refc == 1 &&
+ !(mp->am_flags & AMF_REMOUNT)) {
+ plog(XLOG_INFO, "removing mountpoint directory '%s'", mf->mf_mount);
+ rmdirs(mf->mf_mount);
+ mf->mf_flags &= ~MFF_MKMNT;
+ }
+
+ /*
+ * If this is a pseudo-directory then adjust the link count
+ * in the parent
+ */
+ if (mp->am_parent && mp->am_fattr.na_type == NFDIR)
+ --mp->am_parent->am_fattr.na_nlink;
/*
* Update mtime of parent node
*/
if (mp->am_parent && mp->am_parent->am_mnt)
- mp->am_parent->am_fattr.na_mtime.nt_seconds = clocktime();
-
- free_map(mp);
+ clocktime(&mp->am_parent->am_fattr.na_mtime);
+
+ if (mp->am_parent && (mp->am_flags & AMF_REMOUNT)) {
+ char *fname = strdup(mp->am_name);
+ am_node *mp_parent = mp->am_parent;
+ mntfs *mf_parent = mp_parent->am_mnt;
+ int error = 0;
+
+ free_map(mp);
+ plog(XLOG_INFO, "am_unmounted: remounting %s", fname);
+ mp = mf_parent->mf_ops->lookup_child(mp_parent, fname, &error, VLOOK_CREATE);
+ if (mp && error < 0)
+ mp = mf_parent->mf_ops->mount_child(mp, &error);
+ if (error > 0) {
+ errno = error;
+ plog(XLOG_ERROR, "am_unmounted: could not remount %s: %m", fname);
+ }
+ XFREE(fname);
+ } else
+ /*
+ * We have a race here.
+ * If this node has a pending mount and amd is going down (unmounting
+ * everything in the process), then we could potentially free it here
+ * while a struct continuation still has a reference to it. So when
+ * amfs_cont is called, it blows up.
+ * We avoid the race by refusing to free any nodes that have
+ * pending mounts (defined as having a non-NULL am_mfarray).
+ */
+ if (!mp->am_mfarray)
+ free_map(mp);
}
@@ -406,7 +762,7 @@ top:
am_set_mypid();
foreground = 0;
} else { /* parent process, has one more child */
- NumChild++;
+ NumChildren++;
}
return pid;
@@ -419,10 +775,9 @@ background(void)
int pid = dofork();
if (pid == 0) {
-#ifdef DEBUG
dlog("backgrounded");
-#endif /* DEBUG */
foreground = 0;
- }
+ } else
+ dlog("forked process %d", pid);
return pid;
}
diff --git a/contrib/amd/amd/clock.c b/contrib/amd/amd/clock.c
index 9f1a068..0caa7df 100644
--- a/contrib/amd/amd/clock.c
+++ b/contrib/amd/amd/clock.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1989 Jan-Simon Pendry
* Copyright (c) 1989 Imperial College of Science, Technology & Medicine
* Copyright (c) 1989 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: clock.c,v 1.4.2.4 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/clock.c
*
*/
@@ -59,14 +58,13 @@
#include <am_defs.h>
#include <amd.h>
-int timeout(u_int secs, void (*fn) (voidp), voidp closure);
void reschedule_timeouts(time_t now, time_t then);
typedef struct callout callout;
struct callout {
callout *c_next; /* List of callouts */
- void (*c_fn) (voidp); /* Function to call */
- voidp c_closure; /* Closure to pass to call */
+ callout_fun *c_fn; /* Function to call */
+ opaque_t c_arg; /* Argument to pass to call */
time_t c_time; /* Time of call */
int c_id; /* Unique identifier */
};
@@ -87,7 +85,7 @@ time_t next_softclock; /* Time of next call to softclock() */
/*
* Global assumption: valid id's are non-zero.
*/
-#define CID_ALLOC(struct ) (++callout_id)
+#define CID_ALLOC() (++callout_id)
#define CID_UNDEF (0)
@@ -121,22 +119,22 @@ free_callout(callout *cp)
/*
* Schedule a callout.
*
- * (*fn)(closure) will be called at clocktime() + secs
+ * (*fn)(fn_arg) will be called at clocktime(NULL) + secs
*/
int
-timeout(u_int secs, void (*fn) (voidp), voidp closure)
+timeout(u_int secs, callout_fun *fn, opaque_t fn_arg)
{
callout *cp, *cp2;
- time_t t = clocktime() + secs;
+ time_t t = clocktime(NULL) + secs;
/*
* Allocate and fill in a new callout structure
*/
callout *cpnew = alloc_callout();
- cpnew->c_closure = closure;
+ cpnew->c_arg = fn_arg;
cpnew->c_fn = fn;
cpnew->c_time = t;
- cpnew->c_id = CID_ALLOC(struct );
+ cpnew->c_id = CID_ALLOC();
if (t < next_softclock)
next_softclock = t;
@@ -189,10 +187,8 @@ reschedule_timeouts(time_t now, time_t then)
for (cp = callouts.c_next; cp; cp = cp->c_next) {
if (cp->c_time >= now && cp->c_time <= then) {
plog(XLOG_WARNING, "job %d rescheduled to run immediately", cp->c_id);
-#ifdef DEBUG
dlog("rescheduling job %d back %ld seconds",
cp->c_id, (long) (cp->c_time - now));
-#endif /* DEBUG */
next_softclock = cp->c_time = now;
}
}
@@ -212,14 +208,14 @@ softclock(void)
if (task_notify_todo)
do_task_notify();
- now = clocktime();
+ now = clocktime(NULL);
/*
* While there are more callouts waiting...
*/
while ((cp = callouts.c_next) && cp->c_time <= now) {
/*
- * Extract first from list, save fn & closure and
+ * Extract first from list, save fn & fn_arg and
* unlink callout from list and free.
* Finally call function.
*
@@ -228,12 +224,12 @@ softclock(void)
* function will call timeout()
* and try to allocate a callout
*/
- void (*fn) (voidp) = cp->c_fn;
- voidp closure = cp->c_closure;
+ callout_fun *fn = cp->c_fn;
+ opaque_t fn_arg = cp->c_arg;
callouts.c_next = cp->c_next;
free_callout(cp);
- (*fn) (closure);
+ (*fn) (fn_arg);
}
} while (task_notify_todo);
diff --git a/contrib/amd/amd/conf.c b/contrib/amd/amd/conf.c
index 90bbdda..2fc587b 100644
--- a/contrib/amd/amd/conf.c
+++ b/contrib/amd/amd/conf.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: conf.c,v 1.7.2.8 2004/01/21 04:04:58 ib42 Exp $
+ * File: am-utils/amd/conf.c
*
*/
@@ -76,12 +75,18 @@ struct _func_map {
* FORWARD DECLARATIONS:
*/
static int gopt_arch(const char *val);
+static int gopt_auto_attrcache(const char *val);
static int gopt_auto_dir(const char *val);
+static int gopt_autofs_use_lofs(const char *val);
static int gopt_browsable_dirs(const char *val);
static int gopt_cache_duration(const char *val);
static int gopt_cluster(const char *val);
+static int gopt_debug_mtab_file(const char *val);
static int gopt_debug_options(const char *val);
static int gopt_dismount_interval(const char *val);
+static int gopt_domain_strip(const char *val);
+static int gopt_exec_map_timeout(const char *val);
+static int gopt_forced_unmounts(const char *val);
static int gopt_full_os(const char *val);
static int gopt_fully_qualified_hosts(const char *val);
static int gopt_hesiod_base(const char *val);
@@ -90,21 +95,34 @@ static int gopt_ldap_base(const char *val);
static int gopt_ldap_cache_maxmem(const char *val);
static int gopt_ldap_cache_seconds(const char *val);
static int gopt_ldap_hostports(const char *val);
+static int gopt_ldap_proto_version(const char *val);
static int gopt_local_domain(const char *val);
+static int gopt_localhost_address(const char *val);
static int gopt_log_file(const char *val);
static int gopt_log_options(const char *val);
+static int gopt_map_defaults(const char *val);
static int gopt_map_options(const char *val);
+static int gopt_map_reload_interval(const char *val);
static int gopt_map_type(const char *val);
static int gopt_mount_type(const char *val);
static int gopt_pid_file(const char *val);
static int gopt_portmap_program(const char *val);
+static int gopt_preferred_amq_port(const char *val);
+static int gopt_nfs_allow_any_interface(const char *val);
static int gopt_nfs_allow_insecure_port(const char *val);
static int gopt_nfs_proto(const char *val);
static int gopt_nfs_retransmit_counter(const char *val);
+static int gopt_nfs_retransmit_counter_udp(const char *val);
+static int gopt_nfs_retransmit_counter_tcp(const char *val);
+static int gopt_nfs_retransmit_counter_toplvl(const char *val);
static int gopt_nfs_retry_interval(const char *val);
+static int gopt_nfs_retry_interval_udp(const char *val);
+static int gopt_nfs_retry_interval_tcp(const char *val);
+static int gopt_nfs_retry_interval_toplvl(const char *val);
static int gopt_nfs_vers(const char *val);
static int gopt_nis_domain(const char *val);
static int gopt_normalize_hostnames(const char *val);
+static int gopt_normalize_slashes(const char *val);
static int gopt_os(const char *val);
static int gopt_osver(const char *val);
static int gopt_plock(const char *val);
@@ -114,33 +132,43 @@ static int gopt_restart_mounts(const char *val);
static int gopt_search_path(const char *val);
static int gopt_selectors_in_defaults(const char *val);
static int gopt_show_statfs_entries(const char *val);
+static int gopt_truncate_log(const char *val);
static int gopt_unmount_on_exit(const char *val);
+static int gopt_use_tcpwrappers(const char *val);
static int gopt_vendor(const char *val);
static int process_global_option(const char *key, const char *val);
-static int process_regular_map(cf_map_t *cfm);
+static int process_one_regular_map(const cf_map_t *cfm);
static int process_regular_option(const char *section, const char *key, const char *val, cf_map_t *cfm);
static int ropt_browsable_dirs(const char *val, cf_map_t *cfm);
static int ropt_map_name(const char *val, cf_map_t *cfm);
+static int ropt_map_defaults(const char *val, cf_map_t *cfm);
static int ropt_map_options(const char *val, cf_map_t *cfm);
static int ropt_map_type(const char *val, cf_map_t *cfm);
static int ropt_mount_type(const char *val, cf_map_t *cfm);
static int ropt_search_path(const char *val, cf_map_t *cfm);
static int ropt_tag(const char *val, cf_map_t *cfm);
-static void reset_cf_map(cf_map_t *cfm);
+static void init_cf_map(cf_map_t *cfm);
/*
* STATIC VARIABLES:
*/
-static cf_map_t cur_map;
+static cf_map_t *head_map, *cur_map;
+
static struct _func_map glob_functable[] = {
{"arch", gopt_arch},
+ {"auto_attrcache", gopt_auto_attrcache},
{"auto_dir", gopt_auto_dir},
+ {"autofs_use_lofs", gopt_autofs_use_lofs},
{"browsable_dirs", gopt_browsable_dirs},
{"cache_duration", gopt_cache_duration},
{"cluster", gopt_cluster},
+ {"debug_mtab_file", gopt_debug_mtab_file},
{"debug_options", gopt_debug_options},
{"dismount_interval", gopt_dismount_interval},
+ {"domain_strip", gopt_domain_strip},
+ {"exec_map_timeout", gopt_exec_map_timeout},
+ {"forced_unmounts", gopt_forced_unmounts},
{"fully_qualified_hosts", gopt_fully_qualified_hosts},
{"full_os", gopt_full_os},
{"hesiod_base", gopt_hesiod_base},
@@ -149,21 +177,34 @@ static struct _func_map glob_functable[] = {
{"ldap_cache_maxmem", gopt_ldap_cache_maxmem},
{"ldap_cache_seconds", gopt_ldap_cache_seconds},
{"ldap_hostports", gopt_ldap_hostports},
+ {"ldap_proto_version", gopt_ldap_proto_version},
{"local_domain", gopt_local_domain},
+ {"localhost_address", gopt_localhost_address},
{"log_file", gopt_log_file},
{"log_options", gopt_log_options},
+ {"map_defaults", gopt_map_defaults},
{"map_options", gopt_map_options},
+ {"map_reload_interval", gopt_map_reload_interval},
{"map_type", gopt_map_type},
{"mount_type", gopt_mount_type},
{"pid_file", gopt_pid_file},
{"portmap_program", gopt_portmap_program},
+ {"preferred_amq_port", gopt_preferred_amq_port},
+ {"nfs_allow_any_interface", gopt_nfs_allow_any_interface},
{"nfs_allow_insecure_port", gopt_nfs_allow_insecure_port},
{"nfs_proto", gopt_nfs_proto},
{"nfs_retransmit_counter", gopt_nfs_retransmit_counter},
+ {"nfs_retransmit_counter_udp", gopt_nfs_retransmit_counter_udp},
+ {"nfs_retransmit_counter_tcp", gopt_nfs_retransmit_counter_tcp},
+ {"nfs_retransmit_counter_toplvl", gopt_nfs_retransmit_counter_toplvl},
{"nfs_retry_interval", gopt_nfs_retry_interval},
+ {"nfs_retry_interval_udp", gopt_nfs_retry_interval_udp},
+ {"nfs_retry_interval_tcp", gopt_nfs_retry_interval_tcp},
+ {"nfs_retry_interval_toplvl", gopt_nfs_retry_interval_toplvl},
{"nfs_vers", gopt_nfs_vers},
{"nis_domain", gopt_nis_domain},
{"normalize_hostnames", gopt_normalize_hostnames},
+ {"normalize_slashes", gopt_normalize_slashes},
{"os", gopt_os},
{"osver", gopt_osver},
{"plock", gopt_plock},
@@ -174,61 +215,43 @@ static struct _func_map glob_functable[] = {
{"selectors_on_default", gopt_selectors_in_defaults},
{"selectors_in_defaults", gopt_selectors_in_defaults},
{"show_statfs_entries", gopt_show_statfs_entries},
+ {"truncate_log", gopt_truncate_log},
{"unmount_on_exit", gopt_unmount_on_exit},
+ {"use_tcpwrappers", gopt_use_tcpwrappers},
{"vendor", gopt_vendor},
{NULL, NULL}
};
/*
- * Reset a map.
+ * Initialize a map from [global] defaults.
*/
static void
-reset_cf_map(cf_map_t *cfm)
+init_cf_map(cf_map_t *cfm)
{
if (!cfm)
return;
- if (cfm->cfm_dir) {
- XFREE(cfm->cfm_dir);
- cfm->cfm_dir = NULL;
- }
-
- if (cfm->cfm_name) {
- XFREE(cfm->cfm_name);
- cfm->cfm_name = NULL;
- }
-
- if (cfm->cfm_tag) {
- XFREE(cfm->cfm_tag);
- cfm->cfm_tag = NULL;
- }
-
/*
- * reset/initialize a regular map's flags and other variables from the
+ * Initialize a regular map's flags and other variables from the
* global ones, so that they are applied to all maps. Of course, each map
* can then override the flags individually.
*
* NOTES:
* (1): Will only work for maps that appear after [global].
- * (2): Also be careful not to free() a global option.
- * (3): I'm doing direct char* pointer comparison, and not strcmp(). This
- * is correct!
+ * (2): I'm assigning pointers directly from the global map.
*/
/* initialize map_type from [global] */
- if (cfm->cfm_type && cfm->cfm_type != gopt.map_type)
- XFREE(cfm->cfm_type);
cfm->cfm_type = gopt.map_type;
+ /* initialize map_defaults from [global] */
+ cfm->cfm_defaults = gopt.map_defaults;
+
/* initialize map_opts from [global] */
- if (cfm->cfm_opts && cfm->cfm_opts != gopt.map_options)
- XFREE(cfm->cfm_opts);
cfm->cfm_opts = gopt.map_options;
/* initialize search_path from [global] */
- if (cfm->cfm_search_path && cfm->cfm_search_path != gopt.search_path)
- XFREE(cfm->cfm_search_path);
cfm->cfm_search_path = gopt.search_path;
/*
@@ -242,7 +265,7 @@ reset_cf_map(cf_map_t *cfm)
/*
- * Process configuration file options.
+ * Process configuration file options (called from YACC parser).
* Return 0 if OK, 1 otherwise.
*/
int
@@ -251,50 +274,67 @@ set_conf_kv(const char *section, const char *key, const char *val)
int ret;
#ifdef DEBUG_CONF
- fprintf(stderr,"set_conf_kv: section=%s, key=%s, val=%s\n",
+ fprintf(stderr, "set_conf_kv: section=%s, key=%s, val=%s\n",
section, key, val);
#endif /* DEBUG_CONF */
/*
- * If global section, process them one at a time.
+ * If global section, process kv pairs one at a time.
*/
if (STREQ(section, "global")) {
/*
* Check if a regular map was configured before "global",
- * and process it as needed.
+ * and warn about it.
*/
- if (cur_map.cfm_dir) {
- fprintf(stderr,"processing regular map \"%s\" before global one.\n",
- section);
- ret = process_regular_map(&cur_map); /* will reset map */
- if (ret != 0)
- return ret;
+ if (cur_map && cur_map->cfm_dir) {
+ static short printed_this_error;
+ if (!printed_this_error) {
+ fprintf(stderr, "found regular map \"%s\" before global one.\n",
+ cur_map->cfm_dir);
+ printed_this_error = 1;
+ }
}
/* process the global option first */
ret = process_global_option(key, val);
- /* reset default options for regular maps from just updated globals */
- if (ret == 0)
- reset_cf_map(&cur_map);
-
/* return status from the processing of the global option */
return ret;
}
/*
- * otherwise save options and process a single map all at once.
+ * Otherwise we found a non-global option: store it after some testing.
*/
- /* check if we found a new map, so process one already collected */
- if (cur_map.cfm_dir && !STREQ(cur_map.cfm_dir, section)) {
- ret = process_regular_map(&cur_map); /* will reset map */
- if (ret != 0)
- return ret;
+ /* initialize (static) global list head and current map pointer */
+ if (!head_map && !cur_map) {
+ cur_map = CALLOC(cf_map_t);
+ if (!cur_map) {
+ perror("calloc");
+ exit(1);
+ }
+ /* initialize first head map from global defaults */
+ init_cf_map(cur_map);
+ head_map = cur_map;
+ }
+
+ /* check if we found a new map, then allocate and initialize it */
+ if (cur_map->cfm_dir && !STREQ(cur_map->cfm_dir, section)) {
+ /* allocate new map struct */
+ cf_map_t *tmp_map = CALLOC(cf_map_t);
+ if (!tmp_map) {
+ perror("calloc");
+ exit(1);
+ }
+ /* initialize it from global defaults */
+ init_cf_map(tmp_map);
+ /* append it to end of linked list */
+ cur_map->cfm_next = tmp_map;
+ cur_map = tmp_map;
}
/* now process a single entry of a regular map */
- return process_regular_option(section, key, val, &cur_map);
+ return process_regular_option(section, key, val, cur_map);
}
@@ -332,6 +372,18 @@ gopt_arch(const char *val)
static int
+gopt_auto_attrcache(const char *val)
+{
+ gopt.auto_attrcache = atoi(val);
+ if (gopt.auto_attrcache < 0) {
+ fprintf(stderr, "conf: bad attrcache value: \"%s\"\n", val);
+ return 1;
+ }
+ return 0;
+}
+
+
+static int
gopt_auto_dir(const char *val)
{
gopt.auto_dir = strdup((char *)val);
@@ -340,6 +392,22 @@ gopt_auto_dir(const char *val)
static int
+gopt_autofs_use_lofs(const char *val)
+{
+ if (STREQ(val, "yes")) {
+ gopt.flags |= CFM_AUTOFS_USE_LOFS;
+ return 0;
+ } else if (STREQ(val, "no")) {
+ gopt.flags &= ~CFM_AUTOFS_USE_LOFS;
+ return 0;
+ }
+
+ fprintf(stderr, "conf: unknown value to autofs_use_lofs \"%s\"\n", val);
+ return 1; /* unknown value */
+}
+
+
+static int
gopt_browsable_dirs(const char *val)
{
if (STREQ(val, "full")) {
@@ -377,10 +445,18 @@ gopt_cluster(const char *val)
static int
+gopt_debug_mtab_file(const char *val)
+{
+ gopt.debug_mtab_file = strdup((char*)val);
+ return 0;
+}
+
+
+static int
gopt_debug_options(const char *val)
{
#ifdef DEBUG
- usage += debug_option(strdup((char *)val));
+ usage += debug_option((char *)val);
return 0;
#else /* not DEBUG */
fprintf(stderr, "%s: not compiled with DEBUG option -- sorry.\n",
@@ -401,6 +477,74 @@ gopt_dismount_interval(const char *val)
static int
+gopt_domain_strip(const char *val)
+{
+ if (STREQ(val, "yes")) {
+ gopt.flags |= CFM_DOMAIN_STRIP;
+ return 0;
+ } else if (STREQ(val, "no")) {
+ gopt.flags &= ~CFM_DOMAIN_STRIP;
+ return 0;
+ }
+
+ fprintf(stderr, "conf: unknown value to domain_strip \"%s\"\n", val);
+ return 1; /* unknown value */
+}
+
+
+static int
+gopt_exec_map_timeout(const char *val)
+{
+ gopt.exec_map_timeout = atoi(val);
+ if (gopt.exec_map_timeout <= 0)
+ gopt.exec_map_timeout = AMFS_EXEC_MAP_TIMEOUT; /* default exec map timeout */
+ return 0;
+}
+
+
+static int
+gopt_forced_unmounts(const char *val)
+{
+ if (STREQ(val, "yes")) {
+#if !defined(MNT2_GEN_OPT_DETACH) && !defined(MNT2_GEN_OPT_FORCE)
+ fprintf(stderr, "conf: forced_unmounts unsupported on this system.\n");
+ return 1;
+#else /* defined(MNT2_GEN_OPT_DETACH) || defined(MNT2_GEN_OPT_FORCE) */
+# ifdef __linux__
+ /*
+ * HACK ALERT: Linux has had MNT_FORCE since 2.2, but it hasn't gotten
+ * stable until 2.4. And it had MNT_DETACH since 2.4, but it hasn't
+ * gotten stable since 2.6. So alert users if they're trying to use a
+ * feature that may not work well on their older kernel.
+ */
+ {
+ struct utsname un;
+ if (uname(&un) >= 0) {
+# ifdef MNT2_GEN_OPT_FORCE
+ if (strcmp(un.release, "2.4.0") < 0)
+ fprintf(stderr, "warning: forced-unmounts (MNT_FORCE) may not work well before 2.4.0\n");
+# endif /* MNT2_GEN_OPT_FORCE */
+# ifdef MNT2_GEN_OPT_DETACH
+ if (strcmp(un.release, "2.6.0") < 0)
+ fprintf(stderr, "warning: lazy-unmounts (MNT_DETACH) may not work well before 2.6.0\n");
+# endif /* MNT2_GEN_OPT_DETACH */
+ }
+ }
+# endif /* __linux__ */
+ gopt.flags |= CFM_FORCED_UNMOUNTS;
+ return 0;
+#endif /* defined(MNT2_GEN_OPT_DETACH) || defined(MNT2_GEN_OPT_FORCE) */
+ } else if (STREQ(val, "no")) {
+ gopt.flags &= ~CFM_FORCED_UNMOUNTS;
+ return 0;
+ }
+
+ fprintf(stderr, "conf: unknown value to unmount_on_exit \"%s\"\n", val);
+ return 1; /* unknown value */
+}
+
+
+static int
gopt_full_os(const char *val)
{
gopt.op_sys_full = strdup((char *)val);
@@ -462,6 +606,14 @@ gopt_local_domain(const char *val)
static int
+gopt_localhost_address(const char *val)
+{
+ gopt.localhost_address = strdup((char *)val);
+ return 0;
+}
+
+
+static int
gopt_ldap_base(const char *val)
{
#ifdef HAVE_MAP_LDAP
@@ -527,6 +679,44 @@ gopt_ldap_hostports(const char *val)
static int
+gopt_ldap_proto_version(const char *val)
+{
+#ifdef HAVE_MAP_LDAP
+ char *end;
+
+ gopt.ldap_proto_version = strtol((char *)val, &end, 10);
+ if (end == val) {
+ fprintf(stderr, "conf: bad ldap_proto_version option: %s\n",val);
+ return 1;
+ }
+
+ if (gopt.ldap_proto_version < 0 || gopt.ldap_proto_version > LDAP_VERSION_MAX) {
+ fprintf(stderr, "conf: bad ldap_proto_version option value: %s\n",val);
+ return 1;
+ }
+ switch (gopt.ldap_proto_version) {
+ /* XXX: what about LDAP_VERSION1? */
+ case LDAP_VERSION2:
+#ifdef LDAP_VERSION3
+ case LDAP_VERSION3:
+#endif /* LDAP_VERSION3 */
+#ifdef LDAP_VERSION4
+ case LDAP_VERSION4:
+#endif /* LDAP_VERSION4 */
+ break;
+ default:
+ fprintf(stderr, "conf: unsupported ldap_proto_version option value: %s\n",val);
+ return 1;
+ }
+ return 0;
+#else /* not HAVE_MAP_LDAP */
+ fprintf(stderr, "conf: ldap_proto_version option ignored. No LDAP support available.\n");
+ return 1;
+#endif /* not HAVE_MAP_LDAP */
+}
+
+
+static int
gopt_log_file(const char *val)
{
gopt.logfile = strdup((char *)val);
@@ -537,7 +727,15 @@ gopt_log_file(const char *val)
static int
gopt_log_options(const char *val)
{
- usage += switch_option(strdup((char *)val));
+ usage += switch_option((char *)val);
+ return 0;
+}
+
+
+static int
+gopt_map_defaults(const char *val)
+{
+ gopt.map_defaults = strdup((char *)val);
return 0;
}
@@ -551,6 +749,16 @@ gopt_map_options(const char *val)
static int
+gopt_map_reload_interval(const char *val)
+{
+ gopt.map_reload_interval = atoi(val);
+ if (gopt.map_reload_interval <= 0)
+ gopt.map_reload_interval = ONE_HOUR;
+ return 0;
+}
+
+
+static int
gopt_map_type(const char *val)
{
/* check if map type exist */
@@ -567,9 +775,14 @@ static int
gopt_mount_type(const char *val)
{
if (STREQ(val, "autofs")) {
- fprintf(stderr, "conf: no autofs support available, turning it off\n");
- gopt.flags &= ~CFM_MOUNT_TYPE_AUTOFS;
+#ifdef HAVE_FS_AUTOFS
+ gopt.flags |= CFM_MOUNT_TYPE_AUTOFS;
+ amd_use_autofs++;
return 0;
+#else /* not HAVE_FS_AUTOFS */
+ fprintf(stderr, "conf: no autofs support available\n");
+ return 1;
+#endif /* not HAVE_FS_AUTOFS */
} else if (STREQ(val, "nfs")) {
gopt.flags &= ~CFM_MOUNT_TYPE_AUTOFS;
return 0;
@@ -583,7 +796,7 @@ gopt_mount_type(const char *val)
static int
gopt_portmap_program(const char *val)
{
- gopt.portmap_program = atoi(val);
+ gopt.portmap_program = atol(val);
/*
* allow alternate program numbers to be no more than 10 offset from
* official amd program number (300019).
@@ -602,6 +815,35 @@ gopt_portmap_program(const char *val)
static int
+gopt_preferred_amq_port(const char *val)
+{
+ gopt.preferred_amq_port = atoi(val);
+
+ /*
+ * No need to check value: preferred_amq_port is an unsigned short and 0
+ * is a valid number, meaning "any port".
+ */
+ return 0; /* all is OK */
+}
+
+
+static int
+gopt_nfs_allow_any_interface(const char *val)
+{
+ if (STREQ(val, "yes")) {
+ gopt.flags |= CFM_NFS_ANY_INTERFACE;
+ return 0;
+ } else if (STREQ(val, "no")) {
+ gopt.flags &= ~CFM_NFS_ANY_INTERFACE;
+ return 0;
+ }
+
+ fprintf(stderr, "conf: unknown value to nfs_allow_insecure_port \"%s\"\n", val);
+ return 1; /* unknown value */
+}
+
+
+static int
gopt_nfs_allow_insecure_port(const char *val)
{
if (STREQ(val, "yes")) {
@@ -632,7 +874,34 @@ gopt_nfs_proto(const char *val)
static int
gopt_nfs_retransmit_counter(const char *val)
{
- gopt.amfs_auto_retrans = atoi(val);
+ int i;
+
+ for (i=0; i<AMU_TYPE_MAX; ++i)
+ gopt.amfs_auto_retrans[i] = atoi(val);
+ return 0;
+}
+
+
+static int
+gopt_nfs_retransmit_counter_udp(const char *val)
+{
+ gopt.amfs_auto_retrans[AMU_TYPE_UDP] = atoi(val);
+ return 0;
+}
+
+
+static int
+gopt_nfs_retransmit_counter_tcp(const char *val)
+{
+ gopt.amfs_auto_retrans[AMU_TYPE_TCP] = atoi(val);
+ return 0;
+}
+
+
+static int
+gopt_nfs_retransmit_counter_toplvl(const char *val)
+{
+ gopt.amfs_auto_retrans[AMU_TYPE_TOPLVL] = atoi(val);
return 0;
}
@@ -640,7 +909,34 @@ gopt_nfs_retransmit_counter(const char *val)
static int
gopt_nfs_retry_interval(const char *val)
{
- gopt.amfs_auto_timeo = atoi(val);
+ int i;
+
+ for (i=0; i<AMU_TYPE_MAX; ++i)
+ gopt.amfs_auto_timeo[i] = atoi(val);
+ return 0;
+}
+
+
+static int
+gopt_nfs_retry_interval_udp(const char *val)
+{
+ gopt.amfs_auto_timeo[AMU_TYPE_UDP] = atoi(val);
+ return 0;
+}
+
+
+static int
+gopt_nfs_retry_interval_tcp(const char *val)
+{
+ gopt.amfs_auto_timeo[AMU_TYPE_TCP] = atoi(val);
+ return 0;
+}
+
+
+static int
+gopt_nfs_retry_interval_toplvl(const char *val)
+{
+ gopt.amfs_auto_timeo[AMU_TYPE_TOPLVL] = atoi(val);
return 0;
}
@@ -689,6 +985,22 @@ gopt_normalize_hostnames(const char *val)
static int
+gopt_normalize_slashes(const char *val)
+{
+ if (STREQ(val, "yes")) {
+ gopt.flags |= CFM_NORMALIZE_SLASHES;
+ return 0;
+ } else if (STREQ(val, "no")) {
+ gopt.flags &= ~CFM_NORMALIZE_SLASHES;
+ return 0;
+ }
+
+ fprintf(stderr, "conf: unknown value to normalize_slashes \"%s\"\n", val);
+ return 1; /* unknown value */
+}
+
+
+static int
gopt_os(const char *val)
{
gopt.op_sys = strdup((char *)val);
@@ -740,7 +1052,9 @@ static int
gopt_print_version(const char *val)
{
if (STREQ(val, "yes")) {
- fputs(get_version_string(), stderr);
+ char *vers = get_version_string();
+ fputs(vers, stderr);
+ XFREE(vers);
return 0;
} else if (STREQ(val, "no")) {
return 0;
@@ -808,6 +1122,22 @@ gopt_show_statfs_entries(const char *val)
static int
+gopt_truncate_log(const char *val)
+{
+ if (STREQ(val, "yes")) {
+ gopt.flags |= CFM_TRUNCATE_LOG;
+ return 0;
+ } else if (STREQ(val, "no")) {
+ gopt.flags &= ~CFM_TRUNCATE_LOG;
+ return 0;
+ }
+
+ fprintf(stderr, "conf: unknown value to truncate_log \"%s\"\n", val);
+ return 1; /* unknown value */
+}
+
+
+static int
gopt_unmount_on_exit(const char *val)
{
if (STREQ(val, "yes")) {
@@ -824,6 +1154,27 @@ gopt_unmount_on_exit(const char *val)
static int
+gopt_use_tcpwrappers(const char *val)
+{
+#if defined(HAVE_TCPD_H) && defined(HAVE_LIBWRAP)
+ if (STREQ(val, "yes")) {
+ gopt.flags |= CFM_USE_TCPWRAPPERS;
+ return 0;
+ } else if (STREQ(val, "no")) {
+ gopt.flags &= ~CFM_USE_TCPWRAPPERS;
+ return 0;
+ }
+#else /* not defined(HAVE_TCPD_H) && defined(HAVE_LIBWRAP) */
+ fprintf(stderr, "conf: no tcpd/libwrap support available\n");
+ return 1;
+#endif /* not defined(HAVE_TCPD_H) && defined(HAVE_LIBWRAP) */
+
+ fprintf(stderr, "conf: unknown value to use_tcpwrappers \"%s\"\n", val);
+ return 1; /* unknown value */
+}
+
+
+static int
gopt_vendor(const char *val)
{
gopt.op_sys_vendor = strdup((char *)val);
@@ -857,6 +1208,9 @@ process_regular_option(const char *section, const char *key, const char *val, cf
if (STREQ(key, "map_name"))
return ropt_map_name(val, cfm);
+ if (STREQ(key, "map_defaults"))
+ return ropt_map_defaults(val, cfm);
+
if (STREQ(key, "map_options"))
return ropt_map_options(val, cfm);
@@ -906,6 +1260,14 @@ ropt_map_name(const char *val, cf_map_t *cfm)
static int
+ropt_map_defaults(const char *val, cf_map_t *cfm)
+{
+ cfm->cfm_defaults = strdup((char *)val);
+ return 0;
+}
+
+
+static int
ropt_map_options(const char *val, cf_map_t *cfm)
{
cfm->cfm_opts = strdup((char *)val);
@@ -930,9 +1292,14 @@ static int
ropt_mount_type(const char *val, cf_map_t *cfm)
{
if (STREQ(val, "autofs")) {
- fprintf(stderr, "conf: no autofs support available, turning it off\n");
- cfm->cfm_flags &= ~CFM_MOUNT_TYPE_AUTOFS;
+#ifdef HAVE_FS_AUTOFS
+ cfm->cfm_flags |= CFM_MOUNT_TYPE_AUTOFS;
+ amd_use_autofs++;
return 0;
+#else /* not HAVE_FS_AUTOFS */
+ fprintf(stderr, "conf: no autofs support available\n");
+ return 1;
+#endif /* not HAVE_FS_AUTOFS */
} else if (STREQ(val, "nfs")) {
cfm->cfm_flags &= ~CFM_MOUNT_TYPE_AUTOFS;
return 0;
@@ -963,9 +1330,8 @@ ropt_tag(const char *val, cf_map_t *cfm)
* Process one collected map.
*/
static int
-process_regular_map(cf_map_t *cfm)
+process_one_regular_map(const cf_map_t *cfm)
{
-
if (!cfm->cfm_name) {
fprintf(stderr, "conf: map_name must be defined for map \"%s\"\n", cfm->cfm_dir);
return 1;
@@ -989,22 +1355,52 @@ process_regular_map(cf_map_t *cfm)
fprintf(stderr, "skipping map %s...\n", cfm->cfm_dir);
}
- reset_cf_map(cfm);
return 0;
}
/*
- * Process last map in conf file (if any)
+ * Process all regular maps in conf file (if any)
*/
int
-process_last_regular_map(void)
+process_all_regular_maps(void)
{
+ cf_map_t *tmp_map = head_map;
+
/*
* If the amd.conf file only has a [global] section (pretty useless
- * IMHO), do not try to process a map that does not exist.
+ * IMHO), there's nothing to process
*/
- if (!cur_map.cfm_dir)
+ if (!tmp_map)
return 0;
- return process_regular_map(&cur_map);
+
+ while (tmp_map) {
+ if (process_one_regular_map(tmp_map) != 0)
+ return 1;
+ tmp_map = tmp_map->cfm_next;
+ }
+ return 0;
+}
+
+
+/*
+ * Find a cf_map_t for a given map name.
+ * Return NULL if not found.
+ */
+cf_map_t *
+find_cf_map(const char *name)
+{
+
+ cf_map_t *tmp_map = head_map;
+
+ if (!tmp_map || !name)
+ return NULL;
+
+ while (tmp_map) {
+ if (STREQ(tmp_map->cfm_dir,name)) {
+ return tmp_map;
+ }
+ tmp_map = tmp_map->cfm_next;
+ }
+ return NULL;
}
diff --git a/contrib/amd/amd/conf_parse.y b/contrib/amd/amd/conf_parse.y
index 992d321..b397b05 100644
--- a/contrib/amd/amd/conf_parse.y
+++ b/contrib/amd/amd/conf_parse.y
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1989 Jan-Simon Pendry
* Copyright (c) 1989 Imperial College of Science, Technology & Medicine
* Copyright (c) 1989 The Regents of the University of California.
@@ -37,7 +37,7 @@
* SUCH DAMAGE.
*
*
- * $Id: conf_parse.y,v 1.4.2.5 2004/05/12 15:54:31 ezk Exp $
+ * File: am-utils/amd/conf_parse.y
*
*/
diff --git a/contrib/amd/amd/conf_tok.l b/contrib/amd/amd/conf_tok.l
index 2216993..b572e4d 100644
--- a/contrib/amd/amd/conf_tok.l
+++ b/contrib/amd/amd/conf_tok.l
@@ -1,6 +1,6 @@
%{
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1989 Jan-Simon Pendry
* Copyright (c) 1989 Imperial College of Science, Technology & Medicine
* Copyright (c) 1989 The Regents of the University of California.
@@ -38,7 +38,7 @@
* SUCH DAMAGE.
*
*
- * $Id: conf_tok.l,v 1.3.2.5 2004/05/12 15:54:31 ezk Exp $
+ * File: am-utils/amd/conf_tok.l
*
*/
diff --git a/contrib/amd/amd/get_args.c b/contrib/amd/amd/get_args.c
index df85683..12a7d07 100644
--- a/contrib/amd/amd/get_args.c
+++ b/contrib/amd/amd/get_args.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: get_args.c,v 1.7.2.6 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/get_args.c
*
*/
@@ -55,17 +54,12 @@
/* include auto-generated version file */
#include <build_version.h>
-char *conf_file = "/etc/amd.conf"; /* default amd configuration file */
+char *amu_conf_file = "/etc/amd.conf"; /* default amd configuration file */
char *conf_tag = NULL; /* default conf file tags to use */
int usage = 0;
int use_conf_file = 0; /* default don't use amd.conf file */
char *mnttab_file_name = NULL; /* symbol must be available always */
-#if 0
-#ifdef DEBUG
-int debug_flags = D_AMQ /* Register AMQ */
- | D_DAEMON; /* Enter daemon mode */
-#endif /* DEBUG */
-#endif
+
/*
* Return the version string (dynamic buffer)
@@ -73,48 +67,61 @@ int debug_flags = D_AMQ /* Register AMQ */
char *
get_version_string(void)
{
- static char *vers = NULL;
+ char *vers = NULL;
char tmpbuf[1024];
char *wire_buf;
int wire_buf_len = 0;
+ size_t len; /* max allocated length (to avoid buf overflow) */
- /* first get dynamic string listing all known networks */
+ /*
+ * First get dynamic string listing all known networks.
+ * This could be a long list, if host has lots of interfaces.
+ */
wire_buf = print_wires();
if (wire_buf)
wire_buf_len = strlen(wire_buf);
- vers = xmalloc(2048 + wire_buf_len);
- sprintf(vers, "%s\n%s\n%s\n%s\n",
- "Copyright (c) 1997-2004 Erez Zadok",
- "Copyright (c) 1990 Jan-Simon Pendry",
- "Copyright (c) 1990 Imperial College of Science, Technology & Medicine",
- "Copyright (c) 1990 The Regents of the University of California.");
- sprintf(tmpbuf, "%s version %s (build %d).\n",
- PACKAGE, VERSION, AMU_BUILD_VERSION);
- strcat(vers, tmpbuf);
- sprintf(tmpbuf, "Built by %s@%s on date %s.\n",
- USER_NAME, HOST_NAME, CONFIG_DATE);
- strcat(vers, tmpbuf);
- sprintf(tmpbuf, "cpu=%s (%s-endian), arch=%s, karch=%s.\n",
- cpu, endian, gopt.arch, gopt.karch);
- strcat(vers, tmpbuf);
- sprintf(tmpbuf, "full_os=%s, os=%s, osver=%s, vendor=%s.\n",
- gopt.op_sys_full, gopt.op_sys, gopt.op_sys_ver, gopt.op_sys_vendor);
- strcat(vers, tmpbuf);
-
- strcat(vers, "Map support for: ");
- mapc_showtypes(tmpbuf);
- strcat(vers, tmpbuf);
- strcat(vers, ".\nAMFS: ");
- ops_showamfstypes(tmpbuf);
- strcat(vers, tmpbuf);
- strcat(vers, ".\nFS: ");
- ops_showfstypes(tmpbuf);
- strcat(vers, tmpbuf);
+ len = 2048 + wire_buf_len;
+ vers = xmalloc(len);
+ xsnprintf(vers, len, "%s\n%s\n%s\n%s\n",
+ "Copyright (c) 1997-2006 Erez Zadok",
+ "Copyright (c) 1990 Jan-Simon Pendry",
+ "Copyright (c) 1990 Imperial College of Science, Technology & Medicine",
+ "Copyright (c) 1990 The Regents of the University of California.");
+ xsnprintf(tmpbuf, sizeof(tmpbuf), "%s version %s (build %d).\n",
+ PACKAGE_NAME, PACKAGE_VERSION, AMU_BUILD_VERSION);
+ strlcat(vers, tmpbuf, len);
+ xsnprintf(tmpbuf, sizeof(tmpbuf), "Report bugs to %s.\n", PACKAGE_BUGREPORT);
+ strlcat(vers, tmpbuf, len);
+ xsnprintf(tmpbuf, sizeof(tmpbuf), "Configured by %s@%s on date %s.\n",
+ USER_NAME, HOST_NAME, CONFIG_DATE);
+ strlcat(vers, tmpbuf, len);
+ xsnprintf(tmpbuf, sizeof(tmpbuf), "Built by %s@%s on date %s.\n",
+ BUILD_USER, BUILD_HOST, BUILD_DATE);
+ strlcat(vers, tmpbuf, len);
+ xsnprintf(tmpbuf, sizeof(tmpbuf), "cpu=%s (%s-endian), arch=%s, karch=%s.\n",
+ cpu, endian, gopt.arch, gopt.karch);
+ strlcat(vers, tmpbuf, len);
+ xsnprintf(tmpbuf, sizeof(tmpbuf), "full_os=%s, os=%s, osver=%s, vendor=%s, distro=%s.\n",
+ gopt.op_sys_full, gopt.op_sys, gopt.op_sys_ver, gopt.op_sys_vendor, DISTRO_NAME);
+ strlcat(vers, tmpbuf, len);
+ xsnprintf(tmpbuf, sizeof(tmpbuf), "domain=%s, host=%s, hostd=%s.\n",
+ hostdomain, am_get_hostname(), hostd);
+ strlcat(vers, tmpbuf, len);
+
+ strlcat(vers, "Map support for: ", len);
+ mapc_showtypes(tmpbuf, sizeof(tmpbuf));
+ strlcat(vers, tmpbuf, len);
+ strlcat(vers, ".\nAMFS: ", len);
+ ops_showamfstypes(tmpbuf, sizeof(tmpbuf));
+ strlcat(vers, tmpbuf, len);
+ strlcat(vers, ", inherit.\nFS: ", len); /* hack: "show" that we support type:=inherit */
+ ops_showfstypes(tmpbuf, sizeof(tmpbuf));
+ strlcat(vers, tmpbuf, len);
/* append list of networks if available */
if (wire_buf) {
- strcat(vers, wire_buf);
+ strlcat(vers, wire_buf, len);
XFREE(wire_buf);
}
@@ -122,13 +129,48 @@ get_version_string(void)
}
+static void
+show_usage(void)
+{
+ fprintf(stderr,
+ "Usage: %s [-nprvHS] [-a mount_point] [-c cache_time] [-d domain]\n\
+\t[-k kernel_arch] [-l logfile%s\n\
+\t[-t timeout.retrans] [-w wait_timeout] [-A arch] [-C cluster_name]\n\
+\t[-o op_sys_ver] [-O op_sys_name]\n\
+\t[-F conf_file] [-T conf_tag]", am_get_progname(),
+#ifdef HAVE_SYSLOG
+# ifdef LOG_DAEMON
+ "|\"syslog[:facility]\"]"
+# else /* not LOG_DAEMON */
+ "|\"syslog\"]"
+# endif /* not LOG_DAEMON */
+#else /* not HAVE_SYSLOG */
+ "]"
+#endif /* not HAVE_SYSLOG */
+ );
+
+#ifdef HAVE_MAP_NIS
+ fputs(" [-y nis-domain]\n", stderr);
+#else /* not HAVE_MAP_NIS */
+ fputc('\n', stderr);
+#endif /* HAVE_MAP_NIS */
+
+ show_opts('x', xlog_opt);
+#ifdef DEBUG
+ show_opts('D', dbg_opt);
+#endif /* DEBUG */
+ fprintf(stderr, "\t[directory mapname [-map_options]] ...\n");
+}
+
+
void
get_args(int argc, char *argv[])
{
- int opt_ch;
+ int opt_ch, i;
FILE *fp = stdin;
- char getopt_arguments[] = "+nprvSa:c:d:k:l:o:t:w:x:y:C:D:F:T:O:H";
+ char getopt_arguments[] = "+nprvSa:c:d:k:l:o:t:w:x:y:C:D:F:T:O:HA:";
char *getopt_args;
+ int print_version = 0; /* 1 means we should print version info */
#ifdef HAVE_GNU_GETOPT
getopt_args = getopt_arguments;
@@ -187,24 +229,30 @@ get_args(int argc, char *argv[])
break;
case 't':
- /* timeo.retrans */
+ /* timeo.retrans (also affects toplvl mounts) */
{
char *dot = strchr(optarg, '.');
+ int i;
if (dot)
*dot = '\0';
if (*optarg) {
- gopt.amfs_auto_timeo = atoi(optarg);
+ for (i=0; i<AMU_TYPE_MAX; ++i)
+ gopt.amfs_auto_timeo[i] = atoi(optarg);
}
if (dot) {
- gopt.amfs_auto_retrans = atoi(dot + 1);
+ for (i=0; i<AMU_TYPE_MAX; ++i)
+ gopt.amfs_auto_retrans[i] = atoi(dot + 1);
*dot = '.';
}
}
break;
case 'v':
- fputs(get_version_string(), stderr);
- exit(0);
+ /*
+ * defer to print version info after every variable had been
+ * initialized.
+ */
+ print_version++;
break;
case 'w':
@@ -225,6 +273,10 @@ get_args(int argc, char *argv[])
#endif /* not HAVE_MAP_NIS */
break;
+ case 'A':
+ gopt.arch = optarg;
+ break;
+
case 'C':
gopt.cluster = optarg;
break;
@@ -239,12 +291,13 @@ get_args(int argc, char *argv[])
break;
case 'F':
- conf_file = optarg;
+ amu_conf_file = optarg;
use_conf_file = 1;
break;
case 'H':
- goto show_usage;
+ show_usage();
+ exit(1);
break;
case 'O':
@@ -269,18 +322,19 @@ get_args(int argc, char *argv[])
* specified, then use that amd.conf file. If the file cannot be opened,
* abort amd. If it can be found, open it, parse it, and then close it.
*/
- if (use_conf_file && conf_file) {
- fp = fopen(conf_file, "r");
+ if (use_conf_file && amu_conf_file) {
+ fp = fopen(amu_conf_file, "r");
if (!fp) {
char buf[128];
- sprintf(buf, "Amd configuration file (%s)", conf_file);
+ xsnprintf(buf, sizeof(buf), "Amd configuration file (%s)",
+ amu_conf_file);
perror(buf);
exit(1);
}
yyin = fp;
yyparse();
fclose(fp);
- if (process_last_regular_map() != 0)
+ if (process_all_regular_maps() != 0)
exit(1);
}
@@ -293,8 +347,8 @@ get_args(int argc, char *argv[])
#endif /* DEBUG */
/* log information regarding amd.conf file */
- if (use_conf_file && conf_file)
- plog(XLOG_INFO, "using configuration file %s", conf_file);
+ if (use_conf_file && amu_conf_file)
+ plog(XLOG_INFO, "using configuration file %s", amu_conf_file);
#ifdef HAVE_MAP_LDAP
/* ensure that if ldap_base is specified, that also ldap_hostports is */
@@ -304,8 +358,10 @@ get_args(int argc, char *argv[])
}
#endif /* HAVE_MAP_LDAP */
- if (usage)
- goto show_usage;
+ if (usage) {
+ show_usage();
+ exit(1);
+ }
while (optind <= argc - 2) {
char *dir = argv[optind++];
@@ -327,76 +383,55 @@ get_args(int argc, char *argv[])
hostdomain = gopt.sub_domain;
if (*hostdomain == '.')
hostdomain++;
- strcat(hostd, ".");
- strcat(hostd, hostdomain);
+ xstrlcat(hostd, ".", sizeof(hostd));
+ xstrlcat(hostd, hostdomain, sizeof(hostd));
#ifdef MOUNT_TABLE_ON_FILE
-# ifdef DEBUG
- if (debug_flags & D_MTAB)
- mnttab_file_name = DEBUG_MNTTAB;
+ if (amuDebug(D_MTAB))
+ if (gopt.debug_mtab_file)
+ mnttab_file_name = gopt.debug_mtab_file; /* user supplied debug mtab path */
+ else
+ mnttab_file_name = DEBUG_MNTTAB_FILE; /* default debug mtab path */
else
-# endif /* DEBUG */
mnttab_file_name = MNTTAB_FILE_NAME;
#else /* not MOUNT_TABLE_ON_FILE */
-# ifdef DEBUG
- if (debug_flags & D_MTAB)
+ if (amuDebug(D_MTAB))
dlog("-D mtab option ignored");
-# endif /* DEBUG */
# ifdef MNTTAB_FILE_NAME
mnttab_file_name = MNTTAB_FILE_NAME;
# endif /* MNTTAB_FILE_NAME */
#endif /* not MOUNT_TABLE_ON_FILE */
- if (switch_to_logfile(gopt.logfile, orig_umask) != 0)
- plog(XLOG_USER, "Cannot switch logfile");
-
/*
* If the kernel architecture was not specified
* then use the machine architecture.
*/
- if (gopt.karch == 0)
+ if (gopt.karch == NULL)
gopt.karch = gopt.arch;
- if (gopt.cluster == 0)
+ if (gopt.cluster == NULL)
gopt.cluster = hostdomain;
- if (gopt.amfs_auto_timeo <= 0)
- gopt.amfs_auto_timeo = AMFS_AUTO_TIMEO;
- if (gopt.amfs_auto_retrans <= 0)
- gopt.amfs_auto_retrans = AMFS_AUTO_RETRANS;
- if (gopt.amfs_auto_retrans <= 0)
- gopt.amfs_auto_retrans = 3; /* XXX */
- return;
+ /* sanity checking, normalize values just in case (toplvl too) */
+ for (i=0; i<AMU_TYPE_MAX; ++i) {
+ if (gopt.amfs_auto_timeo[i] == 0)
+ gopt.amfs_auto_timeo[i] = AMFS_AUTO_TIMEO;
+ if (gopt.amfs_auto_retrans[i] == 0)
+ gopt.amfs_auto_retrans[i] = AMFS_AUTO_RETRANS(i);
+ if (gopt.amfs_auto_retrans[i] == 0)
+ gopt.amfs_auto_retrans[i] = 3; /* under very unusual circumstances, could be zero */
+ }
}
-show_usage:
- fprintf(stderr,
- "Usage: %s [-nprvHS] [-a mount_point] [-c cache_time] [-d domain]\n\
-\t[-k kernel_arch] [-l logfile%s\n\
-\t[-t timeout.retrans] [-w wait_timeout] [-C cluster_name]\n\
-\t[-o op_sys_ver] [-O op_sys_name]\n\
-\t[-F conf_file] [-T conf_tag]", am_get_progname(),
-#ifdef HAVE_SYSLOG
-# ifdef LOG_DAEMON
- "|\"syslog[:facility]\"]"
-# else /* not LOG_DAEMON */
- "|\"syslog\"]"
-# endif /* not LOG_DAEMON */
-#else /* not HAVE_SYSLOG */
- "]"
-#endif /* not HAVE_SYSLOG */
- );
+ /* finally print version string and exit, if asked for */
+ if (print_version) {
+ fputs(get_version_string(), stderr);
+ exit(0);
+ }
-#ifdef HAVE_MAP_NIS
- fputs(" [-y nis-domain]\n", stderr);
-#else /* not HAVE_MAP_NIS */
- fputc('\n', stderr);
-#endif /* HAVE_MAP_NIS */
+ if (switch_to_logfile(gopt.logfile, orig_umask,
+ (gopt.flags & CFM_TRUNCATE_LOG)) != 0)
+ plog(XLOG_USER, "Cannot switch logfile");
- show_opts('x', xlog_opt);
-#ifdef DEBUG
- show_opts('D', dbg_opt);
-#endif /* DEBUG */
- fprintf(stderr, "\t[directory mapname [-map_options]] ...\n");
- exit(1);
+ return;
}
diff --git a/contrib/amd/amd/info_exec.c b/contrib/amd/amd/info_exec.c
new file mode 100644
index 0000000..8ccab9a
--- /dev/null
+++ b/contrib/amd/amd/info_exec.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 1997-2006 Erez Zadok
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgment:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *
+ * File: am-utils/amd/info_exec.c
+ *
+ */
+
+/*
+ * Get info from executable map
+ *
+ * Original from Erik Kline, 2004.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* HAVE_CONFIG_H */
+#include <am_defs.h>
+#include <amd.h>
+
+#define MAX_LINE_LEN 1500
+
+/* forward declarations */
+int exec_init(mnt_map *m, char *map, time_t *tp);
+int exec_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp);
+
+
+/*
+ * a timed fgets()
+ */
+static char *
+fgets_timed(char *s, int size, int rdfd, int secs)
+{
+ fd_set fds;
+ struct timeval timeo;
+ time_t start, now;
+ int rval=0, i=0;
+
+ if (!s || size < 0 || rdfd < 0)
+ return 0;
+
+ s[0] = 0;
+ if (size == 0)
+ return s;
+
+ start = clocktime(NULL);
+ while (s[i] != '\n' && i < size-1) {
+ s[i+1] = 0; /* places the requisite trailing '\0' */
+
+ /* ready for reading */
+ rval = read(rdfd, (void *)(s+i), 1);
+ if (rval == 1) {
+ if (s[i] == 0) {
+ rval = 0;
+ break;
+ }
+ i++;
+ continue;
+ } else if (rval == 0) {
+ break;
+ } else if (rval < 0 && errno != EAGAIN && errno != EINTR) {
+ plog(XLOG_WARNING, "fgets_timed read error: %m");
+ break;
+ }
+
+ timeo.tv_usec = 0;
+ now = clocktime(NULL) - start;
+ if (secs <= 0)
+ timeo.tv_sec = 0;
+ else if (now < secs)
+ timeo.tv_sec = secs - now;
+ else {
+ /* timed out (now>=secs) */
+ plog(XLOG_WARNING, "executable map read timed out (> %d secs)", secs);
+ rval = -1;
+ break;
+ }
+
+ FD_ZERO(&fds);
+ FD_SET(rdfd, &fds);
+
+ rval = select(rdfd+1, &fds, 0, 0, &timeo);
+ if (rval < 0) {
+ /* error selecting */
+ plog(XLOG_WARNING, "fgets_timed select error: %m");
+ if (errno == EINTR)
+ continue;
+ rval = -1;
+ break;
+ } else if (rval == 0) {
+ /* timed out */
+ plog(XLOG_WARNING, "executable map read timed out (> %d secs)", secs);
+ rval = -1;
+ break;
+ }
+ }
+
+ if (rval > 0)
+ return s;
+
+ close(rdfd);
+ return (rval == 0 ? s : 0);
+}
+
+
+static int
+read_line(char *buf, int size, int fd)
+{
+ int done = 0;
+
+ while (fgets_timed(buf, size, fd, gopt.exec_map_timeout)) {
+ int len = strlen(buf);
+ done += len;
+ if (len > 1 && buf[len - 2] == '\\' &&
+ buf[len - 1] == '\n') {
+ buf += len - 2;
+ size -= len - 2;
+ *buf = '\n';
+ buf[1] = '\0';
+ } else {
+ return done;
+ }
+ }
+
+ return done;
+}
+
+
+/*
+ * Try to locate a value in a query answer
+ */
+static int
+exec_parse_qanswer(int fd, char *map, char *key, char **pval, time_t *tp)
+{
+ char qanswer[MAX_LINE_LEN], *dc = 0;
+ int chuck = 0;
+ int line_no = 0;
+
+ while (read_line(qanswer, sizeof(qanswer), fd)) {
+ char *cp;
+ char *hash;
+ int len = strlen(qanswer);
+ line_no++;
+
+ /*
+ * Make sure we got the whole line
+ */
+ if (qanswer[len - 1] != '\n') {
+ plog(XLOG_WARNING, "line %d in \"%s\" is too long", line_no, map);
+ chuck = 1;
+ } else {
+ qanswer[len - 1] = '\0';
+ }
+
+ /*
+ * Strip comments
+ */
+ hash = strchr(qanswer, '#');
+ if (hash)
+ *hash = '\0';
+
+ /*
+ * Find beginning of value (query answer)
+ */
+ for (cp = qanswer; *cp && !isascii((int)*cp) && !isspace((int)*cp); cp++)
+ ;;
+
+ /* Ignore blank lines */
+ if (!*cp)
+ goto again;
+
+ /*
+ * Return a copy of the data
+ */
+ dc = strdup(cp);
+ *pval = dc;
+ dlog("%s returns %s", key, dc);
+
+ close(fd);
+ return 0;
+
+ again:
+ /*
+ * If the last read didn't get a whole line then
+ * throw away the remainder before continuing...
+ */
+ if (chuck) {
+ while (fgets_timed(qanswer, sizeof(qanswer), fd, gopt.exec_map_timeout) &&
+ !strchr(qanswer, '\n')) ;
+ chuck = 0;
+ }
+ }
+
+ return ENOENT;
+}
+
+
+static int
+set_nonblock(int fd)
+{
+ int val;
+
+ if (fd < 0)
+ return 0;
+
+ if ((val = fcntl(fd, F_GETFL, 0)) < 0) {
+ plog(XLOG_WARNING, "set_nonblock fcntl F_GETFL error: %m");
+ return 0;
+ }
+
+ val |= O_NONBLOCK;
+ if (fcntl(fd, F_SETFL, val) < 0) {
+ plog(XLOG_WARNING, "set_nonblock fcntl F_SETFL error: %m");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int
+exec_map_open(char *emap, char *key)
+{
+ pid_t p1, p2;
+ int pdes[2], nullfd, i;
+ char *argv[3];
+
+ if (!emap)
+ return 0;
+
+ argv[0] = emap;
+ argv[1] = key;
+ argv[2] = NULL;
+
+ if ((nullfd = open("/dev/null", O_WRONLY|O_NOCTTY)) < 0)
+ return -1;
+
+ if (pipe(pdes) < 0) {
+ close(nullfd);
+ return -1;
+ }
+
+ switch ((p1 = vfork())) {
+ case -1:
+ /* parent: fork error */
+ close(nullfd);
+ close(pdes[0]);
+ close(pdes[1]);
+ return -1;
+ case 0:
+ /* child #1 */
+ p2 = vfork();
+ switch (p2) {
+ case -1:
+ /* child #1: fork error */
+ exit(errno);
+ case 0:
+ /* child #2: init will reap our status */
+ if (pdes[1] != STDOUT_FILENO) {
+ dup2(pdes[1], STDOUT_FILENO);
+ close(pdes[1]);
+ }
+
+ if (nullfd != STDERR_FILENO) {
+ dup2(nullfd, STDERR_FILENO);
+ close(nullfd);
+ }
+
+ for (i=0; i<FD_SETSIZE; i++)
+ if (i != STDOUT_FILENO && i != STDERR_FILENO)
+ close(i);
+
+ /* make the write descriptor non-blocking */
+ if (!set_nonblock(STDOUT_FILENO)) {
+ close(STDOUT_FILENO);
+ exit(-1);
+ }
+
+ execve(emap, argv, NULL);
+ exit(errno); /* in case execve failed */
+ }
+
+ /* child #1 */
+ exit(0);
+ }
+
+ /* parent */
+ close(nullfd);
+ close(pdes[1]);
+
+ /* anti-zombie insurance */
+ while (waitpid(p1,0,0) < 0)
+ if (errno != EINTR)
+ exit(errno);
+
+ /* make the read descriptor non-blocking */
+ if (!set_nonblock(pdes[0])) {
+ close(pdes[0]);
+ return -1;
+ }
+
+ return pdes[0];
+}
+
+
+/*
+ * Check for various permissions on executable map without trying to
+ * fork a new executable-map process.
+ *
+ * return: >0 (errno) if failed
+ * 0 if ok
+ */
+static int
+exec_check_perm(char *map)
+{
+ struct stat sb;
+
+ /* sanity and permission checks */
+ if (!map) {
+ dlog("exec_check_permission got a NULL map");
+ return EINVAL;
+ }
+ if (stat(map, &sb)) {
+ plog(XLOG_ERROR, "map \"%s\" stat failure: %m", map);
+ return errno;
+ }
+ if (!S_ISREG(sb.st_mode)) {
+ plog(XLOG_ERROR, "map \"%s\" should be regular file", map);
+ return EINVAL;
+ }
+ if (sb.st_uid != 0) {
+ plog(XLOG_ERROR, "map \"%s\" owned by uid %u (must be 0)", map, (u_int) sb.st_uid);
+ return EACCES;
+ }
+ if (!(sb.st_mode & S_IXUSR)) {
+ plog(XLOG_ERROR, "map \"%s\" should be executable", map);
+ return EACCES;
+ }
+ if (sb.st_mode & (S_ISUID|S_ISGID)) {
+ plog(XLOG_ERROR, "map \"%s\" should not be setuid/setgid", map);
+ return EACCES;
+ }
+ if (sb.st_mode & S_IWOTH) {
+ plog(XLOG_ERROR, "map \"%s\" should not be world writeable", map);
+ return EACCES;
+ }
+
+ return 0; /* all is well */
+}
+
+
+int
+exec_init(mnt_map *m, char *map, time_t *tp)
+{
+ /*
+ * Basically just test that the executable map can be found
+ * and has proper permissions.
+ */
+ return exec_check_perm(map);
+}
+
+
+int
+exec_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
+{
+ int mapfd, ret;
+
+ if ((ret = exec_check_perm(map)) != 0) {
+ return ret;
+ }
+
+ if (!key)
+ return 0;
+
+ if (logfp)
+ fflush(logfp);
+ dlog("exec_search \"%s\", key: \"%s\"", map, key);
+ mapfd = exec_map_open(map, key);
+
+ if (mapfd >= 0) {
+ if (tp)
+ *tp = clocktime(NULL);
+
+ return exec_parse_qanswer(mapfd, map, key, pval, tp);
+ }
+
+ return errno;
+}
diff --git a/contrib/amd/amd/info_file.c b/contrib/amd/amd/info_file.c
index 8f78868..3777a2a 100644
--- a/contrib/amd/amd/info_file.c
+++ b/contrib/amd/amd/info_file.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: info_file.c,v 1.3.2.5 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/info_file.c
*
*/
@@ -55,10 +54,9 @@
#define MAX_LINE_LEN 1500
/* forward declarations */
-int file_init(mnt_map *m, char *map, time_t *tp);
+int file_init_or_mtime(mnt_map *m, char *map, time_t *tp);
int file_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *));
int file_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp);
-int file_mtime(mnt_map *m, char *map, time_t *tp);
static int
@@ -87,7 +85,7 @@ read_line(char *buf, int size, FILE *fp)
return done;
}
}
- } while (size > 0 && !feof(fp));
+ } while (size > 0 && !feof(fp) && !ferror(fp));
return done;
}
@@ -97,7 +95,12 @@ read_line(char *buf, int size, FILE *fp)
* Try to locate a key in a file
*/
static int
-search_or_reload_file(FILE *fp, char *map, char *key, char **val, mnt_map *m, void (*fn) (mnt_map *m, char *, char *))
+file_search_or_reload(FILE *fp,
+ char *map,
+ char *key,
+ char **val,
+ mnt_map *m,
+ void (*fn) (mnt_map *m, char *, char *))
{
char key_val[MAX_LINE_LEN];
int chuck = 0;
@@ -161,9 +164,7 @@ search_or_reload_file(FILE *fp, char *map, char *key, char **val, mnt_map *m, vo
(*fn) (m, strdup(kp), dc);
} else {
*val = dc;
-#ifdef DEBUG
dlog("%s returns %s", key, dc);
-#endif /* DEBUG */
}
if (!fn)
return 0;
@@ -196,7 +197,7 @@ file_open(char *map, time_t *tp)
if (mapf && tp) {
struct stat stb;
if (fstat(fileno(mapf), &stb) < 0)
- *tp = clocktime();
+ *tp = clocktime(NULL);
else
*tp = stb.st_mtime;
}
@@ -205,7 +206,7 @@ file_open(char *map, time_t *tp)
int
-file_init(mnt_map *m, char *map, time_t *tp)
+file_init_or_mtime(mnt_map *m, char *map, time_t *tp)
{
FILE *mapf = file_open(map, tp);
@@ -223,7 +224,7 @@ file_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *))
FILE *mapf = file_open(map, (time_t *) 0);
if (mapf) {
- int error = search_or_reload_file(mapf, map, 0, 0, m, fn);
+ int error = file_search_or_reload(mapf, map, 0, 0, m, fn);
(void) fclose(mapf);
return error;
}
@@ -243,23 +244,10 @@ file_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
*tp = t;
error = -1;
} else {
- error = search_or_reload_file(mapf, map, key, pval, 0, 0);
+ error = file_search_or_reload(mapf, map, key, pval, 0, 0);
}
(void) fclose(mapf);
return error;
}
return errno;
}
-
-
-int
-file_mtime(mnt_map *m, char *map, time_t *tp)
-{
- FILE *mapf = file_open(map, tp);
-
- if (mapf) {
- (void) fclose(mapf);
- return 0;
- }
- return errno;
-}
diff --git a/contrib/amd/amd/info_hesiod.c b/contrib/amd/amd/info_hesiod.c
index fdcdd56..e345c99 100644
--- a/contrib/amd/amd/info_hesiod.c
+++ b/contrib/amd/amd/info_hesiod.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1989 Jan-Simon Pendry
* Copyright (c) 1989 Imperial College of Science, Technology & Medicine
* Copyright (c) 1989 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: info_hesiod.c,v 1.6.2.4 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/info_hesiod.c
*
*/
@@ -75,13 +74,11 @@ int hesiod_isup(mnt_map *m, char *map);
int
amu_hesiod_init(mnt_map *m, char *map, time_t *tp)
{
-#ifdef DEBUG
dlog("amu_hesiod_init(%s)", map);
-#endif /* DEBUG */
*tp = 0;
#ifdef HAVE_HESIOD_INIT
- if(!hesiod_context && hesiod_init(&hesiod_context) != 0)
+ if (!hesiod_context && hesiod_init(&hesiod_context) != 0)
return ENOENT;
#endif /* HAVE_HESIOD_INIT */
@@ -102,22 +99,21 @@ hesiod_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
int error;
#endif /* not HAVE_HESIOD_INIT */
-#ifdef DEBUG
dlog("hesiod_search(m=%lx, map=%s, key=%s, pval=%lx tp=%lx)",
(unsigned long) m, map, key, (unsigned long) pval, (unsigned long) tp);
-#endif /* DEBUG */
- sprintf(hes_key, "%s.%s", key, map + HES_PREFLEN);
+ if (key[0] == '.')
+ return ENOENT;
+
+ xsnprintf(hes_key, sizeof(hes_key), "%s.%s", key, map + HES_PREFLEN);
/*
* Call the resolver
*/
-#ifdef DEBUG
dlog("Hesiod base is: %s\n", gopt.hesiod_base);
dlog("hesiod_search: hes_resolve(%s, %s)", hes_key, gopt.hesiod_base);
- if (debug_flags & D_INFO)
+ if (amuDebug(D_INFO))
_res.options |= RES_DEBUG;
-#endif /* DEBUG */
#ifdef HAVE_HESIOD_INIT
/* new style hesiod */
@@ -144,9 +140,7 @@ hesiod_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
/*
* Otherwise reflect the hesiod error into a Un*x error
*/
-# ifdef DEBUG
dlog("hesiod_search: Error: %d", hes_error());
-# endif /* DEBUG */
switch (hes_error()) {
case HES_ER_NOTFOUND:
error = ENOENT;
@@ -161,9 +155,7 @@ hesiod_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
error = EINVAL;
break;
}
-# ifdef DEBUG
dlog("hesiod_search: Returning: %d", error);
-# endif /* DEBUG */
return error;
#endif /* not HAVE_HESIOD_INIT */
}
@@ -183,9 +175,7 @@ hesiod_isup(mnt_map *m, char *map)
static int last_status = 1; /* assume up by default */
error = hesiod_search(m, map, "/defaults", &val, &mtime);
-#ifdef DEBUG
dlog("hesiod_isup(%s): %s", map, strerror(error));
-#endif /* DEBUG */
if (error != 0 && error != ENOENT) {
plog(XLOG_ERROR,
"hesiod_isup: error getting `/defaults' entry in map %s: %m", map);
diff --git a/contrib/amd/amd/info_ldap.c b/contrib/amd/amd/info_ldap.c
index 77ae9c4..36ce1c8 100644
--- a/contrib/amd/amd/info_ldap.c
+++ b/contrib/amd/amd/info_ldap.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1989 Jan-Simon Pendry
* Copyright (c) 1989 Imperial College of Science, Technology & Medicine
* Copyright (c) 1989 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: info_ldap.c,v 1.9.2.9 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/info_ldap.c
*
*/
@@ -48,6 +47,20 @@
* LDAP Home Page: http://www.umich.edu/~rsug/ldap/
*/
+/*
+ * WARNING: as of Linux Fedora Core 5 (which comes with openldap-2.3.9), the
+ * ldap.h headers deprecate several functions used in this file, such as
+ * ldap_unbind. You get compile errors about missing extern definitions.
+ * Those externs are still in <ldap.h>, but surrounded by an ifdef
+ * LDAP_DEPRECATED. I am turning on that ifdef here, under the assumption
+ * that the functions may be deprecated, but they still work for this
+ * (older?) version of the LDAP API. It gets am-utils to compile, but it is
+ * not clear if it will work perfectly.
+ */
+#ifndef LDAP_DEPRECATED
+# define LDAP_DEPRECATED 1
+#endif /* not LDAP_DEPRECATED */
+
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
@@ -109,7 +122,7 @@ struct he_ent {
* FORWARD DECLARATIONS:
*/
static int amu_ldap_rebind(ALD *a);
-static int get_ldap_timestamp(LDAP *ld, char *map, time_t *ts);
+static int get_ldap_timestamp(ALD *a, char *map, time_t *ts);
/*
@@ -167,13 +180,54 @@ cr_free(CR *c)
}
+/*
+ * Special ldap_unbind function to handle SIGPIPE.
+ * We first ignore SIGPIPE, in case a remote LDAP server was
+ * restarted, then we reinstall the handler.
+ */
+static int
+amu_ldap_unbind(LDAP *ld)
+{
+ int e;
+#ifdef HAVE_SIGACTION
+ struct sigaction sa;
+#else /* not HAVE_SIGACTION */
+ void (*handler)(int);
+#endif /* not HAVE_SIGACTION */
+
+ dlog("amu_ldap_unbind()\n");
+
+#ifdef HAVE_SIGACTION
+ sa.sa_handler = SIG_IGN;
+ sa.sa_flags = 0;
+ sigemptyset(&(sa.sa_mask));
+ sigaddset(&(sa.sa_mask), SIGPIPE);
+ sigaction(SIGPIPE, &sa, &sa); /* set IGNORE, and get old action */
+#else /* not HAVE_SIGACTION */
+ handler = signal(SIGPIPE, SIG_IGN);
+#endif /* not HAVE_SIGACTION */
+
+ e = ldap_unbind(ld);
+
+#ifdef HAVE_SIGACTION
+ sigemptyset(&(sa.sa_mask));
+ sigaddset(&(sa.sa_mask), SIGPIPE);
+ sigaction(SIGPIPE, &sa, NULL);
+#else /* not HAVE_SIGACTION */
+ (void) signal(SIGPIPE, handler);
+#endif /* not HAVE_SIGACTION */
+
+ return e;
+}
+
+
static void
ald_free(ALD *a)
{
he_free(a->hostent);
cr_free(a->credentials);
if (a->ldap != NULL)
- ldap_unbind(a->ldap);
+ amu_ldap_unbind(a->ldap);
XFREE(a);
}
@@ -184,27 +238,29 @@ amu_ldap_init(mnt_map *m, char *map, time_t *ts)
ALD *aldh;
CR *creds;
+ dlog("-> amu_ldap_init: map <%s>\n", map);
+
/*
* XXX: by checking that map_type must be defined, aren't we
* excluding the possibility of automatic searches through all
* map types?
*/
if (!gopt.map_type || !STREQ(gopt.map_type, AMD_LDAP_TYPE)) {
- return (ENOENT);
- }
-#ifdef DEBUG
- else {
+ dlog("amu_ldap_init called with map_type <%s>\n",
+ (gopt.map_type ? gopt.map_type : "null"));
+ } else {
dlog("Map %s is ldap\n", map);
}
-#endif /* DEBUG */
aldh = ALLOC(ALD);
creds = ALLOC(CR);
- aldh->ldap = NULL ;
+ aldh->ldap = NULL;
aldh->hostent = string2he(gopt.ldap_hostports);
if (aldh->hostent == NULL) {
plog(XLOG_USER, "Unable to parse hostport %s for ldap map %s",
gopt.ldap_hostports ? gopt.ldap_hostports : "(null)", map);
+ XFREE(creds);
+ XFREE(aldh);
return (ENOENT);
}
creds->who = "";
@@ -212,22 +268,17 @@ amu_ldap_init(mnt_map *m, char *map, time_t *ts)
creds->method = LDAP_AUTH_SIMPLE;
aldh->credentials = creds;
aldh->timestamp = 0;
-#ifdef DEBUG
+ aldh->ldap = NULL;
dlog("Trying for %s:%d\n", aldh->hostent->host, aldh->hostent->port);
-#endif /* DEBUG */
if (amu_ldap_rebind(aldh)) {
ald_free(aldh);
return (ENOENT);
}
m->map_data = (void *) aldh;
-#ifdef DEBUG
dlog("Bound to %s:%d\n", aldh->hostent->host, aldh->hostent->port);
-#endif /* DEBUG */
- if (get_ldap_timestamp(aldh->ldap, map, ts))
+ if (get_ldap_timestamp(aldh, map, ts))
return (ENOENT);
-#ifdef DEBUG
- dlog("Got timestamp for map %s: %ld\n", map, *ts);
-#endif /* DEBUG */
+ dlog("Got timestamp for map %s: %ld\n", map, (u_long) *ts);
return (0);
}
@@ -239,16 +290,21 @@ amu_ldap_rebind(ALD *a)
LDAP *ld;
HE_ENT *h;
CR *c = a->credentials;
- time_t now = clocktime();
+ time_t now = clocktime(NULL);
int try;
+ dlog("-> amu_ldap_rebind\n");
+
if (a->ldap != NULL) {
if ((a->timestamp - now) > AMD_LDAP_TTL) {
-#ifdef DEBUG
- dlog("Reestablishing ldap connection\n");
-#endif /* DEBUG */
- ldap_unbind(a->ldap);
+ dlog("Re-establishing ldap connection\n");
+ amu_ldap_unbind(a->ldap);
a->timestamp = now;
+ a->ldap = NULL;
+ } else {
+ /* Assume all is OK. If it wasn't we'll be back! */
+ dlog("amu_ldap_rebind: timestamp OK\n");
+ return (0);
}
}
@@ -258,21 +314,34 @@ amu_ldap_rebind(ALD *a)
plog(XLOG_WARNING, "Unable to ldap_open to %s:%d\n", h->host, h->port);
break;
}
+#if LDAP_VERSION_MAX > LDAP_VERSION2
+ /* handle LDAPv3 and heigher, if available and amd.conf-igured */
+ if (gopt.ldap_proto_version > LDAP_VERSION2) {
+ if (!ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &gopt.ldap_proto_version)) {
+ dlog("amu_ldap_rebind: LDAP protocol version set to %ld\n",
+ gopt.ldap_proto_version);
+ } else {
+ plog(XLOG_WARNING, "Unable to set ldap protocol version to %ld\n",
+ gopt.ldap_proto_version);
+ break;
+ }
+ }
+#endif /* LDAP_VERSION_MAX > LDAP_VERSION2 */
if (ldap_bind_s(ld, c->who, c->pw, c->method) != LDAP_SUCCESS) {
plog(XLOG_WARNING, "Unable to ldap_bind to %s:%d as %s\n",
h->host, h->port, c->who);
break;
}
if (gopt.ldap_cache_seconds > 0) {
-#ifdef HAVE_LDAP_ENABLE_CACHE
+#if defined(HAVE_LDAP_ENABLE_CACHE) && defined(HAVE_EXTERN_LDAP_ENABLE_CACHE)
ldap_enable_cache(ld, gopt.ldap_cache_seconds, gopt.ldap_cache_maxmem);
-#else /* HAVE_LDAP_ENABLE_CACHE */
- plog(XLOG_WARNING, "ldap_enable_cache(%ld) does not exist on this system!\n", gopt.ldap_cache_seconds);
-#endif /* HAVE_LDAP_ENABLE_CACHE */
- a->ldap = ld;
- a->timestamp = now;
- return (0);
+#else /* not defined(HAVE_LDAP_ENABLE_CACHE) && defined(HAVE_EXTERN_LDAP_ENABLE_CACHE) */
+ plog(XLOG_WARNING, "ldap_enable_cache(%ld) is not available on this system!\n", gopt.ldap_cache_seconds);
+#endif /* not defined(HAVE_LDAP_ENABLE_CACHE) && defined(HAVE_EXTERN_LDAP_ENABLE_CACHE) */
}
+ a->ldap = ld;
+ a->timestamp = now;
+ return (0);
}
plog(XLOG_WARNING, "Exhausted list of ldap servers, looping.\n");
}
@@ -283,24 +352,24 @@ amu_ldap_rebind(ALD *a)
static int
-get_ldap_timestamp(LDAP *ld, char *map, time_t *ts)
+get_ldap_timestamp(ALD *a, char *map, time_t *ts)
{
struct timeval tv;
char **vals, *end;
char filter[MAXPATHLEN];
int i, err = 0, nentries = 0;
- LDAPMessage *res, *entry;
+ LDAPMessage *res = NULL, *entry;
+
+ dlog("-> get_ldap_timestamp: map <%s>\n", map);
tv.tv_sec = 3;
tv.tv_usec = 0;
- sprintf(filter, AMD_LDAP_TSFILTER, map);
-#ifdef DEBUG
+ xsnprintf(filter, sizeof(filter), AMD_LDAP_TSFILTER, map);
dlog("Getting timestamp for map %s\n", map);
dlog("Filter is: %s\n", filter);
dlog("Base is: %s\n", gopt.ldap_base);
-#endif /* DEBUG */
for (i = 0; i < AMD_LDAP_RETRIES; i++) {
- err = ldap_search_st(ld,
+ err = ldap_search_st(a->ldap,
gopt.ldap_base,
LDAP_SCOPE_SUBTREE,
filter,
@@ -310,19 +379,32 @@ get_ldap_timestamp(LDAP *ld, char *map, time_t *ts)
&res);
if (err == LDAP_SUCCESS)
break;
-#ifdef DEBUG
- dlog("Timestamp search timed out, trying again...\n");
-#endif /* DEBUG */
+ if (res) {
+ ldap_msgfree(res);
+ res = NULL;
+ }
+ plog(XLOG_USER, "Timestamp LDAP search attempt %d failed: %s\n",
+ i + 1, ldap_err2string(err));
+ if (err != LDAP_TIMEOUT) {
+ dlog("get_ldap_timestamp: unbinding...\n");
+ amu_ldap_unbind(a->ldap);
+ a->ldap = NULL;
+ if (amu_ldap_rebind(a))
+ return (ENOENT);
+ }
+ dlog("Timestamp search failed, trying again...\n");
}
if (err != LDAP_SUCCESS) {
*ts = 0;
plog(XLOG_USER, "LDAP timestamp search failed: %s\n",
ldap_err2string(err));
+ if (res)
+ ldap_msgfree(res);
return (ENOENT);
}
- nentries = ldap_count_entries(ld, res);
+ nentries = ldap_count_entries(a->ldap, res);
if (nentries == 0) {
plog(XLOG_USER, "No timestamp entry for map %s\n", map);
*ts = 0;
@@ -330,8 +412,8 @@ get_ldap_timestamp(LDAP *ld, char *map, time_t *ts)
return (ENOENT);
}
- entry = ldap_first_entry(ld, res);
- vals = ldap_get_values(ld, entry, AMD_LDAP_TSATTR);
+ entry = ldap_first_entry(a->ldap, res);
+ vals = ldap_get_values(a->ldap, entry, AMD_LDAP_TSATTR);
if (ldap_count_values(vals) == 0) {
plog(XLOG_USER, "Missing timestamp value for map %s\n", map);
*ts = 0;
@@ -339,9 +421,7 @@ get_ldap_timestamp(LDAP *ld, char *map, time_t *ts)
ldap_msgfree(res);
return (ENOENT);
}
-#ifdef DEBUG
dlog("TS value is:%s:\n", vals[0]);
-#endif /* DEBUG */
if (vals[0]) {
*ts = (time_t) strtol(vals[0], &end, 10);
@@ -352,7 +432,7 @@ get_ldap_timestamp(LDAP *ld, char *map, time_t *ts)
}
if (!*ts > 0) {
plog(XLOG_USER, "Nonpositive timestamp %ld for map %s\n",
- *ts, map);
+ (u_long) *ts, map);
err = ENOENT;
}
} else {
@@ -363,9 +443,7 @@ get_ldap_timestamp(LDAP *ld, char *map, time_t *ts)
ldap_value_free(vals);
ldap_msgfree(res);
-#ifdef DEBUG
- dlog("The timestamp for %s is %ld (err=%d)\n", map, *ts, err);
-#endif /* DEBUG */
+ dlog("The timestamp for %s is %ld (err=%d)\n", map, (u_long) *ts, err);
return (err);
}
@@ -373,12 +451,15 @@ get_ldap_timestamp(LDAP *ld, char *map, time_t *ts)
int
amu_ldap_search(mnt_map *m, char *map, char *key, char **pval, time_t *ts)
{
- char **vals, filter[MAXPATHLEN];
+ char **vals, filter[MAXPATHLEN], filter2[2 * MAXPATHLEN];
+ char *f1, *f2;
struct timeval tv;
int i, err = 0, nvals = 0, nentries = 0;
- LDAPMessage *entry, *res;
+ LDAPMessage *entry, *res = NULL;
ALD *a = (ALD *) (m->map_data);
+ dlog("-> amu_ldap_search: map <%s>, key <%s>\n", map, key);
+
tv.tv_sec = 2;
tv.tv_usec = 0;
if (a == NULL) {
@@ -388,43 +469,63 @@ amu_ldap_search(mnt_map *m, char *map, char *key, char **pval, time_t *ts)
if (amu_ldap_rebind(a)) /* Check that's the handle is still valid */
return (ENOENT);
- sprintf(filter, AMD_LDAP_FILTER, map, key);
-#ifdef DEBUG
- dlog("Search with filter: %s\n", filter);
-#endif /* DEBUG */
+ xsnprintf(filter, sizeof(filter), AMD_LDAP_FILTER, map, key);
+ /* "*" is special to ldap_search(); run through the filter escaping it. */
+ f1 = filter; f2 = filter2;
+ while (*f1) {
+ if (*f1 == '*') {
+ *f2++ = '\\'; *f2++ = '2'; *f2++ = 'a';
+ f1++;
+ } else {
+ *f2++ = *f1++;
+ }
+ }
+ *f2 = '\0';
+ dlog("Search with filter: <%s>\n", filter2);
for (i = 0; i < AMD_LDAP_RETRIES; i++) {
err = ldap_search_st(a->ldap,
gopt.ldap_base,
LDAP_SCOPE_SUBTREE,
- filter,
+ filter2,
0,
0,
&tv,
&res);
if (err == LDAP_SUCCESS)
break;
+ if (res) {
+ ldap_msgfree(res);
+ res = NULL;
+ }
+ plog(XLOG_USER, "LDAP search attempt %d failed: %s\n",
+ i + 1, ldap_err2string(err));
+ if (err != LDAP_TIMEOUT) {
+ dlog("amu_ldap_search: unbinding...\n");
+ amu_ldap_unbind(a->ldap);
+ a->ldap = NULL;
+ if (amu_ldap_rebind(a))
+ return (ENOENT);
+ }
}
switch (err) {
case LDAP_SUCCESS:
break;
case LDAP_NO_SUCH_OBJECT:
-#ifdef DEBUG
dlog("No object\n");
-#endif /* DEBUG */
- ldap_msgfree(res);
+ if (res)
+ ldap_msgfree(res);
return (ENOENT);
default:
plog(XLOG_USER, "LDAP search failed: %s\n",
ldap_err2string(err));
- ldap_msgfree(res);
+ if (res)
+ ldap_msgfree(res);
return (EIO);
}
nentries = ldap_count_entries(a->ldap, res);
-#ifdef DEBUG
dlog("Search found %d entries\n", nentries);
-#endif /* DEBUG */
if (nentries == 0) {
ldap_msgfree(res);
return (ENOENT);
@@ -438,9 +539,7 @@ amu_ldap_search(mnt_map *m, char *map, char *key, char **pval, time_t *ts)
ldap_msgfree(res);
return (EIO);
}
-#ifdef DEBUG
dlog("Map %s, %s => %s\n", map, key, vals[0]);
-#endif /* DEBUG */
if (vals[0]) {
*pval = strdup(vals[0]);
err = 0;
@@ -461,15 +560,13 @@ amu_ldap_mtime(mnt_map *m, char *map, time_t *ts)
ALD *aldh = (ALD *) (m->map_data);
if (aldh == NULL) {
-#ifdef DEBUG
dlog("LDAP panic: unable to find map data\n");
-#endif /* DEBUG */
return (ENOENT);
}
if (amu_ldap_rebind(aldh)) {
return (ENOENT);
}
- if (get_ldap_timestamp(aldh->ldap, map, ts)) {
+ if (get_ldap_timestamp(aldh, map, ts)) {
return (ENOENT);
}
return (0);
diff --git a/contrib/amd/amd/info_ndbm.c b/contrib/amd/amd/info_ndbm.c
index bd92c13..8a52ba9 100644
--- a/contrib/amd/amd/info_ndbm.c
+++ b/contrib/amd/amd/info_ndbm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1989 Jan-Simon Pendry
* Copyright (c) 1989 Imperial College of Science, Technology & Medicine
* Copyright (c) 1989 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: info_ndbm.c,v 1.3.2.4 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/info_ndbm.c
*
*/
@@ -86,8 +85,8 @@ ndbm_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
#ifdef DBM_SUFFIX
char dbfilename[256];
- strcpy(dbfilename, map);
- strcat(dbfilename, DBM_SUFFIX);
+ xstrlcpy(dbfilename, map, sizeof(dbfilename));
+ xstrlcat(dbfilename, DBM_SUFFIX, sizeof(dbfilename));
error = stat(dbfilename, &stb);
#else /* not DBM_SUFFIX */
error = fstat(dbm_pagfno(db), &stb);
@@ -117,14 +116,14 @@ ndbm_init(mnt_map *m, char *map, time_t *tp)
#ifdef DBM_SUFFIX
char dbfilename[256];
- strcpy(dbfilename, map);
- strcat(dbfilename, DBM_SUFFIX);
+ xstrlcpy(dbfilename, map, sizeof(dbfilename));
+ xstrlcat(dbfilename, DBM_SUFFIX, sizeof(dbfilename));
error = stat(dbfilename, &stb);
#else /* not DBM_SUFFIX */
error = fstat(dbm_pagfno(db), &stb);
#endif /* not DBM_SUFFIX */
if (error < 0)
- *tp = clocktime();
+ *tp = clocktime(NULL);
else
*tp = stb.st_mtime;
dbm_close(db);
diff --git a/contrib/amd/amd/info_nis.c b/contrib/amd/amd/info_nis.c
index b59123f..bcb87d5 100644
--- a/contrib/amd/amd/info_nis.c
+++ b/contrib/amd/amd/info_nis.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1989 Jan-Simon Pendry
* Copyright (c) 1989 Imperial College of Science, Technology & Medicine
* Copyright (c) 1989 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: info_nis.c,v 1.6.2.5 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/info_nis.c
*
*/
@@ -107,9 +106,7 @@ determine_nis_domain(void)
}
if (!*default_domain) {
nis_not_running = 1;
-#ifdef DEBUG
plog(XLOG_WARNING, "NIS domain name is not set. NIS ignored.");
-#endif /* DEBUG */
return ENOENT;
}
gopt.nis_domain = strdup(default_domain);
@@ -144,12 +141,8 @@ callback(int status, char *key, int kl, char *val, int vl, char *data)
/* check what went wrong */
int e = ypprot_err(status);
-#ifdef DEBUG
plog(XLOG_ERROR, "yp enumeration of %s: %s, status=%d, e=%d",
ncdp->ncd_map, yperr_string(e), status, e);
-#else /* not DEBUG */
- plog(XLOG_ERROR, "yp enumeration of %s: %s", ncdp->ncd_map, yperr_string(e));
-#endif /* not DEBUG */
}
return TRUE;
}
@@ -350,9 +343,7 @@ nis_init(mnt_map *m, char *map, time_t *tp)
/* NIS server found */
has_yp_order = 1;
*tp = (time_t) order;
-#ifdef DEBUG
dlog("NIS master for %s@%s has order %lu", map, gopt.nis_domain, (unsigned long) order);
-#endif /* DEBUG */
break;
case YPERR_YPERR:
/* NIS+ server found ! */
@@ -361,9 +352,7 @@ nis_init(mnt_map *m, char *map, time_t *tp)
if (yp_master(gopt.nis_domain, map, &master)) {
return ENOENT;
} else {
-#ifdef DEBUG
dlog("NIS master for %s@%s is a NIS+ server", map, gopt.nis_domain);
-#endif /* DEBUG */
/* Use fake timestamps */
*tp = time(NULL);
}
@@ -442,11 +431,9 @@ am_yp_all(char *indomain, char *inmap, struct ypall_callback *incallback)
&outvallen);
XFREE(outkey_old);
} while (!i);
-#ifdef DEBUG
if (i) {
dlog("yp_next() returned error: %s\n", yperr_string(i));
}
-#endif /* DEBUG */
if (i == YPERR_NOMORE)
return 0;
return i;
diff --git a/contrib/amd/amd/info_nisplus.c b/contrib/amd/amd/info_nisplus.c
index 46018bc..d392b48 100644
--- a/contrib/amd/amd/info_nisplus.c
+++ b/contrib/amd/amd/info_nisplus.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1989 Jan-Simon Pendry
* Copyright (c) 1989 Imperial College of Science, Technology & Medicine
* Copyright (c) 1989 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: info_nisplus.c,v 1.3.2.5 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/info_nisplus.c
*
*/
@@ -74,9 +73,7 @@ nisplus_callback(const nis_name key, const nis_object *value, voidp opaquedata)
char *vp = strnsave(ENTRY_VAL(value, 1), ENTRY_LEN(value, 1));
struct nis_callback_data *data = (struct nis_callback_data *) opaquedata;
-#ifdef DEBUG
dlog("NISplus callback for <%s,%s>", kp, vp);
-#endif /* DEBUG */
(*data->ncd_fn) (data->ncd_m, kp, vp);
@@ -95,6 +92,7 @@ nisplus_reload(mnt_map *m, char *map, void (*fn) ())
nis_result *result;
char *org; /* if map does not have ".org_dir" then append it */
nis_name map_name;
+ size_t l;
org = strstr(map, NISPLUS_ORGDIR);
if (org == NULL)
@@ -103,21 +101,20 @@ nisplus_reload(mnt_map *m, char *map, void (*fn) ())
org = "";
/* make some room for the NIS map_name */
- map_name = xmalloc(strlen(map) + sizeof(NISPLUS_ORGDIR));
+ l = strlen(map) + sizeof(NISPLUS_ORGDIR);
+ map_name = xmalloc(l);
if (map_name == NULL) {
plog(XLOG_ERROR, "Unable to create map_name %s: %s",
map, strerror(ENOMEM));
return ENOMEM;
}
- sprintf(map_name, "%s%s", map, org);
+ xsnprintf(map_name, l, "%s%s", map, org);
data.ncd_m = m;
data.ncd_map = map_name;
data.ncd_fn = fn;
-#ifdef DEBUG
dlog("NISplus reload for %s", map);
-#endif /* DEBUG */
result = nis_list(map_name,
EXPAND_NAME | FOLLOW_LINKS | FOLLOW_PATH,
@@ -145,10 +142,8 @@ nisplus_search_callback(const nis_name key, const nis_object *value, voidp opaqu
{
struct nisplus_search_callback_data *data = (struct nisplus_search_callback_data *) opaquedata;
-#ifdef DEBUG
dlog("NISplus search callback for <%s>", ENTRY_VAL(value, 0));
dlog("NISplus search callback value <%s>", ENTRY_VAL(value, 1));
-#endif /* DEBUG */
data->value = strnsave(ENTRY_VAL(value, 1), ENTRY_LEN(value, 1));
return TRUE;
@@ -166,6 +161,7 @@ nisplus_search(mnt_map *m, char *map, char *key, char **val, time_t *tp)
struct nisplus_search_callback_data data;
nis_name index;
char *org; /* if map does not have ".org_dir" then append it */
+ size_t l;
org = strstr(map, NISPLUS_ORGDIR);
if (org == NULL)
@@ -174,14 +170,14 @@ nisplus_search(mnt_map *m, char *map, char *key, char **val, time_t *tp)
org = "";
/* make some room for the NIS index */
- index = xmalloc(sizeof('[') /* for opening selection criteria */
- +sizeof(NISPLUS_KEY)
- + strlen(key)
- + sizeof(']') /* for closing selection criteria */
- +sizeof(',') /* + 1 for , separator */
- +strlen(map)
- + sizeof(NISPLUS_ORGDIR)
- );
+ l = sizeof('[') /* for opening selection criteria */
+ + sizeof(NISPLUS_KEY)
+ + strlen(key)
+ + sizeof(']') /* for closing selection criteria */
+ + sizeof(',') /* + 1 for , separator */
+ + strlen(map)
+ + sizeof(NISPLUS_ORGDIR);
+ index = xmalloc(l);
if (index == NULL) {
plog(XLOG_ERROR,
"Unable to create index %s: %s",
@@ -189,14 +185,12 @@ nisplus_search(mnt_map *m, char *map, char *key, char **val, time_t *tp)
strerror(ENOMEM));
return ENOMEM;
}
- sprintf(index, "[%s%s],%s%s", NISPLUS_KEY, key, map, org);
+ xsnprintf(index, l, "[%s%s],%s%s", NISPLUS_KEY, key, map, org);
data.key = key;
data.value = NULL;
-#ifdef DEBUG
dlog("NISplus search for %s", index);
-#endif /* DEBUG */
result = nis_list(index,
EXPAND_NAME | FOLLOW_LINKS | FOLLOW_PATH,
@@ -220,11 +214,9 @@ nisplus_search(mnt_map *m, char *map, char *key, char **val, time_t *tp)
if (data.value == NULL) {
nis_object *value = result->objects.objects_val;
-#ifdef DEBUG
dlog("NISplus search found <nothing>");
dlog("NISplus search for %s: %s(%d)",
map, nis_sperrno(result->status), result->status);
-#endif /* DEBUG */
if (value != NULL)
data.value = strnsave(ENTRY_VAL(value, 1), ENTRY_LEN(value, 1));
@@ -233,23 +225,17 @@ nisplus_search(mnt_map *m, char *map, char *key, char **val, time_t *tp)
if (*val) {
error = 0;
-#ifdef DEBUG
dlog("NISplus search found %s", *val);
-#endif /* DEBUG */
} else {
error = ENOENT;
-#ifdef DEBUG
dlog("NISplus search found nothing");
-#endif /* DEBUG */
}
*tp = 0;
break;
case NIS_NOSUCHNAME:
-#ifdef DEBUG
dlog("NISplus search returned %d", result->status);
-#endif /* DEBUG */
error = ENOENT;
break;
@@ -271,6 +257,7 @@ nisplus_init(mnt_map *m, char *map, time_t *tp)
char *org; /* if map does not have ".org_dir" then append it */
nis_name map_name;
int error = 0;
+ size_t l;
org = strstr(map, NISPLUS_ORGDIR);
if (org == NULL)
@@ -279,7 +266,8 @@ nisplus_init(mnt_map *m, char *map, time_t *tp)
org = "";
/* make some room for the NIS map_name */
- map_name = xmalloc(strlen(map) + sizeof(NISPLUS_ORGDIR));
+ l = strlen(map) + sizeof(NISPLUS_ORGDIR);
+ map_name = xmalloc(l);
if (map_name == NULL) {
plog(XLOG_ERROR,
"Unable to create map_name %s: %s",
@@ -287,7 +275,7 @@ nisplus_init(mnt_map *m, char *map, time_t *tp)
strerror(ENOMEM));
return ENOMEM;
}
- sprintf(map_name, "%s%s", map, org);
+ xsnprintf(map_name, l, "%s%s", map, org);
result = nis_lookup(map_name, (EXPAND_NAME | FOLLOW_LINKS | FOLLOW_PATH));
@@ -300,10 +288,8 @@ nisplus_init(mnt_map *m, char *map, time_t *tp)
}
if (result->status != NIS_SUCCESS) {
-#ifdef DEBUG
dlog("NISplus init <%s>: %s (%d)",
map, nis_sperrno(result->status), result->status);
-#endif /* DEBUG */
error = ENOENT;
}
diff --git a/contrib/amd/amd/info_passwd.c b/contrib/amd/amd/info_passwd.c
index a14ac12..c8bf388 100644
--- a/contrib/amd/amd/info_passwd.c
+++ b/contrib/amd/amd/info_passwd.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: info_passwd.c,v 1.3.2.4 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/info_passwd.c
*
*/
@@ -151,11 +150,11 @@ passwd_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
do {
q = strrchr(p, '/');
if (q) {
- strcat(rhost, q + 1);
- strcat(rhost, ".");
+ xstrlcat(rhost, q + 1, sizeof(rhost));
+ xstrlcat(rhost, ".", sizeof(rhost));
*q = '\0';
} else {
- strcat(rhost, p);
+ xstrlcat(rhost, p, sizeof(rhost));
}
} while (q);
@@ -176,11 +175,9 @@ passwd_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
p++;
else
p = "type:=nfs;rfs:=/${var0}/${var1};rhost:=${var1};sublink:=${var2};fs:=${autodir}${var3}";
- sprintf(val, "var0:=%s;var1:=%s;var2:=%s;var3:=%s;%s",
- dir+1, rhost, user, pw->pw_dir, p);
-#ifdef DEBUG
+ xsnprintf(val, sizeof(val), "var0:=%s;var1:=%s;var2:=%s;var3:=%s;%s",
+ dir+1, rhost, user, pw->pw_dir, p);
dlog("passwd_search: map=%s key=%s -> %s", map, key, val);
-#endif /* DEBUG */
if (q)
*q = '.';
*pval = strdup(val);
diff --git a/contrib/amd/amd/info_union.c b/contrib/amd/amd/info_union.c
index 8613f62..8f0631c 100644
--- a/contrib/amd/amd/info_union.c
+++ b/contrib/amd/amd/info_union.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: info_union.c,v 1.3.2.4 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/info_union.c
*
*/
@@ -81,10 +80,12 @@ union_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
char *mapd = strdup(map + UNION_PREFLEN);
char **v = strsplit(mapd, ':', '\"');
char **p;
+ size_t l;
for (p = v; p[1]; p++) ;
- *pval = xmalloc(strlen(*p) + 5);
- sprintf(*pval, "fs:=%s", *p);
+ l = strlen(*p) + 5;
+ *pval = xmalloc(l);
+ xsnprintf(*pval, l, "fs:=%s", *p);
XFREE(mapd);
XFREE(v);
return 0;
@@ -104,7 +105,7 @@ union_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *))
(*fn) (m, strdup("/defaults"), strdup("type:=link;opts:=nounmount;sublink:=${key}"));
for (dir = v; *dir; dir++) {
- int dlen;
+ size_t l;
struct dirent *dp;
DIR *dirp = opendir(*dir);
@@ -112,11 +113,9 @@ union_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *))
plog(XLOG_USER, "Cannot read directory %s: %m", *dir);
continue;
}
- dlen = strlen(*dir);
+ l = strlen(*dir) + 5;
-#ifdef DEBUG
dlog("Reading directory %s...", *dir);
-#endif /* DEBUG */
while ((dp = readdir(dirp))) {
char *val, *dpname = &dp->d_name[0];
if (dpname[0] == '.' &&
@@ -124,11 +123,9 @@ union_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *))
(dpname[1] == '.' && dpname[2] == '\0')))
continue;
-#ifdef DEBUG
dlog("... gives %s", dp->d_name);
-#endif /* DEBUG */
- val = xmalloc(dlen + 5);
- sprintf(val, "fs:=%s", *dir);
+ val = xmalloc(l);
+ xsnprintf(val, l + 5, "fs:=%s", *dir);
(*fn) (m, strdup(dp->d_name), val);
}
closedir(dirp);
@@ -138,9 +135,10 @@ union_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *))
* Add wildcard entry
*/
{
- char *val = xmalloc(strlen(dir[-1]) + 5);
+ size_t l = strlen(*(dir-1)) + 5;
+ char *val = xmalloc(l);
- sprintf(val, "fs:=%s", dir[-1]);
+ xsnprintf(val, l, "fs:=%s", *(dir-1));
(*fn) (m, strdup("*"), val);
}
XFREE(mapd);
diff --git a/contrib/amd/amd/map.c b/contrib/amd/amd/map.c
index dfec3a1..8696dfd 100644
--- a/contrib/amd/amd/map.c
+++ b/contrib/amd/amd/map.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: map.c,v 1.6.2.8 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/map.c
*
*/
@@ -50,7 +49,6 @@
#define smallest_t(t1, t2) (t1 != NEVER ? (t2 != NEVER ? (t1 < t2 ? t1 : t2) : t1) : t2)
#define IGNORE_FLAGS (MFF_MOUNTING|MFF_UNMOUNTING|MFF_RESTART)
-#define NEVER (time_t) 0
#define new_gen() (am_gen++)
/*
@@ -70,11 +68,11 @@
static u_int am_gen = 2; /* Initial generation number */
static int timeout_mp_id; /* Id from last call to timeout */
-am_node *root_node; /* The root of the mount tree */
-am_node **exported_ap = (am_node **) 0;
-int exported_ap_size = 0;
-int first_free_map = 0; /* First available free slot */
-int last_used_map = -1; /* Last unavailable used slot */
+static am_node *root_node; /* The root of the mount tree */
+static am_node **exported_ap = (am_node **) 0;
+static int exported_ap_size = 0;
+static int first_free_map = 0; /* First available free slot */
+static int last_used_map = -1; /* Last unavailable used slot */
/*
@@ -103,9 +101,65 @@ static nfsfattr gen_fattr =
};
/* forward declarations */
-static int unmount_node(am_node *mp);
+static int unmount_node(opaque_t arg);
static void exported_ap_free(am_node *mp);
static void remove_am(am_node *mp);
+static am_node *get_root_ap(char *dir);
+
+
+/*
+ * Iterator functions for exported_ap[]
+ */
+am_node *
+get_first_exported_ap(int *index)
+{
+ *index = -1;
+ return get_next_exported_ap(index);
+}
+
+
+am_node *
+get_next_exported_ap(int *index)
+{
+ (*index)++;
+ while (*index < exported_ap_size) {
+ if (exported_ap[*index] != NULL)
+ return exported_ap[*index];
+ (*index)++;
+ }
+ return NULL;
+}
+
+
+/*
+ * Get exported_ap by index
+ */
+am_node *
+get_exported_ap(int index)
+{
+ if (index < 0 || index >= exported_ap_size)
+ return 0;
+ return exported_ap[index];
+}
+
+
+/*
+ * Get exported_ap by path
+ */
+am_node *
+path_to_exported_ap(char *path)
+{
+ int index;
+ am_node *mp;
+
+ mp = get_first_exported_ap(&index);
+ while (mp != NULL) {
+ if (STREQ(mp->am_path, path))
+ break;
+ mp = get_next_exported_ap(&index);
+ }
+ return mp;
+}
/*
@@ -131,6 +185,46 @@ exported_ap_realloc_map(int nsize)
}
+
+am_node *
+get_ap_child(am_node *mp, char *fname)
+{
+ am_node *new_mp;
+ mntfs *mf = mp->am_mnt;
+
+ /*
+ * Allocate a new map
+ */
+ new_mp = exported_ap_alloc();
+ if (new_mp) {
+ /*
+ * Fill it in
+ */
+ init_map(new_mp, fname);
+
+ /*
+ * Put it in the table
+ */
+ insert_am(new_mp, mp);
+
+ /*
+ * Fill in some other fields,
+ * path and mount point.
+ *
+ * bugfix: do not prepend old am_path if direct map
+ * <wls@astro.umd.edu> William Sebok
+ */
+ new_mp->am_path = str3cat(new_mp->am_path,
+ (mf->mf_fsflags & FS_DIRECT)
+ ? ""
+ : mp->am_path,
+ *fname == '/' ? "" : "/", fname);
+ dlog("setting path to %s", new_mp->am_path);
+ }
+
+ return new_mp;
+}
+
/*
* Allocate a new mount slot and create
* a new node.
@@ -154,7 +248,7 @@ exported_ap_alloc(void)
*/
mpp = exported_ap + first_free_map;
mp = *mpp = ALLOC(struct am_node);
- memset((char *) mp, 0, sizeof(*mp));
+ memset((char *) mp, 0, sizeof(struct am_node));
mp->am_mapno = first_free_map++;
@@ -199,8 +293,9 @@ exported_ap_free(am_node *mp)
first_free_map = mp->am_mapno;
/*
- * Free the mount node
+ * Free the mount node, and zero out it's internal struct data.
*/
+ memset((char *) mp, 0, sizeof(am_node));
XFREE(mp);
}
@@ -229,6 +324,10 @@ insert_am(am_node *mp, am_node *p_mp)
if (mp->am_osib)
mp->am_osib->am_ysib = mp;
p_mp->am_child = mp;
+#ifdef HAVE_FS_AUTOFS
+ if (p_mp->am_mnt->mf_flags & MFF_IS_AUTOFS)
+ mp->am_flags |= AMF_AUTOFS;
+#endif /* HAVE_FS_AUTOFS */
}
@@ -268,27 +367,26 @@ void
new_ttl(am_node *mp)
{
mp->am_timeo_w = 0;
- mp->am_ttl = clocktime();
- mp->am_fattr.na_atime.nt_seconds = mp->am_ttl;
+ mp->am_ttl = clocktime(&mp->am_fattr.na_atime);
mp->am_ttl += mp->am_timeo; /* sun's -tl option */
}
void
-mk_fattr(am_node *mp, nfsftype vntype)
+mk_fattr(nfsfattr *fattr, nfsftype vntype)
{
switch (vntype) {
case NFDIR:
- mp->am_fattr.na_type = NFDIR;
- mp->am_fattr.na_mode = NFSMODE_DIR | 0555;
- mp->am_fattr.na_nlink = 2;
- mp->am_fattr.na_size = 512;
+ fattr->na_type = NFDIR;
+ fattr->na_mode = NFSMODE_DIR | 0555;
+ fattr->na_nlink = 2;
+ fattr->na_size = 512;
break;
case NFLNK:
- mp->am_fattr.na_type = NFLNK;
- mp->am_fattr.na_mode = NFSMODE_LNK | 0777;
- mp->am_fattr.na_nlink = 1;
- mp->am_fattr.na_size = 0;
+ fattr->na_type = NFLNK;
+ fattr->na_mode = NFSMODE_LNK | 0777;
+ fattr->na_nlink = 1;
+ fattr->na_size = 0;
break;
default:
plog(XLOG_FATAL, "Unknown fattr type %d - ignored", vntype);
@@ -308,24 +406,30 @@ init_map(am_node *mp, char *dir)
{
/*
* mp->am_mapno is initialized by exported_ap_alloc
- * other fields don't need to be initialized.
+ * other fields don't need to be set to zero.
*/
mp->am_mnt = new_mntfs();
+ mp->am_mfarray = 0;
mp->am_name = strdup(dir);
mp->am_path = strdup(dir);
mp->am_gen = new_gen();
+#ifdef HAVE_FS_AUTOFS
+ mp->am_autofs_fh = 0;
+#endif /* HAVE_FS_AUTOFS */
mp->am_timeo = gopt.am_timeo;
mp->am_attr.ns_status = NFS_OK;
mp->am_fattr = gen_fattr;
mp->am_fattr.na_fsid = 42;
mp->am_fattr.na_fileid = mp->am_gen;
- mp->am_fattr.na_atime.nt_seconds = clocktime();
- mp->am_fattr.na_atime.nt_useconds = 0;
+ clocktime(&mp->am_fattr.na_atime);
+ /* next line copies a "struct nfstime" among several fields */
mp->am_fattr.na_mtime = mp->am_fattr.na_ctime = mp->am_fattr.na_atime;
new_ttl(mp);
mp->am_stats.s_mtime = mp->am_fattr.na_atime.nt_seconds;
+ mp->am_dev = -1;
+ mp->am_rdev = -1;
}
@@ -336,7 +440,6 @@ init_map(am_node *mp, char *dir)
void
free_map(am_node *mp)
{
-
remove_am(mp);
if (mp->am_link)
@@ -353,188 +456,24 @@ free_map(am_node *mp)
if (mp->am_mnt)
free_mntfs(mp->am_mnt);
- exported_ap_free(mp);
-}
-
-
-/*
- * Convert from file handle to automount node.
- */
-am_node *
-fh_to_mp3(am_nfs_fh *fhp, int *rp, int c_or_d)
-{
- struct am_fh *fp = (struct am_fh *) fhp;
- am_node *ap = 0;
-
- /*
- * Check process id matches
- * If it doesn't then it is probably
- * from an old kernel cached filehandle
- * which is now out of date.
- */
- if (fp->fhh_pid != am_mypid)
- goto drop;
-
- /*
- * Make sure the index is valid before
- * exported_ap is referenced.
- */
- if (fp->fhh_id < 0 || fp->fhh_id >= exported_ap_size)
- goto drop;
-
- /*
- * Get hold of the supposed mount node
- */
- ap = exported_ap[fp->fhh_id];
-
- /*
- * If it exists then maybe...
- */
- if (ap) {
- /*
- * Check the generation number in the node
- * matches the one from the kernel. If not
- * then the old node has been timed out and
- * a new one allocated.
- */
- if (ap->am_gen != fp->fhh_gen) {
- ap = 0;
- goto drop;
- }
- /*
- * If the node is hung then locate a new node
- * for it. This implements the replicated filesystem
- * retries.
- */
- if (ap->am_mnt && FSRV_ISDOWN(ap->am_mnt->mf_server) && ap->am_parent) {
- int error;
- am_node *orig_ap = ap;
-
-#ifdef DEBUG
- dlog("fh_to_mp3: %s (%s) is hung:- call lookup",
- orig_ap->am_path, orig_ap->am_mnt->mf_info);
-#endif /* DEBUG */
-
- /*
- * Update modify time of parent node.
- * With any luck the kernel will re-stat
- * the child node and get new information.
- */
- orig_ap->am_fattr.na_mtime.nt_seconds = clocktime();
-
- /*
- * Call the parent's lookup routine for an object
- * with the same name. This may return -1 in error
- * if a mount is in progress. In any case, if no
- * mount node is returned the error code is propagated
- * to the caller.
- */
- if (c_or_d == VLOOK_CREATE) {
- ap = (*orig_ap->am_parent->am_mnt->mf_ops->lookuppn)
- (orig_ap->am_parent, orig_ap->am_name, &error, c_or_d);
- } else {
- ap = 0;
- error = ESTALE;
- }
- if (ap == 0) {
- if (error < 0 && amd_state == Finishing)
- error = ENOENT;
- *rp = error;
- return 0;
- }
-
- /*
- * Update last access to original node. This
- * avoids timing it out and so sending ESTALE
- * back to the kernel.
- * XXX - Not sure we need this anymore (jsp, 90/10/6).
- */
- new_ttl(orig_ap);
-
- }
-
- /*
- * Disallow references to objects being unmounted, unless
- * they are automount points.
- */
- if (ap->am_mnt && (ap->am_mnt->mf_flags & MFF_UNMOUNTING) &&
- !(ap->am_flags & AMF_ROOT)) {
- if (amd_state == Finishing)
- *rp = ENOENT;
- else
- *rp = -1;
- return 0;
- }
- new_ttl(ap);
- }
-
-drop:
- if (!ap || !ap->am_mnt) {
- /*
- * If we are shutting down then it is likely
- * that this node has disappeared because of
- * a fast timeout. To avoid things thrashing
- * just pretend it doesn't exist at all. If
- * ESTALE is returned, some NFS clients just
- * keep retrying (stupid or what - if it's
- * stale now, what's it going to be in 5 minutes?)
- */
- if (amd_state == Finishing)
- *rp = ENOENT;
- else
- *rp = ESTALE;
- amd_stats.d_stale++;
+ if (mp->am_mfarray) {
+ mntfs **temp_mf;
+ for (temp_mf = mp->am_mfarray; *temp_mf; temp_mf++)
+ free_mntfs(*temp_mf);
+ XFREE(mp->am_mfarray);
}
- return ap;
-}
-
-
-am_node *
-fh_to_mp(am_nfs_fh *fhp)
-{
- int dummy;
-
- return fh_to_mp2(fhp, &dummy);
-}
-
-
-/*
- * Convert from automount node to file handle.
- */
-void
-mp_to_fh(am_node *mp, am_nfs_fh *fhp)
-{
- struct am_fh *fp = (struct am_fh *) fhp;
-
- memset((char *) fhp, 0, sizeof(am_nfs_fh));
-
- /*
- * Take the process id
- */
- fp->fhh_pid = am_mypid;
-
- /*
- * ... the map number
- */
- fp->fhh_id = mp->am_mapno;
+#ifdef HAVE_FS_AUTOFS
+ if (mp->am_autofs_fh)
+ autofs_release_fh(mp);
+#endif /* HAVE_FS_AUTOFS */
- /*
- * ... and the generation number
- */
- fp->fhh_gen = mp->am_gen;
-
- /*
- * ... to make a "unique" triple that will never
- * be reallocated except across reboots (which doesn't matter)
- * or if we are unlucky enough to be given the same
- * pid as a previous amd (very unlikely).
- */
+ exported_ap_free(mp);
}
-am_node *
-find_ap2(char *dir, am_node *mp)
+static am_node *
+find_ap_recursive(char *dir, am_node *mp)
{
if (mp) {
am_node *mp2;
@@ -545,10 +484,10 @@ find_ap2(char *dir, am_node *mp)
STREQ(mp->am_mnt->mf_mount, dir))
return mp;
- mp2 = find_ap2(dir, mp->am_osib);
+ mp2 = find_ap_recursive(dir, mp->am_osib);
if (mp2)
return mp2;
- return find_ap2(dir, mp->am_child);
+ return find_ap_recursive(dir, mp->am_child);
}
return 0;
@@ -567,7 +506,7 @@ find_ap(char *dir)
for (i = last_used_map; i >= 0; --i) {
am_node *mp = exported_ap[i];
if (mp && (mp->am_flags & AMF_ROOT)) {
- mp = find_ap2(dir, exported_ap[i]);
+ mp = find_ap_recursive(dir, exported_ap[i]);
if (mp) {
return mp;
}
@@ -603,22 +542,12 @@ find_mf(mntfs *mf)
* the filehandles of the initial automount points.
*/
am_nfs_fh *
-root_fh(char *dir)
+get_root_nfs_fh(char *dir)
{
static am_nfs_fh nfh;
- am_node *mp = root_ap(dir, TRUE);
+ am_node *mp = get_root_ap(dir);
if (mp) {
mp_to_fh(mp, &nfh);
- /*
- * Patch up PID to match main server...
- */
- if (!foreground) {
- long pid = getppid();
- ((struct am_fh *) &nfh)->fhh_pid = pid;
-#ifdef DEBUG
- dlog("root_fh substitutes pid %ld", (long) pid);
-#endif /* DEBUG */
- }
return &nfh;
}
@@ -631,8 +560,8 @@ root_fh(char *dir)
}
-am_node *
-root_ap(char *dir, int path)
+static am_node *
+get_root_ap(char *dir)
{
am_node *mp = find_ap(dir);
@@ -657,7 +586,7 @@ map_flush_srvr(fserver *fs)
am_node *mp = exported_ap[i];
if (mp && mp->am_mnt && mp->am_mnt->mf_server == fs) {
plog(XLOG_INFO, "Flushed %s; dependent on %s", mp->am_path, fs->fs_host);
- mp->am_ttl = clocktime();
+ mp->am_ttl = clocktime(NULL);
done = 1;
}
}
@@ -673,11 +602,23 @@ map_flush_srvr(fserver *fs)
* automount node to be automounted.
*/
int
-mount_auto_node(char *dir, voidp arg)
+mount_auto_node(char *dir, opaque_t arg)
{
int error = 0;
+ am_node *mp = (am_node *) arg;
+ am_node *new_mp;
+
+ new_mp = mp->am_mnt->mf_ops->lookup_child(mp, dir, &error, VLOOK_CREATE);
+ if (new_mp && error < 0) {
+ /*
+ * We can't allow the fileid of the root node to change.
+ * Should be ok to force it to 1, always.
+ */
+ new_mp->am_gen = new_mp->am_fattr.na_fileid = 1;
+
+ new_mp = mp->am_mnt->mf_ops->mount_child(new_mp, &error);
+ }
- (void) amfs_auto_ops.lookuppn((am_node *) arg, dir, &error, VLOOK_CREATE);
if (error > 0) {
errno = error; /* XXX */
plog(XLOG_ERROR, "Could not mount %s: %m", dir);
@@ -696,7 +637,7 @@ mount_exported(void)
/*
* Iterate over all the nodes to be started
*/
- return root_keyiter((void (*)P((char *, voidp))) mount_auto_node, root_node);
+ return root_keyiter(mount_auto_node, root_node);
}
@@ -735,7 +676,7 @@ make_root_node(void)
/*
* Mount the root
*/
- root_mnt->mf_error = (*root_mnt->mf_ops->mount_fs) (root_node);
+ root_mnt->mf_error = root_mnt->mf_ops->mount_fs(root_node, root_mnt);
}
@@ -750,143 +691,136 @@ umount_exported(void)
for (i = last_used_map; i >= 0; --i) {
am_node *mp = exported_ap[i];
+ mntfs *mf;
- if (mp) {
- mntfs *mf = mp->am_mnt;
- if (mf->mf_flags & MFF_UNMOUNTING) {
- /*
- * If this node is being unmounted then just ignore it. However,
- * this could prevent amd from finishing if the unmount gets blocked
- * since the am_node will never be free'd. am_unmounted needs
- * telling about this possibility. - XXX
- */
- continue;
- }
+ if (!mp)
+ continue;
- if (mf && !(mf->mf_ops->fs_flags & FS_DIRECTORY)) {
- /*
- * When shutting down this had better
- * look like a directory, otherwise it
- * can't be unmounted!
- */
- mk_fattr(mp, NFDIR);
- }
+ mf = mp->am_mnt;
+ if (mf->mf_flags & MFF_UNMOUNTING) {
+ /*
+ * If this node is being unmounted then just ignore it. However,
+ * this could prevent amd from finishing if the unmount gets blocked
+ * since the am_node will never be free'd. am_unmounted needs
+ * telling about this possibility. - XXX
+ */
+ continue;
+ }
- if ((--immediate_abort < 0 &&
- !(mp->am_flags & AMF_ROOT) && mp->am_parent) ||
- (mf->mf_flags & MFF_RESTART)) {
+ if (!(mf->mf_fsflags & FS_DIRECTORY))
+ /*
+ * When shutting down this had better
+ * look like a directory, otherwise it
+ * can't be unmounted!
+ */
+ mk_fattr(&mp->am_fattr, NFDIR);
- /*
- * Just throw this node away without bothering to unmount it. If
- * the server is not known to be up then don't discard the mounted
- * on directory or Amd might hang...
- */
- if (mf->mf_server &&
- (mf->mf_server->fs_flags & (FSF_DOWN | FSF_VALID)) != FSF_VALID)
- mf->mf_flags &= ~MFF_MKMNT;
- if (gopt.flags & CFM_UNMOUNT_ON_EXIT) {
- plog(XLOG_INFO, "on-exit attempt to unmount %s", mf->mf_mount);
- unmount_node(mp);
- }
- am_unmounted(mp);
+ if ((--immediate_abort < 0 &&
+ !(mp->am_flags & AMF_ROOT) && mp->am_parent) ||
+ (mf->mf_flags & MFF_RESTART)) {
- } else {
+ /*
+ * Just throw this node away without bothering to unmount it. If
+ * the server is not known to be up then don't discard the mounted
+ * on directory or Amd might hang...
+ */
+ if (mf->mf_server &&
+ (mf->mf_server->fs_flags & (FSF_DOWN | FSF_VALID)) != FSF_VALID)
+ mf->mf_flags &= ~MFF_MKMNT;
+ if (gopt.flags & CFM_UNMOUNT_ON_EXIT || mp->am_flags & AMF_AUTOFS) {
+ plog(XLOG_INFO, "on-exit attempt to unmount %s", mf->mf_mount);
/*
- * Any other node gets forcibly timed out.
+ * use unmount_mp, not unmount_node, so that unmounts be
+ * backgrounded as needed.
*/
- mp->am_flags &= ~AMF_NOTIMEOUT;
- mp->am_mnt->mf_flags &= ~MFF_RSTKEEP;
- mp->am_ttl = 0;
- mp->am_timeo = 1;
- mp->am_timeo_w = 0;
+ unmount_mp((opaque_t) mp);
+ } else {
+ am_unmounted(mp);
}
+ exported_ap[i] = 0;
+ } else {
+ /*
+ * Any other node gets forcibly timed out.
+ */
+ mp->am_flags &= ~AMF_NOTIMEOUT;
+ mp->am_mnt->mf_flags &= ~MFF_RSTKEEP;
+ mp->am_ttl = 0;
+ mp->am_timeo = 1;
+ mp->am_timeo_w = 0;
}
}
}
+/*
+ * Try to mount a file system. Can be called directly or in a sub-process by run_task.
+ *
+ * Warning: this function might be running in a child process context.
+ * Don't expect any changes made here to survive in the parent amd process.
+ */
+int
+mount_node(opaque_t arg)
+{
+ am_node *mp = (am_node *) arg;
+ mntfs *mf = mp->am_mnt;
+ int error = 0;
+
+#ifdef HAVE_FS_AUTOFS
+ if (mp->am_flags & AMF_AUTOFS)
+ error = autofs_mount_fs(mp, mf);
+ else
+#endif /* HAVE_FS_AUTOFS */
+ if (!(mf->mf_flags & MFF_MOUNTED))
+ error = mf->mf_ops->mount_fs(mp, mf);
+
+ if (error > 0)
+ dlog("mount_node: call to mf_ops->mount_fs(%s) failed: %s",
+ mp->am_path, strerror(error));
+ return error;
+}
+
+
static int
-unmount_node(am_node *mp)
+unmount_node(opaque_t arg)
{
+ am_node *mp = (am_node *) arg;
mntfs *mf = mp->am_mnt;
- int error;
+ int error = 0;
- if ((mf->mf_flags & MFF_ERROR) || mf->mf_refc > 1) {
+ if (mf->mf_flags & MFF_ERROR) {
/*
* Just unlink
*/
-#ifdef DEBUG
- if (mf->mf_flags & MFF_ERROR)
- dlog("No-op unmount of error node %s", mf->mf_info);
-#endif /* DEBUG */
- error = 0;
+ dlog("No-op unmount of error node %s", mf->mf_info);
} else {
-#ifdef DEBUG
- dlog("Unmounting %s (%s)", mf->mf_mount, mf->mf_info);
-#endif /* DEBUG */
- error = (*mf->mf_ops->umount_fs) (mp);
+ dlog("Unmounting <%s> <%s> (%s) flags %x",
+ mp->am_path, mf->mf_mount, mf->mf_info, mf->mf_flags);
+#ifdef HAVE_FS_AUTOFS
+ if (mp->am_flags & AMF_AUTOFS)
+ error = autofs_umount_fs(mp, mf);
+ else
+#endif /* HAVE_FS_AUTOFS */
+ if (mf->mf_refc == 1)
+ error = mf->mf_ops->umount_fs(mp, mf);
}
+ /* do this again, it might have changed */
+ mf = mp->am_mnt;
if (error) {
errno = error; /* XXX */
-#ifdef DEBUG
dlog("%s: unmount: %m", mf->mf_mount);
-#endif /* DEBUG */
}
return error;
}
-static int
-unmount_node_wrap(voidp vp)
-{
- return unmount_node((am_node *) vp);
-
- /*
- * Below is the comment left from the old code
- * that was dependent on the macro FLUSH_KERNEL_NAME_CACHE
- */
- /*
- * This code should just say:
- * return unmount_node((am_node *) vp);
- *
- * However...
- * The kernel keeps a cached copy of filehandles,
- * and doesn't ever uncache them (apparently). So
- * when Amd times out a node the kernel will have a
- * stale filehandle. When the kernel next uses the
- * filehandle it gets ESTALE.
- *
- * The workaround:
- * Arrange that when a node is removed an unlink or
- * rmdir is done on that path so that the kernel
- * cache is done. Yes - yuck.
- *
- * This can all be removed (and the background
- * unmount flag in amfs_link_ops) if/when the kernel does
- * something smarter.
- *
- * If the unlink or rmdir failed then just log a warning,
- * don't fail the unmount. This can occur if the kernel
- * client code decides that the object is still referenced
- * and should be renamed rather than discarded.
- *
- * There is still a race condition here...
- * if another process is trying to access the same
- * filesystem at the time we get here, then
- * it will block, since the MFF_UNMOUNTING flag will
- * be set. That may, or may not, cause the entire
- * system to deadlock. Hmmm...
- */
-}
-
-
static void
-free_map_if_success(int rc, int term, voidp closure)
+free_map_if_success(int rc, int term, opaque_t arg)
{
- am_node *mp = (am_node *) closure;
+ am_node *mp = (am_node *) arg;
mntfs *mf = mp->am_mnt;
+ wchan_t wchan = get_mntfs_wchan(mf);
/*
* Not unmounting any more
@@ -912,14 +846,22 @@ free_map_if_success(int rc, int term, voidp closure)
am_unmounted(mp);
}
#endif /* DEBUG */
+#ifdef HAVE_FS_AUTOFS
+ if (mp->am_flags & AMF_AUTOFS)
+ autofs_umount_failed(mp);
+#endif /* HAVE_FS_AUTOFS */
amd_stats.d_uerr++;
} else if (rc) {
- if (mf->mf_ops == &amfs_program_ops || rc == EBUSY) {
+ if (mf->mf_ops == &amfs_program_ops || rc == EBUSY)
plog(XLOG_STATS, "\"%s\" on %s still active", mp->am_path, mf->mf_mount);
- } else {
- errno = rc; /* XXX */
- plog(XLOG_ERROR, "%s: unmount: %m", mp->am_path);
- }
+ else
+ plog(XLOG_ERROR, "%s: unmount: %s", mp->am_path, strerror(rc));
+#ifdef HAVE_FS_AUTOFS
+ if (mf->mf_flags & MFF_IS_AUTOFS)
+ autofs_get_mp(mp);
+ if (mp->am_flags & AMF_AUTOFS)
+ autofs_umount_failed(mp);
+#endif /* HAVE_FS_AUTOFS */
amd_stats.d_uerr++;
} else {
am_unmounted(mp);
@@ -928,16 +870,21 @@ free_map_if_success(int rc, int term, voidp closure)
/*
* Wakeup anything waiting for this unmount
*/
- wakeup((voidp) mf);
+ wakeup(wchan);
}
-static int
+int
unmount_mp(am_node *mp)
{
int was_backgrounded = 0;
mntfs *mf = mp->am_mnt;
+#ifdef notdef
+ plog(XLOG_INFO, "\"%s\" on %s timed out (flags 0x%x)",
+ mp->am_path, mp->am_mnt->mf_mount, (int) mf->mf_flags);
+#endif /* notdef */
+
#ifndef MNT2_NFS_OPT_SYMTTL
/*
* This code is needed to defeat Solaris 2.4's (and newer) symlink
@@ -946,56 +893,48 @@ unmount_mp(am_node *mp)
* symlink-cache at mount time (such as Irix 5.x and 6.x). -Erez.
*
* Additionally, Linux currently ignores the nt_useconds field,
- * so we must update the nt_seconds field every time.
+ * so we must update the nt_seconds field every time if clocktime(NULL)
+ * didn't return a new number of seconds.
*/
- if (mp->am_parent)
+ if (mp->am_parent) {
+ time_t last = mp->am_parent->am_attr.ns_u.ns_attr_u.na_mtime.nt_seconds;
+ clocktime(&mp->am_parent->am_attr.ns_u.ns_attr_u.na_mtime);
/* defensive programming... can't we assert the above condition? */
- mp->am_parent->am_attr.ns_u.ns_attr_u.na_mtime.nt_seconds++;
+ if (last == (time_t) mp->am_parent->am_attr.ns_u.ns_attr_u.na_mtime.nt_seconds)
+ mp->am_parent->am_attr.ns_u.ns_attr_u.na_mtime.nt_seconds++;
+ }
#endif /* not MNT2_NFS_OPT_SYMTTL */
-#ifdef notdef
- plog(XLOG_INFO, "\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount);
-#endif /* notdef */
+ if (mf->mf_refc == 1 && !FSRV_ISUP(mf->mf_server)) {
+ /*
+ * Don't try to unmount from a server that is known to be down
+ */
+ if (!(mf->mf_flags & MFF_LOGDOWN)) {
+ /* Only log this once, otherwise gets a bit boring */
+ plog(XLOG_STATS, "file server %s is down - timeout of \"%s\" ignored", mf->mf_server->fs_host, mp->am_path);
+ mf->mf_flags |= MFF_LOGDOWN;
+ }
+ return 0;
+ }
+
+ dlog("\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount);
+ mf->mf_flags |= MFF_UNMOUNTING;
- if ((mf->mf_ops->fs_flags & FS_UBACKGROUND) &&
+#ifdef HAVE_FS_AUTOFS
+ if (mf->mf_flags & MFF_IS_AUTOFS)
+ autofs_release_mp(mp);
+#endif /* HAVE_FS_AUTOFS */
+
+ if ((mf->mf_fsflags & FS_UBACKGROUND) &&
(mf->mf_flags & MFF_MOUNTED)) {
- if (mf->mf_refc == 1 && !FSRV_ISUP(mf->mf_server)) {
- /*
- * Don't try to unmount from a server that is known to be down
- */
- if (!(mf->mf_flags & MFF_LOGDOWN)) {
- /* Only log this once, otherwise gets a bit boring */
- plog(XLOG_STATS, "file server %s is down - timeout of \"%s\" ignored", mf->mf_server->fs_host, mp->am_path);
- mf->mf_flags |= MFF_LOGDOWN;
- }
- } else {
- /* Clear logdown flag - since the server must be up */
- mf->mf_flags &= ~MFF_LOGDOWN;
-#ifdef DEBUG
- dlog("\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount);
- /* dlog("Will background the unmount attempt"); */
-#endif /* DEBUG */
- /*
- * Note that we are unmounting this node
- */
- mf->mf_flags |= MFF_UNMOUNTING;
- run_task(unmount_node_wrap, (voidp) mp,
- free_map_if_success, (voidp) mp);
- was_backgrounded = 1;
-#ifdef DEBUG
- dlog("unmount attempt backgrounded");
-#endif /* DEBUG */
- }
+ dlog("Trying unmount in background");
+ run_task(unmount_node, (opaque_t) mp,
+ free_map_if_success, (opaque_t) mp);
+ was_backgrounded = 1;
} else {
-#ifdef DEBUG
- dlog("\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount);
dlog("Trying unmount in foreground");
-#endif /* DEBUG */
- mf->mf_flags |= MFF_UNMOUNTING;
- free_map_if_success(unmount_node(mp), 0, (voidp) mp);
-#ifdef DEBUG
+ free_map_if_success(unmount_node((opaque_t) mp), 0, (opaque_t) mp);
dlog("unmount attempt done");
-#endif /* DEBUG */
}
return was_backgrounded;
@@ -1003,25 +942,23 @@ unmount_mp(am_node *mp)
void
-timeout_mp(voidp v)
+timeout_mp(opaque_t v) /* argument not used?! */
{
int i;
time_t t = NEVER;
- time_t now = clocktime();
- int backoff = NumChild / 4;
+ time_t now = clocktime(NULL);
+ int backoff = NumChildren / 4;
-#ifdef DEBUG
dlog("Timing out automount points...");
-#endif /* DEBUG */
for (i = last_used_map; i >= 0; --i) {
am_node *mp = exported_ap[i];
mntfs *mf;
/*
- * Just continue if nothing mounted, or can't be timed out.
+ * Just continue if nothing mounted
*/
- if (!mp || (mp->am_flags & AMF_NOTIMEOUT))
+ if (!mp)
continue;
/*
@@ -1031,6 +968,17 @@ timeout_mp(voidp v)
if (!mf)
continue;
+#ifdef HAVE_FS_AUTOFS
+ if (mf->mf_flags & MFF_IS_AUTOFS && mp->am_autofs_ttl != NEVER) {
+ if (now >= mp->am_autofs_ttl)
+ autofs_timeout_mp(mp);
+ t = smallest_t(t, mp->am_autofs_ttl);
+ }
+#endif /* HAVE_FS_AUTOFS */
+
+ if (mp->am_flags & AMF_NOTIMEOUT)
+ continue;
+
/*
* Don't delete last reference to a restarted filesystem.
*/
@@ -1087,9 +1035,7 @@ timeout_mp(voidp v)
}
if (t == NEVER) {
-#ifdef DEBUG
dlog("No further timeouts");
-#endif /* DEBUG */
t = now + ONE_HOUR;
}
@@ -1108,9 +1054,7 @@ timeout_mp(voidp v)
*/
if ((int) amd_state >= (int) Finishing)
t = now + 1;
-#ifdef DEBUG
dlog("Next mount timeout in %lds", (long) (t - now));
-#endif /* DEBUG */
timeout_mp_id = timeout(t - now, timeout_mp, 0);
}
diff --git a/contrib/amd/amd/mapc.c b/contrib/amd/amd/mapc.c
index 591c4f3..d7efdbc 100644
--- a/contrib/amd/amd/mapc.c
+++ b/contrib/amd/amd/mapc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1989 Jan-Simon Pendry
* Copyright (c) 1989 Imperial College of Science, Technology & Medicine
* Copyright (c) 1989 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: mapc.c,v 1.7.2.7 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/mapc.c
*
*/
@@ -85,8 +84,6 @@
#define MREC_PART 1
#define MREC_NONE 0
-#define MAX_CHAIN 2048
-
static struct opt_tab mapc_opt[] =
{
{"all", MAPC_ALL},
@@ -201,12 +198,17 @@ extern int ndbm_search(mnt_map *, char *, char *, char **, time_t *);
extern int ndbm_mtime(mnt_map *, char *, time_t *);
#endif /* HAVE_MAP_NDBM */
+/* EXECUTABLE MAPS */
+#ifdef HAVE_MAP_EXEC
+extern int exec_init(mnt_map *, char *, time_t *);
+extern int exec_search(mnt_map *, char *, char *, char **, time_t *);
+#endif /* HAVE_MAP_EXEC */
+
/* FILE MAPS */
#ifdef HAVE_MAP_FILE
-extern int file_init(mnt_map *, char *, time_t *);
+extern int file_init_or_mtime(mnt_map *, char *, time_t *);
extern int file_reload(mnt_map *, char *, add_fn *);
extern int file_search(mnt_map *, char *, char *, char **, time_t *);
-extern int file_mtime(mnt_map *, char *, time_t *);
#endif /* HAVE_MAP_FILE */
@@ -302,14 +304,25 @@ static map_type maptypes[] =
#ifdef HAVE_MAP_FILE
{
"file",
- file_init,
+ file_init_or_mtime,
file_reload,
NULL, /* isup function */
file_search,
- file_mtime,
+ file_init_or_mtime,
MAPC_ALL
},
#endif /* HAVE_MAP_FILE */
+#ifdef HAVE_MAP_EXEC
+ {
+ "exec",
+ exec_init,
+ error_reload,
+ NULL, /* isup function */
+ exec_search,
+ error_mtime,
+ MAPC_INC
+ },
+#endif /* HAVE_MAP_EXEC */
{
"error",
error_init,
@@ -337,16 +350,27 @@ kvhash_of(char *key)
void
-mapc_showtypes(char *buf)
+mapc_showtypes(char *buf, size_t l)
{
- map_type *mt;
- char *sep = "";
+ map_type *mt=NULL, *lastmt;
+ int linesize = 0, i;
+ i = sizeof(maptypes) / sizeof(maptypes[0]);
+ lastmt = maptypes + i;
buf[0] = '\0';
- for (mt = maptypes; mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]); mt++) {
- strcat(buf, sep);
- strcat(buf, mt->name);
- sep = ", ";
+ for (mt = maptypes; mt < lastmt; mt++) {
+ xstrlcat(buf, mt->name, l);
+ if (mt == (lastmt-1))
+ break; /* if last one, don't do xstrlcat's that follows */
+ linesize += strlen(mt->name);
+ if (--i > 0) {
+ xstrlcat(buf, ", ", l);
+ linesize += 2;
+ }
+ if (linesize > 54) {
+ linesize = 0;
+ xstrlcat(buf, "\n\t\t ", l);
+ }
}
}
@@ -386,9 +410,7 @@ mapc_add_kv(mnt_map *m, char *key, char *val)
regex_t re;
#endif /* HAVE_REGEXEC */
-#ifdef DEBUG
dlog("add_kv: %s -> %s", key, val);
-#endif /* DEBUG */
#ifdef HAVE_REGEXEC
if (MAPC_ISRE(m)) {
@@ -398,7 +420,7 @@ mapc_add_kv(mnt_map *m, char *key, char *val)
/*
* Make sure the string is bound to the start and end
*/
- sprintf(pattern, "^%s$", key);
+ xsnprintf(pattern, sizeof(pattern), "^%s$", key);
retval = regcomp(&re, pattern, REG_ICASE);
if (retval != 0) {
char errstr[256];
@@ -492,11 +514,12 @@ mapc_find_wildcard(mnt_map *m)
* Do a map reload.
* Attempt to reload without losing current data by switching the hashes
* round.
+ * If reloading was needed and succeeded, return 1; else return 0.
*/
-static void
+static int
mapc_reload_map(mnt_map *m)
{
- int error;
+ int error, ret = 0;
kv *maphash[NKVHASH], *tmphash[NKVHASH];
time_t t;
@@ -512,11 +535,9 @@ mapc_reload_map(mnt_map *m)
if (m->reloads != 0 && do_mapc_reload != 0) {
if (t <= m->modify) {
plog(XLOG_INFO, "reload of map %s is not needed (in sync)", m->map_name);
-#ifdef DEBUG
dlog("map %s last load time is %d, last modify time is %d",
m->map_name, (int) m->modify, (int) t);
-#endif /* DEBUG */
- return;
+ return ret;
}
}
@@ -524,9 +545,7 @@ mapc_reload_map(mnt_map *m)
memcpy((voidp) maphash, (voidp) m->kvhash, sizeof(m->kvhash));
memset((voidp) m->kvhash, 0, sizeof(m->kvhash));
-#ifdef DEBUG
dlog("calling map reload on %s", m->map_name);
-#endif /* DEBUG */
error = (*m->reload) (m, m->map_name, mapc_add_kv);
if (error) {
if (m->reloads == 0)
@@ -547,15 +566,15 @@ mapc_reload_map(mnt_map *m)
mapc_clear(m);
memcpy((voidp) m->kvhash, (voidp) tmphash, sizeof(m->kvhash));
m->modify = t;
+ ret = 1;
}
m->wildcard = 0;
-#ifdef DEBUG
dlog("calling mapc_search for wildcard");
-#endif /* DEBUG */
error = mapc_search(m, wildcard, &m->wildcard);
if (error)
m->wildcard = 0;
+ return ret;
}
@@ -567,7 +586,7 @@ mapc_create(char *map, char *opt, const char *type)
{
mnt_map *m = ALLOC(struct mnt_map);
map_type *mt;
- time_t modify;
+ time_t modify = 0;
int alloc = 0;
cmdoption(opt, mapc_opt, &alloc);
@@ -603,9 +622,7 @@ mapc_create(char *map, char *opt, const char *type)
for (mt = maptypes;
mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]);
mt++) {
-#ifdef DEBUG
dlog("trying to initialize map %s of type %s ...", map, mt->name);
-#endif /* DEBUG */
if ((*mt->init) (m, map, &modify) == 0) {
break;
}
@@ -652,9 +669,7 @@ mapc_create(char *map, char *opt, const char *type)
#endif /* HAVE_REGEXEC */
}
-#ifdef DEBUG
dlog("Map for %s coming from maptype %s", map, mt->name);
-#endif /* DEBUG */
m->alloc = alloc;
m->reload = mt->reload;
@@ -667,6 +682,8 @@ mapc_create(char *map, char *opt, const char *type)
m->refc = 1;
m->wildcard = 0;
m->reloads = 0;
+ /* Unfortunately with current code structure, this cannot be initialized here */
+ m->cfm = NULL;
/*
* synchronize cache with reality
@@ -732,7 +749,7 @@ mapc_find(char *map, char *opt, const char *maptype)
* add it to the list of maps
*/
ITER(m, mnt_map, &map_list_head)
- if (STREQ(m->map_name, map))
+ if (STREQ(m->map_name, map))
return mapc_dup(m);
m = mapc_create(map, opt, maptype);
ins_que(&m->hdr, &map_list_head);
@@ -745,9 +762,9 @@ mapc_find(char *map, char *opt, const char *maptype)
* Free a map.
*/
void
-mapc_free(voidp v)
+mapc_free(opaque_t arg)
{
- mnt_map *m = v;
+ mnt_map *m = (mnt_map *) arg;
/*
* Decrement the reference count.
@@ -883,12 +900,15 @@ mapc_meta_search(mnt_map *m, char *key, char **pval, int recurse)
* For example:
* "src/gnu/gcc" -> "src / gnu / *" -> "src / *"
*/
- strcpy(wildname, key);
+ xstrlcpy(wildname, key, sizeof(wildname));
while (error && (subp = strrchr(wildname, '/'))) {
- strcpy(subp, "/*");
-#ifdef DEBUG
+ /*
+ * sizeof space left in subp is sizeof wildname minus what's left
+ * after the strchr above returned a pointer inside wildname into
+ * subp.
+ */
+ xstrlcpy(subp, "/*", sizeof(wildname) - (subp - wildname));
dlog("mapc recurses on %s", wildname);
-#endif /* DEBUG */
error = mapc_meta_search(m, wildname, pval, MREC_PART);
if (error)
*subp = 0;
@@ -917,25 +937,42 @@ mapc_search(mnt_map *m, char *key, char **pval)
static void
mapc_sync(mnt_map *m)
{
- if (m->alloc != MAPC_ROOT) {
+ int need_mtime_update = 0;
- /* do not clear map if map service is down */
- if (m->isup) {
- if (!((*m->isup)(m, m->map_name))) {
- plog(XLOG_ERROR, "mapc_sync: map %s is down: not clearing map", m->map_name);
- return;
- }
+ if (m->alloc == MAPC_ROOT)
+ return; /* nothing to do */
+
+ /* do not clear map if map service is down */
+ if (m->isup) {
+ if (!((*m->isup)(m, m->map_name))) {
+ plog(XLOG_ERROR, "mapc_sync: map %s is down: not clearing map", m->map_name);
+ return;
}
+ }
+
+ if (m->alloc >= MAPC_ALL) {
+ /* mapc_reload_map() always works */
+ need_mtime_update = mapc_reload_map(m);
+ } else {
+ mapc_clear(m);
+ /*
+ * Attempt to find the wildcard entry
+ */
+ mapc_find_wildcard(m);
+ need_mtime_update = 1; /* because mapc_clear always works */
+ }
- if (m->alloc >= MAPC_ALL) {
- /* mapc_reload_map() always works */
- mapc_reload_map(m);
+ /*
+ * To be safe, update the mtime of the mnt_map's own node, so that the
+ * kernel will flush all of its cached entries.
+ */
+ if (need_mtime_update && m->cfm) {
+ am_node *mp = find_ap(m->cfm->cfm_dir);
+ if (mp) {
+ clocktime(&mp->am_fattr.na_mtime);
} else {
- mapc_clear(m);
- /*
- * Attempt to find the wildcard entry
- */
- mapc_find_wildcard(m);
+ plog(XLOG_ERROR, "cannot find map %s to update its mtime",
+ m->cfm->cfm_dir);
}
}
}
@@ -972,7 +1009,7 @@ mapc_reload(void)
static int
root_init(mnt_map *m, char *map, time_t *tp)
{
- *tp = clocktime();
+ *tp = clocktime(NULL);
return STREQ(map, ROOT_MAP) ? 0 : ENOENT;
}
@@ -1007,36 +1044,39 @@ root_newmap(const char *dir, const char *opts, const char *map, const cf_map_t *
if (cfm) {
if (map) {
- sprintf(str, "cache:=mapdefault;type:=toplvl;fs:=\"%s\"",
- get_full_path(map, cfm->cfm_search_path, cfm->cfm_type));
+ xsnprintf(str, sizeof(str),
+ "cache:=mapdefault;type:=toplvl;mount_type:=%s;fs:=\"%s\"",
+ cfm->cfm_flags & CFM_MOUNT_TYPE_AUTOFS ? "autofs" : "nfs",
+ get_full_path(map, cfm->cfm_search_path, cfm->cfm_type));
if (opts && opts[0] != '\0') {
- strcat(str, ";");
- strcat(str, opts);
+ xstrlcat(str, ";", sizeof(str));
+ xstrlcat(str, opts, sizeof(str));
}
if (cfm->cfm_flags & CFM_BROWSABLE_DIRS_FULL)
- strcat(str, ";opts:=rw,fullybrowsable");
+ xstrlcat(str, ";opts:=rw,fullybrowsable", sizeof(str));
if (cfm->cfm_flags & CFM_BROWSABLE_DIRS)
- strcat(str, ";opts:=rw,browsable");
+ xstrlcat(str, ";opts:=rw,browsable", sizeof(str));
if (cfm->cfm_type) {
- strcat(str, ";maptype:=");
- strcat(str, cfm->cfm_type);
+ xstrlcat(str, ";maptype:=", sizeof(str));
+ xstrlcat(str, cfm->cfm_type, sizeof(str));
}
} else {
- strcpy(str, opts);
+ xstrlcpy(str, opts, sizeof(str));
}
} else {
if (map)
- sprintf(str, "cache:=mapdefault;type:=toplvl;fs:=\"%s\";%s",
- map, opts ? opts : "");
+ xsnprintf(str, sizeof(str),
+ "cache:=mapdefault;type:=toplvl;fs:=\"%s\";%s",
+ map, opts ? opts : "");
else
- strcpy(str, opts);
+ xstrlcpy(str, opts, sizeof(str));
}
mapc_repl_kv(root_map, strdup((char *)dir), strdup(str));
}
int
-mapc_keyiter(mnt_map *m, void (*fn) (char *, voidp), voidp arg)
+mapc_keyiter(mnt_map *m, key_fun *fn, opaque_t arg)
{
int i;
int c = 0;
@@ -1056,10 +1096,10 @@ mapc_keyiter(mnt_map *m, void (*fn) (char *, voidp), voidp arg)
/*
* Iterate on the root map and call (*fn)() on the key of all the nodes.
- * Finally throw away the root map.
+ * Returns the number of entries in the root map.
*/
int
-root_keyiter(void (*fn)(char *, voidp), voidp arg)
+root_keyiter(key_fun *fn, opaque_t arg)
{
if (root_map) {
int c = mapc_keyiter(root_map, fn, arg);
@@ -1071,132 +1111,6 @@ root_keyiter(void (*fn)(char *, voidp), voidp arg)
/*
- * Was: NEW_TOPLVL_READDIR
- * Search a chain for an entry with some name.
- * -Erez Zadok <ezk@cs.columbia.edu>
- */
-static int
-key_already_in_chain(char *keyname, const nfsentry *chain)
-{
- const nfsentry *tmpchain = chain;
-
- while (tmpchain) {
- if (keyname && tmpchain->ne_name && STREQ(keyname, tmpchain->ne_name))
- return 1;
- tmpchain = tmpchain->ne_nextentry;
- }
-
- return 0;
-}
-
-
-/*
- * Create a chain of entries which are not linked.
- * -Erez Zadok <ezk@cs.columbia.edu>
- */
-nfsentry *
-make_entry_chain(am_node *mp, const nfsentry *current_chain, int fully_browsable)
-{
- static u_int last_cookie = (u_int) 2; /* monotonically increasing */
- static nfsentry chain[MAX_CHAIN];
- static int max_entries = MAX_CHAIN;
- char *key;
- int num_entries = 0, preflen = 0, i;
- nfsentry *retval = (nfsentry *) NULL;
- mntfs *mf;
- mnt_map *mmp;
-
- if (!mp) {
- plog(XLOG_DEBUG, "make_entry_chain: mp is (NULL)");
- return retval;
- }
- mf = mp->am_mnt;
- if (!mf) {
- plog(XLOG_DEBUG, "make_entry_chain: mp->am_mnt is (NULL)");
- return retval;
- }
- mmp = (mnt_map *) mf->mf_private;
- if (!mmp) {
- plog(XLOG_DEBUG, "make_entry_chain: mp->am_mnt->mf_private is (NULL)");
- return retval;
- }
-
- if (mp->am_pref)
- preflen = strlen(mp->am_pref);
-
- /* iterate over keys */
- for (i = 0; i < NKVHASH; i++) {
- kv *k;
- for (k = mmp->kvhash[i]; k ; k = k->next) {
-
- /*
- * Skip unwanted entries which are either not real entries or
- * very difficult to interpret (wildcards...) This test needs
- * lots of improvement. Any takers?
- */
- key = k->key;
- if (!key)
- continue;
-
- /* Skip '*' */
- if (!fully_browsable && strchr(key, '*'))
- continue;
-
- /*
- * If the map has a prefix-string then check if the key starts with
- * this string, and if it does, skip over this prefix. If it has a
- * prefix and it doesn't match the start of the key, skip it.
- */
- if (preflen && (preflen <= (strlen(key)))) {
- if (!NSTREQ(key, mp->am_pref, preflen))
- continue;
- key += preflen;
- } else if (preflen) {
- continue;
- }
-
- /* no more '/' are allowed, unless browsable_dirs=full was used */
- if (!fully_browsable && strchr(key, '/'))
- continue;
-
- /* no duplicates allowed */
- if (key_already_in_chain(key, current_chain))
- continue;
-
- /* fill in a cell and link the entry */
- if (num_entries >= max_entries) {
- /* out of space */
- plog(XLOG_DEBUG, "make_entry_chain: no more space in chain");
- if (num_entries > 0) {
- chain[num_entries - 1].ne_nextentry = 0;
- retval = &chain[0];
- }
- return retval;
- }
-
- /* we have space. put entry in next cell */
- ++last_cookie;
- chain[num_entries].ne_fileid = (u_int) last_cookie;
- *(u_int *) chain[num_entries].ne_cookie = (u_int) last_cookie;
- chain[num_entries].ne_name = key;
- if (num_entries < max_entries - 1) { /* link to next one */
- chain[num_entries].ne_nextentry = &chain[num_entries + 1];
- }
- ++num_entries;
- } /* end of "while (k)" */
- } /* end of "for (i ... NKVHASH ..." */
-
- /* terminate chain */
- if (num_entries > 0) {
- chain[num_entries - 1].ne_nextentry = 0;
- retval = &chain[0];
- }
-
- return retval;
-}
-
-
-/*
* Error map
*/
static int
@@ -1260,15 +1174,15 @@ get_full_path(const char *map, const char *path, const char *type)
return map;
/* now break path into components, and search in each */
- strcpy(component, path);
+ xstrlcpy(component, path, sizeof(component));
str = strtok(component, ":");
do {
- strcpy(full_path, str);
+ xstrlcpy(full_path, str, sizeof(full_path));
len = strlen(full_path);
if (full_path[len - 1] != '/') /* add trailing "/" if needed */
- strcat(full_path, "/");
- strcat(full_path, map);
+ xstrlcat(full_path, "/", sizeof(full_path));
+ xstrlcat(full_path, map, sizeof(full_path));
if (access(full_path, R_OK) == 0)
return full_path;
str = strtok(NULL, ":");
diff --git a/contrib/amd/amd/mntfs.c b/contrib/amd/amd/mntfs.c
index 02bcae3..6021838 100644
--- a/contrib/amd/amd/mntfs.c
+++ b/contrib/amd/amd/mntfs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: mntfs.c,v 1.5.2.5 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/mntfs.c
*
*/
@@ -71,12 +70,14 @@ static void
init_mntfs(mntfs *mf, am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts)
{
mf->mf_ops = ops;
+ mf->mf_fsflags = ops->nfs_fs_flags;
mf->mf_fo = mo;
mf->mf_mount = strdup(mp);
mf->mf_info = strdup(info);
mf->mf_auto = strdup(auto_opts);
mf->mf_mopts = strdup(mopts);
mf->mf_remopts = strdup(remopts);
+ mf->mf_loopdev = NULL;
mf->mf_refc = 1;
mf->mf_flags = 0;
mf->mf_error = -1;
@@ -104,17 +105,25 @@ alloc_mntfs(am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, cha
}
+/* find a matching mntfs in our list */
mntfs *
-find_mntfs(am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts)
+locate_mntfs(am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts)
{
mntfs *mf;
-#ifdef DEBUG
- dlog("Locating mntfs reference to %s", mp);
-#endif /* DEBUG */
+ dlog("Locating mntfs reference to (%s,%s)", mp, info);
ITER(mf, mntfs, &mfhead) {
- if (STREQ(mf->mf_mount, mp)) {
+ /*
+ * For backwards compatibility purposes, we treat already-mounted
+ * filesystems differently and only require a match of their mount point,
+ * not of their server info. After all, there is little we can do if
+ * the user asks us to mount two different things onto the same mount: one
+ * will always cover the other one.
+ */
+ if (STREQ(mf->mf_mount, mp) &&
+ ((mf->mf_flags & MFF_MOUNTED && !(mf->mf_fsflags & FS_DIRECT))
+ || (STREQ(mf->mf_info, info) && mf->mf_ops == ops))) {
/*
* Handle cases where error ops are involved
*/
@@ -125,35 +134,32 @@ find_mntfs(am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char
*/
if (mf->mf_ops != &amfs_error_ops)
continue;
- else
- return dup_mntfs(mf);
- } else { /* ops != &amfs_error_ops */
- /*
- * If the existing ops are amfs_error_ops
- * then continue...
- */
- if (mf->mf_ops == &amfs_error_ops)
- continue;
+ return dup_mntfs(mf);
}
- if ((mf->mf_flags & MFF_RESTART) && amd_state == Run) {
+ dlog("mf->mf_flags = %#x", mf->mf_flags);
+ mf->mf_fo = mo;
+ if ((mf->mf_flags & MFF_RESTART) && amd_state < Finishing) {
/*
* Restart a previously mounted filesystem.
*/
- mntfs *mf2 = alloc_mntfs(&amfs_inherit_ops, mo, mp, info, auto_opts, mopts, remopts);
-#ifdef DEBUG
dlog("Restarting filesystem %s", mf->mf_mount);
-#endif /* DEBUG */
/*
- * Remember who we are restarting
+ * If we are restarting an amd internal filesystem,
+ * we need to initialize it a bit.
+ *
+ * We know it's internal because it is marked as toplvl.
*/
- mf2->mf_private = (voidp) dup_mntfs(mf);
- mf2->mf_prfree = free_mntfs;
- return mf2;
+ if (mf->mf_ops == &amfs_toplvl_ops) {
+ mf->mf_ops = ops;
+ mf->mf_info = strealloc(mf->mf_info, info);
+ ops->mounted(mf); /* XXX: not right, but will do for now */
+ }
+
+ return mf;
}
- mf->mf_fo = mo;
if (!(mf->mf_flags & (MFF_MOUNTED | MFF_MOUNTING | MFF_UNMOUNTING))) {
fserver *fs;
mf->mf_flags &= ~MFF_ERROR;
@@ -164,7 +170,7 @@ find_mntfs(am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char
mf->mf_info = strealloc(mf->mf_info, info);
if (mf->mf_private && mf->mf_prfree) {
- (*mf->mf_prfree) (mf->mf_private);
+ mf->mf_prfree(mf->mf_private);
mf->mf_private = 0;
}
@@ -177,6 +183,18 @@ find_mntfs(am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char
} /* end of "if (STREQ(mf-> ..." */
} /* end of ITER */
+ return 0;
+}
+
+
+/* find a matching mntfs in our list, create a new one if none is found */
+mntfs *
+find_mntfs(am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts)
+{
+ mntfs *mf = locate_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts);
+ if (mf)
+ return mf;
+
return alloc_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts);
}
@@ -189,7 +207,7 @@ new_mntfs(void)
static void
-uninit_mntfs(mntfs *mf, int rmd)
+uninit_mntfs(mntfs *mf)
{
if (mf->mf_auto)
XFREE(mf->mf_auto);
@@ -202,12 +220,6 @@ uninit_mntfs(mntfs *mf, int rmd)
if (mf->mf_private && mf->mf_prfree)
(*mf->mf_prfree) (mf->mf_private);
- /*
- * Clean up any directories that were made
- */
- if (rmd && (mf->mf_flags & MFF_MKMNT))
- rmdirs(mf->mf_mount);
- /* free mf_mount _AFTER_ removing the directories */
if (mf->mf_mount)
XFREE(mf->mf_mount);
@@ -237,7 +249,7 @@ discard_mntfs(voidp v)
/*
* Free memory
*/
- uninit_mntfs(mf, TRUE);
+ uninit_mntfs(mf);
XFREE(mf);
--mntfs_allocated;
@@ -260,17 +272,27 @@ flush_mntfs(void)
void
-free_mntfs(voidp v)
+free_mntfs(opaque_t arg)
{
- mntfs *mf = v;
+ mntfs *mf = (mntfs *) arg;
+
+ dlog("free_mntfs <%s> type %s mf_refc %d flags %x",
+ mf->mf_mount, mf->mf_ops->fs_type, mf->mf_refc, mf->mf_flags);
/*
* We shouldn't ever be called to free something that has
* a non-positive refcount. Something is badly wrong if
* we have been! Ignore the request for now...
*/
- if(mf->mf_refc <= 0) {
- plog(XLOG_ERROR, "IGNORING free_mntfs for <%s>: refc %d, flags %x",
+ if (mf->mf_refc <= 0) {
+ plog(XLOG_ERROR, "IGNORING free_mntfs for <%s>: refc %d, flags %x (bug?)",
+ mf->mf_mount, mf->mf_refc, mf->mf_flags);
+ return;
+ }
+
+ /* don't discard last reference of a restarted/kept mntfs */
+ if (mf->mf_refc == 1 && mf->mf_flags & MFF_RSTKEEP) {
+ plog(XLOG_ERROR, "IGNORING free_mntfs for <%s>: refc %d, flags %x (restarted)",
mf->mf_mount, mf->mf_refc, mf->mf_flags);
return;
}
@@ -292,15 +314,12 @@ free_mntfs(voidp v)
mf->mf_ops->fs_type, mf->mf_mount);
}
- if (mf->mf_ops->fs_flags & FS_DISCARD) {
-#ifdef DEBUG
+ if (mf->mf_fsflags & FS_DISCARD) {
dlog("Immediately discarding mntfs for %s", mf->mf_mount);
-#endif /* DEBUG */
discard_mntfs(mf);
} else {
-#ifdef DEBUG
if (mf->mf_flags & MFF_RESTART) {
dlog("Discarding remount hook for %s", mf->mf_mount);
} else {
@@ -309,7 +328,6 @@ free_mntfs(voidp v)
}
if (mf->mf_flags & (MFF_MOUNTED | MFF_MOUNTING | MFF_UNMOUNTING))
dlog("mntfs reference for %s still active", mf->mf_mount);
-#endif /* DEBUG */
mf->mf_cid = timeout(ALLOWED_MOUNT_TIME, discard_mntfs, (voidp) mf);
}
}
@@ -322,7 +340,7 @@ realloc_mntfs(mntfs *mf, am_ops *ops, am_opts *mo, char *mp, char *info, char *a
mntfs *mf2;
if (mf->mf_refc == 1 &&
- mf->mf_ops == &amfs_inherit_ops &&
+ mf->mf_flags & MFF_RESTART &&
STREQ(mf->mf_mount, mp)) {
/*
* If we are inheriting then just return
@@ -344,23 +362,5 @@ realloc_mntfs(mntfs *mf, am_ops *ops, am_opts *mo, char *mp, char *info, char *a
mf2 = find_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts);
free_mntfs(mf);
-#if 0
- /*
- * XXX: EZK IS THIS RIGHT???
- * The next "if" statement is what supposedly fixes bgmount() in
- * that it will actually use the ops structure of the next mount
- * entry, if the previous one failed.
- */
- if (mf2 &&
- ops &&
- mf2->mf_ops != ops &&
- mf2->mf_ops != &amfs_inherit_ops &&
- mf2->mf_ops != &amfs_toplvl_ops &&
- mf2->mf_ops != &amfs_error_ops) {
- plog(XLOG_WARNING, "realloc_mntfs: copy fallback ops \"%s\" over \"%s\"",
- ops->fs_type, mf2->mf_ops->fs_type);
- mf2->mf_ops = ops;
- }
-#endif
return mf2;
}
diff --git a/contrib/amd/amd/nfs_prot_svc.c b/contrib/amd/amd/nfs_prot_svc.c
index 39d1d45..0dd6992 100644
--- a/contrib/amd/amd/nfs_prot_svc.c
+++ b/contrib/amd/amd/nfs_prot_svc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1989 Jan-Simon Pendry
* Copyright (c) 1989 Imperial College of Science, Technology & Medicine
* Copyright (c) 1989 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: nfs_prot_svc.c,v 1.5.2.6 2004/01/21 04:04:58 ib42 Exp $
+ * File: am-utils/amd/nfs_prot_svc.c
*
*/
@@ -69,7 +68,7 @@ extern nfsreaddirres *nfsproc_readdir_2_svc(nfsreaddirargs *, struct svc_req *);
extern nfsstatfsres *nfsproc_statfs_2_svc(am_nfs_fh *, struct svc_req *);
/* global variables */
-SVCXPRT *nfs_program_2_transp;
+SVCXPRT *current_transp;
/* typedefs */
typedef char *(*nfssvcproc_t)(voidp, struct svc_req *);
@@ -98,30 +97,60 @@ nfs_program_2(struct svc_req *rqstp, SVCXPRT *transp)
char *result;
xdrproc_t xdr_argument, xdr_result;
nfssvcproc_t local;
+
+#ifdef HAVE_TRANSPORT_TYPE_TLI
+ /*
+ * On TLI systems we don't use an INET network type, but a "ticlts" (see
+ * /etc/netconfig and conf/transp_tli.c:create_nfs_service). This means
+ * that packets could only come from the loopback interface, and we don't
+ * need to check them and filter possibly spoofed packets. Therefore we
+ * only need to check if the UID caller is correct.
+ */
+# ifdef HAVE___RPC_GET_LOCAL_UID
+ uid_t u;
+ /* extern definition for an internal libnsl function */
+ extern int __rpc_get_local_uid(SVCXPRT *transp, uid_t *uid);
+ if (__rpc_get_local_uid(transp, &u) >= 0 && u != 0) {
+ plog(XLOG_WARNING, "ignoring request from UID %ld, must be 0", (long) u);
+ return;
+ }
+# else /* not HAVE___RPC_GET_LOCAL_UID */
+ dlog("cannot verify local uid for rpc request");
+# endif /* HAVE___RPC_GET_LOCAL_UID */
+#else /* not HAVE_TRANPORT_TYPE_TLI */
struct sockaddr_in *sinp;
char dq[20], dq2[28];
-
sinp = amu_svc_getcaller(rqstp->rq_xprt);
-#ifdef MNT2_NFS_OPT_RESVPORT
+# ifdef MNT2_NFS_OPT_RESVPORT
/* Verify that the request comes from a reserved port */
- if (ntohs(sinp->sin_port) >= IPPORT_RESERVED) &&
+ if (sinp &&
+ ntohs(sinp->sin_port) >= IPPORT_RESERVED &&
!(gopt.flags & CFM_NFS_INSECURE_PORT)) {
plog(XLOG_WARNING, "ignoring request from %s:%u, port not reserved",
- inet_dquad(dq, sinp->sin_addr.s_addr),
+ inet_dquad(dq, sizeof(dq), sinp->sin_addr.s_addr),
ntohs(sinp->sin_port));
return;
}
-#endif /* MNT2_NFS_OPT_RESVPORT */
+# endif /* MNT2_NFS_OPT_RESVPORT */
/* if the address does not match, ignore the request */
- if (sinp->sin_addr.s_addr && sinp->sin_addr.s_addr != myipaddr.s_addr) {
- plog(XLOG_WARNING, "ignoring request from %s:%u, expected %s",
- inet_dquad(dq, sinp->sin_addr.s_addr),
- ntohs(sinp->sin_port),
- inet_dquad(dq2, myipaddr.s_addr));
- return;
+ if (sinp && (sinp->sin_addr.s_addr != myipaddr.s_addr)) {
+ if (gopt.flags & CFM_NFS_ANY_INTERFACE) {
+ if (!is_interface_local(sinp->sin_addr.s_addr)) {
+ plog(XLOG_WARNING, "ignoring request from %s:%u, not a local interface",
+ inet_dquad(dq, sizeof(dq), sinp->sin_addr.s_addr),
+ ntohs(sinp->sin_port));
+ }
+ } else {
+ plog(XLOG_WARNING, "ignoring request from %s:%u, expected %s",
+ inet_dquad(dq, sizeof(dq), sinp->sin_addr.s_addr),
+ ntohs(sinp->sin_port),
+ inet_dquad(dq2, sizeof(dq2), myipaddr.s_addr));
+ return;
+ }
}
+#endif /* not HAVE_TRANPORT_TYPE_TLI */
- nfs_program_2_transp = NULL;
+ current_transp = NULL;
switch (rqstp->rq_proc) {
@@ -158,7 +187,7 @@ nfs_program_2(struct svc_req *rqstp, SVCXPRT *transp)
* be stored in the am_node structure and later used for
* quick_reply().
*/
- nfs_program_2_transp = transp;
+ current_transp = transp;
break;
case NFSPROC_READLINK:
@@ -256,7 +285,7 @@ nfs_program_2(struct svc_req *rqstp, SVCXPRT *transp)
}
result = (*local) (&argument, rqstp);
- nfs_program_2_transp = NULL;
+ current_transp = NULL;
if (result != NULL && !svc_sendreply(transp,
(XDRPROC_T_TYPE) xdr_result,
diff --git a/contrib/amd/amd/nfs_start.c b/contrib/amd/amd/nfs_start.c
index 1bf6df1..f6aba94 100644
--- a/contrib/amd/amd/nfs_start.c
+++ b/contrib/amd/amd/nfs_start.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: nfs_start.c,v 1.5.2.7 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/nfs_start.c
*
*/
@@ -52,8 +51,8 @@
# define SELECT_MAXWAIT 16
#endif /* not SELECT_MAXWAIT */
-SVCXPRT *nfsxprt;
-u_short nfs_port;
+SVCXPRT *nfsxprt = NULL;
+u_short nfs_port = 0;
#ifndef HAVE_SIGACTION
# define MASKED_SIGS (sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGCHLD)|sigmask(SIGHUP))
@@ -92,7 +91,9 @@ checkup(void)
}
}
-#endif /* DEBUG */
+#else /* not DEBUG */
+#define checkup()
+#endif /* not DEBUG */
static int
@@ -121,10 +122,6 @@ do_select(int smask, int fds, fd_set *fdp, struct timeval *tvp)
} else {
select_intr_valid = 1;
/*
- * Invalidate the current clock value
- */
- clock_valid = 0;
- /*
* Allow interrupts. If a signal
* occurs, then it will cause a longjmp
* up above.
@@ -151,9 +148,9 @@ do_select(int smask, int fds, fd_set *fdp, struct timeval *tvp)
/*
* Perhaps reload the cache?
*/
- if (do_mapc_reload < clocktime()) {
+ if (do_mapc_reload < clocktime(NULL)) {
mapc_reload();
- do_mapc_reload = clocktime() + ONE_HOUR;
+ do_mapc_reload = clocktime(NULL) + gopt.map_reload_interval;
}
return nsel;
}
@@ -168,26 +165,17 @@ rpc_pending_now(void)
{
struct timeval tvv;
int nsel;
-#ifdef FD_SET
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(fwd_sock, &readfds);
-#else /* not FD_SET */
- int readfds = (1 << fwd_sock);
-#endif /* not FD_SET */
tvv.tv_sec = tvv.tv_usec = 0;
nsel = select(FD_SETSIZE, &readfds, (fd_set *) 0, (fd_set *) 0, &tvv);
if (nsel < 1)
return (0);
-#ifdef FD_SET
if (FD_ISSET(fwd_sock, &readfds))
return (1);
-#else /* not FD_SET */
- if (readfds & (1 << fwd_sock))
- return (1);
-#endif /* not FD_SET */
return (0);
}
@@ -203,7 +191,7 @@ run_rpc(void)
int smask = sigblock(MASKED_SIGS);
#endif /* not HAVE_SIGACTION */
- next_softclock = clocktime();
+ next_softclock = clocktime(NULL);
amd_state = Run;
@@ -216,31 +204,27 @@ run_rpc(void)
struct timeval tvv;
int nsel;
time_t now;
-#ifdef HAVE_SVC_GETREQSET
fd_set readfds;
+#ifdef HAVE_SVC_GETREQSET
memmove(&readfds, &svc_fdset, sizeof(svc_fdset));
- FD_SET(fwd_sock, &readfds);
#else /* not HAVE_SVC_GETREQSET */
-# ifdef FD_SET
- fd_set readfds;
FD_ZERO(&readfds);
+# ifdef HAVE_FD_SET_FDS_BITS
readfds.fds_bits[0] = svc_fds;
- FD_SET(fwd_sock, &readfds);
-# else /* not FD_SET */
- int readfds = svc_fds | (1 << fwd_sock);
-# endif /* not FD_SET */
+# else /* not HAVE_FD_SET_FDS_BITS */
+ readfds = svc_fds;
+# endif /* not HAVE_FD_SET_FDS_BITS */
#endif /* not HAVE_SVC_GETREQSET */
+ FD_SET(fwd_sock, &readfds);
-#ifdef DEBUG
checkup();
-#endif /* DEBUG */
/*
* If the full timeout code is not called,
* then recompute the time delta manually.
*/
- now = clocktime();
+ now = clocktime(NULL);
if (next_softclock <= now) {
if (amd_state == Finishing)
@@ -251,29 +235,30 @@ run_rpc(void)
}
tvv.tv_usec = 0;
- if (amd_state == Finishing && last_used_map < 0) {
+ if (amd_state == Finishing && get_exported_ap(0) == NULL) {
flush_mntfs();
amd_state = Quit;
break;
}
+
+#ifdef HAVE_FS_AUTOFS
+ autofs_add_fdset(&readfds);
+#endif /* HAVE_FS_AUTOFS */
+
if (tvv.tv_sec <= 0)
tvv.tv_sec = SELECT_MAXWAIT;
-#ifdef DEBUG
if (tvv.tv_sec) {
dlog("Select waits for %ds", (int) tvv.tv_sec);
} else {
dlog("Select waits for Godot");
}
-#endif /* DEBUG */
nsel = do_select(smask, FD_SETSIZE, &readfds, &tvv);
switch (nsel) {
case -1:
if (errno == EINTR) {
-#ifdef DEBUG
dlog("select interrupted");
-#endif /* DEBUG */
continue;
}
plog(XLOG_ERROR, "select: %m");
@@ -284,22 +269,22 @@ run_rpc(void)
default:
/*
- * Read all pending NFS responses at once to avoid having responses.
+ * Read all pending NFS responses at once to avoid having responses
* queue up as a consequence of retransmissions.
*/
-#ifdef FD_SET
if (FD_ISSET(fwd_sock, &readfds)) {
FD_CLR(fwd_sock, &readfds);
-#else /* not FD_SET */
- if (readfds & (1 << fwd_sock)) {
- readfds &= ~(1 << fwd_sock);
-#endif /* not FD_SET */
--nsel;
do {
fwd_reply();
} while (rpc_pending_now() > 0);
}
+#ifdef HAVE_FS_AUTOFS
+ if (nsel)
+ nsel = autofs_handle_fdset(&readfds, nsel);
+#endif /* HAVE_FS_AUTOFS */
+
if (nsel) {
/*
* Anything left must be a normal
@@ -308,11 +293,11 @@ run_rpc(void)
#ifdef HAVE_SVC_GETREQSET
svc_getreqset(&readfds);
#else /* not HAVE_SVC_GETREQSET */
-# ifdef FD_SET
+# ifdef HAVE_FD_SET_FDS_BITS
svc_getreq(readfds.fds_bits[0]);
-# else /* not FD_SET */
+# else /* not HAVE_FD_SET_FDS_BITS */
svc_getreq(readfds);
-# endif /* not FD_SET */
+# endif /* not HAVE_FD_SET_FDS_BITS */
#endif /* not HAVE_SVC_GETREQSET */
}
break;
@@ -344,26 +329,16 @@ mount_automounter(int ppid)
int nmount, ret;
int soNFS;
int udp_soAMQ, tcp_soAMQ;
-#ifdef HAVE_TRANSPORT_TYPE_TLI
struct netconfig *udp_amqncp, *tcp_amqncp;
-#endif /* HAVE_TRANSPORT_TYPE_TLI */
/*
- * Create the nfs service for amd
+ * This must be done first, because it attempts to bind
+ * to various UDP ports and we don't want anything else
+ * potentially taking over those ports before we get a chance
+ * to reserve them.
*/
-#ifdef HAVE_TRANSPORT_TYPE_TLI
- ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2);
- if (ret != 0)
- return ret;
- ret = create_amq_service(&udp_soAMQ, &udp_amqp, &udp_amqncp, &tcp_soAMQ, &tcp_amqp, &tcp_amqncp);
-#else /* not HAVE_TRANSPORT_TYPE_TLI */
- ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2);
- if (ret != 0)
- return ret;
- ret = create_amq_service(&udp_soAMQ, &udp_amqp, &tcp_soAMQ, &tcp_amqp);
-#endif /* not HAVE_TRANSPORT_TYPE_TLI */
- if (ret != 0)
- return ret;
+ if (gopt.flags & CFM_RESTART_EXISTING_MOUNTS)
+ restart_automounter_nodes();
/*
* Start RPC forwarding
@@ -385,6 +360,46 @@ mount_automounter(int ppid)
restart();
/*
+ * Create the nfs service for amd
+ * If nfs_port is already initialized, it means we
+ * already created the service during restart_automounter_nodes().
+ */
+ if (nfs_port == 0) {
+ ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2);
+ if (ret != 0)
+ return ret;
+ }
+ xsnprintf(pid_fsname, sizeof(pid_fsname), "%s:(pid%ld,port%u)",
+ am_get_hostname(), (long) am_mypid, nfs_port);
+
+ /* security: if user sets -D amq, don't even create listening socket */
+ if (!amuDebug(D_AMQ)) {
+ ret = create_amq_service(&udp_soAMQ,
+ &udp_amqp,
+ &udp_amqncp,
+ &tcp_soAMQ,
+ &tcp_amqp,
+ &tcp_amqncp,
+ gopt.preferred_amq_port);
+ if (ret != 0)
+ return ret;
+ }
+
+#ifdef HAVE_FS_AUTOFS
+ if (amd_use_autofs) {
+ /*
+ * Create the autofs service for amd.
+ */
+ ret = create_autofs_service();
+ /* if autofs service fails it is OK if using a test amd */
+ if (ret != 0) {
+ plog(XLOG_WARNING, "autofs service registration failed, turning off autofs support");
+ amd_use_autofs = 0;
+ }
+ }
+#endif /* HAVE_FS_AUTOFS */
+
+ /*
* Mount the top-level auto-mountpoints
*/
nmount = mount_exported();
@@ -401,41 +416,26 @@ mount_automounter(int ppid)
return 0;
}
-#ifdef DEBUG
- amuDebug(D_AMQ) {
-#endif /* DEBUG */
+ if (!amuDebug(D_AMQ)) {
/*
* Complete registration of amq (first TCP service then UDP)
*/
unregister_amq();
-#ifdef HAVE_TRANSPORT_TYPE_TLI
- ret = svc_reg(tcp_amqp, get_amd_program_number(), AMQ_VERSION,
- amq_program_1, tcp_amqncp);
-#else /* not HAVE_TRANSPORT_TYPE_TLI */
- ret = svc_register(tcp_amqp, get_amd_program_number(), AMQ_VERSION,
- amq_program_1, IPPROTO_TCP);
-#endif /* not HAVE_TRANSPORT_TYPE_TLI */
+ ret = amu_svc_register(tcp_amqp, get_amd_program_number(), AMQ_VERSION,
+ amq_program_1, IPPROTO_TCP, tcp_amqncp);
if (ret != 1) {
plog(XLOG_FATAL, "unable to register (AMQ_PROGRAM=%d, AMQ_VERSION, tcp)", get_amd_program_number());
return 3;
}
-#ifdef HAVE_TRANSPORT_TYPE_TLI
- ret = svc_reg(udp_amqp, get_amd_program_number(), AMQ_VERSION,
- amq_program_1, udp_amqncp);
-#else /* not HAVE_TRANSPORT_TYPE_TLI */
- ret = svc_register(udp_amqp, get_amd_program_number(), AMQ_VERSION,
- amq_program_1, IPPROTO_UDP);
-#endif /* not HAVE_TRANSPORT_TYPE_TLI */
+ ret = amu_svc_register(udp_amqp, get_amd_program_number(), AMQ_VERSION,
+ amq_program_1, IPPROTO_UDP, udp_amqncp);
if (ret != 1) {
plog(XLOG_FATAL, "unable to register (AMQ_PROGRAM=%d, AMQ_VERSION, udp)", get_amd_program_number());
return 4;
}
-
-#ifdef DEBUG
}
-#endif /* DEBUG */
/*
* Start timeout_mp rolling
diff --git a/contrib/amd/amd/nfs_subr.c b/contrib/amd/amd/nfs_subr.c
index c216b3e..80d3ca8 100644
--- a/contrib/amd/amd/nfs_subr.c
+++ b/contrib/amd/amd/nfs_subr.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: nfs_subr.c,v 1.6.2.6 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/nfs_subr.c
*
*/
@@ -57,19 +56,45 @@
# define nfs_error(e) ((nfsstat)(e))
#endif /* nfs_error */
+/*
+ * File Handle structure
+ *
+ * This is interpreted by indexing the exported array
+ * by fhh_id (for old-style filehandles), or by retrieving
+ * the node name from fhh_path (for new-style filehandles).
+ *
+ * The whole structure is mapped onto a standard fhandle_t
+ * when transmitted.
+ */
+struct am_fh {
+ u_int fhh_gen; /* generation number */
+ union {
+ struct {
+ int fhh_type; /* old or new am_fh */
+ pid_t fhh_pid; /* process id */
+ int fhh_id; /* map id */
+ } s;
+ char fhh_path[NFS_FHSIZE-sizeof(u_int)]; /* path to am_node */
+ } u;
+};
+
+
/* forward declarations */
+/* converting am-filehandles to mount-points */
+static am_node *fh_to_mp3(am_nfs_fh *fhp, int *rp, int vop);
+static am_node *fh_to_mp(am_nfs_fh *fhp);
static void count_map_entries(const am_node *mp, u_int *out_blocks, u_int *out_bfree, u_int *out_bavail);
static char *
-do_readlink(am_node *mp, int *error_return, nfsattrstat **attrpp)
+do_readlink(am_node *mp, int *error_return)
{
char *ln;
/*
- * If there is a readlink method, then use
- * that, otherwise if a link exists use
- * that, otherwise use the mount point.
+ * If there is a readlink method then use it,
+ * otherwise if a link exists use that,
+ * otherwise use the mount point.
*/
if (mp->am_mnt->mf_ops->readlink) {
int retry = 0;
@@ -86,8 +111,6 @@ do_readlink(am_node *mp, int *error_return, nfsattrstat **attrpp)
} else {
ln = mp->am_mnt->mf_mount;
}
- if (attrpp)
- *attrpp = &mp->am_attr;
return ln;
}
@@ -108,46 +131,38 @@ nfsproc_getattr_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
static nfsattrstat res;
am_node *mp;
int retry;
- time_t now = clocktime();
+ time_t now = clocktime(NULL);
-#ifdef DEBUG
- amuDebug(D_TRACE)
+ if (amuDebug(D_TRACE))
plog(XLOG_DEBUG, "getattr:");
-#endif /* DEBUG */
- mp = fh_to_mp2(argp, &retry);
+ mp = fh_to_mp3(argp, &retry, VLOOK_CREATE);
if (mp == 0) {
-
-#ifdef DEBUG
- amuDebug(D_TRACE)
+ if (amuDebug(D_TRACE))
plog(XLOG_DEBUG, "\tretry=%d", retry);
-#endif /* DEBUG */
if (retry < 0) {
amd_stats.d_drops++;
return 0;
}
res.ns_status = nfs_error(retry);
- } else {
- nfsattrstat *attrp = &mp->am_attr;
-
-#ifdef DEBUG
- amuDebug(D_TRACE)
- plog(XLOG_DEBUG, "\tstat(%s), size = %d, mtime=%ld",
- mp->am_path,
- (int) attrp->ns_u.ns_attr_u.na_size,
- (long) attrp->ns_u.ns_attr_u.na_mtime.nt_seconds);
-#endif /* DEBUG */
-
- /* Delay unmount of what was looked up */
- if (mp->am_timeo_w < 4 * gopt.am_timeo_w)
- mp->am_timeo_w += gopt.am_timeo_w;
- mp->am_ttl = now + mp->am_timeo_w;
-
- mp->am_stats.s_getattr++;
- return attrp;
+ return &res;
}
+ res = mp->am_attr;
+ if (amuDebug(D_TRACE))
+ plog(XLOG_DEBUG, "\tstat(%s), size = %d, mtime=%ld.%ld",
+ mp->am_path,
+ (int) res.ns_u.ns_attr_u.na_size,
+ (long) res.ns_u.ns_attr_u.na_mtime.nt_seconds,
+ (long) res.ns_u.ns_attr_u.na_mtime.nt_useconds);
+
+ /* Delay unmount of what was looked up */
+ if (mp->am_timeo_w < 4 * gopt.am_timeo_w)
+ mp->am_timeo_w += gopt.am_timeo_w;
+ mp->am_ttl = now + mp->am_timeo_w;
+
+ mp->am_stats.s_getattr++;
return &res;
}
@@ -184,18 +199,16 @@ nfsproc_lookup_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
uid_t uid;
gid_t gid;
-#ifdef DEBUG
- amuDebug(D_TRACE)
+ if (amuDebug(D_TRACE))
plog(XLOG_DEBUG, "lookup:");
-#endif /* DEBUG */
/* finally, find the effective uid/gid from RPC request */
if (getcreds(rqstp, &uid, &gid, nfsxprt) < 0)
plog(XLOG_ERROR, "cannot get uid/gid from RPC credentials");
- sprintf(opt_uid, "%d", (int) uid);
- sprintf(opt_gid, "%d", (int) gid);
+ xsnprintf(opt_uid, sizeof(uid_str), "%d", (int) uid);
+ xsnprintf(opt_gid, sizeof(gid_str), "%d", (int) gid);
- mp = fh_to_mp2(&argp->da_fhandle, &retry);
+ mp = fh_to_mp3(&argp->da_fhandle, &retry, VLOOK_CREATE);
if (mp == 0) {
if (retry < 0) {
amd_stats.d_drops++;
@@ -205,11 +218,11 @@ nfsproc_lookup_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
} else {
int error;
am_node *ap;
-#ifdef DEBUG
- amuDebug(D_TRACE)
- plog(XLOG_DEBUG, "\tlookuppn(%s, %s)", mp->am_path, argp->da_name);
-#endif /* DEBUG */
- ap = (*mp->am_mnt->mf_ops->lookuppn) (mp, argp->da_name, &error, VLOOK_CREATE);
+ if (amuDebug(D_TRACE))
+ plog(XLOG_DEBUG, "\tlookup(%s, %s)", mp->am_path, argp->da_name);
+ ap = mp->am_mnt->mf_ops->lookup_child(mp, argp->da_name, &error, VLOOK_CREATE);
+ if (ap && error < 0)
+ ap = mp->am_mnt->mf_ops->mount_child(ap, &error);
if (ap == 0) {
if (error < 0) {
amd_stats.d_drops++;
@@ -237,7 +250,7 @@ nfsproc_lookup_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
void
-quick_reply(am_node *mp, int error)
+nfs_quick_reply(am_node *mp, int error)
{
SVCXPRT *transp = mp->am_transp;
nfsdiropres res;
@@ -271,11 +284,8 @@ quick_reply(am_node *mp, int error)
/*
* Free up transp. It's only used for one reply.
*/
- XFREE(transp);
- mp->am_transp = NULL;
-#ifdef DEBUG
+ XFREE(mp->am_transp);
dlog("Quick reply sent for %s", mp->am_mnt->mf_mount);
-#endif /* DEBUG */
}
}
@@ -287,12 +297,10 @@ nfsproc_readlink_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
am_node *mp;
int retry;
-#ifdef DEBUG
- amuDebug(D_TRACE)
+ if (amuDebug(D_TRACE))
plog(XLOG_DEBUG, "readlink:");
-#endif /* DEBUG */
- mp = fh_to_mp2(argp, &retry);
+ mp = fh_to_mp3(argp, &retry, VLOOK_CREATE);
if (mp == 0) {
readlink_retry:
if (retry < 0) {
@@ -301,15 +309,12 @@ nfsproc_readlink_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
}
res.rlr_status = nfs_error(retry);
} else {
- char *ln = do_readlink(mp, &retry, (nfsattrstat **) 0);
+ char *ln = do_readlink(mp, &retry);
if (ln == 0)
goto readlink_retry;
res.rlr_status = NFS_OK;
-#ifdef DEBUG
- amuDebug(D_TRACE)
- if (ln)
- plog(XLOG_DEBUG, "\treadlink(%s) = %s", mp->am_path, ln);
-#endif /* DEBUG */
+ if (amuDebug(D_TRACE) && ln)
+ plog(XLOG_DEBUG, "\treadlink(%s) = %s", mp->am_path, ln);
res.rlr_u.rlr_data_u = ln;
mp->am_stats.s_readlink++;
}
@@ -388,12 +393,10 @@ unlink_or_rmdir(nfsdiropargs *argp, struct svc_req *rqstp, int unlinkp)
goto out;
}
-#ifdef DEBUG
- amuDebug(D_TRACE)
+ if (amuDebug(D_TRACE))
plog(XLOG_DEBUG, "\tremove(%s, %s)", mp->am_path, argp->da_name);
-#endif /* DEBUG */
- mp = (*mp->am_mnt->mf_ops->lookuppn) (mp, argp->da_name, &retry, VLOOK_DELETE);
+ mp = mp->am_mnt->mf_ops->lookup_child(mp, argp->da_name, &retry, VLOOK_DELETE);
if (mp == 0) {
/*
* Ignore retries...
@@ -503,12 +506,10 @@ nfsproc_readdir_2_svc(nfsreaddirargs *argp, struct svc_req *rqstp)
am_node *mp;
int retry;
-#ifdef DEBUG
- amuDebug(D_TRACE)
+ if (amuDebug(D_TRACE))
plog(XLOG_DEBUG, "readdir:");
-#endif /* DEBUG */
- mp = fh_to_mp2(&argp->rda_fhandle, &retry);
+ mp = fh_to_mp3(&argp->rda_fhandle, &retry, VLOOK_CREATE);
if (mp == 0) {
if (retry < 0) {
amd_stats.d_drops++;
@@ -516,10 +517,8 @@ nfsproc_readdir_2_svc(nfsreaddirargs *argp, struct svc_req *rqstp)
}
res.rdr_status = nfs_error(retry);
} else {
-#ifdef DEBUG
- amuDebug(D_TRACE)
+ if (amuDebug(D_TRACE))
plog(XLOG_DEBUG, "\treaddir(%s)", mp->am_path);
-#endif /* DEBUG */
res.rdr_status = nfs_error((*mp->am_mnt->mf_ops->readdir)
(mp, argp->rda_cookie,
&res.rdr_u.rdr_reply_u, e_res, argp->rda_count));
@@ -538,12 +537,10 @@ nfsproc_statfs_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
int retry;
mntent_t mnt;
-#ifdef DEBUG
- amuDebug(D_TRACE)
+ if (amuDebug(D_TRACE))
plog(XLOG_DEBUG, "statfs:");
-#endif /* DEBUG */
- mp = fh_to_mp2(argp, &retry);
+ mp = fh_to_mp3(argp, &retry, VLOOK_CREATE);
if (mp == 0) {
if (retry < 0) {
amd_stats.d_drops++;
@@ -552,10 +549,8 @@ nfsproc_statfs_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
res.sfr_status = nfs_error(retry);
} else {
nfsstatfsokres *fp;
-#ifdef DEBUG
- amuDebug(D_TRACE)
+ if (amuDebug(D_TRACE))
plog(XLOG_DEBUG, "\tstat_fs(%s)", mp->am_path);
-#endif /* DEBUG */
/*
* just return faked up file system information
@@ -569,7 +564,7 @@ nfsproc_statfs_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
if ((gopt.flags & CFM_SHOW_STATFS_ENTRIES) &&
mp->am_mnt && mp->am_mnt->mf_mopts) {
mnt.mnt_opts = mp->am_mnt->mf_mopts;
- if (hasmntopt(&mnt, "browsable")) {
+ if (amu_hasmntopt(&mnt, "browsable")) {
count_map_entries(mp,
&fp->sfrok_blocks,
&fp->sfrok_bfree,
@@ -629,3 +624,205 @@ out:
*out_bfree = bfree;
*out_bavail = bavail;
}
+
+
+/*
+ * Convert from file handle to automount node.
+ */
+static am_node *
+fh_to_mp3(am_nfs_fh *fhp, int *rp, int vop)
+{
+ struct am_fh *fp = (struct am_fh *) fhp;
+ am_node *ap = 0;
+
+ if (fp->u.s.fhh_type != 0) {
+ /* New filehandle type */
+ int len = sizeof(*fhp) - sizeof(fp->fhh_gen);
+ char *path = xmalloc(len+1);
+ /*
+ * Because fhp is treated as a filehandle we use memcpy
+ * instead of xstrlcpy.
+ */
+ memcpy(path, (char *) fp->u.fhh_path, len);
+ path[len] = '\0';
+ /* dlog("fh_to_mp3: new filehandle: %s", path); */
+
+ ap = path_to_exported_ap(path);
+ XFREE(path);
+ } else {
+ /* dlog("fh_to_mp3: old filehandle: %d", fp->u.s.fhh_id); */
+ /*
+ * Check process id matches
+ * If it doesn't then it is probably
+ * from an old kernel-cached filehandle
+ * which is now out of date.
+ */
+ if (fp->u.s.fhh_pid != get_server_pid()) {
+ dlog("fh_to_mp3: wrong pid %ld != my pid %ld",
+ (long) fp->u.s.fhh_pid, get_server_pid());
+ goto drop;
+ }
+
+ /*
+ * Get hold of the supposed mount node
+ */
+ ap = get_exported_ap(fp->u.s.fhh_id);
+ }
+
+ /*
+ * Check the generation number in the node
+ * matches the one from the kernel. If not
+ * then the old node has been timed out and
+ * a new one allocated.
+ */
+ if (ap != NULL && ap->am_gen != fp->fhh_gen)
+ ap = 0;
+
+ /*
+ * If it doesn't exists then drop the request
+ */
+ if (!ap)
+ goto drop;
+
+#if 0
+ /*
+ * If the node is hung then locate a new node
+ * for it. This implements the replicated filesystem
+ * retries.
+ */
+ if (ap->am_mnt && FSRV_ISDOWN(ap->am_mnt->mf_server) && ap->am_parent) {
+ int error;
+ am_node *orig_ap = ap;
+
+ dlog("fh_to_mp3: %s (%s) is hung: lookup alternative file server",
+ orig_ap->am_path, orig_ap->am_mnt->mf_info);
+
+ /*
+ * Update modify time of parent node.
+ * With any luck the kernel will re-stat
+ * the child node and get new information.
+ */
+ clocktime(&orig_ap->am_fattr.na_mtime);
+
+ /*
+ * Call the parent's lookup routine for an object
+ * with the same name. This may return -1 in error
+ * if a mount is in progress. In any case, if no
+ * mount node is returned the error code is propagated
+ * to the caller.
+ */
+ if (vop == VLOOK_CREATE) {
+ ap = orig_ap->am_parent->am_mnt->mf_ops->lookup_child(orig_ap->am_parent, orig_ap->am_name, &error, vop);
+ if (ap && error < 0)
+ ap = orig_ap->am_parent->am_mnt->mf_ops->mount_child(ap, &error);
+ } else {
+ ap = 0;
+ error = ESTALE;
+ }
+ if (ap == 0) {
+ if (error < 0 && amd_state == Finishing)
+ error = ENOENT;
+ *rp = error;
+ return 0;
+ }
+
+ /*
+ * Update last access to original node. This
+ * avoids timing it out and so sending ESTALE
+ * back to the kernel.
+ * XXX - Not sure we need this anymore (jsp, 90/10/6).
+ */
+ new_ttl(orig_ap);
+
+ }
+#endif
+
+ /*
+ * Disallow references to objects being unmounted, unless
+ * they are automount points.
+ */
+ if (ap->am_mnt && (ap->am_mnt->mf_flags & MFF_UNMOUNTING) &&
+ !(ap->am_flags & AMF_ROOT)) {
+ if (amd_state == Finishing)
+ *rp = ENOENT;
+ else
+ *rp = -1;
+ return 0;
+ }
+ new_ttl(ap);
+
+drop:
+ if (!ap || !ap->am_mnt) {
+ /*
+ * If we are shutting down then it is likely
+ * that this node has disappeared because of
+ * a fast timeout. To avoid things thrashing
+ * just pretend it doesn't exist at all. If
+ * ESTALE is returned, some NFS clients just
+ * keep retrying (stupid or what - if it's
+ * stale now, what's it going to be in 5 minutes?)
+ */
+ if (amd_state == Finishing)
+ *rp = ENOENT;
+ else
+ *rp = ESTALE;
+ amd_stats.d_stale++;
+ }
+
+ return ap;
+}
+
+
+static am_node *
+fh_to_mp(am_nfs_fh *fhp)
+{
+ int dummy;
+
+ return fh_to_mp3(fhp, &dummy, VLOOK_CREATE);
+}
+
+
+/*
+ * Convert from automount node to file handle.
+ */
+void
+mp_to_fh(am_node *mp, am_nfs_fh *fhp)
+{
+ u_int pathlen;
+ struct am_fh *fp = (struct am_fh *) fhp;
+
+ memset((char *) fhp, 0, sizeof(am_nfs_fh));
+
+ /* Store the generation number */
+ fp->fhh_gen = mp->am_gen;
+
+ pathlen = strlen(mp->am_path);
+ if (pathlen <= sizeof(*fhp) - sizeof(fp->fhh_gen)) {
+ /* dlog("mp_to_fh: new filehandle: %s", mp->am_path); */
+
+ /*
+ * Because fhp is treated as a filehandle we use memcpy instead of
+ * xstrlcpy.
+ */
+ memcpy(fp->u.fhh_path, mp->am_path, pathlen); /* making a filehandle */
+ } else {
+ /*
+ * Take the process id
+ */
+ fp->u.s.fhh_pid = get_server_pid();
+
+ /*
+ * ... the map number
+ */
+ fp->u.s.fhh_id = mp->am_mapno;
+
+ /*
+ * ... and the generation number (previously stored)
+ * to make a "unique" triple that will never
+ * be reallocated except across reboots (which doesn't matter)
+ * or if we are unlucky enough to be given the same
+ * pid as a previous amd (very unlikely).
+ */
+ /* dlog("mp_to_fh: old filehandle: %d", fp->u.s.fhh_id); */
+ }
+}
diff --git a/contrib/amd/amd/ops_TEMPLATE.c b/contrib/amd/amd/ops_TEMPLATE.c
index dcec280..3f74219 100644
--- a/contrib/amd/amd/ops_TEMPLATE.c
+++ b/contrib/amd/amd/ops_TEMPLATE.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: ops_TEMPLATE.c,v 1.3.2.5 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/ops_TEMPLATE.c
*
*/
@@ -62,16 +61,14 @@
/* forward declarations */
static char *foofs_match(am_opts *fo);
static int foofs_init(mntfs *mf);
-static int foofs_mount(am_node *mp);
-static int foofs_fmount(mntfs *mf);
-static int foofs_umount(am_node *mp);
-static int foofs_fumount(mntfs *mf);
+static int foofs_mount(am_node *mp, mntfs *mf);
+static int foofs_umount(am_node *mp, mntfs *mf);
static am_node *foofs_lookuppn(am_node *mp, char *fname, int *error_return, int op);
-static int foofs_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, int count);
+static int foofs_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, u_int count);
static am_node *foofs_readlink(am_node *mp, int *error_return);
-static void foofs_mounted(mntfs *mf);
-static void foofs_umounted(am_node *mp);
-fserver *foofs_ffserver(mntfs *mf);
+static void foofs_mounted(am_node *am, mntfs *mf);
+static void foofs_umounted(am_node *mp, mntfs *mf);
+static fserver *foofs_ffserver(mntfs *mf);
/*
@@ -84,16 +81,19 @@ am_ops foofs_ops =
foofs_match, /* match */
foofs_init, /* initialize */
foofs_mount, /* mount vnode */
- foofs_fmount, /* mount vfs */
foofs_umount, /* unmount vnode */
- foofs_fumount, /* unmount VFS */
- foofs_lookuppn, /* lookup path-name */
+ foofs_lookup_child, /* lookup path-name */
+ foofs_mount_child, /* mount path-name */
foofs_readdir, /* read directory */
foofs_readlink, /* read link */
foofs_mounted, /* after-mount extra actions */
foofs_umounted, /* after-umount extra actions */
foofs_ffserver, /* find a file server */
- FS_MKMNT | FS_BACKGROUND | FS_AMQINFO /* flags */
+ foofs_get_wchan, /* return the waiting channel */
+ FS_MKMNT | FS_BACKGROUND | FS_AMQINFO, /* nfs_fs_flags */
+#ifdef HAVE_FS_AUTOFS
+ AUTOFS_TEMPLATE_FS_FLAGS,
+#endif /* HAVE_FS_AUTOFS */
};
@@ -220,7 +220,7 @@ foofs_lookuppn(am_node *mp, char *fname, int *error_return, int op)
* If OK, fills in ep with chain of directory entries.
*/
static int
-foofs_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, int count)
+foofs_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, u_int count)
{
int error = 0;
@@ -284,10 +284,22 @@ foofs_umounted(am_node *mp)
* Find a file server.
* Returns: fserver of found server, or NULL if not found.
*/
-fserver *
+static fserver *
foofs_ffserver(mntfs *mf)
{
plog(XLOG_INFO, "entering foofs_ffserver...");
return NULL;
}
+
+
+/*
+ * Normally just return mf. Only inherit needs to do special tricks.
+ */
+static wchan_t *
+foofs_get_wchan(mntfs *mf)
+{
+ plog(XLOG_INFO, "entering foofs_get_wchan...");
+
+ return mf;
+}
diff --git a/contrib/amd/amd/ops_cachefs.c b/contrib/amd/amd/ops_cachefs.c
index 08c4875..d3e303b 100644
--- a/contrib/amd/amd/ops_cachefs.c
+++ b/contrib/amd/amd/ops_cachefs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: ops_cachefs.c,v 1.3.2.4 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/ops_cachefs.c
*
*/
@@ -55,8 +54,8 @@
/* forward declarations */
static char *cachefs_match(am_opts *fo);
static int cachefs_init(mntfs *mf);
-static int cachefs_fmount(mntfs *mf);
-static int cachefs_fumount(mntfs *mf);
+static int cachefs_mount(am_node *am, mntfs *mf);
+static int cachefs_umount(am_node *am, mntfs *mf);
/*
@@ -67,17 +66,20 @@ am_ops cachefs_ops =
"cachefs",
cachefs_match,
cachefs_init,
- amfs_auto_fmount,
- cachefs_fmount,
- amfs_auto_fumount,
- cachefs_fumount,
- amfs_error_lookuppn,
+ cachefs_mount,
+ cachefs_umount,
+ amfs_error_lookup_child,
+ amfs_error_mount_child,
amfs_error_readdir,
0, /* cachefs_readlink */
- 0, /* post-mount actions */
- 0, /* post-umount actions */
- find_amfs_auto_srvr,
- FS_MKMNT | FS_NOTIMEOUT | FS_UBACKGROUND | FS_AMQINFO
+ 0, /* cachefs_mounted */
+ 0, /* cachefs_umounted */
+ amfs_generic_find_srvr,
+ 0, /* cachefs_get_wchan */
+ FS_MKMNT | FS_NOTIMEOUT | FS_UBACKGROUND | FS_AMQINFO, /* nfs_fs_flags */
+#ifdef HAVE_FS_AUTOFS
+ AUTOFS_CACHEFS_FS_FLAGS,
+#endif /* HAVE_FS_AUTOFS */
};
@@ -94,9 +96,7 @@ cachefs_match(am_opts *fo)
return NULL;
}
-#ifdef DEBUG
dlog("CACHEFS: using cache directory \"%s\"", fo->opt_cachedir);
-#endif /* DEBUG */
/* determine magic cookie to put in mtab */
return strdup(fo->opt_cachedir);
@@ -113,7 +113,7 @@ cachefs_init(mntfs *mf)
/*
* Save cache directory name
*/
- if (mf->mf_refc == 1) {
+ if (!mf->mf_private) {
mf->mf_private = (voidp) strdup(mf->mf_fo->opt_cachedir);
mf->mf_prfree = (void (*)(voidp)) free;
}
@@ -128,7 +128,8 @@ cachefs_init(mntfs *mf)
* cachedir is the cache directory ($cachedir)
*/
static int
-mount_cachefs(char *mntpt, char *backdir, char *cachedir, char *opts)
+mount_cachefs(char *mntdir, char *backdir, char *cachedir,
+ char *opts, int on_autofs)
{
cachefs_args_t ca;
mntent_t mnt;
@@ -142,12 +143,16 @@ mount_cachefs(char *mntpt, char *backdir, char *cachedir, char *opts)
* Fill in the mount structure
*/
memset((voidp) &mnt, 0, sizeof(mnt));
- mnt.mnt_dir = mntpt;
+ mnt.mnt_dir = mntdir;
mnt.mnt_fsname = backdir;
mnt.mnt_type = MNTTAB_TYPE_CACHEFS;
mnt.mnt_opts = opts;
flags = compute_mount_flags(&mnt);
+#ifdef HAVE_FS_AUTOFS
+ if (on_autofs)
+ flags |= autofs_compute_mount_flags(&mnt);
+#endif /* HAVE_FS_AUTOFS */
/* Fill in cachefs mount arguments */
@@ -170,8 +175,13 @@ mount_cachefs(char *mntpt, char *backdir, char *cachedir, char *opts)
/* CFS fscdir name */
memset(ca.cfs_cacheid, 0, sizeof(ca.cfs_cacheid));
- /* append cacheid and mountpoint */
- sprintf(ca.cfs_cacheid, "%s:%s", ca.cfs_fsid, mntpt);
+ /*
+ * Append cacheid and mountpoint.
+ * sizeof(cfs_cacheid) should be C_MAX_MOUNT_FSCDIRNAME as per
+ * <sys/fs/cachefs_fs.h> (checked on Solaris 8).
+ */
+ xsnprintf(ca.cfs_cacheid, sizeof(ca.cfs_cacheid),
+ "%s:%s", ca.cfs_fsid, mntdir);
/* convert '/' to '_' (Solaris does that...) */
cp = ca.cfs_cacheid;
while ((cp = strpbrk(cp, "/")) != NULL)
@@ -192,19 +202,21 @@ mount_cachefs(char *mntpt, char *backdir, char *cachedir, char *opts)
/*
* Call generic mount routine
*/
- return mount_fs(&mnt, flags, (caddr_t) &ca, 0, type, 0, NULL, mnttab_file_name);
+ return mount_fs(&mnt, flags, (caddr_t) &ca, 0, type, 0, NULL, mnttab_file_name, on_autofs);
}
static int
-cachefs_fmount(mntfs *mf)
+cachefs_mount(am_node *am, mntfs *mf)
{
+ int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
int error;
error = mount_cachefs(mf->mf_mount,
mf->mf_fo->opt_rfs,
mf->mf_fo->opt_cachedir,
- mf->mf_mopts);
+ mf->mf_mopts,
+ on_autofs);
if (error) {
errno = error;
/* according to Solaris, if errno==ESRCH, "options to not match" */
@@ -220,11 +232,12 @@ cachefs_fmount(mntfs *mf)
static int
-cachefs_fumount(mntfs *mf)
+cachefs_umount(am_node *am, mntfs *mf)
{
+ int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
int error;
- error = UMOUNT_FS(mf->mf_mount, mnttab_file_name);
+ error = UMOUNT_FS(mf->mf_mount, mnttab_file_name, unmount_flags);
/*
* In the case of cachefs, we must fsck the cache directory. Otherwise,
@@ -239,7 +252,7 @@ cachefs_fumount(mntfs *mf)
cachedir = (char *) mf->mf_private;
plog(XLOG_INFO, "running fsck on cache directory \"%s\"", cachedir);
- sprintf(cmd, "fsck -F cachefs %s", cachedir);
+ xsnprintf(cmd, sizeof(cmd), "fsck -F cachefs %s", cachedir);
system(cmd);
}
diff --git a/contrib/amd/amd/ops_cdfs.c b/contrib/amd/amd/ops_cdfs.c
index 6487e6d..40355ac 100644
--- a/contrib/amd/amd/ops_cdfs.c
+++ b/contrib/amd/amd/ops_cdfs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: ops_cdfs.c,v 1.4.2.5 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/ops_cdfs.c
*
*/
@@ -54,8 +53,8 @@
/* forward declarations */
static char *cdfs_match(am_opts *fo);
-static int cdfs_fmount(mntfs *mf);
-static int cdfs_fumount(mntfs *mf);
+static int cdfs_mount(am_node *am, mntfs *mf);
+static int cdfs_umount(am_node *am, mntfs *mf);
/*
* Ops structure
@@ -65,17 +64,20 @@ am_ops cdfs_ops =
"cdfs",
cdfs_match,
0, /* cdfs_init */
- amfs_auto_fmount,
- cdfs_fmount,
- amfs_auto_fumount,
- cdfs_fumount,
- amfs_error_lookuppn,
+ cdfs_mount,
+ cdfs_umount,
+ amfs_error_lookup_child,
+ amfs_error_mount_child,
amfs_error_readdir,
0, /* cdfs_readlink */
0, /* cdfs_mounted */
0, /* cdfs_umounted */
- find_amfs_auto_srvr,
- FS_MKMNT | FS_UBACKGROUND | FS_AMQINFO
+ amfs_generic_find_srvr,
+ 0, /* cdfs_get_wchan */
+ FS_MKMNT | FS_UBACKGROUND | FS_AMQINFO, /* nfs_fs_flags */
+#ifdef HAVE_FS_AUTOFS
+ AUTOFS_CDFS_FS_FLAGS,
+#endif /* HAVE_FS_AUTOFS */
};
@@ -89,10 +91,8 @@ cdfs_match(am_opts *fo)
plog(XLOG_USER, "cdfs: no source device specified");
return 0;
}
-#ifdef DEBUG
dlog("CDFS: mounting device \"%s\" on \"%s\"",
fo->opt_dev, fo->opt_fs);
-#endif /* DEBUG */
/*
* Determine magic cookie to put in mtab
@@ -102,11 +102,11 @@ cdfs_match(am_opts *fo)
static int
-mount_cdfs(char *dir, char *fs_name, char *opts)
+mount_cdfs(char *mntdir, char *fs_name, char *opts, int on_autofs)
{
cdfs_args_t cdfs_args;
mntent_t mnt;
- int genflags, cdfs_flags;
+ int genflags, cdfs_flags, retval;
/*
* Figure out the name of the file system type.
@@ -120,13 +120,13 @@ mount_cdfs(char *dir, char *fs_name, char *opts)
* Fill in the mount structure
*/
memset((voidp) &mnt, 0, sizeof(mnt));
- mnt.mnt_dir = dir;
+ mnt.mnt_dir = mntdir;
mnt.mnt_fsname = fs_name;
mnt.mnt_type = MNTTAB_TYPE_CDFS;
mnt.mnt_opts = opts;
#if defined(MNT2_CDFS_OPT_DEFPERM) && defined(MNTTAB_OPT_DEFPERM)
- if (hasmntopt(&mnt, MNTTAB_OPT_DEFPERM))
+ if (amu_hasmntopt(&mnt, MNTTAB_OPT_DEFPERM))
# ifdef MNT2_CDFS_OPT_DEFPERM
cdfs_flags |= MNT2_CDFS_OPT_DEFPERM;
# else /* not MNT2_CDFS_OPT_DEFPERM */
@@ -135,34 +135,38 @@ mount_cdfs(char *dir, char *fs_name, char *opts)
#endif /* defined(MNT2_CDFS_OPT_DEFPERM) && defined(MNTTAB_OPT_DEFPERM) */
#if defined(MNT2_CDFS_OPT_NODEFPERM) && defined(MNTTAB_OPT_NODEFPERM)
- if (hasmntopt(&mnt, MNTTAB_OPT_NODEFPERM))
+ if (amu_hasmntopt(&mnt, MNTTAB_OPT_NODEFPERM))
cdfs_flags |= MNT2_CDFS_OPT_NODEFPERM;
#endif /* MNTTAB_OPT_NODEFPERM */
#if defined(MNT2_CDFS_OPT_NOVERSION) && defined(MNTTAB_OPT_NOVERSION)
- if (hasmntopt(&mnt, MNTTAB_OPT_NOVERSION))
+ if (amu_hasmntopt(&mnt, MNTTAB_OPT_NOVERSION))
cdfs_flags |= MNT2_CDFS_OPT_NOVERSION;
#endif /* defined(MNT2_CDFS_OPT_NOVERSION) && defined(MNTTAB_OPT_NOVERSION) */
#if defined(MNT2_CDFS_OPT_RRIP) && defined(MNTTAB_OPT_RRIP)
- if (hasmntopt(&mnt, MNTTAB_OPT_RRIP))
+ if (amu_hasmntopt(&mnt, MNTTAB_OPT_RRIP))
cdfs_flags |= MNT2_CDFS_OPT_RRIP;
#endif /* defined(MNT2_CDFS_OPT_RRIP) && defined(MNTTAB_OPT_RRIP) */
#if defined(MNT2_CDFS_OPT_NORRIP) && defined(MNTTAB_OPT_NORRIP)
- if (hasmntopt(&mnt, MNTTAB_OPT_NORRIP))
+ if (amu_hasmntopt(&mnt, MNTTAB_OPT_NORRIP))
cdfs_flags |= MNT2_CDFS_OPT_NORRIP;
#endif /* defined(MNT2_CDFS_OPT_NORRIP) && defined(MNTTAB_OPT_NORRIP) */
#if defined(MNT2_CDFS_OPT_GENS) && defined(MNTTAB_OPT_GENS)
- if (hasmntopt(&mnt, MNTTAB_OPT_GENS))
+ if (amu_hasmntopt(&mnt, MNTTAB_OPT_GENS))
cdfs_flags |= MNT2_CDFS_OPT_GENS;
#endif /* defined(MNT2_CDFS_OPT_GENS) && defined(MNTTAB_OPT_GENS) */
#if defined(MNT2_CDFS_OPT_EXTATT) && defined(MNTTAB_OPT_EXTATT)
- if (hasmntopt(&mnt, MNTTAB_OPT_EXTATT))
+ if (amu_hasmntopt(&mnt, MNTTAB_OPT_EXTATT))
cdfs_flags |= MNT2_CDFS_OPT_EXTATT;
#endif /* defined(MNT2_CDFS_OPT_EXTATT) && defined(MNTTAB_OPT_EXTATT) */
genflags = compute_mount_flags(&mnt);
+#ifdef HAVE_FS_AUTOFS
+ if (on_autofs)
+ genflags |= autofs_compute_mount_flags(&mnt);
+#endif /* HAVE_FS_AUTOFS */
#ifdef HAVE_CDFS_ARGS_T_FLAGS
cdfs_args.flags = cdfs_flags;
@@ -176,10 +180,6 @@ mount_cdfs(char *dir, char *fs_name, char *opts)
cdfs_args.iso_pgthresh = hasmntval(&mnt, MNTTAB_OPT_PGTHRESH);
#endif /* HAVE_CDFS_ARGS_T_ISO_PGTHRESH */
-#ifdef HAVE_CDFS_ARGS_T_FSPEC
- cdfs_args.fspec = fs_name;
-#endif /* HAVE_CDFS_ARGS_T_FSPEC */
-
#ifdef HAVE_CDFS_ARGS_T_NORRIP
/* XXX: need to provide norrip mount opt */
cdfs_args.norrip = 0; /* use Rock-Ridge Protocol extensions */
@@ -190,19 +190,26 @@ mount_cdfs(char *dir, char *fs_name, char *opts)
cdfs_args.ssector = 0; /* use 1st session on disk */
#endif /* HAVE_CDFS_ARGS_T_SSECTOR */
+#ifdef HAVE_CDFS_ARGS_T_FSPEC
+ cdfs_args.fspec = fs_name;
+#endif /* HAVE_CDFS_ARGS_T_FSPEC */
+
/*
* Call generic mount routine
*/
- return mount_fs(&mnt, genflags, (caddr_t) &cdfs_args, 0, type, 0, NULL, mnttab_file_name);
+ retval = mount_fs(&mnt, genflags, (caddr_t) &cdfs_args, 0, type, 0, NULL, mnttab_file_name, on_autofs);
+
+ return retval;
}
static int
-cdfs_fmount(mntfs *mf)
+cdfs_mount(am_node *am, mntfs *mf)
{
+ int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
int error;
- error = mount_cdfs(mf->mf_mount, mf->mf_info, mf->mf_mopts);
+ error = mount_cdfs(mf->mf_mount, mf->mf_info, mf->mf_mopts, on_autofs);
if (error) {
errno = error;
plog(XLOG_ERROR, "mount_cdfs: %m");
@@ -213,7 +220,9 @@ cdfs_fmount(mntfs *mf)
static int
-cdfs_fumount(mntfs *mf)
+cdfs_umount(am_node *am, mntfs *mf)
{
- return UMOUNT_FS(mf->mf_mount, mnttab_file_name);
+ int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
+
+ return UMOUNT_FS(mf->mf_mount, mnttab_file_name, unmount_flags);
}
diff --git a/contrib/amd/amd/ops_efs.c b/contrib/amd/amd/ops_efs.c
index 36f47ed..047fe1e 100644
--- a/contrib/amd/amd/ops_efs.c
+++ b/contrib/amd/amd/ops_efs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: ops_efs.c,v 1.3.2.5 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/ops_efs.c
*
*/
@@ -54,8 +53,8 @@
/* forward declarations */
static char *efs_match(am_opts *fo);
-static int efs_fmount(mntfs *mf);
-static int efs_fumount(mntfs *mf);
+static int efs_mount(am_node *am, mntfs *mf);
+static int efs_umount(am_node *am, mntfs *mf);
/*
* Ops structure
@@ -65,17 +64,20 @@ am_ops efs_ops =
"efs",
efs_match,
0, /* efs_init */
- amfs_auto_fmount,
- efs_fmount,
- amfs_auto_fumount,
- efs_fumount,
- amfs_error_lookuppn,
+ efs_mount,
+ efs_umount,
+ amfs_error_lookup_child,
+ amfs_error_mount_child,
amfs_error_readdir,
0, /* efs_readlink */
0, /* efs_mounted */
0, /* efs_umounted */
- find_amfs_auto_srvr,
- FS_MKMNT | FS_NOTIMEOUT | FS_UBACKGROUND | FS_AMQINFO
+ amfs_generic_find_srvr,
+ 0, /* efs_get_wchan */
+ FS_MKMNT | FS_NOTIMEOUT | FS_UBACKGROUND | FS_AMQINFO, /* nfs_fs_flags */
+#ifdef HAVE_FS_AUTOFS
+ AUTOFS_EFS_FS_FLAGS,
+#endif /* HAVE_FS_AUTOFS */
};
@@ -91,9 +93,7 @@ efs_match(am_opts *fo)
return 0;
}
-#ifdef DEBUG
dlog("EFS: mounting device \"%s\" on \"%s\"", fo->opt_dev, fo->opt_fs);
-#endif /* DEBUG */
/*
* Determine magic cookie to put in mtab
@@ -103,7 +103,7 @@ efs_match(am_opts *fo)
static int
-mount_efs(char *dir, char *fs_name, char *opts)
+mount_efs(char *mntdir, char *fs_name, char *opts, int on_autofs)
{
efs_args_t efs_args;
mntent_t mnt;
@@ -120,12 +120,16 @@ mount_efs(char *dir, char *fs_name, char *opts)
* Fill in the mount structure
*/
memset((voidp) &mnt, 0, sizeof(mnt));
- mnt.mnt_dir = dir;
+ mnt.mnt_dir = mntdir;
mnt.mnt_fsname = fs_name;
mnt.mnt_type = MNTTAB_TYPE_EFS;
mnt.mnt_opts = opts;
flags = compute_mount_flags(&mnt);
+#ifdef HAVE_FS_AUTOFS
+ if (on_autofs)
+ flags |= autofs_compute_mount_flags(&mnt);
+#endif /* HAVE_FS_AUTOFS */
#ifdef HAVE_EFS_ARGS_T_FLAGS
efs_args.flags = 0; /* XXX: fix this to correct flags */
@@ -137,16 +141,17 @@ mount_efs(char *dir, char *fs_name, char *opts)
/*
* Call generic mount routine
*/
- return mount_fs(&mnt, flags, (caddr_t) &efs_args, 0, type, 0, NULL, mnttab_file_name);
+ return mount_fs(&mnt, flags, (caddr_t) &efs_args, 0, type, 0, NULL, mnttab_file_name, on_autofs);
}
static int
-efs_fmount(mntfs *mf)
+efs_mount(am_node *am, mntfs *mf)
{
+ int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
int error;
- error = mount_efs(mf->mf_mount, mf->mf_info, mf->mf_mopts);
+ error = mount_efs(mf->mf_mount, mf->mf_info, mf->mf_mopts, on_autofs);
if (error) {
errno = error;
plog(XLOG_ERROR, "mount_efs: %m");
@@ -158,7 +163,10 @@ efs_fmount(mntfs *mf)
static int
-efs_fumount(mntfs *mf)
+efs_umount(am_node *am, mntfs *mf)
{
- return UMOUNT_FS(mf->mf_mount, mnttab_file_name);
+ int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
+
+ return UMOUNT_FS(mf->mf_mount, mnttab_file_name, unmount_flags);
}
+
diff --git a/contrib/amd/amd/ops_lofs.c b/contrib/amd/amd/ops_lofs.c
index 6d27d2c..26fdc9f 100644
--- a/contrib/amd/amd/ops_lofs.c
+++ b/contrib/amd/amd/ops_lofs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: ops_lofs.c,v 1.3.2.5 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/ops_lofs.c
*
*/
@@ -54,10 +53,8 @@
/* forward definitions */
static char *lofs_match(am_opts *fo);
-static int lofs_fmount(mntfs *mf);
-static int lofs_fumount(mntfs *mf);
-static int mount_lofs(char *dir, char *fs_name, char *opts);
-
+static int lofs_mount(am_node *am, mntfs *mf);
+static int lofs_umount(am_node *am, mntfs *mf);
/*
* Ops structure
@@ -67,17 +64,20 @@ am_ops lofs_ops =
"lofs",
lofs_match,
0, /* lofs_init */
- amfs_auto_fmount,
- lofs_fmount,
- amfs_auto_fumount,
- lofs_fumount,
- amfs_error_lookuppn,
+ lofs_mount,
+ lofs_umount,
+ amfs_error_lookup_child,
+ amfs_error_mount_child,
amfs_error_readdir,
0, /* lofs_readlink */
0, /* lofs_mounted */
0, /* lofs_umounted */
- find_amfs_auto_srvr,
- FS_MKMNT | FS_NOTIMEOUT | FS_UBACKGROUND | FS_AMQINFO
+ amfs_generic_find_srvr,
+ 0, /* lofs_get_wchan */
+ FS_MKMNT | FS_NOTIMEOUT | FS_UBACKGROUND | FS_AMQINFO, /* nfs_fs_flags */
+#ifdef HAVE_FS_AUTOFS
+ AUTOFS_LOFS_FS_FLAGS,
+#endif /* HAVE_FS_AUTOFS */
};
@@ -91,10 +91,8 @@ lofs_match(am_opts *fo)
plog(XLOG_USER, "lofs: no source filesystem specified");
return 0;
}
-#ifdef DEBUG
dlog("LOFS: mounting fs \"%s\" on \"%s\"",
fo->opt_rfs, fo->opt_fs);
-#endif /* DEBUG */
/*
* Determine magic cookie to put in mtab
@@ -103,8 +101,8 @@ lofs_match(am_opts *fo)
}
-static int
-mount_lofs(char *dir, char *fs_name, char *opts)
+int
+mount_lofs(char *mntdir, char *fs_name, char *opts, int on_autofs)
{
mntent_t mnt;
int flags;
@@ -118,26 +116,31 @@ mount_lofs(char *dir, char *fs_name, char *opts)
* Fill in the mount structure
*/
memset((voidp) &mnt, 0, sizeof(mnt));
- mnt.mnt_dir = dir;
+ mnt.mnt_dir = mntdir;
mnt.mnt_fsname = fs_name;
mnt.mnt_type = MNTTAB_TYPE_LOFS;
mnt.mnt_opts = opts;
flags = compute_mount_flags(&mnt);
+#ifdef HAVE_FS_AUTOFS
+ if (on_autofs)
+ flags |= autofs_compute_mount_flags(&mnt);
+#endif /* HAVE_FS_AUTOFS */
/*
* Call generic mount routine
*/
- return mount_fs(&mnt, flags, NULL, 0, type, 0, NULL, mnttab_file_name);
+ return mount_fs(&mnt, flags, NULL, 0, type, 0, NULL, mnttab_file_name, on_autofs);
}
static int
-lofs_fmount(mntfs *mf)
+lofs_mount(am_node *am, mntfs *mf)
{
+ int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
int error;
- error = mount_lofs(mf->mf_mount, mf->mf_info, mf->mf_mopts);
+ error = mount_lofs(mf->mf_mount, mf->mf_info, mf->mf_mopts, on_autofs);
if (error) {
errno = error;
plog(XLOG_ERROR, "mount_lofs: %m");
@@ -148,7 +151,9 @@ lofs_fmount(mntfs *mf)
static int
-lofs_fumount(mntfs *mf)
+lofs_umount(am_node *am, mntfs *mf)
{
- return UMOUNT_FS(mf->mf_mount, mnttab_file_name);
+ int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
+
+ return UMOUNT_FS(mf->mf_mount, mnttab_file_name, unmount_flags);
}
diff --git a/contrib/amd/amd/ops_mfs.c b/contrib/amd/amd/ops_mfs.c
index 67d6e98..ccaa49c 100644
--- a/contrib/amd/amd/ops_mfs.c
+++ b/contrib/amd/amd/ops_mfs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: ops_mfs.c,v 1.3.2.4 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/ops_mfs.c
*
*/
diff --git a/contrib/amd/amd/ops_nfs.c b/contrib/amd/amd/ops_nfs.c
index 5f6a474..a6a8585 100644
--- a/contrib/amd/amd/ops_nfs.c
+++ b/contrib/amd/amd/ops_nfs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: ops_nfs.c,v 1.6.2.6 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/ops_nfs.c
*
*/
@@ -64,7 +63,7 @@
*/
#define FH_TTL (5 * 60) /* five minutes */
#define FH_TTL_ERROR (30) /* 30 seconds */
-#define FHID_ALLOC(struct) (++fh_id)
+#define FHID_ALLOC() (++fh_id)
/*
* The NFS layer maintains a cache of file handles.
@@ -92,19 +91,26 @@
typedef struct fh_cache fh_cache;
struct fh_cache {
qelem fh_q; /* List header */
- voidp fh_wchan; /* Wait channel */
+ wchan_t fh_wchan; /* Wait channel */
int fh_error; /* Valid data? */
int fh_id; /* Unique id */
int fh_cid; /* Callout id */
u_long fh_nfs_version; /* highest NFS version on host */
am_nfs_handle_t fh_nfs_handle; /* Handle on filesystem */
+ int fh_status; /* Status of last rpc */
struct sockaddr_in fh_sin; /* Address of mountd */
fserver *fh_fs; /* Server holding filesystem */
char *fh_path; /* Filesystem on host */
};
/* forward definitions */
-static int call_mountd(fh_cache *fp, u_long proc, fwd_fun f, voidp wchan);
+static int nfs_init(mntfs *mf);
+static char *nfs_match(am_opts *fo);
+static int nfs_mount(am_node *am, mntfs *mf);
+static int nfs_umount(am_node *am, mntfs *mf);
+static void nfs_umounted(mntfs *mf);
+static int call_mountd(fh_cache *fp, u_long proc, fwd_fun f, wchan_t wchan);
+static int webnfs_lookup(fh_cache *fp, fwd_fun f, wchan_t wchan);
static int fh_id = 0;
/* globals */
@@ -119,25 +125,28 @@ am_ops nfs_ops =
"nfs",
nfs_match,
nfs_init,
- amfs_auto_fmount,
- nfs_fmount,
- amfs_auto_fumount,
- nfs_fumount,
- amfs_error_lookuppn,
+ nfs_mount,
+ nfs_umount,
+ amfs_error_lookup_child,
+ amfs_error_mount_child,
amfs_error_readdir,
0, /* nfs_readlink */
0, /* nfs_mounted */
nfs_umounted,
find_nfs_srvr,
- FS_MKMNT | FS_BACKGROUND | FS_AMQINFO
+ 0, /* nfs_get_wchan */
+ FS_MKMNT | FS_BACKGROUND | FS_AMQINFO, /* nfs_fs_flags */
+#ifdef HAVE_FS_AUTOFS
+ AUTOFS_NFS_FS_FLAGS,
+#endif /* HAVE_FS_AUTOFS */
};
static fh_cache *
-find_nfs_fhandle_cache(voidp idv, int done)
+find_nfs_fhandle_cache(opaque_t arg, int done)
{
fh_cache *fp, *fp2 = 0;
- int id = (long) idv; /* for 64-bit archs */
+ int id = (long) arg; /* for 64-bit archs */
ITER(fp, fh_cache, &fh_head) {
if (fp->fh_id == id) {
@@ -146,13 +155,11 @@ find_nfs_fhandle_cache(voidp idv, int done)
}
}
-#ifdef DEBUG
if (fp2) {
dlog("fh cache gives fp %#lx, fs %s", (unsigned long) fp2, fp2->fh_path);
} else {
dlog("fh cache search failed");
}
-#endif /* DEBUG */
if (fp2 && !done) {
fp2->fh_error = ETIMEDOUT;
@@ -164,14 +171,18 @@ find_nfs_fhandle_cache(voidp idv, int done)
/*
- * Called when a filehandle appears
+ * Called when a filehandle appears via the mount protocol
*/
static void
-got_nfs_fh(voidp pkt, int len, struct sockaddr_in *sa, struct sockaddr_in *ia, voidp idv, int done)
+got_nfs_fh_mount(voidp pkt, int len, struct sockaddr_in *sa, struct sockaddr_in *ia, opaque_t arg, int done)
{
fh_cache *fp;
+ struct fhstatus res;
+#ifdef HAVE_FS_NFS3
+ struct am_mountres3 res3;
+#endif /* HAVE_FS_NFS3 */
- fp = find_nfs_fhandle_cache(idv, done);
+ fp = find_nfs_fhandle_cache(arg, done);
if (!fp)
return;
@@ -180,28 +191,109 @@ got_nfs_fh(voidp pkt, int len, struct sockaddr_in *sa, struct sockaddr_in *ia, v
* NFS protocol version.
*/
#ifdef HAVE_FS_NFS3
- if (fp->fh_nfs_version == NFS_VERSION3)
- fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &fp->fh_nfs_handle.v3,
- (XDRPROC_T_TYPE) xdr_mountres3);
- else
+ if (fp->fh_nfs_version == NFS_VERSION3) {
+ memset(&res3, 0, sizeof(res3));
+ fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &res3,
+ (XDRPROC_T_TYPE) xdr_am_mountres3);
+ fp->fh_status = unx_error(res3.fhs_status);
+ memset(&fp->fh_nfs_handle.v3, 0, sizeof(am_nfs_fh3));
+ fp->fh_nfs_handle.v3.am_fh3_length = res3.mountres3_u.mountinfo.fhandle.fhandle3_len;
+ memmove(fp->fh_nfs_handle.v3.am_fh3_data,
+ res3.mountres3_u.mountinfo.fhandle.fhandle3_val,
+ fp->fh_nfs_handle.v3.am_fh3_length);
+ } else {
#endif /* HAVE_FS_NFS3 */
- fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &fp->fh_nfs_handle.v2,
+ memset(&res, 0, sizeof(res));
+ fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &res,
(XDRPROC_T_TYPE) xdr_fhstatus);
+ fp->fh_status = unx_error(res.fhs_status);
+ memmove(&fp->fh_nfs_handle.v2, &res.fhs_fh, NFS_FHSIZE);
+#ifdef HAVE_FS_NFS3
+ }
+#endif /* HAVE_FS_NFS3 */
if (!fp->fh_error) {
-#ifdef DEBUG
dlog("got filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path);
-#endif /* DEBUG */
+ } else {
+ plog(XLOG_USER, "filehandle denied for %s:%s", fp->fh_fs->fs_host, fp->fh_path);
+ /*
+ * Force the error to be EACCES. It's debatable whether it should be
+ * ENOENT instead, but the server really doesn't give us any clues, and
+ * EACCES is more in line with the "filehandle denied" message.
+ */
+ fp->fh_error = EACCES;
+ }
+
+ /*
+ * Wakeup anything sleeping on this filehandle
+ */
+ if (fp->fh_wchan) {
+ dlog("Calling wakeup on %#lx", (unsigned long) fp->fh_wchan);
+ wakeup(fp->fh_wchan);
+ }
+}
+
+/*
+ * Called when a filehandle appears via WebNFS
+ */
+static void
+got_nfs_fh_webnfs(voidp pkt, int len, struct sockaddr_in *sa, struct sockaddr_in *ia, opaque_t arg, int done)
+{
+ fh_cache *fp;
+ nfsdiropres res;
+#ifdef HAVE_FS_NFS3
+ am_LOOKUP3res res3;
+#endif /* HAVE_FS_NFS3 */
+
+ fp = find_nfs_fhandle_cache(arg, done);
+ if (!fp)
+ return;
+
+ /*
+ * retrieve the correct RPC reply for the file handle, based on the
+ * NFS protocol version.
+ */
+#ifdef HAVE_FS_NFS3
+ if (fp->fh_nfs_version == NFS_VERSION3) {
+ memset(&res3, 0, sizeof(res3));
+ fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &res3,
+ (XDRPROC_T_TYPE) xdr_am_LOOKUP3res);
+ fp->fh_status = unx_error(res3.status);
+ memset(&fp->fh_nfs_handle.v3, 0, sizeof(am_nfs_fh3));
+ fp->fh_nfs_handle.v3.am_fh3_length = res3.res_u.ok.object.am_fh3_length;
+ memmove(fp->fh_nfs_handle.v3.am_fh3_data,
+ res3.res_u.ok.object.am_fh3_data,
+ fp->fh_nfs_handle.v3.am_fh3_length);
+ } else {
+#endif /* HAVE_FS_NFS3 */
+ memset(&res, 0, sizeof(res));
+ fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &res,
+ (XDRPROC_T_TYPE) xdr_diropres);
+ fp->fh_status = unx_error(res.dr_status);
+ memmove(&fp->fh_nfs_handle.v2, &res.dr_u.dr_drok_u.drok_fhandle, NFS_FHSIZE);
+#ifdef HAVE_FS_NFS3
+ }
+#endif /* HAVE_FS_NFS3 */
+
+ if (!fp->fh_error) {
+ dlog("got filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path);
+ } else {
+ plog(XLOG_USER, "filehandle denied for %s:%s", fp->fh_fs->fs_host, fp->fh_path);
/*
- * Wakeup anything sleeping on this filehandle
+ * Force the error to be EACCES. It's debatable whether it should be
+ * ENOENT instead, but the server really doesn't give us any clues, and
+ * EACCES is more in line with the "filehandle denied" message.
*/
- if (fp->fh_wchan) {
-#ifdef DEBUG
- dlog("Calling wakeup on %#lx", (unsigned long) fp->fh_wchan);
-#endif /* DEBUG */
- wakeup(fp->fh_wchan);
- }
+ fp->fh_error = EACCES;
+ }
+
+ /*
+ * Wakeup anything sleeping on this filehandle
+ */
+ if (fp->fh_wchan) {
+ dlog("Calling wakeup on %#lx", (unsigned long) fp->fh_wchan);
+ wakeup(fp->fh_wchan);
}
}
@@ -212,8 +304,12 @@ flush_nfs_fhandle_cache(fserver *fs)
fh_cache *fp;
ITER(fp, fh_cache, &fh_head) {
- if (fp->fh_fs == fs || fs == 0) {
- fp->fh_sin.sin_port = (u_short) 0;
+ if (fp->fh_fs == fs || fs == NULL) {
+ /*
+ * Only invalidate port info for non-WebNFS servers
+ */
+ if (!(fp->fh_fs->fs_flags & FSF_WEBNFS))
+ fp->fh_sin.sin_port = (u_short) 0;
fp->fh_error = -1;
}
}
@@ -221,15 +317,13 @@ flush_nfs_fhandle_cache(fserver *fs)
static void
-discard_fh(voidp v)
+discard_fh(opaque_t arg)
{
- fh_cache *fp = v;
+ fh_cache *fp = (fh_cache *) arg;
rem_que(&fp->fh_q);
if (fp->fh_fs) {
-#ifdef DEBUG
dlog("Discarding filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path);
-#endif /* DEBUG */
free_srvr(fp->fh_fs);
}
if (fp->fh_path)
@@ -242,88 +336,92 @@ discard_fh(voidp v)
* Determine the file handle for a node
*/
static int
-prime_nfs_fhandle_cache(char *path, fserver *fs, am_nfs_handle_t *fhbuf, voidp wchan)
+prime_nfs_fhandle_cache(char *path, fserver *fs, am_nfs_handle_t *fhbuf, mntfs *mf)
{
fh_cache *fp, *fp_save = 0;
int error;
int reuse_id = FALSE;
-#ifdef DEBUG
dlog("Searching cache for %s:%s", fs->fs_host, path);
-#endif /* DEBUG */
/*
* First search the cache
*/
ITER(fp, fh_cache, &fh_head) {
- if (fs == fp->fh_fs && STREQ(path, fp->fh_path)) {
- switch (fp->fh_error) {
- case 0:
- plog(XLOG_INFO, "prime_nfs_fhandle_cache: NFS version %d", (int) fp->fh_nfs_version);
-#ifdef HAVE_FS_NFS3
- if (fp->fh_nfs_version == NFS_VERSION3)
- error = fp->fh_error = unx_error(fp->fh_nfs_handle.v3.fhs_status);
- else
-#endif /* HAVE_FS_NFS3 */
- error = fp->fh_error = unx_error(fp->fh_nfs_handle.v2.fhs_status);
- if (error == 0) {
- if (fhbuf) {
+ if (fs != fp->fh_fs || !STREQ(path, fp->fh_path))
+ continue; /* skip to next ITER item */
+ /* else we got a match */
+ switch (fp->fh_error) {
+ case 0:
+ plog(XLOG_INFO, "prime_nfs_fhandle_cache: NFS version %d", (int) fp->fh_nfs_version);
+
+ error = fp->fh_error = fp->fh_status;
+
+ if (error == 0) {
+ if (mf->mf_flags & MFF_NFS_SCALEDOWN) {
+ fp_save = fp;
+ /* XXX: why reuse the ID? */
+ reuse_id = TRUE;
+ break;
+ }
+
+ if (fhbuf) {
#ifdef HAVE_FS_NFS3
- if (fp->fh_nfs_version == NFS_VERSION3)
- memmove((voidp) &(fhbuf->v3), (voidp) &(fp->fh_nfs_handle.v3),
- sizeof(fp->fh_nfs_handle.v3));
- else
+ if (fp->fh_nfs_version == NFS_VERSION3) {
+ memmove((voidp) &(fhbuf->v3), (voidp) &(fp->fh_nfs_handle.v3),
+ sizeof(fp->fh_nfs_handle.v3));
+ } else
#endif /* HAVE_FS_NFS3 */
+ {
memmove((voidp) &(fhbuf->v2), (voidp) &(fp->fh_nfs_handle.v2),
sizeof(fp->fh_nfs_handle.v2));
- }
- if (fp->fh_cid)
- untimeout(fp->fh_cid);
- fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp);
- } else if (error == EACCES) {
- /*
- * Now decode the file handle return code.
- */
- plog(XLOG_INFO, "Filehandle denied for \"%s:%s\"",
- fs->fs_host, path);
- } else {
- errno = error; /* XXX */
- plog(XLOG_INFO, "Filehandle error for \"%s:%s\": %m",
- fs->fs_host, path);
+ }
}
-
+ if (fp->fh_cid)
+ untimeout(fp->fh_cid);
+ fp->fh_cid = timeout(FH_TTL, discard_fh, (opaque_t) fp);
+ } else if (error == EACCES) {
/*
- * The error was returned from the remote mount daemon.
- * Policy: this error will be cached for now...
+ * Now decode the file handle return code.
*/
- return error;
+ plog(XLOG_INFO, "Filehandle denied for \"%s:%s\"",
+ fs->fs_host, path);
+ } else {
+ errno = error; /* XXX */
+ plog(XLOG_INFO, "Filehandle error for \"%s:%s\": %m",
+ fs->fs_host, path);
+ }
- case -1:
- /*
- * Still thinking about it, but we can re-use.
- */
- fp_save = fp;
- reuse_id = TRUE;
- break;
+ /*
+ * The error was returned from the remote mount daemon.
+ * Policy: this error will be cached for now...
+ */
+ return error;
- default:
- /*
- * Return the error.
- * Policy: make sure we recompute if required again
- * in case this was caused by a network failure.
- * This can thrash mountd's though... If you find
- * your mountd going slowly then:
- * 1. Add a fork() loop to main.
- * 2. Remove the call to innetgr() and don't use
- * netgroups, especially if you don't use YP.
- */
- error = fp->fh_error;
- fp->fh_error = -1;
- return error;
- }
+ case -1:
+ /*
+ * Still thinking about it, but we can re-use.
+ */
+ fp_save = fp;
+ reuse_id = TRUE;
break;
- }
- }
+
+ default:
+ /*
+ * Return the error.
+ * Policy: make sure we recompute if required again
+ * in case this was caused by a network failure.
+ * This can thrash mountd's though... If you find
+ * your mountd going slowly then:
+ * 1. Add a fork() loop to main.
+ * 2. Remove the call to innetgr() and don't use
+ * netgroups, especially if you don't use YP.
+ */
+ error = fp->fh_error;
+ fp->fh_error = -1;
+ return error;
+ } /* end of switch statement */
+ } /* end of ITER loop */
/*
* Not in cache
@@ -342,13 +440,13 @@ prime_nfs_fhandle_cache(char *path, fserver *fs, am_nfs_handle_t *fhbuf, voidp w
ins_que(&fp->fh_q, &fh_head);
}
if (!reuse_id)
- fp->fh_id = FHID_ALLOC(struct );
- fp->fh_wchan = wchan;
+ fp->fh_id = FHID_ALLOC();
+ fp->fh_wchan = get_mntfs_wchan(mf);
fp->fh_error = -1;
- fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp);
+ fp->fh_cid = timeout(FH_TTL, discard_fh, (opaque_t) fp);
/*
- * if fs->fs_ip is null, remote server is probably down.
+ * If fs->fs_ip is null, remote server is probably down.
*/
if (!fs->fs_ip) {
/* Mark the fileserver down and invalid again */
@@ -359,18 +457,25 @@ prime_nfs_fhandle_cache(char *path, fserver *fs, am_nfs_handle_t *fhbuf, voidp w
}
/*
- * If the address has changed then don't try to re-use the
- * port information
+ * Either fp has been freshly allocated or the address has changed.
+ * Initialize address and nfs version. Don't try to re-use the port
+ * information unless using WebNFS where the port is fixed either by
+ * the spec or the "port" mount option.
*/
if (fp->fh_sin.sin_addr.s_addr != fs->fs_ip->sin_addr.s_addr) {
fp->fh_sin = *fs->fs_ip;
- fp->fh_sin.sin_port = 0;
+ if (!(mf->mf_flags & MFF_WEBNFS))
+ fp->fh_sin.sin_port = 0;
fp->fh_nfs_version = fs->fs_version;
}
+
fp->fh_fs = dup_srvr(fs);
fp->fh_path = strdup(path);
- error = call_mountd(fp, MOUNTPROC_MNT, got_nfs_fh, wchan);
+ if (mf->mf_flags & MFF_WEBNFS)
+ error = webnfs_lookup(fp, got_nfs_fh_webnfs, get_mntfs_wchan(mf));
+ else
+ error = call_mountd(fp, MOUNTPROC_MNT, got_nfs_fh_mount, get_mntfs_wchan(mf));
if (error) {
/*
* Local error - cache for a short period
@@ -378,7 +483,7 @@ prime_nfs_fhandle_cache(char *path, fserver *fs, am_nfs_handle_t *fhbuf, voidp w
*/
untimeout(fp->fh_cid);
fp->fh_cid = timeout(error < 0 ? 2 * ALLOWED_MOUNT_TIME : FH_TTL_ERROR,
- discard_fh, (voidp) fp);
+ discard_fh, (opaque_t) fp);
fp->fh_error = error;
} else {
error = fp->fh_error;
@@ -419,11 +524,11 @@ make_nfs_auth(void)
static int
-call_mountd(fh_cache *fp, u_long proc, fwd_fun f, voidp wchan)
+call_mountd(fh_cache *fp, u_long proc, fwd_fun fun, wchan_t wchan)
{
struct rpc_msg mnt_msg;
int len;
- char iobuf[8192];
+ char iobuf[UDPMSGSIZE];
int error;
u_long mnt_version;
@@ -434,17 +539,17 @@ call_mountd(fh_cache *fp, u_long proc, fwd_fun f, voidp wchan)
}
if (fp->fh_sin.sin_port == 0) {
- u_short port;
- error = nfs_srvr_port(fp->fh_fs, &port, wchan);
+ u_short mountd_port;
+ error = get_mountd_port(fp->fh_fs, &mountd_port, wchan);
if (error)
return error;
- fp->fh_sin.sin_port = port;
+ fp->fh_sin.sin_port = mountd_port;
}
/* find the right version of the mount protocol */
#ifdef HAVE_FS_NFS3
if (fp->fh_nfs_version == NFS_VERSION3)
- mnt_version = MOUNTVERS3;
+ mnt_version = AM_MOUNTVERS3;
else
#endif /* HAVE_FS_NFS3 */
mnt_version = MOUNTVERS;
@@ -462,40 +567,128 @@ call_mountd(fh_cache *fp, u_long proc, fwd_fun f, voidp wchan)
if (len > 0) {
error = fwd_packet(MK_RPC_XID(RPC_XID_MOUNTD, fp->fh_id),
- (voidp) iobuf,
+ iobuf,
len,
&fp->fh_sin,
&fp->fh_sin,
- (voidp) ((long) fp->fh_id), /* for 64-bit archs */
- f);
+ (opaque_t) ((long) fp->fh_id), /* cast to long needed for 64-bit archs */
+ fun);
} else {
error = -len;
}
-/*
- * It may be the case that we're sending to the wrong MOUNTD port. This
- * occurs if mountd is restarted on the server after the port has been
- * looked up and stored in the filehandle cache somewhere. The correct
- * solution, if we're going to cache port numbers is to catch the ICMP
- * port unreachable reply from the server and cause the portmap request
- * to be redone. The quick solution here is to invalidate the MOUNTD
- * port.
- */
+ /*
+ * It may be the case that we're sending to the wrong MOUNTD port. This
+ * occurs if mountd is restarted on the server after the port has been
+ * looked up and stored in the filehandle cache somewhere. The correct
+ * solution, if we're going to cache port numbers is to catch the ICMP
+ * port unreachable reply from the server and cause the portmap request
+ * to be redone. The quick solution here is to invalidate the MOUNTD
+ * port.
+ */
fp->fh_sin.sin_port = 0;
return error;
}
+static int
+webnfs_lookup(fh_cache *fp, fwd_fun fun, wchan_t wchan)
+{
+ struct rpc_msg wnfs_msg;
+ int len;
+ char iobuf[UDPMSGSIZE];
+ int error;
+ u_long proc;
+ XDRPROC_T_TYPE xdr_fn;
+ voidp argp;
+ nfsdiropargs args;
+#ifdef HAVE_FS_NFS3
+ am_LOOKUP3args args3;
+#endif
+ char *wnfs_path;
+ size_t l;
+
+ if (!nfs_auth) {
+ error = make_nfs_auth();
+ if (error)
+ return error;
+ }
+
+ if (fp->fh_sin.sin_port == 0) {
+ /* FIXME: wrong, don't discard sin_port in the first place for WebNFS. */
+ plog(XLOG_WARNING, "webnfs_lookup: port == 0 for nfs on %s, fixed",
+ fp->fh_fs->fs_host);
+ fp->fh_sin.sin_port = htons(NFS_PORT);
+ }
+
+ /*
+ * Use native path like the rest of amd (cf. RFC 2054, 6.1).
+ */
+ l = strlen(fp->fh_path) + 2;
+ wnfs_path = (char *) xmalloc(l);
+ wnfs_path[0] = 0x80;
+ xstrlcpy(wnfs_path + 1, fp->fh_path, l - 1);
+
+ /* find the right program and lookup procedure */
+#ifdef HAVE_FS_NFS3
+ if (fp->fh_nfs_version == NFS_VERSION3) {
+ proc = AM_NFSPROC3_LOOKUP;
+ xdr_fn = (XDRPROC_T_TYPE) xdr_am_LOOKUP3args;
+ argp = &args3;
+ /* WebNFS public file handle */
+ args3.what.dir.am_fh3_length = 0;
+ args3.what.name = wnfs_path;
+ } else {
+#endif /* HAVE_FS_NFS3 */
+ proc = NFSPROC_LOOKUP;
+ xdr_fn = (XDRPROC_T_TYPE) xdr_diropargs;
+ argp = &args;
+ /* WebNFS public file handle */
+ memset(&args.da_fhandle, 0, NFS_FHSIZE);
+ args.da_name = wnfs_path;
+#ifdef HAVE_FS_NFS3
+ }
+#endif /* HAVE_FS_NFS3 */
+
+ plog(XLOG_INFO, "webnfs_lookup: NFS version %d", (int) fp->fh_nfs_version);
+
+ rpc_msg_init(&wnfs_msg, NFS_PROGRAM, fp->fh_nfs_version, proc);
+ len = make_rpc_packet(iobuf,
+ sizeof(iobuf),
+ proc,
+ &wnfs_msg,
+ argp,
+ (XDRPROC_T_TYPE) xdr_fn,
+ nfs_auth);
+
+ if (len > 0) {
+ error = fwd_packet(MK_RPC_XID(RPC_XID_WEBNFS, fp->fh_id),
+ iobuf,
+ len,
+ &fp->fh_sin,
+ &fp->fh_sin,
+ (opaque_t) ((long) fp->fh_id), /* cast to long needed for 64-bit archs */
+ fun);
+ } else {
+ error = -len;
+ }
+
+ XFREE(wnfs_path);
+ return error;
+}
+
+
/*
* NFS needs the local filesystem, remote filesystem
* remote hostname.
* Local filesystem defaults to remote and vice-versa.
*/
-char *
+static char *
nfs_match(am_opts *fo)
{
char *xmtab;
+ size_t l;
if (fo->opt_fs && !fo->opt_rfs)
fo->opt_rfs = fo->opt_fs;
@@ -511,12 +704,11 @@ nfs_match(am_opts *fo)
/*
* Determine magic cookie to put in mtab
*/
- xmtab = (char *) xmalloc(strlen(fo->opt_rhost) + strlen(fo->opt_rfs) + 2);
- sprintf(xmtab, "%s:%s", fo->opt_rhost, fo->opt_rfs);
-#ifdef DEBUG
+ l = strlen(fo->opt_rhost) + strlen(fo->opt_rfs) + 2;
+ xmtab = (char *) xmalloc(l);
+ xsnprintf(xmtab, l, "%s:%s", fo->opt_rhost, fo->opt_rfs);
dlog("NFS: mounting remote server \"%s\", remote fs \"%s\" on \"%s\"",
fo->opt_rhost, fo->opt_rfs, fo->opt_fs);
-#endif /* DEBUG */
return xmtab;
}
@@ -525,24 +717,36 @@ nfs_match(am_opts *fo)
/*
* Initialize am structure for nfs
*/
-int
+static int
nfs_init(mntfs *mf)
{
int error;
am_nfs_handle_t fhs;
char *colon;
- if (mf->mf_private)
- return 0;
+ if (mf->mf_private) {
+ if (mf->mf_flags & MFF_NFS_SCALEDOWN) {
+ fserver *fs;
+
+ /* tell remote mountd that we're done with this filehandle */
+ mf->mf_ops->umounted(mf);
+
+ mf->mf_prfree(mf->mf_private);
+ fs = mf->mf_ops->ffserver(mf);
+ free_srvr(mf->mf_server);
+ mf->mf_server = fs;
+ } else
+ return 0;
+ }
colon = strchr(mf->mf_info, ':');
if (colon == 0)
return ENOENT;
- error = prime_nfs_fhandle_cache(colon + 1, mf->mf_server, &fhs, (voidp) mf);
+ error = prime_nfs_fhandle_cache(colon + 1, mf->mf_server, &fhs, mf);
if (!error) {
- mf->mf_private = (voidp) ALLOC(am_nfs_handle_t);
- mf->mf_prfree = (void (*)(voidp)) free;
+ mf->mf_private = (opaque_t) ALLOC(am_nfs_handle_t);
+ mf->mf_prfree = (void (*)(opaque_t)) free;
memmove(mf->mf_private, (voidp) &fhs, sizeof(fhs));
}
return error;
@@ -550,18 +754,20 @@ nfs_init(mntfs *mf)
int
-mount_nfs_fh(am_nfs_handle_t *fhp, char *dir, char *fs_name, char *opts, mntfs *mf)
+mount_nfs_fh(am_nfs_handle_t *fhp, char *mntdir, char *fs_name, mntfs *mf)
{
MTYPE_TYPE type;
char *colon;
- char *xopts;
+ char *xopts=NULL, transp_timeo_opts[40], transp_retrans_opts[40];
char host[MAXHOSTNAMELEN + MAXPATHLEN + 2];
fserver *fs = mf->mf_server;
u_long nfs_version = fs->fs_version;
char *nfs_proto = fs->fs_proto; /* "tcp" or "udp" */
+ int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
int error;
int genflags;
int retry;
+ int proto = AMU_TYPE_NONE;
mntent_t mnt;
nfs_args_t nfs_args;
@@ -575,26 +781,48 @@ mount_nfs_fh(am_nfs_handle_t *fhp, char *dir, char *fs_name, char *opts, mntfs *
#ifdef MOUNT_TABLE_ON_FILE
*colon = '\0';
#endif /* MOUNT_TABLE_ON_FILE */
- strncpy(host, fs_name, sizeof(host));
+ xstrlcpy(host, fs_name, sizeof(host));
#ifdef MOUNT_TABLE_ON_FILE
*colon = ':';
#endif /* MOUNT_TABLE_ON_FILE */
#ifdef MAXHOSTNAMELEN
/* most kernels have a name length restriction */
if (strlen(host) >= MAXHOSTNAMELEN)
- strcpy(host + MAXHOSTNAMELEN - 3, "..");
+ xstrlcpy(host + MAXHOSTNAMELEN - 3, "..",
+ sizeof(host) - MAXHOSTNAMELEN + 3);
#endif /* MAXHOSTNAMELEN */
+ /*
+ * Create option=VAL for udp/tcp specific timeouts and retrans values, but
+ * only if these options were specified.
+ */
+
+ transp_timeo_opts[0] = transp_retrans_opts[0] = '\0'; /* initialize */
+ if (STREQ(nfs_proto, "udp"))
+ proto = AMU_TYPE_UDP;
+ else if (STREQ(nfs_proto, "tcp"))
+ proto = AMU_TYPE_TCP;
+ if (proto != AMU_TYPE_NONE) {
+ if (gopt.amfs_auto_timeo[proto] > 0)
+ xsnprintf(transp_timeo_opts, sizeof(transp_timeo_opts), "%s=%d,",
+ MNTTAB_OPT_TIMEO, gopt.amfs_auto_timeo[proto]);
+ if (gopt.amfs_auto_retrans[proto] > 0)
+ xsnprintf(transp_retrans_opts, sizeof(transp_retrans_opts), "%s=%d,",
+ MNTTAB_OPT_RETRANS, gopt.amfs_auto_retrans[proto]);
+ }
+
if (mf->mf_remopts && *mf->mf_remopts &&
!islocalnet(fs->fs_ip->sin_addr.s_addr)) {
plog(XLOG_INFO, "Using remopts=\"%s\"", mf->mf_remopts);
- xopts = strdup(mf->mf_remopts);
+ /* use transp_opts first, so map-specific opts will override */
+ xopts = str3cat(xopts, transp_timeo_opts, transp_retrans_opts, mf->mf_remopts);
} else {
- xopts = strdup(opts);
+ /* use transp_opts first, so map-specific opts will override */
+ xopts = str3cat(xopts, transp_timeo_opts, transp_retrans_opts, mf->mf_mopts);
}
memset((voidp) &mnt, 0, sizeof(mnt));
- mnt.mnt_dir = dir;
+ mnt.mnt_dir = mntdir;
mnt.mnt_fsname = fs_name;
mnt.mnt_opts = xopts;
@@ -626,18 +854,19 @@ mount_nfs_fh(am_nfs_handle_t *fhp, char *dir, char *fs_name, char *opts, mntfs *
}
#endif /* HAVE_FS_NFS3 */
plog(XLOG_INFO, "mount_nfs_fh: NFS version %d", (int) nfs_version);
-#if defined(HAVE_FS_NFS3) || defined(HAVE_TRANSPORT_TYPE_TLI)
plog(XLOG_INFO, "mount_nfs_fh: using NFS transport %s", nfs_proto);
-#endif /* defined(HAVE_FS_NFS3) || defined(HAVE_TRANSPORT_TYPE_TLI) */
retry = hasmntval(&mnt, MNTTAB_OPT_RETRY);
if (retry <= 0)
retry = 1; /* XXX */
genflags = compute_mount_flags(&mnt);
+#ifdef HAVE_FS_AUTOFS
+ if (on_autofs)
+ genflags |= autofs_compute_mount_flags(&mnt);
+#endif /* HAVE_FS_AUTOFS */
/* setup the many fields and flags within nfs_args */
-#ifdef HAVE_TRANSPORT_TYPE_TLI
compute_nfs_args(&nfs_args,
&mnt,
genflags,
@@ -648,27 +877,14 @@ mount_nfs_fh(am_nfs_handle_t *fhp, char *dir, char *fs_name, char *opts, mntfs *
fhp,
host,
fs_name);
-#else /* not HAVE_TRANSPORT_TYPE_TLI */
- compute_nfs_args(&nfs_args,
- &mnt,
- genflags,
- fs->fs_ip,
- nfs_version,
- nfs_proto,
- fhp,
- host,
- fs_name);
-#endif /* not HAVE_TRANSPORT_TYPE_TLI */
/* finally call the mounting function */
-#ifdef DEBUG
- amuDebug(D_TRACE) {
+ if (amuDebug(D_TRACE)) {
print_nfs_args(&nfs_args, nfs_version);
plog(XLOG_DEBUG, "Generic mount flags 0x%x used for NFS mount", genflags);
}
-#endif /* DEBUG */
error = mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type,
- nfs_version, nfs_proto, mnttab_file_name);
+ nfs_version, nfs_proto, mnttab_file_name, on_autofs);
XFREE(xopts);
#ifdef HAVE_TRANSPORT_TYPE_TLI
@@ -682,39 +898,62 @@ mount_nfs_fh(am_nfs_handle_t *fhp, char *dir, char *fs_name, char *opts, mntfs *
static int
-mount_nfs(char *dir, char *fs_name, char *opts, mntfs *mf)
+nfs_mount(am_node *am, mntfs *mf)
{
+ int error = 0;
+ mntent_t mnt;
+
if (!mf->mf_private) {
- plog(XLOG_ERROR, "Missing filehandle for %s", fs_name);
+ plog(XLOG_ERROR, "Missing filehandle for %s", mf->mf_info);
return EINVAL;
}
- return mount_nfs_fh((am_nfs_handle_t *) mf->mf_private, dir, fs_name, opts, mf);
-}
+ mnt.mnt_opts = mf->mf_mopts;
+ if (amu_hasmntopt(&mnt, "softlookup") ||
+ (amu_hasmntopt(&mnt, "soft") && !amu_hasmntopt(&mnt, "nosoftlookup")))
+ am->am_flags |= AMF_SOFTLOOKUP;
+ error = mount_nfs_fh((am_nfs_handle_t *) mf->mf_private,
+ mf->mf_mount,
+ mf->mf_info,
+ mf);
-int
-nfs_fmount(mntfs *mf)
-{
- int error = 0;
-
- error = mount_nfs(mf->mf_mount, mf->mf_info, mf->mf_mopts, mf);
-
-#ifdef DEBUG
if (error) {
errno = error;
dlog("mount_nfs: %m");
}
-#endif /* DEBUG */
return error;
}
-int
-nfs_fumount(mntfs *mf)
+static int
+nfs_umount(am_node *am, mntfs *mf)
{
- int error = UMOUNT_FS(mf->mf_mount, mnttab_file_name);
+ int unmount_flags, new_unmount_flags, error;
+
+ unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
+ error = UMOUNT_FS(mf->mf_mount, mnttab_file_name, unmount_flags);
+
+#if defined(HAVE_UMOUNT2) && (defined(MNT2_GEN_OPT_FORCE) || defined(MNT2_GEN_OPT_DETACH))
+ /*
+ * If the attempt to unmount failed with EBUSY, and this fserver was
+ * marked for forced unmounts, then use forced/lazy unmounts.
+ */
+ if (error == EBUSY &&
+ gopt.flags & CFM_FORCED_UNMOUNTS &&
+ mf->mf_server->fs_flags & FSF_FORCE_UNMOUNT) {
+ plog(XLOG_INFO, "EZK: nfs_umount: trying forced/lazy unmounts");
+ /*
+ * XXX: turning off the FSF_FORCE_UNMOUNT may not be perfectly
+ * incorrect. Multiple nodes may need to be timed out and restarted for
+ * a single hung fserver.
+ */
+ mf->mf_server->fs_flags &= ~FSF_FORCE_UNMOUNT;
+ new_unmount_flags = unmount_flags | AMU_UMOUNT_FORCE | AMU_UMOUNT_DETACH;
+ error = UMOUNT_FS(mf->mf_mount, mnttab_file_name, new_unmount_flags);
+ }
+#endif /* HAVE_UMOUNT2 && (MNT2_GEN_OPT_FORCE || MNT2_GEN_OPT_DETACH) */
/*
* Here is some code to unmount 'restarted' file systems.
@@ -743,12 +982,14 @@ nfs_fumount(mntfs *mf)
if (NSTREQ(mf->mf_mount, new_mf->mf_mount, len) &&
new_mf->mf_mount[len] == '/') {
- UMOUNT_FS(new_mf->mf_mount, mnttab_file_name);
+ new_unmount_flags =
+ (new_mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
+ UMOUNT_FS(new_mf->mf_mount, mnttab_file_name, new_unmount_flags);
didsome = 1;
}
}
if (didsome)
- error = UMOUNT_FS(mf->mf_mount, mnttab_file_name);
+ error = UMOUNT_FS(mf->mf_mount, mnttab_file_name, unmount_flags);
}
if (error)
return error;
@@ -757,38 +998,35 @@ nfs_fumount(mntfs *mf)
}
-void
-nfs_umounted(am_node *mp)
+static void
+nfs_umounted(mntfs *mf)
{
- /*
- * Don't bother to inform remote mountd that we are finished. Until a
- * full track of filehandles is maintained the mountd unmount callback
- * cannot be done correctly anyway...
- */
- mntfs *mf = mp->am_mnt;
fserver *fs;
char *colon, *path;
if (mf->mf_error || mf->mf_refc > 1)
return;
- fs = mf->mf_server;
+ /*
+ * No need to inform mountd when WebNFS is in use.
+ */
+ if (mf->mf_flags & MFF_WEBNFS)
+ return;
/*
* Call the mount daemon on the server to announce that we are not using
* the fs any more.
*
- * This is *wrong*. The mountd should be called when the fhandle is
+ * XXX: This is *wrong*. The mountd should be called when the fhandle is
* flushed from the cache, and a reference held to the cached entry while
* the fs is mounted...
*/
+ fs = mf->mf_server;
colon = path = strchr(mf->mf_info, ':');
if (fs && colon) {
fh_cache f;
-#ifdef DEBUG
dlog("calling mountd for %s", mf->mf_info);
-#endif /* DEBUG */
*path++ = '\0';
f.fh_path = path;
f.fh_sin = *fs->fs_ip;
@@ -797,8 +1035,8 @@ nfs_umounted(am_node *mp)
f.fh_fs = fs;
f.fh_id = 0;
f.fh_error = 0;
- prime_nfs_fhandle_cache(colon + 1, mf->mf_server, (am_nfs_handle_t *) 0, (voidp) mf);
- call_mountd(&f, MOUNTPROC_UMNT, (fwd_fun) 0, (voidp) 0);
+ prime_nfs_fhandle_cache(colon + 1, mf->mf_server, (am_nfs_handle_t *) 0, mf);
+ call_mountd(&f, MOUNTPROC_UMNT, (fwd_fun *) 0, (wchan_t) 0);
*colon = ':';
}
}
diff --git a/contrib/amd/amd/ops_nfs3.c b/contrib/amd/amd/ops_nfs3.c
index 8da2cb1..db3c7f9 100644
--- a/contrib/amd/amd/ops_nfs3.c
+++ b/contrib/amd/amd/ops_nfs3.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: ops_nfs3.c,v 1.3.2.4 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/ops_nfs3.c
*
*/
diff --git a/contrib/amd/amd/ops_nullfs.c b/contrib/amd/amd/ops_nullfs.c
index 0ecb1a9..cf621ec 100644
--- a/contrib/amd/amd/ops_nullfs.c
+++ b/contrib/amd/amd/ops_nullfs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: ops_nullfs.c,v 1.3.2.4 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/ops_nullfs.c
*
*/
diff --git a/contrib/amd/amd/ops_pcfs.c b/contrib/amd/amd/ops_pcfs.c
index f148e6d..527dc92 100644
--- a/contrib/amd/amd/ops_pcfs.c
+++ b/contrib/amd/amd/ops_pcfs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: ops_pcfs.c,v 1.3.2.5 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/ops_pcfs.c
*
*/
@@ -54,8 +53,8 @@
/* forward definitions */
static char *pcfs_match(am_opts *fo);
-static int pcfs_fmount(mntfs *mf);
-static int pcfs_fumount(mntfs *mf);
+static int pcfs_mount(am_node *am, mntfs *mf);
+static int pcfs_umount(am_node *am, mntfs *mf);
/*
* Ops structure
@@ -65,17 +64,20 @@ am_ops pcfs_ops =
"pcfs",
pcfs_match,
0, /* pcfs_init */
- amfs_auto_fmount,
- pcfs_fmount,
- amfs_auto_fumount,
- pcfs_fumount,
- amfs_error_lookuppn,
+ pcfs_mount,
+ pcfs_umount,
+ amfs_error_lookup_child,
+ amfs_error_mount_child,
amfs_error_readdir,
0, /* pcfs_readlink */
0, /* pcfs_mounted */
0, /* pcfs_umounted */
- find_amfs_auto_srvr,
- FS_MKMNT | FS_UBACKGROUND | FS_AMQINFO
+ amfs_generic_find_srvr,
+ 0, /* pcfs_get_wchan */
+ FS_MKMNT | FS_UBACKGROUND | FS_AMQINFO, /* nfs_fs_flags */
+#ifdef HAVE_FS_AUTOFS
+ AUTOFS_PCFS_FS_FLAGS,
+#endif /* HAVE_FS_AUTOFS */
};
@@ -90,9 +92,7 @@ pcfs_match(am_opts *fo)
plog(XLOG_USER, "pcfs: no source device specified");
return 0;
}
-#ifdef DEBUG
dlog("PCFS: mounting device \"%s\" on \"%s\"", fo->opt_dev, fo->opt_fs);
-#endif /* DEBUG */
/*
* Determine magic cookie to put in mtab
@@ -102,11 +102,17 @@ pcfs_match(am_opts *fo)
static int
-mount_pcfs(char *dir, char *fs_name, char *opts)
+mount_pcfs(char *mntdir, char *fs_name, char *opts, int on_autofs)
{
pcfs_args_t pcfs_args;
mntent_t mnt;
int flags;
+#if defined(HAVE_PCFS_ARGS_T_MASK) || defined(HAVE_PCFS_ARGS_T_DIRMASK)
+ int mask;
+#endif /* defined(HAVE_PCFS_ARGS_T_MASK) || defined(HAVE_PCFS_ARGS_T_DIRMASK) */
+#if defined(HAVE_PCFS_ARGS_T_UID) || defined(HAVE_PCFS_ARGS_T_UID)
+ char *str;
+#endif /* defined(HAVE_PCFS_ARGS_T_UID) || defined(HAVE_PCFS_ARGS_T_UID) */
/*
* Figure out the name of the file system type.
@@ -119,12 +125,18 @@ mount_pcfs(char *dir, char *fs_name, char *opts)
* Fill in the mount structure
*/
memset((voidp) &mnt, 0, sizeof(mnt));
- mnt.mnt_dir = dir;
+ mnt.mnt_dir = mntdir;
mnt.mnt_fsname = fs_name;
mnt.mnt_type = MNTTAB_TYPE_PCFS;
mnt.mnt_opts = opts;
flags = compute_mount_flags(&mnt);
+#ifdef HAVE_FS_AUTOFS
+ if (on_autofs)
+ flags |= autofs_compute_mount_flags(&mnt);
+#endif /* HAVE_FS_AUTOFS */
+ if (amuDebug(D_TRACE))
+ plog(XLOG_DEBUG, "mount_pcfs: flags=0x%x", (u_int) flags);
#ifdef HAVE_PCFS_ARGS_T_FSPEC
pcfs_args.fspec = fs_name;
@@ -132,14 +144,46 @@ mount_pcfs(char *dir, char *fs_name, char *opts)
#ifdef HAVE_PCFS_ARGS_T_MASK
pcfs_args.mask = 0777; /* this may be the msdos file modes */
+ if ((mask = hasmntval(&mnt, MNTTAB_OPT_MASK)) > 0)
+ pcfs_args.mask = mask;
+ if (amuDebug(D_TRACE))
+ plog(XLOG_DEBUG, "mount_pcfs: mask=%o (octal)", (u_int) pcfs_args.mask);
#endif /* HAVE_PCFS_ARGS_T_MASK */
+#ifdef HAVE_PCFS_ARGS_T_DIRMASK
+ pcfs_args.dirmask = 0777; /* this may be the msdos dir modes */
+ if ((mask = hasmntval(&mnt, MNTTAB_OPT_DIRMASK)) > 0)
+ pcfs_args.dirmask = mask;
+ if (amuDebug(D_TRACE))
+ plog(XLOG_DEBUG, "mount_pcfs: dirmask=%o (octal)", (u_int) pcfs_args.dirmask);
+#endif /* HAVE_PCFS_ARGS_T_DIRMASK */
+
#ifdef HAVE_PCFS_ARGS_T_UID
- pcfs_args.uid = 0; /* root */
+ pcfs_args.uid = 0; /* default to root */
+ if ((str = hasmntstr(&mnt, MNTTAB_OPT_USER)) != NULL) {
+ struct passwd *pw;
+ if ((pw = getpwnam(str)) != NULL)
+ pcfs_args.uid = pw->pw_uid;
+ else /* maybe used passed a UID number, not user name */
+ pcfs_args.uid = atoi(str); /* atoi returns '0' if it failed */
+ XFREE(str);
+ }
+ if (amuDebug(D_TRACE))
+ plog(XLOG_DEBUG, "mount_pcfs: uid=%d", (int) pcfs_args.uid);
#endif /* HAVE_PCFS_ARGS_T_UID */
#ifdef HAVE_PCFS_ARGS_T_GID
- pcfs_args.gid = 0; /* wheel */
+ pcfs_args.gid = 0; /* default to wheel/root group */
+ if ((str = hasmntstr(&mnt, MNTTAB_OPT_GROUP)) != NULL) {
+ struct group *gr;
+ if ((gr = getgrnam(str)) != NULL)
+ pcfs_args.gid = gr->gr_gid;
+ else /* maybe used passed a GID number, not group name */
+ pcfs_args.gid = atoi(str); /* atoi returns '0' if it failed */
+ XFREE(str);
+ }
+ if (amuDebug(D_TRACE))
+ plog(XLOG_DEBUG, "mount_pcfs: gid=%d", (int) pcfs_args.gid);
#endif /* HAVE_PCFS_ARGS_T_GID */
#ifdef HAVE_PCFS_ARGS_T_SECONDSWEST
@@ -152,16 +196,17 @@ mount_pcfs(char *dir, char *fs_name, char *opts)
/*
* Call generic mount routine
*/
- return mount_fs(&mnt, flags, (caddr_t) & pcfs_args, 0, type, 0, NULL, mnttab_file_name);
+ return mount_fs(&mnt, flags, (caddr_t) & pcfs_args, 0, type, 0, NULL, mnttab_file_name, on_autofs);
}
static int
-pcfs_fmount(mntfs *mf)
+pcfs_mount(am_node *am, mntfs *mf)
{
+ int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
int error;
- error = mount_pcfs(mf->mf_mount, mf->mf_info, mf->mf_mopts);
+ error = mount_pcfs(mf->mf_mount, mf->mf_info, mf->mf_mopts, on_autofs);
if (error) {
errno = error;
plog(XLOG_ERROR, "mount_pcfs: %m");
@@ -173,7 +218,9 @@ pcfs_fmount(mntfs *mf)
static int
-pcfs_fumount(mntfs *mf)
+pcfs_umount(am_node *am, mntfs *mf)
{
- return UMOUNT_FS(mf->mf_mount, mnttab_file_name);
+ int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
+
+ return UMOUNT_FS(mf->mf_mount, mnttab_file_name, unmount_flags);
}
diff --git a/contrib/amd/amd/ops_tfs.c b/contrib/amd/amd/ops_tfs.c
index 911c01c..142c320 100644
--- a/contrib/amd/amd/ops_tfs.c
+++ b/contrib/amd/amd/ops_tfs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: ops_tfs.c,v 1.3.2.4 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/ops_tfs.c
*
*/
diff --git a/contrib/amd/amd/ops_tmpfs.c b/contrib/amd/amd/ops_tmpfs.c
index ca2d515..eddd755 100644
--- a/contrib/amd/amd/ops_tmpfs.c
+++ b/contrib/amd/amd/ops_tmpfs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: ops_tmpfs.c,v 1.3.2.4 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/ops_tmpfs.c
*
*/
diff --git a/contrib/amd/amd/ops_ufs.c b/contrib/amd/amd/ops_ufs.c
index 999a669..fd82a5c 100644
--- a/contrib/amd/amd/ops_ufs.c
+++ b/contrib/amd/amd/ops_ufs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: ops_ufs.c,v 1.3.2.5 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/ops_ufs.c
*
*/
@@ -54,8 +53,8 @@
/* forward declarations */
static char *ufs_match(am_opts *fo);
-static int ufs_fmount(mntfs *mf);
-static int ufs_fumount(mntfs *mf);
+static int ufs_mount(am_node *am, mntfs *mf);
+static int ufs_umount(am_node *am, mntfs *mf);
/*
* Ops structure
@@ -65,17 +64,20 @@ am_ops ufs_ops =
"ufs",
ufs_match,
0, /* ufs_init */
- amfs_auto_fmount,
- ufs_fmount,
- amfs_auto_fumount,
- ufs_fumount,
- amfs_error_lookuppn,
+ ufs_mount,
+ ufs_umount,
+ amfs_error_lookup_child,
+ amfs_error_mount_child,
amfs_error_readdir,
0, /* ufs_readlink */
0, /* ufs_mounted */
0, /* ufs_umounted */
- find_amfs_auto_srvr,
- FS_MKMNT | FS_NOTIMEOUT | FS_UBACKGROUND | FS_AMQINFO
+ amfs_generic_find_srvr,
+ 0, /* ufs_get_wchan */
+ FS_MKMNT | FS_NOTIMEOUT | FS_UBACKGROUND | FS_AMQINFO, /* nfs_fs_flags */
+#ifdef HAVE_FS_AUTOFS
+ AUTOFS_UFS_FS_FLAGS,
+#endif /* HAVE_FS_AUTOFS */
};
@@ -91,9 +93,7 @@ ufs_match(am_opts *fo)
return 0;
}
-#ifdef DEBUG
dlog("UFS: mounting device \"%s\" on \"%s\"", fo->opt_dev, fo->opt_fs);
-#endif /* DEBUG */
/*
* Determine magic cookie to put in mtab
@@ -103,7 +103,7 @@ ufs_match(am_opts *fo)
static int
-mount_ufs(char *dir, char *fs_name, char *opts)
+mount_ufs(char *mntdir, char *fs_name, char *opts, int on_autofs)
{
ufs_args_t ufs_args;
mntent_t mnt;
@@ -120,12 +120,16 @@ mount_ufs(char *dir, char *fs_name, char *opts)
* Fill in the mount structure
*/
memset((voidp) &mnt, 0, sizeof(mnt));
- mnt.mnt_dir = dir;
+ mnt.mnt_dir = mntdir;
mnt.mnt_fsname = fs_name;
mnt.mnt_type = MNTTAB_TYPE_UFS;
mnt.mnt_opts = opts;
genflags = compute_mount_flags(&mnt);
+#ifdef HAVE_FS_AUTOFS
+ if (on_autofs)
+ genflags |= autofs_compute_mount_flags(&mnt);
+#endif /* HAVE_FS_AUTOFS */
#ifdef HAVE_UFS_ARGS_T_FLAGS
ufs_args.flags = genflags; /* XXX: is this correct? */
@@ -146,16 +150,17 @@ mount_ufs(char *dir, char *fs_name, char *opts)
/*
* Call generic mount routine
*/
- return mount_fs(&mnt, genflags, (caddr_t) &ufs_args, 0, type, 0, NULL, mnttab_file_name);
+ return mount_fs(&mnt, genflags, (caddr_t) &ufs_args, 0, type, 0, NULL, mnttab_file_name, on_autofs);
}
static int
-ufs_fmount(mntfs *mf)
+ufs_mount(am_node *am, mntfs *mf)
{
+ int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
int error;
- error = mount_ufs(mf->mf_mount, mf->mf_info, mf->mf_mopts);
+ error = mount_ufs(mf->mf_mount, mf->mf_info, mf->mf_mopts, on_autofs);
if (error) {
errno = error;
plog(XLOG_ERROR, "mount_ufs: %m");
@@ -167,7 +172,9 @@ ufs_fmount(mntfs *mf)
static int
-ufs_fumount(mntfs *mf)
+ufs_umount(am_node *am, mntfs *mf)
{
- return UMOUNT_FS(mf->mf_mount, mnttab_file_name);
+ int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
+
+ return UMOUNT_FS(mf->mf_mount, mnttab_file_name, unmount_flags);
}
diff --git a/contrib/amd/amd/ops_umapfs.c b/contrib/amd/amd/ops_umapfs.c
index 65e99cb..5ba735e 100644
--- a/contrib/amd/amd/ops_umapfs.c
+++ b/contrib/amd/amd/ops_umapfs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: ops_umapfs.c,v 1.3.2.4 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/ops_umapfs.c
*
*/
diff --git a/contrib/amd/amd/ops_unionfs.c b/contrib/amd/amd/ops_unionfs.c
index 52059a0..73f8d66 100644
--- a/contrib/amd/amd/ops_unionfs.c
+++ b/contrib/amd/amd/ops_unionfs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: ops_unionfs.c,v 1.3.2.4 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/ops_unionfs.c
*
*/
diff --git a/contrib/amd/amd/ops_xfs.c b/contrib/amd/amd/ops_xfs.c
index 4c9010b..e0e740b 100644
--- a/contrib/amd/amd/ops_xfs.c
+++ b/contrib/amd/amd/ops_xfs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: ops_xfs.c,v 1.3.2.6 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/ops_xfs.c
*
*/
@@ -54,8 +53,8 @@
/* forward declarations */
static char *xfs_match(am_opts *fo);
-static int xfs_fmount(mntfs *mf);
-static int xfs_fumount(mntfs *mf);
+static int xfs_mount(am_node *am, mntfs *mf);
+static int xfs_umount(am_node *am, mntfs *mf);
/*
* Ops structure
@@ -65,17 +64,20 @@ am_ops xfs_ops =
"xfs",
xfs_match,
0, /* xfs_init */
- amfs_auto_fmount,
- xfs_fmount,
- amfs_auto_fumount,
- xfs_fumount,
- amfs_error_lookuppn,
+ xfs_mount,
+ xfs_umount,
+ amfs_error_lookup_child,
+ amfs_error_mount_child,
amfs_error_readdir,
0, /* xfs_readlink */
0, /* xfs_mounted */
0, /* xfs_umounted */
- find_amfs_auto_srvr,
- FS_MKMNT | FS_NOTIMEOUT | FS_UBACKGROUND | FS_AMQINFO
+ amfs_generic_find_srvr,
+ 0, /* xfs_get_wchan */
+ FS_MKMNT | FS_NOTIMEOUT | FS_UBACKGROUND | FS_AMQINFO, /* nfs_fs_flags */
+#ifdef HAVE_FS_AUTOFS
+ AUTOFS_XFS_FS_FLAGS,
+#endif /* HAVE_FS_AUTOFS */
};
@@ -91,9 +93,7 @@ xfs_match(am_opts *fo)
return 0;
}
-#ifdef DEBUG
dlog("XFS: mounting device \"%s\" on \"%s\"", fo->opt_dev, fo->opt_fs);
-#endif /* DEBUG */
/*
* Determine magic cookie to put in mtab
@@ -103,7 +103,7 @@ xfs_match(am_opts *fo)
static int
-mount_xfs(char *dir, char *fs_name, char *opts)
+mount_xfs(char *mntdir, char *fs_name, char *opts, int on_autofs)
{
xfs_args_t xfs_args;
mntent_t mnt;
@@ -120,12 +120,16 @@ mount_xfs(char *dir, char *fs_name, char *opts)
* Fill in the mount structure
*/
memset((voidp) &mnt, 0, sizeof(mnt));
- mnt.mnt_dir = dir;
+ mnt.mnt_dir = mntdir;
mnt.mnt_fsname = fs_name;
mnt.mnt_type = MNTTAB_TYPE_XFS;
mnt.mnt_opts = opts;
flags = compute_mount_flags(&mnt);
+#ifdef HAVE_FS_AUTOFS
+ if (on_autofs)
+ flags |= autofs_compute_mount_flags(&mnt);
+#endif /* HAVE_FS_AUTOFS */
#ifdef HAVE_XFS_ARGS_T_FLAGS
xfs_args.flags = 0; /* XXX: fix this to correct flags */
@@ -137,16 +141,17 @@ mount_xfs(char *dir, char *fs_name, char *opts)
/*
* Call generic mount routine
*/
- return mount_fs(&mnt, flags, (caddr_t) &xfs_args, 0, type, 0, NULL, mnttab_file_name);
+ return mount_fs(&mnt, flags, (caddr_t) &xfs_args, 0, type, 0, NULL, mnttab_file_name, on_autofs);
}
static int
-xfs_fmount(mntfs *mf)
+xfs_mount(am_node *am, mntfs *mf)
{
+ int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
int error;
- error = mount_xfs(mf->mf_mount, mf->mf_info, mf->mf_mopts);
+ error = mount_xfs(mf->mf_mount, mf->mf_info, mf->mf_mopts, on_autofs);
if (error) {
errno = error;
plog(XLOG_ERROR, "mount_xfs: %m");
@@ -158,7 +163,9 @@ xfs_fmount(mntfs *mf)
static int
-xfs_fumount(mntfs *mf)
+xfs_umount(am_node *am, mntfs *mf)
{
- return UMOUNT_FS(mf->mf_mount, mnttab_file_name);
+ int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
+
+ return UMOUNT_FS(mf->mf_mount, mnttab_file_name, unmount_flags);
}
diff --git a/contrib/amd/amd/opts.c b/contrib/amd/amd/opts.c
index 92bceb2..a3d3534 100644
--- a/contrib/amd/amd/opts.c
+++ b/contrib/amd/amd/opts.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1989 Jan-Simon Pendry
* Copyright (c) 1989 Imperial College of Science, Technology & Medicine
* Copyright (c) 1989 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: opts.c,v 1.8.2.7 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/opts.c
*
*/
@@ -94,11 +93,13 @@ struct functable {
* FORWARD DEFINITION:
*/
static int f_in_network(char *);
+static int f_xhost(char *);
static int f_netgrp(char *);
static int f_netgrpd(char *);
static int f_exists(char *);
static int f_false(char *);
static int f_true(char *);
+static inline char *expand_options(char *key);
/*
* STATICS:
@@ -112,7 +113,7 @@ static char *opt_key = nullstr;
static char *opt_keyd = nullstr;
static char *opt_map = nullstr;
static char *opt_path = nullstr;
-static char uid_str[12], gid_str[12];
+char uid_str[SIZEOF_UID_STR], gid_str[SIZEOF_GID_STR];
char *opt_uid = uid_str;
char *opt_gid = gid_str;
static char *vars[8];
@@ -121,11 +122,11 @@ static char *literal_dollar = "$"; /* ${dollar}: a literal '$' in maps */
/*
* GLOBALS
*/
-struct am_opts fs_static; /* copy of the options to play with */
+static struct am_opts fs_static; /* copy of the options to play with */
/*
- * Options in something corresponding to frequency of use so that
+ * Options in some order corresponding to frequency of use so that
* first-match algorithm is sped up.
*/
static struct opt opt_fields[] = {
@@ -191,6 +192,8 @@ static struct opt opt_fields[] = {
&fs_static.opt_mount, 0, 0, FALSE },
{ S("unmount"),
&fs_static.opt_unmount, 0, 0, FALSE },
+ { S("umount"),
+ &fs_static.opt_umount, 0, 0, FALSE },
{ S("cache"),
&fs_static.opt_cache, 0, 0, FALSE },
{ S("user"),
@@ -201,7 +204,6 @@ static struct opt opt_fields[] = {
0, &opt_dkey, 0, FALSE },
{ S("key."),
0, &opt_keyd, 0, FALSE },
- /* XXX: should maptype really be a variable? I think selector. -Erez */
{ S("maptype"),
&fs_static.opt_maptype, 0, 0, FALSE },
{ S("cachedir"),
@@ -212,6 +214,8 @@ static struct opt opt_fields[] = {
0, &opt_uid, 0, FALSE },
{ S("gid"),
0, &opt_gid, 0, FALSE },
+ { S("mount_type"),
+ &fs_static.opt_mount_type, 0, 0, FALSE },
{ S("dollar"),
&literal_dollar, 0, 0, FALSE },
{ S("var0"),
@@ -235,6 +239,7 @@ static struct opt opt_fields[] = {
static struct functable functable[] = {
{ "in_network", f_in_network },
+ { "xhost", f_xhost },
{ "netgrp", f_netgrp },
{ "netgrpd", f_netgrpd },
{ "exists", f_exists },
@@ -265,6 +270,7 @@ static opt_apply expansions[] =
{&fs_static.opt_remopts, "${opts}"},
{&fs_static.opt_mount, 0},
{&fs_static.opt_unmount, 0},
+ {&fs_static.opt_umount, 0},
{&fs_static.opt_cachedir, 0},
{&fs_static.opt_addopts, 0},
{0, 0},
@@ -286,6 +292,7 @@ static opt_apply to_free[] =
{&fs_static.opt_remopts, 0},
{&fs_static.opt_mount, 0},
{&fs_static.opt_unmount, 0},
+ {&fs_static.opt_umount, 0},
{&fs_static.opt_cachedir, 0},
{&fs_static.opt_addopts, 0},
{&vars[0], 0},
@@ -302,6 +309,7 @@ static opt_apply to_free[] =
/*
* expand backslash escape sequences
+ * (escaped slash is handled separately in normalize_slash)
*/
static char
backslash(char **p)
@@ -457,33 +465,99 @@ functable_lookup(char *key)
}
+/*
+ * Fill in the global structure fs_static by
+ * cracking the string opts. opts may be
+ * scribbled on at will. Does NOT evaluate options.
+ * Returns 0 on error, 1 if no syntax errors were discovered.
+ */
static int
-eval_opts(char *opts, char *mapkey)
+split_opts(char *opts, char *mapkey)
{
+ char *o = opts;
+ char *f;
+
/*
- * Fill in the global structure fs_static by
- * cracking the string opts. opts may be
- * scribbled on at will.
+ * For each user-specified option
*/
- char *o = opts;
+ for (f = opt(&o); *f; f = opt(&o)) {
+ struct opt *op;
+ char *eq = strchr(f, '=');
+ char *opt = NULL;
+
+ if (!eq)
+ continue;
+
+ if (*(eq-1) == '!' ||
+ eq[1] == '=' ||
+ eq[1] == '!') { /* != or == or =! */
+ continue; /* we don't care about selectors */
+ }
+
+ if (*(eq-1) == ':') { /* := */
+ *(eq-1) = '\0';
+ } else {
+ /* old style assignment */
+ eq[0] = '\0';
+ }
+ opt = eq + 1;
+
+ /*
+ * For each recognized option
+ */
+ for (op = opt_fields; op->name; op++) {
+ /*
+ * Check whether they match
+ */
+ if (FSTREQ(op->name, f)) {
+ if (op->sel_p) {
+ plog(XLOG_USER, "key %s: Can't assign to a selector (%s)",
+ mapkey, op->name);
+ return 0;
+ }
+ *op->optp = opt; /* actual assignment into fs_static */
+ break; /* break out of for loop */
+ } /* end of "if (FSTREQ(op->name, f))" statement */
+ } /* end of "for (op = opt_fields..." statement */
+
+ if (!op->name)
+ plog(XLOG_USER, "key %s: Unrecognized key/option \"%s\"", mapkey, f);
+ }
+
+ return 1;
+}
+
+
+/*
+ * Just evaluate selectors, which were split by split_opts.
+ * Returns 0 on error or no match, 1 if matched.
+ */
+static int
+eval_selectors(char *opts, char *mapkey)
+{
+ char *o, *old_o;
char *f;
+ int ret = 0;
+
+ o = old_o = strdup(opts);
/*
* For each user-specified option
*/
- while (*(f = opt(&o))) {
+ for (f = opt(&o); *f; f = opt(&o)) {
struct opt *op;
- enum vs_opt vs_opt = VarAss;
+ enum vs_opt vs_opt;
char *eq = strchr(f, '=');
char *fx;
IntFuncPtr func;
char *opt = NULL;
+ char *arg;
- if (!eq || eq[1] == '\0' || eq == f) {
+ if (!eq) {
/*
* No value, is it a function call?
*/
- char *arg = strchr(f, '(');
+ arg = strchr(f, '(');
if (!arg || arg[1] == '\0' || arg == f) {
/*
@@ -502,43 +576,54 @@ eval_opts(char *opts, char *mapkey)
}
*fx = '\0';
+ if (f[0] == '!') {
+ vs_opt = SelNE;
+ f++;
+ } else {
+ vs_opt = SelEQ;
+ }
/*
* look up f in functable and pass it arg.
* func must return 0 on failure, and 1 on success.
*/
if ((func = functable_lookup(f))) {
- if (!(*func) (arg)) {
- return (0);
- }
- continue;
- } else if (NSTREQ(f, "!", 1) && (func = functable_lookup(&f[1]))) {
- /* then this is a negated prefixed function such as "!exists" */
- plog(XLOG_INFO, "executing negated function %s", &f[1]);
- if ((*func) (arg)) {
- return (0);
- }
+ int funok;
+
+ /* this allocates memory, don't forget to free */
+ arg = expand_options(arg);
+ funok = func(arg);
+ XFREE(arg);
+
+ if (vs_opt == SelNE)
+ funok = !funok;
+ if (!funok)
+ goto out;
+
continue;
} else {
plog(XLOG_USER, "key %s: unknown function \"%s\"", mapkey, f);
- return (0);
+ goto out;
+ }
+ } else {
+ if (eq[1] == '\0' || eq == f) {
+ /* misformed selector */
+ plog(XLOG_USER, "key %s: Bad selector \"%s\"", mapkey, f);
+ continue;
}
-
}
/*
* Check what type of operation is happening
* !=, =! is SelNE
* == is SelEQ
- * := is VarAss
+ * =, := is VarAss
*/
- if (eq[-1] == '!') { /* != */
+ if (*(eq-1) == '!') { /* != */
vs_opt = SelNE;
- eq[-1] = '\0';
- opt = eq + 1;
- } else if (eq[-1] == ':') { /* := */
- vs_opt = VarAss;
- eq[-1] = '\0';
+ *(eq-1) = '\0';
opt = eq + 1;
+ } else if (*(eq-1) == ':') { /* := */
+ continue;
} else if (eq[1] == '=') { /* == */
vs_opt = SelEQ;
eq[0] = '\0';
@@ -547,6 +632,9 @@ eval_opts(char *opts, char *mapkey)
vs_opt = SelNE;
eq[0] = '\0';
opt = eq + 2;
+ } else {
+ /* old style assignment */
+ continue;
}
/*
@@ -557,48 +645,47 @@ eval_opts(char *opts, char *mapkey)
* Check whether they match
*/
if (FSTREQ(op->name, f)) {
- int selok;
- switch (vs_opt) {
- case SelEQ:
- case SelNE:
- if ((selok = (op->sel_p != NULL))) {
- if (op->case_insensitive) {
- selok = (STRCEQ(*op->sel_p, opt) == (vs_opt == SelNE));
- } else {
- selok = (STREQ(*op->sel_p, opt) == (vs_opt == SelNE));
- }
- }
- if (selok) {
+ opt = expand_options(opt);
+
+ if (op->sel_p != NULL) {
+ int selok;
+ if (op->case_insensitive) {
+ selok = STRCEQ(*op->sel_p, opt);
+ } else {
+ selok = STREQ(*op->sel_p, opt);
+ }
+ if (vs_opt == SelNE)
+ selok = !selok;
+ if (!selok) {
plog(XLOG_MAP, "key %s: map selector %s (=%s) did not %smatch %s",
mapkey,
op->name,
*op->sel_p,
vs_opt == SelNE ? "mis" : "",
opt);
- return 0;
+ XFREE(opt);
+ goto out;
}
- /* check if to apply a function */
- if (op->fxn_p &&
- ((*op->fxn_p)(opt) == (vs_opt == SelNE))) {
+ XFREE(opt);
+ }
+ /* check if to apply a function */
+ if (op->fxn_p) {
+ int funok;
+
+ funok = op->fxn_p(opt);
+ if (vs_opt == SelNE)
+ funok = !funok;
+ if (!funok) {
plog(XLOG_MAP, "key %s: map function %s did not %smatch %s",
mapkey,
op->name,
vs_opt == SelNE ? "mis" : "",
opt);
- return 0;
- }
- break;
-
- case VarAss:
- if (op->sel_p) {
- plog(XLOG_USER, "key %s: Can't assign to a selector (%s)",
- mapkey, op->name);
- return 0;
+ XFREE(opt);
+ goto out;
}
- *op->optp = opt;
- break;
-
- } /* end of "switch (vs_opt)" statement */
+ XFREE(opt);
+ }
break; /* break out of for loop */
}
}
@@ -607,7 +694,12 @@ eval_opts(char *opts, char *mapkey)
plog(XLOG_USER, "key %s: Unrecognized key/option \"%s\"", mapkey, f);
}
- return 1;
+ /* all is ok */
+ ret = 1;
+
+ out:
+ free(old_o);
+ return ret;
}
@@ -695,9 +787,9 @@ strip_selectors(char *opts, char *mapkey)
* == is SelEQ
* := is VarAss
*/
- if (eq[-1] == '!') { /* != */
+ if (*(eq-1) == '!') { /* != */
vs_opt = SelNE;
- } else if (eq[-1] == ':') { /* := */
+ } else if (*(eq-1) == ':') { /* := */
vs_opt = VarAss;
} else if (eq[1] == '=') { /* == */
vs_opt = SelEQ;
@@ -715,9 +807,7 @@ strip_selectors(char *opts, char *mapkey)
case VarAss:
/* found the first assignment, return the string starting with it */
-#ifdef DEBUG
dlog("found first assignment past selectors \"%s\"", o);
-#endif /* DEBUG */
return oo;
}
}
@@ -738,27 +828,86 @@ f_in_network(char *arg)
int status;
if (!arg)
- return FALSE;
+ return 0;
status = is_network_member(arg);
-#ifdef DEBUG
- plog(XLOG_USER, "%s is %son a local network",
- arg, (status ? "" : "not "));
-#endif /* DEBUG */
+ dlog("%s is %son a local network", arg, (status ? "" : "not "));
return status;
}
+/*
+ * Test if arg is any of this host's names or aliases (CNAMES).
+ * Note: this function compares against the fully expanded host name (hostd).
+ * XXX: maybe we also need to compare against the stripped host name?
+ */
+static int
+f_xhost(char *arg)
+{
+ struct hostent *hp;
+ char **cp;
+
+ if (!arg)
+ return 0;
+
+ /* simple test: does it match main host name? */
+ if (STREQ(arg, opt_hostd))
+ return 1;
+
+ /* now find all of the names of "arg" and compare against opt_hostd */
+ hp = gethostbyname(arg);
+ if (hp == NULL) {
+#ifdef HAVE_HSTRERROR
+ plog(XLOG_ERROR, "gethostbyname xhost(%s): %s", arg, hstrerror(h_errno));
+#else /* not HAVE_HSTRERROR */
+ plog(XLOG_ERROR, "gethostbyname xhost(%s): h_errno %d", arg, h_errno);
+#endif /* not HAVE_HSTRERROR */
+ return 0;
+ }
+ /* check primary name */
+ if (hp->h_name) {
+ dlog("xhost: compare %s==%s", hp->h_name, opt_hostd);
+ if (STREQ(hp->h_name, opt_hostd)) {
+ plog(XLOG_INFO, "xhost(%s): matched h_name %s", arg, hp->h_name);
+ return 1;
+ }
+ }
+ /* check all aliases, if any */
+ if (hp->h_aliases == NULL) {
+ dlog("gethostbyname(%s) has no aliases", arg);
+ return 0;
+ }
+ cp = hp->h_aliases;
+ while (*cp) {
+ dlog("xhost: compare alias %s==%s", *cp, opt_hostd);
+ if (STREQ(*cp, opt_hostd)) {
+ plog(XLOG_INFO, "xhost(%s): matched alias %s", arg, *cp);
+ return 1;
+ }
+ cp++;
+ }
+ /* nothing matched */
+ return 0;
+}
+
+
/* test if this host (short hostname form) is in netgroup (arg) */
static int
f_netgrp(char *arg)
{
int status;
+ char *ptr, *nhost;
- status = innetgr(arg, opt_host, NULL, NULL);
-#ifdef DEBUG
- plog(XLOG_USER, "netgrp = %s status = %d host = %s", arg, status, opt_host);
-#endif /* DEBUG */
+ if ((ptr = strchr(arg, ',')) != NULL) {
+ *ptr = '\0';
+ nhost = ptr + 1;
+ } else {
+ nhost = opt_host;
+ }
+ status = innetgr(arg, nhost, NULL, NULL);
+ dlog("netgrp = %s status = %d host = %s", arg, status, nhost);
+ if (ptr)
+ *ptr = ',';
return status;
}
@@ -768,11 +917,18 @@ static int
f_netgrpd(char *arg)
{
int status;
+ char *ptr, *nhost;
- status = innetgr(arg, opt_hostd, NULL, NULL);
-#ifdef DEBUG
- plog(XLOG_USER, "netgrp = %s status = %d hostd = %s", arg, status, opt_hostd);
-#endif /* DEBUG */
+ if ((ptr = strchr(arg, ',')) != NULL) {
+ *ptr = '\0';
+ nhost = ptr + 1;
+ } else {
+ nhost = opt_hostd;
+ }
+ status = innetgr(arg, nhost, NULL, NULL);
+ dlog("netgrp = %s status = %d hostd = %s", arg, status, nhost);
+ if (ptr)
+ *ptr = ',';
return status;
}
@@ -814,7 +970,6 @@ free_op(opt_apply *p, int b)
{
if (*p->opt) {
XFREE(*p->opt);
- *p->opt = 0;
}
}
@@ -825,9 +980,12 @@ free_op(opt_apply *p, int b)
void
normalize_slash(char *p)
{
- char *f = strchr(p, '/');
- char *f0 = f;
+ char *f, *f0;
+ if (!(gopt.flags & CFM_NORMALIZE_SLASHES))
+ return;
+
+ f0 = f = strchr(p, '/');
if (f) {
char *t = f;
do {
@@ -849,6 +1007,9 @@ normalize_slash(char *p)
/* assert(*f != '/'); */
/* keep copying up to next / */
while (*f && *f != '/') {
+ /* support escaped slashes '\/' */
+ if (f[0] == '\\' && f[1] == '/')
+ f++; /* skip backslash */
*t++ = *f++;
}
@@ -863,22 +1024,20 @@ normalize_slash(char *p)
/*
* Macro-expand an option. Note that this does not
* handle recursive expansions. They will go badly wrong.
- * If sel is true then old expand selectors, otherwise
+ * If sel_p is true then old expand selectors, otherwise
* don't expand selectors.
*/
-static void
-expand_op(opt_apply *p, int sel_p)
+static char *
+expand_op(char *opt, int sel_p)
{
- static const char expand_error[] = "No space to expand \"%s\"";
+#define EXPAND_ERROR "No space to expand \"%s\""
char expbuf[MAXPATHLEN + 1];
char nbuf[NLEN + 1];
char *ep = expbuf;
- char *cp = *p->opt;
+ char *cp = opt;
char *dp;
struct opt *op;
-#ifdef DEBUG
- char *cp_orig = *p->opt;
-#endif /* DEBUG */
+ char *cp_orig = opt;
while ((dp = strchr(cp, '$'))) {
char ch;
@@ -888,12 +1047,18 @@ expand_op(opt_apply *p, int sel_p)
{
int len = dp - cp;
- if (BUFSPACE(ep, len)) {
- strncpy(ep, cp, len);
- ep += len;
- } else {
- plog(XLOG_ERROR, expand_error, *p->opt);
- goto out;
+ if (len > 0) {
+ if (BUFSPACE(ep, len)) {
+ /*
+ * We use strncpy (not xstrlcpy) because 'ep' relies on its
+ * semantics. BUFSPACE guarantees that ep can hold len.
+ */
+ strncpy(ep, cp, len);
+ ep += len;
+ } else {
+ plog(XLOG_ERROR, EXPAND_ERROR, opt);
+ goto out;
+ }
}
}
@@ -903,7 +1068,7 @@ expand_op(opt_apply *p, int sel_p)
if (BUFSPACE(ep, 1)) {
*ep++ = '$';
} else {
- plog(XLOG_ERROR, expand_error, *p->opt);
+ plog(XLOG_ERROR, EXPAND_ERROR, opt);
goto out;
}
} else if (ch == '{') {
@@ -924,7 +1089,7 @@ expand_op(opt_apply *p, int sel_p)
/*
* Just give up
*/
- plog(XLOG_USER, "No closing '}' in \"%s\"", *p->opt);
+ plog(XLOG_USER, "No closing '}' in \"%s\"", opt);
goto out;
}
len = br_p - cp;
@@ -939,7 +1104,7 @@ expand_op(opt_apply *p, int sel_p)
todo = E_File;
cp++;
--len;
- } else if (br_p[-1] == '/') {
+ } else if (*(br_p-1) == '/') {
/*
* Take all but the last component
*/
@@ -952,7 +1117,7 @@ expand_op(opt_apply *p, int sel_p)
todo = E_Domain;
cp++;
--len;
- } else if (br_p[-1] == '.') {
+ } else if (*(br_p-1) == '.') {
/*
* Take host name
*/
@@ -976,6 +1141,11 @@ expand_op(opt_apply *p, int sel_p)
/*
* Put the string into another buffer so
* we can do comparisons.
+ *
+ * We use strncpy here (not xstrlcpy) because the dest is meant
+ * to be truncated and we don't want to log it as an error. The
+ * use of the BUFSPACE macro above guarantees the safe use of
+ * strncpy with nbuf.
*/
strncpy(nbuf, cp, len);
nbuf[len] = '\0';
@@ -1003,12 +1173,12 @@ expand_op(opt_apply *p, int sel_p)
/*
* Copy the string across unexpanded
*/
- sprintf(xbuf, "${%s%s%s}",
- todo == E_File ? "/" :
- todo == E_Domain ? "." : "",
- nbuf,
- todo == E_Dir ? "/" :
- todo == E_Host ? "." : "");
+ xsnprintf(xbuf, sizeof(xbuf), "${%s%s%s}",
+ todo == E_File ? "/" :
+ todo == E_Domain ? "." : "",
+ nbuf,
+ todo == E_Dir ? "/" :
+ todo == E_Host ? "." : "");
val = xbuf;
/*
* Make sure expansion doesn't
@@ -1067,11 +1237,11 @@ expand_op(opt_apply *p, int sel_p)
break;
}
- if (BUFSPACE(ep, vlen)) {
- strcpy(ep, vptr);
+ if (BUFSPACE(ep, vlen+1)) {
+ xstrlcpy(ep, vptr, vlen+1);
ep += vlen;
} else {
- plog(XLOG_ERROR, expand_error, *p->opt);
+ plog(XLOG_ERROR, EXPAND_ERROR, opt);
goto out;
}
}
@@ -1096,17 +1266,15 @@ expand_op(opt_apply *p, int sel_p)
if (env) {
int vlen = strlen(env);
- if (BUFSPACE(ep, vlen)) {
- strcpy(ep, env);
+ if (BUFSPACE(ep, vlen+1)) {
+ xstrlcpy(ep, env, vlen+1);
ep += vlen;
} else {
- plog(XLOG_ERROR, expand_error, *p->opt);
+ plog(XLOG_ERROR, EXPAND_ERROR, opt);
goto out;
}
-#ifdef DEBUG
- amuDebug(D_STR)
+ if (amuDebug(D_STR))
plog(XLOG_DEBUG, "Environment gave \"%s\" -> \"%s\"", nbuf, env);
-#endif /* DEBUG */
} else {
plog(XLOG_USER, "Unknown sequence \"${%s}\"", nbuf);
}
@@ -1115,7 +1283,7 @@ expand_op(opt_apply *p, int sel_p)
/*
* Error, error
*/
- plog(XLOG_USER, "Unknown $ sequence in \"%s\"", *p->opt);
+ plog(XLOG_USER, "Unknown $ sequence in \"%s\"", opt);
}
}
@@ -1123,33 +1291,33 @@ out:
/*
* Handle common case - no expansion
*/
- if (cp == *p->opt) {
- *p->opt = strdup(cp);
+ if (cp == opt) {
+ opt = strdup(cp);
} else {
/*
* Finish off the expansion
*/
- if (BUFSPACE(ep, strlen(cp))) {
- strcpy(ep, cp);
- /* ep += strlen(ep); */
+ int vlen = strlen(cp);
+ if (BUFSPACE(ep, vlen+1)) {
+ xstrlcpy(ep, cp, vlen+1);
+ /* ep += vlen; */
} else {
- plog(XLOG_ERROR, expand_error, *p->opt);
+ plog(XLOG_ERROR, EXPAND_ERROR, opt);
}
/*
* Save the expansion
*/
- *p->opt = strdup(expbuf);
+ opt = strdup(expbuf);
}
- normalize_slash(*p->opt);
+ normalize_slash(opt);
-#ifdef DEBUG
- amuDebug(D_STR) {
+ if (amuDebug(D_STR)) {
plog(XLOG_DEBUG, "Expansion of \"%s\"...", cp_orig);
- plog(XLOG_DEBUG, "... is \"%s\"", *p->opt);
+ plog(XLOG_DEBUG, "......... is \"%s\"", opt);
}
-#endif /* DEBUG */
+ return opt;
}
@@ -1160,15 +1328,15 @@ static void
expand_opts(opt_apply *p, int sel_p)
{
if (*p->opt) {
- expand_op(p, sel_p);
+ *p->opt = expand_op(*p->opt, sel_p);
} else if (p->val) {
/*
* Do double expansion, remembering
* to free the string from the first
* expansion...
*/
- char *s = *p->opt = expand_key(p->val);
- expand_op(p, sel_p);
+ char *s = expand_op(p->val, TRUE);
+ *p->opt = expand_op(s, sel_p);
XFREE(s);
}
}
@@ -1206,18 +1374,22 @@ free_opts(am_opts *fo)
/*
- * Expand lookup key
+ * Expand selectors (variables that cannot be assigned to or overridden)
*/
char *
-expand_key(char *key)
+expand_selectors(char *key)
{
- opt_apply oa;
+ return expand_op(key, TRUE);
+}
- oa.opt = &key;
- oa.val = 0;
- expand_opts(&oa, TRUE);
- return key;
+/*
+ * Expand options (i.e. non-selectors, see above for definition)
+ */
+static inline char *
+expand_options(char *key)
+{
+ return expand_op(key, FALSE);
}
@@ -1225,10 +1397,14 @@ expand_key(char *key)
* Remove trailing /'s from a string
* unless the string is a single / (Steven Glassman)
* or unless it is two slashes // (Kevin D. Bond)
+ * or unless amd.conf says not to touch slashes.
*/
void
deslashify(char *s)
{
+ if (!(gopt.flags & CFM_NORMALIZE_SLASHES))
+ return;
+
if (s && *s) {
char *sl = s + strlen(s);
@@ -1276,24 +1452,27 @@ eval_fs_opts(am_opts *fo, char *opts, char *g_opts, char *path, char *key, char
/*
* Expand global options
*/
- fs_static.fs_glob = expand_key(g_opts);
+ fs_static.fs_glob = expand_selectors(g_opts);
/*
* Expand local options
*/
- fs_static.fs_local = expand_key(opts);
-
- /*
- * Expand default (global) options
- */
- if (!eval_opts(fs_static.fs_glob, key))
- ok = FALSE;
+ fs_static.fs_local = expand_selectors(opts);
- /*
- * Expand local options
- */
- if (ok && !eval_opts(fs_static.fs_local, key))
- ok = FALSE;
+ /* break global options into fs_static fields */
+ if ((ok = split_opts(fs_static.fs_glob, key))) {
+ dlog("global split_opts ok");
+ /*
+ * evaluate local selectors
+ */
+ if ((ok = eval_selectors(fs_static.fs_local, key))) {
+ dlog("local eval_selectors ok");
+ /* if the local selectors matched, then do the local overrides */
+ ok = split_opts(fs_static.fs_local, key);
+ if (ok)
+ dlog("local split_opts ok");
+ }
+ }
/*
* Normalize remote host name.
diff --git a/contrib/amd/amd/readdir.c b/contrib/amd/amd/readdir.c
new file mode 100644
index 0000000..d025c91
--- /dev/null
+++ b/contrib/amd/amd/readdir.c
@@ -0,0 +1,498 @@
+/*
+ * Copyright (c) 1997-2006 Erez Zadok
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgment:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *
+ * File: am-utils/amd/readdir.c
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* HAVE_CONFIG_H */
+#include <am_defs.h>
+#include <amd.h>
+
+
+/****************************************************************************
+ *** MACROS ***
+ ****************************************************************************/
+#define DOT_DOT_COOKIE (u_int) 1
+#define MAX_CHAIN 2048
+
+
+/****************************************************************************
+ *** FORWARD DEFINITIONS ***
+ ****************************************************************************/
+static int key_already_in_chain(char *keyname, const nfsentry *chain);
+static nfsentry *make_entry_chain(am_node *mp, const nfsentry *current_chain, int fully_browsable);
+static int amfs_readdir_browsable(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, u_int count, int fully_browsable);
+
+
+/****************************************************************************
+ *** FUNCTIONS ***
+ ****************************************************************************/
+/*
+ * Was: NEW_TOPLVL_READDIR
+ * Search a chain for an entry with some name.
+ * -Erez Zadok <ezk@cs.columbia.edu>
+ */
+static int
+key_already_in_chain(char *keyname, const nfsentry *chain)
+{
+ const nfsentry *tmpchain = chain;
+
+ while (tmpchain) {
+ if (keyname && tmpchain->ne_name && STREQ(keyname, tmpchain->ne_name))
+ return 1;
+ tmpchain = tmpchain->ne_nextentry;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Create a chain of entries which are not linked.
+ * -Erez Zadok <ezk@cs.columbia.edu>
+ */
+static nfsentry *
+make_entry_chain(am_node *mp, const nfsentry *current_chain, int fully_browsable)
+{
+ static u_int last_cookie = (u_int) 2; /* monotonically increasing */
+ static nfsentry chain[MAX_CHAIN];
+ static int max_entries = MAX_CHAIN;
+ char *key;
+ int num_entries = 0, i;
+ u_int preflen = 0;
+ nfsentry *retval = (nfsentry *) NULL;
+ mntfs *mf;
+ mnt_map *mmp;
+
+ if (!mp) {
+ plog(XLOG_DEBUG, "make_entry_chain: mp is (NULL)");
+ return retval;
+ }
+ mf = mp->am_mnt;
+ if (!mf) {
+ plog(XLOG_DEBUG, "make_entry_chain: mp->am_mnt is (NULL)");
+ return retval;
+ }
+ mmp = (mnt_map *) mf->mf_private;
+ if (!mmp) {
+ plog(XLOG_DEBUG, "make_entry_chain: mp->am_mnt->mf_private is (NULL)");
+ return retval;
+ }
+
+ if (mp->am_pref)
+ preflen = strlen(mp->am_pref);
+
+ /* iterate over keys */
+ for (i = 0; i < NKVHASH; i++) {
+ kv *k;
+ for (k = mmp->kvhash[i]; k ; k = k->next) {
+
+ /*
+ * Skip unwanted entries which are either not real entries or
+ * very difficult to interpret (wildcards...) This test needs
+ * lots of improvement. Any takers?
+ */
+ key = k->key;
+ if (!key)
+ continue;
+
+ /* Skip '/defaults' */
+ if (STREQ(key, "/defaults"))
+ continue;
+
+ /* Skip '*' */
+ if (!fully_browsable && strchr(key, '*'))
+ continue;
+
+ /*
+ * If the map has a prefix-string then check if the key starts with
+ * this string, and if it does, skip over this prefix. If it has a
+ * prefix and it doesn't match the start of the key, skip it.
+ */
+ if (preflen) {
+ if (preflen > strlen(key))
+ continue;
+ if (!NSTREQ(key, mp->am_pref, preflen))
+ continue;
+ key += preflen;
+ }
+
+ /* no more '/' are allowed, unless browsable_dirs=full was used */
+ if (!fully_browsable && strchr(key, '/'))
+ continue;
+
+ /* no duplicates allowed */
+ if (key_already_in_chain(key, current_chain))
+ continue;
+
+ /* fill in a cell and link the entry */
+ if (num_entries >= max_entries) {
+ /* out of space */
+ plog(XLOG_DEBUG, "make_entry_chain: no more space in chain");
+ if (num_entries > 0) {
+ chain[num_entries - 1].ne_nextentry = 0;
+ retval = &chain[0];
+ }
+ return retval;
+ }
+
+ /* we have space. put entry in next cell */
+ ++last_cookie;
+ chain[num_entries].ne_fileid = (u_int) last_cookie;
+ *(u_int *) chain[num_entries].ne_cookie = (u_int) last_cookie;
+ chain[num_entries].ne_name = key;
+ if (num_entries < max_entries - 1) { /* link to next one */
+ chain[num_entries].ne_nextentry = &chain[num_entries + 1];
+ }
+ ++num_entries;
+ } /* end of "while (k)" */
+ } /* end of "for (i ... NKVHASH ..." */
+
+ /* terminate chain */
+ if (num_entries > 0) {
+ chain[num_entries - 1].ne_nextentry = 0;
+ retval = &chain[0];
+ }
+
+ return retval;
+}
+
+
+
+/* This one is called only if map is browsable */
+static int
+amfs_readdir_browsable(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, u_int count, int fully_browsable)
+{
+ u_int gen = *(u_int *) cookie;
+ int chain_length, i;
+ static nfsentry *te, *te_next;
+ static int j;
+
+ dp->dl_eof = FALSE; /* assume readdir not done */
+
+ if (amuDebug(D_READDIR))
+ plog(XLOG_DEBUG, "amfs_readdir_browsable gen=%u, count=%d",
+ gen, count);
+
+ if (gen == 0) {
+ /*
+ * In the default instance (which is used to start a search) we return
+ * "." and "..".
+ *
+ * This assumes that the count is big enough to allow both "." and ".."
+ * to be returned in a single packet. If it isn't (which would be
+ * fairly unbelievable) then tough.
+ */
+ dlog("amfs_readdir_browsable: default search");
+ /*
+ * Check for enough room. This is extremely approximate but is more
+ * than enough space. Really need 2 times:
+ * 4byte fileid
+ * 4byte cookie
+ * 4byte name length
+ * 4byte name
+ * plus the dirlist structure */
+ if (count < (2 * (2 * (sizeof(*ep) + sizeof("..") + 4) + sizeof(*dp))))
+ return EINVAL;
+
+ /*
+ * compute # of entries to send in this chain.
+ * heuristics: 128 bytes per entry.
+ * This is too much probably, but it seems to work better because
+ * of the re-entrant nature of nfs_readdir, and esp. on systems
+ * like OpenBSD 2.2.
+ */
+ chain_length = count / 128;
+
+ /* reset static state counters */
+ te = te_next = NULL;
+
+ dp->dl_entries = ep;
+
+ /* construct "." */
+ ep[0].ne_fileid = mp->am_gen;
+ ep[0].ne_name = ".";
+ ep[0].ne_nextentry = &ep[1];
+ *(u_int *) ep[0].ne_cookie = 0;
+
+ /* construct ".." */
+ if (mp->am_parent)
+ ep[1].ne_fileid = mp->am_parent->am_gen;
+ else
+ ep[1].ne_fileid = mp->am_gen;
+
+ ep[1].ne_name = "..";
+ ep[1].ne_nextentry = 0;
+ *(u_int *) ep[1].ne_cookie = DOT_DOT_COOKIE;
+
+ /*
+ * If map is browsable, call a function make_entry_chain() to construct
+ * a linked list of unmounted keys, and return it. Then link the chain
+ * to the regular list. Get the chain only once, but return
+ * chunks of it each time.
+ */
+ te = make_entry_chain(mp, dp->dl_entries, fully_browsable);
+ if (!te)
+ return 0;
+ if (amuDebug(D_READDIR)) {
+ nfsentry *ne;
+ for (j = 0, ne = te; ne; ne = ne->ne_nextentry)
+ plog(XLOG_DEBUG, "gen1 key %4d \"%s\"", j++, ne->ne_name);
+ }
+
+ /* return only "chain_length" entries */
+ te_next = te;
+ for (i=1; i<chain_length; ++i) {
+ te_next = te_next->ne_nextentry;
+ if (!te_next)
+ break;
+ }
+ if (te_next) {
+ nfsentry *te_saved = te_next->ne_nextentry;
+ te_next->ne_nextentry = NULL; /* terminate "te" chain */
+ te_next = te_saved; /* save rest of "te" for next iteration */
+ dp->dl_eof = FALSE; /* tell readdir there's more */
+ } else {
+ dp->dl_eof = TRUE; /* tell readdir that's it */
+ }
+ ep[1].ne_nextentry = te; /* append this chunk of "te" chain */
+ if (amuDebug(D_READDIR)) {
+ nfsentry *ne;
+ for (j = 0, ne = te; ne; ne = ne->ne_nextentry)
+ plog(XLOG_DEBUG, "gen2 key %4d \"%s\"", j++, ne->ne_name);
+ for (j = 0, ne = ep; ne; ne = ne->ne_nextentry)
+ plog(XLOG_DEBUG, "gen2+ key %4d \"%s\" fi=%d ck=%d",
+ j++, ne->ne_name, ne->ne_fileid, *(u_int *)ne->ne_cookie);
+ plog(XLOG_DEBUG, "EOF is %d", dp->dl_eof);
+ }
+ return 0;
+ } /* end of "if (gen == 0)" statement */
+
+ dlog("amfs_readdir_browsable: real child");
+
+ if (gen == DOT_DOT_COOKIE) {
+ dlog("amfs_readdir_browsable: End of readdir in %s", mp->am_path);
+ dp->dl_eof = TRUE;
+ dp->dl_entries = 0;
+ return 0;
+ }
+
+ /*
+ * If browsable directories, then continue serving readdir() with another
+ * chunk of entries, starting from where we left off (when gen was equal
+ * to 0). Once again, assume last chunk served to readdir.
+ */
+ dp->dl_eof = TRUE;
+ dp->dl_entries = ep;
+
+ te = te_next; /* reset 'te' from last saved te_next */
+ if (!te) { /* another indicator of end of readdir */
+ dp->dl_entries = 0;
+ return 0;
+ }
+ /*
+ * compute # of entries to send in this chain.
+ * heuristics: 128 bytes per entry.
+ */
+ chain_length = count / 128;
+
+ /* return only "chain_length" entries */
+ for (i = 1; i < chain_length; ++i) {
+ te_next = te_next->ne_nextentry;
+ if (!te_next)
+ break;
+ }
+ if (te_next) {
+ nfsentry *te_saved = te_next->ne_nextentry;
+ te_next->ne_nextentry = NULL; /* terminate "te" chain */
+ te_next = te_saved; /* save rest of "te" for next iteration */
+ dp->dl_eof = FALSE; /* tell readdir there's more */
+ }
+ ep = te; /* send next chunk of "te" chain */
+ dp->dl_entries = ep;
+ if (amuDebug(D_READDIR)) {
+ nfsentry *ne;
+ plog(XLOG_DEBUG, "dl_entries=%p, te_next=%p, dl_eof=%d",
+ dp->dl_entries, te_next, dp->dl_eof);
+ for (ne = te; ne; ne = ne->ne_nextentry)
+ plog(XLOG_DEBUG, "gen3 key %4d \"%s\"", j++, ne->ne_name);
+ }
+ return 0;
+}
+
+
+/*
+ * This readdir function which call a special version of it that allows
+ * browsing if browsable_dirs=yes was set on the map.
+ */
+int
+amfs_generic_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, u_int count)
+{
+ u_int gen = *(u_int *) cookie;
+ am_node *xp;
+ mntent_t mnt;
+
+ dp->dl_eof = FALSE; /* assume readdir not done */
+
+ /* check if map is browsable */
+ if (mp->am_mnt && mp->am_mnt->mf_mopts) {
+ mnt.mnt_opts = mp->am_mnt->mf_mopts;
+ if (amu_hasmntopt(&mnt, "fullybrowsable"))
+ return amfs_readdir_browsable(mp, cookie, dp, ep, count, TRUE);
+ if (amu_hasmntopt(&mnt, "browsable"))
+ return amfs_readdir_browsable(mp, cookie, dp, ep, count, FALSE);
+ }
+
+ /* when gen is 0, we start reading from the beginning of the directory */
+ if (gen == 0) {
+ /*
+ * In the default instance (which is used to start a search) we return
+ * "." and "..".
+ *
+ * This assumes that the count is big enough to allow both "." and ".."
+ * to be returned in a single packet. If it isn't (which would be
+ * fairly unbelievable) then tough.
+ */
+ dlog("amfs_generic_readdir: default search");
+ /*
+ * Check for enough room. This is extremely approximate but is more
+ * than enough space. Really need 2 times:
+ * 4byte fileid
+ * 4byte cookie
+ * 4byte name length
+ * 4byte name
+ * plus the dirlist structure */
+ if (count < (2 * (2 * (sizeof(*ep) + sizeof("..") + 4) + sizeof(*dp))))
+ return EINVAL;
+
+ xp = next_nonerror_node(mp->am_child);
+ dp->dl_entries = ep;
+
+ /* construct "." */
+ ep[0].ne_fileid = mp->am_gen;
+ ep[0].ne_name = ".";
+ ep[0].ne_nextentry = &ep[1];
+ *(u_int *) ep[0].ne_cookie = 0;
+
+ /* construct ".." */
+ if (mp->am_parent)
+ ep[1].ne_fileid = mp->am_parent->am_gen;
+ else
+ ep[1].ne_fileid = mp->am_gen;
+ ep[1].ne_name = "..";
+ ep[1].ne_nextentry = 0;
+ *(u_int *) ep[1].ne_cookie = (xp ? xp->am_gen : DOT_DOT_COOKIE);
+
+ if (!xp)
+ dp->dl_eof = TRUE; /* by default assume readdir done */
+
+ if (amuDebug(D_READDIR)) {
+ nfsentry *ne;
+ int j;
+ for (j = 0, ne = ep; ne; ne = ne->ne_nextentry)
+ plog(XLOG_DEBUG, "gen1 key %4d \"%s\" fi=%d ck=%d",
+ j++, ne->ne_name, ne->ne_fileid, *(u_int *)ne->ne_cookie);
+ }
+ return 0;
+ }
+ dlog("amfs_generic_readdir: real child");
+
+ if (gen == DOT_DOT_COOKIE) {
+ dlog("amfs_generic_readdir: End of readdir in %s", mp->am_path);
+ dp->dl_eof = TRUE;
+ dp->dl_entries = 0;
+ if (amuDebug(D_READDIR))
+ plog(XLOG_DEBUG, "end of readdir eof=TRUE, dl_entries=0\n");
+ return 0;
+ }
+
+ /* non-browsable directories code */
+ xp = mp->am_child;
+ while (xp && xp->am_gen != gen)
+ xp = xp->am_osib;
+
+ if (xp) {
+ int nbytes = count / 2; /* conservative */
+ int todo = MAX_READDIR_ENTRIES;
+
+ dp->dl_entries = ep;
+ do {
+ am_node *xp_next = next_nonerror_node(xp->am_osib);
+
+ if (xp_next) {
+ *(u_int *) ep->ne_cookie = xp_next->am_gen;
+ } else {
+ *(u_int *) ep->ne_cookie = DOT_DOT_COOKIE;
+ dp->dl_eof = TRUE;
+ }
+
+ ep->ne_fileid = xp->am_gen;
+ ep->ne_name = xp->am_name;
+ nbytes -= sizeof(*ep) + 1;
+ if (xp->am_name)
+ nbytes -= strlen(xp->am_name);
+
+ xp = xp_next;
+
+ if (nbytes > 0 && !dp->dl_eof && todo > 1) {
+ ep->ne_nextentry = ep + 1;
+ ep++;
+ --todo;
+ } else {
+ todo = 0;
+ }
+ } while (todo > 0);
+
+ ep->ne_nextentry = 0;
+
+ if (amuDebug(D_READDIR)) {
+ nfsentry *ne;
+ int j;
+ for (j=0,ne=ep; ne; ne=ne->ne_nextentry)
+ plog(XLOG_DEBUG, "gen2 key %4d \"%s\" fi=%d ck=%d",
+ j++, ne->ne_name, ne->ne_fileid, *(u_int *)ne->ne_cookie);
+ }
+ return 0;
+ }
+ return ESTALE;
+}
diff --git a/contrib/amd/amd/restart.c b/contrib/amd/amd/restart.c
index 59902f6..4f71e38 100644
--- a/contrib/amd/amd/restart.c
+++ b/contrib/amd/amd/restart.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: restart.c,v 1.3.2.4 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/restart.c
*
*/
@@ -49,14 +48,81 @@
#include <amd.h>
+static void
+restart_fake_mntfs(mntent_t *me, am_ops *fs_ops)
+{
+ mntfs *mf;
+ am_opts mo;
+ char *cp;
+
+ /*
+ * Partially fake up an opts structure
+ */
+ memset(&mo, 0, sizeof(mo));
+ mo.opt_rhost = 0;
+ mo.opt_rfs = 0;
+ cp = strchr(me->mnt_fsname, ':');
+ if (cp) {
+ *cp = '\0';
+ mo.opt_rhost = strdup(me->mnt_fsname);
+ mo.opt_rfs = strdup(cp + 1);
+ *cp = ':';
+ } else if (STREQ(me->mnt_type, MNTTAB_TYPE_NFS)) {
+ /*
+ * Hacky workaround for mnttab NFS entries that only list the server
+ */
+ plog(XLOG_WARNING, "NFS server entry assumed to be %s:/", me->mnt_fsname);
+ mo.opt_rhost = strdup(me->mnt_fsname);
+ mo.opt_rfs = strdup("/");
+ me->mnt_fsname = str3cat(me->mnt_fsname, mo.opt_rhost, ":", "/");
+ }
+ mo.opt_fs = me->mnt_dir;
+ mo.opt_opts = me->mnt_opts;
+
+ /*
+ * Make a new mounted filesystem
+ */
+ mf = find_mntfs(fs_ops, &mo, me->mnt_dir,
+ me->mnt_fsname, "", me->mnt_opts, "");
+ if (mf->mf_refc == 1) {
+ mf->mf_flags |= MFF_RESTART | MFF_MOUNTED;
+ mf->mf_error = 0; /* Already mounted correctly */
+ mf->mf_fo = 0;
+ /*
+ * Only timeout non-NFS entries
+ */
+ if (!STREQ(me->mnt_type, MNTTAB_TYPE_NFS))
+ mf->mf_flags |= MFF_RSTKEEP;
+ if (fs_ops->fs_init) {
+ /*
+ * Don't care whether this worked since
+ * it is checked again when the fs is
+ * inherited.
+ */
+ (void) (*fs_ops->fs_init) (mf);
+ }
+ plog(XLOG_INFO, "%s restarted fstype %s on %s, flags 0x%x",
+ me->mnt_fsname, fs_ops->fs_type, me->mnt_dir, mf->mf_flags);
+ } else {
+ /* Something strange happened - two mounts at the same place! */
+ free_mntfs(mf);
+ }
+ /*
+ * Clean up mo
+ */
+ if (mo.opt_rhost)
+ XFREE(mo.opt_rhost);
+ if (mo.opt_rfs)
+ XFREE(mo.opt_rfs);
+}
+
+
/*
* Handle an amd restart.
*
* Scan through the mount list finding all "interesting" mount points.
* Next hack up partial data structures and add the mounted file
- * system to the list of known filesystems. This will leave a
- * dangling reference to that filesystems, so when the filesystem is
- * finally inherited, an extra "free" must be done on it.
+ * system to the list of known filesystems.
*
* This module relies on internal details of other components. If
* you change something else make *sure* restart() still works.
@@ -64,26 +130,19 @@
void
restart(void)
{
- /*
- * Read the existing mount table
- */
mntlist *ml, *mlp;
/*
- * For each entry, find nfs, ufs or auto mounts
- * and create a partial am_node to represent it.
+ * Read the existing mount table. For each entry, find nfs, ufs or auto
+ * mounts and create a partial am_node to represent it.
*/
for (mlp = ml = read_mtab("restart", mnttab_file_name);
mlp;
mlp = mlp->mnext) {
mntent_t *me = mlp->mnt;
am_ops *fs_ops = 0;
- if (STREQ(me->mnt_type, MNTTAB_TYPE_UFS)) {
- /*
- * UFS entry
- */
- fs_ops = &ufs_ops;
- } else if (STREQ(me->mnt_type, MNTTAB_TYPE_NFS)) {
+
+ if (STREQ(me->mnt_type, MNTTAB_TYPE_NFS)) {
/*
* NFS entry, or possibly an Amd entry...
* The mnt_fsname for daemon mount points is
@@ -92,117 +151,138 @@ restart(void)
* host:daemon(pidXXX)
*/
char *colon = strchr(me->mnt_fsname, ':');
+ if (colon && strstr(colon, "(pid"))
+ continue;
+ }
- if (colon && strstr(colon, "(pid")) {
- plog(XLOG_WARNING, "%s is an existing automount point", me->mnt_dir);
- fs_ops = &amfs_link_ops;
- } else {
- fs_ops = &nfs_ops;
- }
-#ifdef MNTTAB_TYPE_NFS3
- } else if (STREQ(me->mnt_type, MNTTAB_TYPE_NFS3)) {
- fs_ops = &nfs_ops;
-#endif /* MNTTAB_TYPE_NFS3 */
-#ifdef MNTTAB_TYPE_LOFS
- } else if (STREQ(me->mnt_type, MNTTAB_TYPE_LOFS)) {
- fs_ops = &lofs_ops;
-#endif /* MNTTAB_TYPE_LOFS */
-#ifdef MNTTAB_TYPE_CDFS
- } else if (STREQ(me->mnt_type, MNTTAB_TYPE_CDFS)) {
- fs_ops = &cdfs_ops;
-#endif /* MNTTAB_TYPE_CDFS */
-#ifdef MNTTAB_TYPE_PCFS
- } else if (STREQ(me->mnt_type, MNTTAB_TYPE_PCFS)) {
- fs_ops = &pcfs_ops;
-#endif /* MNTTAB_TYPE_PCFS */
-#ifdef MNTTAB_TYPE_MFS
- } else if (STREQ(me->mnt_type, MNTTAB_TYPE_MFS)) {
- /*
- * MFS entry. Fake with a symlink.
- */
- fs_ops = &amfs_link_ops;
-#endif /* MNTTAB_TYPE_MFS */
- } else {
- /*
- * Catch everything else with symlinks to
- * avoid recursive mounts. This is debatable...
- */
+ /* Search for the correct filesystem ops */
+ fs_ops = ops_search(me->mnt_type);
+
+ /*
+ * Catch everything else with symlinks to
+ * avoid recursive mounts. This is debatable...
+ */
+ if (!fs_ops)
fs_ops = &amfs_link_ops;
+
+ restart_fake_mntfs(me, fs_ops);
+ }
+
+ /*
+ * Free the mount list
+ */
+ free_mntlist(ml);
+}
+
+
+/*
+ * Handle an amd restart for amd's own mount points.
+ *
+ * Scan through the mount list finding all daemon mount points
+ * (determined by the presence of a pid inside the mount info).
+ * Next hack up partial data structures and add the mounted file
+ * system to the list of known filesystems.
+ *
+ * This module relies on internal details of other components. If
+ * you change something else make *sure* restart() still works.
+ */
+void
+restart_automounter_nodes(void)
+{
+ mntlist *ml, *mlp;
+ /* reasonably sized list of restarted nfs ports */
+ u_short old_ports[256];
+
+ memset((voidp) &old_ports, 0, sizeof(u_short) * 256);
+
+ /*
+ * Read the existing mount table. For each entry, find nfs, ufs or auto
+ * mounts and create a partial am_node to represent it.
+ */
+ for (mlp = ml = read_mtab("restart", mnttab_file_name);
+ mlp;
+ mlp = mlp->mnext) {
+ mntent_t *me = mlp->mnt;
+ am_ops *fs_ops = 0;
+ char *colon;
+ long pid;
+ u_short port;
+ int err;
+
+ if (!STREQ(me->mnt_type, MNTTAB_TYPE_NFS))
+ continue; /* to next mlp */
+ /*
+ * NFS entry, or possibly an Amd entry...
+ * The mnt_fsname for daemon mount points is
+ * host:(pidXXX)
+ * or (seen on Solaris)
+ * host:daemon(pidXXX)
+ */
+ colon = strchr(me->mnt_fsname, ':');
+ if (!colon || !strstr(colon, "(pid"))
+ continue;
+ /* if got here, then we matched an existing Amd mount point */
+ err = 1;
+
+ plog(XLOG_WARNING, "%s is an existing automount point", me->mnt_dir);
+
+ /* Is the old automounter still alive? */
+ if (sscanf(colon, "%*[^(](pid%ld%*[,)]", &pid) != 1) {
+ plog(XLOG_WARNING, "Can't parse pid in %s", me->mnt_fsname);
+ goto give_up;
+ }
+ if (kill(pid, 0) != -1 || errno != ESRCH) {
+ plog(XLOG_WARNING, "Automounter (pid: %ld) still alive", pid);
+ goto give_up;
}
/*
- * If we found something to do
+ * Do we have a map for this mount point? Who cares, we'll restart
+ * anyway -- getting ESTALE is way better than hanging.
*/
- if (fs_ops) {
- mntfs *mf;
- am_opts mo;
- char *cp;
- cp = strchr(me->mnt_fsname, ':');
- /*
- * Partially fake up an opts structure
- */
- mo.opt_rhost = 0;
- mo.opt_rfs = 0;
- if (cp) {
- *cp = '\0';
- mo.opt_rhost = strdup(me->mnt_fsname);
- mo.opt_rfs = strdup(cp + 1);
- *cp = ':';
- } else if (fs_ops->ffserver == find_nfs_srvr) {
- /*
- * Prototype 4.4 BSD used to end up here -
- * might as well keep the workaround for now
- */
- plog(XLOG_WARNING, "NFS server entry assumed to be %s:/", me->mnt_fsname);
- mo.opt_rhost = strdup(me->mnt_fsname);
- mo.opt_rfs = strdup("/");
- me->mnt_fsname = str3cat(me->mnt_fsname, mo.opt_rhost, ":", "/");
+ /* Can we restart it? Only if it tells us what port it was using... */
+ if (sscanf(colon, "%*[^,],port%hu)", &port) != 1) {
+ plog(XLOG_WARNING, "No port specified for %s", me->mnt_fsname);
+ goto give_up;
+ }
+
+ /* Maybe we already own that port... */
+ if (port != nfs_port) {
+ int i;
+ for (i = 0; i < 256; i++) {
+ if (old_ports[i] == port ||
+ old_ports[i] == 0)
+ break;
+ }
+ if (i == 256) {
+ plog(XLOG_WARNING, "Too many open ports (256)");
+ goto give_up;
}
- mo.opt_fs = me->mnt_dir;
- mo.opt_opts = me->mnt_opts;
- /*
- * Make a new mounted filesystem
- */
- mf = find_mntfs(fs_ops, &mo, me->mnt_dir,
- me->mnt_fsname, "", me->mnt_opts, "");
- if (mf->mf_refc == 1) {
- mf->mf_flags |= MFF_RESTART | MFF_MOUNTED;
- mf->mf_error = 0; /* Already mounted correctly */
- mf->mf_fo = 0;
- /*
- * If the restarted type is a link then
- * don't time out.
- */
- if (fs_ops == &amfs_link_ops || fs_ops == &ufs_ops)
- mf->mf_flags |= MFF_RSTKEEP;
- if (fs_ops->fs_init) {
- /*
- * Don't care whether this worked since
- * it is checked again when the fs is
- * inherited.
- */
- (void) (*fs_ops->fs_init) (mf);
+ if (old_ports[i] == 0) {
+ int soNFS;
+ SVCXPRT *nfsxprt;
+ if (create_nfs_service(&soNFS, &port, &nfsxprt, nfs_program_2) != 0) {
+ plog(XLOG_WARNING, "Can't bind to port %u", port);
+ goto give_up;
}
- plog(XLOG_INFO, "%s restarted fstype %s on %s",
- me->mnt_fsname, fs_ops->fs_type, me->mnt_dir);
- } else {
- /* Something strange happened - two mounts at the same place! */
- free_mntfs(mf);
+ old_ports[i] = nfs_port = port;
}
- /*
- * Clean up mo
- */
- if (mo.opt_rhost)
- XFREE(mo.opt_rhost);
- if (mo.opt_rfs)
- XFREE(mo.opt_rfs);
}
- }
+ err = 0;
- /*
- * Free the mount list
- */
+ give_up:
+ if (err) {
+ plog(XLOG_WARNING, "Can't restart %s, leaving it alone", me->mnt_dir);
+ fs_ops = &amfs_link_ops;
+ } else {
+ fs_ops = &amfs_toplvl_ops;
+ }
+
+ restart_fake_mntfs(me, fs_ops);
+ } /* end of "for (mlp" */
+
+ /* free the mount list */
free_mntlist(ml);
}
diff --git a/contrib/amd/amd/rpc_fwd.c b/contrib/amd/amd/rpc_fwd.c
index 5a5439c..b3c8be4 100644
--- a/contrib/amd/amd/rpc_fwd.c
+++ b/contrib/amd/amd/rpc_fwd.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1989 Jan-Simon Pendry
* Copyright (c) 1989 Imperial College of Science, Technology & Medicine
* Copyright (c) 1989 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: rpc_fwd.c,v 1.3.2.5 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/rpc_fwd.c
*
*/
@@ -58,7 +57,7 @@
* is no need to convert to and from network byte ordering.
*/
-#define XID_ALLOC(struct ) (xid++)
+#define XID_ALLOC() (xid++)
#define MAX_PACKET_SIZE 8192 /* Maximum UDP packet size */
/*
@@ -75,7 +74,7 @@ struct rpc_forward {
time_t rf_ttl; /* Time to live */
u_int rf_xid; /* Packet id */
u_int rf_oldid; /* Original packet id */
- fwd_fun rf_fwd; /* Forwarding function */
+ fwd_fun *rf_fwd; /* Forwarding function */
voidp rf_ptr;
struct sockaddr_in rf_sin;
};
@@ -94,7 +93,7 @@ static u_int xid;
static rpc_forward *
fwd_alloc(void)
{
- time_t now = clocktime();
+ time_t now = clocktime(NULL);
rpc_forward *p = 0, *p2;
/*
@@ -117,9 +116,7 @@ fwd_alloc(void)
* Call forwarding function to say that
* this message was junked.
*/
-#ifdef DEBUG
dlog("Re-using packet forwarding slot - id %#x", p->rf_xid);
-#endif /* DEBUG */
if (p->rf_fwd)
(*p->rf_fwd) (0, 0, 0, &p->rf_sin, p->rf_ptr, FALSE);
rem_que(&p->rf_q);
@@ -228,7 +225,7 @@ fwd_locate(u_int id)
* different address.
*/
int
-fwd_packet(int type_id, voidp pkt, int len, struct sockaddr_in *fwdto, struct sockaddr_in *replyto, voidp i, fwd_fun cb)
+fwd_packet(int type_id, char *pkt, int len, struct sockaddr_in *fwdto, struct sockaddr_in *replyto, opaque_t cb_arg, fwd_fun cb)
{
rpc_forward *p;
u_int *pkt_int;
@@ -247,36 +244,33 @@ fwd_packet(int type_id, voidp pkt, int len, struct sockaddr_in *fwdto, struct so
* Otherwise make sure the type_id is
* fully qualified by allocating an id here.
*/
-#ifdef DEBUG
switch (type_id & RPC_XID_MASK) {
case RPC_XID_PORTMAP:
- dlog("Sending PORTMAP request");
+ dlog("Sending PORTMAP request %#x", type_id);
break;
case RPC_XID_MOUNTD:
dlog("Sending MOUNTD request %#x", type_id);
break;
case RPC_XID_NFSPING:
- dlog("Sending NFS ping");
+ dlog("Sending NFS ping %#x", type_id);
+ break;
+ case RPC_XID_WEBNFS:
+ dlog("Sending WebNFS lookup %#x", type_id);
break;
default:
- dlog("UNKNOWN RPC XID");
+ dlog("UNKNOWN RPC XID %#x", type_id);
break;
}
-#endif /* DEBUG */
if (type_id & ~RPC_XID_MASK) {
p = fwd_locate(type_id);
if (p) {
-#ifdef DEBUG
dlog("Discarding earlier rpc fwd handle");
-#endif /* DEBUG */
fwd_free(p);
}
} else {
-#ifdef DEBUG
dlog("Allocating a new xid...");
-#endif /* DEBUG */
- type_id = MK_RPC_XID(type_id, XID_ALLOC(struct ));
+ type_id = MK_RPC_XID(type_id, XID_ALLOC());
}
p = fwd_alloc();
@@ -290,12 +284,13 @@ fwd_packet(int type_id, voidp pkt, int len, struct sockaddr_in *fwdto, struct so
/*
* Get the original packet id
*/
- p->rf_oldid = *pkt_int;
+ p->rf_oldid = ntohl(*pkt_int);
/*
* Replace with newly allocated id
*/
- p->rf_xid = *pkt_int = type_id;
+ p->rf_xid = type_id;
+ *pkt_int = htonl(type_id);
/*
* The sendto may fail if, for example, the route
@@ -307,9 +302,9 @@ fwd_packet(int type_id, voidp pkt, int len, struct sockaddr_in *fwdto, struct so
{
char dq[20];
if (p && fwdto)
- dlog("Sending packet id %#x to %s.%d",
+ dlog("Sending packet id %#x to %s:%d",
p->rf_xid,
- inet_dquad(dq, fwdto->sin_addr.s_addr),
+ inet_dquad(dq, sizeof(dq), fwdto->sin_addr.s_addr),
ntohs(fwdto->sin_port));
}
#endif /* DEBUG */
@@ -349,7 +344,7 @@ out:
p->rf_sin = *replyto;
else
memset((voidp) &p->rf_sin, 0, sizeof(p->rf_sin));
- p->rf_ptr = i;
+ p->rf_ptr = cb_arg;
return error;
}
@@ -364,6 +359,7 @@ fwd_reply(void)
int len;
u_int pkt[MAX_PACKET_SIZE / sizeof(u_int) + 1];
u_int *pkt_int;
+ u_int pkt_xid;
int rc;
rpc_forward *p;
struct sockaddr_in src_addr;
@@ -396,6 +392,12 @@ again:
rc = ud.udata.len;
else {
plog(XLOG_ERROR,"fwd_reply failed: t_errno=%d, errno=%d, flags=%d",t_errno,errno, flags);
+ /*
+ * Clear error indication, otherwise the error condition persists and
+ * amd gets into an infinite loop.
+ */
+ if (t_errno == TLOOK)
+ t_rcvuderr(fwd_sock, NULL);
}
#else /* not HAVE_TRANSPORT_TYPE_TLI */
rc = recvfrom(fwd_sock,
@@ -428,29 +430,29 @@ again:
* Find packet reference
*/
pkt_int = (u_int *) pkt;
+ pkt_xid = ntohl(*pkt_int);
-#ifdef DEBUG
- switch (*pkt_int & RPC_XID_MASK) {
+ switch (pkt_xid & RPC_XID_MASK) {
case RPC_XID_PORTMAP:
- dlog("Receiving PORTMAP reply");
+ dlog("Receiving PORTMAP reply %#x", pkt_xid);
break;
case RPC_XID_MOUNTD:
- dlog("Receiving MOUNTD reply %#x", *pkt_int);
+ dlog("Receiving MOUNTD reply %#x", pkt_xid);
break;
case RPC_XID_NFSPING:
- dlog("Receiving NFS ping %#x", *pkt_int);
+ dlog("Receiving NFS ping %#x", pkt_xid);
+ break;
+ case RPC_XID_WEBNFS:
+ dlog("Receiving WebNFS lookup %#x", pkt_xid);
break;
default:
- dlog("UNKNOWN RPC XID");
+ dlog("UNKNOWN RPC XID %#x", pkt_xid);
break;
}
-#endif /* DEBUG */
- p = fwd_locate(*pkt_int);
+ p = fwd_locate(pkt_xid);
if (!p) {
-#ifdef DEBUG
- dlog("Can't forward reply id %#x", *pkt_int);
-#endif /* DEBUG */
+ dlog("Can't forward reply id %#x", pkt_xid);
goto out;
}
@@ -459,7 +461,7 @@ again:
* Put the original message id back
* into the packet.
*/
- *pkt_int = p->rf_oldid;
+ *pkt_int = htonl(p->rf_oldid);
/*
* Call forwarding function
diff --git a/contrib/amd/amd/sched.c b/contrib/amd/amd/sched.c
index c32ef0f..8efe57a 100644
--- a/contrib/amd/amd/sched.c
+++ b/contrib/amd/amd/sched.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: sched.c,v 1.4.2.5 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/sched.c
*
*/
@@ -56,12 +55,12 @@
typedef struct pjob pjob;
struct pjob {
- qelem hdr; /* Linked list */
- int pid; /* Process ID of job */
- cb_fun cb_fun; /* Callback function */
- voidp cb_closure; /* Closure for callback */
+ qelem hdr; /* Linked list */
+ int pid; /* Process ID of job */
+ cb_fun *cb_fun; /* Callback function */
+ opaque_t cb_arg; /* Argument for callback */
int w; /* everyone these days uses int, not a "union wait" */
- voidp wchan; /* Wait channel */
+ wchan_t wchan; /* Wait channel */
};
/* globals */
@@ -94,12 +93,12 @@ rem_que(qelem *elem)
static pjob *
-sched_job(cb_fun cf, voidp ca)
+sched_job(cb_fun *cf, opaque_t ca)
{
pjob *p = ALLOC(struct pjob);
p->cb_fun = cf;
- p->cb_closure = ca;
+ p->cb_arg = ca;
/*
* Now place on wait queue
@@ -115,7 +114,7 @@ sched_job(cb_fun cf, voidp ca)
* cf: Continuation function (ca is its arguments)
*/
void
-run_task(task_fun tf, voidp ta, cb_fun cf, voidp ca)
+run_task(task_fun *tf, opaque_t ta, cb_fun *cf, opaque_t ca)
{
pjob *p = sched_job(cf, ca);
#ifdef HAVE_SIGACTION
@@ -124,7 +123,7 @@ run_task(task_fun tf, voidp ta, cb_fun cf, voidp ca)
int mask;
#endif /* not HAVE_SIGACTION */
- p->wchan = (voidp) p;
+ p->wchan = (wchan_t) p;
#ifdef HAVE_SIGACTION
sigemptyset(&new); /* initialize signal set we wish to block */
@@ -143,7 +142,7 @@ run_task(task_fun tf, voidp ta, cb_fun cf, voidp ca)
return;
}
- /* child code runs here, parent have returned to caller */
+ /* child code runs here, parent has returned to caller */
exit((*tf) (ta));
/* firewall... */
@@ -155,19 +154,17 @@ run_task(task_fun tf, voidp ta, cb_fun cf, voidp ca)
* Schedule a task to be run when woken up
*/
void
-sched_task(cb_fun cf, voidp ca, voidp wchan)
+sched_task(cb_fun *cf, opaque_t ca, wchan_t wchan)
{
/*
* Allocate a new task
*/
pjob *p = sched_job(cf, ca);
-#ifdef DEBUG
- dlog("SLEEP on %#lx", (unsigned long) wchan);
-#endif /* DEBUG */
+ dlog("SLEEP on %p", wchan);
p->wchan = wchan;
p->pid = 0;
- memset((voidp) &p->w, 0, sizeof(p->w));
+ p->w = 0; /* was memset (when ->w was union) */
}
@@ -181,7 +178,7 @@ wakeupjob(pjob *p)
void
-wakeup(voidp wchan)
+wakeup(wchan_t wchan)
{
pjob *p, *p2;
@@ -189,7 +186,7 @@ wakeup(voidp wchan)
return;
/*
- * Can't user ITER() here because
+ * Can't use ITER() here because
* wakeupjob() juggles the list.
*/
for (p = AM_FIRST(pjob, &proc_wait_list);
@@ -203,9 +200,20 @@ wakeup(voidp wchan)
void
-wakeup_task(int rc, int term, voidp cl)
+wakeup_task(int rc, int term, wchan_t wchan)
{
- wakeup(cl);
+ wakeup(wchan);
+}
+
+
+wchan_t
+get_mntfs_wchan(mntfs *mf)
+{
+ if (mf &&
+ mf->mf_ops &&
+ mf->mf_ops->get_wchan)
+ return mf->mf_ops->get_wchan(mf);
+ return mf;
}
@@ -236,9 +244,9 @@ do_task_notify(void)
*/
if (p->cb_fun) {
/* these two trigraphs will ensure compatibility with strict POSIX.1 */
- (*p->cb_fun) (WIFEXITED(p->w) ? WEXITSTATUS(p->w) : 0,
- WIFSIGNALED(p->w) ? WTERMSIG(p->w) : 0,
- p->cb_closure);
+ p->cb_fun(WIFEXITED(p->w) ? WEXITSTATUS(p->w) : 0,
+ WIFSIGNALED(p->w) ? WTERMSIG(p->w) : 0,
+ p->cb_arg);
}
XFREE(p);
}
@@ -261,11 +269,9 @@ sigchld(int sig)
if (WIFSIGNALED(w))
plog(XLOG_ERROR, "Process %d exited with signal %d",
pid, WTERMSIG(w));
-#ifdef DEBUG
else
dlog("Process %d exited with status %d",
pid, WEXITSTATUS(w));
-#endif /* DEBUG */
for (p = AM_FIRST(pjob, &proc_wait_list);
p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list);
@@ -277,18 +283,16 @@ sigchld(int sig)
}
} /* end of for loop */
-#ifdef DEBUG
- if (!p)
+ if (p == HEAD(pjob, &proc_wait_list))
dlog("can't locate task block for pid %d", pid);
-#endif /* DEBUG */
/*
* Must count down children inside the while loop, otherwise we won't
- * count them all, and NumChild (and later backoff) will be set
+ * count them all, and NumChildren (and later backoff) will be set
* incorrectly. SH/RUNIT 940519.
*/
- if (--NumChild < 0)
- NumChild = 0;
+ if (--NumChildren < 0)
+ NumChildren = 0;
} /* end of "while wait..." loop */
#ifdef REINSTALL_SIGNAL_HANDLER
diff --git a/contrib/amd/amd/srvr_amfs_auto.c b/contrib/amd/amd/srvr_amfs_auto.c
index 70c93bf..4742cf6 100644
--- a/contrib/amd/amd/srvr_amfs_auto.c
+++ b/contrib/amd/amd/srvr_amfs_auto.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1989 Jan-Simon Pendry
* Copyright (c) 1989 Imperial College of Science, Technology & Medicine
* Copyright (c) 1989 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: srvr_amfs_auto.c,v 1.3.2.6 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/srvr_amfs_auto.c
*
*/
@@ -53,9 +52,9 @@
#include <amd.h>
/* globals */
-qelem amfs_auto_srvr_list = {&amfs_auto_srvr_list, &amfs_auto_srvr_list};
/* statics */
+static qelem amfs_auto_srvr_list = {&amfs_auto_srvr_list, &amfs_auto_srvr_list};
static fserver *localhost;
@@ -63,7 +62,7 @@ static fserver *localhost;
* Find an nfs server for the local host
*/
fserver *
-find_amfs_auto_srvr(mntfs *mf)
+amfs_generic_find_srvr(mntfs *mf)
{
fserver *fs = localhost;
@@ -73,8 +72,8 @@ find_amfs_auto_srvr(mntfs *mf)
fs->fs_host = strdup("localhost");
fs->fs_ip = 0;
fs->fs_cid = 0;
- fs->fs_pinger = 0;
- fs->fs_flags = FSF_VALID;
+ fs->fs_pinger = AM_PINGER;
+ fs->fs_flags = FSF_VALID | FSF_PING_UNINIT;
fs->fs_type = "local";
fs->fs_private = 0;
fs->fs_prfree = 0;
@@ -119,9 +118,7 @@ timeout_srvr(voidp v)
* we are free to remove this node
*/
if (fs->fs_refc == 0) {
-#ifdef DEBUG
dlog("Deleting file server %s", fs->fs_host);
-#endif /* DEBUG */
if (fs->fs_flags & FSF_WANT)
wakeup_srvr(fs);
@@ -167,11 +164,9 @@ free_srvr(fserver *fs)
* removed in AM_TTL seconds if no
* other mntfs is referencing it.
*/
- int ttl = (fs->fs_flags & (FSF_DOWN | FSF_ERROR)) ? 19 : AM_TTL;
+ int ttl = (FSRV_ERROR(fs) || FSRV_ISDOWN(fs)) ? 19 : AM_TTL;
-#ifdef DEBUG
dlog("Last hard reference to file server %s - will timeout in %ds", fs->fs_host, ttl);
-#endif /* DEBUG */
if (fs->fs_cid) {
untimeout(fs->fs_cid);
/*
diff --git a/contrib/amd/amd/srvr_nfs.c b/contrib/amd/amd/srvr_nfs.c
index 48e0789..0c74a65 100644
--- a/contrib/amd/amd/srvr_nfs.c
+++ b/contrib/amd/amd/srvr_nfs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: srvr_nfs.c,v 1.7.2.11 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/srvr_nfs.c
*
*/
@@ -72,8 +71,6 @@
*/
#endif /* (FAST_NFS_PING * MAX_ALLOWED_PINGS) >= ALLOWED_MOUNT_TIME */
-#define NPXID_ALLOC(struct ) (++np_xid)
-
/* structures and typedefs */
typedef struct nfs_private {
u_short np_mountd; /* Mount daemon port number */
@@ -88,9 +85,16 @@ typedef struct nfs_private {
qelem nfs_srvr_list = {&nfs_srvr_list, &nfs_srvr_list};
/* statics */
-static int np_xid; /* For NFS pings */
-static int ping_len;
-static char ping_buf[sizeof(struct rpc_msg) + 32];
+static int global_xid; /* For NFS pings */
+#define XID_ALLOC() (++global_xid)
+
+#ifdef HAVE_FS_NFS3
+# define NUM_NFS_VERS 2
+#else /* not HAVE_FS_NFS3 */
+# define NUM_NFS_VERS 1
+#endif /* not HAVE_FS_NFS3 */
+static int ping_len[NUM_NFS_VERS];
+static char ping_buf[NUM_NFS_VERS][sizeof(struct rpc_msg) + 32];
#if defined(MNTTAB_OPT_PROTO) || defined(HAVE_FS_NFS3)
/*
@@ -99,6 +103,8 @@ static char ping_buf[sizeof(struct rpc_msg) + 32];
* Note that Solaris 8 and newer NetBSD systems are switching to UDP first,
* so this order may have to be adjusted for Amd in the future once more
* vendors make that change. -Erez 11/24/2000
+ *
+ * Or we might simply make this is a platform-specific order. -Ion 09/13/2003
*/
static char *protocols[] = { "tcp", "udp", NULL };
#endif /* defined(MNTTAB_OPT_PROTO) || defined(HAVE_FS_NFS3) */
@@ -107,20 +113,21 @@ static char *protocols[] = { "tcp", "udp", NULL };
static void nfs_keepalive(voidp);
-
/*
- * Flush any cached data
+ * Flush cached data for an fserver (or for all, if fs==NULL)
*/
void
-flush_srvr_nfs_cache(void)
+flush_srvr_nfs_cache(fserver *fs)
{
- fserver *fs = 0;
+ fserver *fs2 = NULL;
- ITER(fs, fserver, &nfs_srvr_list) {
- nfs_private *np = (nfs_private *) fs->fs_private;
- if (np) {
- np->np_mountd_inval = TRUE;
- np->np_error = -1;
+ ITER(fs2, fserver, &nfs_srvr_list) {
+ if (fs == NULL || fs == fs2) {
+ nfs_private *np = (nfs_private *) fs2->fs_private;
+ if (np) {
+ np->np_mountd_inval = TRUE;
+ np->np_error = -1;
+ }
}
}
}
@@ -130,7 +137,7 @@ flush_srvr_nfs_cache(void)
* Startup the NFS ping for a particular version.
*/
static void
-start_ping(u_long nfs_version)
+create_ping_payload(u_long nfs_version)
{
XDR ping_xdr;
struct rpc_msg ping_msg;
@@ -140,16 +147,16 @@ start_ping(u_long nfs_version)
*/
if (nfs_version == 0) {
nfs_version = NFS_VERSION;
- plog(XLOG_WARNING, "start_ping: nfs_version = 0 fixed");
- }
- plog(XLOG_INFO, "start_ping: nfs_version: %d", (int) nfs_version);
+ plog(XLOG_WARNING, "create_ping_payload: nfs_version = 0, changed to 2");
+ } else
+ plog(XLOG_INFO, "create_ping_payload: nfs_version: %d", (int) nfs_version);
rpc_msg_init(&ping_msg, NFS_PROGRAM, nfs_version, NFSPROC_NULL);
/*
* Create an XDR endpoint
*/
- xdrmem_create(&ping_xdr, ping_buf, sizeof(ping_buf), XDR_ENCODE);
+ xdrmem_create(&ping_xdr, ping_buf[nfs_version - NFS_VERSION], sizeof(ping_buf[0]), XDR_ENCODE);
/*
* Create the NFS ping message
@@ -161,7 +168,7 @@ start_ping(u_long nfs_version)
/*
* Find out how long it is
*/
- ping_len = xdr_getpos(&ping_xdr);
+ ping_len[nfs_version - NFS_VERSION] = xdr_getpos(&ping_xdr);
/*
* Destroy the XDR endpoint - we don't need it anymore
@@ -183,7 +190,7 @@ got_portmap(voidp pkt, int len, struct sockaddr_in *sa, struct sockaddr_in *ia,
* Find which fileserver we are talking about
*/
ITER(fs, fserver, &nfs_srvr_list)
- if (fs == fs2)
+ if (fs == fs2)
break;
if (fs == fs2) {
@@ -192,9 +199,7 @@ got_portmap(voidp pkt, int len, struct sockaddr_in *sa, struct sockaddr_in *ia,
nfs_private *np = (nfs_private *) fs->fs_private;
if (!error && port) {
-#ifdef DEBUG
dlog("got port (%d) for mountd on %s", (int) port, fs->fs_host);
-#endif /* DEBUG */
/*
* Grab the port number. Portmap sends back
* an u_long in native ordering, so it
@@ -205,10 +210,8 @@ got_portmap(voidp pkt, int len, struct sockaddr_in *sa, struct sockaddr_in *ia,
np->np_mountd_inval = FALSE;
np->np_error = 0;
} else {
-#ifdef DEBUG
dlog("Error fetching port for mountd on %s", fs->fs_host);
dlog("\t error=%d, port=%d", error, (int) port);
-#endif /* DEBUG */
/*
* Almost certainly no mountd running on remote host
*/
@@ -218,13 +221,9 @@ got_portmap(voidp pkt, int len, struct sockaddr_in *sa, struct sockaddr_in *ia,
if (fs->fs_flags & FSF_WANT)
wakeup_srvr(fs);
} else if (done) {
-#ifdef DEBUG
dlog("Got portmap for old port request");
-#endif /* DEBUG */
} else {
-#ifdef DEBUG
dlog("portmap request timed out");
-#endif /* DEBUG */
}
}
@@ -258,7 +257,7 @@ call_portmap(fserver *fs, AUTH *auth, u_long prog, u_long vers, u_long prot)
memset((voidp) &sin, 0, sizeof(sin));
sin = *fs->fs_ip;
sin.sin_port = htons(PMAPPORT);
- error = fwd_packet(RPC_XID_PORTMAP, (voidp) iobuf, len,
+ error = fwd_packet(RPC_XID_PORTMAP, iobuf, len,
&sin, &sin, (voidp) fs, got_portmap);
} else {
error = -len;
@@ -274,6 +273,12 @@ recompute_portmap(fserver *fs)
int error;
u_long mnt_version;
+ /*
+ * No portmap calls for pure WebNFS servers.
+ */
+ if (fs->fs_flags & FSF_WEBNFS)
+ return;
+
if (nfs_auth)
error = 0;
else
@@ -288,10 +293,11 @@ recompute_portmap(fserver *fs)
if (fs->fs_version == 0)
plog(XLOG_WARNING, "recompute_portmap: nfs_version = 0 fixed");
- plog(XLOG_INFO, "recompute_portmap: NFS version %d", (int) fs->fs_version);
+ plog(XLOG_INFO, "recompute_portmap: NFS version %d on %s",
+ (int) fs->fs_version, fs->fs_host);
#ifdef HAVE_FS_NFS3
if (fs->fs_version == NFS_VERSION3)
- mnt_version = MOUNTVERS3;
+ mnt_version = AM_MOUNTVERS3;
else
#endif /* HAVE_FS_NFS3 */
mnt_version = MOUNTVERS;
@@ -301,19 +307,61 @@ recompute_portmap(fserver *fs)
}
+int
+get_mountd_port(fserver *fs, u_short *port, wchan_t wchan)
+{
+ int error = -1;
+ if (FSRV_ISDOWN(fs))
+ return EWOULDBLOCK;
+
+ if (FSRV_ISUP(fs)) {
+ nfs_private *np = (nfs_private *) fs->fs_private;
+ if (np->np_error == 0) {
+ *port = np->np_mountd;
+ error = 0;
+ } else {
+ error = np->np_error;
+ }
+ /*
+ * Now go get the port mapping again in case it changed.
+ * Note that it is used even if (np_mountd_inval)
+ * is True. The flag is used simply as an
+ * indication that the mountd may be invalid, not
+ * that it is known to be invalid.
+ */
+ if (np->np_mountd_inval)
+ recompute_portmap(fs);
+ else
+ np->np_mountd_inval = TRUE;
+ }
+ if (error < 0 && wchan && !(fs->fs_flags & FSF_WANT)) {
+ /*
+ * If a wait channel is supplied, and no
+ * error has yet occurred, then arrange
+ * that a wakeup is done on the wait channel,
+ * whenever a wakeup is done on this fs node.
+ * Wakeup's are done on the fs node whenever
+ * it changes state - thus causing control to
+ * come back here and new, better things to happen.
+ */
+ fs->fs_flags |= FSF_WANT;
+ sched_task(wakeup_task, wchan, (wchan_t) fs);
+ }
+ return error;
+}
+
+
/*
* This is called when we get a reply to an RPC ping.
* The value of id was taken from the nfs_private
* structure when the ping was transmitted.
*/
static void
-nfs_pinged(voidp pkt, int len, struct sockaddr_in *sp, struct sockaddr_in *tsp, voidp idv, int done)
+nfs_keepalive_callback(voidp pkt, int len, struct sockaddr_in *sp, struct sockaddr_in *tsp, voidp idv, int done)
{
- int xid = (long) idv; /* for 64-bit archs */
+ int xid = (long) idv; /* cast needed for 64-bit archs */
fserver *fs;
-#ifdef DEBUG
int found_map = 0;
-#endif /* DEBUG */
if (!done)
return;
@@ -336,19 +384,15 @@ nfs_pinged(voidp pkt, int len, struct sockaddr_in *sp, struct sockaddr_in *tsp,
} else {
if (np->np_ping > 1)
srvrlog(fs, "ok");
-#ifdef DEBUG
else
srvrlog(fs, "starts up");
-#endif /* DEBUG */
fs->fs_flags |= FSF_VALID;
}
map_flush_srvr(fs);
} else {
if (fs->fs_flags & FSF_VALID) {
-#ifdef DEBUG
dlog("file server %s type nfs is still up", fs->fs_host);
-#endif /* DEBUG */
} else {
if (np->np_ping > 1)
srvrlog(fs, "ok");
@@ -365,13 +409,13 @@ nfs_pinged(voidp pkt, int len, struct sockaddr_in *sp, struct sockaddr_in *tsp,
/*
* Update ttl for this server
*/
- np->np_ttl = clocktime() +
+ np->np_ttl = clocktime(NULL) +
(MAX_ALLOWED_PINGS - 1) * FAST_NFS_PING + fs->fs_pinger - 1;
/*
* New RPC xid...
*/
- np->np_xid = NPXID_ALLOC(struct );
+ np->np_xid = XID_ALLOC();
/*
* Failed pings is zero...
@@ -384,17 +428,53 @@ nfs_pinged(voidp pkt, int len, struct sockaddr_in *sp, struct sockaddr_in *tsp,
if (np->np_mountd_inval)
recompute_portmap(fs);
-#ifdef DEBUG
found_map++;
-#endif /* DEBUG */
break;
}
}
-#ifdef DEBUG
if (found_map == 0)
dlog("Spurious ping packet");
-#endif /* DEBUG */
+}
+
+
+static void
+check_fs_addr_change(fserver *fs)
+{
+ struct hostent *hp = NULL;
+ struct in_addr ia;
+ char *old_ipaddr, *new_ipaddr;
+
+ hp = gethostbyname(fs->fs_host);
+ if (!hp ||
+ hp->h_addrtype != AF_INET ||
+ !STREQ((char *) hp->h_name, fs->fs_host) ||
+ memcmp((voidp) &fs->fs_ip->sin_addr,
+ (voidp) hp->h_addr,
+ sizeof(fs->fs_ip->sin_addr)) == 0)
+ return;
+ /* if got here: downed server changed IP address */
+ old_ipaddr = strdup(inet_ntoa(fs->fs_ip->sin_addr));
+ memmove((voidp) &ia, (voidp) hp->h_addr, sizeof(struct in_addr));
+ new_ipaddr = inet_ntoa(ia); /* ntoa uses static buf */
+ plog(XLOG_WARNING, "EZK: down fileserver %s changed ip: %s -> %s",
+ fs->fs_host, old_ipaddr, new_ipaddr);
+ XFREE(old_ipaddr);
+ /* copy new IP addr */
+ memmove((voidp) &fs->fs_ip->sin_addr,
+ (voidp) hp->h_addr,
+ sizeof(fs->fs_ip->sin_addr));
+ /* XXX: do we need to un/set these flags? */
+ fs->fs_flags &= ~FSF_DOWN;
+ fs->fs_flags |= FSF_VALID | FSF_WANT;
+ map_flush_srvr(fs); /* XXX: a race with flush_srvr_nfs_cache? */
+ flush_srvr_nfs_cache(fs);
+ fs->fs_flags |= FSF_FORCE_UNMOUNT;
+
+#if 0
+ flush_nfs_fhandle_cache(fs); /* done in caller: nfs_keepalive_timeout */
+ /* XXX: need to purge nfs_private so that somehow it will get re-initialized? */
+#endif
}
@@ -402,7 +482,7 @@ nfs_pinged(voidp pkt, int len, struct sockaddr_in *sp, struct sockaddr_in *tsp,
* Called when no ping-reply received
*/
static void
-nfs_timed_out(voidp v)
+nfs_keepalive_timeout(voidp v)
{
fserver *fs = v;
nfs_private *np = (nfs_private *) fs->fs_private;
@@ -423,11 +503,9 @@ nfs_timed_out(voidp v)
/*
* If ttl has expired then guess that it is dead
*/
- if (np->np_ttl < clocktime()) {
+ if (np->np_ttl < clocktime(NULL)) {
int oflags = fs->fs_flags;
-#ifdef DEBUG
dlog("ttl has expired");
-#endif /* DEBUG */
if ((fs->fs_flags & FSF_DOWN) == 0) {
/*
* Server was up, but is now down.
@@ -441,14 +519,13 @@ nfs_timed_out(voidp v)
*/
flush_nfs_fhandle_cache(fs);
np->np_error = -1;
+ check_fs_addr_change(fs); /* check if IP addr of fserver changed */
} else {
/*
* Known to be down
*/
-#ifdef DEBUG
if ((fs->fs_flags & FSF_VALID) == 0)
srvrlog(fs, "starts down");
-#endif /* DEBUG */
fs->fs_flags |= FSF_VALID;
}
if (oflags != fs->fs_flags && (fs->fs_flags & FSF_WANT))
@@ -458,17 +535,15 @@ nfs_timed_out(voidp v)
*/
np->np_ping = 0;
} else {
-#ifdef DEBUG
if (np->np_ping > 1)
dlog("%d pings to %s failed - at most %d allowed", np->np_ping, fs->fs_host, MAX_ALLOWED_PINGS);
-#endif /* DEBUG */
}
/*
* New RPC xid, so any late responses to the previous ping
* get ignored...
*/
- np->np_xid = NPXID_ALLOC(struct );
+ np->np_xid = XID_ALLOC();
/*
* Run keepalive again
@@ -492,19 +567,19 @@ nfs_keepalive(voidp v)
* Send an NFS ping to this node
*/
- if (ping_len == 0)
- start_ping(fs->fs_version);
+ if (ping_len[fs->fs_version - NFS_VERSION] == 0)
+ create_ping_payload(fs->fs_version);
/*
* Queue the packet...
*/
error = fwd_packet(MK_RPC_XID(RPC_XID_NFSPING, np->np_xid),
- (voidp) ping_buf,
- ping_len,
+ ping_buf[fs->fs_version - NFS_VERSION],
+ ping_len[fs->fs_version - NFS_VERSION],
fs->fs_ip,
(struct sockaddr_in *) 0,
- (voidp) ((long) np->np_xid), /* for 64-bit archs */
- nfs_pinged);
+ (voidp) ((long) np->np_xid), /* cast needed for 64-bit archs */
+ nfs_keepalive_callback);
/*
* See if a hard error occurred
@@ -517,7 +592,7 @@ nfs_keepalive(voidp v)
np->np_ping = MAX_ALLOWED_PINGS; /* immediately down */
np->np_ttl = (time_t) 0;
/*
- * This causes an immediate call to nfs_timed_out
+ * This causes an immediate call to nfs_keepalive_timeout
* whenever the server was thought to be up.
* See +++ below.
*/
@@ -525,15 +600,13 @@ nfs_keepalive(voidp v)
break;
case 0:
-#ifdef DEBUG
dlog("Sent NFS ping to %s", fs->fs_host);
-#endif /* DEBUG */
break;
}
/*
* Back off the ping interval if we are not getting replies and
- * the remote system is know to be down.
+ * the remote system is known to be down.
*/
switch (fs->fs_flags & (FSF_DOWN | FSF_VALID)) {
case FSF_VALID: /* Up */
@@ -550,73 +623,41 @@ nfs_keepalive(voidp v)
break;
}
-#ifdef DEBUG
dlog("NFS timeout in %d seconds", fstimeo);
-#endif /* DEBUG */
- fs->fs_cid = timeout(fstimeo, nfs_timed_out, (voidp) fs);
-}
-
-
-int
-nfs_srvr_port(fserver *fs, u_short *port, voidp wchan)
-{
- int error = -1;
- if ((fs->fs_flags & FSF_VALID) == FSF_VALID) {
- if ((fs->fs_flags & FSF_DOWN) == 0) {
- nfs_private *np = (nfs_private *) fs->fs_private;
- if (np->np_error == 0) {
- *port = np->np_mountd;
- error = 0;
- } else {
- error = np->np_error;
- }
- /*
- * Now go get the port mapping again in case it changed.
- * Note that it is used even if (np_mountd_inval)
- * is True. The flag is used simply as an
- * indication that the mountd may be invalid, not
- * that it is known to be invalid.
- */
- if (np->np_mountd_inval)
- recompute_portmap(fs);
- else
- np->np_mountd_inval = TRUE;
- } else {
- error = EWOULDBLOCK;
- }
- }
- if (error < 0 && wchan && !(fs->fs_flags & FSF_WANT)) {
- /*
- * If a wait channel is supplied, and no
- * error has yet occurred, then arrange
- * that a wakeup is done on the wait channel,
- * whenever a wakeup is done on this fs node.
- * Wakeup's are done on the fs node whenever
- * it changes state - thus causing control to
- * come back here and new, better things to happen.
- */
- fs->fs_flags |= FSF_WANT;
- sched_task(wakeup_task, wchan, (voidp) fs);
- }
- return error;
+ fs->fs_cid = timeout(fstimeo, nfs_keepalive_timeout, (voidp) fs);
}
static void
start_nfs_pings(fserver *fs, int pingval)
{
- if (fs->fs_flags & FSF_PINGING) {
-#ifdef DEBUG
- dlog("Already running pings to %s", fs->fs_host);
-#endif /* DEBUG */
+ if (pingval == 0) /* could be because ping mnt option not found */
+ pingval = AM_PINGER;
+ /* if pings haven't been initalized, then init them for first time */
+ if (fs->fs_flags & FSF_PING_UNINIT) {
+ fs->fs_flags &= ~FSF_PING_UNINIT;
+ plog(XLOG_INFO, "initializing %s's pinger to %d sec", fs->fs_host, pingval);
+ goto do_pings;
+ }
+
+ if ((fs->fs_flags & FSF_PINGING) && fs->fs_pinger == pingval) {
+ dlog("already running pings to %s", fs->fs_host);
return;
}
+ /* if got here, then we need to update the ping value */
+ plog(XLOG_INFO, "changing %s's ping value from %d%s to %d%s",
+ fs->fs_host,
+ fs->fs_pinger, (fs->fs_pinger < 0 ? " (off)" : ""),
+ pingval, (pingval < 0 ? " (off)" : ""));
+ do_pings:
+ fs->fs_pinger = pingval;
+
if (fs->fs_cid)
untimeout(fs->fs_cid);
if (pingval < 0) {
- srvrlog(fs, "wired up");
+ srvrlog(fs, "wired up (pings disabled)");
fs->fs_flags |= FSF_VALID;
fs->fs_flags &= ~FSF_DOWN;
} else {
@@ -633,17 +674,18 @@ fserver *
find_nfs_srvr(mntfs *mf)
{
char *host = mf->mf_fo->opt_rhost;
- char *nfs_proto = NULL;
fserver *fs;
int pingval;
mntent_t mnt;
nfs_private *np;
- struct hostent *hp = 0;
- struct sockaddr_in *ip;
+ struct hostent *hp = NULL;
+ struct sockaddr_in *ip = NULL;
u_long nfs_version = 0; /* default is no version specified */
-#ifdef MNTTAB_OPT_PROTO
- char *rfsname = mf->mf_fo->opt_rfs;
-#endif /* MNTTAB_OPT_PROTO */
+ u_long best_nfs_version = 0;
+ char *nfs_proto = NULL; /* no IP protocol either */
+ int nfs_port = 0;
+ int nfs_port_opt = 0;
+ int fserver_is_down = 0;
/*
* Get ping interval from mount options.
@@ -653,49 +695,60 @@ find_nfs_srvr(mntfs *mf)
mnt.mnt_opts = mf->mf_mopts;
pingval = hasmntval(&mnt, "ping");
- /*
- * Get the NFS version from the mount options. This is used
- * to decide the highest NFS version to try.
- */
+ if (mf->mf_flags & MFF_NFS_SCALEDOWN) {
+ /*
+ * the server granted us a filehandle, but we were unable to mount it.
+ * therefore, scale down to NFSv2/UDP and try again.
+ */
+ nfs_version = NFS_VERSION;
+ nfs_proto = "udp";
+ plog(XLOG_WARNING, "find_nfs_srvr: NFS mount failed, trying again with NFSv2/UDP");
+ mf->mf_flags &= ~MFF_NFS_SCALEDOWN;
+ } else {
+ /*
+ * Get the NFS version from the mount options. This is used
+ * to decide the highest NFS version to try.
+ */
#ifdef MNTTAB_OPT_VERS
- nfs_version = hasmntval(&mnt, MNTTAB_OPT_VERS);
+ nfs_version = hasmntval(&mnt, MNTTAB_OPT_VERS);
#endif /* MNTTAB_OPT_VERS */
#ifdef MNTTAB_OPT_PROTO
- {
- char *proto_opt = hasmnteq(&mnt, MNTTAB_OPT_PROTO);
- if (proto_opt) {
- char **p;
- for (p = protocols; *p; p ++)
- if (NSTREQ(proto_opt, *p, strlen(*p))) {
- nfs_proto = *p;
- break;
- }
- if (*p == NULL)
- plog(XLOG_WARNING, "ignoring unknown protocol option for %s:%s",
- host, rfsname);
+ {
+ char *proto_opt = hasmnteq(&mnt, MNTTAB_OPT_PROTO);
+ if (proto_opt) {
+ char **p;
+ for (p = protocols; *p; p++)
+ if (NSTREQ(proto_opt, *p, strlen(*p))) {
+ nfs_proto = *p;
+ break;
+ }
+ if (*p == NULL)
+ plog(XLOG_WARNING, "ignoring unknown protocol option for %s:%s",
+ host, mf->mf_fo->opt_rfs);
+ }
}
- }
#endif /* MNTTAB_OPT_PROTO */
#ifdef HAVE_NFS_NFSV2_H
- /* allow overriding if nfsv2 option is specified in mount options */
- if (hasmntopt(&mnt, "nfsv2")) {
- nfs_version = (u_long) 2; /* nullify any ``vers=X'' statements */
- nfs_proto = "udp"; /* nullify any ``proto=tcp'' statements */
- plog(XLOG_WARNING, "found compatiblity option \"nfsv2\": set options vers=2,proto=udp for host %s", host);
- }
+ /* allow overriding if nfsv2 option is specified in mount options */
+ if (amu_hasmntopt(&mnt, "nfsv2")) {
+ nfs_version = NFS_VERSION;/* nullify any ``vers=X'' statements */
+ nfs_proto = "udp"; /* nullify any ``proto=tcp'' statements */
+ plog(XLOG_WARNING, "found compatibility option \"nfsv2\": set options vers=2,proto=udp for host %s", host);
+ }
#endif /* HAVE_NFS_NFSV2_H */
- /* check if we globally overridden the NFS version/protocol */
- if (gopt.nfs_vers) {
- nfs_version = gopt.nfs_vers;
- plog(XLOG_INFO, "find_nfs_srvr: force NFS version to %d",
- (int) nfs_version);
- }
- if (gopt.nfs_proto) {
- nfs_proto = gopt.nfs_proto;
- plog(XLOG_INFO, "find_nfs_srvr: force NFS protocol transport to %s", nfs_proto);
+ /* check if we've globally overridden the NFS version/protocol */
+ if (gopt.nfs_vers) {
+ nfs_version = gopt.nfs_vers;
+ plog(XLOG_INFO, "find_nfs_srvr: force NFS version to %d",
+ (int) nfs_version);
+ }
+ if (gopt.nfs_proto) {
+ nfs_proto = gopt.nfs_proto;
+ plog(XLOG_INFO, "find_nfs_srvr: force NFS protocol transport to %s", nfs_proto);
+ }
}
/*
@@ -718,72 +771,148 @@ find_nfs_srvr(mntfs *mf)
case AF_INET:
ip = ALLOC(struct sockaddr_in);
memset((voidp) ip, 0, sizeof(*ip));
+ /* as per POSIX, sin_len need not be set (used internally by kernel) */
ip->sin_family = AF_INET;
memmove((voidp) &ip->sin_addr, (voidp) hp->h_addr, sizeof(ip->sin_addr));
-
- ip->sin_port = htons(NFS_PORT);
break;
default:
- ip = 0;
- break;
+ plog(XLOG_USER, "No IP address for host %s", host);
+ goto no_dns;
}
} else {
plog(XLOG_USER, "Unknown host: %s", host);
- ip = 0;
+ goto no_dns;
}
/*
- * Get the NFS Version, and verify server is up. Probably no
- * longer need to start server down below.
+ * This may not be the best way to do things, but it really doesn't make
+ * sense to query a file server which is marked as 'down' for any
+ * version/proto combination.
*/
- if (ip) {
+ ITER(fs, fserver, &nfs_srvr_list) {
+ if (FSRV_ISDOWN(fs) &&
+ STREQ(host, fs->fs_host)) {
+ plog(XLOG_WARNING, "fileserver %s is already hung - not running NFS proto/version discovery", host);
+ fs->fs_refc++;
+ if (ip)
+ XFREE(ip);
+ return fs;
+ }
+ }
+
+ /*
+ * Get the NFS Version, and verify server is up.
+ * If the client only supports NFSv2, hardcode it but still try to
+ * contact the remote portmapper to see if the service is running.
+ */
+#ifndef HAVE_FS_NFS3
+ nfs_version = NFS_VERSION;
+ nfs_proto = "udp";
+ plog(XLOG_INFO, "The client supports only NFS(2,udp)");
+#endif /* not HAVE_FS_NFS3 */
+
+
+ if (amu_hasmntopt(&mnt, MNTTAB_OPT_PUBLIC)) {
+ /*
+ * Use WebNFS to obtain file handles.
+ */
+ mf->mf_flags |= MFF_WEBNFS;
+ plog(XLOG_INFO, "%s option used, NOT contacting the portmapper on %s",
+ MNTTAB_OPT_PUBLIC, host);
+ /*
+ * Prefer NFSv3/tcp if the client supports it (cf. RFC 2054, 7).
+ */
+ if (!nfs_version) {
#ifdef HAVE_FS_NFS3
+ nfs_version = NFS_VERSION3;
+#else /* not HAVE_FS_NFS3 */
+ nfs_version = NFS_VERSION;
+#endif /* not HAVE_FS_NFS3 */
+ plog(XLOG_INFO, "No NFS version specified, will use NFSv%d",
+ (int) nfs_version);
+ }
+ if (!nfs_proto) {
+#if defined(MNTTAB_OPT_PROTO) || defined(HAVE_FS_NFS3)
+ nfs_proto = "tcp";
+#else /* not defined(MNTTAB_OPT_PROTO) || defined(HAVE_FS_NFS3) */
+ nfs_proto = "udp";
+#endif /* not defined(MNTTAB_OPT_PROTO) || defined(HAVE_FS_NFS3) */
+ plog(XLOG_INFO, "No NFS protocol transport specified, will use %s",
+ nfs_proto);
+ }
+ } else {
/*
* Find the best combination of NFS version and protocol.
* When given a choice, use the highest available version,
* and use TCP over UDP if available.
*/
- if (nfs_proto)
- nfs_version = get_nfs_version(host, ip, nfs_version, nfs_proto);
- else {
- int best_nfs_version = 0;
- int proto_nfs_version;
- char **p;
-
- for (p = protocols; *p; p++) {
- proto_nfs_version = get_nfs_version(host, ip, nfs_version, *p);
-
- if (proto_nfs_version > best_nfs_version) {
- best_nfs_version = proto_nfs_version;
- nfs_proto = *p;
+ if (check_pmap_up(host, ip)) {
+ if (nfs_proto) {
+ best_nfs_version = get_nfs_version(host, ip, nfs_version, nfs_proto);
+ nfs_port = ip->sin_port;
+ }
+#ifdef MNTTAB_OPT_PROTO
+ else {
+ u_int proto_nfs_version;
+ char **p;
+
+ for (p = protocols; *p; p++) {
+ proto_nfs_version = get_nfs_version(host, ip, nfs_version, *p);
+
+ if (proto_nfs_version > best_nfs_version) {
+ best_nfs_version = proto_nfs_version;
+ nfs_proto = *p;
+ nfs_port = ip->sin_port;
+ }
}
}
- nfs_version = best_nfs_version;
+#endif /* MNTTAB_OPT_PROTO */
+ } else {
+ plog(XLOG_INFO, "portmapper service not running on %s", host);
}
- if (!nfs_version) {
+ /* use the portmapper results only nfs_version is not set yet */
+ if (!best_nfs_version) {
/*
* If the NFS server is down or does not support the portmapper call
* (such as certain Novell NFS servers) we mark it as version 2 and we
- * let the nfs code deal with the case that is down. If when the
- * server comes back up, it can support NFS V.3 and/or TCP, it will
+ * let the nfs code deal with the case when it is down. If/when the
+ * server comes back up and it can support NFSv3 and/or TCP, it will
* use those.
*/
- nfs_version = NFS_VERSION;
- nfs_proto = "udp";
+ if (nfs_version == 0) {
+ nfs_version = NFS_VERSION;
+ nfs_proto = "udp";
+ }
+ plog(XLOG_INFO, "NFS service not running on %s", host);
+ fserver_is_down = 1;
+ } else {
+ if (nfs_version == 0)
+ nfs_version = best_nfs_version;
+ plog(XLOG_INFO, "Using NFS version %d, protocol %s on host %s",
+ (int) nfs_version, nfs_proto, host);
}
-#else /* not HAVE_FS_NFS3 */
- nfs_version = NFS_VERSION;
-#endif /* not HAVE_FS_NFS3 */
}
- if (!nfs_proto)
- nfs_proto = "udp";
+ /*
+ * Determine the NFS port.
+ *
+ * A valid "port" mount option overrides anything else.
+ * If the port has been determined from the portmapper, use that.
+ * Default to NFS_PORT otherwise (cf. RFC 2054, 3).
+ */
+ nfs_port_opt = hasmntval(&mnt, MNTTAB_OPT_PORT);
+ if (nfs_port_opt > 0)
+ nfs_port = htons(nfs_port_opt);
+ if (!nfs_port)
+ nfs_port = htons(NFS_PORT);
- plog(XLOG_INFO, "Using NFS version %d, protocol %s on host %s",
- (int) nfs_version, nfs_proto, host);
+ dlog("find_nfs_srvr: using port %d for nfs on %s",
+ (int) ntohs(nfs_port), host);
+ ip->sin_port = nfs_port;
+no_dns:
/*
* Try to find an existing fs server structure for this host.
* Note that differing versions or protocols have their own structures.
@@ -795,16 +924,46 @@ find_nfs_srvr(mntfs *mf)
nfs_version == fs->fs_version &&
STREQ(nfs_proto, fs->fs_proto)) {
/*
- * following if statement from Mike Mitchell
- * <mcm@unx.sas.com>
- * Initialize the ping data if we aren't pinging
- * now. The np_ttl and np_ping fields are
- * especially important.
+ * fill in the IP address -- this is only needed
+ * if there is a chance an IP address will change
+ * between mounts.
+ * Mike Mitchell, mcm@unx.sas.com, 09/08/93
+ */
+ if (hp && fs->fs_ip &&
+ memcmp((voidp) &fs->fs_ip->sin_addr,
+ (voidp) hp->h_addr,
+ sizeof(fs->fs_ip->sin_addr)) != 0) {
+ struct in_addr ia;
+ char *old_ipaddr, *new_ipaddr;
+ old_ipaddr = strdup(inet_ntoa(fs->fs_ip->sin_addr));
+ memmove((voidp) &ia, (voidp) hp->h_addr, sizeof(struct in_addr));
+ new_ipaddr = inet_ntoa(ia); /* ntoa uses static buf */
+ plog(XLOG_WARNING, "fileserver %s changed ip: %s -> %s",
+ fs->fs_host, old_ipaddr, new_ipaddr);
+ XFREE(old_ipaddr);
+ flush_nfs_fhandle_cache(fs);
+ memmove((voidp) &fs->fs_ip->sin_addr, (voidp) hp->h_addr, sizeof(fs->fs_ip->sin_addr));
+ }
+
+ /*
+ * If the new file systems doesn't use WebNFS, the nfs pings may
+ * try to contact the portmapper.
+ */
+ if (!(mf->mf_flags & MFF_WEBNFS))
+ fs->fs_flags &= ~FSF_WEBNFS;
+
+ /* check if pingval needs to be updated/set/reset */
+ start_nfs_pings(fs, pingval);
+
+ /*
+ * Following if statement from Mike Mitchell <mcm@unx.sas.com>
+ * Initialize the ping data if we aren't pinging now. The np_ttl and
+ * np_ping fields are especially important.
*/
if (!(fs->fs_flags & FSF_PINGING)) {
np = (nfs_private *) fs->fs_private;
np->np_mountd_inval = TRUE;
- np->np_xid = NPXID_ALLOC(struct );
+ np->np_xid = XID_ALLOC();
np->np_error = -1;
np->np_ping = 0;
/*
@@ -812,18 +971,12 @@ find_nfs_srvr(mntfs *mf)
* after MAX_ALLOWED_PINGS of the fast variety
* have failed.
*/
- np->np_ttl = MAX_ALLOWED_PINGS * FAST_NFS_PING + clocktime() - 1;
+ np->np_ttl = MAX_ALLOWED_PINGS * FAST_NFS_PING + clocktime(NULL) - 1;
+ start_nfs_pings(fs, pingval);
+ if (fserver_is_down)
+ fs->fs_flags |= FSF_VALID | FSF_DOWN;
}
- /*
- * fill in the IP address -- this is only needed
- * if there is a chance an IP address will change
- * between mounts.
- * Mike Mitchell, mcm@unx.sas.com, 09/08/93
- */
- if (hp && fs->fs_ip)
- memmove((voidp) &fs->fs_ip->sin_addr, (voidp) hp->h_addr, sizeof(fs->fs_ip->sin_addr));
- start_nfs_pings(fs, pingval);
fs->fs_refc++;
if (ip)
XFREE(ip);
@@ -852,29 +1005,32 @@ find_nfs_srvr(mntfs *mf)
mf->mf_flags |= MFF_ERROR;
mf->mf_error = ENOENT;
}
+ if (mf->mf_flags & MFF_WEBNFS)
+ fs->fs_flags |= FSF_WEBNFS;
fs->fs_version = nfs_version;
fs->fs_proto = nfs_proto;
fs->fs_type = MNTTAB_TYPE_NFS;
fs->fs_pinger = AM_PINGER;
+ fs->fs_flags |= FSF_PING_UNINIT; /* pinger hasn't been initialized */
np = ALLOC(struct nfs_private);
memset((voidp) np, 0, sizeof(*np));
np->np_mountd_inval = TRUE;
- np->np_xid = NPXID_ALLOC(struct );
+ np->np_xid = XID_ALLOC();
np->np_error = -1;
/*
* Initially the server will be deemed dead after
* MAX_ALLOWED_PINGS of the fast variety have failed.
*/
- np->np_ttl = clocktime() + MAX_ALLOWED_PINGS * FAST_NFS_PING - 1;
+ np->np_ttl = clocktime(NULL) + MAX_ALLOWED_PINGS * FAST_NFS_PING - 1;
fs->fs_private = (voidp) np;
fs->fs_prfree = (void (*)(voidp)) free;
- if (!(fs->fs_flags & FSF_ERROR)) {
- /*
- * Start of keepalive timer
- */
+ if (!FSRV_ERROR(fs)) {
+ /* start of keepalive timer, first updating pingval */
start_nfs_pings(fs, pingval);
+ if (fserver_is_down)
+ fs->fs_flags |= FSF_VALID | FSF_DOWN;
}
/*
OpenPOWER on IntegriCloud