from Jan Pendry
authorKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Sat, 30 Jun 1990 03:44:21 +0000 (19:44 -0800)
committerKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Sat, 30 Jun 1990 03:44:21 +0000 (19:44 -0800)
SCCS-vsn: usr.sbin/amd/Makefile 5.1
SCCS-vsn: usr.sbin/amd/amd/afs_ops.c 5.1
SCCS-vsn: usr.sbin/amd/amd/am_ops.c 5.1
SCCS-vsn: usr.sbin/amd/amd/amd.c 5.1
SCCS-vsn: usr.sbin/amd/amd/amq_subr.c 5.1
SCCS-vsn: usr.sbin/amd/amd/clock.c 5.1
SCCS-vsn: usr.sbin/amd/amd/efs_ops.c 5.1
SCCS-vsn: usr.sbin/amd/amd/get_args.c 5.1
SCCS-vsn: usr.sbin/amd/amd/host_ops.c 5.1
SCCS-vsn: usr.sbin/amd/amd/ifs_ops.c 5.1
SCCS-vsn: usr.sbin/amd/amd/info_file.c 5.1
SCCS-vsn: usr.sbin/amd/amd/info_hes.c 5.1
SCCS-vsn: usr.sbin/amd/amd/info_ndbm.c 5.1
SCCS-vsn: usr.sbin/amd/amd/info_nis.c 5.1
SCCS-vsn: usr.sbin/amd/amd/info_passwd.c 5.1
SCCS-vsn: usr.sbin/amd/amd/map.c 5.1
SCCS-vsn: usr.sbin/amd/amd/mapc.c 5.1
SCCS-vsn: usr.sbin/amd/amd/misc_rpc.c 5.1
SCCS-vsn: usr.sbin/amd/amd/mntfs.c 5.1
SCCS-vsn: usr.sbin/amd/amd/mount_fs.c 5.1
SCCS-vsn: usr.sbin/amd/amd/mtab.c 5.1
SCCS-vsn: usr.sbin/amd/amd/nfs_ops.c 5.1
SCCS-vsn: usr.sbin/amd/amd/nfs_start.c 5.1
SCCS-vsn: usr.sbin/amd/amd/nfs_subr.c 5.1
SCCS-vsn: usr.sbin/amd/amd/opts.c 5.1
SCCS-vsn: usr.sbin/amd/amd/pfs_ops.c 5.1
SCCS-vsn: usr.sbin/amd/amd/restart.c 5.1
SCCS-vsn: usr.sbin/amd/amd/rpc_fwd.c 5.1
SCCS-vsn: usr.sbin/amd/amd/sched.c 5.1
SCCS-vsn: usr.sbin/amd/amd/sfs_ops.c 5.1
SCCS-vsn: usr.sbin/amd/amd/srvr_afs.c 5.1
SCCS-vsn: usr.sbin/amd/amd/srvr_nfs.c 5.1
SCCS-vsn: usr.sbin/amd/amd/ufs_ops.c 5.1
SCCS-vsn: usr.sbin/amd/amd/umount_fs.c 5.1
SCCS-vsn: usr.sbin/amd/amd/util.c 5.1
SCCS-vsn: usr.sbin/amd/amd/amd.8 5.1
SCCS-vsn: usr.sbin/amd/amd/Makefile 5.1
SCCS-vsn: usr.sbin/amd/amq/amq.c 5.1
SCCS-vsn: usr.sbin/amd/amq/amq.8 5.1
SCCS-vsn: usr.sbin/amd/amq/Makefile 5.1
SCCS-vsn: usr.sbin/amd/config/mtab_aix.c 5.1
SCCS-vsn: usr.sbin/amd/config/mtab_bsd.c 5.1
SCCS-vsn: usr.sbin/amd/config/mtab_file.c 5.1
SCCS-vsn: usr.sbin/amd/config/Makefile.aix3 5.1
SCCS-vsn: usr.sbin/amd/config/mtab_ultrix.c 5.1
SCCS-vsn: usr.sbin/amd/config/Makefile.bsd44 5.1
SCCS-vsn: usr.sbin/amd/config/Makefile.config 5.1
SCCS-vsn: usr.sbin/amd/config/Makefile.hpux 5.1
SCCS-vsn: usr.sbin/amd/config/Configure 5.1
SCCS-vsn: usr.sbin/amd/config/arch 5.1
SCCS-vsn: usr.sbin/amd/config/misc-aix3.h 5.1
SCCS-vsn: usr.sbin/amd/config/misc-hpux.h 5.1
SCCS-vsn: usr.sbin/amd/config/misc-ultrix.h 5.1
SCCS-vsn: usr.sbin/amd/config/os-acis43.h 5.1
SCCS-vsn: usr.sbin/amd/config/os-aix3.h 5.1
SCCS-vsn: usr.sbin/amd/config/os-aux.h 5.1
SCCS-vsn: usr.sbin/amd/config/os-bsd44.h 5.1
SCCS-vsn: usr.sbin/amd/config/os-concentrix.h 5.1
SCCS-vsn: usr.sbin/amd/config/os-convex.h 5.1
SCCS-vsn: usr.sbin/amd/config/os-defaults.h 5.1
SCCS-vsn: usr.sbin/amd/config/os-fpx4.h 5.1
SCCS-vsn: usr.sbin/amd/config/os-hlh42.h 5.1
SCCS-vsn: usr.sbin/amd/config/os-hpux.h 5.1
SCCS-vsn: usr.sbin/amd/config/os-pyrOSx.h 5.1
SCCS-vsn: usr.sbin/amd/config/os-riscix.h 5.1
SCCS-vsn: usr.sbin/amd/config/os-sos3.h 5.1
SCCS-vsn: usr.sbin/amd/config/os-sos4.h 5.1
SCCS-vsn: usr.sbin/amd/config/os-u2_2.h 5.1
SCCS-vsn: usr.sbin/amd/config/os-u3_0.h 5.1
SCCS-vsn: usr.sbin/amd/config/os-umax43.h 5.1
SCCS-vsn: usr.sbin/amd/config/os-utx32.h 5.1
SCCS-vsn: usr.sbin/amd/config/os-xinu43.h 5.1
SCCS-vsn: usr.sbin/amd/config/newvers.sh 5.1
SCCS-vsn: usr.sbin/amd/config/os-type 5.1
SCCS-vsn: usr.sbin/amd/text/amd.start.ex 5.1

75 files changed:
usr/src/usr.sbin/amd/Makefile [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/Makefile [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/afs_ops.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/am_ops.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/amd.8 [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/amd.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/amq_subr.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/clock.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/efs_ops.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/get_args.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/host_ops.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/ifs_ops.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/info_file.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/info_hes.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/info_ndbm.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/info_nis.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/info_passwd.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/map.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/mapc.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/misc_rpc.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/mntfs.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/mount_fs.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/mtab.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/nfs_ops.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/nfs_start.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/nfs_subr.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/opts.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/pfs_ops.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/restart.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/rpc_fwd.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/sched.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/sfs_ops.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/srvr_afs.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/srvr_nfs.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/ufs_ops.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/umount_fs.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amd/util.c [new file with mode: 0644]
usr/src/usr.sbin/amd/amq/Makefile [new file with mode: 0644]
usr/src/usr.sbin/amd/amq/amq.8 [new file with mode: 0644]
usr/src/usr.sbin/amd/amq/amq.c [new file with mode: 0644]
usr/src/usr.sbin/amd/config/Configure [new file with mode: 0644]
usr/src/usr.sbin/amd/config/Makefile.aix3 [new file with mode: 0644]
usr/src/usr.sbin/amd/config/Makefile.bsd44 [new file with mode: 0644]
usr/src/usr.sbin/amd/config/Makefile.config [new file with mode: 0644]
usr/src/usr.sbin/amd/config/Makefile.hpux [new file with mode: 0644]
usr/src/usr.sbin/amd/config/arch [new file with mode: 0644]
usr/src/usr.sbin/amd/config/misc-aix3.h [new file with mode: 0644]
usr/src/usr.sbin/amd/config/misc-hpux.h [new file with mode: 0644]
usr/src/usr.sbin/amd/config/misc-ultrix.h [new file with mode: 0644]
usr/src/usr.sbin/amd/config/mtab_aix.c [new file with mode: 0644]
usr/src/usr.sbin/amd/config/mtab_bsd.c [new file with mode: 0644]
usr/src/usr.sbin/amd/config/mtab_file.c [new file with mode: 0644]
usr/src/usr.sbin/amd/config/mtab_ultrix.c [new file with mode: 0644]
usr/src/usr.sbin/amd/config/newvers.sh [new file with mode: 0644]
usr/src/usr.sbin/amd/config/os-acis43.h [new file with mode: 0644]
usr/src/usr.sbin/amd/config/os-aix3.h [new file with mode: 0644]
usr/src/usr.sbin/amd/config/os-aux.h [new file with mode: 0644]
usr/src/usr.sbin/amd/config/os-bsd44.h [new file with mode: 0644]
usr/src/usr.sbin/amd/config/os-concentrix.h [new file with mode: 0644]
usr/src/usr.sbin/amd/config/os-convex.h [new file with mode: 0644]
usr/src/usr.sbin/amd/config/os-defaults.h [new file with mode: 0644]
usr/src/usr.sbin/amd/config/os-fpx4.h [new file with mode: 0644]
usr/src/usr.sbin/amd/config/os-hlh42.h [new file with mode: 0644]
usr/src/usr.sbin/amd/config/os-hpux.h [new file with mode: 0644]
usr/src/usr.sbin/amd/config/os-pyrOSx.h [new file with mode: 0644]
usr/src/usr.sbin/amd/config/os-riscix.h [new file with mode: 0644]
usr/src/usr.sbin/amd/config/os-sos3.h [new file with mode: 0644]
usr/src/usr.sbin/amd/config/os-sos4.h [new file with mode: 0644]
usr/src/usr.sbin/amd/config/os-type [new file with mode: 0644]
usr/src/usr.sbin/amd/config/os-u2_2.h [new file with mode: 0644]
usr/src/usr.sbin/amd/config/os-u3_0.h [new file with mode: 0644]
usr/src/usr.sbin/amd/config/os-umax43.h [new file with mode: 0644]
usr/src/usr.sbin/amd/config/os-utx32.h [new file with mode: 0644]
usr/src/usr.sbin/amd/config/os-xinu43.h [new file with mode: 0644]
usr/src/usr.sbin/amd/text/amd.start.ex [new file with mode: 0644]

diff --git a/usr/src/usr.sbin/amd/Makefile b/usr/src/usr.sbin/amd/Makefile
new file mode 100644 (file)
index 0000000..03600c4
--- /dev/null
@@ -0,0 +1,40 @@
+#
+# $Id: Makefile,v 5.2 90/06/23 22:21:02 jsp Rel $
+#
+# 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.
+#
+# %sccs.include.redist.sh%
+#
+#      @(#)Makefile    5.1 (Berkeley) %G%
+#
+
+SHELL = /bin/sh
+PROGS = amd amq mk-amd-map
+MAKE = make
+MKARGS = -f Makefile.top
+
+all: FRC
+       @for prog in ${PROGS}; do \
+               echo Making $$prog; \
+               (cd $$prog; ${MAKE} $$prog ) \
+       done
+
+${PROGS}: FRC
+       @cd $@; ${MAKE} $@
+
+count clean install lint: FRC
+       @for prog in ${PROGS}; do \
+               echo $@\'ing $$prog; \
+               (cd $$prog; ${MAKE} $@) \
+       done
+
+pat print tarfile sharfile filelist: FRC
+       @$(MAKE) ${MKARGS} ${MFLAGS} $@ OS=undef PROG=doc
+
+FRC:
diff --git a/usr/src/usr.sbin/amd/amd/Makefile b/usr/src/usr.sbin/amd/amd/Makefile
new file mode 100644 (file)
index 0000000..b42d101
--- /dev/null
@@ -0,0 +1,25 @@
+#
+# $Id: Makefile,v 5.2 90/06/23 22:21:10 jsp Rel $
+#
+# 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.
+#
+# %sccs.include.redist.sh%
+#
+#      @(#)Makefile    5.1 (Berkeley) %G%
+
+MKARG = -f ../Makefile.top PROG=amd
+SHELL = /bin/sh
+
+amd: FRC
+       @${MAKE} ${MKARG} $@
+
+install count clean lint: FRC
+       @${MAKE} ${MKARG} $@
+
+FRC:
diff --git a/usr/src/usr.sbin/amd/amd/afs_ops.c b/usr/src/usr.sbin/amd/amd/afs_ops.c
new file mode 100644 (file)
index 0000000..9dc36ce
--- /dev/null
@@ -0,0 +1,1544 @@
+/*
+ * $Id: afs_ops.c,v 5.2 90/06/23 22:19:14 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)afs_ops.c   5.1 (Berkeley) %G%
+ */
+
+#include "am.h"
+
+#define NFS
+#define NFSCLIENT
+
+#include <sys/stat.h>
+#ifdef NFS_3
+typedef nfs_fh fhandle_t;
+#endif /* NFS_3 */
+#ifdef NFS_HDR
+#include NFS_HDR
+#endif /* NFS_HDR */
+#include <sys/mount.h>
+#include "mount.h"
+
+/*
+ * Automount file system
+ */
+
+/*
+ * Interval between forced retries of a mount.
+ */
+#define RETRY_INTERVAL 2
+
+/*
+ * AFS needs nothing in particular.
+ */
+static int afs_match(fo)
+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;
+       /*
+        * fs_mtab turns out to be the name of the mount map
+        */
+       fo->fs_mtab = strealloc(fo->fs_mtab, fo->opt_rfs ? fo->opt_rfs : ".");
+       return 1;
+}
+
+static int afs_init(mf)
+mntfs *mf;
+{
+       /*
+        * Fill in attribute fields
+        */
+       mf->mf_fattr.type = NFDIR;
+       mf->mf_fattr.mode = NFSMODE_DIR | 0555;
+       mf->mf_fattr.nlink = 2;
+       mf->mf_fattr.size = 512;
+
+       return 0;
+}
+
+/*
+ * Mount the an automounter directory.
+ * The automounter is connected into the system
+ * as a user-level NFS server.  mount_afs constructs
+ * the necessary NFS parameters to be given to the
+ * kernel so that it will talk back to us.
+ */
+static int mount_afs(dir, fs_name, opts)
+char *dir;
+char *fs_name;
+char *opts;
+{
+       struct nfs_args nfs_args;
+       struct mntent mnt;
+       int retry;
+       struct sockaddr_in sin;
+       unsigned short port;
+       int flags;
+       extern nfs_fh *root_fh();
+       nfs_fh *fhp;
+       char fs_hostname[MAXHOSTNAMELEN+MAXPATHLEN+1];
+
+       MTYPE_TYPE type = MOUNT_TYPE_NFS;
+
+       bzero((voidp) &nfs_args, sizeof(nfs_args));     /* Paranoid */
+
+       mnt.mnt_dir = dir;
+       mnt.mnt_fsname = fs_name;
+       mnt.mnt_type = MNTTYPE_AUTO;
+       mnt.mnt_opts = opts;
+       mnt.mnt_freq = 0;
+       mnt.mnt_passno = 0;
+
+       retry = hasmntval(&mnt, "retry");
+       if (retry <= 0)
+               retry = 2;      /* XXX */
+
+       /*
+        * get fhandle of remote path for automount point
+        */
+       
+       fhp = root_fh(fs_name);
+       if (!fhp) {
+               plog(XLOG_FATAL, "Can't find root file handle for %s", fs_name);
+               return EINVAL;
+       }
+
+       NFS_FH_DREF(nfs_args.fh, (NFS_FH_TYPE) fhp);
+
+       /*
+        * 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.
+        */
+       bzero((voidp) &sin, sizeof(sin));
+       sin.sin_family = AF_INET;
+       sin.sin_addr = myipaddr;
+       if (port = hasmntval(&mnt, "port")) {
+               sin.sin_port = htons(port);
+       } else {
+               plog(XLOG_ERROR, "no port number specified for %s", fs_name);
+               return EINVAL;
+       }
+
+       /*
+        * set mount args
+        */
+       NFS_SA_DREF(nfs_args, &sin);
+
+       /*
+        * Make a ``hostname'' string for the kernel
+        */
+#ifndef HOSTNAMESZ
+#define        SHORT_MOUNT_NAME
+#endif /* HOSTNAMESZ */
+#ifdef SHORT_MOUNT_NAME
+       sprintf(fs_hostname, "amd:%d", mypid);
+#else
+       sprintf(fs_hostname, "pid%d@%s:%s", mypid, hostname, dir);
+#endif /* SHORT_MOUNT_NAME */
+       nfs_args.hostname = fs_hostname;
+       nfs_args.flags |= NFSMNT_HOSTNAME;
+#ifdef HOSTNAMESZ
+       /*
+        * Most kernels have a name length restriction.
+        */
+       if (strlen(fs_hostname) >= HOSTNAMESZ)
+               strcpy(fs_hostname + HOSTNAMESZ - 3, "..");
+#endif /* HOSTNAMESZ */
+
+       /*
+        * Parse a subset of the standard nfs options.  The
+        * others are probably irrelevant for this application
+        */
+       if (nfs_args.timeo = hasmntval(&mnt, "timeo"))
+               nfs_args.flags |= NFSMNT_TIMEO;
+
+       if (nfs_args.retrans = hasmntval(&mnt, "retrans"))
+               nfs_args.flags |= NFSMNT_RETRANS;
+
+#ifdef NFSMNT_BIODS
+       if (nfs_args.biods = hasmntval(&mnt, "biods"))
+               nfs_args.flags |= NFSMNT_BIODS;
+
+#endif /* NFSMNT_BIODS */
+
+#if defined(NFSMNT_ACREGMIN) && defined(NFSMNT_ACREGMAX)
+       /*
+        * Don't cache attributes - they are changing under
+        * the kernel's feet...
+        */
+       nfs_args.acregmin = nfs_args.acregmax = 1;
+       nfs_args.flags |= NFSMNT_ACREGMIN|NFSMNT_ACREGMAX;
+#endif /* defined(NFSMNT_ACREGMIN) && defined(NFSMNT_ACREGMAX) */
+       /*
+        * These two are constructed internally by the calling routine
+        */
+       if (hasmntopt(&mnt, MNTOPT_SOFT) != NULL)
+               nfs_args.flags |= NFSMNT_SOFT;
+
+#ifdef MNTOPT_INTR
+       if (hasmntopt(&mnt, MNTOPT_INTR) != NULL)
+               nfs_args.flags |= NFSMNT_INT;
+#endif /* MNTOPT_INTR */
+
+       flags = compute_mount_flags(&mnt);
+#ifdef ULTRIX_HACK
+       nfs_args.gfs_flags = flags;
+       flags &= M_RDONLY;
+       if (flags & M_RDONLY)
+               nfs_args.flags |= NFSMNT_RONLY;
+#endif /* ULTRIX_HACK */
+       return mount_fs(&mnt, flags, (caddr_t) &nfs_args, retry, type);
+}
+
+static int afs_mount(mp)
+am_node *mp;
+{
+       mntfs *mf = mp->am_mnt;
+
+       /*
+        * There are two cases to consider...
+        */
+       if (mp->am_parent && mp->am_parent->am_parent) {
+               /*
+                * If this am_node has a parent which is not the root node, in
+                * which case we are supplying a pseudo-directory, in which
+                * case no action is needed.  Pseudo-directories are used to
+                * provide some structure to the automounted directories instead
+                * of putting them all in the top-level automount directory.
+                */
+               mp->am_parent->am_mnt->mf_fattr.nlink++;
+               /*
+                * Info field of . means use parent's info field.
+                */
+               if (mf->mf_info[0] == '.' && mf->mf_info[1] == '\0')
+                       mf->mf_info = strealloc(mf->mf_info, mp->am_parent->am_mnt->mf_info);
+               /*
+                * Compute prefix:
+                *
+                * If there is an option prefix then use that else
+                * If the parent had a prefix then use that with name
+                *      of this node appended else
+                * Use the name of this node.
+                *
+                * That means if you want no prefix you must say so
+                * in the map.
+                */
+               if (mf->mf_fo->opt_pref) {
+                       /*
+                        * the prefix specified as an option
+                        */
+                       mp->am_pref = strdup(mf->mf_fo->opt_pref);
+               } else {
+                       /*
+                        * else the parent's prefix
+                        * followed by the name
+                        * followed by /
+                        */
+                       char *ppref = mp->am_parent->am_pref;
+                       if (ppref == 0)
+                               ppref = "";
+                       mp->am_pref = str3cat((char *) 0, ppref, mp->am_name, "/");
+               }
+       } else {
+               /*
+                * Otherwise, we are mounting the automounter.  In which case
+                * we need to make sure the mount directory exists, construct
+                * the mount options and call the mount_afs routine.
+                */
+               struct stat stb;
+               char opts[256];
+               int error;
+
+               /*
+                * Top-level mount - so make
+                * sure the mount point exists
+                * and is a directory.
+                */
+               error = mkdirs(mp->am_path, 0555);
+               if (error)
+                       return error;
+               mp->am_flags |= AMF_MKPATH;
+
+               if (stat(mp->am_path, &stb) < 0) {
+                       return errno;
+               } else if ((stb.st_mode & S_IFMT) != S_IFDIR) {
+                       plog(XLOG_WARNING, "%s is not a directory", mp->am_path);
+                       return ENOTDIR;
+               }
+
+               mf->mf_mount = strealloc(mf->mf_mount, mp->am_path);
+
+               /*
+                * Construct some mount options
+                */
+               sprintf(opts,
+#ifdef MNTOPT_INTR
+                       "%s,%s,%s=%d,%s=%d,%s=%d,%sdirect",
+                       MNTOPT_INTR,
+#else
+                       "%s,%s=%d,%s=%d,%s=%d,%sdirect",
+#endif /* MNTOPT_INTR */
+#ifdef AUTOMOUNT_RO
+                       MNTOPT_RO,      /* You don't really want this... */
+#else
+                       "rw",
+#endif /* AUTOMOUNT_RO */
+                       "port", nfs_port,
+                       "timeo", afs_timeo,
+                       "retrans", afs_retrans,
+                       mf->mf_ops == &afs_ops ? "in" : "");
+
+               error = mount_afs(mp->am_path, mp->am_name, opts);
+               if (error) {
+                       errno = error;
+                       plog(XLOG_FATAL, "mount_afs: %m");
+                       return error;
+               }
+               mp->am_name = pid_fsname;
+       }
+
+       /*
+        * Build a new map cache for this node, or re-use
+        * an existing cache for the same map.
+        */
+       { char *cache;
+         if (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_prfree = mapc_free;
+       }
+
+       return 0;
+}
+
+/*
+ * Unmount an automount node
+ */
+static int afs_umount(mp)
+am_node *mp;
+{
+       int error;
+
+       /*
+        * 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) {
+               error = 0;
+       } else if (mp->am_parent && mp->am_parent->am_parent) {
+               --mp->am_parent->am_mnt->mf_fattr.nlink;
+               error = 0;
+       } else {
+               struct stat stb;
+again:
+               /*
+                * The lstat is needed if this mount is type=direct.
+                * When that happens, the kernel cache gets confused
+                * between the underlying type (dir) and the mounted
+                * type (link) and so needs to be re-synced before
+                * the unmount.  This is all because the unmount system
+                * call follows links and so can't actually unmount
+                * a link (stupid!).  It was noted that doing an ls -ld
+                * of the mount point to see why things were not working
+                * actually fixed the problem - so simulate an ls -ld here.
+                */
+               if (lstat(mp->am_path, &stb) < 0) {
+#ifdef DEBUG
+                       dlog("lstat(%s): %m", mp->am_path);
+#endif /* DEBUG */
+               }
+               error = UMOUNT_FS(mp->am_path);
+               if (error == EBUSY) {
+                       plog(XLOG_WARNING, "afs_unmount retrying %s in 1s", mp->am_path);
+                       sleep(1);       /* XXX */
+                       goto again;
+               }
+       }
+
+       return error;
+}
+
+/*
+ * Unmount an automount node
+ */
+static void afs_umounted(mp)
+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_mnt->mf_fattr.nlink;
+}
+
+/*
+ * 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 succesful.
+ * 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 *opts;             /* Mount options */
+       am_opts fs_opts;        /* Filesystem options */
+       char *def_opts;         /* Default options */
+       int retry;              /* Try again? */
+       int tried;              /* Have we tried any yet? */
+       time_t start;           /* Time we started this mount */
+       int callout;            /* Callout identifier */
+};
+
+/*
+ * Discard an old continuation
+ */
+static void free_continuation(cp)
+struct continuation *cp;
+{
+       if (cp->callout)
+               untimeout(cp->callout);
+       free((voidp) cp->key);
+       free((voidp) cp->xivec);
+       free((voidp) cp->info);
+       free((voidp) cp->opts);
+       free((voidp) cp->def_opts);
+       free_opts(&cp->fs_opts);
+       free((voidp) cp);
+}
+
+static int afs_bgmount P((struct continuation*, int));
+
+/*
+ * Discard the underlying mount point and replace
+ * with a reference to an error filesystem.
+ */
+static void assign_error_mntfs(mp)
+am_node *mp;
+{
+       if (mp->am_error > 0) {
+               /*
+                * Save the old error code
+                */
+               int error = mp->am_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.
+ */
+static void afs_cont(rc, term, closure)
+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) {
+               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 */
+                       plog(XLOG_ERROR, "%s: mount (afs_cont): %m", cp->mp->am_path);
+               }
+
+               /*
+                * 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++;
+               (void) afs_bgmount(cp, 0);
+               assign_error_mntfs(cp->mp);
+       } else {
+               /*
+                * The mount worked.
+                */
+               am_mounted(cp->mp);
+               free_continuation(cp);
+       }
+
+       reschedule_timeout_mp();
+}
+
+/*
+ * Retry a mount
+ */
+/*ARGSUSED*/
+static void afs_retry(rc, term, closure)
+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 */
+
+       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
+                * afs_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;
+               new_ttl(cp->mp);
+               while (*cp->ivec)
+                       cp->ivec++;
+       }
+
+       (void) afs_bgmount(cp, error);
+       reschedule_timeout_mp();
+}
+
+/*
+ * Try to mount a file system.  Can be called
+ * directly or in a sub-process by run_task
+ */
+static int try_mount(mp)
+am_node *mp;
+{
+       /*
+        * Mount it!
+        */
+       int error;
+
+       error = mount_node(mp);
+#ifdef DEBUG
+       if (error) {
+               errno = error;
+               dlog("afs call to mount_node failed: %m");
+       }
+#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 = initialise 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 occured on this mount then
+               update stats
+               save error in mount point
+       fi
+endfor
+ */
+
+static int afs_bgmount(cp, mpe)
+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->opts && *cp->opts)
+                               cp->def_opts = str3cat(cp->def_opts, cp->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 (strcmp(*cp->ivec, "/") == 0 || strcmp(*cp->ivec, "||") == 0) {
+                       if (cp->tried) {
+#ifdef DEBUG
+                               dlog("Cut: not trying any more locations for %s",
+                                       mp->am_path);
+#endif /* DEBUG */
+                               break;
+                       }
+                       continue;
+               }
+
+#ifdef SUNOS4_COMPAT
+               /*
+                * By default, you only get this bit on SunOS4.
+                * If you want this anyway, then define SUNOS4_COMPAT
+                * in the relevant "os-blah.h" file.
+                *
+                * We make the observation that if the local key line contains
+                * no '=' signs then either it is sick, or it is a SunOS4-style
+                * "host:fs[:link]" line.  In the latter case the am_opts field
+                * is also assumed to be in old-style, so you can't mix & match.
+                * You can use ${} expansions for the fs and link bits though...
+                *
+                * Actually, this doesn't really cover all the possibilities for
+                * the latest SunOS automounter and it is debatable whether there
+                * is any point bothering.
+                */
+               if (strchr(*cp->ivec, '=') == 0)
+                       p = sunos4_match(&cp->fs_opts, *cp->ivec, cp->def_opts, mp->am_path, cp->key, mp->am_parent->am_mnt->mf_info);
+               else
+#endif /* SUNOS4_COMPAT */
+                       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->opts);
+
+               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 == &efs_ops) {
+                       plog(XLOG_MAP, "Map entry %s for %s failed to 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) {
+                       free(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 {
+                               mp->am_link = str3cat((char *) 0,
+                                       mf->mf_fo->opt_fs, "/", link_dir);
+                       }
+               }
+
+               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 */
+                       this_error = 0;
+                       new_ttl(mp);
+                       break;
+               }
+
+               /*
+                * Will usually need to play around with the mount nodes
+                * file attribute structure.  This must be done here.
+                */
+               if (!this_error) {
+                       /*
+                        * Fill in attribute fields
+                        */
+                       mf->mf_fattr.type = NFLNK;
+                       mf->mf_fattr.mode = NFSMODE_LNK | 0777;
+                       mf->mf_fattr.nlink = 1;
+                       mf->mf_fattr.size = MAXPATHLEN / 4;     /* Conservative */
+                       mf->mf_fattr.fileid = mp->am_gen;
+
+                       if (p->fs_init)
+                               this_error = (*p->fs_init)(mf);
+               }
+
+               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 && (cp->start + i) < clocktime()) {
+#ifdef DEBUG
+                               dlog("Mount of %s delayed by %ds", mf->mf_mount, i);
+#endif /* DEBUG */
+                               this_error = -1;
+                       }
+               }
+
+               if (this_error < 0 && !dont_retry) {
+                       if (!mf_retry)
+                               mf_retry = dup_mntfs(mf);
+                       cp->retry = TRUE;
+               }
+
+               if (!this_error) {
+                       /*
+                        * If the directory is not yet made and
+                        * it needs to be made, then make it!
+                        */
+                        if (!(mf->mf_flags & MFF_MKMNT) &&
+                                       p->fs_flags & FS_MKMNT) {
+                               this_error = mkdirs(mf->mf_mount, 0555);
+                               if (!this_error)
+                                       mf->mf_flags |= MFF_MKMNT;
+                       }
+               }
+
+               if (!this_error)
+               if (p->fs_flags & FS_MBACKGROUND) {
+                       mf->mf_flags |= MFF_MOUNTING;   /*XXX*/
+#ifdef DEBUG
+                       dlog("backgrounding mount of \"%s\"", mf->mf_info);
+#endif /* DEBUG */
+                       if (cp->callout) {
+                               untimeout(cp->callout);
+                               cp->callout = 0;
+                       }
+                       run_task(try_mount, (voidp) mp, afs_cont, (voidp) cp);
+                       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(mp);
+               }
+
+               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.
+                */
+               cp->ivec = cp->xivec;
+               cp->def_opts = strealloc(cp->def_opts, cp->opts);
+               /*
+                * Arrange that afs_bgmount is called
+                * after anything else happens.
+                */
+#ifdef DEBUG
+               dlog("Arranging to retry mount of %s", cp->mp->am_path);
+#endif /* DEBUG */
+               sched_task(afs_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;
+       }
+
+       /*
+        * Discard handle on duff filesystem.
+        * This should never happen since it
+        * should be caught by the case above.
+        */
+       if (mf_retry) {
+               plog(XLOG_ERROR, "discarding a retry mntfs for %s", mf_retry->mf_mount);
+               free_mntfs(mf_retry);
+       }
+
+       if (hard_error < 0 || !this_error)
+               hard_error = this_error;
+
+       /*
+        * 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 = 5;
+                       break;
+               default:
+                       cp->mp->am_timeo = 17;
+                       break;
+               }
+               cp->mp->am_timeo_w = 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;
+}
+
+/*
+ * Automount interface to RPC lookup routine
+ */
+static am_node *afs_lookuppn(mp, fname, error_return, op)
+am_node *mp;
+char *fname;
+int *error_return;
+int op;
+{
+#define ereturn(x) { *error_return = x; return 0; }
+
+       /*
+        * Find the corresponding entry and return
+        * the file handle for it.
+        */
+       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 *opts;                     /* Mount 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 we need to mount */
+       int in_progress = 0;            /* # of (un)mount in progress */
+       char *dflts;
+       mntfs *mf;
+
+#ifdef DEBUG
+       dlog("in afs_lookuppn");
+#endif /* DEBUG */
+
+       /*
+        * If the server is shutting down
+        * then don't return information
+        * about the mount point.
+        */
+       if (amd_state == Finishing) {
+#ifdef DEBUG
+               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)) {
+                               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 -- in progress",
+                                       fname, mf->mf_mount);
+#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 */
+                       free(fname);
+                       return ap;
+               }
+       }
+
+       if (in_progress) {
+#ifdef DEBUG
+               dlog("Waiting while %d mount(s) in progress", in_progress);
+#endif /* DEBUG */
+               free(fname);
+               ereturn(-1);
+       }
+
+       /*
+        * If an error occured then return it.
+        */
+       if (error) {
+#ifdef DEBUG
+               errno = error; /* XXX */
+               dlog("Returning error: %m", error);
+#endif /* DEBUG */
+               free(fname);
+               ereturn(error);
+       }
+
+       /*
+        * If doing a delete then don't create again!
+        */
+       switch (op) {
+       case VLOOK_DELETE:
+               ereturn(ENOENT);
+               break;
+
+       case VLOOK_CREATE:
+               break;
+
+       default:
+               plog(XLOG_FATAL, "Unknown op to afs_lookuppn: 0x%x", op);
+               ereturn(EINVAL);
+               break;
+       }
+
+       /*
+        * 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 */
+               free(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) {
+               plog(XLOG_MAP, "No map entry for %s", pfname);
+               free(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) {
+               free((voidp) xivec);
+               free((voidp) info);
+               free((voidp) fname);
+               ereturn(ENOSPC);
+       }
+
+       if (mf->mf_opts)
+               opts = mf->mf_opts;
+       else
+               opts = "";
+
+       opts = strdup(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, '\"');
+               /*
+                * Extract first value
+                */
+               dfl = rvec[0];
+
+               /*
+                * Log error if there were other values
+                */
+               if (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);
+               }
+
+               /*
+                * Don't need info vector any more
+                */
+               free((voidp) rvec);
+
+               /*
+                * If there were any values at all...
+                */
+               if (dfl) {
+                       /*
+                        * Prepend to existing defaults if they exist,
+                        * otherwise just use these defaults.
+                        */
+                       if (*opts && *dfl) {
+                               char *nopts = (char *) xmalloc(strlen(opts)+strlen(dfl)+2);
+                               sprintf(nopts, "%s;%s", dfl, opts);
+                               free(opts);
+                               opts = nopts;
+                       } else if (*dfl) {
+                               opts = strealloc(opts, dfl);
+                       }
+               }
+               free(dflts);
+       }
+
+       /*
+        * 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
+        */
+       new_mp->am_path = str3cat(new_mp->am_path, 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(continuation);
+       cp->mp = new_mp;
+       cp->xivec = xivec;
+       cp->ivec = ivec;
+       cp->info = info;
+       cp->key = pfname;
+       cp->opts = opts;
+       cp->retry = FALSE;
+       cp->tried = FALSE;
+       cp->start = clocktime();
+       cp->def_opts = strdup(opts);
+       bzero((voidp) &cp->fs_opts, 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 = afs_bgmount(cp, error);
+       reschedule_timeout_mp();
+       if (!error) {
+               free(fname);
+               return new_mp;
+       }
+
+       assign_error_mntfs(cp->mp);
+
+       free(fname);
+
+       ereturn(error);
+#undef ereturn
+}
+
+/*
+ * Locate next node in sibling list which is mounted
+ * and is not an error node.
+ */
+static am_node *next_nonerror_node(xp)
+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;
+}
+
+static int afs_readdir(mp, cookie, dp, ep)
+am_node *mp;
+nfscookie cookie;
+struct dirlist *dp;
+struct entry *ep;
+{
+       unsigned int gen = *(unsigned int*) cookie;
+       am_node *xp;
+
+       dp->eof = FALSE;
+
+       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("default search");
+#endif /* DEBUG */
+               xp = next_nonerror_node(mp->am_child);
+               dp->entries = ep;
+
+               /* construct "." */
+               ep[0].fileid = mp->am_gen;
+               ep[0].name = ".";
+               ep[0].nextentry = &ep[1];
+               *(unsigned int *) ep[0].cookie = 0;
+
+               /* construct ".." */
+               if (mp->am_parent)
+                       ep[1].fileid = mp->am_parent->am_gen;
+               else
+                       ep[1].fileid = mp->am_gen;
+               ep[1].name = "..";
+               ep[1].nextentry = 0;
+               *(unsigned int *) ep[1].cookie =
+                       xp ? xp->am_gen : ~(unsigned int)0;
+
+               if (!xp) dp->eof = TRUE;
+               return 0;
+       }
+
+#ifdef DEBUG
+       dlog("real child");
+#endif /* DEBUG */
+
+       if (gen == ~(unsigned int)0) {
+#ifdef DEBUG
+               dlog("End of readdir in %s", mp->am_path);
+#endif /* DEBUG */
+               dp->eof = TRUE;
+               dp->entries = 0;
+               return 0;
+       }
+
+       xp = mp->am_child;
+       while (xp && xp->am_gen != gen)
+               xp = xp->am_osib;
+
+       if (xp) {
+               am_node *xp_next = next_nonerror_node(xp->am_osib);
+
+               if (xp_next) {
+                       *(unsigned int *) ep->cookie = xp_next->am_gen;
+               } else {
+                       *(unsigned int *) ep->cookie = ~(unsigned int)0;
+                       dp->eof = TRUE;
+               }
+
+               ep->fileid = xp->am_gen;
+               ep->name = xp->am_name;
+
+               ep->nextentry = 0;
+               dp->entries = ep;
+
+               return 0;
+       }
+
+       return ESTALE;
+
+}
+
+static am_node *dfs_readlink(mp, error_return)
+am_node *mp;
+int *error_return;
+{
+       am_node *xp;
+       int rc = 0;
+
+       xp = next_nonerror_node(mp->am_child);
+       if (!xp)
+               xp = afs_lookuppn(mp, mp->am_path+1, &rc, VLOOK_CREATE);
+
+       if (xp) {
+               new_ttl(xp);    /* (7/12/89) from Rein Tollevik */
+               return xp;
+       }
+       if (amd_state == Finishing)
+               rc = ENOENT;
+       *error_return = rc;
+       return 0;
+}
+
+/*
+ * Ops structure
+ */
+am_ops afs_ops = {
+       "auto",
+       afs_match,
+       afs_init,
+       afs_mount,
+       afs_umount,
+       afs_lookuppn,
+       afs_readdir,
+       0, /* afs_readlink */
+       0, /* afs_mounted */
+       afs_umounted,
+       find_afs_srvr,
+       FS_NOTIMEOUT|FS_UBACKGROUND|FS_AMQINFO
+};
+
+am_ops dfs_ops = {
+       "direct",
+       afs_match,
+       0, /* dfs_init */
+       afs_mount,
+       afs_umount,
+       efs_lookuppn,
+       efs_readdir,
+       dfs_readlink,
+       0, /* afs_mounted */
+       afs_umounted,
+       find_afs_srvr,
+       FS_NOTIMEOUT|FS_UBACKGROUND|FS_AMQINFO
+};
diff --git a/usr/src/usr.sbin/amd/amd/am_ops.c b/usr/src/usr.sbin/amd/amd/am_ops.c
new file mode 100644 (file)
index 0000000..3fc6389
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * $Id: am_ops.c,v 5.2 90/06/23 22:19:19 jsp Rel $
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)am_ops.c    5.1 (Berkeley) %G%
+ */
+
+#include "am.h"
+
+static am_ops *vops[] = {
+#ifdef HAS_UFS
+       &ufs_ops,
+#endif /* HAS_UFS */
+#ifdef HAS_NFS
+       &nfs_ops,
+#endif /* HAS_NFS */
+#ifdef HAS_HOST
+       &host_ops,
+#endif /* HAS_HOST */
+#ifdef HAS_SFS
+       &sfs_ops,
+#endif /* HAS_SFS */
+#ifdef HAS_LOFS
+       &lofs_ops,
+#endif /* HAS_LOFS */
+#ifdef HAS_PFS
+       &pfs_ops,
+#endif /* HAS_PFS */
+       &afs_ops,       /* These three should be last ... */
+       &dfs_ops,       /* ... */
+       &efs_ops,       /* ... in the order afs; dfs; efs */
+       0
+};
+
+#ifdef SUNOS4_COMPAT
+/*
+ * Crack a SunOS4-style host:fs:sub-link line
+ * Construct an amd-style line and call the
+ * normal amd matcher.
+ */
+am_ops *sunos4_match(fo, key, g_key, path, keym, map)
+am_opts *fo;
+char *key;
+char *g_key;
+char *path;
+char *keym;
+char *map;
+{
+       char *host = key;
+       char *fs = strchr(host, ':');
+       char *sublink = fs ? strchr(fs+1, ':') : 0;
+       char keybuf[MAXPATHLEN];
+
+       sprintf(keybuf, "type:=nfs;rhost:=%s;rfs:=%s;sublink:=%s;opts:=%s", host,
+               fs ? fs+1 : "",
+               sublink ? sublink+1  : "",
+               g_key);
+       return ops_match(fo, keybuf, "", path, keym, map);
+}
+#endif /* SUNOS4_COMPAT */
+
+am_ops *ops_match(fo, key, g_key, path, keym, map)
+am_opts *fo;
+char *key;
+char *g_key;
+char *path;
+char *keym;
+char *map;
+{
+       am_ops **vp;
+       am_ops *rop = 0;
+
+       /*
+        * First crack the global opts and the local opts
+        */
+       if (!eval_fs_opts(fo, key, g_key, path, keym, map)) {
+               rop = &efs_ops;
+       } else if (fo->opt_type == 0) {
+               plog(XLOG_USER, "No fs type specified (somewhere!)");
+               rop = &efs_ops;
+       } else {
+               /*
+                * Next find the correct filesystem type
+                */
+               for (vp = vops; rop = *vp; vp++)
+                       if (strcmp(rop->fs_type, fo->opt_type) == 0)
+                               break;
+
+               if (!rop) {
+                       plog(XLOG_USER, "fs type \"%s\" not recognised", fo->opt_type);
+                       rop = &efs_ops;
+               }
+       }
+
+       /*
+        * Make sure we have a default mount option.
+        * Otherwise skip past any leading '-'.
+        */
+       if (fo->opt_opts == 0)
+               fo->opt_opts = "rw,defaults";
+       else if (*fo->opt_opts == '-')
+               fo->opt_opts++;
+
+       /*
+        * Check the filesystem is happy
+        */
+       if ((*rop->fs_match)(fo))
+               return rop;
+
+       /*
+        * Return error file system
+        */
+       (void) (*efs_ops.fs_match)(fo);
+       return &efs_ops;
+}
diff --git a/usr/src/usr.sbin/amd/amd/amd.8 b/usr/src/usr.sbin/amd/amd/amd.8
new file mode 100644 (file)
index 0000000..20689a2
--- /dev/null
@@ -0,0 +1,212 @@
+.\" $Id: amd.8,v 5.2 90/06/23 22:21:12 jsp Rel $
+.\" 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.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Jan-Simon Pendry at Imperial College, London.
+.\"
+.\"  %sccs.include.redist.man%
+.\"
+.\"    @(#)amd.8       5.1 (Berkeley) %G%
+.\"
+.TH AMD 8 ""
+.SH NAME
+amd \- automatically mount file systems
+.SH SYNOPSIS
+.B amd
+[
+.B \-nprv
+] [
+.BI \-a " mount_point"
+] [
+.BI \-c " duration"
+] [
+.BI \-d " domain"
+] [
+.BI \-k " kernel-arch"
+] [
+.BI \-l " logfile"
+] [
+.BI \-t " interval.interval"
+] [
+.BI \-w " interval"
+] [
+.BI \-x " log-option"
+] [
+.BI \-y " YP-domain"
+] [
+.BI \-C " cluster-name"
+] [
+.BI \-D " option"
+]
+[
+.I directory
+.I mapname
+.RI [ " \-map-options " ]
+] .\|.\|.
+.SH DESCRIPTION
+.B Amd
+is a daemon that automatically mounts filesystems
+whenever a file or directory
+within that filesystem is accessed.
+Filesystems are automatically unmounted when they
+appear to have become quiescent.
+.LP
+.B Amd
+has been designed as a value-added replacement
+for the SunOS 4
+.IR automount (8)
+program.
+Considerable design effort has been expended in making
+.B amd
+robust in the face of
+.SM NFS
+servers going down.
+.B Amd
+operates by attaching itself as an
+.SM NFS
+server to each of the specified
+.IB directories .
+Lookups within the specified directories
+are handled by
+.BR amd ,
+which uses the map contained in
+.I mapname
+to determine how to resolve the lookup.
+Generally, this will be a host name, some filesystem information
+and some mount options for the given filesystem.
+.SH OPTIONS
+.TP
+.B \-n
+Normalize hostnames.
+The name refered to by ${rhost} are normalized relative to the
+host database before being used.  The effect is to translate
+aliases into ``official'' names.
+.TP
+.B \-p
+Print PID.
+Outputs the process-id of
+.B amd
+to standard output where it can be saved into a file.
+.TP
+.B \-r
+Restart existing mounts.
+.B Amd
+will scan the mount file table to determine which filesystems
+are currently mounted.  Whenever one of these would have
+been auto-mounted,
+.B amd
+.I inherits
+it.
+.TP
+.B \-v
+Version.  Displays version and configuration information on standard error.
+If you send a bug report, this should be used to determine
+which version of
+.B amd
+you are using.
+.TP
+.BI \-a " temporary-directory"
+Specify an alternative location for the real mount points.
+The default is
+.BR /a .
+.TP
+.BI \-c " duration"
+Specify a
+.IR duration ,
+in seconds, that a looked up name remains
+cached when not in use.  The default is 5 minutes.
+.TP
+.BI \-d " domain"
+Specify the local domain name.  If this option is not
+given the domain name is determined from the hostname.
+.TP
+.BI \-k " kernel-arch"
+Specifies the kernel architecture.  This is used solely
+to set the ${karch} selector.
+.TP
+.BI \-l " logfile"
+Specify a logfile in which to record mount and unmount events.
+If
+.I logfile
+is the string
+.B syslog
+then the log messages will be sent to the system log daemon by
+.IR syslog (3).
+This is only available on certain systems (e.g.
+.I not
+.SM HP-UX
+and early versions of Ultrix).
+.TP
+.BI \-t " interval.interval"
+Specify the
+.IR interval ,
+in tenths of a second, between NFS/RPC/UDP retries.
+The default is 0.8 seconds.
+The second values alters the restransmit counter.
+Useful defaults are supplied if either or both
+values are missing.
+.TP
+.BI \-w " interval"
+Specify an
+.IR interval ,
+in seconds, between attempts to dismount
+filesystems that have exceeded their cached times.
+The default is 2 minutes.
+.TP
+.BI \-y " domain"
+Specify an alternative YP domain from which to fetch the YP maps.
+The default is the system domain name.
+.TP
+.BI \-x " options"
+Specify run-time logging options.  The options are a comma separated
+list chosen from: fatal, error, user, warn, info, all.
+.TP
+.BI \-D " option"
+Select from a variety of debug options.  Prefixing an
+option with the strings
+.B no
+reverses the effect of that option.  Options are cumulative.
+The most useful option is
+.BR all .
+Since
+.I \-D
+is only used for debugging other options are not documented here:
+the current supported set of options is listed by the \-v option
+and a fuller description is available in the program source.
+.SH FILES
+.PD 0
+.TP 5
+.B /a
+directory under which filesystems are dynamically mounted
+.PD
+.SH CAVEATS
+Some care may be required when creating a mount map.
+.LP
+Symbolic links on an NFS filesystem are incredibly inefficient.
+Their interpolations are not cached by the kernel and each time a symlink is
+encountered during a
+.I lookuppn
+translation it costs an RPC call to the NFS server.
+It would appear that a large improvement in real-time
+performance could be gained by adding a cache somewhere.
+Replacing symlinks with a suitable incarnation of the auto-mounter
+results in a large real-time speedup, but also causes a large
+number of process context switches.
+.LP
+A weird imagination is most useful to gain full advantage of all
+the features.
+.SH "SEE ALSO"
+.BR amq (8),
+.BR domainname (1),
+.BR hostname (1),
+.BR automount (8),
+.BR mount (8),
+.BR umount (8),
+.BR mtab (5),
+.LP
+.I "Amd \- An Automounter"
+.SH AUTHOR
+Jan-Simon Pendry <jsp@doc.ic.ac.uk>, Department of Computing, Imperial College, London, UK.
diff --git a/usr/src/usr.sbin/amd/amd/amd.c b/usr/src/usr.sbin/amd/amd/amd.c
new file mode 100644 (file)
index 0000000..76f7273
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * $Id: amd.c,v 5.2 90/06/23 22:19:18 jsp Rel $
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)amd.c       5.1 (Berkeley) %G%
+ */
+
+/*
+ * Automounter
+ */
+
+#include "am.h"
+#include <sys/signal.h>
+#include <netdb.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <setjmp.h>
+
+char pid_fsname[16 + MAXHOSTNAMELEN];  /* "kiska.southseas.nz:(pid%d)" */
+char *progname;                                /* "amd" */
+#ifdef HAS_HOST
+char *host_helper;
+#endif /* HAS_HOST */
+char *auto_dir = "/a";
+char *hostdomain = "unknown.domain";
+char hostname[MAXHOSTNAMELEN];         /* Hostname */
+char hostd[2*MAXHOSTNAMELEN];          /* Host+domain */
+char *op_sys = OS_REP;                 /* Name of current op_sys */
+char *arch = ARCH_REP;                 /* Name of current architecture */
+char *endian = ARCH_ENDIAN;            /* Big or Little endian */
+int foreground = 1;                    /* This is the top-level server */
+int mypid;                             /* Current process id */
+int immediate_abort;                   /* Should close-down unmounts be retried */
+struct in_addr myipaddr;               /* (An) IP address of this host */
+serv_state amd_state = Start;
+struct amd_stats amd_stats;            /* Server statistics */
+time_t do_mapc_reload = 0;             /* mapc_reload() call required? */
+jmp_buf select_intr;
+int select_intr_valid;
+int orig_umask;
+
+/*
+ * Signal handler:
+ * SIGINT - tells amd to do a full shutdown, including unmounting all filesystem.
+ * SIGTERM - tells amd to shutdown now.  Just unmounts the automount nodes.
+ */
+static void sigterm(sig)
+int sig;
+{
+#ifdef SYS5_SIGNALS
+       signal(sig, sigterm);
+#endif * SYS5_SIGNALS */
+
+       switch (sig) {
+       case SIGINT:
+               immediate_abort = 15;
+               break;
+
+       case SIGTERM:
+               immediate_abort = -1;
+               /* fall through... */
+
+       default:
+               plog(XLOG_WARNING, "WARNING: automounter going down on signal %d", sig);
+               break;
+       }
+       if (select_intr_valid)
+               longjmp(select_intr, sig);
+}
+
+/*
+ * Hook for cache reload.
+ * When a SIGHUP arrives it schedules a call to mapc_reload
+ */
+static void sighup(sig)
+int sig;
+{
+#ifdef SYS5_SIGNALS
+       signal(sig, sighup);
+#endif /* SUS5_SIGNALS */
+
+#ifdef DEBUG
+       if (sig != SIGHUP)
+               dlog("spurious call to sighup");
+#endif /* DEBUG */
+       /*
+        * Force a reload by zero'ing the timer
+        */
+       if (amd_state == Run)
+               do_mapc_reload = 0;
+}
+
+static void parent_exit(sig)
+int sig;
+{
+       exit(0);
+}
+
+static int daemon_mode(P_void)
+{
+       int bgpid = background();
+
+       if (bgpid != 0) {
+               if (print_pid) {
+                       printf("%d\n", bgpid);
+                       fflush(stdout);
+               }
+               /*
+                * Now wait for the automount points to
+                * complete.
+                */
+               signal(SIGQUIT, parent_exit);
+               for (;;)
+                       pause();
+       }
+
+       /*
+        * Pretend we are in the foreground again
+        */
+       foreground = 1;
+#ifdef TIOCNOTTY
+       {
+               int t = open("/dev/tty", O_RDWR);
+               if (t < 0) {
+                       if (errno != ENXIO)     /* not an error if already no controlling tty */
+                               plog(XLOG_WARNING, "Could not open controlling tty: %m");
+               } else if (ioctl(t, TIOCNOTTY, 0) < 0) {
+                       plog(XLOG_WARNING, "Could not disassociate tty (TIOCNOTTY): %m");
+               }
+       }
+#else
+       (void) setpgrp();
+#endif /* TIOCNOTTY */
+
+       return getppid();
+}
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+       struct hostent *hp, *gethostbyname();
+       char *domdot;
+       int ppid = 0;
+       int error;
+
+       /*
+        * Make sure some built-in assumptions are true before we start
+        */
+       assert(sizeof(nfscookie) >= sizeof (unsigned int));
+       assert(sizeof(int) >= 4);
+
+       /*
+        * Set processing status.
+        */
+       amd_state = Start;
+
+       /*
+        * Get local machine name
+        */
+       if (gethostname(hostname, sizeof(hostname)) < 0) {
+               plog(XLOG_FATAL, "gethostname: %m");
+               going_down(1);
+       }
+       /*
+        * Check it makes sense
+        */
+       if (!*hostname) {
+               plog(XLOG_FATAL, "host name is not set");
+               going_down(1);
+       }
+       /*
+        * Partially initialise hostd[].  This
+        * is completed in get_args().
+        */
+       if (domdot = strchr(hostname, '.')) {
+               /*
+                * Hostname already contains domainname.
+                * Split out hostname and domainname
+                * components
+                */
+               *domdot++ = '\0';
+               hostdomain = domdot;
+       }
+       strcpy(hostd, hostname);
+
+       /*
+        * Trap interrupts for shutdowns.
+        */
+       (void) signal(SIGINT, sigterm);
+
+       /*
+        * Hangups tell us to reload the cache
+        */
+       (void) signal(SIGHUP, sighup);
+
+       /*
+        * Trap Terminate so that we can shutdown gracefully (some chance)
+        */
+       (void) signal(SIGTERM, sigterm);
+       /*
+        * Trap Death-of-a-child.  These allow us to
+        * pick up the exit status of backgrounded mounts.
+        * See "sched.c".
+        */
+       (void) signal(SIGCHLD, sigchld);
+
+       /*
+        * Initialise process id.  This is kept
+        * cached since it is used for generating
+        * and using file handles.
+        */
+       mypid = getpid();
+
+#ifdef notdef
+/*
+ * XXX - Doing this plugs most of a memory leak in
+ * gethostbyname on SunOS 4.  I see no good reason
+ * why the host database needs to grab 1.5K of
+ * private data space...  However, for the moment,
+ * I will take its word that it is a _good thing_
+ * (jsp)
+ */
+       (void) sethostent(0);
+#endif /* notdef */
+
+       /*
+        * Fix-up any umask problems.  Most systems default
+        * to 002 which is not too convenient for our purposes
+        */
+       orig_umask = umask(0);
+
+       /*
+        * Determine command-line arguments
+        */
+       get_args(argc, argv);
+
+       /*
+        * Get our own IP address so that we
+        * can mount the automounter.  There
+        * is probably a better way of doing
+        * this, but messing about with SIOCGIFCONF
+        * seems to be heading towards the non-portable
+        * arena.
+        */
+       hp = gethostbyname(hostname);
+       if (!hp || hp->h_addrtype != AF_INET) {
+               plog(XLOG_FATAL, "Can't determine IP address of this host (%s)", hostname);
+               going_down(1);
+       }
+       myipaddr = *(struct in_addr *) hp->h_addr;
+
+       /*
+        * Now check we are root.
+        */
+       if (geteuid() != 0) {
+               plog(XLOG_FATAL, "Must be root to mount filesystems (euid = %d)", geteuid());
+               going_down(1);
+       }
+
+#ifdef HAS_NIS_MAPS
+       /*
+        * If the domain was specified then bind it here
+        * to circumvent any default bindings that may
+        * be done in the C library.
+        */
+       if (domain && yp_bind(domain)) {
+               plog(XLOG_FATAL, "Can't bind to domain \"%s\"", domain);
+               going_down(1);
+       }
+#endif /* HAS_NIS_MAPS */
+
+#ifdef DEBUG
+       Debug(D_DAEMON)
+#endif /* DEBUG */
+       ppid = daemon_mode();
+
+       sprintf(pid_fsname, "%s:(pid%d)", hostname, mypid);
+
+       do_mapc_reload = clocktime() + ONE_HOUR;
+
+       /*
+        * Register automounter with system
+        */
+       error = mount_automounter(ppid);
+       if (error && ppid)
+               kill(SIGALRM, ppid);
+       going_down(error);
+
+       abort();
+}
diff --git a/usr/src/usr.sbin/amd/amd/amq_subr.c b/usr/src/usr.sbin/amd/amd/amq_subr.c
new file mode 100644 (file)
index 0000000..6f0340a
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * $Id: amq_subr.c,v 5.2 90/06/23 22:19:20 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)amq_subr.c  5.1 (Berkeley) %G%
+ */
+/*
+ * Auxilliary routines for amq tool
+ */
+
+#include "am.h"
+#include "amq.h"
+
+#include <sys/param.h>
+
+/*ARGSUSED*/
+voidp
+amqproc_null_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+       static char res;
+
+       return (voidp) &res;
+}
+
+/*
+ * Return a sub-tree of mounts
+ */
+/*ARGSUSED*/
+amq_mount_tree_p *
+amqproc_mnttree_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+       static am_node *mp;
+       mp = find_ap(*(char **) argp);
+       return (amq_mount_tree_p *) &mp;
+}
+
+/*
+ * Unmount a single node
+ */
+/*ARGSUSED*/
+voidp
+amqproc_umnt_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+       static char res;
+       am_node *mp = find_ap(*(char **) argp);
+       if (mp)
+               forcibly_timeout_mp(mp);
+
+       return (voidp) &res;
+}
+
+/*
+ * Return global statistics
+ */
+/*ARGSUSED*/
+amq_mount_stats *
+amqproc_stats_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+       return (amq_mount_stats *) &amd_stats;
+}
+
+/*
+ * Return the entire tree of mount nodes
+ */
+/*ARGSUSED*/
+amq_mount_tree_list *
+amqproc_export_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+       static amq_mount_tree_list aml;
+
+#ifdef oldcode
+       static am_node **mvec;
+       int i;
+       int n = 0;
+
+       mvec = (struct am_node **)
+               xrealloc(mvec, (1+last_used_map) * sizeof(am_node *));
+       for (i = last_used_map; i >= 0; --i) {
+               am_node *mp = exported_ap[i];
+               if (mp && (mp->am_flags & AMF_ROOT))
+                       mvec[n++] = mp;
+       }
+
+       aml.amq_mount_tree_list_val = (amq_mount_tree_p *) mvec;
+       aml.amq_mount_tree_list_len = n;
+#else
+       aml.amq_mount_tree_list_val = (amq_mount_tree_p *) &exported_ap[0];
+       aml.amq_mount_tree_list_len = 1;        /* XXX */
+#endif /* oldcode */
+       return &aml;
+}
+
+int *
+amqproc_setopt_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+       static int rc;
+
+       amq_setopt *opt = (amq_setopt *) argp;
+
+       rc = 0;
+       switch (opt->as_opt) {
+       case AMOPT_DEBUG:
+#ifdef DEBUG
+               if (debug_option(opt->as_str))
+                       rc = EINVAL;
+#else
+               rc = EINVAL;
+#endif /* DEBUG */
+               break;
+
+       case AMOPT_LOGFILE:
+#ifdef not_yet
+               if (switch_to_logfile(opt->as_str))
+                       rc = EINVAL;
+#else
+               rc = EACCES;
+#endif /* not_yet */
+               break;
+
+       case AMOPT_XLOG:
+               if (switch_option(opt->as_str))
+                       rc = EINVAL;
+               break;
+
+       case AMOPT_FLUSHMAPC:
+               if (amd_state == Run) {
+                       plog(XLOG_INFO, "amq says flush cache");
+                       do_mapc_reload = 0;
+               }
+               break;
+       }
+       return &rc;
+}
+
+amq_mount_info_list *
+amqproc_getmntfs_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+extern qelem mfhead;
+       return (amq_mount_info_list *) &mfhead; /* XXX */
+}
+
+/*
+ * XDR routines.
+ */
+bool_t
+xdr_amq_string(xdrs, objp)
+       XDR *xdrs;
+       amq_string *objp;
+{
+       if (!xdr_string(xdrs, objp, AMQ_STRLEN)) {
+               return (FALSE);
+       }
+       return (TRUE);
+}
+
+bool_t
+xdr_amq_setopt(xdrs, objp)
+       XDR *xdrs;
+       amq_setopt *objp;
+{
+       if (!xdr_enum(xdrs, (enum_t *)&objp->as_opt)) {
+               return (FALSE);
+       }
+       if (!xdr_string(xdrs, &objp->as_str, AMQ_STRLEN)) {
+               return (FALSE);
+       }
+       return (TRUE);
+}
+
+/*
+ * More XDR routines  - Should be used for OUTPUT ONLY.
+ */
+bool_t
+xdr_amq_mount_tree(xdrs, objp)
+       XDR *xdrs;
+       amq_mount_tree *objp;
+{
+       am_node *mp = (am_node *) objp;
+
+       if (!xdr_amq_string(xdrs, &mp->am_mnt->mf_info)) {
+               return (FALSE);
+       }
+       if (!xdr_amq_string(xdrs, &mp->am_path)) {
+               return (FALSE);
+       }
+       if (!xdr_amq_string(xdrs, mp->am_link ? &mp->am_link : &mp->am_mnt->mf_mount)) {
+               return (FALSE);
+       }
+       if (!xdr_amq_string(xdrs, &mp->am_mnt->mf_ops->fs_type)) {
+               return (FALSE);
+       }
+       if (!xdr_long(xdrs, &mp->am_stats.s_mtime)) {
+               return (FALSE);
+       }
+       if (!xdr_u_short(xdrs, &mp->am_stats.s_uid)) {
+               return (FALSE);
+       }
+       if (!xdr_int(xdrs, &mp->am_stats.s_getattr)) {
+               return (FALSE);
+       }
+       if (!xdr_int(xdrs, &mp->am_stats.s_lookup)) {
+               return (FALSE);
+       }
+       if (!xdr_int(xdrs, &mp->am_stats.s_readdir)) {
+               return (FALSE);
+       }
+       if (!xdr_int(xdrs, &mp->am_stats.s_readlink)) {
+               return (FALSE);
+       }
+       if (!xdr_int(xdrs, &mp->am_stats.s_statfs)) {
+               return (FALSE);
+       }
+       if (!xdr_pointer(xdrs, (char **)&mp->am_osib, sizeof(amq_mount_tree), xdr_amq_mount_tree)) {
+               return (FALSE);
+       }
+       if (!xdr_pointer(xdrs, (char **)&mp->am_child, sizeof(amq_mount_tree), xdr_amq_mount_tree)) {
+               return (FALSE);
+       }
+       return (TRUE);
+}
+
+bool_t
+xdr_amq_mount_tree_p(xdrs, objp)
+       XDR *xdrs;
+       amq_mount_tree_p *objp;
+{
+       if (!xdr_pointer(xdrs, (char **)objp, sizeof(amq_mount_tree), xdr_amq_mount_tree)) {
+               return (FALSE);
+       }
+       return (TRUE);
+}
+
+
+bool_t
+xdr_amq_mount_stats(xdrs, objp)
+       XDR *xdrs;
+       amq_mount_stats *objp;
+{
+       if (!xdr_int(xdrs, &objp->as_drops)) {
+               return (FALSE);
+       }
+       if (!xdr_int(xdrs, &objp->as_stale)) {
+               return (FALSE);
+       }
+       if (!xdr_int(xdrs, &objp->as_mok)) {
+               return (FALSE);
+       }
+       if (!xdr_int(xdrs, &objp->as_merr)) {
+               return (FALSE);
+       }
+       if (!xdr_int(xdrs, &objp->as_uerr)) {
+               return (FALSE);
+       }
+       return (TRUE);
+}
+
+
+bool_t
+xdr_amq_mount_tree_list(xdrs, objp)
+       XDR *xdrs;
+       amq_mount_tree_list *objp;
+{
+        if (!xdr_array(xdrs, (char **)&objp->amq_mount_tree_list_val, (u_int *)&objp->amq_mount_tree_list_len, ~0, sizeof(amq_mount_tree_p), xdr_amq_mount_tree_p)) {
+               return (FALSE);
+       }
+       return (TRUE);
+}
+
+xdr_amq_mount_info_qelem(xdrs, qhead)
+       XDR *xdrs;
+       qelem *qhead;
+{
+       /*
+        * Compute length of list
+        */
+       mntfs *mf;
+       u_int len = 0;
+       for (mf = LAST(mntfs, qhead); mf != HEAD(mntfs, qhead); mf = PREV(mntfs, mf)) {
+               if (!(mf->mf_ops->fs_flags & FS_AMQINFO))
+                       continue;
+               len++;
+       }
+       xdr_u_int(xdrs, &len);
+
+       /*
+        * Send individual data items
+        */
+       for (mf = LAST(mntfs, qhead); mf != HEAD(mntfs, qhead); mf = PREV(mntfs, mf)) {
+               int up;
+               if (!(mf->mf_ops->fs_flags & FS_AMQINFO))
+                       continue;
+
+               if (!xdr_amq_string(xdrs, &mf->mf_ops->fs_type)) {
+                       return (FALSE);
+               }
+               if (!xdr_amq_string(xdrs, &mf->mf_mount)) {
+                       return (FALSE);
+               }
+               if (!xdr_amq_string(xdrs, &mf->mf_info)) {
+                       return (FALSE);
+               }
+               if (!xdr_amq_string(xdrs, &mf->mf_server->fs_host)) {
+                       return (FALSE);
+               }
+               if (!xdr_int(xdrs, &mf->mf_error)) {
+                       return (FALSE);
+               }
+               if (!xdr_int(xdrs, &mf->mf_refc)) {
+                       return (FALSE);
+               }
+               if (mf->mf_server->fs_flags & FSF_ERROR)
+                       up = 0;
+               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;
+               }
+               if (!xdr_int(xdrs, &up)) {
+                       return (FALSE);
+               }
+       }
+       return (TRUE);
+}
diff --git a/usr/src/usr.sbin/amd/amd/clock.c b/usr/src/usr.sbin/amd/amd/clock.c
new file mode 100644 (file)
index 0000000..c1d3ee5
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * $Id: clock.c,v 5.2 90/06/23 22:19:21 jsp Rel $
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)clock.c     5.1 (Berkeley) %G%
+ */
+
+/*
+ * Callouts.
+ *
+ * Modelled on kernel object of the same name.
+ * See usual references.
+ *
+ * Use of a heap-based mechanism was rejected:
+ * 1.  more complext implementation needed.
+ * 2.  not obvious that a list is too slow for amd.
+ */
+
+#include "am.h"
+
+typedef struct callout callout;
+struct callout {
+       callout *c_next;                /* List of callouts */
+       void    (*c_fn)();              /* Function to call */
+       voidp   c_closure;              /* Closure to pass to call */
+       time_t  c_time;                 /* Time of call */
+       int     c_id;                   /* Unique identifier */
+};
+
+static callout callouts;               /* List of pending callouts */
+static callout *free_callouts;         /* Cache of free callouts */
+static int nfree_callouts;             /* Number on free list */
+static int callout_id;                 /* Next free callout identifier */
+time_t next_softclock;                 /* Time of next call to softclock() */
+
+/*
+ * Number of callout slots we keep on the free list
+ */
+#define        CALLOUT_FREE_SLOP       10
+
+/*
+ * Assumption: valid id's are non-zero.
+ */
+#define        CID_ALLOC()     (++callout_id)
+#define        CID_UNDEF       (0)
+
+static callout *alloc_callout()
+{
+       callout *cp = free_callouts;
+       if (cp) {
+               --nfree_callouts;
+               free_callouts = free_callouts->c_next;
+               return cp;
+       }
+       return ALLOC(callout);
+}
+
+static void free_callout(cp)
+callout *cp;
+{
+       if (nfree_callouts > CALLOUT_FREE_SLOP) {
+               free((voidp) cp);
+       } else {
+               cp->c_next = free_callouts;
+               free_callouts = cp;
+               nfree_callouts++;
+       }
+}
+
+/*
+ * Schedule a callout.
+ *
+ * (*fn)(closure) will be called at clocktime() + secs
+ */
+int timeout(secs, fn, closure)
+unsigned int secs;
+void (*fn)();
+voidp closure;
+{
+       callout *cp, *cp2;
+       time_t t = clocktime() + secs;
+
+       /*
+        * Allocate and fill in a new callout structure
+        */
+       callout *cpnew = alloc_callout();
+       cpnew->c_closure = closure;
+       cpnew->c_fn = fn;
+       cpnew->c_time = t;
+       cpnew->c_id = CID_ALLOC();
+
+       if (t < next_softclock)
+               next_softclock = t;
+
+       /*
+        * Find the correct place in the list
+        */
+       for (cp = &callouts; cp2 = cp->c_next; cp = cp2)
+               if (cp2->c_time >= t)
+                       break;
+
+       /*
+        * And link it in
+        */
+       cp->c_next = cpnew;
+       cpnew->c_next = cp2;
+
+       /*
+        * Return callout identifier
+        */
+       return cpnew->c_id;
+}
+
+/*
+ * De-schedule a callout
+ */
+void untimeout(id)
+int id;
+{
+       callout *cp, *cp2;
+       for (cp = &callouts; cp2 = cp->c_next; cp = cp2) {
+               if (cp2->c_id == id) {
+                       cp->c_next = cp2->c_next;
+                       free_callout(cp2);
+                       break;
+               }
+       }
+}
+
+/*
+ * Clock handler
+ */
+int softclock()
+{
+       time_t now;
+       callout *cp;
+
+       do {
+               if (task_notify_todo)
+                       task_notify();
+
+               now = clocktime();
+
+               /*
+                * While there are more callouts waiting...
+                */
+               while ((cp = callouts.c_next) && cp->c_time <= now) {
+                       /*
+                        * Extract first from list, save fn & closure and
+                        * unlink callout from list and free.
+                        * Finally call function.
+                        *
+                        * The free is done first because
+                        * it is quite common that the
+                        * function will call timeout()
+                        * and try to allocate a callout
+                        */
+                       void (*fn)() = cp->c_fn;
+                       voidp closure = cp->c_closure;
+
+                       callouts.c_next = cp->c_next;
+                       free_callout(cp);
+#ifdef DEBUG
+                       /*dlog("Calling %#x(%#x)", fn, closure);*/
+#endif /* DEBUG */
+                       (*fn)(closure);
+               }
+
+       } while (task_notify_todo);
+
+       /*
+        * Return number of seconds to next event,
+        * or 0 if there is no event.
+        */
+       if (cp = callouts.c_next)
+               return cp->c_time - now;
+       return 0;
+}
diff --git a/usr/src/usr.sbin/amd/amd/efs_ops.c b/usr/src/usr.sbin/amd/amd/efs_ops.c
new file mode 100644 (file)
index 0000000..2d92016
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * $Id: efs_ops.c,v 5.2 90/06/23 22:19:23 jsp Rel $
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)efs_ops.c   5.1 (Berkeley) %G%
+ */
+
+#include "am.h"
+
+#ifdef HAS_EFS
+
+/*
+ * Error file system.
+ * This is used as a last resort catchall if
+ * nothing else worked.  EFS just returns lots
+ * of error codes, except for unmount which
+ * always works of course.
+ */
+
+/*
+ * EFS file system always matches
+ */
+static int efs_match(fo)
+am_opts *fo;
+{
+       fo->fs_mtab = strealloc(fo->fs_mtab, "(error-hook)");
+       return 1;
+}
+
+/*ARGSUSED*/
+static int efs_mount(mp)
+am_node *mp;
+{
+       return ENOENT;
+}
+
+/*ARGSUSED*/
+static int efs_umount(mp)
+am_node *mp;
+{
+       /*
+        * Always succeed
+        */
+
+       return 0;
+}
+
+/*
+ * EFS interface to RPC lookup() routine.
+ * Should never get here in the automounter.
+ * If we do then just give an error.
+ */
+/*ARGSUSED*/
+am_node *efs_lookuppn(mp, fname, error_return, op)
+am_node *mp;
+char *fname;
+int *error_return;
+int op;
+{
+       *error_return = ESTALE;
+       return 0;
+}
+
+/*
+ * EFS interface to RPC readdir() routine.
+ * Should never get here in the automounter.
+ * If we do then just give an error.
+ */
+/*ARGSUSED*/
+int efs_readdir(mp, cookie, dp, ep)
+am_node *mp;
+nfscookie cookie;
+dirlist *dp;
+entry *ep;
+{
+       return ESTALE;
+}
+
+/*
+ * Ops structure
+ */
+am_ops efs_ops = {
+       "error",
+       efs_match,
+       0, /* efs_init */
+       efs_mount,
+       efs_umount,
+       efs_lookuppn,
+       efs_readdir,
+       0, /* efs_readlink */
+       0, /* efs_mounted */
+       0, /* efs_umounted */
+       find_afs_srvr,
+       FS_DISCARD
+};
+
+#endif /* HAS_EFS */
diff --git a/usr/src/usr.sbin/amd/amd/get_args.c b/usr/src/usr.sbin/amd/amd/get_args.c
new file mode 100644 (file)
index 0000000..76b70a8
--- /dev/null
@@ -0,0 +1,510 @@
+/*
+ * $Id: get_args.c,v 5.2 90/06/23 22:19:24 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)get_args.c  5.1 (Berkeley) %G%
+ */
+
+/*
+ * Argument decode
+ */
+
+#include "am.h"
+#ifdef HAS_SYSLOG
+#include <syslog.h>
+#endif /* HAS_SYSLOG */
+#include <sys/stat.h>
+
+extern int optind;
+extern char *optarg;
+
+#if defined(DEBUG) && defined(PARANOID)
+char **gargv;
+#endif /* defined(DEBUG) && defined(PARANOID) */
+int restart_existing_mounts;
+int print_pid;
+int normalize_hosts;
+char *karch;                   /* Kernel architecture */
+char *cluster;                 /* Cluster name */
+#ifdef HAS_NIS_MAPS
+char *domain;                  /* YP domain */
+#endif /* HAS_NIS_MAPS */
+#ifdef UPDATE_MTAB
+char *mtab;
+#endif /* UPDATE_MTAB */
+FILE *logfp = stderr;          /* Log errors to stderr initially */
+#ifdef HAS_SYSLOG
+int syslogging;
+#endif /* HAS_SYSLOG */
+int afs_timeo = -1;
+int afs_retrans = -1;
+int am_timeo = AM_TTL;
+int am_timeo_w = AM_TTL_W;
+int xlog_level = 0;
+int xlog_level_init = ~0;
+
+/*
+ * List of log options
+ */
+static struct opt_tab xlog_opt[] = {
+       { "all", XLOG_ALL },            /* All messages */
+#ifdef DEBUG
+       { "debug", XLOG_DEBUG },        /* Debug messages */
+#endif /* DEBUG */
+       { "error", XLOG_ERROR },        /* Non-fatal system errors */
+       { "fatal", XLOG_FATAL },        /* Fatal errors */
+       { "info", XLOG_INFO },          /* Information */
+       { "map", XLOG_MAP },            /* Map errors */
+       { "stats", XLOG_STATS },        /* Additional statistical information */
+       { "user", XLOG_USER },          /* Non-fatal user errors */
+       { "warn", XLOG_WARNING },       /* Warnings */
+       { "warning", XLOG_WARNING },    /* Warnings */
+       { 0, 0 }
+};
+
+#ifdef DEBUG
+/*
+ * List of debug options.
+ */
+static struct opt_tab dbg_opt[] = {
+       { "all", D_ALL },               /* All */
+       { "amq", D_AMQ },               /* Register for AMQ program */
+       { "daemon", D_DAEMON },         /* Enter daemon mode */
+       { "full", D_FULL },             /* Program trace */
+       { "mem", D_MEM },               /* Trace memory allocations */
+       { "mtab", D_MTAB },             /* Use local mtab file */
+       { "str", D_STR },               /* Debug string munging */
+       { "test", D_TEST },             /* Full debug - but no daemon */
+       { "trace", D_TRACE },           /* Protocol trace */
+       { 0, 0 }
+};
+
+int debug_flags = D_AMQ                        /* Register AMQ */
+                |D_DAEMON              /* Enter daemon mode */
+                ;
+#endif /* DEBUG */
+
+void show_opts(ch, opts)
+int ch;
+struct opt_tab *opts;
+{
+       /*
+        * Display current debug options
+        */
+       int i;
+       int s = '{';
+       fprintf(stderr, "\t[-%c {no}", ch);
+       for (i = 0; opts[i].opt; i++) {
+               fprintf(stderr, "%c%s", s, opts[i].opt);
+               s = ',';
+       }
+       fputs("}]\n", stderr);
+}
+
+static int option(s, optb, flags)
+char *s;
+struct opt_tab *optb;
+int *flags;
+{
+       char *p = s;
+       int errs = 0;
+
+       while (p && *p) {
+               int neg;
+               char *opt;
+               struct opt_tab *dp;
+
+               s = p;
+               p = strchr(p, ',');
+               if (p)
+                       *p = '\0';
+
+               if (s[0] == 'n' && s[1] == 'o') {
+                       opt = s + 2;
+                       neg = 1;
+               } else {
+                       opt = s;
+                       neg = 0;
+               }
+
+               /*
+                * Scan the array of debug options to find the
+                * corresponding flag value.  If it is found
+                * then set (or clear) the flag (depending on
+                * whether the option was prefixed with "no").
+                */
+               for (dp = optb; dp->opt; dp++) {
+                       if (strcmp(opt, dp->opt) == 0) {
+                               if (neg)
+                                       *flags &= ~dp->flag;
+                               else
+                                       *flags |= dp->flag;
+                               break;
+                       }
+               }
+
+               if (dp->opt == 0) {
+                       /*
+                        * This will log to stderr when parsing the command line
+                        * since any -l option will not yet have taken effect.
+                        */
+                       plog(XLOG_USER, "option \"%s\" not recognised", s);
+                       errs++;
+               }
+               /*
+                * Put the comma back
+                */
+               if (p)
+                       *p++ = ',';
+       }
+
+       return errs;
+}
+
+/*
+ * Switch on/off logging options
+ */
+int switch_option(opt)
+char *opt;
+{
+       int xl = xlog_level;
+       int rc = option(opt, xlog_opt, &xl);
+       if (rc) {
+               rc = EINVAL;
+       } else {
+               /*
+                * Keep track of initial log level, and
+                * don't allow options to be turned off.
+                */
+               if (xlog_level_init == ~0)
+                       xlog_level_init = xl;
+               else
+                       xl |= xlog_level_init;
+               xlog_level = xl;
+       }
+       return rc;
+}
+
+#ifdef DEBUG
+/*
+ * Switch on/off debug options
+ */
+int debug_option(opt)
+char *opt;
+{
+       return option(opt, dbg_opt, &debug_flags);
+}
+#endif /* DEBUG */
+
+/*
+ * Change current logfile
+ */
+int switch_to_logfile(logfile)
+char *logfile;
+{
+       FILE *new_logfp = stderr;
+
+       if (logfile) {
+#ifdef HAS_SYSLOG
+               syslogging = 0;
+#endif /* HAS_SYSLOG */
+               if (strcmp(logfile, "/dev/stderr") == 0)
+                       new_logfp = stderr;
+               else if (strcmp(logfile, "syslog") == 0) {
+#ifdef HAS_SYSLOG
+                       syslogging = 1;
+                       new_logfp = stderr;
+#ifdef LOG_CONS
+                       openlog(progname, LOG_PID|LOG_CONS|LOG_NOWAIT,
+                               LOG_DAEMON);
+#else
+                       /* 4.2 compat mode - XXX */
+                       openlog(progname, LOG_PID);
+#endif /* LOG_CONS */
+#else
+                       plog(XLOG_WARNING, "syslog option not supported, logging unchanged");
+#endif /* HAS_SYSLOG */
+               } else {
+                       (void) umask(orig_umask);
+                       new_logfp = fopen(logfile, "a");
+                       umask(0);
+               }
+       }
+
+       /*
+        * If we couldn't open a new file, then continue using the old.
+        */
+       if (!new_logfp && logfile) {
+               plog(XLOG_USER, "%s: Can't open logfile: %m", logfile);
+               return 1;
+       }
+       /*
+        * Close the previous file
+        */
+       if (logfp && logfp != stderr)
+               (void) fclose(logfp);
+       logfp = new_logfp;
+       return 0;
+}
+
+void get_args(c, v)
+int c;
+char *v[];
+{
+       int opt_ch;
+       int usage = 0;
+       char *logfile = 0;
+       char *sub_domain = 0;
+
+#if defined(DEBUG) && defined(PARANOID)
+       gargv = v;
+       progname = v[0];                /* Use argv[0] to try to solve Piete's problem */
+#else
+       if (v[0]) {
+               progname = strrchr(v[0], '/');
+               if (progname && progname[1])
+                       progname++;
+               else
+                       progname = v[0];
+       }
+#endif /* defined(DEBUG) && defined(PARANOID) */
+       if (!progname)
+               progname = "amd";
+
+       while ((opt_ch = getopt(c, v, "mnprva:c:d:h:k:l:t:w:x:y:C:D:")) != EOF)
+       switch (opt_ch) {
+       case 'a':
+               if (*optarg != '/') {
+                       fprintf(stderr, "%s: -a option must begin with a '/'\n",
+                                       progname);
+                       exit(1);
+               }
+               auto_dir = optarg;
+               break;
+
+       case 'c':
+               am_timeo = atoi(optarg);
+               if (am_timeo <= 0)
+                       am_timeo = AM_TTL;
+               break;
+
+       case 'd':
+               sub_domain = optarg;
+               break;
+
+       case 'h':
+#if defined(HAS_HOST) && defined(HOST_EXEC)
+               host_helper = optarg;
+#else
+               plog(XLOG_USER, "-h: option ignored.  HOST_EXEC is not enabled.");
+               break;
+#endif /* defined(HAS_HOST) && defined(HOST_EXEC) */
+
+       case 'k':
+               karch = optarg;
+               break;
+
+       case 'l':
+               logfile = optarg;
+               break;
+
+       case 'm':
+               plog(XLOG_USER, "The -m option is no longer supported.");
+               plog(XLOG_USER, "... Use `ypcat -k am.master` on the command line instead");
+               break;
+
+       case 'n':
+               normalize_hosts = 1;
+               break;
+
+       case 'p':
+               print_pid = 1;
+               break;
+
+       case 'r':
+               restart_existing_mounts = 1;
+               break;
+
+       case 't':
+               /* timeo.retrans */
+               { char *dot = strchr(optarg, '.');
+                 if (dot) *dot = '\0';
+                 if (*optarg) {
+                       afs_timeo = atoi(optarg);
+                 }
+                 if (dot) {
+                       afs_retrans = atoi(dot+1);
+                       *dot = '.';
+                 }
+               }
+               break;
+
+       case 'v':
+               { char buf[256];
+                 show_rcs_info(version, buf);
+                 fputs(buf, stderr);
+               }
+               fprintf(stderr,
+                       " for a%s %s running %s (%s-endian)\n",
+                                       strchr("aeiou", arch[0]) ? "n" : "",
+                                       arch, op_sys, endian);
+               fputs("Map support for: ", stderr);
+               mapc_showtypes(stderr);
+               fputs(".\n", stderr);
+               exit(0);
+               break;
+
+       case 'w':
+               am_timeo_w = atoi(optarg);
+               if (am_timeo_w <= 0)
+                       am_timeo_w = AM_TTL_W;
+               break;
+
+       case 'x':
+               usage += switch_option(optarg);
+               break;
+
+       case 'y':
+#ifdef HAS_NIS_MAPS
+               domain = optarg;
+#else
+               plog(XLOG_USER, "-y: option ignored.  No NIS support available.");
+#endif /* HAS_NIS_MAPS */
+               break;
+
+       case 'C':
+               cluster = optarg;
+               break;
+
+       case 'D':
+#ifdef DEBUG
+               usage += debug_option(optarg);
+#else
+               fprintf(stderr, "%s: not compiled with DEBUG option -- sorry.\n", progname);
+#endif /* DEBUG */
+               break;
+
+       default:
+               usage = 1;
+               break;
+       }
+
+       if (xlog_level == 0) {
+               /* Take copy to avoid writable-strings problem */
+               char *dfstr = strdup(XLOG_DEFSTR);
+               usage += switch_option(dfstr);
+               free((voidp) dfstr);
+#ifdef DEBUG
+               usage += switch_option("debug");
+#endif /* DEBUG */
+       } else {
+#ifdef DEBUG
+               usage += switch_option("debug");
+#endif /* DEBUG */
+       }
+
+       if (usage)
+               goto show_usage;
+
+       while (optind <= c-2) {
+               char *dir = v[optind++];
+               char *map = v[optind++];
+               char *opts = "";
+               if (v[optind] && *v[optind] == '-')
+                       opts = &v[optind++][1];
+
+               root_newmap(dir, opts, map);
+       }
+
+       if (optind == c) {
+#ifdef hpux
+               /*
+                * HP-UX can't handle ./mtab
+                * That system is sick - really.
+                */
+#ifdef DEBUG
+               debug_option("nomtab");
+#endif /* DEBUG */
+#endif /* hpux */
+
+               /*
+                * Append domain name to hostname.
+                * sub_domain overrides hostdomain
+                * if given.
+                */
+               if (sub_domain)
+                       hostdomain = sub_domain;
+               if (*hostdomain == '.')
+                       hostdomain++;
+               strcat(hostd,  ".");
+               strcat(hostd, hostdomain);
+
+#ifdef UPDATE_MTAB
+#ifdef DEBUG
+               if (debug_flags & D_MTAB)
+                       mtab = DEBUG_MTAB;
+               else
+#endif /* DEBUG */
+               mtab = MOUNTED;
+#else
+#ifdef DEBUG
+               { if (debug_flags & D_MTAB) {
+                       dlog("-D mtab option ignored");
+               } }
+#endif /* DEBUG */
+#endif /* UPDATE_MTAB */
+
+               if (switch_to_logfile(logfile) != 0)
+                       plog(XLOG_USER, "Cannot switch logfile");
+
+               /*
+                * If the kernel architecture was not specified
+                * then use the machine architecture.
+                */
+               if (karch == 0)
+                       karch = arch;
+
+               if (cluster == 0)
+                       cluster = hostdomain;
+
+               if (afs_timeo <= 0)
+                       afs_timeo = AFS_TIMEO;
+               if (afs_retrans <= 0)
+                       afs_retrans = AFS_RETRANS;
+               if (afs_retrans <= 0)
+                       afs_retrans = 3;        /* XXX */
+               return;
+       }
+
+show_usage:
+       fprintf(stderr,
+"Usage: %s [-mnprv] [-a mnt_point] [-c cache_time] [-d domain]\n\
+\t[-k kernel_arch] [-l logfile|\"syslog\"] [-t afs_timeout]\n\
+\t[-w wait_timeout] [-C cluster_name]", progname);
+
+#if defined(HAS_HOST) && defined(HOST_EXEC)
+       fputs(" [-h host_helper]\n", stderr);
+#endif /* defined(HAS_HOST) && defined(HOST_EXEC) */
+
+#ifdef HAS_NIS_MAPS
+       fputs(" [-y nis-domain]\n", stderr);
+#else
+       fputc('\n', stderr);
+#endif /* HAS_NIS_MAPS */
+
+       show_opts('x', xlog_opt);
+#ifdef DEBUG
+       show_opts('D', dbg_opt);
+#endif /* DEBUG */
+       fprintf(stderr, "\t{directory mapname [-map_options]} ...\n");
+       exit(1);
+}
diff --git a/usr/src/usr.sbin/amd/amd/host_ops.c b/usr/src/usr.sbin/amd/amd/host_ops.c
new file mode 100644 (file)
index 0000000..efbfa3a
--- /dev/null
@@ -0,0 +1,511 @@
+/*
+ * $Id: host_ops.c,v 5.2 90/06/23 22:19:26 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)host_ops.c  5.1 (Berkeley) %G%
+ */
+
+#include "am.h"
+
+#ifdef HAS_HOST
+
+#include "mount.h"
+#include <sys/stat.h>
+
+/*
+ * NFS host file system
+ */
+
+/*
+ * Define HOST_RPC_UDP to use dgram instead of stream RPC.
+ * Datagrams are generally much faster.
+ */
+#define        HOST_RPC_UDP
+
+/*
+ * Define HOST_MKDIRS to make Amd automatically try
+ * to create the mount points.
+ */
+#define HOST_MKDIRS
+
+/*
+ * Execute needs the same as NFS plus a helper command
+ */
+static int host_match(fo)
+am_opts *fo;
+{
+#ifdef HOST_EXEC
+       if (!host_helper) {
+               plog(XLOG_USER, "No host helper command given");
+               return FALSE;
+       }
+#endif /* HOST_EXEC */
+
+       /*
+        * Make sure rfs is specified to keep nfs_match happy...
+        */
+       if (!fo->opt_rfs)
+               fo->opt_rfs = "/";
+
+       if (!(*nfs_ops.fs_match)(fo))
+               return FALSE;
+
+       return TRUE;
+}
+
+static int host_init(mf)
+mntfs *mf;
+{
+       if (strchr(mf->mf_info, ':') == 0)
+               return ENOENT;
+       return 0;
+}
+
+/*
+ * Two implementations:
+ * HOST_EXEC gets you the external version.  The program specified with
+ * the -h option is called.  The external program is not published...
+ * roll your own.
+ *
+ * Otherwise you get the native version.  Faster but makes the program
+ * bigger.
+ */
+
+#ifndef HOST_EXEC
+
+static bool_t
+xdr_pri_free(xdr_args, args_ptr)
+xdrproc_t xdr_args;
+caddr_t args_ptr;
+{
+       XDR xdr;
+       xdr.x_op = XDR_FREE;
+       return ((*xdr_args)(&xdr, args_ptr));
+}
+
+static int do_mount(fhp, dir, fs_name, opts, mf)
+fhstatus *fhp;
+char *dir;
+char *fs_name;
+char *opts;
+mntfs *mf;
+{
+       struct stat stb;
+#ifdef DEBUG
+       dlog("host: mounting fs %s on %s\n", fs_name, dir);
+#endif /* DEBUG */
+#ifdef HOST_MKDIRS
+       (void) mkdirs(dir, 0555);
+#endif /* HOST_MKDIRS */
+       if (stat(dir, &stb) < 0 || (stb.st_mode & S_IFMT) != S_IFDIR) {
+               plog(XLOG_ERROR, "No mount point for %s - skipping", dir);
+               return ENOENT;
+       }
+
+       return mount_nfs_fh(fhp, dir, fs_name, opts, mf);
+}
+
+static sortfun(a, b)
+exports *a,*b;
+{
+       return strcmp((*a)->ex_dir, (*b)->ex_dir);
+}
+
+/*
+ * Get filehandle
+ */
+static int fetch_fhandle(client, dir, fhp)
+CLIENT *client;
+char *dir;
+fhstatus *fhp;
+{
+       struct timeval tv;
+       enum clnt_stat clnt_stat;
+
+       /*
+        * Pick a number, any number...
+        */
+       tv.tv_sec = 10;
+       tv.tv_usec = 0;
+
+#ifdef DEBUG
+       dlog("Fetching fhandle for %s", dir);
+#endif /* DEBUG */
+       /*
+        * Call the mount daemon on the remote host to
+        * get the filehandle.
+        */
+       clnt_stat = clnt_call(client, MOUNTPROC_MNT, xdr_dirpath, &dir, xdr_fhstatus, fhp, tv);
+       if (clnt_stat != RPC_SUCCESS) {
+               extern char *clnt_sperrno();
+               char *msg = clnt_sperrno(clnt_stat);
+               plog(XLOG_ERROR, "mountd rpc failed: %s", msg);
+               return EIO;
+       }
+       /*
+        * Check status of filehandle
+        */
+       if (fhp->fhs_status) {
+#ifdef DEBUG
+               errno = fhp->fhs_status;
+               dlog("fhandle fetch failed: %m");
+#endif /* DEBUG */
+               return fhp->fhs_status;
+       }
+       return 0;
+}
+
+/*
+ * Mount the export tree from a host
+ */
+static int host_mount(mp)
+am_node *mp;
+{
+       struct timeval tv2;
+       CLIENT *client;
+       enum clnt_stat clnt_stat;
+       int n_export;
+       int j;
+       exports exlist = 0, ex;
+       exports *ep = 0;
+       fhstatus *fp = 0;
+       mntfs *mf = mp->am_mnt;
+       char *host = mf->mf_server->fs_host;
+       int error = 0;
+       struct sockaddr_in sin;
+       int sock = RPC_ANYSOCK;
+       int ok = FALSE;
+       
+#ifdef HOST_RPC_UDP
+       struct timeval tv;
+       tv.tv_sec = 10; tv.tv_usec = 0;
+#endif /* HOST_RPC_UDP */
+
+       /*
+        * Take a copy of the server address
+        */
+       sin = *mf->mf_server->fs_ip;
+
+       /*
+        * Zero out the port - make sure we recompute
+        */
+       sin.sin_port = 0;
+       /*
+        * Make a client end-point
+        */
+#ifdef HOST_RPC_UDP
+       if ((client = clntudp_create(&sin, MOUNTPROG, MOUNTVERS, tv, &sock)) == NULL)
+#else
+       if ((client = clnttcp_create(&sin, MOUNTPROG, MOUNTVERS, &sock, 0, 0)) == NULL)
+#endif /* HOST_RPC_UDP */
+       {
+               plog(XLOG_ERROR, "Failed to make rpc connection to mountd on %s", host);
+               error = EIO;
+               goto out;
+       }
+
+       if (!nfs_auth) {
+               nfs_auth = authunix_create_default();
+               if (!nfs_auth) {
+                       error = ENOBUFS;
+                       goto out;
+               }
+       }
+
+       client->cl_auth = nfs_auth;
+
+#ifdef DEBUG
+       dlog("Fetching export list from %s", host);
+#endif /* DEBUG */
+
+       /*
+        * Fetch the export list
+        */
+       tv2.tv_sec = 10; tv2.tv_usec = 0;
+       clnt_stat = clnt_call(client, MOUNTPROC_EXPORT, xdr_void, 0, xdr_exports, &exlist, tv2);
+       if (clnt_stat != RPC_SUCCESS) {
+               /*clnt_perror(client, "rpc");*/
+               error = EIO;
+               goto out;
+       }
+
+       /*
+        * Figure out how many exports were returned
+        */
+       for (n_export = 0, ex = exlist; ex; ex = ex->ex_next) {
+               /*printf("export %s\n", ex->ex_dir);*/
+               n_export++;
+       }
+#ifdef DEBUG
+       /*dlog("%d exports returned\n", n_export);*/
+#endif /* DEBUG */
+
+       /*
+        * Allocate an array of pointers into the list
+        * so that they can be sorted.
+        */
+       ep = (exports *) xmalloc(n_export * sizeof(exports));
+       for (j = 0, ex = exlist; ex; ex = ex->ex_next, j++)
+               ep[j] = ex;
+
+       /*
+        * Sort into order.
+        * This way the mounts are done in order down the tree,
+        * instead of any random order returned by the mount
+        * daemon (the protocol doesn't specify...).
+        */
+       qsort(ep, n_export, sizeof(exports), sortfun);
+
+       /*
+        * Allocate an array of filehandles
+        */
+       fp = (fhstatus *) xmalloc(n_export * sizeof(fhstatus));
+
+       /*
+        * Try to obtain filehandles for each directory.
+        * If a fetch fails then just zero out the array
+        * reference but discard the error.
+        */
+       for (j = 0; j < n_export; j++) {
+               if (error = fetch_fhandle(client, ep[j]->ex_dir, &fp[j]))
+                       ep[j] = 0;
+       }
+
+       /*
+        * Mount each filesystem for which we have a filehandle.
+        * If any of the mounts succeed then mark "ok" and return
+        * error code 0 at the end.  If they all fail then return
+        * the last error code.
+        */
+       for (j = 0; j < n_export; j++) {
+               ex = ep[j];
+               if (ex) {
+                       char fs_name[MAXPATHLEN];
+                       char mntpt[MAXPATHLEN];
+                       sprintf(fs_name, "%s:%s", host, ex->ex_dir);
+                       if (strcmp(ex->ex_dir, "/") == 0)
+                               strcpy(mntpt, mf->mf_mount);
+                       else
+                               sprintf(mntpt, "%s%s", mf->mf_mount, ex->ex_dir);
+                       error = do_mount(&fp[j], mntpt, fs_name, mf->mf_fo->opt_opts, mf);
+                       if (!error)
+                               ok = TRUE;
+               }
+       }
+
+       /*
+        * Clean up and exit
+        */
+out:
+       if (ep)
+               free(ep);
+       if (fp)
+               free(fp);
+       if (client)
+               clnt_destroy(client);
+       if (exlist)
+               xdr_pri_free(xdr_exports, &exlist);
+       if (ok)
+               return 0;
+       return error;
+}
+
+/*
+ * Return true if pref is a directory prefix of dir.
+ *
+ * TODO:
+ * Does not work if pref is "/".
+ */
+static int directory_prefix(pref, dir)
+char *pref;
+char *dir;
+{
+       int len = strlen(pref);
+       if (strncmp(pref, dir, len) != 0)
+               return FALSE;
+       if (dir[len] == '/' || dir[len] == '\0')
+               return TRUE;
+       return FALSE;
+}
+
+/*
+ * Unmount a mount tree
+ */
+static int host_umount(mp)
+am_node *mp;
+{
+       mntfs *mf = mp->am_mnt;
+       mntlist *ml, *mprev;
+       int xerror = 0;
+
+       /*
+        * Read the mount list
+        */
+       mntlist *mlist = read_mtab(mf->mf_mount);
+
+       /*
+        * Unlock the mount list
+        */
+       unlock_mntlist();
+
+       /*
+        * Reverse list...
+        */
+       ml = mlist;
+       mprev = 0;
+       while (ml) {
+               mntlist *ml2 = ml->mnext;
+               ml->mnext = mprev;
+               mprev = ml;
+               ml = ml2;
+       }
+       mlist = mprev;
+
+       /*
+        * Unmount all filesystems...
+        */
+       for (ml = mlist; ml; ml = ml->mnext) {
+               char *dir = ml->mnt->mnt_dir;
+               if (directory_prefix(mf->mf_mount, dir)) {
+                       int error;
+#ifdef DEBUG
+                       dlog("host: unmounts %s", dir);
+#endif /* DEBUG */
+                       /*
+                        * Unmount "dir"
+                        */
+                       error = UMOUNT_FS(dir);
+                       /*
+                        * Keep track of errors
+                        */
+                       if (error) {
+                               if (!xerror)
+                                       xerror = error;
+                               if (error != EBUSY) {
+                                       errno = error;
+                                       plog("Tree unmount of %s failed: %m", ml->mnt->mnt_dir);
+                               }
+                       } else {
+#ifdef HOST_MKDIRS
+                               (void) rmdirs(dir);
+#endif /* HOST_MKDIRS */
+                       }
+               }
+       }
+
+       /*
+        * Throw away mount list
+        */
+       discard_mntlist(mlist);
+
+       return xerror;
+}
+
+#else /* HOST_EXEC */
+
+static int host_exec(op, host, fs, opts)
+char *op;
+char *host;
+char *fs;
+char *opts;
+{
+       int error;
+       char *argv[7];
+
+       /*
+        * Build arg vector
+        */
+       argv[0] = host_helper;
+       argv[1] = host_helper;
+       argv[2] = op;
+       argv[3] = host;
+       argv[4] = fs;
+       argv[5] = opts && *opts ? opts : "rw,default";
+       argv[6] = 0;
+
+       /*
+        * Put stdout to stderr
+        */
+       (void) fclose(stdout);
+       (void) dup(fileno(logfp));
+       if (fileno(logfp) != fileno(stderr)) {
+               (void) fclose(stderr);
+               (void) dup(fileno(logfp));
+       }
+       /*
+        * Try the exec
+        */
+#ifdef DEBUG
+       Debug(D_FULL) {
+               char **cp = argv;
+               plog(XLOG_DEBUG, "executing (un)mount command...");
+               while (*cp) {
+                       plog(XLOG_DEBUG, "arg[%d] = '%s'", cp-argv, *cp);
+                       cp++;
+               }
+       }
+#endif /* DEBUG */
+       if (argv[0] == 0 || argv[1] == 0) {
+               errno = EINVAL;
+               plog(XLOG_USER, "1st/2nd args missing to (un)mount program");
+       } else {
+               (void) execv(argv[0], argv+1);
+       }
+       /*
+        * Save error number
+        */
+       error = errno;
+       plog(XLOG_ERROR, "exec %s failed: %m", argv[0]);
+
+       /*
+        * Return error
+        */
+       return error;
+}
+
+static int host_mount(mp)
+am_node *mp;
+{
+       mntfs *mf = mp->am_mnt;
+
+       return host_exec("mount", mf->mf_server->fs_host, mf->mf_mount, mf->mf_fo->opt_opts);
+}
+
+static int host_umount(mp)
+am_node *mp;
+{
+       mntfs *mf = mp->am_mnt;
+
+       return host_exec("unmount", mf->mf_server->fs_host, mf->mf_mount, "xxx");
+}
+
+#endif /* HOST_EXEC */
+
+/*
+ * Ops structure
+ */
+am_ops host_ops = {
+       "host",
+       host_match,
+       host_init,
+       host_mount,
+       host_umount,
+       efs_lookuppn,
+       efs_readdir,
+       0, /* host_readlink */
+       0, /* host_mounted */
+       0, /* host_umounted */
+       find_nfs_srvr,
+       FS_MKMNT|FS_BACKGROUND|FS_AMQINFO
+};
+
+#endif /* HAS_HOST */
diff --git a/usr/src/usr.sbin/amd/amd/ifs_ops.c b/usr/src/usr.sbin/amd/amd/ifs_ops.c
new file mode 100644 (file)
index 0000000..7704063
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * $Id: ifs_ops.c,v 5.2 90/06/23 22:19:28 jsp Rel $
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)ifs_ops.c   5.1 (Berkeley) %G%
+ */
+
+#include "am.h"
+
+#ifdef HAS_IFS
+
+/*
+ * Inheritance file system.
+ * This implements a filesystem restart.
+ *
+ * This is a *gross* hack - it knows far too
+ * much about the way other parts of the
+ * sytem work.  See restart.c too.
+ */
+static char not_a_filesystem[] = "Attempting to inherit not-a-filesystem";
+/*
+ * This should never be called.
+ */
+static int ifs_match()
+{
+       plog(XLOG_FATAL, "ifs_match called!");
+       return FALSE;
+}
+
+static int ifs_init(mf)
+mntfs *mf;
+{
+       mntfs *mf_link = (mntfs *) mf->mf_private;
+       if (mf_link == 0) {
+               plog(XLOG_FATAL, not_a_filesystem);
+               return EINVAL;
+       }
+       /*
+        * Fill in attribute fields
+        */
+       mf_link->mf_fattr.type = NFLNK;
+       mf_link->mf_fattr.mode = NFSMODE_LNK | 0777;
+       mf_link->mf_fattr.nlink = 1;
+       mf_link->mf_fattr.size = MAXPATHLEN / 4;
+       if (mf_link->mf_ops->fs_init)
+               return (*mf_link->mf_ops->fs_init)(mf_link);
+       return 0;
+}
+
+/*ARGSUSED*/
+static int ifs_mount(mp)
+am_node *mp;
+{
+       mntfs *mf = mp->am_mnt;
+
+       /*
+        * Take the linked mount point and
+        * propogate.
+        */
+       mntfs *mf_link = (mntfs *) mf->mf_private;
+       if (mf_link == 0) {
+               plog(XLOG_FATAL, not_a_filesystem);
+               return EINVAL;  /*XXX*/
+       }
+
+       mf_link->mf_fo = mf->mf_fo;
+       mf_link->mf_fattr.fileid = mf->mf_fattr.fileid;
+
+       /*
+        * Discard the old map.
+        * Don't call am_unmounted since this
+        * node was never really mounted in the
+        * first place.
+        */
+       mf->mf_private = 0;
+       free_mntfs(mf);
+       /*
+        * Free the dangling reference
+        * to the mount link.
+        */
+       free_mntfs(mf_link);
+       /*
+        * Get a hold of the other entry
+        */
+       mp->am_mnt = mf = mf_link;
+       mf->mf_flags &= ~MFF_RESTART;
+
+       /* Say what happened */
+       plog(XLOG_INFO, "restarting %s on %s", mf->mf_info, mf->mf_mount);
+
+       /*
+        * XXX - must do the am_mounted call here
+        */
+       if (mf->mf_ops->fs_flags & FS_MBACKGROUND)
+               am_mounted(mp);
+
+       new_ttl(mp);
+
+       return 0;
+}
+
+/*ARGSUSED*/
+static int ifs_umount(mp)
+am_node *mp;
+{
+       /*
+        * Always succeed
+        */
+       return 0;
+}
+
+/*
+ * Ops structure
+ */
+am_ops ifs_ops = {
+       "inherit",
+       ifs_match,
+       ifs_init,
+       ifs_mount,
+       ifs_umount,
+       efs_lookuppn,
+       efs_readdir,
+       0, /* ifs_readlink */
+       0, /* ifs_mounted */
+       0, /* ifs_umounted */
+       find_afs_srvr,
+       FS_DISCARD
+};
+
+#endif /* HAS_IFS */
diff --git a/usr/src/usr.sbin/amd/amd/info_file.c b/usr/src/usr.sbin/amd/amd/info_file.c
new file mode 100644 (file)
index 0000000..1c16ebe
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * $Id: info_file.c,v 5.2 90/06/23 22:19:29 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)info_file.c 5.1 (Berkeley) %G%
+ */
+
+/*
+ * Get info from file
+ */
+
+#include "am.h"
+
+#ifdef HAS_FILE_MAPS
+#include <ctype.h>
+#include <sys/stat.h>
+
+#define        MAX_LINE_LEN    2048
+
+static int read_line(buf, size, fp)
+char *buf;
+int size;
+FILE *fp;
+{
+       int done = 0;
+
+       do {
+               while (fgets(buf, size, fp)) {
+                       int len = strlen(buf);
+                       done += len;
+                       if (len > 1 && buf[len-2] == '\\' &&
+                                       buf[len-1] == '\n') {
+                               int ch;
+                               buf += len - 2;
+                               size -= len - 2;
+                               /*
+                                * Skip leading white space on next line
+                                */
+                               while ((ch = getc(fp)) != EOF &&
+                                       isascii(ch) && isspace(ch))
+                                               ;
+                               (void) ungetc(ch, fp);
+                       } else {
+                               return done;
+                       }
+               }
+       } while (size > 0 && !feof(fp));
+
+       return done;
+}
+
+/*
+ * Try to locate a key in a file
+ */
+static int search_or_reload_file(fp, map, key, val, m, fn)
+FILE *fp;
+char *map;
+char *key;
+char **val;
+mnt_map *m;
+void (*fn) P((mnt_map*, char*, char*));
+{
+       char key_val[MAX_LINE_LEN];
+       int chuck = 0;
+       int line_no = 0;
+
+       while (read_line(key_val, sizeof(key_val), fp)) {
+               char *kp;
+               char *cp;
+               char *hash;
+               int len = strlen(key_val);
+               line_no++;
+
+               /*
+                * Make sure we got the whole line
+                */
+               if (key_val[len-1] != '\n') {
+                       plog(XLOG_WARNING, "line %d in \"%s\" is too long", line_no, map);
+                       chuck = 1;
+               } else {
+                       key_val[len-1] = '\0';
+               }
+
+               /*
+                * Strip comments
+                */
+               hash = strchr(key_val, '#');
+               if (hash)
+                       *hash = '\0';
+
+               /*
+                * Find start of key
+                */
+               for (kp = key_val; *kp && isascii(*kp) && isspace(*kp); kp++)
+                       ;
+
+               /*
+                * Ignore blank lines
+                */
+               if (!*kp)
+                       goto again;
+
+               /*
+                * Find end of key
+                */
+               for (cp = kp; *cp&&(!isascii(*cp)||!isspace(*cp)); cp++)
+                       ;
+
+               /*
+                * Check whether key matches
+                */
+               if (*cp)
+                       *cp++ = '\0';
+
+               if ((*key == *kp && strcmp(key, kp) == 0) || fn) {
+                       while (*cp && isascii(*cp) && isspace(*cp))
+                               cp++;
+                       if (*cp) {
+                               /*
+                                * Return a copy of the data
+                                */
+                               char *dc = strdup(cp);
+                               if (fn)
+                                       (*fn)(m, kp, dc);
+                               else
+                                       *val = dc;
+#ifdef DEBUG
+                               dlog("%s returns %s", key, dc);
+#endif /* DEBUG */
+                               if (!fn)
+                                       return 0;
+                       } else {
+                               plog(XLOG_USER, "%s: line %d has no value field", map, line_no);
+                       }
+               }
+
+again:
+               /*
+                * If the last read didn't get a whole line then
+                * throw away the remainder before continuing...
+                */
+               if (chuck) {
+                       while (fgets(key_val, sizeof(key_val), fp) &&
+                               !strchr(key_val, '\n'))
+                                       ;
+                       chuck = 0;
+               }
+       }
+
+       return fn ? 0 : ENOENT;
+}
+
+int file_init(map)
+char *map;
+{
+       FILE *mapf = fopen(map, "r");
+       if (mapf) {
+               (void) fclose(mapf);
+               return 0;
+       }
+       return errno;
+}
+
+int file_reload(m, map, fn)
+mnt_map *m;
+char *map;
+void (*fn)();
+{
+       FILE *mapf = fopen(map, "r");
+       if (mapf) {
+               int error = search_or_reload_file(mapf, map, 0, 0, m, fn);
+               (void) fclose(mapf);
+               return error;
+       }
+
+       return errno;
+}
+
+int file_search(m, map, key, pval, tp)
+mnt_map *m;
+char *map;
+char *key;
+char **pval;
+time_t *tp;
+{
+       FILE *mapf = fopen(map, "r");
+       if (mapf) {
+               struct stat stb;
+               int error;
+               error = fstat(fileno(mapf), &stb);
+               if (!error && *tp < stb.st_mtime) {
+                       *tp = stb.st_mtime;
+                       error = -1;
+               } else {
+                       error = search_or_reload_file(mapf, map, key, pval, 0, 0);
+               }
+               (void) fclose(mapf);
+               return error;
+       }
+
+       return errno;
+}
+#endif /* HAS_FILE_MAPS */
diff --git a/usr/src/usr.sbin/amd/amd/info_hes.c b/usr/src/usr.sbin/amd/amd/info_hes.c
new file mode 100644 (file)
index 0000000..6cb1e58
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * $Id: info_hes.c,v 5.2 90/06/23 22:19:30 jsp Rel $
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)info_hes.c  5.1 (Berkeley) %G%
+ */
+
+/*
+ * Get info from Hesiod
+ */
+
+#include "am.h"
+
+#ifdef HAS_HESIOD_MAPS
+#include <hesiod.h>
+
+#define        HES_PREFIX      "hesiod."
+#define        HES_PREFLEN     7
+
+/*
+ * No way to probe the server - check the map name begins with "hesiod."
+ */
+hesiod_init(map)
+char *map;
+{
+       return strncmp(map, HES_PREFIX, HES_PREFLEN) == 0 ? 0 : ENOENT;
+}
+
+
+/*
+ * Do a Hesiod nameserver call.
+ * Modify time is ignored by Hesiod - XXX
+ */
+int hesiod_search(m, map, key, pval, tp)
+mnt_map *m;
+char *map;
+char *key;
+char **pval;
+time_t *tp;
+{
+       int error;
+       char hes_map[MAXPATHLEN];
+       char **rvec;
+       /*
+        * Make Hesiod name.  Skip past the "hesiod."
+        * at the start of the map name and append
+        * ".automount".  The net effect is that a lookup
+        * of /defaults in hesiod.home will result in a
+        * call to hes_resolve("/defaults", "home.automount");
+        */
+       sprintf(hes_map, "%s%s", map + HES_PREFLEN, ".automount");
+       /*
+        * Call the resolver
+        */
+       rvec = hes_resolve(key, hes_map);
+       /*
+        * If a reply was forthcoming then return
+        * it (and free subsequent replies)
+        */
+       if (rvec && *rvec) {
+               *pval = *rvec;
+               while (*++rvec)
+                       free(*rvec);
+               return 0;
+       }
+
+       /*
+        * Otherwise reflect the hesiod error into a Un*x error
+        */
+       switch (hes_error()) {
+       case HES_ER_NOTFOUND:   error = ENOENT; break;
+       case HES_ER_CONFIG:     error = EIO; break;
+       case HES_ER_NET:        error = ETIMEDOUT; break;
+       default:                error = EINVAL; break;
+       }
+       return error;
+}
+#endif /* HAS_HESIOD_MAPS */
diff --git a/usr/src/usr.sbin/amd/amd/info_ndbm.c b/usr/src/usr.sbin/amd/amd/info_ndbm.c
new file mode 100644 (file)
index 0000000..2566380
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * $Id: info_ndbm.c,v 5.2 90/06/23 22:19:31 jsp Rel $
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)info_ndbm.c 5.1 (Berkeley) %G%
+ */
+
+/*
+ * Get info from NDBM map
+ */
+
+#include "am.h"
+
+#ifdef HAS_NDBM_MAPS
+
+#include <ndbm.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+static int search_ndbm(db, key, val)
+DBM *db;
+char *key;
+char **val;
+{
+       datum k, v;
+       k.dptr = key;
+       k.dsize = strlen(key) + 1;
+       v = dbm_fetch(db, k);
+       if (v.dptr) {
+               *val = strdup(v.dptr);
+               return 0;
+       }
+       return ENOENT;
+}
+
+int ndbm_search(m, map, key, pval, tp)
+mnt_map *m;
+char *map;
+char *key;
+char **pval;
+time_t *tp;
+{
+       DBM *db;
+
+       db = dbm_open(map, O_RDONLY, 0);
+       if (db) {
+               struct stat stb;
+               int error;
+               error = fstat(dbm_pagfno(db), &stb);
+               if (!error && *tp < stb.st_mtime) {
+                       *tp = stb.st_mtime;
+                       error = -1;
+               } else {
+                       error = search_ndbm(db, key, pval);
+               }
+               (void) dbm_close(db);
+               return error;
+       }
+
+       return errno;
+}
+
+int ndbm_init(map)
+char *map;
+{
+       DBM *db;
+
+       db = dbm_open(map, O_RDONLY, 0);
+       if (db) {
+               dbm_close(db);
+               return 0;
+       }
+
+       return errno;
+}
+
+#endif /* HAS_NDBM_MAPS */
diff --git a/usr/src/usr.sbin/amd/amd/info_nis.c b/usr/src/usr.sbin/amd/amd/info_nis.c
new file mode 100644 (file)
index 0000000..e86328d
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * $Id: info_nis.c,v 5.2 90/06/23 22:19:32 jsp Rel $
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)info_nis.c  5.1 (Berkeley) %G%
+ */
+
+/*
+ * Get info from NIS map
+ */
+
+#include "am.h"
+
+#ifdef HAS_NIS_MAPS
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+/*
+ * Figure out the nis domain name
+ */
+static int determine_nis_domain(P_void)
+{
+static  char default_domain[YPMAXDOMAIN];
+
+       if (getdomainname(default_domain, sizeof(default_domain)) < 0) {
+               plog(XLOG_ERROR, "getdomainname: %m");
+               return EIO;
+       }
+
+       domain = default_domain;
+       if (!*domain) {
+               plog(XLOG_ERROR, "YP domain name is not set");
+               return ENOENT;
+       }
+
+       return 0;
+}
+
+/*
+ * Try to locate a key using NIS.
+ * Modify time is ignored in NIS - XXX
+ */
+int nis_search P((mnt_map *m, char *map, char *key, char **val, time_t *tp));
+int nis_search(m, map, key, val, tp)
+mnt_map *m;
+char *map;
+char *key;
+char **val;
+time_t *tp;
+{
+       int outlen;
+       int res;
+
+       if (!domain) {
+               int error = determine_nis_domain();
+               if (error)
+                       return error;
+       }
+
+       res = yp_match(domain, map, key, strlen(key), val, &outlen);
+
+       /*
+        * Do something interesting with the return code
+        */
+       switch (res) {
+       case 0:
+               return 0;
+
+       case YPERR_KEY:
+               return ENOENT;
+
+       default:
+               plog(XLOG_ERROR, "%s: %s", map, yperr_string(res));
+               return EIO;
+       }
+}
+
+int nis_init P((char *map));
+int nis_init(map)
+char *map;
+{
+       char *name = 0;
+
+       if (!domain) {
+               int error = determine_nis_domain();
+               if (error)
+                       return error;
+       }
+
+       /*
+        * To see if the map exists, try to find
+        * a master for it.
+        */
+       if (yp_master(domain, map, &name))
+               return ENOENT;
+       free(name);
+       return 0;
+}
+#endif /* HAS_NIS_MAPS */
diff --git a/usr/src/usr.sbin/amd/amd/info_passwd.c b/usr/src/usr.sbin/amd/amd/info_passwd.c
new file mode 100644 (file)
index 0000000..49617a1
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * $Id: info_passwd.c,v 5.2 90/06/23 22:19:34 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)info_passwd.c       5.1 (Berkeley) %G%
+ */
+
+/*
+ * Get info from password "file"
+ *
+ * This is experimental and probably doesn't
+ * do what you expect.
+ */
+
+#include "am.h"
+
+#ifdef HAS_PASSWD_MAPS
+#include <pwd.h>
+
+#define        PASSWD_MAP      "/etc/passwd"
+
+/*
+ * Nothing to probe - check the map name is PASSWD_MAP.
+ */
+passwd_init(map)
+char *map;
+{
+       return strcmp(map, PASSWD_MAP) == 0 ? 0 : ENOENT;
+}
+
+
+/*
+ * Grab the entry via the getpwname routine
+ * Modify time is ignored by passwd - XXX
+ */
+int passwd_search(m, map, key, pval, tp)
+mnt_map *m;
+char *map;
+char *key;
+char **pval;
+time_t *tp;
+{
+       char *dir = 0;
+       struct passwd *pw;
+       if (strcmp(key, "/defaults") == 0) {
+               *pval = strdup("type:=nfs");
+               return 0;
+       }
+
+       pw = getpwnam(key);
+       if (pw) {
+               /*
+                * We chop the home directory up as follows:
+                * /anydir/dom1/dom2/dom3/user
+                *
+                * and return
+                * rfs:=/anydir/dom3;rhost:=dom3.dom2.dom1;sublink:=user
+                *
+                * This allows cross-domain entries in your passwd file.
+                * ... but forget about security!
+                */
+               char *user;
+               char *p, *q;
+               char val[MAXPATHLEN];
+               char rhost[MAXHOSTNAMELEN];
+               dir = strdup(pw->pw_dir);
+               /*
+                * Find user name.  If no / then Invalid...
+                */
+               user = strrchr(dir, '/');
+               if (!user)
+                       goto enoent;
+               *user++ = '\0';
+               /*
+                * Find start of host "path".  If no / then Invalid...
+                */ 
+               p = strchr(dir+1, '/');
+               if (!p)
+                       goto enoent;
+               *p++ = '\0';
+               /*
+                * At this point, p is dom1/dom2/dom3
+                * Copy, backwards, into rhost replacing
+                * / with .
+                */
+               rhost[0] = '\0';
+               do {
+                       q = strrchr(p, '/');
+                       if (q) {
+                               strcat(rhost, q + 1);
+                               strcat(rhost, ".");
+                               *q = '\0';
+                       } else {
+                               strcat(rhost, p);
+                       }
+               } while (q);
+               /*
+                * Sanity check
+                */
+               if (*rhost == '\0' || *user == '\0' || *dir == '\0')
+                       goto enoent;
+               /*
+                * Make up return string
+                */
+               q = strchr(rhost, '.');
+               if (q)
+                       *q = '\0';
+               sprintf(val, "rfs:=%s/%s;rhost:=%s;sublink:=%s;fs:=${autodir}%s",
+                       dir, rhost, rhost, user, pw->pw_dir);
+               if (q)
+                       *q = '.';
+               *pval = strdup(val);
+               return 0;
+       }
+
+enoent:
+       if (dir)
+               free(dir);
+
+       return ENOENT;
+}
+#endif /* HAS_PASSWD_MAPS */
diff --git a/usr/src/usr.sbin/amd/amd/map.c b/usr/src/usr.sbin/amd/amd/map.c
new file mode 100644 (file)
index 0000000..6b20acb
--- /dev/null
@@ -0,0 +1,906 @@
+/*
+ * $Id: map.c,v 5.2 90/06/23 22:19:35 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)map.c       5.1 (Berkeley) %G%
+ */
+
+#include "am.h"
+
+/*
+ * Generation Numbers.
+ *
+ * Generation numbers are allocated to every node created
+ * by amd.  When a filehandle is computed and sent to the
+ * kernel, the generation number makes sure that it is safe
+ * to reallocate a node slot even when the kernel has a cached
+ * reference to its old incarnation.
+ * No garbage collection is done, since it is assumed that
+ * there is no way that 2^32 generation numbers could ever
+ * be allocated by a single run of amd - there is simply
+ * not enough cpu time available.
+ */
+static unsigned int am_gen = 2;        /* Initial generation number */
+#define new_gen() (am_gen++)
+
+struct am_node *exported_ap[NEXP_AP];
+int first_free_map = 0;                /* First available free slot */
+int last_used_map = -1;                /* Last unavailable used slot */
+static int timeout_mp_id;      /* Id from last call to timeout */
+
+/*
+ * The root of the mount tree.
+ */
+static am_node *root_node;
+
+/*
+ * Allocate a new mount slot and create
+ * a new node.
+ * Fills in the map number of the node,
+ * but leaves everything else uninitialised.
+ */
+struct am_node *exported_ap_alloc(P_void)
+{
+       struct am_node *mp, **mpp;
+
+       /*
+        * First check if there are any slots left
+        */
+       if (first_free_map >= NEXP_AP)
+               return 0;
+
+       /*
+        * Grab the next free slot
+        */
+       mpp = exported_ap + first_free_map;
+       mp = *mpp = ALLOC(am_node);
+       bzero((char *) mp, sizeof(*mp));
+
+       mp->am_mapno = first_free_map++;
+
+       /*
+        * Update free pointer
+        */
+       while (first_free_map < NEXP_AP && exported_ap[first_free_map])
+               first_free_map++;
+
+       if (first_free_map > last_used_map)
+               last_used_map = first_free_map - 1;
+
+#ifdef DEBUG
+       /*dlog("alloc_exp: last_used_map = %d, first_free_map = %d\n",
+               last_used_map, first_free_map);*/
+#endif /* DEBUG */
+
+       return mp;
+}
+
+/*
+ * Free a mount slot
+ */
+void exported_ap_free(mp)
+struct am_node *mp;
+{
+       /*
+        * Sanity check
+        */
+       if (!mp)
+               return;
+
+       /*
+        * Zero the slot pointer to avoid double free's
+        */
+       exported_ap[mp->am_mapno] = 0;
+
+       /*
+        * Update the free and last_used indices
+        */
+       if (mp->am_mapno == last_used_map)
+               while (last_used_map >= 0 && exported_ap[last_used_map] == 0)
+                       --last_used_map;
+
+       if (first_free_map > mp->am_mapno)
+               first_free_map = mp->am_mapno;
+
+#ifdef DEBUG
+       /*dlog("free_exp: last_used_map = %d, first_free_map = %d\n",
+               last_used_map, first_free_map);*/
+#endif /* DEBUG */
+
+       /*
+        * Free the mount node
+        */
+       free(mp);
+}
+
+/*
+ * Insert mp into the correct place,
+ * where p_mp is its parent node.
+ * A new node gets placed as the youngest sibling
+ * of any other children, and the parent's child
+ * pointer is adjusted to point to the new child node.
+ */
+void insert_am(mp, p_mp)
+am_node *mp;
+am_node *p_mp;
+{
+       /*
+        * If this is going in at the root then flag it
+        * so that it cannot be unmounted by amq.
+        */
+       if (p_mp == root_node)
+               mp->am_flags |= AMF_ROOT;
+       /*
+        * Fill in n-way links
+        */
+       mp->am_parent = p_mp;
+       mp->am_osib = p_mp->am_child;
+       if (mp->am_osib)
+               mp->am_osib->am_ysib = mp;
+       p_mp->am_child = mp;
+}
+
+/*
+ * Remove am from its place in the mount tree
+ */
+void remove_am(mp)
+am_node *mp;
+{
+       /*
+        * 1.  Consistency check
+        */
+       if (mp->am_child && mp->am_parent) {
+               plog(XLOG_WARNING, "children of \"%s\" still exist - deleting anyway", mp->am_path);
+       }
+
+       /*
+        * 2.  Update parent's child pointer
+        */
+       if (mp->am_parent && mp->am_parent->am_child == mp)
+               mp->am_parent->am_child = mp->am_osib;
+
+       /*
+        * 3.  Unlink from sibling chain
+        */
+       if (mp->am_ysib)
+               mp->am_ysib->am_osib = mp->am_osib;
+       if (mp->am_osib)
+               mp->am_osib->am_ysib = mp->am_ysib;
+}
+
+/*
+ * Compute a new time to live value for a node.
+ */
+void new_ttl(mp)
+am_node *mp;
+{
+       mp->am_timeo_w = 0;
+
+       mp->am_ttl = clocktime();
+       mp->am_mnt->mf_fattr.atime.seconds = mp->am_ttl;
+       mp->am_ttl += mp->am_timeo;     /* sun's -tl option */
+}
+
+/*
+ * Initialise an allocated mount node.
+ * It is assumed that the mount node was bzero'd
+ * before getting here so anything that would
+ * be set to zero isn't done here.
+ */
+void init_map(mp, dir)
+am_node *mp;
+char *dir;
+{
+       /* mp->am_mapno initalised by exported_ap_alloc */
+       mp->am_mnt = new_mntfs();
+       mp->am_name = strdup(dir);
+       mp->am_path = strdup(dir);
+       /*mp->am_link = 0;*/
+       /*mp->am_parent = 0;*/
+       /*mp->am_ysib = 0;*/
+       /*mp->am_osib = 0;*/
+       /*mp->am_child = 0;*/
+       /*mp->am_flags = 0;*/
+       /*mp->am_error = 0;*/
+       mp->am_gen = new_gen();
+       /*mp->am_pref = 0;*/
+
+       mp->am_timeo = am_timeo;
+       new_ttl(mp);
+       mp->am_stats.s_mtime = mp->am_mnt->mf_fattr.atime.seconds;
+       /*mp->am_private = 0;*/
+}
+
+/*
+ * Free a mount node.
+ * The node must be already unmounted.
+ */
+void free_map(mp)
+am_node *mp;
+{
+       remove_am(mp);
+
+       if (mp->am_link)
+               free(mp->am_link);
+       if (mp->am_name)
+               free(mp->am_name);
+       if (mp->am_path)
+               free(mp->am_path);
+       if (mp->am_pref)
+               free(mp->am_pref);
+
+       if (mp->am_mnt)
+               free_mntfs(mp->am_mnt);
+
+       if (mp->am_flags & AMF_MKPATH)
+               rmdirs(mp->am_path);
+       exported_ap_free(mp);
+}
+
+/*
+ * Convert from file handle to
+ * automount node.
+ */
+am_node *fh_to_mp3(fhp, rp, c_or_d)
+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 != mypid)
+               goto drop;
+
+       /*
+        * Make sure the index is valid before
+        * exported_ap is referenced.
+        */
+       if (fp->fhh_id < 0 || fp->fhh_id >= NEXP_AP)
+               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;
+#ifdef DEBUG
+                       dlog("fh_to_mp3: %s (%s) is hung:- call lookup", ap->am_path, ap->am_mnt->mf_info);
+#endif /* DEBUG */
+                       /*
+                        * Update last access to original node.  This
+                        * avoids timing it out and so sending ESTALE
+                        * back to the kernel.
+                        */
+                       new_ttl(ap);
+
+                       /*
+                        * 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 = (*ap->am_parent->am_mnt->mf_ops->lookuppn)(ap->am_parent,
+                                               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;
+                       }
+               }
+               /*
+                * 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;
+}
+
+am_node *fh_to_mp(fhp)
+nfs_fh *fhp;
+{
+       int dummy;
+       return fh_to_mp2(fhp, &dummy);
+}
+
+/*
+ * Convert from automount node to
+ * file handle.
+ */
+void mp_to_fh(mp, fhp)
+am_node *mp;
+struct nfs_fh *fhp;
+{
+       struct am_fh *fp = (struct am_fh *) fhp;
+
+       /*
+        * Take the process id
+        */
+       fp->fhh_pid = mypid;
+       /*
+        * .. the map number
+        */
+       fp->fhh_id = mp->am_mapno;
+       /*
+        * .. 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).
+        */
+}
+
+static am_node *find_ap2(dir, mp)
+char *dir;
+am_node *mp;
+{
+       if (mp) {
+               am_node *mp2;
+               if (strcmp(mp->am_path, dir) == 0)
+                       return mp;
+
+               if ((mp->am_mnt->mf_flags & MFF_MOUNTED) &&
+                       strcmp(mp->am_mnt->mf_mount, dir) == 0)
+                       return mp;
+
+               mp2 = find_ap2(dir, mp->am_osib);
+               if (mp2)
+                       return mp2;
+               return find_ap2(dir, mp->am_child);
+       }
+
+       return 0;
+}
+
+/*
+ * Find the mount node corresponding
+ * to dir.  dir can match either the
+ * automount path or, if the node is
+ * mounted, the mount location.
+ */
+am_node *find_ap(dir)
+char *dir;
+{
+       int i;
+
+       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]);
+                       if (mp)
+                               return mp;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Get the filehandle for a particular named directory.
+ * This is used during the bootstrap to tell the kernel
+ * the filehandles of the initial automount points.
+ */
+nfs_fh *root_fh(dir)
+char *dir;
+{
+       static nfs_fh nfh;
+       am_node *mp = root_ap(dir, TRUE);
+       if (mp) {
+               mp_to_fh(mp, &nfh);
+               return &nfh;
+       }
+
+       /*
+        * Should never get here...
+        */
+       plog(XLOG_ERROR, "Can't find root filehandle for %s", dir);
+       return 0;
+}
+
+am_node *root_ap(dir, path)
+char *dir;
+int path;
+{
+       am_node *mp = find_ap(dir);
+       if (mp && mp->am_parent == root_node)
+               return mp;
+
+       return 0;
+}
+
+/*
+ * Mount a top level automount node
+ * by calling lookup in the parent
+ * (root) node which will cause the
+ * automount node to be automounted (!)
+ */
+static void mount_auto_node(dir)
+char *dir;
+{
+       int error = 0;
+       (void) afs_ops.lookuppn(root_node, dir, &error, VLOOK_CREATE);
+       if (error) {
+               errno = error; /* XXX */
+               plog(XLOG_ERROR, "Could not start server on %s: %m", dir);
+       }
+}
+
+/*
+ * Cause all the top-level mount nodes
+ * to be automounted
+ */
+int mount_exported()
+{
+       /*
+        * Iterate over all the nodes to be started
+        */
+       return root_keyiter(mount_auto_node);
+}
+
+/*
+ * Construct top-level node
+ */
+void make_root_node()
+{
+       mntfs *root_mnt;
+       char *rootmap = ROOT_MAP;
+       root_node = exported_ap_alloc();
+
+       init_map(root_node, "");
+       root_mnt = find_mntfs(&afs_ops, (am_opts *) 0, "", rootmap, "");
+       root_mnt->mf_mount = strealloc(root_mnt->mf_mount, pid_fsname);
+       root_mnt->mf_private = (voidp) mapc_find(rootmap, "");
+       root_mnt->mf_prfree = mapc_free;
+       free_mntfs(root_node->am_mnt);
+       root_node->am_mnt = root_mnt;
+       root_node->am_flags |= AMF_NOTIMEOUT;
+       root_mnt->mf_error = 0;
+}
+
+/*
+ * Cause all the nodes to be unmounted by timing
+ * them out.
+ */
+void umount_exported(P_void)
+{
+       int i;
+       for (i = last_used_map; i >= 0; --i) {
+               am_node *mp = exported_ap[i];
+               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 (mf && mf->mf_ops == &dfs_ops) {
+                               /*
+                                * When shutting down this had better
+                                * look like a directory, otherwise it
+                                * can't be unmounted!
+                                */
+                               mf->mf_fattr.type = NFDIR;
+                               mf->mf_fattr.mode = NFSMODE_DIR | 0555;
+                       }
+                       if ((--immediate_abort < 0 && !(mp->am_flags & AMF_ROOT) && mp->am_parent) ||
+                           (mf->mf_flags & MFF_RESTART)) {
+                               /*
+                                * 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;
+                               am_unmounted(mp);
+                       } 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;
+                       }
+               }
+       }
+}
+
+static int unmount_node P((am_node *mp));
+static int unmount_node(mp)
+am_node *mp;
+{
+       mntfs *mf = mp->am_mnt;
+       int error;
+
+       if ((mf->mf_flags & MFF_ERROR) || mf->mf_refc > 1) {
+               /*
+                * 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;
+       } else {
+#ifdef DEBUG
+               dlog("Unmounting %s (%s)", mf->mf_mount, mf->mf_info);
+#endif /* DEBUG */
+               error = (*mf->mf_ops->umount_fs)(mp);
+       }
+
+       if (error) {
+#ifdef DEBUG
+               errno = error; /* XXX */
+               dlog("%s: unmount: %m", mf->mf_mount);
+#endif /* DEBUG */
+       }
+
+       return error;
+}
+
+#ifdef FLUSH_KERNEL_NAME_CACHE
+static void flush_kernel_name_cache(mp)
+am_node *mp;
+{
+       int islink = (mp->am_mnt->mf_fattr.type == NFLNK);
+       int isdir = (mp->am_mnt->mf_fattr.type == NFDIR);
+       int elog = 0;
+       if (islink) {
+               if (unlink(mp->am_path) < 0)
+                       elog = 1;
+       } else if (isdir) {
+               if (rmdir(mp->am_path) < 0)
+                       elog = 1;
+       }
+       if (elog)
+               plog(XLOG_WARNING, "failed to clear \"%s\" from dnlc: %m", mp->am_path);
+}
+#endif /* FLUSH_KERNEL_NAME_CACHE */
+
+static int unmount_node_wrap P((voidp vp));
+static int unmount_node_wrap(vp)
+voidp vp;
+{
+#ifndef FLUSH_KERNEL_NAME_CACHE
+       return unmount_node((am_node*) vp);
+#else /* 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 sfs_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 MF_UNMOUNTING flag will
+        * be set.  That may, or may not, cause the entire
+        * system to deadlock.  Hmmm...
+        */
+       am_node *mp = (am_node *) vp;
+       int isauto = mp->am_parent && (mp->am_parent->am_mnt->mf_fattr.type == NFDIR);
+       int error = unmount_node(mp);
+       if (error)
+               return error;
+       if (isauto && (int)amd_state < (int)Finishing)
+               flush_kernel_name_cache(mp);
+
+       return 0;
+#endif /* FLUSH_KERNEL_NAME_CACHE */
+}
+
+static void free_map_if_success(rc, term, closure)
+int rc;
+int term;
+voidp closure;
+{
+       am_node *mp = (am_node *) closure;
+       mntfs *mf = mp->am_mnt;
+
+       /*
+        * Not unmounting any more
+        */
+       mf->mf_flags &= ~MFF_UNMOUNTING;
+
+       /*
+        * If a timeout was defered because the underlying filesystem
+        * was busy then arrange for a timeout as soon as possible.
+        */
+       if (mf->mf_flags & MFF_WANTTIMO) {
+               mf->mf_flags &= ~MFF_WANTTIMO;
+               reschedule_timeout_mp();
+       }
+
+       if (term) {
+               plog(XLOG_ERROR, "unmount for %s got signal %d", mp->am_path, term);
+#ifdef DEBUG
+               /*
+                * dbx likes to put a trap on exit().
+                * Pretend it succeeded for now...
+                */
+               if (term == SIGTRAP) {
+                       am_unmounted(mp);
+               }
+#endif /* DEBUG */
+               amd_stats.d_uerr++;
+       } else if (rc) {
+               if (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);
+               }
+               amd_stats.d_uerr++;
+       } else {
+               am_unmounted(mp);
+       }
+
+       /*
+        * Wakeup anything waiting for this mount
+        */
+       wakeup((voidp) mf);
+}
+
+static void unmount_mp(mp)
+am_node *mp;
+{
+       mntfs *mf = mp->am_mnt;
+#ifdef notdef
+       plog(XLOG_INFO, "\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount);
+#endif /* notdef */
+       if ((mf->mf_ops->fs_flags & 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);
+#ifdef DEBUG
+                       dlog("unmount attempt backgrounded");
+#endif /* DEBUG */
+               }
+       } else {
+#ifdef DEBUG
+               dlog("\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount);
+               dlog("Trying unmount in foreground");
+#endif
+               mf->mf_flags |= MFF_UNMOUNTING;
+               free_map_if_success(unmount_node(mp), 0, (voidp) mp);
+#ifdef DEBUG
+               dlog("unmount attempt done");
+#endif /* DEBUG */
+       }
+}
+
+void timeout_mp()
+{
+#define NEVER (time_t) 0
+#define        smallest_t(t1, t2) \
+       (t1 != NEVER ? (t2 != NEVER ? (t1 < t2 ? t1 : t2) : t1) : t2)
+#define IGNORE_FLAGS (MFF_MOUNTING|MFF_UNMOUNTING|MFF_RESTART)
+
+       int i;
+       time_t t = NEVER;
+       time_t now = clocktime();
+
+#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.
+                */
+               if (!mp || (mp->am_flags & AMF_NOTIMEOUT))
+                       continue;
+               /*
+                * Pick up mounted filesystem
+                */
+               mf = mp->am_mnt;
+               if (!mf)
+                       continue;
+               /*
+                * Don't delete last reference to a restarted filesystem.
+                */
+               if ((mf->mf_flags & MFF_RSTKEEP) && mf->mf_refc == 1)
+                       continue;
+               /*
+                * If there is action on this filesystem then ignore it
+                */
+               if (!(mf->mf_flags & IGNORE_FLAGS)) {
+                       int expired = 0;
+                       mf->mf_flags &= ~MFF_WANTTIMO;
+#ifdef DEBUG
+                       /*dlog("t is initially @%d, zero in %d secs", t, t - now);*/
+#endif /* DEBUG */
+                       if (now >= mp->am_ttl) {
+                               expired = 1;
+                               /*
+                                * Move the ttl forward to avoid thrashing effects
+                                * on the next call to timeout!
+                                */
+                               /* sun's -tw option */
+                               if (mp->am_timeo_w < 4 * am_timeo_w)
+                                       mp->am_timeo_w += am_timeo_w;
+                               mp->am_ttl = now + mp->am_timeo_w;
+                       }
+                       /*
+                        * If the next ttl is smallest, use that
+                        */
+                       t = smallest_t(t, mp->am_ttl);
+
+#ifdef DEBUG
+                       /*dlog("after ttl t is @%d, zero in %d secs", t, t - now);*/
+#endif /* DEBUG */
+
+                       if (!mp->am_child && mf->mf_error >= 0 && expired)
+                               unmount_mp(mp);
+               } else if (mf->mf_flags & MFF_UNMOUNTING) {
+                       mf->mf_flags |= MFF_WANTTIMO;
+               }
+       }
+
+       if (t == NEVER) {
+#ifdef DEBUG
+               dlog("No further timeouts");
+#endif /* DEBUG */
+               t = now + ONE_HOUR;
+       }
+
+       /*
+        * Sanity check to avoid runaways.
+        * Absolutely should never get this but
+        * if you do without this trap amd will thrash.
+        */
+       if (t <= now) {
+               t = now + 6;    /* XXX */
+               plog(XLOG_ERROR, "Got a zero interval in timeout_mp()!");
+       }
+       /*
+        * XXX - when shutting down, make things happen faster
+        */
+       if ((int)amd_state >= (int)Finishing)
+               t = now + 1;
+#ifdef DEBUG
+       dlog("Next mount timeout in %ds", t - now);
+#endif /* DEBUG */
+
+       timeout_mp_id = timeout(t - now, timeout_mp, 0);
+
+#undef NEVER
+#undef smallest_t
+#undef IGNORE_FLAGS
+}
+
+/*
+ * Cause timeout_mp to be called soonest
+ */
+void reschedule_timeout_mp()
+{
+       if (timeout_mp_id)
+               untimeout(timeout_mp_id);
+       timeout_mp_id = timeout(0, timeout_mp, 0);
+}
diff --git a/usr/src/usr.sbin/amd/amd/mapc.c b/usr/src/usr.sbin/amd/amd/mapc.c
new file mode 100644 (file)
index 0000000..f2b1954
--- /dev/null
@@ -0,0 +1,580 @@
+/*
+ * $Id: mapc.c,v 5.2 90/06/23 22:19:37 jsp Rel $
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)mapc.c      5.1 (Berkeley) %G%
+ */
+
+/*
+ * Mount map cache
+ */
+
+#include "am.h"
+
+/*
+ * Hash table size
+ */
+#define        NKVHASH (1 << 2)                /* Power of two */
+
+/*
+ * Wildcard key
+ */
+static char wildcard[] = "*";
+
+/*
+ * Map cache types
+ * default, none, incremental, all
+ */
+#define        MAPC_DFLT       -1
+#define        MAPC_NONE       0
+#define        MAPC_INC        1
+#define        MAPC_ALL        2
+
+/*
+ * Do a map reload
+ */
+#define mapc_reload_map(m) \
+       ((*(m)->reload)(m, m->map_name, mapc_add_kv))
+
+/*
+ * Cache map operations
+ */
+typedef void add_fn P((mnt_map*, char*, char*));
+typedef int init_fn P((char*));
+typedef int search_fn P((mnt_map*, char*, char*, char**, time_t*));
+typedef int reload_fn P((mnt_map*, char*, add_fn*));
+
+static void mapc_sync P((mnt_map*));
+
+/*
+ * Map type
+ */
+typedef struct map_type map_type;
+struct map_type {
+       char *name;                     /* Name of this map type */
+       init_fn *init;                  /* Initialisation */
+       reload_fn *reload;              /* Reload or fill */
+       search_fn *search;              /* Search for new entry */
+       int def_alloc;                  /* Default allocation mode */
+};
+
+/*
+ * Key-value pair
+ */
+typedef struct kv kv;
+struct kv {
+       kv *next;
+       char *key;
+       char *val;
+};
+
+struct mnt_map {
+       qelem hdr;
+       int refc;                       /* Reference count */
+       int alloc;                      /* Allocation mode */
+       time_t modify;                  /* Modify time of map */
+       char *map_name;                 /* Name of this map */
+       char *wildcard;                 /* Wildcard value */
+       reload_fn *reload;              /* Function to be used for reloads */
+       search_fn *search;              /* Function to be used for searching */
+       kv *kvhash[NKVHASH];            /* Cached data */
+};
+
+/*
+ * Map for root node
+ */
+static mnt_map *root_map;
+
+/*
+ * List of known maps
+ */
+extern qelem map_list_head;
+qelem map_list_head = { &map_list_head, &map_list_head };
+
+/*
+ * Configuration
+ */
+/* ROOT MAP */
+static int root_init P((char*));
+
+/* FILE MAPS */
+#ifdef HAS_FILE_MAPS
+extern int file_init P((char*));
+extern int file_reload P((mnt_map*, char*, add_fn*));
+extern int file_search P((mnt_map*, char*, char*, char**, time_t*));
+#endif /* HAS_FILE_MAPS */
+
+/* Network Information Service (NIS) MAPS */
+#ifdef HAS_NIS_MAPS
+extern int nis_init P((char*));
+extern int nis_search P((mnt_map*, char*, char*, char**, time_t*));
+#endif /* HAS_NIS_MAPS */
+
+/* NDBM MAPS */
+#ifdef HAS_NDBM_MAPS
+#ifdef OS_HAS_NDBM
+extern int ndbm_init P((char*));
+extern int ndbm_search P((mnt_map*, char*, char*, char**, time_t*));
+#endif /* OS_HAS_NDBM */
+#endif /* HAS_NDBM_MAPS */
+
+/* PASSWD MAPS */
+#ifdef HAS_PASSWD_MAPS
+extern int passwd_init P((char*));
+extern int passwd_search P((mnt_map*, char*, char*, char**, time_t*));
+#endif /* HAS_PASSWD_MAPS */
+
+/* HESIOD MAPS */
+#ifdef HAS_HESIOD_MAPS
+extern int hesiod_init P((char*));
+extern int hesiod_search P((mnt_map*, char*, char*, char**, time_t*));
+#endif /* HAS_HESIOD_MAPS */
+
+/* ERROR MAP */
+static int error_init P((char*));
+static int error_reload P((mnt_map*, char*, add_fn*));
+static int error_search P((mnt_map*, char*, char*, char**, time_t*));
+
+static map_type maptypes[] = {
+       { "root", root_init, error_reload, error_search, MAPC_ALL },
+
+#ifdef HAS_PASSWD_MAPS
+       { "passwd", passwd_init, error_reload, passwd_search, MAPC_INC },
+#endif /* HAS_PASSWD_MAPS */
+
+#ifdef HAS_HESIOD_MAPS
+       { "hesiod", hesiod_init, error_reload, hesiod_search, MAPC_INC },
+#endif /* HAS_HESIOD_MAPS */
+
+#ifdef HAS_NIS_MAPS
+       { "nis", nis_init, error_reload, nis_search, MAPC_INC },
+#endif /* HAS_NIS_MAPS */
+
+#ifdef HAS_NDBM_MAPS
+       { "ndbm", ndbm_init, error_reload, ndbm_search, MAPC_INC },
+#endif /* HAS_NDBM_MAPS */
+
+#ifdef HAS_FILE_MAPS
+       { "file", file_init, file_reload, file_search, MAPC_ALL },
+#endif /* HAS_FILE_MAPS */
+
+       { "error", error_init, error_reload, error_search, MAPC_NONE },
+};
+
+/*
+ * Hash function
+ */
+static unsigned int kvhash_of(key)
+char *key;
+{
+       unsigned int i, j;
+
+       for (i = 0; j = *key++; i += j)
+               ;
+
+       return i % NKVHASH;
+}
+
+void mapc_showtypes(fp)
+FILE *fp;
+{
+       map_type *mt;
+       char *sep = "";
+       for (mt = maptypes; mt < maptypes+sizeof(maptypes)/sizeof(maptypes[0]); mt++) {
+               fprintf(fp, "%s%s", sep, mt->name);
+               sep = ", ";
+       }
+}
+
+/*
+ * Add key and val to the map m.
+ * key and val are assumed to be safe copies
+ */
+void mapc_add_kv(m, key, val)
+mnt_map *m;
+char *key;
+char *val;
+{
+       kv **h = &m->kvhash[kvhash_of(key)];
+       kv *n = ALLOC(kv);
+       n->key = key;
+       n->val = val;
+       n->next = *h;
+       *h = n;
+}
+
+static int search_map(m, key, valp)
+mnt_map *m;
+char *key;
+char **valp;
+{
+       int rc;
+       do {
+               rc = (*m->search)(m, m->map_name, key, valp, &m->modify);
+               if (rc < 0) {
+                       plog(XLOG_MAP, "Re-synchronizing cache for map %s", m->map_name);
+                       mapc_sync(m);
+               }
+       } while (rc < 0);
+
+       return rc;
+}
+
+/*
+ * Do a wildcard lookup in the map and
+ * save the result.
+ */
+static void mapc_find_wildcard(m)
+mnt_map *m;
+{
+       /*
+        * Attempt to find the wildcard entry
+        */
+       int rc = search_map(m, wildcard, &m->wildcard);
+
+       if (rc != 0)
+               m->wildcard = 0;
+}
+
+/*
+ * Make a duplicate reference to an existing map
+ */
+#define mapc_dup(m) ((m)->refc++, (m))
+
+/*
+ * Create a new map
+ */
+static mnt_map *mapc_create(map, opt)
+char *map;
+char *opt;
+{
+       mnt_map *m = ALLOC(mnt_map);
+       map_type *mt;
+       int alloc = STREQ(opt, "all") ? MAPC_ALL :
+                   (STREQ(opt, "inc") ? MAPC_INC :
+                   ((STREQ(opt, "default") || STREQ(opt, "mapdefault")) ? MAPC_DFLT :
+                   MAPC_NONE));
+
+       for (mt = maptypes; mt < maptypes+sizeof(maptypes)/sizeof(maptypes[0]); mt++)
+               if ((*mt->init)(map) == 0)
+                       break;
+
+#ifdef DEBUG
+       dlog("Map for %s coming from maptype %s", map, mt->name);
+#endif /* DEBUG */
+       /*
+        * If there is no support for reload and it was requested
+        * then back off to incremental instead.
+        */
+       if (mt->reload == error_reload && alloc == MAPC_ALL && mt->def_alloc != MAPC_ALL) {
+               plog(XLOG_WARNING, "Map type \"%s\" does not support cache type \"all\"",
+                                       mt->name);
+               alloc = MAPC_INC;
+       } else if (alloc == MAPC_DFLT)
+               alloc = mt->def_alloc;
+       m->alloc = alloc;
+       m->reload = mt->reload;
+       m->modify = clocktime();
+       m->search = alloc == MAPC_ALL ? error_search : mt->search;
+       bzero((voidp) m->kvhash, sizeof(m->kvhash));
+       m->map_name = strdup(map);
+       m->refc = 1;
+       /*
+        * Attempt to find the wildcard entry
+        */
+       mapc_find_wildcard(m);
+
+       if (alloc == MAPC_ALL) {
+               /*
+                * If cache all is specified then load the cache
+                */
+               if (mapc_reload_map(m)) {
+                       /*
+                        * If that doesn't work then fallback to
+                        * incremental cache mode
+                        */
+                       m->alloc = MAPC_INC;
+               }
+       }
+       return m;
+}
+
+/*
+ * Free the cached data in a map
+ */
+static void mapc_clear(m)
+mnt_map *m;
+{
+       int i;
+
+       /*
+        * For each of the hash slots, chain
+        * along free'ing the data.
+        */
+       for (i = 0; i < NKVHASH; i++) {
+               kv *k = m->kvhash[i];
+               while (k) {
+                       kv *n = k->next;
+                       free(k->key);
+                       if (k->val)
+                               free(k->val);
+                       free(k);
+                       k = n;
+               }
+       }
+       /*
+        * Zero the hash slots
+        */
+       bzero((voidp) m->kvhash, sizeof(m->kvhash));
+       /*
+        * Free the wildcard if it exists
+        */
+       if (m->wildcard) {
+               free(m->wildcard);
+               m->wildcard = 0;
+       }
+}
+
+/*
+ * Find a map, or create one if it does not exist
+ */
+mnt_map *mapc_find(map, opt)
+char *map;
+char *opt;
+{
+       mnt_map *m;
+
+       /*
+        * Search the list of known maps to see if
+        * it has already been loaded.  If it is found
+        * then return a duplicate reference to it.
+        * Otherwise make a new map as required and
+        * add it to the list of maps
+        */
+       ITER(m, mnt_map, &map_list_head)
+               if (STREQ(m->map_name, map))
+                       return mapc_dup(m);
+
+       m = mapc_create(map, opt);
+       ins_que(&m->hdr, &map_list_head);
+       return m;
+}
+
+/*
+ * Free a map.
+ */
+void mapc_free(m)
+mnt_map *m;
+{
+       /*
+        * Decrement the reference count.
+        * If the reference count hits zero
+        * then throw the map away.
+        */
+       if (--m->refc == 0) {
+               mapc_clear(m);
+               free(m->map_name);
+               rem_que(&m->hdr);
+               free(m);
+       }
+}
+
+/*
+ * Search the map for the key.
+ * Put a safe copy in *pval or return
+ * an error code
+ */
+int mapc_search(m, key, pval)
+mnt_map *m;
+char *key;
+char **pval;
+{
+       int error = 0;
+       kv *k;
+
+       /*
+        * Compute the hash table offset
+        */
+       k = m->kvhash[kvhash_of(key)];
+
+       /*
+        * Scan the linked list for the key
+        */
+       while (k && !FSTREQ(k->key, key))
+               k = k->next;
+
+       /*
+        * If found then take a copy
+        */
+       if (k) {
+               if (k->val)
+                       *pval = strdup(k->val);
+               else
+                       error = ENOENT;
+       } else if (m->alloc == MAPC_ALL) {
+               /*
+                * If the entire map is cached then this
+                * key does not exist.
+                */
+               error = ENOENT;
+       } else {
+               /*
+                * Otherwise search the map.  If we are
+                * in incremental mode then add the key
+                * to the cache.
+                */
+               error = search_map(m, key, pval);
+               if (!error && m->alloc == MAPC_INC)
+                       mapc_add_kv(m, strdup(key), strdup(*pval));
+       }
+
+       /*
+        * If an error, and a wildcard exists,
+        * and the key is not internal then
+        * return a copy of the wildcard.
+        */
+       if (error && m->wildcard && *key != '/') {
+               *pval = strdup(m->wildcard);
+               return 0;
+       }
+
+       return error;
+}
+
+static void mapc_sync(m)
+mnt_map *m;
+{
+       mapc_clear(m);
+
+       if (m->alloc == MAPC_ALL)
+               if (mapc_reload_map(m))
+                       m->alloc = MAPC_INC;
+       mapc_find_wildcard(m);
+}
+
+/*
+ * Reload all the maps
+ * Called when amd gets hit by a SIGHUP.
+ */
+void mapc_reload()
+{
+       mnt_map *m;
+
+       /*
+        * For all the maps,
+        * Throw away the existing information.
+        * Do a reload
+        * Find the wildcard
+        */
+       ITER(m, mnt_map, &map_list_head)
+               mapc_sync(m);
+}
+
+/*
+ * Root map.
+ * The root map is used to bootstrap amd.
+ * All the require top-level mounts are added
+ * into the root map and then the map is iterated
+ * and a lookup is done on all the mount points.
+ * This causes the top level mounts to be automounted.
+ */
+
+static int root_init(map)
+char *map;
+{
+       return strcmp(map, ROOT_MAP) == 0 ? 0 : ENOENT;
+}
+
+/*
+ * Add a new entry to the root map
+ *
+ * dir - directory (key)
+ * opts - mount options
+ * map - map name
+ */
+void root_newmap(dir, opts, map)
+char *dir;
+char *opts;
+char *map;
+{
+       char str[MAXPATHLEN];
+
+       /*
+        * First make sure we have a root map to talk about...
+        */
+       if (!root_map)
+               root_map = mapc_find(ROOT_MAP, "all");
+
+       /*
+        * Then add the entry...
+        */
+       dir = strdup(dir);
+       sprintf(str, "cache:=none;type:=auto;fs:=\"%s\";%s", map, opts ? opts : "");
+       mapc_add_kv(root_map, dir, strdup(str));
+}
+
+/*
+ * Iterate of the the root map
+ * and call (*fn)() on the key
+ * of all the nodes.
+ * Finally throw away the root map.
+ */
+int root_keyiter(fn)
+void (*fn)P((char*));
+{
+       int i;
+       int c = 0;
+
+       if (root_map) {
+               for (i = 0; i < NKVHASH; i++) {
+                       kv *k = root_map->kvhash[i];
+                       while (k) {
+                               (*fn)(k->key);
+                               k = k->next;
+                               c++;
+                       }
+               }
+               mapc_free(root_map);
+               root_map = 0;
+       }
+       return c;
+}
+
+/*
+ * Error map
+ */
+static int error_init(map)
+char *map;
+{
+       return 0;
+}
+
+/*ARGSUSED*/
+static int error_search(m, map, key, pval, tp)
+mnt_map *m;
+char *map;
+char *key;
+char **pval;
+time_t *tp;
+{
+       return ENOENT;
+}
+
+/*ARGSUSED*/
+static int error_reload(m, map, fn)
+mnt_map *m;
+char *map;
+add_fn *fn;
+{
+       return ENOENT;
+}
diff --git a/usr/src/usr.sbin/amd/amd/misc_rpc.c b/usr/src/usr.sbin/amd/amd/misc_rpc.c
new file mode 100644 (file)
index 0000000..bc1ee75
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * $Id: misc_rpc.c,v 5.2 90/06/23 22:19:38 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)misc_rpc.c  5.1 (Berkeley) %G%
+ */
+
+/*
+ * Additions to Sun RPC.
+ */
+
+#include "am.h"
+
+void rpc_msg_init P((struct rpc_msg *mp, u_long prog, u_long vers, u_long proc));
+void rpc_msg_init(mp, prog, vers, proc)
+struct rpc_msg *mp;
+unsigned long prog, vers, proc;
+{
+       /*
+        * Initialise the message
+        */
+       bzero((voidp) mp, sizeof(*mp));
+       mp->rm_xid = 0;
+       mp->rm_direction = CALL;
+       mp->rm_call.cb_rpcvers = RPC_MSG_VERSION;
+       mp->rm_call.cb_prog = prog;
+       mp->rm_call.cb_vers = vers;
+       mp->rm_call.cb_proc = proc;
+}
+
+/*
+ * Field reply to call to mountd
+ */
+int pickup_rpc_reply P((voidp pkt, int len, voidp where, xdrproc_t where_xdr));
+int pickup_rpc_reply(pkt, len, where, where_xdr)
+voidp pkt;
+int len;
+voidp where;
+xdrproc_t where_xdr;
+{
+       XDR reply_xdr;
+       int ok;
+       struct rpc_err err;
+       struct rpc_msg reply_msg;
+       int error = 0;
+
+       /*bzero((voidp) &err, sizeof(err));*/
+       bzero((voidp) &reply_msg, sizeof(reply_msg));
+
+       reply_msg.acpted_rply.ar_results.where = (caddr_t) where;
+       reply_msg.acpted_rply.ar_results.proc = where_xdr;
+
+       xdrmem_create(&reply_xdr, pkt, len, XDR_DECODE);
+
+       ok = xdr_replymsg(&reply_xdr, &reply_msg);
+       if (!ok) {
+               error = EIO;
+               goto drop;
+       }
+       _seterr_reply(&reply_msg, &err);
+       if (err.re_status != RPC_SUCCESS) {
+               error = EIO;
+               goto drop;
+       }
+
+drop:
+       if (reply_msg.acpted_rply.ar_verf.oa_base) {
+               reply_xdr.x_op = XDR_FREE;
+               (void)xdr_opaque_auth(&reply_xdr,
+                       &reply_msg.acpted_rply.ar_verf);
+       }
+       xdr_destroy(&reply_xdr);
+
+       return error;
+}
+
+int make_rpc_packet P((char *buf, int buflen, unsigned long proc,
+                       struct rpc_msg *mp, voidp arg, xdrproc_t arg_xdr, AUTH *auth));
+int make_rpc_packet(buf, buflen, proc, mp, arg, arg_xdr, auth)
+char *buf;
+int buflen;
+unsigned long proc;
+struct rpc_msg *mp;
+voidp arg;
+xdrproc_t arg_xdr;
+AUTH *auth;
+{
+       XDR msg_xdr;
+       int len;
+
+       xdrmem_create(&msg_xdr, buf, buflen, XDR_ENCODE);
+       /*
+        * Basic protocol header
+        */
+       if (!xdr_callhdr(&msg_xdr, mp))
+               return -EIO;
+       /*
+        * Called procedure number
+        */
+       if (!xdr_enum(&msg_xdr, &proc))
+               return -EIO;
+       /*
+        * Authorization
+        */
+       if (!AUTH_MARSHALL(auth, &msg_xdr))
+               return -EIO;
+       /*
+        * Arguments
+        */
+       if (!(*arg_xdr)(&msg_xdr, arg))
+               return -EIO;
+       /*
+        * Determine length
+        */
+       len = xdr_getpos(&msg_xdr);
+       /*
+        * Throw away xdr
+        */
+       xdr_destroy(&msg_xdr);
+       return len;
+}
+
+
+#ifdef MISC_RPC
+/*
+ * Early RPC seems to be missing these..
+ * Extracted from the RPC 3.9 sources as indicated
+ */
+
+/* @(#)xdr_reference.c 1.1 87/11/04 3.9 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+
+/*
+ * xdr_pointer():
+ *
+ * XDR a pointer to a possibly recursive data structure. This
+ * differs with xdr_reference in that it can serialize/deserialiaze
+ * trees correctly.
+ *
+ *  What's sent is actually a union:
+ *
+ *  union object_pointer switch (boolean b) {
+ *  case TRUE: object_data data;
+ *  case FALSE: void nothing;
+ *  }
+ *
+ * > objpp: Pointer to the pointer to the object.
+ * > obj_size: size of the object.
+ * > xdr_obj: routine to XDR an object.
+ *
+ */
+bool_t
+xdr_pointer(xdrs,objpp,obj_size,xdr_obj)
+       register XDR *xdrs;
+       char **objpp;
+       u_int obj_size;
+       xdrproc_t xdr_obj;
+{
+
+       bool_t more_data;
+
+       more_data = (*objpp != NULL);
+       if (! xdr_bool(xdrs,&more_data)) {
+               return (FALSE);
+       }
+       if (! more_data) {
+               *objpp = NULL;
+               return (TRUE);
+       }
+       return (xdr_reference(xdrs,objpp,obj_size,xdr_obj));
+}
+
+/* @(#)clnt_perror.c   1.1 87/11/04 3.9 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+struct rpc_errtab {
+       enum clnt_stat status;
+       char *message;
+};
+
+static struct rpc_errtab  rpc_errlist[] = {
+       { RPC_SUCCESS, 
+               "RPC: Success" }, 
+       { RPC_CANTENCODEARGS, 
+               "RPC: Can't encode arguments" },
+       { RPC_CANTDECODERES, 
+               "RPC: Can't decode result" },
+       { RPC_CANTSEND, 
+               "RPC: Unable to send" },
+       { RPC_CANTRECV, 
+               "RPC: Unable to receive" },
+       { RPC_TIMEDOUT, 
+               "RPC: Timed out" },
+       { RPC_VERSMISMATCH, 
+               "RPC: Incompatible versions of RPC" },
+       { RPC_AUTHERROR, 
+               "RPC: Authentication error" },
+       { RPC_PROGUNAVAIL, 
+               "RPC: Program unavailable" },
+       { RPC_PROGVERSMISMATCH, 
+               "RPC: Program/version mismatch" },
+       { RPC_PROCUNAVAIL, 
+               "RPC: Procedure unavailable" },
+       { RPC_CANTDECODEARGS, 
+               "RPC: Server can't decode arguments" },
+       { RPC_SYSTEMERROR, 
+               "RPC: Remote system error" },
+       { RPC_UNKNOWNHOST, 
+               "RPC: Unknown host" },
+/*     { RPC_UNKNOWNPROTO,
+               "RPC: Unknown protocol" },*/
+       { RPC_PMAPFAILURE, 
+               "RPC: Port mapper failure" },
+       { RPC_PROGNOTREGISTERED, 
+               "RPC: Program not registered"},
+       { RPC_FAILED, 
+               "RPC: Failed (unspecified error)"}
+};
+
+
+/*
+ * This interface for use by clntrpc
+ */
+char *
+clnt_sperrno(stat)
+       enum clnt_stat stat;
+{
+       int i;
+
+       for (i = 0; i < sizeof(rpc_errlist)/sizeof(struct rpc_errtab); i++) {
+               if (rpc_errlist[i].status == stat) {
+                       return (rpc_errlist[i].message);
+               }
+       }
+       return ("RPC: (unknown error code)");
+}
+
+#endif /* MISC_RPC */
+
diff --git a/usr/src/usr.sbin/amd/amd/mntfs.c b/usr/src/usr.sbin/amd/amd/mntfs.c
new file mode 100644 (file)
index 0000000..e0eb31e
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * $Id: mntfs.c,v 5.2 90/06/23 22:19:40 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)mntfs.c     5.1 (Berkeley) %G%
+ */
+
+#include "am.h"
+
+extern qelem mfhead;
+qelem mfhead = { &mfhead, &mfhead };
+
+int mntfs_allocated;
+
+/*
+ * This is the default attributes field which
+ * is copied into every new node to be created.
+ * The individual filesystem fs_init() routines
+ * patch the copy to represent the particular
+ * details for the relevant filesystem type
+ */
+static struct fattr gen_fattr = {
+       NFDIR,                          /* type */
+       NFSMODE_DIR | 0555,             /* mode */
+       2,                              /* nlink */
+       0,                              /* uid */
+       0,                              /* gid */
+       512,                            /* size */
+       4096,                           /* blocksize */
+       0,                              /* rdev */
+       1,                              /* blocks */
+       0,                              /* fsid */
+       0,                              /* fileid */
+       { 0, 0 },                       /* atime */
+       { 0, 0 },                       /* mtime */
+       { 0, 0 },                       /* ctime */
+};
+
+mntfs *dup_mntfs(mf)
+mntfs *mf;
+{
+       if (mf->mf_refc == 0) {
+               untimeout(mf->mf_cid);
+               mf->mf_cid = 0;
+               mf->mf_error = -1;
+               mf->mf_flags &= ~MFF_ERROR;
+       }
+       mf->mf_refc++;
+       return mf;
+}
+
+static init_mntfs(mf, ops, mo, mp, info, opts)
+mntfs *mf;
+am_ops *ops;
+am_opts *mo;
+char *mp;
+char *info;
+char *opts;
+{
+       mf->mf_ops = ops;
+       mf->mf_fo = mo;
+       mf->mf_mount = strdup(mp);
+       mf->mf_info = strdup(info);
+       mf->mf_opts = strdup(opts);
+       mf->mf_refc = 1;
+       mf->mf_flags = 0;
+       mf->mf_error = -1;
+       mf->mf_cid = 0;
+       mf->mf_private = 0;
+       mf->mf_prfree = 0;
+       mf->mf_attr.status = NFS_OK;
+       mf->mf_fattr = gen_fattr;
+       mf->mf_fattr.fsid = 42;
+       mf->mf_fattr.fileid = 0;
+       mf->mf_fattr.atime.seconds = clocktime();
+       mf->mf_fattr.atime.useconds = 0;
+       mf->mf_fattr.mtime = mf->mf_fattr.ctime = mf->mf_fattr.atime;
+
+       if (ops->ffserver)
+               mf->mf_server = (*ops->ffserver)(mf);
+       else
+               mf->mf_server = 0;
+}
+
+static mntfs *alloc_mntfs(ops, mo, mp, info, opts)
+am_ops *ops;
+am_opts *mo;
+char *mp;
+char *info;
+char *opts;
+{
+       mntfs *mf = ALLOC(mntfs);
+       init_mntfs(mf, ops, mo, mp, info, opts);
+       ins_que(&mf->mf_q, &mfhead);
+       mntfs_allocated++;
+
+       return mf;
+}
+
+mntfs *find_mntfs(ops, mo, mp, info, opts)
+am_ops *ops;
+am_opts *mo;
+char *mp;
+char *info;
+char *opts;
+{
+       mntfs *mf;
+
+#ifdef DEBUG
+       dlog("Locating mntfs reference to %s", mp);
+#endif /* DEBUG */
+       ITER(mf, mntfs, &mfhead) {
+               if (STREQ(mf->mf_mount, mp)) {
+                       /*
+                        * Handle cases where error ops are involved
+                        */
+                       if (ops == &efs_ops) {
+                               /*
+                                * If the existing ops are not efs_ops
+                                * then continue...
+                                */
+                               if (mf->mf_ops != &efs_ops)
+                                       continue;
+                       } else /* ops != &efs_ops */ {
+                               /*
+                                * If the existing ops are efs_ops
+                                * then continue...
+                                */
+                               if (mf->mf_ops == &efs_ops)
+                                       continue;
+                       }
+
+                       if ((mf->mf_flags & MFF_RESTART) && amd_state == Run) {
+                               /*
+                                * Restart a previously mounted filesystem.
+                                */
+                               mntfs *mf2 = alloc_mntfs(&ifs_ops, mo, mp, info, opts);
+#ifdef DEBUG
+                               dlog("Restarting filesystem %s", mf->mf_mount);
+#endif /* DEBUG */
+                               /*
+                                * Remember who we are restarting
+                                */
+                               mf2->mf_private = (voidp) dup_mntfs(mf);
+                               mf2->mf_prfree = free_mntfs;
+                               return mf2;
+                       }
+                       mf->mf_fo = mo;
+                       if (!(mf->mf_flags & (MFF_MOUNTED|MFF_MOUNTING|MFF_UNMOUNTING))) {
+                               fserver *fs;
+                               mf->mf_opts = strealloc(mf->mf_opts, opts);
+                               mf->mf_info = strealloc(mf->mf_info, info);
+                               fs = ops->ffserver ? (*ops->ffserver)(mf) : (fserver *) 0;
+                               if (mf->mf_server)
+                                       free_srvr(mf->mf_server);
+                               mf->mf_server = fs;
+                       }
+                       return dup_mntfs(mf);
+               }
+       }
+
+       return alloc_mntfs(ops, mo, mp, info, opts);
+}
+
+mntfs *new_mntfs()
+{
+       return alloc_mntfs(&efs_ops, (am_opts *) 0, "//nil//", ".", "");
+}
+
+static void uninit_mntfs(mf, rmd)
+mntfs *mf;
+int rmd;
+{
+       if (mf->mf_mount) free((voidp) mf->mf_mount);
+       if (mf->mf_opts) free((voidp) mf->mf_opts);
+       if (mf->mf_info) free((voidp) mf->mf_info);
+       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);
+
+       /*
+        * Clean up the file server
+        */
+       if (mf->mf_server)
+               free_srvr(mf->mf_server);
+
+       /*
+        * Don't do a callback on this mount
+        */
+       if (mf->mf_cid) {
+               untimeout(mf->mf_cid);
+               mf->mf_cid = 0;
+       }
+}
+
+static void discard_mntfs(mf)
+mntfs *mf;
+{
+       rem_que(&mf->mf_q);
+       /*
+        * Free memory
+        */
+       uninit_mntfs(mf, TRUE);
+       free((voidp) mf);
+
+       --mntfs_allocated;
+}
+
+void flush_mntfs()
+{
+       mntfs *mf;
+
+       mf = FIRST(mntfs, &mfhead);
+       while (mf != HEAD(mntfs, &mfhead)) {
+               mntfs *mf2 = mf;
+               mf = NEXT(mntfs, mf);
+               if (mf2->mf_refc == 0 && mf2->mf_cid)
+                       discard_mntfs(mf2);
+       }
+}
+
+void free_mntfs(mf)
+mntfs *mf;
+{
+       if (--mf->mf_refc == 0) {
+               if (mf->mf_flags & MFF_MOUNTED) {
+                       int quoted;
+                       mf->mf_flags &= ~MFF_MOUNTED;
+
+                       /*
+                        * Record for posterity
+                        */
+                       quoted = strchr(mf->mf_info, ' ') != 0; /* cheap */
+                       plog(XLOG_INFO, "%s%s%s %sed fstype %s from %s",
+                               quoted ? "\"" : "",
+                               mf->mf_info,
+                               quoted ? "\"" : "",
+                               mf->mf_error ? "discard" : "unmount",
+                               mf->mf_ops->fs_type, mf->mf_mount);
+               }
+
+               if (mf->mf_ops->fs_flags & FS_DISCARD) {
+#ifdef DEBUG
+                       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 {
+                               dlog("Discarding last mntfs reference to %s fstype %s",
+                                       mf->mf_mount, mf->mf_ops->fs_type);
+                       }
+                       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);
+               }
+       }
+}
+
+mntfs *realloc_mntfs(mf, ops, mo, mp, info, opts)
+mntfs *mf;
+am_ops *ops;
+am_opts *mo;
+char *mp;
+char *info;
+char *opts;
+{
+       mntfs *mf2;
+       if (mf->mf_refc == 1 && mf->mf_ops == &ifs_ops && STREQ(mf->mf_mount, mp)) {
+               /*
+                * If we are inheriting then just return
+                * the same node...
+                */
+               return mf;
+       }
+       mf2 = find_mntfs(ops, mo, mp, info, opts);
+       free_mntfs(mf);
+       return mf2;
+}
diff --git a/usr/src/usr.sbin/amd/amd/mount_fs.c b/usr/src/usr.sbin/amd/amd/mount_fs.c
new file mode 100644 (file)
index 0000000..12f76a6
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * $Id: mount_fs.c,v 5.2 90/06/23 22:19:42 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)mount_fs.c  5.1 (Berkeley) %G%
+ */
+
+#include "am.h"
+#ifdef NFS_3
+typedef nfs_fh fhandle_t;
+#endif /* NFS_3 */
+#include <sys/mount.h>
+
+/*
+ * System Vr4 / SunOS 4.1 compatibility
+ * - put dev= in the options list
+ *
+ * From: Brent Callaghan <brent@eng.sun.com>
+ */
+#define        MNTINFO_DEV     "dev"
+#include <sys/stat.h>
+
+/*
+ * Standard mount flags
+ */
+#ifdef hpux
+/*
+ * HP-UX has an annoying feature of printing
+ * error msgs on /dev/console
+ */
+#undef M_NOSUID
+#endif /* hpux */
+
+struct opt_tab mnt_flags[] = {
+       { "ro", M_RDONLY },
+#ifdef M_CACHE
+       { "nocache", M_NOCACHE },
+#endif /* M_CACHE */
+#ifdef M_GRPID
+       { "grpid", M_GRPID },
+#endif /* M_GRPID */
+#ifdef M_MULTI
+       { "multi", M_MULTI },
+#endif /* M_MULTI */
+#ifdef M_NODEV
+       { "nodev", M_NODEV },
+#endif /* M_NODEV */
+#ifdef M_NOEXEC
+       { "noexec", M_NOEXEC },
+#endif /* M_NOEXEC */
+#ifdef M_NOSUB
+       { "nosub", M_NOSUB },
+#endif /* M_NOSUB */
+#ifdef M_NOSUID
+       { "nosuid", M_NOSUID },
+#endif /* M_NOSUID */
+#ifdef M_SYNC
+       { "sync", M_SYNC },
+#endif /* M_SYNC */
+       { 0, 0 }
+};
+
+int compute_mount_flags(mnt)
+struct mntent *mnt;
+{
+       struct opt_tab *opt;
+       int flags;
+#ifdef NFS_4
+       flags = M_NEWTYPE;
+#else
+       flags = 0;
+#endif /* NFS_4 */
+
+       /*
+        * Crack basic mount options
+        */
+       for (opt = mnt_flags; opt->opt; opt++)
+               flags |= hasmntopt(mnt, opt->opt) ? opt->flag : 0;
+
+       return flags;
+}
+
+int mount_fs(mnt, flags, mnt_data, retry, type)
+struct mntent *mnt;
+int flags;
+caddr_t mnt_data;
+int retry;
+MTYPE_TYPE type;
+{
+       int error = 0;
+       int automount = 0;
+#ifdef MNTINFO_DEV
+       struct stat stb;
+       char *xopts = 0;
+#endif /* MNTINFO_DEV */
+
+#ifdef DEBUG
+#ifdef NFS_4
+       dlog("%s fstype %s (%s) flags %#x (%s)",
+               mnt->mnt_dir, type, mnt->mnt_type, flags, mnt->mnt_opts);
+#else
+       dlog("%s fstype %d (%s) flags %#x (%s)",
+               mnt->mnt_dir, type, mnt->mnt_type, flags, mnt->mnt_opts);
+#endif /* NFS_4 */
+#endif /* DEBUG */
+
+       /*
+        * Fake some mount table entries for the automounter
+        */
+       if (STREQ(mnt->mnt_type, MNTTYPE_AUTO)) {
+               automount = 1;
+               mnt->mnt_fsname = pid_fsname;
+               /*
+                * Try it with the normal name
+                */
+#ifdef notdef
+               /*
+                * This is notdef'ed because some systems use
+                * the mount table in getwd() (esp. SunOS4) and
+                * if all the mount points are not marked it can
+                * cause major confusion.  This can probably
+                * be changed when no-one is running SunOS 4.0
+                * any more.
+                */
+               mnt->mnt_type = MNTTYPE_IGNORE;
+#endif /* notdef */
+               mnt->mnt_type = MNTTYPE_NFS;
+               /*
+                * Background the mount, so that the stat of the
+                * mountpoint is done in a background process.
+                */
+               if (background())
+                       return 0;
+       }
+
+again:
+       clock_valid = 0;
+       error = MOUNT_TRAP(type, mnt, flags, mnt_data);
+       if (error < 0)
+               plog(XLOG_ERROR, "%s: mount: %m", mnt->mnt_dir);
+       if (error < 0 && --retry > 0) {
+               sleep(1);
+               goto again;
+       }
+       if (error < 0) {
+               if (automount)
+                       going_down(errno);
+               return errno;
+       }
+
+#ifdef UPDATE_MTAB
+#ifdef MNTINFO_DEV
+       /*
+        * Add the extra dev= field to the mount table.
+        */
+       if (lstat(mnt->mnt_dir, &stb) == 0) {
+               char *zopts = (char *) xmalloc(strlen(mnt->mnt_opts) + 32);
+               xopts = mnt->mnt_opts;
+               if (sizeof(stb.st_dev) == 2) {
+                       /* SunOS 4.1 */
+                       sprintf(zopts, "%s,%s=%04lx", xopts, MNTINFO_DEV,
+                                       (u_long) stb.st_dev & 0xffff);
+               } else {
+                       /* System Vr4 */
+                       sprintf(zopts, "%s,%s=%08lx", xopts, MNTINFO_DEV,
+                                       (u_long) stb.st_dev);
+               }
+               mnt->mnt_opts = zopts;
+       }
+#endif /* MNTINFO_DEV */
+
+#ifdef hpux
+       /*
+        * Yet another gratuitously incompatible change in HP-UX
+        */
+       mnt->mnt_time = clocktime();
+#endif /* hpux */
+       write_mntent(mnt);
+#ifdef MNTINFO_DEV
+       if (xopts) {
+               free(mnt->mnt_opts);
+               mnt->mnt_opts = xopts;
+       }
+#endif /* MNTINFO_DEV */
+#endif /* UPDATE_MTAB */
+
+       /*
+        * Needed this way since mnt may contain a pointer
+        * to a local variable in this stack frame.
+        */
+       if (automount)
+               going_down(0);
+       return 0;
+}
+
+#ifdef NEED_MNTOPT_PARSER
+/*
+ * Some systems don't provide these to the user,
+ * but amd needs them, so...
+ *
+ * From: Piete Brooks <pb@cl.cam.ac.uk>
+ */
+
+#include <ctype.h>
+
+static char *nextmntopt(p)
+char **p;
+{
+       char *cp = *p;
+       char *rp;
+       /*
+        * Skip past white space
+        */
+       while (*cp && isspace(*cp))
+               cp++;
+       /*
+        * Word starts here
+        */
+       rp = cp;
+       /*
+        * Scan to send of string or separator
+        */
+       while (*cp && *cp != ',')
+               cp++;
+       /*
+        * If separator found the overwrite with nul char.
+        */
+       if (*cp) {
+               *cp = '\0';
+               cp++;
+       }
+       /*
+        * Return value for next call
+        */
+       *p = cp;
+       return rp;
+}
+
+char *hasmntopt(mnt, opt)
+struct mntent *mnt;
+char *opt;
+{
+       char t[MNTMAXSTR];
+       char *f;
+       char *o = t;
+       int l = strlen(opt);
+       strcpy(t, mnt->mnt_opts);
+
+       while (*(f = nextmntopt(&o)))
+               if (strncmp(opt, f, l) == 0)
+                       return f - t + mnt->mnt_opts;
+
+       return 0;
+}
+#endif /* NEED_MNTOPT_PARSER */
+
+#ifdef MOUNT_AIX3
+
+#include "aix3-nfs.h"
+
+static int aix3_mkvp(p, gfstype, flags, object, stub, host, info, info_size, args)
+char *p;
+int gfstype;
+int flags;
+char *object;
+char *stub;
+char *host;
+char *info;
+int info_size;
+char *args;
+{
+       struct vmount *vp = (struct vmount *) p;
+       bzero((voidp) vp, sizeof(*vp));
+       /*
+        * Fill in standard fields
+        */
+       vp->vmt_revision = VMT_REVISION;
+       vp->vmt_flags = flags;
+       vp->vmt_gfstype = gfstype;
+
+#define        VMT_ROUNDUP(len) (4 * ((len + 3) / 4))
+#define VMT_ASSIGN(vp, idx, data, size) \
+       vp->vmt_data[idx].vmt_off = p - (char *) vp; \
+       vp->vmt_data[idx].vmt_size = size; \
+       bcopy(data, p, size); \
+       p += VMT_ROUNDUP(size);
+
+       /*
+        * Fill in all variable length data
+        */
+       p += sizeof(*vp);
+
+       VMT_ASSIGN(vp, VMT_OBJECT, object, strlen(object) + 1);
+       VMT_ASSIGN(vp, VMT_STUB, stub, strlen(stub) + 1);
+       VMT_ASSIGN(vp, VMT_HOST, host, strlen(host) + 1);
+       VMT_ASSIGN(vp, VMT_HOSTNAME, host, strlen(host) + 1);
+       VMT_ASSIGN(vp, VMT_INFO, info, info_size);
+       VMT_ASSIGN(vp, VMT_ARGS, args, strlen(args) + 1);
+
+#undef VMT_ASSIGN
+#undef VMT_ROUNDUP
+
+       /*
+        * Return length
+        */
+       return vp->vmt_length = p - (char *) vp;
+}
+
+/*
+ * Map from conventional mount arguments
+ * to AIX 3-style arguments.
+ */
+aix3_mount(fsname, dir, flags, type, data, args)
+char *fsname;
+char *dir;
+int flags;
+int type;
+void *data;
+char *args;
+{
+       char buf[4096];
+       int size;
+
+#ifdef DEBUG
+       dlog("aix3_mount: fsname %s, dir %s, type %d", fsname, dir, type);
+#endif /* DEBUG */
+
+/* aix3_mkvp(p, gfstype, flags, object, stub, host, info, info_size, args) */
+
+       switch (type) {
+
+       case MOUNT_TYPE_NFS: {
+               char *host = strdup(fsname);
+               char *rfs = strchr(host, ':');
+               *rfs++ = '\0';
+
+               size = aix3_mkvp(buf, type, flags, rfs, dir, host, data, sizeof(struct nfs_args), args);
+               free(host);
+
+               } break;
+
+       case MOUNT_TYPE_UFS:
+               /* Need to open block device and extract log device info from sblk. */
+               return EINVAL;
+
+       default:
+               return EINVAL;
+       }
+#ifdef DEBUG
+       /*dlog("aix3_mkvp: flags %#x, size %d, args %s", flags, size, args);*/
+#endif /* DEBUG */
+
+       return vmount(buf, size);
+}
+#endif /* MOUNT_AIX3 */
diff --git a/usr/src/usr.sbin/amd/amd/mtab.c b/usr/src/usr.sbin/amd/amd/mtab.c
new file mode 100644 (file)
index 0000000..436c151
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * $Id: mtab.c,v 5.2 90/06/23 22:19:44 jsp Rel $
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)mtab.c      5.1 (Berkeley) %G%
+ */
+
+#include "am.h"
+
+/*
+ * Firewall /etc/mtab entries
+ */
+void mnt_free(mp)
+struct mntent *mp;
+{
+       free(mp->mnt_fsname);
+       free(mp->mnt_dir);
+       free(mp->mnt_type);
+       free(mp->mnt_opts);
+       free((voidp) mp);
+}
+
+/*
+ * Discard memory allocated for mount list
+ */
+void discard_mntlist(mp)
+mntlist *mp;
+{
+       mntlist *mp2;
+
+       while (mp2 = mp) {
+               mp = mp->mnext;
+               if (mp2->mnt)
+                       mnt_free(mp2->mnt);
+               free(mp2);
+       }
+}
+
+/*
+ * Throw away a mount list
+ */
+void free_mntlist(mp)
+mntlist *mp;
+{
+       discard_mntlist(mp);
+       unlock_mntlist();
+}
+
+/*
+ * Utility routine which determines the value of a
+ * numeric option in the mount options (such as port=%d).
+ * Returns 0 if the option is not specified.
+ */
+int hasmntval(mnt, opt)
+struct mntent *mnt;
+char *opt;
+{
+       char *str = hasmntopt(mnt, opt);
+       if (str) {
+               char *eq = strchr(str, '=');
+               if (eq)
+                       return atoi(eq+1);
+               else
+                       plog(XLOG_USER, "bad numeric option \"%s\" in \"%s\"", opt, str);
+       }
+
+       return 0;
+}
diff --git a/usr/src/usr.sbin/amd/amd/nfs_ops.c b/usr/src/usr.sbin/amd/amd/nfs_ops.c
new file mode 100644 (file)
index 0000000..24d9355
--- /dev/null
@@ -0,0 +1,668 @@
+/*
+ * $Id: nfs_ops.c,v 5.2 90/06/23 22:19:45 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)nfs_ops.c   5.1 (Berkeley) %G%
+ */
+
+#include "am.h"
+
+#ifdef HAS_NFS
+
+#define NFS
+#define NFSCLIENT
+#ifdef NFS_3
+typedef nfs_fh fhandle_t;
+#endif /* NFS_3 */
+#ifdef NFS_HDR
+#include NFS_HDR
+#endif /* NFS_HDR */
+#include <sys/mount.h>
+#include "mount.h"
+
+/*
+ * Network file system
+ */
+
+/*
+ * Convert from nfsstat to UN*X error code
+ */
+#define unx_error(e)   ((int)(e))
+
+/*
+ * The NFS layer maintains a cache of file handles.
+ * This is *fundamental* to the implementation and
+ * also allows quick remounting when a filesystem
+ * is accessed soon after timing out.
+ *
+ * The NFS server layer knows to flush this cache
+ * when a server goes down so avoiding stale handles.
+ *
+ * Each cache entry keeps a hard reference to
+ * the corresponding server.  This ensures that
+ * the server keepalive information is maintained.
+ *
+ * The copy of the sockaddr_in here is taken so
+ * that the port can be twiddled to talk to mountd
+ * instead of portmap or the NFS server as used
+ * elsewhere.
+ * The port# is flushed if a server goes down.
+ * The IP address is never flushed - we assume
+ * that the address of a mounted machine never
+ * changes.  If it does, then you have other
+ * problems...
+ */
+typedef struct fh_cache fh_cache;
+struct fh_cache {
+       qelem   fh_q;                   /* List header */
+       voidp   fh_wchan;               /* Wait channel */
+       int     fh_error;               /* Valid data? */
+       int     fh_id;                  /* Unique id */
+       int     fh_cid;                 /* Callout id */
+       struct fhstatus fh_handle;      /* Handle on filesystem */
+       struct sockaddr_in fh_sin;      /* Address of mountd */
+       fserver *fh_fs;                 /* Server holding filesystem */
+       char    *fh_path;               /* Filesystem on host */
+};
+
+/*
+ * FH_TTL is the time a file handle will remain in the cache since
+ * last being used.  If the file handle becomes invalid, then it
+ * will be flushed anyway.
+ */
+#define        FH_TTL          (5 * 60)                /* five minutes */
+#define        FH_TTL_ERROR    (30)                    /* 30 seconds */
+
+static int fh_id = 0;
+#define        FHID_ALLOC()    (++fh_id)
+extern qelem fh_head;
+qelem fh_head = { &fh_head, &fh_head };
+
+static int call_mountd P((fh_cache*, unsigned long, fwd_fun, voidp));
+
+AUTH *nfs_auth;
+
+static fh_cache *find_nfs_fhandle_cache P((voidp idv, int done));
+static fh_cache *find_nfs_fhandle_cache(idv, done)
+voidp idv;
+int done;
+{
+       fh_cache *fp, *fp2 = 0;
+       int id = (int) idv;
+
+       ITER(fp, fh_cache, &fh_head) {
+               if (fp->fh_id == id) {
+                       fp2 = fp;
+                       break;
+               }
+       }
+
+#ifdef DEBUG
+       if (fp2) {
+               dlog("fh cache gives fp %#x, fs %s", fp2, fp2->fh_path);
+       } else {
+               dlog("fh cache search failed");
+       }
+#endif /* DEBUG */
+
+       if (fp2 && !done) {
+               fp2->fh_error = ETIMEDOUT;
+               return 0;
+       }
+
+       return fp2;
+}
+
+/*
+ * Called when a filehandle appears
+ */
+static void got_nfs_fh P((voidp pkt, int len, struct sockaddr_in *sa,
+                               struct sockaddr_in *ia, voidp idv, int done));
+static void got_nfs_fh(pkt, len, sa, ia, idv, done)
+voidp pkt;
+int len;
+struct sockaddr_in *sa, *ia;
+voidp idv;
+int done;
+{
+       fh_cache *fp = find_nfs_fhandle_cache(idv, done);
+       if (fp) {
+               fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &fp->fh_handle, xdr_fhstatus);
+               if (!fp->fh_error) {
+#ifdef DEBUG
+                       dlog("got filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path);
+#endif /* DEBUG */
+                       /*
+                        * Wakeup anything sleeping on this filehandle
+                        */
+                       if (fp->fh_wchan) {
+#ifdef DEBUG
+                               dlog("Calling wakeup on %#x", fp->fh_wchan);
+#endif /* DEBUG */
+                               wakeup(fp->fh_wchan);
+                       }
+               }
+       }
+}
+
+void flush_nfs_fhandle_cache P((fserver *fs));
+void flush_nfs_fhandle_cache(fs)
+fserver *fs;
+{
+       fh_cache *fp;
+       ITER(fp, fh_cache, &fh_head) {
+               if (fp->fh_fs == fs) {
+                       fp->fh_sin.sin_port = (u_short) 0;
+                       fp->fh_error = -1;
+               }
+       }
+}
+
+static void discard_fh P((fh_cache *fp));
+static void discard_fh(fp)
+fh_cache *fp;
+{
+       rem_que(&fp->fh_q);
+#ifdef DEBUG
+       dlog("Discarding filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path);
+#endif /* DEBUG */
+       free_srvr(fp->fh_fs);
+       free((voidp) fp->fh_path);
+       free((voidp) fp);
+}
+
+/*
+ * Determine the file handle for a node
+ */
+static int prime_nfs_fhandle_cache P((char *path, fserver *fs, struct fhstatus *fhbuf, voidp wchan));
+static int prime_nfs_fhandle_cache(path, fs, fhbuf, wchan)
+char *path;
+fserver *fs;
+struct fhstatus *fhbuf;
+voidp wchan;
+{
+       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 && strcmp(path, fp->fh_path) == 0) {
+                       switch (fp->fh_error) {
+                       case 0:
+                               error = fp->fh_error = unx_error(fp->fh_handle.fhs_status);
+                               if (error == 0) {
+                                       if (fhbuf)
+                                               bcopy((voidp) &fp->fh_handle, (voidp) fhbuf,
+                                                       sizeof(fp->fh_handle));
+                                       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);
+                               }
+
+                               /*
+                                * The error was returned from the remote mount daemon.
+                                * Policy: this error will be cached for now...
+                                */
+                               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;
+                       }
+                       break;
+               }
+       }
+
+       /*
+        * Not in cache
+        */
+       if (fp_save) {
+               fp = fp_save;
+               /*
+                * Re-use existing slot
+                */
+               untimeout(fp->fh_cid);
+               free_srvr(fp->fh_fs);
+               free(fp->fh_path);
+       } else {
+               fp = ALLOC(fh_cache);
+               bzero((voidp) fp, sizeof(*fp));
+               ins_que(&fp->fh_q, &fh_head);
+       }
+       if (!reuse_id)
+               fp->fh_id = FHID_ALLOC();
+       fp->fh_wchan = wchan;
+       fp->fh_error = -1;
+       fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp);
+
+       /*
+        * If the address has changed then don't try to re-use the
+        * port information
+        */
+       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;
+       }
+       fp->fh_fs = dup_srvr(fs);
+       fp->fh_path = strdup(path);
+
+       error = call_mountd(fp, MOUNTPROC_MNT, got_nfs_fh, wchan);
+       if (error) {
+               /*
+                * Local error - cache for a short period
+                * just to prevent thrashing.
+                */
+               untimeout(fp->fh_cid);
+               fp->fh_cid = timeout(error < 0 ? 2 * ALLOWED_MOUNT_TIME : FH_TTL_ERROR,
+                                               discard_fh, (voidp) fp);
+               fp->fh_error = error;
+       } else {
+               error = fp->fh_error;
+       }
+       return error;
+}
+
+static int call_mountd P((fh_cache *fp, u_long proc, fwd_fun f, voidp wchan));
+static int call_mountd(fp, proc, f, wchan)
+fh_cache *fp;
+u_long proc;
+fwd_fun f;
+voidp wchan;
+{
+       struct rpc_msg mnt_msg;
+       int len;
+       char iobuf[8192];
+       int error;
+
+       if (!nfs_auth) {
+               nfs_auth = authunix_create_default();
+               if (!nfs_auth)
+                       return ENOBUFS;
+       }
+
+       if (fp->fh_sin.sin_port == 0) {
+               u_short port;
+               error = nfs_srvr_port(fp->fh_fs, &port, wchan);
+               if (error)
+                       return error;
+               fp->fh_sin.sin_port = port;
+       }
+
+       rpc_msg_init(&mnt_msg, MOUNTPROG, MOUNTVERS, (unsigned long) 0);
+       len = make_rpc_packet(iobuf, sizeof(iobuf), proc,
+                       &mnt_msg, (voidp) &fp->fh_path, xdr_nfspath,  nfs_auth);
+
+       if (len > 0) {
+               error = fwd_packet(MK_RPC_XID(RPC_XID_MOUNTD, fp->fh_id),
+                       (voidp) iobuf, len, &fp->fh_sin, &fp->fh_sin, (voidp) fp->fh_id, f);
+       } else {
+               error = -len;
+       }
+       return error;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * NFS needs the local filesystem, remote filesystem
+ * remote hostname.
+ * Local filesystem defaults to remote and vice-versa.
+ */
+static int nfs_match(fo)
+am_opts *fo;
+{
+       if (fo->opt_fs && !fo->opt_rfs)
+               fo->opt_rfs = fo->opt_fs;
+       if (!fo->opt_rfs) {
+               plog(XLOG_USER, "nfs: no remote filesystem specified");
+               return FALSE;
+       }
+       if (!fo->opt_rhost) {
+               plog(XLOG_USER, "nfs: no remote host specified");
+               return FALSE;
+       }
+       /*
+        * Determine magic cookie to put in mtab
+        */
+       fo->fs_mtab = (char *) xrealloc(fo->fs_mtab, strlen(fo->opt_rhost) +
+                               strlen(fo->opt_rfs) + 2);
+       sprintf(fo->fs_mtab, "%s:%s", fo->opt_rhost, fo->opt_rfs);
+#ifdef DEBUG
+       dlog("NFS: mounting remote server \"%s\", remote fs \"%s\" on \"%s\"",
+               fo->opt_rhost, fo->opt_rfs, fo->opt_fs);
+#endif /* DEBUG */
+
+       return TRUE;
+}
+
+/*
+ * Initialise am structure for nfs
+ */
+static int nfs_init(mf)
+mntfs *mf;
+{
+       int error;
+       char *colon = strchr(mf->mf_info, ':');
+       if (colon == 0)
+               return ENOENT;
+
+       error = prime_nfs_fhandle_cache(colon+1, mf->mf_server, (struct fhstatus *) 0, (voidp) mf);
+
+       return error;
+}
+
+mount_nfs_fh(fhp, dir, fs_name, opts, mf)
+struct fhstatus *fhp;
+char *dir;
+char *fs_name;
+char *opts;
+mntfs *mf;
+{
+       struct nfs_args nfs_args;
+       struct mntent mnt;
+       int retry;
+       char *colon;
+       char *path;
+       char host[MAXHOSTNAMELEN + MAXPATHLEN + 2];
+       fserver *fs = mf->mf_server;
+       int flags;
+#ifdef notdef
+       unsigned short port;
+#endif /* notdef */
+
+       MTYPE_TYPE type = MOUNT_TYPE_NFS;
+
+       bzero((voidp) &nfs_args, sizeof(nfs_args));     /* Paranoid */
+
+       /*
+        * Extract host name to give to kernel
+        */
+       if (!(colon = strchr(fs_name, ':')))
+               return ENOENT;
+#ifndef NFS_ARGS_NEEDS_PATH
+       *colon = '\0';
+#endif
+       strncpy(host, fs_name, sizeof(host));
+#ifndef NFS_ARGS_NEEDS_PATH
+       *colon = ':';
+#endif /* NFS_ARGS_NEEDS_PATH */
+       path = colon + 1;
+
+       bzero((voidp) &nfs_args, sizeof(nfs_args));
+
+       mnt.mnt_dir = dir;
+       mnt.mnt_fsname = fs_name;
+       mnt.mnt_type = MTAB_TYPE_NFS;
+       mnt.mnt_opts = opts;
+       mnt.mnt_freq = 0;
+       mnt.mnt_passno = 0;
+
+       retry = hasmntval(&mnt, "retry");
+       if (retry <= 0)
+               retry = 1;      /* XXX */
+
+/*again:*/
+
+       /*
+        * set mount args
+        */
+       NFS_FH_DREF(nfs_args.fh, (NFS_FH_TYPE) fhp->fhstatus_u.fhs_fhandle);
+
+#ifdef ULTRIX_HACK
+       nfs_args.optstr = mnt.mnt_opts;
+#endif /* ULTRIX_HACK */
+
+       nfs_args.hostname = host;
+       nfs_args.flags |= NFSMNT_HOSTNAME;
+#ifdef HOSTNAMESZ
+       /*
+        * Most kernels have a name length restriction.
+        */
+       if (strlen(host) >= HOSTNAMESZ)
+               strcpy(host + HOSTNAMESZ - 3, "..");
+#endif /* HOSTNAMESZ */
+
+       if (nfs_args.rsize = hasmntval(&mnt, "rsize"))
+               nfs_args.flags |= NFSMNT_RSIZE;
+
+       if (nfs_args.wsize = hasmntval(&mnt, "wsize"))
+               nfs_args.flags |= NFSMNT_WSIZE;
+
+       if (nfs_args.timeo = hasmntval(&mnt, "timeo"))
+               nfs_args.flags |= NFSMNT_TIMEO;
+
+       if (nfs_args.retrans = hasmntval(&mnt, "retrans"))
+               nfs_args.flags |= NFSMNT_RETRANS;
+
+#ifdef NFSMNT_BIODS
+       if (nfs_args.biods = hasmntval(&mnt, "biods"))
+               nfs_args.flags |= NFSMNT_BIODS;
+
+#endif /* NFSMNT_BIODS */
+
+#ifdef notdef
+/*
+ * This isn't supported by the ping algorithm yet.
+ * In any case, it is all done in nfs_init().
+ */
+       if (port = hasmntval(&mnt, "port"))
+               sin.sin_port = htons(port);
+       else
+               sin.sin_port = htons(NFS_PORT); /* XXX should use portmapper */
+#endif /* notdef */
+
+       if (hasmntopt(&mnt, MNTOPT_SOFT) != NULL)
+               nfs_args.flags |= NFSMNT_SOFT;
+
+#ifdef MNTOPT_INTR
+       if (hasmntopt(&mnt, MNTOPT_INTR) != NULL)
+               nfs_args.flags |= NFSMNT_INT;
+#endif /* MNTOPT_INTR */
+
+#ifdef MNTOPT_NODEVS
+       if (hasmntopt(&mnt, MNTOPT_NODEVS) != NULL)
+               nfs_args.flags |= NFSMNT_NODEVS;
+#endif /* MNTOPT_NODEVS */
+
+#ifdef NFSMNT_PGTHRESH
+       if (nfs_args.pg_thresh = hasmntval(&mnt, "pgthresh"))
+               nfs_args.flags |= NFSMNT_PGTHRESH;
+#endif /* NFSMNT_PGTHRESH */
+
+       NFS_SA_DREF(nfs_args, fs->fs_ip);
+
+       flags = compute_mount_flags(&mnt);
+
+#ifdef HAS_TCP_NFS
+       if (hasmntopt(&mnt, "tcp") != NULL)
+               nfs_args.sotype = SOCK_STREAM;
+#endif /* HAS_TCP_NFS */
+
+
+#ifdef ULTRIX_HACK
+       /*
+        * Ultrix passes the flags argument as part of the
+        * mount data structure, rather than using the
+        * flags argument to the system call.  This is
+        * confusing...
+        */
+       if (!(nfs_args.flags & NFSMNT_PGTHRESH)) {
+               nfs_args.pg_thresh = 64; /* 64k - XXX */
+               nfs_args.flags |= NFSMNT_PGTHRESH;
+       }
+       nfs_args.gfs_flags = flags;
+       flags &= M_RDONLY;
+       if (flags & M_RDONLY)
+               nfs_args.flags |= NFSMNT_RONLY;
+#endif /* ULTRIX_HACK */
+
+       return mount_fs(&mnt, flags, (caddr_t) &nfs_args, retry, type);
+}
+
+static mount_nfs(dir, fs_name, opts, mf)
+char *dir;
+char *fs_name;
+char *opts;
+mntfs *mf;
+{
+       int error;
+       struct fhstatus fhs;
+       char *colon;
+
+       if (!(colon = strchr(fs_name, ':')))
+               return ENOENT;
+
+#ifdef DEBUG
+       dlog("locating fhandle for %s", fs_name);
+#endif /* DEBUG */
+       error = prime_nfs_fhandle_cache(colon+1, mf->mf_server, &fhs, (voidp) 0);
+
+       if (error)
+               return error;
+
+       return mount_nfs_fh(&fhs, dir, fs_name, opts, mf);
+}
+
+static int nfs_mount(mp)
+am_node *mp;
+{
+       mntfs *mf = mp->am_mnt;
+
+       int error = mount_nfs(mf->mf_mount, mf->mf_info,
+                       mf->mf_fo->opt_opts, mf);
+
+#ifdef DEBUG
+       if (error) {
+               errno = error;
+               dlog("mount_nfs: %m");
+       }
+#endif /* DEBUG */
+       return error;
+}
+
+static int nfs_umount(mp)
+am_node *mp;
+{
+       mntfs *mf = mp->am_mnt;
+
+       int error = UMOUNT_FS(mf->mf_mount);
+       if (error)
+               return error;
+
+       return 0;
+}
+
+static void nfs_umounted(mp)
+am_node *mp;
+{
+#ifdef INFORM_MOUNTD
+       /*
+        * 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;
+
+       /*
+        * 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 flushed from the cache, and
+        * a reference held to the cached entry while the
+        * fs is mounted...
+        */
+       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;
+               f.fh_sin.sin_port = (u_short) 0;
+               f.fh_fs = fs;
+               f.fh_id = 0;
+               f.fh_error = 0;
+               (void) prime_nfs_fhandle_cache(colon+1, mf->mf_server, (struct fhstatus *) 0, (voidp) mf);
+               (void) call_mountd(&f, MOUNTPROC_UMNT, (fwd_fun) 0, (voidp) 0);
+               *colon = ':';
+       }
+#endif /* INFORM_MOUNTD */
+}
+
+/*
+ * Network file system
+ */
+am_ops nfs_ops = {
+       "nfs",
+       nfs_match,
+       nfs_init,
+       nfs_mount,
+       nfs_umount,
+       efs_lookuppn,
+       efs_readdir,
+       0, /* nfs_readlink */
+       0, /* nfs_mounted */
+       nfs_umounted,
+       find_nfs_srvr,
+       FS_MKMNT|FS_BACKGROUND|FS_AMQINFO
+};
+
+#endif /* HAS_NFS */
diff --git a/usr/src/usr.sbin/amd/amd/nfs_start.c b/usr/src/usr.sbin/amd/amd/nfs_start.c
new file mode 100644 (file)
index 0000000..37932ee
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+ * $Id: nfs_start.c,v 5.2 90/06/23 22:19:48 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)nfs_start.c 5.1 (Berkeley) %G%
+ */
+
+#include "am.h"
+#include "amq.h"
+#include <sys/signal.h>
+#include <setjmp.h>
+extern jmp_buf select_intr;
+extern int select_intr_valid;
+
+#ifdef HAS_TFS
+/*
+ * Use replacement for RPC/UDP transport
+ * so that we do NFS gatewaying.
+ */
+#define        svcudp_create svcudp2_create
+extern SVCXPRT *svcudp2_create P((int));
+#endif /* HAS_TFS */
+
+extern void nfs_program_2();
+extern void amq_program_1();
+
+unsigned short nfs_port;
+SVCXPRT *nfsxprt;
+
+extern int fwd_sock;
+int max_fds = -1;
+
+#define        MASKED_SIGS     (sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGCHLD)|sigmask(SIGHUP))
+
+#ifdef DEBUG
+/*
+ * Check that we are not burning resources
+ */
+static void checkup(P_void)
+{
+
+static int max_fd = 0;
+static char *max_mem = 0;
+
+       int next_fd = dup(0);
+       extern caddr_t sbrk P((int));
+       caddr_t next_mem = sbrk(0);
+       close(next_fd);
+
+       /*if (max_fd < 0) {
+               max_fd = next_fd;
+       } else*/ if (max_fd < next_fd) {
+               dlog("%d new fds allocated; total is %d",
+                       next_fd - max_fd, next_fd);
+               max_fd = next_fd;
+       }
+
+       /*if (max_mem == 0) {
+               max_mem = next_mem;
+       } else*/ if (max_mem < next_mem) {
+               dlog("%#x bytes of memory allocated; total is %#x (%d pages)",
+                       next_mem - max_mem,
+                       next_mem,
+                       ((int)next_mem+getpagesize()-1)/getpagesize());
+               max_mem = next_mem;
+       }
+}
+#endif /* DEBUG */
+
+static int do_select(smask, fds, fdp, tvp)
+int smask;
+int fds;
+int *fdp;
+struct timeval *tvp;
+{
+       int sig;
+       int nsel;
+       if (sig = setjmp(select_intr)) {
+               select_intr_valid = 0;
+               /* Got a signal */
+               switch (sig) {
+               case SIGINT:
+               case SIGTERM:
+                       amd_state = Finishing;
+                       reschedule_timeout_mp();
+                       break;
+               }
+               nsel = -1;
+               errno = EINTR;
+       } 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.
+                */
+               (void) sigsetmask(smask);
+               /*
+                * Wait for input
+                */
+               nsel = select(fds, fdp, (int *) 0, (int *) 0,
+                               tvp->tv_sec ? tvp : (struct timeval *) 0);
+
+       }
+
+       (void) sigblock(MASKED_SIGS);
+
+       /*
+        * Perhaps reload the cache?
+        */
+       if (do_mapc_reload < clocktime()) {
+               mapc_reload();
+               do_mapc_reload = clocktime() + ONE_HOUR;
+       }
+       return nsel;
+}
+
+static serv_state run_rpc(P_void)
+{
+       int dtbsz = max_fds + 1;
+       int smask = sigblock(MASKED_SIGS);
+
+       next_softclock = clocktime();
+
+       amd_state = Run;
+
+       /*
+        * Keep on trucking while we are in Run mode.  This state
+        * is switched to Quit after all the file systems have
+        * been unmounted.
+        */
+       while ((int)amd_state <= (int)Finishing) {
+               struct timeval tvv;
+               int nsel;
+               time_t now;
+#ifdef RPC_4
+               fd_set readfds;
+               readfds = svc_fdset;
+               FD_SET(fwd_sock, &readfds);
+#else
+#ifdef FD_SET
+               fd_set readfds;
+               FD_ZERO(&readfds);
+               readfds.fds_bits[0] = svc_fds;
+               FD_SET(fwd_sock, &readfds);
+#else
+               int readfds = svc_fds | (1 << fwd_sock);
+#endif /* FD_SET */
+#endif /* RPC_4 */
+
+#ifdef DEBUG
+               checkup();
+#endif /* DEBUG */
+
+               /*
+                * If the full timeout code is not called,
+                * then recompute the time delta manually.
+                */
+               now = clocktime();
+
+               if (next_softclock <= now) {
+                       if (amd_state == Finishing)
+                               umount_exported();
+                       tvv.tv_sec = softclock();
+               } else {
+                       tvv.tv_sec = next_softclock - now;
+               }
+               tvv.tv_usec = 0;
+
+               if (amd_state == Finishing && last_used_map < 0) {
+                       flush_mntfs();
+                       amd_state = Quit;
+                       break;
+               }
+
+#ifdef DEBUG
+               if (tvv.tv_sec)
+                       dlog("Select waits for %ds", tvv.tv_sec);
+               else
+                       dlog("Select waits for Godot");
+#endif /* DEBUG */
+
+               nsel = do_select(smask, dtbsz, &readfds, &tvv);
+
+
+               switch (nsel) {
+               case -1:
+                       if (errno == EINTR) {
+#ifdef DEBUG
+                               dlog("select interrupted");
+#endif /* DEBUG */
+                               continue;
+                       }
+                       perror("select");
+                       break;
+
+               case 0:
+#ifdef DEBUG
+                       /*dlog("select returned 0");*/
+#endif /* DEBUG */
+                       break;
+
+               default:
+#ifdef FD_SET
+                       if (FD_ISSET(fwd_sock, &readfds)) {
+                               FD_CLR(fwd_sock, &readfds);
+                               fwd_reply();
+                               --nsel;
+                       }
+#else
+                       if (readfds & (1 << fwd_sock)) {
+                               readfds &= ~(1 << fwd_sock);
+                               fwd_reply();
+                               --nsel;
+                       }
+#endif /* FD_SET */
+
+                       if (nsel) {
+                               /*
+                                * Anything left must be a normal
+                                * RPC request.
+                                */
+#ifdef RPC_4
+                               svc_getreqset(&readfds);
+#else
+#ifdef FD_SET
+                               svc_getreq(readfds.fds_bits[0]);
+#else
+                               svc_getreq(readfds);
+#endif /* FD_SET */
+#endif /* RPC_4 */
+                       }
+                       break;
+               }
+       }
+
+       (void) sigsetmask(smask);
+
+       if (amd_state == Quit)
+               amd_state = Done;
+
+       return amd_state;
+}
+
+static int bindnfs_port(so)
+int so;
+{
+       unsigned short port;
+       int error = bind_resv_port(so, &port);
+       if (error == 0)
+               nfs_port = port;
+       return error;
+}
+
+void unregister_amq(P_void)
+{
+#ifdef DEBUG
+       Debug(D_AMQ)
+#endif /* DEBUG */
+       (void) pmap_unset(AMQ_PROGRAM, AMQ_VERSION);
+}
+
+int mount_automounter(ppid)
+int ppid;
+{
+       int so = socket(AF_INET, SOCK_DGRAM, 0);
+       SVCXPRT *amqp;
+       int nmount;
+
+       unregister_amq();
+
+       if (so < 0 || bindnfs_port(so) < 0) {
+               perror("Can't create privileged nfs port");
+               return 1;
+       }
+
+       if ((nfsxprt = svcudp_create(so)) == NULL || 
+                       (amqp = svcudp_create(so)) == NULL) {
+               plog(XLOG_FATAL, "cannot create rpc/udp service");
+               return 2;
+       }
+
+       if (!svc_register(nfsxprt, NFS_PROGRAM, NFS_VERSION, nfs_program_2, 0)) {
+               plog(XLOG_FATAL, "unable to register (NFS_PROGRAM, NFS_VERSION, 0)");
+               return 3;
+       }
+
+#ifdef DEBUG
+       Debug(D_AMQ)
+#endif /* DEBUG */
+       if (!svc_register(amqp, AMQ_PROGRAM, AMQ_VERSION, amq_program_1, IPPROTO_UDP)) {
+               plog(XLOG_FATAL, "unable to register (AMQ_PROGRAM, AMQ_VERSION, udp)");
+               return 3;
+       }
+
+       /*
+        * Start RPC forwarding
+        */
+       if (fwd_init() != 0)
+               return 3;
+
+       /*
+        * One or other of so, fwd_sock
+        * must be the highest fd on
+        * which to select.
+        */
+       if (so > max_fds)
+               max_fds = so;
+       if (fwd_sock > max_fds)
+               max_fds = fwd_sock;
+
+       /*
+        * Construct the root automount node
+        */
+       make_root_node();
+
+       /*
+        * Pick up the pieces from a previous run
+        * This is likely to (indirectly) need the rpc_fwd package
+        * so it *must* come after the call to fwd_init().
+        */
+       if (restart_existing_mounts)
+               restart();
+
+       /*
+        * Mount the top-level auto-mountpoints
+        */
+       nmount = mount_exported();
+
+       /*
+        * Now safe to tell parent that we are up and running
+        */
+       if (ppid)
+               kill(ppid, SIGQUIT);
+
+       if (nmount == 0) {
+               plog(XLOG_FATAL, "No work to do - quitting");
+               amd_state = Done;
+               return 0;
+       }
+
+       /*
+        * Start timeout_mp rolling
+        */
+       reschedule_timeout_mp();
+
+       /*
+        * Start the server
+        */
+       if (run_rpc() != Done) {
+               plog(XLOG_FATAL, "run_rpc failed");
+               amd_state = Done;
+       }
+
+       return 0;
+}
diff --git a/usr/src/usr.sbin/amd/amd/nfs_subr.c b/usr/src/usr.sbin/amd/amd/nfs_subr.c
new file mode 100644 (file)
index 0000000..c167afd
--- /dev/null
@@ -0,0 +1,525 @@
+/*
+ * $Id: nfs_subr.c,v 5.2 90/06/23 22:19:50 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)nfs_subr.c  5.1 (Berkeley) %G%
+ */
+
+#include "am.h"
+
+/*
+ * Convert from UN*X to NFS error code
+ */
+#ifdef NFS_ERROR_MAPPING
+NFS_ERROR_MAPPING
+#define nfs_error(e) \
+        ((nfsstat)((e) > NFS_LOMAP && (e) < NFS_HIMAP ? \
+        nfs_errormap[(e) - NFS_LOMAP] : (e)))
+#else
+#define nfs_error(e) ((nfsstat)(e))
+#endif /* NFS_ERROR_MAPPING */
+
+static char *do_readlink(mp, error_return, attrpp)
+am_node *mp;
+int *error_return;
+struct attrstat **attrpp;
+{
+       char *ln;
+
+       /*
+        * If there is a readlink method, then use
+        * that, otherwise if a link exists use
+        * that, otherwise use the mount point.
+        */
+       if (mp->am_mnt->mf_ops->readlink) {
+               int retry = 0;
+               mp = (*mp->am_mnt->mf_ops->readlink)(mp, &retry);
+               if (mp == 0) {
+                       *error_return = retry;
+                       return 0;
+               }
+               /*reschedule_timeout_mp();*/
+       }
+       if (mp->am_link) {
+               ln = mp->am_link;
+       } else {
+               ln = mp->am_mnt->mf_mount;
+       }
+       if (attrpp)
+               *attrpp = &mp->am_mnt->mf_attr;
+       return ln;
+}
+
+/*ARGSUSED*/
+voidp 
+nfsproc_null_2(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+       static char res;
+
+       return (voidp) &res;
+}
+
+
+/*ARGSUSED*/
+struct attrstat *
+nfsproc_getattr_2(argp, rqstp)
+struct nfs_fh *argp;
+struct svc_req *rqstp;
+{
+       static struct attrstat res;
+       am_node *mp;
+       int retry;
+
+#ifdef DEBUG
+       Debug(D_TRACE)
+               plog(XLOG_DEBUG, "gettattr:");
+#endif /* DEBUG */
+
+       mp = fh_to_mp2(argp, &retry);
+       if (mp == 0) {
+#ifdef PRECISE_SYMLINKS
+getattr_retry:
+#endif /* PRECISE_SYMLINKS */
+
+               if (retry < 0)
+                       return 0;
+               res.status = nfs_error(retry);
+       } else {
+               struct attrstat *attrp = &mp->am_mnt->mf_attr;
+#ifdef PRECISE_SYMLINKS
+               if (mp->am_mnt->mf_fattr.type == NFLNK) {
+                       /*
+                        * Make sure we can read the link,
+                        * and then determine the length.
+                        */
+                       char *ln = do_readlink(mp, &retry, &attrp);
+                       if (ln == 0)
+                               goto getattr_retry;
+               }
+#endif /* PRECISE_SYMLINKS */
+#ifdef DEBUG
+               Debug(D_TRACE)
+                       plog(XLOG_DEBUG, "\tstat(%s), size = %d", mp->am_path, attrp->attrstat_u.attributes.size);
+#endif /* DEBUG */
+               mp->am_stats.s_getattr++;
+               return attrp;
+       }
+
+       return &res;
+}
+
+
+/*ARGSUSED*/
+struct attrstat *
+nfsproc_setattr_2(argp, rqstp)
+struct sattrargs *argp;
+struct svc_req *rqstp;
+{
+       static struct attrstat res;
+
+       if (!fh_to_mp(&argp->file))
+               res.status = nfs_error(ESTALE);
+       else
+               res.status = nfs_error(EROFS);
+
+       return &res;
+}
+
+
+/*ARGSUSED*/
+voidp 
+nfsproc_root_2(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+       static char res;
+
+       return (voidp)&res;
+}
+
+
+/*ARGSUSED*/
+struct diropres *
+nfsproc_lookup_2(argp, rqstp)
+struct diropargs *argp;
+struct svc_req *rqstp;
+{
+       static struct diropres res;
+       am_node *mp;
+       int retry;
+
+#ifdef DEBUG
+       Debug(D_TRACE)
+               plog(XLOG_DEBUG, "lookup:");
+#endif /* DEBUG */
+
+       mp = fh_to_mp2(&argp->dir, &retry);
+       if (mp == 0) {
+               if (retry < 0)
+                       return 0;
+               res.status = nfs_error(retry);
+       } else {
+               int error;
+               am_node *ap;
+#ifdef DEBUG
+               Debug(D_TRACE)
+                       plog(XLOG_DEBUG, "\tlookuppn(%s, %s)", mp->am_path, argp->name);
+#endif /* DEBUG */
+               ap = (*mp->am_mnt->mf_ops->lookuppn)(mp, argp->name, &error, VLOOK_CREATE);
+               if (ap == 0) {
+                       if (error < 0) {
+#ifdef DEBUG
+                               dlog("Not sending RPC reply");
+#endif /* DEBUG */
+                               amd_stats.d_drops++;
+                               return 0;
+                       }
+                       res.status = nfs_error(error);
+               } else {
+#ifdef DEBUG
+                       if (ap->am_mnt->mf_fattr.size < 0)
+                               dlog("\tERROR: size = %d!", ap->am_mnt->mf_fattr.size);
+#endif /* DEBUG */
+                       mp_to_fh(ap, &res.diropres_u.diropres.file);
+                       res.diropres_u.diropres.attributes = ap->am_mnt->mf_fattr;
+                       res.status = NFS_OK;
+               }
+               mp->am_stats.s_lookup++;
+               /*reschedule_timeout_mp();*/
+       }
+
+       return &res;
+}
+
+
+/*ARGSUSED*/
+struct readlinkres *
+nfsproc_readlink_2(argp, rqstp)
+struct nfs_fh *argp;
+struct svc_req *rqstp;
+{
+       static struct readlinkres res;
+       am_node *mp;
+       int retry;
+
+#ifdef DEBUG
+       Debug(D_TRACE)
+               plog(XLOG_DEBUG, "readlink:");
+#endif /* DEBUG */
+
+       mp = fh_to_mp2(argp, &retry);
+       if (mp == 0) {
+readlink_retry:
+               if (retry < 0)
+                       return 0;
+               res.status = nfs_error(retry);
+       } else {
+               char *ln = do_readlink(mp, &retry, (struct attrstat *) 0);
+               if (ln == 0)
+                       goto readlink_retry;
+               res.status = NFS_OK;
+#ifdef DEBUG
+               Debug(D_TRACE)
+                       if (ln)
+                               plog(XLOG_DEBUG, "\treadlink(%s) = %s", mp->am_path, ln);
+#endif /* DEBUG */
+               res.readlinkres_u.data = ln;
+               mp->am_stats.s_readlink++;
+       }
+
+       return &res;
+}
+
+
+/*ARGSUSED*/
+struct readres *
+nfsproc_read_2(argp, rqstp)
+struct readargs *argp;
+struct svc_req *rqstp;
+{
+       static struct readres res;
+
+       bzero((char *)&res, sizeof(res));
+
+       res.status = nfs_error(EACCES);
+
+       return &res;
+}
+
+
+/*ARGSUSED*/
+voidp 
+nfsproc_writecache_2(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+       static char res;
+
+       return (voidp) &res;
+}
+
+
+/*ARGSUSED*/
+struct attrstat *
+nfsproc_write_2(argp, rqstp)
+writeargs *argp;
+struct svc_req *rqstp;
+{
+       static struct attrstat res;
+
+       if (!fh_to_mp(&argp->file))
+               res.status = nfs_error(ESTALE);
+       else
+               res.status = nfs_error(EROFS);
+
+       return &res;
+}
+
+
+/*ARGSUSED*/
+struct diropres *
+nfsproc_create_2(argp, rqstp)
+createargs *argp;
+struct svc_req *rqstp;
+{
+       static struct diropres res;
+
+       if (!fh_to_mp(&argp->where.dir))
+               res.status = nfs_error(ESTALE);
+       else
+               res.status = nfs_error(EROFS);
+
+       return &res;
+}
+
+
+/*ARGSUSED*/
+static nfsstat *
+unlink_or_rmdir(argp, rqstp, unlinkp)
+struct diropargs *argp;
+struct svc_req *rqstp;
+{
+       static nfsstat res;
+       int retry;
+       mntfs *mf;
+       am_node *mp = fh_to_mp3(&argp->dir, &retry, VLOOK_DELETE);
+       if (mp == 0) {
+               if (retry < 0)
+                       return 0;
+               res = nfs_error(retry);
+               goto out;
+       }
+       mf = mp->am_mnt;
+       if (mf->mf_fattr.type != NFDIR) {
+               res = nfs_error(ENOTDIR);
+               goto out;
+       }
+#ifdef DEBUG
+       Debug(D_TRACE)
+               plog(XLOG_DEBUG, "\tremove(%s, %s)", mp->am_path, argp->name);
+#endif /* DEBUG */
+       mp = (*mp->am_mnt->mf_ops->lookuppn)(mp, argp->name, &retry, VLOOK_DELETE);
+       if (mp == 0) {
+               /*
+                * Ignore retries...
+                */
+               if (retry < 0)
+                       retry = 0;
+               /*
+                * Usual NFS workaround...
+                */
+               else if (retry == ENOENT)
+                       retry = 0;
+               res = nfs_error(retry);
+       } else {
+               forcibly_timeout_mp(mp);
+               res = NFS_OK;
+       }
+
+out:
+       return &res;
+}
+
+
+/*ARGSUSED*/
+nfsstat *
+nfsproc_remove_2(argp, rqstp)
+struct diropargs *argp;
+struct svc_req *rqstp;
+{
+       return unlink_or_rmdir(argp, rqstp, 1);
+}
+
+/*ARGSUSED*/
+nfsstat *
+nfsproc_rename_2(argp, rqstp)
+renameargs *argp;
+struct svc_req *rqstp;
+{
+       static nfsstat res;
+       if (!fh_to_mp(&argp->from.dir) || !fh_to_mp(&argp->to.dir))
+               res = nfs_error(ESTALE);
+       /*
+        * If the kernel is doing clever things with referenced files
+        * then let it pretend...
+        */
+       else if (strncmp(argp->to.name, ".nfs", 4) == 0)
+               res = NFS_OK;
+       /*
+        * otherwise a failure
+        */
+       else
+               res = nfs_error(EROFS);
+       return &res;
+}
+
+
+/*ARGSUSED*/
+nfsstat *
+nfsproc_link_2(argp, rqstp)
+linkargs *argp;
+struct svc_req *rqstp;
+{
+       static nfsstat res;
+       if (!fh_to_mp(&argp->from) || !fh_to_mp(&argp->to.dir))
+               res = nfs_error(ESTALE);
+       else
+               res = nfs_error(EROFS);
+
+       return &res;
+}
+
+
+/*ARGSUSED*/
+nfsstat *
+nfsproc_symlink_2(argp, rqstp)
+symlinkargs *argp;
+struct svc_req *rqstp;
+{
+       static nfsstat res;
+       if (!fh_to_mp(&argp->from.dir))
+               res = nfs_error(ESTALE);
+       else
+               res = nfs_error(EROFS);
+
+       return &res;
+}
+
+
+/*ARGSUSED*/
+struct diropres *
+nfsproc_mkdir_2(argp, rqstp)
+createargs *argp;
+struct svc_req *rqstp;
+{
+       static struct diropres res;
+       if (!fh_to_mp(&argp->where.dir))
+               res.status = nfs_error(ESTALE);
+       else
+               res.status = nfs_error(EROFS);
+
+       return &res;
+}
+
+
+/*ARGSUSED*/
+nfsstat *
+nfsproc_rmdir_2(argp, rqstp)
+struct diropargs *argp;
+struct svc_req *rqstp;
+{
+       return unlink_or_rmdir(argp, rqstp, 0);
+}
+
+
+/*ARGSUSED*/
+struct readdirres *
+nfsproc_readdir_2(argp, rqstp)
+readdirargs *argp;
+struct svc_req *rqstp;
+{
+       static readdirres res;
+       static entry e_res[2];
+       am_node *mp;
+       int retry;
+
+#ifdef DEBUG
+       Debug(D_TRACE)
+               plog(XLOG_DEBUG, "readdir:");
+#endif /* DEBUG */
+
+       mp = fh_to_mp2(&argp->dir, &retry);
+       if (mp == 0) {
+               if (retry < 0)
+                       return 0;
+               res.status = nfs_error(retry);
+       } else {
+#ifdef DEBUG
+               Debug(D_TRACE)
+                       plog(XLOG_DEBUG, "\treaddir(%s)", mp->am_path);
+#endif /* DEBUG */
+               res.status = nfs_error((*mp->am_mnt->mf_ops->readdir)(mp, argp->cookie,
+                                       &res.readdirres_u.reply, e_res));
+               mp->am_stats.s_readdir++;
+       }
+
+       /* XXX - need to take argp->count into account */
+
+       return &res;
+}
+
+/*ARGSUSED*/
+struct statfsres *
+nfsproc_statfs_2(argp, rqstp)
+struct nfs_fh *argp;
+struct svc_req *rqstp;
+{
+       static statfsres res;
+       am_node *mp;
+       int retry;
+
+#ifdef DEBUG
+       Debug(D_TRACE)
+               plog(XLOG_DEBUG, "statfs:");
+#endif /* DEBUG */
+
+       mp = fh_to_mp2(argp, &retry);
+       if (mp == 0) {
+               if (retry < 0)
+                       return 0;
+               res.status = nfs_error(retry);
+       } else {
+               statfsokres *fp;
+#ifdef DEBUG
+               Debug(D_TRACE)
+                       plog(XLOG_DEBUG, "\tstat_fs(%s)", mp->am_path);
+#endif /* DEBUG */
+               /*
+                * just return faked up file system information
+                */
+
+               fp = &res.statfsres_u.reply;
+
+               fp->tsize = 1024;
+               fp->bsize = 4192;
+               fp->blocks = 1;
+               fp->bfree = 0;
+               fp->bavail = 0;
+
+               res.status = NFS_OK;
+               mp->am_stats.s_statfs++;
+       }
+
+       return &res;
+}
diff --git a/usr/src/usr.sbin/amd/amd/opts.c b/usr/src/usr.sbin/amd/amd/opts.c
new file mode 100644 (file)
index 0000000..17bfd49
--- /dev/null
@@ -0,0 +1,749 @@
+/*
+ * $Id: opts.c,v 5.2 90/06/23 22:19:51 jsp Rel $
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)opts.c      5.1 (Berkeley) %G%
+ */
+
+#include "am.h"
+
+extern char *getenv P((char *));
+
+/*
+ * static copy of the options with
+ * which to play
+ */
+static struct am_opts fs_static;
+
+static char *opt_host = hostname;
+static char *opt_hostd = hostd;
+static char nullstr[] = "";
+static char *opt_key = nullstr;
+static char *opt_map = nullstr;
+static char *opt_path = nullstr;
+
+static char *vars[8];
+
+/*
+ * Length of longest option name
+ */
+#define        NLEN    16
+#define S(x) (x) , (sizeof(x)-1)
+static struct opt {
+       char *name;             /* Name of the option */
+       int nlen;               /* Length of option name */
+       char **optp;            /* Pointer to option value string */
+       char **sel_p;           /* Pointer to selector value string */
+} opt_fields[] = {
+       /* Options in something corresponding to frequency of use */
+       { S("opts"), &fs_static.opt_opts, 0 },
+       { S("host"), 0, &opt_host },
+       { S("hostd"), 0, &opt_hostd },
+       { S("type"), &fs_static.opt_type, 0 },
+       { S("rhost"), &fs_static.opt_rhost, 0 },
+       { S("rfs"), &fs_static.opt_rfs, 0 },
+       { S("fs"), &fs_static.opt_fs, 0 },
+       { S("key"), 0, &opt_key },
+       { S("map"), 0, &opt_map },
+       { S("sublink"), &fs_static.opt_sublink, 0 },
+       { S("arch"), 0, &arch },
+       { S("dev"), &fs_static.opt_dev, 0 },
+       { S("pref"), &fs_static.opt_pref, 0 },
+       { S("path"), 0, &opt_path },
+       { S("autodir"), 0, &auto_dir },
+       { S("delay"), &fs_static.opt_delay, 0 },
+       { S("domain"), 0, &hostdomain },
+       { S("karch"), 0, &karch },
+       { S("cluster"), 0, &cluster },
+       { S("byte"), 0, &endian },
+       { S("os"), 0, &op_sys },
+       { S("mount"), &fs_static.opt_mount, 0 },
+       { S("unmount"), &fs_static.opt_unmount, 0 },
+       { S("cache"), &fs_static.opt_cache, 0 },
+       { S("user"), &fs_static.opt_user, 0 },
+       { S("group"), &fs_static.opt_group, 0 },
+       { S("var0"), &vars[0], 0 },
+       { S("var1"), &vars[1], 0 },
+       { S("var2"), &vars[2], 0 },
+       { S("var3"), &vars[3], 0 },
+       { S("var4"), &vars[4], 0 },
+       { S("var5"), &vars[5], 0 },
+       { S("var6"), &vars[6], 0 },
+       { S("var7"), &vars[7], 0 },
+       { 0, 0, 0, 0 },
+};
+
+typedef struct opt_apply opt_apply;
+struct opt_apply {
+       char **opt;
+       char *val;
+};
+
+/*
+ * Specially expand the remote host name first
+ */
+static opt_apply rhost_expansion[] = {
+       { &fs_static.opt_rhost, "${host}" },
+       { 0, 0 },
+};
+/*
+ * List of options which need to be expanded
+ * Note that this the order here _may_ be important.
+ */
+static opt_apply expansions[] = {
+/*     { &fs_static.opt_dir, 0 },      */
+       { &fs_static.opt_sublink, 0 },
+       { &fs_static.opt_rfs, "${path}" },
+       { &fs_static.opt_fs, "${autodir}/${rhost}${rfs}" },
+       { &fs_static.opt_opts, "rw" },
+       { &fs_static.opt_mount, 0 },
+       { &fs_static.opt_unmount, 0 },
+       { 0, 0 },
+};
+
+/*
+ * List of options which need to be free'ed before re-use
+ */
+static opt_apply to_free[] = {
+       { &fs_static.fs_glob, 0 },
+       { &fs_static.fs_local, 0 },
+       { &fs_static.fs_mtab, 0 },
+/*     { &fs_static.opt_dir, 0 },      */
+       { &fs_static.opt_sublink, 0 },
+       { &fs_static.opt_rfs, 0 },
+       { &fs_static.opt_fs, 0 },
+       { &fs_static.opt_rhost, 0 },
+       { &fs_static.opt_opts, 0 },
+       { &fs_static.opt_mount, 0 },
+       { &fs_static.opt_unmount, 0 },
+       { &vars[0], 0 },
+       { &vars[1], 0 },
+       { &vars[2], 0 },
+       { &vars[3], 0 },
+       { &vars[4], 0 },
+       { &vars[5], 0 },
+       { &vars[6], 0 },
+       { &vars[7], 0 },
+       { 0, 0 },
+};
+
+/*
+ * Skip to next option in the string
+ */
+static char *opt P((char**));
+static char *opt(p)
+char **p;
+{
+       char *cp = *p;
+       char *dp = cp;
+       char *s = cp;
+
+top:
+       while (*cp && *cp != ';') {
+               if (*cp == '\"') {
+                       /*
+                        * Skip past string
+                        */
+                       cp++;
+                       while (*cp && *cp != '\"')
+                               *dp++ = *cp++;
+                       if (*cp)
+                               cp++;
+               } else {
+                       *dp++ = *cp++;
+               }
+       }
+
+       /*
+        * Skip past any remaining ';'s
+        */
+       while (*cp == ';')
+               cp++;
+
+       /*
+        * If we have a zero length string
+        * and there are more fields, then
+        * parse the next one.  This allows
+        * sequences of empty fields.
+        */
+       if (*cp && dp == s)
+               goto top;
+
+       *dp = '\0';
+
+       *p = cp;
+       return s;
+}
+
+static int eval_opts P((char*));
+static int eval_opts(opts)
+char *opts;
+{
+       /*
+        * Fill in the global structure fs_static by
+        * cracking the string opts.  opts may be
+        * scribbled on at will.
+        */
+       char *o = opts;
+       char *f;
+
+       /*
+        * For each user-specified option
+        */
+       while (*(f = opt(&o))) {
+               struct opt *op;
+               enum vs_opt { OldSyn, SelEQ, SelNE, VarAss } vs_opt;
+               char *eq = strchr(f, '=');
+               char *opt;
+               if (!eq || eq[1] == '\0' || eq == f) {
+                       /*
+                        * No value, just continue
+                        */
+                       plog(XLOG_USER, "No value component in \"%s\"", f);
+                       continue;
+               }
+
+               /*
+                * Check what type of operation is happening
+                * !=, =!  is SelNE
+                * == is SelEQ
+                * := is VarAss
+                * = is OldSyn (either SelEQ or VarAss)
+                */
+               if (eq[-1] == '!') {            /* != */
+                       vs_opt = SelNE;
+                       eq[-1] = '\0';
+                       opt = eq + 1;
+               } else if (eq[-1] == ':') {     /* := */
+                       vs_opt = VarAss;
+                       eq[-1] = '\0';
+                       opt = eq + 1;
+               } else if (eq[1] == '=') {      /* == */
+                       vs_opt = SelEQ;
+                       eq[0] = '\0';
+                       opt = eq + 2;
+               } else if (eq[1] == '!') {      /* =! */
+                       vs_opt = SelNE;
+                       eq[0] = '\0';
+                       opt = eq + 2;
+               } else {                        /* = */
+                       vs_opt = OldSyn;
+                       eq[0] = '\0';
+                       opt = eq + 1;
+               }
+
+               /*
+                * For each recognised option
+                */
+               for (op = opt_fields; op->name; op++) {
+                       /*
+                        * Check whether they match
+                        */
+                       if (FSTREQ(op->name, f)) {
+                               switch (vs_opt) {
+#if AMD_COMPAT <= 5000108
+                               case OldSyn:
+                                       if (!op->sel_p) {
+                                               *op->optp = opt;
+                                               break;
+                                       }
+                                       /* fall through ... */
+#endif /* 5000108 */
+                               case SelEQ:
+                               case SelNE:
+                                       if (op->sel_p && (STREQ(*op->sel_p, opt) == (vs_opt == SelNE))) {
+                                               plog(XLOG_MAP, "map selector %s (=%s) did not %smatch %s",
+                                                       op->name,
+                                                       *op->sel_p,
+                                                       vs_opt == SelNE ? "not " : "",
+                                                       opt);
+                                               return 0;
+                                       }
+                                       break;
+
+                               case VarAss:
+                                       if (op->sel_p) {
+                                               plog(XLOG_USER, "Can't assign to a selector (%s)", op->name);
+                                               return 0;
+                                       }
+                                       *op->optp = opt;
+                                       break;
+                               }
+                               break;
+                       }
+               }
+
+               if (!op->name)
+                       plog(XLOG_USER, "Unrecognised key \"%s\"", f);
+       }
+
+       return 1;
+}
+
+/*
+ * Free an option
+ */
+static void free_op P((opt_apply*, int));
+/*ARGSUSED*/
+static void free_op(p, b)
+opt_apply *p;
+int b;
+{
+       if (*p->opt) {
+               free(*p->opt);
+               *p->opt = 0;
+       }
+}
+
+/*
+ * 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
+ * don't expand selectors.
+ */
+static void expand_op P((opt_apply*, int));
+static void expand_op(p, sel_p)
+opt_apply *p;
+int sel_p;
+{
+/*
+ * The BUFSPACE macros checks that there is enough space
+ * left in the expansion buffer.  If there isn't then we
+ * give up completely.  This is done to avoid crashing the
+ * automounter itself (which would be a bad thing to do).
+ */
+#define BUFSPACE(ep, len) (((ep) + (len)) < expbuf+MAXPATHLEN)
+static char expand_error[] = "No space to expand \"%s\"";
+
+       char expbuf[MAXPATHLEN+1];
+       char nbuf[NLEN+1];
+       char *ep = expbuf;
+       char *cp = *p->opt;
+       char *dp;
+#ifdef DEBUG
+       char *cp_orig = *p->opt;
+#endif /* DEBUG */
+       struct opt *op;
+
+       while (dp = strchr(cp, '$')) {
+               char ch;
+               /*
+                * First copy up to the $
+                */
+               { int len = dp - cp;
+                 if (BUFSPACE(ep, len)) {
+                       strncpy(ep, cp, len);
+                       ep += len;
+                 } else {
+                       plog(XLOG_ERROR, expand_error, *p->opt);
+                       goto out;
+                 }
+               }
+               cp = dp + 1;
+               ch = *cp++;
+               if (ch == '$') {
+                       if (BUFSPACE(ep, 1)) {
+                               *ep++ = '$';
+                       } else {
+                               plog(XLOG_ERROR, expand_error, *p->opt);
+                               goto out;
+                       }
+               } else if (ch == '{') {
+                       /* Expansion... */
+                       enum { E_All, E_Dir, E_File } todo;
+                       /*
+                        * Find closing brace
+                        */
+                       char *br_p = strchr(cp, '}');
+                       int len;
+                       /*
+                        * Check we found it
+                        */
+                       if (!br_p) {
+                               /*
+                                * Just give up
+                                */
+                               plog(XLOG_USER, "No closing '}' in \"%s\"", *p->opt);
+                               goto out;
+                       }
+                       len = br_p - cp;
+                       /*
+                        * Figure out which part of the variable to grab.
+                        */
+                       if (*cp == '/') {
+                               /*
+                                * Just take the last component
+                                */
+                               todo = E_File;
+                               cp++;
+                               --len;
+                       } else if (br_p[-1] == '/') {
+                               /*
+                                * Take all but the last component
+                                */
+                               todo = E_Dir;
+                               --len;
+                       } else {
+                               /*
+                                * Take the whole lot
+                                */
+                               todo = E_All;
+                       }
+                       /*
+                        * Truncate if too long.  Since it won't
+                        * match anyway it doesn't matter that
+                        * it has been cut short.
+                        */
+                       if (len > NLEN)
+                               len = NLEN;
+                       /*
+                        * Put the string into another buffer so
+                        * we can do comparisons.
+                        */
+                       strncpy(nbuf, cp, len);
+                       nbuf[len] = '\0';
+                       /*
+                        * Advance cp
+                        */
+                       cp = br_p + 1;
+                       /*
+                        * Search the option array
+                        */
+                       for (op = opt_fields; op->name; op++) {
+                               /*
+                                * Check for match
+                                */
+                               if (len == op->nlen && STREQ(op->name, nbuf)) {
+                                       char xbuf[NLEN+3];
+                                       char *val;
+                                       /*
+                                        * Found expansion.  Copy
+                                        * the correct value field.
+                                        */
+                                       if (!(!op->sel_p == !sel_p)) {
+                                               /*
+                                                * Copy the string across unexpanded
+                                                */
+                                               sprintf(xbuf, "${%s%s%s}",
+                                                       todo == E_File ? "/" : "",
+                                                       nbuf,
+                                                       todo == E_Dir ? "/" : "");
+                                               val = xbuf;
+                                               /*
+                                                * Make sure expansion doesn't
+                                                * munge the value!
+                                                */
+                                               todo = E_All;
+                                       } else if (op->sel_p) {
+                                               val = *op->sel_p;
+                                       } else {
+                                               val = *op->optp;
+                                       }
+                                       if (val) {
+                                               /*
+                                                * Do expansion:
+                                                * ${/var} means take just the last part
+                                                * ${var/} means take all but the last part
+                                                * ${var} means take the whole lot
+                                                */
+                                               int vlen = strlen(val);
+                                               char *vptr = val;
+                                               switch (todo) {
+                                               case E_Dir:
+                                                       vptr = strrchr(val, '/');
+                                                       if (vptr)
+                                                               vlen = vptr - val;
+                                                       vptr = val;
+                                                       break;
+                                               case E_File:
+                                                       vptr = strrchr(val, '/');
+                                                       if (vptr) {
+                                                               vptr++;
+                                                               vlen = strlen(vptr);
+                                                       } else
+                                                               vptr = val;
+                                                       break;
+                                               }
+#ifdef DEBUG
+                                       /*dlog("Expanding \"%s\" to \"%s\"", nbuf, val);*/
+#endif /* DEBUG */
+                                               if (BUFSPACE(ep, vlen)) {
+                                                       strcpy(ep, vptr);
+                                                       ep += vlen;
+                                               } else {
+                                                       plog(XLOG_ERROR, expand_error, *p->opt);
+                                                       goto out;
+                                               }
+                                       }
+                                       /*
+                                        * Done with this variable
+                                        */
+                                       break;
+                               }
+                       }
+                       /*
+                        * Check that the search was succesful
+                        */
+                       if (!op->name) {
+                               /*
+                                * If it wasn't then scan the
+                                * environment for that name
+                                * and use any value found
+                                */
+                               char *env = getenv(nbuf);
+                               if (env) {
+                                       int vlen = strlen(env);
+
+                                       if (BUFSPACE(ep, vlen)) {
+                                               strcpy(ep, env);
+                                               ep += vlen;
+                                       } else {
+                                               plog(XLOG_ERROR, expand_error, *p->opt);
+                                               goto out;
+                                       }
+#ifdef DEBUG
+                                       Debug(D_STR)
+                                       plog(XLOG_DEBUG, "Environment gave \"%s\" -> \"%s\"", nbuf, env);
+#endif /* DEBUG */
+                               } else {
+                                       plog(XLOG_USER, "Unknown sequence \"${%s}\"", nbuf);
+                               }
+                       }
+               } else {
+                       /*
+                        * Error, error
+                        */
+                       plog(XLOG_USER, "Unknown $ sequence in \"%s\"", *p->opt);
+               }
+       }
+
+out:
+       /*
+        * Handle common case - no expansion
+        */
+       if (cp == *p->opt) {
+               *p->opt = strdup(cp);
+       } else {
+               /*
+                * Finish off the expansion
+                */
+               if (BUFSPACE(ep, strlen(cp))) {
+                       strcpy(ep, cp);
+                       /*ep += strlen(ep);*/
+               } else {
+                       plog(XLOG_ERROR, expand_error, *p->opt);
+               }
+
+               /*
+                * Save the exansion
+                */
+               *p->opt = strdup(expbuf);
+       }
+
+       /*
+        * Normalize slashes in the string.
+        */
+       { char *f = strchr(*p->opt, '/');
+         if (f) {
+               char *t = f;
+               do {
+                       /* assert(*f == '/'); */
+                       /* copy a single / across */
+                       *t++ = *f++;
+
+                       /* assert(f[-1] == '/'); */
+                       /* skip past more /'s */
+                       while (*f == '/')
+                               f++;
+
+                       /* assert(*f != '/'); */
+                       /* keep copying up to next / */
+                       do {
+                               *t++ = *f++;
+                       } while (*f && *f != '/');
+
+                       /* assert(*f == 0 || *f == '/'); */
+
+               } while (*f);
+         }
+       }
+
+#ifdef DEBUG
+       Debug(D_STR) {
+               plog(XLOG_DEBUG, "Expansion of \"%s\"...", cp_orig);
+               plog(XLOG_DEBUG, "... is \"%s\"", *p->opt);
+       }
+#endif /* DEBUG */
+}
+
+/*
+ * Wrapper for expand_op
+ */
+static void expand_opts P((opt_apply*, int));
+static void expand_opts(p, sel_p)
+opt_apply *p;
+int sel_p;
+{
+       if (*p->opt) {
+               expand_op(p, 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);
+               free(s);
+       }
+}
+
+/*
+ * Apply a function to a list of options
+ */
+static void apply_opts(op, ppp, b)
+void (*op)();
+opt_apply ppp[];
+int b;
+{
+       opt_apply *pp;
+       for (pp = ppp; pp->opt; pp++)
+               (*op)(pp, b);
+}
+
+/*
+ * Free the option table
+ */
+void free_opts(fo)
+am_opts *fo;
+{
+       /*
+        * Copy in the structure we are playing with
+        */
+       fs_static = *fo;
+
+       /*
+        * Free previously allocated memory
+        */
+       apply_opts(free_op, to_free, FALSE);
+}
+
+/*
+ * Expand lookup key
+ */
+char *expand_key(key)
+char *key;
+{
+       opt_apply oa;
+
+       oa.opt = &key; oa.val = 0;
+       expand_opts(&oa, TRUE);
+
+       return key;
+}
+
+/*
+ * Remove trailing / from a string
+ */
+static void deslashify(s)
+char *s;
+{
+       if (s) {
+               char *sl = strrchr(s, '/');
+               if (sl && sl[1] == '\0')
+                       *sl = '\0';
+       }
+}
+
+int eval_fs_opts(fo, opts, g_opts, path, key, map)
+am_opts *fo;
+char *opts, *g_opts, *path, *key, *map;
+{
+       int ok = TRUE;
+
+       free_opts(fo);
+
+       /*
+        * Clear out the option table
+        */
+       bzero((voidp) &fs_static, sizeof(fs_static));
+       bzero((voidp) vars, sizeof(vars));
+       bzero((voidp) fo, sizeof(*fo));
+
+       /*
+        * Set key, map & path before expansion
+        */
+       opt_key = key;
+       opt_map = map;
+       opt_path = path;
+
+       /*
+        * Expand global options
+        */
+       fs_static.fs_glob = expand_key(g_opts);
+
+       /*
+        * Expand local options
+        */
+       fs_static.fs_local = expand_key(opts);
+
+       /*
+        * Expand default (global) options
+        */
+       if (!eval_opts(fs_static.fs_glob))
+               ok = FALSE;
+
+       /*
+        * Expand local options
+        */
+       if (ok && !eval_opts(fs_static.fs_local))
+               ok = FALSE;
+
+       /*
+        * Normalise remote host name.
+        * 1.  Expand variables
+        * 2.  Normalize relative to host tables
+        * 3.  Strip local domains from the remote host
+        *     name before using it in other expansions.
+        *     This makes mount point names and other things
+        *     much shorter, while allowing cross domain
+        *     sharing of mount maps.
+        */
+       apply_opts(expand_opts, rhost_expansion, FALSE);
+       if (ok && fs_static.opt_rhost && *fs_static.opt_rhost)
+               host_normalize(&fs_static.opt_rhost);
+
+       /*
+        * Macro expand the options.
+        * Do this regardless of whether we are accepting
+        * this mount - otherwise nasty things happen
+        * with memory allocation.
+        */
+       apply_opts(expand_opts, expansions, FALSE);
+
+       /*
+        * Strip trailing slashes from local pathname...
+        */
+       deslashify(fs_static.opt_fs);
+
+       /*
+        * ok... copy the data back out.
+        */
+       *fo = fs_static;
+
+       /*
+        * Clear defined options
+        */
+       opt_key = opt_map = opt_path = nullstr;
+
+       return ok;
+}
diff --git a/usr/src/usr.sbin/amd/amd/pfs_ops.c b/usr/src/usr.sbin/amd/amd/pfs_ops.c
new file mode 100644 (file)
index 0000000..47ad49c
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * $Id: pfs_ops.c,v 5.2 90/06/23 22:19:53 jsp Rel $
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)pfs_ops.c   5.1 (Berkeley) %G%
+ */
+
+#include "am.h"
+
+#ifdef HAS_PFS
+
+/*
+ * Program file system
+ */
+
+/*
+ * Execute needs a mount and unmount command.
+ */
+static int pfs_match(fo)
+am_opts *fo;
+{
+       char *prog;
+       if (!fo->opt_mount || !fo->opt_unmount) {
+               plog(XLOG_USER, "program: no mount/unmount specified");
+               return FALSE;
+       }
+       prog = strchr(fo->opt_mount, ' ');
+       if (fo->fs_mtab = strealloc(fo->fs_mtab, prog ? prog+1 : fo->opt_mount))
+               return TRUE;
+       return FALSE;
+}
+
+static int pfs_init(mf)
+mntfs *mf;
+{
+       /*
+        * Save unmount command
+        */
+       if (mf->mf_refc == 1) {
+               mf->mf_private = (voidp) strdup(mf->mf_fo->opt_unmount);
+               mf->mf_prfree = (void (*) ()) free;
+       }
+       return 0;
+}
+
+static int pfs_exec(info)
+char *info;
+{
+       char **xivec;
+       int error;
+       /*
+        * Split copy of command info string
+        */
+       info = strdup(info);
+       if (info == 0)
+               return ENOBUFS;
+       xivec = strsplit(info, '\'');
+       /*
+        * Put stdout to stderr
+        */
+       (void) fclose(stdout);
+       (void) dup(fileno(logfp));
+       if (fileno(logfp) != fileno(stderr)) {
+               (void) fclose(stderr);
+               (void) dup(fileno(logfp));
+       }
+       /*
+        * Try the exec
+        */
+#ifdef DEBUG
+       Debug(D_FULL) {
+               char **cp = xivec;
+               plog(XLOG_DEBUG, "executing (un)mount command...");
+               while (*cp) {
+                       plog(XLOG_DEBUG, "arg[%d] = '%s'", cp-xivec, *cp);
+                       cp++;
+               }
+       }
+#endif /* DEBUG */
+       if (xivec[0] == 0 || xivec[1] == 0) {
+               errno = EINVAL;
+               plog(XLOG_USER, "1st/2nd args missing to (un)mount program");
+       } else {
+               (void) execv(xivec[0], xivec+1);
+       }
+       /*
+        * Save error number
+        */
+       error = errno;
+       plog(XLOG_ERROR, "exec failed: %m");
+
+       /*
+        * Free allocate memory
+        */
+       free(info);
+       free(xivec);
+       /*
+        * Return error
+        */
+       return error;
+}
+
+static int pfs_mount(mp)
+am_node *mp;
+{
+       mntfs *mf = mp->am_mnt;
+
+       return pfs_exec(mf->mf_fo->opt_mount);
+}
+
+static int pfs_umount(mp)
+am_node *mp;
+{
+       mntfs *mf = mp->am_mnt;
+
+       return pfs_exec((char *) mf->mf_private);
+}
+
+/*
+ * Ops structure
+ */
+am_ops pfs_ops = {
+       "program",
+       pfs_match,
+       pfs_init,
+       pfs_mount,
+       pfs_umount,
+       efs_lookuppn,
+       efs_readdir,
+       0, /* pfs_readlink */
+       0, /* pfs_mounted */
+       0, /* pfs_umounted */
+       find_afs_srvr,
+       FS_BACKGROUND|FS_AMQINFO
+};
+
+#endif /* HAS_PFS */
diff --git a/usr/src/usr.sbin/amd/amd/restart.c b/usr/src/usr.sbin/amd/amd/restart.c
new file mode 100644 (file)
index 0000000..8773356
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * $Id: restart.c,v 5.2 90/06/23 22:19:55 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)restart.c   5.1 (Berkeley) %G%
+ */
+
+#include "am.h"
+
+/*
+ * 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.
+ *
+ * This module relies on internal details of other components.  If
+ * you change something else make *sure* restart() still works.
+ */
+void restart()
+{
+       /*
+        * 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.
+        */
+       for (mlp = ml = read_mtab("restart"); mlp; mlp = mlp->mnext) {
+               struct mntent *me = mlp->mnt;
+               am_ops *fs_ops = 0;
+               if (STREQ(me->mnt_type, MTAB_TYPE_UFS)) {
+                       /*
+                        * UFS entry
+                        */
+                       fs_ops = &ufs_ops;
+               } else if (STREQ(me->mnt_type, MTAB_TYPE_NFS)) {
+                       /*
+                        * NFS entry, or possibly an Amd entry...
+                        */
+                       int au_pid;
+                       char *colon = strchr(me->mnt_fsname, ':');
+                       if (colon && sscanf(colon, ":(pid%d)", &au_pid) == 1) {
+                               plog(XLOG_WARNING, "%s is an existing automount point", me->mnt_dir);
+                               fs_ops = &sfs_ops;
+                       } else {
+                               fs_ops = &nfs_ops;
+                       }
+#ifdef MTAB_TYPE_MFS
+               } else if (STREQ(me->mnt_type, MTAB_TYPE_MFS)) {
+                       /*
+                        * MFS entry.  Fake with a symlink.
+                        */
+                       fs_ops = &sfs_ops;
+#endif /* MTAB_TYPE_MFS */
+               } else {
+                       /*
+                        * Catch everything else with symlinks to
+                        * avoid recursive mounts.  This is debatable...
+                        */
+                       fs_ops = &sfs_ops;
+               }
+
+               /*
+                * If we found something to do
+                */
+               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, ":", "/");
+                       }
+                       mo.opt_fs = me->mnt_dir;
+
+                       /*
+                        * 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 */
+                               /*
+                                * If the restarted type is a link then
+                                * don't time out.
+                                */
+                               if (fs_ops == &sfs_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);
+                               }
+
+                               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);
+                       }
+                       /*
+                        * Clean up mo
+                        */
+                       if (mo.opt_rhost)
+                               free(mo.opt_rhost);
+                       if (mo.opt_rfs)
+                               free(mo.opt_rfs);
+               }
+       }
+
+       /*
+        * Free the mount list
+        */
+       free_mntlist(ml);
+}
diff --git a/usr/src/usr.sbin/amd/amd/rpc_fwd.c b/usr/src/usr.sbin/amd/amd/rpc_fwd.c
new file mode 100644 (file)
index 0000000..d096acf
--- /dev/null
@@ -0,0 +1,401 @@
+/*
+ * $Id: rpc_fwd.c,v 5.2 90/06/23 22:19:57 jsp Rel $
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)rpc_fwd.c   5.1 (Berkeley) %G%
+ */
+
+/*
+ * RPC packet forwarding
+ */
+
+#include "am.h"
+#include <sys/ioctl.h>
+#ifndef F_SETFL
+#include <fcntl.h>
+#endif /* F_SETFL */
+#ifndef FNDELAY
+#include <sys/file.h>
+#endif /* FNDELAY */
+
+/*
+ * Note that the ID field in the external packet is only
+ * ever treated as a 32 bit opaque data object, so there
+ * is no need to convert to and from network byte ordering.
+ */
+
+/*
+ * Each pending reply has an rpc_forward structure
+ * associated with it.  These have a 15 second lifespan.
+ * If a new structure is required, then an expired
+ * one will be re-allocated if available, otherwise a fresh
+ * one is allocated.  Whenever a reply is received the
+ * structure is discarded.
+ */
+typedef struct rpc_forward rpc_forward;
+struct rpc_forward {
+       qelem   rf_q;           /* Linked list */
+       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 */
+       voidp   rf_ptr;
+       struct sockaddr_in rf_sin;
+};
+
+/*
+ * Head of list of pending replies
+ */
+extern qelem rpc_head;
+qelem rpc_head = { &rpc_head, &rpc_head };
+
+static u_int xid;
+#define        XID_ALLOC()     (xid++)
+
+#define        MAX_PACKET_SIZE 8192    /* Maximum UDP packet size */
+
+int fwd_sock;
+
+/*
+ * Allocate a rely structure
+ */
+static rpc_forward *fwd_alloc()
+{
+       time_t now = clocktime();
+       rpc_forward *p = 0, *p2;
+
+#ifdef DEBUG
+       /*dlog("fwd_alloca: rpc_head = %#x", rpc_head.q_forw);*/
+#endif /* DEBUG */
+       /*
+        * First search for an existing expired one.
+        */
+       ITER(p2, rpc_forward, &rpc_head) {
+               if (p2->rf_ttl <= now) {
+                       p = p2;
+                       break;
+               }
+       }
+
+       /*
+        * If one couldn't be found then allocate
+        * a new structure and link it at the
+        * head of the list.
+        */
+       if (p) {
+               /*
+                * 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);
+       } else {
+               p = ALLOC(rpc_forward);
+       }
+       ins_que(&p->rf_q, &rpc_head);
+
+       /*
+        * Set the time to live field
+        * Timeout in 43 seconds 
+        */
+       p->rf_ttl = now + 43;
+
+#ifdef DEBUG
+       /*dlog("fwd_alloca: rpc_head = %#x", rpc_head.q_forw);*/
+#endif /* DEBUG */
+       return p;
+}
+
+/*
+ * Free an allocated reply structure.
+ * First unlink it from the list, then
+ * discard it.
+ */
+static void fwd_free(p)
+rpc_forward *p;
+{
+#ifdef DEBUG
+       /*dlog("fwd_free: rpc_head = %#x", rpc_head.q_forw);*/
+#endif /* DEBUG */
+       rem_que(&p->rf_q);
+#ifdef DEBUG
+       /*dlog("fwd_free: rpc_head = %#x", rpc_head.q_forw);*/
+#endif /* DEBUG */
+       free(p);
+}
+
+/*
+ * Initialise the RPC forwarder
+ */
+int fwd_init()
+{
+       int on = 1;
+
+       /*
+        * Create ping socket
+        */
+       fwd_sock = socket(AF_INET, SOCK_DGRAM, 0);
+       if (fwd_sock < 0) {
+               plog(XLOG_ERROR, "Unable to create RPC forwarding socket: %m");
+               return errno;
+       }
+
+       /*
+        * Some things we talk to require a priv port - so make one here
+        */
+       if (bind_resv_port(fwd_sock, (unsigned short *) 0) < 0)
+               plog(XLOG_ERROR, "can't bind privileged port");
+
+       if (fcntl(fwd_sock, F_SETFL, FNDELAY) < 0 &&
+                       ioctl(fwd_sock, FIONBIO, &on) < 0) {
+               plog(XLOG_ERROR, "Can't set non-block on forwarding socket: %m");
+               return errno;
+       }
+
+       return 0;
+}
+
+/*
+ * Locate a packet in the forwarding list
+ */
+static rpc_forward *fwd_locate(id)
+u_int id;
+{
+       rpc_forward *p;
+
+       ITER(p, rpc_forward, &rpc_head) {
+               if (p->rf_xid == id)
+                       return p;
+       }
+
+       return 0;
+}
+
+/*
+ * This is called to forward a packet to another
+ * RPC server.  The message id is changed and noted
+ * so that when a reply appears we can tie it up
+ * correctly.  Just matching the reply's source address
+ * would not work because it might come from a
+ * different address.
+ */
+int fwd_packet(type_id, pkt, len, fwdto, replyto, i, cb)
+int type_id;
+voidp pkt;
+int len;
+struct sockaddr_in *fwdto, *replyto;
+voidp i;
+fwd_fun cb;
+{
+       rpc_forward *p;
+       u_int *pkt_int;
+       int error;
+
+       if ((int)amd_state >= (int)Finishing)
+               return ENOENT;
+
+       /*
+        * See if the type_id is fully specified.
+        * If so, then discard any old entries
+        * for this id.
+        * 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"); break;
+       case RPC_XID_MOUNTD: dlog("Sending MOUNTD request %#x", type_id); break;
+       case RPC_XID_NFSPING: dlog("Sending NFS ping"); break;
+       default: dlog("UNKNOWN RPC XID"); break;
+       }
+#endif /* DEBUG */
+
+       if (type_id & ~RPC_XID_MASK) {
+#ifdef DEBUG
+               /*dlog("Fully qualified rpc type provided");*/
+#endif /* DEBUG */
+               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());
+       }
+
+       p = fwd_alloc();
+       if (!p)
+               return ENOBUFS;
+
+       error = 0;
+
+       pkt_int = (u_int *) pkt;
+
+       /*
+        * Get the original packet id
+        */
+       p->rf_oldid = *pkt_int;
+
+       /*
+        * Replace with newly allocated id
+        */
+       p->rf_xid = *pkt_int = type_id;
+
+       /*
+        * The sendto may fail if, for example, the route
+        * to a remote host is lost because an intermediate
+        * gateway has gone down.  Important to fill in the
+        * rest of "p" otherwise nasty things happen later...
+        */
+#ifdef DEBUG
+       dlog("Sending packet id %#x to %#08x.%04x", p->rf_xid, ntohl(fwdto->sin_addr.s_addr), ntohs(fwdto->sin_port));
+#endif /* DEBUG */
+       if (sendto(fwd_sock, (char *) pkt, len, 0,
+                       (struct sockaddr *) fwdto, sizeof(*fwdto)) < 0)
+               error = errno;
+
+       /*
+        * Save callback function and return address
+        */
+       p->rf_fwd = cb;
+       if (replyto)
+               p->rf_sin = *replyto;
+       else
+               bzero((voidp) &p->rf_sin, sizeof(p->rf_sin));
+       p->rf_ptr = i;
+
+       return error;
+}
+
+/*
+ * Called when some data arrives on the forwarding socket
+ */
+void fwd_reply()
+{
+       int len;
+#ifdef DYNAMIC_BUFFERS
+       voidp pkt;
+#else
+       u_int pkt[MAX_PACKET_SIZE/sizeof(u_int)+1];
+#endif /* DYNAMIC_BUFFERS */
+       u_int *pkt_int;
+       int rc;
+       rpc_forward *p;
+       struct sockaddr_in src_addr;
+       int src_addr_len;
+
+       /*
+        * Determine the length of the packet
+        */
+#ifdef DYNAMIC_BUFFERS
+       if (ioctl(fwd_sock, FIONREAD, &len) < 0) {
+               plog(XLOG_ERROR, "Error reading packet size: %m");
+               return;
+       }
+
+       /*
+        * Allocate a buffer
+        */
+       pkt = (voidp) malloc((unsigned) len);
+       if (!pkt) {
+               plog(XLOG_ERROR, "Out of buffers in fwd_reply");
+               return;
+       }
+#else
+       len = MAX_PACKET_SIZE;
+#endif /* DYNAMIC_BUFFERS */
+
+       /*
+        * Read the packet and check for validity
+        */
+again:
+       src_addr_len = sizeof(src_addr);
+       rc = recvfrom(fwd_sock, (char *) pkt, len, 0,
+                       (struct sockaddr *) &src_addr, &src_addr_len);
+       if (rc < 0 || src_addr_len != sizeof(src_addr) ||
+                       src_addr.sin_family != AF_INET) {
+               if (rc < 0 && errno == EINTR)
+                       goto again;
+               plog(XLOG_ERROR, "Error reading RPC reply: %m");
+               goto out;
+       }
+
+#ifdef DYNAMIC_BUFFERS
+       if (rc != len) {
+               plog(XLOG_ERROR, "Short read in fwd_reply");
+               goto out;
+       }
+#endif /* DYNAMIC_BUFFERS */
+
+       /*
+        * Do no more work if finishing soon
+        */
+       if ((int)amd_state >= (int)Finishing)
+               goto out;
+
+       /*
+        * Find packet reference
+        */
+       pkt_int = (u_int *) pkt;
+
+#ifdef DEBUG
+       switch (*pkt_int & RPC_XID_MASK) {
+       case RPC_XID_PORTMAP: dlog("Receiving PORTMAP reply"); break;
+       case RPC_XID_MOUNTD: dlog("Receiving MOUNTD reply %#x", *pkt_int); break;
+       case RPC_XID_NFSPING: dlog("Receiving NFS ping %#x", *pkt_int); break;
+       default: dlog("UNKNOWN RPC XID"); break;
+       }
+#endif /* DEBUG */
+
+       p = fwd_locate(*pkt_int);
+       if (!p) {
+#ifdef DEBUG
+               dlog("Can't forward reply id %#x", *pkt_int);
+#endif /* DEBUG */
+               goto out;
+       }
+
+       if (p->rf_fwd) {
+               /*
+                * Put the original message id back
+                * into the packet.
+                */
+               *pkt_int = p->rf_oldid;
+
+               /*
+                * Call forwarding function
+                */
+               (*p->rf_fwd)(pkt, rc, &src_addr, &p->rf_sin, p->rf_ptr, TRUE);
+       }
+
+       /*
+        * Free forwarding info
+        */
+       fwd_free(p);
+
+out:;
+#ifdef DYNAMIC_BUFFERS
+       /*
+        * Free the packet
+        */
+       free(pkt);
+#endif /* DYNAMIC_BUFFERS */
+}
diff --git a/usr/src/usr.sbin/amd/amd/sched.c b/usr/src/usr.sbin/amd/amd/sched.c
new file mode 100644 (file)
index 0000000..cdacbec
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * $Id: sched.c,v 5.2 90/06/23 22:19:58 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)sched.c     5.1 (Berkeley) %G%
+ */
+
+/*
+ * Process scheduler
+ */
+
+#include "am.h"
+#include <sys/signal.h>
+#include WAIT
+#include <setjmp.h>
+extern jmp_buf select_intr;
+extern int select_intr_valid;
+
+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 */
+       union wait w;                   /* Status filled in by sigchld */
+       voidp wchan;                    /* Wait channel */
+};
+
+extern qelem proc_list_head;
+qelem proc_list_head = { &proc_list_head, &proc_list_head };
+extern qelem proc_wait_list;
+qelem proc_wait_list = { &proc_wait_list, &proc_wait_list };
+
+int task_notify_todo;
+
+void ins_que(elem, pred)
+qelem *elem, *pred;
+{
+       qelem *p = pred->q_forw;
+       elem->q_back = pred;
+       elem->q_forw = p;
+       pred->q_forw = elem;
+       p->q_back = elem;
+}
+
+void rem_que(elem)
+qelem *elem;
+{
+       qelem *p = elem->q_forw;
+       qelem *p2 = elem->q_back;
+       p2->q_forw = p;
+       p->q_back = p2;
+}
+
+static pjob *sched_job(cf, ca)
+cb_fun cf;
+voidp ca;
+{
+       pjob *p = ALLOC(pjob);
+
+       p->cb_fun = cf;
+       p->cb_closure = ca;
+
+       /*
+        * Now place on wait queue
+        */
+       ins_que(&p->hdr, &proc_wait_list);
+
+       return p;
+}
+
+void run_task(tf, ta, cf, ca)
+task_fun tf;
+voidp ta;
+cb_fun cf;
+voidp ca;
+{
+       pjob *p = sched_job(cf, ca);
+       int mask;
+
+       p->wchan = (voidp) p;
+
+       mask = sigblock(sigmask(SIGCHLD));
+
+       if (p->pid = background()) {
+               sigsetmask(mask);
+               return;
+       }
+
+       exit((*tf)(ta));
+       /* firewall... */
+       abort();
+}
+
+/*
+ * Schedule a task to be run when woken up
+ */
+void sched_task(cf, ca, wchan)
+cb_fun cf;
+voidp ca;
+voidp wchan;
+{
+       /*
+        * Allocate a new task
+        */
+       pjob *p = sched_job(cf, ca);
+#ifdef DEBUG
+       /*dlog("sleep(%#x)", wchan);*/
+#endif /* DEBUG */
+       p->wchan = wchan;
+       p->pid = 0;
+       bzero((voidp) &p->w, sizeof(p->w));
+}
+
+static void wakeupjob(p)
+pjob *p;
+{
+       rem_que(&p->hdr);
+       ins_que(&p->hdr, &proc_list_head);
+       task_notify_todo++;
+}
+
+void wakeup(wchan)
+voidp wchan;
+{
+       pjob *p, *p2;
+
+       if (!foreground)
+               return;
+
+#ifdef DEBUG
+       /*dlog("wakeup(%#x)", wchan);*/
+#endif /* DEBUG */
+       /*
+        * Can't user ITER() here because
+        * wakeupjob() juggles the list.
+        */
+       for (p = FIRST(pjob, &proc_wait_list);
+                       p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list);
+                       p = p2) {
+               if (p->wchan == wchan)
+                       wakeupjob(p);
+       }
+}
+
+void wakeup_task(rc, term, cl)
+int rc;
+int term;
+voidp cl;
+{
+       wakeup(cl);
+}
+
+/*ARGSUSED*/
+
+void sigchld(sig)
+int sig;
+{
+       union wait w;
+       int pid;
+
+#ifdef SYS5_SIGNALS
+       if ((pid = wait(&w)) > 0) {
+#else
+       while ((pid = wait3(&w, WNOHANG, (union wait *) 0)) > 0) {
+#endif /* SYS5_SIGNALS */
+               pjob *p, *p2;
+
+               if (WIFSIGNALED(w))
+                       plog(XLOG_ERROR, "Process %d exited with signal %d",
+                               pid, w.w_termsig);
+#ifdef DEBUG
+               else
+                       dlog("Process %d exited with status %d",
+                               pid, w.w_retcode);
+#endif /* DEBUG */
+
+               for (p = FIRST(pjob, &proc_wait_list);
+                               p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list);
+                               p = p2) {
+                       if (p->pid == pid) {
+                               p->w = w;
+                               wakeupjob(p);
+                               break;
+                       }
+               }
+
+#ifdef DEBUG
+               if (p) ; else dlog("can't locate task block for pid %d", pid);
+#endif /* DEBUG */
+       }
+
+#ifdef SYS5_SIGNALS
+       signal(sig, sigchld);
+#endif /* SYS5_SIGNALS */
+       if (select_intr_valid)
+               longjmp(select_intr, sigchld);
+}
+
+/*
+ * Run any pending tasks.
+ * This must be called with SIGCHLD disabled
+ */
+void task_notify(P_void)
+{
+       /*
+        * Keep taking the first item off the list and processing it.
+        *
+        * Done this way because the the callback can, quite reasonably,
+        * queue a new task, so no local reference into the list can be
+        * held here.
+        */
+       while (FIRST(pjob, &proc_list_head) != HEAD(pjob, &proc_list_head)) {
+               pjob *p = FIRST(pjob, &proc_list_head);
+               rem_que(&p->hdr);
+               /*
+                * This job has completed
+                */
+               --task_notify_todo;
+
+               /*
+                * Do callback if it exists
+                */
+               if (p->cb_fun)
+                       (*p->cb_fun)(p->w.w_retcode,
+                               p->w.w_termsig, p->cb_closure);
+
+               free(p);
+       }
+}
diff --git a/usr/src/usr.sbin/amd/amd/sfs_ops.c b/usr/src/usr.sbin/amd/amd/sfs_ops.c
new file mode 100644 (file)
index 0000000..7c0f2cc
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * $Id: sfs_ops.c,v 5.2 90/06/23 22:19:59 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)sfs_ops.c   5.1 (Berkeley) %G%
+ */
+
+#include "am.h"
+
+#ifdef HAS_SFS
+
+/*
+ * Symbol-link file system
+ */
+
+/*
+ * SFS needs a link.
+ */
+static int sfs_match(fo)
+am_opts *fo;
+{
+       if (!fo->opt_fs) {
+               plog(XLOG_USER, "link: no fs specified");
+               return 0;
+       }
+
+       /*
+        * 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 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.
+        *
+        * If sublink is nil then set sublink to fs
+        * else set sublink to fs / sublink
+        *
+        * Finally set fs to ".".
+        */
+       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)
+                       free(fo->opt_sublink);
+               fo->opt_sublink = fullpath;
+               free(fo->opt_fs);
+               fo->opt_fs = strdup(".");
+       }
+
+       fo->fs_mtab = strealloc(fo->fs_mtab, fo->opt_fs);
+
+       return 1;
+}
+
+/*ARGUSED*/
+static int sfs_mount(mp)
+am_node *mp;
+{
+       /*
+        * Wow - this is hard to implement!
+        */
+
+       return 0;
+}
+
+/*ARGUSED*/
+static int sfs_umount(mp)
+am_node *mp;
+{
+       return 0;
+}
+
+/*
+ * Ops structure
+ */
+am_ops sfs_ops = {
+       "link",
+       sfs_match,
+       0, /* sfs_init */
+       sfs_mount,
+       sfs_umount,
+       efs_lookuppn,
+       efs_readdir,
+       0, /* sfs_readlink */
+       0, /* sfs_mounted */
+       0, /* sfs_umounted */
+       find_afs_srvr,
+#ifdef FLUSH_KERNEL_NAME_CACHE
+       FS_UBACKGROUND
+#else /* FLUSH_KERNEL_NAME_CACHE */
+       0
+#endif /* FLUSH_KERNEL_NAME_CACHE */
+};
+
+#endif /* HAS_SFS */
diff --git a/usr/src/usr.sbin/amd/amd/srvr_afs.c b/usr/src/usr.sbin/amd/amd/srvr_afs.c
new file mode 100644 (file)
index 0000000..832e697
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * $Id: srvr_afs.c,v 5.2 90/06/23 22:20:00 jsp Rel $
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)srvr_afs.c  5.1 (Berkeley) %G%
+ */
+
+/*
+ * Automount FS server ("localhost") modeling
+ */
+
+#include "am.h"
+
+extern qelem afs_srvr_list;
+qelem afs_srvr_list = { &afs_srvr_list, &afs_srvr_list };
+
+static fserver *localhost;
+
+/*
+ * Find an nfs server for the local host
+ */
+fserver *find_afs_srvr P((mntfs *));
+fserver *find_afs_srvr(mf)
+mntfs *mf;
+{
+       fserver *fs = localhost;
+
+       if (!fs) {
+               fs = ALLOC(fserver);
+               fs->fs_refc = 0;
+               fs->fs_host = strdup("localhost");
+               fs->fs_ip = 0;
+               fs->fs_cid = 0;
+               fs->fs_pinger = 0;
+               fs->fs_flags = FSF_VALID;
+               fs->fs_type = "local";
+               fs->fs_private = 0;
+               fs->fs_prfree = 0;
+
+               ins_que(&fs->fs_q, &afs_srvr_list);
+
+               srvrlog(fs, "starts up");
+
+               localhost = fs;
+       }
+
+       fs->fs_refc++;
+
+       return fs;
+}
+
+/*------------------------------------------------------------------*/
+               /* Generic routines follow */
+
+/*
+ * Wakeup anything waiting for this server
+ */
+void wakeup_srvr P((fserver *fs));
+void wakeup_srvr(fs)
+fserver *fs;
+{
+       fs->fs_flags &= ~FSF_WANT;
+       wakeup((voidp) fs);
+}
+
+/*
+ * Called when final ttl of server has expired
+ */
+static void timeout_srvr P((fserver *fs));
+static void timeout_srvr(fs)
+fserver *fs;
+{
+       /*
+        * If the reference count is still zero then
+        * 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);
+
+               /*
+                * Remove from queue.
+                */
+               rem_que(&fs->fs_q);
+               /*
+                * (Possibly) call the private free routine.
+                */
+               if (fs->fs_private && fs->fs_prfree)
+                       (*fs->fs_prfree)(fs->fs_private);
+
+               /*
+                * Free the net address
+                */
+               if (fs->fs_ip)
+                       free((voidp) fs->fs_ip);
+
+               /*
+                * Free the host name.
+                */
+               free((voidp) fs->fs_host);
+
+               /*
+                * Discard the fserver object.
+                */
+               free((voidp) fs);
+       }
+}
+
+/*
+ * Free a file server
+ */
+void free_srvr P((fserver *fs));
+void free_srvr(fs)
+fserver *fs;
+{
+       if (--fs->fs_refc == 0) {
+               /*
+                * The reference count is now zero,
+                * so arrange for this node to be
+                * removed in AM_TTL seconds if no
+                * other mntfs is referencing it.
+                */
+               int ttl = (fs->fs_flags & (FSF_DOWN|FSF_ERROR)) ? 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);
+                       /*
+                        * Turn off pinging - XXX
+                        */
+                       fs->fs_flags &= ~FSF_PINGING;
+               }
+               /*
+                * Keep structure lying around for a while
+                */
+               fs->fs_cid = timeout(ttl, timeout_srvr, (voidp) fs);
+               /*
+                * Mark the fileserver down and invalid again
+                */
+               fs->fs_flags &= ~FSF_VALID;
+               fs->fs_flags |= FSF_DOWN;
+       }
+}
+
+/*
+ * Make a duplicate fserver reference
+ */
+fserver *dup_srvr P((fserver *fs));
+fserver *dup_srvr(fs)
+fserver *fs;
+{
+       fs->fs_refc++;
+       return fs;
+}
+
+/*
+ * Log state change
+ */
+void srvrlog P((fserver *fs, char *state));
+void srvrlog(fs, state)
+fserver *fs;
+char *state;
+{
+       plog(XLOG_INFO, "file server %s type %s %s", fs->fs_host, fs->fs_type, state);
+}
diff --git a/usr/src/usr.sbin/amd/amd/srvr_nfs.c b/usr/src/usr.sbin/amd/amd/srvr_nfs.c
new file mode 100644 (file)
index 0000000..2bd9f46
--- /dev/null
@@ -0,0 +1,638 @@
+/*
+ * $Id: srvr_nfs.c,v 5.2 90/06/23 22:20:02 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)srvr_nfs.c  5.1 (Berkeley) %G%
+ */
+
+/*
+ * NFS server modeling
+ */
+
+#include "am.h"
+#include <netdb.h>
+#include <rpc/pmap_prot.h>
+#include "mount.h"
+
+extern qelem nfs_srvr_list;
+qelem nfs_srvr_list = { &nfs_srvr_list, &nfs_srvr_list };
+
+typedef struct nfs_private {
+       u_short np_mountd;      /* Mount daemon port number */
+       char np_mountd_inval;   /* Port may be invalid */
+       int np_ping;            /* Number of failed ping attempts */
+       time_t np_ttl;          /* Time when server is thought dead */
+       int np_xid;             /* RPC transaction id for pings */
+       int np_error;           /* Error during portmap request */
+} nfs_private;
+
+static int np_xid;     /* For NFS pings */
+#define        NPXID_ALLOC()   (++np_xid)
+/*#define      NPXID_ALLOC()   ((++np_xid&0x0fffffff) == 0 ? npxid_gc() : np_xid)*/
+
+/*
+ * Number of pings allowed to fail before host is declared down
+ * - three-fifths of the allowed mount time...
+#define        MAX_ALLOWED_PINGS       ((((ALLOWED_MOUNT_TIME + 5 * AM_PINGER - 1) * 3) / 5) / AM_PINGER)
+ */
+#define        MAX_ALLOWED_PINGS       (3 + /* for luck ... */ 1)
+
+/*
+ * How often to ping when starting a new server
+ */
+#define        FAST_NFS_PING           3
+
+#if (FAST_NFS_PING * MAX_ALLOWED_PINGS) >= ALLOWED_MOUNT_TIME
+ #error: sanity check failed
+/*
+ you cannot do things this way...
+ sufficient fast pings must be given the chance to fail
+ within the allowed mount time
+ */
+#endif /* (FAST_NFS_PING * MAX_ALLOWED_PINGS) >= ALLOWED_MOUNT_TIME */
+
+static int ping_len;
+static char ping_buf[sizeof(struct rpc_msg) + 32];
+
+/*
+ * Startup the NFS ping
+ */
+static void start_ping()
+{
+       XDR ping_xdr;
+       struct rpc_msg ping_msg;
+
+       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);
+
+       /*
+        * Create the NFS ping message
+        */
+       if (!xdr_callmsg(&ping_xdr, &ping_msg)) {
+               plog(XLOG_ERROR, "Couldn't create ping RPC message");
+               going_down(3);
+       }
+
+       /*
+        * Find out how long it is
+        */
+       ping_len = xdr_getpos(&ping_xdr);
+
+       /*
+        * Destroy the XDR endpoint - we don't need it anymore
+        */
+       xdr_destroy(&ping_xdr);
+}
+
+
+/*
+ * Called when a portmap reply arrives
+ */
+static void got_portmap(pkt, len, sa, ia, idv, done)
+voidp pkt;
+int len;
+struct sockaddr_in *sa, *ia;
+voidp idv;
+int done;
+{
+       fserver *fs2 = (fserver *) idv;
+       fserver *fs = 0;
+       ITER(fs, fserver, &nfs_srvr_list)
+               if (fs == fs2)
+                       break;
+
+       if (fs == fs2) {
+               u_long port = 0;        /* XXX - should be short but protocol is naff */
+               int error = done ? pickup_rpc_reply(pkt, len, (voidp) &port, xdr_u_long) : -1;
+               nfs_private *np = (nfs_private *) fs->fs_private;
+               if (!error && port) {
+#ifdef DEBUG
+                       dlog("got port (%d) for mountd on %s", port, fs->fs_host);
+#endif /* DEBUG */
+                       /*
+                        * Grab the port number.  Portmap sends back
+                        * an unsigned long in native ordering, so it
+                        * needs converting to a unsigned short in
+                        * network ordering.
+                        */
+                       np->np_mountd = htons((u_short) port);
+                       np->np_mountd_inval = FALSE;
+                       np->np_error = 0;
+               } else {
+#ifdef DEBUG
+                       dlog("Error fetching port for mountd on %s", fs->fs_host);
+#endif /* DEBUG */
+                       /*
+                        * Almost certainly no mountd running on remote host
+                        */
+                       np->np_error = error ? error : ETIMEDOUT;
+               }
+               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 */
+       }
+}
+
+/*
+ * Obtain portmap information
+ */
+static int call_portmap(fs, auth, prog, vers, prot)
+fserver *fs;
+AUTH *auth;
+unsigned long prog, vers, prot;
+{
+       struct rpc_msg pmap_msg;
+       int len;
+       char iobuf[UDPMSGSIZE];
+       int error;
+       struct pmap pmap;
+
+       rpc_msg_init(&pmap_msg, PMAPPROG, PMAPVERS, (unsigned long) 0);
+       pmap.pm_prog = prog;
+       pmap.pm_vers = vers;
+       pmap.pm_prot = prot;
+       pmap.pm_port = 0;
+       len = make_rpc_packet(iobuf, sizeof(iobuf), PMAPPROC_GETPORT,
+                       &pmap_msg, (voidp) &pmap, xdr_pmap, auth);
+       if (len > 0) {
+               struct sockaddr_in sin;
+               bzero((voidp) &sin, sizeof(sin));
+               sin = *fs->fs_ip;
+               sin.sin_port = htons(PMAPPORT);
+               error = fwd_packet(RPC_XID_PORTMAP, (voidp) iobuf, len,
+                               &sin, &sin, (voidp) fs, got_portmap);
+       } else {
+               error = -len;
+       }
+       return error;
+}
+
+static void nfs_keepalive P((fserver*));
+
+static void recompute_portmap P((fserver *fs));
+static void recompute_portmap(fs)
+fserver *fs;
+{                              
+       if (!nfs_auth)
+               nfs_auth = authunix_create_default();
+       if (!nfs_auth) {
+               nfs_private *np = (nfs_private *) fs->fs_private;
+               np->np_error = ENOBUFS;
+       } else {
+               call_portmap(fs, nfs_auth, MOUNTPROG,
+                       MOUNTVERS, (unsigned long) IPPROTO_UDP);
+       }
+}
+
+/*
+ * 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.
+ */
+/*ARGSUSED*/
+static void nfs_pinged(pkt, len, sp, tsp, idv, done)
+voidp pkt;
+int len;
+struct sockaddr_in *sp, *tsp;
+voidp idv;
+int done;
+{
+       int xid = (int) idv;
+       fserver *fs;
+       int found_map = 0;
+
+       if (!done)
+               return;
+
+       /*
+        * For each node...
+        */
+       ITER(fs, fserver, &nfs_srvr_list) {
+               nfs_private *np = (nfs_private *) fs->fs_private;
+               if (np->np_xid == xid) {
+                       /*
+                        * Reset the ping counter.
+                        * Update the keepalive timer.
+                        * Log what happened.
+                        */
+                       if (fs->fs_flags & FSF_DOWN) {
+                               fs->fs_flags &= ~FSF_DOWN;
+                               if (fs->fs_flags & FSF_VALID) {
+                                       srvrlog(fs, "is up");
+                               } else {
+                                       srvrlog(fs, "ok");
+                                       fs->fs_flags |= FSF_VALID;
+                               }
+
+#ifdef notdef
+                               /* why ??? */
+                               if (fs->fs_flags & FSF_WANT)
+                                       wakeup_srvr(fs);
+#endif /* notdef */
+                       } else {
+                               if (fs->fs_flags & FSF_VALID) {
+#ifdef DEBUG
+                                       dlog("file server %s type nfs is still up", fs->fs_host);
+#endif /* DEBUG */
+                               } else {
+                                       srvrlog(fs, "ok");
+                                       fs->fs_flags |= FSF_VALID;
+                               }
+                       }
+
+                       /*
+                        * Adjust ping interval
+                        */
+                       untimeout(fs->fs_cid);
+                       fs->fs_cid = timeout(fs->fs_pinger, nfs_keepalive, (voidp) fs);
+
+                       /*
+                        * Update ttl for this server
+                        */
+                       np->np_ttl = clocktime() +
+                               (MAX_ALLOWED_PINGS - 1) * FAST_NFS_PING + fs->fs_pinger - 1;
+
+                       /*
+                        * New RPC xid...
+                        */
+                       np->np_xid = NPXID_ALLOC();
+
+                       /*
+                        * Failed pings is zero...
+                        */
+                       np->np_ping = 0;
+
+                       /*
+                        * Recompute portmap information if not known
+                        */
+                       if (np->np_mountd_inval)
+                               recompute_portmap(fs);
+
+                       found_map++;
+                       break;
+               }
+       }
+
+#ifdef DEBUG
+       if (found_map == 0)
+               dlog("Spurious ping packet");
+#endif /* DEBUG */
+}
+
+/*
+ * Called when no ping-reply received
+ */
+static void nfs_timed_out P((fserver *fs));
+static void nfs_timed_out(fs)
+fserver *fs;
+{
+       nfs_private *np = (nfs_private *) fs->fs_private;
+
+       /*
+        * Not known to be up any longer
+        */
+       if (FSRV_ISUP(fs)) {
+               fs->fs_flags &= ~FSF_VALID;
+               srvrlog(fs, "not responding");
+       }
+
+       /*
+        * Another ping has failed
+        */
+       np->np_ping++;
+
+       /*
+        * If ttl has expired then guess that it is dead
+        */
+       if (np->np_ttl < clocktime()) {
+               if ((fs->fs_flags & FSF_DOWN) == 0) {
+                       /*
+                        * Server was up, but is now down.
+                        */
+                       srvrlog(fs, "is down");
+                       fs->fs_flags |= FSF_DOWN|FSF_VALID;
+                       if (fs->fs_flags & FSF_WANT)
+                               wakeup_srvr(fs);
+                       /*
+                        * Since the server is down, the portmap
+                        * information may now be wrong, so it
+                        * must be flushed from the local cache
+                        */
+                       flush_nfs_fhandle_cache(fs);
+                       np->np_error = -1;
+                       /*
+                        * Pretend just one ping has failed now
+                        */
+                       np->np_ping = 1;
+               } else {
+                       /*
+                        * Known to be down
+                        */
+                       fs->fs_flags |= FSF_VALID;
+               }
+       } 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 */
+       }
+
+       /*
+        * Run keepalive again
+        */
+       nfs_keepalive(fs);
+}
+
+/*
+ * Keep track of whether a server is alive
+ */
+static void nfs_keepalive P((fserver *fs));
+static void nfs_keepalive(fs)
+fserver *fs;
+{
+       int error;
+       nfs_private *np = (nfs_private *) fs->fs_private;
+       int fstimeo = -1;
+
+       /*
+        * Send an NFS ping to this node
+        */
+
+       if (ping_len == 0)
+               start_ping();
+
+       /*
+        * Queue the packet...
+        */
+       error = fwd_packet(MK_RPC_XID(RPC_XID_NFSPING, np->np_xid), (voidp) ping_buf,
+               ping_len, fs->fs_ip, (struct sockaddr_in *) 0, (voidp) np->np_xid, nfs_pinged);
+
+       /*
+        * See if a hard error occured
+        */
+       switch (error) {
+       case ENETDOWN:
+       case ENETUNREACH:
+       case EHOSTDOWN:
+       case EHOSTUNREACH:
+               np->np_ping = MAX_ALLOWED_PINGS;        /* immediately down */
+               np->np_ttl = (time_t) 0;
+               /*
+                * This causes an immediate call to nfs_timed_out
+                * whenever the server was thought to be up.
+                * See +++ below.
+                */
+               fstimeo = 0;
+               break;
+
+       case 0:
+#ifdef DEBUG
+               dlog("Sent NFS ping to %s", fs->fs_host);
+#endif /* DEBUG */
+               break;
+       }
+
+#ifdef DEBUG
+       /*dlog("keepalive, ping = %d", np->np_ping);*/
+#endif /* DEBUG */
+
+       /*
+        * Back off the ping interval if we are not getting replies and
+        * the remote system is know to be down.
+        */
+       switch (fs->fs_flags & (FSF_DOWN|FSF_VALID)) {
+       case FSF_VALID:                 /* Up */
+               if (fstimeo < 0)        /* +++ see above */
+                       fstimeo = FAST_NFS_PING;
+               break;
+
+       case FSF_VALID|FSF_DOWN:        /* Down */
+               fstimeo = fs->fs_pinger;
+               break;
+
+       default:                        /* Unknown */
+               fstimeo = FAST_NFS_PING;
+               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(fs, port, wchan)
+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;
+                               /*
+                                * Now go get it again in case it changed
+                                */
+                               np->np_mountd_inval = TRUE;
+                               error = 0;
+                       } else {
+                               if (np->np_error < 0)
+                                       recompute_portmap(fs);
+                               error = np->np_error;
+                       }
+               } else {
+                       error = EWOULDBLOCK;
+               }
+       }
+       if (error < 0 && wchan && !(fs->fs_flags & FSF_WANT)) {
+               /*
+                * If a wait channel is supplied, and no
+                * error has yet occured, 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;
+}
+
+static void start_nfs_pings P((fserver *fs, int pingval));
+static void start_nfs_pings(fs, pingval)
+fserver *fs;
+int pingval;
+{
+       if (!(fs->fs_flags & FSF_PINGING)) {
+               fs->fs_flags |= FSF_PINGING;
+               if (fs->fs_cid)
+                       untimeout(fs->fs_cid);
+               if (pingval < 0) {
+                       srvrlog(fs, "wired up");
+                       fs->fs_flags |= FSF_VALID;
+                       fs->fs_flags &= ~FSF_DOWN;
+               } else {
+                       nfs_keepalive(fs);
+               }
+       } else {
+#ifdef DEBUG
+               dlog("Already running pings to %s", fs->fs_host);
+#endif /* DEBUG */
+       }
+}
+
+/*
+ * Find an nfs server for a host.
+ */
+fserver *find_nfs_srvr P((mntfs *mf));
+fserver *find_nfs_srvr(mf)
+mntfs *mf;
+{
+       fserver *fs;
+       struct hostent *hp = 0;
+       char *host = mf->mf_fo->opt_rhost;
+       struct sockaddr_in *ip;
+       nfs_private *np;
+       int pingval;
+
+       /*
+        * Get ping interval from mount options.
+        * Current only used to decide whether pings
+        * are required or not.  < 0 = no pings.
+        */
+       { struct mntent mnt;
+         mnt.mnt_opts = mf->mf_fo->opt_opts;
+         pingval = hasmntval(&mnt, "ping");
+#ifdef HAS_TCP_NFS
+         /*
+          * Over TCP mount, don't bother to do pings.
+          * This is experimental - maybe you want to
+          * do pings anyway...
+          */
+         if (pingval == 0 && hasmntopt(&mnt, "tcp"))
+               pingval = -1;
+#endif /* HAS_TCP_NFS */
+       }
+
+
+top:
+       /*
+        * Scan the list of known servers looking
+        * for one with the same name
+        */
+       ITER(fs, fserver, &nfs_srvr_list) {
+               if (STREQ(host, fs->fs_host)) {
+                       start_nfs_pings(fs, pingval);
+                       fs->fs_refc++;
+                       return fs;
+               }
+       }
+
+       /*
+        * If the name is not known, it may be
+        * because it was an alternate name for
+        * the same machine.  So do a lookup and
+        * try again with the primary name if that
+        * is different.
+        * All that assuming it wasn't normalized
+        * earlier of course...
+        */
+       if (hp == 0) {
+               hp = gethostbyname(host);
+               if (hp && !STREQ(host, hp->h_name) && !normalize_hosts) {
+                       host = hp->h_name;
+                       goto top;
+               }
+       }
+
+       /*
+        * Get here if we can't find an entry
+        */
+       if (hp) {
+               switch (hp->h_addrtype) {
+               case AF_INET:
+                       ip = ALLOC(sockaddr_in);
+                       bzero((voidp) ip, sizeof(*ip));
+                       ip->sin_family = AF_INET;
+                       ip->sin_addr = *(struct in_addr *) hp->h_addr;
+                       ip->sin_port = htons(NFS_PORT);
+                       break;
+
+               default:
+                       ip = 0;
+                       break;
+               }
+       } else {
+               ip = 0;
+       }
+
+       /*
+        * Allocate a new server
+        */
+       fs = ALLOC(fserver);
+       fs->fs_refc = 1;
+       fs->fs_host = strdup(hp ? hp->h_name : "unknown_hostname");
+       host_normalize(&fs->fs_host);
+       fs->fs_ip = ip;
+       fs->fs_cid = 0;
+       if (ip) {
+               fs->fs_flags = FSF_DOWN;        /* Starts off down */
+       } else {
+               fs->fs_flags = FSF_ERROR|FSF_VALID;
+               mf->mf_flags |= MFF_ERROR;
+               mf->mf_error = ENOENT;
+       }
+       fs->fs_type = "nfs";
+       fs->fs_pinger = AM_PINGER;
+       np = ALLOC(nfs_private);
+       bzero((voidp) np, sizeof(*np));
+       np->np_mountd_inval = TRUE;
+       np->np_xid = NPXID_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;
+       fs->fs_private = (voidp) np;
+       fs->fs_prfree = (void (*)()) free;
+
+       if (!(fs->fs_flags & FSF_ERROR)) {
+               /*
+                * Start of keepalive timer
+                */
+               start_nfs_pings(fs, pingval);
+       }
+
+       /*
+        * Add to list of servers
+        */
+       ins_que(&fs->fs_q, &nfs_srvr_list);
+
+       return fs;
+}
diff --git a/usr/src/usr.sbin/amd/amd/ufs_ops.c b/usr/src/usr.sbin/amd/amd/ufs_ops.c
new file mode 100644 (file)
index 0000000..fdfdf6a
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * $Id: ufs_ops.c,v 5.2 90/06/23 22:20:03 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)ufs_ops.c   5.1 (Berkeley) %G%
+ */
+
+#include "am.h"
+
+#ifdef HAS_UFS
+
+#include <sys/stat.h>
+#ifdef NFS_3
+typedef nfs_fh fhandle_t;
+#endif /* NFS_3 */
+#include <sys/mount.h>
+
+#ifdef UFS_HDR
+#include UFS_HDR
+#endif /* UFS_HDR */
+
+/*
+ * UN*X file system
+ */
+
+/*
+ * UFS needs local filesystem and device.
+ */
+static int ufs_match(fo)
+am_opts *fo;
+{
+       if (!fo->opt_dev) {
+               plog(XLOG_USER, "ufs: no device specified");
+               return 0;
+       }
+       /*
+        * Determine magic cookie to put in mtab
+        */
+       fo->fs_mtab = strealloc(fo->fs_mtab, fo->opt_dev);
+#ifdef DEBUG
+       dlog("UFS: mounting device \"%s\" on \"%s\"",
+               fo->opt_dev, fo->opt_fs);
+#endif /* DEBUG */
+
+       return 1;
+}
+
+static mount_ufs(dir, fs_name, opts)
+char *dir;
+char *fs_name;
+char *opts;
+{
+       struct ufs_args ufs_args;
+       struct mntent mnt;
+       int flags;
+
+       /*
+        * Figure out the name of the file system type.
+        */
+#ifdef M_NEWTYPE
+       char *type = MOUNT_TYPE_UFS;
+#else
+       int type = MOUNT_TYPE_UFS;
+#endif /* M_NEWTYPE */
+
+       bzero((voidp) &ufs_args, sizeof(ufs_args));     /* Paranoid */
+
+       /*
+        * Fill in the mount structure
+        */
+       mnt.mnt_dir = dir;
+       mnt.mnt_fsname = fs_name;
+       mnt.mnt_type = MTAB_TYPE_UFS;
+       mnt.mnt_opts = opts;
+       mnt.mnt_freq = 1;
+       mnt.mnt_passno = 2;
+
+       flags = compute_mount_flags(&mnt);
+
+#ifdef ULTRIX_HACK
+       ufs_args.ufs_flags = flags;
+       ufs_args.ufs_pgthresh = 64; /* 64K - XXX */
+       flags &= M_RDONLY;
+#else
+       ufs_args.fspec = fs_name;
+#endif /* ULTRIX_HACK */
+
+       /*
+        * Call generic mount routine
+        */
+       return mount_fs(&mnt, flags, (caddr_t) &ufs_args, 0, type);
+}
+
+/*ARGSUSED*/
+static int ufs_mount(mp)
+am_node *mp;
+{
+       mntfs *mf = mp->am_mnt;
+
+       int error;
+
+       error = mount_ufs(mf->mf_mount, mf->mf_info, mf->mf_fo->opt_opts);
+       if (error) {
+               errno = error;
+               plog(XLOG_ERROR, "mount_ufs: %m");
+               return error;
+       }
+
+       return 0;
+}
+
+static int ufs_umount(mp)
+am_node *mp;
+{
+       mntfs *mf = mp->am_mnt;
+
+       return UMOUNT_FS(mf->mf_mount);
+}
+
+/*
+ * Ops structure
+ */
+am_ops ufs_ops = {
+       "ufs",
+       ufs_match,
+       0, /* ufs_init */
+       ufs_mount,
+       ufs_umount,
+       efs_lookuppn,
+       efs_readdir,
+       0, /* ufs_readlink */
+       0, /* ufs_mounted */
+       0, /* ufs_umounted */
+       find_afs_srvr,
+#ifdef FLUSH_KERNEL_NAME_CACHE
+       FS_MKMNT|FS_NOTIMEOUT|FS_UBACKGROUND|FS_AMQINFO
+#else /* FLUSH_KERNEL_NAME_CACHE */
+       FS_MKMNT|FS_NOTIMEOUT|FS_UBACKGROUND|FS_AMQINFO
+#endif /* FLUSH_KERNEL_NAME_CACHE */
+};
+
+#endif /* HAS_UFS */
diff --git a/usr/src/usr.sbin/amd/amd/umount_fs.c b/usr/src/usr.sbin/amd/amd/umount_fs.c
new file mode 100644 (file)
index 0000000..2ba551b
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * $Id: umount_fs.c,v 5.2 90/06/23 22:20:04 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)umount_fs.c 5.1 (Berkeley) %G%
+ */
+
+#include "am.h"
+
+#ifdef NEED_UMOUNT_BSD
+
+#include <sys/mount.h>         /* For MNT_NOFORCE */
+
+int umount_fs(fs_name)
+char *fs_name;
+{
+       int error;
+
+eintr:
+       error = unmount(fs_name, MNT_NOFORCE);
+       if (error < 0)
+               error = errno;
+
+       switch (error) {
+       case EINVAL:
+       case ENOTBLK:
+               plog(XLOG_WARNING, "unmount: %s is not mounted", fs_name);
+               error = 0;      /* Not really an error */
+               break;
+
+       case ENOENT:
+               plog(XLOG_ERROR, "mount point %s: %m", fs_name);
+               break;
+
+       case EINTR:
+#ifdef DEBUG
+               /* not sure why this happens, but it does.  ask kirk one day... */
+               dlog("%s: unmount: %m", fs_name);
+#endif /* DEBUG */
+               goto eintr;
+
+#ifdef DEBUG
+       default:
+               dlog("%s: unmount: %m", fs_name);
+               break;
+#endif /* DEBUG */
+       }
+
+       return error;
+}
+
+#endif /* NEED_UMOUNT_BSD */
+
+#ifdef NEED_UMOUNT_FS
+
+int umount_fs(fs_name)
+char *fs_name;
+{
+       mntlist *mlist, *mp, *mp_save = 0;
+       int error = 0;
+
+       mp = mlist = read_mtab(fs_name);
+
+       /*
+        * Search the mount table looking for
+        * the correct (ie last) matching entry
+        */
+       while (mp) {
+               if (strcmp(mp->mnt->mnt_fsname, fs_name) == 0 ||
+                               strcmp(mp->mnt->mnt_dir, fs_name) == 0)
+                       mp_save = mp;
+               mp = mp->mnext;
+       }
+
+       if (mp_save) {
+#ifdef DEBUG
+               dlog("Trying unmount(%s)", mp_save->mnt->mnt_dir);
+#endif /* DEBUG */
+               if (UNMOUNT_TRAP(mp_save->mnt) < 0) {
+                       switch (error = errno) {
+                       case EINVAL:
+                       case ENOTBLK:
+                               plog(XLOG_WARNING, "unmount: %s is not mounted", mp_save->mnt->mnt_dir);
+                               error = 0;      /* Not really an error */
+                               break;
+
+                       case ENOENT:
+                               plog(XLOG_ERROR, "mount point %s: %m", mp_save->mnt->mnt_dir);
+                               break;
+
+                       default:
+#ifdef DEBUG
+                               dlog("%s: unmount: %m", mp_save->mnt->mnt_dir);
+#endif /* DEBUG */
+                               break;
+                       }
+               }
+
+#ifdef UPDATE_MTAB
+               if (!error) {
+                       mnt_free(mp_save->mnt);
+                       mp_save->mnt = 0;
+
+                       rewrite_mtab(mlist);
+               }
+#endif /* UPDATE_MTAB */
+       } else {
+               plog(XLOG_ERROR, "Couldn't find how to unmount %s", fs_name);
+               /*
+                * Assume it is already unmounted
+                */
+               error = 0;
+       }
+
+       free_mntlist(mlist);
+
+       return error;
+}
+
+#endif /* NEED_UMOUNT_FS */
diff --git a/usr/src/usr.sbin/amd/amd/util.c b/usr/src/usr.sbin/amd/amd/util.c
new file mode 100644 (file)
index 0000000..0b50bca
--- /dev/null
@@ -0,0 +1,794 @@
+/*
+ * $Id: util.c,v 5.2 90/06/23 22:20:06 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)util.c      5.1 (Berkeley) %G%
+ */
+
+/*
+ * Utils
+ */
+
+#include "am.h"
+#ifdef HAS_SYSLOG
+#include <syslog.h>
+#endif /* HAS_SYSLOG */
+#include <ctype.h>
+#include <sys/stat.h>
+
+#include <netdb.h>
+
+
+INLINE
+char *strnsave(str, len)
+const char *str;
+int len;
+{
+       char *sp = (char *) xmalloc(len+1);
+
+       bcopy(str, sp, len);
+       sp[len] = 0;
+
+       return sp;
+}
+
+char *strdup(s)
+const char *s;
+{
+       return strnsave(s, strlen(s));
+}
+
+/*
+ * Concatenate three strings and store in buffer pointed to
+ * by p, making p large enough to hold the strings
+ */
+char *str3cat(p, s1, s2, s3)
+char *p;
+char *s1;
+char *s2;
+char *s3;
+{
+       int l1 = strlen(s1);
+       int l2 = strlen(s2);
+       int l3 = strlen(s3);
+       p = (char *) xrealloc(p, l1 + l2 + l3 + 1);
+       bcopy(s1, p, l1);
+       bcopy(s2, p + l1, l2);
+       bcopy(s3, p + l1 + l2, l3 + 1);
+       return p;
+}
+
+char *strealloc(p, s)
+char *p;
+char *s;
+{
+       int len = strlen(s) + 1;
+
+       p = (char *) xrealloc((voidp) p, len);
+
+       strcpy(p, s);
+#ifdef DEBUG_MEM
+       malloc_verify();
+#endif /* DEBUG_MEM */
+       return p;
+}
+
+voidp xrealloc(ptr, len)
+voidp ptr;
+int len;
+{
+#if defined(DEBUG) && defined(DEBUG_MEM)
+       Debug(D_MEM) plog(XLOG_DEBUG, "Reallocated size %d; block %#x", len, ptr);
+#endif /* defined(DEBUG) && defined(DEBUG_MEM) */
+
+       if (ptr)
+               ptr = (voidp) realloc(ptr, (unsigned) len);
+       else
+               ptr = (voidp) xmalloc((unsigned) len);
+
+       if (!ptr) {
+               plog(XLOG_FATAL, "Out of memory in realloc");
+               going_down(1);
+               abort();
+       }
+       return ptr;
+}
+
+char **strsplit(s, qc)
+char *s;
+int qc;
+{
+       char **ivec;
+       int ic = 0;
+       int done = 0;
+
+       ivec = (char **) xmalloc((ic+1)*sizeof(char *));
+
+       while (!done) {
+               char *v;
+               /*
+                * skip white space
+                */
+               while (*s && isascii(*s) && isspace(*s))
+                       s++;
+
+               /*
+                * End of string?
+                */
+               if (!*s)
+                       break;
+
+               /*
+                * remember start of string
+                */
+               v = s;
+
+               /*
+                * skip to white space
+                */
+               while (*s && (!isascii(*s) || !isspace(*s))) {
+                       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(ivec, (ic+1)*sizeof(char *));
+#ifdef DEBUG
+               Debug(D_STR)
+                       plog(XLOG_DEBUG, "strsplit saved \"%s\"", v);
+#endif /* DEBUG */
+       }
+
+#ifdef DEBUG
+       Debug(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
+ * to the local host domain.
+ * Note that this has no effect if the domain
+ * names do not have the same number of
+ * components.  If that restriction proves
+ * to be a problem then the loop needs recoding
+ * to skip from right to left and do partial
+ * matches along the way -- ie more expensive.
+ */
+static void domain_strip P((char *otherdom, char *localdom));
+static void domain_strip(otherdom, localdom)
+char *otherdom, *localdom;
+{
+        char *p1 = otherdom-1;
+       char *p2 = localdom-1;
+
+        do {
+                if (p1 = strchr(p1+1, '.'))
+                if (p2 = strchr(p2+1, '.'))
+                if (strcmp(p1+1, p2+1) == 0) {
+                        *p1 = '\0';
+                        break;
+                }
+        } while (p1 && p2);
+}
+
+/*
+ * Normalize a host name
+ */
+void host_normalize P((char **chp));
+void host_normalize(chp)
+char **chp;
+{
+       /*
+        * Normalize hosts is used to resolve host name aliases
+        * and replace them with the standard-form name.
+        * Invoked with "-n" command line option.
+        */
+       if (normalize_hosts) {
+               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, hp->h_name);
+               }
+       }
+       domain_strip(*chp, hostd);
+}
+
+/*
+ * Keys are not allowed to contain " ' ! or ; to avoid
+ * problems with macro expansions.
+ */
+static char invalid_keys[] = "\"'!;@ \t\n";
+int valid_key P((char *key));
+int valid_key(key)
+char *key;
+{
+       while (*key)
+               if (strchr(invalid_keys, *key++))
+                       return FALSE;
+       return TRUE;
+}
+
+void going_down P((int rc));
+void going_down(rc)
+int rc;
+{
+       if (foreground) {
+               if (amd_state != Start) {
+                       if (amd_state != Done)
+                               return;
+                       unregister_amq();
+               }
+       }
+       if (foreground) {
+               plog(XLOG_INFO, "Finishing with status %d", rc);
+       } else {
+#ifdef DEBUG
+               dlog("background process exiting with status %d", rc);
+#endif /* DEBUG */
+       }
+
+       exit(rc);
+}
+
+#ifdef DEBUG_MEM
+static int mem_bytes;
+static int orig_mem_bytes;
+static void checkup_mem(P_void)
+{
+extern struct mallinfo __mallinfo;
+       if (mem_bytes != __mallinfo.uordbytes) {
+               if (orig_mem_bytes == 0)
+                       mem_bytes = orig_mem_bytes = __mallinfo.uordbytes;
+               else {
+                       fprintf(logfp, "%s[%d]: ", progname, mypid);
+                       if (mem_bytes < __mallinfo.uordbytes) {
+                               fprintf(logfp, "ALLOC: %d bytes",
+                                       __mallinfo.uordbytes - mem_bytes);
+                       } else {
+                               fprintf(logfp, "FREE: %d bytes",
+                                       mem_bytes - __mallinfo.uordbytes);
+                       }
+                       mem_bytes = __mallinfo.uordbytes;
+                       fprintf(logfp, ", making %d missing\n",
+                               mem_bytes - orig_mem_bytes);
+               }
+       }
+       malloc_verify();
+}
+#endif /* DEBUG_MEM */
+
+/*
+ * Take a log format string and expand occurences of %m
+ * with the current error code take from errno.
+ */
+INLINE
+static void expand_error(f, e)
+char *f;
+char *e;
+{
+       extern int sys_nerr;
+       extern char *sys_errlist[];
+       char *p;
+       int error = errno;
+
+       for (p = f; *e = *p; e++, p++) {
+               if (p[0] == '%' && p[1] == 'm') {
+                       char *errstr;
+                       if (error < 0 || error >= sys_nerr)
+                               errstr = 0;
+                       else
+                               errstr = sys_errlist[error];
+                       if (errstr)
+                               strcpy(e, errstr);
+                       else
+                               sprintf(e, "Error %d", error);
+                       e += strlen(e) - 1;
+                       p++;
+               }
+       }
+}
+
+/*
+ * Output the time of day and hostname to the logfile
+ */
+static void show_time_host_and_name(lvl)
+int lvl;
+{
+static time_t last_t = 0;
+static char *last_ctime = 0;
+       time_t t = clocktime();
+       char *sev;
+       extern char *ctime();
+
+#if defined(DEBUG) && defined(PARANOID)
+extern char **gargv;
+#endif /* defined(DEBUG) && defined(PARANOID) */
+
+       if (t != last_t) {
+               last_ctime = ctime(&t);
+               last_t = t;
+       }
+
+       switch (lvl) {
+       case XLOG_FATAL:        sev = "fatal:"; break;
+       case XLOG_ERROR:        sev = "error:"; break;
+       case XLOG_USER:         sev = "user: "; break;
+       case XLOG_WARNING:      sev = "warn: "; break;
+       case XLOG_INFO:         sev = "info: "; break;
+       case XLOG_DEBUG:        sev = "debug:"; break;
+       case XLOG_MAP:          sev = "map:  "; break;
+       case XLOG_STATS:        sev = "stats:"; break;
+       default:                sev = "hmm:  "; break;
+       }
+       fprintf(logfp, "%15.15s %s %s[%d]/%s ",
+               last_ctime+4, hostname,
+#if defined(DEBUG) && defined(PARANOID)
+               gargv[0],
+#else
+               progname,
+#endif /* defined(DEBUG) && defined(PARANOID) */
+               mypid,
+               sev);
+}
+
+#ifdef DEBUG
+/*VARARGS1*/
+void dplog(fmt, j,s,_,p,e,n,d,r,y)
+char *fmt;
+char *j, *s, *_, *p, *e, *n, *d, *r, *y;
+{
+       plog(XLOG_DEBUG, fmt, j,s,_,p,e,n,d,r,y);
+}
+
+#endif /* DEBUG */
+/*VARARGS1*/
+void plog(lvl, fmt, j,s,_,p,e,n,d,r,y)
+int lvl;
+char *fmt;
+char *j, *s, *_, *p, *e, *n, *d, *r, *y;
+{
+       char msg[1024];
+       char efmt[1024];
+       char *ptr = msg;
+
+       if (!(xlog_level & lvl))
+               return;
+
+#ifdef DEBUG_MEM
+       checkup_mem();
+#endif /* DEBUG_MEM */
+
+       expand_error(fmt, efmt);
+       sprintf(ptr, efmt, j,s,_,p,e,n,d,r,y);
+       ptr += strlen(ptr);
+       if (ptr[-1] == '\n')
+               *--ptr  = '\0';
+#ifdef HAS_SYSLOG
+       if (syslogging) {
+               switch(lvl) {   /* from mike <mcooper@usc.edu> */
+               case XLOG_FATAL:        lvl = LOG_CRIT; break;
+               case XLOG_ERROR:        lvl = LOG_ERR; break;
+               case XLOG_USER:         lvl = LOG_WARNING; break;
+               case XLOG_WARNING:      lvl = LOG_WARNING; break;
+               case XLOG_INFO:         lvl = LOG_INFO; break;
+               case XLOG_DEBUG:        lvl = LOG_DEBUG; break;
+               case XLOG_MAP:          lvl = LOG_DEBUG; break;
+               case XLOG_STATS:        lvl = LOG_INFO; break;
+               default:                lvl = LOG_ERR; break;
+               }
+               syslog(lvl, "%s", msg);
+               return;
+       }
+#endif /* HAS_SYSLOG */
+
+       *ptr++ = '\n';
+       *ptr = '\0';
+
+       /*
+        * Mimic syslog header
+        */
+       show_time_host_and_name(lvl);
+       fwrite(msg, ptr - msg, 1, logfp);
+       fflush(logfp);
+}
+
+int bind_resv_port P((int so, u_short *pp));
+int bind_resv_port(so, pp)
+int so;
+u_short *pp;
+{
+       struct sockaddr_in sin;
+       int rc;
+       unsigned short port;
+
+       bzero((voidp) &sin, sizeof(sin));
+       sin.sin_family = AF_INET;
+
+       port = IPPORT_RESERVED;
+
+       do {
+               --port;
+               sin.sin_port = htons(port);
+               rc = bind(so, (struct sockaddr *) &sin, sizeof(sin));
+       } while (rc < 0 && port > IPPORT_RESERVED/2);
+
+       if (pp && rc == 0)
+               *pp = port;
+       return rc;
+}
+
+void forcibly_timeout_mp P((am_node *mp));
+void forcibly_timeout_mp(mp)
+am_node *mp;
+{
+       mntfs *mf = mp->am_mnt;
+       /*
+        * Arrange to timeout this node
+        */
+       if (mf && ((mp->am_flags & AMF_ROOT) ||
+               (mf->mf_flags & (MFF_MOUNTING|MFF_UNMOUNTING)))) {
+               if (!(mf->mf_flags & MFF_UNMOUNTING))
+                       plog(XLOG_WARNING, "ignoring timeout request for active node %s", mp->am_path);
+       } else {
+               plog(XLOG_INFO, "\"%s\" forcibly timed out", mp->am_path);
+               mp->am_flags &= ~AMF_NOTIMEOUT;
+               mp->am_ttl = clocktime();
+               reschedule_timeout_mp();
+       }
+}
+
+void am_mounted P((am_node *mp));
+void am_mounted(mp)
+am_node *mp;
+{
+       mntfs *mf = mp->am_mnt;
+       int quoted;
+       mf->mf_flags |= MFF_MOUNTED;
+       mf->mf_error = 0;
+
+       /*
+        * Patch up path for direct mounts
+        */
+       if (mp->am_parent && mp->am_parent->am_mnt->mf_ops == &dfs_ops)
+               mp->am_path = str3cat(mp->am_path, mp->am_parent->am_path, "/", ".");
+
+       /*
+        * Check whether this mount should be cached permanently
+        */
+       if (mf->mf_ops->fs_flags & FS_NOTIMEOUT) {
+               mp->am_flags |= AMF_NOTIMEOUT;
+       } else if (mf->mf_mount[1] == '\0' && mf->mf_mount[0] == '/') {
+               mp->am_flags |= AMF_NOTIMEOUT;
+       } else {
+               struct mntent mnt;
+               mnt.mnt_opts = mf->mf_fo->opt_opts;
+               if (hasmntopt(&mnt, "nounmount"))
+                       mp->am_flags |= AMF_NOTIMEOUT;
+               if ((mp->am_timeo = hasmntval(&mnt, "utimeout")) == 0)
+                       mp->am_timeo = am_timeo;
+/*             if ((mf->mf_server->fs_pinger = hasmntval(&mnt, "ping")) == 0)
+                       mf->mf_server->fs_pinger = AM_PINGER;
+*/
+       }
+
+       /*
+        * Do mounted callback
+        */
+       if (mf->mf_ops->mounted)
+               (*mf->mf_ops->mounted)(mf);
+
+       /*
+        * If this node is a symlink then
+        * compute the length of the returned string.
+        */
+       if (mf->mf_fattr.type == NFLNK)
+               mf->mf_fattr.size = strlen(mp->am_link ? mp->am_link : mp->am_mnt->mf_mount);
+
+       /*
+        * Record mount time
+        */
+       mf->mf_fattr.mtime.seconds = mp->am_stats.s_mtime = clocktime();
+       new_ttl(mp);
+       /*
+        * Update mtime of parent node
+        */
+       if (mp->am_parent && mp->am_parent->am_mnt)
+               mp->am_parent->am_mnt->mf_fattr.mtime.seconds = mp->am_stats.s_mtime;
+
+       /*
+        * Log message
+        */
+       quoted = strchr(mf->mf_info, ' ') != 0;
+       plog(XLOG_INFO, "%s%s%s mounted fstype %s on %s",
+               quoted ? "\"" : "",
+               mf->mf_info,
+               quoted ? "\"" : "",
+               mf->mf_ops->fs_type, mf->mf_mount);
+
+       /*
+        * Update stats
+        */
+       amd_stats.d_mok++;
+}
+
+int mount_node P((am_node *mp));
+int mount_node(mp)
+am_node *mp;
+{
+       mntfs *mf = mp->am_mnt;
+       int error;
+
+       mf->mf_flags |= MFF_MOUNTING;
+       error = (*mf->mf_ops->mount_fs)(mp);
+       mf = mp->am_mnt;
+       mf->mf_flags &= ~MFF_MOUNTING;
+       if (!error && !(mf->mf_ops->fs_flags & FS_MBACKGROUND)) {
+               /* ...but see ifs_mount */
+               am_mounted(mp);
+       }
+
+       return error;
+}
+
+void am_unmounted P((am_node *mp));
+void am_unmounted(mp)
+am_node *mp;
+{
+       mntfs *mf = mp->am_mnt;
+
+       if (!foreground) /* firewall - should never happen */
+               return;
+
+#ifdef DEBUG
+       /*dlog("in am_unmounted(), foreground = %d", foreground);*/
+#endif /* DEBUG */
+
+       /*
+        * Do unmounted callback
+        */
+       if (mf->mf_ops->umounted)
+               (*mf->mf_ops->umounted)(mp);
+
+       /*
+        * Update mtime of parent node
+        */
+       if (mp->am_parent && mp->am_parent->am_mnt)
+               mp->am_parent->am_mnt->mf_fattr.mtime.seconds = clocktime();
+
+       free_map(mp);
+}
+
+
+/*
+ * Fork the automounter
+ *
+ * TODO: Need a better strategy for handling errors
+ */
+static int dofork(P_void);
+INLINE
+static int dofork()
+{
+       int pid;
+top:
+       pid = fork();
+
+       if (pid < 0) {
+               sleep(1);
+               goto top;
+       }
+
+       if (pid == 0) {
+               mypid = getpid();
+               foreground = 0;
+       }
+
+       return pid;
+}
+
+int background(P_void);
+int background()
+{
+       int pid = dofork();
+       if (pid == 0) {
+#ifdef DEBUG
+               dlog("backgrounded");
+#endif /* DEBUG */
+               foreground = 0;
+       }
+
+       return pid;
+}
+
+int mkdirs P((char *path, int mode));
+int mkdirs(path, mode)
+char *path;
+int mode;
+{
+       /*
+        * take a copy in case path is in readonly store
+        */
+       char *p2 = strdup(path);
+       char *sp = p2;
+       struct stat stb;
+       int error_so_far = 0;
+
+       /*
+        * Skip through the string make the directories.
+        * Mostly ignore errors - the result is tested at the end.
+        *
+        * This assumes we are root so that we can do mkdir in a
+        * mode 555 directory...
+        */
+       while (sp = strchr(sp+1, '/')) {
+               *sp = '\0';
+               if (mkdir(p2, mode) < 0) {
+                       error_so_far = errno;
+               } else {
+#ifdef DEBUG
+                       dlog("mkdir(%s)", p2);
+#endif /* DEBUG */
+               }
+               *sp = '/';
+       }
+
+       if (mkdir(p2, mode) < 0) {
+               error_so_far = errno;
+       } else {
+#ifdef DEBUG
+               dlog("mkdir(%s)", p2);
+#endif /* DEBUG */
+       }
+
+#ifdef SUNOS4_WORKAROUND
+       /*
+        * Do a sync - if we do rmdirs() immediately
+        * and then the system crashes it leaves
+        * the filesystem in a state that fsck -p
+        * can't fix.  (Observed more than once on
+        * SunOS 4 ...)
+        *
+        * The problem was caused by a bug somewhere
+        * in the UFS code which has since been fixed
+        * (at least at Berkeley).
+        *
+        * Attempted workaround - XXX.
+        */
+       sync();
+#endif /* SUNOS4_WORKAROUND */
+
+       free(p2);
+
+       return stat(path, &stb) == 0 &&
+               (stb.st_mode & S_IFMT) == S_IFDIR ? 0 : error_so_far;
+}
+
+void rmdirs P((char *dir));
+void rmdirs(dir)
+char *dir;
+{
+       char *xdp = strdup(dir);
+       char *dp;
+
+       do {
+               struct stat stb;
+               /*
+                * Try to find out whether this was
+                * created by amd.  Do this by checking
+                * for owner write permission.
+                */
+               if (stat(xdp, &stb) == 0 && (stb.st_mode & 0200) == 0) {
+                       if (rmdir(xdp) < 0) {
+                               if (errno != ENOTEMPTY && errno != EBUSY && errno != EEXIST)
+                                       plog(XLOG_ERROR, "rmdir(%s): %m", xdp);
+                               break;
+                       } else {
+#ifdef DEBUG
+                               dlog("rmdir(%s)", xdp);
+#endif /* DEBUG */
+                       }
+               } else {
+                       break;
+               }
+               dp = strrchr(xdp, '/');
+               if (dp)
+                       *dp = '\0';
+       } while (dp && dp > xdp);
+       free(xdp);
+}
+
+/*
+ * Because the internal clock is only used for
+ * timing out mounts, it does not have to be
+ * particularly accurate, so long as it does not run
+ * ahead of the real time.  So, to reduce the system
+ * call overhead, repeated calls to gettimeofday()
+ * are replaced by calls to the macro clocktime().
+ * If the global time (clock_valid) is zero then
+ * update_clocktime() is called to obtain the real time.
+ * Before any system calls that are likely to block for a
+ * significant time, the clock_valid value is set
+ * so that the clock is recomputed next time it is
+ * needed.
+ */
+
+time_t clock_valid = 0;
+#ifndef clocktime
+time_t clocktime(P_void)
+{
+       return time(&clock_valid);
+}
+#endif /* clocktime */
+
+voidp xmalloc(len)
+int len;
+{
+       voidp p;
+       int retries = 600;
+
+       do {
+               p = (voidp) malloc((unsigned) len);
+               if (p) {
+#if defined(DEBUG) && defined(DEBUG_MEM)
+                       Debug(D_MEM) plog(XLOG_DEBUG, "Allocated size %d; block %#x", len, p);
+#endif /* defined(DEBUG) && defined(DEBUG_MEM) */
+                       return p;
+               }
+               if (retries > 0) {
+                       plog(XLOG_ERROR, "Retrying memory allocation");
+                       sleep(1);
+               }
+       } while (--retries);
+
+       plog(XLOG_FATAL, "Out of memory");
+       going_down(1);
+
+       abort();
+
+       return 0;
+}
+
+#if defined(DEBUG) && defined(DEBUG_MEM)
+xfree(f, l, p)
+char *f;
+int l;
+voidp p;
+{
+       Debug(D_MEM) plog(XLOG_DEBUG, "Free in %s:%d: block %#x", f, l, p);
+#undef free
+       free(p);
+}
+#endif /* defined(DEBUG) && defined(DEBUG_MEM) */
diff --git a/usr/src/usr.sbin/amd/amq/Makefile b/usr/src/usr.sbin/amd/amq/Makefile
new file mode 100644 (file)
index 0000000..3123db6
--- /dev/null
@@ -0,0 +1,26 @@
+#
+# $Id: Makefile,v 5.2 90/06/23 22:21:14 jsp Rel $
+#
+# 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.
+#
+# %sccs.include.redist.sh%
+#
+#      @(#)Makefile    5.1 (Berkeley) %G%
+#
+
+MKARG = -f ../Makefile.top PROG=amq
+SHELL = /bin/sh
+
+amq: FRC
+       @${MAKE} ${MKARG} $@
+
+install clean count lint: FRC
+       @${MAKE} ${MKARG} $@
+
+FRC:
diff --git a/usr/src/usr.sbin/amd/amq/amq.8 b/usr/src/usr.sbin/amd/amq/amq.8
new file mode 100644 (file)
index 0000000..68affc3
--- /dev/null
@@ -0,0 +1,94 @@
+.\" $Id: amq.8,v 5.2 90/06/23 22:21:16 jsp Rel $
+.\" 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.
+.\"
+.\" %sccs.include.redist.man%
+.\"
+.\"    @(#)amq.8       5.1 (Berkeley) %G%
+.\"
+.TH AMQ 8 ""
+.SH NAME
+amq \- automounter query tool
+.SH SYNOPSIS
+.B amq
+[
+.BI \-h " hostname"
+] [
+.B \-f
+] [
+.B \-m
+] [
+.B \-s
+] [
+.B \-u
+]
+[
+.I directory
+] .\|.\|.
+.SH DESCRIPTION
+.B Amq
+provides a simple way of determining the current state of
+.B amd
+program.
+Communication is by
+.SM RPC.
+Three modes of operation are supported by the current protocol.
+By default a list of mount points and auto-mounted filesystems
+is output.
+An alternative host can be specified using the
+.I \-h
+option.
+.LP
+If directory names are given, as output by default,
+then per-filesystem information is displayed.
+.SH OPTIONS
+The
+.I \-h
+option specifies an alternate host to query.
+By default the local host is used.  In an
+.SM HP-UX
+cluster, the root server is queried by default, since
+that is the system on which the automounter is normally run.
+.LP
+The
+.I \-f
+option asks the automounter to flush the internal
+mount map cache.
+The
+.I \-m
+option asks the automounter to provide a list of mounted filesystems,
+including the number of references to each filesystem and any error
+which occured while mounting.
+The
+.I \-s
+option asks the automounter to provide system-wide mount statistics.
+.LP
+The
+.I \-u
+option asks the automounter to unmount the named filesystems
+instead of providing information about them.  Unmounts are requested,
+not forced.  They merely cause the mounted filesystem to timeout,
+which will be picked up by
+.BR amd 's
+main scheduler thus causing the normal timeout action to be taken.
+.SH FILES
+.PD 0
+.TP 20
+.B amq.x
+.SM RPC
+protocol description.
+.SH CAVEATS
+.B Amq
+uses a Sun registered
+.SM RPC
+program number (300019 decimal) which may not
+be in the /etc/rpc database.
+.SH "SEE ALSO"
+.BR amd (8)
+.SH AUTHOR
+Jan-Simon Pendry <jsp@doc.ic.ac.uk>, Department of Computing, Imperial College, London, UK.
diff --git a/usr/src/usr.sbin/amd/amq/amq.c b/usr/src/usr.sbin/amd/amq/amq.c
new file mode 100644 (file)
index 0000000..65591f8
--- /dev/null
@@ -0,0 +1,520 @@
+/*
+ * $Id: amq.c,v 5.2 90/06/23 22:20:07 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ */
+
+/*
+ * Automounter query tool
+ */
+
+#ifndef lint
+char copyright[] = "\
+@(#)Copyright (c) 1990 Jan-Simon Pendry\n\
+@(#)Copyright (c) 1990 Imperial College of Science, Technology & Medicine\n\
+@(#)Copyright (c) 1990 The Regents of the University of California.\n\
+@(#)All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char rcsid[] = "$Id: amq.c,v 5.2 90/06/23 22:20:07 jsp Rel $";
+static char sccsid[] = "@(#)amq.c      5.1 (Berkeley) %G%";
+#endif /* not lint */
+
+#include "am.h"
+#include "amq.h"
+#include <stdio.h>
+#include <fcntl.h>
+#include <netdb.h>
+
+char *progname;
+static int flush_flag;
+static int minfo_flag;
+static int unmount_flag;
+static int stats_flag;
+static char *debug_opts;
+static char *logfile;
+static char *xlog_opt;
+static char localhost[] = "localhost";
+static char *def_server = localhost;
+
+extern int optind;
+extern char *optarg;
+
+static struct timeval tmo = { 10, 0 };
+#define        TIMEOUT tmo
+
+enum show_opt { Full, Stats, Calc, Short, ShowDone };
+
+/*
+ * If (e) is Calc then just calculate the sizes
+ * Otherwise display the mount node on stdout
+ */
+static void show_mti(mt, e, mwid, dwid, twid)
+amq_mount_tree *mt;
+enum show_opt e;
+int *mwid;
+int *dwid;
+int *twid;
+{
+       switch (e) {
+       case Calc: {
+               int mw = strlen(mt->mt_mountinfo);
+               int dw = strlen(mt->mt_directory);
+               int tw = strlen(mt->mt_type);
+               if (mw > *mwid) *mwid = mw;
+               if (dw > *dwid) *dwid = dw;
+               if (tw > *twid) *twid = tw;
+       } break;
+
+       case Full: {
+               struct tm *tp = localtime(&mt->mt_mounttime);
+printf("%-*.*s %-*.*s %-*.*s %s\n\t%-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n",
+                       *dwid, *dwid,
+                       *mt->mt_directory ? mt->mt_directory : "/",     /* XXX */
+                       *twid, *twid,
+                       mt->mt_type,
+                       *mwid, *mwid, 
+                       mt->mt_mountinfo,
+                       mt->mt_mountpoint,
+
+                       mt->mt_mountuid,
+                       mt->mt_getattr,
+                       mt->mt_lookup,
+                       mt->mt_readdir,
+                       mt->mt_readlink,
+                       mt->mt_statfs,
+
+                       tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year,
+                       tp->tm_mon+1, tp->tm_mday,
+                       tp->tm_hour, tp->tm_min, tp->tm_sec);
+       } break;
+
+       case Stats: {
+               struct tm *tp = localtime(&mt->mt_mounttime);
+printf("%-*.*s %-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n",
+                       *dwid, *dwid,
+                       *mt->mt_directory ? mt->mt_directory : "/",     /* XXX */
+
+                       mt->mt_mountuid,
+                       mt->mt_getattr,
+                       mt->mt_lookup,
+                       mt->mt_readdir,
+                       mt->mt_readlink,
+                       mt->mt_statfs,
+
+                       tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year,
+                       tp->tm_mon+1, tp->tm_mday,
+                       tp->tm_hour, tp->tm_min, tp->tm_sec);
+       } break;
+
+       case Short: {
+               printf("%-*.*s %-*.*s %-*.*s %s\n",
+                       *dwid, *dwid,
+                       *mt->mt_directory ? mt->mt_directory : "/",
+                       *twid, *twid,
+                       mt->mt_type,
+                       *mwid, *mwid,
+                       mt->mt_mountinfo,
+                       mt->mt_mountpoint);
+       } break;
+       }
+}
+
+/*
+ * Display a mount tree.
+ */
+static void show_mt(mt, e, mwid, dwid, pwid)
+amq_mount_tree *mt;
+enum show_opt e;
+int *mwid;
+int *dwid;
+int *pwid;
+{
+       while (mt) {
+               show_mti(mt, e, mwid, dwid, pwid);
+               show_mt(mt->mt_next, e, mwid, dwid, pwid);
+               mt = mt->mt_child;
+       }
+}
+
+static void show_mi(ml, e, mwid, dwid, twid)
+amq_mount_info_list *ml;
+enum show_opt e;
+int *mwid;
+int *dwid;
+int *twid;
+{
+       int i;
+       switch (e) {
+       case Calc: {
+               for (i = 0; i < ml->amq_mount_info_list_len; i++) {
+                       amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
+                       int mw = strlen(mi->mi_mountinfo);
+                       int dw = strlen(mi->mi_mountpt);
+                       int tw = strlen(mi->mi_type);
+                       if (mw > *mwid) *mwid = mw;
+                       if (dw > *dwid) *dwid = dw;
+                       if (tw > *twid) *twid = tw;
+               }
+       } break;
+
+       case Full: {
+               for (i = 0; i < ml->amq_mount_info_list_len; i++) {
+                       amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
+                       printf("%-*.*s %-*.*s %-*.*s %-3d %s is %s",
+                                               *mwid, *mwid, mi->mi_mountinfo,
+                                               *dwid, *dwid, mi->mi_mountpt,
+                                               *twid, *twid, mi->mi_type,
+                                               mi->mi_refc, mi->mi_fserver,
+                                               mi->mi_up > 0 ? "up" :
+                                               mi->mi_up < 0 ? "starting" : "down");
+                       if (mi->mi_error > 0) {
+                               extern char *sys_errlist[];
+                               extern int sys_nerr;
+                               if (mi->mi_error < sys_nerr)
+                                       printf(" (%s)", sys_errlist[mi->mi_error]);
+                               else
+                                       printf(" (Error %d)", mi->mi_error);
+                       } else if (mi->mi_error < 0) {
+                               fputs(" (in progress)", stdout);
+                       }
+                       fputc('\n', stdout);
+               }
+       } break;
+       }
+}
+
+/*
+ * Display general mount statistics
+ */
+static void show_ms(ms)
+amq_mount_stats *ms;
+{
+       printf("\
+requests  stale     mount     mount     unmount\n\
+deferred  fhandles  ok        failed    failed\n\
+%-9d %-9d %-9d %-9d %-9d\n",
+       ms->as_drops, ms->as_stale, ms->as_mok, ms->as_merr, ms->as_uerr);
+}
+
+static bool_t
+xdr_pri_free(xdr_args, args_ptr)
+xdrproc_t xdr_args;
+caddr_t args_ptr;
+{
+       XDR xdr;
+       xdr.x_op = XDR_FREE;
+       return ((*xdr_args)(&xdr, args_ptr));
+}
+
+#ifdef hpux
+#include <cluster.h>
+static char *cluster_server()
+{
+       struct cct_entry *cp;
+
+       if (cnodeid() == 0) {
+               /*
+                * Not clustered
+                */
+               return def_server;
+       }
+
+       while (cp = getccent())
+               if (cp->cnode_type == 'r')
+                       return cp->cnode_name;
+
+
+       return def_server;
+}
+#endif /* hpux */
+
+/*
+ * MAIN
+ */
+main(argc, argv)
+int argc;
+char *argv[];
+{
+       int opt_ch;
+       int errs = 0;
+       char *server;
+       struct sockaddr_in server_addr;
+       int s = RPC_ANYSOCK;
+       CLIENT *clnt;
+       struct hostent *hp;
+       int nodefault = 0;
+
+       /*
+        * Compute program name
+        */
+       if (argv[0]) {
+               progname = strrchr(argv[0], '/');
+               if (progname && progname[1])
+                       progname++;
+               else
+                       progname = argv[0];
+       }
+       if (!progname)
+               progname = "amq";
+
+       /*
+        * Parse arguments
+        */
+       while ((opt_ch = getopt(argc, argv, "fh:l:msux:D:")) != EOF)
+       switch (opt_ch) {
+       case 'f':
+               flush_flag = 1;
+               break;
+
+       case 'h':
+               def_server = optarg;
+               break;
+
+       case 'l':
+               logfile = optarg;
+               nodefault = 1;
+               break;
+
+       case 'm':
+               minfo_flag = 1;
+               nodefault = 1;
+               break;
+
+       case 's':
+               stats_flag = 1;
+               break;
+
+       case 'u':
+               unmount_flag = 1;
+               break;
+
+       case 'x':
+               xlog_opt = optarg;
+               nodefault = 1;
+               break;
+
+       case 'D':
+               debug_opts = optarg;
+               nodefault = 1;
+               break;
+
+       default:
+               errs = 1;
+               break;
+       }
+
+       if (errs) {
+show_usage:
+               fprintf(stderr, "\
+Usage: %s [-h host] [[-f] [-m] | | [-s] | [[-u] directory ...]] |\n\
+\t[-l logfile|\"syslog\"] [-x log_flags] [-D dbg_opts]\n", progname);
+               exit(1);
+       }
+
+#ifdef hpux
+       /*
+        * Figure out root server of cluster
+        */
+       if (def_server == localhost)
+               server = cluster_server();
+       else
+#endif /* hpux */
+       server = def_server;
+
+       /*
+        * Get address of server
+        */
+       if ((hp = gethostbyname(server)) == 0) {
+               fprintf(stderr, "%s: Can't get address of %s\n", progname, server);
+               exit(1);
+       }
+       bzero(&server_addr, sizeof server_addr);
+       server_addr.sin_family = AF_INET;
+       server_addr.sin_addr = *(struct in_addr *) hp->h_addr;
+
+       /*
+        * Create RPC endpoint
+        */
+       clnt = clntudp_create(&server_addr, AMQ_PROGRAM, AMQ_VERSION, TIMEOUT, &s);
+       if (clnt == 0) {
+               fprintf(stderr, "%s: ", progname);
+               clnt_pcreateerror(server);
+               exit(1);
+       }
+
+       /*
+        * Control debugging
+        */
+       if (debug_opts) {
+               int *rc;
+               amq_setopt opt;
+               opt.as_opt = AMOPT_DEBUG;
+               opt.as_str = debug_opts;
+               rc = amqproc_setopt_1(&opt, clnt);
+               if (rc && *rc < 0) {
+                       fprintf(stderr, "%s: daemon not compiled for debug", progname);
+                       errs = 1;
+               } else if (!rc || *rc > 0) {
+                       fprintf(stderr, "%s: debug setting for \"%s\" failed\n", progname, debug_opts);
+                       errs = 1;
+               }
+       }
+
+       /*
+        * Control logging
+        */
+       if (xlog_opt) {
+               int *rc;
+               amq_setopt opt;
+               opt.as_opt = AMOPT_XLOG;
+               opt.as_str = xlog_opt;
+               rc = amqproc_setopt_1(&opt, clnt);
+               if (!rc || *rc) {
+                       fprintf(stderr, "%s: setting log level to \"%s\" failed\n", progname, xlog_opt);
+                       errs = 1;
+               }
+       }
+
+       /*
+        * Control log file
+        */
+       if (logfile) {
+               int *rc;
+               amq_setopt opt;
+               opt.as_opt = AMOPT_LOGFILE;
+               opt.as_str = logfile;
+               rc = amqproc_setopt_1(&opt, clnt);
+               if (!rc || *rc) {
+                       fprintf(stderr, "%s: setting logfile to \"%s\" failed\n", progname, logfile);
+                       errs = 1;
+               }
+       }
+
+       /*
+        * Flush map cache
+        */
+       if (logfile) {
+               int *rc;
+               amq_setopt opt;
+               opt.as_opt = AMOPT_FLUSHMAPC;
+               opt.as_str = "";
+               rc = amqproc_setopt_1(&opt, clnt);
+               if (!rc || *rc) {
+                       fprintf(stderr, "%s: amd on %s cannot flush the map cache\n", progname, server);
+                       errs = 1;
+               }
+       }
+
+       /*
+        * Mount info
+        */
+       if (minfo_flag) {
+               int dummy;
+               amq_mount_info_list *ml = amqproc_getmntfs_1(&dummy, clnt);
+               if (ml) {
+                       int mwid = 0, dwid = 0, twid = 0;
+                       show_mi(ml, Calc, &mwid, &dwid, &twid);
+                       mwid++; dwid++; twid++;
+                       show_mi(ml, Full, &mwid, &dwid, &twid);
+
+               } else {
+                       fprintf(stderr, "%s: amd on %s cannot provide mount info\n", progname, server);
+               }
+       }
+
+       /*
+        * Apply required operation to all remaining arguments
+        */
+       if (optind < argc) {
+               do {
+                       char *fs = argv[optind++];
+                       if (unmount_flag) {
+                               /*
+                                * Unmount request
+                                */
+                               amqproc_umnt_1(&fs, clnt);
+                       } else {
+                               /*
+                                * Stats request
+                                */
+                               amq_mount_tree_p *mtp = amqproc_mnttree_1(&fs, clnt);
+                               if (mtp) {
+                                       amq_mount_tree *mt = *mtp;
+                                       if (mt) {
+                                               int mwid = 0, dwid = 0, twid = 0;
+                                               show_mt(mt, Calc, &mwid, &dwid, &twid);
+                                               mwid++; dwid++, twid++;
+#ifdef notdef
+               printf("\t%s\n%-*.*s %-*.*s %-*.*s %s\n",
+               "Uid   Getattr Lookup RdDir   RdLnk   Statfs Mounted@",
+                     dwid, dwid, "What", twid, twid, "Type", mwid, mwid, "Info", "Where");
+                                               show_mt(mt, Full, &mwid, &dwid, &twid);
+#endif /* notdef */
+               printf("%-*.*s Uid   Getattr Lookup RdDir   RdLnk   Statfs Mounted@\n",
+                       dwid, dwid, "What");
+                                               show_mt(mt, Stats, &mwid, &dwid, &twid);
+                                       } else {
+                                               fprintf(stderr, "%s: %s not automounted\n", progname, fs);
+                                       }
+                                       xdr_pri_free(xdr_amq_mount_tree_p, (caddr_t) mtp);
+                               } else {
+                                       fprintf(stderr, "%s: ", progname);
+                                       clnt_perror(clnt, server);
+                                       errs = 1;
+                               }
+                       }
+               } while (optind < argc);
+       } else if (unmount_flag) {
+               goto show_usage;
+       } else if (stats_flag) {
+               amq_mount_stats *ms = amqproc_stats_1((voidp) 0, clnt);
+               if (ms) {
+                       show_ms(ms);
+               } else {
+                       fprintf(stderr, "%s: ", progname);
+                       clnt_perror(clnt, server);
+                       errs = 1;
+               }
+       } else if (!nodefault) {
+               amq_mount_tree_list *mlp = amqproc_export_1((voidp) 0, clnt);
+               if (mlp) {
+                       enum show_opt e = Calc;
+                       int mwid = 0, dwid = 0, pwid = 0;
+                       while (e != ShowDone) {
+                               int i;
+                               for (i = 0; i < mlp->amq_mount_tree_list_len; i++) {
+                                       show_mt(mlp->amq_mount_tree_list_val[i],
+                                                e, &mwid, &dwid, &pwid);
+                               }
+                               mwid++; dwid++, pwid++;
+                               if (e == Calc) e = Short;
+                               else if (e == Short) e = ShowDone;
+                       }
+               } else {
+                       fprintf(stderr, "%s: ", progname);
+                       clnt_perror(clnt, server);
+                       errs = 1;
+               }
+       }
+
+       exit(errs);
+}
+
+#ifdef DEBUG
+xfree(f, l, p)
+char *f, *l;
+voidp p;
+{
+       free(p);
+}
+#endif /* DEBUG */
diff --git a/usr/src/usr.sbin/amd/config/Configure b/usr/src/usr.sbin/amd/config/Configure
new file mode 100644 (file)
index 0000000..d7dc24f
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/sh -
+#
+# 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.
+# All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Jan-Simon Pendry at Imperial College, London.
+#
+# %sccs.include.redist.sh%
+#
+#      @(#)Configure   5.1 (Berkeley) %G%
+#
+echo "Making ./arch and ./os-type executable ..."
+until chmod +x ./arch ./os-type; do echo "Error: chmod command failed" >&2; exit 1; done
+echo "Checking ./arch and ./os-type ..."
+echo ""
+arch="`sh ./arch 2>/dev/null`"
+os="`sh ./os-type 2>/dev/null`"
+case "$arch" in
+"") echo "./arch doesn't produce an answer - please check it" >&2; exit 1;;
+esac
+case "$os" in
+"") echo "./os-type doesn't produce an answer - please check it" >&2; exit 1;;
+esac
+cat << %
+This machine appears to be a "$arch" running "$os".
+If that is correct just run make.
+If those are incorrect please edit ./arch and ./os-type
+%
+exit 0
diff --git a/usr/src/usr.sbin/amd/config/Makefile.aix3 b/usr/src/usr.sbin/amd/config/Makefile.aix3
new file mode 100644 (file)
index 0000000..2aa8707
--- /dev/null
@@ -0,0 +1,16 @@
+#
+# $Id: Makefile.aix3,v 5.2 90/06/23 22:20:35 jsp Rel $
+#
+# 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.
+#
+# %sccs.include.redist.sh%
+#
+#      @(#)Makefile.aix3       5.1 (Berkeley) %G%
+#
+SYSLIB = -lbsd
diff --git a/usr/src/usr.sbin/amd/config/Makefile.bsd44 b/usr/src/usr.sbin/amd/config/Makefile.bsd44
new file mode 100644 (file)
index 0000000..fefce9d
--- /dev/null
@@ -0,0 +1,19 @@
+#
+# $Id: Makefile.bsd44,v 5.2 90/06/23 22:20:39 jsp Rel $
+#
+# 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.
+# All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Jan-Simon Pendry at Imperial College, London.
+#
+# %sccs.include.redist.sh%
+#
+#      @(#)Makefile.bsd44      5.1 (Berkeley) %G%
+#
+# Extra Makefile definitions for 4.4 BSD
+#
+
+RPCLIB = -lrpc
diff --git a/usr/src/usr.sbin/amd/config/Makefile.config b/usr/src/usr.sbin/amd/config/Makefile.config
new file mode 100644 (file)
index 0000000..eb3814d
--- /dev/null
@@ -0,0 +1,88 @@
+#
+# $Id: Makefile.config,v 5.2 90/06/23 22:21:19 jsp Rel $
+#
+# 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.
+#
+# %sccs.include.redist.sh%
+#
+#      @(#)Makefile.config     5.1 (Berkeley) %G%
+#
+
+#
+# Comment/uncomment the following lines as required
+#
+
+#
+# Where local include files are stored
+#
+#XINCLUDE = -I/usr/local/athena/include
+
+#
+# Define RESOLV if your C library does not include support
+# for Hesiod and/or Named.
+#
+#RESOLV = -lhesiod -lresolv
+
+#
+# Define XLIBDIR if you have libraries not on the standard
+# search path.
+#
+#XLIBDIR = -L/usr/local/athena/lib
+
+#
+# Define DBM if your C library does not include
+# support for gdbm and/or ndbm.
+#
+#DBM = -lgdbm #-lndbm
+
+#
+# Define RPCLIB if your C library does not include
+# support for RPC
+#
+#RPCLIB = -lrpc
+
+#
+# Include support for Network Information Service (NIS)
+#
+#HAS_NIS_MAPS = -DHAS_NIS_MAPS
+
+#
+# Include support for file maps
+#
+HAS_FILE_MAPS = -DHAS_FILE_MAPS
+
+#
+# Include support for Hesiod
+#
+#HAS_HESIOD_MAPS = -DHAS_HESIOD_MAPS
+
+#
+# Include support for /etc/passwd
+#
+HAS_PASSWD_MAPS = -DHAS_PASSWD_MAPS
+
+#
+# Include support for mountd
+# Not released - design not complete...
+#
+#HAS_MOUNTD_MAPS = -DHAS_MOUNTD_MAPS
+
+#
+# Include support for ndbm.
+# This removes support for gdbm and is only supported
+# if your operating system supports ndbm
+#
+#HAS_NDBM_MAPS = -DHAS_NDBM_MAPS
+
+
+##############################################################
+# Do NOT edit the following lines
+#
+CONFIG = ${XINCLUDE} ${HAS_NIS_MAPS} ${HAS_FILE_MAPS} ${HAS_HESIOD_MAPS} \
+               ${HAS_NDBM_MAPS} ${HAS_MOUNTD_MAPS} ${HAS_PASSWD_MAPS}
diff --git a/usr/src/usr.sbin/amd/config/Makefile.hpux b/usr/src/usr.sbin/amd/config/Makefile.hpux
new file mode 100644 (file)
index 0000000..495c36b
--- /dev/null
@@ -0,0 +1,21 @@
+#
+# $Id: Makefile.hpux,v 5.2 90/06/23 22:20:49 jsp Rel $
+#
+# 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.
+# All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Jan-Simon Pendry at Imperial College, London.
+#
+# %sccs.include.redist.sh%
+#
+#      @(#)Makefile.hpux       5.1 (Berkeley) %G%
+#
+# Extra Makefile definitions for HP-UX
+#
+
+#CC = gcc ${GCCOPTS}
+CC = cc -Wc,-Nd2000
+OLDCC = cc -Wc,-Nd2000
diff --git a/usr/src/usr.sbin/amd/config/arch b/usr/src/usr.sbin/amd/config/arch
new file mode 100644 (file)
index 0000000..8953d09
--- /dev/null
@@ -0,0 +1,84 @@
+#! /bin/sh
+#
+# $Id: arch,v 5.2 90/06/23 22:21:22 jsp Rel $
+#
+# 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.
+# All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Jan-Simon Pendry at Imperial College, London.
+#
+# %sccs.include.redist.sh%
+#
+#      @(#)arch        5.1 (Berkeley) %G%
+#
+# Figure out machine architecture
+#
+
+PATH=/bin:/usr/bin:/usr/ucb:/etc:/usr/local/bin:${PATH} export PATH
+
+#
+# First try to find a standard command
+#
+a=arch         # Sun compat
+m=machine      # BSD compat
+u=uname                # Sys5 compat
+
+if [ -f /etc/$a -o -f /bin/$a -o -f /usr/bin/$a -o -f /usr/local/bin/$a ]
+then
+       exec $a
+elif [ -f /etc/$m -o -f /bin/$m -o -f /usr/bin/$m -o -f /usr/ucb/$m -o -f /usr/local/bin/$m ]
+then
+       exec $m
+elif [ -f /etc/$u -o -f /bin/$u -o -f /usr/bin/$u -o -f /usr/local/bin/$u ]
+then
+       ARCH="`uname`"
+       case "$ARCH" in
+               "HP-UX") echo hp9000; exit 0;;
+               AIX*) MACH="`uname -m`"
+                       case "$MACH" in
+                       00*) echo ibm6000; exit 0;;
+                       10*) echo ibm032; exit 0;;
+                       20*) echo ibm032; exit 0;;
+                       esac
+                       ;;
+               A/UX) echo macII ; exit 0 ;;
+               *) ;;
+       esac
+fi
+
+#
+# Take a pot-shot at your machine architecture
+#
+echo " ... No ARCH= option specified; dynamically determining architecture" >&2
+
+case "`exec 2>/dev/null; head -2 /etc/motd`" in
+*"HP-UX"*)             ARCH=hp9000;;
+*"Ultrix"*)            ARCH=vax;;
+*"RISC iX"*)           ARCH=arm;;
+*"Umax 4.2"*)          ARCH=encore;;
+*"Alliant Concentrix"*)        ARCH=alliant;;
+*"FPS Model 500"*)     ARCH=fps500;;
+*)                     ARCH=unknown;
+                       if [ -d /usr/include/caif ]; then
+                               ARCH=ibm032
+                       elif [ -f /bin/pyr ]; then
+                               if /bin/pyr; then
+                                       echo pyr; exit 0
+                               fi
+                       fi
+                       ;;
+fi
+
+esac
+
+echo " ... architecture appears to be \"${ARCH}\"" >&2
+echo $ARCH
+
+case "$ARCH" in
+unknown) exit 1
+esac
+
+exit 0
diff --git a/usr/src/usr.sbin/amd/config/misc-aix3.h b/usr/src/usr.sbin/amd/config/misc-aix3.h
new file mode 100644 (file)
index 0000000..aa722ad
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * $Id: misc-aix3.h,v 5.2 90/06/23 22:20:34 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)misc-aix3.h 5.1 (Berkeley) %G%
+ */
+
+struct ufs_args {
+       char    *fspec;                         /* Block device */
+};
+
+struct nfs_args {
+       struct sockaddr_in      addr;           /* file server address */
+       fhandle_t               fh;             /* File handle to be mounted */
+       int                     flags;          /* flags */
+       int                     wsize;          /* write size in bytes */
+       int                     rsize;          /* read size in bytes */
+       int                     timeo;          /* initial timeout in .1 secs */
+       int                     retrans;        /* times to retry send */
+       char                    *hostname;      /* server's hostname */
+       int                     acregmin;       /* attr cache file min secs */
+       int                     acregmax;       /* attr cache file max secs */
+       int                     acdirmin;       /* attr cache dir min secs */
+       int                     acdirmax;       /* attr cache dir max secs */
+       char                    *netname;       /* server's netname */
+       int                     biods;          /* number of BIODS */
+};
+
+/*
+ * NFS mount option flags
+ */
+#define        MNTOPT_RO       "ro"    /* read only */
+#define        MNTOPT_RW       "rw"    /* read/write */
+#define        MNTOPT_SOFT     "soft"  /* soft mount */
+#define        MNTOPT_HARD     "hard"  /* hard mount */
+#define        MNTOPT_NOSUID   "nosuid"/* no set uid allowed */
+#define        MNTOPT_NOAUTO   "noauto"/* hide entry from mount -a */
+#define        MNTOPT_INTR     "intr"  /* allow interrupts on hard mount */
+#define MNTOPT_SECURE  "secure"/* use secure RPC for NFS */
+#define MNTOPT_GRPID   "grpid" /* SysV-compatible group-id on create */
+#define MNTOPT_NOSUB   "nosub"  /* disallow mounts beneath this one */
+#define MNTOPT_MULTI   "multi"  /* Do multi-component lookup */
+#define MNTOPT_NOAC    "noac"   /* don't cache attributes */
+
+#define NFSMNT_SOFT    0x001   /* soft mount (hard is default) */
+#define NFSMNT_WSIZE   0x002   /* set write size */
+#define NFSMNT_RSIZE   0x004   /* set read size */
+#define NFSMNT_TIMEO   0x008   /* set initial timeout */
+#define NFSMNT_RETRANS 0x010   /* set number of request retrys */
+#define NFSMNT_HOSTNAME        0x020   /* set hostname for error printf */
+#define NFSMNT_INT     0x040   /* allow interrupts on hard mount */
+#define        NFSMNT_NOAC     0x080   /* don't cache attributes */
+#define        NFSMNT_ACREGMIN 0x0100  /* set min secs for file attr cache */
+#define        NFSMNT_ACREGMAX 0x0200  /* set max secs for file attr cache */
+#define        NFSMNT_ACDIRMIN 0x0400  /* set min secs for dir attr cache */
+#define        NFSMNT_ACDIRMAX 0x0800  /* set max secs for dir attr cache */
+#define NFSMNT_SECURE  0x1000  /* secure mount */
+#define NFSMNT_BIODS   0x10000 /* Number of biods for the file system */
+
+#define DEF_BIODS      6
diff --git a/usr/src/usr.sbin/amd/config/misc-hpux.h b/usr/src/usr.sbin/amd/config/misc-hpux.h
new file mode 100644 (file)
index 0000000..f5bb6ee
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * $Id: misc-hpux.h,v 5.2 90/06/23 22:20:48 jsp Rel $
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)misc-hpux.h 5.1 (Berkeley) %G%
+ */
+
+/*
+ * These definitions are from <nfs/nfs.h>
+ * Unfortunately, that file cannot be included
+ * because it contains lots of structure definitions
+ * that are not wanted (they produce name clashes).
+ * Isn't HP-UX wonderful!
+ */
+
+/*
+ * HP-UX specific definitions
+ */
+struct nfs_args {
+       struct sockaddr_in      *addr;          /* file server address */
+       fhandle_t               *fh;            /* File handle to be mounted */
+       int                     flags;          /* flags */
+       int                     wsize;          /* write size in bytes */
+       int                     rsize;          /* read size in bytes */
+       int                     timeo;          /* initial timeout in .1 secs */
+       int                     retrans;        /* times to retry send */
+       char                    *hostname;      /* server's name */
+};
+
+/*
+ * NFS mount option flags
+ */
+#define        NFSMNT_SOFT     0x001   /* soft mount (hard is default) */
+#define        NFSMNT_WSIZE    0x002   /* set write size */
+#define        NFSMNT_RSIZE    0x004   /* set read size */
+#define        NFSMNT_TIMEO    0x008   /* set initial timeout */
+#define        NFSMNT_RETRANS  0x010   /* set number of request retrys */
+#define        NFSMNT_HOSTNAME 0x020   /* set hostname for error printf */
+#define        NFSMNT_INT      0x040   /* set option to have interruptable mounts */
+#define        NFSMNT_NODEVS   0x080   /* turn off device file access (default on) */
diff --git a/usr/src/usr.sbin/amd/config/misc-ultrix.h b/usr/src/usr.sbin/amd/config/misc-ultrix.h
new file mode 100644 (file)
index 0000000..77014cd
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * $Id: misc-ultrix.h,v 5.2 90/06/23 22:20:56 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)misc-ultrix.h       5.1 (Berkeley) %G%
+ */
+
+#include        <nfs/nfs_gfs.h>
+#define KERNEL
+#include        <sys/fs_types.h>
+#undef  KERNEL
+
+#ifndef HOSTNAMESZ
+#include <nfs/nfs_clnt.h>
+#endif
+
+#include <ufs/ufs_mount.h>
+
+#define        ufs_args ufs_specific
diff --git a/usr/src/usr.sbin/amd/config/mtab_aix.c b/usr/src/usr.sbin/amd/config/mtab_aix.c
new file mode 100644 (file)
index 0000000..c4a0065
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * $Id: mtab_aix.c,v 5.2 90/06/23 22:20:36 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)mtab_aix.c  5.1 (Berkeley) %G%
+ */
+
+#include "am.h"
+
+#ifdef READ_MTAB_AIX3_STYLE
+
+#include <sys/mntctl.h>
+#include <sys/vmount.h>
+
+static struct mntent *mnt_dup(mp)
+struct vmount *mp;
+{
+       struct mntent *new_mp = ALLOC(mntent);
+
+       char *ty;
+       new_mp->mnt_fsname = strdup(vmt2dataptr(mp, VMT_OBJECT));
+       new_mp->mnt_dir = strdup(vmt2dataptr(mp, VMT_STUB));
+       new_mp->mnt_opts = strdup(vmt2dataptr(mp, VMT_ARGS));
+       switch (mp->vmt_gfstype) {
+       case MNT_JFS:  ty = MTAB_TYPE_UFS; break;
+       case MNT_NFS:  ty = MTAB_TYPE_NFS; break;
+       default:  ty = "unknown"; break;
+       }
+       new_mp->mnt_type = strdup(ty);
+       new_mp->mnt_passno = mp->vmt_vfsnumber;
+       new_mp->mnt_freq = 0;
+
+       return new_mp;
+}
+
+/*
+ * Read a mount table into memory
+ */
+mntlist *read_mtab(fs)
+char *fs;
+{
+       mntlist **mpp, *mhp;
+
+       int i;
+       char *mntinfo = 0, *cp;
+       struct vmount *vp;
+       int ret;
+
+       /*
+        * First figure out size of mount table
+        * and allocate space for a copy...
+        * Then get mount table for real.
+        */
+       ret = mntctl(MCTL_QUERY, sizeof(i), &i);
+       if (ret == 0) {
+               mntinfo = xmalloc(i);
+               ret = mntctl(MCTL_QUERY, i, mntinfo);
+       }
+
+       if (ret <= 0) {
+               plog(XLOG_ERROR, "mntctl: %m");
+               goto out;
+       }
+#ifdef DEBUG
+       /*dlog("mntctl returns %d structures", ret);*/
+#endif /* DEBUG */
+
+       mpp = &mhp;
+       for (i = 0, cp = mntinfo; i < ret; i++, cp += vp->vmt_length) {
+               vp = (struct vmount *) cp;
+
+               /*
+                * Allocate a new slot
+                */
+               *mpp = ALLOC(mntlist);
+
+               /*
+                * Copy the data returned by mntctl
+                */
+               (*mpp)->mnt = mnt_dup(vp);
+
+               /*
+                * Move to next pointer
+                */
+               mpp = &(*mpp)->mnext;
+       }
+
+       *mpp = 0;
+
+out:
+       if (mntinfo)
+               free(mntinfo);
+       return mhp;
+}
+
+#endif /* READ_MTAB_AIX3_STYLE */
diff --git a/usr/src/usr.sbin/amd/config/mtab_bsd.c b/usr/src/usr.sbin/amd/config/mtab_bsd.c
new file mode 100644 (file)
index 0000000..727a9c9
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * $Id: mtab_bsd.c,v 5.2 90/06/23 22:20:40 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)mtab_bsd.c  5.1 (Berkeley) %G%
+ */
+
+#include "am.h"
+
+#ifdef READ_MTAB_BSD_STYLE
+
+#include <sys/mount.h>
+
+static struct mntent *mnt_dup(mp)
+struct statfs *mp;
+{
+       struct mntent *new_mp = ALLOC(mntent);
+       char *ty;
+
+       new_mp->mnt_fsname = strdup(mp->f_mntfromname);
+       new_mp->mnt_dir = strdup(mp->f_mntonname);
+       switch (mp->f_type) {
+       case MOUNT_UFS:  ty = MTAB_TYPE_UFS; break;
+       case MOUNT_NFS:  ty = MTAB_TYPE_NFS; break;
+       case MOUNT_MFS:  ty = MTAB_TYPE_MFS; break;
+       default:  ty = "unknown"; break;
+       }
+       new_mp->mnt_type = strdup(ty);
+       new_mp->mnt_opts = strdup("unset");
+       new_mp->mnt_freq = 0;
+       new_mp->mnt_passno = 0;
+
+       return new_mp;
+}
+
+/*
+ * Read a mount table into memory
+ */
+mntlist *read_mtab(fs)
+char *fs;
+{
+       mntlist **mpp, *mhp;
+       struct statfs *mntbufp, *mntp;
+
+       int nloc = getmntinfo(&mntbufp, MNT_NOWAIT);
+
+       if (nloc == 0) {
+               plog(XLOG_ERROR, "Can't read mount table");
+               return 0;
+       }
+
+       mpp = &mhp;
+       for (mntp = mntbufp; mntp < mntbufp + nloc; mntp++) {
+               /*
+                * Allocate a new slot
+                */
+               *mpp = ALLOC(mntlist);
+
+               /*
+                * Copy the data returned by getmntent
+                */
+               (*mpp)->mnt = mnt_dup(mntp);
+
+               /*
+                * Move to next pointer
+                */
+               mpp = &(*mpp)->mnext;
+       }
+
+       return mhp;
+}
+
+#endif /* READ_MTAB_BSD_STYLE */
diff --git a/usr/src/usr.sbin/amd/config/mtab_file.c b/usr/src/usr.sbin/amd/config/mtab_file.c
new file mode 100644 (file)
index 0000000..d65108a
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ * $Id: mtab_file.c,v 5.2 90/06/23 22:20:54 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)mtab_file.c 5.1 (Berkeley) %G%
+ */
+
+#include "am.h"
+
+#ifdef READ_MTAB_FROM_FILE
+
+#ifdef USE_FCNTL
+#include <fcntl.h>
+#else
+#include <sys/file.h>
+#endif /* USE_FCNTL */
+
+#ifdef UPDATE_MTAB
+
+/*
+ * Do strict /etc/mtab locking
+ */
+#define        MTAB_LOCKING
+
+/*
+ * Firewall mtab entries
+ */
+#define        MTAB_STRIPNL
+
+#include <sys/stat.h>
+static FILE *mnt_file;
+
+/*
+ * If the system is being trashed by something, then
+ * opening mtab may fail with ENFILE.  So, go to sleep
+ * for a second and try again. (Yes - this has happened to me.)
+ *
+ * Note that this *may* block the automounter, oh well. 
+ * If we get to this state then things are badly wrong anyway...
+ *
+ * Give the system 10 seconds to recover but then give up.
+ * Hopefully something else will exit and free up some file
+ * table slots in that time.
+ */
+#define        NFILE_RETRIES   10 /* seconds */
+
+#ifdef MTAB_LOCKING
+#ifdef LOCK_FCNTL
+static int lock(fd)
+{
+       int rc;
+       struct flock lk;
+
+       lk.l_type = F_WRLCK;
+       lk.l_whence = 0;
+       lk.l_start = 0;
+       lk.l_len = 0;
+
+again:
+       rc = fcntl(fd, F_SETLKW, (caddr_t) &lk);
+       if (rc < 0 && (errno == EACCES || errno == EAGAIN)) {
+#ifdef DEBUG
+               dlog("Blocked, trying to obtain exclusive mtab lock");
+#endif /* DEBUG */
+               sleep(1);
+               goto again;
+       }
+       return rc;
+}
+#else
+#define lock(fd) (flock((fd), LOCK_EX))
+#endif /* LOCK_FCNTL */
+#endif /* MTAB_LOCKING */
+
+/*
+ * Unlock the mount table
+ */
+void unlock_mntlist()
+{
+       /*
+        * Release file lock, by closing the file
+        */
+       if (mnt_file) {
+               endmntent(mnt_file);
+               mnt_file = 0;
+       }
+}
+
+/*
+ * Write out a mount list
+ */
+void rewrite_mtab(mp)
+mntlist *mp;
+{
+       FILE *mfp;
+
+       /*
+        * Concoct a temporary name in the same
+        * directory as the target mount table
+        * so that rename() will work.
+        */
+       char tmpname[64];
+       int retries;
+       int tmpfd;
+       char *cp;
+       char *mcp = mtab;
+       cp = strrchr(mcp, '/');
+       if (cp) {
+               bcopy(mcp, tmpname, cp - mcp);
+               tmpname[cp-mcp] = '\0';
+       } else {
+               plog(XLOG_WARNING, "No '/' in mtab (%s), using \".\" as tmp directory", mtab);
+               tmpname[0] = '.'; tmpname[1] = '\0';
+       }
+       strcat(tmpname, "/mtabXXXXXX");
+       mktemp(tmpname);
+       retries = 0;
+enfile1:
+       if ((tmpfd = open(tmpname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) {
+               if (errno == ENFILE && retries++ < NFILE_RETRIES) {
+                       sleep(1);
+                       goto enfile1;
+               }
+               plog(XLOG_ERROR, "%s: open: %m", tmpname);
+               return;
+       }
+       if (close(tmpfd) < 0)
+               plog(XLOG_ERROR, "Couldn't close tmp file descriptor: %m");
+
+       retries = 0;
+enfile2:
+       mfp = setmntent(tmpname, "w");
+       if (!mfp) {
+               if (errno == ENFILE && retries++ < NFILE_RETRIES) {
+                       sleep(1);
+                       goto enfile2;
+               }
+               plog(XLOG_ERROR, "setmntent(\"%s\", \"w\"): %m", tmpname);
+               return;
+       }
+
+       while (mp) {
+               if (mp->mnt)
+                       if (addmntent(mfp, mp->mnt))
+                               plog(XLOG_ERROR, "Can't write entry to %s", tmpname);
+               mp = mp->mnext;
+       }
+
+       endmntent(mfp);
+
+       /*
+        * Rename temporary mtab to real mtab
+        */
+       if (rename(tmpname, mtab) < 0)
+               plog(XLOG_ERROR, "rename %s to %s: %m", tmpname, mtab);
+}
+
+#ifdef MTAB_STRIPNL
+static void mtab_stripnl(s)
+char *s;
+{
+       do {
+               s = strchr(s, '\n');
+               if (s)
+                       *s++ = ' ';
+       } while (s);
+}
+#endif /* MTAB_STRIPNL */
+
+/*
+ * Append a mntent structure to the
+ * current mount table.
+ */
+void write_mntent(mp)
+struct mntent *mp;
+{
+       int retries = 0;
+       FILE *mfp;
+enfile:
+       mfp = setmntent(mtab, "a");
+       if (mfp) {
+#ifdef MTAB_STRIPNL
+               mtab_stripnl(mp->mnt_opts);
+#endif /* MTAB_STRIPNL */
+               if (addmntent(mfp, mp))
+                       plog(XLOG_ERROR, "Couldn't write %s: %m", mtab);
+               endmntent(mfp);
+       } else {
+               if (errno == ENFILE && retries < NFILE_RETRIES) {
+                       sleep(1);
+                       goto enfile;
+               }
+               plog(XLOG_ERROR, "setmntent(\"%s\", \"a\"): %m", mtab);
+       }
+}
+
+#endif /* UPDATE_MTAB */
+
+static struct mntent *mnt_dup(mp)
+struct mntent *mp;
+{
+       struct mntent *new_mp = ALLOC(mntent);
+
+       new_mp->mnt_fsname = strdup(mp->mnt_fsname);
+       new_mp->mnt_dir = strdup(mp->mnt_dir);
+       new_mp->mnt_type = strdup(mp->mnt_type);
+       new_mp->mnt_opts = strdup(mp->mnt_opts);
+
+       new_mp->mnt_freq = mp->mnt_freq;
+       new_mp->mnt_passno = mp->mnt_passno;
+
+       return new_mp;
+}
+
+/*
+ * Read a mount table into memory
+ */
+mntlist *read_mtab(fs)
+char *fs;
+{
+       mntlist **mpp, *mhp;
+
+       struct mntent *mep;
+       FILE *mfp = 0;
+
+#ifdef UPDATE_MTAB
+       /*
+        * There is a possible race condition if two processes enter
+        * this routine at the same time.  One will be blocked by the
+        * exclusive lock below (or by the shared lock in setmntent)
+        * and by the time the second process has the exclusive lock
+        * it will be on the wrong underlying object.  To check for this
+        * the mtab file is stat'ed before and after all the locking
+        * sequence, and if it is a different file then we assume that
+        * it may be the wrong file (only "may", since there is another
+        * race between the initial stat and the setmntent).
+        *
+        * Simpler solutions to this problem are invited...
+        */
+       int racing = 0;
+#ifdef MTAB_LOCKING
+       int rc;
+       int retries = 0;
+       struct stat st_before, st_after;
+#endif /* MTAB_LOCKING */
+
+       if (mnt_file) {
+#ifdef DEBUG
+               dlog("Forced close on %s in read_mtab", mtab);
+#endif /* DEBUG */
+               endmntent(mnt_file);
+               mnt_file = 0;
+       }
+
+#ifdef MTAB_LOCKING
+again:
+       if (mfp) {
+               endmntent(mfp);
+               mfp = 0;
+       }
+
+       clock_valid = 0;
+       if (stat(mtab, &st_before) < 0) {
+               plog(XLOG_ERROR, "%s: stat: %m", mtab);
+               if (errno == ESTALE) {
+                       /* happens occasionally */
+                       sleep(1);
+                       goto again;
+               }
+               return 0;
+       }
+#endif /* MTAB_LOCKING */
+#endif /* UPDATE_MTAB */
+
+eacces:
+       mfp = setmntent(mtab, "r+");
+       if (!mfp) {
+               /*
+                * Since setmntent locks the descriptor, it
+                * is possible it can fail... so retry if
+                * needed.
+                */
+               if (errno == EACCES || errno == EAGAIN) {
+#ifdef DEBUG
+                       dlog("Blocked, trying to obtain exclusive mtab lock");
+#endif /* DEBUG */
+                       goto eacces;
+               } else if (errno == ENFILE && retries++ < NFILE_RETRIES) {
+                       sleep(1);
+                       goto eacces;
+               }
+
+               plog(XLOG_ERROR, "setmntent(\"%s\", \"r+\"): %m", mtab);
+               return 0;
+       }
+
+#ifdef MTAB_LOCKING
+#ifdef UPDATE_MTAB
+       /*
+        * At this point we have an exclusive lock on the mount list,
+        * but it may be the wrong one so...
+        */
+
+       /*
+        * Need to get an exclusive lock on the current
+        * mount table until we have a new copy written
+        * out, when the lock is released in free_mntlist.
+        * flock is good enough since the mount table is
+        * not shared between machines.
+        */
+       do
+               rc = lock(fileno(mfp));
+       while (rc < 0 && errno == EINTR);
+       if (rc < 0) {
+               plog(XLOG_ERROR, "Couldn't lock %s: %m", mtab);
+               endmntent(mfp);
+               return 0;
+       }
+       /*
+        * Now check whether the mtab file has changed under our feet
+        */
+       if (stat(mtab, &st_after) < 0) {
+               plog(XLOG_ERROR, "%s: stat", mtab);
+               goto again;
+       }
+
+       if (st_before.st_dev != st_after.st_dev ||
+               st_before.st_ino != st_after.st_ino) {
+                       if (racing == 0) {
+                               /* Sometimes print a warning */
+                               plog(XLOG_WARNING,
+                                       "Possible mount table race - retrying %s", fs);
+                       }
+                       racing = (racing+1) & 3;
+                       goto again;
+       }
+#endif /* UPDATE_MTAB */
+#endif /* MTAB_LOCKING */
+
+       mpp = &mhp;
+
+/*
+ * XXX - In SunOS 4 there is (yet another) memory leak
+ * which loses 1K the first time getmntent is called.
+ * (jsp)
+ */
+       while (mep = getmntent(mfp)) {
+               /*
+                * Allocate a new slot
+                */
+               *mpp = ALLOC(mntlist);
+
+               /*
+                * Copy the data returned by getmntent
+                */
+               (*mpp)->mnt = mnt_dup(mep);
+
+               /*
+                * Move to next pointer
+                */
+               mpp = &(*mpp)->mnext;
+       }
+       *mpp = 0;
+
+#ifdef UPDATE_MTAB
+       /*
+        * If we are not updating the mount table then we
+        * can free the resources held here, otherwise they
+        * must be held until the mount table update is complete
+        */
+       mnt_file = mfp;
+#else
+       endmntent(mfp);
+#endif /* UPDATE_MTAB */
+
+       return mhp;
+}
+
+#endif /* READ_MTAB_FROM_FILE */
diff --git a/usr/src/usr.sbin/amd/config/mtab_ultrix.c b/usr/src/usr.sbin/amd/config/mtab_ultrix.c
new file mode 100644 (file)
index 0000000..47df1b6
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * $Id: mtab_ultrix.c,v 5.2 90/06/23 22:20:57 jsp Rel $
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)mtab_ultrix.c       5.1 (Berkeley) %G%
+ */
+
+#include "am.h"
+
+#ifdef READ_MTAB_ULTRIX_STYLE
+
+#include <sys/mount.h>
+#include <sys/fs_types.h>
+
+static struct mntent *mnt_dup(mp)
+struct fs_data *mp;
+{
+       struct mntent *new_mp = ALLOC(mntent);
+
+       new_mp->mnt_fsname = strdup(mp->fd_devname);
+       new_mp->mnt_dir = strdup(mp->fd_path);
+        if (mp->fd_fstype >= GT_NUMTYPES)
+                mp->fd_fstype = GT_UNKWN;
+        else if (gt_names[mp->fd_fstype] == 0)
+                mp->fd_fstype = GT_UNKWN;
+        new_mp->mnt_type = strdup(gt_names[mp->fd_fstype]);
+       new_mp->mnt_opts = strdup("unset");
+
+       new_mp->mnt_freq = 0;
+       new_mp->mnt_passno = mp->fd_dev;
+
+       return new_mp;
+}
+
+/*
+ * Read a mount table into memory
+ */
+mntlist *read_mtab(fs)
+char *fs;
+{
+       mntlist **mpp, *mhp;
+
+/* From: Piete Brooks <pb@cl.cam.ac.uk> */
+
+       int loc=0;
+#undef NMOUNT
+#define        NMOUNT  20
+       struct fs_data mountbuffer[NMOUNT], *fs_data;
+       int ret;
+
+       mpp = &mhp;
+       while ((ret = getmountent(&loc, mountbuffer, NMOUNT)) > 0) {
+               for (fs_data = mountbuffer; fs_data < &mountbuffer[ret]; fs_data++) {
+                       /*
+                        * Allocate a new slot
+                        */
+                       *mpp = ALLOC(mntlist);
+
+                       /*
+                        * Copy the data returned by getmntent
+                        */
+                       (*mpp)->mnt = mnt_dup(fs_data);
+
+                       /*
+                        * Move to next pointer
+                        */
+                       mpp = &(*mpp)->mnext;
+               }
+       }
+       if (ret < 0) {
+               plog(XLOG_ERROR, "getmountent: %m");
+               return 0;
+       }
+       *mpp = 0;
+
+       return mhp;
+}
+
+#endif /* READ_MTAB_ULTRIX_STYLE */
diff --git a/usr/src/usr.sbin/amd/config/newvers.sh b/usr/src/usr.sbin/amd/config/newvers.sh
new file mode 100644 (file)
index 0000000..7be0dc1
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/sh -
+#
+# $Id: newvers.sh,v 5.2 90/06/23 22:21:21 jsp Rel $
+#
+# 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.
+# All Rights Reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Jan-Simon Pendry at Imperial College, London.
+#
+# %sccs.include.redist.sh%
+#
+#      @(#)newvers.sh  5.1 (Berkeley) %G%
+#
+PATH=/usr/ucb:/bin:/usr/bin
+if [ $# -ne 1 ]; then echo "Usage: newvers program" >&2; exit 1; fi
+version="version.$1"
+if [ ! -r $version ]; then echo 0 > $version; chmod 444 $version; fi
+v=`cat $version`
+u=${USER-${LOGNAME-root}}
+h=`hostname`
+#h=`expr "$h" : '\([^.]*\)'`
+t=`date`
+r=`cat ../config/RELEASE`
+c=`sed 's/$/\\\\n\\\\/' ../text/COPYRIGHT`
+if [ -z "$r" -o -z "$c" ]; then
+       echo ERROR: config file missing >&2
+       exit 1
+fi
+rm -f vers.$1.c
+cat > vers.$1.c << %%
+char version[] = "\\
+${c}
+$1 ${r} #${v}: ${t}\\n\\
+Built by ${u}@${h}";
+%%
+rm -f $version
+/bin/echo `expr ${v} + 1` > $version
+chmod 444 $version
diff --git a/usr/src/usr.sbin/amd/config/os-acis43.h b/usr/src/usr.sbin/amd/config/os-acis43.h
new file mode 100644 (file)
index 0000000..2f50adf
--- /dev/null
@@ -0,0 +1,47 @@
+/* $Id: os-acis43.h,v 5.2 90/06/23 22:20:32 jsp Rel $ */
+
+/*
+ * IBM RT ACIS4.3 definitions for Amd (automounter)
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)os-acis43.h 5.1 (Berkeley) %G%
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#define        VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        NFS_3
+
+/*
+ * Does this OS have NDBM support?
+ */
+#define OS_HAS_NDBM
+
+/*
+ * Name of filesystem types
+ */
+#define        MOUNT_TYPE_NFS  MOUNT_NFS
+#define        MOUNT_TYPE_UFS  MOUNT_UFS
diff --git a/usr/src/usr.sbin/amd/config/os-aix3.h b/usr/src/usr.sbin/amd/config/os-aix3.h
new file mode 100644 (file)
index 0000000..92f1389
--- /dev/null
@@ -0,0 +1,154 @@
+/* $Id: os-aix3.h,v 5.2 90/06/23 22:20:33 jsp Rel $ */
+
+/*
+ * AIX 3.1 definitions for Amd (automounter)
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)os-aix3.h   5.1 (Berkeley) %G%
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#define        VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        RPC_4
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        NFS_AIX3
+
+/*
+ * Does this OS have NDBM support?
+ */
+#define OS_HAS_NDBM
+
+/*
+ * The mount table is obtained from the kernel
+ */
+#undef UPDATE_MTAB
+
+/*
+ * Pick up BSD bits from include files
+ */
+#define        _BSD
+
+/*
+ * No mntent info on AIX 3
+ */
+#undef MNTENT_HDR
+#define        MNTENT_HDR <sys/mntctl.h>
+
+/*
+ * Name of filesystem types
+ */
+#define        MOUNT_TYPE_NFS  MNT_NFS
+#define        MOUNT_TYPE_UFS  MNT_JFS
+#undef MTAB_TYPE_UFS
+#define        MTAB_TYPE_UFS   "jfs"
+
+/*
+ * How to unmount filesystems
+ */
+#undef MOUNT_TRAP
+#define        MOUNT_TRAP(type, mnt, flag, mnt_data) \
+       aix3_mount(mnt->mnt_fsname, mnt->mnt_dir, flag, type, mnt_data, mnt->mnt_opts)
+#undef UNMOUNT_TRAP
+#define        UNMOUNT_TRAP(mnt)       uvmount(mnt->mnt_passno, 0)
+
+
+/*
+ * Byte ordering
+ */
+#ifndef BYTE_ORDER
+#include <sys/machine.h>
+#endif /* BYTE_ORDER */
+
+#undef ARCH_ENDIAN
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define ARCH_ENDIAN "little"
+#else
+#if BYTE_ORDER == BIG_ENDIAN
+#define ARCH_ENDIAN "big"
+#else
+XXX - Probably no hope of running Amd on this machine!
+#endif /* BIG */
+#endif /* LITTLE */
+
+/*
+ * Miscellaneous AIX 3 bits
+ */
+#define        NEED_MNTOPT_PARSER
+#define        SHORT_MOUNT_NAME
+
+#define        MNTMAXSTR       128
+
+#define        MNTTYPE_UFS     "jfs"           /* Un*x file system */
+#define        MNTTYPE_NFS     "nfs"           /* network file system */
+#define        MNTTYPE_IGNORE  "ignore"        /* No type specified, ignore this entry */
+
+struct mntent {
+       char    *mnt_fsname;    /* name of mounted file system */
+       char    *mnt_dir;       /* file system path prefix */
+       char    *mnt_type;      /* MNTTYPE_* */
+       char    *mnt_opts;      /* MNTOPT* */
+       int     mnt_freq;       /* dump frequency, in days */
+       int     mnt_passno;     /* pass number on parallel fsck */
+};
+
+#define        NFS_HDR "misc-aix3.h"
+#define        UFS_HDR "misc-aix3.h"
+#undef NFS_FH_DREF
+#define        NFS_FH_DREF(dst, src) { (dst).addr = *(src); }
+#undef NFS_SA_DREF
+#define        NFS_SA_DREF(dst, src) { (dst).addr = *(src); }
+#define        M_RDONLY MNT_READONLY
+
+/*
+ * How to get a mount list
+ */
+#undef READ_MTAB_FROM_FILE
+#define        READ_MTAB_AIX3_STYLE
+
+/*
+ * The data for the mount syscall needs the path in addition to the
+ * host name since that is the only source of information about the
+ * mounted filesystem.
+#define        NFS_ARGS_NEEDS_PATH
+ */
+
+#define        NFS_LOMAP       34
+#define        NFS_HIMAP       99
+#define NFS_ERROR_MAPPING \
+static nfs_errormap[] = {           0,75,77,99,99,99, \
+                       99,99,99,99,99,78,99,99,99,79, \
+                       99,99,70,99,35,36,37,38,39,40, \
+                       41,42,43,44,45,46,47,48,49,50, \
+                       51,52,53,54,55,56,57,58,60,61, \
+                       64,65,99,67,68,62,63,66,69,68, \
+                       99,99,99,71,99,99,99,99,99,99 \
+                       };
+
+#define        MOUNT_AIX3
+
+/*
+ * Need this too
+ */
+#include <time.h>
diff --git a/usr/src/usr.sbin/amd/config/os-aux.h b/usr/src/usr.sbin/amd/config/os-aux.h
new file mode 100644 (file)
index 0000000..eb11749
--- /dev/null
@@ -0,0 +1,96 @@
+/* $Id: os-aux.h,v 5.2 90/06/23 22:20:37 jsp Rel $ */
+
+/*
+ * A/UX macII definitions for Amd (automounter)
+ * Contributed by Julian Onions <jpo@cs.nott.ac.uk>
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)os-aux.h    5.1 (Berkeley) %G%
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#define        VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        NFS_3
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#define        ARCH_ENDIAN     "big"
+
+/*
+ * Has support for syslog()
+ */
+#define HAS_SYSLOG
+
+/*
+ * No support for ndbm
+ */
+#undef OS_HAS_NDBM
+
+/*
+ * Name of filesystem types
+ */
+#define        MOUNT_TYPE_UFS  MOUNT_UFS
+#define MOUNT_TYPE_NFS MOUNT_NFS
+
+#undef MTAB_TYPE_UFS
+#define        MTAB_TYPE_UFS   "5.2"
+
+#define SIGCHLD        SIGCLD
+#define        SYS5_SIGNALS
+
+/*
+ * Use <fcntl.h> rather than <sys/file.h>
+ */
+#define USE_FCNTL
+
+/*
+ * Use fcntl() rather than flock()
+ */
+#define LOCK_FCNTL
+
+#ifdef __GNUC__
+#define alloca(sz) __builtin_alloca(sz)
+#endif
+
+#define        bzero(ptr, len) memset(ptr, 0, len)
+#define bcopy(from, to, len) memcpy(to, from, len)
+#define getpagesize() (2048)
+#undef MOUNT_TRAP
+#define MOUNT_TRAP(type, mnt, flags, mnt_data) \
+       fsmount(type, mnt->mnt_dir, flags, mnt_data)
+#undef UNMOUNT_TRAP
+#define        UNMOUNT_TRAP(mnt)       unmount(mnt->mnt_dir)
+#define NFDS   30      /* conservative */
+
+/* not included in sys/param.h */
+#include <sys/types.h>
+/* not part of sys/time.h */
+#include <time.h>
+/* for NMOUNT */
+#include <sys/config.h>
diff --git a/usr/src/usr.sbin/amd/config/os-bsd44.h b/usr/src/usr.sbin/amd/config/os-bsd44.h
new file mode 100644 (file)
index 0000000..e062962
--- /dev/null
@@ -0,0 +1,147 @@
+/* $Id: os-bsd44.h,v 5.2 90/06/23 22:20:38 jsp Rel $ */
+
+/*
+ * 4.4 BSD definitions for Amd (automounter)
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)os-bsd44.h  5.1 (Berkeley) %G%
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#define        VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        NFS_44
+#define HAS_TCP_NFS
+
+/*
+ * Does this OS have NDBM support?
+ */
+#define OS_HAS_NDBM
+
+/*
+ * The mount table is obtained from the kernel
+ */
+#undef UPDATE_MTAB
+
+/*
+ * No mntent info on 4.4 BSD
+ */
+#undef MNTENT_HDR
+
+/*
+ * Name of filesystem types
+ */
+#define        MOUNT_TYPE_NFS  MOUNT_NFS
+#define        MOUNT_TYPE_UFS  MOUNT_UFS
+#undef MTAB_TYPE_UFS
+#define        MTAB_TYPE_UFS   "ufs"
+#define        MTAB_TYPE_MFS   "mfs"
+
+/*
+ * How to unmount filesystems
+ */
+#undef UNMOUNT_TRAP
+#undef NEED_UMOUNT_FS
+#define        NEED_UMOUNT_BSD
+
+/*
+ * How to copy an address into an NFS filehandle
+ */
+#undef NFS_SA_DREF
+#define        NFS_SA_DREF(dst, src) { \
+               (dst).addr = (struct sockaddr *) (src); \
+               (dst).sotype = SOCK_DGRAM; \
+               (dst).proto = 0; \
+       }
+
+/*
+ * Byte ordering
+ */
+#ifndef BYTE_ORDER
+#include <machine/endian.h>
+#endif /* BYTE_ORDER */
+
+#undef ARCH_ENDIAN
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define ARCH_ENDIAN "little"
+#else
+#if BYTE_ORDER == BIG_ENDIAN
+#define ARCH_ENDIAN "big"
+#else
+XXX - Probably no hope of running Amd on this machine!
+#endif /* BIG */
+#endif /* LITTLE */
+
+/*
+ * Miscellaneous 4.4 BSD bits
+ */
+#define MISC_RPC
+#define        NEED_MNTOPT_PARSER
+#define        SHORT_MOUNT_NAME
+
+#define        MNTMAXSTR       128
+
+#define        MNTTYPE_UFS     "ufs"           /* Un*x file system */
+#define        MNTTYPE_NFS     "nfs"           /* network file system */
+#define        MNTTYPE_MFS     "mfs"           /* memory file system */
+#define        MNTTYPE_IGNORE  "ignore"        /* No type specified, ignore this entry */
+
+#define        M_RDONLY        MNT_RDONLY
+#define        M_SYNC          MNT_SYNCHRONOUS
+#define        M_NOEXEC        MNT_NOEXEC
+#define        M_NOSUID        MNT_NOSUID
+#define        M_NODEV         MNT_NODEV
+
+#define        MNTOPT_SOFT     "soft"          /* soft mount */
+#define        MNTOPT_INTR     "intr"          /* interrupts allowed */
+
+struct mntent {
+       char    *mnt_fsname;    /* name of mounted file system */
+       char    *mnt_dir;       /* file system path prefix */
+       char    *mnt_type;      /* MNTTYPE_* */
+       char    *mnt_opts;      /* MNTOPT* */
+       int     mnt_freq;       /* dump frequency, in days */
+       int     mnt_passno;     /* pass number on parallel fsck */
+};
+
+/*
+ * Type of a file handle
+ */
+#undef NFS_FH_TYPE
+#define        NFS_FH_TYPE     nfsv2fh_t *
+
+/*
+ * How to get a mount list
+ */
+#undef READ_MTAB_FROM_FILE
+#define        READ_MTAB_BSD_STYLE
+
+/*
+ * The data for the mount syscall needs the path in addition to the
+ * host name since that is the only source of information about the
+ * mounted filesystem.
+ */
+#define        NFS_ARGS_NEEDS_PATH
diff --git a/usr/src/usr.sbin/amd/config/os-concentrix.h b/usr/src/usr.sbin/amd/config/os-concentrix.h
new file mode 100644 (file)
index 0000000..8001e50
--- /dev/null
@@ -0,0 +1,53 @@
+/* $Id: os-concentrix.h,v 5.2 90/06/23 22:20:41 jsp Rel $ */
+
+/*
+ * Alliant Concentrix 5.0.0 definitions for Amd (automounter)
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)os-concentrix.h     5.1 (Berkeley) %G%
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#undef VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        NFS_3
+
+/*
+ * Does this OS have NDBM support?
+ */
+#define OS_HAS_NDBM
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#define        ARCH_ENDIAN     "big"
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_NFS MOUNT_NFS
+#define MOUNT_TYPE_UFS MOUNT_UFS
diff --git a/usr/src/usr.sbin/amd/config/os-convex.h b/usr/src/usr.sbin/amd/config/os-convex.h
new file mode 100644 (file)
index 0000000..662b810
--- /dev/null
@@ -0,0 +1,54 @@
+/* $Id: os-convex.h,v 5.2 90/06/23 22:20:42 jsp Rel $ */
+
+/*
+ * Convex C220, version 7.1 definitions for Amd (automounter)
+ *         from Eitan Mizrotsky <eitan@shum.huji.ac.il>
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)os-convex.h 5.1 (Berkeley) %G%
+ */
+
+
+/*
+ * Does the compiler grok void *
+ */
+#undef VOIDP
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        RPC_3
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        NFS_3
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#define        ARCH_ENDIAN     "big"
+/*
+ * Name of filesystem types
+ */
+#define        MOUNT_TYPE_UFS  MOUNT_UFS
+#define MOUNT_TYPE_NFS MOUNT_NFS
+#define strrchr rindex
+#define strchr  index
diff --git a/usr/src/usr.sbin/amd/config/os-defaults.h b/usr/src/usr.sbin/amd/config/os-defaults.h
new file mode 100644 (file)
index 0000000..557ef59
--- /dev/null
@@ -0,0 +1,102 @@
+/* $Id: os-defaults.h,v 5.2 90/06/23 22:20:44 jsp Rel $ */
+
+/*
+ * Common OS definitions.  These may be overridden in
+ * the OS specific files ("os-foo.h").
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)os-defaults.h       5.1 (Berkeley) %G%
+ */
+
+/*
+ * What level of AMD are we backward compatible with?
+ * This only applies to externally visible characteristics.
+ * Rev.Minor.Branch.Patch (2 digits each)
+ */
+#define        AMD_COMPAT      5000000         /* 5.0 */
+
+/*
+ * What type is free(void*) returning?
+ */
+#define FREE_RETURN_TYPE       void
+
+/*
+ * Is the mount table mirrored in software
+ */
+#define        UPDATE_MTAB
+
+/*
+ * Where to get union wait
+ */
+#define        WAIT    <sys/wait.h>
+
+/*
+ * Where to get mount entry info
+ */
+#define        MNTENT_HDR      <mntent.h>
+
+/*
+ * Include support for syslog()
+ */
+#define        HAS_SYSLOG
+
+/*
+ * Byte ordering
+ */
+#define        ARCH_ENDIAN     "unknown"
+
+/*
+ * Name of filesystem types
+ */
+#define        MTAB_TYPE_NFS   "nfs"
+#define        MTAB_TYPE_UFS   "4.2"
+
+/*
+ * Name of mount & unmount system calls
+ *
+ * NOTE:
+ *  UNMOUNT_TRAP takes a struct mntent *
+ */
+#define        MOUNT_TRAP(type, mnt, flags, mnt_data) \
+       mount(type, mnt->mnt_dir, flags, mnt_data)
+#define        UNMOUNT_TRAP(mnt)       unmount(mnt->mnt_dir)
+
+/*
+ * How to unmount filesystems.
+ * NEED_UMOUNT_FS includes code to scan the mount table
+ * to find the correct information for the unmount system
+ * call.  Some systems, such as 4.4bsd, do not require
+ * this - they can just do an unmount system call directly.
+ */
+#define        NEED_UMOUNT_FS
+#define        UMOUNT_FS(dir)  umount_fs(dir)
+
+/*
+ * Type of a file handle
+ */
+#define        NFS_FH_TYPE     fhandle_t *
+#define        NFS_FH_DREF(dst, src) { (dst) = (src); }
+
+/*
+ * How to copy an address into an NFS filehandle
+ */
+#define        NFS_SA_DREF(dst, src) { (dst).addr = (src); }
+
+/*
+ * Type of filesystem type
+ */
+#define        MTYPE_TYPE      int
+
+/*
+ * How to get a mount list
+ */
+#define        READ_MTAB_FROM_FILE
diff --git a/usr/src/usr.sbin/amd/config/os-fpx4.h b/usr/src/usr.sbin/amd/config/os-fpx4.h
new file mode 100644 (file)
index 0000000..480866e
--- /dev/null
@@ -0,0 +1,64 @@
+/* $Id: os-fpx4.h,v 5.2 90/06/23 22:20:45 jsp Rel $ */
+
+/*
+ * Celerity FPX 4.1/2 definitions for Amd (automounter)
+ *      from Stephen Pope <scp@grizzly.acl.lanl.gov>
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)os-fpx4.h   5.1 (Berkeley) %G%
+ */
+
+/*
+ * FPX wants to include sys headers multiple times
+ */
+#define INCLUDE_HEADERS
+
+/*
+ * FPX sys/mount.h includes sys/nfs.h; prevent this
+ */
+#define INCLUDED_nfs
+
+/*
+ * FPX doesn't define NMOUNT anywhere
+ */
+#define NMOUNT 40
+
+/*
+ * Does the compiler grok void *
+ */
+/* #define VOIDP */
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define NFS_3
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#define ARCH_ENDIAN     "big"
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_NFS MOUNT_NFS
+#define MOUNT_TYPE_UFS MOUNT_UFS
diff --git a/usr/src/usr.sbin/amd/config/os-hlh42.h b/usr/src/usr.sbin/amd/config/os-hlh42.h
new file mode 100644 (file)
index 0000000..1b415ed
--- /dev/null
@@ -0,0 +1,62 @@
+/* $Id: os-hlh42.h,v 5.2 90/06/23 22:20:46 jsp Rel $ */
+
+/*
+ * HLH OTS definitions for Amd (automounter)
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)os-hlh42.h  5.1 (Berkeley) %G%
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#undef VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        NFS_3
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#if defined(hlh)
+#define        ARCH_ENDIAN     "little"
+#endif
+
+/*
+ * Name of filesystem types
+ */
+#define        MOUNT_TYPE_NFS  MOUNT_NFS
+#define        MOUNT_TYPE_UFS  MOUNT_UFS
+
+/*
+ * Miscellaneous HLH 4.2 incantations
+ */
+#define        strchr  index
+#define strrchr        rindex
+#define sigmask(x)     (1 << ((x)-1))
+
+/*
+ * HLH's 4.2 needs the extra RPC definitions.
+ */
+#define MISC_RPC
diff --git a/usr/src/usr.sbin/amd/config/os-hpux.h b/usr/src/usr.sbin/amd/config/os-hpux.h
new file mode 100644 (file)
index 0000000..c2c455f
--- /dev/null
@@ -0,0 +1,114 @@
+/* $Id: os-hpux.h,v 5.2 90/06/23 22:20:47 jsp Rel $ */
+
+/*
+ * HP/9000 HP-UX definitions for Amd (automounter)
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)os-hpux.h   5.1 (Berkeley) %G%
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#ifdef __GNUC__
+#define        VOIDP
+#endif
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        NFS_3
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#if defined(hp9000s200) || defined(hp9000s300)
+#define        ARCH_ENDIAN     "big"
+#endif
+/*
+#if defined(hp9000s800)
+#define ARCH_ENDIAN    "unknown"
+#endif
+*/
+
+/*
+ * No support for syslog()
+ */
+#undef HAS_SYSLOG
+
+/*
+ * No support for ndbm
+ */
+#undef OS_HAS_NDBM
+
+/*
+ * Name of filesystem types
+ */
+#define        MOUNT_TYPE_UFS  MOUNT_UFS
+#define MOUNT_TYPE_NFS MOUNT_NFS
+#undef MTAB_TYPE_UFS
+#define        MTAB_TYPE_UFS   "hfs"
+
+/*
+ * Where to get NFS definitions
+ */
+#define        NFS_HDR "misc-hpux.h"
+
+/*
+ * Where to get union wait
+ */
+#undef WAIT
+#define        WAIT    "uwait.h"
+#ifndef SIGCHLD
+#define SIGCHLD        SIGCLD
+#endif
+#define        SYS5_SIGNALS
+
+/*
+ * Miscellaneous HP-UX definitions
+ */
+
+#define        MISC_RPC
+
+/*
+ * Use <fcntl.h> rather than <sys/file.h>
+ */
+#define USE_FCNTL
+
+/*
+ * Use fcntl() rather than flock()
+ */
+#define LOCK_FCNTL
+
+#ifdef __GNUC__
+#define alloca(sz) __builtin_alloca(sz)
+#endif
+#define        bzero(ptr, len) memset(ptr, 0, len)
+#define bcopy(from, to, len) memcpy(to, from, len)
+#define getpagesize() (2048)
+#undef MOUNT_TRAP
+#define MOUNT_TRAP(type, mnt, flags, mnt_data) \
+       vfsmount(type, mnt->mnt_dir, flags, mnt_data)
+#undef UNMOUNT_TRAP
+#define        UNMOUNT_TRAP(mnt)       umount(mnt->mnt_dir)
+#define NFDS   30      /* conservative */
+#define        MOUNTED MNT_MNTTAB
diff --git a/usr/src/usr.sbin/amd/config/os-pyrOSx.h b/usr/src/usr.sbin/amd/config/os-pyrOSx.h
new file mode 100644 (file)
index 0000000..4fba5e0
--- /dev/null
@@ -0,0 +1,53 @@
+/* $Id: os-pyrOSx.h,v 5.2 90/06/23 22:20:50 jsp Rel $ */
+
+/*
+ * Pyramid OSx definitions for Amd (automounter)
+ *             from Stefan Petri <petri@tubsibr.UUCP>
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)os-pyrOSx.h 5.1 (Berkeley) %G%
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#define        VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        NFS_3
+
+/*
+ * Byte ordering
+ */
+#define        ARCH_ENDIAN     "big"
+
+/*
+ * Name of filesystem types
+ */
+#define        MOUNT_TYPE_UFS  MOUNT_UFS
+#define MOUNT_TYPE_NFS MOUNT_NFS
+
+#define        strchr  index
+#define        strrchr rindex
+
+#define        hostname        mnthostname
diff --git a/usr/src/usr.sbin/amd/config/os-riscix.h b/usr/src/usr.sbin/amd/config/os-riscix.h
new file mode 100644 (file)
index 0000000..354b564
--- /dev/null
@@ -0,0 +1,62 @@
+/* $Id: os-riscix.h,v 5.2 90/06/23 22:20:51 jsp Rel $ */
+
+/*
+ * Acorn Archimedes RISC iX definitions for Amd (automounter)
+ * Contributed by Piete Brooks.
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)os-riscix.h 5.1 (Berkeley) %G%
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#define        VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        NFS_3
+
+/*
+ * Does this OS have NDBM support?
+ */
+#define OS_HAS_NDBM
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#define        ARCH_ENDIAN "little"
+
+/*
+ * Is the mount table mirrored in software
+ */
+#define        UPDATE_MTAB
+
+/*
+ * Name of filesystem types
+ */
+#define        MOUNT_TYPE_NFS  MOUNT_NFS
+#define        MOUNT_TYPE_UFS  MOUNT_UFS
+
+#undef MTAB_TYPE_UFS
+#define        MTAB_TYPE_UFS   MNTTYPE_43
diff --git a/usr/src/usr.sbin/amd/config/os-sos3.h b/usr/src/usr.sbin/amd/config/os-sos3.h
new file mode 100644 (file)
index 0000000..02f704b
--- /dev/null
@@ -0,0 +1,53 @@
+/* $Id: os-sos3.h,v 5.2 90/06/23 22:20:51 jsp Rel $ */
+
+/*
+ * SunOS 3.2 definitions for Amd (automounter)
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)os-sos3.h   5.1 (Berkeley) %G%
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#define        VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        NFS_3
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#if defined(mc68010) || defined(mc68020) || defined(sparc)
+#define        ARCH_ENDIAN     "big"
+#endif
+#if defined(i386)
+#define ARCH_ENDIAN    "little"
+#endif
+
+/*
+ * Name of filesystem types
+ */
+#define        MOUNT_TYPE_UFS  MOUNT_UFS
+#define MOUNT_TYPE_NFS MOUNT_NFS
diff --git a/usr/src/usr.sbin/amd/config/os-sos4.h b/usr/src/usr.sbin/amd/config/os-sos4.h
new file mode 100644 (file)
index 0000000..42a4a40
--- /dev/null
@@ -0,0 +1,81 @@
+/* $Id: os-sos4.h,v 5.2 90/06/23 22:20:52 jsp Rel $ */
+
+/*
+ * SunOS 4.0 definitions for Amd (automounter)
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)os-sos4.h   5.1 (Berkeley) %G%
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#define        VOIDP
+
+/*
+ * What type is free(void*) returning?
+ */
+#undef FREE_RETURN_TYPE
+#define FREE_RETURN_TYPE       int
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        RPC_4
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        NFS_4
+
+/*
+ * Does this OS have NDBM support?
+ */
+#define OS_HAS_NDBM
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#if defined(mc68010) || defined(mc68020) || defined(sparc)
+#define        ARCH_ENDIAN     "big"
+#endif
+#if defined(i386)
+#define ARCH_ENDIAN    "little"
+#endif
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_NFS "nfs"
+#define MOUNT_TYPE_UFS "4.2"
+
+/*
+ * Type of a file handle
+ */
+#undef NFS_FH_TYPE
+#define        NFS_FH_TYPE     caddr_t
+
+/*
+ * Type of filesystem type
+ */
+#undef MTYPE_TYPE
+#define        MTYPE_TYPE      char *
+
+/*
+ * Add support for SunOS 4 automounter files
+ */
+#define        SUNOS4_COMPAT
diff --git a/usr/src/usr.sbin/amd/config/os-type b/usr/src/usr.sbin/amd/config/os-type
new file mode 100644 (file)
index 0000000..012017e
--- /dev/null
@@ -0,0 +1,87 @@
+#!/bin/sh
+#
+# $Id: os-type,v 5.2 90/06/23 22:21:23 jsp Rel $
+#
+# 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.
+# All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Jan-Simon Pendry at Imperial College, London.
+#
+# %sccs.include.redist.sh%
+#
+#      @(#)os-type     5.1 (Berkeley) %G%
+#
+
+#
+# Take a pot-shot at your os type
+#
+echo " ... No OS= option specified; dynamically determining OS type" >&2
+
+#
+# First try poking around in /etc/motd
+#
+
+case "`exec 2>/dev/null; head -2 /etc/motd`" in
+*"Sun UNIX 4.2 Release 3."*)   OS=sos3;;
+*"SunOS Release 4."*)          OS=sos4;;
+*"HP-UX on the HP"*)           OS=hpux;;
+*"Ultrix V2."*)                        OS=u2_2;;
+*"Ultrix-32 V3."*)             OS=u3_0;;
+*"Ultrix Worksystem V2.0"*)    OS=u3_0;;
+*"HLH OTS Version 1."*)                OS=hlh42;;
+*"RISC iX release 1."*)                OS=riscix;;
+*"FPX 4."*)                    OS=fpx4;;
+*"4.4 BSD UNIX"*)              OS=bsd44;;
+*"4.3 BSD UNIX"*)              if [ -f /etc/minidisk ]; then
+                                       OS=acis43
+                               elif [ -f /sbin/nfsiod ]; then
+                                       OS=bsd44        # prototype
+                               else
+                                       OS=xinu43
+                               fi;;
+*"Alliant Concentrix"*)                OS=concentrix;;
+*"Umax 4.3"*)                  OS=umax43;;
+*)
+#
+# Well, that didn't work so apply some heuristics
+# to the filesystem name space...
+#
+                               echo "  ... inspecting File system ..." >&2
+                               if [ -f /usr/bin/cat ]; then
+                                       OS=sos4
+                               elif [ -f /etc/nd ]; then
+                                       OS=sos3
+                               elif [ -f /etc/elcsd ]; then
+                                       echo "  ... Ultrix - assuming U3.0 ..." >&2
+                                       OS=u3_0
+                               elif [ -f /hp-ux ]; then
+                                       OS=hpux
+                               elif [ -f /etc/ttylocal ]; then
+                                       OS=xinu43
+                               elif [ -f /etc/minidisk ]; then
+                                       OS=acis43
+                               elif [ -f /etc/toolboxdaemon ]; then
+                                       OS=aux
+                               elif [ -f /sbin/nfsiod ]; then
+                                       OS=bsd44
+                               elif [ -d /vrm ]; then
+                                       OS=aix2
+                               elif [ -d /etc/aix ]; then
+                                       OS=aix3
+                               elif [ -f /bin/pyr ] && /bin/pyr; then
+                                       OS=pyrOSx
+                               else
+                                       case "`(sh arch)2>/dev/null`" in
+                                       powernode) OS=utx32;;
+                                       ibm032)    OS=acis43;;
+                                       *)         OS=unknown;;
+                                       esac
+                               fi;;
+esac
+
+echo " ... OS appears to be \"${OS}\"" >&2
+echo "${OS}"
+exit 0
diff --git a/usr/src/usr.sbin/amd/config/os-u2_2.h b/usr/src/usr.sbin/amd/config/os-u2_2.h
new file mode 100644 (file)
index 0000000..d43e5d8
--- /dev/null
@@ -0,0 +1,134 @@
+/* $Id: os-u2_2.h,v 5.2 90/06/23 22:20:55 jsp Rel $ */
+
+/*
+ * Ultrix 2.2 definitions for Amd (automounter)
+ *
+ * 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.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)os-u2_2.h   5.1 (Berkeley) %G%
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#undef VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        NFS_3
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#if defined(vax)
+#define        ARCH_ENDIAN "little"
+#endif
+
+/*
+ * The mount table is obtained from the kernel
+ */
+#undef UPDATE_MTAB
+
+/*
+ * No mntent info on Ultrix
+  */
+#undef MNTENT_HDR
+
+/*
+ * No support for syslog()
+ */
+#undef HAS_SYSLOG
+
+/*
+ * No support for ndbm
+ */
+#undef HAS_NDBM_MAPS
+
+/*
+ * Name of filesystem types
+ */
+#define        MOUNT_TYPE_NFS  GT_NFS
+#define        MOUNT_TYPE_UFS  GT_ULTRIX
+#undef MTAB_TYPE_UFS
+#define        MTAB_TYPE_UFS   "ufs"
+
+/*
+ * Name of mount & unmount system calls
+ */
+#undef MOUNT_TRAP
+#define        MOUNT_TRAP(type, mnt, flag, mnt_data) \
+       mount(mnt->mnt_fsname, mnt->mnt_dir, flag, type, mnt_data)
+#undef UNMOUNT_TRAP
+#define        UNMOUNT_TRAP(mnt)       umount(mnt->mnt_passno)
+
+/*
+ * Miscellaneous Ultrix bits
+ */
+#define        M_RDONLY        M_RONLY
+
+#ifndef MNTMAXSTR
+#define        MNTMAXSTR       128
+#endif
+
+#define        MNTTYPE_UFS     "ufs"           /* Un*x file system */
+#define        MNTTYPE_NFS     "nfs"           /* network file system */
+#define        MNTTYPE_IGNORE  "ignore"        /* No type specified, ignore this entry */
+
+#define        MNTOPT_RO       "ro"            /* read only */
+#define        MNTOPT_RW       "rw"            /* read/write */
+#define        MNTOPT_QUOTA    "quota"         /* quotas */
+#define        MNTOPT_NOQUOTA  "noquota"       /* no quotas */
+#define        MNTOPT_HARD     "hard"          /* hard mount */
+#define        MNTOPT_SOFT     "soft"          /* soft mount */
+#define        MNTOPT_INTR     "intr"          /* interrupts allowed */
+
+#define        MNTOPT_NOSUID   "nosuid"        /* no set uid allowed */
+
+struct mntent {
+       char    *mnt_fsname;    /* name of mounted file system */
+       char    *mnt_dir;       /* file system path prefix */
+       char    *mnt_type;      /* MNTTYPE_* */
+       char    *mnt_opts;      /* MNTOPT* */
+       int     mnt_freq;       /* dump frequency, in days */
+       int     mnt_passno;     /* pass number on parallel fsck */
+};
+#define        MOUNTED         "/etc/mtab"
+
+#define        NFS_HDR "misc-ultrix.h"
+#define        UFS_HDR "misc-ultrix.h"
+
+#define        MISC_RPC
+
+#define        nfs_args        nfs_gfs_mount
+#define        ULTRIX_HACK     /* Should be handled better than this !! */
+#define        NEED_MNTOPT_PARSER
+
+/*
+ * How to get a mount list
+ */
+#undef READ_MTAB_FROM_FILE
+#define        READ_MTAB_ULTRIX_STYLE
+
+/*
+ * Need precise length links
+ */
+#define        PRECISE_SYMLINKS
diff --git a/usr/src/usr.sbin/amd/config/os-u3_0.h b/usr/src/usr.sbin/amd/config/os-u3_0.h
new file mode 100644 (file)
index 0000000..5f8626a
--- /dev/null
@@ -0,0 +1,127 @@
+/* $Id: os-u3_0.h,v 5.2 90/06/23 22:20:58 jsp Rel $ */
+
+/*
+ * Ultrix 3.0 definitions for Amd (automounter)
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)os-u3_0.h   5.1 (Berkeley) %G%
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#undef VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        NFS_3
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#if defined(vax) || defined(mips)
+#define        ARCH_ENDIAN "little"
+#endif
+
+/*
+ * The mount table is obtained from the kernel
+ */
+#undef UPDATE_MTAB
+
+/*
+ * No mntent info on Ultrix
+  */
+#undef MNTENT_HDR
+
+/*
+ * No support for syslog()
+ */
+#undef HAS_SYSLOG
+
+/*
+ * Name of filesystem types
+ */
+#define        MOUNT_TYPE_NFS  GT_NFS
+#define        MOUNT_TYPE_UFS  GT_ULTRIX
+#undef MTAB_TYPE_UFS
+#define        MTAB_TYPE_UFS   "ufs"
+
+/*
+ * Name of mount & unmount system calls
+ */
+#undef MOUNT_TRAP
+#define        MOUNT_TRAP(type, mnt, flag, mnt_data) \
+       mount(mnt->mnt_fsname, mnt->mnt_dir, flag, type, mnt_data)
+#undef UNMOUNT_TRAP
+#define        UNMOUNT_TRAP(mnt)       umount(mnt->mnt_passno)
+
+/*
+ * Miscellaneous Ultrix bits
+ */
+#define        M_RDONLY        M_RONLY
+
+#define        MNTMAXSTR       128
+
+#define        MNTTYPE_UFS     "ufs"           /* Un*x file system */
+#define        MNTTYPE_NFS     "nfs"           /* network file system */
+#define        MNTTYPE_IGNORE  "ignore"        /* No type specified, ignore this entry */
+
+#define        MNTOPT_RO       "ro"            /* read only */
+#define        MNTOPT_RW       "rw"            /* read/write */
+#define        MNTOPT_QUOTA    "quota"         /* quotas */
+#define        MNTOPT_NOQUOTA  "noquota"       /* no quotas */
+#define        MNTOPT_HARD     "hard"          /* hard mount */
+#define        MNTOPT_SOFT     "soft"          /* soft mount */
+#define        MNTOPT_INTR     "intr"          /* interrupts allowed */
+
+#define        MNTOPT_NOSUID   "nosuid"        /* no set uid allowed */
+
+struct mntent {
+       char    *mnt_fsname;    /* name of mounted file system */
+       char    *mnt_dir;       /* file system path prefix */
+       char    *mnt_type;      /* MNTTYPE_* */
+       char    *mnt_opts;      /* MNTOPT* */
+       int     mnt_freq;       /* dump frequency, in days */
+       int     mnt_passno;     /* pass number on parallel fsck */
+};
+#define        MOUNTED         "/etc/mtab"
+
+#define        NFS_HDR "misc-ultrix.h"
+#define        UFS_HDR "misc-ultrix.h"
+
+#define        MISC_RPC
+
+#define        nfs_args        nfs_gfs_mount
+#define        ULTRIX_HACK     /* Should be handled better than this !! */
+#define        NEED_MNTOPT_PARSER
+
+/*
+ * How to get a mount list
+ */
+#undef READ_MTAB_FROM_FILE
+#define        READ_MTAB_ULTRIX_STYLE
+
+/*
+ * Need precise length links
+ */
+#define        PRECISE_SYMLINKS
diff --git a/usr/src/usr.sbin/amd/config/os-umax43.h b/usr/src/usr.sbin/amd/config/os-umax43.h
new file mode 100644 (file)
index 0000000..b4a6ffc
--- /dev/null
@@ -0,0 +1,53 @@
+/* $Id: os-umax43.h,v 5.2 90/06/23 22:20:59 jsp Rel $ */
+
+/*
+ * UMAX 4.3 definitions for Amd (automounter)
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)os-umax43.h 5.1 (Berkeley) %G%
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#define        VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        RPC_4
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        NFS_3
+
+/*
+ * Does this OS have NDBM support?
+ */
+#define OS_HAS_NDBM
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#define ARCH_ENDIAN    "little"
+
+/*
+ * Name of filesystem types
+ */
+#define MOUNT_TYPE_NFS MOUNT_NFS
+#define MOUNT_TYPE_UFS MOUNT_UFS
diff --git a/usr/src/usr.sbin/amd/config/os-utx32.h b/usr/src/usr.sbin/amd/config/os-utx32.h
new file mode 100644 (file)
index 0000000..aaaf7a0
--- /dev/null
@@ -0,0 +1,59 @@
+/* $Id: os-utx32.h,v 5.2 90/06/23 22:21:00 jsp Rel $ */
+
+/*
+ * Gould UTX/32 definitions for Amd (automounter)
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)os-utx32.h  5.1 (Berkeley) %G%
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#ifdef __GNUC__
+#define        VOIDP
+#endif
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        RPC_3
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        NFS_3
+
+/*
+ * Does this OS have NDBM support?
+ */
+#define OS_HAS_NDBM
+
+/*
+ * Byte ordering
+ */
+#undef ARCH_ENDIAN
+#if defined(gould) || defined(GOULD_PN)
+#define        ARCH_ENDIAN     "big"
+#endif
+
+/*
+ * Name of filesystem types
+ */
+#define        MOUNT_TYPE_NFS  MOUNT_NFS
+#define        MOUNT_TYPE_UFS  MOUNT_UFS
+#undef MTAB_TYPE_UFS
+#define        MTAB_TYPE_UFS   "4.3"
diff --git a/usr/src/usr.sbin/amd/config/os-xinu43.h b/usr/src/usr.sbin/amd/config/os-xinu43.h
new file mode 100644 (file)
index 0000000..819555b
--- /dev/null
@@ -0,0 +1,84 @@
+/* $Id: os-xinu43.h,v 5.2 90/06/23 22:21:01 jsp Rel $ */
+
+/*
+ * mt Xinu 4.3 (MORE/bsd) definitions for Amd (automounter)
+ * Should work on both Vax and HP ...
+ *
+ * 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.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)os-xinu43.h 5.1 (Berkeley) %G%
+ */
+
+/*
+ * Does the compiler grok void *
+ */
+#define        VOIDP
+
+/*
+ * Which version of the Sun RPC library we are using
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        RPC_4
+
+/*
+ * mt Xinu have a compatibility problem
+ * with getreq vs. getreqset.  On SunOS
+ * getreqset takes a pointer to an fd_set,
+ * whereas on MORE/bsd, getreq takes a
+ * fd_set directly (cf. an integer on SunOS).
+ */
+#define        svc_getreqset(p)        svc_getreq(*p)
+
+/*
+ * Which version of the NFS interface are we using.
+ * This is the implementation release number, not
+ * the protocol revision number.
+ */
+#define        NFS_4
+
+/*
+ * Name of filesystem types
+ */
+#define        MOUNT_TYPE_NFS  "nfs"
+#define        MOUNT_TYPE_UFS  "ufs"
+#undef MTAB_TYPE_UFS
+#define        MTAB_TYPE_UFS   "ufs"
+
+/*
+ * Byte ordering
+ */
+#ifndef BYTE_ORDER
+#include <machine/endian.h>
+#endif /* BYTE_ORDER */
+
+#undef ARCH_ENDIAN
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define ARCH_ENDIAN "little"
+#else
+#if BYTE_ORDER == BIG_ENDIAN
+#define ARCH_ENDIAN "big"
+#else
+XXX - Probably no hope of running Amd on this machine!
+#endif /* BIG */
+#endif /* LITTLE */
+
+/*
+ * Type of a file handle
+ */
+#undef NFS_FH_TYPE
+#define NFS_FH_TYPE     caddr_t
+
+/*
+ * Type of filesystem type
+ */
+#undef MTYPE_TYPE
+#define        MTYPE_TYPE      char *
diff --git a/usr/src/usr.sbin/amd/text/amd.start.ex b/usr/src/usr.sbin/amd/text/amd.start.ex
new file mode 100644 (file)
index 0000000..f1d8925
--- /dev/null
@@ -0,0 +1,61 @@
+#!/bin/sh -
+#
+# Start amd
+#
+# $Id: amd.start.ex,v 5.2 90/06/23 22:21:29 jsp Rel $
+#
+# 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.
+# All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Jan-Simon Pendry at Imperial College, London.
+#
+# %sccs.include.redist.sh%
+#
+#      @(#)amd.start.ex        5.1 (Berkeley) %G%
+#
+PATH=/usr/local/etc:/bin:/usr/bin:/usr/ucb:$PATH export PATH
+
+#
+# Either name of logfile or "syslog"
+#
+#LOGFILE=syslog
+LOGFILE=/var/adm/am.log
+
+#
+# Figure out whether domain name is in host name
+# If the hostname is just the machine name then
+# pass in the name of the local domain so that the
+# hostnames in the map are domain stripped correctly.
+#
+case `hostname` in
+*.*) dmn= ;;
+*) dmn='-d doc.ic.ac.uk'
+esac
+
+#
+# Zap earlier log file
+#
+case "$LOGFILE" in
+*/*)
+       mv "$LOGFILE" "$LOGFILE"-
+       > "$LOGFILE"
+       ;;
+syslog)
+       : nothing
+       ;;
+esac
+
+cd /usr/local/etc
+#
+# -r           restart
+# -d dmn       local domain
+# -w wait      wait between unmount attempts
+# -l log       logfile or "syslog"
+#
+eval nice --4 ./amd -p > /etc/amd.pid -r $dmn -w 240 -l "$LOGFILE" \
+       /homes amd.homes -cache=inc \
+       /home amd.home -cache=inc \
+       /vol amd.vol -cache=inc