[Midnightbsd-cvs] src [10864] trunk/usr.sbin/autofs: add autofs

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Wed Jun 13 18:32:17 EDT 2018


Revision: 10864
          http://svnweb.midnightbsd.org/src/?rev=10864
Author:   laffer1
Date:     2018-06-13 18:32:16 -0400 (Wed, 13 Jun 2018)
Log Message:
-----------
add autofs

Added Paths:
-----------
    trunk/usr.sbin/autofs/
    trunk/usr.sbin/autofs/Makefile
    trunk/usr.sbin/autofs/auto_master.5
    trunk/usr.sbin/autofs/automount.8
    trunk/usr.sbin/autofs/automount.c
    trunk/usr.sbin/autofs/automountd.8
    trunk/usr.sbin/autofs/automountd.c
    trunk/usr.sbin/autofs/autounmountd.8
    trunk/usr.sbin/autofs/autounmountd.c
    trunk/usr.sbin/autofs/common.c
    trunk/usr.sbin/autofs/common.h
    trunk/usr.sbin/autofs/defined.c
    trunk/usr.sbin/autofs/log.c
    trunk/usr.sbin/autofs/popen.c
    trunk/usr.sbin/autofs/token.l

Added: trunk/usr.sbin/autofs/Makefile
===================================================================
--- trunk/usr.sbin/autofs/Makefile	                        (rev 0)
+++ trunk/usr.sbin/autofs/Makefile	2018-06-13 22:32:16 UTC (rev 10864)
@@ -0,0 +1,34 @@
+# $MidnightBSD$
+# $FreeBSD: stable/10/usr.sbin/autofs/Makefile 270096 2014-08-17 09:44:42Z trasz $
+
+PROG=	automountd
+SRCS=	automount.c
+SRCS+=	automountd.c
+SRCS+=	autounmountd.c
+SRCS+=	common.c
+SRCS+=	defined.c
+SRCS+=	getmntopts.c
+SRCS+=	log.c
+SRCS+=	popen.c
+SRCS+=	token.l
+
+CFLAGS+=-I${.CURDIR}
+CFLAGS+=-I${.CURDIR}/../../sys/fs/autofs
+
+MAN=	automount.8 automountd.8 autounmountd.8 auto_master.5
+
+DPADD=	${LIBUTIL}
+LDADD=	-lutil
+
+# Needed for getmntopts.c
+MOUNT=  ${.CURDIR}/../../sbin/mount
+CFLAGS+=-I${MOUNT}
+
+WARNS=	6
+
+LINKS=	${BINDIR}/automountd ${BINDIR}/automount
+LINKS+=	${BINDIR}/automountd ${BINDIR}/autounmountd
+
+.PATH:	${MOUNT}
+
+.include <bsd.prog.mk>


Property changes on: trunk/usr.sbin/autofs/Makefile
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/autofs/auto_master.5
===================================================================
--- trunk/usr.sbin/autofs/auto_master.5	                        (rev 0)
+++ trunk/usr.sbin/autofs/auto_master.5	2018-06-13 22:32:16 UTC (rev 10864)
@@ -0,0 +1,375 @@
+.\" $MidnightBSD$
+.\" Copyright (c) 2014 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This software was developed by Edward Tomasz Napierala under sponsorship
+.\" from the FreeBSD Foundation.
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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.
+.\"
+.\" $FreeBSD: stable/10/usr.sbin/autofs/auto_master.5 283242 2015-05-21 13:42:37Z trasz $
+.\"
+.Dd March 13, 2015
+.Dt AUTO_MASTER 5
+.Os
+.Sh NAME
+.Nm auto_master
+.Nd auto_master and map file format
+.Sh DESCRIPTION
+The automounter configuration consists of the
+.Nm
+configuration file, which assigns filesystem paths to map names,
+and maps, which contain actual mount information.
+The
+.Nm
+configuration file is used by the
+.Xr automount 8
+command.
+Map files are read by the
+.Xr automountd 8
+daemon.
+.Sh AUTO_MASTER SYNTAX
+The
+.Nm
+file consists of lines with two or three entries separated by whitespace
+and terminated by newline character:
+.Bd -literal -offset indent
+.Pa mountpoint Pa map_name Op Ar -options
+.Ed
+.Pp
+.Pa mountpoint
+is either a fully specified path, or
+.Li /- .
+When
+.Pa mountpoint
+is a full path,
+.Pa map_name
+must reference an indirect map.
+Otherwise,
+.Pa map_name
+must reference a direct map.
+See
+.Sx "MAP SYNTAX" below.
+.Pp
+.Pa map_name
+specifies map to use.
+If
+.Pa map_name
+begins with
+.Li - ,
+it specifies a special map.
+See
+.Sx "MAP SYNTAX"
+below.
+If
+.Pa map_name
+is not a fully specified path
+.Pq it does not start with Li / ,
+.Xr automountd 8
+will search for that name in
+.Li /etc .
+Otherwise it will use the path as given.
+If the file indicated by
+.Pa map_name
+is executable,
+.Xr automountd 8
+will assume it is an executable map.
+See
+.Sx "MAP SYNTAX"
+below.
+Otherwise, the file is opened and the contents parsed.
+.Pp
+.Pa -options
+is an optional field that starts with
+.Li -
+and can contain generic filesystem mount options.
+.Pp
+The following example specifies that the /etc/auto_example indirect map
+will be mounted on /example.
+.Bd -literal -offset indent
+/example auto_example
+.Ed
+.Sh MAP SYNTAX
+Map files consist of lines with a number of entries separated by whitespace
+and terminated by newline character:
+.Bd -literal -offset indent
+.Pa key Oo Ar -options Oc Oo Ar mountpoint Oo -options Oc Oc Ar location Op ...
+.Ed
+.Pp
+In most cases, it can be simplified to:
+.Bd -literal -offset indent
+.Pa key Oo Ar -options Oc Ar location
+.Ed
+.Pp
+.Pa key
+is the path component used by
+.Xr automountd 8
+to find the right map entry to use.
+It is also used to form the final mountpoint.
+A wildcard
+.Pq Ql *
+can be used for the key.
+It matches every directory that does not match other keys.
+Those directories will not be visible to the user
+until accessed.
+.Pp
+The
+.Ar options
+field, if present, must begin with
+.Li - .
+When mounting the filesystem, options supplied to
+.Nm
+and options specified in the map entry are concatenated together.
+The special option
+.Li fstype
+is used to specify filesystem type.
+It is not passed to the mount program as an option.
+Instead, it is passed as an argument to
+.Cm "mount -t".
+The default
+.Li fstype
+is
+.Ql nfs .
+The special option
+.Li nobrowse
+is used to disable creation of top-level directories for special
+and executable maps.
+.Pp
+The optional
+.Pa mountpoint
+field is used to specify multiple mount points
+for a single key.
+.Pp
+The
+.Ar location
+field specifies the filesystem to be mounted.
+Ampersands
+.Pq Ql &
+in the
+.Ar location
+field are replaced with the value of
+.Ar key .
+This is typically used with wildcards, like:
+.Bd -literal -offset indent
+.Li *	192.168.1.1:/share/&
+.Ed
+.Pp
+The
+.Ar location
+field may contain references to variables, like:
+.Bd -literal -offset indent
+.Li sys	192.168.1.1:/sys/${OSNAME}
+.Ed
+.Pp
+Defined variables are:
+.Pp
+.Bl -tag -width "-OSNAME" -compact
+.It Li ARCH
+Expands to the output of
+.Li "uname -p" .
+.It Li CPU
+Same as ARCH.
+.It Li HOST
+Expands to the output of
+.Li "uname -n" .
+.It Li OSNAME
+Expands to the output of
+.Li "uname -s" .
+.It Li OSREL
+Expands to the output of
+.Li "uname -r" .
+.It Li OSVERS
+Expands to the output of
+.Li "uname -v" .
+.El
+.Pp
+Additional variables can be defined with the
+.Fl D
+option of
+.Xr automount 8
+and
+.Xr automountd 8 .
+.Pp
+To pass a location that begins with
+.Li / ,
+prefix it with a colon.
+For example,
+.Li :/dev/cd0 .
+.Pp
+This example, when put into
+.Pa /etc/auto_example ,
+and with
+.Nm
+referring to the map as described above, specifies that the NFS share
+.Li 192.168.1.1:/share/example/x
+will be mounted on
+.Pa /example/x/
+when any process attempts to access that mountpoint, with
+.Li intr
+and
+.Li nfsv4
+mount options, described in
+.Xr mount_nfs 8 :
+.Bd -literal -offset indent
+.Li x -intr,nfsv4 192.168.1.1:/share/example/x
+.Ed
+.Pp
+Automatically mount an SMB share on access, as a guest user,
+without prompting for a password:
+.Bd -literal -offset indent
+.Li share -fstype=smbfs,-N ://@server/share
+.Ed
+.Pp
+Automatically mount the CD drive on access:
+.Bd -literal -offset indent
+.Li cd -fstype=cd9660 :/dev/cd0
+.Ed
+.Sh SPECIAL MAPS
+Special maps have names beginning with
+.Li - .
+Supported special maps are:
+.Pp
+.Bl -tag -width "-hosts" -compact
+.It Li -hosts
+Query the remote NFS server and map exported shares.
+This map is traditionally mounted on
+.Pa /net .
+Access to files on a remote NFS server is provided through the
+.Pf /net/ Ar nfs-server-ip Ns / Ns Ar share-name Ns/
+directory without any additional configuration.
+Directories for individual NFS servers are not present until the first access,
+when they are automatically created.
+.It Li -media
+Query devices that are not yet mounted, but contain valid filesystems.
+Generally used to access files on removable media.
+.It Li -noauto
+Mount filesystems configured in
+.Xr fstab 5
+as "noauto".
+This needs to be set up as a direct map.
+.It Li -null
+Prevent
+.Xr automountd 8
+from mounting anything on the mountpoint.
+.El
+.Pp
+It is possible to add custom special maps by adding them, as executable
+maps named
+.Pa special_foo ,
+to the
+.Pa /etc/autofs/
+directory.
+.Sh EXECUTABLE MAPS
+If the map file specified in
+.Nm
+has the execute bit set,
+.Xr automountd 8
+will execute it and parse the standard output instead of parsing
+the file contents.
+When called without command line arguments, the executable is
+expected to output a list of available map keys separated by
+newline characters.
+Otherwise, the executable will be called with a key name as
+a command line argument.
+Output from the executable is expected to be the entry for that key,
+not including the key itself.
+.Sh INDIRECT VERSUS DIRECT MAPS
+Indirect maps are referred to in
+.Nm
+by entries with a fully qualified path as a mount point, and must contain only
+relative paths as keys.
+Direct maps are referred to in
+.Nm
+by entries with
+.Li /-
+as the mountpoint, and must contain only fully qualified paths as keys.
+For indirect maps, the final mount point is determined by concatenating the
+.Nm
+mountpoint with the map entry key and optional map entry mountpoint.
+For direct maps, the final mount point is determined by concatenating
+the map entry key with the optional map entry mountpoint.
+.Pp
+The example above could be rewritten using direct map, by placing this in
+.Nm :
+.Bd -literal -offset indent
+.Li /- auto_example
+.Ed
+.Pp
+and this in
+.Li /etc/auto_example
+map file:
+.Bd -literal -offset indent
+.Li /example/x -intr,nfsv4 192.168.1.1:/share/example/x
+.Li /example/share -fstype=smbfs,-N ://@server/share
+.Li /example/cd -fstype=cd9660 :/dev/cd0
+.Ed
+.Sh DIRECTORY SERVICES
+Both
+.Nm
+and maps may contain entries consisting of a plus sign and map name:
+.Bd -literal -offset indent
+.Li +auto_master
+.Ed
+.Pp
+Those entries cause
+.Xr automountd 8
+daemon to retrieve the named map from directory services (like LDAP)
+and include it where the entry was.
+.Pp
+If the file containing the map referenced in
+.Nm
+is not found, the map will be retrieved from directory services instead.
+.Pp
+To retrieve entries from directory services,
+.Xr automountd 8
+daemon runs
+.Pa /etc/autofs/include ,
+which is usually a shell script, with map name as the only command line
+parameter.
+The script should output entries formatted according to
+.Nm
+or automounter map syntax to standard output.
+An example script to use LDAP is included in
+.Pa /etc/autofs/include_ldap .
+It can be symlinked to
+.Pa /etc/autofs/include .
+.Sh FILES
+.Bl -tag -width ".Pa /etc/auto_master" -compact
+.It Pa /etc/auto_master
+The default location of the
+.Pa auto_master
+file.
+.It Pa /etc/autofs/
+Directory containing shell scripts to implement special maps and directory
+services.
+.El
+.Sh SEE ALSO
+.Xr autofs 5 ,
+.Xr automount 8 ,
+.Xr automountd 8 ,
+.Xr autounmountd 8
+.Sh AUTHORS
+The
+.Nm
+configuration file functionality was developed by
+.An Edward Tomasz Napierala Aq Mt trasz at FreeBSD.org
+under sponsorship from the FreeBSD Foundation.


Property changes on: trunk/usr.sbin/autofs/auto_master.5
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/autofs/automount.8
===================================================================
--- trunk/usr.sbin/autofs/automount.8	                        (rev 0)
+++ trunk/usr.sbin/autofs/automount.8	2018-06-13 22:32:16 UTC (rev 10864)
@@ -0,0 +1,112 @@
+.\" $MidnightBSD$
+.\" Copyright (c) 2014 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This software was developed by Edward Tomasz Napierala under sponsorship
+.\" from the FreeBSD Foundation.
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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.
+.\"
+.\" $FreeBSD: stable/10/usr.sbin/autofs/automount.8 279742 2015-03-07 19:36:06Z trasz $
+.\"
+.Dd November 22, 2014
+.Dt AUTOMOUNT 8
+.Os
+.Sh NAME
+.Nm automount
+.Nd update autofs mounts
+.Sh SYNOPSIS
+.Nm
+.Op Fl D Ar name=value
+.Op Fl L
+.Op Fl c
+.Op Fl f
+.Op Fl o Ar options
+.Op Fl v
+.Op Fl u
+.Sh DESCRIPTION
+When called without options, the
+.Nm
+command parses the
+.Xr auto_master 5
+configuration file and any direct maps that it references, and mounts
+or unmounts
+.Xr autofs 4
+filesystems to match.
+These options are available:
+.Bl -tag -width ".Fl v"
+.It Fl D
+Define a variable.
+It is only useful with
+.Fl L .
+.It Fl L
+Do not mount or unmount anything.
+Instead parse
+.Xr auto_master 5
+and any direct maps, then print them to standard output.
+When specified more than once, all the maps, including indirect ones,
+will be parsed and shown.
+This is useful when debugging configuration problems.
+.It Fl c
+Flush caches, discarding possibly stale information obtained from maps
+and directory services.
+.It Fl f
+Force unmount, to be used with
+.Fl u .
+.It Fl o
+Specify mount options to be used along with the ones specified in the maps.
+It is only useful with
+.Fl L .
+.It Fl u
+Try to unmount filesystems mounted by
+.Xr automountd 8 .
+.Xr autofs 5
+mounts are not unmounted.
+To unmount all
+.Xr autofs
+mounts, use
+.Cm "umount -At autofs".
+.It Fl v
+Increase verbosity.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+Unmount all filesystems mounted by
+.Xr automountd 8 :
+.Dl Nm Fl u
+.Sh SEE ALSO
+.Xr auto_master 5 ,
+.Xr autofs 5 ,
+.Xr automountd 8 ,
+.Xr autounmountd 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Fx 10.1 .
+.Sh AUTHORS
+The
+.Nm
+was developed by
+.An Edward Tomasz Napierala Aq Mt trasz at FreeBSD.org
+under sponsorship from the FreeBSD Foundation.


Property changes on: trunk/usr.sbin/autofs/automount.8
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/autofs/automount.c
===================================================================
--- trunk/usr.sbin/autofs/automount.c	                        (rev 0)
+++ trunk/usr.sbin/autofs/automount.c	2018-06-13 22:32:16 UTC (rev 10864)
@@ -0,0 +1,397 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/usr.sbin/autofs/automount.c 283239 2015-05-21 13:37:48Z trasz $");
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/linker.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/utsname.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <netdb.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libutil.h>
+
+#include "common.h"
+#include "mntopts.h"
+
+static int
+unmount_by_statfs(const struct statfs *sb, bool force)
+{
+	char *fsid_str;
+	int error, ret, flags;
+
+	ret = asprintf(&fsid_str, "FSID:%d:%d",
+	    sb->f_fsid.val[0], sb->f_fsid.val[1]);
+	if (ret < 0)
+		log_err(1, "asprintf");
+
+	log_debugx("unmounting %s using %s", sb->f_mntonname, fsid_str);
+
+	flags = MNT_BYFSID;
+	if (force)
+		flags |= MNT_FORCE;
+	error = unmount(fsid_str, flags);
+	free(fsid_str);
+	if (error != 0)
+		log_warn("cannot unmount %s", sb->f_mntonname);
+
+	return (error);
+}
+
+static const struct statfs *
+find_statfs(const struct statfs *mntbuf, int nitems, const char *mountpoint)
+{
+	int i;
+
+	for (i = 0; i < nitems; i++) {
+		if (strcmp(mntbuf[i].f_mntonname, mountpoint) == 0)
+			return (mntbuf + i);
+	}
+
+	return (NULL);
+}
+
+static void
+mount_autofs(const char *from, const char *fspath, const char *options,
+    const char *prefix)
+{
+	struct iovec *iov = NULL;
+	char errmsg[255];
+	int error, iovlen = 0;
+
+	create_directory(fspath);
+
+	log_debugx("mounting %s on %s, prefix \"%s\", options \"%s\"",
+	    from, fspath, prefix, options);
+	memset(errmsg, 0, sizeof(errmsg));
+
+	build_iovec(&iov, &iovlen, "fstype",
+	    __DECONST(void *, "autofs"), (size_t)-1);
+	build_iovec(&iov, &iovlen, "fspath",
+	    __DECONST(void *, fspath), (size_t)-1);
+	build_iovec(&iov, &iovlen, "from",
+	    __DECONST(void *, from), (size_t)-1);
+	build_iovec(&iov, &iovlen, "errmsg",
+	    errmsg, sizeof(errmsg));
+
+	/*
+	 * Append the options and mountpoint defined in auto_master(5);
+	 * this way automountd(8) does not need to parse it.
+	 */
+	build_iovec(&iov, &iovlen, "master_options",
+	    __DECONST(void *, options), (size_t)-1);
+	build_iovec(&iov, &iovlen, "master_prefix",
+	    __DECONST(void *, prefix), (size_t)-1);
+
+	error = nmount(iov, iovlen, 0);
+	if (error != 0) {
+		if (*errmsg != '\0') {
+			log_err(1, "cannot mount %s on %s: %s",
+			    from, fspath, errmsg);
+		} else {
+			log_err(1, "cannot mount %s on %s", from, fspath);
+		}
+	}
+}
+
+static void
+mount_if_not_already(const struct node *n, const char *map, const char *options,
+    const char *prefix, const struct statfs *mntbuf, int nitems)
+{
+	const struct statfs *sb;
+	char *mountpoint;
+	char *from;
+	int ret;
+
+	ret = asprintf(&from, "map %s", map);
+	if (ret < 0)
+		log_err(1, "asprintf");
+
+	mountpoint = node_path(n);
+	sb = find_statfs(mntbuf, nitems, mountpoint);
+	if (sb != NULL) {
+		if (strcmp(sb->f_fstypename, "autofs") != 0) {
+			log_debugx("unknown filesystem mounted "
+			    "on %s; mounting", mountpoint);
+			/*
+			 * XXX: Compare options and 'from',
+			 *	and update the mount if necessary.
+			 */
+		} else {
+			log_debugx("autofs already mounted "
+			    "on %s", mountpoint);
+			free(from);
+			free(mountpoint);
+			return;
+		}
+	} else {
+		log_debugx("nothing mounted on %s; mounting",
+		    mountpoint);
+	}
+
+	mount_autofs(from, mountpoint, options, prefix);
+	free(from);
+	free(mountpoint);
+}
+
+static void
+mount_unmount(struct node *root)
+{
+	struct statfs *mntbuf;
+	struct node *n, *n2;
+	int i, nitems;
+
+	nitems = getmntinfo(&mntbuf, MNT_WAIT);
+	if (nitems <= 0)
+		log_err(1, "getmntinfo");
+
+	log_debugx("unmounting stale autofs mounts");
+
+	for (i = 0; i < nitems; i++) {
+		if (strcmp(mntbuf[i].f_fstypename, "autofs") != 0) {
+			log_debugx("skipping %s, filesystem type is not autofs",
+			    mntbuf[i].f_mntonname);
+			continue;
+		}
+
+		n = node_find(root, mntbuf[i].f_mntonname);
+		if (n != NULL) {
+			log_debugx("leaving autofs mounted on %s",
+			    mntbuf[i].f_mntonname);
+			continue;
+		}
+
+		log_debugx("autofs mounted on %s not found "
+		    "in new configuration; unmounting", mntbuf[i].f_mntonname);
+		unmount_by_statfs(&(mntbuf[i]), false);
+	}
+
+	log_debugx("mounting new autofs mounts");
+
+	TAILQ_FOREACH(n, &root->n_children, n_next) {
+		if (!node_is_direct_map(n)) {
+			mount_if_not_already(n, n->n_map, n->n_options,
+			    n->n_key, mntbuf, nitems);
+			continue;
+		}
+
+		TAILQ_FOREACH(n2, &n->n_children, n_next) {
+			mount_if_not_already(n2, n->n_map, n->n_options,
+			    "/", mntbuf, nitems);
+		}
+	}
+}
+
+static void
+flush_autofs(const char *fspath)
+{
+	struct iovec *iov = NULL;
+	char errmsg[255];
+	int error, iovlen = 0;
+
+	log_debugx("flushing %s", fspath);
+	memset(errmsg, 0, sizeof(errmsg));
+
+	build_iovec(&iov, &iovlen, "fstype",
+	    __DECONST(void *, "autofs"), (size_t)-1);
+	build_iovec(&iov, &iovlen, "fspath",
+	    __DECONST(void *, fspath), (size_t)-1);
+	build_iovec(&iov, &iovlen, "errmsg",
+	    errmsg, sizeof(errmsg));
+
+	error = nmount(iov, iovlen, MNT_UPDATE);
+	if (error != 0) {
+		if (*errmsg != '\0') {
+			log_err(1, "cannot flush %s: %s",
+			    fspath, errmsg);
+		} else {
+			log_err(1, "cannot flush %s", fspath);
+		}
+	}
+}
+
+static void
+flush_caches(void)
+{
+	struct statfs *mntbuf;
+	int i, nitems;
+
+	nitems = getmntinfo(&mntbuf, MNT_WAIT);
+	if (nitems <= 0)
+		log_err(1, "getmntinfo");
+
+	log_debugx("flushing autofs caches");
+
+	for (i = 0; i < nitems; i++) {
+		if (strcmp(mntbuf[i].f_fstypename, "autofs") != 0) {
+			log_debugx("skipping %s, filesystem type is not autofs",
+			    mntbuf[i].f_mntonname);
+			continue;
+		}
+
+		flush_autofs(mntbuf[i].f_mntonname);
+	}
+}
+
+static void
+unmount_automounted(bool force)
+{
+	struct statfs *mntbuf;
+	int i, nitems;
+
+	nitems = getmntinfo(&mntbuf, MNT_WAIT);
+	if (nitems <= 0)
+		log_err(1, "getmntinfo");
+
+	log_debugx("unmounting automounted filesystems");
+
+	for (i = 0; i < nitems; i++) {
+		if (strcmp(mntbuf[i].f_fstypename, "autofs") == 0) {
+			log_debugx("skipping %s, filesystem type is autofs",
+			    mntbuf[i].f_mntonname);
+			continue;
+		}
+
+		if ((mntbuf[i].f_flags & MNT_AUTOMOUNTED) == 0) {
+			log_debugx("skipping %s, not automounted",
+			    mntbuf[i].f_mntonname);
+			continue;
+		}
+
+		unmount_by_statfs(&(mntbuf[i]), force);
+	}
+}
+
+static void
+usage_automount(void)
+{
+
+	fprintf(stderr, "usage: automount [-D name=value][-o opts][-Lcfuv]\n");
+	exit(1);
+}
+
+int
+main_automount(int argc, char **argv)
+{
+	struct node *root;
+	int ch, debug = 0, show_maps = 0;
+	char *options = NULL;
+	bool do_unmount = false, force_unmount = false, flush = false;
+
+	/*
+	 * Note that in automount(8), the only purpose of variable
+	 * handling is to aid in debugging maps (automount -L).
+	 */
+	defined_init();
+
+	while ((ch = getopt(argc, argv, "D:Lfco:uv")) != -1) {
+		switch (ch) {
+		case 'D':
+			defined_parse_and_add(optarg);
+			break;
+		case 'L':
+			show_maps++;
+			break;
+		case 'c':
+			flush = true;
+			break;
+		case 'f':
+			force_unmount = true;
+			break;
+		case 'o':
+			options = concat(options, ',', optarg);
+			break;
+		case 'u':
+			do_unmount = true;
+			break;
+		case 'v':
+			debug++;
+			break;
+		case '?':
+		default:
+			usage_automount();
+		}
+	}
+	argc -= optind;
+	if (argc != 0)
+		usage_automount();
+
+	if (force_unmount && !do_unmount)
+		usage_automount();
+
+	log_init(debug);
+
+	if (flush) {
+		flush_caches();
+		return (0);
+	}
+
+	if (do_unmount) {
+		unmount_automounted(force_unmount);
+		return (0);
+	}
+
+	root = node_new_root();
+	parse_master(root, AUTO_MASTER_PATH);
+
+	if (show_maps) {
+		if (show_maps > 1) {
+			node_expand_indirect_maps(root);
+			node_expand_ampersand(root, NULL);
+		}
+		node_expand_defined(root);
+		node_print(root, options);
+		return (0);
+	}
+
+	mount_unmount(root);
+
+	return (0);
+}


Property changes on: trunk/usr.sbin/autofs/automount.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/autofs/automountd.8
===================================================================
--- trunk/usr.sbin/autofs/automountd.8	                        (rev 0)
+++ trunk/usr.sbin/autofs/automountd.8	2018-06-13 22:32:16 UTC (rev 10864)
@@ -0,0 +1,104 @@
+.\" $MidnightBSD$
+.\" Copyright (c) 2014 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This software was developed by Edward Tomasz Napierala under sponsorship
+.\" from the FreeBSD Foundation.
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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.
+.\"
+.\" $FreeBSD: stable/10/usr.sbin/autofs/automountd.8 283236 2015-05-21 13:33:06Z trasz $
+.\"
+.Dd March 10, 2015
+.Dt AUTOMOUNTD 8
+.Os
+.Sh NAME
+.Nm automountd
+.Nd daemon handling autofs mount requests
+.Sh SYNOPSIS
+.Nm
+.Op Fl D Ar name=value
+.Op Fl i
+.Op Fl m Ar maxproc
+.Op Fl o Ar options
+.Op Fl d
+.Op Fl v
+.Sh DESCRIPTION
+The
+.Nm
+daemon is responsible for handling
+.Xr autofs 5
+mount requests, parsing maps,
+and mounting filesystems they specify.
+On startup,
+.Nm
+forks into background and waits for kernel requests.
+When a request is received,
+.Nm
+forks a child process.
+The child process parses the appropriate map and mounts filesystems accordingly.
+Then it signals the kernel to release blocked processes that were waiting
+for the mount.
+.Bl -tag -width ".Fl v"
+.It Fl D
+Define a variable.
+.It Fl i
+For indirect mounts, only create subdirectories if there are no wildcard
+entries.
+Without
+.Fl i ,
+.Nm
+creates all the subdirectories it can.
+Users may not realize that the wildcard map entry makes it possible to access
+directories that have not yet been created.
+.It Fl m Ar maxproc
+Limit the number of forked
+.Nm
+processes, and thus the number of mount requests being handled in parallel.
+The default is 30.
+.It Fl d
+Debug mode: increase verbosity and do not daemonize.
+.It Fl o Ar options
+Specify mount options.
+Options specified here will be overridden by options entered in maps or
+.Xr auto_master 5 .
+.It Fl v
+Increase verbosity.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr auto_master 5 ,
+.Xr autofs 5 ,
+.Xr automount 8 ,
+.Xr autounmountd 8
+.Sh HISTORY
+The
+.Nm
+daemon appeared in
+.Fx 10.1 .
+.Sh AUTHORS
+The
+.Nm
+was developed by
+.An Edward Tomasz Napierala Aq Mt trasz at FreeBSD.org
+under sponsorship from the FreeBSD Foundation.


Property changes on: trunk/usr.sbin/autofs/automountd.8
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/autofs/automountd.c
===================================================================
--- trunk/usr.sbin/autofs/automountd.c	                        (rev 0)
+++ trunk/usr.sbin/autofs/automountd.c	2018-06-13 22:32:16 UTC (rev 10864)
@@ -0,0 +1,570 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/usr.sbin/autofs/automountd.c 283241 2015-05-21 13:41:08Z trasz $");
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/linker.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/utsname.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <netdb.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libutil.h>
+
+#include "autofs_ioctl.h"
+
+#include "common.h"
+
+#define AUTOMOUNTD_PIDFILE	"/var/run/automountd.pid"
+
+static int nchildren = 0;
+static int autofs_fd;
+static int request_id;
+
+static void
+done(int request_error, bool wildcards)
+{
+	struct autofs_daemon_done add;
+	int error;
+
+	memset(&add, 0, sizeof(add));
+	add.add_id = request_id;
+	add.add_wildcards = wildcards;
+	add.add_error = request_error;
+
+	log_debugx("completing request %d with error %d",
+	    request_id, request_error);
+
+	error = ioctl(autofs_fd, AUTOFSDONE, &add);
+	if (error != 0)
+		log_warn("AUTOFSDONE");
+}
+
+/*
+ * Remove "fstype=whatever" from optionsp and return the "whatever" part.
+ */
+static char *
+pick_option(const char *option, char **optionsp)
+{
+	char *tofree, *pair, *newoptions;
+	char *picked = NULL;
+	bool first = true;
+
+	tofree = *optionsp;
+
+	newoptions = calloc(strlen(*optionsp) + 1, 1);
+	if (newoptions == NULL)
+		log_err(1, "calloc");
+
+	while ((pair = strsep(optionsp, ",")) != NULL) {
+		/*
+		 * XXX: strncasecmp(3) perhaps?
+		 */
+		if (strncmp(pair, option, strlen(option)) == 0) {
+			picked = checked_strdup(pair + strlen(option));
+		} else {
+			if (first == false)
+				strcat(newoptions, ",");
+			else
+				first = false;
+			strcat(newoptions, pair);
+		}
+	}
+
+	free(tofree);
+	*optionsp = newoptions;
+
+	return (picked);
+}
+
+static void
+create_subtree(const struct node *node, bool incomplete)
+{
+	const struct node *child;
+	char *path;
+	bool wildcard_found = false;
+
+	/*
+	 * Skip wildcard nodes.
+	 */
+	if (strcmp(node->n_key, "*") == 0)
+		return;
+
+	path = node_path(node);
+	log_debugx("creating subtree at %s", path);
+	create_directory(path);
+
+	if (incomplete) {
+		TAILQ_FOREACH(child, &node->n_children, n_next) {
+			if (strcmp(child->n_key, "*") == 0) {
+				wildcard_found = true;
+				break;
+			}
+		}
+
+		if (wildcard_found) {
+			log_debugx("node %s contains wildcard entry; "
+			    "not creating its subdirectories due to -d flag",
+			    path);
+			free(path);
+			return;
+		}
+	}
+
+	free(path);
+
+	TAILQ_FOREACH(child, &node->n_children, n_next)
+		create_subtree(child, incomplete);
+}
+
+static void
+exit_callback(void)
+{
+
+	done(EIO, true);
+}
+
+static void
+handle_request(const struct autofs_daemon_request *adr, char *cmdline_options,
+    bool incomplete_hierarchy)
+{
+	const char *map;
+	struct node *root, *parent, *node;
+	FILE *f;
+	char *key, *options, *fstype, *nobrowse, *retrycnt, *tmp;
+	int error;
+	bool wildcards;
+
+	log_debugx("got request %d: from %s, path %s, prefix \"%s\", "
+	    "key \"%s\", options \"%s\"", adr->adr_id, adr->adr_from,
+	    adr->adr_path, adr->adr_prefix, adr->adr_key, adr->adr_options);
+
+	/*
+	 * Try to notify the kernel about any problems.
+	 */
+	request_id = adr->adr_id;
+	atexit(exit_callback);
+
+	if (strncmp(adr->adr_from, "map ", 4) != 0) {
+		log_errx(1, "invalid mountfrom \"%s\"; failing request",
+		    adr->adr_from);
+	}
+
+	map = adr->adr_from + 4; /* 4 for strlen("map "); */
+	root = node_new_root();
+	if (adr->adr_prefix[0] == '\0' || strcmp(adr->adr_prefix, "/") == 0) {
+		/*
+		 * Direct map.  autofs(4) doesn't have a way to determine
+		 * correct map key, but since it's a direct map, we can just
+		 * use adr_path instead.
+		 */
+		parent = root;
+		key = checked_strdup(adr->adr_path);
+	} else {
+		/*
+		 * Indirect map.
+		 */
+		parent = node_new_map(root, checked_strdup(adr->adr_prefix),
+		    NULL,  checked_strdup(map),
+		    checked_strdup("[kernel request]"), lineno);
+
+		if (adr->adr_key[0] == '\0')
+			key = NULL;
+		else
+			key = checked_strdup(adr->adr_key);
+	}
+
+	/*
+	 * "Wildcards" here actually means "make autofs(4) request
+	 * automountd(8) action if the node being looked up does not
+	 * exist, even though the parent is marked as cached".  This
+	 * needs to be done for maps with wildcard entries, but also
+	 * for special and executable maps.
+	 */
+	parse_map(parent, map, key, &wildcards);
+	if (!wildcards)
+		wildcards = node_has_wildcards(parent);
+	if (wildcards)
+		log_debugx("map may contain wildcard entries");
+	else
+		log_debugx("map does not contain wildcard entries");
+
+	if (key != NULL)
+		node_expand_wildcard(root, key);
+
+	node = node_find(root, adr->adr_path);
+	if (node == NULL) {
+		log_errx(1, "map %s does not contain key for \"%s\"; "
+		    "failing mount", map, adr->adr_path);
+	}
+
+	options = node_options(node);
+
+	/*
+	 * Append options from auto_master.
+	 */
+	options = concat(options, ',', adr->adr_options);
+
+	/*
+	 * Prepend options passed via automountd(8) command line.
+	 */
+	options = concat(cmdline_options, ',', options);
+
+	if (node->n_location == NULL) {
+		log_debugx("found node defined at %s:%d; not a mountpoint",
+		    node->n_config_file, node->n_config_line);
+
+		nobrowse = pick_option("nobrowse", &options);
+		if (nobrowse != NULL && key == NULL) {
+			log_debugx("skipping map %s due to \"nobrowse\" "
+			    "option; exiting", map);
+			done(0, true);
+
+			/*
+			 * Exit without calling exit_callback().
+			 */
+			quick_exit(0);
+		}
+
+		/*
+		 * Not a mountpoint; create directories in the autofs mount
+		 * and complete the request.
+		 */
+		create_subtree(node, incomplete_hierarchy);
+
+		if (incomplete_hierarchy && key != NULL) {
+			/*
+			 * We still need to create the single subdirectory
+			 * user is trying to access.
+			 */
+			tmp = concat(adr->adr_path, '/', key);
+			node = node_find(root, tmp);
+			if (node != NULL)
+				create_subtree(node, false);
+		}
+
+		log_debugx("nothing to mount; exiting");
+		done(0, wildcards);
+
+		/*
+		 * Exit without calling exit_callback().
+		 */
+		quick_exit(0);
+	}
+
+	log_debugx("found node defined at %s:%d; it is a mountpoint",
+	    node->n_config_file, node->n_config_line);
+
+	if (key != NULL)
+		node_expand_ampersand(node, key);
+	error = node_expand_defined(node);
+	if (error != 0) {
+		log_errx(1, "variable expansion failed for %s; "
+		    "failing mount", adr->adr_path);
+	}
+
+	/*
+	 * Append "automounted".
+	 */
+	options = concat(options, ',', "automounted");
+
+	/*
+	 * Remove "nobrowse", mount(8) doesn't understand it.
+	 */
+	pick_option("nobrowse", &options);
+
+	/*
+	 * Figure out fstype.
+	 */
+	fstype = pick_option("fstype=", &options);
+	if (fstype == NULL) {
+		log_debugx("fstype not specified in options; "
+		    "defaulting to \"nfs\"");
+		fstype = checked_strdup("nfs");
+	}
+
+	if (strcmp(fstype, "nfs") == 0) {
+		/*
+		 * The mount_nfs(8) command defaults to retry undefinitely.
+		 * We do not want that behaviour, because it leaves mount_nfs(8)
+		 * instances and automountd(8) children hanging forever.
+		 * Disable retries unless the option was passed explicitly.
+		 */
+		retrycnt = pick_option("retrycnt=", &options);
+		if (retrycnt == NULL) {
+			log_debugx("retrycnt not specified in options; "
+			    "defaulting to 1");
+			options = concat(options, ',', "retrycnt=1");
+		} else {
+			options = concat(options, ',',
+			    concat("retrycnt", '=', retrycnt));
+		}
+	}
+
+	f = auto_popen("mount", "-t", fstype, "-o", options,
+	    node->n_location, adr->adr_path, NULL);
+	assert(f != NULL);
+	error = auto_pclose(f);
+	if (error != 0)
+		log_errx(1, "mount failed");
+
+	log_debugx("mount done; exiting");
+	done(0, wildcards);
+
+	/*
+	 * Exit without calling exit_callback().
+	 */
+	quick_exit(0);
+}
+
+static void
+sigchld_handler(int dummy __unused)
+{
+
+	/*
+	 * The only purpose of this handler is to make SIGCHLD
+	 * interrupt the AUTOFSREQUEST ioctl(2), so we can call
+	 * wait_for_children().
+	 */
+}
+
+static void
+register_sigchld(void)
+{
+	struct sigaction sa;
+	int error;
+
+	bzero(&sa, sizeof(sa));
+	sa.sa_handler = sigchld_handler;
+	sigfillset(&sa.sa_mask);
+	error = sigaction(SIGCHLD, &sa, NULL);
+	if (error != 0)
+		log_err(1, "sigaction");
+
+}
+
+
+static int
+wait_for_children(bool block)
+{
+	pid_t pid;
+	int status;
+	int num = 0;
+
+	for (;;) {
+		/*
+		 * If "block" is true, wait for at least one process.
+		 */
+		if (block && num == 0)
+			pid = wait4(-1, &status, 0, NULL);
+		else
+			pid = wait4(-1, &status, WNOHANG, NULL);
+		if (pid <= 0)
+			break;
+		if (WIFSIGNALED(status)) {
+			log_warnx("child process %d terminated with signal %d",
+			    pid, WTERMSIG(status));
+		} else if (WEXITSTATUS(status) != 0) {
+			log_debugx("child process %d terminated with exit status %d",
+			    pid, WEXITSTATUS(status));
+		} else {
+			log_debugx("child process %d terminated gracefully", pid);
+		}
+		num++;
+	}
+
+	return (num);
+}
+
+static void
+usage_automountd(void)
+{
+
+	fprintf(stderr, "usage: automountd [-D name=value][-m maxproc]"
+	    "[-o opts][-Tidv]\n");
+	exit(1);
+}
+
+int
+main_automountd(int argc, char **argv)
+{
+	struct pidfh *pidfh;
+	pid_t pid, otherpid;
+	const char *pidfile_path = AUTOMOUNTD_PIDFILE;
+	char *options = NULL;
+	struct autofs_daemon_request request;
+	int ch, debug = 0, error, maxproc = 30, retval, saved_errno;
+	bool dont_daemonize = false, incomplete_hierarchy = false;
+
+	defined_init();
+
+	while ((ch = getopt(argc, argv, "D:Tdim:o:v")) != -1) {
+		switch (ch) {
+		case 'D':
+			defined_parse_and_add(optarg);
+			break;
+		case 'T':
+			/*
+			 * For compatibility with other implementations,
+			 * such as OS X.
+			 */
+			debug++;
+			break;
+		case 'd':
+			dont_daemonize = true;
+			debug++;
+			break;
+		case 'i':
+			incomplete_hierarchy = true;
+			break;
+		case 'm':
+			maxproc = atoi(optarg);
+			break;
+		case 'o':
+			options = concat(options, ',', optarg);
+			break;
+		case 'v':
+			debug++;
+			break;
+		case '?':
+		default:
+			usage_automountd();
+		}
+	}
+	argc -= optind;
+	if (argc != 0)
+		usage_automountd();
+
+	log_init(debug);
+
+	pidfh = pidfile_open(pidfile_path, 0600, &otherpid);
+	if (pidfh == NULL) {
+		if (errno == EEXIST) {
+			log_errx(1, "daemon already running, pid: %jd.",
+			    (intmax_t)otherpid);
+		}
+		log_err(1, "cannot open or create pidfile \"%s\"",
+		    pidfile_path);
+	}
+
+	autofs_fd = open(AUTOFS_PATH, O_RDWR | O_CLOEXEC);
+	if (autofs_fd < 0 && errno == ENOENT) {
+		saved_errno = errno;
+		retval = kldload("autofs");
+		if (retval != -1)
+			autofs_fd = open(AUTOFS_PATH, O_RDWR | O_CLOEXEC);
+		else
+			errno = saved_errno;
+	}
+	if (autofs_fd < 0)
+		log_err(1, "failed to open %s", AUTOFS_PATH);
+
+	if (dont_daemonize == false) {
+		if (daemon(0, 0) == -1) {
+			log_warn("cannot daemonize");
+			pidfile_remove(pidfh);
+			exit(1);
+		}
+	} else {
+		lesser_daemon();
+	}
+
+	pidfile_write(pidfh);
+
+	register_sigchld();
+
+	for (;;) {
+		log_debugx("waiting for request from the kernel");
+
+		memset(&request, 0, sizeof(request));
+		error = ioctl(autofs_fd, AUTOFSREQUEST, &request);
+		if (error != 0) {
+			if (errno == EINTR) {
+				nchildren -= wait_for_children(false);
+				assert(nchildren >= 0);
+				continue;
+			}
+
+			log_err(1, "AUTOFSREQUEST");
+		}
+
+		if (dont_daemonize) {
+			log_debugx("not forking due to -d flag; "
+			    "will exit after servicing a single request");
+		} else {
+			nchildren -= wait_for_children(false);
+			assert(nchildren >= 0);
+
+			while (maxproc > 0 && nchildren >= maxproc) {
+				log_debugx("maxproc limit of %d child processes hit; "
+				    "waiting for child process to exit", maxproc);
+				nchildren -= wait_for_children(true);
+				assert(nchildren >= 0);
+			}
+			log_debugx("got request; forking child process #%d",
+			    nchildren);
+			nchildren++;
+
+			pid = fork();
+			if (pid < 0)
+				log_err(1, "fork");
+			if (pid > 0)
+				continue;
+		}
+
+		pidfile_close(pidfh);
+		handle_request(&request, options, incomplete_hierarchy);
+	}
+
+	pidfile_close(pidfh);
+
+	return (0);
+}
+


Property changes on: trunk/usr.sbin/autofs/automountd.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/autofs/autounmountd.8
===================================================================
--- trunk/usr.sbin/autofs/autounmountd.8	                        (rev 0)
+++ trunk/usr.sbin/autofs/autounmountd.8	2018-06-13 22:32:16 UTC (rev 10864)
@@ -0,0 +1,89 @@
+.\" $MidnightBSD$
+.\" Copyright (c) 2014 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This software was developed by Edward Tomasz Napierala under sponsorship
+.\" from the FreeBSD Foundation.
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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.
+.\"
+.\" $FreeBSD: stable/10/usr.sbin/autofs/autounmountd.8 277748 2015-01-26 13:17:20Z trasz $
+.\"
+.Dd December 13, 2014
+.Dt AUTOUNMOUNTD 8
+.Os
+.Sh NAME
+.Nm autounmountd
+.Nd daemon unmounting automounted filesystems
+.Sh SYNOPSIS
+.Nm
+.Op Fl d
+.Op Fl r Ar time
+.Op Fl t Ar time
+.Op Fl v
+.Sh DESCRIPTION
+The
+.Nm
+daemon is responsible for unmounting filesystems mounted by
+.Xr automountd 8 .
+On startup,
+.Nm
+retrieves a list of filesystems that have the
+.Li automounted
+mount option set.
+The list is updated every time a filesystem is mounted or unmounted.
+After a specified time passes,
+.Nm
+attempts to unmount a filesystem, retrying after some time if necessary.
+.Pp
+These options are available:
+.Bl -tag -width ".Fl v"
+.It Fl d
+Debug mode: increase verbosity and do not daemonize.
+.It Fl r
+Number of seconds to wait before trying to unmount an expired filesystem
+after a previous attempt failed, possibly due to filesystem being busy.
+The default value is 600, or ten minutes.
+.It Fl t
+Number of seconds to wait before trying to unmount a filesystem.
+The default value is 600, or ten minutes.
+.It Fl v
+Increase verbosity.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr auto_master 5 ,
+.Xr autofs 5 ,
+.Xr automount 8 ,
+.Xr automountd 8
+.Sh HISTORY
+The
+.Nm
+daemon appeared in
+.Fx 10.1 .
+.Sh AUTHORS
+The
+.Nm
+was developed by
+.An Edward Tomasz Napierala Aq Mt trasz at FreeBSD.org
+under sponsorship from the FreeBSD Foundation.


Property changes on: trunk/usr.sbin/autofs/autounmountd.8
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/autofs/autounmountd.c
===================================================================
--- trunk/usr.sbin/autofs/autounmountd.c	                        (rev 0)
+++ trunk/usr.sbin/autofs/autounmountd.c	2018-06-13 22:32:16 UTC (rev 10864)
@@ -0,0 +1,355 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/usr.sbin/autofs/autounmountd.c 309509 2016-12-03 19:55:55Z trasz $");
+
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/mount.h>
+#include <sys/time.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <libutil.h>
+
+#include "common.h"
+
+#define AUTOUNMOUNTD_PIDFILE	"/var/run/autounmountd.pid"
+
+struct automounted_fs {
+	TAILQ_ENTRY(automounted_fs)	af_next;
+	time_t				af_mount_time;
+	bool				af_mark;
+	fsid_t				af_fsid;
+	char				af_mountpoint[MNAMELEN];
+};
+
+static TAILQ_HEAD(, automounted_fs)	automounted;
+
+static struct automounted_fs *
+automounted_find(fsid_t fsid)
+{
+	struct automounted_fs *af;
+
+	TAILQ_FOREACH(af, &automounted, af_next) {
+		if (af->af_fsid.val[0] == fsid.val[0] &&
+		    af->af_fsid.val[1] == fsid.val[1])
+			return (af);
+	}
+
+	return (NULL);
+}
+
+static struct automounted_fs *
+automounted_add(fsid_t fsid, const char *mountpoint)
+{
+	struct automounted_fs *af;
+
+	af = calloc(sizeof(*af), 1);
+	if (af == NULL)
+		log_err(1, "calloc");
+	af->af_mount_time = time(NULL);
+	af->af_fsid = fsid;
+	strlcpy(af->af_mountpoint, mountpoint, sizeof(af->af_mountpoint));
+
+	TAILQ_INSERT_TAIL(&automounted, af, af_next);
+
+	return (af);
+}
+
+static void
+automounted_remove(struct automounted_fs *af)
+{
+
+	TAILQ_REMOVE(&automounted, af, af_next);
+	free(af);
+}
+
+static void
+refresh_automounted(void)
+{
+	struct automounted_fs *af, *tmpaf;
+	struct statfs *mntbuf;
+	int i, nitems;
+
+	nitems = getmntinfo(&mntbuf, MNT_WAIT);
+	if (nitems <= 0)
+		log_err(1, "getmntinfo");
+
+	log_debugx("refreshing list of automounted filesystems");
+
+	TAILQ_FOREACH(af, &automounted, af_next)
+		af->af_mark = false;
+
+	for (i = 0; i < nitems; i++) {
+		if (strcmp(mntbuf[i].f_fstypename, "autofs") == 0) {
+			log_debugx("skipping %s, filesystem type is autofs",
+			    mntbuf[i].f_mntonname);
+			continue;
+		}
+
+		if ((mntbuf[i].f_flags & MNT_AUTOMOUNTED) == 0) {
+			log_debugx("skipping %s, not automounted",
+			    mntbuf[i].f_mntonname);
+			continue;
+		}
+
+		af = automounted_find(mntbuf[i].f_fsid);
+		if (af == NULL) {
+			log_debugx("new automounted filesystem found on %s "
+			    "(FSID:%d:%d)", mntbuf[i].f_mntonname,
+			    mntbuf[i].f_fsid.val[0], mntbuf[i].f_fsid.val[1]);
+			af = automounted_add(mntbuf[i].f_fsid,
+			    mntbuf[i].f_mntonname);
+		} else {
+			log_debugx("already known automounted filesystem "
+			    "found on %s (FSID:%d:%d)", mntbuf[i].f_mntonname,
+			    mntbuf[i].f_fsid.val[0], mntbuf[i].f_fsid.val[1]);
+		}
+		af->af_mark = true;
+	}
+
+	TAILQ_FOREACH_SAFE(af, &automounted, af_next, tmpaf) {
+		if (af->af_mark)
+			continue;
+		log_debugx("lost filesystem mounted on %s (FSID:%d:%d)",
+		    af->af_mountpoint, af->af_fsid.val[0], af->af_fsid.val[1]);
+		automounted_remove(af);
+	}
+}
+
+static int
+unmount_by_fsid(const fsid_t fsid, const char *mountpoint)
+{
+	char *fsid_str;
+	int error, ret;
+
+	ret = asprintf(&fsid_str, "FSID:%d:%d", fsid.val[0], fsid.val[1]);
+	if (ret < 0)
+		log_err(1, "asprintf");
+
+	error = unmount(fsid_str, MNT_BYFSID);
+	if (error != 0) {
+		if (errno == EBUSY) {
+			log_debugx("cannot unmount %s (%s): %s",
+			    mountpoint, fsid_str, strerror(errno));
+		} else {
+			log_warn("cannot unmount %s (%s)",
+			    mountpoint, fsid_str);
+		}
+	}
+
+	free(fsid_str);
+
+	return (error);
+}
+
+static double
+expire_automounted(double expiration_time)
+{
+	struct automounted_fs *af, *tmpaf;
+	time_t now;
+	double mounted_for, mounted_max = -1.0;
+	int error;
+
+	now = time(NULL);
+
+	log_debugx("expiring automounted filesystems");
+
+	TAILQ_FOREACH_SAFE(af, &automounted, af_next, tmpaf) {
+		mounted_for = difftime(now, af->af_mount_time);
+
+		if (mounted_for < expiration_time) {
+			log_debugx("skipping %s (FSID:%d:%d), mounted "
+			    "for %.0f seconds", af->af_mountpoint,
+			    af->af_fsid.val[0], af->af_fsid.val[1],
+			    mounted_for);
+
+			if (mounted_for > mounted_max)
+				mounted_max = mounted_for;
+
+			continue;
+		}
+
+		log_debugx("filesystem mounted on %s (FSID:%d:%d), "
+		    "was mounted for %.0f seconds; unmounting",
+		    af->af_mountpoint, af->af_fsid.val[0], af->af_fsid.val[1],
+		    mounted_for);
+		error = unmount_by_fsid(af->af_fsid, af->af_mountpoint);
+		if (error != 0) {
+			if (mounted_for > mounted_max)
+				mounted_max = mounted_for;
+		}
+	}
+
+	return (mounted_max);
+}
+
+static void
+usage_autounmountd(void)
+{
+
+	fprintf(stderr, "usage: autounmountd [-r time][-t time][-dv]\n");
+	exit(1);
+}
+
+static void
+do_wait(int kq, double sleep_time)
+{
+	struct timespec timeout;
+	struct kevent unused;
+	int nevents;
+
+	if (sleep_time != -1.0) {
+		assert(sleep_time > 0.0);
+		timeout.tv_sec = sleep_time;
+		timeout.tv_nsec = 0;
+
+		log_debugx("waiting for filesystem event for %.0f seconds", sleep_time);
+		nevents = kevent(kq, NULL, 0, &unused, 1, &timeout);
+	} else {
+		log_debugx("waiting for filesystem event");
+		nevents = kevent(kq, NULL, 0, &unused, 1, NULL);
+	}
+	if (nevents < 0) {
+		if (errno == EINTR)
+			return;
+		log_err(1, "kevent");
+	}
+
+	if (nevents == 0) {
+		log_debugx("timeout reached");
+		assert(sleep_time > 0.0);
+	} else {
+		log_debugx("got filesystem event");
+	}
+}
+
+int
+main_autounmountd(int argc, char **argv)
+{
+	struct kevent event;
+	struct pidfh *pidfh;
+	pid_t otherpid;
+	const char *pidfile_path = AUTOUNMOUNTD_PIDFILE;
+	int ch, debug = 0, error, kq;
+	double expiration_time = 600, retry_time = 600, mounted_max, sleep_time;
+	bool dont_daemonize = false;
+
+	while ((ch = getopt(argc, argv, "dr:t:v")) != -1) {
+		switch (ch) {
+		case 'd':
+			dont_daemonize = true;
+			debug++;
+			break;
+		case 'r':
+			retry_time = atoi(optarg);
+			break;
+		case 't':
+			expiration_time = atoi(optarg);
+			break;
+		case 'v':
+			debug++;
+			break;
+		case '?':
+		default:
+			usage_autounmountd();
+		}
+	}
+	argc -= optind;
+	if (argc != 0)
+		usage_autounmountd();
+
+	if (retry_time <= 0)
+		log_errx(1, "retry time must be greater than zero");
+	if (expiration_time <= 0)
+		log_errx(1, "expiration time must be greater than zero");
+
+	log_init(debug);
+
+	pidfh = pidfile_open(pidfile_path, 0600, &otherpid);
+	if (pidfh == NULL) {
+		if (errno == EEXIST) {
+			log_errx(1, "daemon already running, pid: %jd.",
+			    (intmax_t)otherpid);
+		}
+		log_err(1, "cannot open or create pidfile \"%s\"",
+		    pidfile_path);
+	}
+
+	if (dont_daemonize == false) {
+		if (daemon(0, 0) == -1) {
+			log_warn("cannot daemonize");
+			pidfile_remove(pidfh);
+			exit(1);
+		}
+	}
+
+	pidfile_write(pidfh);
+
+	TAILQ_INIT(&automounted);
+
+	kq = kqueue();
+	if (kq < 0)
+		log_err(1, "kqueue");
+
+	EV_SET(&event, 0, EVFILT_FS, EV_ADD | EV_CLEAR, 0, 0, NULL);
+	error = kevent(kq, &event, 1, NULL, 0, NULL);
+	if (error < 0)
+		log_err(1, "kevent");
+
+	for (;;) {
+		refresh_automounted();
+		mounted_max = expire_automounted(expiration_time);
+		if (mounted_max == -1.0) {
+			sleep_time = mounted_max;
+			log_debugx("no filesystems to expire");
+		} else if (mounted_max < expiration_time) {
+			sleep_time = difftime(expiration_time, mounted_max);
+			log_debugx("some filesystems expire in %.0f seconds",
+			    sleep_time);
+		} else {
+			sleep_time = retry_time;
+			log_debugx("some expired filesystems remain mounted, "
+			    "will retry in %.0f seconds", sleep_time);
+		}
+
+		do_wait(kq, sleep_time);
+	}
+
+	return (0);
+}


Property changes on: trunk/usr.sbin/autofs/autounmountd.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/autofs/common.c
===================================================================
--- trunk/usr.sbin/autofs/common.c	                        (rev 0)
+++ trunk/usr.sbin/autofs/common.c	2018-06-13 22:32:16 UTC (rev 10864)
@@ -0,0 +1,1226 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/usr.sbin/autofs/common.c 283240 2015-05-21 13:39:38Z trasz $");
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/linker.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/utsname.h>
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <netdb.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdint.h>
+#define	_WITH_GETLINE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libutil.h>
+
+#include "autofs_ioctl.h"
+
+#include "common.h"
+
+extern FILE *yyin;
+extern char *yytext;
+extern int yylex(void);
+
+static void	parse_master_yyin(struct node *root, const char *master);
+static void	parse_map_yyin(struct node *parent, const char *map,
+		    const char *executable_key);
+
+char *
+checked_strdup(const char *s)
+{
+	char *c;
+
+	assert(s != NULL);
+
+	c = strdup(s);
+	if (c == NULL)
+		log_err(1, "strdup");
+	return (c);
+}
+
+/*
+ * Concatenate two strings, inserting separator between them, unless not needed.
+ */
+char *
+concat(const char *s1, char separator, const char *s2)
+{
+	char *result;
+	char s1last, s2first;
+	int ret;
+
+	if (s1 == NULL)
+		s1 = "";
+	if (s2 == NULL)
+		s2 = "";
+
+	if (s1[0] == '\0')
+		s1last = '\0';
+	else
+		s1last = s1[strlen(s1) - 1];
+
+	s2first = s2[0];
+
+	if (s1last == separator && s2first == separator) {
+		/*
+		 * If s1 ends with the separator and s2 begins with
+		 * it - skip the latter; otherwise concatenating "/"
+		 * and "/foo" would end up returning "//foo".
+		 */
+		ret = asprintf(&result, "%s%s", s1, s2 + 1);
+	} else if (s1last == separator || s2first == separator ||
+	    s1[0] == '\0' || s2[0] == '\0') {
+		ret = asprintf(&result, "%s%s", s1, s2);
+	} else {
+		ret = asprintf(&result, "%s%c%s", s1, separator, s2);
+	}
+	if (ret < 0)
+		log_err(1, "asprintf");
+
+	//log_debugx("%s: got %s and %s, returning %s", __func__, s1, s2, result);
+
+	return (result);
+}
+
+void
+create_directory(const char *path)
+{
+	char *component, *copy, *tofree, *partial, *tmp;
+	int error;
+
+	assert(path[0] == '/');
+
+	/*
+	 * +1 to skip the leading slash.
+	 */
+	copy = tofree = checked_strdup(path + 1);
+
+	partial = checked_strdup("");
+	for (;;) {
+		component = strsep(&copy, "/");
+		if (component == NULL)
+			break;
+		tmp = concat(partial, '/', component);
+		free(partial);
+		partial = tmp;
+		//log_debugx("creating \"%s\"", partial);
+		error = mkdir(partial, 0755);
+		if (error != 0 && errno != EEXIST) {
+			log_warn("cannot create %s", partial);
+			return;
+		}
+	}
+
+	free(tofree);
+}
+
+struct node *
+node_new_root(void)
+{
+	struct node *n;
+
+	n = calloc(1, sizeof(*n));
+	if (n == NULL)
+		log_err(1, "calloc");
+	// XXX
+	n->n_key = checked_strdup("/");
+	n->n_options = checked_strdup("");
+
+	TAILQ_INIT(&n->n_children);
+
+	return (n);
+}
+
+struct node *
+node_new(struct node *parent, char *key, char *options, char *location,
+    const char *config_file, int config_line)
+{
+	struct node *n;
+
+	n = calloc(1, sizeof(*n));
+	if (n == NULL)
+		log_err(1, "calloc");
+
+	TAILQ_INIT(&n->n_children);
+	assert(key != NULL);
+	assert(key[0] != '\0');
+	n->n_key = key;
+	if (options != NULL)
+		n->n_options = options;
+	else
+		n->n_options = strdup("");
+	n->n_location = location;
+	assert(config_file != NULL);
+	n->n_config_file = config_file;
+	assert(config_line >= 0);
+	n->n_config_line = config_line;
+
+	assert(parent != NULL);
+	n->n_parent = parent;
+	TAILQ_INSERT_TAIL(&parent->n_children, n, n_next);
+
+	return (n);
+}
+
+struct node *
+node_new_map(struct node *parent, char *key, char *options, char *map,
+    const char *config_file, int config_line)
+{
+	struct node *n;
+
+	n = calloc(1, sizeof(*n));
+	if (n == NULL)
+		log_err(1, "calloc");
+
+	TAILQ_INIT(&n->n_children);
+	assert(key != NULL);
+	assert(key[0] != '\0');
+	n->n_key = key;
+	if (options != NULL)
+		n->n_options = options;
+	else
+		n->n_options = strdup("");
+	n->n_map = map;
+	assert(config_file != NULL);
+	n->n_config_file = config_file;
+	assert(config_line >= 0);
+	n->n_config_line = config_line;
+
+	assert(parent != NULL);
+	n->n_parent = parent;
+	TAILQ_INSERT_TAIL(&parent->n_children, n, n_next);
+
+	return (n);
+}
+
+static struct node *
+node_duplicate(const struct node *o, struct node *parent)
+{
+	const struct node *child;
+	struct node *n;
+
+	if (parent == NULL)
+		parent = o->n_parent;
+
+	n = node_new(parent, o->n_key, o->n_options, o->n_location,
+	    o->n_config_file, o->n_config_line);
+
+	TAILQ_FOREACH(child, &o->n_children, n_next)
+		node_duplicate(child, n);
+
+	return (n);
+}
+
+static void
+node_delete(struct node *n)
+{
+	struct node *child, *tmp;
+
+	assert (n != NULL);
+
+	TAILQ_FOREACH_SAFE(child, &n->n_children, n_next, tmp)
+		node_delete(child);
+
+	if (n->n_parent != NULL)
+		TAILQ_REMOVE(&n->n_parent->n_children, n, n_next);
+
+	free(n);
+}
+
+/*
+ * Move (reparent) node 'n' to make it sibling of 'previous', placed
+ * just after it.
+ */
+static void
+node_move_after(struct node *n, struct node *previous)
+{
+
+	TAILQ_REMOVE(&n->n_parent->n_children, n, n_next);
+	n->n_parent = previous->n_parent;
+	TAILQ_INSERT_AFTER(&previous->n_parent->n_children, previous, n, n_next);
+}
+
+static void
+node_expand_includes(struct node *root, bool is_master)
+{
+	struct node *n, *n2, *tmp, *tmp2, *tmproot;
+	int error;
+
+	TAILQ_FOREACH_SAFE(n, &root->n_children, n_next, tmp) {
+		if (n->n_key[0] != '+')
+			continue;
+
+		error = access(AUTO_INCLUDE_PATH, F_OK);
+		if (error != 0) {
+			log_errx(1, "directory services not configured; "
+			    "%s does not exist", AUTO_INCLUDE_PATH);
+		}
+
+		/*
+		 * "+1" to skip leading "+".
+		 */
+		yyin = auto_popen(AUTO_INCLUDE_PATH, n->n_key + 1, NULL);
+		assert(yyin != NULL);
+
+		tmproot = node_new_root();
+		if (is_master)
+			parse_master_yyin(tmproot, n->n_key);
+		else
+			parse_map_yyin(tmproot, n->n_key, NULL);
+
+		error = auto_pclose(yyin);
+		yyin = NULL;
+		if (error != 0) {
+			log_errx(1, "failed to handle include \"%s\"",
+			    n->n_key);
+		}
+
+		/*
+		 * Entries to be included are now in tmproot.  We need to merge
+		 * them with the rest, preserving their place and ordering.
+		 */
+		TAILQ_FOREACH_REVERSE_SAFE(n2,
+		    &tmproot->n_children, nodehead, n_next, tmp2) {
+			node_move_after(n2, n);
+		}
+
+		node_delete(n);
+		node_delete(tmproot);
+	}
+}
+
+static char *
+expand_ampersand(char *string, const char *key)
+{
+	char c, *expanded;
+	int i, ret, before_len = 0;
+	bool backslashed = false;
+
+	assert(key[0] != '\0');
+
+	expanded = checked_strdup(string);
+
+	for (i = 0; string[i] != '\0'; i++) {
+		c = string[i];
+		if (c == '\\' && backslashed == false) {
+			backslashed = true;
+			continue;
+		}
+		if (backslashed) {
+			backslashed = false;
+			continue;
+		}
+		backslashed = false;
+		if (c != '&')
+			continue;
+
+		/*
+		 * The 'before_len' variable contains the number
+		 * of characters before the '&'.
+		 */
+		before_len = i;
+		//assert(i + 1 < (int)strlen(string));
+
+		ret = asprintf(&expanded, "%.*s%s%s",
+		    before_len, string, key, string + before_len + 1);
+		if (ret < 0)
+			log_err(1, "asprintf");
+
+		//log_debugx("\"%s\" expanded with key \"%s\" to \"%s\"",
+		//    string, key, expanded);
+
+		/*
+		 * Figure out where to start searching for next variable.
+		 */
+		string = expanded;
+		i = before_len + strlen(key);
+		backslashed = false;
+		//assert(i < (int)strlen(string));
+	}
+
+	return (expanded);
+}
+
+/*
+ * Expand "&" in n_location.  If the key is NULL, try to use
+ * key from map entries themselves.  Keep in mind that maps
+ * consist of tho levels of node structures, the key is one
+ * level up.
+ *
+ * Variant with NULL key is for "automount -LL".
+ */
+void
+node_expand_ampersand(struct node *n, const char *key)
+{
+	struct node *child;
+
+	if (n->n_location != NULL) {
+		if (key == NULL) {
+			if (n->n_parent != NULL &&
+			    strcmp(n->n_parent->n_key, "*") != 0) {
+				n->n_location = expand_ampersand(n->n_location,
+				    n->n_parent->n_key);
+			}
+		} else {
+			n->n_location = expand_ampersand(n->n_location, key);
+		}
+	}
+
+	TAILQ_FOREACH(child, &n->n_children, n_next)
+		node_expand_ampersand(child, key);
+}
+
+/*
+ * Expand "*" in n_key.
+ */
+void
+node_expand_wildcard(struct node *n, const char *key)
+{
+	struct node *child, *expanded;
+
+	assert(key != NULL);
+
+	if (strcmp(n->n_key, "*") == 0) {
+		expanded = node_duplicate(n, NULL);
+		expanded->n_key = checked_strdup(key);
+		node_move_after(expanded, n);
+	}
+
+	TAILQ_FOREACH(child, &n->n_children, n_next)
+		node_expand_wildcard(child, key);
+}
+
+int
+node_expand_defined(struct node *n)
+{
+	struct node *child;
+	int error, cumulated_error = 0;
+
+	if (n->n_location != NULL) {
+		n->n_location = defined_expand(n->n_location);
+		if (n->n_location == NULL) {
+			log_warnx("failed to expand location for %s",
+			    node_path(n));
+			return (EINVAL);
+		}
+	}
+
+	TAILQ_FOREACH(child, &n->n_children, n_next) {
+		error = node_expand_defined(child);
+		if (error != 0 && cumulated_error == 0)
+			cumulated_error = error;
+	}
+
+	return (cumulated_error);
+}
+
+static bool
+node_is_direct_key(const struct node *n)
+{
+
+	if (n->n_parent != NULL && n->n_parent->n_parent == NULL &&
+	    strcmp(n->n_key, "/-") == 0) {
+		return (true);
+	}
+
+	return (false);
+}
+
+bool
+node_is_direct_map(const struct node *n)
+{
+
+	for (;;) {
+		assert(n->n_parent != NULL);
+		if (n->n_parent->n_parent == NULL)
+			break;
+		n = n->n_parent;
+	}
+
+	return (node_is_direct_key(n));
+}
+
+bool
+node_has_wildcards(const struct node *n)
+{
+	const struct node *child;
+
+	TAILQ_FOREACH(child, &n->n_children, n_next) {
+		if (strcmp(child->n_key, "*") == 0)
+			return (true);
+	}
+
+	return (false);
+}
+
+static void
+node_expand_maps(struct node *n, bool indirect)
+{
+	struct node *child, *tmp;
+
+	TAILQ_FOREACH_SAFE(child, &n->n_children, n_next, tmp) {
+		if (node_is_direct_map(child)) {
+			if (indirect)
+				continue;
+		} else {
+			if (indirect == false)
+				continue;
+		}
+
+		/*
+		 * This is the first-level map node; the one that contains
+		 * the key and subnodes with mountpoints and actual map names.
+		 */
+		if (child->n_map == NULL)
+			continue;
+
+		if (indirect) {
+			log_debugx("map \"%s\" is an indirect map, parsing",
+			    child->n_map);
+		} else {
+			log_debugx("map \"%s\" is a direct map, parsing",
+			    child->n_map);
+		}
+		parse_map(child, child->n_map, NULL, NULL);
+	}
+}
+
+static void
+node_expand_direct_maps(struct node *n)
+{
+
+	node_expand_maps(n, false);
+}
+
+void
+node_expand_indirect_maps(struct node *n)
+{
+
+	node_expand_maps(n, true);
+}
+
+static char *
+node_path_x(const struct node *n, char *x)
+{
+	char *path;
+
+	if (n->n_parent == NULL)
+		return (x);
+
+	/*
+	 * Return "/-" for direct maps only if we were asked for path
+	 * to the "/-" node itself, not to any of its subnodes.
+	 */
+	if (node_is_direct_key(n) && x[0] != '\0')
+		return (x);
+
+	assert(n->n_key[0] != '\0');
+	path = concat(n->n_key, '/', x);
+	free(x);
+
+	return (node_path_x(n->n_parent, path));
+}
+
+/*
+ * Return full path for node, consisting of concatenated
+ * paths of node itself and all its parents, up to the root.
+ */
+char *
+node_path(const struct node *n)
+{
+	char *path;
+	size_t len;
+
+	path = node_path_x(n, checked_strdup(""));
+
+	/*
+	 * Strip trailing slash, unless the whole path is "/".
+	 */
+	len = strlen(path);
+	if (len > 1 && path[len - 1] == '/')
+		path[len - 1] = '\0';
+
+	return (path);
+}
+
+static char *
+node_options_x(const struct node *n, char *x)
+{
+	char *options;
+
+	if (n == NULL)
+		return (x);
+
+	options = concat(x, ',', n->n_options);
+	free(x);
+
+	return (node_options_x(n->n_parent, options));
+}
+
+/*
+ * Return options for node, consisting of concatenated
+ * options from the node itself and all its parents,
+ * up to the root.
+ */
+char *
+node_options(const struct node *n)
+{
+
+	return (node_options_x(n, checked_strdup("")));
+}
+
+static void
+node_print_indent(const struct node *n, const char *cmdline_options,
+    int indent)
+{
+	const struct node *child, *first_child;
+	char *path, *options, *tmp;
+
+	path = node_path(n);
+	tmp = node_options(n);
+	options = concat(cmdline_options, ',', tmp);
+	free(tmp);
+
+	/*
+	 * Do not show both parent and child node if they have the same
+	 * mountpoint; only show the child node.  This means the typical,
+	 * "key location", map entries are shown in a single line;
+	 * the "key mountpoint1 location2 mountpoint2 location2" entries
+	 * take multiple lines.
+	 */
+	first_child = TAILQ_FIRST(&n->n_children);
+	if (first_child == NULL || TAILQ_NEXT(first_child, n_next) != NULL ||
+	    strcmp(path, node_path(first_child)) != 0) {
+		assert(n->n_location == NULL || n->n_map == NULL);
+		printf("%*.s%-*s %s%-*s %-*s # %s map %s at %s:%d\n",
+		    indent, "",
+		    25 - indent,
+		    path,
+		    options[0] != '\0' ? "-" : " ",
+		    20,
+		    options[0] != '\0' ? options : "",
+		    20,
+		    n->n_location != NULL ? n->n_location : n->n_map != NULL ? n->n_map : "",
+		    node_is_direct_map(n) ? "direct" : "indirect",
+		    indent == 0 ? "referenced" : "defined",
+		    n->n_config_file, n->n_config_line);
+	}
+
+	free(path);
+	free(options);
+
+	TAILQ_FOREACH(child, &n->n_children, n_next)
+		node_print_indent(child, cmdline_options, indent + 2);
+}
+
+/*
+ * Recursively print node with all its children.  The cmdline_options
+ * argument is used for additional options to be prepended to all the
+ * others - usually those are the options passed by command line.
+ */
+void
+node_print(const struct node *n, const char *cmdline_options)
+{
+	const struct node *child;
+
+	TAILQ_FOREACH(child, &n->n_children, n_next)
+		node_print_indent(child, cmdline_options, 0);
+}
+
+static struct node *
+node_find_x(struct node *node, const char *path)
+{
+	struct node *child, *found;
+	char *tmp;
+	size_t tmplen;
+
+	//log_debugx("looking up %s in %s", path, node_path(node));
+
+	if (!node_is_direct_key(node)) {
+		tmp = node_path(node);
+		tmplen = strlen(tmp);
+		if (strncmp(tmp, path, tmplen) != 0) {
+			free(tmp);
+			return (NULL);
+		}
+		if (path[tmplen] != '/' && path[tmplen] != '\0') {
+			/*
+			 * If we have two map entries like 'foo' and 'foobar', make
+			 * sure the search for 'foobar' won't match 'foo' instead.
+			 */
+			free(tmp);
+			return (NULL);
+		}
+		free(tmp);
+	}
+
+	TAILQ_FOREACH(child, &node->n_children, n_next) {
+		found = node_find_x(child, path);
+		if (found != NULL)
+			return (found);
+	}
+
+	if (node->n_parent == NULL || node_is_direct_key(node))
+		return (NULL);
+
+	return (node);
+}
+
+struct node *
+node_find(struct node *root, const char *path)
+{
+	struct node *node;
+
+	assert(root->n_parent == NULL);
+
+	node = node_find_x(root, path);
+	if (node != NULL)
+		assert(node != root);
+
+	return (node);
+}
+
+/*
+ * Canonical form of a map entry looks like this:
+ *
+ * key [-options] [ [/mountpoint] [-options2] location ... ]
+ *
+ * Entries for executable maps are slightly different, as they
+ * lack the 'key' field and are always single-line; the key field
+ * for those maps is taken from 'executable_key' argument.
+ *
+ * We parse it in such a way that a map always has two levels - first
+ * for key, and the second, for the mountpoint.
+ */
+static void
+parse_map_yyin(struct node *parent, const char *map, const char *executable_key)
+{
+	char *key = NULL, *options = NULL, *mountpoint = NULL,
+	    *options2 = NULL, *location = NULL;
+	int ret;
+	struct node *node;
+
+	lineno = 1;
+
+	if (executable_key != NULL)
+		key = checked_strdup(executable_key);
+
+	for (;;) {
+		ret = yylex();
+		if (ret == 0 || ret == NEWLINE) {
+			/*
+			 * In case of executable map, the key is always
+			 * non-NULL, even if the map is empty.  So, make sure
+			 * we don't fail empty maps here.
+			 */
+			if ((key != NULL && executable_key == NULL) ||
+			    options != NULL) {
+				log_errx(1, "truncated entry at %s, line %d",
+				    map, lineno);
+			}
+			if (ret == 0 || executable_key != NULL) {
+				/*
+				 * End of file.
+				 */
+				break;
+			} else {
+				key = options = NULL;
+				continue;
+			}
+		}
+		if (key == NULL) {
+			key = checked_strdup(yytext);
+			if (key[0] == '+') {
+				node_new(parent, key, NULL, NULL, map, lineno);
+				key = options = NULL;
+				continue;
+			}
+			continue;
+		} else if (yytext[0] == '-') {
+			if (options != NULL) {
+				log_errx(1, "duplicated options at %s, line %d",
+				    map, lineno);
+			}
+			/*
+			 * +1 to skip leading "-".
+			 */
+			options = checked_strdup(yytext + 1);
+			continue;
+		}
+
+		/*
+		 * We cannot properly handle a situation where the map key
+		 * is "/".  Ignore such entries.
+		 *
+		 * XXX: According to Piete Brooks, Linux automounter uses
+		 *	"/" as a wildcard character in LDAP maps.  Perhaps
+		 *	we should work around this braindamage by substituting
+		 *	"*" for "/"?
+		 */
+		if (strcmp(key, "/") == 0) {
+			log_warnx("nonsensical map key \"/\" at %s, line %d; "
+			    "ignoring map entry ", map, lineno);
+
+			/*
+			 * Skip the rest of the entry.
+			 */
+			do {
+				ret = yylex();
+			} while (ret != 0 && ret != NEWLINE);
+
+			key = options = NULL;
+			continue;
+		}
+
+		//log_debugx("adding map node, %s", key);
+		node = node_new(parent, key, options, NULL, map, lineno);
+		key = options = NULL;
+
+		for (;;) {
+			if (yytext[0] == '/') {
+				if (mountpoint != NULL) {
+					log_errx(1, "duplicated mountpoint "
+					    "in %s, line %d", map, lineno);
+				}
+				if (options2 != NULL || location != NULL) {
+					log_errx(1, "mountpoint out of order "
+					    "in %s, line %d", map, lineno);
+				}
+				mountpoint = checked_strdup(yytext);
+				goto again;
+			}
+
+			if (yytext[0] == '-') {
+				if (options2 != NULL) {
+					log_errx(1, "duplicated options "
+					    "in %s, line %d", map, lineno);
+				}
+				if (location != NULL) {
+					log_errx(1, "options out of order "
+					    "in %s, line %d", map, lineno);
+				}
+				options2 = checked_strdup(yytext + 1);
+				goto again;
+			}
+
+			if (location != NULL) {
+				log_errx(1, "too many arguments "
+				    "in %s, line %d", map, lineno);
+			}
+
+			/*
+			 * If location field starts with colon, e.g. ":/dev/cd0",
+			 * then strip it.
+			 */
+			if (yytext[0] == ':') {
+				location = checked_strdup(yytext + 1);
+				if (location[0] == '\0') {
+					log_errx(1, "empty location in %s, "
+					    "line %d", map, lineno);
+				}
+			} else {
+				location = checked_strdup(yytext);
+			}
+
+			if (mountpoint == NULL)
+				mountpoint = checked_strdup("/");
+			if (options2 == NULL)
+				options2 = checked_strdup("");
+
+#if 0
+			log_debugx("adding map node, %s %s %s",
+			    mountpoint, options2, location);
+#endif
+			node_new(node, mountpoint, options2, location,
+			    map, lineno);
+			mountpoint = options2 = location = NULL;
+again:
+			ret = yylex();
+			if (ret == 0 || ret == NEWLINE) {
+				if (mountpoint != NULL || options2 != NULL ||
+				    location != NULL) {
+					log_errx(1, "truncated entry "
+					    "in %s, line %d", map, lineno);
+				}
+				break;
+			}
+		}
+	}
+}
+
+/*
+ * Parse output of a special map called without argument.  It is a list
+ * of keys, separated by newlines.  They can contain whitespace, so use
+ * getline(3) instead of lexer used for maps.
+ */
+static void
+parse_map_keys_yyin(struct node *parent, const char *map)
+{
+	char *line = NULL, *key;
+	size_t linecap = 0;
+	ssize_t linelen;
+
+	lineno = 1;
+
+	for (;;) {
+		linelen = getline(&line, &linecap, yyin);
+		if (linelen < 0) {
+			/*
+			 * End of file.
+			 */
+			break;
+		}
+		if (linelen <= 1) {
+			/*
+			 * Empty line, consisting of just the newline.
+			 */
+			continue;
+		}
+
+		/*
+		 * "-1" to strip the trailing newline.
+		 */
+		key = strndup(line, linelen - 1);
+
+		log_debugx("adding key \"%s\"", key);
+		node_new(parent, key, NULL, NULL, map, lineno);
+		lineno++;
+	}
+	free(line);
+}
+
+static bool
+file_is_executable(const char *path)
+{
+	struct stat sb;
+	int error;
+
+	error = stat(path, &sb);
+	if (error != 0)
+		log_err(1, "cannot stat %s", path);
+	if ((sb.st_mode & S_IXUSR) || (sb.st_mode & S_IXGRP) ||
+	    (sb.st_mode & S_IXOTH))
+		return (true);
+	return (false);
+}
+
+/*
+ * Parse a special map, e.g. "-hosts".
+ */
+static void
+parse_special_map(struct node *parent, const char *map, const char *key)
+{
+	char *path;
+	int error, ret;
+
+	assert(map[0] == '-');
+
+	/*
+	 * +1 to skip leading "-" in map name.
+	 */
+	ret = asprintf(&path, "%s/special_%s", AUTO_SPECIAL_PREFIX, map + 1);
+	if (ret < 0)
+		log_err(1, "asprintf");
+
+	yyin = auto_popen(path, key, NULL);
+	assert(yyin != NULL);
+
+	if (key == NULL) {
+		parse_map_keys_yyin(parent, map);
+	} else {
+		parse_map_yyin(parent, map, key);
+	}
+
+	error = auto_pclose(yyin);
+	yyin = NULL;
+	if (error != 0)
+		log_errx(1, "failed to handle special map \"%s\"", map);
+
+	node_expand_includes(parent, false);
+	node_expand_direct_maps(parent);
+
+	free(path);
+}
+
+/*
+ * Retrieve and parse map from directory services, e.g. LDAP.
+ * Note that it is different from executable maps, in that
+ * the include script outputs the whole map to standard output
+ * (as opposed to executable maps that only output a single
+ * entry, without the key), and it takes the map name as an
+ * argument, instead of key.
+ */
+static void
+parse_included_map(struct node *parent, const char *map)
+{
+	int error;
+
+	assert(map[0] != '-');
+	assert(map[0] != '/');
+
+	error = access(AUTO_INCLUDE_PATH, F_OK);
+	if (error != 0) {
+		log_errx(1, "directory services not configured;"
+		    " %s does not exist", AUTO_INCLUDE_PATH);
+	}
+
+	yyin = auto_popen(AUTO_INCLUDE_PATH, map, NULL);
+	assert(yyin != NULL);
+
+	parse_map_yyin(parent, map, NULL);
+
+	error = auto_pclose(yyin);
+	yyin = NULL;
+	if (error != 0)
+		log_errx(1, "failed to handle remote map \"%s\"", map);
+
+	node_expand_includes(parent, false);
+	node_expand_direct_maps(parent);
+}
+
+void
+parse_map(struct node *parent, const char *map, const char *key,
+    bool *wildcards)
+{
+	char *path = NULL;
+	int error, ret;
+	bool executable;
+
+	assert(map != NULL);
+	assert(map[0] != '\0');
+
+	log_debugx("parsing map \"%s\"", map);
+
+	if (wildcards != NULL)
+		*wildcards = false;
+
+	if (map[0] == '-') {
+		if (wildcards != NULL)
+			*wildcards = true;
+		return (parse_special_map(parent, map, key));
+	}
+
+	if (map[0] == '/') {
+		path = checked_strdup(map);
+	} else {
+		ret = asprintf(&path, "%s/%s", AUTO_MAP_PREFIX, map);
+		if (ret < 0)
+			log_err(1, "asprintf");
+		log_debugx("map \"%s\" maps to \"%s\"", map, path);
+
+		/*
+		 * See if the file exists.  If not, try to obtain the map
+		 * from directory services.
+		 */
+		error = access(path, F_OK);
+		if (error != 0) {
+			log_debugx("map file \"%s\" does not exist; falling "
+			    "back to directory services", path);
+			return (parse_included_map(parent, map));
+		}
+	}
+
+	executable = file_is_executable(path);
+
+	if (executable) {
+		log_debugx("map \"%s\" is executable", map);
+
+		if (wildcards != NULL)
+			*wildcards = true;
+
+		if (key != NULL) {
+			yyin = auto_popen(path, key, NULL);
+		} else {
+			yyin = auto_popen(path, NULL);
+		}
+		assert(yyin != NULL);
+	} else {
+		yyin = fopen(path, "r");
+		if (yyin == NULL)
+			log_err(1, "unable to open \"%s\"", path);
+	}
+
+	free(path);
+	path = NULL;
+
+	parse_map_yyin(parent, map, executable ? key : NULL);
+
+	if (executable) {
+		error = auto_pclose(yyin);
+		yyin = NULL;
+		if (error != 0) {
+			log_errx(1, "failed to handle executable map \"%s\"",
+			    map);
+		}
+	} else {
+		fclose(yyin);
+	}
+	yyin = NULL;
+
+	log_debugx("done parsing map \"%s\"", map);
+
+	node_expand_includes(parent, false);
+	node_expand_direct_maps(parent);
+}
+
+static void
+parse_master_yyin(struct node *root, const char *master)
+{
+	char *mountpoint = NULL, *map = NULL, *options = NULL;
+	int ret;
+
+	/*
+	 * XXX: 1 gives incorrect values; wtf?
+	 */
+	lineno = 0;
+
+	for (;;) {
+		ret = yylex();
+		if (ret == 0 || ret == NEWLINE) {
+			if (mountpoint != NULL) {
+				//log_debugx("adding map for %s", mountpoint);
+				node_new_map(root, mountpoint, options, map,
+				    master, lineno);
+			}
+			if (ret == 0) {
+				break;
+			} else {
+				mountpoint = map = options = NULL;
+				continue;
+			}
+		}
+		if (mountpoint == NULL) {
+			mountpoint = checked_strdup(yytext);
+		} else if (map == NULL) {
+			map = checked_strdup(yytext);
+		} else if (options == NULL) {
+			/*
+			 * +1 to skip leading "-".
+			 */
+			options = checked_strdup(yytext + 1);
+		} else {
+			log_errx(1, "too many arguments at %s, line %d",
+			    master, lineno);
+		}
+	}
+}
+
+void
+parse_master(struct node *root, const char *master)
+{
+
+	log_debugx("parsing auto_master file at \"%s\"", master);
+
+	yyin = fopen(master, "r");
+	if (yyin == NULL)
+		err(1, "unable to open %s", master);
+
+	parse_master_yyin(root, master);
+
+	fclose(yyin);
+	yyin = NULL;
+
+	log_debugx("done parsing \"%s\"", master);
+
+	node_expand_includes(root, true);
+	node_expand_direct_maps(root);
+}
+
+/*
+ * Two things daemon(3) does, that we actually also want to do
+ * when running in foreground, is closing the stdin and chdiring
+ * to "/".  This is what we do here.
+ */
+void
+lesser_daemon(void)
+{
+	int error, fd;
+
+	error = chdir("/");
+	if (error != 0)
+		log_warn("chdir");
+
+	fd = open(_PATH_DEVNULL, O_RDWR, 0);
+	if (fd < 0) {
+		log_warn("cannot open %s", _PATH_DEVNULL);
+		return;
+	}
+
+	error = dup2(fd, STDIN_FILENO);
+	if (error != 0)
+		log_warn("dup2");
+
+	error = close(fd);
+	if (error != 0) {
+		/* Bloody hell. */
+		log_warn("close");
+	}
+}
+
+int
+main(int argc, char **argv)
+{
+	char *cmdname;
+
+	if (argv[0] == NULL)
+		log_errx(1, "NULL command name");
+
+	cmdname = basename(argv[0]);
+
+	if (strcmp(cmdname, "automount") == 0)
+		return (main_automount(argc, argv));
+	else if (strcmp(cmdname, "automountd") == 0)
+		return (main_automountd(argc, argv));
+	else if (strcmp(cmdname, "autounmountd") == 0)
+		return (main_autounmountd(argc, argv));
+	else
+		log_errx(1, "binary name should be either \"automount\", "
+		    "\"automountd\", or \"autounmountd\"");
+}


Property changes on: trunk/usr.sbin/autofs/common.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/autofs/common.h
===================================================================
--- trunk/usr.sbin/autofs/common.h	                        (rev 0)
+++ trunk/usr.sbin/autofs/common.h	2018-06-13 22:32:16 UTC (rev 10864)
@@ -0,0 +1,115 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD: stable/10/usr.sbin/autofs/common.h 283239 2015-05-21 13:37:48Z trasz $
+ */
+
+#ifndef AUTOMOUNTD_H
+#define	AUTOMOUNTD_H
+
+#include <sys/queue.h>
+#include <stdbool.h>
+
+#define	AUTO_MASTER_PATH	"/etc/auto_master"
+#define	AUTO_MAP_PREFIX		"/etc"
+#define	AUTO_SPECIAL_PREFIX	"/etc/autofs"
+#define	AUTO_INCLUDE_PATH	AUTO_SPECIAL_PREFIX "/include"
+
+struct node {
+	TAILQ_ENTRY(node)	n_next;
+	TAILQ_HEAD(nodehead, node)	n_children;
+	struct node		*n_parent;
+	char			*n_key;
+	char			*n_options;
+	char			*n_location;
+	char			*n_map;
+	const char		*n_config_file;
+	int			n_config_line;
+};
+
+struct defined_value {
+	TAILQ_ENTRY(defined_value)	d_next;
+	char				*d_name;
+	char				*d_value;
+};
+
+void	log_init(int level);
+void	log_set_peer_name(const char *name);
+void	log_set_peer_addr(const char *addr);
+void	log_err(int, const char *, ...)
+	    __dead2 __printf0like(2, 3);
+void	log_errx(int, const char *, ...)
+	    __dead2 __printf0like(2, 3);
+void	log_warn(const char *, ...) __printf0like(1, 2);
+void	log_warnx(const char *, ...) __printflike(1, 2);
+void	log_debugx(const char *, ...) __printf0like(1, 2);
+
+char	*checked_strdup(const char *);
+char	*concat(const char *s1, char separator, const char *s2);
+void	create_directory(const char *path);
+
+struct node	*node_new_root(void);
+struct node	*node_new(struct node *parent, char *key, char *options,
+		    char *location, const char *config_file, int config_line);
+struct node	*node_new_map(struct node *parent, char *key, char *options,
+		    char *map, const char *config_file, int config_line);
+struct node	*node_find(struct node *root, const char *mountpoint);
+bool		node_is_direct_map(const struct node *n);
+bool		node_has_wildcards(const struct node *n);
+char	*node_path(const struct node *n);
+char	*node_options(const struct node *n);
+void	node_expand_ampersand(struct node *root, const char *key);
+void	node_expand_wildcard(struct node *root, const char *key);
+int	node_expand_defined(struct node *root);
+void	node_expand_indirect_maps(struct node *n);
+void	node_print(const struct node *n, const char *cmdline_options);
+void	parse_master(struct node *root, const char *path);
+void	parse_map(struct node *parent, const char *map, const char *args,
+	    bool *wildcards);
+char	*defined_expand(const char *string);
+void	defined_init(void);
+void	defined_parse_and_add(char *def);
+void	lesser_daemon(void);
+
+int	main_automount(int argc, char **argv);
+int	main_automountd(int argc, char **argv);
+int	main_autounmountd(int argc, char **argv);
+
+FILE	*auto_popen(const char *argv0, ...);
+int	auto_pclose(FILE *iop);
+
+/*
+ * lex(1) stuff.
+ */
+extern int lineno;
+
+#define	STR	1
+#define	NEWLINE	2
+
+#endif /* !AUTOMOUNTD_H */


Property changes on: trunk/usr.sbin/autofs/common.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/autofs/defined.c
===================================================================
--- trunk/usr.sbin/autofs/defined.c	                        (rev 0)
+++ trunk/usr.sbin/autofs/defined.c	2018-06-13 22:32:16 UTC (rev 10864)
@@ -0,0 +1,273 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ */
+
+/*
+ * All the "defined" stuff is for handling variables,
+ * such as ${OSNAME}, in maps.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/usr.sbin/autofs/defined.c 270897 2014-08-31 21:48:12Z trasz $");
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/linker.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/utsname.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <netdb.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libutil.h>
+
+#include "common.h"
+
+static TAILQ_HEAD(, defined_value)	defined_values;
+
+static const char *
+defined_find(const char *name)
+{
+	struct defined_value *d;
+
+	TAILQ_FOREACH(d, &defined_values, d_next) {
+		if (strcmp(d->d_name, name) == 0)
+			return (d->d_value);
+	}
+
+	return (NULL);
+}
+
+char *
+defined_expand(const char *string)
+{
+	const char *value;
+	char c, *expanded, *name;
+	int i, ret, before_len = 0, name_off = 0, name_len = 0, after_off = 0;
+	bool backslashed = false, bracketed = false;
+
+	expanded = checked_strdup(string);
+
+	for (i = 0; string[i] != '\0'; i++) {
+		c = string[i];
+		if (c == '\\' && backslashed == false) {
+			backslashed = true;
+			continue;
+		}
+		if (backslashed) {
+			backslashed = false;
+			continue;
+		}
+		backslashed = false;
+		if (c != '$')
+			continue;
+
+		/*
+		 * The 'before_len' variable contains the number
+		 * of characters before the '$'.
+		 */
+		before_len = i;
+		assert(i + 1 < (int)strlen(string));
+		if (string[i + 1] == '{')
+			bracketed = true;
+
+		if (string[i + 1] == '\0') {
+			log_warnx("truncated variable");
+			return (NULL);
+		}
+
+		/*
+		 * Skip '$'.
+		 */
+		i++;
+
+		if (bracketed) {
+			if (string[i + 1] == '\0') {
+				log_warnx("truncated variable");
+				return (NULL);
+			}
+
+			/*
+			 * Skip '{'.
+			 */
+			i++;
+		}
+
+		/*
+		 * The 'name_off' variable contains the number
+		 * of characters before the variable name,
+		 * including the "$" or "${".
+		 */
+		name_off = i;
+
+		for (; string[i] != '\0'; i++) {
+			c = string[i];
+			/*
+			 * XXX: Decide on the set of characters that can be
+			 *	used in a variable name.
+			 */
+			if (isalnum(c) || c == '_')
+				continue;
+
+			/*
+			 * End of variable name.
+			 */
+			if (bracketed) {
+				if (c != '}')
+					continue;
+
+				/*
+				 * The 'after_off' variable contains the number
+				 * of characters before the rest of the string,
+				 * i.e. after the variable name.
+				 */
+				after_off = i + 1;
+				assert(i > 1);
+				assert(i - 1 > name_off);
+				name_len = i - name_off;
+				break;
+			}
+
+			after_off = i;
+			assert(i > 1);
+			assert(i > name_off);
+			name_len = i - name_off;
+			break;
+		}
+
+		name = strndup(string + name_off, name_len);
+		if (name == NULL)
+			log_err(1, "strndup");
+		value = defined_find(name);
+		if (value == NULL) {
+			log_warnx("undefined variable ${%s}", name);
+			return (NULL);
+		}
+
+		/*
+		 * Concatenate it back.
+		 */
+		ret = asprintf(&expanded, "%.*s%s%s",
+		    before_len, string, value, string + after_off);
+		if (ret < 0)
+			log_err(1, "asprintf");
+
+		//log_debugx("\"%s\" expanded to \"%s\"", string, expanded);
+		free(name);
+
+		/*
+		 * Figure out where to start searching for next variable.
+		 */
+		string = expanded;
+		i = before_len + strlen(value);
+		backslashed = bracketed = false;
+		before_len = name_off = name_len = after_off = 0;
+		assert(i <= (int)strlen(string));
+	}
+
+	if (before_len != 0 || name_off != 0 || name_len != 0 || after_off != 0) {
+		log_warnx("truncated variable");
+		return (NULL);
+	}
+
+	return (expanded);
+}
+
+static void
+defined_add(const char *name, const char *value)
+{
+	struct defined_value *d;
+	const char *found;
+
+	found = defined_find(name);
+	if (found != NULL)
+		log_errx(1, "variable %s already defined", name);
+
+	log_debugx("defining variable %s=%s", name, value);
+
+	d = calloc(sizeof(*d), 1);
+	if (d == NULL)
+		log_err(1, "calloc");
+	d->d_name = checked_strdup(name);
+	d->d_value = checked_strdup(value);
+
+	TAILQ_INSERT_TAIL(&defined_values, d, d_next);
+}
+
+void
+defined_parse_and_add(char *def)
+{
+	char *name, *value;
+
+	value = def;
+	name = strsep(&value, "=");
+
+	if (value == NULL || value[0] == '\0')
+		log_errx(1, "missing variable value");
+	if (name == NULL || name[0] == '\0')
+		log_errx(1, "missing variable name");
+
+	defined_add(name, value);
+}
+
+void
+defined_init(void)
+{
+	struct utsname name;
+	int error;
+
+	TAILQ_INIT(&defined_values);
+
+	error = uname(&name);
+	if (error != 0)
+		log_err(1, "uname");
+
+	defined_add("ARCH", name.machine);
+	defined_add("CPU", name.machine);
+	defined_add("HOST", name.nodename);
+	defined_add("OSNAME", name.sysname);
+	defined_add("OSREL", name.release);
+	defined_add("OSVERS", name.version);
+}


Property changes on: trunk/usr.sbin/autofs/defined.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/autofs/log.c
===================================================================
--- trunk/usr.sbin/autofs/log.c	                        (rev 0)
+++ trunk/usr.sbin/autofs/log.c	2018-06-13 22:32:16 UTC (rev 10864)
@@ -0,0 +1,199 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/usr.sbin/autofs/log.c 270897 2014-08-31 21:48:12Z trasz $");
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <vis.h>
+
+#include "common.h"
+
+static int log_level = 0;
+static char *peer_name = NULL;
+static char *peer_addr = NULL;
+
+#define	MSGBUF_LEN	1024
+
+void
+log_init(int level)
+{
+
+	log_level = level;
+	openlog(getprogname(), LOG_NDELAY | LOG_PID, LOG_DAEMON);
+}
+
+void
+log_set_peer_name(const char *name)
+{
+
+	/*
+	 * XXX: Turn it into assertion?
+	 */
+	if (peer_name != NULL)
+		log_errx(1, "%s called twice", __func__);
+	if (peer_addr == NULL)
+		log_errx(1, "%s called before log_set_peer_addr", __func__);
+
+	peer_name = checked_strdup(name);
+}
+
+void
+log_set_peer_addr(const char *addr)
+{
+
+	/*
+	 * XXX: Turn it into assertion?
+	 */
+	if (peer_addr != NULL)
+		log_errx(1, "%s called twice", __func__);
+
+	peer_addr = checked_strdup(addr);
+}
+
+static void
+log_common(int priority, int log_errno, const char *fmt, va_list ap)
+{
+	static char msgbuf[MSGBUF_LEN];
+	static char msgbuf_strvised[MSGBUF_LEN * 4 + 1];
+	int ret;
+
+	ret = vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
+	if (ret < 0) {
+		fprintf(stderr, "%s: snprintf failed", getprogname());
+		syslog(LOG_CRIT, "snprintf failed");
+		exit(1);
+	}
+
+	ret = strnvis(msgbuf_strvised, sizeof(msgbuf_strvised), msgbuf, VIS_NL);
+	if (ret < 0) {
+		fprintf(stderr, "%s: strnvis failed", getprogname());
+		syslog(LOG_CRIT, "strnvis failed");
+		exit(1);
+	}
+
+	if (log_errno == -1) {
+		if (peer_name != NULL) {
+			fprintf(stderr, "%s: %s (%s): %s\n", getprogname(),
+			    peer_addr, peer_name, msgbuf_strvised);
+			syslog(priority, "%s (%s): %s",
+			    peer_addr, peer_name, msgbuf_strvised);
+		} else if (peer_addr != NULL) {
+			fprintf(stderr, "%s: %s: %s\n", getprogname(),
+			    peer_addr, msgbuf_strvised);
+			syslog(priority, "%s: %s",
+			    peer_addr, msgbuf_strvised);
+		} else {
+			fprintf(stderr, "%s: %s\n", getprogname(), msgbuf_strvised);
+			syslog(priority, "%s", msgbuf_strvised);
+		}
+
+	} else {
+		if (peer_name != NULL) {
+			fprintf(stderr, "%s: %s (%s): %s: %s\n", getprogname(),
+			    peer_addr, peer_name, msgbuf_strvised, strerror(errno));
+			syslog(priority, "%s (%s): %s: %s",
+			    peer_addr, peer_name, msgbuf_strvised, strerror(errno));
+		} else if (peer_addr != NULL) {
+			fprintf(stderr, "%s: %s: %s: %s\n", getprogname(),
+			    peer_addr, msgbuf_strvised, strerror(errno));
+			syslog(priority, "%s: %s: %s",
+			    peer_addr, msgbuf_strvised, strerror(errno));
+		} else {
+			fprintf(stderr, "%s: %s: %s\n", getprogname(),
+			    msgbuf_strvised, strerror(errno));
+			syslog(priority, "%s: %s",
+			    msgbuf_strvised, strerror(errno));
+		}
+	}
+}
+
+void
+log_err(int eval, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	log_common(LOG_CRIT, errno, fmt, ap);
+	va_end(ap);
+
+	exit(eval);
+}
+
+void
+log_errx(int eval, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	log_common(LOG_CRIT, -1, fmt, ap);
+	va_end(ap);
+
+	exit(eval);
+}
+
+void
+log_warn(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	log_common(LOG_WARNING, errno, fmt, ap);
+	va_end(ap);
+}
+
+void
+log_warnx(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	log_common(LOG_WARNING, -1, fmt, ap);
+	va_end(ap);
+}
+
+void
+log_debugx(const char *fmt, ...)
+{
+	va_list ap;
+
+	if (log_level == 0)
+		return;
+
+	va_start(ap, fmt);
+	log_common(LOG_DEBUG, -1, fmt, ap);
+	va_end(ap);
+}


Property changes on: trunk/usr.sbin/autofs/log.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/autofs/popen.c
===================================================================
--- trunk/usr.sbin/autofs/popen.c	                        (rev 0)
+++ trunk/usr.sbin/autofs/popen.c	2018-06-13 22:32:16 UTC (rev 10864)
@@ -0,0 +1,194 @@
+/* $MidnightBSD$ */
+/*
+ * Copyright (c) 1988, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This code is derived from software written by Ken Arnold and
+ * published in UNIX Review, Vol. 6, No. 8.
+ *
+ * Portions of this software were developed by Edward Tomasz Napierala
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * 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.
+ * 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/usr.sbin/autofs/popen.c 283231 2015-05-21 13:25:28Z trasz $");
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/wait.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <paths.h>
+
+#include "common.h"
+
+extern char **environ;
+
+struct pid {
+	SLIST_ENTRY(pid) next;
+	FILE *outfp;
+	pid_t pid;
+	char *command;
+};
+static SLIST_HEAD(, pid) pidlist = SLIST_HEAD_INITIALIZER(pidlist);
+
+#define	ARGV_LEN	42
+
+/*
+ * Replacement for popen(3), without stdin (which we do not use), but with
+ * stderr, proper logging, and improved command line arguments passing.
+ * Error handling is built in - if it returns, then it succeeded.
+ */
+FILE *
+auto_popen(const char *argv0, ...)
+{
+	va_list ap;
+	struct pid *cur, *p;
+	pid_t pid;
+	int error, i, nullfd, outfds[2];
+	char *arg, *argv[ARGV_LEN], *command;
+
+	nullfd = open(_PATH_DEVNULL, O_RDWR, 0);
+	if (nullfd < 0)
+		log_err(1, "cannot open %s", _PATH_DEVNULL);
+
+	error = pipe(outfds);
+	if (error != 0)
+		log_err(1, "pipe");
+
+	cur = malloc(sizeof(struct pid));
+	if (cur == NULL)
+		log_err(1, "malloc");
+
+	argv[0] = checked_strdup(argv0);
+	command = argv[0];
+
+	va_start(ap, argv0);
+	for (i = 1;; i++) {
+		if (i >= ARGV_LEN)
+			log_errx(1, "too many arguments to auto_popen");
+		arg = va_arg(ap, char *);
+		argv[i] = arg;
+		if (arg == NULL)
+			break;
+
+		command = concat(command, ' ', arg);
+	}
+	va_end(ap);
+
+	cur->command = checked_strdup(command);
+
+	switch (pid = fork()) {
+	case -1:			/* Error. */
+		log_err(1, "fork");
+		/* NOTREACHED */
+	case 0:				/* Child. */
+		dup2(nullfd, STDIN_FILENO);
+		dup2(outfds[1], STDOUT_FILENO);
+
+		close(nullfd);
+		close(outfds[0]);
+		close(outfds[1]);
+
+		SLIST_FOREACH(p, &pidlist, next)
+			close(fileno(p->outfp));
+		execvp(argv[0], argv);
+		log_err(1, "failed to execute %s", argv[0]);
+		/* NOTREACHED */
+	}
+
+	log_debugx("executing \"%s\" as pid %d", command, pid);
+
+	/* Parent; assume fdopen cannot fail. */
+	cur->outfp = fdopen(outfds[0], "r");
+	close(nullfd);
+	close(outfds[1]);
+
+	/* Link into list of file descriptors. */
+	cur->pid = pid;
+	SLIST_INSERT_HEAD(&pidlist, cur, next);
+
+	return (cur->outfp);
+}
+
+int
+auto_pclose(FILE *iop)
+{
+	struct pid *cur, *last = NULL;
+	int status;
+	pid_t pid;
+
+	/*
+	 * Find the appropriate file pointer and remove it from the list.
+	 */
+	SLIST_FOREACH(cur, &pidlist, next) {
+		if (cur->outfp == iop)
+			break;
+		last = cur;
+	}
+	if (cur == NULL) {
+		return (-1);
+	}
+	if (last == NULL)
+		SLIST_REMOVE_HEAD(&pidlist, next);
+	else
+		SLIST_REMOVE_AFTER(last, next);
+
+	fclose(cur->outfp);
+
+	do {
+		pid = wait4(cur->pid, &status, 0, NULL);
+	} while (pid == -1 && errno == EINTR);
+
+	if (WIFSIGNALED(status)) {
+		log_warnx("\"%s\", pid %d, terminated with signal %d",
+		    cur->command, pid, WTERMSIG(status));
+		return (status);
+	}
+
+	if (WEXITSTATUS(status) != 0) {
+		log_warnx("\"%s\", pid %d, terminated with exit status %d",
+		    cur->command, pid, WEXITSTATUS(status));
+		return (status);
+	}
+
+	log_debugx("\"%s\", pid %d, terminated gracefully", cur->command, pid);
+
+	free(cur->command);
+	free(cur);
+
+	return (pid == -1 ? -1 : status);
+}


Property changes on: trunk/usr.sbin/autofs/popen.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/autofs/token.l
===================================================================
--- trunk/usr.sbin/autofs/token.l	                        (rev 0)
+++ trunk/usr.sbin/autofs/token.l	2018-06-13 22:32:16 UTC (rev 10864)
@@ -0,0 +1,59 @@
+/* $MidnightBSD$ */
+%{
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD: stable/10/usr.sbin/autofs/token.l 274499 2014-11-14 10:53:55Z trasz $
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "common.h"
+
+int lineno;
+
+#define	YY_DECL int yylex(void)
+extern int	yylex(void);
+
+%}
+
+%option noinput
+%option nounput
+%option noyywrap
+
+%%
+\"[^"]+\"		{ yytext++; yytext[strlen(yytext) - 1] = '\0'; return STR; };
+[a-zA-Z0-9\.\+-_/\:\[\]$&%{}]+ { return STR; }
+#.*\n			{ lineno++; return NEWLINE; };
+\\\n			{ lineno++; };
+\n			{ lineno++; return NEWLINE; }
+[ \t]+			/* ignore whitespace */;
+.			{ return STR; }
+%%


Property changes on: trunk/usr.sbin/autofs/token.l
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property


More information about the Midnightbsd-cvs mailing list