diff options
author | obrien <obrien@FreeBSD.org> | 1998-08-23 22:07:21 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 1998-08-23 22:07:21 +0000 |
commit | 663d5a0f32ed8dfc091ffb6153161591ac6ba563 (patch) | |
tree | 60b090a6cbdb64326bb128ea49a231d08eb2680e /contrib/amd/amd | |
download | FreeBSD-src-663d5a0f32ed8dfc091ffb6153161591ac6ba563.zip FreeBSD-src-663d5a0f32ed8dfc091ffb6153161591ac6ba563.tar.gz |
Virgin import of AMD (am-utils) v6.0a16
Diffstat (limited to 'contrib/amd/amd')
62 files changed, 22623 insertions, 0 deletions
diff --git a/contrib/amd/amd/am_ops.c b/contrib/amd/amd/am_ops.c new file mode 100644 index 0000000..918c3f1 --- /dev/null +++ b/contrib/amd/amd/am_ops.c @@ -0,0 +1,441 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: am_ops.c,v 5.2.2.1 1992/02/09 15:08:17 jsp beta $ + * + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + + +/* + * The order of these entries matters, since lookups in this table are done + * on a first-match basis. The entries below are a mixture of native + * filesystems supported by the OS (HAVE_FS_FOO), and some meta-filesystems + * supported by amd (HAVE_AM_FS_FOO). The order is set here in expected + * match-hit such that more popular filesystems are listed first (nfs is the + * most popular, followed by a symlink F/S) + */ +static am_ops *vops[] = +{ +#ifdef HAVE_FS_NFS + &nfs_ops, /* network F/S (version 2) */ +#endif /* HAVE_FS_NFS */ +#ifdef HAVE_AM_FS_LINK + &amfs_link_ops, /* symlink F/S */ +#endif /* HAVE_AM_FS_LINK */ + + /* + * Other amd-supported meta-filesystems. + */ +#ifdef HAVE_AM_FS_NFSX + &amfs_nfsx_ops, /* multiple-nfs F/S */ +#endif /* HAVE_AM_FS_NFSX */ +#ifdef HAVE_AM_FS_NFSL + &amfs_nfsl_ops, /* NFS with local link existence check */ +#endif /* HAVE_AM_FS_NFSL */ +#ifdef HAVE_AM_FS_HOST + &amfs_host_ops, /* multiple exported nfs F/S */ +#endif /* HAVE_AM_FS_HOST */ +#ifdef HAVE_AM_FS_LINKX + &amfs_linkx_ops, /* symlink F/S with link target verify */ +#endif /* HAVE_AM_FS_LINKX */ +#ifdef HAVE_AM_FS_PROGRAM + &amfs_program_ops, /* program F/S */ +#endif /* HAVE_AM_FS_PROGRAM */ +#ifdef HAVE_AM_FS_UNION + &amfs_union_ops, /* union F/S */ +#endif /* HAVE_AM_FS_UNION */ +#ifdef HAVE_AM_FS_INHERIT + &amfs_inherit_ops, /* inheritance F/S */ +#endif /* HAVE_AM_FS_INHERIT */ + + /* + * A few more native filesystems. + */ +#ifdef HAVE_FS_UFS + &ufs_ops, /* Unix F/S */ +#endif /* HAVE_FS_UFS */ +#ifdef HAVE_FS_XFS + &xfs_ops, /* Unix (irix) F/S */ +#endif /* HAVE_FS_XFS */ +#ifdef HAVE_FS_EFS + &efs_ops, /* Unix (irix) F/S */ +#endif /* HAVE_FS_EFS */ +#ifdef HAVE_FS_LOFS + &lofs_ops, /* loopback F/S */ +#endif /* HAVE_FS_LOFS */ +#ifdef HAVE_FS_CDFS + &cdfs_ops, /* CDROM/HSFS/ISO9960 F/S */ +#endif /* HAVE_FS_CDFS */ +#ifdef HAVE_FS_PCFS + &pcfs_ops, /* Floppy/MSDOS F/S */ +#endif /* HAVE_FS_PCFS */ +#ifdef HAVE_FS_CACHEFS + &cachefs_ops, /* caching F/S */ +#endif /* HAVE_FS_CACHEFS */ +#ifdef HAVE_FS_NULLFS +/* FILL IN */ /* null (loopback) F/S */ +#endif /* HAVE_FS_NULLFS */ +#ifdef HAVE_FS_UNIONFS +/* FILL IN */ /* union (bsd44) F/S */ +#endif /* HAVE_FS_UNIONFS */ +#ifdef HAVE_FS_UMAPFS +/* FILL IN */ /* uid/gid mapping F/S */ +#endif /* HAVE_FS_UMAPFS */ + + /* + * These 5 should be last, in the order: + * (1) amfs_auto + * (2) amfs_direct + * (3) amfs_toplvl + * (4) autofs + * (5) amfs_error + */ +#ifdef HAVE_AM_FS_AUTO + &amfs_auto_ops, /* Automounter F/S */ +#endif /* HAVE_AM_FS_AUTO */ +#ifdef HAVE_AM_FS_DIRECT + &amfs_direct_ops, /* direct-mount F/S */ +#endif /* HAVE_AM_FS_DIRECT */ +#ifdef HAVE_AM_FS_TOPLVL + &amfs_toplvl_ops, /* top-level mount F/S */ +#endif /* HAVE_AM_FS_TOPLVL */ +#ifdef HAVE_FS_AUTOFS + &autofs_ops, /* autofs mount F/S */ +#endif /* HAVE_FS_AUTOFS */ +#ifdef HAVE_AM_FS_ERROR + &amfs_error_ops, /* error F/S */ +#endif /* HAVE_AM_FS_ERROR */ + 0 +}; + + +void +ops_showamfstypes(char *buf) +{ + struct am_ops **ap; + int l = 0; + + buf[0] = '\0'; + for (ap = vops; *ap; ap++) { + strcat(buf, (*ap)->fs_type); + if (ap[1]) + strcat(buf, ", "); + l += strlen((*ap)->fs_type) + 2; + if (l > 60) { + l = 0; + strcat(buf, "\n "); + } + } +} + + +static void +ops_show1(char *buf, int *lp, const char *name) +{ + strcat(buf, name); + strcat(buf, ", "); + *lp += strlen(name) + 2; + if (*lp > 60) { + strcat(buf, "\t\n"); + *lp = 0; + } +} + + +void +ops_showfstypes(char *buf) +{ + int l = 0; + + buf[0] = '\0'; + +#ifdef MNTTAB_TYPE_AUTOFS + ops_show1(buf, &l, MNTTAB_TYPE_AUTOFS); +#endif /* MNTTAB_TYPE_AUTOFS */ + +#ifdef MNTTAB_TYPE_CACHEFS + ops_show1(buf, &l, MNTTAB_TYPE_CACHEFS); +#endif /* MNTTAB_TYPE_CACHEFS */ + +#ifdef MNTTAB_TYPE_CDFS + ops_show1(buf, &l, MNTTAB_TYPE_CDFS); +#endif /* MNTTAB_TYPE_CDFS */ + +#ifdef MNTTAB_TYPE_CFS + ops_show1(buf, &l, MNTTAB_TYPE_CFS); +#endif /* MNTTAB_TYPE_CFS */ + +#ifdef MNTTAB_TYPE_LOFS + ops_show1(buf, &l, MNTTAB_TYPE_LOFS); +#endif /* MNTTAB_TYPE_LOFS */ + +#ifdef MNTTAB_TYPE_EFS + ops_show1(buf, &l, MNTTAB_TYPE_EFS); +#endif /* MNTTAB_TYPE_EFS */ + +#ifdef MNTTAB_TYPE_MFS + ops_show1(buf, &l, MNTTAB_TYPE_MFS); +#endif /* MNTTAB_TYPE_MFS */ + +#ifdef MNTTAB_TYPE_NFS + ops_show1(buf, &l, MNTTAB_TYPE_NFS); +#endif /* MNTTAB_TYPE_NFS */ + +#ifdef MNTTAB_TYPE_NFS3 + ops_show1(buf, &l, "nfs3"); /* always hard-code as nfs3 */ +#endif /* MNTTAB_TYPE_NFS3 */ + +#ifdef MNTTAB_TYPE_NULLFS + ops_show1(buf, &l, MNTTAB_TYPE_NULLFS); +#endif /* MNTTAB_TYPE_NULLFS */ + +#ifdef MNTTAB_TYPE_PCFS + ops_show1(buf, &l, MNTTAB_TYPE_PCFS); +#endif /* MNTTAB_TYPE_PCFS */ + +#ifdef MNTTAB_TYPE_TFS + ops_show1(buf, &l, MNTTAB_TYPE_TFS); +#endif /* MNTTAB_TYPE_TFS */ + +#ifdef MNTTAB_TYPE_TMPFS + ops_show1(buf, &l, MNTTAB_TYPE_TMPFS); +#endif /* MNTTAB_TYPE_TMPFS */ + +#ifdef MNTTAB_TYPE_UFS + ops_show1(buf, &l, MNTTAB_TYPE_UFS); +#endif /* MNTTAB_TYPE_UFS */ + +#ifdef MNTTAB_TYPE_UMAPFS + ops_show1(buf, &l, MNTTAB_TYPE_UMAPFS); +#endif /* MNTTAB_TYPE_UMAPFS */ + +#ifdef MNTTAB_TYPE_UNIONFS + ops_show1(buf, &l, MNTTAB_TYPE_UNIONFS); +#endif /* MNTTAB_TYPE_UNIONFS */ + +#ifdef MNTTAB_TYPE_XFS + ops_show1(buf, &l, MNTTAB_TYPE_XFS); +#endif /* MNTTAB_TYPE_XFS */ + + /* terminate with a period, newline, and NULL */ + if (buf[strlen(buf)-1] == '\n') + buf[strlen(buf) - 4] = '\0'; + else + buf[strlen(buf) - 2] = '\0'; + strcat(buf, ".\n"); +} + + +/* + * return string option which is the reverse of opt. + * nosuid -> suid + * quota -> noquota + * ro -> rw + * etc. + * may return pointer to static buffer or subpointer within opt. + */ +static char * +reverse_option(const char *opt) +{ + static char buf[80]; + + /* sanity check */ + if (!opt) + return NULL; + + /* check special cases */ + /* XXX: if this gets too long, rewrite the code more flexibly */ + if (STREQ(opt, "ro")) return "rw"; + if (STREQ(opt, "rw")) return "ro"; + if (STREQ(opt, "bg")) return "fg"; + if (STREQ(opt, "fg")) return "bg"; + if (STREQ(opt, "soft")) return "hard"; + if (STREQ(opt, "hard")) return "soft"; + + /* check if string starts with 'no' and chop it */ + if (NSTREQ(opt, "no", 2)) { + strcpy(buf, &opt[2]); + } else { + /* finally return a string prepended with 'no' */ + strcpy(buf, "no"); + strcat(buf, opt); + } + return buf; +} + + +/* + * start with an empty string. for each opts1 option that is not + * in opts2, add it to the string (make sure the reverse of it + * isn't in either). finally add opts2. return new string. + * Both opts1 and opts2 must not be null! + * Caller must eventually free the string being returned. + */ +static char * +merge_opts(char *opts1, char *opts2) +{ + mntent_t mnt2; /* place holder for opts2 */ + char *newstr; /* new string to return (malloc'ed) */ + char *tmpstr; /* temp */ + char *eq; /* pointer to '=' within temp */ + char oneopt[80]; /* one option w/o value if any */ + char *revoneopt; /* reverse of oneopt */ + int len = strlen(opts1) + strlen(opts2) + 2; /* space for "," and NULL */ + char *s1 = strdup(opts1); /* copy of opts1 to munge */ + + /* initialization */ + mnt2.mnt_opts = opts2; + newstr = xmalloc(len); + newstr[0] = '\0'; + + for (tmpstr = strtok(s1, ","); + tmpstr; + tmpstr = strtok(NULL, ",")) { + /* copy option to temp buffer */ + strncpy(oneopt, tmpstr, 80); + oneopt[79] = '\0'; + /* if option has a value such as rsize=1024, chop the value part */ + if ((eq = strchr(oneopt, '='))) + eq[1] = '\0'; + /* find reverse option of oneopt */ + revoneopt = reverse_option(oneopt); + /* if option orits reverse exist in opts2, ignore it */ + if (hasmntopt(&mnt2, oneopt) || hasmntopt(&mnt2, revoneopt)) + continue; + /* add option to returned string */ + if (newstr && newstr[0]) { + strcat(newstr, ","); + strcat(newstr, tmpstr); + } else { + strcpy(newstr, tmpstr); + } + } + + /* finally, append opts2 itself */ + if (newstr && newstr[0]) { + strcat(newstr, ","); + strcat(newstr, opts2); + } else { + strcpy(newstr, opts2); + } + + XFREE(s1); + return newstr; +} + + +am_ops * +ops_match(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 = &amfs_error_ops; + } else if (fo->opt_type == 0) { + plog(XLOG_USER, "No fs type specified (key = \"%s\", map = \"%s\")", keym, map); + rop = &amfs_error_ops; + } else { + /* + * Next find the correct filesystem type + */ + for (vp = vops; (rop = *vp); vp++) + if (STREQ(rop->fs_type, fo->opt_type)) + break; + if (!rop) { + plog(XLOG_USER, "fs type \"%s\" not recognized", fo->opt_type); + rop = &amfs_error_ops; + } + } + + /* + * Make sure we have a default mount option. + * Otherwise skip past any leading '-'. + */ + if (fo->opt_opts == 0) + fo->opt_opts = strdup("rw,defaults"); + else if (*fo->opt_opts == '-') { + /* + * We cannot simply do fo->opt_opts++ here since the opts + * module will try to free the pointer fo->opt_opts later. + * So just reallocate the thing -- stolcke 11/11/94 + */ + char *old = fo->opt_opts; + fo->opt_opts = strdup(old + 1); + XFREE(old); + } + + /* + * If addopts option was used, then append it to the + * current options. + */ + if (fo->opt_addopts) { + char *mergedstr; + mergedstr = merge_opts(fo->opt_opts, fo->opt_addopts); + plog(XLOG_USER, "merge opts \"%s\" add \"%s\" => \"%s\"", + fo->opt_opts, fo->opt_addopts, mergedstr); + XFREE(fo->opt_opts); + fo->opt_opts = mergedstr; + } + + /* + * Check the filesystem is happy + */ + if (fo->fs_mtab) + XFREE(fo->fs_mtab); + + if ((fo->fs_mtab = (*rop->fs_match) (fo))) + return rop; + + /* + * Return error file system + */ + fo->fs_mtab = (*amfs_error_ops.fs_match) (fo); + return &amfs_error_ops; +} diff --git a/contrib/amd/amd/amd.8 b/contrib/amd/amd/amd.8 new file mode 100644 index 0000000..a738809 --- /dev/null +++ b/contrib/amd/amd/amd.8 @@ -0,0 +1,352 @@ +.\" +.\" Copyright (c) 1997-1998 Erez Zadok +.\" Copyright (c) 1989 Jan-Simon Pendry +.\" Copyright (c) 1989 Imperial College of Science, Technology & Medicine +.\" Copyright (c) 1989 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Jan-Simon Pendry at Imperial College, London. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgment: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" %W% (Berkeley) %G% +.\" +.\" $Id: amd.8,v 5.2.2.1 1992/02/09 15:11:11 jsp beta $ +.\" +.TH AMD 8 "3 November 1989" +.SH NAME +amd \- automatically mount file systems +.SH SYNOPSIS +.B amd +.B \-H +.br +.B amd +[ +.BI \-F " conf_file" +] +.br +.B amd +[ +.B \-nprvHS +] [ +.BI \-a " mount_point" +] [ +.BI \-c " duration" +] [ +.BI \-d " domain" +] [ +.BI \-k " kernel-arch" +] [ +.BI \-l " logfile" +] [ +.BI \-o " op_sys_ver" +] [ +.BI \-t " interval.interval" +] [ +.BI \-w " interval" +] [ +.BI \-x " log-option" +] [ +.BI \-y " YP-domain" +] [ +.BI \-C " cluster-name" +] [ +.BI \-D " option" +] [ +.BI \-F " conf_file" +] [ +.BI \-O " op_sys_name" +] [ +.BI \-T " tag" +] +[ +.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 +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 defined by +.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. +.LP +In the first form depicted above, +.B amd +will print a short help string. In the second form, if no options are +specified, or the +.B -F +is used, +.B amd +will read configuration parameters from the file +.I conf_file +which defaults to +.BR /etc/amd.conf . +The last form is described below. +.SH OPTIONS + +.\"*******************************************************" + +.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). +The default syslog facility used is LOG_DAEMON. If you +wish to change it, append its name to the log file name, delimited by a +single colon. For example, if +.I logfile +is the string +.B syslog:local7 +then +.B Amd +will log messages via +.IR syslog (3) +using the LOG_LOCAL7 facility (if it exists on the system). + +.TP +.B \-n +Normalize hostnames. +The name refereed to by ${rhost} is normalized relative to the +host database before being used. The effect is to translate +aliases into ``official'' names. + +.TP +.BI \-o " op_sys_ver" +Override the compiled-in version number of the operating system. Useful +when the built in version is not desired for backward compatibility reasons. +For example, if the build in version is ``2.5.1'', you can override it to +``5.5.1'', and use older maps that were written with the latter in mind. + +.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 +.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 +.B \-v +Version. Displays version and configuration information on standard error. + +.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 \-x " options" +Specify run-time logging options. The options are a comma separated +list chosen from: fatal, error, user, warn, info, map, stats, all. + +.TP +.BI \-y " domain" +Specify an alternative NIS domain from which to fetch the NIS maps. +The default is the system domain name. This option is ignored if NIS +support is not available. + +.TP +.BI \-C " cluster-name" +Specify an alternative HP-UX cluster name to use. + +.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. + +.TP +.BI \-F " conf_file" +Specify an amd configuration file to use. See +.BR amd.conf (5) +for description of this file's format. This configuration file is used to +specify any options in lieu of typing many of them on the command line. The +.I amd.conf +file includes directives for every command line option amd has, and many +more that are only available via the configuration file facility. The +configuration file specified by this option is processed after all other +options had been processed, regardless of the actual location of this option +on the command line. + +.TP +.B \-H +Print help and usage string. + +.TP +.BI \-O " op_sys_name" +Override the compiled-in name of the operating system. Useful when the +built in name is not desired for backward compatibility reasons. For +example, if the build in name is ``sunos5'', you can override it to +``sos5'', and use older maps which were written with the latter in mind. + +.TP +.B \-S +Do not lock the running executable pages of amd into memory. To improve +amd's performance, systems that support the +.BR plock (3) +call, could lock the amd process into memory. This way there is less chance +the operating system will schedule, page out, and swap the amd process as +needed. This tends improves amd's performance, at the cost of reserving the +memory used by the amd process (making it unavailable for other processes). +If this behavior is not desired, use the +.B \-S +option. + +.TP +.BI \-T " tag" +Specify a tag to use with +.BR amd.conf (5). +All map entries tagged with +.I tag +will be processed. Map entries that are not tagged are always processed. +Map entries that are tagged with a tag other than +.I tag +will not be processed. + +.SH FILES +.PD 0 +.TP 5 +.B /a +directory under which filesystems are dynamically mounted +.TP 5 +.B /etc/amd.conf +default configuration file +.PD +.SH CAVEATS +Some care may be required when creating a mount map. +.LP +Symbolic links on an NFS filesystem can be incredibly inefficient. +In most implementations of NFS, 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 amd.conf (5), +.BR amq (8), +.BR domainname (1), +.BR hostname (1), +.BR automount (8), +.BR mount (8), +.BR umount (8), +.BR mtab (5), +.BR syslog (3). +.LP +.I "Amd \- The 4.4 BSD Automounter" +.SH AUTHORS +Jan-Simon Pendry <jsp@doc.ic.ac.uk>, Department of Computing, Imperial College, London, UK. +.P +Erez Zadok <ezk@cs.columbia.edu>, Department of Computer Science, Columbia +University, New York, USA. +.P +Other authors and contributors to am-utils are listed in the +.B AUTHORS +file distributed with am-utils. diff --git a/contrib/amd/amd/amd.c b/contrib/amd/amd/amd.c new file mode 100644 index 0000000..7ef2ce7 --- /dev/null +++ b/contrib/amd/amd/amd.c @@ -0,0 +1,535 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amd.c,v 5.2.2.1 1992/02/09 15:08:15 jsp beta $ + * + */ + +/* + * Automounter + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +struct amu_global_options gopt; /* where global options are stored */ + +char pid_fsname[16 + MAXHOSTNAMELEN]; /* "kiska.southseas.nz:(pid%d)" */ +char *progname; /* "amd" */ +char *hostdomain = "unknown.domain"; +char hostname[MAXHOSTNAMELEN] = "localhost"; /* Hostname */ +char hostd[2 * MAXHOSTNAMELEN]; /* Host+domain */ +char *endian = ARCH_ENDIAN; /* Big or Little endian */ +char *cpu = HOST_CPU; /* CPU type */ +char *PrimNetName; /* name of primary network */ +char *PrimNetNum; /* number of primary network */ + +int foreground = 1; /* This is the top-level server */ +int immediate_abort; /* Should close-down unmounts be retried */ +int orig_umask; +int select_intr_valid; + +jmp_buf select_intr; +pid_t mypid; /* Current process id */ +serv_state amd_state; +struct amd_stats amd_stats; /* Server statistics */ +struct in_addr myipaddr; /* (An) IP address of this host */ +time_t do_mapc_reload = 0; /* mapc_reload() call required? */ + +#ifdef HAVE_SIGACTION +sigset_t masked_sigs; +#endif /* HAVE_SIGACTION */ + + +/* + * 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 RETSIGTYPE +sigterm(int sig) +{ +#ifdef REINSTALL_SIGNAL_HANDLER + signal(sig, sigterm); +#endif /* REINSTALL_SIGNAL_HANDLER */ + + 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 RETSIGTYPE +sighup(int sig) +{ +#ifdef REINSTALL_SIGNAL_HANDLER + signal(sig, sighup); +#endif /* REINSTALL_SIGNAL_HANDLER */ + +#ifdef DEBUG + if (sig != SIGHUP) + dlog("spurious call to sighup"); +#endif /* DEBUG */ + /* + * Force a reload by zero'ing the timer + */ + if (amd_state == Run) + do_mapc_reload = 0; +} + + +static RETSIGTYPE +parent_exit(int sig) +{ + exit(0); +} + + +static int +daemon_mode(void) +{ + int bgpid; + +#ifdef HAVE_SIGACTION + struct sigaction sa, osa; + + sa.sa_handler = parent_exit; + sa.sa_flags = 0; + sigemptyset(&(sa.sa_mask)); + sigaddset(&(sa.sa_mask), SIGQUIT); + sigaction(SIGQUIT, &sa, &osa); +#else /* not HAVE_SIGACTION */ + signal(SIGQUIT, parent_exit); +#endif /* not HAVE_SIGACTION */ + + bgpid = background(); + + if (bgpid != 0) { + /* + * Now wait for the automount points to + * complete. + */ + for (;;) + pause(); + /* should never reache here */ + } +#ifdef HAVE_SIGACTION + sigaction(SIGQUIT, &osa, NULL); +#else /* not HAVE_SIGACTION */ + signal(SIGQUIT, SIG_DFL); +#endif /* not HAVE_SIGACTION */ + + /* + * Record our pid to make it easier to kill the correct amd. + */ + if (gopt.flags & CFM_PRINT_PID) { + if (STREQ(gopt.pid_file, "/dev/stdout")) { + printf("%ld\n", (long) mypid); + fflush(stdout); + /* do not fclose stdout */ + } else { + FILE *f; + mode_t prev_umask = umask(0022); /* set secure temporary umask */ + + f = fopen(gopt.pid_file, "w"); + if (f) { + fprintf(f, "%ld\n", (long) mypid); + (void) fclose(f); + } else { + fprintf(stderr, "cannot open %s (errno=%d)\n", gopt.pid_file, errno); + } + umask(prev_umask); /* restore umask */ + } + } + + /* + * Pretend we are in the foreground again + */ + foreground = 1; + + /* + * Dissociate from the controlling terminal + */ + amu_release_controlling_tty(); + + return getppid(); +} + + +/* + * Initialize global options structure. + */ +static void +init_global_options(void) +{ +#if defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME) + static struct utsname un; +#endif /* defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME) */ + + memset(&gopt, 0, sizeof(struct amu_global_options)); + + /* name of current architecture */ + gopt.arch = HOST_ARCH; + + /* automounter temp dir */ + gopt.auto_dir = "/a"; + + /* cluster name */ + gopt.cluster = NULL; + + /* + * kernel architecture: this you must get from uname() if possible. + */ +#if defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME) + if (uname(&un) >= 0) + gopt.karch = un.machine; + else +#endif /* defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME) */ + gopt.karch = HOST_ARCH; + + /* amd log file */ + gopt.logfile = NULL; + + /* operating system name */ + gopt.op_sys = HOST_OS_NAME; + + /* OS version */ + gopt.op_sys_ver = HOST_OS_VERSION; + + /* pid file */ + gopt.pid_file = "/dev/stdout"; + + /* local domain */ + gopt.sub_domain = NULL; + + /* NFS retransmit counter */ + gopt.amfs_auto_retrans = -1; + + /* NFS retry interval */ + gopt.amfs_auto_timeo = -1; + + /* cache duration */ + gopt.am_timeo = AM_TTL; + + /* dismount interval */ + gopt.am_timeo_w = AM_TTL_W; + + /* + * various CFM_* flags. + * by default, only the "plock" option is on (if available). + */ + gopt.flags = CFM_PROCESS_LOCK; + +#ifdef HAVE_MAP_HESIOD + /* Hesiod rhs zone */ + gopt.hesiod_base = "automount"; +#endif /* HAVE_MAP_HESIOD */ + +#ifdef HAVE_MAP_LDAP + /* LDAP base */ + gopt.ldap_base = NULL; + + /* LDAP host ports */ + gopt.ldap_hostports = NULL; + + /* LDAP cache */ + gopt.ldap_cache_seconds = 0; + gopt.ldap_cache_maxmem = 131072; +#endif /* HAVE_MAP_LDAP */ + +#ifdef HAVE_MAP_NIS + /* YP domain name */ + gopt.nis_domain = NULL; +#endif /* HAVE_MAP_NIS */ +} + + +int +main(int argc, char *argv[]) +{ + char *domdot, *verstr; + int ppid = 0; + int error; +#ifdef HAVE_SIGACTION + struct sigaction sa; +#endif /* HAVE_SIGACTION */ + + /* + * Make sure some built-in assumptions are true before we start + */ + assert(sizeof(nfscookie) >= sizeof(u_int)); + assert(sizeof(int) >= 4); + + /* + * Set processing status. + */ + amd_state = Start; + + /* + * Determine program name + */ + if (argv[0]) { + progname = strrchr(argv[0], '/'); + if (progname && progname[1]) + progname++; + else + progname = argv[0]; + } + if (!progname) + progname = "amd"; + + /* + * Initialise process id. This is kept + * cached since it is used for generating + * and using file handles. + */ + mypid = getpid(); + + /* + * 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); + } + + /* + * Initialize global options structure. + */ + init_global_options(); + + /* + * 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. + */ +#ifdef HAVE_SIGACTION + sa.sa_handler = sigterm; + sa.sa_flags = 0; + sigemptyset(&(sa.sa_mask)); + sigaddset(&(sa.sa_mask), SIGINT); + sigaddset(&(sa.sa_mask), SIGTERM); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); +#else /* not HAVE_SIGACTION */ + (void) signal(SIGINT, sigterm); +#endif /* not HAVE_SIGACTION */ + + /* + * Trap Terminate so that we can shutdown gracefully (some chance) + */ +#ifdef HAVE_SIGACTION + sa.sa_handler = sigterm; + sa.sa_flags = 0; + sigemptyset(&(sa.sa_mask)); + sigaddset(&(sa.sa_mask), SIGTERM); + sigaction(SIGTERM, &sa, NULL); +#else /* not HAVE_SIGACTION */ + (void) signal(SIGTERM, sigterm); +#endif /* not HAVE_SIGACTION */ + + /* + * Hangups tell us to reload the cache + */ +#ifdef HAVE_SIGACTION + sa.sa_handler = sighup; + sa.sa_flags = 0; + sigemptyset(&(sa.sa_mask)); + sigaddset(&(sa.sa_mask), SIGHUP); + sigaction(SIGHUP, &sa, NULL); +#else /* not HAVE_SIGACTION */ + (void) signal(SIGHUP, sighup); +#endif /* not HAVE_SIGACTION */ + + /* + * Trap Death-of-a-child. These allow us to + * pick up the exit status of backgrounded mounts. + * See "sched.c". + */ +#ifdef HAVE_SIGACTION + sa.sa_handler = sigchld; + sa.sa_flags = 0; + sigemptyset(&(sa.sa_mask)); + sigaddset(&(sa.sa_mask), SIGCHLD); + sigaction(SIGCHLD, &sa, NULL); + + /* + * construct global "masked_sigs" used in nfs_start.c + */ + sigemptyset(&masked_sigs); + sigaddset(&masked_sigs, SIGHUP); + sigaddset(&masked_sigs, SIGCHLD); + sigaddset(&masked_sigs, SIGTERM); + sigaddset(&masked_sigs, SIGINT); +#else /* not HAVE_SIGACTION */ + (void) signal(SIGCHLD, sigchld); +#endif /* not HAVE_SIGACTION */ + + /* + * Fix-up any umask problems. Most systems default + * to 002 which is not too convenient for our purposes + */ + orig_umask = umask(0); + + /* + * Figure out primary network name + */ + getwire(&PrimNetName, &PrimNetNum); + + /* + * Determine command-line arguments + */ + get_args(argc, argv); + + /* + * Log version information. + */ + verstr = strtok(get_version_string(), "\n"); + plog(XLOG_INFO, "AM-UTILS VERSION INFORMATION:"); + while (verstr) { + plog(XLOG_INFO, verstr); + verstr = strtok(NULL, "\n"); + } + + /* + * Get our own IP address so that we + * can mount the automounter. + */ + amu_get_myaddress(&myipaddr); + plog(XLOG_INFO, "My ip addr is 0x%x", htonl(myipaddr.s_addr)); + + /* avoid hanging on other NFS servers if started elsewhere */ + if (chdir("/") < 0) + plog(XLOG_INFO, "cannot chdir to /: %m"); + + /* + * Now check we are root. + */ + if (geteuid() != 0) { + plog(XLOG_FATAL, "Must be root to mount filesystems (euid = %d)", geteuid()); + going_down(1); + } + + /* + * Lock process text and data segment in memory. + */ +#ifdef HAVE_PLOCK + if (gopt.flags & CFM_PROCESS_LOCK) { + if (plock(PROCLOCK) != 0) { + plog(XLOG_WARNING, "Couldn't lock process text and data segment in memory: %m"); + } else { + plog(XLOG_INFO, "Locked process text and data segment in memory"); + } + } +#endif /* HAVE_PLOCK */ + +#ifdef HAVE_MAP_NIS + /* + * If the domain was specified then bind it here + * to circumvent any default bindings that may + * be done in the C library. + */ + if (gopt.nis_domain && yp_bind(gopt.nis_domain)) { + plog(XLOG_FATAL, "Can't bind to NIS domain \"%s\"", gopt.nis_domain); + going_down(1); + } +#endif /* HAVE_MAP_NIS */ + +#ifdef DEBUG + amuDebug(D_DAEMON) +#endif /* DEBUG */ + ppid = daemon_mode(); + + sprintf(pid_fsname, "%s:(pid%ld)", hostname, (long) 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(); + return 1; /* should never get here */ +} diff --git a/contrib/amd/amd/amd.h b/contrib/amd/amd/amd.h new file mode 100644 index 0000000..610dfe2 --- /dev/null +++ b/contrib/amd/amd/amd.h @@ -0,0 +1,303 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amd.h,v 1.1 1996/01/13 23:23:39 ezk Exp ezk $ + * + */ + +#ifndef _AMD_H +#define _AMD_H + + +/* + * MACROS: + */ + +/* options for amd.conf */ +#define CFM_BROWSABLE_DIRS 0x0001 +#define CFM_MOUNT_TYPE_AUTOFS 0x0002 +#define CFM_ENABLE_DEFAULT_SELECTORS 0x0004 +#define CFM_NORMALIZE_HOSTNAMES 0x0008 +#define CFM_PROCESS_LOCK 0x0010 +#define CFM_PRINT_PID 0x0020 +#define CFM_RESTART_EXISTING_MOUNTS 0x0040 +#define CFM_SHOW_STATFS_ENTRIES 0x0080 +#define CFM_FULLY_QUALIFIED_HOSTS 0x0100 +#define CFM_BROWSABLE_DIRS_FULL 0x0200 /* allow '/' in readdir() */ +#define CFM_UNMOUNT_ON_EXIT 0x0400 /* when amd finishing */ + +/* some systems (SunOS 4.x) neglect to define the mount null message */ +#ifndef MOUNTPROC_NULL +# define MOUNTPROC_NULL ((u_long)(0)) +#endif /* not MOUNTPROC_NULL */ + +/* Hash table size */ +#define NKVHASH (1 << 2) /* Power of two */ + +/* interval between forced retries of a mount */ +#define RETRY_INTERVAL 2 + +#define ereturn(x) { *error_return = x; return 0; } + + +/* + * TYPEDEFS: + */ + +typedef struct cf_map cf_map_t; +typedef struct kv kv; +/* + * Cache map operations + */ +typedef void add_fn(mnt_map *, char *, char *); +typedef int init_fn(mnt_map *, char *, time_t *); +typedef int mtime_fn(mnt_map *, char *, time_t *); +typedef int isup_fn(mnt_map *, char *); +typedef int reload_fn(mnt_map *, char *, add_fn *); +typedef int search_fn(mnt_map *, char *, char *, char **, time_t *); + + + +/* + * STRUCTURES: + */ + +/* global amd options that are manipulated by conf.c */ +struct amu_global_options { + char *arch; /* name of current architecture */ + char *auto_dir; /* automounter temp dir */ + char *cluster; /* cluster name */ + char *karch; /* kernel architecture */ + char *logfile; /* amd log file */ + char *op_sys; /* operating system name */ + char *op_sys_ver; /* OS version */ + char *pid_file; /* PID file */ + char *sub_domain; /* local domain */ + char *map_options; /* global map options */ + char *map_type; /* global map type */ + char *search_path; /* search path for maps */ + char *mount_type; /* mount type for map */ + u_int flags; /* various CFM_* flags */ + int amfs_auto_retrans; /* NFS retransmit counter */ + int amfs_auto_timeo; /* NFS retry interval */ + int am_timeo; /* cache duration */ + int am_timeo_w; /* dismount interval */ + int portmap_program; /* amd RPC program number */ +#ifdef HAVE_MAP_HESIOD + char *hesiod_base; /* Hesiod rhs */ +#endif /* HAVE_MAP_HESIOD */ +#ifdef HAVE_MAP_LDAP + char *ldap_base; /* LDAP base */ + char *ldap_hostports; /* LDAP host ports */ + long ldap_cache_seconds; /* LDAP internal cache - keep seconds */ + long ldap_cache_maxmem; /* LDAP internal cache - max memory (bytes) */ +#endif /* HAVE_MAP_LDAP */ +#ifdef HAVE_MAP_NIS + char *nis_domain; /* YP domain name */ +#endif /* HAVE_MAP_NIS */ +}; + +/* if you add anything here, update conf.c:reset_cf_map() */ +struct cf_map { + char *cfm_dir; /* /home, /u, /src */ + char *cfm_name; /* amd.home, /etc/amd.home ... */ + char *cfm_type; /* file, hesiod, ndbm, nis ... */ + char *cfm_opts; /* -cache:=all, etc. */ + char *cfm_search_path; /* /etc/local:/etc/amdmaps:/misc/yp */ + char *cfm_tag; /* optional map tag for amd -T */ + u_int cfm_flags; /* browsable_dirs? mount_type? */ +}; + +/* + * Key-value pair + */ +struct kv { + kv *next; + char *key; +#ifdef HAVE_REGEXEC + regex_t re; /* store the regexp from regcomp() */ +#endif /* HAVE_REGEXEC */ + char *val; +}; + +struct mnt_map { + qelem hdr; + int refc; /* Reference count */ + short flags; /* Allocation flags */ + short 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 */ + isup_fn *isup; /* Is service up or not? (1=up, 0=down) */ + search_fn *search; /* Function to be used for searching */ + mtime_fn *mtime; /* Modify time function */ + kv *kvhash[NKVHASH]; /* Cached data */ + /* options available via amd conf file */ + char *cf_map_type; /* file, hesiod, ndbm, nis, etc. */ + char *cf_search_path; /* /etc/local:/etc/amdmaps:/misc/yp */ + void *map_data; /* Map data black box */ +}; + +/* + * Mounting a file system may take a significant period of time. The + * problem is that if this is done in the main process thread then + * the entire automounter could be blocked, possibly hanging lots of + * processes on the system. Instead we use a continuation scheme to + * allow mounts to be attempted in a sub-process. When the sub-process + * exits we pick up the exit status (by convention a UN*X error number) + * and continue in a notifier. The notifier gets handed a data structure + * and can then determine whether the mount was successful or not. If + * not, it updates the data structure and tries again until there are no + * more ways to try the mount, or some other permanent error occurs. + * In the mean time no RPC reply is sent, even after the mount is 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 *auto_opts; /* Automount options */ + am_opts fs_opts; /* Filesystem options */ + char *def_opts; /* Default automount options */ + int retry; /* Try again? */ + int tried; /* Have we tried any yet? */ + time_t start; /* Time we started this mount */ + int callout; /* Callout identifier */ +}; + + +/* + * EXTERNALS: + */ + +/* Amq server global functions */ +extern amq_mount_info_list *amqproc_getmntfs_1_svc(voidp argp, struct svc_req *rqstp); +extern amq_mount_stats *amqproc_stats_1_svc(voidp argp, struct svc_req *rqstp); +extern amq_mount_tree_list *amqproc_export_1_svc(voidp argp, struct svc_req *rqstp); +extern amq_mount_tree_p *amqproc_mnttree_1_svc(voidp argp, struct svc_req *rqstp); +extern amq_string *amqproc_getvers_1_svc(voidp argp, struct svc_req *rqstp); +extern int *amqproc_getpid_1_svc(voidp argp, struct svc_req *rqstp); +extern int *amqproc_mount_1_svc(voidp argp, struct svc_req *rqstp); +extern int *amqproc_setopt_1_svc(voidp argp, struct svc_req *rqstp); +extern voidp amqproc_null_1_svc(voidp argp, struct svc_req *rqstp); +extern voidp amqproc_umnt_1_svc(voidp argp, struct svc_req *rqstp); + +/* other external definitions */ +extern am_nfs_fh *root_fh(char *dir); +extern am_node * autofs_lookuppn(am_node *mp, char *fname, int *error_return, int op); +extern am_node *find_ap(char *); +extern am_node *find_ap2(char *, am_node *); +extern bool_t xdr_amq_mount_info_qelem(XDR *xdrs, qelem *qhead); +extern fserver *find_nfs_srvr(mntfs *mf); +extern int auto_fmount(am_node *mp); +extern int auto_fumount(am_node *mp); +extern int mount_nfs_fh(am_nfs_handle_t *fhp, char *dir, char *fs_name, char *opts, mntfs *mf); +extern int process_last_regular_map(void); +extern int set_conf_kv(const char *section, const char *k, const char *v); +extern int try_mount(voidp mvp); +extern int yyparse (void); +extern nfsentry *make_entry_chain(am_node *mp, const nfsentry *current_chain, int fully_browsable); +extern void amfs_auto_cont(int rc, int term, voidp closure); +extern void amfs_auto_mkcacheref(mntfs *mf); +extern void amfs_auto_retry(int rc, int term, voidp closure); +extern void assign_error_mntfs(am_node *mp); +extern void flush_srvr_nfs_cache(void); +extern void free_continuation(struct continuation *cp); +extern void mf_mounted(mntfs *mf); +extern void quick_reply(am_node *mp, int error); +extern void root_newmap(const char *, const char *, const char *, const cf_map_t *); + +/* amd global variables */ +extern FILE *yyin; +extern SVCXPRT *nfs_program_2_transp; /* For quick_reply() */ +extern char *conf_tag; +extern int NumChild; +extern int fwd_sock; +extern int select_intr_valid; +extern int usage; +extern int use_conf_file; /* use amd configuration file */ +extern jmp_buf select_intr; +extern qelem mfhead; +extern struct amu_global_options gopt; /* where global options are stored */ + +#ifdef HAVE_SIGACTION +extern sigset_t masked_sigs; +#endif /* HAVE_SIGACTION */ + +#if defined(HAVE_AM_FS_LINK) || defined(HAVE_AM_FS_LINKX) +extern char *amfs_link_match(am_opts *fo); +extern int amfs_link_fumount(mntfs *mf); +#endif /* defined(HAVE_AM_FS_LINK) || defined(HAVE_AM_FS_LINKX) */ + +#ifdef HAVE_AM_FS_NFSL +extern char *nfs_match(am_opts *fo); +#endif /* HAVE_AM_FS_NFSL */ + +#if defined(HAVE_FS_NFS3) && !defined(HAVE_XDR_MOUNTRES3) +extern bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp); +#endif /* defined(HAVE_FS_NFS3) && !defined(HAVE_XDR_MOUNTRES3) */ + +#ifdef HAVE_FS_AUTOFS +extern SVCXPRT *autofsxprt; +extern u_short autofs_port; + +extern int autofs_mount(am_node *mp); +extern int autofs_umount(am_node *mp); +extern int create_autofs_service(int *soAUTOFSp, u_short *autofs_portp, SVCXPRT **autofs_xprtp, void (*dispatch_fxn)(struct svc_req *rqstp, SVCXPRT *transp)); +extern int svc_create_local_service(void (*dispatch) (), u_long prognum, u_long versnum, char *nettype, char *servname); +extern void autofs_mounted(mntfs *mf); +extern void autofs_program_1(struct svc_req *rqstp, SVCXPRT *transp); +#endif /* HAVE_FS_AUTOFS */ + +/* Unix file system (irix) */ +#ifdef HAVE_FS_XFS +extern am_ops xfs_ops; /* Un*x file system */ +#endif /* HAVE_FS_XFS */ + +/* Unix file system (irix) */ +#ifdef HAVE_FS_EFS +extern am_ops efs_ops; /* Un*x file system */ +#endif /* HAVE_FS_EFS */ + +#endif /* not _AMD_H */ diff --git a/contrib/amd/amd/amfs_auto.c b/contrib/amd/amd/amfs_auto.c new file mode 100644 index 0000000..0530142 --- /dev/null +++ b/contrib/amd/amd/amfs_auto.c @@ -0,0 +1,1595 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_auto.c,v 1.1 1997-1998/06/30 19:22:30 ezk Exp ezk $ + * + */ + +/* + * Automount file system + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/**************************************************************************** + *** MACROS *** + ****************************************************************************/ +#define IN_PROGRESS(cp) ((cp)->mp->am_mnt->mf_flags & MFF_MOUNTING) + +/* DEVELOPERS: turn this on for special debugging of readdir code */ +#undef DEBUG_READDIR + +/**************************************************************************** + *** STRUCTURES *** + ****************************************************************************/ + + + +/**************************************************************************** + *** FORWARD DEFINITIONS *** + ****************************************************************************/ +static int amfs_auto_bgmount(struct continuation * cp, int mpe); +static int amfs_auto_mount(am_node *mp); +static int amfs_auto_readdir_browsable(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, int count, int fully_browsable); +static void amfs_auto_umounted(am_node *mp); + + +/**************************************************************************** + *** OPS STRUCTURES *** + ****************************************************************************/ +am_ops amfs_auto_ops = +{ + "auto", + amfs_auto_match, + 0, /* amfs_auto_init */ + amfs_auto_mount, + 0, + amfs_auto_umount, + 0, + amfs_auto_lookuppn, + amfs_auto_readdir, + 0, /* amfs_auto_readlink */ + 0, /* amfs_auto_mounted */ + amfs_auto_umounted, + find_amfs_auto_srvr, + FS_AMQINFO | FS_DIRECTORY +}; + + +/**************************************************************************** + *** FUNCTIONS *** + ****************************************************************************/ +/* + * AMFS_AUTO needs nothing in particular. + */ +char * +amfs_auto_match(am_opts *fo) +{ + char *p = fo->opt_rfs; + + if (!fo->opt_rfs) { + plog(XLOG_USER, "auto: no mount point named (rfs:=)"); + return 0; + } + if (!fo->opt_fs) { + plog(XLOG_USER, "auto: no map named (fs:=)"); + return 0; + } + + /* + * Swap round fs:= and rfs:= options + * ... historical (jsp) + */ + fo->opt_rfs = fo->opt_fs; + fo->opt_fs = p; + + /* + * mtab entry turns out to be the name of the mount map + */ + return strdup(fo->opt_rfs ? fo->opt_rfs : "."); +} + + + + +/* + * Build a new map cache for this node, or re-use + * an existing cache for the same map. + */ +void +amfs_auto_mkcacheref(mntfs *mf) +{ + char *cache; + + if (mf->mf_fo && mf->mf_fo->opt_cache) + cache = mf->mf_fo->opt_cache; + else + cache = "none"; + mf->mf_private = (voidp) mapc_find(mf->mf_info, cache, + mf->mf_fo->opt_maptype); + mf->mf_prfree = mapc_free; +} + + +/* + * Mount a sub-mount + */ +static int +amfs_auto_mount(am_node *mp) +{ + mntfs *mf = mp->am_mnt; + + /* + * Pseudo-directories are used to provide some structure + * to the automounted directories instead + * of putting them all in the top-level automount directory. + * + * Here, just increment the parent's link count. + */ + mp->am_parent->am_fattr.na_nlink++; + + /* + * Info field of . means use parent's info field. + * Historical - not documented. + */ + 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) { + /* allow pref:=null to set a real null prefix */ + if (STREQ(mf->mf_fo->opt_pref, "null")) { + mp->am_pref = ""; + } else { + /* + * 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, "/"); + } + + /* + * Attach a map cache + */ + amfs_auto_mkcacheref(mf); + + return 0; +} + + + + +/* + * Unmount an automount sub-node + */ +int +amfs_auto_umount(am_node *mp) +{ + return 0; +} + + +/* + * Unmount an automount node + */ +static void +amfs_auto_umounted(am_node *mp) +{ + /* + * If this is a pseudo-directory then just adjust the link count + * in the parent, otherwise call the generic unmount routine + */ + if (mp->am_parent && mp->am_parent->am_parent) + --mp->am_parent->am_fattr.na_nlink; +} + + +/* + * Discard an old continuation + */ +void +free_continuation(struct continuation *cp) +{ + if (cp->callout) + untimeout(cp->callout); + XFREE(cp->key); + XFREE(cp->xivec); + XFREE(cp->info); + XFREE(cp->auto_opts); + XFREE(cp->def_opts); + free_opts(&cp->fs_opts); + XFREE(cp); +} + + +/* + * Discard the underlying mount point and replace + * with a reference to an error filesystem. + */ +void +assign_error_mntfs(am_node *mp) +{ + if (mp->am_error > 0) { + /* + * Save the old error code + */ + int error = mp->am_error; + if (error <= 0) + error = mp->am_mnt->mf_error; + /* + * Discard the old filesystem + */ + free_mntfs(mp->am_mnt); + /* + * Allocate a new error reference + */ + mp->am_mnt = new_mntfs(); + /* + * Put back the error code + */ + mp->am_mnt->mf_error = error; + mp->am_mnt->mf_flags |= MFF_ERROR; + /* + * Zero the error in the mount point + */ + mp->am_error = 0; + } +} + + +/* + * The continuation function. This is called by + * the task notifier when a background mount attempt + * completes. + */ +void +amfs_auto_cont(int rc, int term, voidp closure) +{ + struct continuation *cp = (struct continuation *) closure; + mntfs *mf = cp->mp->am_mnt; + + /* + * Definitely not trying to mount at the moment + */ + mf->mf_flags &= ~MFF_MOUNTING; + + /* + * While we are mounting - try to avoid race conditions + */ + new_ttl(cp->mp); + + /* + * Wakeup anything waiting for this mount + */ + wakeup((voidp) mf); + + /* + * Check for termination signal or exit status... + */ + if (rc || term) { + am_node *xmp; + + if (term) { + /* + * Not sure what to do for an error code. + */ + mf->mf_error = EIO; /* XXX ? */ + mf->mf_flags |= MFF_ERROR; + plog(XLOG_ERROR, "mount for %s got signal %d", cp->mp->am_path, term); + } else { + /* + * Check for exit status... + */ + mf->mf_error = rc; + mf->mf_flags |= MFF_ERROR; + errno = rc; /* XXX */ + if (!STREQ(cp->mp->am_mnt->mf_ops->fs_type, "linkx")) + plog(XLOG_ERROR, "%s: mount (amfs_auto_cont): %m", cp->mp->am_path); + } + + /* + * If we get here then that attempt didn't work, so + * move the info vector pointer along by one and + * call the background mount routine again + */ + amd_stats.d_merr++; + cp->ivec++; + xmp = cp->mp; + (void) amfs_auto_bgmount(cp, 0); + assign_error_mntfs(xmp); + } else { + /* + * The mount worked. + */ + am_mounted(cp->mp); + free_continuation(cp); + } + + reschedule_timeout_mp(); +} + + +/* + * Retry a mount + */ +void +amfs_auto_retry(int rc, int term, voidp closure) +{ + struct continuation *cp = (struct continuation *) closure; + int error = 0; + +#ifdef DEBUG + dlog("Commencing retry for mount of %s", cp->mp->am_path); +#endif /* DEBUG */ + + new_ttl(cp->mp); + + if ((cp->start + ALLOWED_MOUNT_TIME) < clocktime()) { + /* + * The entire mount has timed out. Set the error code and skip past all + * the info vectors so that amfs_auto_bgmount will not have any more + * ways to try the mount, so causing an error. + */ + plog(XLOG_INFO, "mount of \"%s\" has timed out", cp->mp->am_path); + error = ETIMEDOUT; + while (*cp->ivec) + cp->ivec++; + /* explicitly forbid further retries after timeout */ + cp->retry = FALSE; + } + if (error || !IN_PROGRESS(cp)) { + (void) amfs_auto_bgmount(cp, error); + } + reschedule_timeout_mp(); +} + + +/* + * Try to mount a file system. Can be called + * directly or in a sub-process by run_task. + */ +int +try_mount(voidp mvp) +{ + int error = 0; + am_node *mp = (am_node *) mvp; + mntfs *mf = mp->am_mnt; + + /* + * If the directory is not yet made and it needs to be made, then make it! + * This may be run in a background process in which case the flag setting + * won't be noticed later - but it is set anyway just after run_task is + * called. It should probably go away totally... + */ + if (!(mf->mf_flags & MFF_MKMNT) && mf->mf_ops->fs_flags & FS_MKMNT) { + error = mkdirs(mf->mf_mount, 0555); + if (!error) + mf->mf_flags |= MFF_MKMNT; + } + + /* + * Mount it! + */ + error = mount_node(mp); + +#ifdef DEBUG + if (error > 0) { + errno = error; + dlog("amfs_auto call to mount_node 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 +amfs_auto_bgmount(struct continuation * cp, int mpe) +{ + mntfs *mf = cp->mp->am_mnt; /* Current mntfs */ + mntfs *mf_retry = 0; /* First mntfs which needed retrying */ + int this_error = -1; /* Per-mount error */ + int hard_error = -1; + int mp_error = mpe; + + /* + * Try to mount each location. + * At the end: + * hard_error == 0 indicates something was mounted. + * hard_error > 0 indicates everything failed with a hard error + * hard_error < 0 indicates nothing could be mounted now + */ + for (; this_error && *cp->ivec; cp->ivec++) { + am_ops *p; + am_node *mp = cp->mp; + char *link_dir; + int dont_retry; + + if (hard_error < 0) + hard_error = this_error; + + this_error = -1; + + if (**cp->ivec == '-') { + /* + * Pick up new defaults + */ + if (cp->auto_opts && *cp->auto_opts) + cp->def_opts = str3cat(cp->def_opts, cp->auto_opts, ";", *cp->ivec + 1); + else + cp->def_opts = strealloc(cp->def_opts, *cp->ivec + 1); +#ifdef DEBUG + dlog("Setting def_opts to \"%s\"", cp->def_opts); +#endif /* DEBUG */ + continue; + } + /* + * If a mount has been attempted, and we find + * a cut then don't try any more locations. + */ + if (STREQ(*cp->ivec, "/") || STREQ(*cp->ivec, "||")) { + if (cp->tried) { +#ifdef DEBUG + dlog("Cut: not trying any more locations for %s", + mp->am_path); +#endif /* DEBUG */ + break; + } + continue; + } + + /* match the operators */ + p = ops_match(&cp->fs_opts, *cp->ivec, cp->def_opts, mp->am_path, cp->key, mp->am_parent->am_mnt->mf_info); + + /* + * Find a mounted filesystem for this node. + */ + mp->am_mnt = mf = realloc_mntfs(mf, p, &cp->fs_opts, + cp->fs_opts.opt_fs, + cp->fs_opts.fs_mtab, + cp->auto_opts, + cp->fs_opts.opt_opts, + cp->fs_opts.opt_remopts); + + p = mf->mf_ops; +#ifdef DEBUG + dlog("Got a hit with %s", p->fs_type); +#endif /* DEBUG */ + + /* + * Note whether this is a real mount attempt + */ + if (p == &amfs_error_ops) { + plog(XLOG_MAP, "Map entry %s for %s 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) { + XFREE(mp->am_link); + mp->am_link = 0; + } + link_dir = mf->mf_fo->opt_sublink; + + if (link_dir && *link_dir) { + if (*link_dir == '/') { + mp->am_link = strdup(link_dir); + } else { + /* + * try getting fs option from continuation, not mountpoint! + * Don't try logging the string from mf, since it may be bad! + */ + if (cp->fs_opts.opt_fs != mf->mf_fo->opt_fs) + plog(XLOG_ERROR, "use %s instead of 0x%x", + cp->fs_opts.opt_fs, mf->mf_fo->opt_fs); + + mp->am_link = str3cat((char *) 0, + cp->fs_opts.opt_fs, "/", link_dir); + + normalize_slash(mp->am_link); + } + } + + if (mf->mf_error > 0) { + this_error = mf->mf_error; + } else if (mf->mf_flags & (MFF_MOUNTING | MFF_UNMOUNTING)) { + /* + * Still mounting - retry later + */ +#ifdef DEBUG + dlog("Duplicate pending mount fstype %s", p->fs_type); +#endif /* DEBUG */ + this_error = -1; + } else if (FSRV_ISDOWN(mf->mf_server)) { + /* + * Would just mount from the same place + * as a hung mount - so give up + */ +#ifdef DEBUG + dlog("%s is already hung - giving up", mf->mf_mount); +#endif /* DEBUG */ + mp_error = EWOULDBLOCK; + dont_retry = TRUE; + this_error = -1; + } else if (mf->mf_flags & MFF_MOUNTED) { +#ifdef DEBUG + dlog("duplicate mount of \"%s\" ...", mf->mf_info); +#endif /* DEBUG */ + + /* + * Just call mounted() + */ + am_mounted(mp); + + this_error = 0; + break; + } + + /* + * Will usually need to play around with the mount nodes + * file attribute structure. This must be done here. + * Try and get things initialised, even if the fileserver + * is not known to be up. In the common case this will + * progress things faster. + */ + if (!this_error) { + /* + * Fill in attribute fields. + */ + if (mf->mf_ops->fs_flags & FS_DIRECTORY) + mk_fattr(mp, NFDIR); + else + mk_fattr(mp, NFLNK); + + mp->am_fattr.na_fileid = mp->am_gen; + + if (p->fs_init) + this_error = (*p->fs_init) (mf); + } + + /* + * Make sure the fileserver is UP before doing any more work + */ + if (!FSRV_ISUP(mf->mf_server)) { +#ifdef DEBUG + dlog("waiting for server %s to become available", mf->mf_server->fs_host); +#endif /* DEBUG */ + this_error = -1; + } + + if (!this_error && mf->mf_fo->opt_delay) { + /* + * If there is a delay timer on the mount + * then don't try to mount if the timer + * has not expired. + */ + int i = atoi(mf->mf_fo->opt_delay); + if (i > 0 && clocktime() < (cp->start + i)) { +#ifdef DEBUG + dlog("Mount of %s delayed by %ds", mf->mf_mount, i - clocktime() + cp->start); +#endif /* DEBUG */ + this_error = -1; + } + } + + if (this_error < 0 && !dont_retry) { + if (!mf_retry) + mf_retry = dup_mntfs(mf); + cp->retry = TRUE; + } + + if (!this_error) { + if (p->fs_flags & FS_MBACKGROUND) { + mf->mf_flags |= MFF_MOUNTING; /* XXX */ +#ifdef DEBUG + dlog("backgrounding mount of \"%s\"", mf->mf_mount); +#endif /* DEBUG */ + if (cp->callout) { + untimeout(cp->callout); + cp->callout = 0; + } + run_task(try_mount, (voidp) mp, amfs_auto_cont, (voidp) cp); + mf->mf_flags |= MFF_MKMNT; /* XXX */ + if (mf_retry) + free_mntfs(mf_retry); + return -1; + } else { +#ifdef DEBUG + dlog("foreground mount of \"%s\" ...", mf->mf_info); +#endif /* DEBUG */ + this_error = try_mount((voidp) mp); + if (this_error < 0) { + if (!mf_retry) + mf_retry = dup_mntfs(mf); + cp->retry = TRUE; + } + } + } + + if (this_error >= 0) { + if (this_error > 0) { + amd_stats.d_merr++; + if (mf != mf_retry) { + mf->mf_error = this_error; + mf->mf_flags |= MFF_ERROR; + } + } + + /* + * Wakeup anything waiting for this mount + */ + wakeup((voidp) mf); + } + } + + if (this_error && cp->retry) { + free_mntfs(mf); + mf = cp->mp->am_mnt = mf_retry; + /* + * Not retrying again (so far) + */ + cp->retry = FALSE; + cp->tried = FALSE; + /* + * Start at the beginning. + * Rewind the location vector and + * reset the default options. + */ + cp->ivec = cp->xivec; + cp->def_opts = strealloc(cp->def_opts, cp->auto_opts); + /* + * Arrange that amfs_auto_bgmount is called + * after anything else happens. + */ +#ifdef DEBUG + dlog("Arranging to retry mount of %s", cp->mp->am_path); +#endif /* DEBUG */ + sched_task(amfs_auto_retry, (voidp) cp, (voidp) mf); + if (cp->callout) + untimeout(cp->callout); + cp->callout = timeout(RETRY_INTERVAL, wakeup, (voidp) mf); + + cp->mp->am_ttl = clocktime() + RETRY_INTERVAL; + + /* + * Not done yet - so don't return anything + */ + return -1; + } + + if (hard_error < 0 || this_error == 0) + hard_error = this_error; + + /* + * Discard handle on duff filesystem. + * This should never happen since it + * should be caught by the case above. + */ + if (mf_retry) { + if (hard_error) + plog(XLOG_ERROR, "discarding a retry mntfs for %s", mf_retry->mf_mount); + free_mntfs(mf_retry); + } + + /* + * If we get here, then either the mount succeeded or + * there is no more mount information available. + */ + if (hard_error < 0 && mp_error) + hard_error = cp->mp->am_error = mp_error; + if (hard_error > 0) { + /* + * Set a small(ish) timeout on an error node if + * the error was not a time out. + */ + switch (hard_error) { + case ETIMEDOUT: + case EWOULDBLOCK: + cp->mp->am_timeo = 17; + break; + default: + cp->mp->am_timeo = 5; + break; + } + new_ttl(cp->mp); + } + + /* + * Make sure that the error value in the mntfs has a + * reasonable value. + */ + if (mf->mf_error < 0) { + mf->mf_error = hard_error; + if (hard_error) + mf->mf_flags |= MFF_ERROR; + } + + /* + * In any case we don't need the continuation any more + */ + free_continuation(cp); + + return hard_error; +} + + +/* + * Automount interface to RPC lookup routine + * Find the corresponding entry and return + * the file handle for it. + */ +am_node * +amfs_auto_lookuppn(am_node *mp, char *fname, int *error_return, int op) +{ + am_node *ap, *new_mp, *ap_hung; + char *info; /* Mount info - where to get the file system */ + char **ivec, **xivec; /* Split version of info */ + char *auto_opts; /* Automount options */ + int error = 0; /* Error so far */ + char path_name[MAXPATHLEN]; /* General path name buffer */ + char *pfname; /* Path for database lookup */ + struct continuation *cp; /* Continuation structure if need to mount */ + int in_progress = 0; /* # of (un)mount in progress */ + char *dflts; + mntfs *mf; + +#ifdef DEBUG + dlog("in amfs_auto_lookuppn"); +#endif /* DEBUG */ + + /* + * If the server is shutting down + * then don't return information + * about the mount point. + */ + if (amd_state == Finishing) { +#ifdef DEBUG + if ((mf = mp->am_mnt) == 0 || mf->mf_ops == &amfs_direct_ops) { + dlog("%s mount ignored - going down", fname); + } else { + dlog("%s/%s mount ignored - going down", mp->am_path, fname); + } +#endif /* DEBUG */ + ereturn(ENOENT); + } + + /* + * Handle special case of "." and ".." + */ + if (fname[0] == '.') { + if (fname[1] == '\0') + return mp; /* "." is the current node */ + if (fname[1] == '.' && fname[2] == '\0') { + if (mp->am_parent) { +#ifdef DEBUG + dlog(".. in %s gives %s", mp->am_path, mp->am_parent->am_path); +#endif /* DEBUG */ + return mp->am_parent; /* ".." is the parent node */ + } + ereturn(ESTALE); + } + } + + /* + * Check for valid key name. + * If it is invalid then pretend it doesn't exist. + */ + if (!valid_key(fname)) { + plog(XLOG_WARNING, "Key \"%s\" contains a disallowed character", fname); + ereturn(ENOENT); + } + + /* + * Expand key name. + * fname is now a private copy. + */ + fname = expand_key(fname); + + for (ap_hung = 0, ap = mp->am_child; ap; ap = ap->am_osib) { + /* + * Otherwise search children of this node + */ + if (FSTREQ(ap->am_name, fname)) { + mf = ap->am_mnt; + if (ap->am_error) { + error = ap->am_error; + continue; + } + /* + * If the error code is undefined then it must be + * in progress. + */ + if (mf->mf_error < 0) + goto in_progrss; + + /* + * Check for a hung node + */ + if (FSRV_ISDOWN(mf->mf_server)) { +#ifdef DEBUG + dlog("server hung"); +#endif /* DEBUG */ + error = ap->am_error; + ap_hung = ap; + continue; + } + /* + * If there was a previous error with this node + * then return that error code. + */ + if (mf->mf_flags & MFF_ERROR) { + error = mf->mf_error; + continue; + } + if (!(mf->mf_flags & MFF_MOUNTED) || (mf->mf_flags & MFF_UNMOUNTING)) { + in_progrss: + /* + * If the fs is not mounted or it is unmounting then there + * is a background (un)mount in progress. In this case + * we just drop the RPC request (return nil) and + * wait for a retry, by which time the (un)mount may + * have completed. + */ +#ifdef DEBUG + dlog("ignoring mount of %s in %s -- flags (%x) in progress", + fname, mf->mf_mount, mf->mf_flags); +#endif /* DEBUG */ + in_progress++; + continue; + } + + /* + * Otherwise we have a hit: return the current mount point. + */ +#ifdef DEBUG + dlog("matched %s in %s", fname, ap->am_path); +#endif /* DEBUG */ + XFREE(fname); + return ap; + } + } + + if (in_progress) { +#ifdef DEBUG + dlog("Waiting while %d mount(s) in progress", in_progress); +#endif /* DEBUG */ + XFREE(fname); + ereturn(-1); + } + + /* + * If an error occured then return it. + */ + if (error) { +#ifdef DEBUG + errno = error; /* XXX */ + dlog("Returning error: %m", error); +#endif /* DEBUG */ + XFREE(fname); + ereturn(error); + } + + /* + * If doing a delete then don't create again! + */ + switch (op) { + case VLOOK_DELETE: + ereturn(ENOENT); + + case VLOOK_CREATE: + break; + + default: + plog(XLOG_FATAL, "Unknown op to amfs_auto_lookuppn: 0x%x", op); + ereturn(EINVAL); + } + + /* + * If the server is going down then just return, + * don't try to mount any more file systems + */ + if ((int) amd_state >= (int) Finishing) { +#ifdef DEBUG + dlog("not found - server going down anyway"); +#endif /* DEBUG */ + XFREE(fname); + ereturn(ENOENT); + } + + /* + * If we get there then this is a reference to an, + * as yet, unknown name so we need to search the mount + * map for it. + */ + if (mp->am_pref) { + sprintf(path_name, "%s%s", mp->am_pref, fname); + pfname = path_name; + } else { + pfname = fname; + } + + mf = mp->am_mnt; + +#ifdef DEBUG + dlog("will search map info in %s to find %s", mf->mf_info, pfname); +#endif /* DEBUG */ + /* + * Consult the oracle for some mount information. + * info is malloc'ed and belongs to this routine. + * It ends up being free'd in free_continuation(). + * + * Note that this may return -1 indicating that information + * is not yet available. + */ + error = mapc_search((mnt_map *) mf->mf_private, pfname, &info); + if (error) { + if (error > 0) + plog(XLOG_MAP, "No map entry for %s", pfname); + else + plog(XLOG_MAP, "Waiting on map entry for %s", pfname); + XFREE(fname); + ereturn(error); + } +#ifdef DEBUG + dlog("mount info is %s", info); +#endif /* DEBUG */ + + /* + * Split info into an argument vector. + * The vector is malloc'ed and belongs to + * this routine. It is free'd in free_continuation() + */ + xivec = ivec = strsplit(info, ' ', '\"'); + + /* + * Default error code... + */ + if (ap_hung) + error = EWOULDBLOCK; + else + error = ENOENT; + + /* + * Allocate a new map + */ + new_mp = exported_ap_alloc(); + if (new_mp == 0) { + XFREE(xivec); + XFREE(info); + XFREE(fname); + ereturn(ENOSPC); + } + if (mf->mf_auto) + auto_opts = mf->mf_auto; + else + auto_opts = ""; + + auto_opts = strdup(auto_opts); + +#ifdef DEBUG + dlog("searching for /defaults entry"); +#endif /* DEBUG */ + if (mapc_search((mnt_map *) mf->mf_private, "/defaults", &dflts) == 0) { + char *dfl; + char **rvec; +#ifdef DEBUG + dlog("/defaults gave %s", dflts); +#endif /* DEBUG */ + if (*dflts == '-') + dfl = dflts + 1; + else + dfl = dflts; + + /* + * Chop the defaults up + */ + rvec = strsplit(dfl, ' ', '\"'); + + if (gopt.flags & CFM_ENABLE_DEFAULT_SELECTORS) { + /* + * Pick whichever first entry matched the list of selectors. + * Strip the selectors from the string, and assign to dfl the + * rest of the string. + */ + if (rvec) { + am_opts ap; + am_ops *pt; + char **sp = rvec; + while (*sp) { /* loop until you find something, if any */ + memset((char *) &ap, 0, sizeof(am_opts)); + pt = ops_match(&ap, *sp, "", mp->am_path, "/defaults", + mp->am_parent->am_mnt->mf_info); + if (pt == &amfs_error_ops) { + plog(XLOG_MAP, "failed to match defaults for \"%s\"", *sp); + } else { + dfl = strip_selectors(*sp, "/defaults"); + plog(XLOG_MAP, "matched default selectors \"%s\"", dfl); + break; + } + ++sp; + } + } + } else { /* not enable_default_selectors */ + /* + * Extract first value + */ + dfl = rvec[0]; + } + + /* + * If there were any values at all... + */ + if (dfl) { + /* + * Log error if there were other values + */ + if (!(gopt.flags & CFM_ENABLE_DEFAULT_SELECTORS) && rvec[1]) { +# ifdef DEBUG + dlog("/defaults chopped into %s", dfl); +# endif /* DEBUG */ + plog(XLOG_USER, "More than a single value for /defaults in %s", mf->mf_info); + } + + /* + * Prepend to existing defaults if they exist, + * otherwise just use these defaults. + */ + if (*auto_opts && *dfl) { + char *nopts = (char *) xmalloc(strlen(auto_opts) + strlen(dfl) + 2); + sprintf(nopts, "%s;%s", dfl, auto_opts); + XFREE(auto_opts); + auto_opts = nopts; + } else if (*dfl) { + auto_opts = strealloc(auto_opts, dfl); + } + } + XFREE(dflts); + /* + * Don't need info vector any more + */ + XFREE(rvec); + } + + /* + * Fill it in + */ + init_map(new_mp, fname); + + /* + * Put it in the table + */ + insert_am(new_mp, mp); + + /* + * Fill in some other fields, + * path and mount point. + * + * bugfix: do not prepend old am_path if direct map + * <wls@astro.umd.edu> William Sebok + */ + new_mp->am_path = str3cat(new_mp->am_path, + mf->mf_ops == &amfs_direct_ops ? "" : mp->am_path, + *fname == '/' ? "" : "/", fname); + +#ifdef DEBUG + dlog("setting path to %s", new_mp->am_path); +#endif /* DEBUG */ + + /* + * Take private copy of pfname + */ + pfname = strdup(pfname); + + /* + * Construct a continuation + */ + cp = ALLOC(struct continuation); + cp->callout = 0; + cp->mp = new_mp; + cp->xivec = xivec; + cp->ivec = ivec; + cp->info = info; + cp->key = pfname; + cp->auto_opts = auto_opts; + cp->retry = FALSE; + cp->tried = FALSE; + cp->start = clocktime(); + cp->def_opts = strdup(auto_opts); + memset((voidp) &cp->fs_opts, 0, sizeof(cp->fs_opts)); + + /* + * Try and mount the file system. If this succeeds immediately (possible + * for a ufs file system) then return the attributes, otherwise just + * return an error. + */ + error = amfs_auto_bgmount(cp, error); + reschedule_timeout_mp(); + if (!error) { + XFREE(fname); + return new_mp; + } + + /* + * Code for quick reply. If nfs_program_2_transp is set, then + * its the transp that's been passed down from nfs_program_2(). + * If new_mp->am_transp is not already set, set it by copying in + * nfs_program_2_transp. Once am_transp is set, quick_reply() can + * use it to send a reply to the client that requested this mount. + */ + if (nfs_program_2_transp && !new_mp->am_transp) { + new_mp->am_transp = (SVCXPRT *) xmalloc(sizeof(SVCXPRT)); + *(new_mp->am_transp) = *nfs_program_2_transp; + } + if (error && (new_mp->am_mnt->mf_ops == &amfs_error_ops)) + new_mp->am_error = error; + + assign_error_mntfs(new_mp); + + XFREE(fname); + + ereturn(error); +} + + +/* + * Locate next node in sibling list which is mounted + * and is not an error node. + */ +am_node * +next_nonerror_node(am_node *xp) +{ + mntfs *mf; + + /* + * Bug report (7/12/89) from Rein Tollevik <rein@ifi.uio.no> + * Fixes a race condition when mounting direct automounts. + * Also fixes a problem when doing a readdir on a directory + * containing hung automounts. + */ + while (xp && + (!(mf = xp->am_mnt) || /* No mounted filesystem */ + mf->mf_error != 0 || /* There was a mntfs error */ + xp->am_error != 0 || /* There was a mount error */ + !(mf->mf_flags & MFF_MOUNTED) || /* The fs is not mounted */ + (mf->mf_server->fs_flags & FSF_DOWN)) /* The fs may be down */ + ) + xp = xp->am_osib; + + return xp; +} + + +/* + * This readdir function which call a special version of it that allows + * browsing if browsable_dirs=yes was set on the map. + */ +int +amfs_auto_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, int count) +{ + u_int gen = *(u_int *) cookie; + am_node *xp; + mntent_t mnt; + + dp->dl_eof = FALSE; /* assume readdir not done */ + + /* check if map is browsable */ + if (mp->am_mnt && mp->am_mnt->mf_mopts) { + mnt.mnt_opts = mp->am_mnt->mf_mopts; + if (hasmntopt(&mnt, "fullybrowsable")) + return amfs_auto_readdir_browsable(mp, cookie, dp, ep, count, TRUE); + if (hasmntopt(&mnt, "browsable")) + return amfs_auto_readdir_browsable(mp, cookie, dp, ep, count, FALSE); + } + + 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 */ + /* + * Check for enough room. This is extremely approximate but is more + * than enough space. Really need 2 times: + * 4byte fileid + * 4byte cookie + * 4byte name length + * 4byte name + * plus the dirlist structure */ + if (count < (2 * (2 * (sizeof(*ep) + sizeof("..") + 4) + sizeof(*dp)))) + return EINVAL; + + xp = next_nonerror_node(mp->am_child); + dp->dl_entries = ep; + + /* construct "." */ + ep[0].ne_fileid = mp->am_gen; + ep[0].ne_name = "."; + ep[0].ne_nextentry = &ep[1]; + *(u_int *) ep[0].ne_cookie = 0; + + /* construct ".." */ + if (mp->am_parent) + ep[1].ne_fileid = mp->am_parent->am_gen; + else + ep[1].ne_fileid = mp->am_gen; + ep[1].ne_name = ".."; + ep[1].ne_nextentry = 0; + *(u_int *) ep[1].ne_cookie = + xp ? xp->am_gen : ~(u_int) 0; + + if (!xp) + dp->dl_eof = TRUE; /* by default assume readdir done */ + + return 0; + } +#ifdef DEBUG + dlog("real child"); +#endif /* DEBUG */ + + if (gen == ~(u_int) 0) { +#ifdef DEBUG + dlog("End of readdir in %s", mp->am_path); +#endif /* DEBUG */ + dp->dl_eof = TRUE; + dp->dl_entries = 0; + return 0; + } + + /* non-browsable directories code */ + xp = mp->am_child; + while (xp && xp->am_gen != gen) + xp = xp->am_osib; + + if (xp) { + int nbytes = count / 2; /* conservative */ + int todo = MAX_READDIR_ENTRIES; + dp->dl_entries = ep; + do { + am_node *xp_next = next_nonerror_node(xp->am_osib); + + if (xp_next) { + *(u_int *) ep->ne_cookie = xp_next->am_gen; + } else { + *(u_int *) ep->ne_cookie = ~(u_int) 0; + dp->dl_eof = TRUE; + } + + ep->ne_fileid = xp->am_gen; + ep->ne_name = xp->am_name; + nbytes -= sizeof(*ep) + 1; + if (xp->am_name) + nbytes -= strlen(xp->am_name); + + xp = xp_next; + + if (nbytes > 0 && !dp->dl_eof && todo > 1) { + ep->ne_nextentry = ep + 1; + ep++; + --todo; + } else { + todo = 0; + } + } while (todo > 0); + + ep->ne_nextentry = 0; + + return 0; + } + return ESTALE; +} + + +/* This one is called only if map is browsable */ +static int +amfs_auto_readdir_browsable(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, int count, int fully_browsable) +{ + u_int gen = *(u_int *) cookie; + int chain_length, i; + static nfsentry *te, *te_next; +#ifdef DEBUG_READDIR + nfsentry *ne; + static int j; +#endif /* DEBUG_READDIR */ + + dp->dl_eof = FALSE; /* assume readdir not done */ + +#ifdef DEBUG_READDIR + plog(XLOG_INFO, "amfs_auto_readdir_browsable gen=%u, count=%d", + gen, count); +#endif /* DEBUG_READDIR */ + + 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 */ + /* + * Check for enough room. This is extremely approximate but is more + * than enough space. Really need 2 times: + * 4byte fileid + * 4byte cookie + * 4byte name length + * 4byte name + * plus the dirlist structure */ + if (count < (2 * (2 * (sizeof(*ep) + sizeof("..") + 4) + sizeof(*dp)))) + return EINVAL; + + /* + * compute # of entries to send in this chain. + * heuristics: 128 bytes per entry. + * This is too much probably, but it seems to work better because + * of the re-entrant nature of nfs_readdir, and esp. on systems + * like OpenBSD 2.2. + */ + chain_length = count / 128; + + /* reset static state counters */ + te = te_next = NULL; + + dp->dl_entries = ep; + + /* construct "." */ + ep[0].ne_fileid = mp->am_gen; + ep[0].ne_name = "."; + ep[0].ne_nextentry = &ep[1]; + *(u_int *) ep[0].ne_cookie = 0; + + /* construct ".." */ + if (mp->am_parent) + ep[1].ne_fileid = mp->am_parent->am_gen; + else + ep[1].ne_fileid = mp->am_gen; + ep[1].ne_name = ".."; + ep[1].ne_nextentry = 0; + *(u_int *) ep[1].ne_cookie = ~(u_int) 0; + + /* + * If map is browsable, call a function make_entry_chain() to construct + * a linked list of unmounted keys, and return it. Then link the chain + * to the regular list. Get the chain only once, but return + * chunks of it each time. + */ + te = make_entry_chain(mp, dp->dl_entries, fully_browsable); + if (!te) + return 0; +#ifdef DEBUG_READDIR + j = 0; + for (ne=te; ne; ne=ne->ne_nextentry) + plog(XLOG_INFO, "gen1 key %4d \"%s\"", j++, ne->ne_name); +#endif /* DEBUG_READDIR */ + + /* return only "chain_length" entries */ + te_next = te; + for (i=1; i<chain_length; ++i) { + te_next = te_next->ne_nextentry; + if (!te_next) + break; + } + if (te_next) { + nfsentry *te_saved = te_next->ne_nextentry; + te_next->ne_nextentry = NULL; /* terminate "te" chain */ + te_next = te_saved; /* save rest of "te" for next interation */ + dp->dl_eof = FALSE; /* tell readdir there's more */ + } else { + dp->dl_eof = TRUE; /* tell readdir that's it */ + } + ep[1].ne_nextentry = te; /* append this chunk of "te" chain */ +#ifdef DEBUG_READDIR + for (ne=te; ne; ne=ne->ne_nextentry) + plog(XLOG_INFO, "gen2 key %4d \"%s\"", j++, ne->ne_name); +#endif /* DEBUG_READDIR */ + return 0; + } /* end of "if (gen == 0)" statement */ + +#ifdef DEBUG + dlog("real child"); +#endif /* DEBUG */ + + if (gen == ~(u_int) 0) { +#ifdef DEBUG + dlog("End of readdir in %s", mp->am_path); +#endif /* DEBUG */ + dp->dl_eof = TRUE; + dp->dl_entries = 0; + return 0; + } + + /* + * If browsable directories, then continue serving readdir() with another + * chunk of entries, starting from where we left off (when gen was equal + * to 0). Once again, assume last chunk served to readdir. + */ + dp->dl_eof = TRUE; + dp->dl_entries = ep; + + te = te_next; /* reset 'te' from last saved te_next */ + if (!te) { /* another indicator of end of readdir */ + dp->dl_entries = 0; + return 0; + } + /* + * compute # of entries to send in this chain. + * heuristics: 128 bytes per entry. + */ + chain_length = count / 128; + + /* return only "chain_length" entries */ + for (i=1; i<chain_length; ++i) { + te_next = te_next->ne_nextentry; + if (!te_next) + break; + } + if (te_next) { + nfsentry *te_saved = te_next->ne_nextentry; + te_next->ne_nextentry = NULL; /* terminate "te" chain */ + te_next = te_saved; /* save rest of "te" for next interation */ + dp->dl_eof = FALSE; /* tell readdir there's more */ + } + ep = te; /* send next chunk of "te" chain */ + dp->dl_entries = ep; +#ifdef DEBUG_READDIR + plog(XLOG_INFO, "dl_entries=0x%x, te_next=0x%x, dl_eof=%d", + dp->dl_entries, te_next, dp->dl_eof); + for (ne=te; ne; ne=ne->ne_nextentry) + plog(XLOG_INFO, "gen3 key %4d \"%s\"", j++, ne->ne_name); +#endif /* DEBUG_READDIR */ + return 0; +} + + +int +amfs_auto_fmount(am_node *mp) +{ + mntfs *mf = mp->am_mnt; + return (*mf->mf_ops->fmount_fs) (mf); +} + + +int +amfs_auto_fumount(am_node *mp) +{ + mntfs *mf = mp->am_mnt; + return (*mf->mf_ops->fumount_fs) (mf); +} diff --git a/contrib/amd/amd/amfs_direct.c b/contrib/amd/amd/amfs_direct.c new file mode 100644 index 0000000..1558ae0 --- /dev/null +++ b/contrib/amd/amd/amfs_direct.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_direct.c,v 1.1 1997-1998/06/30 19:22:30 ezk Exp ezk $ + * + */ + +/* + * Direct file system + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/**************************************************************************** + *** FORWARD DEFINITIONS *** + ****************************************************************************/ +static am_node *amfs_direct_readlink(am_node *mp, int *error_return); + +/**************************************************************************** + *** OPS STRUCTURES *** + ****************************************************************************/ +am_ops amfs_direct_ops = +{ + "direct", + amfs_auto_match, + 0, /* amfs_direct_init */ + amfs_toplvl_mount, + 0, + amfs_toplvl_umount, + 0, + amfs_error_lookuppn, + amfs_error_readdir, + amfs_direct_readlink, + amfs_toplvl_mounted, + 0, /* amfs_auto_umounted */ + find_amfs_auto_srvr, + FS_MKMNT | FS_NOTIMEOUT | FS_BACKGROUND | FS_AMQINFO +}; + + +/**************************************************************************** + *** FUNCTIONS *** + ****************************************************************************/ + +static am_node * +amfs_direct_readlink(am_node *mp, int *error_return) +{ + am_node *xp; + int rc = 0; + + xp = next_nonerror_node(mp->am_child); + if (!xp) { + if (!mp->am_mnt->mf_private) + amfs_auto_mkcacheref(mp->am_mnt); /* XXX */ + xp = amfs_auto_lookuppn(mp, mp->am_path + 1, &rc, VLOOK_CREATE); + } + if (xp) { + new_ttl(xp); /* (7/12/89) from Rein Tollevik */ + return xp; + } + if (amd_state == Finishing) + rc = ENOENT; + *error_return = rc; + return 0; +} diff --git a/contrib/amd/amd/amfs_error.c b/contrib/amd/amd/amfs_error.c new file mode 100644 index 0000000..ccb037b --- /dev/null +++ b/contrib/amd/amd/amfs_error.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_error.c,v 5.2.2.1 1992/02/09 15:08:21 jsp beta $ + * + */ + +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +static char * amfs_error_match(am_opts *fo); +static int amfs_error_fmount(mntfs *mf); +static int amfs_error_fumount(mntfs *mf); +static void amfs_error_umounted(am_node *mp); + + +/* + * Ops structure + */ +am_ops amfs_error_ops = +{ + "error", + amfs_error_match, + 0, /* amfs_error_init */ + amfs_auto_fmount, + amfs_error_fmount, + amfs_auto_fumount, + amfs_error_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* amfs_error_readlink */ + 0, /* amfs_error_mounted */ + amfs_error_umounted, + find_amfs_auto_srvr, + FS_DISCARD +}; + + + +/* + * EFS file system always matches + */ +static char * +amfs_error_match(am_opts *fo) +{ + return strdup("(error-hook)"); +} + + +static int +amfs_error_fmount(mntfs *mf) +{ + return ENOENT; +} + + +static int +amfs_error_fumount(mntfs *mf) +{ + /* + * 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. + */ +am_node * +amfs_error_lookuppn(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. + */ +int +amfs_error_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, int count) +{ + return ESTALE; +} + + +/* + * umounted() callback for EFS. + * + * This prevents core-dumps on callbacks to error file-systems from + * nfsx_fumount. + */ +static void +amfs_error_umounted(am_node *mp) +{ + /* nothing to do */ +} diff --git a/contrib/amd/amd/amfs_host.c b/contrib/amd/amd/amfs_host.c new file mode 100644 index 0000000..6be259d --- /dev/null +++ b/contrib/amd/amd/amfs_host.c @@ -0,0 +1,686 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_host.c,v 5.2.2.2 1992/05/31 16:36:08 jsp Exp $ + * + */ + +/* + * NFS host file system. + * Mounts all exported filesystems from a given host. + * This has now degenerated into a mess but will not + * be rewritten. Amd 6 will support the abstractions + * needed to make this work correctly. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +static char *amfs_host_match(am_opts *fo); +static int amfs_host_fmount(mntfs *mf); +static int amfs_host_fumount(mntfs *mf); +static int amfs_host_init(mntfs *mf); +static void amfs_host_umounted(am_node *mp); + +/* + * Ops structure + */ +am_ops amfs_host_ops = +{ + "host", + amfs_host_match, + amfs_host_init, + amfs_auto_fmount, + amfs_host_fmount, + amfs_auto_fumount, + amfs_host_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* amfs_host_readlink */ + 0, /* amfs_host_mounted */ + amfs_host_umounted, + find_nfs_srvr, + FS_MKMNT | FS_BACKGROUND | FS_AMQINFO +}; + + +/* + * Determine the mount point: + * + * The next change we put in to better handle PCs. This is a bit + * disgusting, so you'd better sit down. We change the make_mntpt function + * to look for exported file systems without a leading '/'. If they don't + * have a leading '/', we add one. If the export is 'a:' through 'z:' + * (without a leading slash), we change it to 'a%' (or b% or z%). This + * allows the entire PC disk to be mounted. + */ +static void +make_mntpt(char *mntpt, const exports ex, const mntfs *mf) +{ + if (ex->ex_dir[0] == '/') { + if (ex->ex_dir[1] == 0) + strcpy(mntpt, (mf)->mf_mount); + else + sprintf(mntpt, "%s%s", mf->mf_mount, ex->ex_dir); + } else if (ex->ex_dir[0] >= 'a' && + ex->ex_dir[0] <= 'z' && + ex->ex_dir[1] == ':' && + ex->ex_dir[2] == '/' && + ex->ex_dir[3] == 0) + sprintf(mntpt, "%s/%c%%", mf->mf_mount, ex->ex_dir[0]); + else + sprintf(mntpt, "%s/%s", mf->mf_mount, ex->ex_dir); +} + + +/* + * Execute needs the same as NFS plus a helper command + */ +static char * +amfs_host_match(am_opts *fo) +{ + extern am_ops nfs_ops; + + /* + * Make sure rfs is specified to keep nfs_match happy... + */ + if (!fo->opt_rfs) + fo->opt_rfs = "/"; + + return (*nfs_ops.fs_match) (fo); +} + + +static int +amfs_host_init(mntfs *mf) +{ + fserver *fs; + u_short port; + + if (strchr(mf->mf_info, ':') == 0) + return ENOENT; + + /* + * This is primarily to schedule a wakeup so that as soon + * as our fileserver is ready, we can continue setting up + * the host filesystem. If we don't do this, the standard + * amfs_auto code will set up a fileserver structure, but it will + * have to wait for another nfs request from the client to come + * in before finishing. Our way is faster since we don't have + * to wait for the client to resend its request (which could + * take a second or two). + */ + /* + * First, we find the fileserver for this mntfs and then call + * nfs_srvr_port with our mntfs passed as the wait channel. + * nfs_srvr_port will check some things and then schedule + * it so that when the fileserver is ready, a wakeup is done + * on this mntfs. amfs_auto_cont() is already sleeping on this mntfs + * so as soon as that wakeup happens amfs_auto_cont() is called and + * this mount is retried. + */ + if ((fs = mf->mf_server)) + /* + * We don't really care if there's an error returned. + * Since this is just to help speed things along, the + * error will get handled properly elsewhere. + */ + (void) nfs_srvr_port(fs, &port, (voidp) mf); + + return 0; +} + + +static int +do_mount(am_nfs_handle_t *fhp, char *dir, char *fs_name, char *opts, mntfs *mf) +{ + struct stat stb; + +#ifdef DEBUG + dlog("amfs_host: mounting fs %s on %s\n", fs_name, dir); +#endif /* DEBUG */ + + (void) mkdirs(dir, 0555); + if (stat(dir, &stb) < 0 || (stb.st_mode & S_IFMT) != S_IFDIR) { + plog(XLOG_ERROR, "No mount point for %s - skipping", dir); + return ENOENT; + } + + return mount_nfs_fh(fhp, dir, fs_name, opts, mf); +} + + +static int +sortfun(const voidp x, const voidp y) +{ + exports *a = (exports *) x; + exports *b = (exports *) y; + + return strcmp((*a)->ex_dir, (*b)->ex_dir); +} + + +/* + * Get filehandle + */ +static int +fetch_fhandle(CLIENT * client, char *dir, am_nfs_handle_t *fhp, u_long nfs_version) +{ + struct timeval tv; + enum clnt_stat clnt_stat; + + /* + * Pick a number, any number... + */ + tv.tv_sec = 20; + tv.tv_usec = 0; + +#ifdef DEBUG + dlog("Fetching fhandle for %s", dir); +#endif /* DEBUG */ + + /* + * Call the mount daemon on the remote host to + * get the filehandle. Use NFS version specific call. + */ + + plog(XLOG_INFO, "fetch_fhandle: NFS version %d", nfs_version); +#ifdef HAVE_FS_NFS3 + if (nfs_version == NFS_VERSION3) { + memset((char *) &fhp->v3, 0, sizeof(fhp->v3)); + clnt_stat = clnt_call(client, + MOUNTPROC_MNT, + (XDRPROC_T_TYPE) xdr_dirpath, + (SVC_IN_ARG_TYPE) &dir, + (XDRPROC_T_TYPE) xdr_mountres3, + (SVC_IN_ARG_TYPE) &fhp->v3, + tv); + if (clnt_stat != RPC_SUCCESS) { + plog(XLOG_ERROR, "mountd rpc failed: %s", clnt_sperrno(clnt_stat)); + return EIO; + } + /* Check the status of the filehandle */ + if ((errno = fhp->v3.fhs_status)) { +#ifdef DEBUG + dlog("fhandle fetch for mount version 3 failed: %m"); +#endif /* DEBUG */ + return errno; + } + } else { /* not NFS_VERSION3 mount */ +#endif /* HAVE_FS_NFS3 */ + clnt_stat = clnt_call(client, + MOUNTPROC_MNT, + (XDRPROC_T_TYPE) xdr_dirpath, + (SVC_IN_ARG_TYPE) &dir, + (XDRPROC_T_TYPE) xdr_fhstatus, + (SVC_IN_ARG_TYPE) &fhp->v2, + tv); + if (clnt_stat != RPC_SUCCESS) { + char *msg = clnt_sperrno(clnt_stat); + plog(XLOG_ERROR, "mountd rpc failed: %s", msg); + return EIO; + } + /* Check status of filehandle */ + if (fhp->v2.fhs_status) { + errno = fhp->v2.fhs_status; +#ifdef DEBUG + dlog("fhandle fetch for mount version 1 failed: %m"); +#endif /* DEBUG */ + return errno; + } +#ifdef HAVE_FS_NFS3 + } /* end of "if (nfs_version == NFS_VERSION3)" statement */ +#endif /* HAVE_FS_NFS3 */ + + /* all is well */ + return 0; +} + + +/* + * Scan mount table to see if something already mounted + */ +static int +already_mounted(mntlist *mlist, char *dir) +{ + mntlist *ml; + + for (ml = mlist; ml; ml = ml->mnext) + if (STREQ(ml->mnt->mnt_dir, dir)) + return 1; + return 0; +} + + +/* + * Mount the export tree from a host + */ +static int +amfs_host_fmount(mntfs *mf) +{ + struct timeval tv2; + CLIENT *client; + enum clnt_stat clnt_stat; + int n_export; + int j, k; + exports exlist = 0, ex; + exports *ep = 0; + am_nfs_handle_t *fp = 0; + char *host; + int error = 0; + struct sockaddr_in sin; + int sock = RPC_ANYSOCK; + int ok = FALSE; + mntlist *mlist; + char fs_name[MAXPATHLEN], *rfs_dir; + char mntpt[MAXPATHLEN]; + struct timeval tv; + u_long mnt_version; + + /* + * Read the mount list + */ + mlist = read_mtab(mf->mf_mount, mnttab_file_name); + +#ifdef MOUNT_TABLE_ON_FILE + /* + * Unlock the mount list + */ + unlock_mntlist(); +#endif /* MOUNT_TABLE_ON_FILE */ + + /* + * Take a copy of the server hostname, address, and nfs version + * to mount version conversion. + */ + host = mf->mf_server->fs_host; + sin = *mf->mf_server->fs_ip; + plog(XLOG_INFO, "amfs_host_fmount: NFS version %d", mf->mf_server->fs_version); +#ifdef HAVE_FS_NFS3 + if (mf->mf_server->fs_version == NFS_VERSION3) + mnt_version = MOUNTVERS3; + else +#endif /* HAVE_FS_NFS3 */ + mnt_version = MOUNTVERS; + + /* + * The original 10 second per try timeout is WAY too large, especially + * if we're only waiting 10 or 20 seconds max for the response. + * That would mean we'd try only once in 10 seconds, and we could + * lose the transmitt or receive packet, and never try again. + * A 2-second per try timeout here is much more reasonable. + * 09/28/92 Mike Mitchell, mcm@unx.sas.com + */ + tv.tv_sec = 2; + tv.tv_usec = 0; + + /* + * Create a client attached to mountd + */ + client = get_mount_client(host, &sin, &tv, &sock, mnt_version); + if (client == NULL) { +#ifdef HAVE_CLNT_SPCREATEERROR + plog(XLOG_ERROR, "get_mount_client failed for %s: %s", + host, clnt_spcreateerror("")); +#else /* not HAVE_CLNT_SPCREATEERROR */ + plog(XLOG_ERROR, "get_mount_client failed for %s", host); +#endif /* not HAVE_CLNT_SPCREATEERROR */ + error = EIO; + goto out; + } + if (!nfs_auth) { + error = make_nfs_auth(); + if (error) + 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, + (XDRPROC_T_TYPE) xdr_void, + 0, + (XDRPROC_T_TYPE) xdr_exports, + (SVC_IN_ARG_TYPE) & exlist, + tv2); + if (clnt_stat != RPC_SUCCESS) { + char *msg = clnt_sperrno(clnt_stat); + plog(XLOG_ERROR, "host_fmount rpc failed: %s", msg); + /* 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++; + } + + /* + * Allocate an array of pointers into the list + * so that they can be sorted. If the filesystem + * is already mounted then ignore it. + */ + ep = (exports *) xmalloc(n_export * sizeof(exports)); + for (j = 0, ex = exlist; ex; ex = ex->ex_next) { + make_mntpt(mntpt, ex, mf); + if (!already_mounted(mlist, mntpt)) + ep[j++] = ex; + } + n_export = j; + + /* + * 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 = (am_nfs_handle_t *) xmalloc(n_export * sizeof(am_nfs_handle_t)); + + /* + * Try to obtain filehandles for each directory. + * If a fetch fails then just zero out the array + * reference but discard the error. + */ + for (j = k = 0; j < n_export; j++) { + /* Check and avoid a duplicated export entry */ + if (j > k && ep[k] && STREQ(ep[j]->ex_dir, ep[k]->ex_dir)) { +#ifdef DEBUG + dlog("avoiding dup fhandle requested for %s", ep[j]->ex_dir); +#endif /* DEBUG */ + ep[j] = 0; + } else { + k = j; + error = fetch_fhandle(client, ep[j]->ex_dir, &fp[j], + mf->mf_server->fs_version); + if (error) + 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. + */ + strncpy(fs_name, mf->mf_info, sizeof(fs_name)); + if ((rfs_dir = strchr(fs_name, ':')) == (char *) 0) { + plog(XLOG_FATAL, "amfs_host_fmount: mf_info has no colon"); + error = EINVAL; + goto out; + } + ++rfs_dir; + for (j = 0; j < n_export; j++) { + ex = ep[j]; + if (ex) { + strcpy(rfs_dir, ex->ex_dir); + make_mntpt(mntpt, ex, mf); + if (do_mount(&fp[j], mntpt, fs_name, mf->mf_mopts, mf) == 0) + ok = TRUE; + } + } + + /* + * Clean up and exit + */ +out: + discard_mntlist(mlist); + if (ep) + XFREE(ep); + if (fp) + XFREE(fp); + if (sock != RPC_ANYSOCK) + (void) amu_close(sock); + if (client) + clnt_destroy(client); + if (exlist) + xdr_pri_free((XDRPROC_T_TYPE) xdr_exports, (caddr_t) &exlist); + if (ok) + return 0; + return error; +} + + +/* + * Return true if pref is a directory prefix of dir. + * + * XXX TODO: + * Does not work if pref is "/". + */ +static int +directory_prefix(char *pref, char *dir) +{ + int len = strlen(pref); + + if (!NSTREQ(pref, dir, len)) + return FALSE; + if (dir[len] == '/' || dir[len] == '\0') + return TRUE; + return FALSE; +} + + +/* + * Unmount a mount tree + */ +static int +amfs_host_fumount(mntfs *mf) +{ + mntlist *ml, *mprev; + int xerror = 0; + + /* + * Read the mount list + */ + mntlist *mlist = read_mtab(mf->mf_mount, mnttab_file_name); + +#ifdef MOUNT_TABLE_ON_FILE + /* + * Unlock the mount list + */ + unlock_mntlist(); +#endif /* MOUNT_TABLE_ON_FILE */ + + /* + * 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 && !xerror; ml = ml->mnext) { + char *dir = ml->mnt->mnt_dir; + if (directory_prefix(mf->mf_mount, dir)) { + int error; +#ifdef DEBUG + dlog("amfs_host: unmounts %s", dir); +#endif /* DEBUG */ + /* + * Unmount "dir" + */ + error = UMOUNT_FS(dir, mnttab_file_name); + /* + * Keep track of errors + */ + if (error) { + if (!xerror) + xerror = error; + if (error != EBUSY) { + errno = error; + plog(XLOG_ERROR, "Tree unmount of %s failed: %m", ml->mnt->mnt_dir); + } + } else { + (void) rmdirs(dir); + } + } + } + + /* + * Throw away mount list + */ + discard_mntlist(mlist); + + /* + * Try to remount, except when we are shutting down. + */ + if (xerror && amd_state != Finishing) { + xerror = amfs_host_fmount(mf); + if (!xerror) { + /* + * Don't log this - it's usually too verbose + plog(XLOG_INFO, "Remounted host %s", mf->mf_info); + */ + xerror = EBUSY; + } + } + return xerror; +} + + +/* + * Tell mountd we're done. + * This is not quite right, because we may still + * have other filesystems mounted, but the existing + * mountd protocol is badly broken anyway. + */ +static void +amfs_host_umounted(am_node *mp) +{ + mntfs *mf = mp->am_mnt; + char *host; + CLIENT *client; + enum clnt_stat clnt_stat; + struct sockaddr_in sin; + int sock = RPC_ANYSOCK; + struct timeval tv; + u_long mnt_version; + + if (mf->mf_error || mf->mf_refc > 1 || !mf->mf_server) + return; + + /* + * Take a copy of the server hostname, address, and NFS version + * to mount version conversion. + */ + host = mf->mf_server->fs_host; + sin = *mf->mf_server->fs_ip; + plog(XLOG_INFO, "amfs_host_umounted: NFS version %d", mf->mf_server->fs_version); +#ifdef HAVE_FS_NFS3 + if (mf->mf_server->fs_version == NFS_VERSION3) + mnt_version = MOUNTVERS3; + else +#endif /* HAVE_FS_NFS3 */ + mnt_version = MOUNTVERS; + + /* + * Create a client attached to mountd + */ + tv.tv_sec = 10; + tv.tv_usec = 0; + client = get_mount_client(host, &sin, &tv, &sock, mnt_version); + if (client == NULL) { +#ifdef HAVE_CLNT_SPCREATEERROR + plog(XLOG_ERROR, "get_mount_client failed for %s: %s", + host, clnt_spcreateerror("")); +#else /* not HAVE_CLNT_SPCREATEERROR */ + plog(XLOG_ERROR, "get_mount_client failed for %s", host); +#endif /* not HAVE_CLNT_SPCREATEERROR */ + goto out; + } + + if (!nfs_auth) { + if (make_nfs_auth()) + goto out; + } + client->cl_auth = nfs_auth; + +#ifdef DEBUG + dlog("Unmounting all from %s", host); +#endif /* DEBUG */ + + clnt_stat = clnt_call(client, + MOUNTPROC_UMNTALL, + (XDRPROC_T_TYPE) xdr_void, + 0, + (XDRPROC_T_TYPE) xdr_void, + 0, + tv); + if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_SYSTEMERROR) { + /* RPC_SYSTEMERROR seems to be returned for no good reason ... */ + char *msg = clnt_sperrno(clnt_stat); + plog(XLOG_ERROR, "unmount all from %s rpc failed: %s", host, msg, clnt_stat); + goto out; + } + +out: + if (sock != RPC_ANYSOCK) + (void) amu_close(sock); + if (client) + clnt_destroy(client); +} diff --git a/contrib/amd/amd/amfs_inherit.c b/contrib/amd/amd/amfs_inherit.c new file mode 100644 index 0000000..e9709bd --- /dev/null +++ b/contrib/amd/amd/amfs_inherit.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_inherit.c,v 5.2.2.1 1992/02/09 15:08:26 jsp beta $ + * + */ + +/* + * Inheritance file system. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* + * This implements a filesystem restart. + * + * This is a *gross* hack - it knows far too + * much about the way other parts of the + * system work. See restart.c too. + */ + +static char *amfs_inherit_match(am_opts *fo); +static int amfs_inherit_fmount(mntfs *mf); +static int amfs_inherit_fumount(mntfs *mf); +static int amfs_inherit_init(mntfs *mf); +static int amfs_inherit_mount(am_node *mp); + + +/* + * Ops structure + */ +am_ops amfs_inherit_ops = +{ + "inherit", + amfs_inherit_match, + amfs_inherit_init, + amfs_inherit_mount, + amfs_inherit_fmount, + amfs_auto_fumount, + amfs_inherit_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* amfs_inherit_readlink */ + 0, /* amfs_inherit_mounted */ + 0, /* amfs_inherit_umounted */ + find_amfs_auto_srvr, + FS_DISCARD +}; + + +/* + * This should never be called. + */ +static char * +amfs_inherit_match(am_opts *fo) +{ + plog(XLOG_FATAL, "amfs_inherit_match called!"); + return 0; +} + + +static int +amfs_inherit_init(mntfs *mf) +{ + mntfs *mf_link = (mntfs *) mf->mf_private; + + if (mf_link == 0) { + plog(XLOG_ERROR, "Remount collision on %s?", mf->mf_mount); + plog(XLOG_FATAL, "Attempting to init not-a-filesystem"); + return EINVAL; + } + + if (mf_link->mf_ops->fs_init) + return (*mf_link->mf_ops->fs_init) (mf_link); + return 0; +} + + +/* + * Take the linked mount point and + * propogate. + */ +static mntfs * +amfs_inherit_inherit(mntfs *mf) +{ + mntfs *mf_link = (mntfs *) mf->mf_private; + + if (mf_link == 0) { + plog(XLOG_FATAL, "Attempting to inherit not-a-filesystem"); + return 0; /* XXX */ + } + mf_link->mf_fo = mf->mf_fo; + + /* + * 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 + */ + mf_link->mf_flags &= ~MFF_RESTART; + + /* Say what happened */ + plog(XLOG_INFO, "restarting %s on %s", mf_link->mf_info, mf_link->mf_mount); + + return mf_link; +} + + +static int +amfs_inherit_mount(am_node *mp) +{ + mntfs *newmf = amfs_inherit_inherit(mp->am_mnt); + + if (newmf) { + mp->am_mnt = newmf; + /* + * XXX - must do the am_mounted call here + */ + if (newmf->mf_ops->fs_flags & FS_MBACKGROUND) + am_mounted(mp); + + new_ttl(mp); + return 0; + } + return EINVAL; +} + + +static int +amfs_inherit_fmount(mntfs *mf) +{ + am_node *mp = find_mf(mf); + + if (mp) + return amfs_inherit_mount(mp); + return amfs_inherit_inherit(mf) ? 0 : EINVAL; +} + + +static int +amfs_inherit_fumount(mntfs *mf) +{ + /* + * Always succeed + */ + return 0; +} diff --git a/contrib/amd/amd/amfs_link.c b/contrib/amd/amd/amfs_link.c new file mode 100644 index 0000000..251c5eb --- /dev/null +++ b/contrib/amd/amd/amfs_link.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_link.c,v 5.2.2.1 1992/02/09 15:09:04 jsp beta $ + * + */ + +/* + * Symbol-link file system + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + + +/* + * Ops structures + */ +am_ops amfs_link_ops = +{ + "link", + amfs_link_match, + 0, /* amfs_link_init */ + amfs_auto_fmount, + amfs_link_fmount, + amfs_auto_fumount, + amfs_link_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* amfs_link_readlink */ + 0, /* amfs_link_mounted */ + 0, /* amfs_link_umounted */ + find_amfs_auto_srvr, + 0 +}; + + +/* + * SFS needs a link. + */ +char * +amfs_link_match(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) + XFREE(fo->opt_sublink); + fo->opt_sublink = fullpath; + fo->opt_fs = str3cat(fo->opt_fs, ".", fullpath, ""); + } + + return strdup(fo->opt_fs); +} + + +int +amfs_link_fmount(mntfs *mf) +{ + /* + * Wow - this is hard to implement! :-) + */ + return 0; +} + + +int +amfs_link_fumount(mntfs *mf) +{ + return 0; +} diff --git a/contrib/amd/amd/amfs_linkx.c b/contrib/amd/amd/amfs_linkx.c new file mode 100644 index 0000000..e46206f --- /dev/null +++ b/contrib/amd/amd/amfs_linkx.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_linkx.c,v 5.2.2.1 1992/02/09 15:09:04 jsp beta $ + * + */ + +/* + * Symbol-link file system, with test that the target of the link exists. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* forward declarations */ +static int amfs_linkx_mount(am_node *mp); + +/* + * linkx operations + */ +struct am_ops amfs_linkx_ops = +{ + "linkx", + amfs_link_match, + 0, /* amfs_linkx_init */ + amfs_linkx_mount, + 0, + amfs_auto_fumount, + amfs_link_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* amfs_linkx_readlink */ + 0, /* amfs_linkx_mounted */ + 0, /* amfs_linkx_umounted */ + find_amfs_auto_srvr, + FS_MBACKGROUND +}; + + +static int +amfs_linkx_mount(am_node *mp) +{ + /* + * Check for existence of target. + */ + struct stat stb; + char *ln; + + if (mp->am_link) + ln = mp->am_link; + else /* should never occur */ + ln = mp->am_mnt->mf_mount; + + /* + * Use lstat, not stat, since we don't + * want to know if the ultimate target of + * a symlink chain exists, just the first. + */ + if (lstat(ln, &stb) < 0) + return errno; + + return 0; +} + diff --git a/contrib/amd/amd/amfs_nfsl.c b/contrib/amd/amd/amfs_nfsl.c new file mode 100644 index 0000000..8132afd --- /dev/null +++ b/contrib/amd/amd/amfs_nfsl.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_nfsl.c,v 5.2.2.3 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * NFSL: Network file system with local existence check. If the local + * path denoted by $rfs exists, it behaves as type:=link. + * + * Example: + * pkg type:=nfsl;rhost:=jonny;rfs:=/n/johnny/src/pkg;fs:=${rfs} + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + + +/* forward declarations */ +static char *amfs_nfsl_match(am_opts *fo); +static int amfs_nfsl_init(mntfs *mf); +static int amfs_nfsl_fmount(mntfs *mf); +static int amfs_nfsl_fumount(mntfs *mf); +static void amfs_nfsl_umounted(am_node *mp); +static fserver *amfs_nfsl_ffserver(mntfs *mf); + +/* + * NFS-Link operations + */ +am_ops amfs_nfsl_ops = +{ + "nfsl", /* name of file system */ + amfs_nfsl_match, /* match */ + amfs_nfsl_init, /* initialize */ + amfs_auto_fmount, /* mount vnode */ + amfs_nfsl_fmount, /* mount vfs */ + amfs_auto_fumount, /* unmount vnode */ + amfs_nfsl_fumount, /* unmount VFS */ + amfs_error_lookuppn, /* lookup path-name */ + amfs_error_readdir, /* read directory */ + 0, /* read link */ + 0, /* after-mount extra actions */ + amfs_nfsl_umounted, /* after-umount extra actions */ + amfs_nfsl_ffserver, /* find a file server */ + FS_MKMNT | FS_BACKGROUND | FS_AMQINFO /* flags */ +}; + + +/* + * Check that f/s has all needed fields. + * Returns: matched string if found, NULL otherwise. + */ +static char * +amfs_nfsl_match(am_opts *fo) +{ + char *cp = fo->opt_fs; + char *ho = fo->opt_rhost; + struct stat stb; + + if (!cp || !ho) { + plog(XLOG_USER, "amfs_nfsl: nost $fs and $rhost must be specified"); + return NULL; + } + + /* + * If this host is not the same as $rhost, or if link does not exist, + * perform nfs_match(), same as for type:=nfs. + * If link value exists (or same host), then perform amfs_link_match(), + * same as for linkx. + */ + if (!STRCEQ(ho, hostname)) { + plog(XLOG_INFO, "amfs_nfsl: \"%s\" is not local host, using type:=nfs", ho); + return nfs_match(fo); + } else if (lstat(cp, &stb) < 0) { + plog(XLOG_INFO, "amfs_nfsl: \"%s\" does not exist, using type:=nfs", cp); + return nfs_match(fo); + } else { + plog(XLOG_INFO, "amfs_nfsl: \"%s\" exists, using type:=link", cp); + return amfs_link_match(fo); + } +} + + +/* + * Initialize. + * Returns: 0 if OK, non-zero (errno) if failed. + */ +static int +amfs_nfsl_init(mntfs *mf) +{ + /* + * If a link, do nothing (same as type:=link). + * If non-link, do nfs_init (same as type:=nfs). + */ + if (mf->mf_flags & MFF_NFSLINK) { + return 0; + } else { + return nfs_init(mf); + } +} + + +/* + * Mount vfs. + * Returns: 0 if OK, non-zero (errno) if failed. + */ +static int +amfs_nfsl_fmount(mntfs *mf) +{ + /* + * If a link, do run amfs_link_fmount() (same as type:=link) + * If non-link, do nfs_fmount (same as type:=nfs). + */ + if (mf->mf_flags & MFF_NFSLINK) { + return amfs_link_fmount(mf); + } else { + return nfs_fmount(mf); + } +} + + +/* + * Unmount VFS. + * Returns: 0 if OK, non-zero (errno) if failed. + */ +static int +amfs_nfsl_fumount(mntfs *mf) +{ + /* + * If a link, do run amfs_link_fumount() (same as type:=link) + * If non-link, do nfs_fumount (same as type:=nfs). + */ + if (mf->mf_flags & MFF_NFSLINK) { + return amfs_link_fumount(mf); + } else { + return nfs_fumount(mf); + } +} + + +/* + * Async unmount callback function. + * After the base umount() succeeds, we may want to take extra actions, + * such as informing remote mount daemons that we've unmounted them. + * See amfs_auto_umounted(), host_umounted(), nfs_umounted(). + */ +static void +amfs_nfsl_umounted(am_node *mp) +{ + mntfs *mf = mp->am_mnt; + + /* + * If a link, do nothing (same as type:=link) + * If non-link, do nfs_fumount (same as type:=nfs). + */ + if (mf->mf_flags & MFF_NFSLINK) { + return; + } else { + nfs_umounted(mp); + /* + * MUST remove mount point directories, because if they remain + * behind, the next nfsl access will think they are a link + * type file system, and not NFS! (when it performs link target + * existence test) + */ + if (mf->mf_flags & MFF_MKMNT) + rmdirs(mf->mf_mount); + return; + } +} + + +/* + * Find a file server. + * Returns: fserver of found server, or NULL if not found. + */ +static fserver * +amfs_nfsl_ffserver(mntfs *mf) +{ + char *cp = mf->mf_fo->opt_fs; + char *ho = mf->mf_fo->opt_rhost; + struct stat stb; + + /* + * If this host is not the same as $rhost, or if link does not exist, + * perform find_nfs_srvr(), same as for type:=nfs. + * If link value exists (or same host), then perform + * find_amfs_auto_srvr(), same as for linkx. + */ + if (!STREQ(ho, hostname) || lstat(cp, &stb) < 0) { + return find_nfs_srvr(mf); + } else { + mf->mf_flags |= MFF_NFSLINK; + return find_amfs_auto_srvr(mf); + } +} diff --git a/contrib/amd/amd/amfs_nfsx.c b/contrib/amd/amd/amfs_nfsx.c new file mode 100644 index 0000000..272e10d --- /dev/null +++ b/contrib/amd/amd/amfs_nfsx.c @@ -0,0 +1,532 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_linxx.c,v 5.2.2.3 1992/05/31 16:13:07 jsp Exp $ + * + */ + +/* + * NFS hierarchical mounts + * + * TODO: Re-implement. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* + * The rfs field contains a list of mounts to be done from + * the remote host. + */ +typedef struct amfs_nfsx_mnt { + mntfs *n_mnt; + int n_error; +} amfs_nfsx_mnt; + +struct amfs_nfsx { + int nx_c; /* Number of elements in nx_v */ + amfs_nfsx_mnt *nx_v; /* Underlying mounts */ + amfs_nfsx_mnt *nx_try; +}; + +/* forward definitions */ +static char *amfs_nfsx_match(am_opts *fo); +static int amfs_nfsx_fmount (mntfs *); +static int amfs_nfsx_fmount(mntfs *mf); +static int amfs_nfsx_fumount(mntfs *mf); +static int amfs_nfsx_init(mntfs *mf); + +/* + * Ops structure + */ +am_ops amfs_nfsx_ops = +{ + "nfsx", + amfs_nfsx_match, + amfs_nfsx_init, + amfs_auto_fmount, + amfs_nfsx_fmount, + amfs_auto_fumount, + amfs_nfsx_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* amfs_nfsx_readlink */ + 0, /* amfs_nfsx_mounted */ + 0, /* amfs_nfsx_umounted */ + find_nfs_srvr, /* XXX */ + /* FS_UBACKGROUND| */ FS_AMQINFO +}; + + +static char * +amfs_nfsx_match(am_opts *fo) +{ + char *xmtab; + char *ptr; + int len; + + if (!fo->opt_rfs) { + plog(XLOG_USER, "amfs_nfsx: no remote filesystem specified"); + return FALSE; + } + + if (!fo->opt_rhost) { + plog(XLOG_USER, "amfs_nfsx: no remote host specified"); + return FALSE; + } + + /* set default sublink */ + if (fo->opt_sublink == 0) { + ptr = strchr(fo->opt_rfs, ','); + if (ptr && ptr != (fo->opt_rfs + 1)) + fo->opt_sublink = strnsave(fo->opt_rfs + 1, ptr - fo->opt_rfs - 1); + } + + /* + * Remove trailing ",..." from ${fs} + * After deslashifying, overwrite the end of ${fs} with "/" + * to make sure it is unique. + */ + if ((ptr = strchr(fo->opt_fs, ','))) + *ptr = '\0'; + deslashify(fo->opt_fs); + + /* + * Bump string length to allow trailing / + */ + len = strlen(fo->opt_fs); + fo->opt_fs = xrealloc(fo->opt_fs, len + 1 + 1); + ptr = fo->opt_fs + len; + + /* + * Make unique... + */ + *ptr++ = '/'; + *ptr = '\0'; + + /* + * Determine magic cookie to put in mtab + */ + xmtab = str3cat((char *) 0, 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 xmtab; +} + + +static void +amfs_nfsx_prfree(voidp vp) +{ + struct amfs_nfsx *nx = (struct amfs_nfsx *) vp; + int i; + + for (i = 0; i < nx->nx_c; i++) { + mntfs *m = nx->nx_v[i].n_mnt; + if (m) + free_mntfs(m); + } + + XFREE(nx->nx_v); + XFREE(nx); +} + + +static int +amfs_nfsx_init(mntfs *mf) +{ + /* + * mf_info has the form: + * host:/prefix/path,sub,sub,sub + */ + int i; + int glob_error; + struct amfs_nfsx *nx; + int asked_for_wakeup = 0; + + nx = (struct amfs_nfsx *) mf->mf_private; + + if (nx == 0) { + char **ivec; + char *info = 0; + char *host; + char *pref; + int error = 0; + + info = strdup(mf->mf_info); + host = strchr(info, ':'); + if (!host) { + error = EINVAL; + goto errexit; + } + pref = host +1; + host = info; + + /* + * Split the prefix off from the suffices + */ + ivec = strsplit(pref, ',', '\''); + + /* + * Count array size + */ + for (i = 0; ivec[i]; i++) ; + + nx = ALLOC(struct amfs_nfsx); + mf->mf_private = (voidp) nx; + mf->mf_prfree = amfs_nfsx_prfree; + + nx->nx_c = i - 1; /* i-1 because we don't want the prefix */ + nx->nx_v = (amfs_nfsx_mnt *) xmalloc(nx->nx_c * sizeof(amfs_nfsx_mnt)); + { + char *mp = 0; + char *xinfo = 0; + char *fs = mf->mf_fo->opt_fs; + char *rfs = 0; + for (i = 0; i < nx->nx_c; i++) { + char *path = ivec[i + 1]; + rfs = str3cat(rfs, pref, "/", path); + /* + * Determine the mount point. + * If this is the root, then don't remove + * the trailing slash to avoid mntfs name clashes. + */ + mp = str3cat(mp, fs, "/", rfs); + normalize_slash(mp); + deslashify(mp); + /* + * Determine the mount info + */ + xinfo = str3cat(xinfo, host, *path == '/' ? "" : "/", path); + normalize_slash(xinfo); + if (pref[1] != '\0') + deslashify(xinfo); +#ifdef DEBUG + dlog("amfs_nfsx: init mount for %s on %s", xinfo, mp); +#endif /* DEBUG */ + nx->nx_v[i].n_error = -1; + nx->nx_v[i].n_mnt = find_mntfs(&nfs_ops, mf->mf_fo, mp, xinfo, "", mf->mf_mopts, mf->mf_remopts); + } + if (rfs) + XFREE(rfs); + if (mp) + XFREE(mp); + if (xinfo) + XFREE(xinfo); + } + + XFREE(ivec); + errexit: + if (info) + XFREE(info); + if (error) + return error; + } + + /* + * Iterate through the mntfs's and call + * the underlying init routine on each + */ + glob_error = 0; + + for (i = 0; i < nx->nx_c; i++) { + amfs_nfsx_mnt *n = &nx->nx_v[i]; + mntfs *m = n->n_mnt; + int error = (*m->mf_ops->fs_init) (m); + /* + * if you just "return error" here, you will have made a failure + * in any submounts to fail the whole group. There was old unused code + * here before. + */ + if (error > 0) + n->n_error = error; + + else if (error < 0) { + glob_error = -1; + if (!asked_for_wakeup) { + asked_for_wakeup = 1; + sched_task(wakeup_task, (voidp) mf, (voidp) m); + } + } + } + + return glob_error; +} + + +static void +amfs_nfsx_cont(int rc, int term, voidp closure) +{ + mntfs *mf = (mntfs *) closure; + struct amfs_nfsx *nx = (struct amfs_nfsx *) mf->mf_private; + amfs_nfsx_mnt *n = nx->nx_try; + + n->n_mnt->mf_flags &= ~(MFF_ERROR | MFF_MOUNTING); + mf->mf_flags &= ~MFF_ERROR; + + /* + * Wakeup anything waiting for this mount + */ + wakeup((voidp) n->n_mnt); + + if (rc || term) { + if (term) { + /* + * Not sure what to do for an error code. + */ + plog(XLOG_ERROR, "mount for %s got signal %d", n->n_mnt->mf_mount, term); + n->n_error = EIO; + } else { + /* + * Check for exit status + */ + errno = rc; /* XXX */ + plog(XLOG_ERROR, "%s: mount (amfs_nfsx_cont): %m", n->n_mnt->mf_mount); + n->n_error = rc; + } + free_mntfs(n->n_mnt); + n->n_mnt = new_mntfs(); + n->n_mnt->mf_error = n->n_error; + n->n_mnt->mf_flags |= MFF_ERROR; + } else { + /* + * The mount worked. + */ + mf_mounted(n->n_mnt); + n->n_error = 0; + } + + /* + * Do the remaining bits + */ + if (amfs_nfsx_fmount(mf) >= 0) { + wakeup((voidp) mf); + mf->mf_flags &= ~MFF_MOUNTING; + mf_mounted(mf); + } +} + + +static int +try_amfs_nfsx_mount(voidp mv) +{ + mntfs *mf = (mntfs *) mv; + int error; + + mf->mf_flags |= MFF_MOUNTING; + error = (*mf->mf_ops->fmount_fs) (mf); + mf->mf_flags &= ~MFF_MOUNTING; + + return error; +} + + +static int +amfs_nfsx_remount(mntfs *mf, int fg) +{ + struct amfs_nfsx *nx = (struct amfs_nfsx *) mf->mf_private; + amfs_nfsx_mnt *n; + int glob_error = -1; + + for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) { + mntfs *m = n->n_mnt; + if (n->n_error < 0) { + if (!(m->mf_flags & MFF_MKMNT) && m->mf_ops->fs_flags & FS_MKMNT) { + int error = mkdirs(m->mf_mount, 0555); + if (!error) + m->mf_flags |= MFF_MKMNT; + } + } + } + + /* + * Iterate through the mntfs's and mount each filesystem + * which is not yet mounted. + */ + for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) { + mntfs *m = n->n_mnt; + if (n->n_error < 0) { + /* + * Check fmount entry pt. exists + * and then mount... + */ + if (!m->mf_ops->fmount_fs) { + n->n_error = EINVAL; + } else { +#ifdef DEBUG + dlog("calling underlying fmount on %s", m->mf_mount); +#endif /* DEBUG */ + if (!fg && foreground && (m->mf_ops->fs_flags & FS_MBACKGROUND)) { + m->mf_flags |= MFF_MOUNTING; /* XXX */ +#ifdef DEBUG + dlog("backgrounding mount of \"%s\"", m->mf_info); +#endif /* DEBUG */ + nx->nx_try = n; + run_task(try_amfs_nfsx_mount, (voidp) m, amfs_nfsx_cont, (voidp) mf); + n->n_error = -1; + return -1; + } else { +#ifdef DEBUG + dlog("foreground mount of \"%s\" ...", mf->mf_info); +#endif /* DEBUG */ + n->n_error = (*m->mf_ops->fmount_fs) (m); + } + } + +#ifdef DEBUG + if (n->n_error > 0) { + errno = n->n_error; /* XXX */ + dlog("underlying fmount of %s failed: %m", m->mf_mount); + } +#endif /* DEBUG */ + + if (n->n_error == 0) { + glob_error = 0; + } else if (glob_error < 0) { + glob_error = n->n_error; + } + } + } + + return glob_error < 0 ? 0 : glob_error; +} + + +static int +amfs_nfsx_fmount(mntfs *mf) +{ + return amfs_nfsx_remount(mf, FALSE); +} + + +/* + * Unmount an NFS hierarchy. + * Note that this is called in the foreground + * and so may hang under extremely rare conditions. + */ +static int +amfs_nfsx_fumount(mntfs *mf) +{ + struct amfs_nfsx *nx = (struct amfs_nfsx *) mf->mf_private; + amfs_nfsx_mnt *n; + int glob_error = 0; + + /* + * Iterate in reverse through the mntfs's and unmount each filesystem + * which is mounted. + */ + for (n = nx->nx_v + nx->nx_c - 1; n >= nx->nx_v; --n) { + mntfs *m = n->n_mnt; + /* + * If this node has not been messed with + * and there has been no error so far + * then try and unmount. + * If an error had occured then zero + * the error code so that the remount + * only tries to unmount those nodes + * which had been successfully unmounted. + */ + if (n->n_error == 0) { +#ifdef DEBUG + dlog("calling underlying fumount on %s", m->mf_mount); +#endif /* DEBUG */ + n->n_error = (*m->mf_ops->fumount_fs) (m); + if (n->n_error) { + glob_error = n->n_error; + n->n_error = 0; + } else { + /* + * Make sure remount gets this node + */ + n->n_error = -1; + } + } + } + + /* + * If any unmounts failed then remount the + * whole lot... + */ + if (glob_error) { + glob_error = amfs_nfsx_remount(mf, TRUE); + if (glob_error) { + errno = glob_error; /* XXX */ + plog(XLOG_USER, "amfs_nfsx: remount of %s failed: %m", mf->mf_mount); + } + glob_error = EBUSY; + } else { + /* + * Remove all the mount points + */ + for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) { + mntfs *m = n->n_mnt; + am_node am; + + /* + * XXX: all the umounted handler needs is a + * mntfs pointer, so pass an am_node with the right + * pointer in it. + */ + memset((voidp) &am, 0, sizeof(am)); + am.am_mnt = m; +#ifdef DEBUG + dlog("calling underlying umounted on %s", m->mf_mount); +#endif /* DEBUG */ + (*m->mf_ops->umounted) (&am); + + if (n->n_error < 0) { + if (m->mf_ops->fs_flags & FS_MKMNT) { + (void) rmdirs(m->mf_mount); + m->mf_flags &= ~MFF_MKMNT; + } + } + free_mntfs(m); + n->n_mnt = 0; + n->n_error = -1; + } + } + + return glob_error; +} diff --git a/contrib/amd/amd/amfs_program.c b/contrib/amd/amd/amfs_program.c new file mode 100644 index 0000000..2bd0778 --- /dev/null +++ b/contrib/amd/amd/amfs_program.c @@ -0,0 +1,191 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_program.c,v 5.2.2.1 1992/02/09 15:08:56 jsp beta $ + * + */ + +/* + * Program file system + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* forward definitions */ +static char *amfs_program_match(am_opts *fo); +static int amfs_program_fmount(mntfs *mf); +static int amfs_program_fumount(mntfs *mf); +static int amfs_program_init(mntfs *mf); + +/* + * Ops structure + */ +am_ops amfs_program_ops = +{ + "program", + amfs_program_match, + amfs_program_init, + amfs_auto_fmount, + amfs_program_fmount, + amfs_auto_fumount, + amfs_program_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* amfs_program_readlink */ + 0, /* amfs_program_mounted */ + 0, /* amfs_program_umounted */ + find_amfs_auto_srvr, + FS_BACKGROUND | FS_AMQINFO +}; + + +/* + * Execute needs a mount and unmount command. + */ +static char * +amfs_program_match(am_opts *fo) +{ + char *prog; + + if (!fo->opt_mount || !fo->opt_unmount) { + plog(XLOG_USER, "program: no mount/unmount specified"); + return 0; + } + prog = strchr(fo->opt_mount, ' '); + + return strdup(prog ? prog + 1 : fo->opt_mount); +} + + +static int +amfs_program_init(mntfs *mf) +{ + /* + * Save unmount command + */ + if (mf->mf_refc == 1) { + mf->mf_private = (voidp) strdup(mf->mf_fo->opt_unmount); + mf->mf_prfree = (void (*)(voidp)) free; + } + + return 0; +} + + +static int +amfs_program_exec(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 + amuDebug(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 + */ + XFREE(info); + XFREE(xivec); + + /* + * Return error + */ + return error; +} + + +static int +amfs_program_fmount(mntfs *mf) +{ + return amfs_program_exec(mf->mf_fo->opt_mount); +} + + +static int +amfs_program_fumount(mntfs *mf) +{ + return amfs_program_exec((char *) mf->mf_private); +} diff --git a/contrib/amd/amd/amfs_root.c b/contrib/amd/amd/amfs_root.c new file mode 100644 index 0000000..3c1cd17 --- /dev/null +++ b/contrib/amd/amd/amfs_root.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_root.c,v 1.1 1997-1998/06/30 19:22:30 ezk Exp ezk $ + * + */ + +/* + * Root file system + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/**************************************************************************** + *** FORWARD DEFINITIONS *** + ****************************************************************************/ +static int amfs_root_mount(am_node *mp); + +/**************************************************************************** + *** OPS STRUCTURES *** + ****************************************************************************/ +am_ops amfs_root_ops = +{ + "root", + 0, /* amfs_root_match */ + 0, /* amfs_root_init */ + amfs_root_mount, + 0, + amfs_auto_umount, + 0, + amfs_auto_lookuppn, + amfs_auto_readdir, + 0, /* amfs_root_readlink */ + 0, /* amfs_root_mounted */ + 0, /* amfs_root_umounted */ + find_amfs_auto_srvr, + FS_NOTIMEOUT | FS_AMQINFO | FS_DIRECTORY +}; + + +/**************************************************************************** + *** FUNCTIONS *** + ****************************************************************************/ + +/* + * Mount the root... + */ +static int +amfs_root_mount(am_node *mp) +{ + mntfs *mf = mp->am_mnt; + + mf->mf_mount = strealloc(mf->mf_mount, pid_fsname); + mf->mf_private = (voidp) mapc_find(mf->mf_info, "", NULL); + mf->mf_prfree = mapc_free; + + return 0; +} diff --git a/contrib/amd/amd/amfs_toplvl.c b/contrib/amd/amd/amfs_toplvl.c new file mode 100644 index 0000000..f36c66f --- /dev/null +++ b/contrib/amd/amd/amfs_toplvl.c @@ -0,0 +1,355 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_toplvl.c,v 1.1 1997-1998/06/30 19:22:30 ezk Exp ezk $ + * + */ + +/* + * Top-level file system + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/**************************************************************************** + *** FORWARD DEFINITIONS *** + ****************************************************************************/ + + +/**************************************************************************** + *** OPS STRUCTURES *** + ****************************************************************************/ +am_ops amfs_toplvl_ops = +{ + "toplvl", + amfs_auto_match, + 0, /* amfs_auto_init */ + amfs_toplvl_mount, + 0, + amfs_toplvl_umount, + 0, + amfs_auto_lookuppn, + amfs_auto_readdir, /* browsable version of readdir() */ + 0, /* amfs_toplvl_readlink */ + amfs_toplvl_mounted, + 0, /* amfs_toplvl_umounted */ + find_amfs_auto_srvr, + FS_MKMNT | FS_NOTIMEOUT | FS_BACKGROUND | FS_AMQINFO | FS_DIRECTORY +}; + + +/**************************************************************************** + *** FUNCTIONS *** + ****************************************************************************/ + +/* + * Mount an automounter directory. + * The automounter is connected into the system + * as a user-level NFS server. mount_amfs_toplvl constructs + * the necessary NFS parameters to be given to the + * kernel so that it will talk back to us. + * + * NOTE: automounter mounts in themselves are using NFS Version 2. + */ +static int +mount_amfs_toplvl(char *dir, char *opts) +{ + char fs_hostname[MAXHOSTNAMELEN + MAXPATHLEN + 1]; + int retry, error, genflags; + mntent_t mnt; + nfs_args_t nfs_args; + am_nfs_fh *fhp; + am_nfs_handle_t anh; + MTYPE_TYPE type = MOUNT_TYPE_NFS; +#ifndef HAVE_TRANSPORT_TYPE_TLI + u_short port; + struct sockaddr_in sin; +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + memset((voidp) &mnt, 0, sizeof(mnt)); + mnt.mnt_dir = dir; + mnt.mnt_fsname = pid_fsname; + mnt.mnt_opts = opts; + + /* + * Make sure that amd's top-level NFS mounts are hidden by default + * from df. + * If they don't appear to support the either the "ignore" mnttab + * option entry, or the "auto" one, set the mount type to "nfs". + */ + mnt.mnt_type = HIDE_MOUNT_TYPE; + + retry = hasmntval(&mnt, MNTTAB_OPT_RETRY); + if (retry <= 0) + retry = 2; /* XXX */ + + /* + * SET MOUNT ARGS + */ + /* + * get fhandle of remote path for automount point + */ + fhp = root_fh(dir); + if (!fhp) { + plog(XLOG_FATAL, "Can't find root file handle for %s", dir); + return EINVAL; + } + +#ifndef HAVE_TRANSPORT_TYPE_TLI + /* + * 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. + */ + memset((voidp) &sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr = myipaddr; + port = hasmntval(&mnt, MNTTAB_OPT_PORT); + if (port) { + sin.sin_port = htons(port); + } else { + plog(XLOG_ERROR, "no port number specified for %s", dir); + return EINVAL; + } +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + /* + * Make a ``hostname'' string for the kernel + */ + sprintf(fs_hostname, "pid%ld@%s:%s", + (long) (foreground ? mypid : getppid()), + hostname, + dir); + /* + * Most kernels have a name length restriction (64 bytes)... + */ + if (strlen(fs_hostname) >= MAXHOSTNAMELEN) + strcpy(fs_hostname + MAXHOSTNAMELEN - 3, ".."); +#ifdef HOSTNAMESZ + /* + * ... and some of these restrictions are 32 bytes (HOSTNAMESZ) + * If you need to get the definition for HOSTNAMESZ found, you may + * add the proper header file to the conf/nfs_prot/nfs_prot_*.h file. + */ + if (strlen(fs_hostname) >= HOSTNAMESZ) + strcpy(fs_hostname + HOSTNAMESZ - 3, ".."); +#endif /* HOSTNAMESZ */ + + /* + * Finally we can compute the mount genflags set above. + */ + genflags = compute_mount_flags(&mnt); + + /* setup the many fields and flags within nfs_args */ + memmove(&anh.v2.fhs_fh, fhp, sizeof(*fhp)); +#ifdef HAVE_TRANSPORT_TYPE_TLI + compute_nfs_args(&nfs_args, + &mnt, + genflags, + nfsncp, + NULL, /* remote host IP addr is set below */ + NFS_VERSION, /* version 2 */ + "udp", + &anh, + fs_hostname, + pid_fsname); + /* + * IMPORTANT: set the correct IP address AFTERWARDS. It cannot + * be done using the normal mechanism of compute_nfs_args(), because + * that one will allocate a new address and use NFS_SA_DREF() to copy + * parts to it, while assuming that the ip_addr passed is always + * a "struct sockaddr_in". That assumption is incorrect on TLI systems, + * because they define a special macro HOST_SELF which is DIFFERENT + * than localhost (127.0.0.1)! + */ + nfs_args.addr = &nfsxprt->xp_ltaddr; +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + compute_nfs_args(&nfs_args, + &mnt, + genflags, + &sin, + NFS_VERSION, /* version 2 */ + "udp", + &anh, + fs_hostname, + pid_fsname); +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + /************************************************************************* + * NOTE: while compute_nfs_args() works ok for regular NFS mounts * + * the toplvl one is not, and so some options must be corrected by hand * + * more carefully, *after* compute_nfs_args() runs. * + *************************************************************************/ + compute_automounter_nfs_args(&nfs_args, &mnt); + + /* This is it! Here we try to mount amd on its mount points */ +#ifdef DEBUG + amuDebug(D_TRACE) + print_nfs_args(&nfs_args, 0); +#endif /* DEBUG */ + error = mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, + 0, NULL, mnttab_file_name); + +#ifdef HAVE_TRANSPORT_TYPE_TLI + free_knetconfig(nfs_args.knconf); + /* + * local automounter mounts do not allocate a special address, so + * no need to XFREE(nfs_args.addr) under TLI. + */ +#endif /* HAVE_TRANSPORT_TYPE_TLI */ + + return error; +} + + +/* + * Mount the top-level + */ +int +amfs_toplvl_mount(am_node *mp) +{ + mntfs *mf = mp->am_mnt; + struct stat stb; + char opts[256], preopts[256]; + int error; + char *mnttype; + + /* + * Mounting the automounter. + * Make sure the mount directory exists, construct + * the mount options and call the mount_amfs_toplvl routine. + */ + + 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; + } + if (mf->mf_ops == &amfs_toplvl_ops) + mnttype = "indirect"; + else if (mf->mf_ops == &amfs_direct_ops) + mnttype = "direct"; +#ifdef HAVE_AM_FS_UNION + else if (mf->mf_ops == &amfs_union_ops) + mnttype = "union"; +#endif /* HAVE_AM_FS_UNION */ + else + mnttype = "auto"; + + /* + * Construct some mount options: + * + * Tack on magic map=<mapname> option in mtab to emulate + * SunOS automounter behavior. + */ + preopts[0] = '\0'; +#ifdef MNTTAB_OPT_INTR + strcat(preopts, MNTTAB_OPT_INTR); + strcat(preopts, ","); +#endif /* MNTTAB_OPT_INTR */ +#ifdef MNTTAB_OPT_IGNORE + strcat(preopts, MNTTAB_OPT_IGNORE); + strcat(preopts, ","); +#endif /* MNTTAB_OPT_IGNORE */ + sprintf(opts, "%s%s,%s=%d,%s=%d,%s=%d,%s,map=%s", + preopts, + MNTTAB_OPT_RW, + MNTTAB_OPT_PORT, nfs_port, + MNTTAB_OPT_TIMEO, gopt.amfs_auto_timeo, + MNTTAB_OPT_RETRANS, gopt.amfs_auto_retrans, + mnttype, mf->mf_info); + + /* now do the mount */ + error = mount_amfs_toplvl(mf->mf_mount, opts); + if (error) { + errno = error; + plog(XLOG_FATAL, "mount_amfs_toplvl: %m"); + return error; + } + return 0; +} + + +void +amfs_toplvl_mounted(mntfs *mf) +{ + amfs_auto_mkcacheref(mf); +} + + +/* + * Unmount a top-level automount node + */ +int +amfs_toplvl_umount(am_node *mp) +{ + int error; + 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, mnttab_file_name); + if (error == EBUSY) { + plog(XLOG_WARNING, "amfs_toplvl_unmount retrying %s in 1s", mp->am_path); + sleep(1); /* XXX */ + goto again; + } + return error; +} diff --git a/contrib/amd/amd/amfs_union.c b/contrib/amd/amd/amfs_union.c new file mode 100644 index 0000000..95fc8fd --- /dev/null +++ b/contrib/amd/amd/amfs_union.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_union.c,v 1.1 1997-1998/06/30 19:22:30 ezk Exp ezk $ + * + */ + +/* + * Union automounter file system + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/**************************************************************************** + *** FORWARD DEFINITIONS *** + ****************************************************************************/ +static void amfs_union_mounted(mntfs *mf); + + +/**************************************************************************** + *** OPS STRUCTURES *** + ****************************************************************************/ +am_ops amfs_union_ops = +{ + "union", + amfs_auto_match, + 0, /* amfs_auto_init */ + amfs_toplvl_mount, + 0, + amfs_toplvl_umount, + 0, + amfs_auto_lookuppn, + amfs_auto_readdir, + 0, /* amfs_toplvl_readlink */ + amfs_union_mounted, + 0, /* amfs_toplvl_umounted */ + find_amfs_auto_srvr, + FS_MKMNT | FS_NOTIMEOUT | FS_BACKGROUND | FS_AMQINFO | FS_DIRECTORY +}; + + +/* + * Create a reference to a union'ed entry + * XXX: this function may not be used anywhere... + */ +static int +create_amfs_union_node(char *dir, voidp arg) +{ + if (!STREQ(dir, "/defaults")) { + int error = 0; + (void) amfs_toplvl_ops.lookuppn(arg, dir, &error, VLOOK_CREATE); + if (error > 0) { + errno = error; /* XXX */ + plog(XLOG_ERROR, "Could not mount %s: %m", dir); + } + return error; + } + return 0; +} + + +static void +amfs_union_mounted(mntfs *mf) +{ + int i; + + amfs_auto_mkcacheref(mf); + + /* + * Having made the union mount point, + * populate all the entries... + */ + for (i = 0; i <= last_used_map; i++) { + am_node *mp = exported_ap[i]; + if (mp && mp->am_mnt == mf) { + /* return value from create_amfs_union_node is ignored by mapc_keyiter */ + (void) mapc_keyiter((mnt_map *) mp->am_mnt->mf_private, + (void (*)(char *, voidp)) create_amfs_union_node, + mp); + break; + } + } +} diff --git a/contrib/amd/amd/amq_subr.c b/contrib/amd/amd/amq_subr.c new file mode 100644 index 0000000..775ee81 --- /dev/null +++ b/contrib/amd/amd/amq_subr.c @@ -0,0 +1,501 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amq_subr.c,v 5.2.2.1 1992/02/09 15:08:18 jsp beta $ + * + */ +/* + * Auxilliary routines for amq tool + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* forward definitions */ +bool_t xdr_amq_mount_tree_node(XDR *xdrs, amq_mount_tree *objp); +bool_t xdr_amq_mount_subtree(XDR *xdrs, amq_mount_tree *objp); + + +voidp +amqproc_null_1_svc(voidp argp, struct svc_req *rqstp) +{ + static char res; + + return (voidp) &res; +} + + +/* + * Return a sub-tree of mounts + */ +amq_mount_tree_p * +amqproc_mnttree_1_svc(voidp argp, struct svc_req *rqstp) +{ + static am_node *mp; + + mp = find_ap(*(char **) argp); + return (amq_mount_tree_p *) ∓ +} + + +/* + * Unmount a single node + */ +voidp +amqproc_umnt_1_svc(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 + */ +amq_mount_stats * +amqproc_stats_1_svc(voidp argp, struct svc_req *rqstp) +{ + return (amq_mount_stats *) &amd_stats; +} + + +/* + * Return the entire tree of mount nodes + */ +amq_mount_tree_list * +amqproc_export_1_svc(voidp argp, struct svc_req *rqstp) +{ + static amq_mount_tree_list aml; + + aml.amq_mount_tree_list_val = (amq_mount_tree_p *) &exported_ap[0]; + aml.amq_mount_tree_list_len = 1; /* XXX */ + + return &aml; +} + + +int * +amqproc_setopt_1_svc(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)) +#endif /* DEBUG */ + rc = EINVAL; + break; + + case AMOPT_LOGFILE: + if (gopt.logfile && opt->as_str + && STREQ(gopt.logfile, opt->as_str)) { + if (switch_to_logfile(opt->as_str)) + rc = EINVAL; + } else { + rc = EACCES; + } + 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; + flush_nfs_fhandle_cache((fserver *) 0); + flush_srvr_nfs_cache(); + } + break; + } + + return &rc; +} + + +amq_mount_info_list * +amqproc_getmntfs_1_svc(voidp argp, struct svc_req *rqstp) +{ + return (amq_mount_info_list *) &mfhead; /* XXX */ +} + +#ifdef ENABLE_AMQ_MOUNT +/* + * This is code that is vulnerable to IP spoofing attacks. Unless you + * absolutely need it, I suggest you do not enable it + * (using configure --enable-amq-mount) + */ +static int +ok_security(struct svc_req *rqstp) +{ + struct sockaddr_in *sin = (struct sockaddr_in *) NULL; + + if ((sin = amu_svc_getcaller(rqstp->rq_xprt)) == NULL) { + plog(XLOG_ERROR, "amu_svc_getcaller returned NULL"); + return(0); /* assume security is therefore not OK */ + } + + if (ntohs(sin->sin_port) >= 1024 || + !(sin->sin_addr.s_addr == htonl(0x7f000001) || + sin->sin_addr.s_addr == myipaddr.s_addr)) { + char dq[20]; + plog(XLOG_INFO, "AMQ request from %s.%d DENIED", + inet_dquad(dq, sin->sin_addr.s_addr), + ntohs(sin->sin_port)); + return (0); + } + + return (1); +} + + +int * +amqproc_mount_1_svc(voidp argp, struct svc_req *rqstp) +{ + static int rc; + char *s = *(amq_string *) argp; + char *cp; + + plog(XLOG_INFO, "amq requested mount of %s", s); + /* + * Minimalist security check. + */ + if (!ok_security(rqstp)) { + rc = EACCES; + return &rc; + } + /* + * Find end of key + */ + for (cp = (char *) s; *cp && (!isascii(*cp) || !isspace(*cp)); cp++) ; + + if (!*cp) { + plog(XLOG_INFO, "amqproc_mount: Invalid arguments"); + rc = EINVAL; + return &rc; + } + *cp++ = '\0'; + + /* + * Find start of value + */ + while (*cp && isascii(*cp) && isspace(*cp)) + cp++; + + root_newmap(s, cp, (char *) 0, NULL); + rc = mount_auto_node(s, (voidp) root_node); + if (rc < 0) + return 0; + return &rc; +} + +#else /* not ENABLE_AMQ_MOUNT */ + +int * +amqproc_mount_1_svc(voidp argp, struct svc_req *rqstp) +{ + static int rc; + char *s = *(amq_string *) argp; + + plog(XLOG_ERROR, "amq requested mount of %s, but code is disabled", s); + + rc = EINVAL; + return &rc; +} +#endif /* not ENABLE_AMQ_MOUNT */ + + +amq_string * +amqproc_getvers_1_svc(voidp argp, struct svc_req *rqstp) +{ + static amq_string res; + + res = get_version_string(); + return &res; +} + + +/* get PID of remote amd */ +int * +amqproc_getpid_1_svc(voidp argp, struct svc_req *rqstp) +{ + static int res; + + res = getpid(); + return &res; +} + + +/* + * XDR routines. + */ + + +bool_t +xdr_amq_setopt(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_node(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, (long *) &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); + } + return (TRUE); +} + + +bool_t +xdr_amq_mount_subtree(XDR *xdrs, amq_mount_tree *objp) +{ + am_node *mp = (am_node *) objp; + + if (!xdr_amq_mount_tree_node(xdrs, objp)) { + return (FALSE); + } + if (!xdr_pointer(xdrs, (char **) &mp->am_osib, sizeof(amq_mount_tree), (XDRPROC_T_TYPE) xdr_amq_mount_subtree)) { + return (FALSE); + } + if (!xdr_pointer(xdrs, (char **) &mp->am_child, sizeof(amq_mount_tree), (XDRPROC_T_TYPE) xdr_amq_mount_subtree)) { + return (FALSE); + } + return (TRUE); +} + + +bool_t +xdr_amq_mount_tree(XDR *xdrs, amq_mount_tree *objp) +{ + am_node *mp = (am_node *) objp; + am_node *mnil = 0; + + if (!xdr_amq_mount_tree_node(xdrs, objp)) { + return (FALSE); + } + if (!xdr_pointer(xdrs, (char **) &mnil, sizeof(amq_mount_tree), (XDRPROC_T_TYPE) xdr_amq_mount_subtree)) { + return (FALSE); + } + if (!xdr_pointer(xdrs, (char **) &mp->am_child, sizeof(amq_mount_tree), (XDRPROC_T_TYPE) xdr_amq_mount_subtree)) { + return (FALSE); + } + return (TRUE); +} + + +bool_t +xdr_amq_mount_tree_p(XDR *xdrs, amq_mount_tree_p *objp) +{ + if (!xdr_pointer(xdrs, (char **) objp, sizeof(amq_mount_tree), (XDRPROC_T_TYPE) xdr_amq_mount_tree)) { + return (FALSE); + } + return (TRUE); +} + + +bool_t +xdr_amq_mount_stats(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(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), + (XDRPROC_T_TYPE) xdr_amq_mount_tree_p)) { + return (FALSE); + } + return (TRUE); +} + + + +/* + * Compute length of list + */ +bool_t +xdr_amq_mount_info_qelem(XDR *xdrs, qelem *qhead) +{ + mntfs *mf; + u_int len = 0; + + for (mf = AM_LAST(mntfs, qhead); mf != HEAD(mntfs, qhead); mf = PREV(mntfs, mf)) { + if (!(mf->mf_ops->fs_flags & FS_AMQINFO)) + continue; + len++; + } + xdr_u_int(xdrs, &len); + + /* + * Send individual data items + */ + for (mf = AM_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); +} + + +bool_t +xdr_pri_free(XDRPROC_T_TYPE xdr_args, caddr_t args_ptr) +{ + XDR xdr; + + xdr.x_op = XDR_FREE; + return ((*xdr_args) (&xdr, (caddr_t *) args_ptr)); +} diff --git a/contrib/amd/amd/amq_svc.c b/contrib/amd/amd/amq_svc.c new file mode 100644 index 0000000..5e4c9fd --- /dev/null +++ b/contrib/amd/amd/amq_svc.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amq_svc.c,v 5.2.2.1 1992/02/09 15:09:26 jsp beta $ + * + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* typedefs */ +typedef char *(*amqsvcproc_t)(voidp, struct svc_req *); + + +void +amq_program_1(struct svc_req *rqstp, SVCXPRT *transp) +{ + union { + amq_string amqproc_mnttree_1_arg; + amq_string amqproc_umnt_1_arg; + amq_setopt amqproc_setopt_1_arg; + amq_string amqproc_mount_1_arg; + } argument; + char *result; + xdrproc_t xdr_argument, xdr_result; + amqsvcproc_t local; + + switch (rqstp->rq_proc) { + + case AMQPROC_NULL: + xdr_argument = (xdrproc_t) xdr_void; + xdr_result = (xdrproc_t) xdr_void; + local = (amqsvcproc_t) amqproc_null_1_svc; + break; + + case AMQPROC_MNTTREE: + xdr_argument = (xdrproc_t) xdr_amq_string; + xdr_result = (xdrproc_t) xdr_amq_mount_tree_p; + local = (amqsvcproc_t) amqproc_mnttree_1_svc; + break; + + case AMQPROC_UMNT: + xdr_argument = (xdrproc_t) xdr_amq_string; + xdr_result = (xdrproc_t) xdr_void; + local = (amqsvcproc_t) amqproc_umnt_1_svc; + break; + + case AMQPROC_STATS: + xdr_argument = (xdrproc_t) xdr_void; + xdr_result = (xdrproc_t) xdr_amq_mount_stats; + local = (amqsvcproc_t) amqproc_stats_1_svc; + break; + + case AMQPROC_EXPORT: + xdr_argument = (xdrproc_t) xdr_void; + xdr_result = (xdrproc_t) xdr_amq_mount_tree_list; + local = (amqsvcproc_t) amqproc_export_1_svc; + break; + + case AMQPROC_SETOPT: + xdr_argument = (xdrproc_t) xdr_amq_setopt; + xdr_result = (xdrproc_t) xdr_int; + local = (amqsvcproc_t) amqproc_setopt_1_svc; + break; + + case AMQPROC_GETMNTFS: + xdr_argument = (xdrproc_t) xdr_void; + xdr_result = (xdrproc_t) xdr_amq_mount_info_qelem; + local = (amqsvcproc_t) amqproc_getmntfs_1_svc; + break; + + case AMQPROC_MOUNT: + xdr_argument = (xdrproc_t) xdr_amq_string; + xdr_result = (xdrproc_t) xdr_int; + local = (amqsvcproc_t) amqproc_mount_1_svc; + break; + + case AMQPROC_GETVERS: + xdr_argument = (xdrproc_t) xdr_void; + xdr_result = (xdrproc_t) xdr_amq_string; + local = (amqsvcproc_t) amqproc_getvers_1_svc; + break; + + case AMQPROC_GETPID: + xdr_argument = (xdrproc_t) xdr_void; + xdr_result = (xdrproc_t) xdr_int; + local = (amqsvcproc_t) amqproc_getpid_1_svc; + break; + + default: + svcerr_noproc(transp); + return; + } + + memset((char *) &argument, 0, sizeof(argument)); + if (!svc_getargs(transp, + (XDRPROC_T_TYPE) xdr_argument, + (SVC_IN_ARG_TYPE) & argument)) { + svcerr_decode(transp); + return; + } + + result = (*local) (&argument, rqstp); + + if (result != NULL && !svc_sendreply(transp, + (XDRPROC_T_TYPE) xdr_result, + result)) { + svcerr_systemerr(transp); + } + + if (!svc_freeargs(transp, + (XDRPROC_T_TYPE) xdr_argument, + (SVC_IN_ARG_TYPE) & argument)) { + plog(XLOG_FATAL, "unable to free rpc arguments in amqprog_1"); + going_down(1); + } +} diff --git a/contrib/amd/amd/autil.c b/contrib/amd/amd/autil.c new file mode 100644 index 0000000..ca089bd --- /dev/null +++ b/contrib/amd/amd/autil.c @@ -0,0 +1,418 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: autil.c,v 5.2.2.2 1992/03/07 17:52:06 jsp Exp $ + * + */ + +/* + * utilities specified to amd, taken out of the older amd/util.c. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +int NumChild = 0; /* number of children of primary amd */ +static char invalid_keys[] = "\"'!;@ \t\n"; + +#ifdef HAVE_TRANSPORT_TYPE_TLI +# define PARENT_USLEEP_TIME 100000 /* 0.1 seconds */ +#endif /* HAVE_TRANSPORT_TYPE_TLI */ + + +char * +strealloc(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; +} + + +char ** +strsplit(char *s, int ch, int qc) +{ + char **ivec; + int ic = 0; + int done = 0; + + ivec = (char **) xmalloc((ic + 1) * sizeof(char *)); + + while (!done) { + char *v; + + /* + * skip to split char + */ + while (*s && (ch == ' ' ? (isascii(*s) && isspace((int)*s)) : *s == ch)) + *s++ = '\0'; + + /* + * End of string? + */ + if (!*s) + break; + + /* + * remember start of string + */ + v = s; + + /* + * skip to split char + */ + while (*s && !(ch == ' ' ? (isascii(*s) && isspace((int)*s)) : *s == ch)) { + if (*s++ == qc) { + /* + * Skip past string. + */ + s++; + while (*s && *s != qc) + s++; + if (*s == qc) + s++; + } + } + + if (!*s) + done = 1; + *s++ = '\0'; + + /* + * save string in new ivec slot + */ + ivec[ic++] = v; + ivec = (char **) xrealloc((voidp) ivec, (ic + 1) * sizeof(char *)); +#ifdef DEBUG + amuDebug(D_STR) + plog(XLOG_DEBUG, "strsplit saved \"%s\"", v); +#endif /* DEBUG */ + } + +#ifdef DEBUG + amuDebug(D_STR) + plog(XLOG_DEBUG, "strsplit saved a total of %d strings", ic); +#endif /* DEBUG */ + + ivec[ic] = 0; + + return ivec; +} + + +/* + * Strip off the trailing part of a domain + * to produce a short-form domain relative + * 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(char *otherdom, char *localdom) +{ + char *p1, *p2; + + if ((p1 = strchr(otherdom, '.')) && + (p2 = strchr(localdom, '.')) && + STREQ(p1 + 1, p2 + 1)) + *p1 = '\0'; +} + + +/* + * Normalize a host name + */ +void +host_normalize(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 (gopt.flags & CFM_NORMALIZE_HOSTNAMES) { + struct hostent *hp; + clock_valid = 0; + hp = gethostbyname(*chp); + if (hp && hp->h_addrtype == AF_INET) { +#ifdef DEBUG + dlog("Hostname %s normalized to %s", *chp, hp->h_name); +#endif /* DEBUG */ + *chp = strealloc(*chp, (char *) hp->h_name); + } + } + domain_strip(*chp, hostd); +} + + + +/* + * Keys are not allowed to contain " ' ! or ; to avoid + * problems with macro expansions. + */ +int +valid_key(char *key) +{ + while (*key) + if (strchr(invalid_keys, *key++)) + return FALSE; + return TRUE; +} + + +void +forcibly_timeout_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 +mf_mounted(mntfs *mf) +{ + int quoted; + int wasmounted = mf->mf_flags & MFF_MOUNTED; + + if (!wasmounted) { + /* + * If this is a freshly mounted + * filesystem then update the + * mntfs structure... + */ + mf->mf_flags |= MFF_MOUNTED; + mf->mf_error = 0; + + /* + * Do mounted callback + */ + if (mf->mf_ops->mounted) { + (*mf->mf_ops->mounted) (mf); + } + mf->mf_fo = 0; + } + + /* + * Log message + */ + quoted = strchr(mf->mf_info, ' ') != 0; + plog(XLOG_INFO, "%s%s%s %s fstype %s on %s", + quoted ? "\"" : "", + mf->mf_info, + quoted ? "\"" : "", + wasmounted ? "referenced" : "mounted", + mf->mf_ops->fs_type, mf->mf_mount); +} + + +void +am_mounted(am_node *mp) +{ + mntfs *mf = mp->am_mnt; + + mf_mounted(mf); + + /* + * Patch up path for direct mounts + */ + if (mp->am_parent && mp->am_parent->am_mnt->mf_ops == &amfs_direct_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 { + mntent_t mnt; + if (mf->mf_mopts) { + mnt.mnt_opts = mf->mf_mopts; + if (hasmntopt(&mnt, "nounmount")) + mp->am_flags |= AMF_NOTIMEOUT; + if ((mp->am_timeo = hasmntval(&mnt, "utimeout")) == 0) + mp->am_timeo = gopt.am_timeo; + } + } + + /* + * If this node is a symlink then + * compute the length of the returned string. + */ + if (mp->am_fattr.na_type == NFLNK) + mp->am_fattr.na_size = strlen(mp->am_link ? mp->am_link : mp->am_mnt->mf_mount); + + /* + * Record mount time + */ + mp->am_fattr.na_mtime.nt_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_fattr.na_mtime.nt_seconds = mp->am_stats.s_mtime; + + /* + * Now, if we can, do a reply to our NFS client here + * to speed things up. + */ + quick_reply(mp, 0); + + /* + * Update stats + */ + amd_stats.d_mok++; +} + + +int +mount_node(am_node *mp) +{ + mntfs *mf = mp->am_mnt; + int error = 0; + + mf->mf_flags |= MFF_MOUNTING; + error = (*mf->mf_ops->mount_fs) (mp); + + mf = mp->am_mnt; + if (error >= 0) + mf->mf_flags &= ~MFF_MOUNTING; + if (!error && !(mf->mf_ops->fs_flags & FS_MBACKGROUND)) { + /* ...but see ifs_mount */ + am_mounted(mp); + } + + return error; +} + + +void +am_unmounted(am_node *mp) +{ + mntfs *mf = mp->am_mnt; + + if (!foreground) /* firewall - should never happen */ + return; + + /* + * 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_fattr.na_mtime.nt_seconds = clocktime(); + + free_map(mp); +} + + +/* + * Fork the automounter + * + * TODO: Need a better strategy for handling errors + */ +static int +dofork(void) +{ + int pid; + +top: + pid = fork(); + + if (pid < 0) { /* fork error, retry in 1 second */ + sleep(1); + goto top; + } + if (pid == 0) { /* child process (foreground==false) */ + mypid = getpid(); + foreground = 0; + } else { /* parent process, has one more child */ + NumChild++; + } + + return pid; +} + + +int +background(void) +{ + int pid = dofork(); + + if (pid == 0) { +#ifdef DEBUG + dlog("backgrounded"); +#endif /* DEBUG */ + foreground = 0; + } + return pid; +} diff --git a/contrib/amd/amd/clock.c b/contrib/amd/amd/clock.c new file mode 100644 index 0000000..3c0494a --- /dev/null +++ b/contrib/amd/amd/clock.c @@ -0,0 +1,247 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: clock.c,v 5.2.2.1 1992/02/09 15:08:20 jsp beta $ + * + */ + +/* + * Callouts. + * + * Modelled on kernel object of the same name. + * See usual references. + * + * Use of a heap-based mechanism was rejected: + * 1. more complex implementation needed. + * 2. not obvious that a list is too slow for Amd. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +int timeout(u_int secs, void (*fn) (voidp), voidp closure); +void reschedule_timeouts(time_t now, time_t then); + +typedef struct callout callout; +struct callout { + callout *c_next; /* List of callouts */ + void (*c_fn) (voidp); /* Function to call */ + voidp c_closure; /* Closure to pass to call */ + 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 + +/* + * Global assumption: valid id's are non-zero. + */ +#define CID_ALLOC(struct ) (++callout_id) +#define CID_UNDEF (0) + + +static callout * +alloc_callout(void) +{ + callout *cp = free_callouts; + + if (cp) { + --nfree_callouts; + free_callouts = free_callouts->c_next; + return cp; + } + return ALLOC(struct callout); +} + + +static void +free_callout(callout *cp) +{ + if (nfree_callouts > CALLOUT_FREE_SLOP) { + XFREE(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(u_int secs, void (*fn) (voidp), 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(struct ); + + 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(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; + } + } +} + + +/* + * Reschedule after clock changed + */ +void +reschedule_timeouts(time_t now, time_t then) +{ + callout *cp; + + for (cp = callouts.c_next; cp; cp = cp->c_next) { + if (cp->c_time >= now && cp->c_time <= then) { + plog(XLOG_WARNING, "job %d rescheduled to run immediately", cp->c_id); +#ifdef DEBUG + dlog("rescheduling job %d back %d seconds", cp->c_id, cp->c_time - now); +#endif /* DEBUG */ + next_softclock = cp->c_time = now; + } + } +} + + +/* + * Clock handler + */ +int +softclock(void) +{ + time_t now; + callout *cp; + + do { + if (task_notify_todo) + do_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) (voidp) = cp->c_fn; + voidp closure = cp->c_closure; + + callouts.c_next = cp->c_next; + free_callout(cp); + (*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/contrib/amd/amd/conf.c b/contrib/amd/amd/conf.c new file mode 100644 index 0000000..a97b1b1 --- /dev/null +++ b/contrib/amd/amd/conf.c @@ -0,0 +1,939 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: conf.c,v 5.2.2.1 1992/02/09 15:08:23 jsp beta $ + * + */ + +/* + * Functions to handle the configuration file. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + + +/* + * MACROS: + */ +/* Turn on to show some info about maps being configured */ +/* #define DEBUG_CONF */ + +/* + * TYPEDEFS: + */ +typedef int (*OptFuncPtr)(const char *); + +/* + * STRUCTURES: + */ +struct _func_map { + char *name; + OptFuncPtr func; +}; + +/* + * FORWARD DECLARATIONS: + */ +static int gopt_arch(const char *val); +static int gopt_auto_dir(const char *val); +static int gopt_browsable_dirs(const char *val); +static int gopt_cache_duration(const char *val); +static int gopt_cluster(const char *val); +static int gopt_debug_options(const char *val); +static int gopt_dismount_interval(const char *val); +static int gopt_fully_qualified_hosts(const char *val); +static int gopt_hesiod_base(const char *val); +static int gopt_karch(const char *val); +static int gopt_ldap_base(const char *val); +static int gopt_ldap_cache_maxmem(const char *val); +static int gopt_ldap_cache_seconds(const char *val); +static int gopt_ldap_hostports(const char *val); +static int gopt_local_domain(const char *val); +static int gopt_log_file(const char *val); +static int gopt_log_options(const char *val); +static int gopt_map_options(const char *val); +static int gopt_map_type(const char *val); +static int gopt_mount_type(const char *val); +static int gopt_pid_file(const char *val); +static int gopt_portmap_program(const char *val); +static int gopt_nfs_retransmit_counter(const char *val); +static int gopt_nfs_retry_interval(const char *val); +static int gopt_nis_domain(const char *val); +static int gopt_normalize_hostnames(const char *val); +static int gopt_os(const char *val); +static int gopt_osver(const char *val); +static int gopt_plock(const char *val); +static int gopt_print_pid(const char *val); +static int gopt_print_version(const char *val); +static int gopt_restart_mounts(const char *val); +static int gopt_search_path(const char *val); +static int gopt_selectors_on_default(const char *val); +static int gopt_show_statfs_entries(const char *val); +static int gopt_unmount_on_exit(const char *val); +static int process_global_option(const char *key, const char *val); +static int process_regular_map(cf_map_t *cfm); +static int process_regular_option(const char *section, const char *key, const char *val, cf_map_t *cfm); +static int ropt_browsable_dirs(const char *val, cf_map_t *cfm); +static int ropt_map_name(const char *val, cf_map_t *cfm); +static int ropt_map_options(const char *val, cf_map_t *cfm); +static int ropt_map_type(const char *val, cf_map_t *cfm); +static int ropt_mount_type(const char *val, cf_map_t *cfm); +static int ropt_search_path(const char *val, cf_map_t *cfm); +static int ropt_tag(const char *val, cf_map_t *cfm); +static void reset_cf_map(cf_map_t *cfm); + + +/* + * STATIC VARIABLES: + */ +static cf_map_t cur_map; +static struct _func_map glob_functable[] = { + {"arch", gopt_arch}, + {"auto_dir", gopt_auto_dir}, + {"browsable_dirs", gopt_browsable_dirs}, + {"cache_duration", gopt_cache_duration}, + {"cluster", gopt_cluster}, + {"debug_options", gopt_debug_options}, + {"dismount_interval", gopt_dismount_interval}, + {"fully_qualified_hosts", gopt_fully_qualified_hosts}, + {"hesiod_base", gopt_hesiod_base}, + {"karch", gopt_karch}, + {"ldap_base", gopt_ldap_base}, + {"ldap_cache_maxmem", gopt_ldap_cache_maxmem}, + {"ldap_cache_seconds", gopt_ldap_cache_seconds}, + {"ldap_hostports", gopt_ldap_hostports}, + {"local_domain", gopt_local_domain}, + {"log_file", gopt_log_file}, + {"log_options", gopt_log_options}, + {"map_options", gopt_map_options}, + {"map_type", gopt_map_type}, + {"mount_type", gopt_mount_type}, + {"pid_file", gopt_pid_file}, + {"portmap_program", gopt_portmap_program}, + {"nfs_retransmit_counter", gopt_nfs_retransmit_counter}, + {"nfs_retry_interval", gopt_nfs_retry_interval}, + {"nis_domain", gopt_nis_domain}, + {"normalize_hostnames", gopt_normalize_hostnames}, + {"os", gopt_os}, + {"osver", gopt_osver}, + {"plock", gopt_plock}, + {"print_pid", gopt_print_pid}, + {"print_version", gopt_print_version}, + {"restart_mounts", gopt_restart_mounts}, + {"search_path", gopt_search_path}, + {"selectors_on_default", gopt_selectors_on_default}, + {"show_statfs_entries", gopt_show_statfs_entries}, + {"unmount_on_exit", gopt_unmount_on_exit}, + {NULL, NULL} +}; + + +/* + * Reset a map. + */ +static void +reset_cf_map(cf_map_t *cfm) +{ + if (!cfm) + return; + + if (cfm->cfm_dir) { + XFREE(cfm->cfm_dir); + cfm->cfm_dir = NULL; + } + + if (cfm->cfm_name) { + XFREE(cfm->cfm_name); + cfm->cfm_name = NULL; + } + + if (cfm->cfm_tag) { + XFREE(cfm->cfm_tag); + cfm->cfm_tag = NULL; + } + + /* + * reset/initialize a regular map's flags and other variables from the + * global ones, so that they are applied to all maps. Of course, each map + * can then override the flags individually. + * + * NOTES: + * (1): Will only work for maps that appear after [global]. + * (2): Also be careful not to free() a global option. + * (3): I'm doing direct char* pointer comparison, and not strcmp(). This + * is correct! + */ + + /* initialize map_type from [global] */ + if (cfm->cfm_type && cfm->cfm_type != gopt.map_type) + XFREE(cfm->cfm_type); + cfm->cfm_type = gopt.map_type; + + /* initialize map_opts from [global] */ + if (cfm->cfm_opts && cfm->cfm_opts != gopt.map_options) + XFREE(cfm->cfm_opts); + cfm->cfm_opts = gopt.map_options; + + /* initialize search_path from [global] */ + if (cfm->cfm_search_path && cfm->cfm_search_path != gopt.search_path) + XFREE(cfm->cfm_search_path); + cfm->cfm_search_path = gopt.search_path; + + /* + * Initialize flags that are common both to [global] and a local map. + */ + cfm->cfm_flags = gopt.flags & (CFM_BROWSABLE_DIRS | + CFM_BROWSABLE_DIRS_FULL | + CFM_MOUNT_TYPE_AUTOFS | + CFM_ENABLE_DEFAULT_SELECTORS); +} + + +/* + * Process configuration file options. + * Return 0 if OK, 1 otherwise. + */ +int +set_conf_kv(const char *section, const char *key, const char *val) +{ + int ret; + +#ifdef DEBUG_CONF + fprintf(stderr,"set_conf_kv: section=%s, key=%s, val=%s\n", + section, key, val); +#endif /* DEBUG_CONF */ + + /* + * If global section, process them one at a time. + */ + if (STREQ(section, "global")) { + /* + * Check if a regular map was configured before "global", + * and process it as needed. + */ + if (cur_map.cfm_dir) { + fprintf(stderr,"processing regular map \"%s\" before global one.\n", + section); + ret = process_regular_map(&cur_map); /* will reset map */ + if (ret != 0) + return ret; + } + + /* process the global option first */ + ret = process_global_option(key, val); + + /* reset default options for regular maps from just updated globals */ + if (ret == 0) + reset_cf_map(&cur_map); + + /* return status from the processing of the global option */ + return ret; + } + + /* + * otherwise save options and process a single map all at once. + */ + + /* check if we found a new map, so process one already collected */ + if (cur_map.cfm_dir && !STREQ(cur_map.cfm_dir, section)) { + ret = process_regular_map(&cur_map); /* will reset map */ + if (ret != 0) + return ret; + } + + /* now process a single entry of a regular map */ + return process_regular_option(section, key, val, &cur_map); +} + + +/* + * Process global section of configuration file options. + * Return 0 upon success, 1 otherwise. + */ +static int +process_global_option(const char *key, const char *val) +{ + struct _func_map *gfp; + + /* ensure that val is valid */ + if (!val || val[0] == '\0') + return 1; + + /* + * search for global function. + */ + for (gfp = glob_functable; gfp->name; gfp++) + if (FSTREQ(gfp->name, key)) + return (gfp->func)(val); + + fprintf(stderr, "conf: unknown global key: \"%s\"\n", key); + return 1; /* failed to match any command */ +} + + +static int +gopt_arch(const char *val) +{ + gopt.arch = strdup((char *)val); + return 0; +} + + +static int +gopt_auto_dir(const char *val) +{ + gopt.auto_dir = strdup((char *)val); + return 0; +} + + +static int +gopt_browsable_dirs(const char *val) +{ + if (STREQ(val, "full")) { + gopt.flags |= CFM_BROWSABLE_DIRS_FULL; + return 0; + } else if (STREQ(val, "yes")) { + gopt.flags |= CFM_BROWSABLE_DIRS; + return 0; + } else if (STREQ(val, "no")) { + gopt.flags &= ~CFM_BROWSABLE_DIRS; + return 0; + } + + fprintf(stderr, "conf: unknown value to browsable_dirs \"%s\"\n", val); + return 1; /* unknown value */ +} + + +static int +gopt_cache_duration(const char *val) +{ + gopt.am_timeo = atoi(val); + if (gopt.am_timeo <= 0) + gopt.am_timeo = AM_TTL; + return 0; +} + + +static int +gopt_cluster(const char *val) +{ + gopt.cluster = strdup((char *)val); + return 0; +} + + +static int +gopt_debug_options(const char *val) +{ +#ifdef DEBUG + usage += debug_option(strdup((char *)val)); + return 0; +#else /* not DEBUG */ + fprintf(stderr, "%s: not compiled with DEBUG option -- sorry.\n", + progname); + return 1; +#endif /* not DEBUG */ +} + + +static int +gopt_dismount_interval(const char *val) +{ + gopt.am_timeo_w = atoi(val); + if (gopt.am_timeo_w <= 0) + gopt.am_timeo_w = AM_TTL_W; + return 0; +} + + +static int +gopt_fully_qualified_hosts(const char *val) +{ + if (STREQ(val, "yes")) { + gopt.flags |= CFM_FULLY_QUALIFIED_HOSTS; + return 0; + } else if (STREQ(val, "no")) { + gopt.flags &= ~CFM_FULLY_QUALIFIED_HOSTS; + return 0; + } + + fprintf(stderr, "conf: unknown value to fully_qualified_hosts \"%s\"\n", val); + return 1; /* unknown value */ +} + + +static int +gopt_hesiod_base(const char *val) +{ +#ifdef HAVE_MAP_HESIOD + gopt.hesiod_base = strdup((char *)val); + return 0; +#else /* not HAVE_MAP_HESIOD */ + fprintf(stderr, "conf: hesiod_base option ignored. No Hesiod support available.\n"); + return 1; +#endif /* not HAVE_MAP_HESIOD */ +} + + +static int +gopt_karch(const char *val) +{ + gopt.karch = strdup((char *)val); + return 0; +} + + +static int +gopt_pid_file(const char *val) +{ + gopt.pid_file = strdup((char *)val); + return 0; +} + + +static int +gopt_local_domain(const char *val) +{ + gopt.sub_domain = strdup((char *)val); + return 0; +} + + +static int +gopt_ldap_base(const char *val) +{ +#ifdef HAVE_MAP_LDAP + gopt.ldap_base = strdup((char *)val); + return 0; +#else /* not HAVE_MAP_LDAP */ + fprintf(stderr, "conf: ldap_base option ignored. No LDAP support available.\n"); + return 1; +#endif /* not HAVE_MAP_LDAP */ +} + + +static int +gopt_ldap_cache_seconds(const char *val) +{ +#ifdef HAVE_MAP_LDAP + char *end; + + gopt.ldap_cache_seconds = strtol((char *)val, &end, 10); + if (end == val) { + fprintf(stderr, "conf: bad LDAP cache (seconds) option: %s\n",val); + return 1; + } + return 0; +#else /* not HAVE_MAP_LDAP */ + fprintf(stderr, "conf: ldap_cache option ignored. No LDAP support available.\n"); + return 1; +#endif /* not HAVE_MAP_LDAP */ +} + + +static int +gopt_ldap_cache_maxmem(const char *val) +{ +#ifdef HAVE_MAP_LDAP + char *end; + + gopt.ldap_cache_maxmem = strtol((char *)val, &end, 10); + if (end == val) { + fprintf(stderr, "conf: bad LDAP cache (maxmem) option: %s\n",val); + return 1; + } + return 0; +#else /* not HAVE_MAP_LDAP */ + fprintf(stderr, "conf: ldap_cache option ignored. No LDAP support available.\n"); + return 1; +#endif /* not HAVE_MAP_LDAP */ +} + + +static int +gopt_ldap_hostports(const char *val) +{ +#ifdef HAVE_MAP_LDAP + gopt.ldap_hostports = strdup((char *)val); + return 0; +#else /* not HAVE_MAP_LDAP */ + fprintf(stderr, "conf: ldap_hostports option ignored. No LDAP support available.\n"); + return 1; +#endif /* not HAVE_MAP_LDAP */ + +} + + +static int +gopt_log_file(const char *val) +{ + gopt.logfile = strdup((char *)val); + return 0; +} + + +static int +gopt_log_options(const char *val) +{ + usage += switch_option(strdup((char *)val)); + return 0; +} + + +static int +gopt_map_options(const char *val) +{ + gopt.map_options = strdup((char *)val); + return 0; +} + + +static int +gopt_map_type(const char *val) +{ + gopt.map_type = strdup((char *)val); + return 0; +} + + +static int +gopt_mount_type(const char *val) +{ + if (STREQ(val, "autofs")) { +#ifdef HAVE_FS_AUTOFS + gopt.flags |= CFM_MOUNT_TYPE_AUTOFS; + return 0; +#else /* not HAVE_FS_AUTOFS */ + fprintf(stderr, "conf: no autofs support available\n"); + return 1; +#endif /* not HAVE_FS_AUTOFS */ + } else if (STREQ(val, "nfs")) { + gopt.flags &= ~CFM_MOUNT_TYPE_AUTOFS; + return 0; + } + + fprintf(stderr, "conf: unknown value to mount_type \"%s\"\n", val); + return 1; /* unknown value */ +} + + +static int +gopt_portmap_program(const char *val) +{ + gopt.portmap_program = atoi(val); + /* + * allow alternate program numbers to be no more than 10 offset from + * official amd program number (300019). + */ + if (gopt.portmap_program < AMQ_PROGRAM || + gopt.portmap_program > AMQ_PROGRAM + 10) { + gopt.portmap_program = AMQ_PROGRAM; + set_amd_program_number(gopt.portmap_program); + fprintf(stderr, "conf: illegal amd program numver \"%s\"\n", val); + return 1; + } + + set_amd_program_number(gopt.portmap_program); + return 0; /* all is OK */ +} + + +static int +gopt_nfs_retransmit_counter(const char *val) +{ + gopt.amfs_auto_retrans = atoi(val); + return 0; +} + + +static int +gopt_nfs_retry_interval(const char *val) +{ + gopt.amfs_auto_timeo = atoi(val); + return 0; +} + + +static int +gopt_nis_domain(const char *val) +{ +#ifdef HAVE_MAP_NIS + gopt.nis_domain = strdup((char *)val); + return 0; +#else /* not HAVE_MAP_NIS */ + fprintf(stderr, "conf: nis_domain option ignored. No NIS support available.\n"); + return 1; +#endif /* not HAVE_MAP_NIS */ +} + + +static int +gopt_normalize_hostnames(const char *val) +{ + if (STREQ(val, "yes")) { + gopt.flags |= CFM_NORMALIZE_HOSTNAMES; + return 0; + } else if (STREQ(val, "no")) { + gopt.flags &= ~CFM_NORMALIZE_HOSTNAMES; + return 0; + } + + fprintf(stderr, "conf: unknown value to normalize_hostnames \"%s\"\n", val); + return 1; /* unknown value */ +} + + +static int +gopt_os(const char *val) +{ + gopt.op_sys = strdup((char *)val); + return 0; +} + + +static int +gopt_osver(const char *val) +{ + gopt.op_sys_ver = strdup((char *)val); + return 0; +} + + +static int +gopt_plock(const char *val) +{ + if (STREQ(val, "yes")) { + gopt.flags |= CFM_PROCESS_LOCK; + return 0; + } else if (STREQ(val, "no")) { + gopt.flags &= ~CFM_PROCESS_LOCK; + return 0; + } + + fprintf(stderr, "conf: unknown value to plock \"%s\"\n", val); + return 1; /* unknown value */ +} + + +static int +gopt_print_pid(const char *val) +{ + if (STREQ(val, "yes")) { + gopt.flags |= CFM_PRINT_PID; + return 0; + } else if (STREQ(val, "no")) { + gopt.flags &= ~CFM_PRINT_PID; + return 0; + } + + fprintf(stderr, "conf: unknown value to print_pid \"%s\"\n", val); + return 1; /* unknown value */ +} + + +static int +gopt_print_version(const char *val) +{ + if (STREQ(val, "yes")) { + fputs(get_version_string(), stderr); + return 0; + } else if (STREQ(val, "no")) { + return 0; + } + + fprintf(stderr, "conf: unknown value to print_version \"%s\"\n", val); + return 1; /* unknown value */ +} + + +static int +gopt_restart_mounts(const char *val) +{ + if (STREQ(val, "yes")) { + gopt.flags |= CFM_RESTART_EXISTING_MOUNTS; + return 0; + } else if (STREQ(val, "no")) { + gopt.flags &= ~CFM_RESTART_EXISTING_MOUNTS; + return 0; + } + + fprintf(stderr, "conf: unknown value to restart_mounts \"%s\"\n", val); + return 1; /* unknown value */ +} + + +static int +gopt_search_path(const char *val) +{ + gopt.search_path = strdup((char *)val); + return 0; +} + + +static int +gopt_selectors_on_default(const char *val) +{ + if (STREQ(val, "yes")) { + gopt.flags |= CFM_ENABLE_DEFAULT_SELECTORS; + return 0; + } else if (STREQ(val, "no")) { + gopt.flags &= ~CFM_ENABLE_DEFAULT_SELECTORS; + return 0; + } + + fprintf(stderr, "conf: unknown value to enable_default_selectors \"%s\"\n", val); + return 1; /* unknown value */ +} + + +static int +gopt_show_statfs_entries(const char *val) +{ + if (STREQ(val, "yes")) { + gopt.flags |= CFM_SHOW_STATFS_ENTRIES; + return 0; + } else if (STREQ(val, "no")) { + gopt.flags &= ~CFM_SHOW_STATFS_ENTRIES; + return 0; + } + + fprintf(stderr, "conf: unknown value to show_statfs_entries \"%s\"\n", val); + return 1; /* unknown value */ +} + + +static int +gopt_unmount_on_exit(const char *val) +{ + if (STREQ(val, "yes")) { + gopt.flags |= CFM_UNMOUNT_ON_EXIT; + return 0; + } else if (STREQ(val, "no")) { + gopt.flags &= ~CFM_UNMOUNT_ON_EXIT; + return 0; + } + + fprintf(stderr, "conf: unknown value to unmount_on_exit \"%s\"\n", val); + return 1; /* unknown value */ +} + + +/* + * Collect one entry for a regular map + */ +static int +process_regular_option(const char *section, const char *key, const char *val, cf_map_t *cfm) +{ + /* ensure that val is valid */ + if (!section || section[0] == '\0' || + !key || key[0] == '\0' || + !val || val[0] == '\0' || + !cfm) { + fprintf(stderr, "conf: process_regular_option: null entries\n"); + return 1; + } + + /* check if initializing a new map */ + if (!cfm->cfm_dir) + cfm->cfm_dir = strdup((char *)section); + + /* check for each possible field */ + if (STREQ(key, "browsable_dirs")) + return ropt_browsable_dirs(val, cfm); + + if (STREQ(key, "map_name")) + return ropt_map_name(val, cfm); + + if (STREQ(key, "map_options")) + return ropt_map_options(val, cfm); + + if (STREQ(key, "map_type")) + return ropt_map_type(val, cfm); + + if (STREQ(key, "mount_type")) + return ropt_mount_type(val, cfm); + + if (STREQ(key, "search_path")) + return ropt_search_path(val, cfm); + + if (STREQ(key, "tag")) + return ropt_tag(val, cfm); + + fprintf(stderr, "conf: unknown regular key \"%s\" for section \"%s\"\n", + key, section); + return 1; /* failed to match any command */ +} + + +static int +ropt_browsable_dirs(const char *val, cf_map_t *cfm) +{ + if (STREQ(val, "full")) { + cfm->cfm_flags |= CFM_BROWSABLE_DIRS_FULL; + return 0; + } else if (STREQ(val, "yes")) { + cfm->cfm_flags |= CFM_BROWSABLE_DIRS; + return 0; + } else if (STREQ(val, "no")) { + cfm->cfm_flags &= ~CFM_BROWSABLE_DIRS; + return 0; + } + + fprintf(stderr, "conf: unknown value to browsable_dirs \"%s\"\n", val); + return 1; /* unknown value */ +} + + +static int +ropt_map_name(const char *val, cf_map_t *cfm) +{ + cfm->cfm_name = strdup((char *)val); + return 0; +} + + +static int +ropt_map_options(const char *val, cf_map_t *cfm) +{ + cfm->cfm_opts = strdup((char *)val); + return 0; +} + + +static int +ropt_map_type(const char *val, cf_map_t *cfm) +{ + cfm->cfm_type = strdup((char *)val); + return 0; +} + + +static int +ropt_mount_type(const char *val, cf_map_t *cfm) +{ + if (STREQ(val, "autofs")) { +#ifdef HAVE_FS_AUTOFS + cfm->cfm_flags |= CFM_MOUNT_TYPE_AUTOFS; + return 0; +#else /* not HAVE_FS_AUTOFS */ + fprintf(stderr, "conf: no autofs support available\n"); + return 1; +#endif /* not HAVE_FS_AUTOFS */ + } else if (STREQ(val, "nfs")) { + cfm->cfm_flags &= ~CFM_MOUNT_TYPE_AUTOFS; + return 0; + } + + fprintf(stderr, "conf: unknown value to mount_type \"%s\"\n", val); + return 1; /* unknown value */ +} + + +static int +ropt_search_path(const char *val, cf_map_t *cfm) +{ + cfm->cfm_search_path = strdup((char *)val); + return 0; +} + + +static int +ropt_tag(const char *val, cf_map_t *cfm) +{ + cfm->cfm_tag = strdup((char *)val); + return 0; +} + + +/* + * Process one collected map. + */ +static int +process_regular_map(cf_map_t *cfm) +{ + + if (!cfm->cfm_name) { + fprintf(stderr, "conf: map_name must be defined for map \"%s\"\n", cfm->cfm_dir); + return 1; + } + /* + * If map has no tag defined, process the map. + * If no conf_tag was set in amd -T, process all untagged entries. + * If a tag is defined, then process it only if it matches the map tag. + */ + if (!cfm->cfm_tag || + (conf_tag && STREQ(cfm->cfm_tag, conf_tag))) { +#ifdef DEBUG_CONF + fprintf(stderr, "processing map %s (flags=0x%x)...\n", + cfm->cfm_dir, cfm->cfm_flags); +#endif /* DEBUG_CONF */ + root_newmap(cfm->cfm_dir, + cfm->cfm_opts ? cfm->cfm_opts : "", + cfm->cfm_name, + cfm); + } else { + fprintf(stderr, "skipping map %s...\n", cfm->cfm_dir); + } + + reset_cf_map(cfm); + return 0; +} + + +/* + * Process last map in conf file (if any) + */ +int +process_last_regular_map(void) +{ + /* + * If the amd.conf file only has a [global] section (pretty useless + * IMHO), do not try to process a map that does not exist. + */ + if (!cur_map.cfm_dir) + return 0; + return process_regular_map(&cur_map); +} diff --git a/contrib/amd/amd/conf_parse.y b/contrib/amd/amd/conf_parse.y new file mode 100644 index 0000000..2a9877a --- /dev/null +++ b/contrib/amd/amd/conf_parse.y @@ -0,0 +1,159 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: conf_parse.y,v 5.2.2.1 1992/02/09 15:09:35 jsp beta $ + * + */ + +%{ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +extern char *yytext; +extern int yylineno; +extern int yylex(void); + +static int yyerror(const char *s); +static int retval; +static char *header_section = NULL; /* start with no header section */ + +#define YYDEBUG 1 + +#define PARSE_DEBUG 0 + +#if PARSE_DEBUG +# define dprintf(f,s) fprintf(stderr, (f), yylineno, (s)) +# define amu_return(v) +#else +# define dprintf(f,s) +# define amu_return(v) return((v)) +#endif /* PARSE_DEBUG */ + +%} + +%union { +char *strtype; +} + +%token LEFT_BRACKET RIGHT_BRACKET EQUAL +%token NEWLINE +%token <strtype> NONWS_STRING +%token <strtype> NONWSEQ_STRING +%token <strtype> QUOTED_NONWSEQ_STRING + +%start file +%% + +/****************************************************************************/ +file : { yydebug = PARSE_DEBUG; } newlines map_sections + | { yydebug = PARSE_DEBUG; } map_sections + ; + +newlines : NEWLINE + | NEWLINE newlines + ; + +map_sections : map_section + | map_section map_sections + ; + +map_section : sec_header kv_pairs + ; + +sec_header : LEFT_BRACKET NONWS_STRING RIGHT_BRACKET NEWLINE + { + if (yydebug) + fprintf(stderr, "sec_header1 = \"%s\"\n", $2); + header_section = $2; + } + ; + +kv_pairs : kv_pair + | kv_pair kv_pairs + ; + +kv_pair : NONWS_STRING EQUAL NONWS_STRING NEWLINE + { + if (yydebug) + fprintf(stderr,"parse1: key=\"%s\", val=\"%s\"\n", $1, $3); + retval = set_conf_kv(header_section, $1, $3); + if (retval != 0) { + yyerror("syntax error"); + YYABORT; + } + } + | NONWS_STRING EQUAL NONWSEQ_STRING NEWLINE + { + if (yydebug) + fprintf(stderr,"parse2: key=\"%s\", val=\"%s\"\n", $1, $3); + retval = set_conf_kv(header_section, $1, $3); + if (retval != 0) { + yyerror("syntax error"); + YYABORT; + } + } + | NONWS_STRING EQUAL QUOTED_NONWSEQ_STRING NEWLINE + { + if (yydebug) + fprintf(stderr,"parse3: key=\"%s\", val=\"%s\"\n", $1, $3); + retval = set_conf_kv(header_section, $1, $3); + if (retval != 0) { + yyerror("syntax error"); + YYABORT; + } + } + | NEWLINE + ; + +/****************************************************************************/ +%% + +static int +yyerror(const char *s) +{ + fprintf(stderr, "AMDCONF: %s on line %d (section %s)\n", + s, yylineno, + (header_section ? header_section : "null")); + exit(1); + return 1; /* to full compilers that insist on a return statement */ +} diff --git a/contrib/amd/amd/conf_tok.l b/contrib/amd/amd/conf_tok.l new file mode 100644 index 0000000..0ec067b --- /dev/null +++ b/contrib/amd/amd/conf_tok.l @@ -0,0 +1,186 @@ +%{ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: conf_tok.l,v 5.2.2.1 1992/02/09 15:09:36 jsp beta $ + * + */ + +/* + * Lexical analyzer for AMD configuration parser. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +/* + * Some systems include a definition for the macro ECHO in <sys/ioctl.h>, + * and their (bad) version of lex defines it too at the very beginning of + * the generated lex.yy.c file (before it can be easily undefined), + * resulting in a conflict. So undefine it here before needed. + * Luckily, it does not appear that this macro is actually used in the rest + * of the generated lex.yy.c file. + */ +#ifdef ECHO +# undef ECHO +#endif /* ECHO */ +#include <am_defs.h> +#include <amd.h> +#include <conf_parse.h> +/* and once again undefine this, just in case */ +#ifdef ECHO +# undef ECHO +#endif /* ECHO */ + +/* + * There are some things that need to be defined only if useing GNU flex. + * These must not be defined if using standard lex + */ +#ifdef FLEX_SCANNER +# ifndef ECHO +# define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +# endif /* not ECHO */ +int yylineno = 0; +#endif /* FLEX_SCANNER */ + +int yylex(void); +/* + * some systems such as DU-4.x have a different GNU flex in /usr/bin + * which automatically generates yywrap macros and symbols. So I must + * distinguish between them and when yywrap is actually needed. + */ +#ifndef yywrap +int yywrap(void); +#endif /* not yywrap */ + +#define TOK_DEBUG 0 + +#if TOK_DEBUG +# define dprintf(f,s) fprintf(stderr, (f), yylineno, (s)) +# define amu_return(v) +#else +# define dprintf(f,s) +# define amu_return(v) return((v)) +#endif /* TOK_DEBUG */ + +/* no need to use yyunput() or yywrap() */ +#define YY_NO_UNPUT +#define YY_SKIP_YYWRAP + +%} + +DIGIT [0-9] +ALPHA [A-Za-z] +ALPHANUM [A-Za-z0-9] +SYMBOL [A-Za-z0-9_-] +PATH [A-Za-z0-9_-/] +NONWSCHAR [^ \t\n\[\]=] +NONWSEQCHAR [^ \t\n\[\]] +NONNL [^\n] +NONQUOTE [^\"] + +%% + +\n { + yylineno++; + amu_return(NEWLINE); + } + +\[ { + dprintf("%8d: Left bracket \"%s\"\n", yytext); + yylval.strtype = strdup((char *)yytext); + amu_return(LEFT_BRACKET); + } + +\] { + dprintf("%8d: Right bracket \"%s\"\n", yytext); + yylval.strtype = strdup((char *)yytext); + amu_return(RIGHT_BRACKET); + } + += { + dprintf("%8d: Equal \"%s\"\n", yytext); + yylval.strtype = strdup((char *)yytext); + amu_return(EQUAL); + } + +[ \t]* { + dprintf("%8d: Whitespace \"%s\"\n", yytext); + } +"#"[^\n]*\n { + /* a comment line includes the terminating \n */ + yylineno++; + yytext[strlen((char *)yytext)-1] = '\0'; + dprintf("%8d: Comment \"%s\"\n", yytext); + } + +{NONWSCHAR}{NONWSCHAR}* { + dprintf("%8d: Non-WS string \"%s\"\n", yytext); + yylval.strtype = strdup((char *)yytext); + amu_return(NONWS_STRING); + } + +\"{NONQUOTE}{NONQUOTE}*\" { + dprintf("%8d: QUOTED-Non-WS-EQ string \"%s\"\n", yytext); + /* must strip quotes */ + yytext[strlen((char *)yytext)-1] = '\0'; + yylval.strtype = strdup((char *)&yytext[1]); + amu_return(QUOTED_NONWSEQ_STRING); + } + +{NONWSEQCHAR}{NONWSEQCHAR}* { + dprintf("%8d: Non-WS-EQ string \"%s\"\n", yytext); + yylval.strtype = strdup((char *)yytext); + amu_return(NONWSEQ_STRING); + } + +%% + +/* + * some systems such as DU-4.x have a different GNU flex in /usr/bin + * which automatically generates yywrap macros and symbols. So I must + * distinguish between them and when yywrap is actually needed. + */ +#ifndef yywrap +int yywrap(void) +{ + return 1; +} +#endif /* not yywrap */ diff --git a/contrib/amd/amd/get_args.c b/contrib/amd/amd/get_args.c new file mode 100644 index 0000000..b365ff7 --- /dev/null +++ b/contrib/amd/amd/get_args.c @@ -0,0 +1,389 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: get_args.c,v 5.2.2.1 1992/02/09 15:08:23 jsp beta $ + * + */ + +/* + * Argument decode + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* include auto-generated version file */ +#include <build_version.h> + +char *conf_file = "/etc/amd.conf"; /* default amd configuration file */ +char *conf_tag = NULL; /* default conf file tags to use */ +int usage = 0; +int use_conf_file = 0; /* default don't use amd.conf file */ +char *mnttab_file_name = NULL; /* symbol must be available always */ +#ifdef DEBUG +int debug_flags = D_AMQ /* Register AMQ */ + | D_DAEMON; /* Enter daemon mode */ +#endif /* DEBUG */ + + +/* + * Return the version string (dynamic buffer) + */ +char * +get_version_string(void) +{ + static char *vers = NULL; + char tmpbuf[1024]; + char *wire_buf; + int wire_buf_len = 0; + + /* first get dynamic string listing all known networks */ + wire_buf = print_wires(); + if (wire_buf) + wire_buf_len = strlen(wire_buf); + + vers = xmalloc(2048 + wire_buf_len); + sprintf(vers, "%s\n%s\n%s\n%s\n", + "Copyright (c) 1997-1998 Erez Zadok", + "Copyright (c) 1990 Jan-Simon Pendry", + "Copyright (c) 1990 Imperial College of Science, Technology & Medicine", + "Copyright (c) 1990 The Regents of the University of California."); + sprintf(tmpbuf, "%s version %s (build %d).\n", + PACKAGE, VERSION, AMU_BUILD_VERSION); + strcat(vers, tmpbuf); + sprintf(tmpbuf, "Built by %s@%s on date %s.\n", + USER_NAME, HOST_NAME, CONFIG_DATE); + strcat(vers, tmpbuf); + sprintf(tmpbuf, "cpu=%s (%s-endian), arch=%s, karch=%s.\n", + cpu, endian, gopt.arch, gopt.karch); + strcat(vers, tmpbuf); + sprintf(tmpbuf, "full_os=%s, os=%s, osver=%s, vendor=%s.\n", + HOST_OS, gopt.op_sys, gopt.op_sys_ver, HOST_VENDOR); + strcat(vers, tmpbuf); + + strcat(vers, "Map support for: "); + mapc_showtypes(tmpbuf); + strcat(vers, tmpbuf); + strcat(vers, ".\nAMFS: "); + ops_showamfstypes(tmpbuf); + strcat(vers, tmpbuf); + strcat(vers, ".\nFS: "); + ops_showfstypes(tmpbuf); + strcat(vers, tmpbuf); + + /* append list of networks if available */ + if (wire_buf) { + strcat(vers, wire_buf); + XFREE(wire_buf); + } + + return vers; +} + + +void +get_args(int argc, char *argv[]) +{ + int opt_ch; + FILE *fp = stdin; + + /* if no arguments were passed, try to use /etc/amd.conf file */ + if (argc <= 1) + use_conf_file = 1; + + while ((opt_ch = getopt(argc, argv, "nprvSa:c:d:k:l:o:t:w:x:y:C:D:F:T:O:H")) != EOF) + switch (opt_ch) { + + case 'a': + if (*optarg != '/') { + fprintf(stderr, "%s: -a option must begin with a '/'\n", + progname); + exit(1); + } + gopt.auto_dir = optarg; + break; + + case 'c': + gopt.am_timeo = atoi(optarg); + if (gopt.am_timeo <= 0) + gopt.am_timeo = AM_TTL; + break; + + case 'd': + gopt.sub_domain = optarg; + break; + + case 'k': + gopt.karch = optarg; + break; + + case 'l': + gopt.logfile = optarg; + break; + + case 'n': + gopt.flags |= CFM_NORMALIZE_HOSTNAMES; + break; + + case 'o': + gopt.op_sys_ver = optarg; + break; + + case 'p': + gopt.flags |= CFM_PRINT_PID; + break; + + case 'r': + gopt.flags |= CFM_RESTART_EXISTING_MOUNTS; + break; + + case 't': + /* timeo.retrans */ + { + char *dot = strchr(optarg, '.'); + if (dot) + *dot = '\0'; + if (*optarg) { + gopt.amfs_auto_timeo = atoi(optarg); + } + if (dot) { + gopt.amfs_auto_retrans = atoi(dot + 1); + *dot = '.'; + } + } + break; + + case 'v': + fputs(get_version_string(), stderr); + exit(0); + break; + + case 'w': + gopt.am_timeo_w = atoi(optarg); + if (gopt.am_timeo_w <= 0) + gopt.am_timeo_w = AM_TTL_W; + break; + + case 'x': + usage += switch_option(optarg); + break; + + case 'y': +#ifdef HAVE_MAP_NIS + gopt.nis_domain = optarg; +#else /* not HAVE_MAP_NIS */ + plog(XLOG_USER, "-y: option ignored. No NIS support available."); +#endif /* not HAVE_MAP_NIS */ + break; + + case 'C': + gopt.cluster = optarg; + break; + + case 'D': +#ifdef DEBUG + usage += debug_option(optarg); +#else /* not DEBUG */ + fprintf(stderr, "%s: not compiled with DEBUG option -- sorry.\n", progname); +#endif /* not DEBUG */ + break; + + case 'F': + conf_file = optarg; + use_conf_file = 1; + break; + + case 'H': + goto show_usage; + break; + + case 'O': + gopt.op_sys = optarg; + break; + + case 'S': + gopt.flags &= ~CFM_PROCESS_LOCK; /* turn process locking off */ + break; + + case 'T': + conf_tag = optarg; + break; + + default: + usage = 1; + break; + } + + /* + * amd.conf file: if not command-line arguments were used, or if -F was + * specified, then use that amd.conf file. If the file cannot be opened, + * abort amd. If it can be found, open it, parse it, and then close it. + */ + if (use_conf_file && conf_file) { + fp = fopen(conf_file, "r"); + if (!fp) { + char buf[128]; + sprintf(buf, "Amd configuration file (%s)", conf_file); + perror(buf); + exit(1); + } + yyin = fp; + yyparse(); + fclose(fp); + if (process_last_regular_map() != 0) + exit(1); + } + + /* make sure there are some default options defined */ + if (xlog_level_init == ~0) { + switch_option(""); + } +#ifdef DEBUG + usage += switch_option("debug"); +#endif /* DEBUG */ + + /* log information regarding amd.conf file */ + if (use_conf_file && conf_file) + plog(XLOG_INFO, "using configuration file %s", conf_file); + +#ifdef HAVE_MAP_LDAP + /* ensure that if ldap_base is specified, that also ldap_hostports is */ + if (gopt.ldap_hostports && !gopt.ldap_base) { + fprintf(stderr, "must specify both ldap_hostports and ldap_base\n"); + exit(1); + } +#endif /* HAVE_MAP_LDAP */ + + if (usage) + goto show_usage; + + while (optind <= argc - 2) { + char *dir = argv[optind++]; + char *map = argv[optind++]; + char *opts = ""; + if (argv[optind] && *argv[optind] == '-') + opts = &argv[optind++][1]; + + root_newmap(dir, opts, map, NULL); + } + + if (optind == argc) { + /* + * Append domain name to hostname. + * sub_domain overrides hostdomain + * if given. + */ + if (gopt.sub_domain) + hostdomain = gopt.sub_domain; + if (*hostdomain == '.') + hostdomain++; + strcat(hostd, "."); + strcat(hostd, hostdomain); + +#ifdef MOUNT_TABLE_ON_FILE +# ifdef DEBUG + if (debug_flags & D_MTAB) + mnttab_file_name = DEBUG_MNTTAB; + else +# endif /* DEBUG */ + mnttab_file_name = MNTTAB_FILE_NAME; +#else /* not MOUNT_TABLE_ON_FILE */ +# ifdef DEBUG + if (debug_flags & D_MTAB) + dlog("-D mtab option ignored"); +# endif /* DEBUG */ +#endif /* not MOUNT_TABLE_ON_FILE */ + + if (switch_to_logfile(gopt.logfile) != 0) + plog(XLOG_USER, "Cannot switch logfile"); + + /* + * If the kernel architecture was not specified + * then use the machine architecture. + */ + if (gopt.karch == 0) + gopt.karch = gopt.arch; + + if (gopt.cluster == 0) + gopt.cluster = hostdomain; + + if (gopt.amfs_auto_timeo <= 0) + gopt.amfs_auto_timeo = AMFS_AUTO_TIMEO; + if (gopt.amfs_auto_retrans <= 0) + gopt.amfs_auto_retrans = AMFS_AUTO_RETRANS; + if (gopt.amfs_auto_retrans <= 0) + gopt.amfs_auto_retrans = 3; /* XXX */ + return; + } + +show_usage: + fprintf(stderr, + "Usage: %s [-nprvHS] [-a mount_point] [-c cache_time] [-d domain]\n\ +\t[-k kernel_arch] [-l logfile%s\n\ +\t[-t timeout.retrans] [-w wait_timeout] [-C cluster_name]\n\ +\t[-o op_sys_ver] [-O op_sys_name]\n\ +\t[-F conf_file] [-T conf_tag]", progname, +#ifdef HAVE_SYSLOG +# ifdef LOG_DAEMON + "|\"syslog[:facility]\"]" +# else /* not LOG_DAEMON */ + "|\"syslog\"]" +# endif /* not LOG_DAEMON */ +#else /* not HAVE_SYSLOG */ + "]" +#endif /* not HAVE_SYSLOG */ + ); + +#ifdef HAVE_MAP_NIS + fputs(" [-y nis-domain]\n", stderr); +#else /* not HAVE_MAP_NIS */ + fputc('\n', stderr); +#endif /* HAVE_MAP_NIS */ + + show_opts('x', xlog_opt); +#ifdef DEBUG + show_opts('D', dbg_opt); +#endif /* DEBUG */ + fprintf(stderr, "\t[directory mapname [-map_options]] ...\n"); + exit(1); +} diff --git a/contrib/amd/amd/info_file.c b/contrib/amd/amd/info_file.c new file mode 100644 index 0000000..55c24bd --- /dev/null +++ b/contrib/amd/amd/info_file.c @@ -0,0 +1,265 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: info_file.c,v 5.2.2.1 1992/02/09 15:08:28 jsp beta $ + * + */ + +/* + * Get info from file + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +#define MAX_LINE_LEN 1500 + +/* forward declarations */ +int file_init(mnt_map *m, char *map, time_t *tp); +int file_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *)); +int file_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp); +int file_mtime(mnt_map *m, char *map, time_t *tp); + + +static int +read_line(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; + *buf = '\n'; + buf[1] = '\0'; + /* + * 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(FILE * fp, char *map, char *key, char **val, mnt_map *m, void (*fn) (mnt_map *m, char *, char *)) +{ + char key_val[MAX_LINE_LEN]; + int chuck = 0; + 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((int)*kp); kp++) ; + + /* + * Ignore blank lines + */ + if (!*kp) + goto again; + + /* + * Find end of key + */ + for (cp = kp; *cp && (!isascii(*cp) || !isspace((int)*cp)); cp++) ; + + /* + * Check whether key matches + */ + if (*cp) + *cp++ = '\0'; + + if (fn || (*key == *kp && STREQ(key, kp))) { + while (*cp && isascii(*cp) && isspace((int)*cp)) + cp++; + if (*cp) { + /* + * Return a copy of the data + */ + char *dc = strdup(cp); + if (fn) { + (*fn) (m, strdup(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; +} + + +static FILE * +file_open(char *map, time_t *tp) +{ + FILE *mapf = fopen(map, "r"); + + if (mapf && tp) { + struct stat stb; + if (fstat(fileno(mapf), &stb) < 0) + *tp = clocktime(); + else + *tp = stb.st_mtime; + } + return mapf; +} + + +int +file_init(mnt_map *m, char *map, time_t *tp) +{ + FILE *mapf = file_open(map, tp); + + if (mapf) { + fclose(mapf); + return 0; + } + return errno; +} + + +int +file_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *)) +{ + FILE *mapf = file_open(map, (time_t *) 0); + + if (mapf) { + int error = search_or_reload_file(mapf, map, 0, 0, m, fn); + (void) fclose(mapf); + return error; + } + return errno; +} + + +int +file_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp) +{ + time_t t; + FILE *mapf = file_open(map, &t); + + if (mapf) { + int error; + if (*tp < t) { + *tp = t; + error = -1; + } else { + error = search_or_reload_file(mapf, map, key, pval, 0, 0); + } + (void) fclose(mapf); + return error; + } + return errno; +} + + +int +file_mtime(mnt_map *m, char *map, time_t *tp) +{ + FILE *mapf = file_open(map, tp); + + if (mapf) { + (void) fclose(mapf); + return 0; + } + return errno; +} diff --git a/contrib/amd/amd/info_hesiod.c b/contrib/amd/amd/info_hesiod.c new file mode 100644 index 0000000..a4607e1 --- /dev/null +++ b/contrib/amd/amd/info_hesiod.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: info_hesiod.c,v 1.1 1997-1998/07/11 08:34:52 danny Exp danny $ + * + */ + +/* + * Get info from Hesiod + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +#define HES_PREFIX "hesiod." +#define HES_PREFLEN 7 + +#ifdef HAVE_HESIOD_INIT +/* bsdi3 does not define this extern in any header file */ +extern char **hesiod_resolve(void *context, const char *name, const char *type); + +static voidp hesiod_context; +#endif /* HAVE_HESIOD_INIT */ + +/* + * No easy way to probe the server - check the map name begins with "hesiod." + * Note: this name includes 'amu_' so as to not conflict with libhesiod's + * hesiod_init() function. + */ +int +amu_hesiod_init(mnt_map *m, char *map, time_t *tp) +{ +#ifdef DEBUG + dlog("amu_hesiod_init(%s)", map); +#endif /* DEBUG */ + *tp = 0; + +#ifdef HAVE_HESIOD_INIT + if(!hesiod_context && hesiod_init(&hesiod_context) != 0) + return ENOENT; +#endif /* HAVE_HESIOD_INIT */ + + return NSTREQ(map, HES_PREFIX, HES_PREFLEN) ? 0 : ENOENT; +} + + +/* + * Do a Hesiod nameserver call. + * Modify time is ignored by Hesiod - XXX + */ +int +hesiod_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp) +{ + char hes_key[MAXPATHLEN]; + char **rvec; +#ifndef HAVE_HESIOD_INIT + int error; +#endif /* not HAVE_HESIOD_INIT */ + +#ifdef DEBUG + dlog("hesiod_search(m=%x, map=%s, key=%s, pval=%x tp=%x)", m, map, key, pval, tp); +#endif /* DEBUG */ + + sprintf(hes_key, "%s.%s", key, map + HES_PREFLEN); + + /* + * Call the resolver + */ +#ifdef DEBUG + dlog("Hesiod base is: %s\n", gopt.hesiod_base); + dlog("hesiod_search: hes_resolve(%s, %s)", hes_key, gopt.hesiod_base); + if (debug_flags & D_INFO) + _res.options |= RES_DEBUG; +#endif /* DEBUG */ + +#ifdef HAVE_HESIOD_INIT + /* new style hesiod */ + rvec = hesiod_resolve(hesiod_context, hes_key, gopt.hesiod_base); +#else /* not HAVE_HESIOD_INIT */ + rvec = hes_resolve(hes_key, gopt.hesiod_base); +#endif /* not HAVE_HESIOD_INIT */ + + /* + * If a reply was forthcoming then return + * it (and free subsequent replies) + */ + if (rvec && *rvec) { + *pval = *rvec; + while (*++rvec) + XFREE(*rvec); + return 0; + } + +#ifdef HAVE_HESIOD_INIT + /* new style hesiod */ + return errno; +#else /* not HAVE_HESIOD_INIT */ + /* + * Otherwise reflect the hesiod error into a Un*x error + */ +# ifdef DEBUG + dlog("hesiod_search: Error: %d", hes_error()); +# endif /* DEBUG */ + switch (hes_error()) { + case HES_ER_NOTFOUND: + error = ENOENT; + break; + case HES_ER_CONFIG: + error = EIO; + break; + case HES_ER_NET: + error = ETIMEDOUT; + break; + default: + error = EINVAL; + break; + } +# ifdef DEBUG + dlog("hesiod_search: Returning: %d", error); +# endif /* DEBUG */ + return error; +#endif /* not HAVE_HESIOD_INIT */ +} diff --git a/contrib/amd/amd/info_ldap.c b/contrib/amd/amd/info_ldap.c new file mode 100644 index 0000000..e2f0367 --- /dev/null +++ b/contrib/amd/amd/info_ldap.c @@ -0,0 +1,465 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: info_ldap.c,v 5.2.2.1 1992/02/09 15:08:29 jsp beta $ + * + */ + + +/* + * Get info from LDAP (Lightweight Directory Access Protocol) + * LDAP Home Page: http://www.umich.edu/~rsug/ldap/ + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + + +/* + * MACROS: + */ +#define AMD_LDAP_TYPE "ldap" +/* Time to live for an LDAP cached in an mnt_map */ +#define AMD_LDAP_TTL 3600 +#define AMD_LDAP_RETRIES 5 +#define AMD_LDAP_HOST "ldap" +#ifndef LDAP_PORT +# define LDAP_PORT 389 +#endif /* LDAP_PORT */ + +/* How timestamps are searched */ +#define AMD_LDAP_TSFILTER "(&(objectClass=amdmapTimestamp)(amdmapName=%s))" +/* How maps are searched */ +#define AMD_LDAP_FILTER "(&(objectClass=amdmap)(amdmapName=%s)(amdmapKey=%s))" +/* How timestamps are stored */ +#define AMD_LDAP_TSATTR "amdmaptimestamp" +/* How maps are stored */ +#define AMD_LDAP_ATTR "amdmapvalue" + +/* + * TYPEDEFS: + */ +typedef struct ald_ent ALD; +typedef struct cr_ent CR; +typedef struct he_ent HE; + +/* + * STRUCTURES: + */ +struct ald_ent { + LDAP *ldap; + HE *hostent; + CR *credentials; + time_t timestamp; +}; + +struct cr_ent { + char *who; + char *pw; + int method; +}; + +struct he_ent { + char *host; + int port; + struct he_ent *next; +}; + +/* + * FORWARD DECLARATIONS: + */ +static int amu_ldap_rebind(ALD *a); +static int get_ldap_timestamp(LDAP *ld, char *map, time_t *ts); + + +/* + * FUNCTIONS: + */ + +static void +he_free(HE *h) +{ + XFREE(h->host); + if (h->next != NULL) + he_free(h->next); + XFREE(h); +} + + +static HE * +string2he(char *s) +{ + char *c, *p; + HE *new, *old = NULL; + + if (s == NULL) + return (NULL); + for (p = s; p; p = strchr(p, ',')) { + if (old != NULL) { + new = (HE *) xmalloc(sizeof(HE)); + old->next = new; + old = new; + } else { + old = (HE *) xmalloc(sizeof(HE)); + old->next = NULL; + } + c = strchr(p, ':'); + if (c) { /* Host and port */ + *c++ = '\0'; + old->host = strdup(p); + old->port = atoi(c); + } else + old->host = strdup(p); + + } + return (old); +} + + +static void +cr_free(CR *c) +{ + XFREE(c->who); + XFREE(c->pw); + XFREE(c); +} + + +static void +ald_free(ALD *a) +{ + he_free(a->hostent); + cr_free(a->credentials); + if (a->ldap != NULL) + ldap_unbind(a->ldap); + XFREE(a); +} + + +int +amu_ldap_init(mnt_map *m, char *map, time_t *ts) +{ + ALD *aldh; + CR *creds; + + if (!STREQ(gopt.map_type, AMD_LDAP_TYPE)) { + return (ENOENT); + } +#ifdef DEBUG + else { + dlog("Map %s is ldap\n", map); + } +#endif /* DEBUG */ + + aldh = (ALD *) xmalloc(sizeof(ALD)); + creds = (CR *) xmalloc(sizeof(CR)); + + aldh->hostent = string2he(gopt.ldap_hostports); + if (aldh->hostent == NULL) { + plog(XLOG_USER, "Unable to parse hostport %s for ldap map %s", + gopt.ldap_hostports, map); + return (ENOENT); + } + creds->who = ""; + creds->pw = ""; + creds->method = LDAP_AUTH_SIMPLE; + aldh->credentials = creds; + aldh->timestamp = 0; +#ifdef DEBUG + dlog("Trying for %s:%d\n", aldh->hostent->host, aldh->hostent->port); +#endif /* DEBUG */ + if (amu_ldap_rebind(aldh)) { + ald_free(aldh); + return (ENOENT); + } + m->map_data = (void *) aldh; +#ifdef DEBUG + dlog("Bound to %s:%d\n", aldh->hostent->host, aldh->hostent->port); +#endif /* DEBUG */ + if (get_ldap_timestamp(aldh->ldap, map, ts)) + return (ENOENT); +#ifdef DEBUG + dlog("Got timestamp for map %s: %d\n", map, *ts); +#endif /* DEBUG */ + + return (0); +} + + +static int +amu_ldap_rebind(ALD *a) +{ + LDAP *ld; + HE *h; + CR *c = a->credentials; + time_t now = clocktime(); + + if (a->ldap != NULL) { + if ((a->timestamp - now) > AMD_LDAP_TTL) { +#ifdef DEBUG + dlog("Reestablishing ldap connection\n"); +#endif /* DEBUG */ + ldap_unbind(a->ldap); + a->timestamp = now; + } else + return (0); + } + + while (TRUE) { + for (h = a->hostent; h != NULL; h = h->next) { + if ((ld = ldap_open(h->host, h->port)) == NULL) { + plog(XLOG_WARNING, "Unable to ldap_open to %s:%d\n", h->host, h->port); + break; + } + if (ldap_bind_s(ld, c->who, c->pw, c->method) != LDAP_SUCCESS) { + plog(XLOG_WARNING, "Unable to ldap_bind to %s:%d as %s\n", + h->host, h->port, c->who); + break; + } + if (gopt.ldap_cache_seconds > 0) { + ldap_enable_cache(ld, gopt.ldap_cache_seconds, gopt.ldap_cache_maxmem); + a->ldap = ld; + a->timestamp = now; + return (0); + } + } + plog(XLOG_WARNING, "Exausted list of ldap servers, looping.\n"); + } + + plog(XLOG_USER, "Unable to (re)bind to any ldap hosts\n"); + return (ENOENT); +} + + +static int +get_ldap_timestamp(LDAP * ld, char *map, time_t *ts) +{ + struct timeval tv; + char **vals, *end; + char filter[MAXPATHLEN]; + int i, err, nentries = 0; + LDAPMessage *res, *entry; + + tv.tv_sec = 3; + tv.tv_usec = 0; + sprintf(filter, AMD_LDAP_TSFILTER, map); +#ifdef DEBUG + dlog("Getting timestamp for map %s\n", map); + dlog("Filter is: %s\n", filter); + dlog("Base is: %s\n", gopt.ldap_base); +#endif /* DEBUG */ + for (i = 0; i < AMD_LDAP_RETRIES; i++) { + err = ldap_search_st(ld, + gopt.ldap_base, + LDAP_SCOPE_SUBTREE, + filter, + 0, + 0, + &tv, + &res); + if (err == LDAP_SUCCESS) + break; + dlog("Timestamp search timed out, trying again...\n"); + } + + if (err != LDAP_SUCCESS) { + *ts = 0; + plog(XLOG_USER, "LDAP timestamp search failed: %s\n", + ldap_err2string(ld->ld_errno)); + return (ENOENT); + } + + nentries = ldap_count_entries(ld, res); + if (nentries == 0) { + plog(XLOG_USER, "No timestamp entry for map %s\n", map); + *ts = 0; + ldap_msgfree(res); + return (ENOENT); + } + + entry = ldap_first_entry(ld, res); + vals = ldap_get_values(ld, entry, AMD_LDAP_TSATTR); + if (ldap_count_values(vals) == 0) { + plog(XLOG_USER, "Missing timestamp value for map %s\n", map); + *ts = 0; + ldap_value_free(vals); + ldap_msgfree(res); + ldap_msgfree(entry); + return (ENOENT); + } +#ifdef DEBUG + dlog("TS value is:%s:\n", vals[0]); +#endif /* DEBUG */ + + if (vals[0]) { + *ts = (time_t) strtol(vals[0], &end, 10); + if (end == vals[0]) { + plog(XLOG_USER, "Unable to decode ldap timestamp %s for map %s\n", + vals[0], map); + err = ENOENT; + } + if (!*ts > 0) { + plog(XLOG_USER, "Nonpositive timestamp %d for map %s\n", + *ts, map); + err = ENOENT; + } + } else { + plog(XLOG_USER, "Empty timestamp value for map %s\n", map); + *ts = 0; + err = ENOENT; + } + + ldap_value_free(vals); + ldap_msgfree(res); + ldap_msgfree(entry); +#ifdef DEBUG + dlog("The timestamp for %s is %d (err=%d)\n", map, *ts, err); +#endif /* DEBUG */ + return (err); +} + + +int +amu_ldap_search(mnt_map *m, char *map, char *key, char **pval, time_t *ts) +{ + char **vals, filter[MAXPATHLEN]; + struct timeval tv; + int i, err, nvals = 0, nentries = 0; + LDAPMessage *entry, *res; + ALD *a = (ALD *) (m->map_data); + + tv.tv_sec = 2; + tv.tv_usec = 0; + if (a == NULL) { + plog(XLOG_USER, "LDAP panic: no map data\n"); + return (EIO); + } + if (amu_ldap_rebind(a)) /* Check that's the handle is still valid */ + return (ENOENT); + + sprintf(filter, AMD_LDAP_FILTER, map, key); +#ifdef DEBUG + dlog("Search with filter: %s\n", filter); +#endif /* DEBUG */ + for (i = 0; i < AMD_LDAP_RETRIES; i++) { + err = ldap_search_st(a->ldap, + gopt.ldap_base, + LDAP_SCOPE_SUBTREE, + filter, + 0, + 0, + &tv, + &res); + if (err == LDAP_SUCCESS) + break; + } + + switch (err) { + case LDAP_SUCCESS: + break; + case LDAP_NO_SUCH_OBJECT: +#ifdef DEBUG + dlog("No object\n"); +#endif /* DEBUG */ + ldap_msgfree(res); + return (ENOENT); + default: + plog(XLOG_USER, "LDAP search failed: %s\n", + ldap_err2string(a->ldap->ld_errno)); + ldap_msgfree(res); + return (EIO); + } + + nentries = ldap_count_entries(a->ldap, res); +#ifdef DEBUG + dlog("Search found %d entries\n", nentries); +#endif /* DEBUG */ + if (nentries == 0) { + ldap_msgfree(res); + return (ENOENT); + } + entry = ldap_first_entry(a->ldap, res); + vals = ldap_get_values(a->ldap, entry, AMD_LDAP_ATTR); + nvals = ldap_count_values(vals); + if (nvals == 0) { + plog(XLOG_USER, "Missing value for %s in map %s\n", key, map); + ldap_value_free(vals); + ldap_msgfree(res); + ldap_msgfree(entry); + return (EIO); + } +#ifdef DEBUG + dlog("Map %s, %s => %s\n", map, key, vals[0]); +#endif /* DEBUG */ + if (vals[0]) { + *pval = strdup(vals[0]); + err = 0; + } else { + plog(XLOG_USER, "Empty value for %s in map %s\n", key, map); + err = ENOENT; + } + ldap_msgfree(res); + ldap_msgfree(entry); + ldap_value_free(vals); + + return (err); +} + + +int +amu_ldap_mtime(mnt_map *m, char *map, time_t *ts) +{ + ALD *aldh = (ALD *) (m->map_data); + + if (aldh == NULL) { + dlog("LDAP panic: unable to find map data\n"); + return (ENOENT); + } + if (amu_ldap_rebind(aldh)) { + return (ENOENT); + } + if (get_ldap_timestamp(aldh->ldap, map, ts)) { + return (ENOENT); + } + return (0); +} diff --git a/contrib/amd/amd/info_ndbm.c b/contrib/amd/amd/info_ndbm.c new file mode 100644 index 0000000..0b93fa6 --- /dev/null +++ b/contrib/amd/amd/info_ndbm.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: info_ndbm.c,v 5.2.2.1 1992/02/09 15:08:31 jsp beta $ + * + */ + +/* + * Get info from NDBM map + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* forward declarations */ +int ndbm_init(mnt_map *m, char *map, time_t *tp); +int ndbm_mtime(mnt_map *m, char *map, time_t *tp); +int ndbm_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp); + + +static int +search_ndbm(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(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; +#ifdef DBM_SUFFIX + char dbfilename[256]; + + strcpy(dbfilename, map); + strcat(dbfilename, DBM_SUFFIX); + error = stat(dbfilename, &stb); +#else /* not DBM_SUFFIX */ + error = fstat(dbm_pagfno(db), &stb); +#endif /* not DBM_SUFFIX */ + 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(mnt_map *m, char *map, time_t *tp) +{ + DBM *db; + + db = dbm_open(map, O_RDONLY, 0); + if (db) { + struct stat stb; + int error; +#ifdef DBM_SUFFIX + char dbfilename[256]; + + strcpy(dbfilename, map); + strcat(dbfilename, DBM_SUFFIX); + error = stat(dbfilename, &stb); +#else /* not DBM_SUFFIX */ + error = fstat(dbm_pagfno(db), &stb); +#endif /* not DBM_SUFFIX */ + if (error < 0) + *tp = clocktime(); + else + *tp = stb.st_mtime; + dbm_close(db); + return 0; + } + return errno; +} + + +int +ndbm_mtime(mnt_map *m, char *map, time_t *tp) +{ + return ndbm_init(m,map, tp); +} diff --git a/contrib/amd/amd/info_nis.c b/contrib/amd/amd/info_nis.c new file mode 100644 index 0000000..eceb73a --- /dev/null +++ b/contrib/amd/amd/info_nis.c @@ -0,0 +1,401 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: info_nis.c,v 5.2.2.1 1992/02/09 15:08:32 jsp beta $ + * + */ + +/* + * Get info from NIS map + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* + * NIS+ servers in NIS compat mode don't have yp_order() + */ +static int has_yp_order = FALSE; + +/* forward declarations */ +int nis_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *)); +int nis_search(mnt_map *m, char *map, char *key, char **val, time_t *tp); +int nis_init(mnt_map *m, char *map, time_t *tp); +int nis_mtime(mnt_map *m, char *map, time_t *tp); + +/* typedefs */ +typedef void (*nis_callback_fxn_t)(mnt_map *, char *, char *); +#ifndef DEFINED_YPALL_CALLBACK_FXN_T +typedef int (*ypall_callback_fxn_t)(); +#endif /* DEFINED_YPALL_CALLBACK_FXN_T */ + +struct nis_callback_data { + mnt_map *ncd_m; + char *ncd_map; + nis_callback_fxn_t ncd_fn; +}; + +/* Map to the right version of yp_all */ +#ifdef HAVE_BAD_YP_ALL +# define yp_all am_yp_all +static int am_yp_all(char *indomain, char *inmap, struct ypall_callback *incallback); +#endif /* HAVE_BAD_YP_ALL */ + + +/* + * Figure out the nis domain name + */ +static int +determine_nis_domain(void) +{ + static int nis_not_running = 0; + char default_domain[YPMAXDOMAIN]; + + if (nis_not_running) + return ENOENT; + + if (getdomainname(default_domain, sizeof(default_domain)) < 0) { + nis_not_running = 1; + plog(XLOG_ERROR, "getdomainname: %m"); + return EIO; + } + if (!*default_domain) { + nis_not_running = 1; + plog(XLOG_WARNING, "NIS domain name is not set. NIS ignored."); + return ENOENT; + } + gopt.nis_domain = strdup(default_domain); + + return 0; +} + + +/* + * Callback from yp_all + */ +static int +callback(int status, char *key, int kl, char *val, int vl, char *data) +{ + struct nis_callback_data *ncdp = (struct nis_callback_data *) data; + + if (status == YP_TRUE) { + + /* + * Add to list of maps + */ + char *kp = strnsave(key, kl); + char *vp = strnsave(val, vl); + (*ncdp->ncd_fn) (ncdp->ncd_m, kp, vp); + + /* + * We want more ... + */ + return FALSE; + + } else { + + /* + * NOMORE means end of map - otherwise log error + */ + if (status != YP_NOMORE) { + /* + * Check what went wrong + */ + int e = ypprot_err(status); + +#ifdef DEBUG + plog(XLOG_ERROR, "yp enumeration of %s: %s, status=%d, e=%d", + ncdp->ncd_map, yperr_string(e), status, e); +#else /* not DEBUG */ + plog(XLOG_ERROR, "yp enumeration of %s: %s", ncdp->ncd_map, yperr_string(e)); +#endif /* not DEBUG */ + } + return TRUE; + } +} + + +int +nis_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *)) +{ + int error; + struct nis_callback_data data; + struct ypall_callback cbinfo; + + if (!gopt.nis_domain) { + error = determine_nis_domain(); + if (error) + return error; + } + data.ncd_m = m; + data.ncd_map = map; + data.ncd_fn = fn; + cbinfo.data = (voidp) &data; + cbinfo.foreach = (ypall_callback_fxn_t) callback; + + /* + * If you are using NIS and your yp_all function is "broken", you have to + * get it fixed. The bug in yp_all() is that it does not close a TCP + * connection to ypserv, and this ypserv runs out of open file descriptors, + * getting into an infinite loop, thus all YP clients eventually unbind + * and hang too. + */ + error = yp_all(gopt.nis_domain, map, &cbinfo); + + if (error) + plog(XLOG_ERROR, "error grabbing nis map of %s: %s", map, yperr_string(ypprot_err(error))); + return error; +} + + +/* + * Check if NIS is up, so we can determine if to clear the map or not. + * Test it by checking the yp order. + * Returns: 0 if NIS is down, 1 if it is up. + */ +int +nis_isup(mnt_map *m, char *map) +{ + YP_ORDER_OUTORDER_TYPE order; + int error; + static int last_status = 1; /* assume up by default */ + + if (has_yp_order) { + error = yp_order(gopt.nis_domain, map, &order); + if (error != 0) { + plog(XLOG_ERROR, + "nis_isup: error getting the order of map of %s: %s", + map, yperr_string(ypprot_err(error))); + last_status = 0; + return 0; /* NIS is down */ + } + } + if (last_status == 0) { /* if was down before */ + time_t dummy; + plog(XLOG_INFO, "nis_isup: NIS came back up for map %s", map); + /* XXX: do we really need to reinitialize nis? */ + error = nis_init(m, map, &dummy); + if (!error) + last_status = 1; + } + return 1; /* NIS is up */ +} + + +/* + * Try to locate a key using NIS. + */ +int +nis_search(mnt_map *m, char *map, char *key, char **val, time_t *tp) +{ + int outlen; + int res; + YP_ORDER_OUTORDER_TYPE order; + + /* + * Make sure domain initialised + */ + if (!gopt.nis_domain) { + int error = determine_nis_domain(); + if (error) + return error; + } + + + if (has_yp_order) { + /* + * Check if map has changed + */ + if (yp_order(gopt.nis_domain, map, &order)) + return EIO; + if ((time_t) order > *tp) { + *tp = (time_t) order; + return -1; + } + } else { + /* + * NIS+ server without yp_order + * Check if timeout has expired to invalidate the cache + */ + order = time(NULL); + if ((time_t)order - *tp > gopt.am_timeo) { + *tp = (time_t)order; + return(-1); + } + } + + /* + * Lookup key + */ + res = yp_match(gopt.nis_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(mnt_map *m, char *map, time_t *tp) +{ + YP_ORDER_OUTORDER_TYPE order; + int yp_order_result; + char *master; + + if (!gopt.nis_domain) { + int error = determine_nis_domain(); + if (error) + return error; + } + + /* + * To see if the map exists, try to find + * a master for it. + */ + yp_order_result = yp_order(gopt.nis_domain, map, &order); + switch (yp_order_result) { + case 0: + has_yp_order = TRUE; + *tp = (time_t) order; +#ifdef DEBUG + dlog("NIS master for %s@%s has order %d", map, gopt.nis_domain, order); +#endif /* DEBUG */ + break; + case YPERR_YPERR: + /* NIS+ server found ! */ + has_yp_order = FALSE; + /* try yp_master() instead */ + if (yp_master(gopt.nis_domain, map, &master)) { + return ENOENT; + } else { +#ifdef DEBUG + dlog("NIS master for %s@%s is a NIS+ server", map, gopt.nis_domain); +#endif /* DEBUG */ + /* Use fake timestamps */ + *tp = time(NULL); + } + break; + default: + return ENOENT; + } + return 0; +} + + +int +nis_mtime(mnt_map *m, char *map, time_t *tp) +{ + return nis_init(m, map, tp); +} + + +#ifdef HAVE_BAD_YP_ALL +/* + * If you are using NIS and your yp_all function is "broken", use an + * alternate code which avoids a bug in yp_all(). The bug in yp_all() is + * that it does not close a TCP connection to ypserv, and this ypserv runs + * out of open filedescriptors, getting into an infinite loop, thus all YP + * clients enevtually unbind and hang too. + * + * Systems known to be plagued with this bug: + * earlier SunOS 4.x + * all irix systems (at this time, up to 6.4 was checked) + * + * -Erez Zadok <ezk@cs.columbia.edu> + * -James Tanis <jtt@cs.columbia.edu> */ +static int +am_yp_all(char *indomain, char *inmap, struct ypall_callback *incallback) +{ + int i, j; + char *outkey, *outval; + int outkeylen, outvallen; + char *outkey_old; + int outkeylen_old; + + plog(XLOG_INFO, "NIS map %s reloading using am_yp_all", inmap); + + i = yp_first(indomain, inmap, &outkey, &outkeylen, &outval, &outvallen); + if (i) { + plog(XLOG_ERROR, "yp_first() returned error: %s\n", yperr_string(i)); + } + do { + j = (incallback->foreach)(YP_TRUE, + outkey, + outkeylen, + outval, + outvallen, + incallback->data); + if (j != FALSE) /* terminate loop */ + break; + outkey_old = outkey; + outkeylen_old = outkeylen; + i = yp_next(indomain, + inmap, + outkey_old, + outkeylen_old, + &outkey, + &outkeylen, + &outval, + &outvallen); + } while (!i); +#ifdef DEBUG + if (i) { + dlog("yp_next() returned error: %s\n", yperr_string(i)); + } +#endif /* DEBUG */ + if (i == YPERR_NOMORE) + return 0; + return i; +} +#endif /* HAVE_BAD_YP_ALL */ diff --git a/contrib/amd/amd/info_nisplus.c b/contrib/amd/amd/info_nisplus.c new file mode 100644 index 0000000..71f29e9 --- /dev/null +++ b/contrib/amd/amd/info_nisplus.c @@ -0,0 +1,321 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: info_nisplus.c,v 5.2.2.1 1992/02/09 15:08:32 jsp beta $ + * + */ + +/* + * Get info from NIS+ (version 3) map + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +#define NISPLUS_KEY "key=" +#define NISPLUS_ORGDIR ".org_dir" + +struct nis_callback_data { + mnt_map *ncd_m; + char *ncd_map; + void (*ncd_fn)(); +}; + +struct nisplus_search_callback_data { + nis_name key; + char *value; +}; + + +static int +nisplus_callback(const nis_name key, const nis_object *value, voidp opaquedata) +{ + char *kp = strnsave(ENTRY_VAL(value, 0), ENTRY_LEN(value, 0)); + char *vp = strnsave(ENTRY_VAL(value, 1), ENTRY_LEN(value, 1)); + struct nis_callback_data *data = (struct nis_callback_data *) opaquedata; + +#ifdef DEBUG + dlog("NISplus callback for <%s,%s>", kp, vp); +#endif /* DEBUG */ + + (*data->ncd_fn) (data->ncd_m, kp, vp); + + /* + * We want more ... + */ + return FALSE; +} + + +int +nisplus_reload(mnt_map *m, char *map, void (*fn) ()) +{ + int error = 0; + struct nis_callback_data data; + nis_result *result; + char *org; /* if map does not have ".org_dir" then append it */ + nis_name map_name; + + org = strstr(map, NISPLUS_ORGDIR); + if (org == NULL) + org = NISPLUS_ORGDIR; + else + org = ""; + + /* make some room for the NIS map_name */ + map_name = xmalloc(strlen(map) + sizeof(NISPLUS_ORGDIR)); + if (map_name == NULL) { + plog(XLOG_ERROR, "Unable to create map_name %s: %s", + map, strerror(ENOMEM)); + return ENOMEM; + } + sprintf(map_name, "%s%s", map, org); + + data.ncd_m = m; + data.ncd_map = map_name; + data.ncd_fn = fn; + +#ifdef DEBUG + dlog("NISplus reload for %s", map); +#endif /* DEBUG */ + + result = nis_list(map_name, + EXPAND_NAME | FOLLOW_LINKS | FOLLOW_PATH, + (int (*)()) nisplus_callback, + &data); + + /* free off the NIS map_name */ + XFREE(map_name); + + if (result->status != NIS_SUCCESS && result->status != NIS_CBRESULTS) + error = 1; + + if (error) + plog(XLOG_ERROR, "error grabbing nisplus map of %s: %s", + map, + nis_sperrno(result->status)); + + nis_freeresult(result); + return error; +} + + +static int +nisplus_search_callback(const nis_name key, const nis_object *value, voidp opaquedata) +{ + struct nisplus_search_callback_data *data = (struct nisplus_search_callback_data *) opaquedata; + +#ifdef DEBUG + dlog("NISplus search callback for <%s>", ENTRY_VAL(value, 0)); + dlog("NISplus search callback value <%s>", ENTRY_VAL(value, 1)); +#endif /* DEBUG */ + + data->value = strnsave(ENTRY_VAL(value, 1), ENTRY_LEN(value, 1)); + return TRUE; +} + + +/* + * Try to locate a key using NIS+. + */ +int +nisplus_search(mnt_map *m, char *map, char *key, char **val, time_t *tp) +{ + nis_result *result; + int error = 0; + struct nisplus_search_callback_data data; + nis_name index; + char *org; /* if map does not have ".org_dir" then append it */ + + org = strstr(map, NISPLUS_ORGDIR); + if (org == NULL) + org = NISPLUS_ORGDIR; + else + org = ""; + + /* make some room for the NIS index */ + index = xmalloc(sizeof('[') /* for opening selection criteria */ + +sizeof(NISPLUS_KEY) + + strlen(key) + + sizeof(']') /* for closing selection criteria */ + +sizeof(',') /* + 1 for , separator */ + +strlen(map) + + sizeof(NISPLUS_ORGDIR) + ); + if (index == NULL) { + plog(XLOG_ERROR, + "Unable to create index %s: %s", + map, + strerror(ENOMEM)); + return ENOMEM; + } + sprintf(index, "[%s%s],%s%s", NISPLUS_KEY, key, map, org); + + data.key = key; + data.value = NULL; + +#ifdef DEBUG + dlog("NISplus search for %s", index); +#endif /* DEBUG */ + + result = nis_list(index, + EXPAND_NAME | FOLLOW_LINKS | FOLLOW_PATH, + (int (*)()) nisplus_search_callback, + &data); + + /* free off the NIS index */ + XFREE(index); + + if (result == NULL) { + plog(XLOG_ERROR, "%s: %s", map, strerror(ENOMEM)); + return ENOMEM; + } + + /* + * Do something interesting with the return code + */ + switch (result->status) { + case NIS_SUCCESS: + case NIS_CBRESULTS: + + if (data.value == NULL) { + nis_object *value = result->objects.objects_val; +#ifdef DEBUG + dlog("NISplus search found <nothing>"); + dlog("NISplus search for %s: %s(%d)", + map, nis_sperrno(result->status), result->status); +#endif /* DEBUG */ + + if (value != NULL) + data.value = strnsave(ENTRY_VAL(value, 1), ENTRY_LEN(value, 1)); + } + *val = data.value; + + if (*val) { + error = 0; +#ifdef DEBUG + dlog("NISplus search found %s", *val); +#endif /* DEBUG */ + } else { + error = ENOENT; +#ifdef DEBUG + dlog("NISplus search found nothing"); +#endif /* DEBUG */ + } + + *tp = 0; + break; + + case NIS_NOSUCHNAME: +#ifdef DEBUG + dlog("NISplus search returned %d", result->status); +#endif /* DEBUG */ + error = ENOENT; + break; + + default: + plog(XLOG_ERROR, "%s: %s", map, nis_sperrno(result->status)); + error = EIO; + break; + } + nis_freeresult(result); + + return error; +} + + +int +nisplus_init(mnt_map *m, char *map, time_t *tp) +{ + nis_result *result; + char *org; /* if map does not have ".org_dir" then append it */ + nis_name map_name; + int error = 0; + + org = strstr(map, NISPLUS_ORGDIR); + if (org == NULL) + org = NISPLUS_ORGDIR; + else + org = ""; + + /* make some room for the NIS map_name */ + map_name = xmalloc(strlen(map) + sizeof(NISPLUS_ORGDIR)); + if (map_name == NULL) { + plog(XLOG_ERROR, + "Unable to create map_name %s: %s", + map, + strerror(ENOMEM)); + return ENOMEM; + } + sprintf(map_name, "%s%s", map, org); + + result = nis_lookup(map_name, (EXPAND_NAME | FOLLOW_LINKS | FOLLOW_PATH)); + + /* free off the NIS map_name */ + XFREE(map_name); + + if (result == NULL) { + plog(XLOG_ERROR, "NISplus init <%s>: %s", map, strerror(ENOMEM)); + return ENOMEM; + } + + if (result->status != NIS_SUCCESS) { +#ifdef DEBUG + dlog("NISplus init <%s>: %s (%d)", + map, nis_sperrno(result->status), result->status); +#endif /* DEBUG */ + + error = ENOENT; + } + + *tp = 0; /* no time */ + nis_freeresult(result); + return error; +} + + +int +nisplus_mtime(mnt_map *m, char *map, time_t *tp) +{ + return nisplus_init(m,map, tp); +} diff --git a/contrib/amd/amd/info_passwd.c b/contrib/amd/amd/info_passwd.c new file mode 100644 index 0000000..32d92f4 --- /dev/null +++ b/contrib/amd/amd/info_passwd.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: info_passwd.c,v 5.2.2.1 1992/02/09 15:08:33 jsp beta $ + * + */ + +/* + * Get info from password "file" + * + * This is experimental and probably doesn't do what you expect. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +#define PASSWD_MAP "/etc/passwd" + +/* forward declarations */ +int passwd_init(mnt_map *m, char *map, time_t *tp); +int passwd_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp); + + +/* + * Nothing to probe - check the map name is PASSWD_MAP. + */ +int +passwd_init(mnt_map *m, char *map, time_t *tp) +{ + *tp = 0; + + /* + * Recognize the old format "PASSWD_MAP" + * Uses default return string + * "type:=nfs;rfs:=/${var0}/${var1};rhost:=${var1};sublink:=${var2};fs:=${autodir}${var3}" + */ + if (STREQ(map, PASSWD_MAP)) + return 0; + /* + * Recognize the new format "PASSWD_MAP:pval-format" + */ + if (!NSTREQ(map, PASSWD_MAP, sizeof(PASSWD_MAP) - 1)) + return ENOENT; + if (map[sizeof(PASSWD_MAP)-1] != ':') + return ENOENT; + + return 0; +} + + +/* + * Grab the entry via the getpwname routine + * Modify time is ignored by passwd - XXX + */ +int +passwd_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp) +{ + char *dir = 0; + struct passwd *pw; + + if (STREQ(key, "/defaults")) { + *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 + * and now have + * var0:=pw-prefix:=anydir + * var1:=pw-rhost:=dom3.dom2.dom1 + * var2:=pw-user:=user + * var3:=pw-home:=/anydir/dom1/dom2/dom3/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'; + p = strchr(map, ':'); + if (p) + p++; + else + p = "type:=nfs;rfs:=/${var0}/${var1};rhost:=${var1};sublink:=${var2};fs:=${autodir}${var3}"; + sprintf(val, "var0:=%s;var1:=%s;var2:=%s;var3:=%s;%s", + dir+1, rhost, user, pw->pw_dir, p); +#ifdef DEBUG + dlog("passwd_search: map=%s key=%s -> %s", map, key, val); +#endif /* DEBUG */ + if (q) + *q = '.'; + *pval = strdup(val); + return 0; + } + +enoent: + if (dir) + XFREE(dir); + + return ENOENT; +} diff --git a/contrib/amd/amd/info_union.c b/contrib/amd/amd/info_union.c new file mode 100644 index 0000000..7f757f9 --- /dev/null +++ b/contrib/amd/amd/info_union.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: info_union.c,v 5.2.2.1 1992/02/09 15:08:34 jsp beta $ + * + */ + +/* + * Get info from the system namespace + * + * NOTE: Cannot handle reads back through the automounter. + * THIS WILL CAUSE A DEADLOCK! + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +#define UNION_PREFIX "union:" +#define UNION_PREFLEN 6 + +/* forward declarations */ +int union_init(mnt_map *m, char *map, time_t *tp); +int union_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp); +int union_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *)); + + +/* + * No way to probe - check the map name begins with "union:" + */ +int +union_init(mnt_map *m, char *map, time_t *tp) +{ + *tp = 0; + return NSTREQ(map, UNION_PREFIX, UNION_PREFLEN) ? 0 : ENOENT; +} + + +int +union_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp) +{ + char *mapd = strdup(map + UNION_PREFLEN); + char **v = strsplit(mapd, ':', '\"'); + char **p; + + for (p = v; p[1]; p++) ; + *pval = xmalloc(strlen(*p) + 5); + sprintf(*pval, "fs:=%s", *p); + XFREE(mapd); + XFREE(v); + return 0; +} + + +int +union_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *)) +{ + char *mapd = strdup(map + UNION_PREFLEN); + char **v = strsplit(mapd, ':', '\"'); + char **dir; + + /* + * Add fake /defaults entry + */ + (*fn) (m, strdup("/defaults"), strdup("type:=link;opts:=nounmount;sublink:=${key}")); + + for (dir = v; *dir; dir++) { + int dlen; + struct dirent *dp; + + DIR *dirp = opendir(*dir); + if (!dirp) { + plog(XLOG_USER, "Cannot read directory %s: %m", *dir); + continue; + } + dlen = strlen(*dir); + +#ifdef DEBUG + dlog("Reading directory %s...", *dir); +#endif /* DEBUG */ + while ((dp = readdir(dirp))) { + char *val, *dpname = &dp->d_name[0]; + if (dpname[0] == '.' && + (dpname[1] == '\0' || + (dpname[1] == '.' && dpname[2] == '\0'))) + continue; + +#ifdef DEBUG + dlog("... gives %s", dp->d_name); +#endif /* DEBUG */ + val = xmalloc(dlen + 5); + sprintf(val, "fs:=%s", *dir); + (*fn) (m, strdup(dp->d_name), val); + } + closedir(dirp); + } + + /* + * Add wildcard entry + */ + { + char *val = xmalloc(strlen(dir[-1]) + 5); + + sprintf(val, "fs:=%s", dir[-1]); + (*fn) (m, strdup("*"), val); + } + XFREE(mapd); + XFREE(v); + return 0; +} diff --git a/contrib/amd/amd/map.c b/contrib/amd/amd/map.c new file mode 100644 index 0000000..20320d9 --- /dev/null +++ b/contrib/amd/amd/map.c @@ -0,0 +1,1112 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: map.c,v 5.2.2.2 1992/08/02 10:42:21 jsp Exp $ + * + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +#define smallest_t(t1, t2) (t1 != NEVER ? (t2 != NEVER ? (t1 < t2 ? t1 : t2) : t1) : t2) +#define IGNORE_FLAGS (MFF_MOUNTING|MFF_UNMOUNTING|MFF_RESTART) +#define NEVER (time_t) 0 +#define new_gen() (am_gen++) + +/* + * 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 u_int am_gen = 2; /* Initial generation number */ +static int timeout_mp_id; /* Id from last call to timeout */ + +am_node *root_node; /* The root of the mount tree */ +am_node **exported_ap = (am_node **) 0; +int exported_ap_size = 0; +int first_free_map = 0; /* First available free slot */ +int last_used_map = -1; /* Last unavailable used slot */ + + +/* + * 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 nfsfattr gen_fattr = +{ + NFLNK, /* type */ + NFSMODE_LNK | 0777, /* mode */ + 1, /* nlink */ + 0, /* uid */ + 0, /* gid */ + 0, /* size */ + 4096, /* blocksize */ + 0, /* rdev */ + 1, /* blocks */ + 0, /* fsid */ + 0, /* fileid */ + {0, 0}, /* atime */ + {0, 0}, /* mtime */ + {0, 0}, /* ctime */ +}; + +/* forward declarations */ +static int unmount_node(am_node *mp); +static void exported_ap_free(am_node *mp); +static void remove_am(am_node *mp); + + +/* + * Resize exported_ap map + */ +static int +exported_ap_realloc_map(int nsize) +{ + /* + * this shouldn't happen, but... + */ + if (nsize < 0 || nsize == exported_ap_size) + return 0; + + exported_ap = (am_node **) xrealloc((voidp) exported_ap, nsize * sizeof(am_node *)); + + if (nsize > exported_ap_size) + memset((char *) (exported_ap + exported_ap_size), 0, + (nsize - exported_ap_size) * sizeof(am_node *)); + exported_ap_size = nsize; + + return 1; +} + + +/* + * Allocate a new mount slot and create + * a new node. + * Fills in the map number of the node, + * but leaves everything else uninitialised. + */ +am_node * +exported_ap_alloc(void) +{ + am_node *mp, **mpp; + + /* + * First check if there are any slots left, realloc if needed + */ + if (first_free_map >= exported_ap_size) + if (!exported_ap_realloc_map(exported_ap_size + NEXP_AP)) + return 0; + + /* + * Grab the next free slot + */ + mpp = exported_ap + first_free_map; + mp = *mpp = ALLOC(struct am_node); + memset((char *) mp, 0, sizeof(*mp)); + + mp->am_mapno = first_free_map++; + + /* + * Update free pointer + */ + while (first_free_map < exported_ap_size && exported_ap[first_free_map]) + first_free_map++; + + if (first_free_map > last_used_map) + last_used_map = first_free_map - 1; + + return mp; +} + + +/* + * Free a mount slot + */ +static void +exported_ap_free(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; + + /* + * Free the mount node + */ + XFREE(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(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 + */ +static void +remove_am(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(am_node *mp) +{ + mp->am_timeo_w = 0; + mp->am_ttl = clocktime(); + mp->am_fattr.na_atime.nt_seconds = mp->am_ttl; + mp->am_ttl += mp->am_timeo; /* sun's -tl option */ +} + + +void +mk_fattr(am_node *mp, nfsftype vntype) +{ + switch (vntype) { + case NFDIR: + mp->am_fattr.na_type = NFDIR; + mp->am_fattr.na_mode = NFSMODE_DIR | 0555; + mp->am_fattr.na_nlink = 2; + mp->am_fattr.na_size = 512; + break; + case NFLNK: + mp->am_fattr.na_type = NFLNK; + mp->am_fattr.na_mode = NFSMODE_LNK | 0777; + mp->am_fattr.na_nlink = 1; + mp->am_fattr.na_size = 0; + break; + default: + plog(XLOG_FATAL, "Unknown fattr type %d - ignored", vntype); + break; + } +} + + +/* + * Initialise an allocated mount node. + * It is assumed that the mount node was b-zero'd + * before getting here so anything that would + * be set to zero isn't done here. + */ +void +init_map(am_node *mp, char *dir) +{ + /* + * mp->am_mapno is initialized by exported_ap_alloc + * other fields don't need to be set to zero. + */ + mp->am_mnt = new_mntfs(); + mp->am_name = strdup(dir); + mp->am_path = strdup(dir); + mp->am_gen = new_gen(); + + mp->am_timeo = gopt.am_timeo; + mp->am_attr.ns_status = NFS_OK; + mp->am_fattr = gen_fattr; + mp->am_fattr.na_fsid = 42; + mp->am_fattr.na_fileid = 0; + mp->am_fattr.na_atime.nt_seconds = clocktime(); + mp->am_fattr.na_atime.nt_useconds = 0; + mp->am_fattr.na_mtime = mp->am_fattr.na_ctime = mp->am_fattr.na_atime; + + new_ttl(mp); + mp->am_stats.s_mtime = mp->am_fattr.na_atime.nt_seconds; +} + + +/* + * Free a mount node. + * The node must be already unmounted. + */ +void +free_map(am_node *mp) +{ + + remove_am(mp); + + if (mp->am_link) + XFREE(mp->am_link); + if (mp->am_name) + XFREE(mp->am_name); + if (mp->am_path) + XFREE(mp->am_path); + if (mp->am_pref) + XFREE(mp->am_pref); + if (mp->am_transp) + XFREE(mp->am_transp); + + if (mp->am_mnt) + free_mntfs(mp->am_mnt); + + exported_ap_free(mp); +} + + +/* + * Convert from file handle to automount node. + */ +am_node * +fh_to_mp3(am_nfs_fh *fhp, int *rp, int c_or_d) +{ + struct am_fh *fp = (struct am_fh *) fhp; + am_node *ap = 0; + + /* + * Check process id matches + * If it doesn't then it is probably + * from an old kernel cached filehandle + * which is now out of date. + */ + if (fp->fhh_pid != mypid) + goto drop; + + /* + * Make sure the index is valid before + * exported_ap is referenced. + */ + if (fp->fhh_id < 0 || fp->fhh_id >= exported_ap_size) + goto drop; + + /* + * Get hold of the supposed mount node + */ + ap = exported_ap[fp->fhh_id]; + + /* + * If it exists then maybe... + */ + if (ap) { + /* + * Check the generation number in the node + * matches the one from the kernel. If not + * then the old node has been timed out and + * a new one allocated. + */ + if (ap->am_gen != fp->fhh_gen) { + ap = 0; + goto drop; + } + /* + * If the node is hung then locate a new node + * for it. This implements the replicated filesystem + * retries. + */ + if (ap->am_mnt && FSRV_ISDOWN(ap->am_mnt->mf_server) && ap->am_parent) { + int error; + am_node *orig_ap = ap; + +#ifdef DEBUG + dlog("fh_to_mp3: %s (%s) is hung:- call lookup", + orig_ap->am_path, orig_ap->am_mnt->mf_info); +#endif /* DEBUG */ + + /* + * Update modify time of parent node. + * With any luck the kernel will re-stat + * the child node and get new information. + */ + orig_ap->am_fattr.na_mtime.nt_seconds = clocktime(); + + /* + * Call the parent's lookup routine for an object + * with the same name. This may return -1 in error + * if a mount is in progress. In any case, if no + * mount node is returned the error code is propagated + * to the caller. + */ + if (c_or_d == VLOOK_CREATE) { + ap = (*orig_ap->am_parent->am_mnt->mf_ops->lookuppn) + (orig_ap->am_parent, orig_ap->am_name, &error, c_or_d); + } else { + ap = 0; + error = ESTALE; + } + if (ap == 0) { + if (error < 0 && amd_state == Finishing) + error = ENOENT; + *rp = error; + return 0; + } + + /* + * Update last access to original node. This + * avoids timing it out and so sending ESTALE + * back to the kernel. + * XXX - Not sure we need this anymore (jsp, 90/10/6). + */ + new_ttl(orig_ap); + + } + + /* + * Disallow references to objects being unmounted, unless + * they are automount points. + */ + if (ap->am_mnt && (ap->am_mnt->mf_flags & MFF_UNMOUNTING) && + !(ap->am_flags & AMF_ROOT)) { + if (amd_state == Finishing) + *rp = ENOENT; + else + *rp = -1; + return 0; + } + new_ttl(ap); + } + +drop: + if (!ap || !ap->am_mnt) { + /* + * If we are shutting down then it is likely + * that this node has disappeared because of + * a fast timeout. To avoid things thrashing + * just pretend it doesn't exist at all. If + * ESTALE is returned, some NFS clients just + * keep retrying (stupid or what - if it's + * stale now, what's it going to be in 5 minutes?) + */ + if (amd_state == Finishing) + *rp = ENOENT; + else + *rp = ESTALE; + amd_stats.d_stale++; + } + + return ap; +} + + +am_node * +fh_to_mp(am_nfs_fh *fhp) +{ + int dummy; + + return fh_to_mp2(fhp, &dummy); +} + + +/* + * Convert from automount node to file handle. + */ +void +mp_to_fh(am_node *mp, am_nfs_fh *fhp) +{ + struct am_fh *fp = (struct am_fh *) fhp; + + memset((char *) fhp, 0, sizeof(am_nfs_fh)); + + /* + * Take the process id + */ + fp->fhh_pid = 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). + */ +} + + +am_node * +find_ap2(char *dir, am_node *mp) +{ + if (mp) { + am_node *mp2; + if (STREQ(mp->am_path, dir)) + return mp; + + if ((mp->am_mnt->mf_flags & MFF_MOUNTED) && + STREQ(mp->am_mnt->mf_mount, dir)) + 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(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; +} + + +/* + * Find the mount node corresponding + * to the mntfs structure. + */ +am_node * +find_mf(mntfs *mf) +{ + int i; + + for (i = last_used_map; i >= 0; --i) { + am_node *mp = exported_ap[i]; + if (mp && mp->am_mnt == mf) + 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. + */ +am_nfs_fh * +root_fh(char *dir) +{ + static am_nfs_fh nfh; + am_node *mp = root_ap(dir, TRUE); + if (mp) { + mp_to_fh(mp, &nfh); + /* + * Patch up PID to match main server... + */ + if (!foreground) { + long pid = getppid(); + ((struct am_fh *) &nfh)->fhh_pid = pid; +#ifdef DEBUG + dlog("root_fh substitutes pid %d", pid); +#endif /* DEBUG */ + } + return &nfh; + } + + /* + * Should never get here... + */ + plog(XLOG_ERROR, "Can't find root filehandle for %s", dir); + + return 0; +} + + +am_node * +root_ap(char *dir, int path) +{ + am_node *mp = find_ap(dir); + + if (mp && mp->am_parent == root_node) + return mp; + + return 0; +} + + +/* + * Timeout all nodes waiting on + * a given Fserver. + */ +void +map_flush_srvr(fserver *fs) +{ + int i; + int done = 0; + + for (i = last_used_map; i >= 0; --i) { + am_node *mp = exported_ap[i]; + if (mp && mp->am_mnt && mp->am_mnt->mf_server == fs) { + plog(XLOG_INFO, "Flushed %s; dependent on %s", mp->am_path, fs->fs_host); + mp->am_ttl = clocktime(); + done = 1; + } + } + if (done) + reschedule_timeout_mp(); +} + + +/* + * Mount a top level automount node + * by calling lookup in the parent + * (root) node which will cause the + * automount node to be automounted. + */ +int +mount_auto_node(char *dir, voidp arg) +{ + int error = 0; + + (void) amfs_auto_ops.lookuppn((am_node *) arg, dir, &error, VLOOK_CREATE); + if (error > 0) { + errno = error; /* XXX */ + plog(XLOG_ERROR, "Could not mount %s: %m", dir); + } + return error; +} + + +/* + * Cause all the top-level mount nodes + * to be automounted + */ +int +mount_exported(void) +{ + /* + * Iterate over all the nodes to be started + */ + return root_keyiter((void (*)P((char *, voidp))) mount_auto_node, root_node); +} + + +/* + * Construct top-level node + */ +void +make_root_node(void) +{ + mntfs *root_mnt; + char *rootmap = ROOT_MAP; + root_node = exported_ap_alloc(); + + /* + * Allocate a new map + */ + init_map(root_node, ""); + + /* + * Allocate a new mounted filesystem + */ + root_mnt = find_mntfs(&amfs_root_ops, (am_opts *) 0, "", rootmap, "", "", ""); + + /* + * Replace the initial null reference + */ + free_mntfs(root_node->am_mnt); + root_node->am_mnt = root_mnt; + + /* + * Initialise the root + */ + if (root_mnt->mf_ops->fs_init) + (*root_mnt->mf_ops->fs_init) (root_mnt); + + /* + * Mount the root + */ + root_mnt->mf_error = (*root_mnt->mf_ops->mount_fs) (root_node); +} + + +/* + * Cause all the nodes to be unmounted by timing + * them out. + */ +void +umount_exported(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->fs_flags & FS_DIRECTORY)) { + /* + * When shutting down this had better + * look like a directory, otherwise it + * can't be unmounted! + */ + mk_fattr(mp, NFDIR); + } + + 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; + if (gopt.flags & CFM_UNMOUNT_ON_EXIT) { + plog(XLOG_INFO, "on-exit attempt to unmount %s", mf->mf_mount); + unmount_node(mp); + } + am_unmounted(mp); + + } 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(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) { + errno = error; /* XXX */ +#ifdef DEBUG + dlog("%s: unmount: %m", mf->mf_mount); +#endif /* DEBUG */ + } + + return error; +} + + +static int +unmount_node_wrap(voidp vp) +{ + return unmount_node((am_node *) vp); + + /* + * Below is the comment left from the old code + * that was dependent on the macro FLUSH_KERNEL_NAME_CACHE + */ + /* + * This code should just say: + * return unmount_node((am_node *) vp); + * + * However... + * The kernel keeps a cached copy of filehandles, + * and doesn't ever uncache them (apparently). So + * when Amd times out a node the kernel will have a + * stale filehandle. When the kernel next uses the + * filehandle it gets ESTALE. + * + * The workaround: + * Arrange that when a node is removed an unlink or + * rmdir is done on that path so that the kernel + * cache is done. Yes - yuck. + * + * This can all be removed (and the background + * unmount flag in amfs_link_ops) if/when the kernel does + * something smarter. + * + * If the unlink or rmdir failed then just log a warning, + * don't fail the unmount. This can occur if the kernel + * client code decides that the object is still referenced + * and should be renamed rather than discarded. + * + * There is still a race condition here... + * if another process is trying to access the same + * filesystem at the time we get here, then + * it will block, since the MF_UNMOUNTING flag will + * be set. That may, or may not, cause the entire + * system to deadlock. Hmmm... + */ +} + + +static void +free_map_if_success(int rc, int term, voidp closure) +{ + 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); +#if defined(DEBUG) && defined(SIGTRAP) + /* + * 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 int +unmount_mp(am_node *mp) +{ + int was_backgrounded = 0; + mntfs *mf = mp->am_mnt; + +#ifdef notdef + plog(XLOG_INFO, "\"%s\" on %s timed out", 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); + was_backgrounded = 1; +#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 /* DEBUG */ + mf->mf_flags |= MFF_UNMOUNTING; + free_map_if_success(unmount_node(mp), 0, (voidp) mp); +#ifdef DEBUG + dlog("unmount attempt done"); +#endif /* DEBUG */ + } + + return was_backgrounded; +} + + +void +timeout_mp(voidp v) +{ + int i; + time_t t = NEVER; + time_t now = clocktime(); + int backoff = NumChild / 4; + +#ifdef DEBUG + dlog("Timing out automount points..."); +#endif /* DEBUG */ + + for (i = last_used_map; i >= 0; --i) { + am_node *mp = exported_ap[i]; + mntfs *mf; + + /* + * Just continue if nothing mounted, or can't be timed out. + */ + 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; + if (now >= mp->am_ttl) { + if (!backoff) { + 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 * gopt.am_timeo_w) + mp->am_timeo_w += gopt.am_timeo_w; + mp->am_ttl = now + mp->am_timeo_w; + + } else { + /* + * Just backoff this unmount for + * a couple of seconds to avoid + * many multiple unmounts being + * started in parallel. + */ + mp->am_ttl = now + backoff + 1; + } + } + + /* + * If the next ttl is smallest, use that + */ + t = smallest_t(t, mp->am_ttl); + + if (!mp->am_child && mf->mf_error >= 0 && expired) { + /* + * If the unmount was backgrounded then + * bump the backoff counter. + */ + if (unmount_mp(mp)) { + backoff = 2; + } + } + } 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); +} + + +/* + * Cause timeout_mp to be called soonest + */ +void +reschedule_timeout_mp(void) +{ + if (timeout_mp_id) + untimeout(timeout_mp_id); + timeout_mp_id = timeout(0, timeout_mp, 0); +} diff --git a/contrib/amd/amd/mapc.c b/contrib/amd/amd/mapc.c new file mode 100644 index 0000000..de95e13 --- /dev/null +++ b/contrib/amd/amd/mapc.c @@ -0,0 +1,1205 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: mapc.c,v 5.2.2.2 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * Mount map cache + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* + * Make a duplicate reference to an existing map + */ +#define mapc_dup(m) ((m)->refc++, (m)) + +/* + * Map cache types + * default, none, incremental, all, regexp + * MAPC_RE implies MAPC_ALL and must be numerically + * greater. + */ +#define MAPC_DFLT 0x000 +#define MAPC_NONE 0x001 +#define MAPC_INC 0x002 +#define MAPC_ROOT 0x004 +#define MAPC_ALL 0x010 +#define MAPC_CACHE_MASK 0x0ff +#define MAPC_SYNC 0x100 + +#ifdef HAVE_REGEXEC +# define MAPC_RE 0x020 +# define MAPC_ISRE(m) ((m)->alloc == MAPC_RE) +#else /* not HAVE_REGEXEC */ +# define MAPC_ISRE(m) FALSE +#endif /* not HAVE_REGEXEC */ + +/* + * Lookup recursion + */ +#define MREC_FULL 2 +#define MREC_PART 1 +#define MREC_NONE 0 + +#define MAX_CHAIN 2048 + +static struct opt_tab mapc_opt[] = +{ + {"all", MAPC_ALL}, + {"default", MAPC_DFLT}, + {"inc", MAPC_INC}, + {"mapdefault", MAPC_DFLT}, + {"none", MAPC_NONE}, +#ifdef HAVE_REGEXEC + {"re", MAPC_RE}, + {"regexp", MAPC_RE}, +#endif /* HAVE_REGEXEC */ + {"sync", MAPC_SYNC}, + {0, 0} +}; + +/* + * Wildcard key + */ +static char wildcard[] = "*"; + +/* + * 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 */ + isup_fn *isup; /* Is service up or not? (1=up, 0=down) */ + search_fn *search; /* Search for new entry */ + mtime_fn *mtime; /* Find modify time */ + int def_alloc; /* Default allocation mode */ +}; + +/* + * Map for root node + */ +static mnt_map *root_map; + +/* + * List of known maps + */ +qelem map_list_head = {&map_list_head, &map_list_head}; + +/* + * Configuration + */ + +/* forward definitions */ +static const char *get_full_path(const char *map, const char *path, const char *type); +static int mapc_meta_search(mnt_map *, char *, char **, int); +static void mapc_sync(mnt_map *); + +/* ROOT MAP */ +static int root_init(mnt_map *, char *, time_t *); + +/* ERROR MAP */ +static int error_init(mnt_map *, char *, time_t *); +static int error_reload(mnt_map *, char *, add_fn *); +static int error_search(mnt_map *, char *, char *, char **, time_t *); +static int error_mtime(mnt_map *, char *, time_t *); + +/* PASSWD MAPS */ +#ifdef HAVE_MAP_PASSWD +extern int passwd_init(mnt_map *, char *, time_t *); +extern int passwd_search(mnt_map *, char *, char *, char **, time_t *); +#endif /* HAVE_MAP_PASSWD */ + +/* HESIOD MAPS */ +#ifdef HAVE_MAP_HESIOD +extern int amu_hesiod_init(mnt_map *, char *map, time_t *tp); +extern int hesiod_search(mnt_map *, char *, char *, char **, time_t *); +#endif /* HAVE_MAP_HESIOD */ + +/* LDAP MAPS */ +#ifdef HAVE_MAP_LDAP +extern int amu_ldap_init(mnt_map *, char *map, time_t *tp); +extern int amu_ldap_search(mnt_map *, char *, char *, char **, time_t *); +extern int amu_ldap_mtime(mnt_map *, char *, time_t *); +#endif /* HAVE_MAP_LDAP */ + +/* UNION MAPS */ +#ifdef HAVE_MAP_UNION +extern int union_init(mnt_map *, char *, time_t *); +extern int union_search(mnt_map *, char *, char *, char **, time_t *); +extern int union_reload(mnt_map *, char *, add_fn *); +#endif /* HAVE_MAP_UNION */ + +/* Network Information Service PLUS (NIS+) */ +#ifdef HAVE_MAP_NISPLUS +extern int nisplus_init(mnt_map *, char *, time_t *); +extern int nisplus_reload(mnt_map *, char *, add_fn *); +extern int nisplus_search(mnt_map *, char *, char *, char **, time_t *); +extern int nisplus_mtime(mnt_map *, char *, time_t *); +#endif /* HAVE_MAP_NISPLUS */ + +/* Network Information Service (YP, Yellow Pages) */ +#ifdef HAVE_MAP_NIS +extern int nis_init(mnt_map *, char *, time_t *); +extern int nis_reload(mnt_map *, char *, add_fn *); +extern int nis_isup(mnt_map *, char *); +extern int nis_search(mnt_map *, char *, char *, char **, time_t *); +extern int nis_mtime(mnt_map *, char *, time_t *); +#endif /* HAVE_MAP_NIS */ + +/* NDBM MAPS */ +#ifdef HAVE_MAP_NDBM +extern int ndbm_init(mnt_map *, char *, time_t *); +extern int ndbm_search(mnt_map *, char *, char *, char **, time_t *); +extern int ndbm_mtime(mnt_map *, char *, time_t *); +#endif /* HAVE_MAP_NDBM */ + +/* FILE MAPS */ +#ifdef HAVE_MAP_FILE +extern int file_init(mnt_map *, char *, time_t *); +extern int file_reload(mnt_map *, char *, add_fn *); +extern int file_search(mnt_map *, char *, char *, char **, time_t *); +extern int file_mtime(mnt_map *, char *, time_t *); +#endif /* HAVE_MAP_FILE */ + + +/* note that the choice of MAPC_{INC,ALL} will affect browsable_dirs */ +static map_type maptypes[] = +{ + { + "root", + root_init, + error_reload, + NULL, /* isup function */ + error_search, + error_mtime, + MAPC_ROOT + }, +#ifdef HAVE_MAP_PASSWD + { + "passwd", + passwd_init, + error_reload, + NULL, /* isup function */ + passwd_search, + error_mtime, + MAPC_ALL + }, +#endif /* HAVE_MAP_PASSWD */ +#ifdef HAVE_MAP_HESIOD + { + "hesiod", + amu_hesiod_init, + error_reload, + NULL, /* isup function */ + hesiod_search, + error_mtime, + MAPC_ALL + }, +#endif /* HAVE_MAP_HESIOD */ +#ifdef HAVE_MAP_LDAP + { + "ldap", + amu_ldap_init, + error_reload, + NULL, /* isup function */ + amu_ldap_search, + amu_ldap_mtime, + MAPC_ALL + }, +#endif /* HAVE_MAP_LDAP */ +#ifdef HAVE_MAP_UNION + { + "union", + union_init, + union_reload, + NULL, /* isup function */ + union_search, + error_mtime, + MAPC_ALL + }, +#endif /* HAVE_MAP_UNION */ +#ifdef HAVE_MAP_NISPLUS + { + "nisplus", + nisplus_init, + nisplus_reload, + NULL, /* isup function */ + nisplus_search, + nisplus_mtime, + MAPC_INC + }, +#endif /* HAVE_MAP_NISPLUS */ +#ifdef HAVE_MAP_NIS + { + "nis", + nis_init, + nis_reload, + nis_isup, /* is NIS up or not? */ + nis_search, + nis_mtime, + MAPC_ALL + }, +#endif /* HAVE_MAP_NIS */ +#ifdef HAVE_MAP_NDBM + { + "ndbm", + ndbm_init, + error_reload, + NULL, /* isup function */ + ndbm_search, + ndbm_mtime, + MAPC_ALL + }, +#endif /* HAVE_MAP_NDBM */ +#ifdef HAVE_MAP_FILE + { + "file", + file_init, + file_reload, + NULL, /* isup function */ + file_search, + file_mtime, + MAPC_ALL + }, +#endif /* HAVE_MAP_FILE */ + { + "error", + error_init, + error_reload, + NULL, /* isup function */ + error_search, + error_mtime, + MAPC_NONE + }, +}; + + +/* + * Hash function + */ +static u_int +kvhash_of(char *key) +{ + u_int i, j; + + for (i = 0; (j = *key++); i += j) ; + + return i % NKVHASH; +} + + +void +mapc_showtypes(char *buf) +{ + map_type *mt; + char *sep = ""; + + buf[0] = '\0'; + for (mt = maptypes; mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]); mt++) { + strcat(buf, sep); + strcat(buf, mt->name); + sep = ", "; + } +} + + +/* + * Add key and val to the map m. + * key and val are assumed to be safe copies + */ +void mapc_add_kv(mnt_map *m, char *key, char *val) +{ + kv **h; + kv *n; + int hash = kvhash_of(key); +#ifdef HAVE_REGEXEC + regex_t re; +#endif /* HAVE_REGEXEC */ + +#ifdef DEBUG + dlog("add_kv: %s -> %s", key, val); +#endif /* DEBUG */ + +#ifdef HAVE_REGEXEC + if (MAPC_ISRE(m)) { + char pattern[MAXPATHLEN]; + int retval; + + /* + * Make sure the string is bound to the start and end + */ + sprintf(pattern, "^%s$", key); + retval = regcomp(&re, pattern, REG_ICASE); + if (retval != 0) { + char errstr[256]; + + /* XXX: this code was recently ported, and must be tested -Erez */ + errstr[0] = '\0'; + regerror(retval, &re, errstr, 256); + plog(XLOG_USER, "error compiling RE \"%s\": %s", pattern, errstr); + return; + } + } +#endif /* HAVE_REGEXEC */ + + h = &m->kvhash[hash]; + n = ALLOC(struct kv); + n->key = key; +#ifdef HAVE_REGEXEC + memcpy(&n->re, &re, sizeof(regex_t)); +#endif /* HAVE_REGEXEC */ + n->val = val; + n->next = *h; + *h = n; +} + + +static void +mapc_repl_kv(mnt_map *m, char *key, char *val) +{ + 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 (k) { + XFREE(k->val); + k->val = val; + } else { + mapc_add_kv(m, key, val); + } +} + + +/* + * Search a map for a key. + * Calls map specific search routine. + * While map is out of date, keep re-syncing. + */ +static int +search_map(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(mnt_map *m) +{ + /* + * Attempt to find the wildcard entry + */ + int rc = search_map(m, wildcard, &m->wildcard); + + if (rc != 0) + m->wildcard = 0; +} + + +/* + * Do a map reload + */ +static int +mapc_reload_map(mnt_map *m) +{ + int error; + +#ifdef DEBUG + dlog("calling map reload on %s", m->map_name); +#endif /* DEBUG */ + error = (*m->reload) (m, m->map_name, mapc_add_kv); + if (error) + return error; + m->wildcard = 0; + +#ifdef DEBUG + dlog("calling mapc_search for wildcard"); +#endif /* DEBUG */ + error = mapc_search(m, wildcard, &m->wildcard); + if (error) + m->wildcard = 0; + + return 0; +} + + +/* + * Create a new map + */ +static mnt_map * +mapc_create(char *map, char *opt, const char *type) +{ + mnt_map *m = ALLOC(struct mnt_map); + map_type *mt; + time_t modify; + int alloc = 0; + + cmdoption(opt, mapc_opt, &alloc); + + /* + * If using a configuration file, and the map_type is defined, then look + * for it, in the maptypes array. If found, initialize the map using that + * map_type. If not found, return error. If no map_type was defined, + * default to cycling through all maptypes. + */ + if (use_conf_file && type) { + /* find what type of map this one is */ + for (mt = maptypes; + mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]); + mt++) { + if (STREQ(type, mt->name)) { + plog(XLOG_INFO, "initializing amd conf map %s of type %s", map, type); + if ((*mt->init) (m, map, &modify) == 0) { + break; + } else { + plog(XLOG_ERROR, "failed to initialize map %s", map); + error_init(m, map, &modify); + break; + } + } + } /* end of "for (mt =" loop */ + + } else { /* cycle through all known maptypes */ + + /* + * not using amd conf file or using it by w/o specifying map type + */ + for (mt = maptypes; + mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]); + mt++) { +#ifdef DEBUG + dlog("trying to initialize map %s of type %s ...", map, mt->name); +#endif /* DEBUG */ + if ((*mt->init) (m, map, &modify) == 0) { + break; + } + } + } /* end of "if (use_conf_file && (colpos = strchr ..." statement */ + + /* assert: mt in maptypes */ + + m->flags = alloc & ~MAPC_CACHE_MASK; + alloc &= MAPC_CACHE_MASK; + + if (alloc == MAPC_DFLT) + alloc = mt->def_alloc; + + switch (alloc) { + default: + plog(XLOG_USER, "Ambiguous map cache type \"%s\"; using \"inc\"", opt); + alloc = MAPC_INC; + /* fallthrough... */ + case MAPC_NONE: + case MAPC_INC: + case MAPC_ROOT: + break; + + case MAPC_ALL: + /* + * If there is no support for reload and it was requested + * then back off to incremental instead. + */ + if (mt->reload == error_reload) { + plog(XLOG_WARNING, "Map type \"%s\" does not support cache type \"all\"; using \"inc\"", mt->name); + alloc = MAPC_INC; + } + break; + +#ifdef HAVE_REGEXEC + case MAPC_RE: + if (mt->reload == error_reload) { + plog(XLOG_WARNING, "Map type \"%s\" does not support cache type \"re\"", mt->name); + mt = &maptypes[sizeof(maptypes) / sizeof(maptypes[0]) - 1]; + /* assert: mt->name == "error" */ + } + break; +#endif /* HAVE_REGEXEC */ + } + +#ifdef DEBUG + dlog("Map for %s coming from maptype %s", map, mt->name); +#endif /* DEBUG */ + + m->alloc = alloc; + m->reload = mt->reload; + m->isup = mt->isup; + m->modify = modify; + m->search = alloc >= MAPC_ALL ? error_search : mt->search; + m->mtime = mt->mtime; + memset((voidp) m->kvhash, 0, sizeof(m->kvhash)); + m->map_name = strdup(map); + m->refc = 1; + m->wildcard = 0; + + /* + * synchronize cache with reality + */ + mapc_sync(m); + + return m; +} + + +/* + * Free the cached data in a map + */ +static void +mapc_clear(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; + XFREE(k->key); + if (k->val) + XFREE(k->val); + XFREE(k); + k = n; + } + } + + /* + * Zero the hash slots + */ + memset((voidp) m->kvhash, 0, sizeof(m->kvhash)); + + /* + * Free the wildcard if it exists + */ + if (m->wildcard) { + XFREE(m->wildcard); + m->wildcard = 0; + } +} + + +/* + * Find a map, or create one if it does not exist + */ +mnt_map * +mapc_find(char *map, char *opt, const char *maptype) +{ + 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, maptype); + ins_que(&m->hdr, &map_list_head); + + return m; +} + + +/* + * Free a map. + */ +void +mapc_free(voidp v) +{ + mnt_map *m = v; + + /* + * Decrement the reference count. + * If the reference count hits zero + * then throw the map away. + */ + if (m && --m->refc == 0) { + mapc_clear(m); + XFREE(m->map_name); + rem_que(&m->hdr); + XFREE(m); + } +} + + +/* + * Search the map for the key. Put a safe (malloc'ed) copy in *pval or + * return an error code + */ +static int +mapc_meta_search(mnt_map *m, char *key, char **pval, int recurse) +{ + int error = 0; + kv *k = 0; + + /* + * Firewall + */ + if (!m) { + plog(XLOG_ERROR, "Null map request for %s", key); + return ENOENT; + } + if (m->flags & MAPC_SYNC) { + /* + * Get modify time... + */ + time_t t; + error = (*m->mtime) (m, m->map_name, &t); + if (error || t > m->modify) { + m->modify = t; + plog(XLOG_INFO, "Map %s is out of date", m->map_name); + mapc_sync(m); + } + } + + if (!MAPC_ISRE(m)) { + /* + * 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; + + } + +#ifdef HAVE_REGEXEC + else if (recurse == MREC_FULL) { + /* + * Try for an RE match against the entire map. + * Note that this will be done in a "random" + * order. + */ + int i; + + for (i = 0; i < NKVHASH; i++) { + k = m->kvhash[i]; + while (k) { + int retval; + + /* XXX: this code was recently ported, and must be tested -Erez */ + retval = regexec(&k->re, key, 0, 0, 0); + if (retval == 0) { /* succeeded */ + break; + } else { /* failed to match, log error */ + char errstr[256]; + + errstr[0] = '\0'; + regerror(retval, &k->re, errstr, 256); + plog(XLOG_USER, "error matching RE \"%s\" against \"%s\": %s", + key, k->key, errstr); + } + k = k->next; + } + if (k) + break; + } + } +#endif /* HAVE_REGEXEC */ + + /* + * 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 > 0) { + if (recurse == MREC_FULL && !MAPC_ISRE(m)) { + char wildname[MAXPATHLEN]; + char *subp; + if (*key == '/') + return error; + /* + * Keep chopping sub-directories from the RHS + * and replacing with "/ *" and repeat the lookup. + * For example: + * "src/gnu/gcc" -> "src / gnu / *" -> "src / *" + */ + strcpy(wildname, key); + while (error && (subp = strrchr(wildname, '/'))) { + strcpy(subp, "/*"); +#ifdef DEBUG + dlog("mapc recurses on %s", wildname); +#endif /* DEBUG */ + error = mapc_meta_search(m, wildname, pval, MREC_PART); + if (error) + *subp = 0; + } + + if (error > 0 && m->wildcard) { + *pval = strdup(m->wildcard); + error = 0; + } + } + } + return error; +} + + +int +mapc_search(mnt_map *m, char *key, char **pval) +{ + return mapc_meta_search(m, key, pval, MREC_FULL); +} + + +/* + * Get map cache in sync with physical representation + */ +static void +mapc_sync(mnt_map *m) +{ + if (m->alloc != MAPC_ROOT) { + + /* do not clear map if map service is down */ + if (m->isup) { + if (!((*m->isup)(m, m->map_name))) { + plog(XLOG_ERROR, "mapc_sync: map %s is down: not clearing map", m->map_name); + return; + } + } + + mapc_clear(m); + + if (m->alloc >= MAPC_ALL) + if (mapc_reload_map(m)) + m->alloc = MAPC_INC; + /* + * Attempt to find the wildcard entry + */ + if (m->alloc < MAPC_ALL) + mapc_find_wildcard(m); + } +} + + +/* + * Reload all the maps + * Called when Amd gets hit by a SIGHUP. + */ +void +mapc_reload(void) +{ + 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(mnt_map *m, char *map, time_t *tp) +{ + *tp = clocktime(); + return STREQ(map, ROOT_MAP) ? 0 : ENOENT; +} + + +/* + * Add a new entry to the root map + * + * dir - directory (key) + * opts - mount options + * map - map name + * cfm - optional amd configuration file map section structure + */ +void +root_newmap(const char *dir, const char *opts, const char *map, const cf_map_t *cfm) +{ + char str[MAXPATHLEN]; + + /* + * First make sure we have a root map to talk about... + */ + if (!root_map) + root_map = mapc_find(ROOT_MAP, "mapdefault", NULL); + + /* + * Then add the entry... + */ + + /* + * Here I plug in the code to process other amd.conf options like + * map_type, search_path, and flags (browsable_dirs, mount_type). + */ + + if (cfm) { + if (map) { + sprintf(str, "cache:=mapdefault;type:=%s;fs:=\"%s\"", + cfm->cfm_flags & CFM_MOUNT_TYPE_AUTOFS ? "autofs" : "toplvl", + get_full_path(map, cfm->cfm_search_path, cfm->cfm_type)); + if (opts && opts[0] != '\0') { + strcat(str, ";"); + strcat(str, opts); + } + if (cfm->cfm_flags & CFM_BROWSABLE_DIRS_FULL) + strcat(str, ";opts:=rw,fullybrowsable"); + if (cfm->cfm_flags & CFM_BROWSABLE_DIRS) + strcat(str, ";opts:=rw,browsable"); + if (cfm->cfm_type) { + strcat(str, ";maptype:="); + strcat(str, cfm->cfm_type); + } + } else { + strcpy(str, opts); + } + } else { + if (map) + sprintf(str, "cache:=mapdefault;type:=toplvl;fs:=\"%s\";%s", + map, opts ? opts : ""); + else + strcpy(str, opts); + } + mapc_repl_kv(root_map, strdup((char *)dir), strdup(str)); +} + + +int +mapc_keyiter(mnt_map *m, void (*fn) (char *, voidp), voidp arg) +{ + int i; + int c = 0; + + for (i = 0; i < NKVHASH; i++) { + kv *k = m->kvhash[i]; + while (k) { + (*fn) (k->key, arg); + k = k->next; + c++; + } + } + + return c; +} + + +/* + * Iterate on the root map and call (*fn)() on the key of all the nodes. + * Finally throw away the root map. + */ +int +root_keyiter(void (*fn)(char *, voidp), voidp arg) +{ + if (root_map) { + int c = mapc_keyiter(root_map, fn, arg); + return c; + } + + return 0; +} + + +/* + * Was: NEW_TOPLVL_READDIR + * Search a chain for an entry with some name. + * -Erez Zadok <ezk@cs.columbia.edu> + */ +static int +key_already_in_chain(char *keyname, const nfsentry *chain) +{ + const nfsentry *tmpchain = chain; + + while (tmpchain) { + if (keyname && tmpchain->ne_name && STREQ(keyname, tmpchain->ne_name)) + return 1; + tmpchain = tmpchain->ne_nextentry; + } + + return 0; +} + + +/* + * Create a chain of entries which are not linked. + * -Erez Zadok <ezk@cs.columbia.edu> + */ +nfsentry * +make_entry_chain(am_node *mp, const nfsentry *current_chain, int fully_browsable) +{ + static u_int last_cookie = ~(u_int) 0 - 1; + static nfsentry chain[MAX_CHAIN]; + static int max_entries = MAX_CHAIN; + char *key; + int num_entries = 0, preflen = 0, i; + nfsentry *retval = (nfsentry *) NULL; + mntfs *mf; + mnt_map *mmp; + + if (!mp) { + plog(XLOG_DEBUG, "make_entry_chain: mp is (NULL)"); + return retval; + } + mf = mp->am_mnt; + if (!mf) { + plog(XLOG_DEBUG, "make_entry_chain: mp->am_mnt is (NULL)"); + return retval; + } + mmp = (mnt_map *) mf->mf_private; + if (!mmp) { + plog(XLOG_DEBUG, "make_entry_chain: mp->am_mnt->mf_private is (NULL)"); + return retval; + } + + /* iterate over keys */ + for (i = 0; i < NKVHASH; i++) { + kv *k; + for (k = mmp->kvhash[i]; k ; k = k->next) { + + /* + * Skip unwanted entries which are either not real entries or + * very difficult to interpret (wildcards...) This test needs + * lots of improvement. Any takers? + */ + key = k->key; + if (!key) + continue; + + /* Skip '*' */ + if (!fully_browsable && strchr(key, '*')) + continue; + + /* + * If the map has a prefix-string then check if the key starts with + * this * string, and if it does, skip over this prefix. + */ + if (preflen) { + if (!NSTREQ(key, mp->am_pref, preflen)) + continue; + key += preflen; + } + + /* no more '/' are allowed, unless browsable_dirs=full was used */ + if (!fully_browsable && strchr(key, '/')) + continue; + + /* no duplicates allowed */ + if (key_already_in_chain(key, current_chain)) + continue; + + /* fill in a cell and link the entry */ + if (num_entries >= max_entries) { + /* out of space */ + plog(XLOG_DEBUG, "make_entry_chain: no more space in chain"); + if (num_entries > 0) { + chain[num_entries - 1].ne_nextentry = 0; + retval = &chain[0]; + } + return retval; + } + + /* we have space. put entry in next cell */ + --last_cookie; + chain[num_entries].ne_fileid = (u_int) last_cookie; + *(u_int *) chain[num_entries].ne_cookie = + (u_int) last_cookie; + chain[num_entries].ne_name = key; + if (num_entries < max_entries - 1) { /* link to next one */ + chain[num_entries].ne_nextentry = &chain[num_entries + 1]; + } + ++num_entries; + } /* end of "while (k)" */ + } /* end of "for (i ... NKVHASH ..." */ + + /* terminate chain */ + if (num_entries > 0) { + chain[num_entries - 1].ne_nextentry = 0; + retval = &chain[0]; + } + + return retval; +} + + +/* + * Error map + */ +static int +error_init(mnt_map *m, char *map, time_t *tp) +{ + plog(XLOG_USER, "No source data for map %s", map); + *tp = 0; + + return 0; +} + + +static int +error_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp) +{ + return ENOENT; +} + + +static int +error_reload(mnt_map *m, char *map, add_fn *fn) +{ + return ENOENT; +} + + +static int +error_mtime(mnt_map *m, char *map, time_t *tp) +{ + *tp = 0; + + return 0; +} + + +/* + * Return absolute path of map, searched in a type-specific path. + * Note: uses a static buffer for returned data. + */ +static const char * +get_full_path(const char *map, const char *path, const char *type) +{ + char component[MAXPATHLEN], *str; + static char full_path[MAXPATHLEN]; + int len; + + /* for now, only file-type search paths are implemented */ + if (type && !STREQ(type, "file")) + return map; + + /* if null map, return it */ + if (!map) + return map; + + /* if map includes a '/', return it (absolute or relative path) */ + if (strchr(map, '/')) + return map; + + /* if path is empty, return map */ + if (!path) + return map; + + /* now break path into components, and search in each */ + strcpy(component, path); + + str = strtok(component, ":"); + do { + strcpy(full_path, str); + len = strlen(full_path); + if (full_path[len - 1] != '/') /* add trailing "/" if needed */ + strcat(full_path, "/"); + strcat(full_path, map); + if (access(full_path, R_OK) == 0) + return full_path; + str = strtok(NULL, ":"); + } while (str); + + return map; /* if found nothing, return map */ +} diff --git a/contrib/amd/amd/mntfs.c b/contrib/amd/amd/mntfs.c new file mode 100644 index 0000000..31fa331 --- /dev/null +++ b/contrib/amd/amd/mntfs.c @@ -0,0 +1,335 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: mntfs.c,v 5.2.2.2 1992/08/02 10:42:21 jsp Exp $ + * + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +qelem mfhead = {&mfhead, &mfhead}; + +int mntfs_allocated; + + +mntfs * +dup_mntfs(mntfs *mf) +{ + if (mf->mf_refc == 0) { + if (mf->mf_cid) + untimeout(mf->mf_cid); + mf->mf_cid = 0; + } + mf->mf_refc++; + + return mf; +} + + +static void +init_mntfs(mntfs *mf, am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts) +{ + mf->mf_ops = ops; + mf->mf_fo = mo; + mf->mf_mount = strdup(mp); + mf->mf_info = strdup(info); + mf->mf_auto = strdup(auto_opts); + mf->mf_mopts = strdup(mopts); + mf->mf_remopts = strdup(remopts); + mf->mf_refc = 1; + mf->mf_flags = 0; + mf->mf_error = -1; + mf->mf_cid = 0; + mf->mf_private = 0; + mf->mf_prfree = 0; + + if (ops->ffserver) + mf->mf_server = (*ops->ffserver) (mf); + else + mf->mf_server = 0; +} + + +static mntfs * +alloc_mntfs(am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts) +{ + mntfs *mf = ALLOC(struct mntfs); + + init_mntfs(mf, ops, mo, mp, info, auto_opts, mopts, remopts); + ins_que(&mf->mf_q, &mfhead); + mntfs_allocated++; + + return mf; +} + + +mntfs * +find_mntfs(am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts) +{ + mntfs *mf; + +#ifdef DEBUG + dlog("Locating mntfs reference to %s", mp); +#endif /* DEBUG */ + + ITER(mf, mntfs, &mfhead) { + if (STREQ(mf->mf_mount, mp)) { + /* + * Handle cases where error ops are involved + */ + if (ops == &amfs_error_ops) { + /* + * If the existing ops are not amfs_error_ops + * then continue... + */ + if (mf->mf_ops != &amfs_error_ops) + continue; + else + return dup_mntfs(mf); + } else { /* ops != &amfs_error_ops */ + /* + * If the existing ops are amfs_error_ops + * then continue... + */ + if (mf->mf_ops == &amfs_error_ops) + continue; + } + + if ((mf->mf_flags & MFF_RESTART) && amd_state == Run) { + /* + * Restart a previously mounted filesystem. + */ + mntfs *mf2 = alloc_mntfs(&amfs_inherit_ops, mo, mp, info, auto_opts, mopts, remopts); +#ifdef DEBUG + dlog("Restarting filesystem %s", mf->mf_mount); +#endif /* DEBUG */ + + /* + * Remember who we are restarting + */ + 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_flags &= ~MFF_ERROR; + mf->mf_error = -1; + mf->mf_auto = strealloc(mf->mf_auto, auto_opts); + mf->mf_mopts = strealloc(mf->mf_mopts, mopts); + mf->mf_remopts = strealloc(mf->mf_remopts, remopts); + mf->mf_info = strealloc(mf->mf_info, info); + + if (mf->mf_private && mf->mf_prfree) { + (*mf->mf_prfree) (mf->mf_private); + mf->mf_private = 0; + } + + fs = ops->ffserver ? (*ops->ffserver) (mf) : (fserver *) NULL; + if (mf->mf_server) + free_srvr(mf->mf_server); + mf->mf_server = fs; + } + return dup_mntfs(mf); + } + } + + return alloc_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts); +} + + +mntfs * +new_mntfs(void) +{ + return alloc_mntfs(&amfs_error_ops, (am_opts *) 0, "//nil//", ".", "", "", ""); +} + + +static void +uninit_mntfs(mntfs *mf, int rmd) +{ + if (mf->mf_auto) + XFREE(mf->mf_auto); + if (mf->mf_mopts) + XFREE(mf->mf_mopts); + if (mf->mf_remopts) + XFREE(mf->mf_remopts); + if (mf->mf_info) + XFREE(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); + /* free mf_mount _AFTER_ removing the directories */ + if (mf->mf_mount) + XFREE(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(voidp v) +{ + mntfs *mf = v; + + rem_que(&mf->mf_q); + + /* + * Free memory + */ + uninit_mntfs(mf, TRUE); + XFREE(mf); + + --mntfs_allocated; +} + + +void +flush_mntfs(void) +{ + mntfs *mf; + + mf = AM_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(voidp v) +{ + mntfs *mf = v; + + 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(mntfs *mf, am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts) +{ + mntfs *mf2; + + if (mf->mf_refc == 1 && mf->mf_ops == &amfs_inherit_ops && STREQ(mf->mf_mount, mp)) { + /* + * If we are inheriting then just return + * the same node... + */ + return mf; + } + + /* + * Re-use the existing mntfs if it is mounted. + * This traps a race in nfsx. + */ + if (mf->mf_ops != &amfs_error_ops && + (mf->mf_flags & MFF_MOUNTED) && + !FSRV_ISDOWN(mf->mf_server)) { + mf->mf_fo = mo; + return mf; + } + + mf2 = find_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts); + free_mntfs(mf); + return mf2; +} diff --git a/contrib/amd/amd/nfs_prot_svc.c b/contrib/amd/amd/nfs_prot_svc.c new file mode 100644 index 0000000..e2b1c70 --- /dev/null +++ b/contrib/amd/amd/nfs_prot_svc.c @@ -0,0 +1,250 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: nfs_prot_svc.c,v 5.2.2.1 1992/02/09 15:09:30 jsp beta $ + * + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* external definitions */ +extern voidp nfsproc_null_2_svc(voidp, struct svc_req *); +extern nfsattrstat * nfsproc_getattr_2_svc(am_nfs_fh *, struct svc_req *); +extern nfsattrstat * nfsproc_setattr_2_svc(nfssattrargs *, struct svc_req *); +extern voidp nfsproc_root_2_svc(voidp, struct svc_req *); +extern nfsdiropres * nfsproc_lookup_2_svc(nfsdiropargs *, struct svc_req *); +extern nfsreadlinkres * nfsproc_readlink_2_svc(am_nfs_fh *, struct svc_req *); +extern nfsreadres * nfsproc_read_2_svc(nfsreadargs *, struct svc_req *); +extern voidp nfsproc_writecache_2_svc(voidp, struct svc_req *); +extern nfsattrstat * nfsproc_write_2_svc(nfswriteargs *, struct svc_req *); +extern nfsdiropres * nfsproc_create_2_svc(nfscreateargs *, struct svc_req *); +extern nfsstat * nfsproc_remove_2_svc(nfsdiropargs *, struct svc_req *); +extern nfsstat * nfsproc_rename_2_svc(nfsrenameargs *, struct svc_req *); +extern nfsstat * nfsproc_link_2_svc(nfslinkargs *, struct svc_req *); +extern nfsstat * nfsproc_symlink_2_svc(nfssymlinkargs *, struct svc_req *); +extern nfsdiropres * nfsproc_mkdir_2_svc(nfscreateargs *, struct svc_req *); +extern nfsstat * nfsproc_rmdir_2_svc(nfsdiropargs *, struct svc_req *); +extern nfsreaddirres * nfsproc_readdir_2_svc(nfsreaddirargs *, struct svc_req *); +extern nfsstatfsres * nfsproc_statfs_2_svc(am_nfs_fh *, struct svc_req *); + +/* global variables */ +SVCXPRT *nfs_program_2_transp; + +/* typedefs */ +typedef char *(*nfssvcproc_t)(voidp, struct svc_req *); + + +void +nfs_program_2(struct svc_req *rqstp, SVCXPRT *transp) +{ + union { + am_nfs_fh nfsproc_getattr_2_arg; + nfssattrargs nfsproc_setattr_2_arg; + nfsdiropargs nfsproc_lookup_2_arg; + am_nfs_fh nfsproc_readlink_2_arg; + nfsreadargs nfsproc_read_2_arg; + nfswriteargs nfsproc_write_2_arg; + nfscreateargs nfsproc_create_2_arg; + nfsdiropargs nfsproc_remove_2_arg; + nfsrenameargs nfsproc_rename_2_arg; + nfslinkargs nfsproc_link_2_arg; + nfssymlinkargs nfsproc_symlink_2_arg; + nfscreateargs nfsproc_mkdir_2_arg; + nfsdiropargs fsproc_rmdir_2_arg; + nfsreaddirargs nfsproc_readdir_2_arg; + am_nfs_fh nfsproc_statfs_2_arg; + } argument; + char *result; + xdrproc_t xdr_argument, xdr_result; + nfssvcproc_t local; + + nfs_program_2_transp = NULL; + + switch (rqstp->rq_proc) { + + case NFSPROC_NULL: + xdr_argument = (xdrproc_t) xdr_void; + xdr_result = (xdrproc_t) xdr_void; + local = (nfssvcproc_t) nfsproc_null_2_svc; + break; + + case NFSPROC_GETATTR: + xdr_argument = (xdrproc_t) xdr_nfs_fh; + xdr_result = (xdrproc_t) xdr_attrstat; + local = (nfssvcproc_t) nfsproc_getattr_2_svc; + break; + + case NFSPROC_SETATTR: + xdr_argument = (xdrproc_t) xdr_sattrargs; + xdr_result = (xdrproc_t) xdr_attrstat; + local = (nfssvcproc_t) nfsproc_setattr_2_svc; + break; + + case NFSPROC_ROOT: + xdr_argument = (xdrproc_t) xdr_void; + xdr_result = (xdrproc_t) xdr_void; + local = (nfssvcproc_t) nfsproc_root_2_svc; + break; + + case NFSPROC_LOOKUP: + xdr_argument = (xdrproc_t) xdr_diropargs; + xdr_result = (xdrproc_t) xdr_diropres; + local = (nfssvcproc_t) nfsproc_lookup_2_svc; + /* + * Cheap way to pass transp down to amfs_auto_lookuppn so it can + * be stored in the am_node structure and later used for + * quick_reply(). + */ + nfs_program_2_transp = transp; + break; + + case NFSPROC_READLINK: + xdr_argument = (xdrproc_t) xdr_nfs_fh; + xdr_result = (xdrproc_t) xdr_readlinkres; + local = (nfssvcproc_t) nfsproc_readlink_2_svc; + break; + + case NFSPROC_READ: + xdr_argument = (xdrproc_t) xdr_readargs; + xdr_result = (xdrproc_t) xdr_readres; + local = (nfssvcproc_t) nfsproc_read_2_svc; + break; + + case NFSPROC_WRITECACHE: + xdr_argument = (xdrproc_t) xdr_void; + xdr_result = (xdrproc_t) xdr_void; + local = (nfssvcproc_t) nfsproc_writecache_2_svc; + break; + + case NFSPROC_WRITE: + xdr_argument = (xdrproc_t) xdr_writeargs; + xdr_result = (xdrproc_t) xdr_attrstat; + local = (nfssvcproc_t) nfsproc_write_2_svc; + break; + + case NFSPROC_CREATE: + xdr_argument = (xdrproc_t) xdr_createargs; + xdr_result = (xdrproc_t) xdr_diropres; + local = (nfssvcproc_t) nfsproc_create_2_svc; + break; + + case NFSPROC_REMOVE: + xdr_argument = (xdrproc_t) xdr_diropargs; + xdr_result = (xdrproc_t) xdr_nfsstat; + local = (nfssvcproc_t) nfsproc_remove_2_svc; + break; + + case NFSPROC_RENAME: + xdr_argument = (xdrproc_t) xdr_renameargs; + xdr_result = (xdrproc_t) xdr_nfsstat; + local = (nfssvcproc_t) nfsproc_rename_2_svc; + break; + + case NFSPROC_LINK: + xdr_argument = (xdrproc_t) xdr_linkargs; + xdr_result = (xdrproc_t) xdr_nfsstat; + local = (nfssvcproc_t) nfsproc_link_2_svc; + break; + + case NFSPROC_SYMLINK: + xdr_argument = (xdrproc_t) xdr_symlinkargs; + xdr_result = (xdrproc_t) xdr_nfsstat; + local = (nfssvcproc_t) nfsproc_symlink_2_svc; + break; + + case NFSPROC_MKDIR: + xdr_argument = (xdrproc_t) xdr_createargs; + xdr_result = (xdrproc_t) xdr_diropres; + local = (nfssvcproc_t) nfsproc_mkdir_2_svc; + break; + + case NFSPROC_RMDIR: + xdr_argument = (xdrproc_t) xdr_diropargs; + xdr_result = (xdrproc_t) xdr_nfsstat; + local = (nfssvcproc_t) nfsproc_rmdir_2_svc; + break; + + case NFSPROC_READDIR: + xdr_argument = (xdrproc_t) xdr_readdirargs; + xdr_result = (xdrproc_t) xdr_readdirres; + local = (nfssvcproc_t) nfsproc_readdir_2_svc; + break; + + case NFSPROC_STATFS: + xdr_argument = (xdrproc_t) xdr_nfs_fh; + xdr_result = (xdrproc_t) xdr_statfsres; + local = (nfssvcproc_t) nfsproc_statfs_2_svc; + break; + + default: + svcerr_noproc(transp); + return; + } + + memset((char *) &argument, 0, sizeof(argument)); + if (!svc_getargs(transp, + (XDRPROC_T_TYPE) xdr_argument, + (SVC_IN_ARG_TYPE) &argument)) { + plog(XLOG_ERROR, + "NFS xdr decode failed for %d %d %d", + rqstp->rq_prog, rqstp->rq_vers, rqstp->rq_proc); + svcerr_decode(transp); + return; + } + result = (*local) (&argument, rqstp); + + nfs_program_2_transp = NULL; + + if (result != NULL && !svc_sendreply(transp, + (XDRPROC_T_TYPE) xdr_result, + result)) { + svcerr_systemerr(transp); + } + if (!svc_freeargs(transp, + (XDRPROC_T_TYPE) xdr_argument, + (SVC_IN_ARG_TYPE) & argument)) { + plog(XLOG_FATAL, "unable to free rpc arguments in nfs_program_2"); + going_down(1); + } +} diff --git a/contrib/amd/amd/nfs_start.c b/contrib/amd/amd/nfs_start.c new file mode 100644 index 0000000..e5740f6 --- /dev/null +++ b/contrib/amd/amd/nfs_start.c @@ -0,0 +1,472 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: nfs_start.c,v 5.2.2.1 1992/02/09 15:08:51 jsp beta $ + * + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +#ifndef SELECT_MAXWAIT +# define SELECT_MAXWAIT 16 +#endif /* not SELECT_MAXWAIT */ + +SVCXPRT *nfsxprt; +u_short nfs_port; + +#ifdef HAVE_FS_AUTOFS +SVCXPRT *autofsxprt = NULL; +u_short autofs_port = 0; +#endif /* HAVE_FS_AUTOFS */ + +#ifndef HAVE_SIGACTION +# define MASKED_SIGS (sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGCHLD)|sigmask(SIGHUP)) +#endif /* not HAVE_SIGACTION */ + +#ifdef DEBUG +/* + * Check that we are not burning resources + */ +static void +checkup(void) +{ + + static int max_fd = 0; + static char *max_mem = 0; + + int next_fd = dup(0); + caddr_t next_mem = sbrk(0); + close(next_fd); + + 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 < next_mem) { +#ifdef HAVE_GETPAGESIZE + dlog("%#x bytes of memory allocated; total is %#x (%ld pages)", + next_mem - max_mem, next_mem, + ((long) next_mem + getpagesize() - 1) / getpagesize()); +#else /* not HAVE_GETPAGESIZE */ + dlog("%#x bytes of memory allocated; total is %#x", + next_mem - max_mem, next_mem); +#endif /* not HAVE_GETPAGESIZE */ + max_mem = next_mem; + + } +} +#endif /* DEBUG */ + + +static int +#ifdef HAVE_SIGACTION +do_select(sigset_t smask, int fds, fd_set *fdp, struct timeval *tvp) +#else /* not HAVE_SIGACTION */ +do_select(int smask, int fds, fd_set *fdp, struct timeval *tvp) +#endif /* not HAVE_SIGACTION */ +{ + + 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. + */ +#ifdef HAVE_SIGACTION + sigprocmask(SIG_SETMASK, &smask, NULL); +#else /* not HAVE_SIGACTION */ + (void) sigsetmask(smask); +#endif /* not HAVE_SIGACTION */ + + /* + * Wait for input + */ + nsel = select(fds, fdp, (fd_set *) 0, (fd_set *) 0, + tvp->tv_sec ? tvp : (struct timeval *) 0); + } + +#ifdef HAVE_SIGACTION + sigprocmask(SIG_BLOCK, &masked_sigs, NULL); +#else /* not HAVE_SIGACTION */ + (void) sigblock(MASKED_SIGS); +#endif /* not HAVE_SIGACTION */ + + /* + * Perhaps reload the cache? + */ + if (do_mapc_reload < clocktime()) { + mapc_reload(); + do_mapc_reload = clocktime() + ONE_HOUR; + } + return nsel; +} + + +/* + * Determine whether anything is left in + * the RPC input queue. + */ +static int +rpc_pending_now(void) +{ + struct timeval tvv; + int nsel; +#ifdef FD_SET + fd_set readfds; + + FD_ZERO(&readfds); + FD_SET(fwd_sock, &readfds); +#else /* not FD_SET */ + int readfds = (1 << fwd_sock); +#endif /* not FD_SET */ + + tvv.tv_sec = tvv.tv_usec = 0; + nsel = select(FD_SETSIZE, &readfds, (fd_set *) 0, (fd_set *) 0, &tvv); + if (nsel < 1) + return (0); +#ifdef FD_SET + if (FD_ISSET(fwd_sock, &readfds)) + return (1); +#else /* not FD_SET */ + if (readfds & (1 << fwd_sock)) + return (1); +#endif /* not FD_SET */ + + return (0); +} + + +static serv_state +run_rpc(void) +{ +#ifdef HAVE_SIGACTION + sigset_t smask; + sigprocmask(SIG_BLOCK, &masked_sigs, &smask); +#else /* not HAVE_SIGACTION */ + int smask = sigblock(MASKED_SIGS); +#endif /* not HAVE_SIGACTION */ + + 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 HAVE_SVC_GETREQSET + fd_set readfds; + + memmove(&readfds, &svc_fdset, sizeof(svc_fdset)); + FD_SET(fwd_sock, &readfds); +#else /* not HAVE_SVC_GETREQSET */ +# ifdef FD_SET + fd_set readfds; + FD_ZERO(&readfds); + readfds.fds_bits[0] = svc_fds; + FD_SET(fwd_sock, &readfds); +# else /* not FD_SET */ + int readfds = svc_fds | (1 << fwd_sock); +# endif /* not FD_SET */ +#endif /* not HAVE_SVC_GETREQSET */ + +#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; + } + if (tvv.tv_sec <= 0) + tvv.tv_sec = SELECT_MAXWAIT; +#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, FD_SETSIZE, &readfds, &tvv); + + switch (nsel) { + case -1: + if (errno == EINTR) { +#ifdef DEBUG + dlog("select interrupted"); +#endif /* DEBUG */ + continue; + } + perror("select"); + break; + + case 0: + break; + + default: + /* + * Read all pending NFS responses at once to avoid having responses. + * queue up as a consequence of retransmissions. + */ +#ifdef FD_SET + if (FD_ISSET(fwd_sock, &readfds)) { + FD_CLR(fwd_sock, &readfds); +#else /* not FD_SET */ + if (readfds & (1 << fwd_sock)) { + readfds &= ~(1 << fwd_sock); +#endif /* not FD_SET */ + --nsel; + do { + fwd_reply(); + } while (rpc_pending_now() > 0); + } + + if (nsel) { + /* + * Anything left must be a normal + * RPC request. + */ +#ifdef HAVE_SVC_GETREQSET + svc_getreqset(&readfds); +#else /* not HAVE_SVC_GETREQSET */ +# ifdef FD_SET + svc_getreq(readfds.fds_bits[0]); +# else /* not FD_SET */ + svc_getreq(readfds); +# endif /* not FD_SET */ +#endif /* not HAVE_SVC_GETREQSET */ + } + break; + } + } + +#ifdef HAVE_SIGACTION + sigprocmask(SIG_SETMASK, &smask, NULL); +#else /* not HAVE_SIGACTION */ + (void) sigsetmask(smask); +#endif /* not HAVE_SIGACTION */ + + if (amd_state == Quit) + amd_state = Done; + + return amd_state; +} + + +int +mount_automounter(int ppid) +{ + /* + * Old code replaced by rpc-trash patch. + * Erez Zadok <ezk@cs.columbia.edu> + int so = socket(AF_INET, SOCK_DGRAM, 0); + */ + SVCXPRT *udp_amqp = NULL, *tcp_amqp = NULL; + int nmount, ret; + int soNFS; + int udp_soAMQ, tcp_soAMQ; +#ifdef HAVE_TRANSPORT_TYPE_TLI + struct netconfig *udp_amqncp, *tcp_amqncp; +#endif /* HAVE_TRANSPORT_TYPE_TLI */ +#ifdef HAVE_FS_AUTOFS + int soAUTOFS; +#endif /* HAVE_FS_AUTOFS */ + + /* + * Create the nfs service for amd + */ +#ifdef HAVE_TRANSPORT_TYPE_TLI + ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2); + if (ret != 0) + return ret; + ret = create_amq_service(&udp_soAMQ, &udp_amqp, &udp_amqncp, &tcp_soAMQ, &tcp_amqp, &tcp_amqncp); +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2); + if (ret != 0) + return ret; + ret = create_amq_service(&udp_soAMQ, &udp_amqp, &tcp_soAMQ, &tcp_amqp); +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + if (ret != 0) + return ret; + +#ifdef HAVE_FS_AUTOFS + /* + * Create the autofs service for amd. + */ + plog(XLOG_INFO, "creating autofs service listener"); + ret = create_autofs_service(&soAUTOFS, &autofs_port, &autofsxprt, autofs_program_1); + /* if autofs service fails it is OK if using a test amd */ + if (ret != 0 && gopt.portmap_program == AMQ_PROGRAM) + return ret; +#endif /* HAVE_FS_AUTOFS */ + + /* + * Start RPC forwarding + */ + if (fwd_init() != 0) + return 3; + + /* + * 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 (gopt.flags & CFM_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; + } + +#ifdef DEBUG + amuDebug(D_AMQ) { +#endif /* DEBUG */ + /* + * Complete registration of amq (first TCP service then UDP) + */ + unregister_amq(); + +#ifdef HAVE_TRANSPORT_TYPE_TLI + ret = svc_reg(tcp_amqp, get_amd_program_number(), AMQ_VERSION, + amq_program_1, tcp_amqncp); +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + ret = svc_register(tcp_amqp, get_amd_program_number(), AMQ_VERSION, + amq_program_1, IPPROTO_TCP); +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + if (ret != 1) { + plog(XLOG_FATAL, "unable to register (AMQ_PROGRAM=%d, AMQ_VERSION, tcp)", get_amd_program_number()); + return 3; + } + +#ifdef HAVE_TRANSPORT_TYPE_TLI + ret = svc_reg(udp_amqp, get_amd_program_number(), AMQ_VERSION, + amq_program_1, udp_amqncp); +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + ret = svc_register(udp_amqp, get_amd_program_number(), AMQ_VERSION, + amq_program_1, IPPROTO_UDP); +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + if (ret != 1) { + plog(XLOG_FATAL, "unable to register (AMQ_PROGRAM=%d, AMQ_VERSION, udp)", get_amd_program_number()); + return 4; + } + +#ifdef DEBUG + } +#endif /* DEBUG */ + + /* + * Start timeout_mp rolling + */ + reschedule_timeout_mp(); + + /* + * Start the server + */ + if (run_rpc() != Done) { + plog(XLOG_FATAL, "run_rpc failed"); + amd_state = Done; + } + return 0; +} diff --git a/contrib/amd/amd/nfs_subr.c b/contrib/amd/amd/nfs_subr.c new file mode 100644 index 0000000..3de0861 --- /dev/null +++ b/contrib/amd/amd/nfs_subr.c @@ -0,0 +1,610 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: nfs_subr.c,v 5.2.2.1 1992/02/09 15:08:53 jsp beta $ + * + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* + * Convert from UN*X to NFS error code. + * Some systems like linux define their own (see + * conf/mount/mount_linux.h). + */ +#ifndef nfs_error +# define nfs_error(e) ((nfsstat)(e)) +#endif /* nfs_error */ + +/* forward declarations */ +static void count_map_entries(const am_node *mp, u_int *out_blocks, u_int *out_bfree, u_int *out_bavail); + + +static char * +do_readlink(am_node *mp, int *error_return, nfsattrstat **attrpp) +{ + 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_attr; + + return ln; +} + + +voidp +nfsproc_null_2_svc(voidp argp, struct svc_req *rqstp) +{ + static char res; + + return (voidp) &res; +} + + +nfsattrstat * +nfsproc_getattr_2_svc(am_nfs_fh *argp, struct svc_req *rqstp) +{ + static nfsattrstat res; + am_node *mp; + int retry; + +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "getattr:"); +#endif /* DEBUG */ + + mp = fh_to_mp2(argp, &retry); + if (mp == 0) { + +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "\tretry=%d", retry); +#endif /* DEBUG */ + + if (retry < 0) + return 0; + res.ns_status = nfs_error(retry); + } else { + nfsattrstat *attrp = &mp->am_attr; + +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "\tstat(%s), size = %d", mp->am_path, + attrp->ns_u.ns_attr_u.na_size); +#endif /* DEBUG */ + + mp->am_stats.s_getattr++; + return attrp; + } + +#ifndef MNT2_NFS_OPT_SYMTTL + /* + * This code is needed to defeat Solaris 2.4's (and newer) symlink values + * cache. It forces the last-modifed time of the symlink to be current. + * It is not needed if the O/S has an nfs flag to turn off the + * symlink-cache at mount time (such as Irix 5.x and 6.x). -Erez. + */ + if (++res.ns_u.ns_attr_u.na_mtime.nt_useconds == 0) + ++res.ns_u.ns_attr_u.na_mtime.nt_seconds; +#endif /* not MNT2_NFS_OPT_SYMTTL */ + + return &res; +} + + +nfsattrstat * +nfsproc_setattr_2_svc(nfssattrargs *argp, struct svc_req *rqstp) +{ + static nfsattrstat res; + + if (!fh_to_mp(&argp->sag_fhandle)) + res.ns_status = nfs_error(ESTALE); + else + res.ns_status = nfs_error(EROFS); + + return &res; +} + + +voidp +nfsproc_root_2_svc(voidp argp, struct svc_req *rqstp) +{ + static char res; + + return (voidp) &res; +} + + +nfsdiropres * +nfsproc_lookup_2_svc(nfsdiropargs *argp, struct svc_req *rqstp) +{ + static nfsdiropres res; + am_node *mp; + int retry; + +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "lookup:"); +#endif /* DEBUG */ + + mp = fh_to_mp2(&argp->da_fhandle, &retry); + if (mp == 0) { + if (retry < 0) + return 0; + res.dr_status = nfs_error(retry); + } else { + int error; + am_node *ap; +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "\tlookuppn(%s, %s)", mp->am_path, argp->da_name); +#endif /* DEBUG */ + ap = (*mp->am_mnt->mf_ops->lookuppn) (mp, argp->da_name, &error, VLOOK_CREATE); + if (ap == 0) { + if (error < 0) { +#ifdef DEBUG + dlog("Not sending RPC reply"); +#endif /* DEBUG */ + amd_stats.d_drops++; + return 0; + } + res.dr_status = nfs_error(error); + } else { + mp_to_fh(ap, &res.dr_u.dr_drok_u.drok_fhandle); + res.dr_u.dr_drok_u.drok_attributes = ap->am_fattr; + res.dr_status = NFS_OK; + } + mp->am_stats.s_lookup++; + /* reschedule_timeout_mp(); */ + } + + return &res; +} + + +void +quick_reply(am_node *mp, int error) +{ + SVCXPRT *transp = mp->am_transp; + nfsdiropres res; + xdrproc_t xdr_result = (xdrproc_t) xdr_diropres; + + /* + * If there's a transp structure then we can reply to the client's + * nfs lookup request. + */ + if (transp) { + if (error == 0) { + /* + * Construct a valid reply to a lookup request. Same + * code as in nfsproc_lookup_2_svc() above. + */ + mp_to_fh(mp, &res.dr_u.dr_drok_u.drok_fhandle); + res.dr_u.dr_drok_u.drok_attributes = mp->am_fattr; + res.dr_status = NFS_OK; + } else + /* + * Return the error that was passed to us. + */ + res.dr_status = nfs_error(error); + + /* + * Send off our reply + */ + if (!svc_sendreply(transp, (XDRPROC_T_TYPE) xdr_result, (SVC_IN_ARG_TYPE) & res)) + svcerr_systemerr(transp); + + /* + * Free up transp. It's only used for one reply. + */ + XFREE(transp); + mp->am_transp = NULL; +#ifdef DEBUG + dlog("Quick reply sent for %s", mp->am_mnt->mf_mount); +#endif /* DEBUG */ + } +} + + +nfsreadlinkres * +nfsproc_readlink_2_svc(am_nfs_fh *argp, struct svc_req *rqstp) +{ + static nfsreadlinkres res; + am_node *mp; + int retry; + +#ifdef DEBUG + amuDebug(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.rlr_status = nfs_error(retry); + } else { + char *ln = do_readlink(mp, &retry, (nfsattrstat **) 0); + if (ln == 0) + goto readlink_retry; + res.rlr_status = NFS_OK; +#ifdef DEBUG + amuDebug(D_TRACE) + if (ln) + plog(XLOG_DEBUG, "\treadlink(%s) = %s", mp->am_path, ln); +#endif /* DEBUG */ + res.rlr_u.rlr_data_u = ln; + mp->am_stats.s_readlink++; + } + + return &res; +} + + +nfsreadres * +nfsproc_read_2_svc(nfsreadargs *argp, struct svc_req *rqstp) +{ + static nfsreadres res; + + memset((char *) &res, 0, sizeof(res)); + res.rr_status = nfs_error(EACCES); + + return &res; +} + + +voidp +nfsproc_writecache_2_svc(voidp argp, struct svc_req *rqstp) +{ + static char res; + + return (voidp) &res; +} + + +nfsattrstat * +nfsproc_write_2_svc(nfswriteargs *argp, struct svc_req *rqstp) +{ + static nfsattrstat res; + + if (!fh_to_mp(&argp->wra_fhandle)) + res.ns_status = nfs_error(ESTALE); + else + res.ns_status = nfs_error(EROFS); + + return &res; +} + + +nfsdiropres * +nfsproc_create_2_svc(nfscreateargs *argp, struct svc_req *rqstp) +{ + static nfsdiropres res; + + if (!fh_to_mp(&argp->ca_where.da_fhandle)) + res.dr_status = nfs_error(ESTALE); + else + res.dr_status = nfs_error(EROFS); + + return &res; +} + + +static nfsstat * +unlink_or_rmdir(nfsdiropargs *argp, struct svc_req *rqstp, int unlinkp) +{ + static nfsstat res; + int retry; + + am_node *mp = fh_to_mp3(&argp->da_fhandle, &retry, VLOOK_DELETE); + if (mp == 0) { + if (retry < 0) + return 0; + res = nfs_error(retry); + goto out; + } + + if (mp->am_fattr.na_type != NFDIR) { + res = nfs_error(ENOTDIR); + goto out; + } + +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "\tremove(%s, %s)", mp->am_path, argp->da_name); +#endif /* DEBUG */ + + mp = (*mp->am_mnt->mf_ops->lookuppn) (mp, argp->da_name, &retry, VLOOK_DELETE); + 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; +} + + +nfsstat * +nfsproc_remove_2_svc(nfsdiropargs *argp, struct svc_req *rqstp) +{ + return unlink_or_rmdir(argp, rqstp, TRUE); +} + + +nfsstat * +nfsproc_rename_2_svc(nfsrenameargs *argp, struct svc_req *rqstp) +{ + static nfsstat res; + + if (!fh_to_mp(&argp->rna_from.da_fhandle) || !fh_to_mp(&argp->rna_to.da_fhandle)) + res = nfs_error(ESTALE); + /* + * If the kernel is doing clever things with referenced files + * then let it pretend... + */ + else if (NSTREQ(argp->rna_to.da_name, ".nfs", 4)) + res = NFS_OK; + /* + * otherwise a failure + */ + else + res = nfs_error(EROFS); + + return &res; +} + + +nfsstat * +nfsproc_link_2_svc(nfslinkargs *argp, struct svc_req *rqstp) +{ + static nfsstat res; + + if (!fh_to_mp(&argp->la_fhandle) || !fh_to_mp(&argp->la_to.da_fhandle)) + res = nfs_error(ESTALE); + else + res = nfs_error(EROFS); + + return &res; +} + + +nfsstat * +nfsproc_symlink_2_svc(nfssymlinkargs *argp, struct svc_req *rqstp) +{ + static nfsstat res; + + if (!fh_to_mp(&argp->sla_from.da_fhandle)) + res = nfs_error(ESTALE); + else + res = nfs_error(EROFS); + + return &res; +} + + +nfsdiropres * +nfsproc_mkdir_2_svc(nfscreateargs *argp, struct svc_req *rqstp) +{ + static nfsdiropres res; + + if (!fh_to_mp(&argp->ca_where.da_fhandle)) + res.dr_status = nfs_error(ESTALE); + else + res.dr_status = nfs_error(EROFS); + + return &res; +} + + +nfsstat * +nfsproc_rmdir_2_svc(nfsdiropargs *argp, struct svc_req *rqstp) +{ + return unlink_or_rmdir(argp, rqstp, FALSE); +} + + +nfsreaddirres * +nfsproc_readdir_2_svc(nfsreaddirargs *argp, struct svc_req *rqstp) +{ + static nfsreaddirres res; + static nfsentry e_res[MAX_READDIR_ENTRIES]; + am_node *mp; + int retry; + +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "readdir:"); +#endif /* DEBUG */ + + mp = fh_to_mp2(&argp->rda_fhandle, &retry); + if (mp == 0) { + if (retry < 0) + return 0; + res.rdr_status = nfs_error(retry); + } else { +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "\treaddir(%s)", mp->am_path); +#endif /* DEBUG */ + res.rdr_status = nfs_error((*mp->am_mnt->mf_ops->readdir) + (mp, argp->rda_cookie, + &res.rdr_u.rdr_reply_u, e_res, argp->rda_count)); + mp->am_stats.s_readdir++; + } + + return &res; +} + + +nfsstatfsres * +nfsproc_statfs_2_svc(am_nfs_fh *argp, struct svc_req *rqstp) +{ + static nfsstatfsres res; + am_node *mp; + int retry; + mntent_t mnt; + +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "statfs:"); +#endif /* DEBUG */ + + mp = fh_to_mp2(argp, &retry); + if (mp == 0) { + if (retry < 0) + return 0; + res.sfr_status = nfs_error(retry); + } else { + nfsstatfsokres *fp; +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "\tstat_fs(%s)", mp->am_path); +#endif /* DEBUG */ + + /* + * just return faked up file system information + */ + fp = &res.sfr_u.sfr_reply_u; + + fp->sfrok_tsize = 1024; + fp->sfrok_bsize = 1024; + + /* check if map is browsable and show_statfs_entries=yes */ + if ((gopt.flags & CFM_SHOW_STATFS_ENTRIES) && + mp->am_mnt && mp->am_mnt->mf_mopts) { + mnt.mnt_opts = mp->am_mnt->mf_mopts; + if (hasmntopt(&mnt, "browsable")) { + count_map_entries(mp, + &fp->sfrok_blocks, + &fp->sfrok_bfree, + &fp->sfrok_bavail); + } + } else { + fp->sfrok_blocks = 0; /* set to 1 if you don't want empty automounts */ + fp->sfrok_bfree = 0; + fp->sfrok_bavail = 0; + } + + res.sfr_status = NFS_OK; + mp->am_stats.s_statfs++; + } + + return &res; +} + + +/* + * count how many total entries there are in a map, and how many + * of them are in use. + */ +static void +count_map_entries(const am_node *mp, u_int *out_blocks, u_int *out_bfree, u_int *out_bavail) +{ + u_int blocks, bfree, bavail, i; + mntfs *mf; + mnt_map *mmp; + kv *k; + + blocks = bfree = bavail = 0; + if (!mp) + goto out; + mf = mp->am_mnt; + if (!mf) + goto out; + mmp = (mnt_map *) mf->mf_private; + if (!mmp) + goto out; + + /* iterate over keys */ + for (i = 0; i < NKVHASH; i++) { + for (k = mmp->kvhash[i]; k ; k = k->next) { + if (!k->key) + continue; + blocks++; + /* + * XXX: Need to count how many are actively in use and recompute + * bfree and bavail based on it. + */ + } + } + +out: + *out_blocks = blocks; + *out_bfree = bfree; + *out_bavail = bavail; +} diff --git a/contrib/amd/amd/ops_TEMPLATE.c b/contrib/amd/amd/ops_TEMPLATE.c new file mode 100644 index 0000000..7a60206 --- /dev/null +++ b/contrib/amd/amd/ops_TEMPLATE.c @@ -0,0 +1,293 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_TEMPLATE.c,v 5.2.2.3 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * An empty template for an amd pseudo filesystem "foofs". + */ + +/* + * NOTE: if this is an Amd file system, prepend "amfs_" to all foofs symbols + * and renamed the file name to amfs_foofs.c. If it is a native file system + * (such as pcfs, isofs, or ffs), then you can keep the names as is, and + * just rename the file to ops_foofs.c. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* forward declarations */ +static char * foofs_match(am_opts *fo); +static int foofs_init(mntfs *mf); +static int foofs_mount(am_node *mp); +static int foofs_fmount(mntfs *mf); +static int foofs_umount(am_node *mp); +static int foofs_fumount(mntfs *mf); +static am_node * foofs_lookuppn(am_node *mp, char *fname, int *error_return, int op); +static int foofs_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, int count); +static am_node * foofs_readlink(am_node *mp, int *error_return); +static void foofs_mounted(mntfs *mf); +static void foofs_umounted(am_node *mp); +fserver * foofs_ffserver(mntfs *mf); + + +/* + * Foofs operations. + * Define only those you need, others set to 0 (NULL) + */ +am_ops foofs_ops = +{ + "foofs", /* name of file system */ + foofs_match, /* match */ + foofs_init, /* initialize */ + foofs_mount, /* mount vnode */ + foofs_fmount, /* mount vfs */ + foofs_umount, /* unmount vnode */ + foofs_fumount, /* unmount VFS */ + foofs_lookuppn, /* lookup path-name */ + foofs_readdir, /* read directory */ + foofs_readlink, /* read link */ + foofs_mounted, /* after-mount extra actions */ + foofs_umounted, /* after-umount extra actions */ + foofs_ffserver, /* find a file server */ + FS_MKMNT | FS_BACKGROUND | FS_AMQINFO /* flags */ +}; + + +/* + * Check that f/s has all needed fields. + * Returns: matched string if found, NULL otherwise. + */ +static char * +foofs_match(am_opts *fo) +{ + char *cp = "fill this with a way to find the match"; + + plog(XLOG_INFO, "entering foofs_match..."); + + if (cp) + return cp; /* OK */ + + return NULL; /* not OK */ +} + + +/* + * Initialize. + * Returns: 0 if OK, non-zero (errno) if failed. + */ +static int +foofs_init(mntfs *mf) +{ + int error = 0; + + plog(XLOG_INFO, "entering foofs_init..."); + + error = EPERM; /* XXX: fixme */ + return error; +} + + +/* + * Mount vnode. + * Returns: 0 if OK, non-zero (errno) if failed. + */ +static int +foofs_mount(am_node *mp) +{ + int error = 0; + + plog(XLOG_INFO, "entering foofs_mount..."); + + error = EPERM; /* XXX: fixme */ + return error; +} + + +/* + * Mount vfs. + * Returns: 0 if OK, non-zero (errno) if failed. + */ +static int +foofs_fmount(mntfs *mf) +{ + int error = 0; + + plog(XLOG_INFO, "entering foofs_fmount..."); + + error = EPERM; /* XXX: fixme */ + return error; +} + + +/* + * Unmount vnode. + * Returns: 0 if OK, non-zero (errno) if failed. + */ +static int +foofs_umount(am_node *mp) +{ + int error = 0; + + plog(XLOG_INFO, "entering foofs_umount..."); + + error = EPERM; /* XXX: fixme */ + return error; +} + + +/* + * Unmount VFS. + * Returns: 0 if OK, non-zero (errno) if failed. + */ +static int +foofs_fumount(mntfs *mf) +{ + int error = 0; + + plog(XLOG_INFO, "entering foofs_fumount..."); + + error = EPERM; /* XXX: fixme */ + return error; +} + + +/* + * Lookup path-name. + * Returns: the am_node that was found, or NULL if failed. + * If failed, also fills in errno in error_return. + */ +static am_node * +foofs_lookuppn(am_node *mp, char *fname, int *error_return, int op) +{ + int error = 0; + + plog(XLOG_INFO, "entering foofs_lookuppn..."); + + error = EPERM; /* XXX: fixme */ + + *error_return = error; + return NULL; +} + + +/* + * Read directory. + * Returns: 0 if OK, non-zero (errno) if failed. + * If OK, fills in ep with chain of directory entries. + */ +static int +foofs_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, int count) +{ + int error = 0; + + plog(XLOG_INFO, "entering foofs_readdir..."); + + error = EPERM; /* XXX: fixme */ + return error; +} + + +/* + * Read link. + * Returns: am_node found, or NULL if not found. + * If failed, fills in errno in error_return. + */ +static am_node * +foofs_readlink(am_node *mp, int *error_return) +{ + int error = 0; + + plog(XLOG_INFO, "entering foofs_readlink..."); + + error = EPERM; /* XXX: fixme */ + + *error_return = error; + return NULL; +} + + +/* + * Async mount callback function. + * After the base mount went OK, sometimes + * there are additional actions that are needed. See union_mounted() and + * toplvl_mounted(). + */ +static void +foofs_mounted(mntfs *mf) +{ + plog(XLOG_INFO, "entering foofs_mounted..."); + + return; +} + + +/* + * Async unmount callback function. + * After the base umount() succeeds, we may want to take extra actions, + * such as informing remote mount daemons that we've unmounted them. + * See amfs_auto_umounted(), host_umounted(), nfs_umounted(). + */ +static void +foofs_umounted(am_node *mp) +{ + plog(XLOG_INFO, "entering foofs_umounted..."); + + return; +} + + +/* + * Find a file server. + * Returns: fserver of found server, or NULL if not found. + */ +fserver * +foofs_ffserver(mntfs *mf) +{ + plog(XLOG_INFO, "entering foofs_ffserver..."); + + return NULL; +} diff --git a/contrib/amd/amd/ops_autofs.c b/contrib/amd/amd/ops_autofs.c new file mode 100644 index 0000000..a566fc4 --- /dev/null +++ b/contrib/amd/amd/ops_autofs.c @@ -0,0 +1,1275 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_autofs.c,v 5.2.2.3 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * Automounter filesystem + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* + * CLUDGE: wrap whole file in HAVE_FS_AUTOFS, becasue + * not all systems with an automounter file system are supported + * by am-utils yet... + */ + +#ifdef HAVE_FS_AUTOFS + +/* + * MACROS: + */ +#ifndef AUTOFS_NULL +# define AUTOFS_NULL ((u_long)0) +#endif /* not AUTOFS_NULL */ + +/* + * VARIABLES: + */ + +/* forward declarations */ +static int mount_autofs(char *dir, char *opts); +static int autofs_mount_1_svc(struct mntrequest *mr, struct mntres *result, struct authunix_parms *cred); +static int autofs_unmount_1_svc(struct umntrequest *ur, struct umntres *result, struct authunix_parms *cred); + +/* externam declarations */ +extern bool_t xdr_mntrequest(XDR *, mntrequest *); +extern bool_t xdr_mntres(XDR *, mntres *); +extern bool_t xdr_umntrequest(XDR *, umntrequest *); +extern bool_t xdr_umntres(XDR *, umntres *); + +/* + * STRUCTURES: + */ + +/* Sun's kernel-based automounter-supporting file system */ +am_ops autofs_ops = +{ + "autofs", + amfs_auto_match, + 0, /* amfs_auto_init */ + autofs_mount, + 0, + autofs_umount, + 0, + amfs_auto_lookuppn, + amfs_auto_readdir, /* browsable version of readdir() */ + 0, /* autofs_readlink */ + autofs_mounted, + 0, /* autofs_umounted */ + find_amfs_auto_srvr, + FS_MKMNT | FS_NOTIMEOUT | FS_BACKGROUND | FS_AMQINFO | FS_DIRECTORY +}; + + +/**************************************************************************** + *** FUNCTIONS *** + ****************************************************************************/ + +/* + * Mount the top-level using autofs + */ +int +autofs_mount(am_node *mp) +{ + mntfs *mf = mp->am_mnt; + struct stat stb; + char opts[256], preopts[256]; + int error; + char *mnttype; + + /* + * Mounting the automounter. + * Make sure the mount directory exists, construct + * the mount options and call the mount_autofs routine. + */ + + 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; + } + if (mf->mf_ops == &autofs_ops) + mnttype = "indirect"; + else if (mf->mf_ops == &amfs_direct_ops) + mnttype = "direct"; +#ifdef HAVE_AM_FS_UNION + else if (mf->mf_ops == &amfs_union_ops) + mnttype = "union"; +#endif /* HAVE_AM_FS_UNION */ + else + mnttype = "auto"; + + /* + * Construct some mount options: + * + * Tack on magic map=<mapname> option in mtab to emulate + * SunOS automounter behavior. + */ + preopts[0] = '\0'; +#ifdef MNTTAB_OPT_INTR + strcat(preopts, MNTTAB_OPT_INTR); + strcat(preopts, ","); +#endif /* MNTTAB_OPT_INTR */ +#ifdef MNTTAB_OPT_IGNORE + strcat(preopts, MNTTAB_OPT_IGNORE); + strcat(preopts, ","); +#endif /* MNTTAB_OPT_IGNORE */ + sprintf(opts, "%s%s,%s=%d,%s=%d,%s=%d,%s,map=%s", + preopts, + MNTTAB_OPT_RW, + MNTTAB_OPT_PORT, nfs_port, + MNTTAB_OPT_TIMEO, gopt.amfs_auto_timeo, + MNTTAB_OPT_RETRANS, gopt.amfs_auto_retrans, + mnttype, mf->mf_info); + + /* now do the mount */ + error = mount_autofs(mf->mf_mount, opts); + if (error) { + errno = error; + plog(XLOG_FATAL, "mount_autofs: %m"); + return error; + } + return 0; +} + + +void +autofs_mounted(mntfs *mf) +{ + amfs_auto_mkcacheref(mf); +} + + +/* + * Unmount a top-level automount node + */ +int +autofs_umount(am_node *mp) +{ + int error; + struct stat stb; + + /* + * 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, mnttab_file_name); + if (error == EBUSY && mp->am_flags & AMF_AUTOFS) { + plog(XLOG_WARNING, "autofs_unmount of %s busy (autofs). exit", mp->am_path); + error = 0; /* fake unmount was ok */ + } + return error; +} + + +/* + * Mount an automounter directory. + * The automounter is connected into the system + * as a user-level NFS server. mount_autofs constructs + * the necessary NFS parameters to be given to the + * kernel so that it will talk back to us. + */ +static int +mount_autofs(char *dir, char *opts) +{ + char fs_hostname[MAXHOSTNAMELEN + MAXPATHLEN + 1]; + char *map_opt, buf[MAXHOSTNAMELEN]; + int retry, error, flags; + struct utsname utsname; + mntent_t mnt; + autofs_args_t autofs_args; + MTYPE_TYPE type = MOUNT_TYPE_AUTOFS; + + memset((voidp) &autofs_args, 0, sizeof(autofs_args)); /* Paranoid */ + + memset((voidp) &mnt, 0, sizeof(mnt)); + mnt.mnt_dir = dir; + mnt.mnt_fsname = pid_fsname; + mnt.mnt_opts = opts; + mnt.mnt_type = type; + + retry = hasmntval(&mnt, "retry"); + if (retry <= 0) + retry = 2; /* XXX */ + + /* + * SET MOUNT ARGS + */ + if (uname(&utsname) < 0) { + strcpy(buf, "localhost.autofs"); + } else { + strcpy(buf, utsname.nodename); + strcat(buf, ".autofs"); + } +#ifdef HAVE_FIELD_AUTOFS_ARGS_T_ADDR + autofs_args.addr.buf = buf; + autofs_args.addr.len = strlen(autofs_args.addr.buf); + autofs_args.addr.maxlen = autofs_args.addr.len; +#endif /* HAVE_FIELD_AUTOFS_ARGS_T_ADDR */ + + autofs_args.path = dir; + autofs_args.opts = opts; + + map_opt = hasmntopt(&mnt, "map"); + if (map_opt) { + map_opt += sizeof("map="); /* skip the "map=" */ + if (map_opt == NULL) { + plog(XLOG_WARNING, "map= has a null map name. reset to amd.unknown"); + map_opt = "amd.unknown"; + } + } + autofs_args.map = map_opt; + + /* XXX: these I set arbitrarily... */ + autofs_args.mount_to = 300; + autofs_args.rpc_to = 60; + autofs_args.direct = 0; + + /* + * Make a ``hostname'' string for the kernel + */ + sprintf(fs_hostname, "pid%ld@%s:%s", foreground ? mypid : getppid(), + hostname, dir); + + /* + * Most kernels have a name length restriction. + */ + if (strlen(fs_hostname) >= MAXHOSTNAMELEN) + strcpy(fs_hostname + MAXHOSTNAMELEN - 3, ".."); + + /* + * Finally we can compute the mount flags set above. + */ + flags = compute_mount_flags(&mnt); + + /* + * This is it! Here we try to mount amd on its mount points. + */ + error = mount_fs(&mnt, flags, (caddr_t) &autofs_args, retry, type, 0, NULL, mnttab_file_name); + return error; +} + + +/****************************************************************************/ +/* autofs program dispatcher */ +void +autofs_program_1(struct svc_req *rqstp, SVCXPRT *transp) +{ + int ret; + union { + mntrequest autofs_mount_1_arg; + umntrequest autofs_umount_1_arg; + } argument; + union { + mntres mount_res; + umntres umount_res; + } result; + + bool_t (*xdr_argument)(), (*xdr_result)(); + int (*local)(); + + switch (rqstp->rq_proc) { + + case AUTOFS_NULL: + svc_sendreply(transp, + (XDRPROC_T_TYPE) xdr_void, + (SVC_IN_ARG_TYPE) NULL); + return; + + case AUTOFS_MOUNT: + xdr_argument = xdr_mntrequest; + xdr_result = xdr_mntres; + local = (int (*)()) autofs_mount_1_svc; + break; + + case AUTOFS_UNMOUNT: + xdr_argument = xdr_umntrequest; + xdr_result = xdr_umntres; + local = (int (*)()) autofs_unmount_1_svc; + break; + + default: + svcerr_noproc(transp); + return; + } + + memset((char *) &argument, 0, sizeof(argument)); + if (!svc_getargs(transp, + (XDRPROC_T_TYPE) xdr_argument, + (SVC_IN_ARG_TYPE) &argument)) { + plog(XLOG_ERROR, + "AUTOFS xdr decode failed for %d %d %d", + rqstp->rq_prog, rqstp->rq_vers, rqstp->rq_proc); + svcerr_decode(transp); + return; + } + + ret = (*local) (&argument, &result, rqstp); + if (!svc_sendreply(transp, + (XDRPROC_T_TYPE) xdr_result, + (SVC_IN_ARG_TYPE) &result)) { + svcerr_systemerr(transp); + } + + if (!svc_freeargs(transp, + (XDRPROC_T_TYPE) xdr_argument, + (SVC_IN_ARG_TYPE) &argument)) { + plog(XLOG_FATAL, "unable to free rpc arguments in autofs_program_1"); + going_down(1); + } +} + + +static int +autofs_mount_1_svc(struct mntrequest *mr, struct mntres *result, struct authunix_parms *cred) +{ + int err = 0; + am_node *anp, *anp2; + + plog(XLOG_INFO, "XXX: autofs_mount_1_svc: %s:%s:%s:%s", + mr->map, mr->name, mr->opts, mr->path); + + /* look for map (eg. "/home") */ + anp = find_ap(mr->path); + if (!anp) { + plog(XLOG_ERROR, "map %s not found", mr->path); + err = ENOENT; + goto out; + } + /* turn on autofs in map flags */ + if (!(anp->am_flags & AMF_AUTOFS)) { + plog(XLOG_INFO, "turning on AMF_AUTOFS for node %s", mr->path); + anp->am_flags |= AMF_AUTOFS; + } + + /* + * Look for (and create if needed) the new node. + * + * If an error occurred, return it. If a -1 was returned, that indicates + * that a mount is in progress, so sleep a while (while the backgrounded + * mount is happening), and then signal the autofs to retry the mount. + * + * There's something I don't understand. I was thinking that this code + * here is the one which will succeed eventually and will send an RPC + * reply to the kernel, but apparently that happens somewhere else, not + * here. It works though, just that I don't know how. Arg. -Erez. + * */ + err = 0; + anp2 = autofs_lookuppn(anp, mr->name, &err, VLOOK_CREATE); + if (!anp2) { + if (err == -1) { /* then tell autofs to retry */ + sleep(1); + err = EAGAIN; + } + goto out; + } + +out: + result->status = err; + return err; +} + + +static int +autofs_unmount_1_svc(struct umntrequest *ur, struct umntres *result, struct authunix_parms *cred) +{ + int err = 0; + +#ifdef HAVE_FIELD_UMNTREQUEST_RDEVID + plog(XLOG_INFO, "XXX: autofs_unmount_1_svc: %d:%u:%lu:0x%x", + ur->isdirect, ur->devid, ur->rdevid, ur->next); +#else /* HAVE_FIELD_UMNTREQUEST_RDEVID */ + plog(XLOG_INFO, "XXX: autofs_unmount_1_svc: %d:%u:0x%x", + ur->isdirect, ur->devid, ur->next); +#endif /* HAVE_FIELD_UMNTREQUEST_RDEVID */ + + err = EINVAL; /* XXX: not implemented yet */ + goto out; + +out: + result->status = err; + return err; +} + + +/* + * 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 +autofs_bgmount(struct continuation * cp, int mpe) +{ + mntfs *mf = cp->mp->am_mnt; /* Current mntfs */ + mntfs *mf_retry = 0; /* First mntfs which needed retrying */ + int this_error = -1; /* Per-mount error */ + int hard_error = -1; + int mp_error = mpe; + + /* + * Try to mount each location. + * At the end: + * hard_error == 0 indicates something was mounted. + * hard_error > 0 indicates everything failed with a hard error + * hard_error < 0 indicates nothing could be mounted now + */ + for (; this_error && *cp->ivec; cp->ivec++) { + am_ops *p; + am_node *mp = cp->mp; + char *link_dir; + int dont_retry; + + if (hard_error < 0) + hard_error = this_error; + + this_error = -1; + + if (**cp->ivec == '-') { + /* + * Pick up new defaults + */ + if (cp->auto_opts && *cp->auto_opts) + cp->def_opts = str3cat(cp->def_opts, cp->auto_opts, ";", *cp->ivec + 1); + else + cp->def_opts = strealloc(cp->def_opts, *cp->ivec + 1); +#ifdef DEBUG + dlog("Setting def_opts to \"%s\"", cp->def_opts); +#endif /* DEBUG */ + continue; + } + /* + * If a mount has been attempted, and we find + * a cut then don't try any more locations. + */ + if (STREQ(*cp->ivec, "/") || STREQ(*cp->ivec, "||")) { + if (cp->tried) { +#ifdef DEBUG + dlog("Cut: not trying any more locations for %s", + mp->am_path); +#endif /* DEBUG */ + break; + } + continue; + } + + /* match the operators */ + p = ops_match(&cp->fs_opts, *cp->ivec, cp->def_opts, mp->am_path, cp->key, mp->am_parent->am_mnt->mf_info); + + /* + * Find a mounted filesystem for this node. + */ + mp->am_mnt = mf = realloc_mntfs(mf, p, &cp->fs_opts, + cp->fs_opts.opt_fs, + cp->fs_opts.fs_mtab, + cp->auto_opts, + cp->fs_opts.opt_opts, + cp->fs_opts.opt_remopts); + + p = mf->mf_ops; +#ifdef DEBUG + dlog("Got a hit with %s", p->fs_type); +#endif /* DEBUG */ + + /* + * Note whether this is a real mount attempt + */ + if (p == &amfs_error_ops) { + plog(XLOG_MAP, "Map entry %s for %s 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) { + XFREE(mp->am_link); + mp->am_link = 0; + } + link_dir = mf->mf_fo->opt_sublink; + + if (link_dir && *link_dir) { + if (*link_dir == '/') { + mp->am_link = strdup(link_dir); + } else { + /* + * try getting fs option from continuation, not mountpoint! + * Don't try logging the string from mf, since it may be bad! + */ + if (cp->fs_opts.opt_fs != mf->mf_fo->opt_fs) + plog(XLOG_ERROR, "use %s instead of 0x%x", + cp->fs_opts.opt_fs, mf->mf_fo->opt_fs); + + mp->am_link = str3cat((char *) 0, + cp->fs_opts.opt_fs, "/", link_dir); + + normalize_slash(mp->am_link); + } + } + + if (mf->mf_error > 0) { + this_error = mf->mf_error; + } else if (mf->mf_flags & (MFF_MOUNTING | MFF_UNMOUNTING)) { + /* + * Still mounting - retry later + */ +#ifdef DEBUG + dlog("Duplicate pending mount fstype %s", p->fs_type); +#endif /* DEBUG */ + this_error = -1; + } else if (FSRV_ISDOWN(mf->mf_server)) { + /* + * Would just mount from the same place + * as a hung mount - so give up + */ +#ifdef DEBUG + dlog("%s is already hung - giving up", mf->mf_mount); +#endif /* DEBUG */ + mp_error = EWOULDBLOCK; + dont_retry = TRUE; + this_error = -1; + } else if (mf->mf_flags & MFF_MOUNTED) { +#ifdef DEBUG + dlog("duplicate mount of \"%s\" ...", mf->mf_info); +#endif /* DEBUG */ + + /* + * Just call mounted() + */ + am_mounted(mp); + + this_error = 0; + break; + } + + /* + * Will usually need to play around with the mount nodes + * file attribute structure. This must be done here. + * Try and get things initialised, even if the fileserver + * is not known to be up. In the common case this will + * progress things faster. + */ + if (!this_error) { + /* + * Fill in attribute fields. + */ + if (mf->mf_ops->fs_flags & FS_DIRECTORY) + mk_fattr(mp, NFDIR); + else + mk_fattr(mp, NFLNK); + + mp->am_fattr.na_fileid = mp->am_gen; + + if (p->fs_init) + this_error = (*p->fs_init) (mf); + } + + /* + * Make sure the fileserver is UP before doing any more work + */ + if (!FSRV_ISUP(mf->mf_server)) { +#ifdef DEBUG + dlog("waiting for server %s to become available", mf->mf_server->fs_host); +#endif /* DEBUG */ + this_error = -1; + } + + if (!this_error && mf->mf_fo->opt_delay) { + /* + * If there is a delay timer on the mount + * then don't try to mount if the timer + * has not expired. + */ + int i = atoi(mf->mf_fo->opt_delay); + if (i > 0 && clocktime() < (cp->start + i)) { +#ifdef DEBUG + dlog("Mount of %s delayed by %ds", mf->mf_mount, i - clocktime() + cp->start); +#endif /* DEBUG */ + this_error = -1; + } + } + + if (this_error < 0 && !dont_retry) { + if (!mf_retry) + mf_retry = dup_mntfs(mf); + cp->retry = TRUE; + } + + if (!this_error) + if (p->fs_flags & FS_MBACKGROUND) { + mf->mf_flags |= MFF_MOUNTING; /* XXX */ +#ifdef DEBUG + dlog("backgrounding mount of \"%s\"", mf->mf_mount); +#endif /* DEBUG */ + if (cp->callout) { + untimeout(cp->callout); + cp->callout = 0; + } + run_task(try_mount, (voidp) mp, amfs_auto_cont, (voidp) cp); + mf->mf_flags |= MFF_MKMNT; /* XXX */ + if (mf_retry) + free_mntfs(mf_retry); + return -1; + } else { +#ifdef DEBUG + dlog("foreground mount of \"%s\" ...", mf->mf_info); +#endif /* DEBUG */ + this_error = try_mount((voidp) mp); + if (this_error < 0) { + if (!mf_retry) + mf_retry = dup_mntfs(mf); + cp->retry = TRUE; + } + } + + if (this_error >= 0) { + if (this_error > 0) { + amd_stats.d_merr++; + if (mf != mf_retry) { + mf->mf_error = this_error; + mf->mf_flags |= MFF_ERROR; + } + } + + /* + * Wakeup anything waiting for this mount + */ + wakeup((voidp) mf); + } + } + + if (this_error && cp->retry) { + free_mntfs(mf); + mf = cp->mp->am_mnt = mf_retry; + /* + * Not retrying again (so far) + */ + cp->retry = FALSE; + cp->tried = FALSE; + /* + * Start at the beginning. + * Rewind the location vector and + * reset the default options. + */ + cp->ivec = cp->xivec; + cp->def_opts = strealloc(cp->def_opts, cp->auto_opts); + /* + * Arrange that autofs_bgmount is called + * after anything else happens. + */ +#ifdef DEBUG + dlog("Arranging to retry mount of %s", cp->mp->am_path); +#endif /* DEBUG */ + sched_task(amfs_auto_retry, (voidp) cp, (voidp) mf); + if (cp->callout) + untimeout(cp->callout); + cp->callout = timeout(RETRY_INTERVAL, wakeup, (voidp) mf); + + cp->mp->am_ttl = clocktime() + RETRY_INTERVAL; + + /* + * Not done yet - so don't return anything + */ + return -1; + } + + if (hard_error < 0 || this_error == 0) + hard_error = this_error; + + /* + * Discard handle on duff filesystem. + * This should never happen since it + * should be caught by the case above. + */ + if (mf_retry) { + if (hard_error) + plog(XLOG_ERROR, "discarding a retry mntfs for %s", mf_retry->mf_mount); + free_mntfs(mf_retry); + } + + /* + * If we get here, then either the mount succeeded or + * there is no more mount information available. + */ + if (hard_error < 0 && mp_error) + hard_error = cp->mp->am_error = mp_error; + if (hard_error > 0) { + /* + * Set a small(ish) timeout on an error node if + * the error was not a time out. + */ + switch (hard_error) { + case ETIMEDOUT: + case EWOULDBLOCK: + cp->mp->am_timeo = 17; + break; + default: + cp->mp->am_timeo = 5; + break; + } + new_ttl(cp->mp); + } + + /* + * Make sure that the error value in the mntfs has a + * reasonable value. + */ + if (mf->mf_error < 0) { + mf->mf_error = hard_error; + if (hard_error) + mf->mf_flags |= MFF_ERROR; + } + + /* + * In any case we don't need the continuation any more + */ + free_continuation(cp); + + return hard_error; +} + + +/* + * Automount interface to RPC lookup routine + * Find the corresponding entry and return + * the file handle for it. + */ +am_node * +autofs_lookuppn(am_node *mp, char *fname, int *error_return, int op) +{ + am_node *ap, *new_mp, *ap_hung; + char *info; /* Mount info - where to get the file system */ + char **ivec, **xivec; /* Split version of info */ + char *auto_opts; /* Automount options */ + int error = 0; /* Error so far */ + char path_name[MAXPATHLEN]; /* General path name buffer */ + char apath[MAXPATHLEN]; /* authofs path (added space) */ + char *pfname; /* Path for database lookup */ + struct continuation *cp; /* Continuation structure if need to mount */ + int in_progress = 0; /* # of (un)mount in progress */ + char *dflts; + mntfs *mf; + +#ifdef DEBUG + dlog("in autofs_lookuppn"); +#endif /* DEBUG */ + + /* + * If the server is shutting down + * then don't return information + * about the mount point. + */ + if (amd_state == Finishing) { +#ifdef DEBUG + if ((mf = mp->am_mnt) == 0 || mf->mf_ops == &amfs_direct_ops) + dlog("%s mount ignored - going down", fname); + else + dlog("%s/%s mount ignored - going down", mp->am_path, fname); +#endif /* DEBUG */ + ereturn(ENOENT); + } + + /* + * Handle special case of "." and ".." + */ + if (fname[0] == '.') { + if (fname[1] == '\0') + return mp; /* "." is the current node */ + if (fname[1] == '.' && fname[2] == '\0') { + if (mp->am_parent) { +#ifdef DEBUG + dlog(".. in %s gives %s", mp->am_path, mp->am_parent->am_path); +#endif /* DEBUG */ + return mp->am_parent; /* ".." is the parent node */ + } + ereturn(ESTALE); + } + } + + /* + * Check for valid key name. + * If it is invalid then pretend it doesn't exist. + */ + if (!valid_key(fname)) { + plog(XLOG_WARNING, "Key \"%s\" contains a disallowed character", fname); + ereturn(ENOENT); + } + + /* + * Expand key name. + * fname is now a private copy. + */ + fname = expand_key(fname); + + for (ap_hung = 0, ap = mp->am_child; ap; ap = ap->am_osib) { + /* + * Otherwise search children of this node + */ + if (FSTREQ(ap->am_name, fname)) { + mf = ap->am_mnt; + if (ap->am_error) { + error = ap->am_error; + continue; + } + /* + * If the error code is undefined then it must be + * in progress. + */ + if (mf->mf_error < 0) + goto in_progrss; + + /* + * Check for a hung node + */ + if (FSRV_ISDOWN(mf->mf_server)) { +#ifdef DEBUG + dlog("server hung"); +#endif /* DEBUG */ + error = ap->am_error; + ap_hung = ap; + continue; + } + /* + * If there was a previous error with this node + * then return that error code. + */ + if (mf->mf_flags & MFF_ERROR) { + error = mf->mf_error; + continue; + } + if (!(mf->mf_flags & MFF_MOUNTED) || (mf->mf_flags & MFF_UNMOUNTING)) { + in_progrss: + /* + * If the fs is not mounted or it is unmounting then there + * is a background (un)mount in progress. In this case + * we just drop the RPC request (return nil) and + * wait for a retry, by which time the (un)mount may + * have completed. + */ +#ifdef DEBUG + dlog("ignoring mount of %s in %s -- flags (%x) in progress", + fname, mf->mf_mount, mf->mf_flags); +#endif /* DEBUG */ + in_progress++; + continue; + } + + /* + * Otherwise we have a hit: return the current mount point. + */ +#ifdef DEBUG + dlog("matched %s in %s", fname, ap->am_path); +#endif /* DEBUG */ + XFREE(fname); + return ap; + } + } + + if (in_progress) { +#ifdef DEBUG + dlog("Waiting while %d mount(s) in progress", in_progress); +#endif /* DEBUG */ + XFREE(fname); + ereturn(-1); + } + + /* + * If an error occured then return it. + */ + if (error) { +#ifdef DEBUG + errno = error; /* XXX */ + dlog("Returning error: %m", error); +#endif /* DEBUG */ + XFREE(fname); + ereturn(error); + } + + /* + * If doing a delete then don't create again! + */ + switch (op) { + case VLOOK_DELETE: + ereturn(ENOENT); + + case VLOOK_CREATE: + break; + + default: + plog(XLOG_FATAL, "Unknown op to autofs_lookuppn: 0x%x", op); + ereturn(EINVAL); + } + + /* + * If the server is going down then just return, + * don't try to mount any more file systems + */ + if ((int) amd_state >= (int) Finishing) { +#ifdef DEBUG + dlog("not found - server going down anyway"); +#endif /* DEBUG */ + XFREE(fname); + ereturn(ENOENT); + } + + /* + * If we get there then this is a reference to an, + * as yet, unknown name so we need to search the mount + * map for it. + */ + if (mp->am_pref) { + sprintf(path_name, "%s%s", mp->am_pref, fname); + pfname = path_name; + } else { + pfname = fname; + } + + mf = mp->am_mnt; + +#ifdef DEBUG + dlog("will search map info in %s to find %s", mf->mf_info, pfname); +#endif /* DEBUG */ + /* + * Consult the oracle for some mount information. + * info is malloc'ed and belongs to this routine. + * It ends up being free'd in free_continuation(). + * + * Note that this may return -1 indicating that information + * is not yet available. + */ + error = mapc_search((mnt_map *) mf->mf_private, pfname, &info); + if (error) { + if (error > 0) + plog(XLOG_MAP, "No map entry for %s", pfname); + else + plog(XLOG_MAP, "Waiting on map entry for %s", pfname); + XFREE(fname); + ereturn(error); + } +#ifdef DEBUG + dlog("mount info is %s", info); +#endif /* DEBUG */ + + /* + * Split info into an argument vector. + * The vector is malloc'ed and belongs to + * this routine. It is free'd in free_continuation() + */ + xivec = ivec = strsplit(info, ' ', '\"'); + + /* + * Default error code... + */ + if (ap_hung) + error = EWOULDBLOCK; + else + error = ENOENT; + + /* + * Allocate a new map + */ + new_mp = exported_ap_alloc(); + if (new_mp == 0) { + XFREE(xivec); + XFREE(info); + XFREE(fname); + ereturn(ENOSPC); + } + if (mf->mf_auto) + auto_opts = mf->mf_auto; + else + auto_opts = ""; + + auto_opts = strdup(auto_opts); + +#ifdef DEBUG + dlog("searching for /defaults entry"); +#endif /* DEBUG */ + if (mapc_search((mnt_map *) mf->mf_private, "/defaults", &dflts) == 0) { + char *dfl; + char **rvec; +#ifdef DEBUG + dlog("/defaults gave %s", dflts); +#endif /* DEBUG */ + if (*dflts == '-') + dfl = dflts + 1; + else + dfl = dflts; + + /* + * Chop the defaults up + */ + rvec = strsplit(dfl, ' ', '\"'); + + if (gopt.flags & CFM_ENABLE_DEFAULT_SELECTORS) { + /* + * Pick whichever first entry matched the list of selectors. + * Strip the selectors from the string, and assign to dfl the + * rest of the string. + */ + if (rvec) { + am_opts ap; + am_ops *pt; + char **sp = rvec; + while (*sp) { /* loop until you find something, if any */ + memset((char *) &ap, 0, sizeof(am_opts)); + pt = ops_match(&ap, *sp, "", mp->am_path, "/defaults", + mp->am_parent->am_mnt->mf_info); + if (pt == &amfs_error_ops) { + plog(XLOG_MAP, "failed to match defaults for \"%s\"", *sp); + } else { + dfl = strip_selectors(*sp, "/defaults"); + plog(XLOG_MAP, "matched default selectors \"%s\"", dfl); + break; + } + ++sp; + } + } + } else { /* not enable_default_selectors */ + /* + * Extract first value + */ + dfl = rvec[0]; + } + + /* + * If there were any values at all... + */ + if (dfl) { + /* + * Log error if there were other values + */ + if (!(gopt.flags & CFM_ENABLE_DEFAULT_SELECTORS) && rvec[1]) { +# ifdef DEBUG + dlog("/defaults chopped into %s", dfl); +# endif /* DEBUG */ + plog(XLOG_USER, "More than a single value for /defaults in %s", mf->mf_info); + } + + /* + * Prepend to existing defaults if they exist, + * otherwise just use these defaults. + */ + if (*auto_opts && *dfl) { + char *nopts = (char *) xmalloc(strlen(auto_opts) + strlen(dfl) + 2); + sprintf(nopts, "%s;%s", dfl, auto_opts); + XFREE(auto_opts); + auto_opts = nopts; + } else if (*dfl) { + auto_opts = strealloc(auto_opts, dfl); + } + } + XFREE(dflts); + /* + * Don't need info vector any more + */ + XFREE(rvec); + } + + /* + * Fill it in + */ + init_map(new_mp, fname); + + /* + * Turn on autofs flag if needed. + */ + if (mp->am_flags & AMF_AUTOFS) { + new_mp->am_flags |= AMF_AUTOFS; + } + + /* + * Put it in the table + */ + insert_am(new_mp, mp); + + /* + * Fill in some other fields, + * path and mount point. + * + * bugfix: do not prepend old am_path if direct map + * <wls@astro.umd.edu> William Sebok + */ + + strcpy(apath, fname); + strcat(apath, " "); + new_mp->am_path = str3cat(new_mp->am_path, + mf->mf_ops == &amfs_direct_ops ? "" : mp->am_path, + *fname == '/' ? "" : "/", + apath); + +#ifdef DEBUG + dlog("setting path to \"%s\"", new_mp->am_path); +#endif /* DEBUG */ + + /* + * Take private copy of pfname + */ + pfname = strdup(pfname); + + /* + * Construct a continuation + */ + cp = ALLOC(struct continuation); + cp->callout = 0; + cp->mp = new_mp; + cp->xivec = xivec; + cp->ivec = ivec; + cp->info = info; + cp->key = pfname; + cp->auto_opts = auto_opts; + cp->retry = FALSE; + cp->tried = FALSE; + cp->start = clocktime(); + cp->def_opts = strdup(auto_opts); + memset((voidp) &cp->fs_opts, 0, sizeof(cp->fs_opts)); + + /* + * Try and mount the file system. If this succeeds immediately (possible + * for a ufs file system) then return the attributes, otherwise just + * return an error. + */ + error = autofs_bgmount(cp, error); + reschedule_timeout_mp(); + if (!error) { + XFREE(fname); + return new_mp; + } + + /* + * Code for quick reply. If nfs_program_2_transp is set, then + * its the transp that's been passed down from nfs_program_2(). + * If new_mp->am_transp is not already set, set it by copying in + * nfs_program_2_transp. Once am_transp is set, quick_reply() can + * use it to send a reply to the client that requested this mount. + */ + if (nfs_program_2_transp && !new_mp->am_transp) { + new_mp->am_transp = (SVCXPRT *) xmalloc(sizeof(SVCXPRT)); + *(new_mp->am_transp) = *nfs_program_2_transp; + } + if (error && (new_mp->am_mnt->mf_ops == &amfs_error_ops)) + new_mp->am_error = error; + + assign_error_mntfs(new_mp); + + XFREE(fname); + + ereturn(error); +} +#endif /* HAVE_FS_AUTOFS */ diff --git a/contrib/amd/amd/ops_cachefs.c b/contrib/amd/amd/ops_cachefs.c new file mode 100644 index 0000000..0c40085 --- /dev/null +++ b/contrib/amd/amd/ops_cachefs.c @@ -0,0 +1,247 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_cachefs.c,v 5.2.2.3 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * Caching filesystem (Solaris 2.x) + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* forward declarations */ +static char *cachefs_match(am_opts *fo); +static int cachefs_init(mntfs *mf); +static int cachefs_fmount(mntfs *mf); +static int cachefs_fumount(mntfs *mf); + + +/* + * Ops structure + */ +am_ops cachefs_ops = +{ + "cachefs", + cachefs_match, + cachefs_init, + amfs_auto_fmount, + cachefs_fmount, + amfs_auto_fumount, + cachefs_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* cachefs_readlink */ + 0, /* post-mount actions */ + 0, /* post-umount actions */ + find_amfs_auto_srvr, + FS_MKMNT | FS_NOTIMEOUT | FS_UBACKGROUND | FS_AMQINFO +}; + + +/* + * Check that f/s has all needed fields. + * Returns: matched string if found, NULL otherwise. + */ +static char * +cachefs_match(am_opts *fo) +{ + /* sanity check */ + if (!fo->opt_rfs || !fo->opt_fs || !fo->opt_cachedir) { + plog(XLOG_USER, "cachefs: must specify cachedir, rfs, and fs"); + return NULL; + } + +#ifdef DEBUG + dlog("CACHEFS: using cache directory \"%s\"", fo->opt_cachedir); +#endif /* DEBUG */ + + /* determine magic cookie to put in mtab */ + return strdup(fo->opt_cachedir); +} + + +/* + * Initialize. + * Returns: 0 if OK, non-zero (errno) if failed. + */ +static int +cachefs_init(mntfs *mf) +{ + /* + * Save cache directory name + */ + if (mf->mf_refc == 1) { + mf->mf_private = (voidp) strdup(mf->mf_fo->opt_cachedir); + mf->mf_prfree = (void (*)(voidp)) free; + } + + return 0; +} + + +/* + * mntpt is the mount point ($fs) [XXX: was 'dir'] + * backdir is the mounted pathname ($rfs) [XXX: was 'fs_name'] + * cachedir is the cache directory ($cachedir) + */ +static int +mount_cachefs(char *mntpt, char *backdir, char *cachedir, char *opts) +{ + cachefs_args_t ca; + mntent_t mnt; + int flags; + char *cp; + MTYPE_TYPE type = MOUNT_TYPE_CACHEFS; /* F/S mount type */ + + memset((voidp) &ca, 0, sizeof(ca)); /* Paranoid */ + + /* + * Fill in the mount structure + */ + memset((voidp) &mnt, 0, sizeof(mnt)); + mnt.mnt_dir = mntpt; + mnt.mnt_fsname = backdir; + mnt.mnt_type = MNTTAB_TYPE_CACHEFS; + mnt.mnt_opts = opts; + + flags = compute_mount_flags(&mnt); + + /* Fill in cachefs mount arguments */ + + /* + * XXX: Caveats + * (1) cache directory is NOT checked for sanity beforehand, nor is it + * purged. Maybe it should be purged first? + * (2) cache directory is NOT locked. Should we? + */ + + /* mount flags */ + ca.cfs_options.opt_flags = CFS_WRITE_AROUND | CFS_ACCESS_BACKFS; + /* cache population size */ + ca.cfs_options.opt_popsize = DEF_POP_SIZE; /* default: 64K */ + /* filegrp size */ + ca.cfs_options.opt_fgsize = DEF_FILEGRP_SIZE; /* default: 256 */ + + /* CFS ID for file system (must be unique) */ + ca.cfs_fsid = cachedir; + + /* CFS fscdir name */ + memset(ca.cfs_cacheid, 0, sizeof(ca.cfs_cacheid)); + /* append cacheid and mountpoint */ + sprintf(ca.cfs_cacheid, "%s:%s", ca.cfs_fsid, mntpt); + /* convert '/' to '_' (Solaris does that...) */ + cp = ca.cfs_cacheid; + while ((cp = strpbrk(cp, "/")) != NULL) + *cp = '_'; + + /* path for this cache dir */ + ca.cfs_cachedir = cachedir; + + /* back filesystem dir */ + ca.cfs_backfs = backdir; + + /* same as nfs values (XXX: need to handle these options) */ + ca.cfs_acregmin = 0; + ca.cfs_acregmax = 0; + ca.cfs_acdirmin = 0; + ca.cfs_acdirmax = 0; + + /* + * Call generic mount routine + */ + return mount_fs(&mnt, flags, (caddr_t) &ca, 0, type, 0, NULL, mnttab_file_name); +} + + +static int +cachefs_fmount(mntfs *mf) +{ + int error; + + error = mount_cachefs(mf->mf_mount, + mf->mf_fo->opt_rfs, + mf->mf_fo->opt_cachedir, + mf->mf_mopts); + if (error) { + errno = error; + /* according to Solaris, if errno==ESRCH, "options to not match" */ + if (error == ESRCH) + plog(XLOG_ERROR, "mount_cachefs: options to no match: %m"); + else + plog(XLOG_ERROR, "mount_cachefs: %m"); + return error; + } + + return 0; +} + + +static int +cachefs_fumount(mntfs *mf) +{ + int error; + + error = UMOUNT_FS(mf->mf_mount, mnttab_file_name); + + /* + * In the case of cachefs, we must fsck the cache directory. Otherwise, + * it will remain inconsistent, and the next cachefs mount will fail + * with the error "no space left on device" (ENOSPC). + * + * XXX: this is hacky! use fork/exec/wait instead... + */ + if (!error) { + char *cachedir = NULL; + char cmd[128]; + + cachedir = (char *) mf->mf_private; + plog(XLOG_INFO, "running fsck on cache directory \"%s\"", cachedir); + sprintf(cmd, "fsck -F cachefs %s", cachedir); + system(cmd); + } + + return error; +} diff --git a/contrib/amd/amd/ops_cdfs.c b/contrib/amd/amd/ops_cdfs.c new file mode 100644 index 0000000..3a143e2 --- /dev/null +++ b/contrib/amd/amd/ops_cdfs.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_cdfs.c,v 5.2.2.1 1992/02/09 15:09:08 jsp beta $ + * + */ + +/* + * High Sierra (CD-ROM) file system + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* forward declarations */ +static char *cdfs_match(am_opts *fo); +static int cdfs_fmount(mntfs *mf); +static int cdfs_fumount(mntfs *mf); + +/* + * Ops structure + */ +am_ops cdfs_ops = +{ + "cdfs", + cdfs_match, + 0, /* cdfs_init */ + amfs_auto_fmount, + cdfs_fmount, + amfs_auto_fumount, + cdfs_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* cdfs_readlink */ + 0, /* cdfs_mounted */ + 0, /* cdfs_umounted */ + find_amfs_auto_srvr, + FS_MKMNT | FS_UBACKGROUND | FS_AMQINFO +}; + + +/* + * CDFS needs remote filesystem. + */ +static char * +cdfs_match(am_opts *fo) +{ + if (!fo->opt_dev) { + plog(XLOG_USER, "cdfs: no source device specified"); + return 0; + } +#ifdef DEBUG + dlog("CDFS: mounting device \"%s\" on \"%s\"", + fo->opt_dev, fo->opt_fs); +#endif /* DEBUG */ + + /* + * Determine magic cookie to put in mtab + */ + return strdup(fo->opt_dev); +} + + +static int +mount_cdfs(char *dir, char *fs_name, char *opts) +{ + cdfs_args_t cdfs_args; + mntent_t mnt; + int genflags, cdfs_flags; + + /* + * Figure out the name of the file system type. + */ + MTYPE_TYPE type = MOUNT_TYPE_CDFS; + + memset((voidp) &cdfs_args, 0, sizeof(cdfs_args)); /* Paranoid */ + cdfs_flags = 0; + + /* + * Fill in the mount structure + */ + memset((voidp) &mnt, 0, sizeof(mnt)); + mnt.mnt_dir = dir; + mnt.mnt_fsname = fs_name; + mnt.mnt_type = MNTTAB_TYPE_CDFS; + mnt.mnt_opts = opts; + +#if defined(MNT2_CDFS_OPT_DEFPERM) && defined(MNTTAB_OPT_DEFPERM) + if (hasmntopt(&mnt, MNTTAB_OPT_DEFPERM)) +# ifdef MNT2_CDFS_OPT_DEFPERM + cdfs_flags |= MNT2_CDFS_OPT_DEFPERM; +# else /* not MNT2_CDFS_OPT_DEFPERM */ + cdfs_flags &= ~MNT2_CDFS_OPT_NODEFPERM; +# endif /* not MNT2_CDFS_OPT_DEFPERM */ +#endif /* defined(MNT2_CDFS_OPT_DEFPERM) && defined(MNTTAB_OPT_DEFPERM) */ + +#if defined(MNT2_CDFS_OPT_NODEFPERM) && defined(MNTTAB_OPT_NODEFPERM) + if (hasmntopt(&mnt, MNTTAB_OPT_NODEFPERM)) + cdfs_flags |= MNT2_CDFS_OPT_NODEFPERM; +#endif /* MNTTAB_OPT_NODEFPERM */ + +#if defined(MNT2_CDFS_OPT_NOVERSION) && defined(MNTTAB_OPT_NOVERSION) + if (hasmntopt(&mnt, MNTTAB_OPT_NOVERSION)) + cdfs_flags |= MNT2_CDFS_OPT_NOVERSION; +#endif /* defined(MNT2_CDFS_OPT_NOVERSION) && defined(MNTTAB_OPT_NOVERSION) */ + +#if defined(MNT2_CDFS_OPT_RRIP) && defined(MNTTAB_OPT_RRIP) + if (hasmntopt(&mnt, MNTTAB_OPT_RRIP)) + cdfs_flags |= MNT2_CDFS_OPT_RRIP; +#endif /* defined(MNT2_CDFS_OPT_RRIP) && defined(MNTTAB_OPT_RRIP) */ + + genflags = compute_mount_flags(&mnt); + +#ifdef HAVE_FIELD_CDFS_ARGS_T_FLAGS + cdfs_args.flags = cdfs_flags; +#endif /* HAVE_FIELD_CDFS_ARGS_T_FLAGS */ + +#ifdef HAVE_FIELD_CDFS_ARGS_T_ISO_FLAGS + cdfs_args.iso_flags = genflags | cdfs_flags; +#endif /* HAVE_FIELD_CDFS_ARGS_T_ISO_FLAGS */ + +#ifdef HAVE_FIELD_CDFS_ARGS_T_ISO_PGTHRESH + cdfs_args.iso_pgthresh = hasmntval(&mnt, MNTTAB_OPT_PGTHRESH); +#endif /* HAVE_FIELD_CDFS_ARGS_T_ISO_PGTHRESH */ + +#ifdef HAVE_FIELD_CDFS_ARGS_T_FSPEC + cdfs_args.fspec = fs_name; +#endif /* HAVE_FIELD_CDFS_ARGS_T_FSPEC */ + +#ifdef HAVE_FIELD_CDFS_ARGS_T_NORRIP + /* XXX: need to provide norrip mount opt */ + cdfs_args.norrip = 0; /* use Rock-Ridge Protocol extensions */ +#endif /* HAVE_FIELD_CDFS_ARGS_T_NORRIP */ + +#ifdef HAVE_FIELD_CDFS_ARGS_T_SSECTOR + /* XXX: need to provide ssector mount option */ + cdfs_args.ssector = 0; /* use 1st session on disk */ +#endif /* HAVE_FIELD_CDFS_ARGS_T_SSECTOR */ + + /* + * Call generic mount routine + */ + return mount_fs(&mnt, genflags, (caddr_t) &cdfs_args, 0, type, 0, NULL, mnttab_file_name); +} + + +static int +cdfs_fmount(mntfs *mf) +{ + int error; + + error = mount_cdfs(mf->mf_mount, mf->mf_info, mf->mf_mopts); + if (error) { + errno = error; + plog(XLOG_ERROR, "mount_cdfs: %m"); + return error; + } + return 0; +} + + +static int +cdfs_fumount(mntfs *mf) +{ + return UMOUNT_FS(mf->mf_mount, mnttab_file_name); +} diff --git a/contrib/amd/amd/ops_efs.c b/contrib/amd/amd/ops_efs.c new file mode 100644 index 0000000..4f915f7 --- /dev/null +++ b/contrib/amd/amd/ops_efs.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_efs.c,v 5.2.2.1 1992/02/09 15:09:08 jsp beta $ + * + */ + +/* + * Irix UN*X file system: EFS (Extent File System) + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* forward declarations */ +static char *efs_match(am_opts *fo); +static int efs_fmount(mntfs *mf); +static int efs_fumount(mntfs *mf); + +/* + * Ops structure + */ +am_ops efs_ops = +{ + "efs", + efs_match, + 0, /* efs_init */ + amfs_auto_fmount, + efs_fmount, + amfs_auto_fumount, + efs_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* efs_readlink */ + 0, /* efs_mounted */ + 0, /* efs_umounted */ + find_amfs_auto_srvr, + FS_MKMNT | FS_NOTIMEOUT | FS_UBACKGROUND | FS_AMQINFO +}; + + +/* + * EFS needs local filesystem and device. + */ +static char * +efs_match(am_opts *fo) +{ + + if (!fo->opt_dev) { + plog(XLOG_USER, "efs: no device specified"); + return 0; + } + +#ifdef DEBUG + dlog("EFS: mounting device \"%s\" on \"%s\"", fo->opt_dev, fo->opt_fs); +#endif /* DEBUG */ + + /* + * Determine magic cookie to put in mtab + */ + return strdup(fo->opt_dev); +} + + +static int +mount_efs(char *dir, char *fs_name, char *opts) +{ + efs_args_t efs_args; + mntent_t mnt; + int flags; + + /* + * Figure out the name of the file system type. + */ + MTYPE_TYPE type = MOUNT_TYPE_EFS; + + memset((voidp) &efs_args, 0, sizeof(efs_args)); /* Paranoid */ + + /* + * Fill in the mount structure + */ + memset((voidp) &mnt, 0, sizeof(mnt)); + mnt.mnt_dir = dir; + mnt.mnt_fsname = fs_name; + mnt.mnt_type = MNTTAB_TYPE_EFS; + mnt.mnt_opts = opts; + + flags = compute_mount_flags(&mnt); + +#ifdef HAVE_FIELD_EFS_ARGS_T_FLAGS + efs_args.flags = 0; /* XXX: fix this to correct flags */ +#endif /* HAVE_FIELD_EFS_ARGS_T_FLAGS */ +#ifdef HAVE_FIELD_EFS_ARGS_T_FSPEC + efs_args.fspec = fs_name; +#endif /* HAVE_FIELD_EFS_ARGS_T_FSPEC */ + + /* + * Call generic mount routine + */ + return mount_fs(&mnt, flags, (caddr_t) &efs_args, 0, type, 0, NULL, mnttab_file_name); +} + + +static int +efs_fmount(mntfs *mf) +{ + int error; + + error = mount_efs(mf->mf_mount, mf->mf_info, mf->mf_mopts); + if (error) { + errno = error; + plog(XLOG_ERROR, "mount_efs: %m"); + return error; + } + + return 0; +} + + +static int +efs_fumount(mntfs *mf) +{ + return UMOUNT_FS(mf->mf_mount, mnttab_file_name); +} diff --git a/contrib/amd/amd/ops_lofs.c b/contrib/amd/amd/ops_lofs.c new file mode 100644 index 0000000..6555db5 --- /dev/null +++ b/contrib/amd/amd/ops_lofs.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_lofs.c,v 5.2.2.1 1992/02/09 15:09:08 jsp beta $ + * + */ + +/* + * Loopback file system + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* forward definitions */ +static char * lofs_match(am_opts *fo); +static int lofs_fmount(mntfs *mf); +static int lofs_fumount(mntfs *mf); +static int mount_lofs(char *dir, char *fs_name, char *opts); + + +/* + * Ops structure + */ +am_ops lofs_ops = +{ + "lofs", + lofs_match, + 0, /* lofs_init */ + amfs_auto_fmount, + lofs_fmount, + amfs_auto_fumount, + lofs_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* lofs_readlink */ + 0, /* lofs_mounted */ + 0, /* lofs_umounted */ + find_amfs_auto_srvr, + FS_MKMNT | FS_NOTIMEOUT | FS_UBACKGROUND | FS_AMQINFO +}; + + +/* + * LOFS needs remote filesystem. + */ +static char * +lofs_match(am_opts *fo) +{ + if (!fo->opt_rfs) { + plog(XLOG_USER, "lofs: no source filesystem specified"); + return 0; + } +#ifdef DEBUG + dlog("LOFS: mounting fs \"%s\" on \"%s\"", + fo->opt_rfs, fo->opt_fs); +#endif /* DEBUG */ + + /* + * Determine magic cookie to put in mtab + */ + return strdup(fo->opt_rfs); +} + + +static int +mount_lofs(char *dir, char *fs_name, char *opts) +{ + mntent_t mnt; + int flags; + + /* + * Figure out the name of the file system type. + */ + MTYPE_TYPE type = MOUNT_TYPE_LOFS; + + /* + * Fill in the mount structure + */ + memset((voidp) &mnt, 0, sizeof(mnt)); + mnt.mnt_dir = dir; + mnt.mnt_fsname = fs_name; + mnt.mnt_type = MNTTAB_TYPE_LOFS; + mnt.mnt_opts = opts; + + flags = compute_mount_flags(&mnt); + + /* + * Call generic mount routine + */ + return mount_fs(&mnt, flags, NULL, 0, type, 0, NULL, mnttab_file_name); +} + + +static int +lofs_fmount(mntfs *mf) +{ + int error; + + error = mount_lofs(mf->mf_mount, mf->mf_info, mf->mf_mopts); + if (error) { + errno = error; + plog(XLOG_ERROR, "mount_lofs: %m"); + return error; + } + return 0; +} + + +static int +lofs_fumount(mntfs *mf) +{ + return UMOUNT_FS(mf->mf_mount, mnttab_file_name); +} diff --git a/contrib/amd/amd/ops_mfs.c b/contrib/amd/amd/ops_mfs.c new file mode 100644 index 0000000..f93c30b --- /dev/null +++ b/contrib/amd/amd/ops_mfs.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_mfs.c,v 5.2.2.3 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * Memory file system (RAM filesystem) + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* FEEL FREE TO INPLEMENT THIS... :-) */ diff --git a/contrib/amd/amd/ops_nfs.c b/contrib/amd/amd/ops_nfs.c new file mode 100644 index 0000000..a7006b4 --- /dev/null +++ b/contrib/amd/amd/ops_nfs.c @@ -0,0 +1,799 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_nfs.c,v 5.2.2.3 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * Network file system + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* + * Convert from nfsstat to UN*X error code + */ +#define unx_error(e) ((int)(e)) + +/* + * 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 */ +#define FHID_ALLOC(struct) (++fh_id) + +/* + * 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 */ + u_long fh_nfs_version; /* highest NFS version on host */ + am_nfs_handle_t fh_nfs_handle; /* Handle on filesystem */ + struct sockaddr_in fh_sin; /* Address of mountd */ + fserver *fh_fs; /* Server holding filesystem */ + char *fh_path; /* Filesystem on host */ +}; + +/* forward definitions */ +static int call_mountd(fh_cache *fp, u_long proc, fwd_fun f, voidp wchan); +static int fh_id = 0; + +/* globals */ +AUTH *nfs_auth; +qelem fh_head = {&fh_head, &fh_head}; + +/* + * Network file system operations + */ +am_ops nfs_ops = +{ + "nfs", + nfs_match, + nfs_init, + amfs_auto_fmount, + nfs_fmount, + amfs_auto_fumount, + nfs_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* nfs_readlink */ + 0, /* nfs_mounted */ + nfs_umounted, + find_nfs_srvr, + FS_MKMNT | FS_BACKGROUND | FS_AMQINFO +}; + + +static fh_cache * +find_nfs_fhandle_cache(voidp idv, int done) +{ + fh_cache *fp, *fp2 = 0; + int id = (long) idv; /* for 64-bit archs */ + + 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(voidp pkt, int len, struct sockaddr_in * sa, struct sockaddr_in * ia, voidp idv, int done) +{ + fh_cache *fp; + + fp = find_nfs_fhandle_cache(idv, done); + if (!fp) + return; + + /* + * retrieve the correct RPC reply for the file handle, based on the + * NFS protocol version. + */ +#ifdef HAVE_FS_NFS3 + if (fp->fh_nfs_version == NFS_VERSION3) + fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &fp->fh_nfs_handle.v3, + (XDRPROC_T_TYPE) xdr_mountres3); + else +#endif /* HAVE_FS_NFS3 */ + fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &fp->fh_nfs_handle.v2, + (XDRPROC_T_TYPE) 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(fserver *fs) +{ + fh_cache *fp; + + ITER(fp, fh_cache, &fh_head) { + if (fp->fh_fs == fs || fs == 0) { + fp->fh_sin.sin_port = (u_short) 0; + fp->fh_error = -1; + } + } +} + + +static void +discard_fh(voidp v) +{ + fh_cache *fp = v; + + rem_que(&fp->fh_q); + if (fp->fh_fs) { +#ifdef DEBUG + dlog("Discarding filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path); +#endif /* DEBUG */ + free_srvr(fp->fh_fs); + } + if (fp->fh_path) + XFREE(fp->fh_path); + XFREE(fp); +} + + +/* + * Determine the file handle for a node + */ +static int +prime_nfs_fhandle_cache(char *path, fserver *fs, am_nfs_handle_t *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 && STREQ(path, fp->fh_path)) { + switch (fp->fh_error) { + case 0: + plog(XLOG_INFO, "prime_nfs_fhandle_cache: NFS version %d", fp->fh_nfs_version); +#ifdef HAVE_FS_NFS3 + if (fp->fh_nfs_version == NFS_VERSION3) + error = fp->fh_error = unx_error(fp->fh_nfs_handle.v3.fhs_status); + else +#endif /* HAVE_FS_NFS3 */ + error = fp->fh_error = unx_error(fp->fh_nfs_handle.v2.fhs_status); + if (error == 0) { + if (fhbuf) { +#ifdef HAVE_FS_NFS3 + if (fp->fh_nfs_version == NFS_VERSION3) + memmove((voidp) &(fhbuf->v3), (voidp) &(fp->fh_nfs_handle.v3), + sizeof(fp->fh_nfs_handle.v3)); + else +#endif /* HAVE_FS_NFS3 */ + memmove((voidp) &(fhbuf->v2), (voidp) &(fp->fh_nfs_handle.v2), + sizeof(fp->fh_nfs_handle.v2)); + } + if (fp->fh_cid) + untimeout(fp->fh_cid); + fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp); + } else if (error == EACCES) { + /* + * Now decode the file handle return code. + */ + plog(XLOG_INFO, "Filehandle denied for \"%s:%s\"", + fs->fs_host, path); + } else { + errno = error; /* XXX */ + plog(XLOG_INFO, "Filehandle error for \"%s:%s\": %m", + fs->fs_host, path); + } + + /* + * 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); + XFREE(fp->fh_path); + } else { + fp = ALLOC(struct fh_cache); + memset((voidp) fp, 0, sizeof(struct fh_cache)); + ins_que(&fp->fh_q, &fh_head); + } + if (!reuse_id) + fp->fh_id = FHID_ALLOC(struct ); + fp->fh_wchan = wchan; + fp->fh_error = -1; + fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp); + + /* + * if fs->fs_ip is null, remote server is probably down. + */ + if (!fs->fs_ip) { + /* Mark the fileserver down and invalid again */ + fs->fs_flags &= ~FSF_VALID; + fs->fs_flags |= FSF_DOWN; + error = AM_ERRNO_HOST_DOWN; + return error; + } + + /* + * 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_nfs_version = fs->fs_version; + } + fp->fh_fs = dup_srvr(fs); + fp->fh_path = strdup(path); + + error = call_mountd(fp, MOUNTPROC_MNT, got_nfs_fh, wchan); + if (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; +} + + +int +make_nfs_auth(void) +{ + AUTH_CREATE_GIDLIST_TYPE group_wheel = 0; + + /* Some NFS mounts (particularly cross-domain) require FQDNs to succeed */ + +#ifdef HAVE_TRANSPORT_TYPE_TLI + if (gopt.flags & CFM_FULLY_QUALIFIED_HOSTS) { + plog(XLOG_INFO, "Using NFS auth for fqhn \"%s\"", hostd); + nfs_auth = authsys_create(hostd, 0, 0, 1, &group_wheel); + } else { + nfs_auth = authsys_create_default(); + } +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + if (gopt.flags & CFM_FULLY_QUALIFIED_HOSTS) { + plog(XLOG_INFO, "Using NFS auth for fqhn \"%s\"", hostd); + nfs_auth = authunix_create(hostd, 0, 0, 1, &group_wheel); + } else { + nfs_auth = authunix_create_default(); + } +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + if (!nfs_auth) + return ENOBUFS; + + return 0; +} + + +static int +call_mountd(fh_cache *fp, u_long proc, fwd_fun f, voidp wchan) +{ + struct rpc_msg mnt_msg; + int len; + char iobuf[8192]; + int error; + u_long mnt_version; + + if (!nfs_auth) { + error = make_nfs_auth(); + if (error) + return error; + } + + 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; + } + + /* find the right version of the mount protocol */ +#ifdef HAVE_FS_NFS3 + if (fp->fh_nfs_version == NFS_VERSION3) + mnt_version = MOUNTVERS3; + else +#endif /* HAVE_FS_NFS3 */ + mnt_version = MOUNTVERS; + plog(XLOG_INFO, "call_mountd: NFS version %d, mount version %d", + fp->fh_nfs_version, mnt_version); + + rpc_msg_init(&mnt_msg, MOUNTPROG, mnt_version, MOUNTPROC_NULL); + len = make_rpc_packet(iobuf, + sizeof(iobuf), + proc, + &mnt_msg, + (voidp) &fp->fh_path, + (XDRPROC_T_TYPE) 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) ((long) fp->fh_id), /* for 64-bit archs */ + f); + } else { + error = -len; + } + +/* + * It may be the case that we're sending to the wrong MOUNTD port. This + * occurs if mountd is restarted on the server after the port has been + * looked up and stored in the filehandle cache somewhere. The correct + * solution, if we're going to cache port numbers is to catch the ICMP + * port unreachable reply from the server and cause the portmap request + * to be redone. The quick solution here is to invalidate the MOUNTD + * port. + */ + fp->fh_sin.sin_port = 0; + + return error; +} + + +/* + * NFS needs the local filesystem, remote filesystem + * remote hostname. + * Local filesystem defaults to remote and vice-versa. + */ +char * +nfs_match(am_opts *fo) +{ + char *xmtab; + + 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 NULL; + } + if (!fo->opt_rhost) { + plog(XLOG_USER, "nfs: no remote host specified"); + return NULL; + } + + /* + * Determine magic cookie to put in mtab + */ + xmtab = (char *) xmalloc(strlen(fo->opt_rhost) + strlen(fo->opt_rfs) + 2); + sprintf(xmtab, "%s:%s", fo->opt_rhost, fo->opt_rfs); +#ifdef DEBUG + dlog("NFS: mounting remote server \"%s\", remote fs \"%s\" on \"%s\"", + fo->opt_rhost, fo->opt_rfs, fo->opt_fs); +#endif /* DEBUG */ + + return xmtab; +} + + +/* + * Initialize am structure for nfs + */ +int +nfs_init(mntfs *mf) +{ + int error; + am_nfs_handle_t fhs; + char *colon; + + if (mf->mf_private) + return 0; + + colon = strchr(mf->mf_info, ':'); + if (colon == 0) + return ENOENT; + + error = prime_nfs_fhandle_cache(colon + 1, mf->mf_server, &fhs, (voidp) mf); + if (!error) { + mf->mf_private = (voidp) ALLOC(am_nfs_handle_t); + mf->mf_prfree = (void (*)(voidp)) free; + memmove(mf->mf_private, (voidp) &fhs, sizeof(fhs)); + } + return error; +} + + +int +mount_nfs_fh(am_nfs_handle_t *fhp, char *dir, char *fs_name, char *opts, mntfs *mf) +{ + MTYPE_TYPE type; + char *colon; + char *xopts; + char host[MAXHOSTNAMELEN + MAXPATHLEN + 2]; + fserver *fs = mf->mf_server; + u_long nfs_version = fs->fs_version; + char *nfs_proto = fs->fs_proto; /* "tcp" or "udp" */ + int error; + int genflags; + int retry; + mntent_t mnt; + nfs_args_t nfs_args; + + /* + * Extract HOST name to give to kernel. + * Some systems like osf1/aix3/bsd44 variants may need old code + * for NFS_ARGS_NEEDS_PATH. + */ + if (!(colon = strchr(fs_name, ':'))) + return ENOENT; +#ifdef MOUNT_TABLE_ON_FILE + *colon = '\0'; +#endif /* MOUNT_TABLE_ON_FILE */ + strncpy(host, fs_name, sizeof(host)); +#ifdef MOUNT_TABLE_ON_FILE + *colon = ':'; +#endif /* MOUNT_TABLE_ON_FILE */ +#ifdef MAXHOSTNAMELEN + /* most kernels have a name length restriction */ + if (strlen(host) >= MAXHOSTNAMELEN) + strcpy(host + MAXHOSTNAMELEN - 3, ".."); +#endif /* MAXHOSTNAMELEN */ + + if (mf->mf_remopts && *mf->mf_remopts && !islocalnet(fs->fs_ip->sin_addr.s_addr)) + xopts = strdup(mf->mf_remopts); + else + xopts = strdup(opts); + + memset((voidp) &mnt, 0, sizeof(mnt)); + mnt.mnt_dir = dir; + mnt.mnt_fsname = fs_name; + mnt.mnt_opts = xopts; + + /* + * Set mount types accordingly + */ +#ifndef HAVE_FS_NFS3 + type = MOUNT_TYPE_NFS; + mnt.mnt_type = MNTTAB_TYPE_NFS; +#else /* HAVE_FS_NFS3 */ + if (nfs_version == NFS_VERSION3) { + type = MOUNT_TYPE_NFS3; + /* + * Systems that include the mount table "vers" option generally do not + * set the mnttab entry to "nfs3", but to "nfs" and then they set + * "vers=3". Setting it to "nfs3" works, but it may break some things + * like "df -t nfs" and the "quota" program (esp. on Solaris and Irix). + * So on those systems, set it to "nfs". + * Note: MNTTAB_OPT_VERS is always set for NFS3 (see am_compat.h). + */ +# if defined(MNTTAB_OPT_VERS) && defined(MOUNT_TABLE_ON_FILE) + mnt.mnt_type = MNTTAB_TYPE_NFS; +# else /* defined(MNTTAB_OPT_VERS) && defined(MOUNT_TABLE_ON_FILE) */ + mnt.mnt_type = MNTTAB_TYPE_NFS3; +# endif /* defined(MNTTAB_OPT_VERS) && defined(MOUNT_TABLE_ON_FILE) */ + } else { + type = MOUNT_TYPE_NFS; + mnt.mnt_type = MNTTAB_TYPE_NFS; + } +#endif /* HAVE_FS_NFS3 */ + plog(XLOG_INFO, "mount_nfs_fh: NFS version %d", nfs_version); +#if defined(HAVE_FS_NFS3) || defined(HAVE_TRANSPORT_TYPE_TLI) + plog(XLOG_INFO, "mount_nfs_fh: using NFS transport %s", nfs_proto); +#endif /* defined(HAVE_FS_NFS3) || defined(HAVE_TRANSPORT_TYPE_TLI) */ + + retry = hasmntval(&mnt, MNTTAB_OPT_RETRY); + if (retry <= 0) + retry = 1; /* XXX */ + + genflags = compute_mount_flags(&mnt); + + /* setup the many fields and flags within nfs_args */ +#ifdef HAVE_TRANSPORT_TYPE_TLI + compute_nfs_args(&nfs_args, + &mnt, + genflags, + NULL, /* struct netconfig *nfsncp */ + fs->fs_ip, + nfs_version, + nfs_proto, + fhp, + host, + fs_name); +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + compute_nfs_args(&nfs_args, + &mnt, + genflags, + fs->fs_ip, + nfs_version, + nfs_proto, + fhp, + host, + fs_name); +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + /* finally call the mounting function */ +#ifdef DEBUG + amuDebug(D_TRACE) + print_nfs_args(&nfs_args, nfs_version); +#endif /* DEBUG */ + error = mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, + nfs_version, nfs_proto, mnttab_file_name); + XFREE(xopts); + +#ifdef HAVE_TRANSPORT_TYPE_TLI + free_knetconfig(nfs_args.knconf); + if (nfs_args.addr) + XFREE(nfs_args.addr); /* allocated in compute_nfs_args() */ +#endif /* HAVE_TRANSPORT_TYPE_TLI */ + + return error; +} + + +static int +mount_nfs(char *dir, char *fs_name, char *opts, mntfs *mf) +{ + if (!mf->mf_private) { + plog(XLOG_ERROR, "Missing filehandle for %s", fs_name); + return EINVAL; + } + + return mount_nfs_fh((am_nfs_handle_t *) mf->mf_private, dir, fs_name, opts, mf); +} + + +int +nfs_fmount(mntfs *mf) +{ + int error = 0; + + error = mount_nfs(mf->mf_mount, mf->mf_info, mf->mf_mopts, mf); + +#ifdef DEBUG + if (error) { + errno = error; + dlog("mount_nfs: %m"); + } +#endif /* DEBUG */ + + return error; +} + + +int +nfs_fumount(mntfs *mf) +{ + int error = UMOUNT_FS(mf->mf_mount, mnttab_file_name); + + /* + * Here is some code to unmount 'restarted' file systems. + * The restarted file systems are marked as 'nfs', not + * 'host', so we only have the map information for the + * the top-level mount. The unmount will fail (EBUSY) + * if there are anything else from the NFS server mounted + * below the mount-point. This code checks to see if there + * is anything mounted with the same prefix as the + * file system to be unmounted ("/a/b/c" when unmounting "/a/b"). + * If there is, and it is a 'restarted' file system, we unmount + * it. + * Added by Mike Mitchell, mcm@unx.sas.com, 09/08/93 + */ + if (error == EBUSY) { + mntfs *new_mf; + int len = strlen(mf->mf_mount); + int didsome = 0; + + ITER(new_mf, mntfs, &mfhead) { + if (new_mf->mf_ops != mf->mf_ops || + new_mf->mf_refc > 1 || + mf == new_mf || + ((new_mf->mf_flags & (MFF_MOUNTED | MFF_UNMOUNTING | MFF_RESTART)) == (MFF_MOUNTED | MFF_RESTART))) + continue; + + if (NSTREQ(mf->mf_mount, new_mf->mf_mount, len) && + new_mf->mf_mount[len] == '/') { + UMOUNT_FS(new_mf->mf_mount, mnttab_file_name); + didsome = 1; + } + } + if (didsome) + error = UMOUNT_FS(mf->mf_mount, mnttab_file_name); + } + if (error) + return error; + + return 0; +} + + +void +nfs_umounted(am_node *mp) +{ + /* + * 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_nfs_version = fs->fs_version; + f.fh_fs = fs; + f.fh_id = 0; + f.fh_error = 0; + prime_nfs_fhandle_cache(colon + 1, mf->mf_server, (am_nfs_handle_t *) 0, (voidp) mf); + call_mountd(&f, MOUNTPROC_UMNT, (fwd_fun) 0, (voidp) 0); + *colon = ':'; + } +} diff --git a/contrib/amd/amd/ops_nfs3.c b/contrib/amd/amd/ops_nfs3.c new file mode 100644 index 0000000..5db0713 --- /dev/null +++ b/contrib/amd/amd/ops_nfs3.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_nfs3.c,v 5.2.2.3 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * Network file system version 3.0 + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* FEEL FREE TO INPLEMENT THIS... :-) */ diff --git a/contrib/amd/amd/ops_nullfs.c b/contrib/amd/amd/ops_nullfs.c new file mode 100644 index 0000000..bf2009f --- /dev/null +++ b/contrib/amd/amd/ops_nullfs.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_nullfs.c,v 5.2.2.3 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * The null filesystem in BSD-4.4 is similar to the loopback one. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* FEEL FREE TO INPLEMENT THIS... :-) */ diff --git a/contrib/amd/amd/ops_pcfs.c b/contrib/amd/amd/ops_pcfs.c new file mode 100644 index 0000000..e46b711 --- /dev/null +++ b/contrib/amd/amd/ops_pcfs.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_pcfs.c,v 5.2.2.1 1992/02/09 15:09:08 jsp beta $ + * + */ + +/* + * PC (MS-DOS) file system + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* forward definitions */ +static char *pcfs_match(am_opts *fo); +static int pcfs_fmount(mntfs *mf); +static int pcfs_fumount(mntfs *mf); + +/* + * Ops structure + */ +am_ops pcfs_ops = +{ + "pcfs", + pcfs_match, + 0, /* pcfs_init */ + amfs_auto_fmount, + pcfs_fmount, + amfs_auto_fumount, + pcfs_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* pcfs_readlink */ + 0, /* pcfs_mounted */ + 0, /* pcfs_umounted */ + find_amfs_auto_srvr, + FS_MKMNT | FS_UBACKGROUND | FS_AMQINFO +}; + + + +/* + * PCFS needs remote filesystem. + */ +static char * +pcfs_match(am_opts *fo) +{ + if (!fo->opt_dev) { + plog(XLOG_USER, "pcfs: no source device specified"); + return 0; + } +#ifdef DEBUG + dlog("PCFS: mounting device \"%s\" on \"%s\"", fo->opt_dev, fo->opt_fs); +#endif /* DEBUG */ + + /* + * Determine magic cookie to put in mtab + */ + return strdup(fo->opt_dev); +} + + +static int +mount_pcfs(char *dir, char *fs_name, char *opts) +{ + pcfs_args_t pcfs_args; + mntent_t mnt; + int flags; + + /* + * Figure out the name of the file system type. + */ + MTYPE_TYPE type = MOUNT_TYPE_PCFS; + + memset((voidp) &pcfs_args, 0, sizeof(pcfs_args)); /* Paranoid */ + + /* + * Fill in the mount structure + */ + memset((voidp) &mnt, 0, sizeof(mnt)); + mnt.mnt_dir = dir; + mnt.mnt_fsname = fs_name; + mnt.mnt_type = MNTTAB_TYPE_PCFS; + mnt.mnt_opts = opts; + + flags = compute_mount_flags(&mnt); + +#ifdef HAVE_FIELD_PCFS_ARGS_T_FSPEC + pcfs_args.fspec = fs_name; +#endif /* HAVE_FIELD_PCFS_ARGS_T_FSPEC */ + +#ifdef HAVE_FIELD_PCFS_ARGS_T_MASK + pcfs_args.mask = 0777; /* this may be the msdos file modes */ +#endif /* HAVE_FIELD_PCFS_ARGS_T_MASK */ + +#ifdef HAVE_FIELD_PCFS_ARGS_T_UID + pcfs_args.uid = 0; /* root */ +#endif /* HAVE_FIELD_PCFS_ARGS_T_UID */ + +#ifdef HAVE_FIELD_PCFS_ARGS_T_GID + pcfs_args.gid = 0; /* wheel */ +#endif /* HAVE_FIELD_PCFS_ARGS_T_GID */ + +#ifdef HAVE_FIELD_PCFS_ARGS_T_SECONDSWEST + pcfs_args.secondswest = 0; /* XXX: fill in correct values */ +#endif /* HAVE_FIELD_PCFS_ARGS_T_SECONDSWEST */ +#ifdef HAVE_FIELD_PCFS_ARGS_T_DSTTIME + pcfs_args.dsttime = 0; /* XXX: fill in correct values */ +#endif /* HAVE_FIELD_PCFS_ARGS_T_DSTTIME */ + + /* + * Call generic mount routine + */ + return mount_fs(&mnt, flags, (caddr_t) & pcfs_args, 0, type, 0, NULL, mnttab_file_name); +} + + +static int +pcfs_fmount(mntfs *mf) +{ + int error; + + error = mount_pcfs(mf->mf_mount, mf->mf_info, mf->mf_mopts); + if (error) { + errno = error; + plog(XLOG_ERROR, "mount_pcfs: %m"); + return error; + } + + return 0; +} + + +static int +pcfs_fumount(mntfs *mf) +{ + return UMOUNT_FS(mf->mf_mount, mnttab_file_name); +} diff --git a/contrib/amd/amd/ops_tfs.c b/contrib/amd/amd/ops_tfs.c new file mode 100644 index 0000000..97cd18c --- /dev/null +++ b/contrib/amd/amd/ops_tfs.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_tfs.c,v 5.2.2.3 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * Translucent file system + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* FEEL FREE TO INPLEMENT THIS... :-) */ diff --git a/contrib/amd/amd/ops_tmpfs.c b/contrib/amd/amd/ops_tmpfs.c new file mode 100644 index 0000000..ce1b4fd --- /dev/null +++ b/contrib/amd/amd/ops_tmpfs.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_tmpfs.c,v 5.2.2.3 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * TMPFS file system (combines RAM-fs and swap-fs) + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* FEEL FREE TO INPLEMENT THIS... :-) */ diff --git a/contrib/amd/amd/ops_ufs.c b/contrib/amd/amd/ops_ufs.c new file mode 100644 index 0000000..9883af1 --- /dev/null +++ b/contrib/amd/amd/ops_ufs.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_ufs.c,v 5.2.2.1 1992/02/09 15:09:08 jsp beta $ + * + */ + +/* + * UN*X file system + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* forward declarations */ +static char *ufs_match(am_opts *fo); +static int ufs_fmount(mntfs *mf); +static int ufs_fumount(mntfs *mf); + +/* + * Ops structure + */ +am_ops ufs_ops = +{ + "ufs", + ufs_match, + 0, /* ufs_init */ + amfs_auto_fmount, + ufs_fmount, + amfs_auto_fumount, + ufs_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* ufs_readlink */ + 0, /* ufs_mounted */ + 0, /* ufs_umounted */ + find_amfs_auto_srvr, + FS_MKMNT | FS_NOTIMEOUT | FS_UBACKGROUND | FS_AMQINFO +}; + + +/* + * UFS needs local filesystem and device. + */ +static char * +ufs_match(am_opts *fo) +{ + + if (!fo->opt_dev) { + plog(XLOG_USER, "ufs: no device specified"); + return 0; + } + +#ifdef DEBUG + dlog("UFS: mounting device \"%s\" on \"%s\"", fo->opt_dev, fo->opt_fs); +#endif /* DEBUG */ + + /* + * Determine magic cookie to put in mtab + */ + return strdup(fo->opt_dev); +} + + +static int +mount_ufs(char *dir, char *fs_name, char *opts) +{ + ufs_args_t ufs_args; + mntent_t mnt; + int genflags; + + /* + * Figure out the name of the file system type. + */ + MTYPE_TYPE type = MOUNT_TYPE_UFS; + + memset((voidp) &ufs_args, 0, sizeof(ufs_args)); /* Paranoid */ + + /* + * Fill in the mount structure + */ + memset((voidp) &mnt, 0, sizeof(mnt)); + mnt.mnt_dir = dir; + mnt.mnt_fsname = fs_name; + mnt.mnt_type = MNTTAB_TYPE_UFS; + mnt.mnt_opts = opts; + + genflags = compute_mount_flags(&mnt); + +#ifdef HAVE_FIELD_UFS_ARGS_T_FLAGS + ufs_args.flags = genflags; /* XXX: is this correct? */ +#endif /* HAVE_FIELD_UFS_ARGS_T_FLAGS */ + +#ifdef HAVE_FIELD_UFS_ARGS_T_UFS_FLAGS + ufs_args.ufs_flags = genflags; /* XXX: is this correct? */ +#endif /* HAVE_FIELD_UFS_ARGS_T_UFS_FLAGS */ + +#ifdef HAVE_FIELD_UFS_ARGS_T_FSPEC + ufs_args.fspec = fs_name; +#endif /* HAVE_FIELD_UFS_ARGS_T_FSPEC */ + +#ifdef HAVE_FIELD_UFS_ARGS_T_UFS_PGTHRESH + ufs_args.ufs_pgthresh = hasmntval(&mnt, MNTTAB_OPT_PGTHRESH); +#endif /* HAVE_FIELD_UFS_ARGS_T_UFS_PGTHRESH */ + + /* + * Call generic mount routine + */ + return mount_fs(&mnt, genflags, (caddr_t) &ufs_args, 0, type, 0, NULL, mnttab_file_name); +} + + +static int +ufs_fmount(mntfs *mf) +{ + int error; + + error = mount_ufs(mf->mf_mount, mf->mf_info, mf->mf_mopts); + if (error) { + errno = error; + plog(XLOG_ERROR, "mount_ufs: %m"); + return error; + } + + return 0; +} + + +static int +ufs_fumount(mntfs *mf) +{ + return UMOUNT_FS(mf->mf_mount, mnttab_file_name); +} diff --git a/contrib/amd/amd/ops_umapfs.c b/contrib/amd/amd/ops_umapfs.c new file mode 100644 index 0000000..b2dcd72 --- /dev/null +++ b/contrib/amd/amd/ops_umapfs.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_umapfs.c,v 5.2.2.3 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * uid/gid mapping filesystem. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* FEEL FREE TO INPLEMENT THIS... :-) */ diff --git a/contrib/amd/amd/ops_unionfs.c b/contrib/amd/amd/ops_unionfs.c new file mode 100644 index 0000000..24f7e1f --- /dev/null +++ b/contrib/amd/amd/ops_unionfs.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_unionfs.c,v 5.2.2.3 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * Union filesystem (ala BSD-4.4) + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* FEEL FREE TO INPLEMENT THIS... :-) */ diff --git a/contrib/amd/amd/ops_xfs.c b/contrib/amd/amd/ops_xfs.c new file mode 100644 index 0000000..1b4aab4 --- /dev/null +++ b/contrib/amd/amd/ops_xfs.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_xfs.c,v 5.2.2.1 1992/02/09 15:09:08 jsp beta $ + * + */ + +/* + * Irix UN*X file system: XFS (Extended File System) + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* forward declarations */ +static char * xfs_match(am_opts *fo); +static int xfs_fmount(mntfs *mf); +static int xfs_fumount(mntfs *mf); + +/* + * Ops structure + */ +am_ops xfs_ops = +{ + "xfs", + xfs_match, + 0, /* xfs_init */ + amfs_auto_fmount, + xfs_fmount, + amfs_auto_fumount, + xfs_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* xfs_readlink */ + 0, /* xfs_mounted */ + 0, /* xfs_umounted */ + find_amfs_auto_srvr, + FS_MKMNT | FS_NOTIMEOUT | FS_UBACKGROUND | FS_AMQINFO +}; + + +/* + * XFS needs local filesystem and device. + */ +static char * +xfs_match(am_opts *fo) +{ + + if (!fo->opt_dev) { + plog(XLOG_USER, "xfs: no device specified"); + return 0; + } + +#ifdef DEBUG + dlog("XFS: mounting device \"%s\" on \"%s\"", fo->opt_dev, fo->opt_fs); +#endif /* DEBUG */ + + /* + * Determine magic cookie to put in mtab + */ + return strdup(fo->opt_dev); +} + + +static int +mount_xfs(char *dir, char *fs_name, char *opts) +{ + xfs_args_t xfs_args; + mntent_t mnt; + int flags; + + /* + * Figure out the name of the file system type. + */ + MTYPE_TYPE type = MOUNT_TYPE_XFS; + + memset((voidp) &xfs_args, 0, sizeof(xfs_args)); /* Paranoid */ + + /* + * Fill in the mount structure + */ + memset((voidp) &mnt, 0, sizeof(mnt)); + mnt.mnt_dir = dir; + mnt.mnt_fsname = fs_name; + mnt.mnt_type = MNTTAB_TYPE_XFS; + mnt.mnt_opts = opts; + + flags = compute_mount_flags(&mnt); + +#ifdef HAVE_FIELD_XFS_ARGS_T_FLAGS + xfs_args.flags = 0; /* XXX: fix this to correct flags */ +#endif /* HAVE_FIELD_XFS_ARGS_T_FLAGS */ +#ifdef HAVE_FIELD_XFS_ARGS_T_FSPEC + xfs_args.fspec = fs_name; +#endif /* HAVE_FIELD_XFS_ARGS_T_FSPEC */ + + /* + * Call generic mount routine + */ + return mount_fs(&mnt, flags, (caddr_t) &xfs_args, 0, type, 0, NULL, mnttab_file_name); +} + + +static int +xfs_fmount(mntfs *mf) +{ + int error; + + error = mount_xfs(mf->mf_mount, mf->mf_info, mf->mf_mopts); + if (error) { + errno = error; + plog(XLOG_ERROR, "mount_xfs: %m"); + return error; + } + + return 0; +} + + +static int +xfs_fumount(mntfs *mf) +{ + return UMOUNT_FS(mf->mf_mount, mnttab_file_name); +} diff --git a/contrib/amd/amd/opts.c b/contrib/amd/amd/opts.c new file mode 100644 index 0000000..294cdb7 --- /dev/null +++ b/contrib/amd/amd/opts.c @@ -0,0 +1,1304 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: opts.c,v 5.2.2.4 1992/08/02 10:42:21 jsp Exp $ + * + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* + * MACROS: + */ +#define NLEN 16 /* Length of longest option name (conservative) */ +#define S(x) (x) , (sizeof(x)-1) +/* + * 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) + +/* + * TYPEDEFS: + */ +typedef int (*IntFuncPtr) (char *); +typedef struct opt_apply opt_apply; +enum vs_opt { SelEQ, SelNE, VarAss }; + +/* + * STRUCTURES + */ +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 */ + int (*fxn_p)(char *); /* Pointer to boolean function */ + int case_insensitive; /* How to do selector comparisons */ +}; + +struct opt_apply { + char **opt; + char *val; +}; + +struct functable { + char *name; + IntFuncPtr func; +}; + +/* + * FORWARD DEFINITSION: + */ +static int f_in_network(char *); +static int f_netgrp(char *); +static int f_exists(char *); +static int f_false(char *); +static int f_true(char *); + +/* + * STATICS: + */ +static struct am_opts fs_static; /* copy of the options to play with */ +static char NullStr[] = "<NULL>"; +static char nullstr[] = ""; +static char *opt_dkey = NullStr; +static char *opt_host = hostname; +static char *opt_hostd = hostd; +static char *opt_key = nullstr; +static char *opt_keyd = nullstr; +static char *opt_map = nullstr; +static char *opt_path = nullstr; +static char *vars[8]; + + +/* + * Options in something corresponding to frequency of use so that + * first-match algorithm is sped up. + */ +static struct opt opt_fields[] = { + /* Name and length. + Option str. Selector str. boolean fxn. flags */ + { S("opts"), + &fs_static.opt_opts, 0, 0, FALSE }, + { S("host"), + 0, &opt_host, 0, TRUE }, + { S("hostd"), + 0, &opt_hostd, 0, TRUE }, + { S("type"), + &fs_static.opt_type, 0, 0, FALSE }, + { S("rhost"), + &fs_static.opt_rhost, 0, 0, TRUE }, + { S("rfs"), + &fs_static.opt_rfs, 0, 0, FALSE }, + { S("fs"), + &fs_static.opt_fs, 0, 0, FALSE }, + { S("key"), + 0, &opt_key, 0, FALSE }, + { S("map"), + 0, &opt_map, 0, FALSE }, + { S("sublink"), + &fs_static.opt_sublink, 0, 0, FALSE }, + { S("arch"), + 0, &gopt.arch, 0, TRUE }, + { S("dev"), + &fs_static.opt_dev, 0, 0, FALSE }, + { S("pref"), + &fs_static.opt_pref, 0, 0, FALSE }, + { S("autopref"), + &fs_static.opt_autopref,0, 0, FALSE }, + { S("path"), + 0, &opt_path, 0, FALSE }, + { S("autodir"), + 0, &gopt.auto_dir, 0, FALSE }, + { S("delay"), + &fs_static.opt_delay, 0, 0, FALSE }, + { S("domain"), + 0, &hostdomain, 0, TRUE }, + { S("karch"), + 0, &gopt.karch, 0, TRUE }, + { S("cluster"), + 0, &gopt.cluster, 0, TRUE }, + { S("wire"), + 0, 0, f_in_network, TRUE }, + { S("network"), + 0, 0, f_in_network, TRUE }, + { S("netnumber"), + 0, 0, f_in_network, TRUE }, + { S("byte"), + 0, &endian, 0, TRUE }, + { S("os"), + 0, &gopt.op_sys, 0, TRUE }, + { S("osver"), + 0, &gopt.op_sys_ver, 0, TRUE }, + { S("remopts"), + &fs_static.opt_remopts, 0, 0, FALSE }, + { S("mount"), + &fs_static.opt_mount, 0, 0, FALSE }, + { S("unmount"), + &fs_static.opt_unmount, 0, 0, FALSE }, + { S("cache"), + &fs_static.opt_cache, 0, 0, FALSE }, + { S("user"), + &fs_static.opt_user, 0, 0, FALSE }, + { S("group"), + &fs_static.opt_group, 0, 0, FALSE }, + { S(".key"), + 0, &opt_dkey, 0, FALSE }, + { S("key."), + 0, &opt_keyd, 0, FALSE }, + { S("maptype"), + &fs_static.opt_maptype, 0, 0, FALSE }, + { S("cachedir"), + &fs_static.opt_cachedir, 0, 0, FALSE }, + { S("addopts"), + &fs_static.opt_addopts, 0, 0, FALSE }, + { S("var0"), + &vars[0], 0, 0, FALSE }, + { S("var1"), + &vars[1], 0, 0, FALSE }, + { S("var2"), + &vars[2], 0, 0, FALSE }, + { S("var3"), + &vars[3], 0, 0, FALSE }, + { S("var4"), + &vars[4], 0, 0, FALSE }, + { S("var5"), + &vars[5], 0, 0, FALSE }, + { S("var6"), + &vars[6], 0, 0, FALSE }, + { S("var7"), + &vars[7], 0, 0, FALSE }, + { 0, 0, 0, 0, 0, FALSE }, +}; + +static struct functable functable[] = { + { "in_network", f_in_network }, + { "netgrp", f_netgrp }, + { "exists", f_exists }, + { "false", f_false }, + { "true", f_true }, + { 0, 0 }, +}; + +/* + * 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 the order here _may_ be important. + */ +static opt_apply expansions[] = +{ + {&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_remopts, "${opts}"}, + {&fs_static.opt_mount, 0}, + {&fs_static.opt_unmount, 0}, + {&fs_static.opt_cachedir, 0}, + {&fs_static.opt_addopts, 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_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_remopts, 0}, + {&fs_static.opt_mount, 0}, + {&fs_static.opt_unmount, 0}, + {&fs_static.opt_cachedir, 0}, + {&fs_static.opt_addopts, 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}, +}; + + +/* + * expand backslash escape sequences + */ +static char +backslash(char **p) +{ + char c; + + if ((*p)[1] == '\0') { + plog(XLOG_USER, "Empty backslash escape"); + return **p; + } + + if (**p == '\\') { + (*p)++; + switch (**p) { + case 'a': + c = '\007'; /* Bell */ + break; + case 'b': + c = '\010'; /* Backspace */ + break; + case 't': + c = '\011'; /* Horizontal Tab */ + break; + case 'n': + c = '\012'; /* New Line */ + break; + case 'v': + c = '\013'; /* Vertical Tab */ + break; + case 'f': + c = '\014'; /* Form Feed */ + break; + case 'r': + c = '\015'; /* Carriage Return */ + break; + case 'e': + c = '\033'; /* Escape */ + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + int cnt, val, ch; + + for (cnt = 0, val = 0; cnt < 3; cnt++) { + ch = *(*p)++; + if (ch < '0' || ch > '7') { + (*p)--; + break; + } + val = (val << 3) | (ch - '0'); + } + + if ((val & 0xffffff00) != 0) + plog(XLOG_USER, + "Too large character constant %u\n", + val); + c = (char) val; + --(*p); + } + break; + + default: + c = **p; + break; + } + } else + c = **p; + + return c; +} + + +/* + * Skip to next option in the string + */ +static char * +opt(char **p) +{ + char *cp = *p; + char *dp = cp; + char *s = cp; + +top: + while (*cp && *cp != ';') { + if (*cp == '"') { + /* + * Skip past string + */ + for (cp++; *cp && *cp != '"'; cp++) + if (*cp == '\\') + *dp++ = backslash(&cp); + else + *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; +} + + +/* + * These routines add a new style of selector; function-style boolean + * operators. To add new ones, just define functions as in true, false, + * exists (below) and add them to the functable, above. + * + * Usage example: Some people have X11R5 local, some go to a server. I do + * this: + * + * * exists(/usr/pkg/${key});type:=link;fs:=/usr/pkg/${key} || \ + * -type:=nfs;rfs=/usr/pkg/${key} \ + * rhost:=server1 \ + * rhost:=server2 + * + * -Rens Troost <rens@imsi.com> + */ +static IntFuncPtr +functable_lookup(char *key) +{ + struct functable *fp; + + for (fp = functable; fp->name; fp++) + if (FSTREQ(fp->name, key)) + return (fp->func); + return (IntFuncPtr) NULL; +} + + +static int +eval_opts(char *opts, char *mapkey) +{ + /* + * 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 vs_opt = VarAss; + char *eq = strchr(f, '='); + char *fx; + IntFuncPtr func; + char *opt = NULL; + + if (!eq || eq[1] == '\0' || eq == f) { + /* + * No value, is it a function call? + */ + char *arg = strchr(f, '('); + + if (!arg || arg[1] == '\0' || arg == f) { + /* + * No, just continue + */ + plog(XLOG_USER, "key %s: No value component in \"%s\"", mapkey, f); + continue; + } + + /* null-terminate the argument */ + *arg++ = '\0'; + fx = strchr(arg, ')'); + if (!arg || fx == arg) { + plog(XLOG_USER, "key %s: Malformed function in \"%s\"", mapkey, f); + continue; + } + *fx = '\0'; + + /* + * look up f in functable and pass it arg. + * func must return 0 on failure, and 1 on success. + */ + if ((func = functable_lookup(f))) { + if (!(*func) (arg)) { + return (0); + } + continue; + } else if (NSTREQ(f, "!", 1) && (func = functable_lookup(&f[1]))) { + /* then this is a negated prefixed function such as "!exists" */ + plog(XLOG_USER, "executing negated function %s", &f[1]); + if ((*func) (arg)) { + return (0); + } + continue; + } else { + plog(XLOG_USER, "key %s: unknown function \"%s\"", mapkey, f); + return (0); + } + + } + + /* + * Check what type of operation is happening + * !=, =! is SelNE + * == is SelEQ + * := is 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; + } + + /* + * For each recognized option + */ + for (op = opt_fields; op->name; op++) { + /* + * Check whether they match + */ + if (FSTREQ(op->name, f)) { + int selok; + switch (vs_opt) { + case SelEQ: + case SelNE: + if ((selok = (op->sel_p != NULL))) { + if (op->case_insensitive) { + selok = (STRCEQ(*op->sel_p, opt) == (vs_opt == SelNE)); + } else { + selok = (STREQ(*op->sel_p, opt) == (vs_opt == SelNE)); + } + } + if (selok) { + plog(XLOG_MAP, "key %s: map selector %s (=%s) did not %smatch %s", + mapkey, + op->name, + *op->sel_p, + vs_opt == SelNE ? "mis" : "", + opt); + return 0; + } + /* check if to apply a function */ + if (op->fxn_p && + ((*op->fxn_p)(opt) == (vs_opt == SelNE))) { + plog(XLOG_MAP, "key %s: map function %s did not %smatch %s", + mapkey, + op->name, + vs_opt == SelNE ? "mis" : "", + opt); + return 0; + } + break; + + case VarAss: + if (op->sel_p) { + plog(XLOG_USER, "key %s: Can't assign to a selector (%s)", + mapkey, op->name); + return 0; + } + *op->optp = opt; + break; + + } /* end of "switch (vs_opt)" statement */ + break; /* break out of for loop */ + } + } + + if (!op->name) + plog(XLOG_USER, "key %s: Unrecognized key/option \"%s\"", mapkey, f); + } + + return 1; +} + + +/* + * Skip to next option in the string, but don't scribble over the string. + * However, *p gets repointed to the start of the next string past ';'. + */ +static char * +opt_no_scribble(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; + + *p = cp; + return s; +} + + +/* + * Strip any selectors from a string. Selectors are all assumed to be + * first in the string. This is used for the new /defaults method which will + * use selectors as well. + */ +char * +strip_selectors(char *opts, char *mapkey) +{ + /* + * Fill in the global structure fs_static by + * cracking the string opts. opts may be + * scribbled on at will. + */ + char *o = opts; + char *oo = opts; + char *f; + + /* + * Scan options. Note that the opt() function scribbles on the opt string. + */ + while (*(f = opt_no_scribble(&o))) { + enum vs_opt vs_opt = VarAss; + char *eq = strchr(f, '='); + + if (!eq || eq[1] == '\0' || eq == f) { + /* + * No option or assignment? Return as is. + */ + plog(XLOG_USER, "key %s: No option or assignment in \"%s\"", mapkey, f); + return o; + } + /* + * Check what type of operation is happening + * !=, =! is SelNE + * == is SelEQ + * := is VarAss + */ + if (eq[-1] == '!') { /* != */ + vs_opt = SelNE; + } else if (eq[-1] == ':') { /* := */ + vs_opt = VarAss; + } else if (eq[1] == '=') { /* == */ + vs_opt = SelEQ; + } else if (eq[1] == '!') { /* =! */ + vs_opt = SelNE; + } + switch (vs_opt) { + case SelEQ: + case SelNE: + /* Skip this selector, maybe there's another one following it */ + plog(XLOG_USER, "skipping selector to \"%s\"", o); + /* store previous match. it may have been the first assignment */ + oo = o; + break; + + case VarAss: + /* found the first assignment, return the string starting with it */ +#ifdef DEBUG + dlog("found first assignment past selectors \"%s\"", o); +#endif /* DEBUG */ + return oo; + } + } + + /* return the same string by default. should not happen. */ + return oo; +} + + +/***************************************************************************** + *** BOOLEAN FUNCTIONS (return 0 if false, 1 if true): *** + *****************************************************************************/ + +/* test if arg is any of this host's network names or numbers */ +static int +f_in_network(char *arg) +{ + int status; + + if (!arg) + return FALSE; + + status = is_network_member(arg); +#ifdef DEBUG + plog(XLOG_USER, "%s is %son a local network", + arg, (status ? "" : "not ")); +#endif /* DEBUG */ + return status; +} + + +/* test if this host is in netgroup (arg) */ +static int +f_netgrp(char *arg) +{ + int status; + + status = innetgr(arg, opt_host, NULL, NULL); +#ifdef DEBUG + plog(XLOG_USER, "netgrp = %s status = %d host = %s", arg, status, opt_host); +#endif /* DEBUG */ + return status; +} + + +/* test if file (arg) exists via lstat */ +static int +f_exists(char *arg) +{ + struct stat buf; + + if (lstat(arg, &buf) < 0) + return (0); + else + return (1); +} + + +/* always false */ +static int +f_false(char *arg) +{ + return (0); +} + + +/* always true */ +static int +f_true(char *arg) +{ + return (1); +} + + +/* + * Free an option + */ +static void +free_op(opt_apply *p, int b) +{ + if (*p->opt) { + XFREE(*p->opt); + *p->opt = 0; + } +} + + +/* + * Normalize slashes in the string. + */ +void +normalize_slash(char *p) +{ + char *f = strchr(p, '/'); + char *f0 = f; + + if (f) { + char *t = f; + do { + /* assert(*f == '/'); */ + if (f == f0 && f[0] == '/' && f[1] == '/') { + /* copy double slash iff first */ + *t++ = *f++; + *t++ = *f++; + } else { + /* copy a single / across */ + *t++ = *f++; + } + + /* assert(f[-1] == '/'); */ + /* skip past more /'s */ + while (*f == '/') + f++; + + /* assert(*f != '/'); */ + /* keep copying up to next / */ + while (*f && *f != '/') { + *t++ = *f++; + } + + /* assert(*f == 0 || *f == '/'); */ + + } while (*f); + *t = 0; /* derived from fix by Steven Glassman */ + } +} + + +/* + * 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(opt_apply *p, int sel_p) +{ + 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; + struct opt *op; +#ifdef DEBUG + char *cp_orig = *p->opt; +#endif /* DEBUG */ + + 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, E_Domain, E_Host + } 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 if (*cp == '.') { + /* + * Take domain name + */ + todo = E_Domain; + cp++; + --len; + } else if (br_p[-1] == '.') { + /* + * Take host name + */ + todo = E_Host; + --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 ? "/" : + todo == E_Domain ? "." : "", + nbuf, + todo == E_Dir ? "/" : + todo == E_Host ? "." : ""); + 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 all but first part + * ${var.} means take just the first 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; + case E_Domain: + vptr = strchr(val, '.'); + if (vptr) { + vptr++; + vlen = strlen(vptr); + } else { + vptr = ""; + vlen = 0; + } + break; + case E_Host: + vptr = strchr(val, '.'); + if (vptr) + vlen = vptr - val; + vptr = val; + break; + case E_All: + break; + } + + 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 + amuDebug(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_slash(*p->opt); + +#ifdef DEBUG + amuDebug(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(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); + XFREE(s); + } +} + + +/* + * Apply a function to a list of options + */ +static void +apply_opts(void (*op) (opt_apply *, int), opt_apply ppp[], int b) +{ + opt_apply *pp; + + for (pp = ppp; pp->opt; pp++) + (*op) (pp, b); +} + + +/* + * Free the option table + */ +void +free_opts(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(char *key) +{ + opt_apply oa; + + oa.opt = &key; + oa.val = 0; + expand_opts(&oa, TRUE); + + return key; +} + + +/* + * Remove trailing /'s from a string + * unless the string is a single / (Steven Glassman) + * or unless it is two slashes // (Kevin D. Bond) + */ +void +deslashify(char *s) +{ + if (s && *s) { + char *sl = s + strlen(s); + + while (*--sl == '/' && sl > s) + *sl = '\0'; + } +} + + +int +eval_fs_opts(am_opts *fo, char *opts, char *g_opts, char *path, char *key, char *map) +{ + int ok = TRUE; + + free_opts(fo); + + /* + * Clear out the option table + */ + memset((voidp) &fs_static, 0, sizeof(fs_static)); + memset((voidp) vars, 0, sizeof(vars)); + memset((voidp) fo, 0, sizeof(*fo)); + + /* + * Set key, map & path before expansion + */ + opt_key = key; + opt_map = map; + opt_path = path; + + opt_dkey = strchr(key, '.'); + if (!opt_dkey) { + opt_dkey = NullStr; + opt_keyd = key; + } else { + opt_keyd = strnsave(key, opt_dkey - key); + opt_dkey++; + if (*opt_dkey == '\0') /* check for 'host.' */ + opt_dkey = NullStr; + } + + /* + * 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, key)) + ok = FALSE; + + /* + * Expand local options + */ + if (ok && !eval_opts(fs_static.fs_local, key)) + 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 + */ + if (opt_keyd != key && opt_keyd != nullstr) + XFREE(opt_keyd); + opt_keyd = nullstr; + opt_dkey = NullStr; + opt_key = opt_map = opt_path = nullstr; + + return ok; +} diff --git a/contrib/amd/amd/restart.c b/contrib/amd/amd/restart.c new file mode 100644 index 0000000..572df86 --- /dev/null +++ b/contrib/amd/amd/restart.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: restart.c,v 5.2.2.2 1992/08/02 10:42:21 jsp Exp $ + * + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.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(void) +{ + /* + * Read the existing mount table + */ + mntlist *ml, *mlp; + + /* + * For each entry, find nfs, ufs or auto mounts + * and create a partial am_node to represent it. + */ + for (mlp = ml = read_mtab("restart", mnttab_file_name); + mlp; + mlp = mlp->mnext) { + mntent_t *me = mlp->mnt; + am_ops *fs_ops = 0; + if (STREQ(me->mnt_type, MNTTAB_TYPE_UFS)) { + /* + * UFS entry + */ + fs_ops = &ufs_ops; + } else if (STREQ(me->mnt_type, MNTTAB_TYPE_NFS)) { + /* + * NFS entry, or possibly an Amd entry... + * The mnt_fsname for daemon mount points is + * host:(pidXXX) + * or (seen on Solaris) + * host:daemon(pidXXX) + */ + char *colon = strchr(me->mnt_fsname, ':'); + + if (colon && strstr(colon, "(pid")) { + plog(XLOG_WARNING, "%s is an existing automount point", me->mnt_dir); + fs_ops = &amfs_link_ops; + } else { + fs_ops = &nfs_ops; + } +#ifdef MNTTAB_TYPE_NFS3 + } else if (STREQ(me->mnt_type, MNTTAB_TYPE_NFS3)) { + fs_ops = &nfs_ops; +#endif /* MNTTAB_TYPE_NFS3 */ +#ifdef MNTTAB_TYPE_LOFS + } else if (STREQ(me->mnt_type, MNTTAB_TYPE_LOFS)) { + fs_ops = &lofs_ops; +#endif /* MNTTAB_TYPE_LOFS */ +#ifdef MNTTAB_TYPE_CDFS + } else if (STREQ(me->mnt_type, MNTTAB_TYPE_CDFS)) { + fs_ops = &cdfs_ops; +#endif /* MNTTAB_TYPE_CDFS */ +#ifdef MNTTAB_TYPE_PCFS + } else if (STREQ(me->mnt_type, MNTTAB_TYPE_PCFS)) { + fs_ops = &pcfs_ops; +#endif /* MNTTAB_TYPE_PCFS */ +#ifdef MNTTAB_TYPE_MFS + } else if (STREQ(me->mnt_type, MNTTAB_TYPE_MFS)) { + /* + * MFS entry. Fake with a symlink. + */ + fs_ops = &amfs_link_ops; +#endif /* MNTTAB_TYPE_MFS */ + } else { + /* + * Catch everything else with symlinks to + * avoid recursive mounts. This is debatable... + */ + fs_ops = &amfs_link_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; + mo.opt_opts = me->mnt_opts; + + /* + * Make a new mounted filesystem + */ + mf = find_mntfs(fs_ops, &mo, me->mnt_dir, + me->mnt_fsname, "", me->mnt_opts, ""); + if (mf->mf_refc == 1) { + mf->mf_flags |= MFF_RESTART | MFF_MOUNTED; + mf->mf_error = 0; /* Already mounted correctly */ + mf->mf_fo = 0; + /* + * If the restarted type is a link then + * don't time out. + */ + if (fs_ops == &amfs_link_ops || fs_ops == &ufs_ops) + mf->mf_flags |= MFF_RSTKEEP; + if (fs_ops->fs_init) { + /* + * Don't care whether this worked since + * it is checked again when the fs is + * inherited. + */ + (void) (*fs_ops->fs_init) (mf); + } + 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) + XFREE(mo.opt_rhost); + if (mo.opt_rfs) + XFREE(mo.opt_rfs); + } + } + + /* + * Free the mount list + */ + free_mntlist(ml); +} diff --git a/contrib/amd/amd/rpc_fwd.c b/contrib/amd/amd/rpc_fwd.c new file mode 100644 index 0000000..7f3c59b --- /dev/null +++ b/contrib/amd/amd/rpc_fwd.c @@ -0,0 +1,476 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: rpc_fwd.c,v 5.2.2.1 1992/02/09 15:09:01 jsp beta $ + * + */ + +/* + * RPC packet forwarding + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* + * 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. + */ + +#define XID_ALLOC(struct ) (xid++) +#define MAX_PACKET_SIZE 8192 /* Maximum UDP packet size */ + +/* + * 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 + */ +qelem rpc_head = {&rpc_head, &rpc_head}; +int fwd_sock; +static u_int xid; + + +/* + * Allocate a rely structure + */ +static rpc_forward * +fwd_alloc(void) +{ + time_t now = clocktime(); + rpc_forward *p = 0, *p2; + + /* + * 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(struct rpc_forward); + } + ins_que(&p->rf_q, &rpc_head); + + /* + * Set the time to live field + * Timeout in 43 seconds + */ + p->rf_ttl = now + 43; + + return p; +} + + +/* + * Free an allocated reply structure. + * First unlink it from the list, then + * discard it. + */ +static void +fwd_free(rpc_forward *p) +{ + rem_que(&p->rf_q); + XFREE(p); +} + + +/* + * Initialize the RPC forwarder + */ +int +fwd_init(void) +{ +#ifdef FIONBIO + int on = 1; +#endif /* FIONBIO */ + +#ifdef HAVE_TRANSPORT_TYPE_TLI + /* + * Create ping TLI socket (/dev/tcp and /dev/ticlts did not work) + * (HPUX-11 does not like using O_NDELAY in flags) + */ + fwd_sock = t_open("/dev/udp", O_RDWR|O_NONBLOCK, 0); + if (fwd_sock < 0) { + plog(XLOG_ERROR, "unable to create RPC forwarding TLI socket: %s", + t_errlist[t_errno]); + return errno; + } +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + /* + * 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; + } +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + /* + * Some things we talk to require a priv port - so make one here + */ + if (bind_resv_port(fwd_sock, (u_short *) 0) < 0) + plog(XLOG_ERROR, "can't bind privileged port"); + + if (fcntl(fwd_sock, F_SETFL, FNDELAY) < 0 +#ifdef FIONBIO + && ioctl(fwd_sock, FIONBIO, &on) < 0 +#endif /* FIONBIO */ + ) { + 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(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(int type_id, voidp pkt, int len, struct sockaddr_in *fwdto, struct sockaddr_in *replyto, voidp i, fwd_fun cb) +{ + rpc_forward *p; + u_int *pkt_int; + int error; +#ifdef HAVE_TRANSPORT_TYPE_TLI + struct t_unitdata ud; +#endif /* HAVE_TRANSPORT_TYPE_TLI */ + + 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) { + p = fwd_locate(type_id); + if (p) { +#ifdef DEBUG + dlog("Discarding earlier rpc fwd handle"); +#endif /* DEBUG */ + fwd_free(p); + } + } else { +#ifdef DEBUG + dlog("Allocating a new xid..."); +#endif /* DEBUG */ + type_id = MK_RPC_XID(type_id, XID_ALLOC(struct )); + } + + 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 + { + char dq[20]; + if (p && fwdto) + dlog("Sending packet id %#x to %s.%d", + p->rf_xid, + inet_dquad(dq, fwdto->sin_addr.s_addr), + ntohs(fwdto->sin_port)); + } +#endif /* DEBUG */ + + /* if NULL, remote server probably down */ + if (!fwdto) { + error = AM_ERRNO_HOST_DOWN; + goto out; + } + +#ifdef HAVE_TRANSPORT_TYPE_TLI + ud.addr.buf = (char *) fwdto; + if (fwdto) /* if NULL, set sizes to zero */ + ud.addr.maxlen = ud.addr.len = sizeof(struct sockaddr_in); + else + ud.addr.maxlen = ud.addr.len = 0; + ud.opt.buf = (char *) NULL; + ud.opt.maxlen = ud.opt.len = 0; + ud.udata.buf = pkt; + ud.udata.maxlen = ud.udata.len = len; + if (t_sndudata(fwd_sock, &ud) < 0) { + plog(XLOG_ERROR,"fwd_packet failed: t_errno=%d, errno=%d",t_errno,errno); + error = errno; + } +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + if (sendto(fwd_sock, (char *) pkt, len, 0, + (struct sockaddr *) fwdto, sizeof(*fwdto)) < 0) + error = errno; +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + /* + * Save callback function and return address + */ +out: + p->rf_fwd = cb; + if (replyto) + p->rf_sin = *replyto; + else + memset((voidp) &p->rf_sin, 0, sizeof(p->rf_sin)); + p->rf_ptr = i; + + return error; +} + + +/* + * Called when some data arrives on the forwarding socket + */ +void +fwd_reply(void) +{ + int len; + u_int pkt[MAX_PACKET_SIZE / sizeof(u_int) + 1]; + u_int *pkt_int; + int rc; + rpc_forward *p; + struct sockaddr_in src_addr; + RECVFROM_FROMLEN_TYPE src_addr_len; +#ifdef HAVE_TRANSPORT_TYPE_TLI + struct t_unitdata ud; + int flags = 0; +#endif /* HAVE_TRANSPORT_TYPE_TLI */ + + /* + * Determine the length of the packet + */ + len = MAX_PACKET_SIZE; + + /* + * Read the packet and check for validity + */ +again: + src_addr_len = sizeof(src_addr); +#ifdef HAVE_TRANSPORT_TYPE_TLI + ud.addr.buf = (char *) &src_addr; + ud.addr.maxlen = ud.addr.len = src_addr_len; + ud.opt.buf = (char *) NULL; + ud.opt.maxlen = ud.opt.len = 0; + ud.udata.buf = (char *) pkt; + ud.udata.maxlen = ud.udata.len = len; + /* XXX: use flags accordingly such as if T_MORE set */ + rc = t_rcvudata(fwd_sock, &ud, &flags); + if (rc == 0) /* success, reset rc to length */ + rc = ud.udata.len; + else { + plog(XLOG_ERROR,"fwd_reply failed: t_errno=%d, errno=%d, flags=%d",t_errno,errno, flags); + } +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + rc = recvfrom(fwd_sock, + (char *) pkt, + len, + 0, + (struct sockaddr *) &src_addr, + &src_addr_len); +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + /* + * XXX: in svr4, if the T_MORE bit of flags is set, what do + * we then do? -Erez + */ + 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; + } + + /* + * 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) ((voidp) pkt, rc, &src_addr, &p->rf_sin, p->rf_ptr, TRUE); + } + + /* + * Free forwarding info + */ + fwd_free(p); + +out:; +} diff --git a/contrib/amd/amd/sched.c b/contrib/amd/amd/sched.c new file mode 100644 index 0000000..ffbe2c8 --- /dev/null +++ b/contrib/amd/amd/sched.c @@ -0,0 +1,300 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: sched.c,v 5.2.2.1 1992/02/09 15:09:02 jsp beta $ + * + */ + +/* + * Process scheduler + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + + +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 */ + int w; /* everyone these days uses int, not a "union wait" */ + voidp wchan; /* Wait channel */ +}; + +/* globals */ +qelem proc_list_head = {&proc_list_head, &proc_list_head}; +qelem proc_wait_list = {&proc_wait_list, &proc_wait_list}; +int task_notify_todo; + + +void +ins_que(qelem *elem, qelem *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(qelem *elem) +{ + qelem *p = elem->q_forw; + qelem *p2 = elem->q_back; + + p2->q_forw = p; + p->q_back = p2; +} + + +static pjob * +sched_job(cb_fun cf, voidp ca) +{ + pjob *p = ALLOC(struct pjob); + + p->cb_fun = cf; + p->cb_closure = ca; + + /* + * Now place on wait queue + */ + ins_que(&p->hdr, &proc_wait_list); + + return p; +} + + +/* + * tf: The task to execute (ta is its arguments) + * cf: Continuation function (ca is its arguments) + */ +void +run_task(task_fun tf, voidp ta, cb_fun cf, voidp ca) +{ + pjob *p = sched_job(cf, ca); +#ifdef HAVE_SIGACTION + sigset_t new, mask; +#else /* not HAVE_SIGACTION */ + int mask; +#endif /* not HAVE_SIGACTION */ + + p->wchan = (voidp) p; + +#ifdef HAVE_SIGACTION + sigemptyset(&new); /* initialise signal set we wish to block */ + sigaddset(&new, SIGCHLD); /* only block on SIGCHLD */ + sigprocmask(SIG_BLOCK, &new, &mask); +#else /* not HAVE_SIGACTION */ + mask = sigblock(sigmask(SIGCHLD)); +#endif /* not HAVE_SIGACTION */ + + if ((p->pid = background())) { +#ifdef HAVE_SIGACTION + sigprocmask(SIG_SETMASK, &mask, NULL); +#else /* not HAVE_SIGACTION */ + sigsetmask(mask); +#endif /* not HAVE_SIGACTION */ + return; + } + + /* child code runs here, parent have returned to caller */ + + exit((*tf) (ta)); + /* firewall... */ + abort(); +} + + +/* + * Schedule a task to be run when woken up + */ +void +sched_task(cb_fun cf, voidp ca, voidp wchan) +{ + /* + * Allocate a new task + */ + pjob *p = sched_job(cf, ca); + +#ifdef DEBUG + dlog("SLEEP on %#x", wchan); +#endif /* DEBUG */ + p->wchan = wchan; + p->pid = 0; + memset((voidp) &p->w, 0, sizeof(p->w)); +} + + +static void +wakeupjob(pjob *p) +{ + rem_que(&p->hdr); + ins_que(&p->hdr, &proc_list_head); + task_notify_todo++; +} + + +void +wakeup(voidp wchan) +{ + pjob *p, *p2; + + if (!foreground) + return; + + /* + * Can't user ITER() here because + * wakeupjob() juggles the list. + */ + for (p = AM_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(int rc, int term, voidp cl) +{ + wakeup(cl); +} + + +/* + * Run any pending tasks. + * This must be called with SIGCHLD disabled + */ +void +do_task_notify(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 (AM_FIRST(pjob, &proc_list_head) != HEAD(pjob, &proc_list_head)) { + pjob *p = AM_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) { + /* these two trigraphs will ensure compatibity with strict POSIX.1 */ + (*p->cb_fun) (WIFEXITED(p->w) ? WEXITSTATUS(p->w) : 0, + WIFSIGNALED(p->w) ? WTERMSIG(p->w) : 0, + p->cb_closure); + } + XFREE(p); + } +} + + +RETSIGTYPE +sigchld(int sig) +{ + int w; /* everyone these days uses int, not a "union wait" */ + int pid; + +#ifdef HAVE_WAITPID + while ((pid = waitpid((pid_t) -1, &w, WNOHANG)) > 0) { +#else /* not HAVE_WAITPID */ + while ((pid = wait3( &w, WNOHANG, (struct rusage *) 0)) > 0) { +#endif /* not HAVE_WAITPID */ + pjob *p, *p2; + + if (WIFSIGNALED(w)) + plog(XLOG_ERROR, "Process %d exited with signal %d", + pid, WTERMSIG(w)); +#ifdef DEBUG + else + dlog("Process %d exited with status %d", + pid, WEXITSTATUS(w)); +#endif /* DEBUG */ + + for (p = AM_FIRST(pjob, &proc_wait_list); + p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list); + p = p2) { + if (p->pid == pid) { + p->w = w; + wakeupjob(p); + break; + } + } /* end of for loop */ + +#ifdef DEBUG + if (!p) + dlog("can't locate task block for pid %d", pid); +#endif /* DEBUG */ + + /* + * Must count down children inside the while loop, otherwise we won't + * count them all, and NumChild (and later backoff) will be set + * incorrectly. SH/RUNIT 940519. + */ + if (--NumChild < 0) + NumChild = 0; + } /* end of "while wait..." loop */ + +#ifdef REINSTALL_SIGNAL_HANDLER + signal(sig, sigchld); +#endif /* REINSTALL_SIGNAL_HANDLER */ + + if (select_intr_valid) + longjmp(select_intr, sig); +} diff --git a/contrib/amd/amd/srvr_amfs_auto.c b/contrib/amd/amd/srvr_amfs_auto.c new file mode 100644 index 0000000..e77c591 --- /dev/null +++ b/contrib/amd/amd/srvr_amfs_auto.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: srvr_amfs_auto.c,v 5.2.2.1 1992/02/09 15:09:05 jsp beta $ + * + */ + +/* + * Automount FS server ("localhost") modeling + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* globals */ +qelem amfs_auto_srvr_list = {&amfs_auto_srvr_list, &amfs_auto_srvr_list}; + +/* statics */ +static fserver *localhost; + + +/* + * Find an nfs server for the local host + */ +fserver * +find_amfs_auto_srvr(mntfs *mf) +{ + fserver *fs = localhost; + + if (!fs) { + fs = ALLOC(struct 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, &amfs_auto_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(fserver *fs) +{ + fs->fs_flags &= ~FSF_WANT; + wakeup((voidp) fs); +} + + +/* + * Called when final ttl of server has expired + */ +static void +timeout_srvr(voidp v) +{ + fserver *fs = v; + + /* + * 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) + XFREE(fs->fs_ip); + + /* + * Free the host name. + */ + XFREE(fs->fs_host); + + /* + * Discard the fserver object. + */ + XFREE(fs); + } +} + + +/* + * Free a file server + */ +void +free_srvr(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(fserver *fs) +{ + fs->fs_refc++; + return fs; +} + + +/* + * Log state change + */ +void srvrlog(fserver *fs, char *state) +{ + plog(XLOG_INFO, "file server %s type %s %s", fs->fs_host, fs->fs_type, state); +} diff --git a/contrib/amd/amd/srvr_nfs.c b/contrib/amd/amd/srvr_nfs.c new file mode 100644 index 0000000..22a2640 --- /dev/null +++ b/contrib/amd/amd/srvr_nfs.c @@ -0,0 +1,851 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: srvr_nfs.c,v 5.2.2.1 1992/02/09 15:09:06 jsp beta $ + * + */ + +/* + * NFS server modeling + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* + * Number of pings allowed to fail before host is declared down + * - three-fifths of the allowed mount time... + */ +#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 in srvr_nfs.c +/* + * 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 */ + +#define NPXID_ALLOC(struct ) (++np_xid) + +/* structures and typedefs */ +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; + +/* globals */ +qelem nfs_srvr_list = {&nfs_srvr_list, &nfs_srvr_list}; + +/* statics */ +static int np_xid; /* For NFS pings */ +static int ping_len; +static char ping_buf[sizeof(struct rpc_msg) + 32]; + +#if defined(MNTTAB_OPT_PROTO) || defined(HAVE_FS_NFS3) +/* protocols we know about, in order of preference */ +static char *protocols[] = { "tcp", "udp", NULL }; +#endif /* defined(MNTTAB_OPT_PROTO) || defined(HAVE_FS_NFS3) */ + +/* forward definitions */ +static void nfs_keepalive(voidp); + + + +/* + * Flush any cached data + */ +void +flush_srvr_nfs_cache(void) +{ + fserver *fs = 0; + + ITER(fs, fserver, &nfs_srvr_list) { + nfs_private *np = (nfs_private *) fs->fs_private; + if (np) { + np->np_mountd_inval = TRUE; + np->np_error = -1; + } + } +} + + +/* + * Startup the NFS ping for a particular version. + */ +static void +start_ping(u_long nfs_version) +{ + XDR ping_xdr; + struct rpc_msg ping_msg; + + /* + * Non nfs mounts like /afs/glue.umd.edu have ended up here. + */ + if (nfs_version == 0) { + nfs_version = NFS_VERSION; + plog(XLOG_WARNING, "start_ping: nfs_version = 0 fixed"); + } + plog(XLOG_INFO, "start_ping: nfs_version: %d", nfs_version); + + rpc_msg_init(&ping_msg, NFS_PROGRAM, nfs_version, NFSPROC_NULL); + + /* + * Create an XDR endpoint + */ + xdrmem_create(&ping_xdr, ping_buf, sizeof(ping_buf), XDR_ENCODE); + + /* + * 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(voidp pkt, int len, struct sockaddr_in * sa, struct sockaddr_in * ia, voidp idv, int done) +{ + fserver *fs2 = (fserver *) idv; + fserver *fs = 0; + + /* + * Find which fileserver we are talking about + */ + 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, (XDRPROC_T_TYPE) 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 u_long in native ordering, so it + * needs converting to a u_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); + dlog("\t error=%d, port=%d", error, port); +#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(fserver *fs, AUTH * auth, u_long prog, u_long vers, u_long prot) +{ + struct rpc_msg pmap_msg; + int len; + char iobuf[UDPMSGSIZE]; + int error; + struct pmap pmap; + + rpc_msg_init(&pmap_msg, PMAPPROG, PMAPVERS, PMAPPROC_NULL); + 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, + (XDRPROC_T_TYPE) xdr_pmap, + auth); + if (len > 0) { + struct sockaddr_in sin; + memset((voidp) &sin, 0, 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 +recompute_portmap(fserver *fs) +{ + int error; + u_long mnt_version; + + if (nfs_auth) + error = 0; + else + error = make_nfs_auth(); + + if (error) { + nfs_private *np = (nfs_private *) fs->fs_private; + np->np_error = error; + return; + } + + if (fs->fs_version == 0) + plog(XLOG_WARNING, "recompute_portmap: nfs_version = 0 fixed"); + + plog(XLOG_INFO, "recompute_portmap: NFS version %d", fs->fs_version); +#ifdef HAVE_FS_NFS3 + if (fs->fs_version == NFS_VERSION3) + mnt_version = MOUNTVERS3; + else +#endif /* HAVE_FS_NFS3 */ + mnt_version = MOUNTVERS; + + plog(XLOG_INFO, "Using MOUNT version: %d", mnt_version); + call_portmap(fs, nfs_auth, MOUNTPROG, mnt_version, (u_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. + */ +static void +nfs_pinged(voidp pkt, int len, struct sockaddr_in * sp, struct sockaddr_in * tsp, voidp idv, int done) +{ + int xid = (long) idv; /* for 64-bit archs */ + fserver *fs; +#ifdef DEBUG + int found_map = 0; +#endif /* DEBUG */ + + 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 && (fs->fs_flags & FSF_PINGING)) { + /* + * 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 { + if (np->np_ping > 1) + srvrlog(fs, "ok"); +#ifdef DEBUG + else + srvrlog(fs, "starts up"); +#endif /* DEBUG */ + fs->fs_flags |= FSF_VALID; + } + + map_flush_srvr(fs); + } else { + if (fs->fs_flags & FSF_VALID) { +#ifdef DEBUG + dlog("file server %s type nfs is still up", fs->fs_host); +#endif /* DEBUG */ + } else { + if (np->np_ping > 1) + srvrlog(fs, "ok"); + 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(struct ); + + /* + * Failed pings is zero... + */ + np->np_ping = 0; + + /* + * Recompute portmap information if not known + */ + if (np->np_mountd_inval) + recompute_portmap(fs); + +#ifdef DEBUG + found_map++; +#endif /* DEBUG */ + break; + } + } + +#ifdef DEBUG + if (found_map == 0) + dlog("Spurious ping packet"); +#endif /* DEBUG */ +} + + +/* + * Called when no ping-reply received + */ +static void +nfs_timed_out(voidp v) +{ + fserver *fs = v; + nfs_private *np = (nfs_private *) fs->fs_private; + + /* + * Another ping has failed + */ + np->np_ping++; + + /* + * Not known to be up any longer + */ + if (FSRV_ISUP(fs)) { + fs->fs_flags &= ~FSF_VALID; + if (np->np_ping > 1) + srvrlog(fs, "not responding"); + } + + /* + * If ttl has expired then guess that it is dead + */ + if (np->np_ttl < clocktime()) { + int oflags = fs->fs_flags; + 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; + /* + * 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; + } else { + /* + * Known to be down + */ +#ifdef DEBUG + if ((fs->fs_flags & FSF_VALID) == 0) + srvrlog(fs, "starts down"); +#endif /* DEBUG */ + fs->fs_flags |= FSF_VALID; + } + if (oflags != fs->fs_flags && (fs->fs_flags & FSF_WANT)) + wakeup_srvr(fs); + } 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(voidp v) +{ + fserver *fs = v; + 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(fs->fs_version); + + /* + * 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) ((long) np->np_xid), /* for 64-bit archs */ + 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; + } + + /* + * 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(fserver *fs, u_short * port, voidp wchan) +{ + int error = -1; + if ((fs->fs_flags & FSF_VALID) == FSF_VALID) { + if ((fs->fs_flags & FSF_DOWN) == 0) { + nfs_private *np = (nfs_private *) fs->fs_private; + if (np->np_error == 0) { + *port = np->np_mountd; + error = 0; + } else { + error = np->np_error; + } + /* + * Now go get the port mapping again in case it changed. + * Note that it is used even if (np_mountd_inval) + * is True. The flag is used simply as an + * indication that the mountd may be invalid, not + * that it is known to be invalid. + */ + if (np->np_mountd_inval) + recompute_portmap(fs); + else + np->np_mountd_inval = TRUE; + } else { + error = EWOULDBLOCK; + } + } + if (error < 0 && wchan && !(fs->fs_flags & FSF_WANT)) { + /* + * If a wait channel is supplied, and no + * error has yet 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(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(mntfs *mf) +{ + char *host = mf->mf_fo->opt_rhost; + char *nfs_proto = NULL; + fserver *fs; + int pingval; + mntent_t mnt; + nfs_private *np; + struct hostent *hp = 0; + struct sockaddr_in *ip; + u_long nfs_version = 0; /* default is no version specified */ +#ifdef MNTTAB_OPT_PROTO + char *rfsname = mf->mf_fo->opt_rfs; +#endif /* MNTTAB_OPT_PROTO */ + + /* + * Get ping interval from mount options. + * Current only used to decide whether pings + * are required or not. < 0 = no pings. + */ + mnt.mnt_opts = mf->mf_mopts; + pingval = hasmntval(&mnt, "ping"); + + /* + * Get the NFS version from the mount options. This is used + * to decide the highest NFS version to try. + */ +#ifdef MNTTAB_OPT_VERS + nfs_version = hasmntval(&mnt, MNTTAB_OPT_VERS); +#endif /* MNTTAB_OPT_VERS */ + +#ifdef MNTTAB_OPT_PROTO + { + char *proto_opt = hasmntopt(&mnt, MNTTAB_OPT_PROTO); + if (proto_opt) { + char **p; + + proto_opt += sizeof(MNTTAB_OPT_PROTO) - 1; /* skip the "proto" */ + + for (p = protocols; *p; p ++) + if (proto_opt[0] == '=' && + NSTREQ(&proto_opt[1], *p, strlen(*p))) { + nfs_proto = *p; + break; + } + if (*p == NULL) + plog(XLOG_WARNING, "ignoring unknown protocol option for %s:%s", + host, rfsname); + } + } +#endif /* MNTTAB_OPT_PROTO */ + + /* + * lookup host address and canonical name + */ + hp = gethostbyname(host); + + /* + * New code from Bob Harris <harris@basil-rathbone.mit.edu> + * Use canonical name to keep track of file server + * information. This way aliases do not generate + * multiple NFS pingers. (Except when we're normalizing + * hosts.) + */ + if (hp && !(gopt.flags & CFM_NORMALIZE_HOSTNAMES)) + host = (char *) hp->h_name; + + if (hp) { + switch (hp->h_addrtype) { + case AF_INET: + ip = ALLOC(struct sockaddr_in); + memset((voidp) ip, 0, sizeof(*ip)); + ip->sin_family = AF_INET; + memmove((voidp) &ip->sin_addr, (voidp) hp->h_addr, sizeof(ip->sin_addr)); + + ip->sin_port = htons(NFS_PORT); + break; + + default: + ip = 0; + break; + } + } else { + plog(XLOG_USER, "Unknown host: %s", host); + ip = 0; + } + + /* + * Get the NFS Version, and verify server is up. Probably no + * longer need to start server down below. + */ + if (ip) { +#ifdef HAVE_FS_NFS3 + /* + * Find the best combination of NFS version and protocol. + * When given a choice, use the highest available version, + * and use TCP over UDP if available. + */ + if (nfs_proto) + nfs_version = get_nfs_version(host, ip, nfs_version, nfs_proto); + else { + int best_nfs_version = 0; + int proto_nfs_version; + char **p; + + for (p = protocols; *p; p ++) { + proto_nfs_version = get_nfs_version(host, ip, nfs_version, *p); + + if (proto_nfs_version > best_nfs_version) { + best_nfs_version = proto_nfs_version; + nfs_proto = *p; + } + } + nfs_version = best_nfs_version; + } + + if (!nfs_version) { + /* + * If the NFS server is down or does not support the portmapper call + * (such as certain Novell NFS servers) we mark it as version 2 and we + * let the nfs code deal with the case that is down. If when the + * server comes back up, it can support NFS V.3 and/or TCP, it will + * use those. + */ + nfs_version = NFS_VERSION; + nfs_proto = "udp"; + } +#else /* not HAVE_FS_NFS3 */ + nfs_version = NFS_VERSION; +#endif /* not HAVE_FS_NFS3 */ + } + + if (!nfs_proto) + nfs_proto = "udp"; + + plog(XLOG_INFO, "Using NFS version %d, protocol %s on host %s", + nfs_version, nfs_proto, host); + + /* + * Try to find an existing fs server stucture for this host. + * Note that differing versions or protocols have their own structures. + * XXX: Need to fix the ping mechanism to actually use the NFS protocol + * chosen here (right now it always uses datagram sockets). + */ + ITER(fs, fserver, &nfs_srvr_list) { + if (STREQ(host, fs->fs_host) && + nfs_version == fs->fs_version && + STREQ(nfs_proto, fs->fs_proto)) { + /* + * following if statement from Mike Mitchell + * <mcm@unx.sas.com> + * Initialize the ping data if we aren't pinging + * now. The np_ttl and np_ping fields are + * especially important. + */ + if (!(fs->fs_flags & FSF_PINGING)) { + np = (nfs_private *) fs->fs_private; + np->np_mountd_inval = TRUE; + np->np_xid = NPXID_ALLOC(struct ); + np->np_error = -1; + np->np_ping = 0; + /* + * Initially the server will be deemed dead + * after MAX_ALLOWED_PINGS of the fast variety + * have failed. + */ + np->np_ttl = MAX_ALLOWED_PINGS * FAST_NFS_PING + clocktime() - 1; + } + /* + * fill in the IP address -- this is only needed + * if there is a chance an IP address will change + * between mounts. + * Mike Mitchell, mcm@unx.sas.com, 09/08/93 + */ + if (hp && fs->fs_ip) + memmove((voidp) &fs->fs_ip->sin_addr, (voidp) hp->h_addr, sizeof(fs->fs_ip->sin_addr)); + + start_nfs_pings(fs, pingval); + fs->fs_refc++; + if (ip) + XFREE(ip); + return fs; + } + } + + /* + * Get here if we can't find an entry + */ + + /* + * Allocate a new server + */ + fs = ALLOC(struct fserver); + fs->fs_refc = 1; + fs->fs_host = strdup(hp ? hp->h_name : "unknown_hostname"); + if (gopt.flags & CFM_NORMALIZE_HOSTNAMES) + 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_version = nfs_version; + fs->fs_proto = nfs_proto; + fs->fs_type = MNTTAB_TYPE_NFS; + fs->fs_pinger = AM_PINGER; + np = ALLOC(struct nfs_private); + memset((voidp) np, 0, sizeof(*np)); + np->np_mountd_inval = TRUE; + np->np_xid = NPXID_ALLOC(struct ); + 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 (*)(voidp)) 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; +} |