From 59fe2c14b4029930a239ecc380c3cfb365ef9284 Mon Sep 17 00:00:00 2001 From: Bruce Evans Date: Sat, 2 Aug 1997 19:36:03 +0000 Subject: [PATCH] Import Lite2's src/usr.sbin, except for timed. All changed files except one unimportant one have already left the vendor branch. --- sbin/sysctl/sysctl.8 | 229 ++++ sbin/sysctl/sysctl.c | 644 ++++++++++ usr.sbin/amd/amd/afs_ops.c | 1820 +++++++++++++++++++++++++++++ usr.sbin/amd/amd/amd.8 | 233 ++++ usr.sbin/amd/amd/nfs_ops.c | 811 +++++++++++++ usr.sbin/amd/amd/ufs_ops.c | 178 +++ usr.sbin/amd/config/misc-bsd44l.h | 48 + usr.sbin/amd/config/mtab_bsd.c | 118 ++ usr.sbin/amd/config/os-bsd44.h | 228 ++++ usr.sbin/amd/text/INSTALL | 194 +++ usr.sbin/arp/arp.8 | 122 ++ usr.sbin/arp/arp.c | 531 +++++++++ usr.sbin/arp/arp4.4 | 124 ++ usr.sbin/bad144/bad144.c | 662 +++++++++++ usr.sbin/config.new/Makefile | 12 + usr.sbin/config.new/config.8 | 167 +++ usr.sbin/diskpart/diskpart.c | 476 ++++++++ usr.sbin/edquota/edquota.8 | 160 +++ usr.sbin/edquota/edquota.c | 724 ++++++++++++ usr.sbin/inetd/inetd.8 | 376 ++++++ usr.sbin/iostat/iostat.c | 391 +++++++ usr.sbin/mtree/Makefile | 9 + usr.sbin/mtree/spec.c | 280 +++++ usr.sbin/portmap/Makefile | 8 + usr.sbin/portmap/portmap.8 | 110 ++ usr.sbin/portmap/portmap.c | 541 +++++++++ usr.sbin/pwd_mkdb/pwd_mkdb.8 | 128 ++ usr.sbin/quot/quot.8 | 84 ++ usr.sbin/repquota/repquota.c | 380 ++++++ usr.sbin/rmt/rmt.8 | 218 ++++ usr.sbin/sendmail/README | 4 + usr.sbin/sliplogin/slip.hosts | 11 + usr.sbin/sliplogin/slip.login | 12 + usr.sbin/sysctl/sysctl.8 | 229 ++++ usr.sbin/sysctl/sysctl.c | 644 ++++++++++ usr.sbin/traceroute/traceroute.8 | 337 ++++++ usr.sbin/update/Makefile | 6 + usr.sbin/update/update.8 | 74 ++ usr.sbin/update/update.c | 75 ++ usr.sbin/vipw/pw_util.c | 220 ++++ 40 files changed, 11618 insertions(+) create mode 100644 sbin/sysctl/sysctl.8 create mode 100644 sbin/sysctl/sysctl.c create mode 100644 usr.sbin/amd/amd/afs_ops.c create mode 100644 usr.sbin/amd/amd/amd.8 create mode 100644 usr.sbin/amd/amd/nfs_ops.c create mode 100644 usr.sbin/amd/amd/ufs_ops.c create mode 100644 usr.sbin/amd/config/misc-bsd44l.h create mode 100644 usr.sbin/amd/config/mtab_bsd.c create mode 100644 usr.sbin/amd/config/os-bsd44.h create mode 100644 usr.sbin/amd/text/INSTALL create mode 100644 usr.sbin/arp/arp.8 create mode 100644 usr.sbin/arp/arp.c create mode 100644 usr.sbin/arp/arp4.4 create mode 100644 usr.sbin/bad144/bad144.c create mode 100644 usr.sbin/config.new/Makefile create mode 100644 usr.sbin/config.new/config.8 create mode 100644 usr.sbin/diskpart/diskpart.c create mode 100644 usr.sbin/edquota/edquota.8 create mode 100644 usr.sbin/edquota/edquota.c create mode 100644 usr.sbin/inetd/inetd.8 create mode 100644 usr.sbin/iostat/iostat.c create mode 100644 usr.sbin/mtree/Makefile create mode 100644 usr.sbin/mtree/spec.c create mode 100644 usr.sbin/portmap/Makefile create mode 100644 usr.sbin/portmap/portmap.8 create mode 100644 usr.sbin/portmap/portmap.c create mode 100644 usr.sbin/pwd_mkdb/pwd_mkdb.8 create mode 100644 usr.sbin/quot/quot.8 create mode 100644 usr.sbin/repquota/repquota.c create mode 100644 usr.sbin/rmt/rmt.8 create mode 100644 usr.sbin/sendmail/README create mode 100644 usr.sbin/sliplogin/slip.hosts create mode 100644 usr.sbin/sliplogin/slip.login create mode 100644 usr.sbin/sysctl/sysctl.8 create mode 100644 usr.sbin/sysctl/sysctl.c create mode 100644 usr.sbin/traceroute/traceroute.8 create mode 100644 usr.sbin/update/Makefile create mode 100644 usr.sbin/update/update.8 create mode 100644 usr.sbin/update/update.c create mode 100644 usr.sbin/vipw/pw_util.c diff --git a/sbin/sysctl/sysctl.8 b/sbin/sysctl/sysctl.8 new file mode 100644 index 000000000000..bc348a9d9051 --- /dev/null +++ b/sbin/sysctl/sysctl.8 @@ -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. +.\" +.\" @(#)sysctl.8 8.2 (Berkeley) 5/9/95 +.\" +.Dd "May 9, 1995" +.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 +.Pp +The +.Nm sysctl +program can get or set debugging variables +that have been identified for its display. +This information can be obtained by using the command: +.Bd -literal -offset indent +sysctl debug +.Ed +In addition, +.Nm sysctl +can extract information about the filesystems that have been compiled +into the running system. +This information can be obtained by using the command: +.Bd -literal -offset indent +sysctl vfs +.Ed +By default, only filesystems that are actively being used are listed. +Use of the +.Fl A +flag lists all the filesystems compiled into the running kernel. +.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 -compact +.It Pa +definitions for top level identifiers, second level kernel and hardware +identifiers, and user level identifiers +.It Pa +definitions for second level network identifiers +.It Pa +definitions for third level profiling identifiers +.It Pa +definitions for second level virtual memory identifiers +.It Pa +definitions for third level Internet identifiers and +fourth level IP identifiers +.It Pa +definitions for fourth level ICMP identifiers +.It Pa +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..9f42981e50c6 --- /dev/null +++ b/sbin/sysctl/sysctl.c @@ -0,0 +1,644 @@ +/* + * 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.5 (Berkeley) 5/9/95"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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]; +struct ctlname *vfsname; +#ifdef CTL_MACHDEP_NAMES +struct ctlname machdepname[] = CTL_MACHDEP_NAMES; +#endif +char names[BUFSIZ]; +int lastused; + +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_VFS */ + { 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 (argc == 0 && (Aflag || aflag)) { + debuginit(); + vfsinit(); + for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++) + listall(topname[lvl1].ctl_name, &secondlevel[lvl1]); + exit(0); + } + if (argc == 0) + usage(); + for (; *argv != NULL; ++argv) + 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, len; + size_t size; + int special = 0; + void *newval = 0; + int intval, newsize = 0; + quad_t quadval; + struct list *lp; + struct vfsconf vfc; + 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_VFS) + vfsinit(); + 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_VFS: + mib[3] = mib[1]; + mib[1] = VFS_GENERIC; + mib[2] = VFS_CONF; + len = 4; + size = sizeof vfc; + if (sysctl(mib, 4, &vfc, &size, (void *)0, (size_t)0) < 0) { + perror("vfs print"); + return; + } + if (flags == 0 && vfc.vfc_refcount == 0) + return; + if (!nflag) + fprintf(stdout, "%s has %d mounted instance%s\n", + string, vfc.vfc_refcount, + vfc.vfc_refcount != 1 ? "s" : ""); + else + fprintf(stdout, "%d\n", vfc.vfc_refcount); + return; + + 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], loc, i; + size_t size; + + if (secondlevel[CTL_DEBUG].list != 0) + return; + secondlevel[CTL_DEBUG].list = debugname; + mib[0] = CTL_DEBUG; + mib[2] = CTL_DEBUG_NAME; + for (loc = lastused, 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; + } + lastused = loc; +} + +/* + * Initialize the set of filesystem names + */ +vfsinit() +{ + int mib[4], maxtypenum, cnt, loc, size; + struct vfsconf vfc; + size_t buflen; + + if (secondlevel[CTL_VFS].list != 0) + return; + mib[0] = CTL_VFS; + mib[1] = VFS_GENERIC; + mib[2] = VFS_MAXTYPENUM; + buflen = 4; + if (sysctl(mib, 3, &maxtypenum, &buflen, (void *)0, (size_t)0) < 0) + return; + if ((vfsname = malloc(maxtypenum * sizeof(*vfsname))) == 0) + return; + memset(vfsname, 0, maxtypenum * sizeof(*vfsname)); + mib[2] = VFS_CONF; + buflen = sizeof vfc; + for (loc = lastused, cnt = 0; cnt < maxtypenum; cnt++) { + mib[3] = cnt; + if (sysctl(mib, 4, &vfc, &buflen, (void *)0, (size_t)0) < 0) { + if (errno == EOPNOTSUPP) + continue; + perror("vfsinit"); + free(vfsname); + return; + } + strcat(&names[loc], vfc.vfc_name); + vfsname[cnt].ctl_name = &names[loc]; + vfsname[cnt].ctl_type = CTLTYPE_INT; + size = strlen(vfc.vfc_name) + 1; + loc += size; + } + lastused = loc; + secondlevel[CTL_VFS].list = vfsname; + secondlevel[CTL_VFS].size = maxtypenum; + return; +} + +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/usr.sbin/amd/amd/afs_ops.c b/usr.sbin/amd/amd/afs_ops.c new file mode 100644 index 000000000000..efd8da4dddf1 --- /dev/null +++ b/usr.sbin/amd/amd/afs_ops.c @@ -0,0 +1,1820 @@ +/* + * 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.2 (Berkeley) 5/10/95 + * + * $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 +#ifdef NFS_3 +typedef nfs_fh fhandle_t; +#endif /* NFS_3 */ +#include +#ifdef NFS_HDR +#include NFS_HDR +#endif /* NFS_HDR */ +#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; + } + +#ifdef NFS_ARGSVERSION + nfs_args.version = NFS_ARGSVERSION; +#endif + + 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 + * 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 + * 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/amd.8 b/usr.sbin/amd/amd/amd.8 new file mode 100644 index 000000000000..1d3e5ec07114 --- /dev/null +++ b/usr.sbin/amd/amd/amd.8 @@ -0,0 +1,233 @@ +.\" +.\" 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.11 (Berkeley) 6/1/94 +.\" +.\" $Id: amd.8,v 5.2.2.1 1992/02/09 15:11:39 jsp beta $ +.\" +.Dd "June 1, 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. +.ne 1i +.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 +, 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/nfs_ops.c b/usr.sbin/amd/amd/nfs_ops.c new file mode 100644 index 000000000000..6b3cec9ea8f5 --- /dev/null +++ b/usr.sbin/amd/amd/nfs_ops.c @@ -0,0 +1,811 @@ +/*- + * 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.2 (Berkeley) 5/10/95"; +#endif /* not lint */ + +#include "am.h" +#include + +#ifdef HAS_NFS + +#define NFS +#define NFSCLIENT +#ifdef NFS_3 +typedef nfs_fh fhandle_t; +#endif /* NFS_3 */ +#include +#ifdef NFS_HDR +#include NFS_HDR +#endif /* NFS_HDR */ +#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 + * 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); + + 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 + */ +#ifdef NFS_ARGSVERSION + nfs_args.version = NFS_ARGSVERSION; +#endif + + 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/ufs_ops.c b/usr.sbin/amd/amd/ufs_ops.c new file mode 100644 index 000000000000..28cb418488b6 --- /dev/null +++ b/usr.sbin/amd/amd/ufs_ops.c @@ -0,0 +1,178 @@ +/* + * 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. + * + * @(#)ufs_ops.c 8.2 (Berkeley) 5/10/95 + * + * $Id: ufs_ops.c,v 5.2.2.1 1992/02/09 15:09:08 jsp beta $ + * + */ + +#include "am.h" + +#ifdef HAS_UFS + +#include +#ifdef NFS_3 +typedef nfs_fh fhandle_t; +#endif /* NFS_3 */ + +#include + +#ifdef UFS_HDR +#include UFS_HDR +#endif /* UFS_HDR */ + +/* + * UN*X file system + */ + +/* + * UFS needs local filesystem and device. + */ +static char *ufs_match P((am_opts *fo)); +static char *ufs_match(fo) +am_opts *fo; +{ + if (!fo->opt_dev) { + plog(XLOG_USER, "ufs: no device specified"); + return 0; + } + +#ifdef DEBUG + dlog("UFS: mounting device \"%s\" on \"%s\"", + fo->opt_dev, fo->opt_fs); +#endif /* DEBUG */ + + /* + * Determine magic cookie to put in mtab + */ + return strdup(fo->opt_dev); +} + +static mount_ufs(dir, fs_name, opts) +char *dir; +char *fs_name; +char *opts; +{ + struct ufs_args ufs_args; + struct mntent mnt; + int flags; + + /* + * Figure out the name of the file system type. + */ +#ifdef M_NEWTYPE + char *type = MOUNT_TYPE_UFS; +#else + int type = MOUNT_TYPE_UFS; +#endif /* M_NEWTYPE */ + + bzero((voidp) &ufs_args, sizeof(ufs_args)); /* Paranoid */ + + /* + * Fill in the mount structure + */ + mnt.mnt_dir = dir; + mnt.mnt_fsname = fs_name; + mnt.mnt_type = MTAB_TYPE_UFS; + mnt.mnt_opts = opts; + mnt.mnt_freq = 1; + mnt.mnt_passno = 2; + + flags = compute_mount_flags(&mnt); + +#ifdef ULTRIX_HACK + ufs_args.ufs_flags = flags; + ufs_args.ufs_pgthresh = 64; /* 64K - XXX */ + flags &= M_RDONLY; +#else + ufs_args.fspec = fs_name; +#endif /* ULTRIX_HACK */ + + /* + * Call generic mount routine + */ + return mount_fs(&mnt, flags, (caddr_t) &ufs_args, 0, type); +} + +/*ARGSUSED*/ +static int ufs_fmount(mf) +mntfs *mf; +{ + int error; + + error = mount_ufs(mf->mf_mount, mf->mf_info, mf->mf_mopts); + if (error) { + errno = error; + plog(XLOG_ERROR, "mount_ufs: %m"); + return error; + } + + return 0; +} + +static int ufs_fumount(mf) +mntfs *mf; +{ + return UMOUNT_FS(mf->mf_mount); +} + +/* + * Ops structure + */ +am_ops ufs_ops = { + "ufs", + ufs_match, + 0, /* ufs_init */ + auto_fmount, + ufs_fmount, + auto_fumount, + ufs_fumount, + efs_lookuppn, + efs_readdir, + 0, /* ufs_readlink */ + 0, /* ufs_mounted */ + 0, /* ufs_umounted */ + find_afs_srvr, +#ifdef FLUSH_KERNEL_NAME_CACHE + FS_MKMNT|FS_NOTIMEOUT|FS_UBACKGROUND|FS_AMQINFO +#else /* FLUSH_KERNEL_NAME_CACHE */ + FS_MKMNT|FS_NOTIMEOUT|FS_UBACKGROUND|FS_AMQINFO +#endif /* FLUSH_KERNEL_NAME_CACHE */ +}; + +#endif /* HAS_UFS */ diff --git a/usr.sbin/amd/config/misc-bsd44l.h b/usr.sbin/amd/config/misc-bsd44l.h new file mode 100644 index 000000000000..7f4e595bb718 --- /dev/null +++ b/usr.sbin/amd/config/misc-bsd44l.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 1995 Jan-Simon Pendry + * Copyright (c) 1995 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry. + * + * 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-bsd44l.h 8.1 (Berkeley) 5/10/95 + * + */ + +#define M_NEWTYPE 0 + +#include +#include +#define NFS_NPROCS 26 /* from */ +#include + +#include diff --git a/usr.sbin/amd/config/mtab_bsd.c b/usr.sbin/amd/config/mtab_bsd.c new file mode 100644 index 000000000000..c541096807e0 --- /dev/null +++ b/usr.sbin/amd/config/mtab_bsd.c @@ -0,0 +1,118 @@ +/* + * 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. + * + * @(#)mtab_bsd.c 8.2 (Berkeley) 5/10/95 + * + * $Id: mtab_bsd.c,v 5.2.2.1 1992/02/09 15:10:13 jsp beta $ + * + */ + +#include "am.h" + +#ifdef READ_MTAB_BSD_STYLE + +#include + +static struct mntent *mnt_dup(mp) +struct statfs *mp; +{ + struct mntent *new_mp = ALLOC(mntent); + char *ty; + + new_mp->mnt_fsname = strdup(mp->f_mntfromname); + new_mp->mnt_dir = strdup(mp->f_mntonname); +#if BSD >= 199506 + ty = mp->f_fstypename; +#else + switch (mp->f_type) { + case MOUNT_UFS: ty = MTAB_TYPE_UFS; break; + case MOUNT_NFS: ty = MTAB_TYPE_NFS; break; + case MOUNT_MFS: ty = MTAB_TYPE_MFS; break; + default: ty = "unknown"; break; + } +#endif + new_mp->mnt_type = strdup(ty); + new_mp->mnt_opts = strdup("unset"); + new_mp->mnt_freq = 0; + new_mp->mnt_passno = 0; + + return new_mp; +} + +/* + * Read a mount table into memory + */ +mntlist *read_mtab(fs) +char *fs; +{ + mntlist **mpp, *mhp; + struct statfs *mntbufp, *mntp; + + int nloc = getmntinfo(&mntbufp, MNT_NOWAIT); + + if (nloc == 0) { + plog(XLOG_ERROR, "Can't read mount table"); + return 0; + } + + mpp = &mhp; + for (mntp = mntbufp; mntp < mntbufp + nloc; mntp++) { + /* + * Allocate a new slot + */ + *mpp = ALLOC(mntlist); + + /* + * Copy the data returned by getmntent + */ + (*mpp)->mnt = mnt_dup(mntp); + + /* + * Move to next pointer + */ + mpp = &(*mpp)->mnext; + } + + /* + * Terminate the list + */ + *mpp = 0; + + return mhp; +} + +#endif /* READ_MTAB_BSD_STYLE */ diff --git a/usr.sbin/amd/config/os-bsd44.h b/usr.sbin/amd/config/os-bsd44.h new file mode 100644 index 000000000000..7f6a558e4deb --- /dev/null +++ b/usr.sbin/amd/config/os-bsd44.h @@ -0,0 +1,228 @@ +/* + * 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. + * + * @(#)os-bsd44.h 8.2 (Berkeley) 5/10/95 + * + * $Id: os-bsd44.h,v 5.2.2.1 1992/02/09 15:10:11 jsp beta $ + * + * 4.4 BSD definitions for Amd (automounter) + */ + +/* + * Does the compiler grok void * + */ +#define VOIDP + +/* + * Which version of the Sun RPC library we are using + * This is the implementation release number, not + * the protocol revision number. + */ +#define RPC_4 + +#include +#if BSD >= 199506 +#define NFS_HDR "misc-bsd44l.h" +#define UFS_HDR "misc-bsd44l.h" +#endif + +/* + * Which version of the NFS interface are we using. + * This is the implementation release number, not + * the protocol revision number. + */ +#define NFS_44 +#define HAS_TCP_NFS + +/* + * Does this OS have NDBM support? + */ +#define OS_HAS_NDBM + +/* + * 4.4 doesn't provide NIS. + */ +#undef HAS_NIS_MAPS + +/* + * OS provides strerror() + */ +#define HAS_STRERROR + +/* + * The mount table is obtained from the kernel + */ +#undef UPDATE_MTAB + +/* + * No mntent info on 4.4 BSD + */ +#undef MNTENT_HDR + +/* + * Name of filesystem types + */ +#define MOUNT_TYPE_NFS MOUNT_NFS +#define MOUNT_TYPE_UFS MOUNT_UFS +#undef MTAB_TYPE_UFS +#define MTAB_TYPE_UFS "ufs" +#define MTAB_TYPE_MFS "mfs" + +/* + * How to unmount filesystems + */ +#undef UNMOUNT_TRAP +#undef NEED_UMOUNT_FS +#define NEED_UMOUNT_BSD + +/* + * How to copy an address into an NFS filehandle + */ +#undef NFS_SA_DREF +#if BSD >= 199506 +#define NFS_SA_DREF(dst, src) { \ + (dst).addr = (struct sockaddr *) (src); \ + (dst).addrlen = sizeof(*src); \ + (dst).sotype = SOCK_DGRAM; \ + (dst).proto = 0; \ + (dst).fhsize = FHSIZE; \ + (dst).wsize = NFS_WSIZE; \ + (dst).rsize = NFS_RSIZE; \ + (dst).readdirsize = NFS_READDIRSIZE; \ + (dst).timeo = 10; \ + (dst).retrans = NFS_RETRANS; \ + (dst).maxgrouplist = NFS_MAXGRPS; \ + (dst).readahead = NFS_DEFRAHEAD; \ + (dst).leaseterm = 0; \ + (dst).deadthresh = 0; \ + } +#else +#define NFS_SA_DREF(dst, src) { \ + (dst).addr = (struct sockaddr *) (src); \ + (dst).addrlen = sizeof(*src); \ + (dst).sotype = SOCK_DGRAM; \ + (dst).proto = 0; \ + } +#endif + +/* + * Byte ordering + */ +#ifndef BYTE_ORDER +#include +#endif /* BYTE_ORDER */ + +#undef ARCH_ENDIAN +#if BYTE_ORDER == LITTLE_ENDIAN +#define ARCH_ENDIAN "little" +#else +#if BYTE_ORDER == BIG_ENDIAN +#define ARCH_ENDIAN "big" +#else +XXX - Probably no hope of running Amd on this machine! +#endif /* BIG */ +#endif /* LITTLE */ + +/* + * Miscellaneous 4.4 BSD bits + */ +#define NEED_MNTOPT_PARSER +#define SHORT_MOUNT_NAME + +#define MNTMAXSTR 128 + +#define MNTTYPE_UFS "ufs" /* Un*x file system */ +#define MNTTYPE_NFS "nfs" /* network file system */ +#define MNTTYPE_MFS "mfs" /* memory file system */ +#define MNTTYPE_IGNORE "ignore" /* No type specified, ignore this entry */ + +#define M_RDONLY MNT_RDONLY +#define M_SYNC MNT_SYNCHRONOUS +#define M_NOEXEC MNT_NOEXEC +#define M_NOSUID MNT_NOSUID +#define M_NODEV MNT_NODEV + +#define MNTOPT_SOFT "soft" /* soft mount */ +#define MNTOPT_INTR "intr" /* interrupts allowed */ + +#define NFSMNT_HOSTNAME 0 /* hostname on 4.4 is not optional */ + +struct mntent { + char *mnt_fsname; /* name of mounted file system */ + char *mnt_dir; /* file system path prefix */ + char *mnt_type; /* MNTTYPE_* */ + char *mnt_opts; /* MNTOPT* */ + int mnt_freq; /* dump frequency, in days */ + int mnt_passno; /* pass number on parallel fsck */ +}; + +/* + * Type of a file handle + */ +#undef NFS_FH_TYPE +#if BSD >= 199506 +#define NFS_FH_TYPE void * +#else +#define NFS_FH_TYPE nfsv2fh_t * +#endif + +/* + * How to get a mount list + */ +#undef READ_MTAB_FROM_FILE +#define READ_MTAB_BSD_STYLE + +/* + * The data for the mount syscall needs the path in addition to the + * host name since that is the only source of information about the + * mounted filesystem. + */ +#define NFS_ARGS_NEEDS_PATH + +/* + * 4.4 has RE support built in + */ +#undef RE_HDR +#define RE_HDR + +#if BSD >= 199506 +#undef MTYPE_TYPE +#define MTYPE_TYPE char * +#define MOUNT_NFS "nfs" +#define MOUNT_UFS "ffs" +#define MOUNT_MFS "mfs" +#endif diff --git a/usr.sbin/amd/text/INSTALL b/usr.sbin/amd/text/INSTALL new file mode 100644 index 000000000000..5cdf889ab857 --- /dev/null +++ b/usr.sbin/amd/text/INSTALL @@ -0,0 +1,194 @@ +Installation Notes for Amd. + +NOTE: Please read all of this before starting. + It is not very long and may save you time in the long term. + +1. ``Getting started...'' + +If you don't know what an Automounter does for you then read the +documentation in doc/amdref.texinfo. You can either use TeX to print +it out or read it directly using the GNU info package. + +2. ``Find out what version of UN*X you are running...'' + +To install Amd you need a port for your version of UN*X. In the +config/ directory are several files called os-*.h. One of these +should correspond to your version of UN*X. Run the program +"config/os-type" to find out what system Amd thinks you have. Check +the correspondong config/os-??? file to make sure that you and Amd are +in agreement. If os-type returns "unknown" then either no-one has yet +done a port, or your version of UN*X is so braindead that a port is +not possible (e.g. System V without reliable signals). The current +known operating systems (grouped by architecture) are: + + acis43 (AOS) ACIS 4.3BSD on an IBM RT + aix3 AIX 3.2 + aux Apple A/UX + bsd44 4.4 BSD on whatever + concentrix Concentrix on an Alliant + dgux Data General AViiON + fpx4 Celerity FPX 4.1/2 + hlh42 4.2 BSD on HLH Orion 1/05 + hpux HP-UX 6.* and 7.* on a HP9000/300 + irix3 SGI Iris + irix4 SGI Iris w/Irix 4.0.x + next NeXT + riscix 4.3 BSD on an Acorn Archimedes + sos3, sos4 SunOS 3.* and 4.* on a Sun-3 and Sun-4 + u2_2 Ultrix 2.2 (or 2.*?) on a VAX (broken) + u3_0 Ultrix 3.0 (or 3.*?) on a VAX (broken) + u4_2 Ultrix 4.2 + umax43 4.3 BSD on an Encore Multimax + xinu43 More/BSD (4.3 BSD) on a VAX or HP9000/300 + + + some others... + +If you do define a new operating system type foo, you may need to create a +file called Makefile.foo which defines the special Makefile parameters. + +3. ``Hacking the Makefile...'' + +Amd tries very hard to determine what type of machine you are using +and how best to compile itself. If this does not work then you will +have to find some heuristic which can differentiate your +configuration. You may need to edit "config/arch" and +"config/os-type". If you do make sure your changes can cope if +/etc/motd is missing and please send it to the address below. + +To check whether things are working, run: + sh config/arch + sh config/os-type + +You may care to tailor some site specific preferences in "Makefile.com". The +variables most likely to be changes are at the top. Any changes should be +added to a file called config/Makefile.local (if they are applicable to all +operating systems at your site) or Makefile.local.foo (where foo is the OS type +as determined in part 2). + +Additionally, some configuration options may be altered in +"config/Makefile.config". This means that you should not need to edit any +distributed files apart from "config/Makefile.config". As a minimum, you +should check: + +* You are using the correct C compiler. Amd, as shipped, does not use GCC. + Note that using GCC version 1.34 or later (e.g. 1.36) gives structure + passing problems with some parts of Sun's RPC library at least on Sun-4's. + The current workaround is to use the system CC to compile the part of the + automounter that gets hit by this problem. [[This is not the same problem + that is fixed by -fpcc-struct-return.]] Amd contains no "register" + declarations, so using old PCC based code generators is probably bad news. + + To use GNU CC, add the following to config/Makefile.local{.os-type}: + + CC = gcc ${GCCOPTS} + +* The installation directory (ETC) is set up correctly. + +* If you are running tests then it may be worth switching on the DEBUG flag + which will cause a running commentary to be printed to the log file. To + compile in the debug code, add the following to + config/Makefile.local{.os-type}: + + DEBUG = -DDEBUG + CCOPTS = -g + + The -g option will also allow you to use gdb. Using dbx is not advisable + since it puts a breakpoint on exit() which causes all of Amd's child + processes to dump core. gdb does not suffer from this problem. + +4. ``Build the executable...'' + +Now you need to compile the automounter. To do this you type: + + make + +in the top-level directory. You can also go into each of the program +directories and just run make there. + +If you are porting to a new machine you may want to do: + + make OS=foo + +where foo is the name of your version of UN*X as determined in part 1, until +you have made the changes to config/os-type and/or config/arch. When the +compilation is complete you will end up with a program called "A.arch_foo/amd". + +Try running: + + A.arch_foo/amd -v + +and check the output. It should look something like: + + Copyright (c) 1990 Jan-Simon Pendry + Copyright (c) 1990 Imperial College of Science, Technology & Medicine + Copyright (c) 1990 The Regents of the University of California. + amd 5.2.1.5 of 90/09/16 13:22:46 5.3Alpha5 #0: Sun Sep 16 13:23:28 BST 1990 + Built by pendry@okeeffe.Berkeley.EDU for a tahoe running bsd44 (big-endian) + Map support for: root, passwd, nis, file, error. + fstypes: ufs, nfs, nfsx, host, link, program, auto, direct, toplvl, error. + +Make sure the O/S and architecture types were correctly derived during the +build. + +5. ``Installation...'' + +If you are not just testing Amd, then you can install it by typing: + + make install + +to install "A.arch_foo/amd" in "/usr/local/etc/amd" (or as otherwise +modified in part 3). + +6. ``Update /etc/rpc'' + +Amq uses Sun RPC to talk to Amd using program number 300019 which has +been registered with Sun. Add the following lines to /etc/rpc or your +YP or Hesiod master: + +# Automount control protocol +amd 300019 amq + +Amd does not require this addition - it just keeps rpcinfo happy. + +7. ``Hanging your machine...'' + +WARNING: THIS MAY HANG YOUR MACHINE IF YOU GET IT WRONG. + +Running Amd with a carelessly thought out mount map can cause your Amd to +enter a deadlock inside the kernel. For example, attempting to automount a +directory which is automounted. This will cause the automounter to issue a mount +request causing the kernel to send an NFS request back to the same automounter, +which is currently stuck in a system call and unable to respond - even +kill -s KILL won't get you out of this one. + +There is nothing you can do to fix it without rebooting your machine, so... + +Find a diskless workstation and play with that first before trying this on +your main 200 user service machine (unless you hate your users). Something +like a diskless Sun-4 is best for development testing - you can compile on a +Sun-4 server and run the binary on the diskless node. They reboot very fast +as well between tests. + +Now you can try running Amd. Please read the documentation in doc/Amd.tex +for more details. The configuration file "maps/a_master" provides a sample for +you to play with. Something like: + + ./amd -c 40 -D test,nodaemon /tmp/amnt ../maps/a_master & + +is good for testing. Note that Amd will clean up correctly if you send it a +SIGINT or SIGTERM. Other signals are either ignored or will blow it away, +leaving your machine in a potentially dangerous state. + +Remember that Amd needs to run as root in order to do mounts/unmounts +though it does check this condition somewhere near line one of main(). +It will also need write permission in the working directory if you +have built it with DEBUG defined and your system's mount table is +reflected in a file. In this case watch out for NFS stepping in and +mapping root to nobody. + +8. ``Report what happened...'' + +If anything interesting happened, eg it didn't work, please report it to me +-- Jan-Simon Pendry -- as detailed in the README file. + +$Id: INSTALL,v 5.2.2.2 1992/05/31 16:49:22 jsp Exp $ diff --git a/usr.sbin/arp/arp.8 b/usr.sbin/arp/arp.8 new file mode 100644 index 000000000000..313aba2457b9 --- /dev/null +++ b/usr.sbin/arp/arp.8 @@ -0,0 +1,122 @@ +.\" Copyright (c) 1985, 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. +.\" +.\" @(#)arp.8 8.2 (Berkeley) 4/27/95 +.\" +.Dd April 27, 1995 +.Dt ARP 8 +.Os BSD 4.3 +.Sh NAME +.Nm arp +.Nd address resolution display and control +.Sh SYNOPSIS +.Nm arp +.Ar hostname +.Nm arp +.Fl a +.Nm arp +.Fl d Ar hostname +.Nm arp +.Fl s Ar hostname ether_addr +.Op Ar temp +.Op Ar pub +.Nm arp +.Fl f Ar filename +.Sh DESCRIPTION +The +.Nm arp +program displays and modifies the Internet-to-Ethernet address translation +tables used by the address resolution protocol +.Pq Xr arp 4 . +With no flags, the program displays the current +.Tn ARP +entry for +.Ar hostname . +The host may be specified by name or by number, +using Internet dot notation. +.Pp +Available options: +.Bl -tag -width Ds +.It Fl a +The program displays all of the current +.Tn ARP +entries. +.It Fl d +A super-user may delete an entry for the host called +.Ar hostname +with the +.Fl d +flag. +.It Fl s Ar hostname ether_addr +Create an +.Tn ARP +entry for the host called +.Ar hostname +with the Ethernet address +.Ar ether_addr . +The Ethernet address is given as six hex bytes separated by colons. +The entry will be permanent unless the word +.Ar temp +is given in the command. +If the word +.Ar pub +is given, the entry will be "published"; i.e., this system will +act as an +.Tn ARP +server, +responding to requests for +.Ar hostname +even though the host address is not its own. +.It Fl f +Causes the file +.Ar filename +to be read and multiple entries to be set in the +.Tn ARP +tables. Entries +in the file should be of the form +.Pp +.Bd -filled -offset indent -compact +.Ar hostname ether_addr +.Op Ar temp +.Op Ar pub +.Ed +.Pp +with argument meanings as given above. +.El +.Sh SEE ALSO +.Xr inet 3 , +.Xr arp 4 , +.Xr ifconfig 8 +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.3 . diff --git a/usr.sbin/arp/arp.c b/usr.sbin/arp/arp.c new file mode 100644 index 000000000000..4ab7177138ab --- /dev/null +++ b/usr.sbin/arp/arp.c @@ -0,0 +1,531 @@ +/* + * Copyright (c) 1984, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Sun Microsystems, Inc. + * + * 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) 1984, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)arp.c 8.3 (Berkeley) 4/28/95"; +#endif /* not lint */ + +/* + * arp - display, set, and delete arp table entries + */ + + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int pid; +static int nflag; +static int s = -1; + +int delete __P((char *, char *)); +void dump __P((u_long)); +int ether_aton __P((char *, u_char *)); +void ether_print __P((u_char *)); +int file __P((char *)); +void get __P((char *)); +void getsocket __P((void)); +int rtmsg __P((int)); +int set __P((int, char **)); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char **argv; +{ + int ch; + + pid = getpid(); + while ((ch = getopt(argc, argv, "ands")) != EOF) + switch((char)ch) { + case 'a': + dump(0); + exit(0); + case 'd': + if (argc < 3 || argc > 4) + usage(); + delete(argv[2], argv[3]); + exit(0); + case 'n': + nflag = 1; + continue; + case 's': + if (argc < 4 || argc > 7) + usage(); + exit(set(argc-2, &argv[2]) ? 1 : 0); + case '?': + default: + usage(); + } + if (argc != 2) + usage(); + get(argv[1]); + return (0); +} + +/* + * Process a file to set standard arp entries + */ +int +file(name) + char *name; +{ + FILE *fp; + int i, retval; + char line[100], arg[5][50], *args[5]; + + if ((fp = fopen(name, "r")) == NULL) { + fprintf(stderr, "arp: cannot open %s\n", name); + exit(1); + } + args[0] = &arg[0][0]; + args[1] = &arg[1][0]; + args[2] = &arg[2][0]; + args[3] = &arg[3][0]; + args[4] = &arg[4][0]; + retval = 0; + while(fgets(line, 100, fp) != NULL) { + i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2], + arg[3], arg[4]); + if (i < 2) { + fprintf(stderr, "arp: bad line: %s\n", line); + retval = 1; + continue; + } + if (set(i, args)) + retval = 1; + } + fclose(fp); + return (retval); +} + +void +getsocket() { + if (s < 0) { + s = socket(PF_ROUTE, SOCK_RAW, 0); + if (s < 0) { + perror("arp: socket"); + exit(1); + } + } +} + +struct sockaddr_in so_mask = {8, 0, 0, { 0xffffffff}}; +struct sockaddr_inarp blank_sin = {sizeof(blank_sin), AF_INET }, sin_m; +struct sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m; +int expire_time, flags, export_only, doing_proxy, found_entry; +struct { + struct rt_msghdr m_rtm; + char m_space[512]; +} m_rtmsg; + +/* + * Set an individual arp entry + */ +int +set(argc, argv) + int argc; + char **argv; +{ + struct hostent *hp; + register struct sockaddr_inarp *sin = &sin_m; + register struct sockaddr_dl *sdl; + register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm); + u_char *ea; + char *host = argv[0], *eaddr = argv[1]; + + getsocket(); + argc -= 2; + argv += 2; + sdl_m = blank_sdl; + sin_m = blank_sin; + sin->sin_addr.s_addr = inet_addr(host); + if (sin->sin_addr.s_addr == -1) { + if (!(hp = gethostbyname(host))) { + fprintf(stderr, "arp: %s: ", host); + herror((char *)NULL); + return (1); + } + bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, + sizeof sin->sin_addr); + } + ea = (u_char *)LLADDR(&sdl_m); + if (ether_aton(eaddr, ea) == 0) + sdl_m.sdl_alen = 6; + doing_proxy = flags = export_only = expire_time = 0; + while (argc-- > 0) { + if (strncmp(argv[0], "temp", 4) == 0) { + struct timeval time; + gettimeofday(&time, 0); + expire_time = time.tv_sec + 20 * 60; + } + else if (strncmp(argv[0], "pub", 3) == 0) { + flags |= RTF_ANNOUNCE; + doing_proxy = SIN_PROXY; + } else if (strncmp(argv[0], "trail", 5) == 0) { + printf("%s: Sending trailers is no longer supported\n", + host); + } + argv++; + } +tryagain: + if (rtmsg(RTM_GET) < 0) { + perror(host); + return (1); + } + sin = (struct sockaddr_inarp *)(rtm + 1); + sdl = (struct sockaddr_dl *)(sin->sin_len + (char *)sin); + if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) { + if (sdl->sdl_family == AF_LINK && + (rtm->rtm_flags & RTF_LLINFO) && + !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) { + case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: + case IFT_ISO88024: case IFT_ISO88025: + goto overwrite; + } + if (doing_proxy == 0) { + printf("set: can only proxy for %s\n", host); + return (1); + } + if (sin_m.sin_other & SIN_PROXY) { + printf("set: proxy entry exists for non 802 device\n"); + return(1); + } + sin_m.sin_other = SIN_PROXY; + export_only = 1; + goto tryagain; + } +overwrite: + if (sdl->sdl_family != AF_LINK) { + printf("cannot intuit interface index and type for %s\n", host); + return (1); + } + sdl_m.sdl_type = sdl->sdl_type; + sdl_m.sdl_index = sdl->sdl_index; + return (rtmsg(RTM_ADD)); +} + +/* + * Display an individual arp entry + */ +void +get(host) + char *host; +{ + struct hostent *hp; + struct sockaddr_inarp *sin = &sin_m; + + sin_m = blank_sin; + sin->sin_addr.s_addr = inet_addr(host); + if (sin->sin_addr.s_addr == -1) { + if (!(hp = gethostbyname(host))) { + fprintf(stderr, "arp: %s: ", host); + herror((char *)NULL); + exit(1); + } + bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, + sizeof sin->sin_addr); + } + dump(sin->sin_addr.s_addr); + if (found_entry == 0) { + printf("%s (%s) -- no entry\n", + host, inet_ntoa(sin->sin_addr)); + exit(1); + } +} + +/* + * Delete an arp entry + */ +int +delete(host, info) + char *host; + char *info; +{ + struct hostent *hp; + register struct sockaddr_inarp *sin = &sin_m; + register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; + struct sockaddr_dl *sdl; + + if (info && strncmp(info, "pro", 3) ) + export_only = 1; + getsocket(); + sin_m = blank_sin; + sin->sin_addr.s_addr = inet_addr(host); + if (sin->sin_addr.s_addr == -1) { + if (!(hp = gethostbyname(host))) { + fprintf(stderr, "arp: %s: ", host); + herror((char *)NULL); + return (1); + } + bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, + sizeof sin->sin_addr); + } +tryagain: + if (rtmsg(RTM_GET) < 0) { + perror(host); + return (1); + } + sin = (struct sockaddr_inarp *)(rtm + 1); + sdl = (struct sockaddr_dl *)(sin->sin_len + (char *)sin); + if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) { + if (sdl->sdl_family == AF_LINK && + (rtm->rtm_flags & RTF_LLINFO) && + !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) { + case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: + case IFT_ISO88024: case IFT_ISO88025: + goto delete; + } + } + if (sin_m.sin_other & SIN_PROXY) { + fprintf(stderr, "delete: can't locate %s\n",host); + return (1); + } else { + sin_m.sin_other = SIN_PROXY; + goto tryagain; + } +delete: + if (sdl->sdl_family != AF_LINK) { + printf("cannot locate %s\n", host); + return (1); + } + if (rtmsg(RTM_DELETE)) + return (1); + printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr)); + return (0); +} + +/* + * Dump the entire arp table + */ +void +dump(addr) + u_long addr; +{ + int mib[6]; + size_t needed; + char *host, *lim, *buf, *next; + struct rt_msghdr *rtm; + struct sockaddr_inarp *sin; + struct sockaddr_dl *sdl; + extern int h_errno; + struct hostent *hp; + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = AF_INET; + mib[4] = NET_RT_FLAGS; + mib[5] = RTF_LLINFO; + if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) + err(1, "route-sysctl-estimate"); + if ((buf = malloc(needed)) == NULL) + err(1, "malloc"); + if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) + err(1, "actual retrieval of routing table"); + lim = buf + needed; + for (next = buf; next < lim; next += rtm->rtm_msglen) { + rtm = (struct rt_msghdr *)next; + sin = (struct sockaddr_inarp *)(rtm + 1); + sdl = (struct sockaddr_dl *)(sin + 1); + if (addr) { + if (addr != sin->sin_addr.s_addr) + continue; + found_entry = 1; + } + if (nflag == 0) + hp = gethostbyaddr((caddr_t)&(sin->sin_addr), + sizeof sin->sin_addr, AF_INET); + else + hp = 0; + if (hp) + host = hp->h_name; + else { + host = "?"; + if (h_errno == TRY_AGAIN) + nflag = 1; + } + printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr)); + if (sdl->sdl_alen) + ether_print((u_char *)LLADDR(sdl)); + else + printf("(incomplete)"); + if (rtm->rtm_rmx.rmx_expire == 0) + printf(" permanent"); + if (sin->sin_other & SIN_PROXY) + printf(" published (proxy only)"); + if (rtm->rtm_addrs & RTA_NETMASK) { + sin = (struct sockaddr_inarp *) + (sdl->sdl_len + (char *)sdl); + if (sin->sin_addr.s_addr == 0xffffffff) + printf(" published"); + if (sin->sin_len != 8) + printf("(wierd)"); + } + printf("\n"); + } +} + +void +ether_print(cp) + u_char *cp; +{ + printf("%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); +} + +int +ether_aton(a, n) + char *a; + u_char *n; +{ + int i, o[6]; + + i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], + &o[3], &o[4], &o[5]); + if (i != 6) { + fprintf(stderr, "arp: invalid Ethernet address '%s'\n", a); + return (1); + } + for (i=0; i<6; i++) + n[i] = o[i]; + return (0); +} + +void +usage() +{ + printf("usage: arp hostname\n"); + printf(" arp -a [kernel] [kernel_memory]\n"); + printf(" arp -d hostname\n"); + printf(" arp -s hostname ether_addr [temp] [pub]\n"); + printf(" arp -f filename\n"); + exit(1); +} + +int +rtmsg(cmd) + int cmd; +{ + static int seq; + int rlen; + register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; + register char *cp = m_rtmsg.m_space; + register int l; + + errno = 0; + if (cmd == RTM_DELETE) + goto doit; + bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); + rtm->rtm_flags = flags; + rtm->rtm_version = RTM_VERSION; + + switch (cmd) { + default: + fprintf(stderr, "arp: internal wrong cmd\n"); + exit(1); + case RTM_ADD: + rtm->rtm_addrs |= RTA_GATEWAY; + rtm->rtm_rmx.rmx_expire = expire_time; + rtm->rtm_inits = RTV_EXPIRE; + rtm->rtm_flags |= (RTF_HOST | RTF_STATIC); + sin_m.sin_other = 0; + if (doing_proxy) { + if (export_only) + sin_m.sin_other = SIN_PROXY; + else { + rtm->rtm_addrs |= RTA_NETMASK; + rtm->rtm_flags &= ~RTF_HOST; + } + } + /* FALLTHROUGH */ + case RTM_GET: + rtm->rtm_addrs |= RTA_DST; + } +#define NEXTADDR(w, s) \ + if (rtm->rtm_addrs & (w)) { \ + bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);} + + NEXTADDR(RTA_DST, sin_m); + NEXTADDR(RTA_GATEWAY, sdl_m); + NEXTADDR(RTA_NETMASK, so_mask); + + rtm->rtm_msglen = cp - (char *)&m_rtmsg; +doit: + l = rtm->rtm_msglen; + rtm->rtm_seq = ++seq; + rtm->rtm_type = cmd; + if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { + if (errno != ESRCH || cmd != RTM_DELETE) { + perror("writing to routing socket"); + return (-1); + } + } + do { + l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); + } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid)); + if (l < 0) + (void) fprintf(stderr, "arp: read from routing socket: %s\n", + strerror(errno)); + return (0); +} diff --git a/usr.sbin/arp/arp4.4 b/usr.sbin/arp/arp4.4 new file mode 100644 index 000000000000..0cd716145005 --- /dev/null +++ b/usr.sbin/arp/arp4.4 @@ -0,0 +1,124 @@ +.\" Copyright (c) 1985, 1986, 1988, 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. +.\" +.\" @(#)arp4.4 6.5 (Berkeley) 4/18/94 +.\" +.Dd April 18, 1994 +.Dt ARP 4 +.Os BSD 4 +.Sh NAME +.Nm arp +.Nd Address Resolution Protocol +.Sh SYNOPSIS +.Em "pseudo-device ether" +.Sh DESCRIPTION +The Address Resolution Protocol (ARP) is a protocol used to dynamically +map between Internet host addresses and 10Mb/s Ethernet addresses. +It is used by all the 10Mb/s Ethernet interface drivers. +It is not specific to Internet protocols or to 10Mb/s Ethernet, +but this implementation currently supports only that combination. +.Pp +ARP caches Internet-Ethernet address mappings. +When an interface requests a mapping for an address not in the cache, +ARP queues the message which requires the mapping and broadcasts +a message on the associated network requesting the address mapping. +If a response is provided, the new mapping is cached and any pending +message is transmitted. +ARP will queue at most one packet while waiting for a response to a +mapping request; +only the most recently ``transmitted'' packet is kept. +If the target host does not respond after several requests, +the host is considered to be down for a short period (normally 20 seconds), +allowing an error to be returned to transmission attempts during this +interval. +The error is +.Li EHOSTDOWN +for a non-responding destination host, and +.Li EHOSTUNREACH +for a non-responding router. +.Pp +The ARP cache is stored in the system routing table as +dynamically-created host routes. +The route to a directly-attached Ethernet network is installed as a +.Dq cloning +route (one with the +.Li RTF_CLONING +flag set), +causing routes to individual hosts on that network to be created on +demand. +These routes time out periodically (normally 20 minutes after validated; +entries are not validated when not in use). +An entry for a host which is not responding is a +.Dq reject +route (one with the +.Li RTF_REJECT +flag set). +.Pp +ARP entries may be added, deleted or changed with the +.Xr arp 8 +utility. +Manually-added entries may be temporary or permanent, +and may be +.Dq published , +in which case the system will respond to ARP requests for that host +as if it were the target of the request. +.Pp +In the past, +ARP was used to negotiate the use of a trailer encapsulation. +This is no longer supported. +.Pp +ARP watches passively for hosts impersonating the local host (i.e. a host +which responds to an ARP mapping request for the local host's address). +.Sh DIAGNOSTICS +.Em "duplicate IP address %x!! sent from ethernet address: %x:%x:%x:%x:%x:%x." +ARP has discovered another host on the local network which responds to +mapping requests for its own Internet address with a different Ethernet +address, generally indicating that two hosts are attempting to use the +same Internet address. +.Sh SEE ALSO +.Xr inet 4 , +.Xr route 4 , +.Xr arp 8 , +.Xr ifconfig 8 , +.Xr route 8 +.sp +.Rs +.%A Plummer, D. +.%B "An Ethernet Address Resolution Protocol" +.%T RFC826 +.Re +.Rs +.%A Leffler, S.J. +.%A Karels, M.J. +.%B "Trailer Encapsulations +.%T RFC893 +.Re + diff --git a/usr.sbin/bad144/bad144.c b/usr.sbin/bad144/bad144.c new file mode 100644 index 000000000000..aa9f631a1c6a --- /dev/null +++ b/usr.sbin/bad144/bad144.c @@ -0,0 +1,662 @@ +/* + * Copyright (c) 1980, 1986, 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) 1980, 1986, 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif not lint + +#ifndef lint +static char sccsid[] = "@(#)bad144.c 8.2 (Berkeley) 4/27/95"; +#endif not lint + +/* + * bad144 + * + * This program prints and/or initializes a bad block record for a pack, + * in the format used by the DEC standard 144. + * It can also add bad sector(s) to the record, moving the sector + * replacements as necessary. + * + * It is preferable to write the bad information with a standard formatter, + * but this program will do. + * + * RP06 sectors are marked as bad by inverting the format bit in the + * header; on other drives the valid-sector bit is cleared. + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#define RETRIES 10 /* number of retries on reading old sectors */ +#define RAWPART "c" /* disk partition containing badsector tables */ + +int fflag, add, copy, verbose, nflag; +int compare(); +int dups; +int badfile = -1; /* copy of badsector table to use, -1 if any */ +#define MAXSECSIZE 1024 +struct dkbad curbad, oldbad; +#define DKBAD_MAGIC 0 + +char label[BBSIZE]; +daddr_t size, getold(), badsn(); +struct disklabel *dp; +char name[BUFSIZ]; +char *malloc(); +off_t lseek(); + +main(argc, argv) + int argc; + char *argv[]; +{ + register struct bt_bad *bt; + daddr_t sn, bn[126]; + int i, f, nbad, new, bad, errs; + + argc--, argv++; + while (argc > 0 && **argv == '-') { + (*argv)++; + while (**argv) { + switch (**argv) { +#if vax + case 'f': + fflag++; + break; +#endif + case 'a': + add++; + break; + case 'c': + copy++; + break; + case 'v': + verbose++; + break; + case 'n': + nflag++; + verbose++; + break; + default: + if (**argv >= '0' && **argv <= '4') { + badfile = **argv - '0'; + break; + } + goto usage; + } + (*argv)++; + } + argc--, argv++; + } + if (argc < 1) { +usage: + fprintf(stderr, + "usage: bad144 [ -f ] disk [ snum [ bn ... ] ]\n"); + fprintf(stderr, + "to read or overwrite bad-sector table, e.g.: bad144 hp0\n"); + fprintf(stderr, + "or bad144 -a [ -f ] [ -c ] disk bn ...\n"); + fprintf(stderr, "where options are:\n"); + fprintf(stderr, "\t-a add new bad sectors to the table\n"); + fprintf(stderr, "\t-f reformat listed sectors as bad\n"); + fprintf(stderr, "\t-c copy original sector to replacement\n"); + exit(1); + } + if (argv[0][0] != '/') + (void)sprintf(name, "%s/r%s%s", _PATH_DEV, argv[0], RAWPART); + else + strcpy(name, argv[0]); + f = open(name, argc == 1? O_RDONLY : O_RDWR); + if (f < 0) + Perror(name); + if (read(f, label, sizeof(label)) < 0) + Perror("read"); + for (dp = (struct disklabel *)(label + LABELOFFSET); + dp < (struct disklabel *) + (label + sizeof(label) - sizeof(struct disklabel)); + dp = (struct disklabel *)((char *)dp + 64)) + if (dp->d_magic == DISKMAGIC && dp->d_magic2 == DISKMAGIC) + break; + if (dp->d_magic != DISKMAGIC || dp->d_magic2 != DISKMAGIC) { + fprintf(stderr, "Bad pack magic number (pack is unlabeled)\n"); + exit(1); + } + if (dp->d_secsize > MAXSECSIZE || dp->d_secsize <= 0) { + fprintf(stderr, "Disk sector size too large/small (%d)\n", + dp->d_secsize); + exit(7); + } + size = dp->d_nsectors * dp->d_ntracks * dp->d_ncylinders; + argc--; + argv++; + if (argc == 0) { + sn = getold(f, &oldbad); + printf("bad block information at sector %d in %s:\n", + sn, name); + printf("cartridge serial number: %d(10)\n", oldbad.bt_csn); + switch (oldbad.bt_flag) { + + case (u_short)-1: + printf("alignment cartridge\n"); + break; + + case DKBAD_MAGIC: + break; + + default: + printf("bt_flag=%x(16)?\n", oldbad.bt_flag); + break; + } + bt = oldbad.bt_bad; + for (i = 0; i < 126; i++) { + bad = (bt->bt_cyl<<16) + bt->bt_trksec; + if (bad < 0) + break; + printf("sn=%d, cn=%d, tn=%d, sn=%d\n", badsn(bt), + bt->bt_cyl, bt->bt_trksec>>8, bt->bt_trksec&0xff); + bt++; + } + (void) checkold(&oldbad); + exit(0); + } + if (add) { + /* + * Read in the old badsector table. + * Verify that it makes sense, and the bad sectors + * are in order. Copy the old table to the new one. + */ + (void) getold(f, &oldbad); + i = checkold(&oldbad); + if (verbose) + printf("Had %d bad sectors, adding %d\n", i, argc); + if (i + argc > 126) { + printf("bad144: not enough room for %d more sectors\n", + argc); + printf("limited to 126 by information format\n"); + exit(1); + } + curbad = oldbad; + } else { + curbad.bt_csn = atoi(*argv++); + argc--; + curbad.bt_mbz = 0; + curbad.bt_flag = DKBAD_MAGIC; + if (argc > 126) { + printf("bad144: too many bad sectors specified\n"); + printf("limited to 126 by information format\n"); + exit(1); + } + i = 0; + } + errs = 0; + new = argc; + while (argc > 0) { + daddr_t sn = atoi(*argv++); + argc--; + if (sn < 0 || sn >= size) { + printf("%d: out of range [0,%d) for disk %s\n", + sn, size, dp->d_typename); + errs++; + continue; + } + bn[i] = sn; + curbad.bt_bad[i].bt_cyl = sn / (dp->d_nsectors*dp->d_ntracks); + sn %= (dp->d_nsectors*dp->d_ntracks); + curbad.bt_bad[i].bt_trksec = + ((sn/dp->d_nsectors) << 8) + (sn%dp->d_nsectors); + i++; + } + if (errs) + exit(1); + nbad = i; + while (i < 126) { + curbad.bt_bad[i].bt_trksec = -1; + curbad.bt_bad[i].bt_cyl = -1; + i++; + } + if (add) { + /* + * Sort the new bad sectors into the list. + * Then shuffle the replacement sectors so that + * the previous bad sectors get the same replacement data. + */ + qsort((char *)curbad.bt_bad, nbad, sizeof (struct bt_bad), + compare); + if (dups) { + fprintf(stderr, +"bad144: bad sectors have been duplicated; can't add existing sectors\n"); + exit(3); + } + shift(f, nbad, nbad-new); + } + if (badfile == -1) + i = 0; + else + i = badfile * 2; + for (; i < 10 && i < dp->d_nsectors; i += 2) { + if (lseek(f, dp->d_secsize * (size - dp->d_nsectors + i), + L_SET) < 0) + Perror("lseek"); + if (verbose) + printf("write badsect file at %d\n", + size - dp->d_nsectors + i); + if (nflag == 0 && write(f, (caddr_t)&curbad, sizeof(curbad)) != + sizeof(curbad)) { + char msg[80]; + (void)sprintf(msg, "bad144: write bad sector file %d", + i/2); + perror(msg); + } + if (badfile != -1) + break; + } +#ifdef vax + if (nflag == 0 && fflag) + for (i = nbad - new; i < nbad; i++) + format(f, bn[i]); +#endif +#ifdef DIOCSBAD + if (nflag == 0 && ioctl(f, DIOCSBAD, (caddr_t)&curbad) < 0) + fprintf(stderr, + "Can't sync bad-sector file; reboot for changes to take effect\n"); +#endif + exit(0); +} + +daddr_t +getold(f, bad) +struct dkbad *bad; +{ + register int i; + daddr_t sn; + char msg[80]; + + if (badfile == -1) + i = 0; + else + i = badfile * 2; + for (; i < 10 && i < dp->d_nsectors; i += 2) { + sn = size - dp->d_nsectors + i; + if (lseek(f, sn * dp->d_secsize, L_SET) < 0) + Perror("lseek"); + if (read(f, (char *) bad, dp->d_secsize) == dp->d_secsize) { + if (i > 0) + printf("Using bad-sector file %d\n", i/2); + return(sn); + } + (void)sprintf(msg, "bad144: read bad sector file at sn %d", sn); + perror(msg); + if (badfile != -1) + break; + } + fprintf(stderr, "bad144: %s: can't read bad block info\n", name); + exit(1); + /*NOTREACHED*/ +} + +checkold() +{ + register int i; + register struct bt_bad *bt; + daddr_t sn, lsn; + int errors = 0, warned = 0; + + if (oldbad.bt_flag != DKBAD_MAGIC) { + fprintf(stderr, "bad144: %s: bad flag in bad-sector table\n", + name); + errors++; + } + if (oldbad.bt_mbz != 0) { + fprintf(stderr, "bad144: %s: bad magic number\n", name); + errors++; + } + bt = oldbad.bt_bad; + for (i = 0; i < 126; i++, bt++) { + if (bt->bt_cyl == 0xffff && bt->bt_trksec == 0xffff) + break; + if ((bt->bt_cyl >= dp->d_ncylinders) || + ((bt->bt_trksec >> 8) >= dp->d_ntracks) || + ((bt->bt_trksec & 0xff) >= dp->d_nsectors)) { + fprintf(stderr, + "bad144: cyl/trk/sect out of range in existing entry: "); + fprintf(stderr, "sn=%d, cn=%d, tn=%d, sn=%d\n", + badsn(bt), bt->bt_cyl, bt->bt_trksec>>8, + bt->bt_trksec & 0xff); + errors++; + } + sn = (bt->bt_cyl * dp->d_ntracks + + (bt->bt_trksec >> 8)) * + dp->d_nsectors + (bt->bt_trksec & 0xff); + if (i > 0 && sn < lsn && !warned) { + fprintf(stderr, + "bad144: bad sector file is out of order\n"); + errors++; + warned++; + } + if (i > 0 && sn == lsn) { + fprintf(stderr, + "bad144: bad sector file contains duplicates (sn %d)\n", + sn); + errors++; + } + lsn = sn; + } + if (errors) + exit(1); + return (i); +} + +/* + * Move the bad sector replacements + * to make room for the new bad sectors. + * new is the new number of bad sectors, old is the previous count. + */ +shift(f, new, old) +{ + daddr_t repl; + + /* + * First replacement is last sector of second-to-last track. + */ + repl = size - dp->d_nsectors - 1; + new--; old--; + while (new >= 0 && new != old) { + if (old < 0 || + compare(&curbad.bt_bad[new], &oldbad.bt_bad[old]) > 0) { + /* + * Insert new replacement here-- copy original + * sector if requested and possible, + * otherwise write a zero block. + */ + if (!copy || + !blkcopy(f, badsn(&curbad.bt_bad[new]), repl - new)) + blkzero(f, repl - new); + } else { + if (blkcopy(f, repl - old, repl - new) == 0) + fprintf(stderr, + "Can't copy replacement sector %d to %d\n", + repl-old, repl-new); + old--; + } + new--; + } +} + +char *buf; + +/* + * Copy disk sector s1 to s2. + */ +blkcopy(f, s1, s2) +daddr_t s1, s2; +{ + register tries, n; + + if (buf == (char *)NULL) { + buf = malloc((unsigned)dp->d_secsize); + if (buf == (char *)NULL) { + fprintf(stderr, "Out of memory\n"); + exit(20); + } + } + for (tries = 0; tries < RETRIES; tries++) { + if (lseek(f, dp->d_secsize * s1, L_SET) < 0) + Perror("lseek"); + if ((n = read(f, buf, dp->d_secsize)) == dp->d_secsize) + break; + } + if (n != dp->d_secsize) { + fprintf(stderr, "bad144: can't read sector, %d: ", s1); + if (n < 0) + perror((char *)0); + return(0); + } + if (lseek(f, dp->d_secsize * s2, L_SET) < 0) + Perror("lseek"); + if (verbose) + printf("copying %d to %d\n", s1, s2); + if (nflag == 0 && write(f, buf, dp->d_secsize) != dp->d_secsize) { + fprintf(stderr, + "bad144: can't write replacement sector, %d: ", s2); + perror((char *)0); + return(0); + } + return(1); +} + +char *zbuf; + +blkzero(f, sn) +daddr_t sn; +{ + + if (zbuf == (char *)NULL) { + zbuf = malloc((unsigned)dp->d_secsize); + if (zbuf == (char *)NULL) { + fprintf(stderr, "Out of memory\n"); + exit(20); + } + } + if (lseek(f, dp->d_secsize * sn, L_SET) < 0) + Perror("lseek"); + if (verbose) + printf("zeroing %d\n", sn); + if (nflag == 0 && write(f, zbuf, dp->d_secsize) != dp->d_secsize) { + fprintf(stderr, + "bad144: can't write replacement sector, %d: ", sn); + perror((char *)0); + } +} + +compare(b1, b2) +register struct bt_bad *b1, *b2; +{ + if (b1->bt_cyl > b2->bt_cyl) + return(1); + if (b1->bt_cyl < b2->bt_cyl) + return(-1); + if (b1->bt_trksec == b2->bt_trksec) + dups++; + return (b1->bt_trksec - b2->bt_trksec); +} + +daddr_t +badsn(bt) +register struct bt_bad *bt; +{ + return ((bt->bt_cyl*dp->d_ntracks + (bt->bt_trksec>>8)) * dp->d_nsectors + + (bt->bt_trksec&0xff)); +} + +#ifdef vax + +struct rp06hdr { + short h_cyl; + short h_trksec; + short h_key1; + short h_key2; + char h_data[512]; +#define RP06_FMT 010000 /* 1 == 16 bit, 0 == 18 bit */ +}; + +/* + * Most massbus and unibus drives + * have headers of this form + */ +struct hpuphdr { + u_short hpup_cyl; + u_char hpup_sect; + u_char hpup_track; + char hpup_data[512]; +#define HPUP_OKSECT 0xc000 /* this normally means sector is good */ +#define HPUP_16BIT 0x1000 /* 1 == 16 bit format */ +}; +int rp06format(), hpupformat(); + +struct formats { + char *f_name; /* disk name */ + int f_bufsize; /* size of sector + header */ + int f_bic; /* value to bic in hpup_cyl */ + int (*f_routine)(); /* routine for special handling */ +} formats[] = { + { "rp06", sizeof (struct rp06hdr), RP06_FMT, rp06format }, + { "eagle", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, + { "capricorn", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, + { "rm03", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, + { "rm05", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, + { "9300", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, + { "9766", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, + { 0, 0, 0, 0 } +}; + +/*ARGSUSED*/ +hpupformat(fp, dp, blk, buf, count) + struct formats *fp; + struct disklabel *dp; + daddr_t blk; + char *buf; + int count; +{ + struct hpuphdr *hdr = (struct hpuphdr *)buf; + int sect; + + if (count < sizeof(struct hpuphdr)) { + hdr->hpup_cyl = (HPUP_OKSECT | HPUP_16BIT) | + (blk / (dp->d_nsectors * dp->d_ntracks)); + sect = blk % (dp->d_nsectors * dp->d_ntracks); + hdr->hpup_track = (u_char)(sect / dp->d_nsectors); + hdr->hpup_sect = (u_char)(sect % dp->d_nsectors); + } + return (0); +} + +/*ARGSUSED*/ +rp06format(fp, dp, blk, buf, count) + struct formats *fp; + struct disklabel *dp; + daddr_t blk; + char *buf; + int count; +{ + + if (count < sizeof(struct rp06hdr)) { + fprintf(stderr, "Can't read header on blk %d, can't reformat\n", + blk); + return (-1); + } + return (0); +} + +format(fd, blk) + int fd; + daddr_t blk; +{ + register struct formats *fp; + static char *buf; + static char bufsize; + struct format_op fop; + int n; + + for (fp = formats; fp->f_name; fp++) + if (strcmp(dp->d_typename, fp->f_name) == 0) + break; + if (fp->f_name == 0) { + fprintf(stderr, "bad144: don't know how to format %s disks\n", + dp->d_typename); + exit(2); + } + if (buf && bufsize < fp->f_bufsize) { + free(buf); + buf = NULL; + } + if (buf == NULL) + buf = malloc((unsigned)fp->f_bufsize); + if (buf == NULL) { + fprintf(stderr, "bad144: can't allocate sector buffer\n"); + exit(3); + } + bufsize = fp->f_bufsize; + /* + * Here we do the actual formatting. All we really + * do is rewrite the sector header and flag the bad sector + * according to the format table description. If a special + * purpose format routine is specified, we allow it to + * process the sector as well. + */ + if (verbose) + printf("format blk %d\n", blk); + bzero((char *)&fop, sizeof(fop)); + fop.df_buf = buf; + fop.df_count = fp->f_bufsize; + fop.df_startblk = blk; + bzero(buf, fp->f_bufsize); + if (ioctl(fd, DIOCRFORMAT, &fop) < 0) + perror("bad144: read format"); + if (fp->f_routine && + (*fp->f_routine)(fp, dp, blk, buf, fop.df_count) != 0) + return; + if (fp->f_bic) { + struct hpuphdr *xp = (struct hpuphdr *)buf; + + xp->hpup_cyl &= ~fp->f_bic; + } + if (nflag) + return; + bzero((char *)&fop, sizeof(fop)); + fop.df_buf = buf; + fop.df_count = fp->f_bufsize; + fop.df_startblk = blk; + if (ioctl(fd, DIOCWFORMAT, &fop) < 0) + Perror("write format"); + if (fop.df_count != fp->f_bufsize) { + char msg[80]; + (void)sprintf(msg, "bad144: write format %d", blk); + perror(msg); + } +} +#endif + +Perror(op) + char *op; +{ + + fprintf(stderr, "bad144: "); perror(op); + exit(4); +} diff --git a/usr.sbin/config.new/Makefile b/usr.sbin/config.new/Makefile new file mode 100644 index 000000000000..aec467b07b4c --- /dev/null +++ b/usr.sbin/config.new/Makefile @@ -0,0 +1,12 @@ +# @(#)Makefile 8.3 (Berkeley) 5/29/94 + +PROG= config +SRCS= files.c gram.y hash.c main.c mkheaders.c mkioconf.c mkmakefile.c \ + mkswap.c pack.c scan.l sem.c util.c +CFLAGS+=-I${.CURDIR} -I. +CLEANFILES=gram.c scan.c y.tab.h +MAN8= config.0 + +.include + +.depend: gram.c scan.c diff --git a/usr.sbin/config.new/config.8 b/usr.sbin/config.new/config.8 new file mode 100644 index 000000000000..5eae8d34f554 --- /dev/null +++ b/usr.sbin/config.new/config.8 @@ -0,0 +1,167 @@ +.\" 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. +.\" +.\" @(#)config.8 8.2 (Berkeley) 4/19/94 +.\" +.Dd April 19, 1994 +.Dt CONFIG.NEW 8 +.Os BSD 4 +.Sh NAME +.Nm config.new +.Nd build kernel compilation directories +.Sh SYNOPSIS +.Nm config +.Op Fl p +.Ar system-name +.Sh DESCRIPTION +.Pp +This is the new version of the +.Nm config +program. +It understands the more modern autoconfiguration scheme +used on the SPARC and i386 platforms. +The old version of config is still used with the +HP300, DECstation, and derivative platforms. +Only the version of +.Nm config +applicable to the architecture that you are running +will be installed on your machine. +.Pp +.Nm Config +builds a set of configuration files from the file +.Ar system-name , +which describes +the system to configure. +.Pp +.Nm Config +should run from the +.Pa conf +subdirectory of the top-level machine-specific directory +of the system source (usually +.Pa /sys/MACHINE/conf , +where +.Pa MACHINE +is one of +.Pa vax , +.Pa tahoe , +.Pa hp300 , +and so forth). +.Nm Config +assumes the directory +.Pa ../../compile +exists; it places all output files in a subdirectory there, +creating the subdirectory if necessary. +The subdirectory name is taken from the +.Ar system-name ; +thus, configuring with +.Dq Li config PICKLE +will use the directory +.Pa ../../compile/PICKLE . +.Pp +If the +.Fl p +option is supplied, +.Pa .PROF +is appended to the compilation directory name, and +.Nm config +acts as if the lines +.Dq Li makeoptions PROF="-pg" +and +.Dq Li options GPROF +appeared in the configuration file. +This will build a system that includes profiling code; see +.Xr kgmon 8 +and +.Xr gprof 1 . +The +.Fl p +flag is expected to be used for +.Dq one-shot +profiles of existing systems; +for regular profiling, +it is probably wiser to make a separate configuration +containing the +.Li makeoptions +line. +.Pp +The old undocumented +.Fl g +flag is no longer supported. +Instead, use +.Dq Li makeoptions DEBUG="-g" +and (typically) +.Dq Li options KGDB . +.Pp +The output of +.Nm config +consists of a number of files, principally +.Pa ioconf.c , +a description of I/O devices that may be attached to the system; and a +.Pa Makefile , +used by +.Xr make 1 +in building the kernel. +.Pp +After running +.Nm config , +it is wise to run +.Dq Li make depend +in the directory where the new makefile +was created. +.Nm Config +prints a reminder of this when it completes. +.Pp +If +.Nm config +stops due to errors, the problems reported should be corrected and +.Nm config +should be run again. +.Nm Config +attempts to avoid changing the compilation directory +if there are configuration errors, +but this code is not well-tested, +and some problems (such as running out of disk space) +are unrecoverable. +.Sh SEE ALSO +The SYNOPSIS portion of each device in section 4. +.Rs +.%T "Building 4.4 BSD Systems with Config" +.\" .%T "Device Support in 4.4BSD" +.Re +.sp +.Xr config 8 +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.1 . +It was completely revised in +.Bx 4.4 . diff --git a/usr.sbin/diskpart/diskpart.c b/usr.sbin/diskpart/diskpart.c new file mode 100644 index 000000000000..3732f768e40e --- /dev/null +++ b/usr.sbin/diskpart/diskpart.c @@ -0,0 +1,476 @@ +/* + * Copyright (c) 1983, 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) 1983, 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)diskpart.c 8.3 (Berkeley) 11/30/94"; +#endif /* not lint */ + +/* + * Program to calculate standard disk partition sizes. + */ +#include +#define DKTYPENAMES +#include + +#include +#include + +#define for_now /* show all of `c' partition for disklabel */ +#define NPARTITIONS 8 +#define PART(x) (x - 'a') + +/* + * Default partition sizes, where they exist. + */ +#define NDEFAULTS 4 +int defpart[NDEFAULTS][NPARTITIONS] = { + { 15884, 66880, 0, 15884, 307200, 0, 0, 291346 }, /* ~ 356+ Mbytes */ + { 15884, 33440, 0, 15884, 55936, 0, 0, 291346 }, /* ~ 206-355 Mbytes */ + { 15884, 33440, 0, 15884, 55936, 0, 0, 0 }, /* ~ 61-205 Mbytes */ + { 15884, 10032, 0, 15884, 0, 0, 0, 0 }, /* ~ 20-60 Mbytes */ +}; + +/* + * Each array defines a layout for a disk; + * that is, the collection of partitions totally + * covers the physical space on a disk. + */ +#define NLAYOUTS 3 +char layouts[NLAYOUTS][NPARTITIONS] = { + { 'a', 'b', 'h', 'g' }, + { 'a', 'b', 'h', 'd', 'e', 'f' }, + { 'c' }, +}; + +/* + * Default disk block and disk block fragment + * sizes for each file system. Those file systems + * with zero block and frag sizes are special cases + * (e.g. swap areas or for access to the entire device). + */ +struct partition defparam[NPARTITIONS] = { + { 0, 0, 1024, FS_UNUSED, 8, 0 }, /* a */ + { 0, 0, 1024, FS_SWAP, 8, 0 }, /* b */ + { 0, 0, 1024, FS_UNUSED, 8, 0 }, /* c */ + { 0, 0, 512, FS_UNUSED, 8, 0 }, /* d */ + { 0, 0, 1024, FS_UNUSED, 8, 0 }, /* e */ + { 0, 0, 1024, FS_UNUSED, 8, 0 }, /* f */ + { 0, 0, 1024, FS_UNUSED, 8, 0 }, /* g */ + { 0, 0, 1024, FS_UNUSED, 8, 0 } /* h */ +}; + +/* + * Each disk has some space reserved for a bad sector + * forwarding table. DEC standard 144 uses the first + * 5 even numbered sectors in the last track of the + * last cylinder for replicated storage of the bad sector + * table; another 126 sectors past this is needed as a + * pool of replacement sectors. + */ +int badsecttable = 126; /* # sectors */ + +int pflag; /* print device driver partition tables */ +int dflag; /* print disktab entry */ + +struct disklabel *promptfordisk(); + +main(argc, argv) + int argc; + char *argv[]; +{ + struct disklabel *dp; + register int curcyl, spc, def, part, layout, j; + int threshhold, numcyls[NPARTITIONS], startcyl[NPARTITIONS]; + int totsize = 0; + char *lp, *tyname; + + argc--, argv++; + if (argc < 1) { + fprintf(stderr, + "usage: disktab [ -p ] [ -d ] [ -s size ] disk-type\n"); + exit(1); + } + if (argc > 0 && strcmp(*argv, "-p") == 0) { + pflag++; + argc--, argv++; + } + if (argc > 0 && strcmp(*argv, "-d") == 0) { + dflag++; + argc--, argv++; + } + if (argc > 1 && strcmp(*argv, "-s") == 0) { + totsize = atoi(argv[1]); + argc += 2, argv += 2; + } + dp = getdiskbyname(*argv); + if (dp == NULL) { + if (isatty(0)) + dp = promptfordisk(*argv); + if (dp == NULL) { + fprintf(stderr, "%s: unknown disk type\n", *argv); + exit(2); + } + } else { + if (dp->d_flags & D_REMOVABLE) + tyname = "removable"; + else if (dp->d_flags & D_RAMDISK) + tyname = "simulated"; + else + tyname = "winchester"; + } + spc = dp->d_secpercyl; + /* + * Bad sector table contains one track for the replicated + * copies of the table and enough full tracks preceding + * the last track to hold the pool of free blocks to which + * bad sectors are mapped. + * If disk size was specified explicitly, use specified size. + */ + if (dp->d_type == DTYPE_SMD && dp->d_flags & D_BADSECT && + totsize == 0) { + badsecttable = dp->d_nsectors + + roundup(badsecttable, dp->d_nsectors); + threshhold = howmany(spc, badsecttable); + } else { + badsecttable = 0; + threshhold = 0; + } + /* + * If disk size was specified, recompute number of cylinders + * that may be used, and set badsecttable to any remaining + * fraction of the last cylinder. + */ + if (totsize != 0) { + dp->d_ncylinders = howmany(totsize, spc); + badsecttable = spc * dp->d_ncylinders - totsize; + } + + /* + * Figure out if disk is large enough for + * expanded swap area and 'd', 'e', and 'f' + * partitions. Otherwise, use smaller defaults + * based on RK07. + */ + for (def = 0; def < NDEFAULTS; def++) { + curcyl = 0; + for (part = PART('a'); part < NPARTITIONS; part++) + curcyl += howmany(defpart[def][part], spc); + if (curcyl < dp->d_ncylinders - threshhold) + break; + } + if (def >= NDEFAULTS) { + fprintf(stderr, "%s: disk too small, calculate by hand\n", + *argv); + exit(3); + } + + /* + * Calculate number of cylinders allocated to each disk + * partition. We may waste a bit of space here, but it's + * in the interest of (very backward) compatibility + * (for mixed disk systems). + */ + for (curcyl = 0, part = PART('a'); part < NPARTITIONS; part++) { + numcyls[part] = 0; + if (defpart[def][part] != 0) { + numcyls[part] = howmany(defpart[def][part], spc); + curcyl += numcyls[part]; + } + } + numcyls[PART('f')] = dp->d_ncylinders - curcyl; + numcyls[PART('g')] = + numcyls[PART('d')] + numcyls[PART('e')] + numcyls[PART('f')]; + numcyls[PART('c')] = dp->d_ncylinders; + defpart[def][PART('f')] = numcyls[PART('f')] * spc - badsecttable; + defpart[def][PART('g')] = numcyls[PART('g')] * spc - badsecttable; + defpart[def][PART('c')] = numcyls[PART('c')] * spc; +#ifndef for_now + if (totsize || !pflag) +#else + if (totsize) +#endif + defpart[def][PART('c')] -= badsecttable; + + /* + * Calculate starting cylinder number for each partition. + * Note the 'h' partition is physically located before the + * 'g' or 'd' partition. This is reflected in the layout + * arrays defined above. + */ + for (layout = 0; layout < NLAYOUTS; layout++) { + curcyl = 0; + for (lp = layouts[layout]; *lp != 0; lp++) { + startcyl[PART(*lp)] = curcyl; + curcyl += numcyls[PART(*lp)]; + } + } + + if (pflag) { + printf("}, %s_sizes[%d] = {\n", dp->d_typename, NPARTITIONS); + for (part = PART('a'); part < NPARTITIONS; part++) { + if (numcyls[part] == 0) { + printf("\t0,\t0,\n"); + continue; + } + if (dp->d_type != DTYPE_MSCP) { + printf("\t%d,\t%d,\t\t/* %c=cyl %d thru %d */\n", + defpart[def][part], startcyl[part], + 'A' + part, startcyl[part], + startcyl[part] + numcyls[part] - 1); + continue; + } + printf("\t%d,\t%d,\t\t/* %c=sectors %d thru %d */\n", + defpart[def][part], spc * startcyl[part], + 'A' + part, spc * startcyl[part], + spc * startcyl[part] + defpart[def][part] - 1); + } + exit(0); + } + if (dflag) { + int nparts; + + /* + * In case the disk is in the ``in-between'' range + * where the 'g' partition is smaller than the 'h' + * partition, reverse the frag sizes so the /usr partition + * is always set up with a frag size larger than the + * user's partition. + */ + if (defpart[def][PART('g')] < defpart[def][PART('h')]) { + int temp; + + temp = defparam[PART('h')].p_fsize; + defparam[PART('h')].p_fsize = + defparam[PART('g')].p_fsize; + defparam[PART('g')].p_fsize = temp; + } + printf("%s:\\\n", dp->d_typename); + printf("\t:ty=%s:ns#%d:nt#%d:nc#%d:", tyname, + dp->d_nsectors, dp->d_ntracks, dp->d_ncylinders); + if (dp->d_secpercyl != dp->d_nsectors * dp->d_ntracks) + printf("sc#%d:", dp->d_secpercyl); + if (dp->d_type == DTYPE_SMD && dp->d_flags & D_BADSECT) + printf("sf:"); + printf("\\\n\t:dt=%s:", dktypenames[dp->d_type]); + for (part = NDDATA - 1; part >= 0; part--) + if (dp->d_drivedata[part]) + break; + for (j = 0; j <= part; j++) + printf("d%d#%d:", j, dp->d_drivedata[j]); + printf("\\\n"); + for (nparts = 0, part = PART('a'); part < NPARTITIONS; part++) + if (defpart[def][part] != 0) + nparts++; + for (part = PART('a'); part < NPARTITIONS; part++) { + if (defpart[def][part] == 0) + continue; + printf("\t:p%c#%d:", 'a' + part, defpart[def][part]); + printf("o%c#%d:b%c#%d:f%c#%d:", + 'a' + part, spc * startcyl[part], + 'a' + part, + defparam[part].p_frag * defparam[part].p_fsize, + 'a' + part, defparam[part].p_fsize); + if (defparam[part].p_fstype == FS_SWAP) + printf("t%c=swap:", 'a' + part); + nparts--; + printf("%s\n", nparts > 0 ? "\\" : ""); + } +#ifdef for_now + defpart[def][PART('c')] -= badsecttable; + part = PART('c'); + printf("#\t:p%c#%d:", 'a' + part, defpart[def][part]); + printf("o%c#%d:b%c#%d:f%c#%d:\n", + 'a' + part, spc * startcyl[part], + 'a' + part, + defparam[part].p_frag * defparam[part].p_fsize, + 'a' + part, defparam[part].p_fsize); +#endif + exit(0); + } + printf("%s: #sectors/track=%d, #tracks/cylinder=%d #cylinders=%d\n", + dp->d_typename, dp->d_nsectors, dp->d_ntracks, + dp->d_ncylinders); + printf("\n Partition\t Size\t Offset\t Range\n"); + for (part = PART('a'); part < NPARTITIONS; part++) { + printf("\t%c\t", 'a' + part); + if (numcyls[part] == 0) { + printf(" unused\n"); + continue; + } + printf("%7d\t%7d\t%4d - %d%s\n", + defpart[def][part], startcyl[part] * spc, + startcyl[part], startcyl[part] + numcyls[part] - 1, + defpart[def][part] % spc ? "*" : ""); + } +} + +struct disklabel disk; + +struct field { + char *f_name; + char *f_defaults; + u_int32_t *f_location; +} fields[] = { + { "sector size", "512", &disk.d_secsize }, + { "#sectors/track", 0, &disk.d_nsectors }, + { "#tracks/cylinder", 0, &disk.d_ntracks }, + { "#cylinders", 0, &disk.d_ncylinders }, + { 0, 0, 0 }, +}; + +struct disklabel * +promptfordisk(name) + char *name; +{ + register struct disklabel *dp = &disk; + register struct field *fp; + register i; + char buf[BUFSIZ], **tp, *cp, *gets(); + + strncpy(dp->d_typename, name, sizeof(dp->d_typename)); + fprintf(stderr, + "%s: unknown disk type, want to supply parameters (y/n)? ", + name); + (void) gets(buf); + if (*buf != 'y') + return ((struct disklabel *)0); + for (;;) { + fprintf(stderr, "Disk/controller type (%s)? ", dktypenames[1]); + (void) gets(buf); + if (buf[0] == 0) { + dp->d_type = 1; + break; + } + if ((i = gettype(buf, dktypenames)) >= 0) { + dp->d_type = i; + break; + } + fprintf(stderr, "%s: unrecognized controller type\n", buf); + fprintf(stderr, "use one of:\n", buf); + for (tp = dktypenames; *tp; tp++) + if (index(*tp, ' ') == 0) + fprintf(stderr, "\t%s\n", *tp); + } +gettype: + dp->d_flags = 0; + fprintf(stderr, "type (winchester|removable|simulated)? "); + (void) gets(buf); + if (strcmp(buf, "removable") == 0) + dp->d_flags = D_REMOVABLE; + else if (strcmp(buf, "simulated") == 0) + dp->d_flags = D_RAMDISK; + else if (strcmp(buf, "winchester")) { + fprintf(stderr, "%s: bad disk type\n", buf); + goto gettype; + } + strncpy(dp->d_typename, buf, sizeof(dp->d_typename)); + fprintf(stderr, "(type to get default value, if only one)\n"); + if (dp->d_type == DTYPE_SMD) + fprintf(stderr, "Do %ss support bad144 bad block forwarding (yes)? ", + dp->d_typename); + (void) gets(buf); + if (*buf != 'n') + dp->d_flags |= D_BADSECT; + for (fp = fields; fp->f_name != NULL; fp++) { +again: + fprintf(stderr, "%s ", fp->f_name); + if (fp->f_defaults != NULL) + fprintf(stderr, "(%s)", fp->f_defaults); + fprintf(stderr, "? "); + cp = gets(buf); + if (*cp == '\0') { + if (fp->f_defaults == NULL) { + fprintf(stderr, "no default value\n"); + goto again; + } + cp = fp->f_defaults; + } + *fp->f_location = atol(cp); + if (*fp->f_location == 0) { + fprintf(stderr, "%s: bad value\n", cp); + goto again; + } + } + fprintf(stderr, "sectors/cylinder (%d)? ", + dp->d_nsectors * dp->d_ntracks); + (void) gets(buf); + if (buf[0] == 0) + dp->d_secpercyl = dp->d_nsectors * dp->d_ntracks; + else + dp->d_secpercyl = atol(buf); + fprintf(stderr, "Drive-type-specific parameters, to terminate:\n"); + for (i = 0; i < NDDATA; i++) { + fprintf(stderr, "d%d? ", i); + (void) gets(buf); + if (buf[0] == 0) + break; + dp->d_drivedata[i] = atol(buf); + } + return (dp); +} + +gettype(t, names) + char *t; + char **names; +{ + register char **nm; + + for (nm = names; *nm; nm++) + if (ustrcmp(t, *nm) == 0) + return (nm - names); + if (isdigit(*t)) + return (atoi(t)); + return (-1); +} + +ustrcmp(s1, s2) + register char *s1, *s2; +{ +#define lower(c) (islower(c) ? (c) : tolower(c)) + + for (; *s1; s1++, s2++) { + if (*s1 == *s2) + continue; + if (isalpha(*s1) && isalpha(*s2) && + lower(*s1) == lower(*s2)) + continue; + return (*s2 - *s1); + } + return (0); +} diff --git a/usr.sbin/edquota/edquota.8 b/usr.sbin/edquota/edquota.8 new file mode 100644 index 000000000000..664357b22528 --- /dev/null +++ b/usr.sbin/edquota/edquota.8 @@ -0,0 +1,160 @@ +.\" Copyright (c) 1983, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Robert Elz at The University of Melbourne. +.\" +.\" 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. +.\" +.\" @(#)edquota.8 8.2 (Berkeley) 4/27/95 +.\" +.Dd "April 27, 1995" +.Dt EDQUOTA 8 +.Os +.Sh NAME +.Nm edquota +.Nd edit user quotas +.Sh SYNOPSIS +.Nm edquota +.Op Fl u +.Op Fl p Ar proto-username +.Ar username ... +.Nm edquota +.Fl g +.Op Fl p Ar proto-groupname +.Ar groupname ... +.Nm edquota +.Fl t +.Op Fl u +.Nm edquota +.Fl t +.Fl g +.Sh DESCRIPTION +.Nm Edquota +is a quota editor. +By default, or if the +.Fl u +flag is specified, +one or more users may be specified on the command line. +For each user a temporary file is created +with an ASCII representation of the current +disk quotas for that user. +The list of filesystems with user quotas is determined from +.Pa /etc/fstab . +An editor is invoked on the ASCII file. +The editor invoked is +.Xr vi 1 +unless the environment variable +.Ev EDITOR +specifies otherwise. +.Pp +The quotas may then be modified, new quotas added, etc. +Setting a quota to zero indicates that no quota should be imposed. +Setting a hard limit to one indicates that no allocations should +be permitted. +Setting a soft limit to one with a hard limit of zero +indicates that allocations should be permitted on +only a temporary basis (see +.Fl t +below). +The current usage information in the file is for informational purposes; +only the hard and soft limits can be changed. +.Pp +On leaving the editor, +.Nm edquota +reads the temporary file and modifies the binary +quota files to reflect the changes made. +.Pp +If the +.Fl p +flag is specified, +.Nm edquota +will duplicate the quotas of the prototypical user +specified for each user specified. +This is the normal mechanism used to +initialize quotas for groups of users. +.Pp +If the +.Fl g +flag is specified, +.Nm edquota +is invoked to edit the quotas of +one or more groups specified on the command line. +The +.Fl p +flag can be specified in conjunction with +the +.Fl g +flag to specify a prototypical group +to be duplicated among the listed set of groups. +.Pp +Users are permitted to exceed their soft limits +for a grace period that may be specified per filesystem. +Once the grace period has expired, +the soft limit is enforced as a hard limit. +The default grace period for a filesystem is specified in +.Pa /usr/include/ufs/ufs/quota.h . +The +.Fl t +flag can be used to change the grace period. +By default, or when invoked with the +.Fl u +flag, the grace period is set for all the filesystems with user +quotas specified in +.Pa /etc/fstab . +When invoked with the +.Fl g +flag the grace period is +set for all the filesystems with group quotas specified in +.Pa /etc/fstab . +The grace period may be specified in days, hours, minutes, or seconds. +Setting a grace period to zero indicates that the default +grace period should be imposed. +Setting a grace period to one second indicates that no +grace period should be granted. +.Pp +Only the super-user may edit quotas. +.Sh FILES +.Bl -tag -width 24n -compact +.It Pa quota.user +at the filesystem root with user quotas +.It Pa quota.group +at the filesystem root with group quotas +.It Pa /etc/fstab +to find filesystem names and locations +.El +.Sh SEE ALSO +.Xr quota 1 , +.Xr quotactl 2 , +.Xr fstab 5 , +.Xr quotacheck 8 , +.Xr quotaon 8 , +.Xr repquota 8 +.Sh DIAGNOSTICS +Various messages about inaccessible files; self-explanatory. diff --git a/usr.sbin/edquota/edquota.c b/usr.sbin/edquota/edquota.c new file mode 100644 index 000000000000..28e1da5954b2 --- /dev/null +++ b/usr.sbin/edquota/edquota.c @@ -0,0 +1,724 @@ +/* + * Copyright (c) 1980, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Elz at The University of Melbourne. + * + * 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) 1980, 1990, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)edquota.c 8.3 (Berkeley) 4/27/95"; +#endif /* not lint */ + +/* + * Disk quota editor. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pathnames.h" + +char *qfname = QUOTAFILENAME; +char *qfextension[] = INITQFNAMES; +char *quotagroup = QUOTAGROUP; +char tmpfil[] = _PATH_TMP; + +struct quotause { + struct quotause *next; + long flags; + struct dqblk dqblk; + char fsname[MAXPATHLEN + 1]; + char qfname[1]; /* actually longer */ +} *getprivs(); +#define FOUND 0x01 + +main(argc, argv) + register char **argv; + int argc; +{ + register struct quotause *qup, *protoprivs, *curprivs; + extern char *optarg; + extern int optind; + register long id, protoid; + register int quotatype, tmpfd; + char *protoname, ch; + int tflag = 0, pflag = 0; + + if (argc < 2) + usage(); + if (getuid()) { + fprintf(stderr, "edquota: permission denied\n"); + exit(1); + } + quotatype = USRQUOTA; + while ((ch = getopt(argc, argv, "ugtp:")) != EOF) { + switch(ch) { + case 'p': + protoname = optarg; + pflag++; + break; + case 'g': + quotatype = GRPQUOTA; + break; + case 'u': + quotatype = USRQUOTA; + break; + case 't': + tflag++; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + if (pflag) { + if ((protoid = getentry(protoname, quotatype)) == -1) + exit(1); + protoprivs = getprivs(protoid, quotatype); + for (qup = protoprivs; qup; qup = qup->next) { + qup->dqblk.dqb_btime = 0; + qup->dqblk.dqb_itime = 0; + } + while (argc-- > 0) { + if ((id = getentry(*argv++, quotatype)) < 0) + continue; + putprivs(id, quotatype, protoprivs); + } + exit(0); + } + tmpfd = mkstemp(tmpfil); + fchown(tmpfd, getuid(), getgid()); + if (tflag) { + protoprivs = getprivs(0, quotatype); + if (writetimes(protoprivs, tmpfd, quotatype) == 0) + exit(1); + if (editit(tmpfil) && readtimes(protoprivs, tmpfd)) + putprivs(0, quotatype, protoprivs); + freeprivs(protoprivs); + exit(0); + } + for ( ; argc > 0; argc--, argv++) { + if ((id = getentry(*argv, quotatype)) == -1) + continue; + curprivs = getprivs(id, quotatype); + if (writeprivs(curprivs, tmpfd, *argv, quotatype) == 0) + continue; + if (editit(tmpfil) && readprivs(curprivs, tmpfd)) + putprivs(id, quotatype, curprivs); + freeprivs(curprivs); + } + close(tmpfd); + unlink(tmpfil); + exit(0); +} + +usage() +{ + fprintf(stderr, "%s%s%s%s", + "Usage: edquota [-u] [-p username] username ...\n", + "\tedquota -g [-p groupname] groupname ...\n", + "\tedquota [-u] -t\n", "\tedquota -g -t\n"); + exit(1); +} + +/* + * This routine converts a name for a particular quota type to + * an identifier. This routine must agree with the kernel routine + * getinoquota as to the interpretation of quota types. + */ +getentry(name, quotatype) + char *name; + int quotatype; +{ + struct passwd *pw; + struct group *gr; + + if (alldigits(name)) + return (atoi(name)); + switch(quotatype) { + case USRQUOTA: + if (pw = getpwnam(name)) + return (pw->pw_uid); + fprintf(stderr, "%s: no such user\n", name); + break; + case GRPQUOTA: + if (gr = getgrnam(name)) + return (gr->gr_gid); + fprintf(stderr, "%s: no such group\n", name); + break; + default: + fprintf(stderr, "%d: unknown quota type\n", quotatype); + break; + } + sleep(1); + return (-1); +} + +/* + * Collect the requested quota information. + */ +struct quotause * +getprivs(id, quotatype) + register long id; + int quotatype; +{ + register struct fstab *fs; + register struct quotause *qup, *quptail; + struct quotause *quphead; + int qcmd, qupsize, fd; + char *qfpathname; + static int warned = 0; + extern int errno; + + setfsent(); + quphead = (struct quotause *)0; + qcmd = QCMD(Q_GETQUOTA, quotatype); + while (fs = getfsent()) { + if (strcmp(fs->fs_vfstype, "ufs")) + continue; + if (!hasquota(fs, quotatype, &qfpathname)) + continue; + qupsize = sizeof(*qup) + strlen(qfpathname); + if ((qup = (struct quotause *)malloc(qupsize)) == NULL) { + fprintf(stderr, "edquota: out of memory\n"); + exit(2); + } + if (quotactl(fs->fs_file, qcmd, id, &qup->dqblk) != 0) { + if (errno == EOPNOTSUPP && !warned) { + warned++; + fprintf(stderr, "Warning: %s\n", + "Quotas are not compiled into this kernel"); + sleep(3); + } + if ((fd = open(qfpathname, O_RDONLY)) < 0) { + fd = open(qfpathname, O_RDWR|O_CREAT, 0640); + if (fd < 0 && errno != ENOENT) { + perror(qfpathname); + free(qup); + continue; + } + fprintf(stderr, "Creating quota file %s\n", + qfpathname); + sleep(3); + (void) fchown(fd, getuid(), + getentry(quotagroup, GRPQUOTA)); + (void) fchmod(fd, 0640); + } + lseek(fd, (off_t)(id * sizeof(struct dqblk)), L_SET); + switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) { + case 0: /* EOF */ + /* + * Convert implicit 0 quota (EOF) + * into an explicit one (zero'ed dqblk) + */ + bzero((caddr_t)&qup->dqblk, + sizeof(struct dqblk)); + break; + + case sizeof(struct dqblk): /* OK */ + break; + + default: /* ERROR */ + fprintf(stderr, "edquota: read error in "); + perror(qfpathname); + close(fd); + free(qup); + continue; + } + close(fd); + } + strcpy(qup->qfname, qfpathname); + strcpy(qup->fsname, fs->fs_file); + if (quphead == NULL) + quphead = qup; + else + quptail->next = qup; + quptail = qup; + qup->next = 0; + } + endfsent(); + return (quphead); +} + +/* + * Store the requested quota information. + */ +putprivs(id, quotatype, quplist) + long id; + int quotatype; + struct quotause *quplist; +{ + register struct quotause *qup; + int qcmd, fd; + + qcmd = QCMD(Q_SETQUOTA, quotatype); + for (qup = quplist; qup; qup = qup->next) { + if (quotactl(qup->fsname, qcmd, id, &qup->dqblk) == 0) + continue; + if ((fd = open(qup->qfname, O_WRONLY)) < 0) { + perror(qup->qfname); + } else { + lseek(fd, + (off_t)(id * (long)sizeof (struct dqblk)), L_SET); + if (write(fd, &qup->dqblk, sizeof (struct dqblk)) != + sizeof (struct dqblk)) { + fprintf(stderr, "edquota: "); + perror(qup->qfname); + } + close(fd); + } + } +} + +/* + * Take a list of priviledges and get it edited. + */ +editit(tmpfile) + char *tmpfile; +{ + long omask; + int pid, stat; + extern char *getenv(); + + omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); + top: + if ((pid = fork()) < 0) { + extern errno; + + if (errno == EPROCLIM) { + fprintf(stderr, "You have too many processes\n"); + return(0); + } + if (errno == EAGAIN) { + sleep(1); + goto top; + } + perror("fork"); + return (0); + } + if (pid == 0) { + register char *ed; + + sigsetmask(omask); + setgid(getgid()); + setuid(getuid()); + if ((ed = getenv("EDITOR")) == (char *)0) + ed = _PATH_VI; + execlp(ed, ed, tmpfile, 0); + perror(ed); + exit(1); + } + waitpid(pid, &stat, 0); + sigsetmask(omask); + if (!WIFEXITED(stat) || WEXITSTATUS(stat) != 0) + return (0); + return (1); +} + +/* + * Convert a quotause list to an ASCII file. + */ +writeprivs(quplist, outfd, name, quotatype) + struct quotause *quplist; + int outfd; + char *name; + int quotatype; +{ + register struct quotause *qup; + FILE *fd; + + ftruncate(outfd, 0); + lseek(outfd, 0, L_SET); + if ((fd = fdopen(dup(outfd), "w")) == NULL) { + fprintf(stderr, "edquota: "); + perror(tmpfil); + exit(1); + } + fprintf(fd, "Quotas for %s %s:\n", qfextension[quotatype], name); + for (qup = quplist; qup; qup = qup->next) { + fprintf(fd, "%s: %s %d, limits (soft = %d, hard = %d)\n", + qup->fsname, "blocks in use:", + dbtob(qup->dqblk.dqb_curblocks) / 1024, + dbtob(qup->dqblk.dqb_bsoftlimit) / 1024, + dbtob(qup->dqblk.dqb_bhardlimit) / 1024); + fprintf(fd, "%s %d, limits (soft = %d, hard = %d)\n", + "\tinodes in use:", qup->dqblk.dqb_curinodes, + qup->dqblk.dqb_isoftlimit, qup->dqblk.dqb_ihardlimit); + } + fclose(fd); + return (1); +} + +/* + * Merge changes to an ASCII file into a quotause list. + */ +readprivs(quplist, infd) + struct quotause *quplist; + int infd; +{ + register struct quotause *qup; + FILE *fd; + int cnt; + register char *cp; + struct dqblk dqblk; + char *fsp, line1[BUFSIZ], line2[BUFSIZ]; + + lseek(infd, 0, L_SET); + fd = fdopen(dup(infd), "r"); + if (fd == NULL) { + fprintf(stderr, "Can't re-read temp file!!\n"); + return (0); + } + /* + * Discard title line, then read pairs of lines to process. + */ + (void) fgets(line1, sizeof (line1), fd); + while (fgets(line1, sizeof (line1), fd) != NULL && + fgets(line2, sizeof (line2), fd) != NULL) { + if ((fsp = strtok(line1, " \t:")) == NULL) { + fprintf(stderr, "%s: bad format\n", line1); + return (0); + } + if ((cp = strtok((char *)0, "\n")) == NULL) { + fprintf(stderr, "%s: %s: bad format\n", fsp, + &fsp[strlen(fsp) + 1]); + return (0); + } + cnt = sscanf(cp, + " blocks in use: %d, limits (soft = %d, hard = %d)", + &dqblk.dqb_curblocks, &dqblk.dqb_bsoftlimit, + &dqblk.dqb_bhardlimit); + if (cnt != 3) { + fprintf(stderr, "%s:%s: bad format\n", fsp, cp); + return (0); + } + dqblk.dqb_curblocks = btodb(dqblk.dqb_curblocks * 1024); + dqblk.dqb_bsoftlimit = btodb(dqblk.dqb_bsoftlimit * 1024); + dqblk.dqb_bhardlimit = btodb(dqblk.dqb_bhardlimit * 1024); + if ((cp = strtok(line2, "\n")) == NULL) { + fprintf(stderr, "%s: %s: bad format\n", fsp, line2); + return (0); + } + cnt = sscanf(cp, + "\tinodes in use: %d, limits (soft = %d, hard = %d)", + &dqblk.dqb_curinodes, &dqblk.dqb_isoftlimit, + &dqblk.dqb_ihardlimit); + if (cnt != 3) { + fprintf(stderr, "%s: %s: bad format\n", fsp, line2); + return (0); + } + for (qup = quplist; qup; qup = qup->next) { + if (strcmp(fsp, qup->fsname)) + continue; + /* + * Cause time limit to be reset when the quota + * is next used if previously had no soft limit + * or were under it, but now have a soft limit + * and are over it. + */ + if (dqblk.dqb_bsoftlimit && + qup->dqblk.dqb_curblocks >= dqblk.dqb_bsoftlimit && + (qup->dqblk.dqb_bsoftlimit == 0 || + qup->dqblk.dqb_curblocks < + qup->dqblk.dqb_bsoftlimit)) + qup->dqblk.dqb_btime = 0; + if (dqblk.dqb_isoftlimit && + qup->dqblk.dqb_curinodes >= dqblk.dqb_isoftlimit && + (qup->dqblk.dqb_isoftlimit == 0 || + qup->dqblk.dqb_curinodes < + qup->dqblk.dqb_isoftlimit)) + qup->dqblk.dqb_itime = 0; + qup->dqblk.dqb_bsoftlimit = dqblk.dqb_bsoftlimit; + qup->dqblk.dqb_bhardlimit = dqblk.dqb_bhardlimit; + qup->dqblk.dqb_isoftlimit = dqblk.dqb_isoftlimit; + qup->dqblk.dqb_ihardlimit = dqblk.dqb_ihardlimit; + qup->flags |= FOUND; + if (dqblk.dqb_curblocks == qup->dqblk.dqb_curblocks && + dqblk.dqb_curinodes == qup->dqblk.dqb_curinodes) + break; + fprintf(stderr, + "%s: cannot change current allocation\n", fsp); + break; + } + } + fclose(fd); + /* + * Disable quotas for any filesystems that have not been found. + */ + for (qup = quplist; qup; qup = qup->next) { + if (qup->flags & FOUND) { + qup->flags &= ~FOUND; + continue; + } + qup->dqblk.dqb_bsoftlimit = 0; + qup->dqblk.dqb_bhardlimit = 0; + qup->dqblk.dqb_isoftlimit = 0; + qup->dqblk.dqb_ihardlimit = 0; + } + return (1); +} + +/* + * Convert a quotause list to an ASCII file of grace times. + */ +writetimes(quplist, outfd, quotatype) + struct quotause *quplist; + int outfd; + int quotatype; +{ + register struct quotause *qup; + char *cvtstoa(); + FILE *fd; + + ftruncate(outfd, 0); + lseek(outfd, 0, L_SET); + if ((fd = fdopen(dup(outfd), "w")) == NULL) { + fprintf(stderr, "edquota: "); + perror(tmpfil); + exit(1); + } + fprintf(fd, "Time units may be: days, hours, minutes, or seconds\n"); + fprintf(fd, "Grace period before enforcing soft limits for %ss:\n", + qfextension[quotatype]); + for (qup = quplist; qup; qup = qup->next) { + fprintf(fd, "%s: block grace period: %s, ", + qup->fsname, cvtstoa(qup->dqblk.dqb_btime)); + fprintf(fd, "file grace period: %s\n", + cvtstoa(qup->dqblk.dqb_itime)); + } + fclose(fd); + return (1); +} + +/* + * Merge changes of grace times in an ASCII file into a quotause list. + */ +readtimes(quplist, infd) + struct quotause *quplist; + int infd; +{ + register struct quotause *qup; + FILE *fd; + int cnt; + register char *cp; + time_t itime, btime, iseconds, bseconds; + char *fsp, bunits[10], iunits[10], line1[BUFSIZ]; + + lseek(infd, 0, L_SET); + fd = fdopen(dup(infd), "r"); + if (fd == NULL) { + fprintf(stderr, "Can't re-read temp file!!\n"); + return (0); + } + /* + * Discard two title lines, then read lines to process. + */ + (void) fgets(line1, sizeof (line1), fd); + (void) fgets(line1, sizeof (line1), fd); + while (fgets(line1, sizeof (line1), fd) != NULL) { + if ((fsp = strtok(line1, " \t:")) == NULL) { + fprintf(stderr, "%s: bad format\n", line1); + return (0); + } + if ((cp = strtok((char *)0, "\n")) == NULL) { + fprintf(stderr, "%s: %s: bad format\n", fsp, + &fsp[strlen(fsp) + 1]); + return (0); + } + cnt = sscanf(cp, + " block grace period: %d %s file grace period: %d %s", + &btime, bunits, &itime, iunits); + if (cnt != 4) { + fprintf(stderr, "%s:%s: bad format\n", fsp, cp); + return (0); + } + if (cvtatos(btime, bunits, &bseconds) == 0) + return (0); + if (cvtatos(itime, iunits, &iseconds) == 0) + return (0); + for (qup = quplist; qup; qup = qup->next) { + if (strcmp(fsp, qup->fsname)) + continue; + qup->dqblk.dqb_btime = bseconds; + qup->dqblk.dqb_itime = iseconds; + qup->flags |= FOUND; + break; + } + } + fclose(fd); + /* + * reset default grace periods for any filesystems + * that have not been found. + */ + for (qup = quplist; qup; qup = qup->next) { + if (qup->flags & FOUND) { + qup->flags &= ~FOUND; + continue; + } + qup->dqblk.dqb_btime = 0; + qup->dqblk.dqb_itime = 0; + } + return (1); +} + +/* + * Convert seconds to ASCII times. + */ +char * +cvtstoa(time) + time_t time; +{ + static char buf[20]; + + if (time % (24 * 60 * 60) == 0) { + time /= 24 * 60 * 60; + sprintf(buf, "%d day%s", time, time == 1 ? "" : "s"); + } else if (time % (60 * 60) == 0) { + time /= 60 * 60; + sprintf(buf, "%d hour%s", time, time == 1 ? "" : "s"); + } else if (time % 60 == 0) { + time /= 60; + sprintf(buf, "%d minute%s", time, time == 1 ? "" : "s"); + } else + sprintf(buf, "%d second%s", time, time == 1 ? "" : "s"); + return (buf); +} + +/* + * Convert ASCII input times to seconds. + */ +cvtatos(time, units, seconds) + time_t time; + char *units; + time_t *seconds; +{ + + if (bcmp(units, "second", 6) == 0) + *seconds = time; + else if (bcmp(units, "minute", 6) == 0) + *seconds = time * 60; + else if (bcmp(units, "hour", 4) == 0) + *seconds = time * 60 * 60; + else if (bcmp(units, "day", 3) == 0) + *seconds = time * 24 * 60 * 60; + else { + printf("%s: bad units, specify %s\n", units, + "days, hours, minutes, or seconds"); + return (0); + } + return (1); +} + +/* + * Free a list of quotause structures. + */ +freeprivs(quplist) + struct quotause *quplist; +{ + register struct quotause *qup, *nextqup; + + for (qup = quplist; qup; qup = nextqup) { + nextqup = qup->next; + free(qup); + } +} + +/* + * Check whether a string is completely composed of digits. + */ +alldigits(s) + register char *s; +{ + register c; + + c = *s++; + do { + if (!isdigit(c)) + return (0); + } while (c = *s++); + return (1); +} + +/* + * Check to see if a particular quota is to be enabled. + */ +hasquota(fs, type, qfnamep) + register struct fstab *fs; + int type; + char **qfnamep; +{ + register char *opt; + char *cp, *index(), *strtok(); + static char initname, usrname[100], grpname[100]; + static char buf[BUFSIZ]; + + if (!initname) { + sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname); + sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname); + initname = 1; + } + strcpy(buf, fs->fs_mntops); + for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { + if (cp = index(opt, '=')) + *cp++ = '\0'; + if (type == USRQUOTA && strcmp(opt, usrname) == 0) + break; + if (type == GRPQUOTA && strcmp(opt, grpname) == 0) + break; + } + if (!opt) + return (0); + if (cp) { + *qfnamep = cp; + return (1); + } + (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]); + *qfnamep = buf; + return (1); +} diff --git a/usr.sbin/inetd/inetd.8 b/usr.sbin/inetd/inetd.8 new file mode 100644 index 000000000000..72c5b4fcc125 --- /dev/null +++ b/usr.sbin/inetd/inetd.8 @@ -0,0 +1,376 @@ +.\" Copyright (c) 1985, 1991, 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. +.\" +.\" @(#)inetd.8 8.4 (Berkeley) 6/1/94 +.\" +.Dd June 1, 1994 +.Dt INETD 8 +.Os BSD 4.4 +.Sh NAME +.Nm inetd +.Nd internet +.Dq super-server +.Sh SYNOPSIS +.Nm inetd +.Op Fl d +.Op Fl R Ar rate +.Op Ar configuration file +.Sh DESCRIPTION +The +.Nm inetd +program +should be run at boot time by +.Pa /etc/rc +(see +.Xr rc 8 ) . +It then listens for connections on certain +internet sockets. When a connection is found on one +of its sockets, it decides what service the socket +corresponds to, and invokes a program to service the request. +The server program is invoked with the service socket +as its standard input, output and error descriptors. +After the program is +finished, +.Nm inetd +continues to listen on the socket (except in some cases which +will be described below). Essentially, +.Nm inetd +allows running one daemon to invoke several others, +reducing load on the system. +.Pp +The options available for +.Nm inetd: +.Bl -tag -width Ds +.It Fl d +Turns on debugging. +.It Fl R Ar rate +Specifies the maximum number of times a service can be invoked +in one minute; the default is 1000. +.El +.Pp +Upon execution, +.Nm inetd +reads its configuration information from a configuration +file which, by default, is +.Pa /etc/inetd.conf . +There must be an entry for each field of the configuration +file, with entries for each field separated by a tab or +a space. Comments are denoted by a ``#'' at the beginning +of a line. There must be an entry for each field. The +fields of the configuration file are as follows: +.Pp +.Bd -unfilled -offset indent -compact +service name +socket type +protocol +wait/nowait +user +server program +server program arguments +.Ed +.Pp +There are two types of services that +.Nm inetd +can start: standard and TCPMUX. +A standard service has a well-known port assigned to it; +it may be a service that implements an official Internet standard or is a +BSD-specific service. +As described in +.Tn RFC 1078 , +TCPMUX services are nonstandard services that do not have a +well-known port assigned to them. +They are invoked from +.Nm inetd +when a program connects to the +.Dq tcpmux +well-known port and specifies +the service name. +This feature is useful for adding locally-developed servers. +.Pp +The +.Em service-name +entry is the name of a valid service in +the file +.Pa /etc/services . +For +.Dq internal +services (discussed below), the service +name +.Em must +be the official name of the service (that is, the first entry in +.Pa /etc/services ) . +For TCPMUX services, the value of the +.Em service-name +field consists of the string +.Dq tcpmux +followed by a slash and the +locally-chosen service name. +The service names listed in +.Pa /etc/services +and the name +.Dq help +are reserved. +Try to choose unique names for your TCPMUX services by prefixing them with +your organization's name and suffixing them with a version number. +.Pp +The +.Em socket-type +should be one of +.Dq stream , +.Dq dgram , +.Dq raw , +.Dq rdm , +or +.Dq seqpacket , +depending on whether the socket is a stream, datagram, raw, +reliably delivered message, or sequenced packet socket. +TCPMUX services must use +.Dq stream . +.Pp +The +.Em protocol +must be a valid protocol as given in +.Pa /etc/protocols . +Examples might be +.Dq tcp +or +.Dq udp . +TCPMUX services must use +.Dq tcp . +.Pp +The +.Em wait/nowait +entry specifies whether the server that is invoked by inetd will take over +the socket associated with the service access point, and thus whether +.Nm inetd +should wait for the server to exit before listening for new service +requests. +Datagram servers must use +.Dq wait , +as they are always invoked with the original datagram socket bound +to the specified service address. +These servers must read at least one datagram from the socket +before exiting. +If a datagram server connects +to its peer, freeing the socket so +.Nm inetd +can received further messages on the socket, it is said to be +a +.Dq multi-threaded +server; +it should read one datagram from the socket and create a new socket +connected to the peer. +It should fork, and the parent should then exit +to allow +.Nm inetd +to check for new service requests to spawn new servers. +Datagram servers which process all incoming datagrams +on a socket and eventually time out are said to be +.Dq single-threaded . +.Xr Comsat 8 , +.Pq Xr biff 1 +and +.Xr talkd 8 +are both examples of the latter type of +datagram server. +.Xr Tftpd 8 +is an example of a multi-threaded datagram server. +.Pp +Servers using stream sockets generally are multi-threaded and +use the +.Dq nowait +entry. +Connection requests for these services are accepted by +.Nm inetd , +and the server is given only the newly-accepted socket connected +to a client of the service. +Most stream-based services operate in this manner. +Stream-based servers that use +.Dq wait +are started with the listening service socket, and must accept +at least one connection request before exiting. +Such a server would normally accept and process incoming connection +requests until a timeout. +TCPMUX services must use +.Dq nowait . +.Pp +The +.Em user +entry should contain the user name of the user as whom the server +should run. This allows for servers to be given less permission +than root. +.Pp +The +.Em server-program +entry should contain the pathname of the program which is to be +executed by +.Nm inetd +when a request is found on its socket. If +.Nm inetd +provides this service internally, this entry should +be +.Dq internal . +.Pp +The +.Em server program arguments +should be just as arguments +normally are, starting with argv[0], which is the name of +the program. If the service is provided internally, the +word +.Dq internal +should take the place of this entry. +.Pp +The +.Nm inetd +program +provides several +.Dq trivial +services internally by use of +routines within itself. These services are +.Dq echo , +.Dq discard , +.Dq chargen +(character generator), +.Dq daytime +(human readable time), and +.Dq time +(machine readable time, +in the form of the number of seconds since midnight, January +1, 1900). All of these services are tcp based. For +details of these services, consult the appropriate +.Tn RFC +from the Network Information Center. +.Pp +The +.Nm inetd +program +rereads its configuration file when it receives a hangup signal, +.Dv SIGHUP . +Services may be added, deleted or modified when the configuration file +is reread. +.Sh TCPMUX +.Pp +.Tn RFC 1078 +describes the TCPMUX protocol: +``A TCP client connects to a foreign host on TCP port 1. It sends the +service name followed by a carriage-return line-feed . The +service name is never case sensitive. The server replies with a +single character indicating positive (+) or negative (\-) +acknowledgment, immediately followed by an optional message of +explanation, terminated with a . If the reply was positive, +the selected protocol begins; otherwise the connection is closed.'' +The program is passed the TCP connection as file descriptors 0 and 1. +.Pp +If the TCPMUX service name begins with a ``+'', +.Nm inetd +returns the positive reply for the program. +This allows you to invoke programs that use stdin/stdout +without putting any special server code in them. +.Pp +The special service name +.Dq help +causes +.Nm inetd +to list TCPMUX services in +.Pa inetd.conf . +.ne 1i +.Sh "EXAMPLES" +.Pp +Here are several example service entries for the various types of services: +.Bd -literal +ftp stream tcp nowait root /usr/libexec/ftpd ftpd -l +ntalk dgram udp wait root /usr/libexec/ntalkd ntalkd +tcpmux/+date stream tcp nowait guest /bin/date date +tcpmux/phonebook stream tcp nowait guest /usr/local/bin/phonebook phonebook +.Ed +.Sh "ERROR MESSAGES" +The +.Nm inetd +server +logs error messages using +.Xr syslog 3 . +Important error messages and their explanations are: +.Bd -literal +\fIservice\fP/\fIprotocol\fP server failing (looping), service terminated. +.Ed +The number of requests for the specified service in the past minute +exceeded the limit. The limit exists to prevent a broken program +or a malicious user from swamping the system. +This message may occur for several reasons: +1) there are lots of hosts requesting the service within a short time period, +2) a 'broken' client program is requesting the service too frequently, +3) a malicious user is running a program to invoke the service in +a 'denial of service' attack, or +4) the invoked service program has an error that causes clients +to retry quickly. +Use the +.Op Fl R +option, +as described above, to change the rate limit. +Once the limit is reached, the service will be +reenabled automatically in 10 minutes. +.sp +.Bd -literal +\fIservice\fP/\fIprotocol\fP: No such user '\fIuser\fP', service ignored +\fIservice\fP/\fIprotocol\fP: getpwnam: \fIuser\fP: No such user +.Ed +No entry for +.Em user +exists in the +.Pa passwd +file. The first message +occurs when +.Nm inetd +(re)reads the configuration file. The second message occurs when the +service is invoked. +.sp +.Bd -literal +\fIservice\fP: can't set uid \fInumber\fP +\fIservice\fP: can't set gid \fInumber\fP +.Ed +The user or group ID for the entry's +.Em user +is invalid. +.Sh SEE ALSO +.Xr comsat 8 , +.Xr fingerd 8 , +.Xr ftpd 8 , +.Xr rexecd 8 , +.Xr rlogind 8 , +.Xr rshd 8 , +.Xr telnetd 8 , +.Xr tftpd 8 +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.3 . +TCPMUX is based on code and documentation by Mark Lottor. diff --git a/usr.sbin/iostat/iostat.c b/usr.sbin/iostat/iostat.c new file mode 100644 index 000000000000..42da0fa7c4ac --- /dev/null +++ b/usr.sbin/iostat/iostat.c @@ -0,0 +1,391 @@ +/*- + * Copyright (c) 1986, 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1986, 1991, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)iostat.c 8.3 (Berkeley) 4/28/95"; +#endif /* not lint */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct nlist namelist[] = { +#define X_DK_TIME 0 + { "_dk_time" }, +#define X_DK_XFER 1 + { "_dk_xfer" }, +#define X_DK_WDS 2 + { "_dk_wds" }, +#define X_TK_NIN 3 + { "_tk_nin" }, +#define X_TK_NOUT 4 + { "_tk_nout" }, +#define X_DK_SEEK 5 + { "_dk_seek" }, +#define X_CP_TIME 6 + { "_cp_time" }, +#define X_DK_WPMS 7 + { "_dk_wpms" }, +#define X_HZ 8 + { "_hz" }, +#define X_STATHZ 9 + { "_stathz" }, +#define X_DK_NDRIVE 10 + { "_dk_ndrive" }, +#define X_END 10 +#if defined(hp300) || defined(luna68k) +#define X_HPDINIT (X_END+1) + { "_hp_dinit" }, +#endif +#ifdef mips +#define X_SCSI_DINIT (X_END+1) + { "_scsi_dinit" }, +#endif +#ifdef tahoe +#define X_VBDINIT (X_END+1) + { "_vbdinit" }, +#endif +#ifdef vax + { "_mbdinit" }, +#define X_MBDINIT (X_END+1) + { "_ubdinit" }, +#define X_UBDINIT (X_END+2) +#endif + { NULL }, +}; + +struct _disk { + long cp_time[CPUSTATES]; + long *dk_time; + long *dk_wds; + long *dk_seek; + long *dk_xfer; + long tk_nin; + long tk_nout; +} cur, last; + +kvm_t *kd; +double etime; +long *dk_wpms; +int dk_ndrive, *dr_select, hz, kmemfd, ndrives; +char **dr_name; + +#define nlread(x, v) \ + kvm_read(kd, namelist[x].n_value, &(v), sizeof(v)) + +#include "names.c" /* XXX */ + +void cpustats __P((void)); +void dkstats __P((void)); +void phdr __P((int)); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register int i; + long tmp; + int ch, hdrcnt, reps, interval, stathz, ndrives; + char **cp, *memf, *nlistf, buf[30]; + char errbuf[_POSIX2_LINE_MAX]; + + interval = reps = 0; + nlistf = memf = NULL; + while ((ch = getopt(argc, argv, "c:M:N:w:")) != EOF) + switch(ch) { + case 'c': + if ((reps = atoi(optarg)) <= 0) + errx(1, "repetition count <= 0."); + break; + case 'M': + memf = optarg; + break; + case 'N': + nlistf = optarg; + break; + case 'w': + if ((interval = atoi(optarg)) <= 0) + errx(1, "interval <= 0."); + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + /* + * Discard setgid privileges if not the running kernel so that bad + * guys can't print interesting stuff from kernel memory. + */ + if (nlistf != NULL || memf != NULL) + setgid(getgid()); + + kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); + if (kd == 0) + errx(1, "kvm_openfiles: %s", errbuf); + if (kvm_nlist(kd, namelist) == -1) + errx(1, "kvm_nlist: %s", kvm_geterr(kd)); + if (namelist[X_DK_NDRIVE].n_type == 0) + errx(1, "dk_ndrive not found in namelist"); + (void)nlread(X_DK_NDRIVE, dk_ndrive); + if (dk_ndrive <= 0) + errx(1, "invalid dk_ndrive %d\n", dk_ndrive); + + cur.dk_time = calloc(dk_ndrive, sizeof(long)); + cur.dk_wds = calloc(dk_ndrive, sizeof(long)); + cur.dk_seek = calloc(dk_ndrive, sizeof(long)); + cur.dk_xfer = calloc(dk_ndrive, sizeof(long)); + last.dk_time = calloc(dk_ndrive, sizeof(long)); + last.dk_wds = calloc(dk_ndrive, sizeof(long)); + last.dk_seek = calloc(dk_ndrive, sizeof(long)); + last.dk_xfer = calloc(dk_ndrive, sizeof(long)); + dr_select = calloc(dk_ndrive, sizeof(int)); + dr_name = calloc(dk_ndrive, sizeof(char *)); + dk_wpms = calloc(dk_ndrive, sizeof(long)); + + for (i = 0; i < dk_ndrive; i++) { + (void)sprintf(buf, "dk%d", i); + dr_name[i] = strdup(buf); + } + if (!read_names()) + exit(1); + (void)nlread(X_HZ, hz); + (void)nlread(X_STATHZ, stathz); + if (stathz) + hz = stathz; + (void)kvm_read(kd, namelist[X_DK_WPMS].n_value, dk_wpms, + dk_ndrive * sizeof(dk_wpms)); + + /* + * Choose drives to be displayed. Priority goes to (in order) drives + * supplied as arguments and default drives. If everything isn't + * filled in and there are drives not taken care of, display the first + * few that fit. + * + * The backward compatibility #ifdefs permit the syntax: + * iostat [ drives ] [ interval [ count ] ] + */ +#define BACKWARD_COMPATIBILITY + for (ndrives = 0; *argv; ++argv) { +#ifdef BACKWARD_COMPATIBILITY + if (isdigit(**argv)) + break; +#endif + for (i = 0; i < dk_ndrive; i++) { + if (strcmp(dr_name[i], *argv)) + continue; + dr_select[i] = 1; + ++ndrives; + } + } +#ifdef BACKWARD_COMPATIBILITY + if (*argv) { + interval = atoi(*argv); + if (*++argv) + reps = atoi(*argv); + } +#endif + + if (interval) { + if (!reps) + reps = -1; + } else + if (reps) + interval = 1; + + for (i = 0; i < dk_ndrive && ndrives < 4; i++) { + if (dr_select[i] || dk_wpms[i] == 0) + continue; + for (cp = defdrives; *cp; cp++) + if (strcmp(dr_name[i], *cp) == 0) { + dr_select[i] = 1; + ++ndrives; + break; + } + } + for (i = 0; i < dk_ndrive && ndrives < 4; i++) { + if (dr_select[i]) + continue; + dr_select[i] = 1; + ++ndrives; + } + + (void)signal(SIGCONT, phdr); + + for (hdrcnt = 1;;) { + if (!--hdrcnt) { + phdr(0); + hdrcnt = 20; + } + (void)kvm_read(kd, namelist[X_DK_TIME].n_value, + cur.dk_time, dk_ndrive * sizeof(long)); + (void)kvm_read(kd, namelist[X_DK_XFER].n_value, + cur.dk_xfer, dk_ndrive * sizeof(long)); + (void)kvm_read(kd, namelist[X_DK_WDS].n_value, + cur.dk_wds, dk_ndrive * sizeof(long)); + (void)kvm_read(kd, namelist[X_DK_SEEK].n_value, + cur.dk_seek, dk_ndrive * sizeof(long)); + (void)kvm_read(kd, namelist[X_TK_NIN].n_value, + &cur.tk_nin, sizeof(cur.tk_nin)); + (void)kvm_read(kd, namelist[X_TK_NOUT].n_value, + &cur.tk_nout, sizeof(cur.tk_nout)); + (void)kvm_read(kd, namelist[X_CP_TIME].n_value, + cur.cp_time, sizeof(cur.cp_time)); + for (i = 0; i < dk_ndrive; i++) { + if (!dr_select[i]) + continue; +#define X(fld) tmp = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = tmp + X(dk_xfer); + X(dk_seek); + X(dk_wds); + X(dk_time); + } + tmp = cur.tk_nin; + cur.tk_nin -= last.tk_nin; + last.tk_nin = tmp; + tmp = cur.tk_nout; + cur.tk_nout -= last.tk_nout; + last.tk_nout = tmp; + etime = 0; + for (i = 0; i < CPUSTATES; i++) { + X(cp_time); + etime += cur.cp_time[i]; + } + if (etime == 0.0) + etime = 1.0; + etime /= (float)hz; + (void)printf("%4.0f%5.0f", + cur.tk_nin / etime, cur.tk_nout / etime); + dkstats(); + cpustats(); + (void)printf("\n"); + (void)fflush(stdout); + + if (reps >= 0 && --reps <= 0) + break; + (void)sleep(interval); + } + exit(0); +} + +/* ARGUSED */ +void +phdr(signo) + int signo; +{ + register int i; + + (void)printf(" tty"); + for (i = 0; i < dk_ndrive; i++) + if (dr_select[i]) + (void)printf(" %3.3s ", dr_name[i]); + (void)printf(" cpu\n tin tout"); + for (i = 0; i < dk_ndrive; i++) + if (dr_select[i]) + (void)printf(" sps tps msps "); + (void)printf(" us ni sy in id\n"); +} + +void +dkstats() +{ + register int dn; + double atime, itime, msps, words, xtime; + + for (dn = 0; dn < dk_ndrive; ++dn) { + if (!dr_select[dn]) + continue; + words = cur.dk_wds[dn] * 32; /* words xfer'd */ + (void)printf("%4.0f", /* sectors */ + words / (DEV_BSIZE / 2) / etime); + + (void)printf("%4.0f", cur.dk_xfer[dn] / etime); + + if (dk_wpms[dn] && cur.dk_xfer[dn]) { + atime = cur.dk_time[dn]; /* ticks disk busy */ + atime /= (float)hz; /* ticks to seconds */ + xtime = words / dk_wpms[dn]; /* transfer time */ + itime = atime - xtime; /* time not xfer'ing */ + if (itime < 0) + msps = 0; + else + msps = itime * 1000 / cur.dk_xfer[dn]; + } else + msps = 0; + (void)printf("%5.1f ", msps); + } +} + +void +cpustats() +{ + register int state; + double time; + + time = 0; + for (state = 0; state < CPUSTATES; ++state) + time += cur.cp_time[state]; + for (state = 0; state < CPUSTATES; ++state) + (void)printf("%3.0f", + 100. * cur.cp_time[state] / (time ? time : 1)); +} + +void +usage() +{ + (void)fprintf(stderr, +"usage: iostat [-c count] [-M core] [-N system] [-w wait] [drives]\n"); + exit(1); +} diff --git a/usr.sbin/mtree/Makefile b/usr.sbin/mtree/Makefile new file mode 100644 index 000000000000..c8f6b35778df --- /dev/null +++ b/usr.sbin/mtree/Makefile @@ -0,0 +1,9 @@ +# @(#)Makefile 8.2 (Berkeley) 4/27/95 + +PROG= mtree +MAN8= mtree.0 +#CFLAGS+=-DDEBUG +SRCS= compare.c crc.c create.c misc.c mtree.c spec.c verify.c +.PATH: ${.CURDIR}/../../usr.bin/cksum + +.include diff --git a/usr.sbin/mtree/spec.c b/usr.sbin/mtree/spec.c new file mode 100644 index 000000000000..bb40471ad502 --- /dev/null +++ b/usr.sbin/mtree/spec.c @@ -0,0 +1,280 @@ +/*- + * Copyright (c) 1989, 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 sccsid[] = "@(#)spec.c 8.2 (Berkeley) 4/28/95"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mtree.h" +#include "extern.h" + +int lineno; /* Current spec line number. */ + +static void set __P((char *, NODE *)); +static void unset __P((char *, NODE *)); + +NODE * +spec() +{ + register NODE *centry, *last; + register char *p; + NODE ginfo, *root; + int c_cur, c_next; + char buf[2048]; + + root = NULL; + bzero(&ginfo, sizeof(ginfo)); + c_cur = c_next = 0; + for (lineno = 1; fgets(buf, sizeof(buf), stdin); + ++lineno, c_cur = c_next, c_next = 0) { + /* Skip empty lines. */ + if (buf[0] == '\n') + continue; + + /* Find end of line. */ + if ((p = index(buf, '\n')) == NULL) + err("line %d too long", lineno); + + /* See if next line is continuation line. */ + if (p[-1] == '\\') { + --p; + c_next = 1; + } + + /* Null-terminate the line. */ + *p = '\0'; + + /* Skip leading whitespace. */ + for (p = buf; *p && isspace(*p); ++p); + + /* If nothing but whitespace or comment char, continue. */ + if (!*p || *p == '#') + continue; + +#ifdef DEBUG + (void)fprintf(stderr, "line %d: {%s}\n", lineno, p); +#endif + if (c_cur) { + set(p, centry); + continue; + } + + /* Grab file name, "$", "set", or "unset". */ + if ((p = strtok(p, "\n\t ")) == NULL) + err("missing field"); + + if (p[0] == '/') + switch(p[1]) { + case 's': + if (strcmp(p + 1, "set")) + break; + set(NULL, &ginfo); + continue; + case 'u': + if (strcmp(p + 1, "unset")) + break; + unset(NULL, &ginfo); + continue; + } + + if (index(p, '/')) + err("slash character in file name"); + + if (!strcmp(p, "..")) { + /* Don't go up, if haven't gone down. */ + if (!root) + goto noparent; + if (last->type != F_DIR || last->flags & F_DONE) { + if (last == root) + goto noparent; + last = last->parent; + } + last->flags |= F_DONE; + continue; + +noparent: err("no parent node"); + } + + if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL) + err("%s", strerror(errno)); + *centry = ginfo; + (void)strcpy(centry->name, p); +#define MAGIC "?*[" + if (strpbrk(p, MAGIC)) + centry->flags |= F_MAGIC; + set(NULL, centry); + + if (!root) { + last = root = centry; + root->parent = root; + } else if (last->type == F_DIR && !(last->flags & F_DONE)) { + centry->parent = last; + last = last->child = centry; + } else { + centry->parent = last->parent; + centry->prev = last; + last = last->next = centry; + } + } + return (root); +} + +static void +set(t, ip) + char *t; + register NODE *ip; +{ + register int type; + register char *kw, *val; + struct group *gr; + struct passwd *pw; + mode_t *m; + int value; + char *ep; + + for (; kw = strtok(t, "= \t\n"); t = NULL) { + ip->flags |= type = parsekey(kw, &value); + if (value && (val = strtok(NULL, " \t\n")) == NULL) + err("missing value"); + switch(type) { + case F_CKSUM: + ip->cksum = strtoul(val, &ep, 10); + if (*ep) + err("invalid checksum %s", val); + break; + case F_GID: + ip->st_gid = strtoul(val, &ep, 10); + if (*ep) + err("invalid gid %s", val); + break; + case F_GNAME: + if ((gr = getgrnam(val)) == NULL) + err("unknown group %s", val); + ip->st_gid = gr->gr_gid; + break; + case F_IGN: + /* just set flag bit */ + break; + case F_MODE: + if ((m = setmode(val)) == NULL) + err("invalid file mode %s", val); + ip->st_mode = getmode(m, 0); + break; + case F_NLINK: + ip->st_nlink = strtoul(val, &ep, 10); + if (*ep) + err("invalid link count %s", val); + break; + case F_SIZE: + ip->st_size = strtouq(val, &ep, 10); + if (*ep) + err("invalid size %s", val); + break; + case F_SLINK: + if ((ip->slink = strdup(val)) == NULL) + err("%s", strerror(errno)); + break; + case F_TIME: + ip->st_mtimespec.ts_sec = strtoul(val, &ep, 10); + if (*ep != '.') + err("invalid time %s", val); + val = ep + 1; + ip->st_mtimespec.ts_nsec = strtoul(val, &ep, 10); + if (*ep) + err("invalid time %s", val); + break; + case F_TYPE: + switch(*val) { + case 'b': + if (!strcmp(val, "block")) + ip->type = F_BLOCK; + break; + case 'c': + if (!strcmp(val, "char")) + ip->type = F_CHAR; + break; + case 'd': + if (!strcmp(val, "dir")) + ip->type = F_DIR; + break; + case 'f': + if (!strcmp(val, "file")) + ip->type = F_FILE; + if (!strcmp(val, "fifo")) + ip->type = F_FIFO; + break; + case 'l': + if (!strcmp(val, "link")) + ip->type = F_LINK; + break; + case 's': + if (!strcmp(val, "socket")) + ip->type = F_SOCK; + break; + default: + err("unknown file type %s", val); + } + break; + case F_UID: + ip->st_uid = strtoul(val, &ep, 10); + if (*ep) + err("invalid uid %s", val); + break; + case F_UNAME: + if ((pw = getpwnam(val)) == NULL) + err("unknown user %s", val); + ip->st_uid = pw->pw_uid; + break; + } + } +} + +static void +unset(t, ip) + char *t; + register NODE *ip; +{ + register char *p; + + while (p = strtok(t, "\n\t ")) + ip->flags &= ~parsekey(p, NULL); +} diff --git a/usr.sbin/portmap/Makefile b/usr.sbin/portmap/Makefile new file mode 100644 index 000000000000..244a1925d0aa --- /dev/null +++ b/usr.sbin/portmap/Makefile @@ -0,0 +1,8 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= portmap +DPADD= ${LIBRPC} +LDADD= -lrpc +MAN8= portmap.0 + +.include diff --git a/usr.sbin/portmap/portmap.8 b/usr.sbin/portmap/portmap.8 new file mode 100644 index 000000000000..a651f5fb0aba --- /dev/null +++ b/usr.sbin/portmap/portmap.8 @@ -0,0 +1,110 @@ +.\" Copyright (c) 1987 Sun Microsystems +.\" Copyright (c) 1990, 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. +.\" +.\" @(#)portmap.8 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt PORTMAP 8 +.Os BSD 4.3 +.Sh NAME +.Nm portmap +.Nd +.Tn DARPA +port to +.Tn RPC +program number mapper +.Sh SYNOPSIS +.Nm portmap +.Op Fl d +.Sh DESCRIPTION +.Nm Portmap +is a server that converts +.Tn RPC +program numbers into +.Tn DARPA +protocol port numbers. +It must be running in order to make +.Tn RPC +calls. +.Pp +When an +.Tn RPC +server is started, it will tell +.Nm portmap +what port number it is listening to, and what +.Tn RPC +program numbers it is prepared to serve. +When a client wishes to make an +.Tn RPC +call to a given program number, +it will first contact +.Nm portmap +on the server machine to determine +the port number where +.Tn RPC +packets should be sent. +.Pp +.Nm Portmap +must be started before any +.Tn RPC +servers are invoked. +.Pp +Normally +.Nm portmap +forks and dissociates itself from the terminal +like any other daemon. +.Nm Portmap +then logs errors using +.Xr syslog 3 . +.Pp +Option available: +.Bl -tag -width Ds +.It Fl d +(debug) prevents +.Nm portmap +from running as a daemon, +and causes errors and debugging information +to be printed to the standard error output. +.El +.Sh SEE ALSO +.Xr inetd.conf 5 , +.Xr rpcinfo 8 , +.Xr inetd 8 +.Sh BUGS +If +.Nm portmap +crashes, all servers must be restarted. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.3 diff --git a/usr.sbin/portmap/portmap.c b/usr.sbin/portmap/portmap.c new file mode 100644 index 000000000000..3118a2839615 --- /dev/null +++ b/usr.sbin/portmap/portmap.c @@ -0,0 +1,541 @@ +/*- + * Copyright (c) 1990, 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) 1990, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)portmap.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* +@(#)portmap.c 2.3 88/08/11 4.0 RPCSRC +static char sccsid[] = "@(#)portmap.c 1.32 87/08/06 Copyr 1984 Sun Micro"; +*/ + +/* + * portmap.c, Implements the program,version to port number mapping for + * rpc. + */ + +/* + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void reg_service(); +void reap(); +static void callit(); +struct pmaplist *pmaplist; +int debugging = 0; +extern int errno; + +main(argc, argv) + int argc; + char **argv; +{ + SVCXPRT *xprt; + int sock, c; + struct sockaddr_in addr; + int len = sizeof(struct sockaddr_in); + register struct pmaplist *pml; + + while ((c = getopt(argc, argv, "d")) != EOF) { + switch (c) { + + case 'd': + debugging = 1; + break; + + default: + (void) fprintf(stderr, "usage: %s [-d]\n", argv[0]); + exit(1); + } + } + + if (!debugging && daemon(0, 0)) { + (void) fprintf(stderr, "portmap: fork: %s", strerror(errno)); + exit(1); + } + + openlog("portmap", debugging ? LOG_PID | LOG_PERROR : LOG_PID, + LOG_DAEMON); + + if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { + syslog(LOG_ERR, "cannot create udp socket: %m"); + exit(1); + } + + addr.sin_addr.s_addr = 0; + addr.sin_family = AF_INET; + addr.sin_port = htons(PMAPPORT); + if (bind(sock, (struct sockaddr *)&addr, len) != 0) { + syslog(LOG_ERR, "cannot bind udp: %m"); + exit(1); + } + + if ((xprt = svcudp_create(sock)) == (SVCXPRT *)NULL) { + syslog(LOG_ERR, "couldn't do udp_create"); + exit(1); + } + /* make an entry for ourself */ + pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist)); + pml->pml_next = 0; + pml->pml_map.pm_prog = PMAPPROG; + pml->pml_map.pm_vers = PMAPVERS; + pml->pml_map.pm_prot = IPPROTO_UDP; + pml->pml_map.pm_port = PMAPPORT; + pmaplist = pml; + + if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + syslog(LOG_ERR, "cannot create tcp socket: %m"); + exit(1); + } + if (bind(sock, (struct sockaddr *)&addr, len) != 0) { + syslog(LOG_ERR, "cannot bind udp: %m"); + exit(1); + } + if ((xprt = svctcp_create(sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE)) + == (SVCXPRT *)NULL) { + syslog(LOG_ERR, "couldn't do tcp_create"); + exit(1); + } + /* make an entry for ourself */ + pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist)); + pml->pml_map.pm_prog = PMAPPROG; + pml->pml_map.pm_vers = PMAPVERS; + pml->pml_map.pm_prot = IPPROTO_TCP; + pml->pml_map.pm_port = PMAPPORT; + pml->pml_next = pmaplist; + pmaplist = pml; + + (void)svc_register(xprt, PMAPPROG, PMAPVERS, reg_service, FALSE); + + (void)signal(SIGCHLD, reap); + svc_run(); + syslog(LOG_ERR, "run_svc returned unexpectedly"); + abort(); +} + +#ifndef lint +/* need to override perror calls in rpc library */ +void +perror(what) + const char *what; +{ + + syslog(LOG_ERR, "%s: %m", what); +} +#endif + +static struct pmaplist * +find_service(prog, vers, prot) + u_long prog, vers, prot; +{ + register struct pmaplist *hit = NULL; + register struct pmaplist *pml; + + for (pml = pmaplist; pml != NULL; pml = pml->pml_next) { + if ((pml->pml_map.pm_prog != prog) || + (pml->pml_map.pm_prot != prot)) + continue; + hit = pml; + if (pml->pml_map.pm_vers == vers) + break; + } + return (hit); +} + +/* + * 1 OK, 0 not + */ +void +reg_service(rqstp, xprt) + struct svc_req *rqstp; + SVCXPRT *xprt; +{ + struct pmap reg; + struct pmaplist *pml, *prevpml, *fnd; + int ans, port; + caddr_t t; + + if (debugging) + (void) fprintf(stderr, "server: about do a switch\n"); + switch (rqstp->rq_proc) { + + case PMAPPROC_NULL: + /* + * Null proc call + */ + if (!svc_sendreply(xprt, xdr_void, (caddr_t)0) && debugging) { + abort(); + } + break; + + case PMAPPROC_SET: + /* + * Set a program,version to port mapping + */ + if (!svc_getargs(xprt, xdr_pmap, ®)) + svcerr_decode(xprt); + else { + /* + * check to see if already used + * find_service returns a hit even if + * the versions don't match, so check for it + */ + fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot); + if (fnd && fnd->pml_map.pm_vers == reg.pm_vers) { + if (fnd->pml_map.pm_port == reg.pm_port) { + ans = 1; + goto done; + } + else { + ans = 0; + goto done; + } + } else { + /* + * add to END of list + */ + pml = (struct pmaplist *) + malloc((u_int)sizeof(struct pmaplist)); + pml->pml_map = reg; + pml->pml_next = 0; + if (pmaplist == 0) { + pmaplist = pml; + } else { + for (fnd= pmaplist; fnd->pml_next != 0; + fnd = fnd->pml_next); + fnd->pml_next = pml; + } + ans = 1; + } + done: + if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) && + debugging) { + (void) fprintf(stderr, "svc_sendreply\n"); + abort(); + } + } + break; + + case PMAPPROC_UNSET: + /* + * Remove a program,version to port mapping. + */ + if (!svc_getargs(xprt, xdr_pmap, ®)) + svcerr_decode(xprt); + else { + ans = 0; + for (prevpml = NULL, pml = pmaplist; pml != NULL; ) { + if ((pml->pml_map.pm_prog != reg.pm_prog) || + (pml->pml_map.pm_vers != reg.pm_vers)) { + /* both pml & prevpml move forwards */ + prevpml = pml; + pml = pml->pml_next; + continue; + } + /* found it; pml moves forward, prevpml stays */ + ans = 1; + t = (caddr_t)pml; + pml = pml->pml_next; + if (prevpml == NULL) + pmaplist = pml; + else + prevpml->pml_next = pml; + free(t); + } + if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) && + debugging) { + (void) fprintf(stderr, "svc_sendreply\n"); + abort(); + } + } + break; + + case PMAPPROC_GETPORT: + /* + * Lookup the mapping for a program,version and return its port + */ + if (!svc_getargs(xprt, xdr_pmap, ®)) + svcerr_decode(xprt); + else { + fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot); + if (fnd) + port = fnd->pml_map.pm_port; + else + port = 0; + if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&port)) && + debugging) { + (void) fprintf(stderr, "svc_sendreply\n"); + abort(); + } + } + break; + + case PMAPPROC_DUMP: + /* + * Return the current set of mapped program,version + */ + if (!svc_getargs(xprt, xdr_void, NULL)) + svcerr_decode(xprt); + else { + if ((!svc_sendreply(xprt, xdr_pmaplist, + (caddr_t)&pmaplist)) && debugging) { + (void) fprintf(stderr, "svc_sendreply\n"); + abort(); + } + } + break; + + case PMAPPROC_CALLIT: + /* + * Calls a procedure on the local machine. If the requested + * procedure is not registered this procedure does not return + * error information!! + * This procedure is only supported on rpc/udp and calls via + * rpc/udp. It passes null authentication parameters. + */ + callit(rqstp, xprt); + break; + + default: + svcerr_noproc(xprt); + break; + } +} + + +/* + * Stuff for the rmtcall service + */ +#define ARGSIZE 9000 + +struct encap_parms { + u_long arglen; + char *args; +}; + +static bool_t +xdr_encap_parms(xdrs, epp) + XDR *xdrs; + struct encap_parms *epp; +{ + + return (xdr_bytes(xdrs, &(epp->args), &(epp->arglen), ARGSIZE)); +} + +struct rmtcallargs { + u_long rmt_prog; + u_long rmt_vers; + u_long rmt_port; + u_long rmt_proc; + struct encap_parms rmt_args; +}; + +static bool_t +xdr_rmtcall_args(xdrs, cap) + register XDR *xdrs; + register struct rmtcallargs *cap; +{ + + /* does not get a port number */ + if (xdr_u_long(xdrs, &(cap->rmt_prog)) && + xdr_u_long(xdrs, &(cap->rmt_vers)) && + xdr_u_long(xdrs, &(cap->rmt_proc))) { + return (xdr_encap_parms(xdrs, &(cap->rmt_args))); + } + return (FALSE); +} + +static bool_t +xdr_rmtcall_result(xdrs, cap) + register XDR *xdrs; + register struct rmtcallargs *cap; +{ + if (xdr_u_long(xdrs, &(cap->rmt_port))) + return (xdr_encap_parms(xdrs, &(cap->rmt_args))); + return (FALSE); +} + +/* + * only worries about the struct encap_parms part of struct rmtcallargs. + * The arglen must already be set!! + */ +static bool_t +xdr_opaque_parms(xdrs, cap) + XDR *xdrs; + struct rmtcallargs *cap; +{ + + return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen)); +} + +/* + * This routine finds and sets the length of incoming opaque paraters + * and then calls xdr_opaque_parms. + */ +static bool_t +xdr_len_opaque_parms(xdrs, cap) + register XDR *xdrs; + struct rmtcallargs *cap; +{ + register u_int beginpos, lowpos, highpos, currpos, pos; + + beginpos = lowpos = pos = xdr_getpos(xdrs); + highpos = lowpos + ARGSIZE; + while ((int)(highpos - lowpos) >= 0) { + currpos = (lowpos + highpos) / 2; + if (xdr_setpos(xdrs, currpos)) { + pos = currpos; + lowpos = currpos + 1; + } else { + highpos = currpos - 1; + } + } + xdr_setpos(xdrs, beginpos); + cap->rmt_args.arglen = pos - beginpos; + return (xdr_opaque_parms(xdrs, cap)); +} + +/* + * Call a remote procedure service + * This procedure is very quiet when things go wrong. + * The proc is written to support broadcast rpc. In the broadcast case, + * a machine should shut-up instead of complain, less the requestor be + * overrun with complaints at the expense of not hearing a valid reply ... + * + * This now forks so that the program & process that it calls can call + * back to the portmapper. + */ +static void +callit(rqstp, xprt) + struct svc_req *rqstp; + SVCXPRT *xprt; +{ + struct rmtcallargs a; + struct pmaplist *pml; + u_short port; + struct sockaddr_in me; + int pid, so = -1; + CLIENT *client; + struct authunix_parms *au = (struct authunix_parms *)rqstp->rq_clntcred; + struct timeval timeout; + char buf[ARGSIZE]; + + timeout.tv_sec = 5; + timeout.tv_usec = 0; + a.rmt_args.args = buf; + if (!svc_getargs(xprt, xdr_rmtcall_args, &a)) + return; + if ((pml = find_service(a.rmt_prog, a.rmt_vers, + (u_long)IPPROTO_UDP)) == NULL) + return; + /* + * fork a child to do the work. Parent immediately returns. + * Child exits upon completion. + */ + if ((pid = fork()) != 0) { + if (pid < 0) + syslog(LOG_ERR, "CALLIT (prog %lu): fork: %m", + a.rmt_prog); + return; + } + port = pml->pml_map.pm_port; + get_myaddress(&me); + me.sin_port = htons(port); + client = clntudp_create(&me, a.rmt_prog, a.rmt_vers, timeout, &so); + if (client != (CLIENT *)NULL) { + if (rqstp->rq_cred.oa_flavor == AUTH_UNIX) { + client->cl_auth = authunix_create(au->aup_machname, + au->aup_uid, au->aup_gid, au->aup_len, au->aup_gids); + } + a.rmt_port = (u_long)port; + if (clnt_call(client, a.rmt_proc, xdr_opaque_parms, &a, + xdr_len_opaque_parms, &a, timeout) == RPC_SUCCESS) { + svc_sendreply(xprt, xdr_rmtcall_result, (caddr_t)&a); + } + AUTH_DESTROY(client->cl_auth); + clnt_destroy(client); + } + (void)close(so); + exit(0); +} + +void +reap() +{ + while (wait3((int *)NULL, WNOHANG, (struct rusage *)NULL) > 0); +} diff --git a/usr.sbin/pwd_mkdb/pwd_mkdb.8 b/usr.sbin/pwd_mkdb/pwd_mkdb.8 new file mode 100644 index 000000000000..3d012e343216 --- /dev/null +++ b/usr.sbin/pwd_mkdb/pwd_mkdb.8 @@ -0,0 +1,128 @@ +.\" Copyright (c) 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. +.\" +.\" @(#)pwd_mkdb.8 8.2 (Berkeley) 4/27/95 +.\" +.Dd April 27, 1995 +.Dt PWD_MKDB 8 +.Os +.Sh NAME +.Nm pwd_mkdb +.Nd "generate the password databases" +.Sh SYNOPSIS +.Nm pwd_mkdb +.Op Fl p +.Ar file +.Sh DESCRIPTION +.Nm Pwd_mkdb +creates +.Xr db 3 +style secure and insecure databases for the specified file. +These databases are then installed into +.Dq Pa /etc/spwd.db +and +.Dq Pa /etc/pwd.db +respectively. +The file is installed into +.Dq Pa /etc/master.passwd . +The file must be in the correct format (see +.Xr passwd 5 ) . +It is important to note that the format used in this system is +different from the historic Version 7 style format. +.Pp +The options are as follows: +.Bl -tag -width flag +.It Fl p +Create a Version 7 style password file and install it into +.Dq Pa /etc/passwd . +.El +.Pp +The two databases differ in that the secure version contains the user's +encrypted password and the insecure version has an asterisk (``*'') +.Pp +The databases are used by the C library password routines (see +.Xr getpwent 3 ) . +.Pp +.Nm Pwd_mkdb +exits zero on success, non-zero on failure. +.Sh FILES +.Bl -tag -width Pa -compact +.It Pa /etc/master.passwd +The current password file. +.It Pa /etc/passwd +A Version 7 format password file. +.It Pa /etc/pwd.db +The insecure password database file. +.It Pa /etc/pwd.db.tmp +A temporary file. +.It Pa /etc/spwd.db +The secure password database file. +.It Pa /etc/spwd.db.tmp +A temporary file. +.El +.Sh BUGS +Because of the necessity for atomic update of the password files, +.Nm pwd_mkdb +uses +.Xr rename 2 +to install them. +This, however, requires that the file specified on the command line live +on the same file system as the +.Dq Pa /etc +directory. +.Pp +There are the obvious races with multiple people running +.Nm pwd_mkdb +on different password files at the same time. +The front-ends to +.Nm pwd_mkdb , +.Xr chpass 1 , +.Xr passwd 1 +and +.Xr vipw 8 , +handle the locking necessary to avoid this problem. +.Sh COMPATIBILITY +Previous versions of the system had a program similar to +.Nm pwd_mkdb , +.Xr mkpasswd 8 , +which built +.Xr dbm 3 +style databases for the password file but depended on the calling programs +to install them. +The program was renamed in order that previous users of the program +not be surprised by the changes in functionality. +.Sh SEE ALSO +.Xr chpass 1 , +.Xr passwd 1 , +.Xr db 3 , +.Xr getpwent 3 , +.Xr passwd 5 , +.Xr vipw 8 diff --git a/usr.sbin/quot/quot.8 b/usr.sbin/quot/quot.8 new file mode 100644 index 000000000000..b1aefdebe668 --- /dev/null +++ b/usr.sbin/quot/quot.8 @@ -0,0 +1,84 @@ +.\" 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. +.\" +.\" @(#)quot.8 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt QUOT 8 +.Os BSD 4 +.Sh NAME +.Nm quot +.Nd display total block usage per user for a file system +.Sh SYNOPSIS +.Nm quot +.Op Fl ncf +.Op Ar filesystem Ar ... +.Sh DESCRIPTION +The +.Nm quot +command +displays the total count of blocks owned by a user for the filesystem +.Ar filesystem . +If the filesystem option +.Ar filesystem +is not specified, +the file systems listed in +.Pa /etc/fstab +are used. +The following options are available: +.Bl -tag -width Ds +.It Fl c +Display information on file size and block usage. The file sizes +are listed in the first column, the second column contains a count +of how many files of that size were found and the third column +lists the cumulative block usage for the displayed size and all smaller +files. +.It Fl f +For each user, +the number of files (inodes) owned is displayed in addition +to the block usage. +.It Fl n +A list sorted by block usage is displayed. +This is the result of +.Nm quot +executing the following command: +.Bd -literal -offset indent +ncheck filesystem \&| sort +0n \&| quot \-n filesystem +.Ed +.El +.Sh SEE ALSO +.Xr ls 1 , +.Xr du 1 +.Sh HISTORY +The +.Nm +command appeared in +.At 32v . diff --git a/usr.sbin/repquota/repquota.c b/usr.sbin/repquota/repquota.c new file mode 100644 index 000000000000..a37cea061157 --- /dev/null +++ b/usr.sbin/repquota/repquota.c @@ -0,0 +1,380 @@ +/* + * Copyright (c) 1980, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Elz at The University of Melbourne. + * + * 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) 1980, 1990, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)repquota.c 8.2 (Berkeley) 11/22/94"; +#endif /* not lint */ + +/* + * Quota report + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char *qfname = QUOTAFILENAME; +char *qfextension[] = INITQFNAMES; + +struct fileusage { + struct fileusage *fu_next; + struct dqblk fu_dqblk; + u_long fu_id; + char fu_name[1]; + /* actually bigger */ +}; +#define FUHASH 1024 /* must be power of two */ +struct fileusage *fuhead[MAXQUOTAS][FUHASH]; +struct fileusage *lookup(); +struct fileusage *addid(); +u_long highid[MAXQUOTAS]; /* highest addid()'ed identifier per type */ + +int vflag; /* verbose */ +int aflag; /* all file systems */ + +main(argc, argv) + int argc; + char **argv; +{ + register struct fstab *fs; + register struct passwd *pw; + register struct group *gr; + int gflag = 0, uflag = 0, errs = 0; + long i, argnum, done = 0; + extern char *optarg; + extern int optind; + char ch, *qfnp; + + while ((ch = getopt(argc, argv, "aguv")) != EOF) { + switch(ch) { + case 'a': + aflag++; + break; + case 'g': + gflag++; + break; + case 'u': + uflag++; + break; + case 'v': + vflag++; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + if (argc == 0 && !aflag) + usage(); + if (!gflag && !uflag) { + if (aflag) + gflag++; + uflag++; + } + if (gflag) { + setgrent(); + while ((gr = getgrent()) != 0) + (void) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name); + endgrent(); + } + if (uflag) { + setpwent(); + while ((pw = getpwent()) != 0) + (void) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name); + endpwent(); + } + setfsent(); + while ((fs = getfsent()) != NULL) { + if (strcmp(fs->fs_vfstype, "ufs")) + continue; + if (aflag) { + if (gflag && hasquota(fs, GRPQUOTA, &qfnp)) + errs += repquota(fs, GRPQUOTA, qfnp); + if (uflag && hasquota(fs, USRQUOTA, &qfnp)) + errs += repquota(fs, USRQUOTA, qfnp); + continue; + } + if ((argnum = oneof(fs->fs_file, argv, argc)) >= 0 || + (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) { + done |= 1 << argnum; + if (gflag && hasquota(fs, GRPQUOTA, &qfnp)) + errs += repquota(fs, GRPQUOTA, qfnp); + if (uflag && hasquota(fs, USRQUOTA, &qfnp)) + errs += repquota(fs, USRQUOTA, qfnp); + } + } + endfsent(); + for (i = 0; i < argc; i++) + if ((done & (1 << i)) == 0) + fprintf(stderr, "%s not found in fstab\n", argv[i]); + exit(errs); +} + +usage() +{ + fprintf(stderr, "Usage:\n\t%s\n\t%s\n", + "repquota [-v] [-g] [-u] -a", + "repquota [-v] [-g] [-u] filesys ..."); + exit(1); +} + +repquota(fs, type, qfpathname) + register struct fstab *fs; + int type; + char *qfpathname; +{ + register struct fileusage *fup; + FILE *qf; + u_long id; + struct dqblk dqbuf; + char *timeprt(); + static struct dqblk zerodqblk; + static int warned = 0; + static int multiple = 0; + extern int errno; + + if (quotactl(fs->fs_file, QCMD(Q_SYNC, type), 0, 0) < 0 && + errno == EOPNOTSUPP && !warned && vflag) { + warned++; + fprintf(stdout, + "*** Warning: Quotas are not compiled into this kernel\n"); + } + if (multiple++) + printf("\n"); + if (vflag) + fprintf(stdout, "*** Report for %s quotas on %s (%s)\n", + qfextension[type], fs->fs_file, fs->fs_spec); + if ((qf = fopen(qfpathname, "r")) == NULL) { + perror(qfpathname); + return (1); + } + for (id = 0; ; id++) { + fread(&dqbuf, sizeof(struct dqblk), 1, qf); + if (feof(qf)) + break; + if (dqbuf.dqb_curinodes == 0 && dqbuf.dqb_curblocks == 0) + continue; + if ((fup = lookup(id, type)) == 0) + fup = addid(id, type, (char *)0); + fup->fu_dqblk = dqbuf; + } + fclose(qf); + printf(" Block limits File limits\n"); + printf("User used soft hard grace used soft hard grace\n"); + for (id = 0; id <= highid[type]; id++) { + fup = lookup(id, type); + if (fup == 0) + continue; + if (fup->fu_dqblk.dqb_curinodes == 0 && + fup->fu_dqblk.dqb_curblocks == 0) + continue; + printf("%-10s", fup->fu_name); + printf("%c%c%8d%8d%8d%7s", + fup->fu_dqblk.dqb_bsoftlimit && + fup->fu_dqblk.dqb_curblocks >= + fup->fu_dqblk.dqb_bsoftlimit ? '+' : '-', + fup->fu_dqblk.dqb_isoftlimit && + fup->fu_dqblk.dqb_curinodes >= + fup->fu_dqblk.dqb_isoftlimit ? '+' : '-', + dbtob(fup->fu_dqblk.dqb_curblocks) / 1024, + dbtob(fup->fu_dqblk.dqb_bsoftlimit) / 1024, + dbtob(fup->fu_dqblk.dqb_bhardlimit) / 1024, + fup->fu_dqblk.dqb_bsoftlimit && + fup->fu_dqblk.dqb_curblocks >= + fup->fu_dqblk.dqb_bsoftlimit ? + timeprt(fup->fu_dqblk.dqb_btime) : ""); + printf(" %6d%6d%6d%7s\n", + fup->fu_dqblk.dqb_curinodes, + fup->fu_dqblk.dqb_isoftlimit, + fup->fu_dqblk.dqb_ihardlimit, + fup->fu_dqblk.dqb_isoftlimit && + fup->fu_dqblk.dqb_curinodes >= + fup->fu_dqblk.dqb_isoftlimit ? + timeprt(fup->fu_dqblk.dqb_itime) : ""); + fup->fu_dqblk = zerodqblk; + } + return (0); +} + +/* + * Check to see if target appears in list of size cnt. + */ +oneof(target, list, cnt) + register char *target, *list[]; + int cnt; +{ + register int i; + + for (i = 0; i < cnt; i++) + if (strcmp(target, list[i]) == 0) + return (i); + return (-1); +} + +/* + * Check to see if a particular quota is to be enabled. + */ +hasquota(fs, type, qfnamep) + register struct fstab *fs; + int type; + char **qfnamep; +{ + register char *opt; + char *cp, *index(), *strtok(); + static char initname, usrname[100], grpname[100]; + static char buf[BUFSIZ]; + + if (!initname) { + sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname); + sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname); + initname = 1; + } + strcpy(buf, fs->fs_mntops); + for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { + if (cp = index(opt, '=')) + *cp++ = '\0'; + if (type == USRQUOTA && strcmp(opt, usrname) == 0) + break; + if (type == GRPQUOTA && strcmp(opt, grpname) == 0) + break; + } + if (!opt) + return (0); + if (cp) { + *qfnamep = cp; + return (1); + } + (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]); + *qfnamep = buf; + return (1); +} + +/* + * Routines to manage the file usage table. + * + * Lookup an id of a specific type. + */ +struct fileusage * +lookup(id, type) + u_long id; + int type; +{ + register struct fileusage *fup; + + for (fup = fuhead[type][id & (FUHASH-1)]; fup != 0; fup = fup->fu_next) + if (fup->fu_id == id) + return (fup); + return ((struct fileusage *)0); +} + +/* + * Add a new file usage id if it does not already exist. + */ +struct fileusage * +addid(id, type, name) + u_long id; + int type; + char *name; +{ + struct fileusage *fup, **fhp; + int len; + extern char *calloc(); + + if (fup = lookup(id, type)) + return (fup); + if (name) + len = strlen(name); + else + len = 10; + if ((fup = (struct fileusage *)calloc(1, sizeof(*fup) + len)) == NULL) { + fprintf(stderr, "out of memory for fileusage structures\n"); + exit(1); + } + fhp = &fuhead[type][id & (FUHASH - 1)]; + fup->fu_next = *fhp; + *fhp = fup; + fup->fu_id = id; + if (id > highid[type]) + highid[type] = id; + if (name) { + bcopy(name, fup->fu_name, len + 1); + } else { + sprintf(fup->fu_name, "%u", id); + } + return (fup); +} + +/* + * Calculate the grace period and return a printable string for it. + */ +char * +timeprt(seconds) + time_t seconds; +{ + time_t hours, minutes; + static char buf[20]; + static time_t now; + + if (now == 0) + time(&now); + if (now > seconds) + return ("none"); + seconds -= now; + minutes = (seconds + 30) / 60; + hours = (minutes + 30) / 60; + if (hours >= 36) { + sprintf(buf, "%ddays", (hours + 12) / 24); + return (buf); + } + if (minutes >= 60) { + sprintf(buf, "%2d:%d", minutes / 60, minutes % 60); + return (buf); + } + sprintf(buf, "%2d", minutes); + return (buf); +} diff --git a/usr.sbin/rmt/rmt.8 b/usr.sbin/rmt/rmt.8 new file mode 100644 index 000000000000..dd3fead7eeee --- /dev/null +++ b/usr.sbin/rmt/rmt.8 @@ -0,0 +1,218 @@ +.\" Copyright (c) 1983, 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. +.\" +.\" @(#)rmt.8 8.3 (Berkeley) 6/1/94 +.\" +.Dd June 1, 1994 +.Dt RMT 8 +.Os BSD 4.2 +.Sh NAME +.Nm rmt +.Nd remote magtape protocol module +.Sh SYNOPSIS +.Nm rmt +.Sh DESCRIPTION +.Nm Rmt +is a program used by the remote dump and restore programs +in manipulating a magnetic tape drive through an interprocess +communication connection. +.Nm Rmt +is normally started up with an +.Xr rexec 3 +or +.Xr rcmd 3 +call. +.Pp +The +.Nm rmt +program accepts requests specific to the manipulation of +magnetic tapes, performs the commands, then responds with +a status indication. All responses are in +.Tn ASCII +and in +one of two forms. +Successful commands have responses of: +.Bd -filled -offset indent +.Sm off +.Sy A Ar number No \en +.Sm on +.Ed +.Pp +.Ar Number +is an +.Tn ASCII +representation of a decimal number. +Unsuccessful commands are responded to with: +.Bd -filled -offset indent +.Sm off +.Xo Sy E Ar error-number +.No \en Ar error-message +.No \en +.Xc +.Sm on +.Ed +.Pp +.Ar Error-number +is one of the possible error +numbers described in +.Xr intro 2 +and +.Ar error-message +is the corresponding error string as printed +from a call to +.Xr perror 3 . +The protocol is comprised of the +following commands, which are sent as indicated - no spaces are supplied +between the command and its arguments, or between its arguments, and +.Ql \en +indicates that a newline should be supplied: +.Bl -tag -width Ds +.Sm off +.It Xo Sy \&O Ar device +.No \en Ar mode No \en +.Xc +Open the specified +.Ar device +using the indicated +.Ar mode . +.Ar Device +is a full pathname and +.Ar mode +is an +.Tn ASCII +representation of a decimal +number suitable for passing to +.Xr open 2 . +If a device had already been opened, it is +closed before a new open is performed. +.It Xo Sy C Ar device No \en +.Xc +Close the currently open device. The +.Ar device +specified is ignored. +.It Xo Sy L +.Ar whence No \en +.Ar offset No \en +.Xc +.Sm on +Perform an +.Xr lseek 2 +operation using the specified parameters. +The response value is that returned from the +.Xr lseek +call. +.Sm off +.It Sy W Ar count No \en +.Sm on +Write data onto the open device. +.Nm Rmt +reads +.Ar count +bytes from the connection, aborting if +a premature end-of-file is encountered. +The response value is that returned from +the +.Xr write 2 +call. +.Sm off +.It Sy R Ar count No \en +.Sm on +Read +.Ar count +bytes of data from the open device. +If +.Ar count +exceeds the size of the data buffer (10 kilobytes), it is +truncated to the data buffer size. +.Nm rmt +then performs the requested +.Xr read 2 +and responds with +.Sm off +.Sy A Ar count-read No \en +.Sm on +if the read was +successful; otherwise an error in the +standard format is returned. If the read +was successful, the data read is then sent. +.Sm off +.It Xo Sy I Ar operation +.No \en Ar count No \en +.Xc +.Sm on +Perform a +.Dv MTIOCOP +.Xr ioctl 2 +command using the specified parameters. +The parameters are interpreted as the +.Tn ASCII +representations of the decimal values +to place in the +.Ar mt_op +and +.Ar mt_count +fields of the structure used in the +.Xr ioctl +call. The return value is the +.Ar count +parameter when the operation is successful. +.ne 1i +.It Sy S +Return the status of the open device, as +obtained with a +.Dv MTIOCGET +.Xr ioctl +call. If the operation was successful, +an ``ack'' is sent with the size of the +status buffer, then the status buffer is +sent (in binary). +.El +.Sm on +.Pp +Any other command causes +.Nm rmt +to exit. +.Sh DIAGNOSTICS +All responses are of the form described above. +.Sh SEE ALSO +.Xr rcmd 3 , +.Xr rexec 3 , +.Xr mtio 4 , +.Xr rdump 8 , +.Xr rrestore 8 +.Sh BUGS +People should be discouraged from using this for a remote +file access protocol. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.2 . diff --git a/usr.sbin/sendmail/README b/usr.sbin/sendmail/README new file mode 100644 index 000000000000..9b91f7e58d6b --- /dev/null +++ b/usr.sbin/sendmail/README @@ -0,0 +1,4 @@ +The beta version of sendmail 2.7.0 was removed at the developers request. + +You can FTP the latest version from ftp.cs.berkeley.edu:/ucb/sendmail + diff --git a/usr.sbin/sliplogin/slip.hosts b/usr.sbin/sliplogin/slip.hosts new file mode 100644 index 000000000000..f6ebf4095605 --- /dev/null +++ b/usr.sbin/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/usr.sbin/sliplogin/slip.login b/usr.sbin/sliplogin/slip.login new file mode 100644 index 000000000000..3c70095a2fcc --- /dev/null +++ b/usr.sbin/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/sysctl/sysctl.8 b/usr.sbin/sysctl/sysctl.8 new file mode 100644 index 000000000000..bc348a9d9051 --- /dev/null +++ b/usr.sbin/sysctl/sysctl.8 @@ -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. +.\" +.\" @(#)sysctl.8 8.2 (Berkeley) 5/9/95 +.\" +.Dd "May 9, 1995" +.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 +.Pp +The +.Nm sysctl +program can get or set debugging variables +that have been identified for its display. +This information can be obtained by using the command: +.Bd -literal -offset indent +sysctl debug +.Ed +In addition, +.Nm sysctl +can extract information about the filesystems that have been compiled +into the running system. +This information can be obtained by using the command: +.Bd -literal -offset indent +sysctl vfs +.Ed +By default, only filesystems that are actively being used are listed. +Use of the +.Fl A +flag lists all the filesystems compiled into the running kernel. +.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 -compact +.It Pa +definitions for top level identifiers, second level kernel and hardware +identifiers, and user level identifiers +.It Pa +definitions for second level network identifiers +.It Pa +definitions for third level profiling identifiers +.It Pa +definitions for second level virtual memory identifiers +.It Pa +definitions for third level Internet identifiers and +fourth level IP identifiers +.It Pa +definitions for fourth level ICMP identifiers +.It Pa +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/usr.sbin/sysctl/sysctl.c b/usr.sbin/sysctl/sysctl.c new file mode 100644 index 000000000000..9f42981e50c6 --- /dev/null +++ b/usr.sbin/sysctl/sysctl.c @@ -0,0 +1,644 @@ +/* + * 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.5 (Berkeley) 5/9/95"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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]; +struct ctlname *vfsname; +#ifdef CTL_MACHDEP_NAMES +struct ctlname machdepname[] = CTL_MACHDEP_NAMES; +#endif +char names[BUFSIZ]; +int lastused; + +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_VFS */ + { 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 (argc == 0 && (Aflag || aflag)) { + debuginit(); + vfsinit(); + for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++) + listall(topname[lvl1].ctl_name, &secondlevel[lvl1]); + exit(0); + } + if (argc == 0) + usage(); + for (; *argv != NULL; ++argv) + 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, len; + size_t size; + int special = 0; + void *newval = 0; + int intval, newsize = 0; + quad_t quadval; + struct list *lp; + struct vfsconf vfc; + 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_VFS) + vfsinit(); + 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_VFS: + mib[3] = mib[1]; + mib[1] = VFS_GENERIC; + mib[2] = VFS_CONF; + len = 4; + size = sizeof vfc; + if (sysctl(mib, 4, &vfc, &size, (void *)0, (size_t)0) < 0) { + perror("vfs print"); + return; + } + if (flags == 0 && vfc.vfc_refcount == 0) + return; + if (!nflag) + fprintf(stdout, "%s has %d mounted instance%s\n", + string, vfc.vfc_refcount, + vfc.vfc_refcount != 1 ? "s" : ""); + else + fprintf(stdout, "%d\n", vfc.vfc_refcount); + return; + + 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], loc, i; + size_t size; + + if (secondlevel[CTL_DEBUG].list != 0) + return; + secondlevel[CTL_DEBUG].list = debugname; + mib[0] = CTL_DEBUG; + mib[2] = CTL_DEBUG_NAME; + for (loc = lastused, 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; + } + lastused = loc; +} + +/* + * Initialize the set of filesystem names + */ +vfsinit() +{ + int mib[4], maxtypenum, cnt, loc, size; + struct vfsconf vfc; + size_t buflen; + + if (secondlevel[CTL_VFS].list != 0) + return; + mib[0] = CTL_VFS; + mib[1] = VFS_GENERIC; + mib[2] = VFS_MAXTYPENUM; + buflen = 4; + if (sysctl(mib, 3, &maxtypenum, &buflen, (void *)0, (size_t)0) < 0) + return; + if ((vfsname = malloc(maxtypenum * sizeof(*vfsname))) == 0) + return; + memset(vfsname, 0, maxtypenum * sizeof(*vfsname)); + mib[2] = VFS_CONF; + buflen = sizeof vfc; + for (loc = lastused, cnt = 0; cnt < maxtypenum; cnt++) { + mib[3] = cnt; + if (sysctl(mib, 4, &vfc, &buflen, (void *)0, (size_t)0) < 0) { + if (errno == EOPNOTSUPP) + continue; + perror("vfsinit"); + free(vfsname); + return; + } + strcat(&names[loc], vfc.vfc_name); + vfsname[cnt].ctl_name = &names[loc]; + vfsname[cnt].ctl_type = CTLTYPE_INT; + size = strlen(vfc.vfc_name) + 1; + loc += size; + } + lastused = loc; + secondlevel[CTL_VFS].list = vfsname; + secondlevel[CTL_VFS].size = maxtypenum; + return; +} + +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/usr.sbin/traceroute/traceroute.8 b/usr.sbin/traceroute/traceroute.8 new file mode 100644 index 000000000000..5a1ca4c4af32 --- /dev/null +++ b/usr.sbin/traceroute/traceroute.8 @@ -0,0 +1,337 @@ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Van Jacobson. +.\" +.\" 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. +.\" +.\" @(#)traceroute.8 8.2 (Berkeley) 6/1/94 +.\" +.Dd June 1, 1994 +.Dt TRACEROUTE 8 +.Os BSD 4.3 +.Sh NAME +.Nm traceroute +.Nd print the route packets take to network host +.Sh SYNOPSIS +.Nm traceroute +.Op Fl m Ar max_ttl +.Op Fl n +.Op Fl p Ar port +.Op Fl q Ar nqueries +.Op Fl r +.Bk -words +.Op Fl s Ar src_addr +.Ek +.Op Fl t Ar tos +.Op Fl w Ar waittime +.Ar host +.Op Ar packetsize +.Sh DESCRIPTION +The Internet is a large and complex aggregation of +network hardware, connected together by gateways. +Tracking the route one's packets follow (or finding the miscreant +gateway that's discarding your packets) can be difficult. +.Nm Traceroute +utilizes the IP protocol `time to live' field and attempts to elicit an +.Tn ICMP +.Dv TIME_EXCEEDED +response from each gateway along the path to some +host. +.Pp +The only mandatory parameter is the destination host name or IP number. +The default probe datagram length is 38 bytes, but this may be increased +by specifying a packet size (in bytes) after the destination host +name. +.Pp +Other options are: +.Bl -tag -width Ds +.It Fl m Ar max_ttl +Set the max time-to-live (max number of hops) used in outgoing probe +packets. The default is 30 hops (the same default used for +.Tn TCP +connections). +.It Fl n +Print hop addresses numerically rather than symbolically and numerically +(saves a nameserver address-to-name lookup for each gateway found on the +path). +.It Fl p Ar port +Set the base +.Tn UDP +.Ar port +number used in probes (default is 33434). +.Nm Traceroute +hopes that nothing is listening on +.Tn UDP +ports +.Em base +to +.Em base+nhops-1 +at the destination host (so an +.Tn ICMP +.Dv PORT_UNREACHABLE +message will +be returned to terminate the route tracing). If something is +listening on a port in the default range, this option can be used +to pick an unused port range. +.It Fl q Ar nqueries +Set the number of probes per ``ttl'' to +.Ar nqueries +(default is three probes). +.It Fl r +Bypass the normal routing tables and send directly to a host on an attached +network. +If the host is not on a directly-attached network, +an error is returned. +This option can be used to ping a local host through an interface +that has no route through it (e.g., after the interface was dropped by +.Xr routed 8 ) . +.It Fl s Ar src_addr +Use the following IP address +(which must be given as an IP number, not +a hostname) as the source address in outgoing probe packets. On +hosts with more than one IP address, this option can be used to +force the source address to be something other than the IP address +of the interface the probe packet is sent on. If the IP address +is not one of this machine's interface addresses, an error is +returned and nothing is sent. +.ne 1i +.It Fl t Ar tos +Set the +.Em type-of-service +in probe packets to the following value (default zero). The value must be +a decimal integer in the range 0 to 255. This option can be used to +see if different types-of-service result in different paths. (If you +are not running a +.Bx 4.3 tahoe +or later system, this may be academic since the normal network +services like telnet and ftp don't let you control the +.Dv TOS ) . +Not all values of +.Dv TOS +are legal or +meaningful \- see the IP spec for definitions. Useful values are +probably +.Ql \-t 16 +(low delay) and +.Ql \-t 8 +(high throughput). +.It Fl v +Verbose output. Received +.Tn ICMP +packets other than +.Dv TIME_EXCEEDED +and +.Dv UNREACHABLE Ns s +are listed. +.It Fl w +Set the time (in seconds) to wait for a response to a probe (default 3 +sec.). +.El +.Pp +This program attempts to trace the route an IP packet would follow to some +internet host by launching +.Tn UDP +probe +packets with a small ttl (time to live) then listening for an +.Tn ICMP +"time exceeded" reply from a gateway. We start our probes +with a ttl of one and increase by one until we get an +.Tn ICMP +"port unreachable" +(which means we got to "host") or hit a max (which +defaults to 30 hops & can be changed with the +.Fl m +flag). Three +probes (changed with +.Fl q +flag) are sent at each ttl setting and a +line is printed showing the ttl, address of the gateway and +round trip time of each probe. If the probe answers come from +different gateways, the address of each responding system will +be printed. If there is no response within a 3 sec. timeout +interval (changed with the +.Fl w +flag), a "*" is printed for that +probe. +.Pp +We don't want the destination +host to process the +.Tn UDP +probe packets so the destination port is set to an +unlikely value (if some clod on the destination is using that +value, it can be changed with the +.Fl p +flag). +.Pp +A sample use and output might be: +.Bd -literal +[yak 71]% traceroute nis.nsf.net. +traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet +1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms +2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms +3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms +4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms +5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms +6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms +7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms +8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms +9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms +10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms +11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms + +.Ed +Note that lines 2 & 3 are the same. This is due to a buggy +kernel on the 2nd hop system \- lbl-csam.arpa \- that forwards +packets with a zero ttl (a bug in the distributed version +of 4.3 +.Tn BSD ) . +Note that you have to guess what path +the packets are taking cross-country since the +.Tn NSFNet +(129.140) +doesn't supply address-to-name translations for its +.Tn NSS Ns es . +.Pp +A more interesting example is: +.Bd -literal +[yak 72]% traceroute allspice.lcs.mit.edu. +traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max +1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms +2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms +3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms +4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms +5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms +6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms +7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms +8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms +9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms +10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms +11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms +12 * * * +13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms +14 * * * +15 * * * +16 * * * +17 * * * +18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms + +.Ed +Note that the gateways 12, 14, 15, 16 & 17 hops away +either don't send +.Tn ICMP +"time exceeded" messages or send them +with a ttl too small to reach us. 14 \- 17 are running the +.Tn MIT +C Gateway code that doesn't send "time exceeded"s. God +only knows what's going on with 12. +.Pp +The silent gateway 12 in the above may be the result of a bug in +the 4.[23] +.Tn BSD +network code (and its derivatives): 4.x (x <= 3) +sends an unreachable message using whatever ttl remains in the +original datagram. Since, for gateways, the remaining ttl is +zero, the +.Tn ICMP +"time exceeded" is guaranteed to not make it back +to us. The behavior of this bug is slightly more interesting +when it appears on the destination system: +.Bd -literal +1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms +2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms +3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms +4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms +5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms +6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms +7 * * * +8 * * * +9 * * * +10 * * * +11 * * * +12 * * * +13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms ! + +.Ed +Notice that there are 12 "gateways" (13 is the final +destination) and exactly the last half of them are "missing". +What's really happening is that rip (a Sun-3 running Sun OS3.5) +is using the ttl from our arriving datagram as the ttl in its +.Tn ICMP +reply. So, the reply will time out on the return path +(with no notice sent to anyone since +.Tn ICMP's +aren't sent for +.Tn ICMP's ) +until we probe with a ttl that's at least twice the path +length. I.e., rip is really only 7 hops away. A reply that +returns with a ttl of 1 is a clue this problem exists. +.Nm Traceroute +prints a "!" after the time if the ttl is <= 1. +Since vendors ship a lot of obsolete +.Pf ( Tn DEC Ns \'s +Ultrix, Sun 3.x) or +non-standard +.Pq Tn HPUX +software, expect to see this problem +frequently and/or take care picking the target host of your +probes. +Other possible annotations after the time are +.Sy !H , +.Sy !N , +.Sy !P +(got a host, network or protocol unreachable, respectively), +.Sy !S +or +.Sy !F +(source route failed or fragmentation needed \- neither of these should +ever occur and the associated gateway is busted if you see one). If +almost all the probes result in some kind of unreachable, +.Nm traceroute +will give up and exit. +.Pp +This program is intended for use in network testing, measurement +and management. +It should be used primarily for manual fault isolation. +Because of the load it could impose on the network, it is unwise to use +.Nm traceroute +during normal operations or from automated scripts. +.Sh AUTHOR +Implemented by Van Jacobson from a suggestion by Steve Deering. Debugged +by a cast of thousands with particularly cogent suggestions or fixes from +C. Philip Wood, Tim Seaver and Ken Adelman. +.Sh SEE ALSO +.Xr netstat 1 , +.Xr ping 8 +.Sh HISTORY +The +.Nm +command +.Bt diff --git a/usr.sbin/update/Makefile b/usr.sbin/update/Makefile new file mode 100644 index 000000000000..ea20d0566b2e --- /dev/null +++ b/usr.sbin/update/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= update +MAN8= update.0 + +.include diff --git a/usr.sbin/update/update.8 b/usr.sbin/update/update.8 new file mode 100644 index 000000000000..78665fafe71d --- /dev/null +++ b/usr.sbin/update/update.8 @@ -0,0 +1,74 @@ +.\" Copyright (c) 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. +.\" +.\" @(#)update.8 8.3 (Berkeley) 4/19/94 +.\" +.Dd April 19, 1994 +.Dt UPDATE 8 +.Os +.Sh NAME +.Nm update +.Nd flush internal filesystem caches to disk frequently +.Sh SYNOPSIS +.Nm update +.Sh DESCRIPTION +The +.Nm update +command helps protect the integrity of disk volumes +by flushing +volatile cached filesystem data +to disk at thirty second intervals. +.Nm Update +uses the +.Xr sync 2 +function call to do the task. +.Pp +.Nm Update +is commonly invoked at startup time by +.Xr rc 8 +when the system goes multi-user. +.Sh SEE ALSO +.Xr sync 2 , +.Xr fsck 8 , +.Xr init 8 , +.Xr rc 8 , +.Xr sync 8 +.Sh BUGS +It is possible on some systems that a +.Xr sync +occurring simultaneously with a crash may cause +file system damage. See +.Xr fsck 8 . +.Sh HISTORY +An +.Nm update +command appeared in +.At v6 . diff --git a/usr.sbin/update/update.c b/usr.sbin/update/update.c new file mode 100644 index 000000000000..ae83ad10b08c --- /dev/null +++ b/usr.sbin/update/update.c @@ -0,0 +1,75 @@ +/*- + * Copyright (c) 1987, 1990, 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) 1987, 1990, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)update.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include + +main() +{ + struct itimerval value; + void mysync(); + + daemon(0, 0); + + (void)signal(SIGALRM, mysync); + + value.it_interval.tv_sec = 30; + value.it_interval.tv_usec = 0; + value.it_value = value.it_interval; + if (setitimer(ITIMER_REAL, &value, NULL)) { + perror("update: setitimer"); + exit(1); + } + for (;;) + sigpause(sigblock(0L)); + /* NOTREACHED */ +} + +void +mysync() +{ + (void)sync(); +} diff --git a/usr.sbin/vipw/pw_util.c b/usr.sbin/vipw/pw_util.c new file mode 100644 index 000000000000..13851a1bbcdb --- /dev/null +++ b/usr.sbin/vipw/pw_util.c @@ -0,0 +1,220 @@ +/*- + * 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.4 (Berkeley) 4/28/95"; +#endif /* not lint */ + +/* + * This file is used by all the "password" programs; vipw(8), chpass(1), + * and passwd(1). + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pw_util.h" + +extern char *tempname; +static pid_t editpid = -1; +static int lockfd; + +void +pw_cont(sig) + int sig; +{ + + if (editpid != -1) + kill(editpid, sig); +} + +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(SIGCONT, pw_cont); + + /* Create with exact permissions. */ + (void)umask(0); +} + +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; + char *p, *editor; + + if (!(editor = getenv("EDITOR"))) + editor = _PATH_VI; + if (p = strrchr(editor, '/')) + ++p; + else + p = editor; + + if (!(editpid = vfork())) { + if (notsetuid) { + (void)setgid(getgid()); + (void)setuid(getuid()); + } + execlp(editor, p, tempname, NULL); + _exit(1); + } + for (;;) { + editpid = waitpid(editpid, (int *)&pstat, WUNTRACED); + if (editpid == -1) + pw_error(editor, 1, 1); + else if (WIFSTOPPED(pstat)) + raise(WSTOPSIG(pstat)); + else if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0) + break; + else + pw_error(editor, 1, 1); + } + editpid = -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); +}