diff options
657 files changed, 183029 insertions, 0 deletions
diff --git a/lib/libc/gen/pw_scan.c b/lib/libc/gen/pw_scan.c new file mode 100644 index 000000000000..3093ac257e5b --- /dev/null +++ b/lib/libc/gen/pw_scan.c @@ -0,0 +1,122 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)pw_scan.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +/* + * This module is used to "verify" password entries by chpass(1) and + * pwd_mkdb(8). + */ + +#include <sys/param.h> + +#include <err.h> +#include <fcntl.h> +#include <pwd.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include "pw_scan.h" + +int +pw_scan(bp, pw) + char *bp; + struct passwd *pw; +{ + long id; + int root; + char *p, *sh; + + if (!(pw->pw_name = strsep(&bp, ":"))) /* login */ + goto fmt; + root = !strcmp(pw->pw_name, "root"); + + if (!(pw->pw_passwd = strsep(&bp, ":"))) /* passwd */ + goto fmt; + + if (!(p = strsep(&bp, ":"))) /* uid */ + goto fmt; + id = atol(p); + if (root && id) { + warnx("root uid should be 0"); + return (0); + } + if (id > USHRT_MAX) { + warnx("%s > max uid value (%d)", p, USHRT_MAX); + return (0); + } + pw->pw_uid = id; + + if (!(p = strsep(&bp, ":"))) /* gid */ + goto fmt; + id = atol(p); + if (id > USHRT_MAX) { + warnx("%s > max gid value (%d)", p, USHRT_MAX); + return (0); + } + pw->pw_gid = id; + + pw->pw_class = strsep(&bp, ":"); /* class */ + if (!(p = strsep(&bp, ":"))) /* change */ + goto fmt; + pw->pw_change = atol(p); + if (!(p = strsep(&bp, ":"))) /* expire */ + goto fmt; + pw->pw_expire = atol(p); + pw->pw_gecos = strsep(&bp, ":"); /* gecos */ + pw->pw_dir = strsep(&bp, ":"); /* directory */ + if (!(pw->pw_shell = strsep(&bp, ":"))) /* shell */ + goto fmt; + + p = pw->pw_shell; + if (root && *p) /* empty == /bin/sh */ + for (setusershell();;) { + if (!(sh = getusershell())) { + warnx("warning, unknown root shell"); + break; + } + if (!strcmp(p, sh)) + break; + } + + if (p = strsep(&bp, ":")) { /* too many */ +fmt: warnx("corrupted entry"); + return (0); + } + return (1); +} diff --git a/lib/libc/gen/pw_scan.h b/lib/libc/gen/pw_scan.h new file mode 100644 index 000000000000..d1d4bc1ef631 --- /dev/null +++ b/lib/libc/gen/pw_scan.h @@ -0,0 +1,36 @@ +/*- + * Copyright (c) 1994 + * The Regents of the University of California. All rights reserved. + * + * 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. + * + * @(#)pw_scan.h 8.1 (Berkeley) 4/1/94 + */ + +extern int pw_scan __P((char *, struct passwd *)); diff --git a/lib/libutil/pw_util.c b/lib/libutil/pw_util.c new file mode 100644 index 000000000000..9873f74c3a31 --- /dev/null +++ b/lib/libutil/pw_util.c @@ -0,0 +1,204 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)pw_util.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +/* + * This file is used by all the "password" programs; vipw(8), chpass(1), + * and passwd(1). + */ + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/stat.h> +#include <sys/wait.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <paths.h> +#include <pwd.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "pw_util.h" + +extern char *tempname; + +void +pw_init() +{ + struct rlimit rlim; + + /* Unlimited resource limits. */ + rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; + (void)setrlimit(RLIMIT_CPU, &rlim); + (void)setrlimit(RLIMIT_FSIZE, &rlim); + (void)setrlimit(RLIMIT_STACK, &rlim); + (void)setrlimit(RLIMIT_DATA, &rlim); + (void)setrlimit(RLIMIT_RSS, &rlim); + + /* Don't drop core (not really necessary, but GP's). */ + rlim.rlim_cur = rlim.rlim_max = 0; + (void)setrlimit(RLIMIT_CORE, &rlim); + + /* Turn off signals. */ + (void)signal(SIGALRM, SIG_IGN); + (void)signal(SIGHUP, SIG_IGN); + (void)signal(SIGINT, SIG_IGN); + (void)signal(SIGPIPE, SIG_IGN); + (void)signal(SIGQUIT, SIG_IGN); + (void)signal(SIGTERM, SIG_IGN); + (void)signal(SIGTSTP, SIG_IGN); + (void)signal(SIGTTOU, SIG_IGN); + + /* Create with exact permissions. */ + (void)umask(0); +} + +static int lockfd; + +int +pw_lock() +{ + /* + * If the master password file doesn't exist, the system is hosed. + * Might as well try to build one. Set the close-on-exec bit so + * that users can't get at the encrypted passwords while editing. + * Open should allow flock'ing the file; see 4.4BSD. XXX + */ + lockfd = open(_PATH_MASTERPASSWD, O_RDONLY, 0); + if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1) + err(1, "%s", _PATH_MASTERPASSWD); + if (flock(lockfd, LOCK_EX|LOCK_NB)) + errx(1, "the password db file is busy"); + return (lockfd); +} + +int +pw_tmp() +{ + static char path[MAXPATHLEN] = _PATH_MASTERPASSWD; + int fd; + char *p; + + if (p = strrchr(path, '/')) + ++p; + else + p = path; + strcpy(p, "pw.XXXXXX"); + if ((fd = mkstemp(path)) == -1) + err(1, "%s", path); + tempname = path; + return (fd); +} + +int +pw_mkdb() +{ + int pstat; + pid_t pid; + + warnx("rebuilding the database..."); + (void)fflush(stderr); + if (!(pid = vfork())) { + execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", tempname, NULL); + pw_error(_PATH_PWD_MKDB, 1, 1); + } + pid = waitpid(pid, &pstat, 0); + if (pid == -1 || !WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0) + return (0); + warnx("done"); + return (1); +} + +void +pw_edit(notsetuid) + int notsetuid; +{ + int pstat; + pid_t pid; + char *p, *editor; + + if (!(editor = getenv("EDITOR"))) + editor = _PATH_VI; + if (p = strrchr(editor, '/')) + ++p; + else + p = editor; + + if (!(pid = vfork())) { + if (notsetuid) { + (void)setgid(getgid()); + (void)setuid(getuid()); + } + execlp(editor, p, tempname, NULL); + _exit(1); + } + pid = waitpid(pid, (int *)&pstat, 0); + if (pid == -1 || !WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0) + pw_error(editor, 1, 1); +} + +void +pw_prompt() +{ + int c; + + (void)printf("re-edit the password file? [y]: "); + (void)fflush(stdout); + c = getchar(); + if (c != EOF && c != '\n') + while (getchar() != '\n'); + if (c == 'n') + pw_error(NULL, 0, 0); +} + +void +pw_error(name, err, eval) + char *name; + int err, eval; +{ + if (err) + warn(name); + + warnx("%s: unchanged", _PATH_MASTERPASSWD); + (void)unlink(tempname); + exit(eval); +} diff --git a/sbin/sysctl/Makefile b/sbin/sysctl/Makefile new file mode 100644 index 000000000000..40d12d2fede4 --- /dev/null +++ b/sbin/sysctl/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= sysctl +MAN8= sysctl.0 + +.include <bsd.prog.mk> diff --git a/sbin/sysctl/pathconf.c b/sbin/sysctl/pathconf.c new file mode 100644 index 000000000000..4b60ccfb1c09 --- /dev/null +++ b/sbin/sysctl/pathconf.c @@ -0,0 +1,229 @@ +/* + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)pathconf.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/sysctl.h> +#include <sys/unistd.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define PC_NAMES { \ + { 0, 0 }, \ + { "link_max", CTLTYPE_INT }, \ + { "max_canon", CTLTYPE_INT }, \ + { "max_input", CTLTYPE_INT }, \ + { "name_max", CTLTYPE_INT }, \ + { "path_max", CTLTYPE_INT }, \ + { "pipe_buf", CTLTYPE_INT }, \ + { "chown_restricted", CTLTYPE_INT }, \ + { "no_trunc", CTLTYPE_INT }, \ + { "vdisable", CTLTYPE_INT }, \ +} +#define PC_MAXID 10 + +struct ctlname pcnames[] = PC_NAMES; +char names[BUFSIZ]; + +struct list { + struct ctlname *list; + int size; +}; +struct list pclist = { pcnames, PC_MAXID }; + +int Aflag, aflag, nflag, wflag, stdinflag; + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + char *path; + int ch; + + while ((ch = getopt(argc, argv, "Aan")) != EOF) { + switch (ch) { + + case 'A': + Aflag = 1; + break; + + case 'a': + aflag = 1; + break; + + case 'n': + nflag = 1; + break; + + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (argc == 0) + usage(); + path = *argv++; + if (strcmp(path, "-") == 0) + stdinflag = 1; + argc--; + if (Aflag || aflag) { + listall(path, &pclist); + exit(0); + } + if (argc == 0) + usage(); + while (argc-- > 0) + parse(path, *argv, 1); + exit(0); +} + +/* + * List all variables known to the system. + */ +listall(path, lp) + char *path; + struct list *lp; +{ + int lvl2; + + if (lp->list == 0) + return; + for (lvl2 = 0; lvl2 < lp->size; lvl2++) { + if (lp->list[lvl2].ctl_name == 0) + continue; + parse(path, lp->list[lvl2].ctl_name, Aflag); + } +} + +/* + * Parse a name into an index. + * Lookup and print out the attribute if it exists. + */ +parse(pathname, string, flags) + char *pathname; + char *string; + int flags; +{ + int indx, value; + char *bufp, buf[BUFSIZ]; + + bufp = buf; + snprintf(buf, BUFSIZ, "%s", string); + if ((indx = findname(string, "top", &bufp, &pclist)) == -1) + return; + if (bufp) { + fprintf(stderr, "name %s in %s is unknown\n", *bufp, string); + return; + } + if (stdinflag) + value = fpathconf(0, indx); + else + value = pathconf(pathname, indx); + if (value == -1) { + if (flags == 0) + return; + switch (errno) { + case EOPNOTSUPP: + fprintf(stderr, "%s: value is not available\n", string); + return; + case ENOTDIR: + fprintf(stderr, "%s: specification is incomplete\n", + string); + return; + case ENOMEM: + fprintf(stderr, "%s: type is unknown to this program\n", + string); + return; + default: + perror(string); + return; + } + } + if (!nflag) + fprintf(stdout, "%s = ", string); + fprintf(stdout, "%d\n", value); +} + +/* + * Scan a list of names searching for a particular name. + */ +findname(string, level, bufp, namelist) + char *string; + char *level; + char **bufp; + struct list *namelist; +{ + char *name; + int i; + + if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) { + fprintf(stderr, "%s: incomplete specification\n", string); + return (-1); + } + for (i = 0; i < namelist->size; i++) + if (namelist->list[i].ctl_name != NULL && + strcmp(name, namelist->list[i].ctl_name) == 0) + break; + if (i == namelist->size) { + fprintf(stderr, "%s level name %s in %s is invalid\n", + level, name, string); + return (-1); + } + return (i); +} + +usage() +{ + + (void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n", + "pathname [-n] variable ...", + "pathname [-n] -a", "pathname [-n] -A"); + exit(1); +} diff --git a/sbin/sysctl/sysctl.8 b/sbin/sysctl/sysctl.8 new file mode 100644 index 000000000000..9def5093a221 --- /dev/null +++ b/sbin/sysctl/sysctl.8 @@ -0,0 +1,208 @@ +.\" Copyright (c) 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" 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. +.\" +.\" @(#)sysctl.8 8.1 (Berkeley) 6/6/93 +.\" +.Dd "June 6, 1993" +.Dt SYSCTL 8 +.Os +.Sh NAME +.Nm sysctl +.Nd get or set kernel state +.Sh SYNOPSIS +.Nm sysctl +.Op Fl n +.Ar name ... +.Nm sysctl +.Op Fl n +.Fl w +.Ar name=value ... +.Nm sysctl +.Op Fl n +.Fl aA +.Sh DESCRIPTION +The +.Nm sysctl +utility retrieves kernel state and allows processes with +appropriate privilege to set kernel state. +The state to be retrieved or set is described using a +``Management Information Base'' (``MIB'') style name, +described as a dotted set of components. +The +.Fl a +flag can be used to list all the currently available string or integer values. +The +.Fl A +flag will list all the known MIB names including tables. +Those with string or integer values will be printed as with the +.Fl a +flag; for the table values, +the name of the utility to retrieve them is given. +.Pp +The +.Fl n +flag specifies that the printing of the field name should be +suppressed and that only its value should be output. +This flag is useful for setting shell variables. +For example, to save the pagesize in variable psize, use: +.Bd -literal -offset indent -compact +set psize=`sysctl -n hw.pagesize` +.Ed +.Pp +If just a MIB style name is given, +the corresponding value is retrieved. +If a value is to be set, the +.Fl w +flag must be specified and the MIB name followed +by an equal sign and the new value to be used. +.Pp +The information available from +.Nm sysctl +consists of integers, strings, and tables. +The tabular information can only be retrieved by special +purpose programs such as +.Nm ps , +.Nm systat , +and +.Nm netstat . +The string and integer information is summaried below. +For a detailed description of these variable see +.Xr sysctl 3 . +The changeable column indicates whether a process with appropriate +privilege can change the value. +.Bl -column net.inet.ip.forwardingxxxxxx integerxxx +.It Sy Name Type Changeable +.It kern.ostype string no +.It kern.osrelease string no +.It kern.osrevision integer no +.It kern.version string no +.It kern.maxvnodes integer yes +.It kern.maxproc integer yes +.It kern.maxfiles integer yes +.It kern.argmax integer no +.It kern.securelevel integer raise only +.It kern.hostname string yes +.It kern.hostid integer yes +.It kern.clockrate struct no +.It kern.posix1version integer no +.It kern.ngroups integer no +.It kern.job_control integer no +.It kern.saved_ids integer no +.It kern.link_max integer no +.It kern.max_canon integer no +.It kern.max_input integer no +.It kern.name_max integer no +.It kern.path_max integer no +.It kern.pipe_buf integer no +.It kern.chown_restricted integer no +.It kern.no_trunc integer no +.It kern.vdisable integer no +.It kern.boottime struct no +.It vm.loadavg struct no +.It machdep.console_device dev_t no +.It net.inet.ip.forwarding integer yes +.It net.inet.ip.redirect integer yes +.It net.inet.ip.ttl integer yes +.It net.inet.icmp.maskrepl integer yes +.It net.inet.udp.checksum integer yes +.It hw.machine string no +.It hw.model string no +.It hw.ncpu integer no +.It hw.byteorder integer no +.It hw.physmem integer no +.It hw.usermem integer no +.It hw.pagesize integer no +.It user.cs_path string no +.It user.bc_base_max integer no +.It user.bc_dim_max integer no +.It user.bc_scale_max integer no +.It user.bc_string_max integer no +.It user.coll_weights_max integer no +.It user.expr_nest_max integer no +.It user.line_max integer no +.It user.re_dup_max integer no +.It user.posix2_version integer no +.It user.posix2_c_bind integer no +.It user.posix2_c_dev integer no +.It user.posix2_char_term integer no +.It user.posix2_fort_dev integer no +.It user.posix2_fort_run integer no +.It user.posix2_localedef integer no +.It user.posix2_sw_dev integer no +.It user.posix2_upe integer no +.El +.Sh EXAMPLES +.Pp +For example, to retrieve the maximum number of processes allowed +in the system, one would use the follow request: +.Bd -literal -offset indent -compact +sysctl kern.maxproc +.Ed +.Pp +To set the maximum number of processes allowed +in the system to 1000, one would use the follow request: +.Bd -literal -offset indent -compact +sysctl -w kern.maxproc=1000 +.Ed +.Pp +Information about the system clock rate may be obtained with: +.Bd -literal -offset indent -compact +sysctl kern.clockrate +.Ed +.Pp +Information about the load average history may be obtained with +.Bd -literal -offset indent -compact +sysctl vm.loadavg +.Ed +.Sh FILES +.Bl -tag -width <netinet/icmpXvar.h> -compact +.It Pa <sys/sysctl.h> +definitions for top level identifiers, second level kernel and hardware +identifiers, and user level identifiers +.It Pa <sys/socket.h> +definitions for second level network identifiers +.It Pa <sys/gmon.h> +definitions for third level profiling identifiers +.It Pa <vm/vm_param.h> +definitions for second level virtual memory identifiers +.It Pa <netinet/in.h> +definitions for third level Internet identifiers and +fourth level IP identifiers +.It Pa <netinet/icmp_var.h> +definitions for fourth level ICMP identifiers +.It Pa <netinet/udp_var.h> +definitions for fourth level UDP identifiers +.El +.Sh SEE ALSO +.Xr sysctl 3 +.Sh HISTORY +.Nm sysctl +first appeared in 4.4BSD. diff --git a/sbin/sysctl/sysctl.c b/sbin/sysctl/sysctl.c new file mode 100644 index 000000000000..a3426868b4f2 --- /dev/null +++ b/sbin/sysctl/sysctl.c @@ -0,0 +1,572 @@ +/* + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)sysctl.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/gmon.h> +#include <sys/stat.h> +#include <sys/sysctl.h> +#include <sys/socket.h> +#include <vm/vm_param.h> +#include <machine/cpu.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_icmp.h> +#include <netinet/icmp_var.h> +#include <netinet/ip_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +struct ctlname topname[] = CTL_NAMES; +struct ctlname kernname[] = CTL_KERN_NAMES; +struct ctlname vmname[] = CTL_VM_NAMES; +struct ctlname netname[] = CTL_NET_NAMES; +struct ctlname hwname[] = CTL_HW_NAMES; +struct ctlname username[] = CTL_USER_NAMES; +struct ctlname debugname[CTL_DEBUG_MAXID]; +#ifdef CTL_MACHDEP_NAMES +struct ctlname machdepname[] = CTL_MACHDEP_NAMES; +#endif +char names[BUFSIZ]; + +struct list { + struct ctlname *list; + int size; +}; +struct list toplist = { topname, CTL_MAXID }; +struct list secondlevel[] = { + { 0, 0 }, /* CTL_UNSPEC */ + { kernname, KERN_MAXID }, /* CTL_KERN */ + { vmname, VM_MAXID }, /* CTL_VM */ + { 0, 0 }, /* CTL_FS */ + { netname, NET_MAXID }, /* CTL_NET */ + { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */ + { hwname, HW_MAXID }, /* CTL_HW */ +#ifdef CTL_MACHDEP_NAMES + { machdepname, CPU_MAXID }, /* CTL_MACHDEP */ +#else + { 0, 0 }, /* CTL_MACHDEP */ +#endif + { username, USER_MAXID }, /* CTL_USER_NAMES */ +}; + +int Aflag, aflag, nflag, wflag; + +/* + * Variables requiring special processing. + */ +#define CLOCK 0x00000001 +#define BOOTTIME 0x00000002 +#define CONSDEV 0x00000004 + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + int ch, lvl1; + + while ((ch = getopt(argc, argv, "Aanw")) != EOF) { + switch (ch) { + + case 'A': + Aflag = 1; + break; + + case 'a': + aflag = 1; + break; + + case 'n': + nflag = 1; + break; + + case 'w': + wflag = 1; + break; + + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (Aflag || aflag) { + debuginit(); + for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++) + listall(topname[lvl1].ctl_name, &secondlevel[lvl1]); + exit(0); + } + if (argc == 0) + usage(); + while (argc-- > 0) + parse(*argv, 1); + exit(0); +} + +/* + * List all variables known to the system. + */ +listall(prefix, lp) + char *prefix; + struct list *lp; +{ + int lvl2; + char *cp, name[BUFSIZ]; + + if (lp->list == 0) + return; + strcpy(name, prefix); + cp = &name[strlen(name)]; + *cp++ = '.'; + for (lvl2 = 0; lvl2 < lp->size; lvl2++) { + if (lp->list[lvl2].ctl_name == 0) + continue; + strcpy(cp, lp->list[lvl2].ctl_name); + parse(name, Aflag); + } +} + +/* + * Parse a name into a MIB entry. + * Lookup and print out the MIB entry if it exists. + * Set a new value if requested. + */ +parse(string, flags) + char *string; + int flags; +{ + int indx, type, state, size, len; + int special = 0; + void *newval = 0; + int intval, newsize = 0; + quad_t quadval; + struct list *lp; + int mib[CTL_MAXNAME]; + char *cp, *bufp, buf[BUFSIZ], strval[BUFSIZ]; + + bufp = buf; + snprintf(buf, BUFSIZ, "%s", string); + if ((cp = strchr(string, '=')) != NULL) { + if (!wflag) { + fprintf(stderr, "Must specify -w to set variables\n"); + exit(2); + } + *strchr(buf, '=') = '\0'; + *cp++ = '\0'; + while (isspace(*cp)) + cp++; + newval = cp; + newsize = strlen(cp); + } + if ((indx = findname(string, "top", &bufp, &toplist)) == -1) + return; + mib[0] = indx; + if (indx == CTL_DEBUG) + debuginit(); + lp = &secondlevel[indx]; + if (lp->list == 0) { + fprintf(stderr, "%s: class is not implemented\n", + topname[indx]); + return; + } + if (bufp == NULL) { + listall(topname[indx].ctl_name, lp); + return; + } + if ((indx = findname(string, "second", &bufp, lp)) == -1) + return; + mib[1] = indx; + type = lp->list[indx].ctl_type; + len = 2; + switch (mib[0]) { + + case CTL_KERN: + switch (mib[1]) { + case KERN_PROF: + mib[2] = GPROF_STATE; + size = sizeof state; + if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) { + if (flags == 0) + return; + if (!nflag) + fprintf(stdout, "%s: ", string); + fprintf(stderr, + "kernel is not compiled for profiling\n"); + return; + } + if (!nflag) + fprintf(stdout, "%s: %s\n", string, + state == GMON_PROF_OFF ? "off" : "running"); + return; + case KERN_VNODE: + case KERN_FILE: + if (flags == 0) + return; + fprintf(stderr, + "Use pstat to view %s information\n", string); + return; + case KERN_PROC: + if (flags == 0) + return; + fprintf(stderr, + "Use ps to view %s information\n", string); + return; + case KERN_CLOCKRATE: + special |= CLOCK; + break; + case KERN_BOOTTIME: + special |= BOOTTIME; + break; + } + break; + + case CTL_HW: + break; + + case CTL_VM: + if (mib[1] == VM_LOADAVG) { + double loads[3]; + + getloadavg(loads, 3); + if (!nflag) + fprintf(stdout, "%s: ", string); + fprintf(stdout, "%.2f %.2f %.2f\n", + loads[0], loads[1], loads[2]); + return; + } + if (flags == 0) + return; + fprintf(stderr, + "Use vmstat or systat to view %s information\n", string); + return; + + case CTL_NET: + if (mib[1] == PF_INET) { + len = sysctl_inet(string, &bufp, mib, flags, &type); + if (len >= 0) + break; + return; + } + if (flags == 0) + return; + fprintf(stderr, "Use netstat to view %s information\n", string); + return; + + case CTL_DEBUG: + mib[2] = CTL_DEBUG_VALUE; + len = 3; + break; + + case CTL_MACHDEP: +#ifdef CPU_CONSDEV + if (mib[1] == CPU_CONSDEV) + special |= CONSDEV; +#endif + break; + + case CTL_FS: + case CTL_USER: + break; + + default: + fprintf(stderr, "Illegal top level value: %d\n", mib[0]); + return; + + } + if (bufp) { + fprintf(stderr, "name %s in %s is unknown\n", *bufp, string); + return; + } + if (newsize > 0) { + switch (type) { + case CTLTYPE_INT: + intval = atoi(newval); + newval = &intval; + newsize = sizeof intval; + break; + + case CTLTYPE_QUAD: + sscanf(newval, "%qd", &quadval); + newval = &quadval; + newsize = sizeof quadval; + break; + } + } + size = BUFSIZ; + if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) { + if (flags == 0) + return; + switch (errno) { + case EOPNOTSUPP: + fprintf(stderr, "%s: value is not available\n", string); + return; + case ENOTDIR: + fprintf(stderr, "%s: specification is incomplete\n", + string); + return; + case ENOMEM: + fprintf(stderr, "%s: type is unknown to this program\n", + string); + return; + default: + perror(string); + return; + } + } + if (special & CLOCK) { + struct clockinfo *clkp = (struct clockinfo *)buf; + + if (!nflag) + fprintf(stdout, "%s: ", string); + fprintf(stdout, + "hz = %d, tick = %d, profhz = %d, stathz = %d\n", + clkp->hz, clkp->tick, clkp->profhz, clkp->stathz); + return; + } + if (special & BOOTTIME) { + struct timeval *btp = (struct timeval *)buf; + + if (!nflag) + fprintf(stdout, "%s = %s\n", string, + ctime(&btp->tv_sec)); + else + fprintf(stdout, "%d\n", btp->tv_sec); + return; + } + if (special & CONSDEV) { + dev_t dev = *(dev_t *)buf; + + if (!nflag) + fprintf(stdout, "%s = %s\n", string, + devname(dev, S_IFCHR)); + else + fprintf(stdout, "0x%x\n", dev); + return; + } + switch (type) { + case CTLTYPE_INT: + if (newsize == 0) { + if (!nflag) + fprintf(stdout, "%s = ", string); + fprintf(stdout, "%d\n", *(int *)buf); + } else { + if (!nflag) + fprintf(stdout, "%s: %d -> ", string, + *(int *)buf); + fprintf(stdout, "%d\n", *(int *)newval); + } + return; + + case CTLTYPE_STRING: + if (newsize == 0) { + if (!nflag) + fprintf(stdout, "%s = ", string); + fprintf(stdout, "%s\n", buf); + } else { + if (!nflag) + fprintf(stdout, "%s: %s -> ", string, buf); + fprintf(stdout, "%s\n", newval); + } + return; + + case CTLTYPE_QUAD: + if (newsize == 0) { + if (!nflag) + fprintf(stdout, "%s = ", string); + fprintf(stdout, "%qd\n", *(quad_t *)buf); + } else { + if (!nflag) + fprintf(stdout, "%s: %qd -> ", string, + *(quad_t *)buf); + fprintf(stdout, "%qd\n", *(quad_t *)newval); + } + return; + + case CTLTYPE_STRUCT: + fprintf(stderr, "%s: unknown structure returned\n", + string); + return; + + default: + case CTLTYPE_NODE: + fprintf(stderr, "%s: unknown type returned\n", + string); + return; + } +} + +/* + * Initialize the set of debugging names + */ +debuginit() +{ + int mib[3], size, loc, i; + + if (secondlevel[CTL_DEBUG].list != 0) + return; + secondlevel[CTL_DEBUG].list = debugname; + mib[0] = CTL_DEBUG; + mib[2] = CTL_DEBUG_NAME; + for (loc = 0, i = 0; i < CTL_DEBUG_MAXID; i++) { + mib[1] = i; + size = BUFSIZ - loc; + if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1) + continue; + debugname[i].ctl_name = &names[loc]; + debugname[i].ctl_type = CTLTYPE_INT; + loc += size; + } +} + +struct ctlname inetname[] = CTL_IPPROTO_NAMES; +struct ctlname ipname[] = IPCTL_NAMES; +struct ctlname icmpname[] = ICMPCTL_NAMES; +struct ctlname udpname[] = UDPCTL_NAMES; +struct list inetlist = { inetname, IPPROTO_MAXID }; +struct list inetvars[] = { + { ipname, IPCTL_MAXID }, /* ip */ + { icmpname, ICMPCTL_MAXID }, /* icmp */ + { 0, 0 }, /* igmp */ + { 0, 0 }, /* ggmp */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, /* tcp */ + { 0, 0 }, + { 0, 0 }, /* egp */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, /* pup */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { udpname, UDPCTL_MAXID }, /* udp */ +}; + +/* + * handle internet requests + */ +sysctl_inet(string, bufpp, mib, flags, typep) + char *string; + char **bufpp; + int mib[]; + int flags; + int *typep; +{ + struct list *lp; + int indx; + + if (*bufpp == NULL) { + listall(string, &inetlist); + return (-1); + } + if ((indx = findname(string, "third", bufpp, &inetlist)) == -1) + return (-1); + mib[2] = indx; + if (indx <= IPPROTO_UDP && inetvars[indx].list != NULL) + lp = &inetvars[indx]; + else if (!flags) + return (-1); + else { + fprintf(stderr, "%s: no variables defined for this protocol\n", + string); + return (-1); + } + if (*bufpp == NULL) { + listall(string, lp); + return (-1); + } + if ((indx = findname(string, "fourth", bufpp, lp)) == -1) + return (-1); + mib[3] = indx; + *typep = lp->list[indx].ctl_type; + return (4); +} + +/* + * Scan a list of names searching for a particular name. + */ +findname(string, level, bufp, namelist) + char *string; + char *level; + char **bufp; + struct list *namelist; +{ + char *name; + int i; + + if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) { + fprintf(stderr, "%s: incomplete specification\n", string); + return (-1); + } + for (i = 0; i < namelist->size; i++) + if (namelist->list[i].ctl_name != NULL && + strcmp(name, namelist->list[i].ctl_name) == 0) + break; + if (i == namelist->size) { + fprintf(stderr, "%s level name %s in %s is invalid\n", + level, name, string); + return (-1); + } + return (i); +} + +usage() +{ + + (void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n", + "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...", + "sysctl [-n] -a", "sysctl [-n] -A"); + exit(1); +} diff --git a/secure/usr.sbin/sendmail/Makefile b/secure/usr.sbin/sendmail/Makefile new file mode 100644 index 000000000000..3b21e37d6324 --- /dev/null +++ b/secure/usr.sbin/sendmail/Makefile @@ -0,0 +1,24 @@ +# @(#)Makefile 8.4 (Berkeley) 4/22/94 + +SUBDIR= src mailstats makemap praliases cf/cf +FTPDIR= barad-dur:/disks/barad-dur/ftp/sendmail/. +VER= XX + +tar: Files.base Files.cf Files.misc Files.xdoc + (cd src; ${MAKE}) + (cd doc; PRINTER=ps ${MAKE}) + (cd doc; chmod 444 op/op.ps intro/intro.ps usenix/usenix.ps) + (cd cf/cf; ${MAKE}) + pax -w -x tar -L -f sendmail.${VER}.base.tar `grep -v ^# Files.base` + compress sendmail.${VER}.base.tar + pax -w -x tar -L -f sendmail.${VER}.cf.tar `grep -v ^# Files.cf` + compress sendmail.${VER}.cf.tar + pax -w -x tar -L -f sendmail.${VER}.misc.tar `grep -v ^# Files.misc` + compress sendmail.${VER}.misc.tar + pax -w -x tar -L -f sendmail.${VER}.xdoc.tar `grep -v ^# Files.xdoc` + compress sendmail.${VER}.xdoc.tar + +ftp: sendmail.${VER}.base.tar.Z sendmail.${VER}.cf.tar.Z sendmail.${VER}.misc.tar.Z sendmail.${VER}.xdoc.tar.Z + rcp sendmail.${VER}.*.tar.Z RELEASE_NOTES FAQ KNOWNBUGS ${FTPDIR} + +.include <bsd.subdir.mk> diff --git a/share/examples/sliplogin/slip.hosts b/share/examples/sliplogin/slip.hosts new file mode 100644 index 000000000000..f6ebf4095605 --- /dev/null +++ b/share/examples/sliplogin/slip.hosts @@ -0,0 +1,11 @@ +# @(#)slip.hosts 8.1 (Berkeley) 6/6/93 +# +# login local-addr remote-addr mask opt1 opt2 +# (normal,compress,noicmp) +# +Schez vangogh chez 0xffffff00 compress +Sjun vangogh 128.32.130.36 0xffffff00 normal +Sleconte vangogh leconte 0xffffff00 compress +Sleeb vangogh leeb 0xffffff00 compress +Smjk vangogh pissaro-sl 0xffffff00 compress +Soxford vangogh oxford 0xffffff00 compress diff --git a/share/examples/sliplogin/slip.login b/share/examples/sliplogin/slip.login new file mode 100644 index 000000000000..3c70095a2fcc --- /dev/null +++ b/share/examples/sliplogin/slip.login @@ -0,0 +1,12 @@ +#!/bin/sh - +# +# @(#)slip.login 8.1 (Berkeley) 6/6/93 + +# +# generic login file for a slip line. sliplogin invokes this with +# the parameters: +# 1 2 3 4 5 6 7-n +# slipunit ttyspeed loginname local-addr remote-addr mask opt-args +# +/sbin/ifconfig sl$1 inet $4 $5 netmask $6 +exit diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile new file mode 100644 index 000000000000..84676086deb5 --- /dev/null +++ b/usr.sbin/Makefile @@ -0,0 +1,26 @@ +# @(#)Makefile 5.20 (Berkeley) 6/12/93 + +SUBDIR= ac accton amd arp chown chroot cron dev_mkdb diskpart edquota \ + inetd kgmon kvm_mkdb lpr mkproto mtree portmap pstat pwd_mkdb \ + quot quotaon repquota rmt rwhod sa sendmail sliplogin sysctl \ + syslogd traceroute trpt trsp update vipw + +.if make(clean) || make(cleandir) +SUBDIR+=bad144 config config.new eeprom iostat timed +.elif ${MACHINE} == "hp300" +SUBDIR+=config iostat timed +.elif ${MACHINE} == "i386" +SUBDIR+=bad144 config iostat +.elif ${MACHINE} == "luna68k" +SUBDIR+=config iostat timed +.elif ${MACHINE} == "mips" +SUBDIR+=config iostat timed +.elif ${MACHINE} == "sparc" +SUBDIR+=config.new eeprom timed +.elif ${MACHINE} == "tahoe" +SUBDIR+=config iostat timed +.elif ${MACHINE} == "vax" +SUBDIR+=bad144 config iostat timed +.endif + +.include <bsd.subdir.mk> diff --git a/usr.sbin/Makefile.inc b/usr.sbin/Makefile.inc new file mode 100644 index 000000000000..fd9286474425 --- /dev/null +++ b/usr.sbin/Makefile.inc @@ -0,0 +1,3 @@ +# @(#)Makefile.inc 8.1 (Berkeley) 6/6/93 + +BINDIR?= /usr/sbin diff --git a/usr.sbin/ac/ac.8 b/usr.sbin/ac/ac.8 new file mode 100644 index 000000000000..0c834a7a991e --- /dev/null +++ b/usr.sbin/ac/ac.8 @@ -0,0 +1,107 @@ +.\" Copyright (c) 1980, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" 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. +.\" +.\" @(#)ac.8 8.2 (Berkeley) 4/19/94 +.\" +.Dd April 19, 1994 +.Dt AC 8 +.Os BSD 4 +.Sh NAME +.Nm ac +.Nd display connect time accounting +.Sh SYNOPSIS +.Nm ac +.Op Fl d +.Op Fl p +.Op Fl w Ar file +.Op Ar users ... +.Sh DESCRIPTION +If the file +.Pa /var/log/wtmp +exists, +a record of individual +login and logout times are written to it by +.Xr init 8 +and +.Xr login 8 +respectively. +The program +.Nm ac +examines these +records and writes the accumulated connect time for all logins to the +standard output. +.Pp +Options available: +.Bl -tag -width people +.It Fl d +Display the connect times in 24 hour chunks. +.It Fl p +Display individual user totals. +.It Fl w Ar file +Read raw connect time data from +.Ar file +instead of the default file +.Pa /var/log/wtmp . +.It Ar users ... +Display totals for the given individuals +only. +.El +.Pp +If no arguments are given, +.Nm +displays the total amount of login time for all active accounts on the +system. +.Pp +The default +.Pa wtmp +file is an infinitely increasing file +unless frequently truncated. This is normally +done by the daily daemon scripts scheduled by +.Xr cron 8 +which rename and rotate the +.Pa wtmp +files before truncating them (and keeping about a weeks worth on hand). +No login times are collected however, if the file does not exist. +.Sh FILES +.Bl -tag -width /var/log/wtmp.[0-7] -compact +.It Pa /var/log/wtmp +.It Pa /var/log/wtmp.[0-7] +rotated files +.El +.Sh SEE ALSO +.Xr init 8 , +.Xr sa 8 , +.Xr login 1 , +.Xr utmp 5 . +.Sh HISTORY +A +.Nm +command appeared in Version 6 AT&T UNIX. diff --git a/usr.sbin/accton/Makefile b/usr.sbin/accton/Makefile new file mode 100644 index 000000000000..15152a63765b --- /dev/null +++ b/usr.sbin/accton/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= accton +NOMAN= noman + +.include <bsd.prog.mk> diff --git a/usr.sbin/accton/accton.c b/usr.sbin/accton/accton.c new file mode 100644 index 000000000000..c65ef680afc4 --- /dev/null +++ b/usr.sbin/accton/accton.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)accton.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include <sys/types.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int ch; + + while ((ch = getopt(argc, argv, "")) != EOF) + switch(ch) { + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + switch(argc) { + case 0: + if (acct(NULL)) { + (void)fprintf(stderr, + "accton: %s\n", strerror(errno)); + exit(1); + } + break; + case 1: + if (acct(*argv)) { + (void)fprintf(stderr, + "accton: %s: %s\n", *argv, strerror(errno)); + exit(1); + } + break; + default: + usage(); + } + exit(0); +} + +void +usage() +{ + (void)fprintf(stderr, "usage: accton [file]\n"); + exit(1); +} diff --git a/usr.sbin/amd/Makefile b/usr.sbin/amd/Makefile new file mode 100644 index 000000000000..96405b8fe90c --- /dev/null +++ b/usr.sbin/amd/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +SUBDIR= amd amq fsinfo mk-amd-map + +.include <bsd.subdir.mk> diff --git a/usr.sbin/amd/amd/ChangeLog b/usr.sbin/amd/amd/ChangeLog new file mode 100644 index 000000000000..2cd1807260d4 --- /dev/null +++ b/usr.sbin/amd/amd/ChangeLog @@ -0,0 +1,1169 @@ +Sun Jun 7 19:01:37 1992 Jan-Simon Pendry (jsp at achilles) + + * Code cut for BSD 4.4 alpha. + +Sun May 31 17:28:52 1992 Jan-Simon Pendry (jsp at achilles) + + * (afs_ops.c) make sure error code is returned to user if there + is an immediate error in afs_lookuppn. + + * (nfs_ops.c) clear out mountd port number after use. + + * (nfs_ops.c) optionally (KICK_KERNEL) run lstat over the old + mount point. This should go somewhere else more appropriate. + +Sun Mar 29 16:22:01 1992 Jan-Simon Pendry (jsp at achilles) + + * (mount_fs.c) FASCIST_DF_COMMAND is now defined as the fstype + you want df to see. + + * (opts.c) fix buffer overrun in slash munging. + + * (host_ops.c) add support for INFORM_MOUNTD. + +Sat Mar 7 10:23:04 1992 Jan-Simon Pendry (jsp at achilles) + + * (nfsx_ops.c) fix buffer overrun problem by allocating sufficient + memory. + + * (afs_ops.c) fix dereference of free'ed memory when calling + assign_error_mntfs. + + * (xutil.c) fix xmalloc and xrealloc to allow zero sized + allocation. + + * (os-type) make it recognise aix3.2 + +Sun Feb 9 13:14:54 1992 Jan-Simon Pendry (jsp at achilles) + + * Release 5.3 Beta + + * hpux 8 support is still missing. + + * (os-bsd44.h) merged in changes for new bsd nfs code. still need + to add in lease and kerberos support. + +Sun Dec 1 16:20:21 1991 Jan-Simon Pendry (jsp at achilles) + + * (info_nis.c) changed so that it remembers if the NIS domainname + is set and doesn't repeatedly complain. Message changed from an + Error to a Warning. + + * (sfs_ops.c) added linkx fstype. linkx is the same as link but + it also checks that the target exists. This makes it useful for + wildcard map entries. + + * (wire.c) applied changes from Dirk Grunwald. Now stands a + better chance of correctly determining the network name. + + * (map.c) changes in timeout_mp to cause second and subsequent + backgrounded unmount attempts to backoff and so reduce the chance + of running more than one backgrounded unmount at a time. + + * (misc_rpc.c) bug fix from Martyn Johnson to avoid xdr_free'ing + the wrong piece of memory. This was causing random core dumps, + often with a stack trace through pickup_rpc_reply. + +Sun Sep 15 21:16:38 1991 Jan-Simon Pendry (jsp at achilles) + + * Release 5.3 alpha 14. + + * (os-osf1.h) merged in OSF/1 support. + +Sun Aug 4 18:25:04 1991 Jan-Simon Pendry (jsp at achilles) + + * (os-stellix.h) merged in Stellix support. + + * (os-u4_2.h) merged in Ultrix 4.2 support. + + * (host_ops.c) made TCP the default transport protocol. Define + HOST_RPC_UDP somewhere to get UDP transport. + + * (many) added support for ${remopts}. Suggested by Steve + Heimlich. remopts is the same as opts, but is used when the + remote server is not on the local network. If it is not set it + defaults to whatever value ${opts} has. + +Tue May 7 22:30:00 1991 Jan-Simon Pendry (jsp at achilles) + + * Checkpoint for Berkeley network tape II. + +Sat May 4 22:06:24 1991 Jan-Simon Pendry (jsp at achilles) + + * New Berkeley Copyright. + + * (mntfs.c) more short-circuiting in realloc_mntfs(). + + * (host_ops.c) increase RPC timeout to 20 seconds. + + * (info_hes.c) now supports lookup in other domains. + + * (srvr_nfs.c) call map_flush_srvr whenever a server comes up. + + * (map.c) added hook to flush hung file servers. + + * (wire.c) make loop step more portable. + + * (util.c) fix for compiling on rios. + +Sun Apr 21 21:54:52 1991 Jan-Simon Pendry (jsp at forest) + + * (util.c) ignore EINVAL returned by rmdir(). + + * (am_ops.c, afs_ops.c) remove SunOS4 map compat code. + + * (nfsx_ops.c) don't clear MFF_MOUNTING until finished mount attempts. + + * (nfsx_ops.c) don't call sched_task more than once. + + * (afs_ops.c) don't call afs_bgmount if a mount is in progress. + + * (info_file.c) handle case where map ends with \ + +Fri Apr 5 19:23:50 1991 Jan-Simon Pendry (jsp at forest) + + * Release 5.3 Alpha 12. + + * (util.c) don't clear MFF_MOUNTING flag if mount is still in progress. + + * (srvr_nfs.c) calls make_nfs_auth() as required. + + * (host_ops.c) calls make_nfs_auth() as required. + + * (afs_ops.c) allow foreground mounts to return pending. This is + used by nfsx_ops.c. + + * (mapc.c) uses new RE_HDR abstraction coping with systems which + already have the re package installed. + + * (nfsx_ops.c) automatically generates a suitable sublink to make + things work. Remounts now work correctly, but are done in the + foreground so there is a possibility that things may hang. This is + too hard to do differently. + +Wed Apr 3 17:49:05 1991 Jan-Simon Pendry (jsp at achilles) + + * (nfs_ops.c) HAS_NFS_QUALIFIED_NAME is a new compile time switch + which puts a qualified domain name into the RPC authentication + instead of using the default value. Abstracted this out into new + routine called make_nfs_auth(). + + * (afs_ops.c) fixed bug which caused spurious ENOENTs to appear. + this was caused by some code motion which also got slightly + altered int the process. moral: don't make two changes at once. + +Sun Mar 17 12:05:27 1991 Jan-Simon Pendry (jsp at forest) + + * Release 5.3 Alpha 11. + + * (amq.8) Updated. + + * (amq.c) Added new -v option which displays the version number of + the target Amd. Also added support to Amd and reworked newvers + script. Got rid of rcs_info.c. + + * (mk-amd-map.c) Changed name of remove function to avoid clash + with ANSI C. + + * (wire.c) Fixed to work with new 4.4BSD sockaddr's. + + * Changed const to Const everywhere and added new define in config.h. + + * (mk-amd-map.c) New -p option which just writes the output to + stdout. Useful for making NIS or Hesiod maps. + + * (amdref) Small updates and clarifications. + +Sat Mar 16 20:35:17 1991 Jan-Simon Pendry (jsp at forest) + + * (amq_subr.c) Flush request now flushes all internal caches. + + * (amq_subr.c) Changed xdr_amq_mount_tree to return only the + required sub-tree. + + * (ifs_ops.c) Added missing return 0; to ifs_mount. + +Sat Mar 9 19:31:25 1991 Jan-Simon Pendry (jsp at forest) + + * (get_args.c) Output the primary network interface information + with the -v option. + + * (mapc.c) Fixed spurious warning about "root" map not supporting + cache mode "all". Added new (unnamed) cache mode MAPC_ROOT. + + * (info_nis.c) Fixed order number testing which was the cause of a + loop. + +Sun Mar 3 17:57:03 1991 Jan-Simon Pendry (jsp at forest) + + * Release 5.3 Alpha 10. + + * Introduced new inet_dquad routine which prints IP addresses in + dotted quad format. The C library routine is not used because it + uses a static buffer and it takes a structure argument on some + machines and unsigned longs on others. This confuses the hell out + of some compilers and causes SEGVs. + + * task_notify becomes do_task_notify to avoid clash with Mach. + + * (mntfs.c) In realloc_mntfs, the private data field wasn't being + cleared out when the mntfs object was being re-used. This meant + that the data might be used for the wrong mount, so causing + various obscure errors. + + * (info_file.c) Reworked to provide support for map cache "sync" + option. + + * (mapc.c) Added new "sync" option to map cache. This ensures + that the cached data doesn't become stale wrt the source. + Currently this isn't implemented for passwd and hesiod maps. + +Wed Feb 27 11:38:07 1991 Jan-Simon Pendry (jsp at forest) + + * (afs_ops.c) Fixed pid put in fs_hostname for toplvl mount. + +Sun Feb 24 19:37:55 1991 Jan-Simon Pendry (jsp at forest) + + * (wire.c) New module which determines the name of the primary + attached network. This could be used to determine which + server to use. + + * (srvr_nfs.c) Changed mount daemon port mapping caching. This is + now much more eager to recompute the mapping than before. Will + also now work even if pinging is switched off (for example "tcp"). + + * (info_nis.c) Added back old NIS reload code to allow NIS maps to + support "regexp" caching. + + * (mapc.c) Added support for "regexp" caching. This is a type of + map cache where the entries are all REs to be matched against the + requested key. This implies "all" since all the keys must be + loaded for the search to work. + +Sat Feb 23 15:32:43 1991 Jan-Simon Pendry (jsp at forest) + + * (afs_ops.c) Avoid spurious error messages about discarding a + retry mntfs. + + * (amq_subr.c) Removed inet_ntoa call due to disagreement between + gcc and libc about 4 byte structure passing. + + * (xutil.c) Changed way initial logging is done to make command + line more usable. Default logging flags are set statically and + can then be modified by -x options. At the end an additional call + to switch_option is made to initialise xlog_level_init. + + * (umount_fs.c) ENOENT now treated the same as EINVAL. If the + filesystem gets removed and the mountpoint deleted then just + assume the filesystem isn't there - which it isn't. + + * (host_ops.c) Now copes with unmount failures by attempting to + remount the filesystems which had been unmounted. + + * (host_ops.c) Added check during fhandle collection to detect + duplicate entries in the export list (from Stefan Petri). + + * (nfsx_ops.c) Reworked to correctly keep track of what is and + isn't mounted. + +Sun Jan 27 16:58:02 1991 Jan-Simon Pendry (jsp at achilles) + + * (misc-next.h) Added missing NeXT config file. + + * Merged Harris HCX/UX support from Chris Metcalf. + + * (ifs_ops.c) added ifs_fmount entry point to keep nfsx_ops happy. + +Sun Jan 13 18:19:19 1991 Jan-Simon Pendry (jsp at beauty) + + * (nfsx_ops.c) play with opt_fs field to make sure it is unique. + +Fri Dec 21 15:35:45 1990 Jan-Simon Pendry (jsp at forest) + + * Release 5.3 Alpha 9. This is still not Beta! + + * (host_ops.c) use normalized hostname in mtab entries, from + Chris Metcalf. + + * (map.c) enum ftype -> ftype, from Andrew Findlay. + +Mon Dec 17 01:11:25 1990 Jan-Simon Pendry (jsp at beauty) + + * (amdref.texinfo) merged in fsinfo documentation from Nick. + +Sat Dec 15 15:39:07 1990 Jan-Simon Pendry (jsp at beauty) + + * (clock.c) minor tweaks to messages. + + * (sfs_ops.c) make the opt_fs field unique, rather than always + ".", but make sure it still begins with a "." to avoid a clash + with any other existing mounts. + + * (amd.c) changed way local IP address is obtained to avoid using + a call to the name server. It was observed that if the power to + the building goes and everything reboots simultaneously then there + would be a good chance that the nameserver would not recover + before Amd on another machine required it. This happened :-) Now + use the RPC get_myaddress call. + + * (info_hes.c) added hesiod_reload code from Bruce Cole. + Optionally compiled when HAS_HESIOD_RELOAD is defined. + + * (amq_subr.c) fix "security" check. + + * (amq.c) make sure a privileged port is allocated. In fact + RPC3.9 and newer make this guarentee but older versions don't so + we do it here. + +Sun Dec 2 21:30:07 1990 Jan-Simon Pendry (jsp at achilles) + + * (afs_ops.c) fixed problem with pointer pre-increment. + +Mon Nov 19 00:31:28 1990 Jan-Simon Pendry (jsp at achilles) + + * (nfs_ops.c) saved filehandle with mntfs structure. this allows + nfsx unmounts to be undone even if the filehandle cache has lost + the entry. all of this is bogus and deserves a rewrite... + +Sun Nov 18 22:55:43 1990 Jan-Simon Pendry (jsp at achilles) + + * (nfsx_ops.c) now handles mounts of root filesystem correctly. + + * (afs_ops.c) fixed dfs_ops definition to call toplvl_mounted when + done, so making sure that a map cache reference is set up. + +Sun Nov 11 21:09:34 1990 Jan-Simon Pendry (jsp at achilles) + + * (fsinfo/wr_fstab.c) has per-ostype fstab rules. + + * (fsinfo/fsi_lex.l) now works correctly with flex. + +Mon Nov 5 00:08:30 1990 Jan-Simon Pendry (jsp at achilles) + + * Release 5.3 Alpha 8. No more new features from now to 5.3Rel. + Call next one Beta. + + * (amdref.texinfo) more updates. + + * (info_union.c) reload routine now adds a wildcard pointing to + the last named directory so that new files get created correctly. + +Sun Nov 4 22:02:50 1990 Jan-Simon Pendry (jsp at achilles) + + * (os-u4_0.h) Ultrix 4.0 support merged. + + * (os-utek.h) Utek 4.0 support merged. + + * (amdref.texinfo) fixed & updated. + + * (nfsx_ops.c) reworked string munging to prevent ..//.. strings + from occuring. + + * (util.c) am_mounted now correctly updates the am_node for + duplicate mounts. + + * (afs_ops.c) added union fstype. derived from "toplvl" except it + causes all the filesystems to be mounted. cannot be used for + filesystem types whose mounts may be defered (eg nfs) since it + doesn't retry the mounts. + + * (info_union.c) map type for union fstype support. currently + can't handle being given automounted filesystems - causes a + deadlock. + +Sun Oct 21 22:56:16 1990 Jan-Simon Pendry (jsp at achilles) + + * (fsinfo/*) finally integrated the fsinfo package. currently no + documentation or man page. this is a pre-req to getting mmd up. + +Sun Oct 14 20:02:11 1990 Jan-Simon Pendry (jsp at achilles) + + * (amdref.texinfo) reworking of documentation continues. + + * (clock.c) reschedule_timeouts() now called in the event that the + system clock goes backwards. this is possible during the average + bootstrap juggling act with timed/xntpd etc. especially useful if + your machines TOY clock gets way ahead of time. + +Sat Oct 6 19:57:55 1990 Jan-Simon Pendry (jsp at achilles) + + * (map.c) when expanding the filehandle for a server which is + down, don't update the ttl on the original node unless a new node + gets allocated. this should give the original mount a chance to + go away as soon as the server comes back. + + * (arch, os-type) Updated. + + * (nfs_ops.c) Added "noconn", "spongy" and "compress" mount + options for 4.4 BSD. + +Sun Sep 30 18:37:54 1990 Jan-Simon Pendry (jsp at beauty) + + * Release 5.3 Alpha 6. + + * (util.c) domain_strip now doesn't leave partial domains behind. + if it can't strip the complete domain it leaves the string untouched. + + * (restart.c) remember to initialise opt_opts field from mtab. + + * (nfs_ops.c) supports "nocto" option for SunOS4.1. + + * (os-irix.h) new SGI Iris port. + + * (os-next.h) new NeXT port. + + * (os-dgux.h) new DG/UX port. + + * (many) fixed problem where mf_opts was being used for two + different purposes. Now have two fields. + + * (mapc.c) error map prints error message whenever used. + + * (mapc.c) wildcard code rewritten. + + * (util.c) slpit into two parts - some code now in xutil.c. This + is used by mmd (not yet shipped). + +Sun Aug 19 19:58:16 1990 Jan-Simon Pendry (jsp at achilles) + + * (srvr_nfs.c) reduce verbosity of "nfs server yoyo is ok" messages. + + * (opts.c) fix deslashification in expand. + + * (nfs_start.c) amq registering done just before the server kicks + in. running amd with nothing to do leaves the portmapper in peace. + + * (mapc.c) bootstrap code abstracted to allow AMQ_MOUNT entry point. + + * (nfsx_ops.c) new filesystem type, supporting groups of nfs + mounts. needs abstracting to allow groups of (*) mounts. + + * (am.h, *_ops.c) am_ops structure changed; corresponding changes + in the filesystem implemention source. Change was to allow nfsx + filesystem implementation. + + * (amd.c) hostname defaults to "localhost" startup code re-ordered + so that logging still works in case things go wrong early. + + * (am_ops.c) new routine to print list of available fs types; used + by the -v option. + + * (info_file.c) bug fix to make reloads work correctly. + + * (mtab_file.c) does locking on single write, to avoid trashing + mount table when a mount and unmount are done at the same time. + + * (mount_fs.c) automount hack removed since afs_ops no longer + needs it. + + * (afs_ops.c) split "auto" into several other filesystem types. + Now much cleaner. + + * (amq.c) new -M option. + + * (amq_subr.c) support for AMQ_MOUNT added. + + * (amq.x) new AMQ_MOUNT RPC call allows mount map entries to be + passed in at run-time. Automount points can now be added + dynamically, but not yet deleted. + +Sat Jun 23 22:12:48 1990 Jan-Simon Pendry (jsp at beauty) + + * Release 5.2 for Berkeley. + + * (*) Re-organised source code layout. Now much more complicated. + + * (map.c) code which flushed the kernel name cache is not really + needed now that the modify times on the automount directories are + correctly updated so ifdef the whole lot. Remove later... + + * (map.c) make sure that the automount directories modify times + are updated when a change occurs so that the nfs client code can + decide when to update its name cache. + + * (srvr_nfs.c) fixed bug which caused mounted filesystems to + appear down when they were up. + + * YP becomes NIS. + +Mon May 28 19:50:34 1990 Jan-Simon Pendry (jsp at achilles) + + * (amd.tex) substantially updated with more explanation of the + theory and more examples. + + * (nfs_stubs.c) statfs now claims to have a single used block. + Avoids ambiguity between 100% and 0% full. + + * (nfs_stubs.c) changed to allow the size of symlinks optionally + to be accurate wrt the length of the string returned. Optional + because it is cheaper to ignore the length when doing a getattr + and just send any length for the readlink. However, this breaks + on some systems (e.g. Ultrix). + + * (mount_fs.c) automount points get marked type "nfs" instead of + "ignore". This is to fix an interaction with getwd(). Can go + away when getwd() gets re-written. Really only applies to SunOS4 + but change applies to everything to keep consistent across platforms. + + * (mount_fs.c) abstracted out mount options into a table and + corresponding loop. + + * (srvr_nfs.c) make sure portmap information is available when + needed, not just after a ping has succeeded. This needed changing + after the ping algorithm got changed. + + * (mntfs.c) fixed incorrect reference to mf_error instead of mf_flags. + + * (nfs_start.c) keep track of number of fds in use, so don't run + select on system maximum (which is bad news if you have a large + system maximum). + + * (host_ops.c) new NFS tree mount filesystem type (ala Sun -hosts). + + * (nfs_ops.c) abstracted out NFS mount code to support host_ops. + + * (afs_ops.c) dfs_readlink now returns the am_node, instead of the + link. This allows getattr to return the correct set of attributes + so keeping Ultrix happy. + + * (afs_ops.c) Make certain the hostname field given to mount() + does not get too long - otherwise random EINVAL errors occur. + + * Putting closing comments on all #endif's + +Sun May 13 16:07:21 1990 Jan-Simon Pendry (jsp at achilles) + + * (srvr_nfs.c) second rewrite of NFS ping algorithm. + +Sun Apr 29 21:12:33 1990 Jan-Simon Pendry (jsp at achilles) + + * (nfs_stubs.c) re-arranged readlink code to avoid need to + pre-mount a direct filesystem whenever possible. + + * (host_ops.c) finally incorporated new module to support /net + mount point. + +Sat Mar 24 13:18:47 1990 Jan-Simon Pendry (jsp at achilles) + + * (nfs_stubs.c) workaround added to rename entry point to avoid + arguments with NFS client code. + + * (srvr_nfs.c) changed the way NFS pings are done and cleaned up + the process for deciding when a server is up or down. Now there + is just a simple time limit on a reply from the server. The limit + is adjusted depending on whether the state of the server is known. + + * (opts.c) fixed bug with ${var/} expansion et al. Added ${varN} + N = 0..7 for use as scratch variables. + + * (mntfs.c) fixed bug in dup_mntfs(). + +Thu Jan 11 16:56:41 1990 Jan-Simon Pendry (jsp at achilles) + + * Release 5.1c. + + * (amq*) has new options. -f flushes the map cache and -m prints + information about mounted filesystem and fileservers. + +Tue Jan 2 14:44:21 1990 Jan-Simon Pendry (jsp at achilles) + + * (util.c) am_mounted() patches the path for "direct" mounted + filesystems - cosmetic. + + * (afs_ops.c) when possible sets a small kernel attribute cache + timeout on the automount points. + + * (nfs_stubs.c) delete() and rmdir() operations implemented. Used + when a mount point is timed out so the kernel name cache gets to + know about the changes. Fixes most ESTALE errors. + + * (nfs_stubs.c) New do_readlink() function added. This is used to + make sure that a filesystem is mounted at the time a link is read + in the case of "direct" mounts. Done so that the length of the + link is available when the initial getattr is done on the mountpoint. + + * (sfs_ops.c) Changed implementation to avoid race conditions. + The link target is re-arranged so that sublink points to the + target and fs always points at ".". + + * Fixed mount flag bug on Ultrix. + + * Added support from Sjoerd Mullender for Alliant FX/4 and Encore + Multimax. + +Thu Dec 7 17:55:29 1989 Jan-Simon Pendry (jsp at achilles) + + * (afs_ops.c) dfs_readlink now does a new_ttl on the node it + returns. + + * (afs_ops.c) next_nonerror_node now implements the task after + which it is named. + +Tue Nov 28 17:20:52 1989 Jan-Simon Pendry (jsp at achilles) + + * Release 5.1b. + + * (restart.c) Generates link nodes for any unrecognised filesystem + types and then marks them so that they are never deleted (since + they could never be automounted later). + + * (os-*.h) Irrelevant #undef's deleted. + + * (arch) Now knows about AIX on RTs. + + * (amq.c) Rationalised the output. Now only gives you what you + asked for. + + * (am.h) New macro: FSRV_ISDOWN(fs), which checks whether a + fileserver is down. + + * (afs_ops.c) When a mount fails due to a timeout the underlying + filesystem is ripped away and replaced with an error fs. This + avoids the possibility of being left with a single error reference + to a valid mounted filesystem. + +Thu Nov 23 18:04:29 1989 Jan-Simon Pendry (jsp at achilles) + + * (nfs_start.c) Re-order bootstrap sequence to avoid potential + deadlock if restart() ends up accessing one of the automount points. + + * (amq.c) Don't produce default mount output if one of the -l, -x + or -D options was used. + + * (umount_fs.c) Add alternative unmount routine for 4.4 BSD. + +Mon Nov 20 16:22:50 1989 Jan-Simon Pendry (jsp at achilles) + + * (os-bsd44.h) Fixed redefinition of UMOUNT_FS. + + * (info_ndbm.c) Added missing #include <sys/stat.h>. + + * (mapc.c) Fixed typo in ifdef around gdbm config entry. + +Sat Nov 18 16:39:13 1989 Jan-Simon Pendry (jsp at achilles) + + * (util.c) If "/" is automounted, make sure it is never timed out. + + * (mtab.c) Missing clock invalidation added in read_mtab (from a file). + + * (mntfs.c) realloc_mntfs simplified. + + * (map.c) Closed a race condition during shutdown when second and + subsequent duplicate mounts were deleted prematurely. + + * (afs_ops.c) Duplicate mounts are now given the correct return + code. + +Fri Nov 17 18:58:18 1989 Jan-Simon Pendry (jsp at achilles) + + * 5.1 Release. + +Thu Nov 16 17:57:02 1989 Jan-Simon Pendry (jsp at achilles) + + * (mntfs.c) Make sure inherit mntfs structures are not cached + after last reference; otherwise a second reference to the + inherited filesystem will get stuck on the inherit rather than the + (now) fully mounted filesystem. + + * (am.c, nfs_start.c) After forking the server, make sure the + parent does not exit until the automount points are mounted. This + allows a clean sequence during system startup. + + * Initial port to 4.4 BSD. Several new configuration abstractions + were added to make this port possible. + +Thu Nov 9 21:42:14 1989 Jan-Simon Pendry (jsp at achilles) + + * (afs_ops.c, opts.c) Added map logging to facilitate mount map + debugging without needing a -DDEBUG version of Amd. + + * (afs_ops.c) Make sure the length of the fs_hostname mount + parameter does not exceed MAXHOSTNAMESZ. + +Wed Nov 8 13:44:02 1989 Jan-Simon Pendry (jsp at achilles) + + * Change the message log format to indicate the severity of the + message to allow simpler analysis of the log file. + +Tue Nov 7 14:11:36 1989 Jan-Simon Pendry (jsp at achilles) + + * 5.0 Patchlevel 11. + + * (os-bsd44.h) Initial guess at 4.4 BSD definitions. + + * (os-aux.h) Port for Macintosh II from Julian Onions. + + * (amq.c) Output formats cleaned up. AMQ_MNTTREE is still broken + in amq_subr.c though. + + * (afs_ops.c) If a mount timed out, for example an NFS server was + down at the time, it was possible for the error code to remain + unset thus jamming that mount node in a state from which it could + not recover. Just make sure that the mf_error field gets filled + in when an error occurs. + + * (afs_ops.c) strsplit is run over /defaults to avoid problems + with whitespace creeping in. + +Sun Nov 5 11:50:51 1989 Jan-Simon Pendry (jsp at achilles) + + * (util.c) am_mounted: Added missing initialisation of stats.s_mtime. + +Fri Nov 3 17:33:02 1989 Jan-Simon Pendry (jsp at achilles) + + * 5.0 Patchlevel 10. + + * Changed the copyright. + +Thu Nov 2 17:07:53 1989 Jan-Simon Pendry (jsp at achilles) + + * 5.0 Patchlevel 9. + + * (opts.c) new option syntax: == != := + + * (nfs_ops.c) Less caching of filehandles. Now cached errors are + discarded after use. + + * (mtab.c) now attempts to deal with a lack of open file slots (ENFILE). + + * (mount_fs.c) automount entries in the mount table now have a + dev= entry in the same way as NFS and UFS. + + * (mntfs.c) mntfs nodes are now cached after the last reference + and discarded <ALLOWED_MOUNT_TIME> seconds later. This avoids + thrashing during a mount. + + * (mapc.c) map default cache mode is now selected with + "mapdefault", not "default" + + * (amd.tex) numerous clarifications. Still more work required... + + * (amq_subr.c) now allows the -x option of amq to operate. + + * (afs_ops.c) afs_bgmount now keeps track of which filesystem + needed retrying and ensures that the mount node in the + continuation correctly points at an unmounted filesystem. This + fixes a problem whereby a valid mounted filesystem could appear to + have failed to mount. + + * Configure now gives more of a running commentary and checks + whether os-type and arch actually worked. + + * Allow spurious ';'s in a mount location. + +Fri Oct 27 14:03:31 1989 Jan-Simon Pendry (jsp at achilles) + + * foo=blah changed to foo:=blah, foo==blah and foo!=blah. + + * -l stderr changed to -l /dev/stderr. + +Thu Oct 19 15:34:28 1989 Jan-Simon Pendry (jsp at achilles) + + * 5.0 Patchlevel 6. + + * LOG_INFO messages have been rationalised so that some + statistics, graphs and so on can be generated. + + * Transaction ID's for RPC calls are now allocated by the + individual callers, rather than from a central pool. This + decreases the load on mount daemons and NFS servers since the + same XID is used for retries when needed. + + * Many fine details of the new data structures have been changed. + Some areas have been optimized. + +Fri Oct 13 12:31:26 1989 Jan-Simon Pendry (jsp at achilles) + + * Restart code re-implemented to work with the new data structures. + + * Fine tuning applied to new NFS server modeling code. + +Thu Oct 12 15:57:24 1989 Jan-Simon Pendry (jsp at achilles) + + * Added ${/var} and ${var/} variable expansions. The first gives + the "basename" component of the variable, the latter gives the + "dirname" component. Additionally, spurious /'s are deleted after + the variable expansions is complete. + + * Added new -C option to allow the machine's cluster name to be + given to amd. ${cluster} fetches the value and can be used as + another selector. + + * Broken the major data struct (am_node) into three layers: + am_node (one for each automount node), mntfs (one for each mounted + filesystem) and fserver (one for each file server). Machine + up/down state is maintained in the fserver layer. Filesystem + mount/unmount state is maintained in the mntfs layer. This change + fixes the last known major problem caused by the lack of a central + focus for filesystem and fileserver status. There is a dummy file + server layer for local filesystems (ufs, link, program, error). + +Tue Oct 10 11:15:42 1989 Jan-Simon Pendry (jsp at achilles) + + * 5.0 Patchlevel 5. + + * (nfs_ops.c) the filehandle cache is now flushed when a + filesystem is unmounted. This avoids ending up with stale + information if a server bounces. + + * (clock.c) new module to implement callouts. Many other + routines changed to use callouts instead of messing with ttl + fields. + +Sun Oct 1 17:08:20 1989 Jan-Simon Pendry (jsp at achilles) + + * 5.0 Patchlevel 3 & 4. + + * Numerous cleanups. + +Wed Sep 13 14:30:05 1989 Jan-Simon Pendry (jsp at achilles) + + * 5.0 Patchlevel 2. + + * (nfs_ops.c) portmap information is not remembered beyond the + basic filehandle cache interval. That avoids problems when a new + portmap and/or rpc.mountd is started and the bound port changes. + + * (mapc.c) cache reloads are automatically done every hour. + + * Removed xlog macro in favour of plog() so that the log level + can be reflected through to syslog(). log() routine renamed to + plog() which takes an extra parameter indicating the log level. + +Tue Sep 5 20:00:19 1989 Jan-Simon Pendry (jsp at achilles) + + * (nfs_ops.c) when a server is known to be down, any cached file + handles and port mapping informaton is flushed since that may have + changed when it comes back up. + + * (map.c) timeout no longer attempts to unmount a hung mount point. + +Mon Sep 4 14:49:18 1989 Jan-Simon Pendry (jsp at achilles) + + * (afs_ops.c) a mount node which timed out during mount is now + retained for the normal timeout interval rather than for a short + period. This avoids wasting time retrying mounts from a server + which is down. + + * (afs_ops.c) hung mounts are now detected and not used as a + duplicate mount - something which defeated the replacement fs + scheme. + + * (nfs_ops.c) keepalive's now back-off when a server has gone + down. + +Thu Aug 31 21:18:35 1989 Jan-Simon Pendry (jsp at achilles) + + * 5.0 Patchlevel 1. + + * Fixed several bugs which showed up in the keepalive + implementation when a gateway went down causing + a different sequence of errors than usual. + +Wed Aug 30 11:29:21 1989 Jan-Simon Pendry (jsp at achilles) + + * (amq.x) now uses a Sun assigned program number. + + * Revision 5.0 - can now start using metaconfig. + +Tue Aug 29 14:36:48 1989 Jan-Simon Pendry (jsp at achilles) + + * (os-u3_0.h, os-type) now knows about DECstations (mips). + + * (nfs_stubs.c) Added hooks to readlink entry point to call + per-fs readlink routine if it exists, otherwise old behaviour. + + * (afs_ops.c) Added implementation of "type=direct". This is + the same as "type=auto" but is itself the link to the + mount point, rather than being a directory containing a list + of links to mount points. + +Mon Aug 28 17:48:15 1989 Jan-Simon Pendry (jsp at achilles) + + * (afs_ops.c) Changed readdir to workaround a problem on + ultrix 3 where it seems to forget that eof has been reached. + +Thu Aug 24 15:17:55 1989 Jan-Simon Pendry (jsp at achilles) + + * Created "beta16". + + * (afs_ops.c) /defaults is located along with every key. + this makes it possible to update the /defaults in + a map and get to use it. + + * (mapc.c) added map cache synchronization support. if + a file or ndbm map is updated the cache is junked so avoiding + things getting out of sync. + +Wed Aug 23 19:17:52 1989 Jan-Simon Pendry (jsp at achilles) + + * (os-u3_0.h) new file to support Ultrix 3.0 + + * (opts.c) allow environment variables to be accessed via + the same ${env} syntax used for options & selectors. + +Tue Aug 22 13:19:49 1989 Jan-Simon Pendry (jsp at achilles) + + * (opts.c, get_args.c) added support for kernel architecture + type to allow /usr/kvm to be automounted under SunOS 4.x. + + * (os-xinu43.h) updated for june '89 release of MORE/bsd. + + * (opts.c) fixed memory allocation problems where some strings + may not have been strdup'ed before they were free'ed so causing + the malloc arena to get into a twist. This caused core dumps on + some machines and infinite loops on others. + + * (*.c) clock handling is now done by a macro. Global variable + clock_valid is > 0 (ie the time) when valid, 0 if invalid. + + * (map.c) timeout code survived a complete rewrite and is now + O(n) rather than O(n^2). + + * (info_hes.c) new database hooks for Hesiod nameserver. + + * (get_args.c) the local sub-domain is picked up from the + hostname if it is not specifed with -d. The subdomain is + then stripped from the hostname. + + * (am.c) when a SIGTERM is received, an immediate abort + occurs - only the top-level automounts are unmounted; all + other mounts stay -- use amd -r to restart. + + * (afs_ops.c) cleaned up key prefix handling. Again updated + the "hostname" string passed to the kernel so that includes + the hostname, pid and mount point. + +Tue Aug 8 16:05:23 1989 Jan-Simon Pendry (jsp at achilles) + + * (nfs_ops.c) changed the way the file handle cache is managed. + No longer gets a race condition between something entering the + cache and being used and discard. + +Tue Jul 25 20:40:51 1989 Jan-Simon Pendry (jsp at achilles) + + * (map.c) changed fh_to_mp2 so that it does not return + ESTALE during shutdown. it returns ENOENT instead which + avoids thrashing with the kernel. + +Sun Jul 23 15:06:10 1989 Jan-Simon Pendry (jsp at achilles) + + * (afs_ops.c) make sure the incoming key from the kernel + does not contain any characters which could cause trouble + during macro expansion (such as `"! etc). + + * (afs_ops.c) fixed contruction of "mtab" entry. + +Fri Jul 21 11:01:05 1989 Jan-Simon Pendry (jsp at achilles) + + * (afs_ops.c) some changes to support the new startup + shutdown scheme. + + * (map.c) startup and shutdown are now done using the + standard interfaces. Startup is done by creating a + private cache map ";root;" and then doing lookups + on all the names in it. Shutdown is done by forcibly + timing out all the mount points including the automount + points. + + * (info_*.c) modified to provide interface required by + mapc.c module. + + * (mapc.c) new module to implement map caching. Caching + can be controlled by an fs option. "all" means cache + the entire map (if possible). "inc" means cache things + incrementally. "none" means never cache things. Each + map type has a default caching mode which is used if + cache option "default" is used. + +Wed Jul 19 16:14:52 1989 Jan-Simon Pendry (jsp at achilles) + + * (sched.c) implements a general sleep/wakeup scheme and uses + it for sub-process handling. + + * (nfs_start.c) task_notify() called from where it used to + be called. + + * (nfs_ops.c) now implements a non-blocking rpc library. + Everything in nfs_ops was changed to use it. This should + not be in this file and will be moved later. + + * (map.c) if a mount point times out and it is deferred then + issue a wakeup so that it can be retried. + + * (map.c) when creating a new mount point fetches the entry + "/defaults" from the associated map if no other options are + specified. + + * (am.c) implements the -p (print process id) option. + + * (afs_ops.c) a mount attempt now has a time-to-live of twenty + seconds. if only deferred attempts are waiting after that + interval the kernel gets sent ETIMEDOUT. + + * (afs_ops.c) the name by which the kernel knows the filesystem + has changed from pid%d@host to /mountpoint@host. That looks + better to users who get hit by it. + +Fri Jul 14 18:46:16 1989 Jan-Simon Pendry (jsp at achilles) + + * (afs_ops.c) now knows about defered mounts - mounts which + are not in progress, not completed, and not failed. + + * (sched.c) added new entry point sched_ast(). This simulates + a completed job. The basic idea is to let something else return + to the main scheduling loop with a guarentee that it will be + called back when some other action has taken place. + + * (nfs_ops.c) implemented a file handle cache. The nfs_init + routine starts up a request for the filehandle and the mount + routine uses it when it arrives. + +Thu Jul 13 18:07:58 1989 Jan-Simon Pendry (jsp at achilles) + + * (afs_ops.c) found a race condition between an error occuring + and the am_node being timed out. Fixed by updating the + time-to-live and keepalive counters in the node whenever + AMF_MOUNTING is cleared. Also changed afs_lookuppn() so that + it doesn't destroy the node when it returns the error code. + This stops thrashing and the node is eventually timed out. + Now the only way a node gets deleted is by the timeout code + which seems more elegant. + +Tue Jul 11 15:36:44 1989 Jan-Simon Pendry (jsp at achilles) + + * Created "beta15". + + * Fixed *all* references to "u2.2". Some where missed in + the original change. They are now u2_2. + + * (mk-amd-map.c) new command. Converts plain files into + ndbm databases for use by the info_ndbm module. Hooks + included for future support for gdbm just as soon as I + can get a copy. + +Sun Jul 9 19:00:22 1989 Jan-Simon Pendry (jsp at achilles) + + * Created "beta14". + + * (get_info.c) code to handle yp and files now split into + new files info_yp.c and info_file.c New support for ndbm + databases is in info_ndbm.c. A table in get_info.c controls + what and in which order things are searched. + + * (map.c, nfs_stubs.c) better handling for hung mount points. + if a filehandle is passed in by the kernel which references + a hung node, then try to find a replacement, possibly by calling + lookup explicitly. + + * (*.c) use new xlog(level)(message) interface + +Thu Jun 8 20:28:55 1989 Jan-Simon Pendry (jsp at achilles) + + * (nfs_ops.c, ufs_ops.c) when compiled with DEBUG, display + the fs options being used. + + * (am.c) make test for root a little more polite. + + * (get_args.c) update Usage message to include -r option. + +Wed Jun 7 16:28:51 1989 Jan-Simon Pendry (jsp at achilles) + + * (rpc_fwd.c) fwd_reply: if the recvfrom call fails because it + is interrupted then try again. + +Tue Jun 6 16:39:15 1989 Jan-Simon Pendry (jsp at achilles) + + * Created "beta12". + + * (afs_ops.c) inheriting mount option list from command line + is now cumulative. A -foo on the command line is prepended + to the default option list taken from the map. This can be + used to override the ``default default'' options in opts.c. + + * (get_args.c, am.c) added new -r (restart) option. Restart of + mounted filesystems is only done if this option is specified. + [Should *not* be specified in /etc/rc.local of course. - wrong] + + * (yp_master.c) make the enumeration error message more verbose + when debugging is enabled. + + * (rpc_fwd.c) rearranged some declarations at the top. Removed + a spurious call to free which was causing grief on some systems, + but not on Sun's. [This problem was the reason for implementing + the -D mem option.] + + * (opts.c) make sure opt_key and opt_path are set to a zero + length string unless otherwise specified. Previously they + were a source of dangling pointers. + + * (nfs_ops.c) make sure that the allocated nfs_private identifiers + are unique even when some filesystem are being restarted. This mean + starting the basic allocation from 1, not zero. + + * (am.h, get_args.c, util.c) added definition and implmentation of + a simple memory allocation trace (D_MEM). + + * (afs_ops.c) afs_lookuppn: tightened up memory allocation and + delay string copying until last possible moment. + +Mon Jun 5 18:01:18 1989 Jan-Simon Pendry (jsp at achilles) + + * (Makefile.com) diffs: added new rule to generate diffs + between versions. + + * (get_info.c) search_file: added a new dlog() to note when + wildcards are returned. + + * (afs_ops.c) afs_lookuppn: call to init_map specifies efs as + the default ops structure. If the location list only contained + defaults and no real mounts then this previously caused a null + pointer dereference. + + * (map.c) last_used_map: Added new variable. Keeps track of the + last used map, which may be wildly different from first_free_map. + This fixes bugs in several routines in this file. + + * (util.c) mkdirs, rmdirs: Changed directory make/unmake. It is + not possible to quickly determine how many directories need to + be created or deleted, so we try to make as many as possible. + + * (opts.c) Added default values for rfs, rhost and fs. + The new defaults guarentee unique names to allow the NFS + keepalive stuff to work. + +Sun Jun 4 16:12:15 1989 Jan-Simon Pendry (jsp at achilles) + + * First draft of documentation included in the next release. + + * Hooks for TFS added, though this still requires a lot of work. + + * Re-implemented option handling. Options are now allocated + dynamically on a per-mount basis in the continuation structure. + + * Changed os type u2.2 to u2_2 to allow for regular expression + matching in selectors. + + * Format of mount maps is now entirely different. Instead of + guessing which filesystem type is being used, it is now explicitly + stated along with the required options. Variable expansion is + done on the options and selectors are also implemented. The + requested name can also contain any of the selectors. + +Wed May 24 15:21:39 1989 Jan-Simon Pendry (jsp at achilles) + + * Re-implemented NFS ping algorithm to use the new RPC forwarding + system. This allowed a large amount of nfs_ops specific code + to be removed from nfs_start.c and moved to nfs_ops.c. + There is still no strategy for hung file systems. At the moment + it will merely try to mount an alternative (or the same again) + to the same place in the file system. + + * Added RPC forwarding package. This supports general RPC gatewaying + over a UDP transport. The idea is to put a packet identifier into + each outgoing RPC packet and then match that up in a database when + a reply comes in. The database records the original packet identifier + (so that it can be replaced), the source address for the packet and + a function to call to do the forwarding. + + * ChangeLog added between beta8 and beta9. Should have done this sooner. diff --git a/usr.sbin/amd/amd/Makefile b/usr.sbin/amd/amd/Makefile new file mode 100644 index 000000000000..328fd8064a86 --- /dev/null +++ b/usr.sbin/amd/amd/Makefile @@ -0,0 +1,33 @@ +# @(#)Makefile 8.2 (Berkeley) 4/22/94 + +PROG= amd +MAN8= amd.0 +OS= bsd44 +SRCS= afs_ops.c am_ops.c clock.c util.c xutil.c \ + efs_ops.c mapc.c info_file.c info_hes.c \ + info_ndbm.c info_passwd.c info_nis.c \ + info_union.c map.c srvr_afs.c srvr_nfs.c \ + mntfs.c misc_rpc.c mount_fs.c mount_xdr.c \ + mtab.c mtab_bsd.c nfs_ops.c nfs_prot_svc.c \ + nfs_start.c nfs_subr.c nfs_prot_xdr.c opts.c \ + pfs_ops.c rpc_fwd.c sched.c sfs_ops.c amq_svc.c \ + amq_subr.c umount_fs.c host_ops.c nfsx_ops.c \ + ufs_ops.c ifs_ops.c amd.c get_args.c restart.c wire.c +OBJS+= vers.${PROG}.o +LDADD+= -lrpc +CFLAGS+=-I${.CURDIR}/../rpcx +CFLAGS+=-I${.CURDIR}/../config +CFLAGS+=-I${.CURDIR}/../include +CFLAGS+=-DARCH_REP=\"${MACHINE}\" +CFLAGS+=-DOS_REP=\"${OS}\" +CFLAGS+=-DOS_HDR=\"os-${OS}.h\" +CFLAGS+=${CONFIG} +CLEANFILES+=vers.${PROG}.c vers.${PROG}.o version.amd + +vers.${PROG}.c: ${SRCS:.c=.o} + @d=${.CURDIR}/ sh ${.CURDIR}/../config/newvers.sh ${PROG} ${MACHINE} ${OS} + +.PATH: ${.CURDIR}/../rpcx ${.CURDIR}/../config +.include "Makefile.config" +.include "../../Makefile.inc" +.include <bsd.prog.mk> diff --git a/usr.sbin/amd/amd/afs_ops.c b/usr.sbin/amd/amd/afs_ops.c new file mode 100644 index 000000000000..6dfdc1401bcb --- /dev/null +++ b/usr.sbin/amd/amd/afs_ops.c @@ -0,0 +1,1816 @@ +/* + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990, 1993 + * 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. + * + * @(#)afs_ops.c 8.1 (Berkeley) 6/6/93 + * + * $Id: afs_ops.c,v 5.2.2.4 1992/05/31 16:36:36 jsp Exp $ + * + */ + +#include "am.h" + +#define NFS +#define NFSCLIENT + +#include <sys/stat.h> +#ifdef NFS_3 +typedef nfs_fh fhandle_t; +#endif /* NFS_3 */ +#ifdef NFS_HDR +#include NFS_HDR +#endif /* NFS_HDR */ +#include <sys/mount.h> +#include "mount.h" + +/* + * Automount file system + * Direct file system + * Root file system + * Top-level file system + */ + +/* + * Interval between forced retries of a mount. + */ +#define RETRY_INTERVAL 2 + +/* + * AFS needs nothing in particular. + */ +static char *afs_match P((am_opts *fo)); +static char *afs_match(fo) +am_opts *fo; +{ + char *p = fo->opt_rfs; + if (!fo->opt_rfs) { + plog(XLOG_USER, "auto: no mount point named (rfs:=)"); + return 0; + } + if (!fo->opt_fs) { + plog(XLOG_USER, "auto: no map named (fs:=)"); + return 0; + } + /* + * Swap round fs:= and rfs:= options + * ... historical (jsp) + */ + fo->opt_rfs = fo->opt_fs; + fo->opt_fs = p; + /* + * mtab entry turns out to be the name of the mount map + */ + return strdup(fo->opt_rfs ? fo->opt_rfs : "."); +} + +/* + * Mount an automounter directory. + * The automounter is connected into the system + * as a user-level NFS server. mount_toplvl constructs + * the necessary NFS parameters to be given to the + * kernel so that it will talk back to us. + */ +static int mount_toplvl P((char *dir, char *opts)); +static int mount_toplvl(dir, opts) +char *dir; +char *opts; +{ + struct nfs_args nfs_args; + struct mntent mnt; + int retry; + struct sockaddr_in sin; + unsigned short port; + int flags; + extern nfs_fh *root_fh(); + nfs_fh *fhp; + char fs_hostname[MAXHOSTNAMELEN+MAXPATHLEN+1]; + + MTYPE_TYPE type = MOUNT_TYPE_NFS; + + bzero((voidp) &nfs_args, sizeof(nfs_args)); /* Paranoid */ + + mnt.mnt_dir = dir; + mnt.mnt_fsname = pid_fsname; + mnt.mnt_type = MNTTYPE_AUTO; + mnt.mnt_opts = opts; + mnt.mnt_freq = 0; + mnt.mnt_passno = 0; + + retry = hasmntval(&mnt, "retry"); + if (retry <= 0) + retry = 2; /* XXX */ + + /* + * get fhandle of remote path for automount point + */ + + fhp = root_fh(dir); + if (!fhp) { + plog(XLOG_FATAL, "Can't find root file handle for %s", dir); + return EINVAL; + } + + NFS_FH_DREF(nfs_args.fh, (NFS_FH_TYPE) fhp); + + /* + * Create sockaddr to point to the local machine. 127.0.0.1 + * is not used since that will not work in HP-UX clusters and + * this is no more expensive. + */ + bzero((voidp) &sin, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr = myipaddr; + if (port = hasmntval(&mnt, "port")) { + sin.sin_port = htons(port); + } else { + plog(XLOG_ERROR, "no port number specified for %s", dir); + return EINVAL; + } + + /* + * set mount args + */ + NFS_SA_DREF(nfs_args, &sin); + + /* + * Make a ``hostname'' string for the kernel + */ +#ifndef HOSTNAMESZ +#define SHORT_MOUNT_NAME +#endif /* HOSTNAMESZ */ +#ifdef SHORT_MOUNT_NAME + sprintf(fs_hostname, "amd:%d", foreground ? mypid : getppid()); +#else + sprintf(fs_hostname, "pid%d@%s:%s", foreground ? mypid : getppid(), hostname, dir); +#endif /* SHORT_MOUNT_NAME */ + nfs_args.hostname = fs_hostname; + nfs_args.flags |= NFSMNT_HOSTNAME; +#ifdef HOSTNAMESZ + /* + * Most kernels have a name length restriction. + */ + if (strlen(fs_hostname) >= HOSTNAMESZ) + strcpy(fs_hostname + HOSTNAMESZ - 3, ".."); +#endif /* HOSTNAMESZ */ + +#ifdef NFSMNT_DUMBTIMR + nfs_args.flags |= NFSMNT_DUMBTIMR; + plog(XLOG_INFO, "defeating nfs window computation"); +#endif + + /* + * Parse a subset of the standard nfs options. The + * others are probably irrelevant for this application + */ + if (nfs_args.timeo = hasmntval(&mnt, "timeo")) + nfs_args.flags |= NFSMNT_TIMEO; + + if (nfs_args.retrans = hasmntval(&mnt, "retrans")) + nfs_args.flags |= NFSMNT_RETRANS; + +#ifdef NFSMNT_BIODS + if (nfs_args.biods = hasmntval(&mnt, "biods")) + nfs_args.flags |= NFSMNT_BIODS; + +#endif /* NFSMNT_BIODS */ + +#if defined(NFSMNT_ACREGMIN) && defined(NFSMNT_ACREGMAX) + /* + * Don't cache attributes - they are changing under + * the kernel's feet... + */ + nfs_args.acregmin = nfs_args.acregmax = 1; + nfs_args.flags |= NFSMNT_ACREGMIN|NFSMNT_ACREGMAX; +#endif /* defined(NFSMNT_ACREGMIN) && defined(NFSMNT_ACREGMAX) */ + /* + * These two are constructed internally by the calling routine + */ + if (hasmntopt(&mnt, MNTOPT_SOFT) != NULL) + nfs_args.flags |= NFSMNT_SOFT; + +#ifdef MNTOPT_INTR + if (hasmntopt(&mnt, MNTOPT_INTR) != NULL) + nfs_args.flags |= NFSMNT_INT; +#endif /* MNTOPT_INTR */ + + flags = compute_mount_flags(&mnt); +#ifdef ULTRIX_HACK + nfs_args.gfs_flags = flags; + flags &= M_RDONLY; + if (flags & M_RDONLY) + nfs_args.flags |= NFSMNT_RONLY; +#endif /* ULTRIX_HACK */ + return mount_fs(&mnt, flags, (caddr_t) &nfs_args, retry, type); +} + +static void afs_mkcacheref P((mntfs *mf)); +static void afs_mkcacheref(mf) +mntfs *mf; +{ + /* + * Build a new map cache for this node, or re-use + * an existing cache for the same map. + */ + 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_prfree = mapc_free; +} + +/* + * Mount the root... + */ +static int root_mount P((am_node *mp)); +static int root_mount(mp) +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, ""); + mf->mf_prfree = mapc_free; + + return 0; +} + +/* + * Mount a sub-mount + */ +static int afs_mount P((am_node *mp)); +static int afs_mount(mp) +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.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) { + /* + * 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 + */ + afs_mkcacheref(mf); + + return 0; +} + +/* + * Mount the top-level + */ +static int toplvl_mount P((am_node *mp)); +static int toplvl_mount(mp) +am_node *mp; +{ + mntfs *mf = mp->am_mnt; + struct stat stb; + char opts[256]; + int error; + char *mnttype; + + /* + * Mounting the automounter. + * Make sure the mount directory exists, construct + * the mount options and call the mount_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 == &toplvl_ops) mnttype = "indirect"; + else if (mf->mf_ops == &dfs_ops) mnttype = "direct"; +#ifdef HAS_UNION_FS + else if (mf->mf_ops == &union_ops) mnttype = "union"; +#endif + else mnttype = "auto"; + + /* + * Construct some mount options + */ + sprintf(opts, +#ifdef MNTOPT_INTR + "%s,%s,%s=%d,%s=%d,%s=%d,%s", + MNTOPT_INTR, +#else + "%s,%s=%d,%s=%d,%s=%d,%s", +#endif /* MNTOPT_INTR */ + "rw", + "port", nfs_port, + "timeo", afs_timeo, + "retrans", afs_retrans, + mnttype); + + error = mount_toplvl(mf->mf_mount, opts); + if (error) { + errno = error; + plog(XLOG_FATAL, "mount_toplvl: %m"); + return error; + } + + return 0; +} + +static void toplvl_mounted P((mntfs *mf)); +static void toplvl_mounted(mf) +mntfs *mf; +{ + afs_mkcacheref(mf); +} + +#ifdef HAS_UNION_FS +/* + * Create a reference to a union'ed entry + */ +static int create_union_node P((char *dir, voidp arg)); +static int create_union_node(dir, arg) +char *dir; +voidp arg; +{ + if (strcmp(dir, "/defaults") != 0) { + int error = 0; + (void) 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 union_mounted P((mntfs *mf)); +static void union_mounted(mf) +mntfs *mf; +{ + int i; + + afs_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_union_node is ignored by mapc_keyiter */ + (void) mapc_keyiter((mnt_map *) mp->am_mnt->mf_private, + (void (*)P((char*,void*))) create_union_node, mp); + break; + } + } + +#ifdef notdef + /* + * would be nice to flush most of the cache, but we need to + * keep the wildcard and /defaults entries... + */ + mapc_free(mf->mf_private); + mf->mf_private = (voidp) mapc_find(mf->mf_info, "inc"); +/* mapc_add_kv(mf->mf_private, strdup("/defaults"), + strdup("type:=link;opts:=nounmount;sublink:=${key}")); */ +#endif +} +#endif /* HAS_UNION_FS */ + +/* + * Unmount an automount sub-node + */ +static int afs_umount P((am_node *mp)); +static int afs_umount(mp) +am_node *mp; +{ + return 0; +} + +/* + * Unmount a top-level automount node + */ +static int toplvl_umount P((am_node *mp)); +static int toplvl_umount(mp) +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); + if (error == EBUSY) { + plog(XLOG_WARNING, "afs_unmount retrying %s in 1s", mp->am_path); + sleep(1); /* XXX */ + goto again; + } + + return error; +} + +/* + * Unmount an automount node + */ +static void afs_umounted P((am_node *mp)); +static void afs_umounted(mp) +am_node *mp; +{ + /* + * If this is a pseudo-directory then just adjust the link count + * in the parent, otherwise call the generic unmount routine + */ + if (mp->am_parent && mp->am_parent->am_parent) + --mp->am_parent->am_fattr.nlink; +} + +/* + * Mounting a file system may take a significant period of time. The + * problem is that if this is done in the main process thread then + * the entire automounter could be blocked, possibly hanging lots of + * processes on the system. Instead we use a continuation scheme to + * allow mounts to be attempted in a sub-process. When the sub-process + * exits we pick up the exit status (by convention a UN*X error number) + * and continue in a notifier. The notifier gets handed a data structure + * and can then determine whether the mount was successful or not. If + * not, it updates the data structure and tries again until there are no + * more ways to try the mount, or some other permanent error occurs. + * In the mean time no RPC reply is sent, even after the mount is succesful. + * We rely on the RPC retry mechanism to resend the lookup request which + * can then be handled. + */ + + +struct continuation { + char **ivec; /* Current mount info */ + am_node *mp; /* Node we are trying to mount */ + char *key; /* Map key */ + char *info; /* Info string */ + char **xivec; /* Saved strsplit vector */ + char *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 */ +}; + +#define IN_PROGRESS(cp) ((cp)->mp->am_mnt->mf_flags & MFF_MOUNTING) + +/* + * Discard an old continuation + */ +static void free_continuation P((struct continuation *cp)); +static void free_continuation(cp) +struct continuation *cp; +{ + if (cp->callout) + untimeout(cp->callout); + free((voidp) cp->key); + free((voidp) cp->xivec); + free((voidp) cp->info); + free((voidp) cp->auto_opts); + free((voidp) cp->def_opts); + free_opts(&cp->fs_opts); + free((voidp) cp); +} + +static int afs_bgmount P((struct continuation*, int)); + +/* + * Discard the underlying mount point and replace + * with a reference to an error filesystem. + */ +static void assign_error_mntfs P((am_node *mp)); +static void assign_error_mntfs(mp) +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. + */ +static void afs_cont P((int rc, int term, voidp closure)); +static void afs_cont(rc, term, closure) +int rc; +int term; +voidp closure; +{ + struct continuation *cp = (struct continuation *) closure; + mntfs *mf = cp->mp->am_mnt; + + /* + * Definitely not trying to mount at the moment + */ + mf->mf_flags &= ~MFF_MOUNTING; + /* + * While we are mounting - try to avoid race conditions + */ + new_ttl(cp->mp); + + /* + * Wakeup anything waiting for this mount + */ + wakeup((voidp) mf); + + /* + * Check for termination signal or exit status... + */ + if (rc || term) { + 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 */ + plog(XLOG_ERROR, "%s: mount (afs_cont): %m", cp->mp->am_path); + } + + /* + * If we get here then that attempt didn't work, so + * move the info vector pointer along by one and + * call the background mount routine again + */ + amd_stats.d_merr++; + cp->ivec++; + xmp = cp->mp; + (void) afs_bgmount(cp, 0); + assign_error_mntfs(xmp); + } else { + /* + * The mount worked. + */ + am_mounted(cp->mp); + free_continuation(cp); + } + + reschedule_timeout_mp(); +} + +/* + * Retry a mount + */ +/*ARGSUSED*/ +static void afs_retry P((int rc, int term, voidp closure)); +static void afs_retry(rc, term, closure) +int rc; +int term; +voidp closure; +{ + struct continuation *cp = (struct continuation *) closure; + int error = 0; + +#ifdef DEBUG + dlog("Commencing retry for mount of %s", cp->mp->am_path); +#endif /* DEBUG */ + + 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 + * afs_bgmount will not have any more + * ways to try the mount, so causing + * an error. + */ + plog(XLOG_INFO, "mount of \"%s\" has timed out", cp->mp->am_path); + error = ETIMEDOUT; + while (*cp->ivec) + cp->ivec++; + } + + if (error || !IN_PROGRESS(cp)) { + (void) afs_bgmount(cp, error); + } + reschedule_timeout_mp(); +} + +/* + * Try to mount a file system. Can be called + * directly or in a sub-process by run_task + */ +static int try_mount P((voidp mvp)); +static int try_mount(mvp) +voidp mvp; +{ + /* + * Mount it! + */ + int error; + 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 backgroun 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; + } + + error = mount_node(mp); +#ifdef DEBUG + if (error > 0) { + errno = error; + dlog("afs call to mount_node failed: %m"); + } +#endif /* DEBUG */ + return error; +} + +/* + * Pick a file system to try mounting and + * do that in the background if necessary + * +For each location: + if it is new -defaults then + extract and process + continue; + fi + if it is a cut then + if a location has been tried then + break; + fi + continue; + fi + parse mount location + discard previous mount location if required + find matching mounted filesystem + if not applicable then + this_error = No such file or directory + continue + fi + if the filesystem failed to be mounted then + this_error = error from filesystem + elif the filesystem is mounting or unmounting then + this_error = -1 + elif the fileserver is down then + this_error = -1 + elif the filesystem is already mounted + this_error = 0 + break + fi + if no error on this mount then + this_error = initialise mount point + fi + if no error on this mount and mount is delayed then + this_error = -1 + fi + if this_error < 0 then + retry = true + fi + if no error on this mount then + make mount point if required + fi + if no error on this mount then + if mount in background then + run mount in background + return -1 + else + this_error = mount in foreground + fi + fi + if an error occured on this mount then + update stats + save error in mount point + fi +endfor + */ + +static int afs_bgmount P((struct continuation *cp, int mpe)); +static int afs_bgmount(cp, mpe) +struct continuation *cp; +int mpe; +{ + mntfs *mf = cp->mp->am_mnt; /* Current mntfs */ + mntfs *mf_retry = 0; /* First mntfs which needed retrying */ + int this_error = -1; /* Per-mount error */ + int hard_error = -1; + int mp_error = mpe; + + /* + * Try to mount each location. + * At the end: + * hard_error == 0 indicates something was mounted. + * hard_error > 0 indicates everything failed with a hard error + * hard_error < 0 indicates nothing could be mounted now + */ + for (; this_error && *cp->ivec; cp->ivec++) { + am_ops *p; + am_node *mp = cp->mp; + char *link_dir; + int dont_retry; + + if (hard_error < 0) + hard_error = this_error; + + this_error = -1; + + if (**cp->ivec == '-') { + /* + * Pick up new defaults + */ + if (cp->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 (strcmp(*cp->ivec, "/") == 0 || strcmp(*cp->ivec, "||") == 0) { + if (cp->tried) { +#ifdef DEBUG + dlog("Cut: not trying any more locations for %s", + mp->am_path); +#endif /* DEBUG */ + break; + } + continue; + } + +#ifdef SUNOS4_COMPAT +#ifdef nomore + /* + * By default, you only get this bit on SunOS4. + * If you want this anyway, then define SUNOS4_COMPAT + * in the relevant "os-blah.h" file. + * + * We make the observation that if the local key line contains + * no '=' signs then either it is sick, or it is a SunOS4-style + * "host:fs[:link]" line. In the latter case the am_opts field + * is also assumed to be in old-style, so you can't mix & match. + * You can use ${} expansions for the fs and link bits though... + * + * Actually, this doesn't really cover all the possibilities for + * the latest SunOS automounter and it is debatable whether there + * is any point bothering. + */ + if (strchr(*cp->ivec, '=') == 0) + p = sunos4_match(&cp->fs_opts, *cp->ivec, cp->def_opts, mp->am_path, cp->key, mp->am_parent->am_mnt->mf_info); + else +#endif +#endif /* SUNOS4_COMPAT */ + p = ops_match(&cp->fs_opts, *cp->ivec, cp->def_opts, mp->am_path, cp->key, mp->am_parent->am_mnt->mf_info); + + /* + * Find a mounted filesystem for this node. + */ + mp->am_mnt = mf = realloc_mntfs(mf, p, &cp->fs_opts, cp->fs_opts.opt_fs, + cp->fs_opts.fs_mtab, cp->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 == &efs_ops) { + plog(XLOG_MAP, "Map entry %s for %s failed to match", *cp->ivec, mp->am_path); + if (this_error <= 0) + this_error = ENOENT; + continue; + } else { + if (cp->fs_opts.fs_mtab) { + plog(XLOG_MAP, "Trying mount of %s on %s fstype %s", + cp->fs_opts.fs_mtab, mp->am_path, p->fs_type); + } + cp->tried = TRUE; + } + + this_error = 0; + dont_retry = FALSE; + + if (mp->am_link) { + free(mp->am_link); + mp->am_link = 0; + } + + link_dir = mf->mf_fo->opt_sublink; + + if (link_dir && *link_dir) { + if (*link_dir == '/') { + mp->am_link = strdup(link_dir); + } else { + mp->am_link = str3cat((char *) 0, + mf->mf_fo->opt_fs, "/", link_dir); + 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.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 + 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, afs_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 afs_bgmount is called + * after anything else happens. + */ +#ifdef DEBUG + dlog("Arranging to retry mount of %s", cp->mp->am_path); +#endif /* DEBUG */ + sched_task(afs_retry, (voidp) cp, (voidp) mf); + if (cp->callout) + untimeout(cp->callout); + cp->callout = timeout(RETRY_INTERVAL, wakeup, (voidp) mf); + + cp->mp->am_ttl = clocktime() + RETRY_INTERVAL; + + /* + * Not done yet - so don't return anything + */ + return -1; + } + + 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 = 5; + break; + default: + cp->mp->am_timeo = 17; + 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 + */ +static am_node *afs_lookuppn P((am_node *mp, char *fname, int *error_return, int op)); +static am_node *afs_lookuppn(mp, fname, error_return, op) +am_node *mp; +char *fname; +int *error_return; +int op; +{ +#define ereturn(x) { *error_return = x; return 0; } + + /* + * Find the corresponding entry and return + * the file handle for it. + */ + am_node *ap, *new_mp, *ap_hung; + char *info; /* Mount info - where to get the file system */ + char **ivec, **xivec; /* Split version of info */ + char *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 we need to mount */ + int in_progress = 0; /* # of (un)mount in progress */ + char *dflts; + mntfs *mf; + +#ifdef DEBUG + dlog("in afs_lookuppn"); +#endif /* DEBUG */ + + /* + * If the server is shutting down + * then don't return information + * about the mount point. + */ + if (amd_state == Finishing) { +#ifdef DEBUG + if ((mf = mp->am_mnt) == 0 || mf->mf_ops == &dfs_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 -- in progress", + fname, mf->mf_mount); +#endif /* DEBUG */ + in_progress++; + continue; + } + + /* + * Otherwise we have a hit: return the current mount point. + */ +#ifdef DEBUG + dlog("matched %s in %s", fname, ap->am_path); +#endif /* DEBUG */ + free(fname); + return ap; + } + } + + if (in_progress) { +#ifdef DEBUG + dlog("Waiting while %d mount(s) in progress", in_progress); +#endif /* DEBUG */ + free(fname); + ereturn(-1); + } + + /* + * If an error occured then return it. + */ + if (error) { +#ifdef DEBUG + errno = error; /* XXX */ + dlog("Returning error: %m", error); +#endif /* DEBUG */ + free(fname); + ereturn(error); + } + + /* + * If doing a delete then don't create again! + */ + switch (op) { + case VLOOK_DELETE: + ereturn(ENOENT); + break; + + case VLOOK_CREATE: + break; + + default: + plog(XLOG_FATAL, "Unknown op to afs_lookuppn: 0x%x", op); + ereturn(EINVAL); + break; + } + + /* + * If the server is going down then just return, + * don't try to mount any more file systems + */ + if ((int)amd_state >= (int)Finishing) { +#ifdef DEBUG + dlog("not found - server going down anyway"); +#endif /* DEBUG */ + free(fname); + ereturn(ENOENT); + } + + /* + * If we get there then this is a reference to an, + * as yet, unknown name so we need to search the mount + * map for it. + */ + if (mp->am_pref) { + sprintf(path_name, "%s%s", mp->am_pref, fname); + pfname = path_name; + } else { + pfname = fname; + } + + mf = mp->am_mnt; + +#ifdef DEBUG + dlog("will search map info in %s to find %s", mf->mf_info, pfname); +#endif /* DEBUG */ + /* + * Consult the oracle for some mount information. + * info is malloc'ed and belongs to this routine. + * It ends up being free'd in free_continuation(). + * + * Note that this may return -1 indicating that information + * is not yet available. + */ + error = mapc_search((mnt_map*) mf->mf_private, pfname, &info); + if (error) { + if (error > 0) + plog(XLOG_MAP, "No map entry for %s", pfname); + else + plog(XLOG_MAP, "Waiting on map entry for %s", pfname); + free(fname); + ereturn(error); + } + +#ifdef DEBUG + dlog("mount info is %s", info); +#endif /* DEBUG */ + + /* + * Split info into an argument vector. + * The vector is malloc'ed and belongs to + * this routine. It is free'd in free_continuation() + */ + xivec = ivec = strsplit(info, ' ', '\"'); + + /* + * Default error code... + */ + if (ap_hung) + error = EWOULDBLOCK; + else + error = ENOENT; + + /* + * Allocate a new map + */ + new_mp = exported_ap_alloc(); + if (new_mp == 0) { + free((voidp) xivec); + free((voidp) info); + free((voidp) fname); + ereturn(ENOSPC); + } + + if (mf->mf_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, ' ', '\"'); + /* + * Extract first value + */ + dfl = rvec[0]; + + /* + * If there were any values at all... + */ + if (dfl) { + /* + * Log error if there were other values + */ + if (rvec[1]) { +#ifdef DEBUG + dlog("/defaults chopped into %s", dfl); +#endif /* DEBUG */ + plog(XLOG_USER, "More than a single value for /defaults in %s", mf->mf_info); + } + + /* + * 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); + free(auto_opts); + auto_opts = nopts; + } else if (*dfl) { + auto_opts = strealloc(auto_opts, dfl); + } + } + free(dflts); + /* + * Don't need info vector any more + */ + free((voidp) 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 == &dfs_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(continuation); + 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); + bzero((voidp) &cp->fs_opts, sizeof(cp->fs_opts)); + + /* + * Try and mount the file system + * If this succeeds immediately (possible + * for a ufs file system) then return + * the attributes, otherwise just + * return an error. + */ + error = afs_bgmount(cp, error); + reschedule_timeout_mp(); + if (!error) { + free(fname); + return new_mp; + } + + if (error && (cp->mp->am_mnt->mf_ops == &efs_ops)) + cp->mp->am_error = error; + + assign_error_mntfs(new_mp); + + free(fname); + + ereturn(error); +#undef ereturn +} + +/* + * Locate next node in sibling list which is mounted + * and is not an error node. + */ +static am_node *next_nonerror_node P((am_node *xp)); +static am_node *next_nonerror_node(xp) +am_node *xp; +{ + mntfs *mf; + + /* + * Bug report (7/12/89) from Rein Tollevik <rein@ifi.uio.no> + * Fixes a race condition when mounting direct automounts. + * Also fixes a problem when doing a readdir on a directory + * containing hung automounts. + */ + while (xp && + (!(mf = xp->am_mnt) || /* No mounted filesystem */ + mf->mf_error != 0 || /* There was a mntfs error */ + xp->am_error != 0 || /* There was a mount error */ + !(mf->mf_flags & MFF_MOUNTED) || /* The fs is not mounted */ + (mf->mf_server->fs_flags & FSF_DOWN)) /* The fs may be down */ + ) + xp = xp->am_osib; + + return xp; +} + +static int afs_readdir P((am_node *mp, nfscookie cookie, struct dirlist *dp, struct entry *ep, int count)); +static int afs_readdir(mp, cookie, dp, ep, count) +am_node *mp; +nfscookie cookie; +struct dirlist *dp; +struct entry *ep; +int count; +{ + unsigned int gen = *(unsigned int*) cookie; + am_node *xp; + + dp->eof = FALSE; + + if (gen == 0) { + /* + * In the default instance (which is used to + * start a search) we return "." and "..". + * + * This assumes that the count is big enough + * to allow both "." and ".." to be returned in + * a single packet. If it isn't (which would + * be fairly unbelievable) then tough. + */ +#ifdef DEBUG + dlog("default search"); +#endif /* DEBUG */ + /* + * 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->entries = ep; + + /* construct "." */ + ep[0].fileid = mp->am_gen; + ep[0].name = "."; + ep[0].nextentry = &ep[1]; + *(unsigned int *) ep[0].cookie = 0; + + /* construct ".." */ + if (mp->am_parent) + ep[1].fileid = mp->am_parent->am_gen; + else + ep[1].fileid = mp->am_gen; + ep[1].name = ".."; + ep[1].nextentry = 0; + *(unsigned int *) ep[1].cookie = + xp ? xp->am_gen : ~(unsigned int)0; + + if (!xp) dp->eof = TRUE; + return 0; + } + +#ifdef DEBUG + dlog("real child"); +#endif /* DEBUG */ + + if (gen == ~(unsigned int)0) { +#ifdef DEBUG + dlog("End of readdir in %s", mp->am_path); +#endif /* DEBUG */ + dp->eof = TRUE; + dp->entries = 0; + return 0; + } + + xp = mp->am_child; + while (xp && xp->am_gen != gen) + xp = xp->am_osib; + + if (xp) { + int nbytes = count / 2; /* conservative */ + int todo = MAX_READDIR_ENTRIES; + dp->entries = ep; + do { + am_node *xp_next = next_nonerror_node(xp->am_osib); + + if (xp_next) { + *(unsigned int *) ep->cookie = xp_next->am_gen; + } else { + *(unsigned int *) ep->cookie = ~(unsigned int)0; + dp->eof = TRUE; + } + + ep->fileid = xp->am_gen; + ep->name = xp->am_name; + nbytes -= sizeof(*ep) + strlen(xp->am_name) + 1; + + xp = xp_next; + + if (nbytes > 0 && !dp->eof && todo > 1) { + ep->nextentry = ep + 1; + ep++; + --todo; + } else { + todo = 0; + } + } while (todo > 0); + + ep->nextentry = 0; + + return 0; + } + + return ESTALE; + +} + +static am_node *dfs_readlink P((am_node *mp, int *error_return)); +static am_node *dfs_readlink(mp, error_return) +am_node *mp; +int *error_return; +{ + am_node *xp; + int rc = 0; + + xp = next_nonerror_node(mp->am_child); + if (!xp) { + if (!mp->am_mnt->mf_private) + afs_mkcacheref(mp->am_mnt); /* XXX */ + xp = afs_lookuppn(mp, mp->am_path+1, &rc, VLOOK_CREATE); + } + + if (xp) { + new_ttl(xp); /* (7/12/89) from Rein Tollevik */ + return xp; + } + if (amd_state == Finishing) + rc = ENOENT; + *error_return = rc; + return 0; +} + +/* + * Ops structure + */ +am_ops root_ops = { + "root", + 0, /* root_match */ + 0, /* root_init */ + root_mount, + 0, + afs_umount, + 0, + afs_lookuppn, + afs_readdir, + 0, /* root_readlink */ + 0, /* root_mounted */ + 0, /* root_umounted */ + find_afs_srvr, + FS_NOTIMEOUT|FS_AMQINFO|FS_DIRECTORY +}; + +am_ops afs_ops = { + "auto", + afs_match, + 0, /* afs_init */ + afs_mount, + 0, + afs_umount, + 0, + afs_lookuppn, + afs_readdir, + 0, /* afs_readlink */ + 0, /* afs_mounted */ + afs_umounted, + find_afs_srvr, + FS_AMQINFO|FS_DIRECTORY +}; + +am_ops toplvl_ops = { + "toplvl", + afs_match, + 0, /* afs_init */ + toplvl_mount, + 0, + toplvl_umount, + 0, + afs_lookuppn, + afs_readdir, + 0, /* toplvl_readlink */ + toplvl_mounted, + 0, /* toplvl_umounted */ + find_afs_srvr, + FS_MKMNT|FS_NOTIMEOUT|FS_BACKGROUND|FS_AMQINFO|FS_DIRECTORY +}; + +am_ops dfs_ops = { + "direct", + afs_match, + 0, /* dfs_init */ + toplvl_mount, + 0, + toplvl_umount, + 0, + efs_lookuppn, + efs_readdir, + dfs_readlink, + toplvl_mounted, + 0, /* afs_umounted */ + find_afs_srvr, + FS_MKMNT|FS_NOTIMEOUT|FS_BACKGROUND|FS_AMQINFO +}; + +#ifdef HAS_UNION_FS +am_ops union_ops = { + "union", + afs_match, + 0, /* afs_init */ + toplvl_mount, + 0, + toplvl_umount, + 0, + afs_lookuppn, + afs_readdir, + 0, /* toplvl_readlink */ + union_mounted, + 0, /* toplvl_umounted */ + find_afs_srvr, + FS_MKMNT|FS_NOTIMEOUT|FS_BACKGROUND|FS_AMQINFO|FS_DIRECTORY +}; +#endif /* HAS_UNION_FS */ diff --git a/usr.sbin/amd/amd/am_ops.c b/usr.sbin/amd/amd/am_ops.c new file mode 100644 index 000000000000..436011010fef --- /dev/null +++ b/usr.sbin/amd/amd/am_ops.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989, 1993 + * 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. + * + * @(#)am_ops.c 8.1 (Berkeley) 6/6/93 + * + * $Id: am_ops.c,v 5.2.2.1 1992/02/09 15:08:17 jsp beta $ + * + */ + +#include "am.h" + +static am_ops *vops[] = { +#ifdef HAS_UFS + &ufs_ops, +#endif +#ifdef HAS_NFS + &nfs_ops, +#endif +#ifdef HAS_NFSX + &nfsx_ops, +#endif +#ifdef HAS_HOST + &host_ops, +#endif +#ifdef HAS_SFS + &sfs_ops, +#endif +#ifdef HAS_SFSX + &sfsx_ops, +#endif +#ifdef HAS_LOFS + &lofs_ops, +#endif +#ifdef HAS_PFS + &pfs_ops, +#endif +#ifdef HAS_UNION_FS + &union_ops, +#endif + &afs_ops, /* These four should be last ... */ + &dfs_ops, /* ... */ + &toplvl_ops, /* ... */ + &efs_ops, /* ... in the order afs; dfs; toplvl; efs */ + 0 +}; + +void ops_showfstypes P((FILE *fp)); +void ops_showfstypes(fp) +FILE *fp; +{ + struct am_ops **ap; + int l = 0; + + for (ap = vops; *ap; ap++) { + fputs((*ap)->fs_type, fp); + if (ap[1]) fputs(", ", fp); + l += strlen((*ap)->fs_type) + 2; + if (l > 60) { l = 0; fputs("\n ", fp); } + } +} + +#ifdef SUNOS4_COMPAT +#ifdef nomore +/* + * Crack a SunOS4-style host:fs:sub-link line + * Construct an amd-style line and call the + * normal amd matcher. + */ +am_ops *sunos4_match(fo, key, g_key, path, keym, map) +am_opts *fo; +char *key; +char *g_key; +char *path; +char *keym; +char *map; +{ + char *host = key; + char *fs = strchr(host, ':'); + char *sublink = fs ? strchr(fs+1, ':') : 0; + char keybuf[MAXPATHLEN]; + + sprintf(keybuf, "type:=nfs;rhost:=%s;rfs:=%s;sublink:=%s;opts:=%s", host, + fs ? fs+1 : "", + sublink ? sublink+1 : "", + g_key); + return ops_match(fo, keybuf, "", path, keym, map); +} +#endif +#endif /* SUNOS4_COMPAT */ + +am_ops *ops_match(fo, key, g_key, path, keym, map) +am_opts *fo; +char *key; +char *g_key; +char *path; +char *keym; +char *map; +{ + am_ops **vp; + am_ops *rop = 0; + + /* + * First crack the global opts and the local opts + */ + if (!eval_fs_opts(fo, key, g_key, path, keym, map)) { + rop = &efs_ops; + } else if (fo->opt_type == 0) { + plog(XLOG_USER, "No fs type specified (key = \"%s\", map = \"%s\")", keym, map); + rop = &efs_ops; + } else { + /* + * Next find the correct filesystem type + */ + for (vp = vops; rop = *vp; vp++) + if (strcmp(rop->fs_type, fo->opt_type) == 0) + break; + + if (!rop) { + plog(XLOG_USER, "fs type \"%s\" not recognised", fo->opt_type); + rop = &efs_ops; + } + } + + /* + * Make sure we have a default mount option. + * Otherwise skip past any leading '-'. + */ + if (fo->opt_opts == 0) + fo->opt_opts = "rw,defaults"; + else if (*fo->opt_opts == '-') + fo->opt_opts++; + + /* + * Check the filesystem is happy + */ + if (fo->fs_mtab) + free((voidp) fo->fs_mtab); + + if (fo->fs_mtab = (*rop->fs_match)(fo)) + return rop; + + /* + * Return error file system + */ + fo->fs_mtab = (*efs_ops.fs_match)(fo); + return &efs_ops; +} diff --git a/usr.sbin/amd/amd/amd.8 b/usr.sbin/amd/amd/amd.8 new file mode 100644 index 000000000000..9fa01a2b469d --- /dev/null +++ b/usr.sbin/amd/amd/amd.8 @@ -0,0 +1,232 @@ +.\" +.\" Copyright (c) 1989 Jan-Simon Pendry +.\" Copyright (c) 1989 Imperial College of Science, Technology & Medicine +.\" Copyright (c) 1989, 1991, 1993 +.\" 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. +.\" +.\" @(#)amd.8 5.10 (Berkeley) 4/19/94 +.\" +.\" $Id: amd.8,v 5.2.2.1 1992/02/09 15:11:39 jsp beta $ +.\" +.Dd "April 19, 1994" +.Dt AMD 8 +.Os +.Sh NAME +.Nm amd +.Nd automatically mount file systems +.Sh SYNOPSIS +.Nm amd +.Op Fl nprv +.Op Fl a Ar mount_point +.Op Fl c Ar duration +.Op Fl d Ar domain +.Bk -words +.Op Fl k Ar kernel-arch +.Ek +.Op Fl l Ar logfile +.Op Fl t Ar interval.interval +.Bk -words +.Op Fl w Ar interval +.Ek +.Op Fl x Ar log-option +.Op Fl y Ar YP-domain +.Bk -words +.Op Fl C Ar cluster-name +.Ek +.Op Fl D Ar option +.Oo +.Ar directory mapname +.Op Fl map-options +.Oc +.Ar ... +.Sh DESCRIPTION +.Nm 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 be quiescent. +.Pp +.Nm Amd +operates by attaching itself as an +.Tn NFS +server to each of the specified +.Ar directories . +Lookups within the specified directories +are handled by +.Nm amd , +which uses the map defined by +.Ar mapname +to determine how to resolve the lookup. +Generally, this will be a host name, some filesystem information +and some mount options for the given filesystem. +.Sh OPTIONS +.Bl -tag -width Ds +.It Fl a Ar temporary-directory +Specify an alternative location for the real mount points. +The default is +.Pa /a . +.It Fl c Ar duration +Specify a +.Ar duration , +in seconds, that a looked up name remains +cached when not in use. The default is 5 minutes. +.It Fl d Ar domain +Specify the local domain name. If this option is not +given the domain name is determined from the hostname. +.It Fl k Ar kernel-arch +Specifies the kernel architecture. This is used solely +to set the ${karch} selector. +.It Fl l Ar logfile +Specify a logfile in which to record mount and unmount events. +If +.Ar logfile +is the string +.Em syslog , +the log messages will be sent to the system log daemon by +.Xr syslog 3 . +.It Fl n +Normalize hostnames. +The name referred to by ${rhost} is normalized relative to the +host database before being used. The effect is to translate +aliases into ``official'' names. +.It Fl p +Print +.Em PID . +Outputs the process-id of +.Nm amd +to standard output where it can be saved into a file. +.It Fl r +Restart existing mounts. +.Nm Amd +will scan the mount file table to determine which filesystems +are currently mounted. Whenever one of these would have +been auto-mounted, +.Nm amd +.Em inherits +it. +.It Fl t Ar interval.interval +Specify the +.Ar interval , +in tenths of a second, between +.Tn NFS/RPC/UDP +retries. +The default is 0.8 seconds. +The second values alters the retransmit counter. +Useful defaults are supplied if either or both +values are missing. +.It Fl v +Version. Displays version and configuration information on standard error. +.It Fl w Ar interval +Specify an +.Ar interval , +in seconds, between attempts to dismount +filesystems that have exceeded their cached times. +The default is 2 minutes. +.It Fl y Ar domain +Specify an alternative +.Tn NIS +domain from which to fetch the +.Tn NIS +maps. +The default is the system domain name. +This option is ignored if +.Tn NIS +support is not available. +.It Fl x Ar options +Specify run-time logging options. The options are a comma separated +list chosen from: fatal, error, user, warn, info, map, stats, all. +.It Fl D Ar option +Select from a variety of debug options. Prefixing an +option with the string +.Em no +reverses the effect of that option. Options are cumulative. +The most useful option is +.Ar all . +.El +.Pp +Since +.Fl D +is only used for debugging other options are not documented here: +the current supported set of options is listed by the +.Fl v +option +and a fuller description is available in the program source. +.Sh FILES +.Bl -tag -width /axx +.It Pa /a +directory under which filesystems are dynamically mounted +.El +.Sh CAVEATS +Some care may be required when creating a mount map. +.Pp +Symbolic links on an +.Tn NFS +filesystem can be incredibly inefficient. +In most implementations of +.Tn NFS , +their interpolations are not cached by +the kernel and each time a symbolic link is +encountered during a +.Em lookuppn +translation it costs an +.Tn RPC +call to the +.Tn NFS +server. +A large improvement in real-time +performance could be gained by adding a cache somewhere. +Replacing +.Xr symlinks 2 +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. +.Pp +A weird imagination is most useful to gain full advantage of all +the features. +.Sh SEE ALSO +.Xr amq 8 , +.Xr hostname 1 , +.Xr mount 8 , +.Xr umount 8 , +.Rs +.%T Amd \- The 4.4 BSD Automounter +.Re +.Sh AUTHOR +.An Jan-Simon Pendry +<jsp@doc.ic.ac.uk>, Department of Computing, Imperial College, London, UK. +.Sh HISTORY +The +.Nm amd +utility first appeared in 4.4BSD. diff --git a/usr.sbin/amd/amd/amd.c b/usr.sbin/amd/amd/amd.c new file mode 100644 index 000000000000..c3b2b61f3ed2 --- /dev/null +++ b/usr.sbin/amd/amd/amd.c @@ -0,0 +1,344 @@ +/* + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989, 1993 + * 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. + * + * @(#)amd.c 8.1 (Berkeley) 6/6/93 + * + * $Id: amd.c,v 5.2.2.1 1992/02/09 15:08:15 jsp beta $ + * + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +/* + * Automounter + */ + +#include "am.h" +#include <sys/signal.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <setjmp.h> + +char pid_fsname[16 + MAXHOSTNAMELEN]; /* "kiska.southseas.nz:(pid%d)" */ +char *progname; /* "amd" */ +#ifdef HAS_HOST +#ifdef HOST_EXEC +char *host_helper; +#endif /* HOST_EXEC */ +#endif /* HAS_HOST */ +char *auto_dir = "/a"; +char *hostdomain = "unknown.domain"; +char hostname[MAXHOSTNAMELEN] = "localhost"; /* Hostname */ +char hostd[2*MAXHOSTNAMELEN]; /* Host+domain */ +char *op_sys = OS_REP; /* Name of current op_sys */ +char *arch = ARCH_REP; /* Name of current architecture */ +char *endian = ARCH_ENDIAN; /* Big or Little endian */ +char *wire; +int foreground = 1; /* This is the top-level server */ +int mypid; /* Current process id */ +int immediate_abort; /* Should close-down unmounts be retried */ +struct in_addr myipaddr; /* (An) IP address of this host */ +serv_state amd_state; +struct amd_stats amd_stats; /* Server statistics */ +time_t do_mapc_reload = 0; /* mapc_reload() call required? */ +jmp_buf select_intr; +int select_intr_valid; +int orig_umask; + +/* + * Signal handler: + * SIGINT - tells amd to do a full shutdown, including unmounting all filesystem. + * SIGTERM - tells amd to shutdown now. Just unmounts the automount nodes. + */ +static void sigterm(sig) +int sig; +{ +#ifdef SYS5_SIGNALS + signal(sig, sigterm); +#endif /* SYS5_SIGNALS */ + + switch (sig) { + case SIGINT: + immediate_abort = 15; + break; + + case SIGTERM: + immediate_abort = -1; + /* fall through... */ + + default: + plog(XLOG_WARNING, "WARNING: automounter going down on signal %d", sig); + break; + } + if (select_intr_valid) + longjmp(select_intr, sig); +} + +/* + * Hook for cache reload. + * When a SIGHUP arrives it schedules a call to mapc_reload + */ +/*ARGSUSED*/ +static void sighup(sig) +int sig; +{ +#ifdef SYS5_SIGNALS + signal(sig, sighup); +#endif /* SYS5_SIGNALS */ + +#ifdef DEBUG + if (sig != SIGHUP) + dlog("spurious call to sighup"); +#endif /* DEBUG */ + /* + * Force a reload by zero'ing the timer + */ + if (amd_state == Run) + do_mapc_reload = 0; +} + +/*ARGSUSED*/ +static void parent_exit(sig) +int sig; +{ + exit(0); +} + +static int daemon_mode(P_void) +{ + int bgpid; + + signal(SIGQUIT, parent_exit); + bgpid = background(); + + if (bgpid != 0) { + if (print_pid) { + printf("%d\n", bgpid); + fflush(stdout); + } + /* + * Now wait for the automount points to + * complete. + */ + for (;;) + pause(); + } + + signal(SIGQUIT, SIG_DFL); + + /* + * Pretend we are in the foreground again + */ + foreground = 1; + +#ifdef TIOCNOTTY + { + int t = open("/dev/tty", O_RDWR); + if (t < 0) { + if (errno != ENXIO) /* not an error if already no controlling tty */ + plog(XLOG_WARNING, "Could not open controlling tty: %m"); + } else { + if (ioctl(t, TIOCNOTTY, 0) < 0 && errno != ENOTTY) + plog(XLOG_WARNING, "Could not disassociate tty (TIOCNOTTY): %m"); + (void) close(t); + } + } +#else + (void) setpgrp(); +#endif /* TIOCNOTTY */ + + return getppid(); +} + +main(argc, argv) +int argc; +char *argv[]; +{ + char *domdot; + int ppid = 0; + int error; + + /* + * Make sure some built-in assumptions are true before we start + */ + assert(sizeof(nfscookie) >= sizeof (unsigned int)); + assert(sizeof(int) >= 4); + + /* + * Set processing status. + */ + amd_state = Start; + + /* + * 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); + } + /* + * Partially initialise hostd[]. This + * is completed in get_args(). + */ + if (domdot = strchr(hostname, '.')) { + /* + * Hostname already contains domainname. + * Split out hostname and domainname + * components + */ + *domdot++ = '\0'; + hostdomain = domdot; + } + strcpy(hostd, hostname); + + /* + * Trap interrupts for shutdowns. + */ + (void) signal(SIGINT, sigterm); + + /* + * Hangups tell us to reload the cache + */ + (void) signal(SIGHUP, sighup); + + /* + * Trap Terminate so that we can shutdown gracefully (some chance) + */ + (void) signal(SIGTERM, sigterm); + /* + * Trap Death-of-a-child. These allow us to + * pick up the exit status of backgrounded mounts. + * See "sched.c". + */ + (void) signal(SIGCHLD, sigchld); + + /* + * 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 + */ + wire = getwire(); + + /* + * Determine command-line arguments + */ + get_args(argc, argv); + + /* + * Get our own IP address so that we + * can mount the automounter. + */ + { struct sockaddr_in sin; + get_myaddress(&sin); + myipaddr.s_addr = sin.sin_addr.s_addr; + } + + /* + * Now check we are root. + */ + if (geteuid() != 0) { + plog(XLOG_FATAL, "Must be root to mount filesystems (euid = %d)", geteuid()); + going_down(1); + } + +#ifdef HAS_NIS_MAPS + /* + * If the domain was specified then bind it here + * to circumvent any default bindings that may + * be done in the C library. + */ + if (domain && yp_bind(domain)) { + plog(XLOG_FATAL, "Can't bind to domain \"%s\"", domain); + going_down(1); + } +#endif /* HAS_NIS_MAPS */ + +#ifdef DEBUG + Debug(D_DAEMON) +#endif /* DEBUG */ + ppid = daemon_mode(); + + sprintf(pid_fsname, "%s:(pid%d)", hostname, mypid); + + do_mapc_reload = clocktime() + ONE_HOUR; + + /* + * Register automounter with system + */ + error = mount_automounter(ppid); + if (error && ppid) + kill(SIGALRM, ppid); + going_down(error); + + abort(); +} diff --git a/usr.sbin/amd/amd/amq_subr.c b/usr.sbin/amd/amd/amq_subr.c new file mode 100644 index 000000000000..cf04d9d4160b --- /dev/null +++ b/usr.sbin/amd/amd/amq_subr.c @@ -0,0 +1,464 @@ +/* + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990, 1993 + * 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. + * + * @(#)amq_subr.c 8.1 (Berkeley) 6/6/93 + * + * $Id: amq_subr.c,v 5.2.2.1 1992/02/09 15:08:18 jsp beta $ + * + */ +/* + * Auxilliary routines for amq tool + */ + +#include "am.h" +#include "amq.h" +#include <ctype.h> + +/*ARGSUSED*/ +voidp +amqproc_null_1(argp, rqstp) +voidp argp; +struct svc_req *rqstp; +{ + static char res; + + return (voidp) &res; +} + +/* + * Return a sub-tree of mounts + */ +/*ARGSUSED*/ +amq_mount_tree_p * +amqproc_mnttree_1(argp, rqstp) +voidp argp; +struct svc_req *rqstp; +{ + static am_node *mp; + mp = find_ap(*(char **) argp); + return (amq_mount_tree_p *) ∓ +} + +/* + * Unmount a single node + */ +/*ARGSUSED*/ +voidp +amqproc_umnt_1(argp, rqstp) +voidp argp; +struct svc_req *rqstp; +{ + static char res; + am_node *mp = find_ap(*(char **) argp); + if (mp) + forcibly_timeout_mp(mp); + + return (voidp) &res; +} + +/* + * Return global statistics + */ +/*ARGSUSED*/ +amq_mount_stats * +amqproc_stats_1(argp, rqstp) +voidp argp; +struct svc_req *rqstp; +{ + return (amq_mount_stats *) &amd_stats; +} + +/* + * Return the entire tree of mount nodes + */ +/*ARGSUSED*/ +amq_mount_tree_list * +amqproc_export_1(argp, rqstp) +voidp argp; +struct svc_req *rqstp; +{ + static amq_mount_tree_list aml; + + 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(argp, rqstp) +voidp argp; +struct svc_req *rqstp; +{ + static int rc; + + amq_setopt *opt = (amq_setopt *) argp; + + rc = 0; + switch (opt->as_opt) { + case AMOPT_DEBUG: +#ifdef DEBUG + if (debug_option(opt->as_str)) + rc = EINVAL; +#else + rc = EINVAL; +#endif /* DEBUG */ + break; + + case AMOPT_LOGFILE: +#ifdef not_yet + if (switch_to_logfile(opt->as_str)) + rc = EINVAL; +#else + rc = EACCES; +#endif /* not_yet */ + break; + + case AMOPT_XLOG: + if (switch_option(opt->as_str)) + rc = EINVAL; + break; + + case AMOPT_FLUSHMAPC: + if (amd_state == Run) { + plog(XLOG_INFO, "amq says flush cache"); + do_mapc_reload = 0; + flush_nfs_fhandle_cache((fserver *) 0); + flush_srvr_nfs_cache(); + } + break; + } + return &rc; +} + +amq_mount_info_list * +amqproc_getmntfs_1(argp, rqstp) +voidp argp; +struct svc_req *rqstp; +{ +extern qelem mfhead; + return (amq_mount_info_list *) &mfhead; /* XXX */ +} + +static int ok_security(rqstp) +struct svc_req *rqstp; +{ + struct sockaddr_in *sin; + + sin = svc_getcaller(rqstp->rq_xprt); + 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(argp, rqstp) +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); + rc = mount_auto_node(s, (voidp) root_node); + if (rc < 0) + return 0; + return &rc; +} + +amq_string * +amqproc_getvers_1(argp, rqstp) +voidp argp; +struct svc_req *rqstp; +{ +static amq_string res; + res = version; + return &res; +} + +/* + * XDR routines. + */ +bool_t +xdr_amq_string(xdrs, objp) + XDR *xdrs; + amq_string *objp; +{ + if (!xdr_string(xdrs, objp, AMQ_STRLEN)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_amq_setopt(xdrs, objp) + XDR *xdrs; + amq_setopt *objp; +{ + if (!xdr_enum(xdrs, (enum_t *)&objp->as_opt)) { + return (FALSE); + } + if (!xdr_string(xdrs, &objp->as_str, AMQ_STRLEN)) { + return (FALSE); + } + return (TRUE); +} + +/* + * More XDR routines - Should be used for OUTPUT ONLY. + */ +bool_t +xdr_amq_mount_tree_node(xdrs, objp) + XDR *xdrs; + amq_mount_tree *objp; +{ + am_node *mp = (am_node *) objp; + + if (!xdr_amq_string(xdrs, &mp->am_mnt->mf_info)) { + return (FALSE); + } + if (!xdr_amq_string(xdrs, &mp->am_path)) { + return (FALSE); + } + if (!xdr_amq_string(xdrs, mp->am_link ? &mp->am_link : &mp->am_mnt->mf_mount)) { + return (FALSE); + } + if (!xdr_amq_string(xdrs, &mp->am_mnt->mf_ops->fs_type)) { + return (FALSE); + } + if (!xdr_long(xdrs, &mp->am_stats.s_mtime)) { + return (FALSE); + } + if (!xdr_u_short(xdrs, &mp->am_stats.s_uid)) { + return (FALSE); + } + if (!xdr_int(xdrs, &mp->am_stats.s_getattr)) { + return (FALSE); + } + if (!xdr_int(xdrs, &mp->am_stats.s_lookup)) { + return (FALSE); + } + if (!xdr_int(xdrs, &mp->am_stats.s_readdir)) { + return (FALSE); + } + if (!xdr_int(xdrs, &mp->am_stats.s_readlink)) { + return (FALSE); + } + if (!xdr_int(xdrs, &mp->am_stats.s_statfs)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_amq_mount_subtree(xdrs, objp) + 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), xdr_amq_mount_subtree)) { + return (FALSE); + } + if (!xdr_pointer(xdrs, (char **)&mp->am_child, sizeof(amq_mount_tree), xdr_amq_mount_subtree)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_amq_mount_tree(xdrs, objp) + 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), xdr_amq_mount_subtree)) { + return (FALSE); + } + if (!xdr_pointer(xdrs, (char **)&mp->am_child, sizeof(amq_mount_tree), xdr_amq_mount_subtree)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_amq_mount_tree_p(xdrs, objp) + XDR *xdrs; + amq_mount_tree_p *objp; +{ + if (!xdr_pointer(xdrs, (char **)objp, sizeof(amq_mount_tree), xdr_amq_mount_tree)) { + return (FALSE); + } + return (TRUE); +} + + +bool_t +xdr_amq_mount_stats(xdrs, objp) + XDR *xdrs; + amq_mount_stats *objp; +{ + if (!xdr_int(xdrs, &objp->as_drops)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->as_stale)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->as_mok)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->as_merr)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->as_uerr)) { + return (FALSE); + } + return (TRUE); +} + + +bool_t +xdr_amq_mount_tree_list(xdrs, objp) + XDR *xdrs; + amq_mount_tree_list *objp; +{ + if (!xdr_array(xdrs, (char **)&objp->amq_mount_tree_list_val, (u_int *)&objp->amq_mount_tree_list_len, ~0, sizeof(amq_mount_tree_p), xdr_amq_mount_tree_p)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_amq_mount_info_qelem(xdrs, qhead) + XDR *xdrs; + qelem *qhead; +{ + /* + * Compute length of list + */ + mntfs *mf; + u_int len = 0; + for (mf = LAST(mntfs, qhead); mf != HEAD(mntfs, qhead); mf = PREV(mntfs, mf)) { + if (!(mf->mf_ops->fs_flags & FS_AMQINFO)) + continue; + len++; + } + xdr_u_int(xdrs, &len); + + /* + * Send individual data items + */ + for (mf = LAST(mntfs, qhead); mf != HEAD(mntfs, qhead); mf = PREV(mntfs, mf)) { + int up; + if (!(mf->mf_ops->fs_flags & FS_AMQINFO)) + continue; + + if (!xdr_amq_string(xdrs, &mf->mf_ops->fs_type)) { + return (FALSE); + } + if (!xdr_amq_string(xdrs, &mf->mf_mount)) { + return (FALSE); + } + if (!xdr_amq_string(xdrs, &mf->mf_info)) { + return (FALSE); + } + if (!xdr_amq_string(xdrs, &mf->mf_server->fs_host)) { + return (FALSE); + } + if (!xdr_int(xdrs, &mf->mf_error)) { + return (FALSE); + } + if (!xdr_int(xdrs, &mf->mf_refc)) { + return (FALSE); + } + if (mf->mf_server->fs_flags & FSF_ERROR) + up = 0; + else switch (mf->mf_server->fs_flags & (FSF_DOWN|FSF_VALID)) { + case FSF_DOWN|FSF_VALID: up = 0; break; + case FSF_VALID: up = 1; break; + default: up = -1; break; + } + if (!xdr_int(xdrs, &up)) { + return (FALSE); + } + } + return (TRUE); +} diff --git a/usr.sbin/amd/amd/clock.c b/usr.sbin/amd/amd/clock.c new file mode 100644 index 000000000000..91e11eec4962 --- /dev/null +++ b/usr.sbin/amd/amd/clock.c @@ -0,0 +1,241 @@ +/* + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989, 1993 + * 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. + * + * @(#)clock.c 8.1 (Berkeley) 6/6/93 + * + * $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. + */ + +#include "am.h" + +typedef struct callout callout; +struct callout { + callout *c_next; /* List of callouts */ + void (*c_fn)(); /* Function to call */ + voidp c_closure; /* Closure to pass to call */ + time_t c_time; /* Time of call */ + int c_id; /* Unique identifier */ +}; + +static callout callouts; /* List of pending callouts */ +static callout *free_callouts; /* Cache of free callouts */ +static int nfree_callouts; /* Number on free list */ +static int callout_id; /* Next free callout identifier */ +time_t next_softclock; /* Time of next call to softclock() */ + +/* + * Number of callout slots we keep on the free list + */ +#define CALLOUT_FREE_SLOP 10 + +/* + * Global assumption: valid id's are non-zero. + */ +#define CID_ALLOC() (++callout_id) +#define CID_UNDEF (0) + +static callout *alloc_callout(P_void); +static callout *alloc_callout() +{ + callout *cp = free_callouts; + if (cp) { + --nfree_callouts; + free_callouts = free_callouts->c_next; + return cp; + } + return ALLOC(callout); +} + +static void free_callout P((callout *cp)); +static void free_callout(cp) +callout *cp; +{ + if (nfree_callouts > CALLOUT_FREE_SLOP) { + free((voidp) cp); + } else { + cp->c_next = free_callouts; + free_callouts = cp; + nfree_callouts++; + } +} + +/* + * Schedule a callout. + * + * (*fn)(closure) will be called at clocktime() + secs + */ +int timeout P((unsigned int secs, void (*fn)(), voidp closure)); +int timeout(secs, fn, closure) +unsigned int secs; +void (*fn)(); +voidp closure; +{ + callout *cp, *cp2; + time_t t = clocktime() + secs; + + /* + * Allocate and fill in a new callout structure + */ + callout *cpnew = alloc_callout(); + cpnew->c_closure = closure; + cpnew->c_fn = fn; + cpnew->c_time = t; + cpnew->c_id = CID_ALLOC(); + + if (t < next_softclock) + next_softclock = t; + + /* + * Find the correct place in the list + */ + for (cp = &callouts; cp2 = cp->c_next; cp = cp2) + if (cp2->c_time >= t) + break; + + /* + * And link it in + */ + cp->c_next = cpnew; + cpnew->c_next = cp2; + + /* + * Return callout identifier + */ + return cpnew->c_id; +} + +/* + * De-schedule a callout + */ +void untimeout P((int id)); +void untimeout(id) +int id; +{ + callout *cp, *cp2; + for (cp = &callouts; cp2 = cp->c_next; cp = cp2) { + if (cp2->c_id == id) { + cp->c_next = cp2->c_next; + free_callout(cp2); + break; + } + } +} + +/* + * Reschedule after clock changed + */ +void reschedule_timeouts P((time_t now, time_t then)); +void reschedule_timeouts(now, then) +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 + next_softclock = cp->c_time = now; + } + } +} + +/* + * Clock handler + */ +int softclock(P_void); +int softclock() +{ + 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)() = cp->c_fn; + voidp closure = cp->c_closure; + + callouts.c_next = cp->c_next; + free_callout(cp); +#ifdef DEBUG + /*dlog("Calling %#x(%#x)", fn, closure);*/ +#endif /* DEBUG */ + (*fn)(closure); + } + + } while (task_notify_todo); + + /* + * Return number of seconds to next event, + * or 0 if there is no event. + */ + if (cp = callouts.c_next) + return cp->c_time - now; + return 0; +} diff --git a/usr.sbin/amd/amd/efs_ops.c b/usr.sbin/amd/amd/efs_ops.c new file mode 100644 index 000000000000..6630277eab4c --- /dev/null +++ b/usr.sbin/amd/amd/efs_ops.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989, 1993 + * 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. + * + * @(#)efs_ops.c 8.1 (Berkeley) 6/6/93 + * + * $Id: efs_ops.c,v 5.2.2.1 1992/02/09 15:08:21 jsp beta $ + * + */ + +#include "am.h" + +#ifdef HAS_EFS + +/* + * Error file system. + * This is used as a last resort catchall if + * nothing else worked. EFS just returns lots + * of error codes, except for unmount which + * always works of course. + */ + +/* + * EFS file system always matches + */ +static char *efs_match(fo) +am_opts *fo; +{ + return strdup("(error-hook)"); +} + +/*ARGSUSED*/ +static int efs_fmount(mf) +mntfs *mf; +{ + return ENOENT; +} + +/*ARGSUSED*/ +static int efs_fumount(mf) +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. + */ +/*ARGSUSED*/ +am_node *efs_lookuppn(mp, fname, error_return, op) +am_node *mp; +char *fname; +int *error_return; +int op; +{ + *error_return = ESTALE; + return 0; +} + +/* + * EFS interface to RPC readdir() routine. + * Should never get here in the automounter. + * If we do then just give an error. + */ +/*ARGSUSED*/ +int efs_readdir(mp, cookie, dp, ep, count) +am_node *mp; +nfscookie cookie; +dirlist *dp; +entry *ep; +int count; +{ + return ESTALE; +} + +/* + * Ops structure + */ +am_ops efs_ops = { + "error", + efs_match, + 0, /* efs_init */ + auto_fmount, + efs_fmount, + auto_fumount, + efs_fumount, + efs_lookuppn, + efs_readdir, + 0, /* efs_readlink */ + 0, /* efs_mounted */ + 0, /* efs_umounted */ + find_afs_srvr, + FS_DISCARD +}; + +#endif /* HAS_EFS */ diff --git a/usr.sbin/amd/amd/get_args.c b/usr.sbin/amd/amd/get_args.c new file mode 100644 index 000000000000..0567d5dd5ea3 --- /dev/null +++ b/usr.sbin/amd/amd/get_args.c @@ -0,0 +1,336 @@ +/* + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990, 1993 + * 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. + * + * @(#)get_args.c 8.1 (Berkeley) 6/6/93 + * + * $Id: get_args.c,v 5.2.2.1 1992/02/09 15:08:23 jsp beta $ + * + */ + +/* + * Argument decode + */ + +#include "am.h" +#ifdef HAS_SYSLOG +#include <syslog.h> +#endif /* HAS_SYSLOG */ +#include <sys/stat.h> + +extern int optind; +extern char *optarg; + +#if defined(DEBUG) && defined(PARANOID) +char **gargv; +#endif /* defined(DEBUG) && defined(PARANOID) */ +int restart_existing_mounts; +int print_pid; +int normalize_hosts; +char *karch; /* Kernel architecture */ +char *cluster; /* Cluster name */ +#ifdef HAS_NIS_MAPS +char *domain; /* YP domain */ +#endif /* HAS_NIS_MAPS */ +#ifdef UPDATE_MTAB +char *mtab; +#endif /* UPDATE_MTAB */ +int afs_timeo = -1; +int afs_retrans = -1; +int am_timeo = AM_TTL; +int am_timeo_w = AM_TTL_W; + +#ifdef DEBUG +/* + * List of debug options. + */ +static struct opt_tab dbg_opt[] = { + { "all", D_ALL }, /* All */ + { "amq", D_AMQ }, /* Register for AMQ program */ + { "daemon", D_DAEMON }, /* Enter daemon mode */ + { "full", D_FULL }, /* Program trace */ + { "mem", D_MEM }, /* Trace memory allocations */ + { "mtab", D_MTAB }, /* Use local mtab file */ + { "str", D_STR }, /* Debug string munging */ + { "test", D_TEST }, /* Full debug - but no daemon */ + { "trace", D_TRACE }, /* Protocol trace */ + { 0, 0 } +}; + +int debug_flags = D_AMQ /* Register AMQ */ + |D_DAEMON /* Enter daemon mode */ + ; + +/* + * Switch on/off debug options + */ +int debug_option(opt) +char *opt; +{ + return cmdoption(opt, dbg_opt, &debug_flags); +} +#endif /* DEBUG */ + +void get_args(c, v) +int c; +char *v[]; +{ + int opt_ch; + int usage = 0; + char *logfile = 0; + char *sub_domain = 0; + + while ((opt_ch = getopt(c, v, "mnprva:c:d:h:k:l:t:w:x:y:C:D:")) != EOF) + switch (opt_ch) { + case 'a': + if (*optarg != '/') { + fprintf(stderr, "%s: -a option must begin with a '/'\n", + progname); + exit(1); + } + auto_dir = optarg; + break; + + case 'c': + am_timeo = atoi(optarg); + if (am_timeo <= 0) + am_timeo = AM_TTL; + break; + + case 'd': + sub_domain = optarg; + break; + + case 'h': +#if defined(HAS_HOST) && defined(HOST_EXEC) + host_helper = optarg; +#else + plog(XLOG_USER, "-h: option ignored. HOST_EXEC is not enabled."); + break; +#endif /* defined(HAS_HOST) && defined(HOST_EXEC) */ + + case 'k': + karch = optarg; + break; + + case 'l': + logfile = optarg; + break; + + case 'm': + plog(XLOG_USER, "The -m option is no longer supported."); + plog(XLOG_USER, "... Use `ypcat -k am.master` on the command line instead"); + break; + + case 'n': + normalize_hosts = 1; + break; + + case 'p': + print_pid = 1; + break; + + case 'r': + restart_existing_mounts = 1; + break; + + case 't': + /* timeo.retrans */ + { char *dot = strchr(optarg, '.'); + if (dot) *dot = '\0'; + if (*optarg) { + afs_timeo = atoi(optarg); + } + if (dot) { + afs_retrans = atoi(dot+1); + *dot = '.'; + } + } + break; + + case 'v': + fprintf(stderr, "%s%s (%s-endian).\n", copyright, version, endian); + fputs("Map support for: ", stderr); + mapc_showtypes(stderr); + fputs(".\nFS: ", stderr); + ops_showfstypes(stderr); + fputs(".\n", stderr); + fprintf(stderr, "Primary network is %s.\n", wire); + exit(0); + break; + + case 'w': + am_timeo_w = atoi(optarg); + if (am_timeo_w <= 0) + am_timeo_w = AM_TTL_W; + break; + + case 'x': + usage += switch_option(optarg); + break; + + case 'y': +#ifdef HAS_NIS_MAPS + domain = optarg; +#else + plog(XLOG_USER, "-y: option ignored. No NIS support available."); +#endif /* HAS_NIS_MAPS */ + break; + + case 'C': + cluster = optarg; + break; + + case 'D': +#ifdef DEBUG + usage += debug_option(optarg); +#else + fprintf(stderr, "%s: not compiled with DEBUG option -- sorry.\n", progname); +#endif /* DEBUG */ + break; + + default: + usage = 1; + break; + } + + if (xlog_level_init == ~0) { + (void) switch_option(""); +#ifdef DEBUG + usage += switch_option("debug"); +#endif /* DEBUG */ + } else { +#ifdef DEBUG + usage += switch_option("debug"); +#endif /* DEBUG */ + } + + if (usage) + goto show_usage; + + while (optind <= c-2) { + char *dir = v[optind++]; + char *map = v[optind++]; + char *opts = ""; + if (v[optind] && *v[optind] == '-') + opts = &v[optind++][1]; + + root_newmap(dir, opts, map); + } + + if (optind == c) { +#ifdef hpux + /* + * HP-UX can't handle ./mtab + * That system is sick - really. + */ +#ifdef DEBUG + debug_option("nomtab"); +#endif /* DEBUG */ +#endif /* hpux */ + + /* + * Append domain name to hostname. + * sub_domain overrides hostdomain + * if given. + */ + if (sub_domain) + hostdomain = sub_domain; + if (*hostdomain == '.') + hostdomain++; + strcat(hostd, "."); + strcat(hostd, hostdomain); + +#ifdef UPDATE_MTAB +#ifdef DEBUG + if (debug_flags & D_MTAB) + mtab = DEBUG_MTAB; + else +#endif /* DEBUG */ + mtab = MOUNTED; +#else +#ifdef DEBUG + { if (debug_flags & D_MTAB) { + dlog("-D mtab option ignored"); + } } +#endif /* DEBUG */ +#endif /* UPDATE_MTAB */ + + if (switch_to_logfile(logfile) != 0) + plog(XLOG_USER, "Cannot switch logfile"); + + /* + * If the kernel architecture was not specified + * then use the machine architecture. + */ + if (karch == 0) + karch = arch; + + if (cluster == 0) + cluster = hostdomain; + + if (afs_timeo <= 0) + afs_timeo = AFS_TIMEO; + if (afs_retrans <= 0) + afs_retrans = AFS_RETRANS; + if (afs_retrans <= 0) + afs_retrans = 3; /* XXX */ + return; + } + +show_usage: + fprintf(stderr, +"Usage: %s [-mnprv] [-a mnt_point] [-c cache_time] [-d domain]\n\ +\t[-k kernel_arch] [-l logfile|\"syslog\"] [-t afs_timeout]\n\ +\t[-w wait_timeout] [-C cluster_name]", progname); + +#if defined(HAS_HOST) && defined(HOST_EXEC) + fputs(" [-h host_helper]\n", stderr); +#endif /* defined(HAS_HOST) && defined(HOST_EXEC) */ + +#ifdef HAS_NIS_MAPS + fputs(" [-y nis-domain]\n", stderr); +#else + fputc('\n', stderr); +#endif /* HAS_NIS_MAPS */ + + show_opts('x', xlog_opt); +#ifdef DEBUG + show_opts('D', dbg_opt); +#endif /* DEBUG */ + fprintf(stderr, "\t{directory mapname [-map_options]} ...\n"); + exit(1); +} diff --git a/usr.sbin/amd/amd/host_ops.c b/usr.sbin/amd/amd/host_ops.c new file mode 100644 index 000000000000..ba0dedb43154 --- /dev/null +++ b/usr.sbin/amd/amd/host_ops.c @@ -0,0 +1,681 @@ +/* + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990, 1993 + * 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. + * + * @(#)host_ops.c 8.1 (Berkeley) 6/6/93 + * + * $Id: host_ops.c,v 5.2.2.2 1992/05/31 16:36:08 jsp Exp $ + * + */ + +#include "am.h" + +#ifdef HAS_HOST + +#include "mount.h" +#include <sys/stat.h> + +/* + * 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. + */ + +/* + * Define HOST_RPC_UDP to use dgram instead of stream RPC. + * Datagrams are generally much faster. + */ +/*#define HOST_RPC_UDP*/ + +/* + * Define HOST_MKDIRS to make Amd automatically try + * to create the mount points. + */ +#define HOST_MKDIRS + +/* + * Determine the mount point + */ +#define MAKE_MNTPT(mntpt, ex, mf) { \ + if (strcmp((ex)->ex_dir, "/") == 0) \ + strcpy((mntpt), (mf)->mf_mount); \ + else \ + sprintf((mntpt), "%s%s", (mf)->mf_mount, (ex)->ex_dir); \ +} + +/* + * Execute needs the same as NFS plus a helper command + */ +static char *host_match P((am_opts *fo)); +static char *host_match(fo) +am_opts *fo; +{ +#ifdef HOST_EXEC + if (!host_helper) { + plog(XLOG_USER, "No host helper command given"); + return FALSE; + } +#endif /* HOST_EXEC */ + + /* + * Make sure rfs is specified to keep nfs_match happy... + */ + if (!fo->opt_rfs) + fo->opt_rfs = "/"; + + + return (*nfs_ops.fs_match)(fo); +} + +static int host_init(mf) +mntfs *mf; +{ + if (strchr(mf->mf_info, ':') == 0) + return ENOENT; + return 0; +} + +/* + * Two implementations: + * HOST_EXEC gets you the external version. The program specified with + * the -h option is called. The external program is not published... + * roll your own. + * + * Otherwise you get the native version. Faster but makes the program + * bigger. + */ + +#ifndef HOST_EXEC + +static bool_t +xdr_pri_free(xdr_args, args_ptr) +xdrproc_t xdr_args; +caddr_t args_ptr; +{ + XDR xdr; + xdr.x_op = XDR_FREE; + return ((*xdr_args)(&xdr, args_ptr)); +} + +static int do_mount P((fhstatus *fhp, char *dir, char *fs_name, char *opts, mntfs *mf)); +static int do_mount(fhp, dir, fs_name, opts, mf) +fhstatus *fhp; +char *dir; +char *fs_name; +char *opts; +mntfs *mf; +{ + struct stat stb; +#ifdef DEBUG + dlog("host: mounting fs %s on %s\n", fs_name, dir); +#endif /* DEBUG */ +#ifdef HOST_MKDIRS + (void) mkdirs(dir, 0555); +#endif /* HOST_MKDIRS */ + if (stat(dir, &stb) < 0 || (stb.st_mode & S_IFMT) != S_IFDIR) { + plog(XLOG_ERROR, "No mount point for %s - skipping", dir); + return ENOENT; + } + + return mount_nfs_fh(fhp, dir, fs_name, opts, mf); +} + +static int sortfun P((exports *a, exports *b)); +static int sortfun(a, b) +exports *a,*b; +{ + return strcmp((*a)->ex_dir, (*b)->ex_dir); +} + +/* + * Get filehandle + */ +static int fetch_fhandle P((CLIENT *client, char *dir, fhstatus *fhp)); +static int fetch_fhandle(client, dir, fhp) +CLIENT *client; +char *dir; +fhstatus *fhp; +{ + struct timeval tv; + enum clnt_stat clnt_stat; + + /* + * Pick a number, any number... + */ + tv.tv_sec = 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. + */ + clnt_stat = clnt_call(client, MOUNTPROC_MNT, xdr_dirpath, &dir, xdr_fhstatus, fhp, tv); + if (clnt_stat != RPC_SUCCESS) { + extern char *clnt_sperrno(); + char *msg = clnt_sperrno(clnt_stat); + plog(XLOG_ERROR, "mountd rpc failed: %s", msg); + return EIO; + } + /* + * Check status of filehandle + */ + if (fhp->fhs_status) { +#ifdef DEBUG + errno = fhp->fhs_status; + dlog("fhandle fetch failed: %m"); +#endif /* DEBUG */ + return fhp->fhs_status; + } + return 0; +} + +/* + * Scan mount table to see if something already mounted + */ +static int already_mounted P((mntlist *mlist, char*dir)); +static int already_mounted(mlist, dir) +mntlist *mlist; +char *dir; +{ + mntlist *ml; + + for (ml = mlist; ml; ml = ml->mnext) + if (strcmp(ml->mnt->mnt_dir, dir) == 0) + return 1; + return 0; +} + +/* + * Mount the export tree from a host + */ +static int host_fmount P((mntfs *mf)); +static int host_fmount(mf) +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; + fhstatus *fp = 0; + char *host = mf->mf_server->fs_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; + tv.tv_sec = 10; tv.tv_usec = 0; + + /* + * Read the mount list + */ + mlist = read_mtab(mf->mf_mount); + + /* + * Unlock the mount list + */ + unlock_mntlist(); + + /* + * Take a copy of the server address + */ + sin = *mf->mf_server->fs_ip; + + /* + * Zero out the port - make sure we recompute + */ + sin.sin_port = 0; + /* + * Make a client end-point. + * Try TCP first + */ + if ((client = clnttcp_create(&sin, MOUNTPROG, MOUNTVERS, &sock, 0, 0)) == NULL && + (client = clntudp_create(&sin, MOUNTPROG, MOUNTVERS, tv, &sock)) == NULL) { + plog(XLOG_ERROR, "Failed to make rpc connection to mountd on %s", host); + 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, xdr_void, 0, xdr_exports, &exlist, tv2); + if (clnt_stat != RPC_SUCCESS) { + /*clnt_perror(client, "rpc");*/ + error = EIO; + goto out; + } + + /* + * Figure out how many exports were returned + */ + for (n_export = 0, ex = exlist; ex; ex = ex->ex_next) { + /*printf("export %s\n", ex->ex_dir);*/ + n_export++; + } +#ifdef DEBUG + /*dlog("%d exports returned\n", n_export);*/ +#endif /* DEBUG */ + + /* + * Allocate an array of pointers into the list + * so that they can be sorted. 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 = (fhstatus *) xmalloc(n_export * sizeof(fhstatus)); + + /* + * Try to obtain filehandles for each directory. + * If a fetch fails then just zero out the array + * reference but discard the error. + */ + for (j = k = 0; j < n_export; j++) { + /* Check and avoid a duplicated export entry */ + if (j > k && ep[k] && strcmp(ep[j]->ex_dir, ep[k]->ex_dir) == 0) { +#ifdef DEBUG + dlog("avoiding dup fhandle requested for %s", ep[j]->ex_dir); +#endif + ep[j] = 0; + } else { + k = j; + if (error = fetch_fhandle(client, ep[j]->ex_dir, &fp[j])) + ep[j] = 0; + } + } + + /* + * Mount each filesystem for which we have a filehandle. + * If any of the mounts succeed then mark "ok" and return + * error code 0 at the end. If they all fail then return + * the last error code. + */ + strncpy(fs_name, mf->mf_info, sizeof(fs_name)); + if ((rfs_dir = strchr(fs_name, ':')) == (char *) 0) { + plog(XLOG_FATAL, "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) + free(ep); + if (fp) + free(fp); + if (client) + clnt_destroy(client); + if (exlist) + xdr_pri_free(xdr_exports, &exlist); + if (ok) + return 0; + return error; +} + +/* + * Return true if pref is a directory prefix of dir. + * + * TODO: + * Does not work if pref is "/". + */ +static int directory_prefix P((char *pref, char *dir)); +static int directory_prefix(pref, dir) +char *pref; +char *dir; +{ + int len = strlen(pref); + if (strncmp(pref, dir, len) != 0) + return FALSE; + if (dir[len] == '/' || dir[len] == '\0') + return TRUE; + return FALSE; +} + +/* + * Unmount a mount tree + */ +static int host_fumount P((mntfs *mf)); +static int host_fumount(mf) +mntfs *mf; +{ + mntlist *ml, *mprev; + int xerror = 0; + + /* + * Read the mount list + */ + mntlist *mlist = read_mtab(mf->mf_mount); + + /* + * Unlock the mount list + */ + unlock_mntlist(); + + /* + * Reverse list... + */ + ml = mlist; + mprev = 0; + while (ml) { + mntlist *ml2 = ml->mnext; + ml->mnext = mprev; + mprev = ml; + ml = ml2; + } + mlist = mprev; + + /* + * Unmount all filesystems... + */ + for (ml = mlist; ml && !xerror; ml = ml->mnext) { + char *dir = ml->mnt->mnt_dir; + if (directory_prefix(mf->mf_mount, dir)) { + int error; +#ifdef DEBUG + dlog("host: unmounts %s", dir); +#endif /* DEBUG */ + /* + * Unmount "dir" + */ + error = UMOUNT_FS(dir); + /* + * Keep track of errors + */ + if (error) { + if (!xerror) + xerror = error; + if (error != EBUSY) { + errno = error; + plog("Tree unmount of %s failed: %m", ml->mnt->mnt_dir); + } + } else { +#ifdef HOST_MKDIRS + (void) rmdirs(dir); +#endif /* HOST_MKDIRS */ + } + } + } + + /* + * Throw away mount list + */ + discard_mntlist(mlist); + + /* + * Try to remount, except when we are shutting down. + */ + if (xerror && amd_state != Finishing) { + xerror = 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 host_umounted(mp) +am_node *mp; +{ +#ifdef INFORM_MOUNTD + 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; + tv.tv_sec = 10; tv.tv_usec = 0; + + if (mf->mf_error || mf->mf_refc > 1 || ! mf->mf_server) + return; + + host = mf->mf_server->fs_host; + sin = *mf->mf_server->fs_ip; + + /* + * Zero out the port - make sure we recompute + */ + sin.sin_port = 0; + /* + * Make a client end-point. + * Try TCP first + */ + if ((client = clnttcp_create(&sin, MOUNTPROG, MOUNTVERS, &sock, 0, 0)) == NULL && + (client = clntudp_create(&sin, MOUNTPROG, MOUNTVERS, tv, &sock)) == NULL) { + plog(XLOG_ERROR, "Failed to make rpc connection to mountd on %s", host); + 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, xdr_void, 0, xdr_void, 0, tv); + if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_SYSTEMERROR) { + /* RPC_SYSTEMERROR seems to be returned for no good reason ...*/ + extern char *clnt_sperrno(); + char *msg = clnt_sperrno(clnt_stat); + plog(XLOG_ERROR, "unmount all from %s rpc failed: %s", host, msg, clnt_stat); + goto out; + } + +out: + if (client) + clnt_destroy(client); + +#endif /* INFORM_MOUNTD */ +} + + +#else /* HOST_EXEC */ + +static int host_exec P((char*op, char*host, char*fs, char*opts)); +static int host_exec(op, host, fs, opts) +char *op; +char *host; +char *fs; +char *opts; +{ + int error; + char *argv[7]; + + /* + * Build arg vector + */ + argv[0] = host_helper; + argv[1] = host_helper; + argv[2] = op; + argv[3] = host; + argv[4] = fs; + argv[5] = opts && *opts ? opts : "rw,default"; + argv[6] = 0; + + /* + * Put stdout to stderr + */ + (void) fclose(stdout); + (void) dup(fileno(logfp)); + if (fileno(logfp) != fileno(stderr)) { + (void) fclose(stderr); + (void) dup(fileno(logfp)); + } + /* + * Try the exec + */ +#ifdef DEBUG + Debug(D_FULL) { + char **cp = argv; + plog(XLOG_DEBUG, "executing (un)mount command..."); + while (*cp) { + plog(XLOG_DEBUG, "arg[%d] = '%s'", cp-argv, *cp); + cp++; + } + } +#endif /* DEBUG */ + if (argv[0] == 0 || argv[1] == 0) { + errno = EINVAL; + plog(XLOG_USER, "1st/2nd args missing to (un)mount program"); + } else { + (void) execv(argv[0], argv+1); + } + /* + * Save error number + */ + error = errno; + plog(XLOG_ERROR, "exec %s failed: %m", argv[0]); + + /* + * Return error + */ + return error; +} + +static int host_mount P((am_node *mp)); +static int host_mount(mp) +am_node *mp; +{ + mntfs *mf = mp->am_mnt; + + return host_exec("mount", mf->mf_server->fs_host, mf->mf_mount, mf->mf_opts); +} + +static int host_umount P((am_node *mp)); +static int host_umount(mp) +am_node *mp; +{ + mntfs *mf = mp->am_mnt; + + return host_exec("unmount", mf->mf_server->fs_host, mf->mf_mount, "xxx"); +} + +#endif /* HOST_EXEC */ + +/* + * Ops structure + */ +am_ops host_ops = { + "host", + host_match, + host_init, + auto_fmount, + host_fmount, + auto_fumount, + host_fumount, + efs_lookuppn, + efs_readdir, + 0, /* host_readlink */ + 0, /* host_mounted */ +#ifdef HOST_EXEC + 0, /* host_umounted */ +#else + host_umounted, +#endif + find_nfs_srvr, + FS_MKMNT|FS_BACKGROUND|FS_AMQINFO +}; + +#endif /* HAS_HOST */ diff --git a/usr.sbin/amd/amd/ifs_ops.c b/usr.sbin/amd/amd/ifs_ops.c new file mode 100644 index 000000000000..14df832b24c6 --- /dev/null +++ b/usr.sbin/amd/amd/ifs_ops.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989, 1993 + * 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. + * + * @(#)ifs_ops.c 8.1 (Berkeley) 6/6/93 + * + * $Id: ifs_ops.c,v 5.2.2.1 1992/02/09 15:08:26 jsp beta $ + * + */ + +#include "am.h" + +#ifdef HAS_IFS + +/* + * Inheritance file system. + * This implements a filesystem restart. + * + * This is a *gross* hack - it knows far too + * much about the way other parts of the + * sytem work. See restart.c too. + */ +static char not_a_filesystem[] = "Attempting to inherit not-a-filesystem"; +/* + * This should never be called. + */ +/*ARGSUSED*/ +static char *ifs_match P((am_opts *fo)); +static char *ifs_match(fo) +am_opts *fo; +{ + plog(XLOG_FATAL, "ifs_match called!"); + return 0; +} + +static int ifs_init P((mntfs *mf)); +static int ifs_init(mf) +mntfs *mf; +{ + mntfs *mf_link = (mntfs *) mf->mf_private; + if (mf_link == 0) { + plog(XLOG_FATAL, not_a_filesystem); + return EINVAL; + } +#ifdef notdef + /* + * Fill in attribute fields + */ + mf_link->mf_fattr.type = NFLNK; + mf_link->mf_fattr.mode = NFSMODE_LNK | 0777; + mf_link->mf_fattr.nlink = 1; + mf_link->mf_fattr.size = MAXPATHLEN / 4; +#endif + if (mf_link->mf_ops->fs_init) + return (*mf_link->mf_ops->fs_init)(mf_link); + return 0; +} + +static mntfs *ifs_inherit P((mntfs *mf)); +static mntfs *ifs_inherit(mf) +mntfs *mf; +{ + /* + * Take the linked mount point and + * propogate. + */ + mntfs *mf_link = (mntfs *) mf->mf_private; + if (mf_link == 0) { + plog(XLOG_FATAL, not_a_filesystem); + return 0; /*XXX*/ + } + + mf_link->mf_fo = mf->mf_fo; +#ifdef notdef + mf_link->mf_fattr.fileid = mf->mf_fattr.fileid; +#endif /* notdef */ + + /* + * 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 ifs_mount P((am_node *mp)); +static int ifs_mount(mp) +am_node *mp; +{ + mntfs *newmf = ifs_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 ifs_fmount P((mntfs *mf)); +static int ifs_fmount(mf) +mntfs *mf; +{ + am_node *mp = find_mf(mf); + if (mp) + return ifs_mount(mp); + return ifs_inherit(mf) ? 0 : EINVAL; +} + +/*ARGSUSED*/ +static int ifs_fumount P((mntfs *mf)); +static int ifs_fumount(mf) +mntfs *mf; +{ + /* + * Always succeed + */ + return 0; +} + +/* + * Ops structure + */ +am_ops ifs_ops = { + "inherit", + ifs_match, + ifs_init, + ifs_mount, + ifs_fmount, + auto_fumount, + ifs_fumount, + efs_lookuppn, + efs_readdir, + 0, /* ifs_readlink */ + 0, /* ifs_mounted */ + 0, /* ifs_umounted */ + find_afs_srvr, + FS_DISCARD +}; + +#endif /* HAS_IFS */ diff --git a/usr.sbin/amd/amd/info_file.c b/usr.sbin/amd/amd/info_file.c new file mode 100644 index 000000000000..c43b2a7b07c2 --- /dev/null +++ b/usr.sbin/amd/amd/info_file.c @@ -0,0 +1,276 @@ +/* + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990, 1993 + * 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. + * + * @(#)info_file.c 8.1 (Berkeley) 6/6/93 + * + * $Id: info_file.c,v 5.2.2.1 1992/02/09 15:08:28 jsp beta $ + * + */ + +/* + * Get info from file + */ + +#include "am.h" + +#ifdef HAS_FILE_MAPS +#include <ctype.h> +#include <sys/stat.h> + +#define MAX_LINE_LEN 2048 + +static int read_line P((char *buf, int size, FILE *fp)); +static int read_line(buf, size, fp) +char *buf; +int size; +FILE *fp; +{ + int done = 0; + + do { + while (fgets(buf, size, fp)) { + int len = strlen(buf); + done += len; + if (len > 1 && buf[len-2] == '\\' && + buf[len-1] == '\n') { + int ch; + buf += len - 2; + size -= len - 2; + *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 P((FILE *fp, char *map, char *key, char **val, mnt_map *m, void (*fn)(mnt_map *m, char*, char*))); +static int search_or_reload_file(fp, map, key, val, m, fn) +FILE *fp; +char *map; +char *key; +char **val; +mnt_map *m; +void (*fn) P((mnt_map*, char*, char*)); +{ + char key_val[MAX_LINE_LEN]; + int chuck = 0; + int line_no = 0; + + while (read_line(key_val, sizeof(key_val), fp)) { + char *kp; + char *cp; + char *hash; + int len = strlen(key_val); + line_no++; + + /* + * Make sure we got the whole line + */ + if (key_val[len-1] != '\n') { + plog(XLOG_WARNING, "line %d in \"%s\" is too long", line_no, map); + chuck = 1; + } else { + key_val[len-1] = '\0'; + } + + /* + * Strip comments + */ + hash = strchr(key_val, '#'); + if (hash) + *hash = '\0'; + + /* + * Find start of key + */ + for (kp = key_val; *kp && isascii(*kp) && isspace(*kp); kp++) + ; + + /* + * Ignore blank lines + */ + if (!*kp) + goto again; + + /* + * Find end of key + */ + for (cp = kp; *cp&&(!isascii(*cp)||!isspace(*cp)); cp++) + ; + + /* + * Check whether key matches + */ + if (*cp) + *cp++ = '\0'; + + if (fn || (*key == *kp && strcmp(key, kp) == 0)) { + while (*cp && isascii(*cp) && isspace(*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 P((char *map, time_t *tp)); +static FILE *file_open(map, tp) +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 P((char *map, time_t *tp)); +int file_init(map, tp) +char *map; +time_t *tp; +{ + FILE *mapf = file_open(map, tp); + if (mapf) { + (void) fclose(mapf); + return 0; + } + return errno; +} + +int file_reload P((mnt_map *m, char *map, void (*fn)())); +int file_reload(m, map, fn) +mnt_map *m; +char *map; +void (*fn)(); +{ + 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 P((mnt_map *m, char *map, char *key, char **pval, time_t *tp)); +int file_search(m, map, key, pval, tp) +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 P((char *map, time_t *tp)); +int file_mtime(map, tp) +char *map; +time_t *tp; +{ + FILE *mapf = file_open(map, tp); + if (mapf) { + (void) fclose(mapf); + return 0; + } + + return errno; +} +#endif /* HAS_FILE_MAPS */ diff --git a/usr.sbin/amd/amd/info_hes.c b/usr.sbin/amd/amd/info_hes.c new file mode 100644 index 000000000000..875cfe7257b8 --- /dev/null +++ b/usr.sbin/amd/amd/info_hes.c @@ -0,0 +1,697 @@ +/* + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989, 1993 + * 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. + * + * @(#)info_hes.c 8.1 (Berkeley) 6/6/93 + * + * $Id: info_hes.c,v 5.2.2.1 1992/02/09 15:08:29 jsp beta $ + * + */ + +/* + * Get info from Hesiod + * + * Zone transfer code from Bruce Cole <cole@cs.wisc.edu> + */ + +#include "am.h" + +#ifdef HAS_HESIOD_MAPS +#include <hesiod.h> + +#define HES_PREFIX "hesiod." +#define HES_PREFLEN 7 + +#ifdef HAS_HESIOD_RELOAD +#include <arpa/nameser.h> +#include <resolv.h> +#include <sys/uio.h> +#include <netdb.h> + +/* + * Patch up broken system include files + */ +#ifndef C_HS +#define C_HS 4 +#endif +#ifndef T_TXT +#define T_TXT 16 +#endif + +static int soacnt; +static struct timeval hs_timeout; +static int servernum; +#endif /* HAS_HESIOD_RELOAD */ + +/* + * No easy way to probe the server - check the map name begins with "hesiod." + */ +int hesiod_init P((char *map, time_t *tp)); +int hesiod_init(map, tp) +char *map; +time_t *tp; +{ +#ifdef DEBUG + dlog("hesiod_init(%s)", map); +#endif + *tp = 0; + return strncmp(map, HES_PREFIX, HES_PREFLEN) == 0 ? 0 : ENOENT; +} + + +/* + * Make Hesiod name. Skip past the "hesiod." + * at the start of the map name and append + * ".automount". The net effect is that a lookup + * of /defaults in hesiod.home will result in a + * call to hes_resolve("/defaults", "home.automount"); + */ +#ifdef notdef +#define MAKE_HES_NAME(dest, src) sprintf(dest, "%s%s", src + HES_PREFLEN, ".automount") +#endif + +/* + * Do a Hesiod nameserver call. + * Modify time is ignored by Hesiod - XXX + */ +int hesiod_search P((mnt_map *m, char *map, char **pval, time_t *tp)); +int hesiod_search(m, map, key, pval, tp) +mnt_map *m; +char *map; +char *key; +char **pval; +time_t *tp; +{ + int error; + char hes_key[MAXPATHLEN]; + char **rvec; +#ifdef DEBUG + dlog("hesiod_search(m=%x, map=%s, key=%s, pval=%x tp=%x)", m, map, key, pval, tp); +#endif + /*MAKE_HES_NAME(hes_map, map);*/ + sprintf(hes_key, "%s.%s", key, map+HES_PREFLEN); + + /* + * Call the resolver + */ +#ifdef DEBUG + dlog("hesiod_search: hes_resolve(%s, %s)", hes_key, "automount"); +#ifdef HAS_HESIOD_RELOAD + if (debug_flags & D_FULL) + _res.options |= RES_DEBUG; +#endif +#endif + rvec = hes_resolve(hes_key, "automount"); + /* + * If a reply was forthcoming then return + * it (and free subsequent replies) + */ + if (rvec && *rvec) { + *pval = *rvec; + while (*++rvec) + free(*rvec); + return 0; + } + + /* + * Otherwise reflect the hesiod error into a Un*x error + */ +#ifdef DEBUG + dlog("hesiod_search: Error: %d", hes_error()); +#endif + 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 + return error; +} + +#ifdef HAS_HESIOD_RELOAD +/* + * Zone transfer... + */ + +#define MAXHSNS 8 +#define MAX_NSADDR 16 + +static char *hs_domain; +static mnt_map *hs_map; +static int hs_nscount; +static char nsaddr_list[MAX_NSADDR][sizeof(struct in_addr)]; + +int hesiod_reload P((mnt_map *m, char *map, void (*fn)())); +int hesiod_reload(m, map, fn) +mnt_map *m; +char *map; +void (*fn)(); +{ + char *zone_name, *cp; + short domainlen; + int status; + +#ifdef DEBUG + dlog("hesiod_reload (%x %s %x)", m, map, fn); +#endif DEBUG + if (status = res_init()) { +#ifdef DEBUG + dlog("hesiod_reload: res_init failed with %d", status); +#endif + return(status); + } + _res.retrans = 90; + hs_map = m; + domainlen = strlen(hostdomain); + zone_name = hes_to_bind(map+HES_PREFLEN, "automount"); + if (*zone_name == '.') + zone_name++; + hs_domain = zone_name; + /* Traverse the DNS tree until we find an SOA we can transfer from. + (Our initial zone_name is likely to just be a subtree of a + real zone). */ + do { + /* If we can't find any NS records, go up a level in the + DNS tree */ + if (hs_get_ns_list(zone_name) == 0 && + hs_zone_transfer(zone_name) == 0) + return(0); + /* Move up DNS tree by one component */ + if (cp = strchr(zone_name, '.')) + zone_name = ++cp; + else + break; + } while (strlen(zone_name) >= domainlen); +#ifdef DEBUG + dlog("hesiod_reload: Giving up on %s", hs_domain); +#endif + return(-1); +} + +hs_zone_transfer(domain) +char *domain; +{ + int status, len; + char buf[PACKETSZ]; + /* Want to make sure ansbuf is well alligned */ + long ansbuf[PACKETSZ/sizeof(long)]; + +#ifdef DEBUG + dlog("hs_zone_transfer (%s)", domain); +#endif + if ((len = res_mkquery(QUERY, domain, C_HS, T_AXFR, + (char *)NULL, 0, NULL, buf, PACKETSZ)) == -1) { +#ifdef DEBUG + dlog("hs_zone_transfer: res_mkquery failed"); +#endif + errno = 0; + return(-1); + } + if ((status = hs_res_send(buf, len, (char *)ansbuf, PACKETSZ)) == -1) { +#ifdef DEBUG + dlog("hs_zone_transfer: hs_res_send failed. status %d errno %d", + status, errno); +#endif + errno = 0; + return(-1); + } + return(0); +} + +#define hs_server_addr(ns) ((struct in_addr *) nsaddr_list[ns]) + +hs_res_send(buf, buflen, answer, anslen) +char *buf; +int buflen; +char *answer; +int anslen; +{ + int retry, ns; + u_short id, len; + HEADER *hp = (HEADER *) buf; + struct iovec iov[2]; + static int s = -1; + int status; + struct sockaddr_in server; + + soacnt = 0; + id = hp->id; + /* + * Send request, RETRY times, or until successful + */ + for (retry = _res.retry; retry > 0; retry--) { + for (ns = 0; ns < hs_nscount; ns++) { + hs_timeout.tv_sec = + (_res.retrans << (_res.retry - retry)) + / hs_nscount; + if (hs_timeout.tv_sec <= 0) + hs_timeout.tv_sec = 1; + hs_timeout.tv_usec = 0; + if (s < 0) { + s = socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) { + continue; + } + servernum = ns; + bcopy(hs_server_addr(ns), &server.sin_addr, + sizeof(struct in_addr)); + server.sin_family = AF_INET; + server.sin_port = htons(NAMESERVER_PORT); + + if (connect(s, &server, + sizeof(struct sockaddr)) < 0) { + (void) close(s); + s = -1; + continue; + } + } + /* + * Send length & message + */ + len = htons((u_short)buflen); + iov[0].iov_base = (caddr_t)&len; + iov[0].iov_len = sizeof(len); + iov[1].iov_base = buf; + iov[1].iov_len = buflen; + if (writev(s, iov, 2) != sizeof(len) + buflen) { + (void) close(s); + s = -1; + continue; + } + status = 0; + while (s != -1 && soacnt < 2 && status != -2) { + if ((status = + hs_readresp(s, answer, anslen)) == -1) { + (void) close(s); + s = -1; + continue; + } + } + if (status == -2) { + /* There was a permanent error transfering this + zone. Give up. */ + if (s != -1) { + (void) close(s); + s = -1; + } + return(-1); + } + if (s == -1) + continue; + return (0); + } + } + if (errno == 0) + errno = ETIMEDOUT; + return (-1); +} + +/* Returns: + 0: Success + -1: Error + -2: Permanent failure +*/ +hs_readresp(s, answer, anslen) +int s; +char *answer; +int anslen; +{ + register int len, n; + char *cp; + + cp = answer; + len = sizeof(short); + while (len != 0 && + (n = hs_res_vcread(s, (char *)cp, (int)len, &hs_timeout)) > 0) { + cp += n; + len -= n; + } + if (n <= 0) + return(-1); + cp = answer; + if ((len = _getshort(cp)) > anslen) { +#ifdef DEBUG + dlog("hs_readresp: response too long: %d", len); +#endif + return(-1); + } + while (len != 0 && + (n = hs_res_vcread(s, (char *)cp, (int)len, &hs_timeout)) > 0) { + cp += n; + len -= n; + } + if (n <= 0) + return(-1); + return(hs_parse(answer, answer+PACKETSZ)); +} + +hs_res_vcread(sock, buf, buflen, timeout) +int sock, buflen; +char *buf; +struct timeval *timeout; +{ + register int n; + + if ((n = hs_res_selwait(sock, timeout)) > 0) + return(read(sock, buf, buflen)); + else + return(n); +} + +hs_res_selwait(sock, timeout) +int sock; +struct timeval *timeout; +{ + fd_set dsmask; + register int n; + + /* + * Wait for reply + */ + FD_ZERO(&dsmask); + FD_SET(sock, &dsmask); + n = select(sock+1, &dsmask, (fd_set *)NULL, + (fd_set *)NULL, timeout); + return(n); +} + +/* Returns: + 0: Success + -1: Error + -2: Permanent failure +*/ +hs_parse(msg, eom) +char *msg, *eom; +{ + register char *cp; + register HEADER *hp; + register int n, len; + int qdcount, ancount; + char key[PACKETSZ]; + char *key_cpy, *value, *hs_make_value(); + short type; + + hp = (HEADER *)msg; + if (hp->rcode != NOERROR || hp->opcode != QUERY) { + char dq[20]; +#ifdef DEBUG + dlog("Bad response (%d) from nameserver %s", hp->rcode, inet_dquad(dq, hs_server_addr(servernum)->s_addr)); +#endif DEBUG + return(-1); + } + cp = msg + sizeof(HEADER); + ancount = ntohs(hp->ancount); + qdcount = ntohs(hp->qdcount); + while (qdcount-- > 0) + cp += dn_skipname(cp, eom) + QFIXEDSZ; + if (soacnt == 0 && ancount == 0) { + /* XXX We should look for NS records to find SOA */ +#ifdef DEBUG + dlog("No SOA found"); +#endif + return(-2); + } + while (ancount-- > 0 && cp < eom) { + if ((n = dn_expand(msg, eom, cp, key, PACKETSZ)) < 0) + break; + cp += n; + if ((type = _getshort(cp)) == T_SOA) { + soacnt++; + } + cp += 2*sizeof(u_short) + sizeof(u_long); + len = _getshort(cp); + cp += sizeof(u_short); + /* Check to see if key is in our domain */ + if (type == T_TXT && hs_strip_our_domain(key)) { + value = hs_make_value(cp, len); + if (value == NULL) + return(-1); + key_cpy = strdup(key); +#ifdef DEBUG + dlog("hs_parse: Parsed key: %s, value: %s", key, + value); +#endif + mapc_add_kv(hs_map, key_cpy, value); + } + cp += len; + errno = 0; + } + return(0); +} + +/* Check to see if the domain name in the supplied argument matches + hs_domain. Strip hs_domain from supplied argument if so. */ +hs_strip_our_domain(name) +char *name; +{ + char *end_pos; + short targ_len, cur_len; + + targ_len = strlen(hs_domain); + cur_len = strlen(name); + if (cur_len <= targ_len) + return(0); + end_pos = &name[cur_len - targ_len]; + if (strcmp(end_pos, hs_domain) != 0) + return(0); + if (*--end_pos != '.') + return(0); + *end_pos = '\0'; + return(1); +} + +#define MAXDATA 8*1024 + +char * +hs_make_value(cp, len) +char *cp; +int len; +{ + char *value, *cpcpy, *valuep; + int cnt, nextcnt, totalcnt, lencpy; +#ifdef DEBUG + char *dbgname; + + dbgname = &cp[1]; +#endif DEBUG + + lencpy = len; + cpcpy = cp; + totalcnt = 0; + cnt = *cpcpy++; + while (cnt) { + totalcnt += cnt; + lencpy -= cnt+1; + if (lencpy == 0) + break; + nextcnt = cpcpy[cnt]; + cpcpy = &cpcpy[cnt+1]; + cnt = nextcnt; + } + if (totalcnt < 1 || totalcnt > MAXDATA || totalcnt > len) { +#ifdef DEBUG + dlog("TXT RR not of expected length (%d %d): %s", totalcnt, + len, dbgname); +#endif DEBUG + return(NULL); + } + /* Allocate null terminated string */ + value = (char *) xmalloc(totalcnt+1); + value[totalcnt] = '\0'; + cnt = *cp++; + valuep = value; + while (cnt) { + bcopy(cp, valuep, cnt); + len -= cnt+1; + if (len == 0) + break; + valuep = &valuep[cnt]; + nextcnt = cp[cnt]; + cp = &cp[cnt+1]; + cnt = nextcnt; + } + return(value); +} + +hs_make_ns_query(domain, ansbuf) +char *domain; +char *ansbuf; +{ + int status, len; + char buf[PACKETSZ]; + + if ((len = res_mkquery(QUERY, domain, C_HS, T_NS, + (char *)NULL, 0, NULL, buf, PACKETSZ)) == -1) { +#ifdef DEBUG + dlog("hs_get_ns_list: res_mkquery failed"); +#endif + errno = 0; + return(-1); + } + if ((status = res_send(buf, len, (char *)ansbuf, PACKETSZ)) == -1) { +#ifdef DEBUG + dlog("hs_get_ns_list: res_send failed. status %d errno %d", + status, errno); +#endif + errno = 0; + return(-1); + } + return(0); +} + +static void +add_address(addr) +struct in_addr *addr; +{ + char dq[20]; + bcopy((char *)addr, nsaddr_list[hs_nscount++], sizeof(struct in_addr)); +#ifdef DEBUG + dlog("Adding NS address %s", inet_dquad(dq, addr->s_addr)); +#endif DEBUG +} + +hs_get_ns_list(domain) +char *domain; +{ + register HEADER *hp; + int qdcount, nscount; + register char *cp; + register int n, len; + char key[PACKETSZ], name[PACKETSZ], msg[PACKETSZ], *eom; + register long **hptr; + struct hostent *ghp; + int numns; + char nsname[MAXHSNS][MAXDATA]; + int nshaveaddr[MAXHSNS], i; + short type; + + if (hs_make_ns_query(domain, msg) == -1) + return(-1); + numns = hs_nscount = 0; + eom = &msg[PACKETSZ]; + bzero(nsname, sizeof(nsname)); + hp = (HEADER *)msg; + if (hp->rcode != NOERROR || hp->opcode != QUERY) { +#ifdef DEBUG + dlog("Bad response (%d) from nameserver %#x", hp->rcode, + hs_server_addr(servernum)->s_addr); +#endif DEBUG + return(-1); + } + cp = msg + sizeof(HEADER); + qdcount = ntohs(hp->qdcount); + while (qdcount-- > 0) + cp += dn_skipname(cp, eom) + QFIXEDSZ; + nscount = ntohs(hp->ancount) + ntohs(hp->nscount) + ntohs(hp->arcount); +#ifdef DEBUG + dlog("hs_get_ns_list: Processing %d response records", nscount); +#endif + for (;nscount; nscount--) { + if ((n = dn_expand(msg, eom, cp, key, PACKETSZ)) < 0) + break; + cp += n; + type = _getshort(cp); + cp += 2*sizeof(u_short) + sizeof(u_long); + len = _getshort(cp); + cp += sizeof(u_short); +#ifdef DEBUG + dlog("hs_get_ns_list: Record type: %d", type); +#endif + switch (type) { + case T_NS: + if (numns >= MAXHSNS || strcasecmp(domain, key) != 0) + break; + if ((n = dn_expand(msg, eom, cp, name, PACKETSZ)) < 0) + break; +#ifdef DEBUG + dlog("hs_get_ns_list: NS name: %s", name); +#endif + for (i = 0; i < numns; i++) + if (strcasecmp(nsname[i], name) == 0) + break; + if (i == numns) { +#ifdef DEBUG + dlog("hs_get_ns_list: Saving name %s", name); +#endif + strncpy(nsname[numns], name, MAXDATA); + nshaveaddr[numns] = 0; + numns++; + } + break; + case T_A: + if (hs_nscount == MAX_NSADDR) + break; + for (i = 0; i < numns; i++) { + if (strcasecmp(nsname[i], domain) == 0) { + nshaveaddr[i]++; + add_address((struct in_addr *) cp); + break; + } + } + break; + default: + break; + } + if (hs_nscount == MAX_NSADDR) + break; + cp += len; + errno = 0; + } +#ifdef DEBUG + dlog("hs_get_ns_list: Found %d NS records", numns); +#endif + for (i = 0; i < numns; i++) { + if (nshaveaddr[i]) + continue; + if ((ghp = gethostbyname(nsname[i])) == 0) + continue; + for (hptr = (long **)ghp->h_addr_list; + *hptr && hs_nscount < MAX_NSADDR; hptr++) { + add_address((struct in_addr *) *hptr); + } + } + if (hs_nscount) + return(0); +#ifdef DEBUG + dlog("No NS records found for %s", domain); + return(-1); +#endif DEBUG +} +#endif /* HAS_HESIOD_RELOAD */ +#endif /* HAS_HESIOD_MAPS */ diff --git a/usr.sbin/amd/amd/info_ndbm.c b/usr.sbin/amd/amd/info_ndbm.c new file mode 100644 index 000000000000..d3deaa187f9f --- /dev/null +++ b/usr.sbin/amd/amd/info_ndbm.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989, 1993 + * 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. + * + * @(#)info_ndbm.c 8.1 (Berkeley) 6/6/93 + * + * $Id: info_ndbm.c,v 5.2.2.1 1992/02/09 15:08:31 jsp beta $ + * + */ + +/* + * Get info from NDBM map + */ + +#include "am.h" + +#ifdef HAS_NDBM_MAPS + +#include <ndbm.h> +#include <fcntl.h> +#include <sys/stat.h> + +static int search_ndbm P((DBM *db, char *key, char **val)); +static int search_ndbm(db, key, val) +DBM *db; +char *key; +char **val; +{ + datum k, v; + k.dptr = key; + k.dsize = strlen(key) + 1; + v = dbm_fetch(db, k); + if (v.dptr) { + *val = strdup(v.dptr); + return 0; + } + return ENOENT; +} + +int ndbm_search P((mnt_map *m, char *map, char *key, char **pval, time_t *tp)); +int ndbm_search(m, map, key, pval, tp) +mnt_map *m; +char *map; +char *key; +char **pval; +time_t *tp; +{ + DBM *db; + + db = dbm_open(map, O_RDONLY, 0); + if (db) { + struct stat stb; + int error; + error = fstat(dbm_pagfno(db), &stb); + if (!error && *tp < stb.st_mtime) { + *tp = stb.st_mtime; + error = -1; + } else { + error = search_ndbm(db, key, pval); + } + (void) dbm_close(db); + return error; + } + + return errno; +} + +int ndbm_init P((char *map, time_t *tp)); +int ndbm_init(map, tp) +char *map; +time_t *tp; +{ + DBM *db; + + db = dbm_open(map, O_RDONLY, 0); + if (db) { + struct stat stb; + + if (fstat(dbm_pagfno(db), &stb) < 0) + *tp = clocktime(); + else + *tp = stb.st_mtime; + dbm_close(db); + return 0; + } + + return errno; +} + +#endif /* HAS_NDBM_MAPS */ diff --git a/usr.sbin/amd/amd/info_nis.c b/usr.sbin/amd/amd/info_nis.c new file mode 100644 index 000000000000..ac80f5f975dd --- /dev/null +++ b/usr.sbin/amd/amd/info_nis.c @@ -0,0 +1,247 @@ +/* + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989, 1993 + * 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. + * + * @(#)info_nis.c 8.1 (Berkeley) 6/6/93 + * + * $Id: info_nis.c,v 5.2.2.1 1992/02/09 15:08:32 jsp beta $ + * + */ + +/* + * Get info from NIS map + */ + +#include "am.h" + +#ifdef HAS_NIS_MAPS +#include <rpcsvc/yp_prot.h> +#include <rpcsvc/ypclnt.h> + +/* + * Figure out the nis domain name + */ +static int determine_nis_domain(P_void) +{ +static 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; + } + + domain = strdup(default_domain); + + return 0; +} + + +#ifdef HAS_NIS_RELOAD +struct nis_callback_data { + mnt_map *ncd_m; + char *ncd_map; + void (*ncd_fn)(); +}; + +/* + * Callback from yp_all + */ +static int callback(status, key, kl, val, vl, data) +int status; +char *key; +int kl; +char *val; +int vl; +struct nis_callback_data *data; +{ + if (status == YP_TRUE) { + /* + * Add to list of maps + */ + char *kp = strnsave(key, kl); + char *vp = strnsave(val, vl); + (*data->ncd_fn)(data->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", + data->ncd_map, yperr_string(e), status, e); +#else + plog(XLOG_ERROR, "yp enumeration of %s: %s", data->ncd_map, yperr_string(e)); +#endif + } + + return TRUE; + } +} + +int nis_reload P((mnt_map *m, char *map, void (*fn)())); +int nis_reload(m, map, fn) +mnt_map *m; +char *map; +void (*fn)(); +{ + struct ypall_callback cbinfo; + int error; + struct nis_callback_data data; + + if (!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 = callback; + + error = yp_all(domain, map, &cbinfo); + + if (error) + plog(XLOG_ERROR, "error grabbing nis map of %s: %s", map, yperr_string(ypprot_err(error))); + + return error; +} +#endif /* HAS_NIS_RELOAD */ + +/* + * Try to locate a key using NIS. + */ +int nis_search P((mnt_map *m, char *map, char *key, char **val, time_t *tp)); +int nis_search(m, map, key, val, tp) +mnt_map *m; +char *map; +char *key; +char **val; +time_t *tp; +{ + int outlen; + int res; + int order; + + /* + * Make sure domain initialised + */ + if (!domain) { + int error = determine_nis_domain(); + if (error) + return error; + } + + /* + * Check if map has changed + */ + if (yp_order(domain, map, &order)) + return EIO; + if ((time_t) order > *tp) { + *tp = (time_t) order; + return -1; + } + + /* + * Lookup key + */ + res = yp_match(domain, map, key, strlen(key), val, &outlen); + + /* + * Do something interesting with the return code + */ + switch (res) { + case 0: + return 0; + + case YPERR_KEY: + return ENOENT; + + default: + plog(XLOG_ERROR, "%s: %s", map, yperr_string(res)); + return EIO; + } +} + +int nis_init P((char *map, time_t *tp)); +int nis_init(map, tp) +char *map; +time_t *tp; +{ + int order; + + if (!domain) { + int error = determine_nis_domain(); + if (error) + return error; + } + + /* + * To see if the map exists, try to find + * a master for it. + */ + if (yp_order(domain, map, &order)) + return ENOENT; + *tp = (time_t) order; +#ifdef DEBUG + dlog("NIS master for %s@%s has order %d", map, domain, order); +#endif + return 0; +} +#endif /* HAS_NIS_MAPS */ diff --git a/usr.sbin/amd/amd/info_passwd.c b/usr.sbin/amd/amd/info_passwd.c new file mode 100644 index 000000000000..3123e38c8d96 --- /dev/null +++ b/usr.sbin/amd/amd/info_passwd.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990, 1993 + * 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. + * + * @(#)info_passwd.c 8.1 (Berkeley) 6/6/93 + * + * $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. + */ + +#include "am.h" + +#ifdef HAS_PASSWD_MAPS +#include <pwd.h> + +#define PASSWD_MAP "/etc/passwd" + +/* + * Nothing to probe - check the map name is PASSWD_MAP. + */ +int passwd_init P((char *map, time_t *tp)); +int passwd_init(map, tp) +char *map; +time_t *tp; +{ + *tp = 0; + return strcmp(map, PASSWD_MAP) == 0 ? 0 : ENOENT; +} + + +/* + * Grab the entry via the getpwname routine + * Modify time is ignored by passwd - XXX + */ +int passwd_search P((mnt_map *m, char *map, char *key, char **pval, time_t *tp)); +int passwd_search(m, map, key, pval, tp) +mnt_map *m; +char *map; +char *key; +char **pval; +time_t *tp; +{ + char *dir = 0; + struct passwd *pw; + if (strcmp(key, "/defaults") == 0) { + *pval = strdup("type:=nfs"); + return 0; + } + + pw = getpwnam(key); + if (pw) { + /* + * We chop the home directory up as follows: + * /anydir/dom1/dom2/dom3/user + * + * and return + * rfs:=/anydir/dom3;rhost:=dom3.dom2.dom1;sublink:=user + * + * This allows cross-domain entries in your passwd file. + * ... but forget about security! + */ + char *user; + char *p, *q; + char val[MAXPATHLEN]; + char rhost[MAXHOSTNAMELEN]; + dir = strdup(pw->pw_dir); + /* + * Find user name. If no / then Invalid... + */ + user = strrchr(dir, '/'); + if (!user) + goto enoent; + *user++ = '\0'; + /* + * Find start of host "path". If no / then Invalid... + */ + p = strchr(dir+1, '/'); + if (!p) + goto enoent; + *p++ = '\0'; + /* + * At this point, p is dom1/dom2/dom3 + * Copy, backwards, into rhost replacing + * / with . + */ + rhost[0] = '\0'; + do { + q = strrchr(p, '/'); + if (q) { + strcat(rhost, q + 1); + strcat(rhost, "."); + *q = '\0'; + } else { + strcat(rhost, p); + } + } while (q); + /* + * Sanity check + */ + if (*rhost == '\0' || *user == '\0' || *dir == '\0') + goto enoent; + /* + * Make up return string + */ + q = strchr(rhost, '.'); + if (q) + *q = '\0'; + sprintf(val, "rfs:=%s/%s;rhost:=%s;sublink:=%s;fs:=${autodir}%s", + dir, rhost, rhost, user, pw->pw_dir); + if (q) + *q = '.'; + *pval = strdup(val); + return 0; + } + +enoent: + if (dir) + free(dir); + + return ENOENT; +} +#endif /* HAS_PASSWD_MAPS */ diff --git a/usr.sbin/amd/amd/info_union.c b/usr.sbin/amd/amd/info_union.c new file mode 100644 index 000000000000..e3062adaa5a3 --- /dev/null +++ b/usr.sbin/amd/amd/info_union.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990, 1993 + * 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. + * + * @(#)info_union.c 8.1 (Berkeley) 6/6/93 + * + * $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! + */ + +#include "am.h" + +#ifdef HAS_UNION_MAPS + +#ifdef _POSIX_SOURCE +#include <dirent.h> +#define DIRENT struct dirent +#else +#include <sys/dir.h> +#define DIRENT struct direct +#endif + +#define UNION_PREFIX "union:" +#define UNION_PREFLEN 6 + +/* + * No way to probe - check the map name begins with "union:" + */ +int union_init P((char *map, time_t *tp)); +int union_init(map, tp) +char *map; +time_t *tp; +{ + *tp = 0; + return strncmp(map, UNION_PREFIX, UNION_PREFLEN) == 0 ? 0 : ENOENT; +} + +int union_search P((mnt_map *m, char *map, char *key, char **pval, time_t *tp)); +int union_search(m, map, key, pval, tp) +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); + free(mapd); + free(v); + return 0; +} + +int union_reload P((mnt_map *m, char *map, void (*fn)())); +int union_reload(m, map, fn) +mnt_map *m; +char *map; +void (*fn)(); +{ + 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; + 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 + while (dp = readdir(dirp)) { + char *val; + if (dp->d_name[0] == '.' && + (dp->d_name[1] == '\0' || + (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) + continue; + +#ifdef DEBUG + dlog("... gives %s", dp->d_name); +#endif + 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); + } + free(mapd); + free(v); + return 0; +} + +#endif /* HAS_UNION_MAPS */ diff --git a/usr.sbin/amd/amd/map.c b/usr.sbin/amd/amd/map.c new file mode 100644 index 000000000000..6f2acb383907 --- /dev/null +++ b/usr.sbin/amd/amd/map.c @@ -0,0 +1,1140 @@ +/*- + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990, 1993 + * 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. + * + * $Id: map.c,v 5.2.2.1 1992/02/09 15:08:36 jsp beta $ + */ + +#ifndef lint +static char sccsid[] = "@(#)map.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "am.h" + +/* + * Generation Numbers. + * + * Generation numbers are allocated to every node created + * by amd. When a filehandle is computed and sent to the + * kernel, the generation number makes sure that it is safe + * to reallocate a node slot even when the kernel has a cached + * reference to its old incarnation. + * No garbage collection is done, since it is assumed that + * there is no way that 2^32 generation numbers could ever + * be allocated by a single run of amd - there is simply + * not enough cpu time available. + */ +static unsigned int am_gen = 2; /* Initial generation number */ +#define new_gen() (am_gen++) + +am_node **exported_ap = (am_node **) 0; +int exported_ap_size = 0; +int first_free_map = 0; /* First available free slot */ +int last_used_map = -1; /* Last unavailable used slot */ +static int timeout_mp_id; /* Id from last call to timeout */ + +/* + * This is the default attributes field which + * is copied into every new node to be created. + * The individual filesystem fs_init() routines + * patch the copy to represent the particular + * details for the relevant filesystem type + */ +static struct fattr gen_fattr = { + 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 */ +}; + +/* + * Resize exported_ap map + */ +static int exported_ap_realloc_map P((int nsize)); +static int exported_ap_realloc_map(nsize) +int nsize; +{ +#ifdef notdef + /* + * If a second realloc occasionally causes Amd to die + * in then include this check. + */ + if (exported_ap_size != 0) /* XXX */ + return 0; +#endif + + /* + * 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) + bzero((char*) (exported_ap+exported_ap_size), + (nsize - exported_ap_size) * sizeof(am_node*)); + exported_ap_size = nsize; + + return 1; +} + + +/* + * The root of the mount tree. + */ +am_node *root_node; + +/* + * Allocate a new mount slot and create + * a new node. + * Fills in the map number of the node, + * but leaves everything else uninitialised. + */ +am_node *exported_ap_alloc(P_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(am_node); + bzero((char *) mp, 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; + + /* + * Shrink exported_ap if reasonable + */ + if (last_used_map < exported_ap_size - (NEXP_AP + NEXP_AP_MARGIN)) + exported_ap_realloc_map(exported_ap_size - NEXP_AP); + +#ifdef DEBUG + /*dlog("alloc_exp: last_used_map = %d, first_free_map = %d\n", + last_used_map, first_free_map);*/ +#endif /* DEBUG */ + + return mp; +} + +/* + * Free a mount slot + */ +void exported_ap_free P((am_node *mp)); +void exported_ap_free(mp) +am_node *mp; +{ + /* + * Sanity check + */ + if (!mp) + return; + + /* + * Zero the slot pointer to avoid double free's + */ + exported_ap[mp->am_mapno] = 0; + + /* + * Update the free and last_used indices + */ + if (mp->am_mapno == last_used_map) + while (last_used_map >= 0 && exported_ap[last_used_map] == 0) + --last_used_map; + + if (first_free_map > mp->am_mapno) + first_free_map = mp->am_mapno; + +#ifdef DEBUG + /*dlog("free_exp: last_used_map = %d, first_free_map = %d\n", + last_used_map, first_free_map);*/ +#endif /* DEBUG */ + + /* + * Free the mount node + */ + free((voidp) mp); +} + +/* + * Insert mp into the correct place, + * where p_mp is its parent node. + * A new node gets placed as the youngest sibling + * of any other children, and the parent's child + * pointer is adjusted to point to the new child node. + */ +void insert_am(mp, p_mp) +am_node *mp; +am_node *p_mp; +{ + /* + * If this is going in at the root then flag it + * so that it cannot be unmounted by amq. + */ + if (p_mp == root_node) + mp->am_flags |= AMF_ROOT; + /* + * Fill in n-way links + */ + mp->am_parent = p_mp; + mp->am_osib = p_mp->am_child; + if (mp->am_osib) + mp->am_osib->am_ysib = mp; + p_mp->am_child = mp; +} + +/* + * Remove am from its place in the mount tree + */ +void remove_am(mp) +am_node *mp; +{ + /* + * 1. Consistency check + */ + if (mp->am_child && mp->am_parent) { + plog(XLOG_WARNING, "children of \"%s\" still exist - deleting anyway", mp->am_path); + } + + /* + * 2. Update parent's child pointer + */ + if (mp->am_parent && mp->am_parent->am_child == mp) + mp->am_parent->am_child = mp->am_osib; + + /* + * 3. Unlink from sibling chain + */ + if (mp->am_ysib) + mp->am_ysib->am_osib = mp->am_osib; + if (mp->am_osib) + mp->am_osib->am_ysib = mp->am_ysib; +} + +/* + * Compute a new time to live value for a node. + */ +void new_ttl(mp) +am_node *mp; +{ + mp->am_timeo_w = 0; + + mp->am_ttl = clocktime(); + mp->am_fattr.atime.seconds = mp->am_ttl; + mp->am_ttl += mp->am_timeo; /* sun's -tl option */ +} + +void mk_fattr P((am_node *mp, ftype vntype)); +void mk_fattr(mp, vntype) +am_node *mp; +ftype vntype; +{ + switch (vntype) { + case NFDIR: + mp->am_fattr.type = NFDIR; + mp->am_fattr.mode = NFSMODE_DIR | 0555; + mp->am_fattr.nlink = 2; + mp->am_fattr.size = 512; + break; + case NFLNK: + mp->am_fattr.type = NFLNK; + mp->am_fattr.mode = NFSMODE_LNK | 0777; + mp->am_fattr.nlink = 1; + mp->am_fattr.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 bzero'd + * before getting here so anything that would + * be set to zero isn't done here. + */ +void init_map(mp, dir) +am_node *mp; +char *dir; +{ + /* mp->am_mapno initalised by exported_ap_alloc */ + mp->am_mnt = new_mntfs(); + mp->am_name = strdup(dir); + mp->am_path = strdup(dir); + /*mp->am_link = 0;*/ + /*mp->am_parent = 0;*/ + /*mp->am_ysib = 0;*/ + /*mp->am_osib = 0;*/ + /*mp->am_child = 0;*/ + /*mp->am_flags = 0;*/ + /*mp->am_error = 0;*/ + mp->am_gen = new_gen(); + /*mp->am_pref = 0;*/ + + mp->am_timeo = am_timeo; + mp->am_attr.status = NFS_OK; + mp->am_fattr = gen_fattr; + mp->am_fattr.fsid = 42; + mp->am_fattr.fileid = 0; + mp->am_fattr.atime.seconds = clocktime(); + mp->am_fattr.atime.useconds = 0; + mp->am_fattr.mtime = mp->am_fattr.ctime = mp->am_fattr.atime; + + new_ttl(mp); + mp->am_stats.s_mtime = mp->am_fattr.atime.seconds; + /*mp->am_private = 0;*/ +} + +/* + * Free a mount node. + * The node must be already unmounted. + */ +void free_map(mp) +am_node *mp; +{ + remove_am(mp); + + if (mp->am_link) + free(mp->am_link); + if (mp->am_name) + free(mp->am_name); + if (mp->am_path) + free(mp->am_path); + if (mp->am_pref) + free(mp->am_pref); + + if (mp->am_mnt) + free_mntfs(mp->am_mnt); + + exported_ap_free(mp); +} + +/* + * Convert from file handle to + * automount node. + */ +am_node *fh_to_mp3(fhp, rp, c_or_d) +nfs_fh *fhp; +int *rp; +int c_or_d; +{ + struct am_fh *fp = (struct am_fh *) fhp; + am_node *ap = 0; + + /* + * Check process id matches + * If it doesn't then it is probably + * from an old kernel cached filehandle + * which is now out of date. + */ + if (fp->fhh_pid != mypid) + goto drop; + + /* + * Make sure the index is valid before + * exported_ap is referenced. + */ + if (fp->fhh_id < 0 || fp->fhh_id >= 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.mtime.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(fhp) +nfs_fh *fhp; +{ + int dummy; + return fh_to_mp2(fhp, &dummy); +} + +/* + * Convert from automount node to + * file handle. + */ +void mp_to_fh(mp, fhp) +am_node *mp; +struct nfs_fh *fhp; +{ + struct am_fh *fp = (struct am_fh *) fhp; + + /* + * Take the process id + */ + fp->fhh_pid = mypid; + /* + * .. the map number + */ + fp->fhh_id = mp->am_mapno; + /* + * .. and the generation number + */ + fp->fhh_gen = mp->am_gen; + /* + * .. to make a "unique" triple that will never + * be reallocated except across reboots (which doesn't matter) + * or if we are unlucky enough to be given the same + * pid as a previous amd (very unlikely). + */ +} + +static am_node *find_ap2 P((char *dir, am_node *mp)); +static am_node *find_ap2(dir, mp) +char *dir; +am_node *mp; +{ + if (mp) { + am_node *mp2; + if (strcmp(mp->am_path, dir) == 0) + return mp; + + if ((mp->am_mnt->mf_flags & MFF_MOUNTED) && + strcmp(mp->am_mnt->mf_mount, dir) == 0) + return mp; + + mp2 = find_ap2(dir, mp->am_osib); + if (mp2) + return mp2; + return find_ap2(dir, mp->am_child); + } + + return 0; +} + +/* + * Find the mount node corresponding + * to dir. dir can match either the + * automount path or, if the node is + * mounted, the mount location. + */ +am_node *find_ap P((char *dir)); +am_node *find_ap(dir) +char *dir; +{ + int i; + + for (i = last_used_map; i >= 0; --i) { + am_node *mp = exported_ap[i]; + if (mp && (mp->am_flags & AMF_ROOT)) { + mp = find_ap2(dir, exported_ap[i]); + if (mp) + return mp; + } + } + + return 0; +} + +/* + * Find the mount node corresponding + * to the mntfs structure. + */ +am_node *find_mf P((mntfs *mf)); +am_node *find_mf(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. + */ +nfs_fh *root_fh(dir) +char *dir; +{ + static nfs_fh nfh; + am_node *mp = root_ap(dir, TRUE); + if (mp) { + mp_to_fh(mp, &nfh); + /* + * 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 + } + return &nfh; + } + + /* + * Should never get here... + */ + plog(XLOG_ERROR, "Can't find root filehandle for %s", dir); + return 0; +} + +am_node *root_ap(dir, path) +char *dir; +int path; +{ + am_node *mp = find_ap(dir); + if (mp && mp->am_parent == root_node) + return mp; + + return 0; +} + +/* + * Timeout all nodes waiting on + * a given Fserver. + */ +void map_flush_srvr P((fserver *fs)); +void map_flush_srvr(fs) +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 P((char *dir, voidp arg)); +int mount_auto_node(dir, arg) +char *dir; +voidp arg; +{ + int error = 0; + (void) afs_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 P((void)); +int mount_exported() +{ + /* + * Iterate over all the nodes to be started + */ + return root_keyiter((void (*)P((char*,void*))) mount_auto_node, root_node); +} + +/* + * Construct top-level node + */ +void make_root_node P((void)); +void make_root_node() +{ + 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(&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(P_void) +{ + int i; + for (i = last_used_map; i >= 0; --i) { + am_node *mp = exported_ap[i]; + if (mp) { + mntfs *mf = mp->am_mnt; + if (mf->mf_flags & MFF_UNMOUNTING) { + /* + * If this node is being unmounted then + * just ignore it. However, this could + * prevent amd from finishing if the + * unmount gets blocked since the am_node + * will never be free'd. am_unmounted needs + * telling about this possibility. - XXX + */ + continue; + } + if (mf && !(mf->mf_ops->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; + am_unmounted(mp); + } else { + /* + * Any other node gets forcibly + * timed out + */ + mp->am_flags &= ~AMF_NOTIMEOUT; + mp->am_mnt->mf_flags &= ~MFF_RSTKEEP; + mp->am_ttl = 0; + mp->am_timeo = 1; + mp->am_timeo_w = 0; + } + } + } +} + +static int unmount_node P((am_node *mp)); +static int unmount_node(mp) +am_node *mp; +{ + mntfs *mf = mp->am_mnt; + int error; + + if ((mf->mf_flags & MFF_ERROR) || mf->mf_refc > 1) { + /* + * Just unlink + */ +#ifdef DEBUG + if (mf->mf_flags & MFF_ERROR) + dlog("No-op unmount of error node %s", mf->mf_info); +#endif /* DEBUG */ + error = 0; + } else { +#ifdef DEBUG + dlog("Unmounting %s (%s)", mf->mf_mount, mf->mf_info); +#endif /* DEBUG */ + error = (*mf->mf_ops->umount_fs)(mp); + } + + if (error) { +#ifdef DEBUG + errno = error; /* XXX */ + dlog("%s: unmount: %m", mf->mf_mount); +#endif /* DEBUG */ + } + + return error; +} + +#ifdef FLUSH_KERNEL_NAME_CACHE +static void flush_kernel_name_cache P((am_node*)); +static void flush_kernel_name_cache(mp) +am_node *mp; +{ + int islink = (mp->am_mnt->mf_fattr.type == NFLNK); + int isdir = (mp->am_mnt->mf_fattr.type == NFDIR); + int elog = 0; + if (islink) { + if (unlink(mp->am_path) < 0) + elog = 1; + } else if (isdir) { + if (rmdir(mp->am_path) < 0) + elog = 1; + } + if (elog) + plog(XLOG_WARNING, "failed to clear \"%s\" from dnlc: %m", mp->am_path); +} +#endif /* FLUSH_KERNEL_NAME_CACHE */ + +static int unmount_node_wrap P((voidp vp)); +static int unmount_node_wrap(vp) +voidp vp; +{ +#ifndef FLUSH_KERNEL_NAME_CACHE + return unmount_node((am_node*) vp); +#else /* FLUSH_KERNEL_NAME_CACHE */ + /* + * This code should just say: + * return unmount_node((am_node *) vp); + * + * However... + * The kernel keeps a cached copy of filehandles, + * and doesn't ever uncache them (apparently). So + * when Amd times out a node the kernel will have a + * stale filehandle. When the kernel next uses the + * filehandle it gets ESTALE. + * + * The workaround: + * Arrange that when a node is removed an unlink or + * rmdir is done on that path so that the kernel + * cache is done. Yes - yuck. + * + * This can all be removed (and the background + * unmount flag in sfs_ops) if/when the kernel does + * something smarter. + * + * If the unlink or rmdir failed then just log a warning, + * don't fail the unmount. This can occur if the kernel + * client code decides that the object is still referenced + * and should be renamed rather than discarded. + * + * There is still a race condition here... + * if another process is trying to access the same + * filesystem at the time we get here, then + * it will block, since the MF_UNMOUNTING flag will + * be set. That may, or may not, cause the entire + * system to deadlock. Hmmm... + */ + am_node *mp = (am_node *) vp; + int isauto = mp->am_parent && (mp->am_parent->am_mnt->mf_fattr.type == NFDIR); + int error = unmount_node(mp); + if (error) + return error; + if (isauto && (int)amd_state < (int)Finishing) + flush_kernel_name_cache(mp); + + return 0; +#endif /* FLUSH_KERNEL_NAME_CACHE */ +} + +static void free_map_if_success(rc, term, closure) +int rc; +int term; +voidp closure; +{ + am_node *mp = (am_node *) closure; + mntfs *mf = mp->am_mnt; + + /* + * Not unmounting any more + */ + mf->mf_flags &= ~MFF_UNMOUNTING; + + /* + * If a timeout was defered because the underlying filesystem + * was busy then arrange for a timeout as soon as possible. + */ + if (mf->mf_flags & MFF_WANTTIMO) { + mf->mf_flags &= ~MFF_WANTTIMO; + reschedule_timeout_mp(); + } + + if (term) { + plog(XLOG_ERROR, "unmount for %s got signal %d", mp->am_path, term); +#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(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 + 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() +{ +#define NEVER (time_t) 0 +#define smallest_t(t1, t2) \ + (t1 != NEVER ? (t2 != NEVER ? (t1 < t2 ? t1 : t2) : t1) : t2) +#define IGNORE_FLAGS (MFF_MOUNTING|MFF_UNMOUNTING|MFF_RESTART) + + int i; + time_t t = NEVER; + time_t now = clocktime(); + int backoff = 0; + +#ifdef DEBUG + dlog("Timing out automount points..."); +#endif /* DEBUG */ + for (i = last_used_map; i >= 0; --i) { + am_node *mp = exported_ap[i]; + mntfs *mf; + /* + * Just continue if nothing mounted, or can't be timed out. + */ + if (!mp || (mp->am_flags & AMF_NOTIMEOUT)) + continue; + /* + * Pick up mounted filesystem + */ + mf = mp->am_mnt; + if (!mf) + continue; + /* + * Don't delete last reference to a restarted filesystem. + */ + if ((mf->mf_flags & MFF_RSTKEEP) && mf->mf_refc == 1) + continue; + /* + * If there is action on this filesystem then ignore it + */ + if (!(mf->mf_flags & IGNORE_FLAGS)) { + int expired = 0; + mf->mf_flags &= ~MFF_WANTTIMO; +#ifdef DEBUG + /*dlog("t is initially @%d, zero in %d secs", t, t - now);*/ +#endif /* DEBUG */ + if (now >= mp->am_ttl) { + 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 * am_timeo_w) + mp->am_timeo_w += 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); + +#ifdef DEBUG + /*dlog("after ttl t is @%d, zero in %d secs", t, t - now);*/ +#endif /* DEBUG */ + + if (!mp->am_child && mf->mf_error >= 0 && expired) { + /* + * If the unmount was backgrounded then + * bump the backoff counter. + */ + if (unmount_mp(mp)) { + backoff = 2; +#ifdef DEBUG + /*dlog("backing off subsequent unmounts by at least %d seconds", backoff);*/ +#endif + } + } + } else if (mf->mf_flags & MFF_UNMOUNTING) { + mf->mf_flags |= MFF_WANTTIMO; + } + } + + if (t == NEVER) { +#ifdef DEBUG + dlog("No further timeouts"); +#endif /* DEBUG */ + t = now + ONE_HOUR; + } + + /* + * Sanity check to avoid runaways. + * Absolutely should never get this but + * if you do without this trap amd will thrash. + */ + if (t <= now) { + t = now + 6; /* XXX */ + plog(XLOG_ERROR, "Got a zero interval in timeout_mp()!"); + } + /* + * XXX - when shutting down, make things happen faster + */ + if ((int)amd_state >= (int)Finishing) + t = now + 1; +#ifdef DEBUG + dlog("Next mount timeout in %ds", t - now); +#endif /* DEBUG */ + + timeout_mp_id = timeout(t - now, timeout_mp, 0); + +#undef NEVER +#undef smallest_t +#undef IGNORE_FLAGS +} + +/* + * Cause timeout_mp to be called soonest + */ +void reschedule_timeout_mp() +{ + if (timeout_mp_id) + untimeout(timeout_mp_id); + timeout_mp_id = timeout(0, timeout_mp, 0); +} diff --git a/usr.sbin/amd/amd/mapc.c b/usr.sbin/amd/amd/mapc.c new file mode 100644 index 000000000000..2155f19cfa4b --- /dev/null +++ b/usr.sbin/amd/amd/mapc.c @@ -0,0 +1,914 @@ +/*- + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989, 1993 + * 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. + * + * $Id: mapc.c,v 5.2.2.1 1992/02/09 15:08:38 jsp beta $ + */ + +#ifndef lint +static char sccsid[] = "@(#)mapc.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Mount map cache + */ + +#include "am.h" +#ifdef HAS_REGEXP +#include RE_HDR +#endif + +/* + * Hash table size + */ +#define NKVHASH (1 << 2) /* Power of two */ + +/* + * Wildcard key + */ +static char wildcard[] = "*"; + +/* + * 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 +#ifdef HAS_REGEXP +#define MAPC_RE 0x020 +#define MAPC_ISRE(m) ((m)->alloc == MAPC_RE) +#else +#define MAPC_ISRE(m) FALSE +#endif +#define MAPC_CACHE_MASK 0x0ff +#define MAPC_SYNC 0x100 + +static struct opt_tab mapc_opt[] = { + { "all", MAPC_ALL }, + { "default", MAPC_DFLT }, + { "inc", MAPC_INC }, + { "mapdefault", MAPC_DFLT }, + { "none", MAPC_NONE }, +#ifdef HAS_REGEXP + { "re", MAPC_RE }, + { "regexp", MAPC_RE }, +#endif + { "sync", MAPC_SYNC }, + { 0, 0 } +}; + +/* + * Lookup recursion + */ +#define MREC_FULL 2 +#define MREC_PART 1 +#define MREC_NONE 0 + +/* + * Cache map operations + */ +typedef void add_fn P((mnt_map*, char*, char*)); +typedef int init_fn P((char*, time_t*)); +typedef int search_fn P((mnt_map*, char*, char*, char**, time_t*)); +typedef int reload_fn P((mnt_map*, char*, add_fn*)); +typedef int mtime_fn P((char*, time_t*)); + +static void mapc_sync P((mnt_map*)); + +/* + * Map type + */ +typedef struct map_type map_type; +struct map_type { + char *name; /* Name of this map type */ + init_fn *init; /* Initialisation */ + reload_fn *reload; /* Reload or fill */ + search_fn *search; /* Search for new entry */ + mtime_fn *mtime; /* Find modify time */ + int def_alloc; /* Default allocation mode */ +}; + +/* + * Key-value pair + */ +typedef struct kv kv; +struct kv { + kv *next; + char *key; + char *val; +}; + +struct mnt_map { + qelem hdr; + int refc; /* Reference count */ + 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 */ + search_fn *search; /* Function to be used for searching */ + mtime_fn *mtime; /* Modify time function */ + kv *kvhash[NKVHASH]; /* Cached data */ +}; + +/* + * Map for root node + */ +static mnt_map *root_map; + +/* + * List of known maps + */ +extern qelem map_list_head; +qelem map_list_head = { &map_list_head, &map_list_head }; + +/* + * Configuration + */ + +/* ROOT MAP */ +static int root_init P((char*, time_t*)); + +/* FILE MAPS */ +#ifdef HAS_FILE_MAPS +extern int file_init P((char*, time_t*)); +extern int file_reload P((mnt_map*, char*, add_fn*)); +extern int file_search P((mnt_map*, char*, char*, char**, time_t*)); +extern int file_mtime P((char*, time_t*)); +#endif /* HAS_FILE_MAPS */ + +/* Network Information Service (NIS) MAPS */ +#ifdef HAS_NIS_MAPS +extern int nis_init P((char*, time_t*)); +#ifdef HAS_NIS_RELOAD +extern int nis_reload P((mnt_map*, char*, add_fn*)); +#else +#define nis_reload error_reload +#endif +extern int nis_search P((mnt_map*, char*, char*, char**, time_t*)); +#define nis_mtime nis_init +#endif /* HAS_NIS_MAPS */ + +/* NDBM MAPS */ +#ifdef HAS_NDBM_MAPS +#ifdef OS_HAS_NDBM +extern int ndbm_init P((char*, time_t*)); +extern int ndbm_search P((mnt_map*, char*, char*, char**, time_t*)); +#define ndbm_mtime ndbm_init +#endif /* OS_HAS_NDBM */ +#endif /* HAS_NDBM_MAPS */ + +/* PASSWD MAPS */ +#ifdef HAS_PASSWD_MAPS +extern int passwd_init P((char*, time_t*)); +extern int passwd_search P((mnt_map*, char*, char*, char**, time_t*)); +#endif /* HAS_PASSWD_MAPS */ + +/* HESIOD MAPS */ +#ifdef HAS_HESIOD_MAPS +extern int hesiod_init P((char*, time_t*)); +#ifdef HAS_HESIOD_RELOAD +extern int hesiod_reload P((mnt_map*, char*, add_fn*)); +#else +#define hesiod_reload error_reload +#endif +extern int hesiod_search P((mnt_map*, char*, char*, char**, time_t*)); +#endif /* HAS_HESIOD_MAPS */ + +/* UNION MAPS */ +#ifdef HAS_UNION_MAPS +extern int union_init P((char*, time_t*)); +extern int union_search P((mnt_map*, char*, char*, char**, time_t*)); +extern int union_reload P((mnt_map*, char*, add_fn*)); +#endif /* HAS_UNION_MAPS */ + +/* ERROR MAP */ +static int error_init P((char*, time_t*)); +static int error_reload P((mnt_map*, char*, add_fn*)); +static int error_search P((mnt_map*, char*, char*, char**, time_t*)); +static int error_mtime P((char*, time_t*)); + +static map_type maptypes[] = { + { "root", root_init, error_reload, error_search, error_mtime, MAPC_ROOT }, + +#ifdef HAS_PASSWD_MAPS + { "passwd", passwd_init, error_reload, passwd_search, error_mtime, MAPC_INC }, +#endif + +#ifdef HAS_HESIOD_MAPS + { "hesiod", hesiod_init, hesiod_reload, hesiod_search, error_mtime, MAPC_ALL }, +#endif + +#ifdef HAS_UNION_MAPS + { "union", union_init, union_reload, union_search, error_mtime, MAPC_ALL }, +#endif + +#ifdef HAS_NIS_MAPS + { "nis", nis_init, nis_reload, nis_search, nis_mtime, MAPC_INC }, +#endif + +#ifdef HAS_NDBM_MAPS + { "ndbm", ndbm_init, error_reload, ndbm_search, ndbm_mtime, MAPC_INC }, +#endif + +#ifdef HAS_FILE_MAPS + { "file", file_init, file_reload, file_search, file_mtime, MAPC_ALL }, +#endif + + { "error", error_init, error_reload, error_search, error_mtime, MAPC_NONE }, +}; + +/* + * Hash function + */ +static unsigned int kvhash_of P((char *key)); +static unsigned int kvhash_of(key) +char *key; +{ + unsigned int i, j; + + for (i = 0; j = *key++; i += j) + ; + + return i % NKVHASH; +} + +void mapc_showtypes P((FILE *fp)); +void mapc_showtypes(fp) +FILE *fp; +{ + map_type *mt; + char *sep = ""; + for (mt = maptypes; mt < maptypes+sizeof(maptypes)/sizeof(maptypes[0]); mt++) { + fprintf(fp, "%s%s", sep, mt->name); + sep = ", "; + } +} + +static Const char *reg_error = "?"; +void regerror P((Const char *m)); +void regerror(m) +Const char *m; +{ + reg_error = m; +} + +/* + * Add key and val to the map m. + * key and val are assumed to be safe copies + */ +void mapc_add_kv P((mnt_map *m, char *key, char *val)); +void mapc_add_kv(m, key, val) +mnt_map *m; +char *key; +char *val; +{ + kv **h; + kv *n; + int hash = kvhash_of(key); + +#ifdef DEBUG + dlog("add_kv: %s -> %s", key, val); +#endif + +#ifdef HAS_REGEXP + if (MAPC_ISRE(m)) { + char keyb[MAXPATHLEN]; + regexp *re; + /* + * Make sure the string is bound to the start and end + */ + sprintf(keyb, "^%s$", key); + re = regcomp(keyb); + if (re == 0) { + plog(XLOG_USER, "error compiling RE \"%s\": %s", keyb, reg_error); + return; + } else { + free(key); + key = (char *) re; + } + } +#endif + + h = &m->kvhash[hash]; + n = ALLOC(kv); + n->key = key; + n->val = val; + n->next = *h; + *h = n; +} + +void mapc_repl_kv P((mnt_map *m, char *key, char *val)); +void mapc_repl_kv(m, key, val) +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) { + free(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 P((mnt_map *m, char *key, char **valp)); +static int search_map(m, key, valp) +mnt_map *m; +char *key; +char **valp; +{ + int rc; + do { + rc = (*m->search)(m, m->map_name, key, valp, &m->modify); + if (rc < 0) { + plog(XLOG_MAP, "Re-synchronizing cache for map %s", m->map_name); + mapc_sync(m); + } + } while (rc < 0); + + return rc; +} + +/* + * Do a wildcard lookup in the map and + * save the result. + */ +static void mapc_find_wildcard P((mnt_map *m)); +static void mapc_find_wildcard(m) +mnt_map *m; +{ + /* + * Attempt to find the wildcard entry + */ + int rc = search_map(m, wildcard, &m->wildcard); + + if (rc != 0) + m->wildcard = 0; +} + +/* + * Make a duplicate reference to an existing map + */ +#define mapc_dup(m) ((m)->refc++, (m)) + +/* + * Do a map reload + */ +static int mapc_reload_map(m) +mnt_map *m; +{ + int error; +#ifdef DEBUG + dlog("calling map reload on %s", m->map_name); +#endif + 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 + error = mapc_search(m, wildcard, &m->wildcard); + if (error) + m->wildcard = 0; + return 0; +} + +/* + * Create a new map + */ +static mnt_map *mapc_create P((char *map, char *opt)); +static mnt_map *mapc_create(map, opt) +char *map; +char *opt; +{ + mnt_map *m = ALLOC(mnt_map); + map_type *mt; + time_t modify; + int alloc = 0; + + (void) cmdoption(opt, mapc_opt, &alloc); + + for (mt = maptypes; mt < maptypes+sizeof(maptypes)/sizeof(maptypes[0]); mt++) + if ((*mt->init)(map, &modify) == 0) + break; + /* 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 HAS_REGEXP + 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 + } + +#ifdef DEBUG + dlog("Map for %s coming from maptype %s", map, mt->name); +#endif + + m->alloc = alloc; + m->reload = mt->reload; + m->modify = modify; + m->search = alloc >= MAPC_ALL ? error_search : mt->search; + m->mtime = mt->mtime; + bzero((voidp) m->kvhash, 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 P((mnt_map *m)); +static void mapc_clear(m) +mnt_map *m; +{ + int i; + + /* + * For each of the hash slots, chain + * along free'ing the data. + */ + for (i = 0; i < NKVHASH; i++) { + kv *k = m->kvhash[i]; + while (k) { + kv *n = k->next; + free((voidp) k->key); + if (k->val) + free((voidp) k->val); + free((voidp) k); + k = n; + } + } + /* + * Zero the hash slots + */ + bzero((voidp) m->kvhash, sizeof(m->kvhash)); + /* + * Free the wildcard if it exists + */ + if (m->wildcard) { + free(m->wildcard); + m->wildcard = 0; + } +} + +/* + * Find a map, or create one if it does not exist + */ +mnt_map *mapc_find P((char *map, char *opt)); +mnt_map *mapc_find(map, opt) +char *map; +char *opt; +{ + mnt_map *m; + + /* + * Search the list of known maps to see if + * it has already been loaded. If it is found + * then return a duplicate reference to it. + * Otherwise make a new map as required and + * add it to the list of maps + */ + ITER(m, mnt_map, &map_list_head) + if (STREQ(m->map_name, map)) + return mapc_dup(m); + + m = mapc_create(map, opt); + ins_que(&m->hdr, &map_list_head); + return m; +} + +/* + * Free a map. + */ +void mapc_free P((mnt_map *m)); +void mapc_free(m) +mnt_map *m; +{ + /* + * Decrement the reference count. + * If the reference count hits zero + * then throw the map away. + */ + if (m && --m->refc == 0) { + mapc_clear(m); + free((voidp) m->map_name); + rem_que(&m->hdr); + free((voidp) m); + } +} + +/* + * Search the map for the key. + * Put a safe copy in *pval or return + * an error code + */ +int mapc_meta_search P((mnt_map *m, char *key, char **pval, int recurse)); +int mapc_meta_search(m, key, pval, recurse) +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->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 HAS_REGEXP + 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) { + if (regexec((regexp *) k->key, key)) + break; + k = k->next; + } + if (k) + break; + } + } +#endif + + /* + * 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 + 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 P((mnt_map *m, char *key, char **pval)); +int mapc_search(m, key, pval) +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 P((mnt_map *m)); +static void mapc_sync(m) +mnt_map *m; +{ + if (m->alloc != MAPC_ROOT) { + 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(P_void); +void mapc_reload() +{ + mnt_map *m; + + /* + * For all the maps, + * Throw away the existing information. + * Do a reload + * Find the wildcard + */ + ITER(m, mnt_map, &map_list_head) + mapc_sync(m); +} + +/* + * Root map. + * The root map is used to bootstrap amd. + * All the require top-level mounts are added + * into the root map and then the map is iterated + * and a lookup is done on all the mount points. + * This causes the top level mounts to be automounted. + */ + +static int root_init P((char *map, time_t *tp)); +static int root_init(map, tp) +char *map; +time_t *tp; +{ + *tp = clocktime(); + return strcmp(map, ROOT_MAP) == 0 ? 0 : ENOENT; +} + +/* + * Add a new entry to the root map + * + * dir - directory (key) + * opts - mount options + * map - map name + */ +void root_newmap P((char *dir, char *opts, char *map)); +void root_newmap(dir, opts, map) +char *dir; +char *opts; +char *map; +{ + char str[MAXPATHLEN]; + + /* + * First make sure we have a root map to talk about... + */ + if (!root_map) + root_map = mapc_find(ROOT_MAP, "mapdefault"); + + /* + * Then add the entry... + */ + dir = strdup(dir); + if (map) + sprintf(str, "cache:=mapdefault;type:=toplvl;fs:=\"%s\";%s", + map, opts ? opts : ""); + else + strcpy(str, opts); + mapc_repl_kv(root_map, dir, strdup(str)); +} + +int mapc_keyiter P((mnt_map *m, void (*fn)(char*,voidp), voidp arg)); +int mapc_keyiter(m, fn, arg) +mnt_map *m; +void (*fn)P((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 of the the root map + * and call (*fn)() on the key + * of all the nodes. + * Finally throw away the root map. + */ +int root_keyiter P((void (*fn)(char*,voidp), voidp arg)); +int root_keyiter(fn, arg) +void (*fn)P((char*,voidp)); +voidp arg; +{ + if (root_map) { + int c = mapc_keyiter(root_map, fn, arg); +#ifdef notdef + mapc_free(root_map); + root_map = 0; +#endif + return c; + } + return 0; +} + +/* + * Error map + */ +static int error_init P((char *map, time_t *tp)); +static int error_init(map, tp) +char *map; +time_t *tp; +{ + plog(XLOG_USER, "No source data for map %s", map); + *tp = 0; + return 0; +} + +/*ARGSUSED*/ +static int error_search P((mnt_map *m, char *map, char *key, char **pval, time_t *tp)); +static int error_search(m, map, key, pval, tp) +mnt_map *m; +char *map; +char *key; +char **pval; +time_t *tp; +{ + return ENOENT; +} + +/*ARGSUSED*/ +static int error_reload P((mnt_map *m, char *map, add_fn *fn)); +static int error_reload(m, map, fn) +mnt_map *m; +char *map; +add_fn *fn; +{ + return ENOENT; +} + +static int error_mtime P((char *map, time_t *tp)); +static int error_mtime(map, tp) +char *map; +time_t *tp; +{ + *tp = 0; + return 0; +} diff --git a/usr.sbin/amd/amd/misc_rpc.c b/usr.sbin/amd/amd/misc_rpc.c new file mode 100644 index 000000000000..0fb10c8ad741 --- /dev/null +++ b/usr.sbin/amd/amd/misc_rpc.c @@ -0,0 +1,333 @@ +/* + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990, 1993 + * 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. + * + * @(#)misc_rpc.c 8.1 (Berkeley) 6/6/93 + * + * $Id: misc_rpc.c,v 5.2.2.1 1992/02/09 15:08:40 jsp beta $ + * + */ + +/* + * Additions to Sun RPC. + */ + +#include "am.h" + +void rpc_msg_init P((struct rpc_msg *mp, u_long prog, u_long vers, u_long proc)); +void rpc_msg_init(mp, prog, vers, proc) +struct rpc_msg *mp; +unsigned long prog, vers, proc; +{ + /* + * Initialise the message + */ + bzero((voidp) mp, sizeof(*mp)); + mp->rm_xid = 0; + mp->rm_direction = CALL; + mp->rm_call.cb_rpcvers = RPC_MSG_VERSION; + mp->rm_call.cb_prog = prog; + mp->rm_call.cb_vers = vers; + mp->rm_call.cb_proc = proc; +} + +/* + * Field reply to call to mountd + */ +int pickup_rpc_reply P((voidp pkt, int len, voidp where, xdrproc_t where_xdr)); +int pickup_rpc_reply(pkt, len, where, where_xdr) +voidp pkt; +int len; +voidp where; +xdrproc_t where_xdr; +{ + XDR reply_xdr; + int ok; + struct rpc_err err; + struct rpc_msg reply_msg; + int error = 0; + + /*bzero((voidp) &err, sizeof(err));*/ + bzero((voidp) &reply_msg, sizeof(reply_msg)); + + reply_msg.acpted_rply.ar_results.where = (caddr_t) where; + reply_msg.acpted_rply.ar_results.proc = where_xdr; + + xdrmem_create(&reply_xdr, pkt, len, XDR_DECODE); + + ok = xdr_replymsg(&reply_xdr, &reply_msg); + if (!ok) { + error = EIO; + goto drop; + } + _seterr_reply(&reply_msg, &err); + if (err.re_status != RPC_SUCCESS) { + error = EIO; + goto drop; + } + +drop: + if (reply_msg.rm_reply.rp_stat == MSG_ACCEPTED && + reply_msg.acpted_rply.ar_verf.oa_base) { + reply_xdr.x_op = XDR_FREE; + (void)xdr_opaque_auth(&reply_xdr, + &reply_msg.acpted_rply.ar_verf); + } + xdr_destroy(&reply_xdr); + + return error; +} + +int make_rpc_packet P((char *buf, int buflen, unsigned long proc, + struct rpc_msg *mp, voidp arg, xdrproc_t arg_xdr, AUTH *auth)); +int make_rpc_packet(buf, buflen, proc, mp, arg, arg_xdr, auth) +char *buf; +int buflen; +unsigned long proc; +struct rpc_msg *mp; +voidp arg; +xdrproc_t arg_xdr; +AUTH *auth; +{ + XDR msg_xdr; + int len; + + xdrmem_create(&msg_xdr, buf, buflen, XDR_ENCODE); + /* + * Basic protocol header + */ + if (!xdr_callhdr(&msg_xdr, mp)) + return -EIO; + /* + * Called procedure number + */ + if (!xdr_enum(&msg_xdr, &proc)) + return -EIO; + /* + * Authorization + */ + if (!AUTH_MARSHALL(auth, &msg_xdr)) + return -EIO; + /* + * Arguments + */ + if (!(*arg_xdr)(&msg_xdr, arg)) + return -EIO; + /* + * Determine length + */ + len = xdr_getpos(&msg_xdr); + /* + * Throw away xdr + */ + xdr_destroy(&msg_xdr); + return len; +} + + +/* + * Early RPC seems to be missing these.. + * Extracted from the RPC 3.9 sources as indicated + */ + +#ifdef NEED_XDR_POINTER +/* @(#)xdr_reference.c 1.1 87/11/04 3.9 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + + +/* + * xdr_pointer(): + * + * XDR a pointer to a possibly recursive data structure. This + * differs with xdr_reference in that it can serialize/deserialiaze + * trees correctly. + * + * What's sent is actually a union: + * + * union object_pointer switch (boolean b) { + * case TRUE: object_data data; + * case FALSE: void nothing; + * } + * + * > objpp: Pointer to the pointer to the object. + * > obj_size: size of the object. + * > xdr_obj: routine to XDR an object. + * + */ +bool_t +xdr_pointer(xdrs,objpp,obj_size,xdr_obj) + register XDR *xdrs; + char **objpp; + u_int obj_size; + xdrproc_t xdr_obj; +{ + + bool_t more_data; + + more_data = (*objpp != NULL); + if (! xdr_bool(xdrs,&more_data)) { + return (FALSE); + } + if (! more_data) { + *objpp = NULL; + return (TRUE); + } + return (xdr_reference(xdrs,objpp,obj_size,xdr_obj)); +} +#endif /* NEED_XDR_POINTER */ + +#ifdef NEED_CLNT_SPERRNO +/* @(#)clnt_perror.c 1.1 87/11/04 3.9 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +struct rpc_errtab { + enum clnt_stat status; + char *message; +}; + +static struct rpc_errtab rpc_errlist[] = { + { RPC_SUCCESS, + "RPC: Success" }, + { RPC_CANTENCODEARGS, + "RPC: Can't encode arguments" }, + { RPC_CANTDECODERES, + "RPC: Can't decode result" }, + { RPC_CANTSEND, + "RPC: Unable to send" }, + { RPC_CANTRECV, + "RPC: Unable to receive" }, + { RPC_TIMEDOUT, + "RPC: Timed out" }, + { RPC_VERSMISMATCH, + "RPC: Incompatible versions of RPC" }, + { RPC_AUTHERROR, + "RPC: Authentication error" }, + { RPC_PROGUNAVAIL, + "RPC: Program unavailable" }, + { RPC_PROGVERSMISMATCH, + "RPC: Program/version mismatch" }, + { RPC_PROCUNAVAIL, + "RPC: Procedure unavailable" }, + { RPC_CANTDECODEARGS, + "RPC: Server can't decode arguments" }, + { RPC_SYSTEMERROR, + "RPC: Remote system error" }, + { RPC_UNKNOWNHOST, + "RPC: Unknown host" }, +/* { RPC_UNKNOWNPROTO, + "RPC: Unknown protocol" },*/ + { RPC_PMAPFAILURE, + "RPC: Port mapper failure" }, + { RPC_PROGNOTREGISTERED, + "RPC: Program not registered"}, + { RPC_FAILED, + "RPC: Failed (unspecified error)"} +}; + + +/* + * This interface for use by clntrpc + */ +char * +clnt_sperrno(stat) + enum clnt_stat stat; +{ + int i; + + for (i = 0; i < sizeof(rpc_errlist)/sizeof(struct rpc_errtab); i++) { + if (rpc_errlist[i].status == stat) { + return (rpc_errlist[i].message); + } + } + return ("RPC: (unknown error code)"); +} + +#endif /* NEED_CLNT_SPERRNO */ + diff --git a/usr.sbin/amd/amd/mntfs.c b/usr.sbin/amd/amd/mntfs.c new file mode 100644 index 000000000000..ef8f17f2cbf1 --- /dev/null +++ b/usr.sbin/amd/amd/mntfs.c @@ -0,0 +1,367 @@ +/*- + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990, 1993 + * 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. + * + * $Id: mntfs.c,v 5.2.2.1 1992/02/09 15:08:42 jsp beta $ + */ + +#ifndef lint +static char sccsid[] = "@(#)mntfs.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + + +#include "am.h" + +extern qelem mfhead; +qelem mfhead = { &mfhead, &mfhead }; + +int mntfs_allocated; + +#ifdef notdef +/* + * This is the default attributes field which + * is copied into every new node to be created. + * The individual filesystem fs_init() routines + * patch the copy to represent the particular + * details for the relevant filesystem type + */ +static struct fattr gen_fattr = { + NFDIR, /* type */ + NFSMODE_DIR | 0555, /* mode */ + 2, /* nlink */ + 0, /* uid */ + 0, /* gid */ + 512, /* size */ + 4096, /* blocksize */ + 0, /* rdev */ + 1, /* blocks */ + 0, /* fsid */ + 0, /* fileid */ + { 0, 0 }, /* atime */ + { 0, 0 }, /* mtime */ + { 0, 0 }, /* ctime */ +}; +#endif /* notdef */ + +mntfs *dup_mntfs(mf) +mntfs *mf; +{ + if (mf->mf_refc == 0) { + if (mf->mf_cid) + untimeout(mf->mf_cid); + mf->mf_cid = 0; +#ifdef notdef + mf->mf_error = -1; + mf->mf_flags &= ~MFF_ERROR; +#endif + } + mf->mf_refc++; + return mf; +} + +static void init_mntfs P((mntfs *mf, am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts)); +static void init_mntfs(mf, ops, mo, mp, info, auto_opts, mopts, remopts) +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; +#ifdef notdef + mf->mf_attr.status = NFS_OK; + mf->mf_fattr = gen_fattr; + mf->mf_fattr.fsid = 42; + mf->mf_fattr.fileid = 0; + mf->mf_fattr.atime.seconds = clocktime(); + mf->mf_fattr.atime.useconds = 0; + mf->mf_fattr.mtime = mf->mf_fattr.ctime = mf->mf_fattr.atime; +#endif + + if (ops->ffserver) + mf->mf_server = (*ops->ffserver)(mf); + else + mf->mf_server = 0; +} + +static mntfs *alloc_mntfs P((am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts)); +static mntfs *alloc_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts) +am_ops *ops; +am_opts *mo; +char *mp; +char *info; +char *auto_opts; +char *mopts; +char *remopts; +{ + mntfs *mf = ALLOC(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 P((am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts)); +mntfs *find_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts) +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 == &efs_ops) { + /* + * If the existing ops are not efs_ops + * then continue... + */ + if (mf->mf_ops != &efs_ops) + continue; + } else /* ops != &efs_ops */ { + /* + * If the existing ops are efs_ops + * then continue... + */ + if (mf->mf_ops == &efs_ops) + continue; + } + + if ((mf->mf_flags & MFF_RESTART) && amd_state == Run) { + /* + * Restart a previously mounted filesystem. + */ + mntfs *mf2 = alloc_mntfs(&ifs_ops, mo, mp, info, 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 *) 0; + if (mf->mf_server) + free_srvr(mf->mf_server); + mf->mf_server = fs; + } + return dup_mntfs(mf); + } + } + + return alloc_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts); +} + +mntfs *new_mntfs() +{ + return alloc_mntfs(&efs_ops, (am_opts *) 0, "//nil//", ".", "", "", ""); +} + +static void uninit_mntfs(mf, rmd) +mntfs *mf; +int rmd; +{ + if (mf->mf_mount) free((voidp) mf->mf_mount); + if (mf->mf_auto) free((voidp) mf->mf_auto); + if (mf->mf_mopts) free((voidp) mf->mf_mopts); + if (mf->mf_remopts) free((voidp) mf->mf_remopts); + if (mf->mf_info) free((voidp) mf->mf_info); + if (mf->mf_private && mf->mf_prfree) + (*mf->mf_prfree)(mf->mf_private); + /* + * Clean up any directories that were made + */ + if (rmd && (mf->mf_flags & MFF_MKMNT)) + rmdirs(mf->mf_mount); + + /* + * Clean up the file server + */ + if (mf->mf_server) + free_srvr(mf->mf_server); + + /* + * Don't do a callback on this mount + */ + if (mf->mf_cid) { + untimeout(mf->mf_cid); + mf->mf_cid = 0; + } +} + +static void discard_mntfs(mf) +mntfs *mf; +{ + rem_que(&mf->mf_q); + /* + * Free memory + */ + uninit_mntfs(mf, TRUE); + free((voidp) mf); + + --mntfs_allocated; +} + +void flush_mntfs() +{ + mntfs *mf; + + mf = FIRST(mntfs, &mfhead); + while (mf != HEAD(mntfs, &mfhead)) { + mntfs *mf2 = mf; + mf = NEXT(mntfs, mf); + if (mf2->mf_refc == 0 && mf2->mf_cid) + discard_mntfs(mf2); + } +} + +void free_mntfs(mf) +mntfs *mf; +{ + if (--mf->mf_refc == 0) { + if (mf->mf_flags & MFF_MOUNTED) { + int quoted; + mf->mf_flags &= ~MFF_MOUNTED; + + /* + * Record for posterity + */ + quoted = strchr(mf->mf_info, ' ') != 0; /* cheap */ + plog(XLOG_INFO, "%s%s%s %sed fstype %s from %s", + quoted ? "\"" : "", + mf->mf_info, + quoted ? "\"" : "", + mf->mf_error ? "discard" : "unmount", + mf->mf_ops->fs_type, mf->mf_mount); + } + + if (mf->mf_ops->fs_flags & FS_DISCARD) { +#ifdef DEBUG + dlog("Immediately discarding mntfs for %s", mf->mf_mount); +#endif /* DEBUG */ + discard_mntfs(mf); + } else { +#ifdef DEBUG + if (mf->mf_flags & MFF_RESTART) { + dlog("Discarding remount hook for %s", mf->mf_mount); + } else { + dlog("Discarding last mntfs reference to %s fstype %s", + mf->mf_mount, mf->mf_ops->fs_type); + } + if (mf->mf_flags & (MFF_MOUNTED|MFF_MOUNTING|MFF_UNMOUNTING)) + dlog("mntfs reference for %s still active", mf->mf_mount); +#endif /* DEBUG */ + mf->mf_cid = timeout(ALLOWED_MOUNT_TIME, discard_mntfs, (voidp) mf); + } + } +} + +mntfs *realloc_mntfs P((mntfs *mf, am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts)); +mntfs *realloc_mntfs(mf, ops, mo, mp, info, auto_opts, mopts, remopts) +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 == &ifs_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 != &efs_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/usr.sbin/amd/amd/mount_fs.c b/usr.sbin/amd/amd/mount_fs.c new file mode 100644 index 000000000000..43a06251ddc4 --- /dev/null +++ b/usr.sbin/amd/amd/mount_fs.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990, 1993 + * 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. + * + * @(#)mount_fs.c 8.1 (Berkeley) 6/6/93 + * + * $Id: mount_fs.c,v 5.2.2.2 1992/05/31 16:35:45 jsp Exp $ + * + */ + +#include "am.h" +#ifdef NFS_3 +typedef nfs_fh fhandle_t; +#endif /* NFS_3 */ +#include <sys/mount.h> + +#include <sys/stat.h> + +/* + * Standard mount flags + */ +#ifdef hpux +/* + * HP-UX has an annoying feature of printing + * error msgs on /dev/console + */ +#undef M_NOSUID +#endif /* hpux */ + +struct opt_tab mnt_flags[] = { + { "ro", M_RDONLY }, +#ifdef M_CACHE + { "nocache", M_NOCACHE }, +#endif /* M_CACHE */ +#ifdef M_GRPID + { "grpid", M_GRPID }, +#endif /* M_GRPID */ +#ifdef M_MULTI + { "multi", M_MULTI }, +#endif /* M_MULTI */ +#ifdef M_NODEV + { "nodev", M_NODEV }, +#endif /* M_NODEV */ +#ifdef M_NOEXEC + { "noexec", M_NOEXEC }, +#endif /* M_NOEXEC */ +#ifdef M_NOSUB + { "nosub", M_NOSUB }, +#endif /* M_NOSUB */ +#ifdef M_NOSUID + { "nosuid", M_NOSUID }, +#endif /* M_NOSUID */ +#ifdef M_SYNC + { "sync", M_SYNC }, +#endif /* M_SYNC */ + { 0, 0 } +}; + +int compute_mount_flags(mnt) +struct mntent *mnt; +{ + struct opt_tab *opt; + int flags; +#ifdef NFS_4 + flags = M_NEWTYPE; +#else + flags = 0; +#endif /* NFS_4 */ + + /* + * Crack basic mount options + */ + for (opt = mnt_flags; opt->opt; opt++) + flags |= hasmntopt(mnt, opt->opt) ? opt->flag : 0; + + return flags; +} + +int mount_fs P((struct mntent *mnt, int flags, caddr_t mnt_data, int retry, MTYPE_TYPE type)); +int mount_fs(mnt, flags, mnt_data, retry, type) +struct mntent *mnt; +int flags; +caddr_t mnt_data; +int retry; +MTYPE_TYPE type; +{ + int error = 0; +#ifdef MNTINFO_DEV + struct stat stb; + char *xopts = 0; +#endif /* MNTINFO_DEV */ + +#ifdef DEBUG +#ifdef NFS_4 + dlog("%s fstype %s (%s) flags %#x (%s)", + mnt->mnt_dir, type, mnt->mnt_type, flags, mnt->mnt_opts); +#else + dlog("%s fstype %d (%s) flags %#x (%s)", + mnt->mnt_dir, type, mnt->mnt_type, flags, mnt->mnt_opts); +#endif /* NFS_4 */ +#endif /* DEBUG */ + + /* + * Fake some mount table entries for the automounter + */ +#ifdef FASCIST_DF_COMMAND + /* + * Some systems have a df command which blows up when + * presented with an unknown mount type. + */ + if (STREQ(mnt->mnt_type, MNTTYPE_AUTO)) { + /* + * Try it with the normal name + */ + mnt->mnt_type = FASCIST_DF_COMMAND; + } +#endif /* FASCIST_DF_COMMAND */ + +again: + clock_valid = 0; + error = MOUNT_TRAP(type, mnt, flags, mnt_data); + if (error < 0) + plog(XLOG_ERROR, "%s: mount: %m", mnt->mnt_dir); + if (error < 0 && --retry > 0) { + sleep(1); + goto again; + } + if (error < 0) { +#ifdef notdef + if (automount) + going_down(errno); +#endif + return errno; + } + +#ifdef UPDATE_MTAB +#ifdef MNTINFO_DEV + /* + * Add the extra dev= field to the mount table. + */ + if (lstat(mnt->mnt_dir, &stb) == 0) { + char *zopts = (char *) xmalloc(strlen(mnt->mnt_opts) + 32); + xopts = mnt->mnt_opts; + if (sizeof(stb.st_dev) == 2) { + /* e.g. SunOS 4.1 */ + sprintf(zopts, "%s,%s=%s%04lx", xopts, MNTINFO_DEV, + MNTINFO_PREF, (u_long) stb.st_dev & 0xffff); + } else { + /* e.g. System Vr4 */ + sprintf(zopts, "%s,%s=%s%08lx", xopts, MNTINFO_DEV, + MNTINFO_PREF, (u_long) stb.st_dev); + } + mnt->mnt_opts = zopts; + } +#endif /* MNTINFO_DEV */ + +#ifdef FIXUP_MNTENT + /* + * Additional fields in struct mntent + * are fixed up here + */ + FIXUP_MNTENT(mnt); +#endif + + write_mntent(mnt); +#ifdef MNTINFO_DEV + if (xopts) { + free(mnt->mnt_opts); + mnt->mnt_opts = xopts; + } +#endif /* MNTINFO_DEV */ +#endif /* UPDATE_MTAB */ + + return 0; +} + +#ifdef NEED_MNTOPT_PARSER +/* + * Some systems don't provide these to the user, + * but amd needs them, so... + * + * From: Piete Brooks <pb@cl.cam.ac.uk> + */ + +#include <ctype.h> + +static char *nextmntopt(p) +char **p; +{ + char *cp = *p; + char *rp; + /* + * Skip past white space + */ + while (*cp && isspace(*cp)) + cp++; + /* + * Word starts here + */ + rp = cp; + /* + * Scan to send of string or separator + */ + while (*cp && *cp != ',') + cp++; + /* + * If separator found the overwrite with nul char. + */ + if (*cp) { + *cp = '\0'; + cp++; + } + /* + * Return value for next call + */ + *p = cp; + return rp; +} + +char *hasmntopt(mnt, opt) +struct mntent *mnt; +char *opt; +{ + char t[MNTMAXSTR]; + char *f; + char *o = t; + int l = strlen(opt); + strcpy(t, mnt->mnt_opts); + + while (*(f = nextmntopt(&o))) + if (strncmp(opt, f, l) == 0) + return f - t + mnt->mnt_opts; + + return 0; +} +#endif /* NEED_MNTOPT_PARSER */ + +#ifdef MOUNT_HELPER_SOURCE +#include MOUNT_HELPER_SOURCE +#endif /* MOUNT_HELPER_SOURCE */ diff --git a/usr.sbin/amd/amd/mtab.c b/usr.sbin/amd/amd/mtab.c new file mode 100644 index 000000000000..43b3a26e9a7f --- /dev/null +++ b/usr.sbin/amd/amd/mtab.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989, 1993 + * 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. + * + * @(#)mtab.c 8.1 (Berkeley) 6/6/93 + * + * $Id: mtab.c,v 5.2.2.1 1992/02/09 15:08:45 jsp beta $ + * + */ + +#include "am.h" + +/* + * Firewall /etc/mtab entries + */ +void mnt_free P((struct mntent *mp)); +void mnt_free(mp) +struct mntent *mp; +{ + free(mp->mnt_fsname); + free(mp->mnt_dir); + free(mp->mnt_type); + free(mp->mnt_opts); + free((voidp) mp); +} + +/* + * Discard memory allocated for mount list + */ +void discard_mntlist P((mntlist *mp)); +void discard_mntlist(mp) +mntlist *mp; +{ + mntlist *mp2; + + while (mp2 = mp) { + mp = mp->mnext; + if (mp2->mnt) + mnt_free(mp2->mnt); + free((voidp) mp2); + } +} + +/* + * Throw away a mount list + */ +void free_mntlist P((mntlist *mp)); +void free_mntlist(mp) +mntlist *mp; +{ + discard_mntlist(mp); + unlock_mntlist(); +} + +/* + * Utility routine which determines the value of a + * numeric option in the mount options (such as port=%d). + * Returns 0 if the option is not specified. + */ +int hasmntval P((struct mntent *mnt, char *opt)); +int hasmntval(mnt, opt) +struct mntent *mnt; +char *opt; +{ + char *str = hasmntopt(mnt, opt); + if (str) { + char *eq = strchr(str, '='); + if (eq) + return atoi(eq+1); + else + plog(XLOG_USER, "bad numeric option \"%s\" in \"%s\"", opt, str); + } + + return 0; +} diff --git a/usr.sbin/amd/amd/nfs_ops.c b/usr.sbin/amd/amd/nfs_ops.c new file mode 100644 index 000000000000..bcfd7a598fe1 --- /dev/null +++ b/usr.sbin/amd/amd/nfs_ops.c @@ -0,0 +1,809 @@ +/*- + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990, 1993 + * 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. + * + * $Id: nfs_ops.c,v 5.2.2.2 1992/05/31 16:35:05 jsp Exp $ + */ + +#ifndef lint +static char sccsid[] = "@(#)nfs_ops.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "am.h" +#include <sys/stat.h> + +#ifdef HAS_NFS + +#define NFS +#define NFSCLIENT +#ifdef NFS_3 +typedef nfs_fh fhandle_t; +#endif /* NFS_3 */ +#ifdef NFS_HDR +#include NFS_HDR +#endif /* NFS_HDR */ +#include <sys/mount.h> +#include "mount.h" + +/* + * Network file system + */ + +/* + * Convert from nfsstat to UN*X error code + */ +#define unx_error(e) ((int)(e)) + +/* + * The NFS layer maintains a cache of file handles. + * This is *fundamental* to the implementation and + * also allows quick remounting when a filesystem + * is accessed soon after timing out. + * + * The NFS server layer knows to flush this cache + * when a server goes down so avoiding stale handles. + * + * Each cache entry keeps a hard reference to + * the corresponding server. This ensures that + * the server keepalive information is maintained. + * + * The copy of the sockaddr_in here is taken so + * that the port can be twiddled to talk to mountd + * instead of portmap or the NFS server as used + * elsewhere. + * The port# is flushed if a server goes down. + * The IP address is never flushed - we assume + * that the address of a mounted machine never + * changes. If it does, then you have other + * problems... + */ +typedef struct fh_cache fh_cache; +struct fh_cache { + qelem fh_q; /* List header */ + voidp fh_wchan; /* Wait channel */ + int fh_error; /* Valid data? */ + int fh_id; /* Unique id */ + int fh_cid; /* Callout id */ + struct fhstatus fh_handle; /* Handle on filesystem */ + struct sockaddr_in fh_sin; /* Address of mountd */ + fserver *fh_fs; /* Server holding filesystem */ + char *fh_path; /* Filesystem on host */ +}; + +/* + * FH_TTL is the time a file handle will remain in the cache since + * last being used. If the file handle becomes invalid, then it + * will be flushed anyway. + */ +#define FH_TTL (5 * 60) /* five minutes */ +#define FH_TTL_ERROR (30) /* 30 seconds */ + +static int fh_id = 0; +#define FHID_ALLOC() (++fh_id) +extern qelem fh_head; +qelem fh_head = { &fh_head, &fh_head }; + +static int call_mountd P((fh_cache*, unsigned long, fwd_fun, voidp)); + +AUTH *nfs_auth; + +static fh_cache *find_nfs_fhandle_cache P((voidp idv, int done)); +static fh_cache *find_nfs_fhandle_cache(idv, done) +voidp idv; +int done; +{ + fh_cache *fp, *fp2 = 0; + int id = (int) idv; + + ITER(fp, fh_cache, &fh_head) { + if (fp->fh_id == id) { + fp2 = fp; + break; + } + } + +#ifdef DEBUG + if (fp2) { + dlog("fh cache gives fp %#x, fs %s", fp2, fp2->fh_path); + } else { + dlog("fh cache search failed"); + } +#endif /* DEBUG */ + + if (fp2 && !done) { + fp2->fh_error = ETIMEDOUT; + return 0; + } + + return fp2; +} + +/* + * Called when a filehandle appears + */ +static void got_nfs_fh P((voidp pkt, int len, struct sockaddr_in *sa, + struct sockaddr_in *ia, voidp idv, int done)); +static void got_nfs_fh(pkt, len, sa, ia, idv, done) +voidp pkt; +int len; +struct sockaddr_in *sa, *ia; +voidp idv; +int done; +{ + fh_cache *fp = find_nfs_fhandle_cache(idv, done); + if (fp) { + fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &fp->fh_handle, xdr_fhstatus); + if (!fp->fh_error) { +#ifdef DEBUG + dlog("got filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path); +#endif /* DEBUG */ + /* + * Wakeup anything sleeping on this filehandle + */ + if (fp->fh_wchan) { +#ifdef DEBUG + dlog("Calling wakeup on %#x", fp->fh_wchan); +#endif /* DEBUG */ + wakeup(fp->fh_wchan); + } + } + } +} + +void flush_nfs_fhandle_cache P((fserver *fs)); +void flush_nfs_fhandle_cache(fs) +fserver *fs; +{ + fh_cache *fp; + ITER(fp, fh_cache, &fh_head) { + if (fp->fh_fs == fs || fs == 0) { + fp->fh_sin.sin_port = (u_short) 0; + fp->fh_error = -1; + } + } +} + +static void discard_fh P((fh_cache *fp)); +static void discard_fh(fp) +fh_cache *fp; +{ + rem_que(&fp->fh_q); +#ifdef DEBUG + dlog("Discarding filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path); +#endif /* DEBUG */ + free_srvr(fp->fh_fs); + free((voidp) fp->fh_path); + free((voidp) fp); +} + +/* + * Determine the file handle for a node + */ +static int prime_nfs_fhandle_cache P((char *path, fserver *fs, struct fhstatus *fhbuf, voidp wchan)); +static int prime_nfs_fhandle_cache(path, fs, fhbuf, wchan) +char *path; +fserver *fs; +struct fhstatus *fhbuf; +voidp wchan; +{ + fh_cache *fp, *fp_save = 0; + int error; + int reuse_id = FALSE; + +#ifdef DEBUG + dlog("Searching cache for %s:%s", fs->fs_host, path); +#endif /* DEBUG */ + + /* + * First search the cache + */ + ITER(fp, fh_cache, &fh_head) { + if (fs == fp->fh_fs && strcmp(path, fp->fh_path) == 0) { + switch (fp->fh_error) { + case 0: + error = fp->fh_error = unx_error(fp->fh_handle.fhs_status); + if (error == 0) { + if (fhbuf) + bcopy((voidp) &fp->fh_handle, (voidp) fhbuf, + sizeof(fp->fh_handle)); + if (fp->fh_cid) + untimeout(fp->fh_cid); + fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp); + } else if (error == EACCES) { + /* + * Now decode the file handle return code. + */ + plog(XLOG_INFO, "Filehandle denied for \"%s:%s\"", + fs->fs_host, path); + } else { + errno = error; /* XXX */ + plog(XLOG_INFO, "Filehandle error for \"%s:%s\": %m", + fs->fs_host, path); + } + + /* + * The error was returned from the remote mount daemon. + * Policy: this error will be cached for now... + */ + return error; + + case -1: + /* + * Still thinking about it, but we can re-use. + */ + fp_save = fp; + reuse_id = TRUE; + break; + + default: + /* + * Return the error. + * Policy: make sure we recompute if required again + * in case this was caused by a network failure. + * This can thrash mountd's though... If you find + * your mountd going slowly then: + * 1. Add a fork() loop to main. + * 2. Remove the call to innetgr() and don't use + * netgroups, especially if you don't use YP. + */ + error = fp->fh_error; + fp->fh_error = -1; + return error; + } + break; + } + } + + /* + * Not in cache + */ + if (fp_save) { + fp = fp_save; + /* + * Re-use existing slot + */ + untimeout(fp->fh_cid); + free_srvr(fp->fh_fs); + free(fp->fh_path); + } else { + fp = ALLOC(fh_cache); + bzero((voidp) fp, sizeof(*fp)); + ins_que(&fp->fh_q, &fh_head); + } + if (!reuse_id) + fp->fh_id = FHID_ALLOC(); + fp->fh_wchan = wchan; + fp->fh_error = -1; + fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp); + + /* + * If the address has changed then don't try to re-use the + * port information + */ + if (fp->fh_sin.sin_addr.s_addr != fs->fs_ip->sin_addr.s_addr) { + fp->fh_sin = *fs->fs_ip; + fp->fh_sin.sin_port = 0; + } + fp->fh_fs = dup_srvr(fs); + fp->fh_path = strdup(path); + + error = call_mountd(fp, MOUNTPROC_MNT, got_nfs_fh, wchan); + if (error) { + /* + * Local error - cache for a short period + * just to prevent thrashing. + */ + untimeout(fp->fh_cid); + fp->fh_cid = timeout(error < 0 ? 2 * ALLOWED_MOUNT_TIME : FH_TTL_ERROR, + discard_fh, (voidp) fp); + fp->fh_error = error; + } else { + error = fp->fh_error; + } + return error; +} + +int make_nfs_auth P((void)) +{ +#ifdef HAS_NFS_QUALIFIED_NAMES + /* + * From: Chris Metcalf <metcalf@masala.lcs.mit.edu> + * Use hostd, not just hostname. Note that uids + * and gids and the gidlist are type *int* and not the + * system uid_t and gid_t types. + */ + static int group_wheel = 0; + nfs_auth = authunix_create(hostd, 0, 0, 1, &group_wheel); +#else + nfs_auth = authunix_create_default(); +#endif + if (!nfs_auth) + return ENOBUFS; + return 0; +} + +static int call_mountd P((fh_cache *fp, u_long proc, fwd_fun f, voidp wchan)); +static int call_mountd(fp, proc, f, wchan) +fh_cache *fp; +u_long proc; +fwd_fun f; +voidp wchan; +{ + struct rpc_msg mnt_msg; + int len; + char iobuf[8192]; + int error; + + if (!nfs_auth) { + 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; + } + + rpc_msg_init(&mnt_msg, MOUNTPROG, MOUNTVERS, (unsigned long) 0); + len = make_rpc_packet(iobuf, sizeof(iobuf), proc, + &mnt_msg, (voidp) &fp->fh_path, xdr_nfspath, nfs_auth); + + if (len > 0) { + error = fwd_packet(MK_RPC_XID(RPC_XID_MOUNTD, fp->fh_id), + (voidp) iobuf, len, &fp->fh_sin, &fp->fh_sin, (voidp) fp->fh_id, f); + } else { + error = -len; + } +/* + * 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. + */ +static char *nfs_match(fo) +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 FALSE; + } + if (!fo->opt_rhost) { + plog(XLOG_USER, "nfs: no remote host specified"); + return FALSE; + } + /* + * 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; +} + +/* + * Initialise am structure for nfs + */ +static int nfs_init(mf) +mntfs *mf; +{ + if (!mf->mf_private) { + int error; + struct fhstatus fhs; + + char *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(fhstatus); + mf->mf_prfree = (void (*)()) free; + bcopy((voidp) &fhs, mf->mf_private, sizeof(fhs)); + } + return error; + } + + return 0; +} + +int mount_nfs_fh P((struct fhstatus *fhp, char *dir, char *fs_name, char *opts, mntfs *mf)); +int mount_nfs_fh(fhp, dir, fs_name, opts, mf) +struct fhstatus *fhp; +char *dir; +char *fs_name; +char *opts; +mntfs *mf; +{ + struct nfs_args nfs_args; + struct mntent mnt; + int retry; + char *colon; + /*char *path;*/ + char host[MAXHOSTNAMELEN + MAXPATHLEN + 2]; + fserver *fs = mf->mf_server; + int flags; + char *xopts; + int error; +#ifdef notdef + unsigned short port; +#endif /* notdef */ + + MTYPE_TYPE type = MOUNT_TYPE_NFS; + + bzero((voidp) &nfs_args, sizeof(nfs_args)); /* Paranoid */ + + /* + * Extract host name to give to kernel + */ + if (!(colon = strchr(fs_name, ':'))) + return ENOENT; +#ifndef NFS_ARGS_NEEDS_PATH + *colon = '\0'; +#endif + strncpy(host, fs_name, sizeof(host)); +#ifndef NFS_ARGS_NEEDS_PATH + *colon = ':'; +#endif /* NFS_ARGS_NEEDS_PATH */ + /*path = colon + 1;*/ + + if (mf->mf_remopts && *mf->mf_remopts && !islocalnet(fs->fs_ip->sin_addr.s_addr)) + xopts = strdup(mf->mf_remopts); + else + xopts = strdup(opts); + + bzero((voidp) &nfs_args, sizeof(nfs_args)); + + mnt.mnt_dir = dir; + mnt.mnt_fsname = fs_name; + mnt.mnt_type = MTAB_TYPE_NFS; + mnt.mnt_opts = xopts; + mnt.mnt_freq = 0; + mnt.mnt_passno = 0; + + retry = hasmntval(&mnt, "retry"); + if (retry <= 0) + retry = 1; /* XXX */ + +/*again:*/ + + /* + * set mount args + */ + NFS_FH_DREF(nfs_args.fh, (NFS_FH_TYPE) fhp->fhstatus_u.fhs_fhandle); + +#ifdef ULTRIX_HACK + nfs_args.optstr = mnt.mnt_opts; +#endif /* ULTRIX_HACK */ + + nfs_args.hostname = host; + nfs_args.flags |= NFSMNT_HOSTNAME; +#ifdef HOSTNAMESZ + /* + * Most kernels have a name length restriction. + */ + if (strlen(host) >= HOSTNAMESZ) + strcpy(host + HOSTNAMESZ - 3, ".."); +#endif /* HOSTNAMESZ */ + + if (nfs_args.rsize = hasmntval(&mnt, "rsize")) + nfs_args.flags |= NFSMNT_RSIZE; + + if (nfs_args.wsize = hasmntval(&mnt, "wsize")) + nfs_args.flags |= NFSMNT_WSIZE; + + if (nfs_args.timeo = hasmntval(&mnt, "timeo")) + nfs_args.flags |= NFSMNT_TIMEO; + + if (nfs_args.retrans = hasmntval(&mnt, "retrans")) + nfs_args.flags |= NFSMNT_RETRANS; + +#ifdef NFSMNT_BIODS + if (nfs_args.biods = hasmntval(&mnt, "biods")) + nfs_args.flags |= NFSMNT_BIODS; + +#endif /* NFSMNT_BIODS */ + +#ifdef NFSMNT_MAXGRPS + if (nfs_args.maxgrouplist = hasmntval(&mnt, "maxgroups")) + nfs_args.flags |= NFSMNT_MAXGRPS; +#endif /* NFSMNT_MAXGRPS */ + +#ifdef notdef +/* + * This isn't supported by the ping algorithm yet. + * In any case, it is all done in nfs_init(). + */ + if (port = hasmntval(&mnt, "port")) + sin.sin_port = htons(port); + else + sin.sin_port = htons(NFS_PORT); /* XXX should use portmapper */ +#endif /* notdef */ + + if (hasmntopt(&mnt, MNTOPT_SOFT) != NULL) + nfs_args.flags |= NFSMNT_SOFT; + +#ifdef NFSMNT_SPONGY + if (hasmntopt(&mnt, "spongy") != NULL) { + nfs_args.flags |= NFSMNT_SPONGY; + if (nfs_args.flags & NFSMNT_SOFT) { + plog(XLOG_USER, "Mount opts soft and spongy are incompatible - soft ignored"); + nfs_args.flags &= ~NFSMNT_SOFT; + } + } +#endif /* MNTOPT_SPONGY */ + +#ifdef MNTOPT_INTR + if (hasmntopt(&mnt, MNTOPT_INTR) != NULL) + nfs_args.flags |= NFSMNT_INT; +#endif /* MNTOPT_INTR */ + +#ifdef MNTOPT_NODEVS + if (hasmntopt(&mnt, MNTOPT_NODEVS) != NULL) + nfs_args.flags |= NFSMNT_NODEVS; +#endif /* MNTOPT_NODEVS */ + +#ifdef MNTOPT_COMPRESS + if (hasmntopt(&mnt, "compress") != NULL) + nfs_args.flags |= NFSMNT_COMPRESS; +#endif /* MNTOPT_COMPRESS */ + +#ifdef MNTOPT_NOCONN + if (hasmntopt(&mnt, "noconn") != NULL) + nfs_args.flags |= NFSMNT_NOCONN; +#endif /* MNTOPT_NOCONN */ + +#ifdef NFSMNT_PGTHRESH + if (nfs_args.pg_thresh = hasmntval(&mnt, "pgthresh")) + nfs_args.flags |= NFSMNT_PGTHRESH; +#endif /* NFSMNT_PGTHRESH */ + + NFS_SA_DREF(nfs_args, fs->fs_ip); + + flags = compute_mount_flags(&mnt); + +#ifdef NFSMNT_NOCTO + if (hasmntopt(&mnt, "nocto") != NULL) + nfs_args.flags |= NFSMNT_NOCTO; +#endif /* NFSMNT_NOCTO */ + +#ifdef HAS_TCP_NFS + if (hasmntopt(&mnt, "tcp") != NULL) + nfs_args.sotype = SOCK_STREAM; +#endif /* HAS_TCP_NFS */ + + +#ifdef ULTRIX_HACK + /* + * Ultrix passes the flags argument as part of the + * mount data structure, rather than using the + * flags argument to the system call. This is + * confusing... + */ + if (!(nfs_args.flags & NFSMNT_PGTHRESH)) { + nfs_args.pg_thresh = 64; /* 64k - XXX */ + nfs_args.flags |= NFSMNT_PGTHRESH; + } + nfs_args.gfs_flags = flags; + flags &= M_RDONLY; + if (flags & M_RDONLY) + nfs_args.flags |= NFSMNT_RONLY; +#endif /* ULTRIX_HACK */ + + error = mount_fs(&mnt, flags, (caddr_t) &nfs_args, retry, type); + free(xopts); + return error; +} + +static int mount_nfs(dir, fs_name, opts, mf) +char *dir; +char *fs_name; +char *opts; +mntfs *mf; +{ +#ifdef notdef + int error; + struct fhstatus fhs; + char *colon; + + if (!(colon = strchr(fs_name, ':'))) + return ENOENT; + +#ifdef DEBUG + dlog("locating fhandle for %s", fs_name); +#endif /* DEBUG */ + error = prime_nfs_fhandle_cache(colon+1, mf->mf_server, &fhs, (voidp) 0); + + if (error) + return error; + + return mount_nfs_fh(&fhs, dir, fs_name, opts, mf); +#endif + if (!mf->mf_private) { + plog(XLOG_ERROR, "Missing filehandle for %s", fs_name); + return EINVAL; + } + + return mount_nfs_fh((struct fhstatus *) mf->mf_private, dir, fs_name, opts, mf); +} + +static int nfs_fmount(mf) +mntfs *mf; +{ + int error; + + 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; +} + +static int nfs_fumount(mf) +mntfs *mf; +{ + int error = UMOUNT_FS(mf->mf_mount); + if (error) + return error; + + return 0; +} + +static void nfs_umounted(mp) +am_node *mp; +{ +#ifdef INFORM_MOUNTD + /* + * Don't bother to inform remote mountd + * that we are finished. Until a full + * track of filehandles is maintained + * the mountd unmount callback cannot + * be done correctly anyway... + */ + + mntfs *mf = mp->am_mnt; + fserver *fs; + char *colon, *path; + + if (mf->mf_error || mf->mf_refc > 1) + return; + + fs = mf->mf_server; + + /* + * Call the mount daemon on the server to + * announce that we are not using the fs any more. + * + * This is *wrong*. The mountd should be called + * when the fhandle is flushed from the cache, and + * a reference held to the cached entry while the + * fs is mounted... + */ + colon = path = strchr(mf->mf_info, ':'); + if (fs && colon) { + fh_cache f; +#ifdef DEBUG + dlog("calling mountd for %s", mf->mf_info); +#endif /* DEBUG */ + *path++ = '\0'; + f.fh_path = path; + f.fh_sin = *fs->fs_ip; + f.fh_sin.sin_port = (u_short) 0; + f.fh_fs = fs; + f.fh_id = 0; + f.fh_error = 0; + (void) prime_nfs_fhandle_cache(colon+1, mf->mf_server, (struct fhstatus *) 0, (voidp) mf); + (void) call_mountd(&f, MOUNTPROC_UMNT, (fwd_fun) 0, (voidp) 0); + *colon = ':'; + } +#endif /* INFORM_MOUNTD */ + +#ifdef KICK_KERNEL + /* This should go into the mainline code, not in nfs_ops... */ + + /* + * Run lstat over the underlying directory in + * case this was a direct mount. This will + * get the kernel back in sync with reality. + */ + if (mp->am_parent && mp->am_parent->am_path && + STREQ(mp->am_parent->am_mnt->mf_ops->fs_type, "direct")) { + struct stat stb; + int pid; + if ((pid = background()) == 0) { + if (lstat(mp->am_parent->am_path, &stb) < 0) { + plog(XLOG_ERROR, "lstat(%s) after unmount: %m", mp->am_parent->am_path); +#ifdef DEBUG + } else { + dlog("hack lstat(%s): ok", mp->am_parent->am_path); +#endif /* DEBUG */ + } + _exit(0); + } + } +#endif /* KICK_KERNEL */ +} + +/* + * Network file system + */ +am_ops nfs_ops = { + "nfs", + nfs_match, + nfs_init, + auto_fmount, + nfs_fmount, + auto_fumount, + nfs_fumount, + efs_lookuppn, + efs_readdir, + 0, /* nfs_readlink */ + 0, /* nfs_mounted */ + nfs_umounted, + find_nfs_srvr, + FS_MKMNT|FS_BACKGROUND|FS_AMQINFO +}; + +#endif /* HAS_NFS */ diff --git a/usr.sbin/amd/amd/nfs_start.c b/usr.sbin/amd/amd/nfs_start.c new file mode 100644 index 000000000000..13d36a14ee8b --- /dev/null +++ b/usr.sbin/amd/amd/nfs_start.c @@ -0,0 +1,435 @@ +/* + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990, 1993 + * 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. + * + * @(#)nfs_start.c 8.1 (Berkeley) 6/6/93 + * + * $Id: nfs_start.c,v 5.2.2.1 1992/02/09 15:08:51 jsp beta $ + * + */ + +#include "am.h" +#include "amq.h" +#include <sys/signal.h> +#include <setjmp.h> +extern jmp_buf select_intr; +extern int select_intr_valid; + +#ifdef HAS_TFS +/* + * Use replacement for RPC/UDP transport + * so that we do NFS gatewaying. + */ +#define svcudp_create svcudp2_create +extern SVCXPRT *svcudp2_create P((int)); +#endif /* HAS_TFS */ + +extern void nfs_program_2(); +extern void amq_program_1(); + +unsigned short nfs_port; +SVCXPRT *nfsxprt; + +extern int fwd_sock; +int max_fds = -1; + +#define MASKED_SIGS (sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGCHLD)|sigmask(SIGHUP)) + +#ifdef DEBUG +/* + * Check that we are not burning resources + */ +static void checkup(P_void) +{ + +static int max_fd = 0; +static char *max_mem = 0; + + int next_fd = dup(0); + extern caddr_t sbrk P((int)); + caddr_t next_mem = sbrk(0); + close(next_fd); + + /*if (max_fd < 0) { + max_fd = next_fd; + } else*/ if (max_fd < next_fd) { + dlog("%d new fds allocated; total is %d", + next_fd - max_fd, next_fd); + max_fd = next_fd; + } + + /*if (max_mem == 0) { + max_mem = next_mem; + } else*/ if (max_mem < next_mem) { + dlog("%#x bytes of memory allocated; total is %#x (%d pages)", + next_mem - max_mem, + next_mem, + ((int)next_mem+getpagesize()-1)/getpagesize()); + max_mem = next_mem; + } +} +#endif /* DEBUG */ + +static int do_select(smask, fds, fdp, tvp) +int smask; +int fds; +int *fdp; +struct timeval *tvp; +{ + int sig; + int nsel; + if (sig = setjmp(select_intr)) { + select_intr_valid = 0; + /* Got a signal */ + switch (sig) { + case SIGINT: + case SIGTERM: + amd_state = Finishing; + reschedule_timeout_mp(); + break; + } + nsel = -1; + errno = EINTR; + } else { + select_intr_valid = 1; + /* + * Invalidate the current clock value + */ + clock_valid = 0; + /* + * Allow interrupts. If a signal + * occurs, then it will cause a longjmp + * up above. + */ + (void) sigsetmask(smask); + /* + * Wait for input + */ + nsel = select(fds, fdp, (int *) 0, (int *) 0, + tvp->tv_sec ? tvp : (struct timeval *) 0); + + } + + (void) sigblock(MASKED_SIGS); + + /* + * Perhaps reload the cache? + */ + if (do_mapc_reload < clocktime()) { + mapc_reload(); + do_mapc_reload = clocktime() + ONE_HOUR; + } + return nsel; +} + +/* + * Determine whether anything is left in + * the RPC input queue. + */ +static int rpc_pending_now() +{ + struct timeval tvv; + int nsel; +#ifdef FD_SET + fd_set readfds; + + FD_ZERO(&readfds); + FD_SET(fwd_sock, &readfds); +#else + int readfds = (1 << fwd_sock); +#endif /* FD_SET */ + + tvv.tv_sec = tvv.tv_usec = 0; + nsel = select(max_fds+1, &readfds, (int *) 0, (int *) 0, &tvv); + if (nsel < 1) + return(0); +#ifdef FD_SET + if (FD_ISSET(fwd_sock, &readfds)) + return(1); +#else + if (readfds & (1 << fwd_sock)) + return(1); +#endif + return(0); +} + +static serv_state run_rpc(P_void) +{ + int dtbsz = max_fds + 1; + int smask = sigblock(MASKED_SIGS); + + next_softclock = clocktime(); + + amd_state = Run; + + /* + * Keep on trucking while we are in Run mode. This state + * is switched to Quit after all the file systems have + * been unmounted. + */ + while ((int)amd_state <= (int)Finishing) { + struct timeval tvv; + int nsel; + time_t now; +#ifdef RPC_4 + fd_set readfds; + readfds = svc_fdset; + FD_SET(fwd_sock, &readfds); +#else +#ifdef FD_SET + fd_set readfds; + FD_ZERO(&readfds); + readfds.fds_bits[0] = svc_fds; + FD_SET(fwd_sock, &readfds); +#else + int readfds = svc_fds | (1 << fwd_sock); +#endif /* FD_SET */ +#endif /* RPC_4 */ + +#ifdef DEBUG + checkup(); +#endif /* DEBUG */ + + /* + * If the full timeout code is not called, + * then recompute the time delta manually. + */ + now = clocktime(); + + if (next_softclock <= now) { + if (amd_state == Finishing) + umount_exported(); + tvv.tv_sec = softclock(); + } else { + tvv.tv_sec = next_softclock - now; + } + tvv.tv_usec = 0; + + if (amd_state == Finishing && last_used_map < 0) { + flush_mntfs(); + amd_state = Quit; + break; + } + +#ifdef DEBUG + if (tvv.tv_sec) + dlog("Select waits for %ds", tvv.tv_sec); + else + dlog("Select waits for Godot"); +#endif /* DEBUG */ + + nsel = do_select(smask, dtbsz, &readfds, &tvv); + + + switch (nsel) { + case -1: + if (errno == EINTR) { +#ifdef DEBUG + dlog("select interrupted"); +#endif /* DEBUG */ + continue; + } + perror("select"); + break; + + case 0: +#ifdef DEBUG + /*dlog("select returned 0");*/ +#endif /* DEBUG */ + break; + + default: + /* 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 + if (readfds & (1 << fwd_sock)) { + readfds &= ~(1 << fwd_sock); +#endif + --nsel; + do { + fwd_reply(); + } while (rpc_pending_now() > 0); + } + + if (nsel) { + /* + * Anything left must be a normal + * RPC request. + */ +#ifdef RPC_4 + svc_getreqset(&readfds); +#else +#ifdef FD_SET + svc_getreq(readfds.fds_bits[0]); +#else + svc_getreq(readfds); +#endif /* FD_SET */ +#endif /* RPC_4 */ + } + break; + } + } + + (void) sigsetmask(smask); + + if (amd_state == Quit) + amd_state = Done; + + return amd_state; +} + +static int bindnfs_port(so) +int so; +{ + unsigned short port; + int error = bind_resv_port(so, &port); + if (error == 0) + nfs_port = port; + return error; +} + +void unregister_amq(P_void) +{ +#ifdef DEBUG + Debug(D_AMQ) +#endif /* DEBUG */ + (void) pmap_unset(AMQ_PROGRAM, AMQ_VERSION); +} + +int mount_automounter(ppid) +int ppid; +{ + int so = socket(AF_INET, SOCK_DGRAM, 0); + SVCXPRT *amqp; + int nmount; + + if (so < 0 || bindnfs_port(so) < 0) { + perror("Can't create privileged nfs port"); + return 1; + } + + if ((nfsxprt = svcudp_create(so)) == NULL || + (amqp = svcudp_create(so)) == NULL) { + plog(XLOG_FATAL, "cannot create rpc/udp service"); + return 2; + } + + if (!svc_register(nfsxprt, NFS_PROGRAM, NFS_VERSION, nfs_program_2, 0)) { + plog(XLOG_FATAL, "unable to register (NFS_PROGRAM, NFS_VERSION, 0)"); + return 3; + } + + /* + * Start RPC forwarding + */ + if (fwd_init() != 0) + return 3; + + /* + * One or other of so, fwd_sock + * must be the highest fd on + * which to select. + */ + if (so > max_fds) + max_fds = so; + if (fwd_sock > max_fds) + max_fds = fwd_sock; + + /* + * Construct the root automount node + */ + make_root_node(); + + /* + * Pick up the pieces from a previous run + * This is likely to (indirectly) need the rpc_fwd package + * so it *must* come after the call to fwd_init(). + */ + if (restart_existing_mounts) + restart(); + + /* + * Mount the top-level auto-mountpoints + */ + nmount = mount_exported(); + + /* + * Now safe to tell parent that we are up and running + */ + if (ppid) + kill(ppid, SIGQUIT); + + if (nmount == 0) { + plog(XLOG_FATAL, "No work to do - quitting"); + amd_state = Done; + return 0; + } + +#ifdef DEBUG + Debug(D_AMQ) { +#endif /* DEBUG */ + /* + * Register with amq + */ + unregister_amq(); + + if (!svc_register(amqp, AMQ_PROGRAM, AMQ_VERSION, amq_program_1, IPPROTO_UDP)) { + plog(XLOG_FATAL, "unable to register (AMQ_PROGRAM, AMQ_VERSION, udp)"); + return 3; + } +#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/usr.sbin/amd/amd/nfs_subr.c b/usr.sbin/amd/amd/nfs_subr.c new file mode 100644 index 000000000000..297cf9330617 --- /dev/null +++ b/usr.sbin/amd/amd/nfs_subr.c @@ -0,0 +1,552 @@ +/* + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990, 1993 + * 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. + * + * @(#)nfs_subr.c 8.1 (Berkeley) 6/6/93 + * + * $Id: nfs_subr.c,v 5.2.2.1 1992/02/09 15:08:53 jsp beta $ + * + */ + +#include "am.h" + +/* + * Convert from UN*X to NFS error code + */ +#ifdef NFS_ERROR_MAPPING +NFS_ERROR_MAPPING +#define nfs_error(e) \ + ((nfsstat)((e) > NFS_LOMAP && (e) < NFS_HIMAP ? \ + nfs_errormap[(e) - NFS_LOMAP] : (e))) +#else +#define nfs_error(e) ((nfsstat)(e)) +#endif /* NFS_ERROR_MAPPING */ + +static char *do_readlink P((am_node *mp, int *error_return, struct attrstat **attrpp)); +static char *do_readlink(mp, error_return, attrpp) +am_node *mp; +int *error_return; +struct attrstat **attrpp; +{ + char *ln; + + /* + * If there is a readlink method, then use + * that, otherwise if a link exists use + * that, otherwise use the mount point. + */ + if (mp->am_mnt->mf_ops->readlink) { + int retry = 0; + mp = (*mp->am_mnt->mf_ops->readlink)(mp, &retry); + if (mp == 0) { + *error_return = retry; + return 0; + } + /*reschedule_timeout_mp();*/ + } + if (mp->am_link) { + ln = mp->am_link; + } else { + ln = mp->am_mnt->mf_mount; + } + if (attrpp) + *attrpp = &mp->am_attr; + return ln; +} + +/*ARGSUSED*/ +voidp +nfsproc_null_2(argp, rqstp) +voidp argp; +struct svc_req *rqstp; +{ + static char res; + + return (voidp) &res; +} + + +/*ARGSUSED*/ +struct attrstat * +nfsproc_getattr_2(argp, rqstp) +struct nfs_fh *argp; +struct svc_req *rqstp; +{ + static struct attrstat res; + am_node *mp; + int retry; + +#ifdef DEBUG + Debug(D_TRACE) + plog(XLOG_DEBUG, "gettattr:"); +#endif /* DEBUG */ + + mp = fh_to_mp2(argp, &retry); + if (mp == 0) { +#ifdef PRECISE_SYMLINKS +getattr_retry: +#endif /* PRECISE_SYMLINKS */ + + if (retry < 0) + return 0; + res.status = nfs_error(retry); + } else { + struct attrstat *attrp = &mp->am_attr; +#ifdef PRECISE_SYMLINKS + if (mp->am_fattr.type == NFLNK) { + /* + * Make sure we can read the link, + * and then determine the length. + */ + char *ln = do_readlink(mp, &retry, &attrp); + if (ln == 0) + goto getattr_retry; + } +#endif /* PRECISE_SYMLINKS */ +#ifdef DEBUG + Debug(D_TRACE) + plog(XLOG_DEBUG, "\tstat(%s), size = %d", mp->am_path, attrp->attrstat_u.attributes.size); +#endif /* DEBUG */ + mp->am_stats.s_getattr++; + return attrp; + } + + return &res; +} + + +/*ARGSUSED*/ +struct attrstat * +nfsproc_setattr_2(argp, rqstp) +struct sattrargs *argp; +struct svc_req *rqstp; +{ + static struct attrstat res; + + if (!fh_to_mp(&argp->file)) + res.status = nfs_error(ESTALE); + else + res.status = nfs_error(EROFS); + + return &res; +} + + +/*ARGSUSED*/ +voidp +nfsproc_root_2(argp, rqstp) +voidp argp; +struct svc_req *rqstp; +{ + static char res; + + return (voidp)&res; +} + + +/*ARGSUSED*/ +struct diropres * +nfsproc_lookup_2(argp, rqstp) +struct diropargs *argp; +struct svc_req *rqstp; +{ + static struct diropres res; + am_node *mp; + int retry; + +#ifdef DEBUG + Debug(D_TRACE) + plog(XLOG_DEBUG, "lookup:"); +#endif /* DEBUG */ + + mp = fh_to_mp2(&argp->dir, &retry); + if (mp == 0) { + if (retry < 0) + return 0; + res.status = nfs_error(retry); + } else { + int error; + am_node *ap; +#ifdef DEBUG + Debug(D_TRACE) + plog(XLOG_DEBUG, "\tlookuppn(%s, %s)", mp->am_path, argp->name); +#endif /* DEBUG */ + ap = (*mp->am_mnt->mf_ops->lookuppn)(mp, argp->name, &error, VLOOK_CREATE); + if (ap == 0) { + if (error < 0) { +#ifdef DEBUG + dlog("Not sending RPC reply"); +#endif /* DEBUG */ + amd_stats.d_drops++; + return 0; + } + res.status = nfs_error(error); + } else { + mp_to_fh(ap, &res.diropres_u.diropres.file); + res.diropres_u.diropres.attributes = ap->am_fattr; + res.status = NFS_OK; + } + mp->am_stats.s_lookup++; + /*reschedule_timeout_mp();*/ + } + + return &res; +} + + +/*ARGSUSED*/ +struct readlinkres * +nfsproc_readlink_2(argp, rqstp) +struct nfs_fh *argp; +struct svc_req *rqstp; +{ + static struct readlinkres res; + am_node *mp; + int retry; + +#ifdef DEBUG + Debug(D_TRACE) + plog(XLOG_DEBUG, "readlink:"); +#endif /* DEBUG */ + + mp = fh_to_mp2(argp, &retry); + if (mp == 0) { +readlink_retry: + if (retry < 0) + return 0; + res.status = nfs_error(retry); + } else { + char *ln = do_readlink(mp, &retry, (struct attrstat **) 0); + if (ln == 0) + goto readlink_retry; + res.status = NFS_OK; +#ifdef DEBUG + Debug(D_TRACE) + if (ln) + plog(XLOG_DEBUG, "\treadlink(%s) = %s", mp->am_path, ln); +#endif /* DEBUG */ + res.readlinkres_u.data = ln; + mp->am_stats.s_readlink++; + } + + return &res; +} + + +/*ARGSUSED*/ +struct readres * +nfsproc_read_2(argp, rqstp) +struct readargs *argp; +struct svc_req *rqstp; +{ + static struct readres res; + + bzero((char *)&res, sizeof(res)); + + res.status = nfs_error(EACCES); + + return &res; +} + + +/*ARGSUSED*/ +voidp +nfsproc_writecache_2(argp, rqstp) +voidp argp; +struct svc_req *rqstp; +{ + static char res; + + return (voidp) &res; +} + + +/*ARGSUSED*/ +struct attrstat * +nfsproc_write_2(argp, rqstp) +writeargs *argp; +struct svc_req *rqstp; +{ + static struct attrstat res; + + if (!fh_to_mp(&argp->file)) + res.status = nfs_error(ESTALE); + else + res.status = nfs_error(EROFS); + + return &res; +} + + +/*ARGSUSED*/ +struct diropres * +nfsproc_create_2(argp, rqstp) +createargs *argp; +struct svc_req *rqstp; +{ + static struct diropres res; + + if (!fh_to_mp(&argp->where.dir)) + res.status = nfs_error(ESTALE); + else + res.status = nfs_error(EROFS); + + return &res; +} + + +/*ARGSUSED*/ +static nfsstat * +unlink_or_rmdir(argp, rqstp, unlinkp) +struct diropargs *argp; +struct svc_req *rqstp; +int unlinkp; +{ + static nfsstat res; + int retry; + /*mntfs *mf;*/ + am_node *mp = fh_to_mp3(&argp->dir, &retry, VLOOK_DELETE); + if (mp == 0) { + if (retry < 0) + return 0; + res = nfs_error(retry); + goto out; + } + /*mf = mp->am_mnt;*/ + if (mp->am_fattr.type != NFDIR) { + res = nfs_error(ENOTDIR); + goto out; + } +#ifdef DEBUG + Debug(D_TRACE) + plog(XLOG_DEBUG, "\tremove(%s, %s)", mp->am_path, argp->name); +#endif /* DEBUG */ + mp = (*mp->am_mnt->mf_ops->lookuppn)(mp, argp->name, &retry, VLOOK_DELETE); + if (mp == 0) { + /* + * Ignore retries... + */ + if (retry < 0) + retry = 0; + /* + * Usual NFS workaround... + */ + else if (retry == ENOENT) + retry = 0; + res = nfs_error(retry); + } else { + forcibly_timeout_mp(mp); + res = NFS_OK; + } + +out: + return &res; +} + + +/*ARGSUSED*/ +nfsstat * +nfsproc_remove_2(argp, rqstp) +struct diropargs *argp; +struct svc_req *rqstp; +{ + return unlink_or_rmdir(argp, rqstp, TRUE); +} + +/*ARGSUSED*/ +nfsstat * +nfsproc_rename_2(argp, rqstp) +renameargs *argp; +struct svc_req *rqstp; +{ + static nfsstat res; + if (!fh_to_mp(&argp->from.dir) || !fh_to_mp(&argp->to.dir)) + res = nfs_error(ESTALE); + /* + * If the kernel is doing clever things with referenced files + * then let it pretend... + */ + else if (strncmp(argp->to.name, ".nfs", 4) == 0) + res = NFS_OK; + /* + * otherwise a failure + */ + else + res = nfs_error(EROFS); + return &res; +} + + +/*ARGSUSED*/ +nfsstat * +nfsproc_link_2(argp, rqstp) +linkargs *argp; +struct svc_req *rqstp; +{ + static nfsstat res; + if (!fh_to_mp(&argp->from) || !fh_to_mp(&argp->to.dir)) + res = nfs_error(ESTALE); + else + res = nfs_error(EROFS); + + return &res; +} + + +/*ARGSUSED*/ +nfsstat * +nfsproc_symlink_2(argp, rqstp) +symlinkargs *argp; +struct svc_req *rqstp; +{ + static nfsstat res; + if (!fh_to_mp(&argp->from.dir)) + res = nfs_error(ESTALE); + else + res = nfs_error(EROFS); + + return &res; +} + + +/*ARGSUSED*/ +struct diropres * +nfsproc_mkdir_2(argp, rqstp) +createargs *argp; +struct svc_req *rqstp; +{ + static struct diropres res; + if (!fh_to_mp(&argp->where.dir)) + res.status = nfs_error(ESTALE); + else + res.status = nfs_error(EROFS); + + return &res; +} + + +/*ARGSUSED*/ +nfsstat * +nfsproc_rmdir_2(argp, rqstp) +struct diropargs *argp; +struct svc_req *rqstp; +{ + return unlink_or_rmdir(argp, rqstp, FALSE); +} + + +/*ARGSUSED*/ +struct readdirres * +nfsproc_readdir_2(argp, rqstp) +readdirargs *argp; +struct svc_req *rqstp; +{ + static readdirres res; + static entry e_res[MAX_READDIR_ENTRIES]; + am_node *mp; + int retry; + +#ifdef DEBUG + Debug(D_TRACE) + plog(XLOG_DEBUG, "readdir:"); +#endif /* DEBUG */ + + mp = fh_to_mp2(&argp->dir, &retry); + if (mp == 0) { + if (retry < 0) + return 0; + res.status = nfs_error(retry); + } else { +#ifdef DEBUG + Debug(D_TRACE) + plog(XLOG_DEBUG, "\treaddir(%s)", mp->am_path); +#endif /* DEBUG */ + res.status = nfs_error((*mp->am_mnt->mf_ops->readdir)(mp, argp->cookie, + &res.readdirres_u.reply, e_res, argp->count)); + mp->am_stats.s_readdir++; + } + + return &res; +} + +/*ARGSUSED*/ +struct statfsres * +nfsproc_statfs_2(argp, rqstp) +struct nfs_fh *argp; +struct svc_req *rqstp; +{ + static statfsres res; + am_node *mp; + int retry; + +#ifdef DEBUG + Debug(D_TRACE) + plog(XLOG_DEBUG, "statfs:"); +#endif /* DEBUG */ + + mp = fh_to_mp2(argp, &retry); + if (mp == 0) { + if (retry < 0) + return 0; + res.status = nfs_error(retry); + } else { + statfsokres *fp; +#ifdef DEBUG + Debug(D_TRACE) + plog(XLOG_DEBUG, "\tstat_fs(%s)", mp->am_path); +#endif /* DEBUG */ + /* + * just return faked up file system information + */ + + fp = &res.statfsres_u.reply; + + fp->tsize = 1024; + fp->bsize = 4096; +#ifdef HAS_EMPTY_AUTOMOUNTS + fp->blocks = 0; +#else + fp->blocks = 1; +#endif + fp->bfree = 0; + fp->bavail = 0; + + res.status = NFS_OK; + mp->am_stats.s_statfs++; + } + + return &res; +} diff --git a/usr.sbin/amd/amd/nfsx_ops.c b/usr.sbin/amd/amd/nfsx_ops.c new file mode 100644 index 000000000000..ba18cdcfebe8 --- /dev/null +++ b/usr.sbin/amd/amd/nfsx_ops.c @@ -0,0 +1,516 @@ +/* + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990, 1993 + * 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. + * + * @(#)nfsx_ops.c 8.1 (Berkeley) 6/6/93 + * + * $Id: nfsx_ops.c,v 5.2.2.3 1992/05/31 16:13:07 jsp Exp $ + * + */ + +#include "am.h" + +#ifdef HAS_NFSX + +/* + * NFS hierarchical mounts + * + * TODO: Re-implement. + */ + +/* + * The rfs field contains a list of mounts to be done from + * the remote host. + */ +typedef struct nfsx_mnt { + mntfs *n_mnt; + int n_error; +} nfsx_mnt; + +struct nfsx { + int nx_c; /* Number of elements in nx_v */ + nfsx_mnt *nx_v; /* Underlying mounts */ + nfsx_mnt *nx_try; +}; + +static int nfsx_fmount P((mntfs*)); + +static char *nfsx_match(fo) +am_opts *fo; +{ + char *xmtab; + char *ptr; + int len; + + if (!fo->opt_rfs) { + plog(XLOG_USER, "nfsx: no remote filesystem specified"); + return FALSE; + } + if (!fo->opt_rhost) { + plog(XLOG_USER, "nfsx: no remote host specified"); + return FALSE; + } + +#ifdef notdef + /* fiddle sublink, must be last... */ + if (fo->opt_sublink) { + plog(XLOG_WARNING, "nfsx: sublink %s ignored", fo->opt_sublink); + free((voidp) fo->opt_sublink); + fo->opt_sublink = 0; + } +#endif + + /* 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 nfsx_prfree P((voidp vp)); +static void nfsx_prfree(vp) +voidp vp; +{ + struct nfsx *nx = (struct 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); + } + + free((voidp) nx->nx_v); + free((voidp) nx); +} + +static int nfsx_init(mf) +mntfs *mf; +{ + /* + * mf_info has the form: + * host:/prefix/path,sub,sub,sub + */ + int i; + int glob_error; + struct nfsx *nx; + int asked_for_wakeup = 0; + + nx = (struct 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(nfsx); + mf->mf_private = (voidp) nx; + mf->mf_prfree = nfsx_prfree; + + nx->nx_c = i - 1; /* i-1 because we don't want the prefix */ + nx->nx_v = (nfsx_mnt *) xmalloc(nx->nx_c * sizeof(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("nfsx: init mount for %s on %s", xinfo, mp); +#endif + 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) free(rfs); + if (mp) free(mp); + if (xinfo) free(xinfo); + } + + free((voidp) ivec); +errexit: + if (info) + free(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++) { + nfsx_mnt *n = &nx->nx_v[i]; + mntfs *m = n->n_mnt; + int error = (*m->mf_ops->fs_init)(m); + /* + * If HARD_NFSX_ERRORS is defined, make any + * initialisation failure a hard error and + * fail the entire group. Otherwise only fail + * if none of the group is mountable (see nfsx_fmount). + */ +#ifdef HARD_NFSX_ERRORS + if (error > 0) + return error; +#else + if (error > 0) + n->n_error = error; +#endif + 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 nfsx_cont P((int rc, int term, voidp closure)); +static void nfsx_cont(rc, term, closure) +int rc; +int term; +voidp closure; +{ + mntfs *mf = (mntfs *) closure; + struct nfsx *nx = (struct nfsx *) mf->mf_private; + 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 (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 (nfsx_fmount(mf) >= 0) { + wakeup((voidp) mf); + mf->mf_flags &= ~MFF_MOUNTING; + mf_mounted(mf); + } +} + +static int try_nfsx_mount P((voidp mv)); +static int try_nfsx_mount(mv) +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 nfsx_remount P((mntfs *mf, int fg)); +static int nfsx_remount(mf, fg) +mntfs *mf; +int fg; +{ + struct nfsx *nx = (struct nfsx *) mf->mf_private; + 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 + 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 + nx->nx_try = n; + run_task(try_nfsx_mount, (voidp) m, nfsx_cont, (voidp) mf); + n->n_error = -1; + return -1; + } else { +#ifdef DEBUG + dlog("foreground mount of \"%s\" ...", mf->mf_info); +#endif + 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 + 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 nfsx_fmount P((mntfs *mf)); +static int nfsx_fmount(mf) +mntfs *mf; +{ + return 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 nfsx_fumount(mf) +mntfs *mf; +{ + struct nfsx *nx = (struct nfsx *) mf->mf_private; + 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 + 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 = nfsx_remount(mf, TRUE); + if (glob_error) { + errno = glob_error; /* XXX */ + plog(XLOG_USER, "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; + 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; +} + +/* + * Ops structure + */ +am_ops nfsx_ops = { + "nfsx", + nfsx_match, + nfsx_init, + auto_fmount, + nfsx_fmount, + auto_fumount, + nfsx_fumount, + efs_lookuppn, + efs_readdir, + 0, /* nfsx_readlink */ + 0, /* nfsx_mounted */ + 0, /* nfsx_umounted */ + find_nfs_srvr, /* XXX */ + /*FS_UBACKGROUND|*/FS_AMQINFO +}; + +#endif /* HAS_NFSX */ diff --git a/usr.sbin/amd/amd/opts.c b/usr.sbin/amd/amd/opts.c new file mode 100644 index 000000000000..54c967528c44 --- /dev/null +++ b/usr.sbin/amd/amd/opts.c @@ -0,0 +1,835 @@ +/*- + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989, 1993 + * 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. + * + * $Id: opts.c,v 5.2.2.3 1992/05/31 16:34:13 jsp Exp $ + */ + +#ifndef lint +static char sccsid[] = "@(#)opts.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "am.h" + +extern char *getenv P((const char *)); + +/* + * static copy of the options with + * which to play + */ +static struct am_opts fs_static; + +static char *opt_host = hostname; +static char *opt_hostd = hostd; +static char nullstr[] = ""; +static char *opt_key = nullstr; +static char *opt_map = nullstr; +static char *opt_path = nullstr; + +static char *vars[8]; + +/* + * Length of longest option name + */ +#define NLEN 16 /* conservative */ +#define S(x) (x) , (sizeof(x)-1) +static struct opt { + char *name; /* Name of the option */ + int nlen; /* Length of option name */ + char **optp; /* Pointer to option value string */ + char **sel_p; /* Pointer to selector value string */ +} opt_fields[] = { + /* Options in something corresponding to frequency of use */ + { S("opts"), &fs_static.opt_opts, 0 }, + { S("host"), 0, &opt_host }, + { S("hostd"), 0, &opt_hostd }, + { S("type"), &fs_static.opt_type, 0 }, + { S("rhost"), &fs_static.opt_rhost, 0 }, + { S("rfs"), &fs_static.opt_rfs, 0 }, + { S("fs"), &fs_static.opt_fs, 0 }, + { S("key"), 0, &opt_key }, + { S("map"), 0, &opt_map }, + { S("sublink"), &fs_static.opt_sublink, 0 }, + { S("arch"), 0, &arch }, + { S("dev"), &fs_static.opt_dev, 0 }, + { S("pref"), &fs_static.opt_pref, 0 }, + { S("path"), 0, &opt_path }, + { S("autodir"), 0, &auto_dir }, + { S("delay"), &fs_static.opt_delay, 0 }, + { S("domain"), 0, &hostdomain }, + { S("karch"), 0, &karch }, + { S("cluster"), 0, &cluster }, + { S("wire"), 0, &wire }, + { S("byte"), 0, &endian }, + { S("os"), 0, &op_sys }, + { S("remopts"), &fs_static.opt_remopts, 0 }, + { S("mount"), &fs_static.opt_mount, 0 }, + { S("unmount"), &fs_static.opt_unmount, 0 }, + { S("cache"), &fs_static.opt_cache, 0 }, + { S("user"), &fs_static.opt_user, 0 }, + { S("group"), &fs_static.opt_group, 0 }, + { S("var0"), &vars[0], 0 }, + { S("var1"), &vars[1], 0 }, + { S("var2"), &vars[2], 0 }, + { S("var3"), &vars[3], 0 }, + { S("var4"), &vars[4], 0 }, + { S("var5"), &vars[5], 0 }, + { S("var6"), &vars[6], 0 }, + { S("var7"), &vars[7], 0 }, + { 0, 0, 0, 0 }, +}; + +typedef struct opt_apply opt_apply; +struct opt_apply { + char **opt; + char *val; +}; + +/* + * Specially expand the remote host name first + */ +static opt_apply rhost_expansion[] = { + { &fs_static.opt_rhost, "${host}" }, + { 0, 0 }, +}; +/* + * List of options which need to be expanded + * Note that this the order here _may_ be important. + */ +static opt_apply expansions[] = { +/* { &fs_static.opt_dir, 0 }, */ + { &fs_static.opt_sublink, 0 }, + { &fs_static.opt_rfs, "${path}" }, + { &fs_static.opt_fs, "${autodir}/${rhost}${rfs}" }, + { &fs_static.opt_opts, "rw" }, + { &fs_static.opt_remopts, "${opts}" }, + { &fs_static.opt_mount, 0 }, + { &fs_static.opt_unmount, 0 }, + { 0, 0 }, +}; + +/* + * List of options which need to be free'ed before re-use + */ +static opt_apply to_free[] = { + { &fs_static.fs_glob, 0 }, + { &fs_static.fs_local, 0 }, + { &fs_static.fs_mtab, 0 }, +/* { &fs_static.opt_dir, 0 }, */ + { &fs_static.opt_sublink, 0 }, + { &fs_static.opt_rfs, 0 }, + { &fs_static.opt_fs, 0 }, + { &fs_static.opt_rhost, 0 }, + { &fs_static.opt_opts, 0 }, + { &fs_static.opt_remopts, 0 }, + { &fs_static.opt_mount, 0 }, + { &fs_static.opt_unmount, 0 }, + { &vars[0], 0 }, + { &vars[1], 0 }, + { &vars[2], 0 }, + { &vars[3], 0 }, + { &vars[4], 0 }, + { &vars[5], 0 }, + { &vars[6], 0 }, + { &vars[7], 0 }, + { 0, 0 }, +}; + +/* + * Skip to next option in the string + */ +static char *opt P((char**)); +static char *opt(p) +char **p; +{ + char *cp = *p; + char *dp = cp; + char *s = cp; + +top: + while (*cp && *cp != ';') { + if (*cp == '\"') { + /* + * Skip past string + */ + cp++; + while (*cp && *cp != '\"') + *dp++ = *cp++; + if (*cp) + cp++; + } else { + *dp++ = *cp++; + } + } + + /* + * Skip past any remaining ';'s + */ + while (*cp == ';') + cp++; + + /* + * If we have a zero length string + * and there are more fields, then + * parse the next one. This allows + * sequences of empty fields. + */ + if (*cp && dp == s) + goto top; + + *dp = '\0'; + + *p = cp; + return s; +} + +static int eval_opts P((char*, char*)); +static int eval_opts(opts, mapkey) +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 { OldSyn, SelEQ, SelNE, VarAss } vs_opt; + char *eq = strchr(f, '='); + char *opt; + if (!eq || eq[1] == '\0' || eq == f) { + /* + * No value, just continue + */ + plog(XLOG_USER, "key %s: No value component in \"%s\"", mapkey, f); + continue; + } + + /* + * Check what type of operation is happening + * !=, =! is SelNE + * == is SelEQ + * := is VarAss + * = is OldSyn (either SelEQ or VarAss) + */ + if (eq[-1] == '!') { /* != */ + vs_opt = SelNE; + eq[-1] = '\0'; + opt = eq + 1; + } else if (eq[-1] == ':') { /* := */ + vs_opt = VarAss; + eq[-1] = '\0'; + opt = eq + 1; + } else if (eq[1] == '=') { /* == */ + vs_opt = SelEQ; + eq[0] = '\0'; + opt = eq + 2; + } else if (eq[1] == '!') { /* =! */ + vs_opt = SelNE; + eq[0] = '\0'; + opt = eq + 2; + } else { /* = */ + vs_opt = OldSyn; + eq[0] = '\0'; + opt = eq + 1; + } + + /* + * For each recognised option + */ + for (op = opt_fields; op->name; op++) { + /* + * Check whether they match + */ + if (FSTREQ(op->name, f)) { + switch (vs_opt) { +#if AMD_COMPAT <= 5000108 + case OldSyn: + plog(XLOG_WARNING, "key %s: Old syntax selector found: %s=%s", mapkey, f, opt); + if (!op->sel_p) { + *op->optp = opt; + break; + } + /* fall through ... */ +#endif /* 5000108 */ + case SelEQ: + case SelNE: + if (op->sel_p && (STREQ(*op->sel_p, opt) == (vs_opt == SelNE))) { + plog(XLOG_MAP, "key %s: map selector %s (=%s) did not %smatch %s", + mapkey, + op->name, + *op->sel_p, + vs_opt == SelNE ? "not " : "", + 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; + } + break; + } + } + + if (!op->name) + plog(XLOG_USER, "key %s: Unrecognised key/option \"%s\"", mapkey, f); + } + + return 1; +} + +/* + * Free an option + */ +static void free_op P((opt_apply*, int)); +/*ARGSUSED*/ +static void free_op(p, b) +opt_apply *p; +int b; +{ + if (*p->opt) { + free(*p->opt); + *p->opt = 0; + } +} + +/* + * Normalize slashes in the string. + */ +void normalize_slash P((char *p)); +void normalize_slash(p) +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 P((opt_apply*, int)); +static void expand_op(p, sel_p) +opt_apply *p; +int sel_p; +{ +/* + * The BUFSPACE macros checks that there is enough space + * left in the expansion buffer. If there isn't then we + * give up completely. This is done to avoid crashing the + * automounter itself (which would be a bad thing to do). + */ +#define BUFSPACE(ep, len) (((ep) + (len)) < expbuf+MAXPATHLEN) +static char expand_error[] = "No space to expand \"%s\""; + + char expbuf[MAXPATHLEN+1]; + char nbuf[NLEN+1]; + char *ep = expbuf; + char *cp = *p->opt; + char *dp; +#ifdef DEBUG + char *cp_orig = *p->opt; +#endif /* DEBUG */ + struct opt *op; + + while (dp = strchr(cp, '$')) { + char ch; + /* + * First copy up to the $ + */ + { int len = dp - cp; + if (BUFSPACE(ep, len)) { + strncpy(ep, cp, len); + ep += len; + } else { + plog(XLOG_ERROR, expand_error, *p->opt); + goto out; + } + } + cp = dp + 1; + ch = *cp++; + if (ch == '$') { + if (BUFSPACE(ep, 1)) { + *ep++ = '$'; + } else { + plog(XLOG_ERROR, expand_error, *p->opt); + goto out; + } + } else if (ch == '{') { + /* Expansion... */ + enum { E_All, E_Dir, E_File, 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; + } +#ifdef DEBUG + /*dlog("Expanding \"%s\" to \"%s\"", nbuf, val);*/ +#endif /* DEBUG */ + if (BUFSPACE(ep, vlen)) { + strcpy(ep, vptr); + ep += vlen; + } else { + plog(XLOG_ERROR, expand_error, *p->opt); + goto out; + } + } + /* + * Done with this variable + */ + break; + } + } + /* + * Check that the search was succesful + */ |