xref: /dragonfly/sbin/devd/devd.cc (revision 6a8bb22d)
171fc104fSHasso Tepper /*-
216e73e71SEitan Adler  * Copyright (c) 2002-2010 M. Warner Losh.
371fc104fSHasso Tepper  * All rights reserved.
471fc104fSHasso Tepper  *
571fc104fSHasso Tepper  * Redistribution and use in source and binary forms, with or without
671fc104fSHasso Tepper  * modification, are permitted provided that the following conditions
771fc104fSHasso Tepper  * are met:
871fc104fSHasso Tepper  * 1. Redistributions of source code must retain the above copyright
971fc104fSHasso Tepper  *    notice, this list of conditions and the following disclaimer.
1071fc104fSHasso Tepper  * 2. Redistributions in binary form must reproduce the above copyright
1171fc104fSHasso Tepper  *    notice, this list of conditions and the following disclaimer in the
1271fc104fSHasso Tepper  *    documentation and/or other materials provided with the distribution.
1371fc104fSHasso Tepper  *
1471fc104fSHasso Tepper  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1571fc104fSHasso Tepper  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1671fc104fSHasso Tepper  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1771fc104fSHasso Tepper  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1871fc104fSHasso Tepper  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1971fc104fSHasso Tepper  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2071fc104fSHasso Tepper  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2171fc104fSHasso Tepper  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2271fc104fSHasso Tepper  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2371fc104fSHasso Tepper  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2471fc104fSHasso Tepper  * SUCH DAMAGE.
2571fc104fSHasso Tepper  *
26e348c2adSSascha Wildner  * my_system is a variation on lib/libc/stdlib/system.c:
27e348c2adSSascha Wildner  *
28e348c2adSSascha Wildner  * Copyright (c) 1988, 1993
29e348c2adSSascha Wildner  *	The Regents of the University of California.  All rights reserved.
30e348c2adSSascha Wildner  *
31e348c2adSSascha Wildner  * Redistribution and use in source and binary forms, with or without
32e348c2adSSascha Wildner  * modification, are permitted provided that the following conditions
33e348c2adSSascha Wildner  * are met:
34e348c2adSSascha Wildner  * 1. Redistributions of source code must retain the above copyright
35e348c2adSSascha Wildner  *    notice, this list of conditions and the following disclaimer.
36e348c2adSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
37e348c2adSSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
38e348c2adSSascha Wildner  *    documentation and/or other materials provided with the distribution.
39c66c7e2fSzrj  * 3. Neither the name of the University nor the names of its contributors
40e348c2adSSascha Wildner  *    may be used to endorse or promote products derived from this software
41e348c2adSSascha Wildner  *    without specific prior written permission.
42e348c2adSSascha Wildner  *
43e348c2adSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44e348c2adSSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45e348c2adSSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46e348c2adSSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47e348c2adSSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48e348c2adSSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49e348c2adSSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50e348c2adSSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51e348c2adSSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52e348c2adSSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53e348c2adSSascha Wildner  * SUCH DAMAGE.
54e348c2adSSascha Wildner  *
5575627d21SSascha Wildner  * $FreeBSD: head/sbin/devd/devd.cc 270004 2014-08-14 22:33:56Z asomers $
5671fc104fSHasso Tepper  */
5771fc104fSHasso Tepper 
5871fc104fSHasso Tepper /*
5971fc104fSHasso Tepper  * DEVD control daemon.
6071fc104fSHasso Tepper  */
6171fc104fSHasso Tepper 
6271fc104fSHasso Tepper // TODO list:
6371fc104fSHasso Tepper //	o devd.conf and devd man pages need a lot of help:
6471fc104fSHasso Tepper //	  - devd needs to document the unix domain socket
6571fc104fSHasso Tepper //	  - devd.conf needs more details on the supported statements.
6671fc104fSHasso Tepper 
6771fc104fSHasso Tepper #include <sys/param.h>
6871fc104fSHasso Tepper #include <sys/socket.h>
6971fc104fSHasso Tepper #include <sys/stat.h>
7071fc104fSHasso Tepper #include <sys/sysctl.h>
7171fc104fSHasso Tepper #include <sys/types.h>
72e348c2adSSascha Wildner #include <sys/wait.h>
7371fc104fSHasso Tepper #include <sys/un.h>
7471fc104fSHasso Tepper 
7568dbf06eSEitan Adler #include <cctype>
7668dbf06eSEitan Adler #include <cerrno>
7768dbf06eSEitan Adler #include <cstdlib>
7868dbf06eSEitan Adler #include <cstdio>
79e348c2adSSascha Wildner #include <csignal>
8068dbf06eSEitan Adler #include <cstring>
81e348c2adSSascha Wildner #include <cstdarg>
8268dbf06eSEitan Adler 
8371fc104fSHasso Tepper #include <dirent.h>
8471fc104fSHasso Tepper #include <err.h>
8571fc104fSHasso Tepper #include <fcntl.h>
8671fc104fSHasso Tepper #include <libutil.h>
87e348c2adSSascha Wildner #include <paths.h>
88e348c2adSSascha Wildner #include <poll.h>
8971fc104fSHasso Tepper #include <regex.h>
90e348c2adSSascha Wildner #include <syslog.h>
9171fc104fSHasso Tepper #include <unistd.h>
9271fc104fSHasso Tepper 
9371fc104fSHasso Tepper #include <algorithm>
9471fc104fSHasso Tepper #include <map>
9571fc104fSHasso Tepper #include <string>
9671fc104fSHasso Tepper #include <list>
9771fc104fSHasso Tepper #include <vector>
9871fc104fSHasso Tepper 
9971fc104fSHasso Tepper #include "devd.h"		/* C compatible definitions */
10071fc104fSHasso Tepper #include "devd.hh"		/* C++ class definitions */
10171fc104fSHasso Tepper 
10275627d21SSascha Wildner #define STREAMPIPE "/var/run/devd.pipe"
10375627d21SSascha Wildner #define SEQPACKETPIPE "/var/run/devd.seqpacket.pipe"
10471fc104fSHasso Tepper #define CF "/etc/devd.conf"
10571fc104fSHasso Tepper #define SYSCTL "hw.bus.devctl_disable"
10671fc104fSHasso Tepper 
107e348c2adSSascha Wildner /*
108e348c2adSSascha Wildner  * Since the client socket is nonblocking, we must increase its send buffer to
109e348c2adSSascha Wildner  * handle brief event storms.  On FreeBSD, AF_UNIX sockets don't have a receive
110e348c2adSSascha Wildner  * buffer, so the client can't increate the buffersize by itself.
111e348c2adSSascha Wildner  *
112e348c2adSSascha Wildner  * For example, when creating a ZFS pool, devd emits one 165 character
113e348c2adSSascha Wildner  * resource.fs.zfs.statechange message for each vdev in the pool.  A 64k
114e348c2adSSascha Wildner  * buffer has enough space for almost 400 drives, which would be very large but
115e348c2adSSascha Wildner  * not impossibly large pool.  A 128k buffer has enough space for 794 drives,
116e348c2adSSascha Wildner  * which is more than can fit in a rack with modern technology.
117e348c2adSSascha Wildner  */
118e348c2adSSascha Wildner #define CLIENT_BUFSIZE 131072
119e348c2adSSascha Wildner 
12071fc104fSHasso Tepper using namespace std;
12171fc104fSHasso Tepper 
12275627d21SSascha Wildner typedef struct client {
12375627d21SSascha Wildner 	int fd;
12475627d21SSascha Wildner 	int socktype;
12575627d21SSascha Wildner } client_t;
12675627d21SSascha Wildner 
12771fc104fSHasso Tepper extern FILE *yyin;
12871fc104fSHasso Tepper extern int lineno;
12971fc104fSHasso Tepper 
13071fc104fSHasso Tepper static const char notify = '!';
13171fc104fSHasso Tepper static const char nomatch = '?';
13271fc104fSHasso Tepper static const char attach = '+';
13371fc104fSHasso Tepper static const char detach = '-';
13471fc104fSHasso Tepper 
135d316f7c9SJohn Marino static struct pidfh *pfh;
136e348c2adSSascha Wildner 
137e348c2adSSascha Wildner static int no_daemon = 0;
138e348c2adSSascha Wildner static int daemonize_quick = 0;
139e348c2adSSascha Wildner static int quiet_mode = 0;
140e348c2adSSascha Wildner static unsigned total_events = 0;
141e348c2adSSascha Wildner static volatile sig_atomic_t got_siginfo = 0;
142c7383cd6SEitan Adler static volatile sig_atomic_t romeo_must_die = 0;
14371fc104fSHasso Tepper 
14471fc104fSHasso Tepper static const char *configfile = CF;
14571fc104fSHasso Tepper 
146e348c2adSSascha Wildner static void devdlog(int priority, const char* message, ...)
147e348c2adSSascha Wildner 	__printflike(2, 3);
14871fc104fSHasso Tepper static void event_loop(void);
14971fc104fSHasso Tepper static void usage(void);
15071fc104fSHasso Tepper 
15171fc104fSHasso Tepper template <class T> void
delete_and_clear(vector<T * > & v)15271fc104fSHasso Tepper delete_and_clear(vector<T *> &v)
15371fc104fSHasso Tepper {
15471fc104fSHasso Tepper 	typename vector<T *>::const_iterator i;
15571fc104fSHasso Tepper 
156e22fcc9eSEitan Adler 	for (i = v.begin(); i != v.end(); ++i)
15771fc104fSHasso Tepper 		delete *i;
15871fc104fSHasso Tepper 	v.clear();
15971fc104fSHasso Tepper }
16071fc104fSHasso Tepper 
16171fc104fSHasso Tepper config cfg;
16271fc104fSHasso Tepper 
event_proc()16371fc104fSHasso Tepper event_proc::event_proc() : _prio(-1)
16471fc104fSHasso Tepper {
165e348c2adSSascha Wildner 	_epsvec.reserve(4);
16671fc104fSHasso Tepper }
16771fc104fSHasso Tepper 
~event_proc()16871fc104fSHasso Tepper event_proc::~event_proc()
16971fc104fSHasso Tepper {
17071fc104fSHasso Tepper 	delete_and_clear(_epsvec);
17171fc104fSHasso Tepper }
17271fc104fSHasso Tepper 
17371fc104fSHasso Tepper void
add(eps * eps)17471fc104fSHasso Tepper event_proc::add(eps *eps)
17571fc104fSHasso Tepper {
17671fc104fSHasso Tepper 	_epsvec.push_back(eps);
17771fc104fSHasso Tepper }
17871fc104fSHasso Tepper 
17971fc104fSHasso Tepper bool
matches(config & c) const18016e73e71SEitan Adler event_proc::matches(config &c) const
18171fc104fSHasso Tepper {
18271fc104fSHasso Tepper 	vector<eps *>::const_iterator i;
18371fc104fSHasso Tepper 
184e22fcc9eSEitan Adler 	for (i = _epsvec.begin(); i != _epsvec.end(); ++i)
18571fc104fSHasso Tepper 		if (!(*i)->do_match(c))
18671fc104fSHasso Tepper 			return (false);
18771fc104fSHasso Tepper 	return (true);
18871fc104fSHasso Tepper }
18971fc104fSHasso Tepper 
19071fc104fSHasso Tepper bool
run(config & c) const19116e73e71SEitan Adler event_proc::run(config &c) const
19271fc104fSHasso Tepper {
19371fc104fSHasso Tepper 	vector<eps *>::const_iterator i;
19471fc104fSHasso Tepper 
195e22fcc9eSEitan Adler 	for (i = _epsvec.begin(); i != _epsvec.end(); ++i)
19671fc104fSHasso Tepper 		if (!(*i)->do_action(c))
19771fc104fSHasso Tepper 			return (false);
19871fc104fSHasso Tepper 	return (true);
19971fc104fSHasso Tepper }
20071fc104fSHasso Tepper 
action(const char * cmd)20171fc104fSHasso Tepper action::action(const char *cmd)
20271fc104fSHasso Tepper 	: _cmd(cmd)
20371fc104fSHasso Tepper {
20471fc104fSHasso Tepper 	// nothing
20571fc104fSHasso Tepper }
20671fc104fSHasso Tepper 
~action()20771fc104fSHasso Tepper action::~action()
20871fc104fSHasso Tepper {
20971fc104fSHasso Tepper 	// nothing
21071fc104fSHasso Tepper }
21171fc104fSHasso Tepper 
212e348c2adSSascha Wildner static int
my_system(const char * command)213e348c2adSSascha Wildner my_system(const char *command)
214e348c2adSSascha Wildner {
215e348c2adSSascha Wildner 	pid_t pid, savedpid;
216e348c2adSSascha Wildner 	int pstat;
217e348c2adSSascha Wildner 	struct sigaction ign, intact, quitact;
218e348c2adSSascha Wildner 	sigset_t newsigblock, oldsigblock;
219e348c2adSSascha Wildner 
220e348c2adSSascha Wildner 	if (!command)		/* just checking... */
221e348c2adSSascha Wildner 		return (1);
222e348c2adSSascha Wildner 
223e348c2adSSascha Wildner 	/*
224e348c2adSSascha Wildner 	 * Ignore SIGINT and SIGQUIT, block SIGCHLD. Remember to save
225e348c2adSSascha Wildner 	 * existing signal dispositions.
226e348c2adSSascha Wildner 	 */
227e348c2adSSascha Wildner 	ign.sa_handler = SIG_IGN;
228e348c2adSSascha Wildner 	::sigemptyset(&ign.sa_mask);
229e348c2adSSascha Wildner 	ign.sa_flags = 0;
230e348c2adSSascha Wildner 	::sigaction(SIGINT, &ign, &intact);
231e348c2adSSascha Wildner 	::sigaction(SIGQUIT, &ign, &quitact);
232e348c2adSSascha Wildner 	::sigemptyset(&newsigblock);
233e348c2adSSascha Wildner 	::sigaddset(&newsigblock, SIGCHLD);
234e348c2adSSascha Wildner 	::sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock);
235e348c2adSSascha Wildner 	switch (pid = ::fork()) {
236e348c2adSSascha Wildner 	case -1:			/* error */
237e348c2adSSascha Wildner 		break;
238e348c2adSSascha Wildner 	case 0:				/* child */
239e348c2adSSascha Wildner 		/*
240e348c2adSSascha Wildner 		 * Restore original signal dispositions and exec the command.
241e348c2adSSascha Wildner 		 */
242e348c2adSSascha Wildner 		::sigaction(SIGINT, &intact, NULL);
243e348c2adSSascha Wildner 		::sigaction(SIGQUIT,  &quitact, NULL);
244e348c2adSSascha Wildner 		::sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
245e348c2adSSascha Wildner 		/*
246e348c2adSSascha Wildner 		 * Close the PID file, and all other open descriptors.
247e348c2adSSascha Wildner 		 * Inherit std{in,out,err} only.
248e348c2adSSascha Wildner 		 */
249e348c2adSSascha Wildner 		cfg.close_pidfile();
250e348c2adSSascha Wildner 		::closefrom(3);
251e348c2adSSascha Wildner 		::execl(_PATH_BSHELL, "sh", "-c", command, (char *)NULL);
252e348c2adSSascha Wildner 		::_exit(127);
253e348c2adSSascha Wildner 	default:			/* parent */
254e348c2adSSascha Wildner 		savedpid = pid;
255e348c2adSSascha Wildner 		do {
256e348c2adSSascha Wildner 			pid = ::wait4(savedpid, &pstat, 0, (struct rusage *)0);
257e348c2adSSascha Wildner 		} while (pid == -1 && errno == EINTR);
258e348c2adSSascha Wildner 		break;
259e348c2adSSascha Wildner 	}
260e348c2adSSascha Wildner 	::sigaction(SIGINT, &intact, NULL);
261e348c2adSSascha Wildner 	::sigaction(SIGQUIT,  &quitact, NULL);
262e348c2adSSascha Wildner 	::sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
263e348c2adSSascha Wildner 	return (pid == -1 ? -1 : pstat);
264e348c2adSSascha Wildner }
265e348c2adSSascha Wildner 
26671fc104fSHasso Tepper bool
do_action(config & c)26771fc104fSHasso Tepper action::do_action(config &c)
26871fc104fSHasso Tepper {
269d316f7c9SJohn Marino 	string s = c.expand_string(_cmd.c_str());
270e348c2adSSascha Wildner 	devdlog(LOG_INFO, "Executing '%s'\n", s.c_str());
271e348c2adSSascha Wildner 	my_system(s.c_str());
27271fc104fSHasso Tepper 	return (true);
27371fc104fSHasso Tepper }
27471fc104fSHasso Tepper 
match(config & c,const char * var,const char * re)275d316f7c9SJohn Marino match::match(config &c, const char *var, const char *re) :
276d316f7c9SJohn Marino 	_inv(re[0] == '!'),
277d316f7c9SJohn Marino 	_var(var),
278d316f7c9SJohn Marino 	_re(c.expand_string(_inv ? re + 1 : re, "^", "$"))
27971fc104fSHasso Tepper {
28071fc104fSHasso Tepper 	regcomp(&_regex, _re.c_str(), REG_EXTENDED | REG_NOSUB | REG_ICASE);
28171fc104fSHasso Tepper }
28271fc104fSHasso Tepper 
~match()28371fc104fSHasso Tepper match::~match()
28471fc104fSHasso Tepper {
28571fc104fSHasso Tepper 	regfree(&_regex);
28671fc104fSHasso Tepper }
28771fc104fSHasso Tepper 
28871fc104fSHasso Tepper bool
do_match(config & c)28971fc104fSHasso Tepper match::do_match(config &c)
29071fc104fSHasso Tepper {
29116e73e71SEitan Adler 	const string &value = c.get_variable(_var);
29271fc104fSHasso Tepper 	bool retval;
29371fc104fSHasso Tepper 
294d316f7c9SJohn Marino 	/*
295d316f7c9SJohn Marino 	 * This function gets called WAY too often to justify calling syslog()
296d316f7c9SJohn Marino 	 * each time, even at LOG_DEBUG.  Because if syslogd isn't running, it
297d316f7c9SJohn Marino 	 * can consume excessive amounts of systime inside of connect().  Only
298d316f7c9SJohn Marino 	 * log when we're in -d mode.
299d316f7c9SJohn Marino 	 */
300e348c2adSSascha Wildner 	if (no_daemon) {
301e348c2adSSascha Wildner 		devdlog(LOG_DEBUG, "Testing %s=%s against %s, invert=%d\n",
302e348c2adSSascha Wildner 		    _var.c_str(), value.c_str(), _re.c_str(), _inv);
303e348c2adSSascha Wildner 	}
30471fc104fSHasso Tepper 
30571fc104fSHasso Tepper 	retval = (regexec(&_regex, value.c_str(), 0, NULL, 0) == 0);
306d316f7c9SJohn Marino 	if (_inv == 1)
307d316f7c9SJohn Marino 		retval = (retval == 0) ? 1 : 0;
308d316f7c9SJohn Marino 
309d316f7c9SJohn Marino 	return (retval);
31071fc104fSHasso Tepper }
31171fc104fSHasso Tepper 
31271fc104fSHasso Tepper #include <sys/sockio.h>
31371fc104fSHasso Tepper #include <net/if.h>
31471fc104fSHasso Tepper #include <net/if_media.h>
31571fc104fSHasso Tepper 
media(config &,const char * var,const char * type)31671fc104fSHasso Tepper media::media(config &, const char *var, const char *type)
31771fc104fSHasso Tepper 	: _var(var), _type(-1)
31871fc104fSHasso Tepper {
31971fc104fSHasso Tepper 	static struct ifmedia_description media_types[] = {
32071fc104fSHasso Tepper 		{ IFM_ETHER,		"Ethernet" },
32171fc104fSHasso Tepper 		{ IFM_IEEE80211,	"802.11" },
32271fc104fSHasso Tepper 		{ IFM_ATM,		"ATM" },
32371fc104fSHasso Tepper 		{ IFM_CARP,		"CARP" },
32471fc104fSHasso Tepper 		{ -1,			"unknown" },
32571fc104fSHasso Tepper 		{ 0, NULL },
32671fc104fSHasso Tepper 	};
32716e73e71SEitan Adler 	for (int i = 0; media_types[i].ifmt_string != NULL; ++i)
32871fc104fSHasso Tepper 		if (strcasecmp(type, media_types[i].ifmt_string) == 0) {
32971fc104fSHasso Tepper 			_type = media_types[i].ifmt_word;
33071fc104fSHasso Tepper 			break;
33171fc104fSHasso Tepper 		}
33271fc104fSHasso Tepper }
33371fc104fSHasso Tepper 
~media()33471fc104fSHasso Tepper media::~media()
33571fc104fSHasso Tepper {
33671fc104fSHasso Tepper }
33771fc104fSHasso Tepper 
33871fc104fSHasso Tepper bool
do_match(config & c)33971fc104fSHasso Tepper media::do_match(config &c)
34071fc104fSHasso Tepper {
34171fc104fSHasso Tepper 	string value;
34271fc104fSHasso Tepper 	struct ifmediareq ifmr;
34371fc104fSHasso Tepper 	bool retval;
34471fc104fSHasso Tepper 	int s;
34571fc104fSHasso Tepper 
34671fc104fSHasso Tepper 	// Since we can be called from both a device attach/detach
34771fc104fSHasso Tepper 	// context where device-name is defined and what we want,
34871fc104fSHasso Tepper 	// as well as from a link status context, where subsystem is
34971fc104fSHasso Tepper 	// the name of interest, first try device-name and fall back
35071fc104fSHasso Tepper 	// to subsystem if none exists.
35171fc104fSHasso Tepper 	value = c.get_variable("device-name");
3521a98d7d1SEitan Adler 	if (value.empty())
35371fc104fSHasso Tepper 		value = c.get_variable("subsystem");
354e348c2adSSascha Wildner 	devdlog(LOG_DEBUG, "Testing media type of %s against 0x%x\n",
35571fc104fSHasso Tepper 		    value.c_str(), _type);
35671fc104fSHasso Tepper 
35771fc104fSHasso Tepper 	retval = false;
35871fc104fSHasso Tepper 
35971fc104fSHasso Tepper 	s = socket(PF_INET, SOCK_DGRAM, 0);
36071fc104fSHasso Tepper 	if (s >= 0) {
36171fc104fSHasso Tepper 		memset(&ifmr, 0, sizeof(ifmr));
36271fc104fSHasso Tepper 		strncpy(ifmr.ifm_name, value.c_str(), sizeof(ifmr.ifm_name));
36371fc104fSHasso Tepper 
36471fc104fSHasso Tepper 		if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0 &&
36571fc104fSHasso Tepper 		    ifmr.ifm_status & IFM_AVALID) {
366e348c2adSSascha Wildner 			devdlog(LOG_DEBUG, "%s has media type 0x%x\n",
36771fc104fSHasso Tepper 				    value.c_str(), IFM_TYPE(ifmr.ifm_active));
36871fc104fSHasso Tepper 			retval = (IFM_TYPE(ifmr.ifm_active) == _type);
36971fc104fSHasso Tepper 		} else if (_type == -1) {
370e348c2adSSascha Wildner 			devdlog(LOG_DEBUG, "%s has unknown media type\n",
37171fc104fSHasso Tepper 				    value.c_str());
37271fc104fSHasso Tepper 			retval = true;
37371fc104fSHasso Tepper 		}
37471fc104fSHasso Tepper 		close(s);
37571fc104fSHasso Tepper 	}
37671fc104fSHasso Tepper 
377d316f7c9SJohn Marino 	return (retval);
37871fc104fSHasso Tepper }
37971fc104fSHasso Tepper 
38071fc104fSHasso Tepper const string var_list::bogus = "_$_$_$_$_B_O_G_U_S_$_$_$_$_";
38171fc104fSHasso Tepper const string var_list::nothing = "";
38271fc104fSHasso Tepper 
38371fc104fSHasso Tepper const string &
get_variable(const string & var) const38471fc104fSHasso Tepper var_list::get_variable(const string &var) const
38571fc104fSHasso Tepper {
38671fc104fSHasso Tepper 	map<string, string>::const_iterator i;
38771fc104fSHasso Tepper 
38871fc104fSHasso Tepper 	i = _vars.find(var);
38971fc104fSHasso Tepper 	if (i == _vars.end())
39071fc104fSHasso Tepper 		return (var_list::bogus);
39171fc104fSHasso Tepper 	return (i->second);
39271fc104fSHasso Tepper }
39371fc104fSHasso Tepper 
39471fc104fSHasso Tepper bool
is_set(const string & var) const39571fc104fSHasso Tepper var_list::is_set(const string &var) const
39671fc104fSHasso Tepper {
39771fc104fSHasso Tepper 	return (_vars.find(var) != _vars.end());
39871fc104fSHasso Tepper }
39971fc104fSHasso Tepper 
40071fc104fSHasso Tepper void
set_variable(const string & var,const string & val)40171fc104fSHasso Tepper var_list::set_variable(const string &var, const string &val)
40271fc104fSHasso Tepper {
403d316f7c9SJohn Marino 	/*
404d316f7c9SJohn Marino 	 * This function gets called WAY too often to justify calling syslog()
405d316f7c9SJohn Marino 	 * each time, even at LOG_DEBUG.  Because if syslogd isn't running, it
406d316f7c9SJohn Marino 	 * can consume excessive amounts of systime inside of connect().  Only
407d316f7c9SJohn Marino 	 * log when we're in -d mode.
408d316f7c9SJohn Marino 	 */
409e348c2adSSascha Wildner 	if (no_daemon)
410e348c2adSSascha Wildner 		devdlog(LOG_DEBUG, "setting %s=%s\n", var.c_str(), val.c_str());
41171fc104fSHasso Tepper 	_vars[var] = val;
41271fc104fSHasso Tepper }
41371fc104fSHasso Tepper 
41471fc104fSHasso Tepper void
reset(void)41571fc104fSHasso Tepper config::reset(void)
41671fc104fSHasso Tepper {
41771fc104fSHasso Tepper 	_dir_list.clear();
41871fc104fSHasso Tepper 	delete_and_clear(_var_list_table);
41971fc104fSHasso Tepper 	delete_and_clear(_attach_list);
42071fc104fSHasso Tepper 	delete_and_clear(_detach_list);
42171fc104fSHasso Tepper 	delete_and_clear(_nomatch_list);
42271fc104fSHasso Tepper 	delete_and_clear(_notify_list);
42371fc104fSHasso Tepper }
42471fc104fSHasso Tepper 
42571fc104fSHasso Tepper void
parse_one_file(const char * fn)42671fc104fSHasso Tepper config::parse_one_file(const char *fn)
42771fc104fSHasso Tepper {
428e348c2adSSascha Wildner 	devdlog(LOG_DEBUG, "Parsing %s\n", fn);
42971fc104fSHasso Tepper 	yyin = fopen(fn, "r");
43071fc104fSHasso Tepper 	if (yyin == NULL)
43171fc104fSHasso Tepper 		err(1, "Cannot open config file %s", fn);
43271fc104fSHasso Tepper 	lineno = 1;
43371fc104fSHasso Tepper 	if (yyparse() != 0)
43471fc104fSHasso Tepper 		errx(1, "Cannot parse %s at line %d", fn, lineno);
43571fc104fSHasso Tepper 	fclose(yyin);
43671fc104fSHasso Tepper }
43771fc104fSHasso Tepper 
43871fc104fSHasso Tepper void
parse_files_in_dir(const char * dirname)43971fc104fSHasso Tepper config::parse_files_in_dir(const char *dirname)
44071fc104fSHasso Tepper {
44171fc104fSHasso Tepper 	DIR *dirp;
44271fc104fSHasso Tepper 	struct dirent *dp;
44371fc104fSHasso Tepper 	char path[PATH_MAX];
44471fc104fSHasso Tepper 
445e348c2adSSascha Wildner 	devdlog(LOG_DEBUG, "Parsing files in %s\n", dirname);
44671fc104fSHasso Tepper 	dirp = opendir(dirname);
44771fc104fSHasso Tepper 	if (dirp == NULL)
44871fc104fSHasso Tepper 		return;
44971fc104fSHasso Tepper 	readdir(dirp);		/* Skip . */
45071fc104fSHasso Tepper 	readdir(dirp);		/* Skip .. */
45171fc104fSHasso Tepper 	while ((dp = readdir(dirp)) != NULL) {
45271fc104fSHasso Tepper 		if (strcmp(dp->d_name + dp->d_namlen - 5, ".conf") == 0) {
45371fc104fSHasso Tepper 			snprintf(path, sizeof(path), "%s/%s",
45471fc104fSHasso Tepper 			    dirname, dp->d_name);
45571fc104fSHasso Tepper 			parse_one_file(path);
45671fc104fSHasso Tepper 		}
45771fc104fSHasso Tepper 	}
458d316f7c9SJohn Marino 	closedir(dirp);
45971fc104fSHasso Tepper }
46071fc104fSHasso Tepper 
46171fc104fSHasso Tepper class epv_greater {
46271fc104fSHasso Tepper public:
operator ()(event_proc * const & l1,event_proc * const & l2) const46316e73e71SEitan Adler 	int operator()(event_proc *const&l1, event_proc *const&l2) const
46471fc104fSHasso Tepper 	{
46571fc104fSHasso Tepper 		return (l1->get_priority() > l2->get_priority());
46671fc104fSHasso Tepper 	}
46771fc104fSHasso Tepper };
46871fc104fSHasso Tepper 
46971fc104fSHasso Tepper void
sort_vector(vector<event_proc * > & v)47071fc104fSHasso Tepper config::sort_vector(vector<event_proc *> &v)
47171fc104fSHasso Tepper {
472e348c2adSSascha Wildner 	stable_sort(v.begin(), v.end(), epv_greater());
47371fc104fSHasso Tepper }
47471fc104fSHasso Tepper 
47571fc104fSHasso Tepper void
parse(void)47671fc104fSHasso Tepper config::parse(void)
47771fc104fSHasso Tepper {
47871fc104fSHasso Tepper 	vector<string>::const_iterator i;
47971fc104fSHasso Tepper 
48071fc104fSHasso Tepper 	parse_one_file(configfile);
481e22fcc9eSEitan Adler 	for (i = _dir_list.begin(); i != _dir_list.end(); ++i)
48271fc104fSHasso Tepper 		parse_files_in_dir((*i).c_str());
48371fc104fSHasso Tepper 	sort_vector(_attach_list);
48471fc104fSHasso Tepper 	sort_vector(_detach_list);
48571fc104fSHasso Tepper 	sort_vector(_nomatch_list);
48671fc104fSHasso Tepper 	sort_vector(_notify_list);
48771fc104fSHasso Tepper }
48871fc104fSHasso Tepper 
48971fc104fSHasso Tepper void
open_pidfile()49071fc104fSHasso Tepper config::open_pidfile()
49171fc104fSHasso Tepper {
492938e7d42Szrj 	pid_t otherpid = -1;
493d316f7c9SJohn Marino 
494d316f7c9SJohn Marino 	if (_pidfile.empty())
495d316f7c9SJohn Marino 		return;
496d316f7c9SJohn Marino 	pfh = pidfile_open(_pidfile.c_str(), 0600, &otherpid);
497d316f7c9SJohn Marino 	if (pfh == NULL) {
498d316f7c9SJohn Marino 		if (errno == EEXIST)
499d316f7c9SJohn Marino 			errx(1, "devd already running, pid: %d", (int)otherpid);
500d316f7c9SJohn Marino 		warn("cannot open pid file");
501d316f7c9SJohn Marino 	}
502d316f7c9SJohn Marino }
503d316f7c9SJohn Marino 
504d316f7c9SJohn Marino void
write_pidfile()505d316f7c9SJohn Marino config::write_pidfile()
506d316f7c9SJohn Marino {
507d316f7c9SJohn Marino 
508d316f7c9SJohn Marino 	pidfile_write(pfh);
509d316f7c9SJohn Marino }
510d316f7c9SJohn Marino 
511d316f7c9SJohn Marino void
close_pidfile()512d316f7c9SJohn Marino config::close_pidfile()
513d316f7c9SJohn Marino {
514d316f7c9SJohn Marino 
515d316f7c9SJohn Marino 	pidfile_close(pfh);
516d316f7c9SJohn Marino }
517d316f7c9SJohn Marino 
518d316f7c9SJohn Marino void
remove_pidfile()519d316f7c9SJohn Marino config::remove_pidfile()
520d316f7c9SJohn Marino {
521d316f7c9SJohn Marino 
522d316f7c9SJohn Marino 	pidfile_remove(pfh);
52371fc104fSHasso Tepper }
52471fc104fSHasso Tepper 
52571fc104fSHasso Tepper void
add_attach(int prio,event_proc * p)52671fc104fSHasso Tepper config::add_attach(int prio, event_proc *p)
52771fc104fSHasso Tepper {
52871fc104fSHasso Tepper 	p->set_priority(prio);
52971fc104fSHasso Tepper 	_attach_list.push_back(p);
53071fc104fSHasso Tepper }
53171fc104fSHasso Tepper 
53271fc104fSHasso Tepper void
add_detach(int prio,event_proc * p)53371fc104fSHasso Tepper config::add_detach(int prio, event_proc *p)
53471fc104fSHasso Tepper {
53571fc104fSHasso Tepper 	p->set_priority(prio);
53671fc104fSHasso Tepper 	_detach_list.push_back(p);
53771fc104fSHasso Tepper }
53871fc104fSHasso Tepper 
53971fc104fSHasso Tepper void
add_directory(const char * dir)54071fc104fSHasso Tepper config::add_directory(const char *dir)
54171fc104fSHasso Tepper {
54271fc104fSHasso Tepper 	_dir_list.push_back(string(dir));
54371fc104fSHasso Tepper }
54471fc104fSHasso Tepper 
54571fc104fSHasso Tepper void
add_nomatch(int prio,event_proc * p)54671fc104fSHasso Tepper config::add_nomatch(int prio, event_proc *p)
54771fc104fSHasso Tepper {
54871fc104fSHasso Tepper 	p->set_priority(prio);
54971fc104fSHasso Tepper 	_nomatch_list.push_back(p);
55071fc104fSHasso Tepper }
55171fc104fSHasso Tepper 
55271fc104fSHasso Tepper void
add_notify(int prio,event_proc * p)55371fc104fSHasso Tepper config::add_notify(int prio, event_proc *p)
55471fc104fSHasso Tepper {
55571fc104fSHasso Tepper 	p->set_priority(prio);
55671fc104fSHasso Tepper 	_notify_list.push_back(p);
55771fc104fSHasso Tepper }
55871fc104fSHasso Tepper 
55971fc104fSHasso Tepper void
set_pidfile(const char * fn)56071fc104fSHasso Tepper config::set_pidfile(const char *fn)
56171fc104fSHasso Tepper {
5622eadcd17SEitan Adler 	_pidfile = fn;
56371fc104fSHasso Tepper }
56471fc104fSHasso Tepper 
56571fc104fSHasso Tepper void
push_var_table()56671fc104fSHasso Tepper config::push_var_table()
56771fc104fSHasso Tepper {
56871fc104fSHasso Tepper 	var_list *vl;
56971fc104fSHasso Tepper 
57071fc104fSHasso Tepper 	vl = new var_list();
57171fc104fSHasso Tepper 	_var_list_table.push_back(vl);
572e348c2adSSascha Wildner 	devdlog(LOG_DEBUG, "Pushing table\n");
57371fc104fSHasso Tepper }
57471fc104fSHasso Tepper 
57571fc104fSHasso Tepper void
pop_var_table()57671fc104fSHasso Tepper config::pop_var_table()
57771fc104fSHasso Tepper {
57871fc104fSHasso Tepper 	delete _var_list_table.back();
57971fc104fSHasso Tepper 	_var_list_table.pop_back();
580e348c2adSSascha Wildner 	devdlog(LOG_DEBUG, "Popping table\n");
58171fc104fSHasso Tepper }
58271fc104fSHasso Tepper 
58371fc104fSHasso Tepper void
set_variable(const char * var,const char * val)58471fc104fSHasso Tepper config::set_variable(const char *var, const char *val)
58571fc104fSHasso Tepper {
58671fc104fSHasso Tepper 	_var_list_table.back()->set_variable(var, val);
58771fc104fSHasso Tepper }
58871fc104fSHasso Tepper 
58971fc104fSHasso Tepper const string &
get_variable(const string & var)59071fc104fSHasso Tepper config::get_variable(const string &var)
59171fc104fSHasso Tepper {
59271fc104fSHasso Tepper 	vector<var_list *>::reverse_iterator i;
59371fc104fSHasso Tepper 
594e22fcc9eSEitan Adler 	for (i = _var_list_table.rbegin(); i != _var_list_table.rend(); ++i) {
59571fc104fSHasso Tepper 		if ((*i)->is_set(var))
59671fc104fSHasso Tepper 			return ((*i)->get_variable(var));
59771fc104fSHasso Tepper 	}
59871fc104fSHasso Tepper 	return (var_list::nothing);
59971fc104fSHasso Tepper }
60071fc104fSHasso Tepper 
60171fc104fSHasso Tepper bool
is_id_char(char ch) const602c90fe191SEitan Adler config::is_id_char(char ch) const
60371fc104fSHasso Tepper {
60471fc104fSHasso Tepper 	return (ch != '\0' && (isalpha(ch) || isdigit(ch) || ch == '_' ||
60571fc104fSHasso Tepper 	    ch == '-'));
60671fc104fSHasso Tepper }
60771fc104fSHasso Tepper 
60871fc104fSHasso Tepper void
expand_one(const char * & src,string & dst)60971fc104fSHasso Tepper config::expand_one(const char *&src, string &dst)
61071fc104fSHasso Tepper {
61171fc104fSHasso Tepper 	int count;
612d316f7c9SJohn Marino 	string buffer;
61371fc104fSHasso Tepper 
61471fc104fSHasso Tepper 	src++;
61571fc104fSHasso Tepper 	// $$ -> $
61671fc104fSHasso Tepper 	if (*src == '$') {
617278a5d3aSEitan Adler 		dst += *src++;
61871fc104fSHasso Tepper 		return;
61971fc104fSHasso Tepper 	}
62071fc104fSHasso Tepper 
62171fc104fSHasso Tepper 	// $(foo) -> $(foo)
62271fc104fSHasso Tepper 	// Not sure if I want to support this or not, so for now we just pass
62371fc104fSHasso Tepper 	// it through.
62471fc104fSHasso Tepper 	if (*src == '(') {
625278a5d3aSEitan Adler 		dst += '$';
62671fc104fSHasso Tepper 		count = 1;
62771fc104fSHasso Tepper 		/* If the string ends before ) is matched , return. */
62871fc104fSHasso Tepper 		while (count > 0 && *src) {
62971fc104fSHasso Tepper 			if (*src == ')')
63071fc104fSHasso Tepper 				count--;
63171fc104fSHasso Tepper 			else if (*src == '(')
63271fc104fSHasso Tepper 				count++;
633278a5d3aSEitan Adler 			dst += *src++;
63471fc104fSHasso Tepper 		}
63571fc104fSHasso Tepper 		return;
63671fc104fSHasso Tepper 	}
63771fc104fSHasso Tepper 
638278a5d3aSEitan Adler 	// $[^A-Za-z] -> $\1
63971fc104fSHasso Tepper 	if (!isalpha(*src)) {
640278a5d3aSEitan Adler 		dst += '$';
641278a5d3aSEitan Adler 		dst += *src++;
64271fc104fSHasso Tepper 		return;
64371fc104fSHasso Tepper 	}
64471fc104fSHasso Tepper 
64571fc104fSHasso Tepper 	// $var -> replace with value
64671fc104fSHasso Tepper 	do {
647278a5d3aSEitan Adler 		buffer += *src++;
64871fc104fSHasso Tepper 	} while (is_id_char(*src));
649d316f7c9SJohn Marino 	dst.append(get_variable(buffer));
65071fc104fSHasso Tepper }
65171fc104fSHasso Tepper 
65271fc104fSHasso Tepper const string
expand_string(const char * src,const char * prepend,const char * append)653d316f7c9SJohn Marino config::expand_string(const char *src, const char *prepend, const char *append)
65471fc104fSHasso Tepper {
655d316f7c9SJohn Marino 	const char *var_at;
65671fc104fSHasso Tepper 	string dst;
65771fc104fSHasso Tepper 
658d316f7c9SJohn Marino 	/*
659d316f7c9SJohn Marino 	 * 128 bytes is enough for 2427 of 2438 expansions that happen
660d316f7c9SJohn Marino 	 * while parsing config files, as tested on 2013-01-30.
661d316f7c9SJohn Marino 	 */
662d316f7c9SJohn Marino 	dst.reserve(128);
663d316f7c9SJohn Marino 
664d316f7c9SJohn Marino 	if (prepend != NULL)
665d316f7c9SJohn Marino 		dst = prepend;
666d316f7c9SJohn Marino 
667d316f7c9SJohn Marino 	for (;;) {
668d316f7c9SJohn Marino 		var_at = strchr(src, '$');
669d316f7c9SJohn Marino 		if (var_at == NULL) {
670d316f7c9SJohn Marino 			dst.append(src);
671d316f7c9SJohn Marino 			break;
67271fc104fSHasso Tepper 		}
673d316f7c9SJohn Marino 		dst.append(src, var_at - src);
674d316f7c9SJohn Marino 		src = var_at;
675d316f7c9SJohn Marino 		expand_one(src, dst);
676d316f7c9SJohn Marino 	}
677d316f7c9SJohn Marino 
678d316f7c9SJohn Marino 	if (append != NULL)
679d316f7c9SJohn Marino 		dst.append(append);
68071fc104fSHasso Tepper 
68171fc104fSHasso Tepper 	return (dst);
68271fc104fSHasso Tepper }
68371fc104fSHasso Tepper 
68471fc104fSHasso Tepper bool
chop_var(char * & buffer,char * & lhs,char * & rhs) const685c90fe191SEitan Adler config::chop_var(char *&buffer, char *&lhs, char *&rhs) const
68671fc104fSHasso Tepper {
68771fc104fSHasso Tepper 	char *walker;
68871fc104fSHasso Tepper 
68971fc104fSHasso Tepper 	if (*buffer == '\0')
69071fc104fSHasso Tepper 		return (false);
69171fc104fSHasso Tepper 	walker = lhs = buffer;
69271fc104fSHasso Tepper 	while (is_id_char(*walker))
69371fc104fSHasso Tepper 		walker++;
69471fc104fSHasso Tepper 	if (*walker != '=')
69571fc104fSHasso Tepper 		return (false);
69671fc104fSHasso Tepper 	walker++;		// skip =
69771fc104fSHasso Tepper 	if (*walker == '"') {
69871fc104fSHasso Tepper 		walker++;	// skip "
69971fc104fSHasso Tepper 		rhs = walker;
70071fc104fSHasso Tepper 		while (*walker && *walker != '"')
70171fc104fSHasso Tepper 			walker++;
70271fc104fSHasso Tepper 		if (*walker != '"')
70371fc104fSHasso Tepper 			return (false);
70471fc104fSHasso Tepper 		rhs[-2] = '\0';
70571fc104fSHasso Tepper 		*walker++ = '\0';
70671fc104fSHasso Tepper 	} else {
70771fc104fSHasso Tepper 		rhs = walker;
70871fc104fSHasso Tepper 		while (*walker && !isspace(*walker))
70971fc104fSHasso Tepper 			walker++;
71071fc104fSHasso Tepper 		if (*walker != '\0')
71171fc104fSHasso Tepper 			*walker++ = '\0';
71271fc104fSHasso Tepper 		rhs[-1] = '\0';
71371fc104fSHasso Tepper 	}
71471fc104fSHasso Tepper 	while (isspace(*walker))
71571fc104fSHasso Tepper 		walker++;
71671fc104fSHasso Tepper 	buffer = walker;
71771fc104fSHasso Tepper 	return (true);
71871fc104fSHasso Tepper }
71971fc104fSHasso Tepper 
72071fc104fSHasso Tepper 
72171fc104fSHasso Tepper char *
set_vars(char * buffer)72271fc104fSHasso Tepper config::set_vars(char *buffer)
72371fc104fSHasso Tepper {
72471fc104fSHasso Tepper 	char *lhs;
72571fc104fSHasso Tepper 	char *rhs;
72671fc104fSHasso Tepper 
72771fc104fSHasso Tepper 	while (1) {
72871fc104fSHasso Tepper 		if (!chop_var(buffer, lhs, rhs))
72971fc104fSHasso Tepper 			break;
73071fc104fSHasso Tepper 		set_variable(lhs, rhs);
73171fc104fSHasso Tepper 	}
73271fc104fSHasso Tepper 	return (buffer);
73371fc104fSHasso Tepper }
73471fc104fSHasso Tepper 
73571fc104fSHasso Tepper void
find_and_execute(char type)73671fc104fSHasso Tepper config::find_and_execute(char type)
73771fc104fSHasso Tepper {
73871fc104fSHasso Tepper 	vector<event_proc *> *l;
73971fc104fSHasso Tepper 	vector<event_proc *>::const_iterator i;
74071fc104fSHasso Tepper 	const char *s;
74171fc104fSHasso Tepper 
74271fc104fSHasso Tepper 	switch (type) {
74371fc104fSHasso Tepper 	default:
74471fc104fSHasso Tepper 		return;
74571fc104fSHasso Tepper 	case notify:
74671fc104fSHasso Tepper 		l = &_notify_list;
74771fc104fSHasso Tepper 		s = "notify";
74871fc104fSHasso Tepper 		break;
74971fc104fSHasso Tepper 	case nomatch:
75071fc104fSHasso Tepper 		l = &_nomatch_list;
75171fc104fSHasso Tepper 		s = "nomatch";
75271fc104fSHasso Tepper 		break;
75371fc104fSHasso Tepper 	case attach:
75471fc104fSHasso Tepper 		l = &_attach_list;
75571fc104fSHasso Tepper 		s = "attach";
75671fc104fSHasso Tepper 		break;
75771fc104fSHasso Tepper 	case detach:
75871fc104fSHasso Tepper 		l = &_detach_list;
75971fc104fSHasso Tepper 		s = "detach";
76071fc104fSHasso Tepper 		break;
76171fc104fSHasso Tepper 	}
762e348c2adSSascha Wildner 	devdlog(LOG_DEBUG, "Processing %s event\n", s);
763e22fcc9eSEitan Adler 	for (i = l->begin(); i != l->end(); ++i) {
76471fc104fSHasso Tepper 		if ((*i)->matches(*this)) {
76571fc104fSHasso Tepper 			(*i)->run(*this);
76671fc104fSHasso Tepper 			break;
76771fc104fSHasso Tepper 		}
76871fc104fSHasso Tepper 	}
76971fc104fSHasso Tepper 
77071fc104fSHasso Tepper }
77171fc104fSHasso Tepper 
772d316f7c9SJohn Marino 
77371fc104fSHasso Tepper static void
process_event(char * buffer)77471fc104fSHasso Tepper process_event(char *buffer)
77571fc104fSHasso Tepper {
77671fc104fSHasso Tepper 	char type;
77771fc104fSHasso Tepper 	char *sp;
77871fc104fSHasso Tepper 
77971fc104fSHasso Tepper 	sp = buffer + 1;
780e348c2adSSascha Wildner 	devdlog(LOG_INFO, "Processing event '%s'\n", buffer);
78171fc104fSHasso Tepper 	type = *buffer++;
78271fc104fSHasso Tepper 	cfg.push_var_table();
78371fc104fSHasso Tepper 	// No match doesn't have a device, and the format is a little
78471fc104fSHasso Tepper 	// different, so handle it separately.
78571fc104fSHasso Tepper 	switch (type) {
78671fc104fSHasso Tepper 	case notify:
78771fc104fSHasso Tepper 		sp = cfg.set_vars(sp);
78871fc104fSHasso Tepper 		break;
78971fc104fSHasso Tepper 	case nomatch:
79071fc104fSHasso Tepper 		//? at location pnp-info on bus
79171fc104fSHasso Tepper 		sp = strchr(sp, ' ');
79271fc104fSHasso Tepper 		if (sp == NULL)
79371fc104fSHasso Tepper 			return;	/* Can't happen? */
79471fc104fSHasso Tepper 		*sp++ = '\0';
795d316f7c9SJohn Marino 		while (isspace(*sp))
796d316f7c9SJohn Marino 			sp++;
79771fc104fSHasso Tepper 		if (strncmp(sp, "at ", 3) == 0)
79871fc104fSHasso Tepper 			sp += 3;
79971fc104fSHasso Tepper 		sp = cfg.set_vars(sp);
800d316f7c9SJohn Marino 		while (isspace(*sp))
801d316f7c9SJohn Marino 			sp++;
80271fc104fSHasso Tepper 		if (strncmp(sp, "on ", 3) == 0)
80371fc104fSHasso Tepper 			cfg.set_variable("bus", sp + 3);
80471fc104fSHasso Tepper 		break;
80571fc104fSHasso Tepper 	case attach:	/*FALLTHROUGH*/
80671fc104fSHasso Tepper 	case detach:
80771fc104fSHasso Tepper 		sp = strchr(sp, ' ');
80871fc104fSHasso Tepper 		if (sp == NULL)
80971fc104fSHasso Tepper 			return;	/* Can't happen? */
81071fc104fSHasso Tepper 		*sp++ = '\0';
81171fc104fSHasso Tepper 		cfg.set_variable("device-name", buffer);
812d316f7c9SJohn Marino 		while (isspace(*sp))
813d316f7c9SJohn Marino 			sp++;
81471fc104fSHasso Tepper 		if (strncmp(sp, "at ", 3) == 0)
81571fc104fSHasso Tepper 			sp += 3;
81671fc104fSHasso Tepper 		sp = cfg.set_vars(sp);
817d316f7c9SJohn Marino 		while (isspace(*sp))
818d316f7c9SJohn Marino 			sp++;
81971fc104fSHasso Tepper 		if (strncmp(sp, "on ", 3) == 0)
82071fc104fSHasso Tepper 			cfg.set_variable("bus", sp + 3);
82171fc104fSHasso Tepper 		break;
82271fc104fSHasso Tepper 	}
82371fc104fSHasso Tepper 
82471fc104fSHasso Tepper 	cfg.find_and_execute(type);
82571fc104fSHasso Tepper 	cfg.pop_var_table();
82671fc104fSHasso Tepper }
82771fc104fSHasso Tepper 
82871fc104fSHasso Tepper int
create_socket(const char * name,int socktype)82975627d21SSascha Wildner create_socket(const char *name, int socktype)
83071fc104fSHasso Tepper {
83171fc104fSHasso Tepper 	int fd, slen;
83271fc104fSHasso Tepper 	struct sockaddr_un sun;
83371fc104fSHasso Tepper 
83475627d21SSascha Wildner 	if ((fd = socket(PF_LOCAL, socktype, 0)) < 0)
83571fc104fSHasso Tepper 		err(1, "socket");
83671fc104fSHasso Tepper 	bzero(&sun, sizeof(sun));
83771fc104fSHasso Tepper 	sun.sun_family = AF_UNIX;
83871fc104fSHasso Tepper 	strlcpy(sun.sun_path, name, sizeof(sun.sun_path));
83971fc104fSHasso Tepper 	slen = SUN_LEN(&sun);
84071fc104fSHasso Tepper 	unlink(name);
84171fc104fSHasso Tepper 	if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
84271fc104fSHasso Tepper 	    	err(1, "fcntl");
84316e73e71SEitan Adler 	if (::bind(fd, (struct sockaddr *) & sun, slen) < 0)
84471fc104fSHasso Tepper 		err(1, "bind");
84571fc104fSHasso Tepper 	listen(fd, 4);
84671fc104fSHasso Tepper 	chown(name, 0, 0);	/* XXX - root.wheel */
84771fc104fSHasso Tepper 	chmod(name, 0666);
84871fc104fSHasso Tepper 	return (fd);
84971fc104fSHasso Tepper }
85071fc104fSHasso Tepper 
851*6a8bb22dSSascha Wildner unsigned int max_clients = 10;	/* Default, can be overridden on cmdline. */
852e348c2adSSascha Wildner unsigned int num_clients;
85375627d21SSascha Wildner 
85475627d21SSascha Wildner list<client_t> clients;
85571fc104fSHasso Tepper 
85671fc104fSHasso Tepper void
notify_clients(const char * data,int len)85771fc104fSHasso Tepper notify_clients(const char *data, int len)
85871fc104fSHasso Tepper {
85975627d21SSascha Wildner 	list<client_t>::iterator i;
86071fc104fSHasso Tepper 
861e348c2adSSascha Wildner 	/*
862e348c2adSSascha Wildner 	 * Deliver the data to all clients.  Throw clients overboard at the
863e348c2adSSascha Wildner 	 * first sign of trouble.  This reaps clients who've died or closed
864e348c2adSSascha Wildner 	 * their sockets, and also clients who are alive but failing to keep up
865e348c2adSSascha Wildner 	 * (or who are maliciously not reading, to consume buffer space in
866e348c2adSSascha Wildner 	 * kernel memory or tie up the limited number of available connections).
867e348c2adSSascha Wildner 	 */
868e348c2adSSascha Wildner 	for (i = clients.begin(); i != clients.end(); ) {
86975627d21SSascha Wildner 		int flags;
87075627d21SSascha Wildner 		if (i->socktype == SOCK_SEQPACKET)
87175627d21SSascha Wildner 			flags = MSG_EOR;
87275627d21SSascha Wildner 		else
87375627d21SSascha Wildner 			flags = 0;
87475627d21SSascha Wildner 
87575627d21SSascha Wildner 		if (send(i->fd, data, len, flags) != len) {
876e348c2adSSascha Wildner 			--num_clients;
87775627d21SSascha Wildner 			close(i->fd);
878e348c2adSSascha Wildner 			i = clients.erase(i);
87975627d21SSascha Wildner 			devdlog(LOG_WARNING, "notify_clients: send() failed; "
880e348c2adSSascha Wildner 			    "dropping unresponsive client\n");
881e348c2adSSascha Wildner 		} else
882e348c2adSSascha Wildner 			++i;
88371fc104fSHasso Tepper 	}
88471fc104fSHasso Tepper }
88571fc104fSHasso Tepper 
886e348c2adSSascha Wildner void
check_clients(void)887e348c2adSSascha Wildner check_clients(void)
888e348c2adSSascha Wildner {
889e348c2adSSascha Wildner 	int s;
890e348c2adSSascha Wildner 	struct pollfd pfd;
89175627d21SSascha Wildner 	list<client_t>::iterator i;
892e348c2adSSascha Wildner 
893e348c2adSSascha Wildner 	/*
894e348c2adSSascha Wildner 	 * Check all existing clients to see if any of them have disappeared.
895e348c2adSSascha Wildner 	 * Normally we reap clients when we get an error trying to send them an
896e348c2adSSascha Wildner 	 * event.  This check eliminates the problem of an ever-growing list of
897e348c2adSSascha Wildner 	 * zombie clients because we're never writing to them on a system
898e348c2adSSascha Wildner 	 * without frequent device-change activity.
899e348c2adSSascha Wildner 	 */
900e348c2adSSascha Wildner 	pfd.events = 0;
901e348c2adSSascha Wildner 	for (i = clients.begin(); i != clients.end(); ) {
90275627d21SSascha Wildner 		pfd.fd = i->fd;
903e348c2adSSascha Wildner 		s = poll(&pfd, 1, 0);
904e348c2adSSascha Wildner 		if ((s < 0 && s != EINTR ) ||
905e348c2adSSascha Wildner 		    (s > 0 && (pfd.revents & POLLHUP))) {
906e348c2adSSascha Wildner 			--num_clients;
90775627d21SSascha Wildner 			close(i->fd);
908e348c2adSSascha Wildner 			i = clients.erase(i);
909e348c2adSSascha Wildner 			devdlog(LOG_NOTICE, "check_clients:  "
910e348c2adSSascha Wildner 			    "dropping disconnected client\n");
911e348c2adSSascha Wildner 		} else
912e348c2adSSascha Wildner 			++i;
913e348c2adSSascha Wildner 	}
91471fc104fSHasso Tepper }
91571fc104fSHasso Tepper 
91671fc104fSHasso Tepper void
new_client(int fd,int socktype)91775627d21SSascha Wildner new_client(int fd, int socktype)
91871fc104fSHasso Tepper {
91975627d21SSascha Wildner 	client_t s;
920e348c2adSSascha Wildner 	int sndbuf_size;
92171fc104fSHasso Tepper 
922e348c2adSSascha Wildner 	/*
923e348c2adSSascha Wildner 	 * First go reap any zombie clients, then accept the connection, and
924e348c2adSSascha Wildner 	 * shut down the read side to stop clients from consuming kernel memory
925e348c2adSSascha Wildner 	 * by sending large buffers full of data we'll never read.
926e348c2adSSascha Wildner 	 */
927e348c2adSSascha Wildner 	check_clients();
92875627d21SSascha Wildner 	s.socktype = socktype;
92975627d21SSascha Wildner 	s.fd = accept(fd, NULL, NULL);
93075627d21SSascha Wildner 	if (s.fd != -1) {
931e348c2adSSascha Wildner 		sndbuf_size = CLIENT_BUFSIZE;
93275627d21SSascha Wildner 		if (setsockopt(s.fd, SOL_SOCKET, SO_SNDBUF, &sndbuf_size,
933e348c2adSSascha Wildner 		    sizeof(sndbuf_size)))
934e348c2adSSascha Wildner 			err(1, "setsockopt");
93575627d21SSascha Wildner 		shutdown(s.fd, SHUT_RD);
93671fc104fSHasso Tepper 		clients.push_back(s);
937e348c2adSSascha Wildner 		++num_clients;
938e348c2adSSascha Wildner 	} else
939e348c2adSSascha Wildner 		err(1, "accept");
94071fc104fSHasso Tepper }
94171fc104fSHasso Tepper 
94271fc104fSHasso Tepper static void
event_loop(void)94371fc104fSHasso Tepper event_loop(void)
94471fc104fSHasso Tepper {
94571fc104fSHasso Tepper 	int rv;
94671fc104fSHasso Tepper 	int fd;
94771fc104fSHasso Tepper 	char buffer[DEVCTL_MAXBUF];
94871fc104fSHasso Tepper 	int once = 0;
94975627d21SSascha Wildner 	int stream_fd, seqpacket_fd, max_fd;
950e348c2adSSascha Wildner 	int accepting;
95171fc104fSHasso Tepper 	timeval tv;
95271fc104fSHasso Tepper 	fd_set fds;
95371fc104fSHasso Tepper 
954e348c2adSSascha Wildner 	fd = open(PATH_DEVCTL, O_RDONLY | O_CLOEXEC);
95571fc104fSHasso Tepper 	if (fd == -1)
95671fc104fSHasso Tepper 		err(1, "Can't open devctl device %s", PATH_DEVCTL);
95775627d21SSascha Wildner 	stream_fd = create_socket(STREAMPIPE, SOCK_STREAM);
95875627d21SSascha Wildner 	seqpacket_fd = create_socket(SEQPACKETPIPE, SOCK_SEQPACKET);
959e348c2adSSascha Wildner 	accepting = 1;
96075627d21SSascha Wildner 	max_fd = max(fd, max(stream_fd, seqpacket_fd)) + 1;
961dbd752b9SEitan Adler 	while (!romeo_must_die) {
962e348c2adSSascha Wildner 		if (!once && !no_daemon && !daemonize_quick) {
96371fc104fSHasso Tepper 			// Check to see if we have any events pending.
96471fc104fSHasso Tepper 			tv.tv_sec = 0;
96571fc104fSHasso Tepper 			tv.tv_usec = 0;
96671fc104fSHasso Tepper 			FD_ZERO(&fds);
96771fc104fSHasso Tepper 			FD_SET(fd, &fds);
96813d2556aSEitan Adler 			rv = select(fd + 1, &fds, NULL, NULL, &tv);
96971fc104fSHasso Tepper 			// No events -> we've processed all pending events
97071fc104fSHasso Tepper 			if (rv == 0) {
971e348c2adSSascha Wildner 				devdlog(LOG_DEBUG, "Calling daemon\n");
972d316f7c9SJohn Marino 				cfg.remove_pidfile();
97371fc104fSHasso Tepper 				cfg.open_pidfile();
974d316f7c9SJohn Marino 				daemon(0, 0);
975d316f7c9SJohn Marino 				cfg.write_pidfile();
97671fc104fSHasso Tepper 				once++;
97771fc104fSHasso Tepper 			}
97871fc104fSHasso Tepper 		}
979e348c2adSSascha Wildner 		/*
980e348c2adSSascha Wildner 		 * When we've already got the max number of clients, stop
98175627d21SSascha Wildner 		 * accepting new connections (don't put the listening sockets in
98275627d21SSascha Wildner 		 * the set), shrink the accept() queue to reject connections
98375627d21SSascha Wildner 		 * quickly, and poll the existing clients more often, so that we
98475627d21SSascha Wildner 		 * notice more quickly when any of them disappear to free up
98575627d21SSascha Wildner 		 * client slots.
986e348c2adSSascha Wildner 		 */
98771fc104fSHasso Tepper 		FD_ZERO(&fds);
98871fc104fSHasso Tepper 		FD_SET(fd, &fds);
989e348c2adSSascha Wildner 		if (num_clients < max_clients) {
990e348c2adSSascha Wildner 			if (!accepting) {
99175627d21SSascha Wildner 				listen(stream_fd, max_clients);
99275627d21SSascha Wildner 				listen(seqpacket_fd, max_clients);
993e348c2adSSascha Wildner 				accepting = 1;
994e348c2adSSascha Wildner 			}
99575627d21SSascha Wildner 			FD_SET(stream_fd, &fds);
99675627d21SSascha Wildner 			FD_SET(seqpacket_fd, &fds);
997e348c2adSSascha Wildner 			tv.tv_sec = 60;
998e348c2adSSascha Wildner 			tv.tv_usec = 0;
999e348c2adSSascha Wildner 		} else {
1000e348c2adSSascha Wildner 			if (accepting) {
100175627d21SSascha Wildner 				listen(stream_fd, 0);
100275627d21SSascha Wildner 				listen(seqpacket_fd, 0);
1003e348c2adSSascha Wildner 				accepting = 0;
1004e348c2adSSascha Wildner 			}
1005e348c2adSSascha Wildner 			tv.tv_sec = 2;
1006e348c2adSSascha Wildner 			tv.tv_usec = 0;
1007e348c2adSSascha Wildner 		}
1008e348c2adSSascha Wildner 		rv = select(max_fd, &fds, NULL, NULL, &tv);
1009e348c2adSSascha Wildner 		if (got_siginfo) {
1010e348c2adSSascha Wildner 			devdlog(LOG_NOTICE, "Events received so far=%u\n",
1011e348c2adSSascha Wildner 			    total_events);
1012e348c2adSSascha Wildner 			got_siginfo = 0;
1013e348c2adSSascha Wildner 		}
101471fc104fSHasso Tepper 		if (rv == -1) {
101571fc104fSHasso Tepper 			if (errno == EINTR)
101671fc104fSHasso Tepper 				continue;
101771fc104fSHasso Tepper 			err(1, "select");
1018e348c2adSSascha Wildner 		} else if (rv == 0)
1019e348c2adSSascha Wildner 			check_clients();
102071fc104fSHasso Tepper 		if (FD_ISSET(fd, &fds)) {
102171fc104fSHasso Tepper 			rv = read(fd, buffer, sizeof(buffer) - 1);
102271fc104fSHasso Tepper 			if (rv > 0) {
1023e348c2adSSascha Wildner 				total_events++;
1024e348c2adSSascha Wildner 				if (rv == sizeof(buffer) - 1) {
1025e348c2adSSascha Wildner 					devdlog(LOG_WARNING, "Warning: "
1026e348c2adSSascha Wildner 					    "available event data exceeded "
1027e348c2adSSascha Wildner 					    "buffer space\n");
1028e348c2adSSascha Wildner 				}
102971fc104fSHasso Tepper 				notify_clients(buffer, rv);
103071fc104fSHasso Tepper 				buffer[rv] = '\0';
103171fc104fSHasso Tepper 				while (buffer[--rv] == '\n')
103271fc104fSHasso Tepper 					buffer[rv] = '\0';
103371fc104fSHasso Tepper 				process_event(buffer);
103471fc104fSHasso Tepper 			} else if (rv < 0) {
103571fc104fSHasso Tepper 				if (errno != EINTR)
103671fc104fSHasso Tepper 					break;
103771fc104fSHasso Tepper 			} else {
103871fc104fSHasso Tepper 				/* EOF */
103971fc104fSHasso Tepper 				break;
104071fc104fSHasso Tepper 			}
104171fc104fSHasso Tepper 		}
104275627d21SSascha Wildner 		if (FD_ISSET(stream_fd, &fds))
104375627d21SSascha Wildner 			new_client(stream_fd, SOCK_STREAM);
104475627d21SSascha Wildner 		/*
104575627d21SSascha Wildner 		 * Aside from the socket type, both sockets use the same
104675627d21SSascha Wildner 		 * protocol, so we can process clients the same way.
104775627d21SSascha Wildner 		 */
104875627d21SSascha Wildner 		if (FD_ISSET(seqpacket_fd, &fds))
104975627d21SSascha Wildner 			new_client(seqpacket_fd, SOCK_SEQPACKET);
105071fc104fSHasso Tepper 	}
105171fc104fSHasso Tepper 	close(fd);
105271fc104fSHasso Tepper }
1053d316f7c9SJohn Marino 
105471fc104fSHasso Tepper /*
105571fc104fSHasso Tepper  * functions that the parser uses.
105671fc104fSHasso Tepper  */
105771fc104fSHasso Tepper void
add_attach(int prio,event_proc * p)105871fc104fSHasso Tepper add_attach(int prio, event_proc *p)
105971fc104fSHasso Tepper {
106071fc104fSHasso Tepper 	cfg.add_attach(prio, p);
106171fc104fSHasso Tepper }
106271fc104fSHasso Tepper 
106371fc104fSHasso Tepper void
add_detach(int prio,event_proc * p)106471fc104fSHasso Tepper add_detach(int prio, event_proc *p)
106571fc104fSHasso Tepper {
106671fc104fSHasso Tepper 	cfg.add_detach(prio, p);
106771fc104fSHasso Tepper }
106871fc104fSHasso Tepper 
106971fc104fSHasso Tepper void
add_directory(const char * dir)107071fc104fSHasso Tepper add_directory(const char *dir)
107171fc104fSHasso Tepper {
107271fc104fSHasso Tepper 	cfg.add_directory(dir);
107371fc104fSHasso Tepper 	free(const_cast<char *>(dir));
107471fc104fSHasso Tepper }
107571fc104fSHasso Tepper 
107671fc104fSHasso Tepper void
add_nomatch(int prio,event_proc * p)107771fc104fSHasso Tepper add_nomatch(int prio, event_proc *p)
107871fc104fSHasso Tepper {
107971fc104fSHasso Tepper 	cfg.add_nomatch(prio, p);
108071fc104fSHasso Tepper }
108171fc104fSHasso Tepper 
108271fc104fSHasso Tepper void
add_notify(int prio,event_proc * p)108371fc104fSHasso Tepper add_notify(int prio, event_proc *p)
108471fc104fSHasso Tepper {
108571fc104fSHasso Tepper 	cfg.add_notify(prio, p);
108671fc104fSHasso Tepper }
108771fc104fSHasso Tepper 
108871fc104fSHasso Tepper event_proc *
add_to_event_proc(event_proc * ep,eps * eps)108971fc104fSHasso Tepper add_to_event_proc(event_proc *ep, eps *eps)
109071fc104fSHasso Tepper {
109171fc104fSHasso Tepper 	if (ep == NULL)
109271fc104fSHasso Tepper 		ep = new event_proc();
109371fc104fSHasso Tepper 	ep->add(eps);
109471fc104fSHasso Tepper 	return (ep);
109571fc104fSHasso Tepper }
109671fc104fSHasso Tepper 
109771fc104fSHasso Tepper eps *
new_action(const char * cmd)109871fc104fSHasso Tepper new_action(const char *cmd)
109971fc104fSHasso Tepper {
110071fc104fSHasso Tepper 	eps *e = new action(cmd);
110171fc104fSHasso Tepper 	free(const_cast<char *>(cmd));
110271fc104fSHasso Tepper 	return (e);
110371fc104fSHasso Tepper }
110471fc104fSHasso Tepper 
110571fc104fSHasso Tepper eps *
new_match(const char * var,const char * re)110671fc104fSHasso Tepper new_match(const char *var, const char *re)
110771fc104fSHasso Tepper {
110871fc104fSHasso Tepper 	eps *e = new match(cfg, var, re);
110971fc104fSHasso Tepper 	free(const_cast<char *>(var));
111071fc104fSHasso Tepper 	free(const_cast<char *>(re));
111171fc104fSHasso Tepper 	return (e);
111271fc104fSHasso Tepper }
111371fc104fSHasso Tepper 
111471fc104fSHasso Tepper eps *
new_media(const char * var,const char * re)111571fc104fSHasso Tepper new_media(const char *var, const char *re)
111671fc104fSHasso Tepper {
111771fc104fSHasso Tepper 	eps *e = new media(cfg, var, re);
111871fc104fSHasso Tepper 	free(const_cast<char *>(var));
111971fc104fSHasso Tepper 	free(const_cast<char *>(re));
112071fc104fSHasso Tepper 	return (e);
112171fc104fSHasso Tepper }
112271fc104fSHasso Tepper 
112371fc104fSHasso Tepper void
set_pidfile(const char * name)112471fc104fSHasso Tepper set_pidfile(const char *name)
112571fc104fSHasso Tepper {
112671fc104fSHasso Tepper 	cfg.set_pidfile(name);
112771fc104fSHasso Tepper 	free(const_cast<char *>(name));
112871fc104fSHasso Tepper }
112971fc104fSHasso Tepper 
113071fc104fSHasso Tepper void
set_variable(const char * var,const char * val)113171fc104fSHasso Tepper set_variable(const char *var, const char *val)
113271fc104fSHasso Tepper {
113371fc104fSHasso Tepper 	cfg.set_variable(var, val);
113471fc104fSHasso Tepper 	free(const_cast<char *>(var));
113571fc104fSHasso Tepper 	free(const_cast<char *>(val));
113671fc104fSHasso Tepper }
113771fc104fSHasso Tepper 
1138d316f7c9SJohn Marino 
113971fc104fSHasso Tepper 
114071fc104fSHasso Tepper static void
gensighand(int)114171fc104fSHasso Tepper gensighand(int)
114271fc104fSHasso Tepper {
1143dbd752b9SEitan Adler 	romeo_must_die = 1;
1144e348c2adSSascha Wildner }
1145e348c2adSSascha Wildner 
1146e348c2adSSascha Wildner /*
1147e348c2adSSascha Wildner  * SIGINFO handler.  Will print useful statistics to the syslog or stderr
1148e348c2adSSascha Wildner  * as appropriate
1149e348c2adSSascha Wildner  */
1150e348c2adSSascha Wildner static void
siginfohand(int)1151e348c2adSSascha Wildner siginfohand(int)
1152e348c2adSSascha Wildner {
1153e348c2adSSascha Wildner 	got_siginfo = 1;
1154e348c2adSSascha Wildner }
1155e348c2adSSascha Wildner 
1156e348c2adSSascha Wildner /*
1157e348c2adSSascha Wildner  * Local logging function.  Prints to syslog if we're daemonized; stderr
1158e348c2adSSascha Wildner  * otherwise.
1159e348c2adSSascha Wildner  */
1160e348c2adSSascha Wildner static void
devdlog(int priority,const char * fmt,...)1161e348c2adSSascha Wildner devdlog(int priority, const char* fmt, ...)
1162e348c2adSSascha Wildner {
1163e348c2adSSascha Wildner 	va_list argp;
1164e348c2adSSascha Wildner 
1165e348c2adSSascha Wildner 	va_start(argp, fmt);
1166e348c2adSSascha Wildner 	if (no_daemon)
1167e348c2adSSascha Wildner 		vfprintf(stderr, fmt, argp);
1168e348c2adSSascha Wildner 	else if ((! quiet_mode) || (priority <= LOG_WARNING))
1169e348c2adSSascha Wildner 		vsyslog(priority, fmt, argp);
1170e348c2adSSascha Wildner 	va_end(argp);
117171fc104fSHasso Tepper }
117271fc104fSHasso Tepper 
117371fc104fSHasso Tepper static void
usage()117471fc104fSHasso Tepper usage()
117571fc104fSHasso Tepper {
1176e348c2adSSascha Wildner 	fprintf(stderr, "usage: %s [-dnq] [-l connlimit] [-f file]\n",
1177e348c2adSSascha Wildner 	    getprogname());
117871fc104fSHasso Tepper 	exit(1);
117971fc104fSHasso Tepper }
118071fc104fSHasso Tepper 
118171fc104fSHasso Tepper static void
check_devd_enabled()118271fc104fSHasso Tepper check_devd_enabled()
118371fc104fSHasso Tepper {
118471fc104fSHasso Tepper 	int val = 0;
118571fc104fSHasso Tepper 	size_t len;
118671fc104fSHasso Tepper 
118771fc104fSHasso Tepper 	len = sizeof(val);
118871fc104fSHasso Tepper 	if (sysctlbyname(SYSCTL, &val, &len, NULL, 0) != 0)
118971fc104fSHasso Tepper 		errx(1, "devctl sysctl missing from kernel!");
119071fc104fSHasso Tepper 	if (val) {
119171fc104fSHasso Tepper 		warnx("Setting " SYSCTL " to 0");
119271fc104fSHasso Tepper 		val = 0;
119371fc104fSHasso Tepper 		sysctlbyname(SYSCTL, NULL, NULL, &val, sizeof(val));
119471fc104fSHasso Tepper 	}
119571fc104fSHasso Tepper }
119671fc104fSHasso Tepper 
119771fc104fSHasso Tepper /*
119871fc104fSHasso Tepper  * main
119971fc104fSHasso Tepper  */
120071fc104fSHasso Tepper int
main(int argc,char ** argv)120171fc104fSHasso Tepper main(int argc, char **argv)
120271fc104fSHasso Tepper {
120371fc104fSHasso Tepper 	int ch;
120471fc104fSHasso Tepper 
120571fc104fSHasso Tepper 	check_devd_enabled();
1206e348c2adSSascha Wildner 	while ((ch = getopt(argc, argv, "df:l:nq")) != -1) {
120771fc104fSHasso Tepper 		switch (ch) {
120871fc104fSHasso Tepper 		case 'd':
1209e348c2adSSascha Wildner 			no_daemon = 1;
121071fc104fSHasso Tepper 			break;
121171fc104fSHasso Tepper 		case 'f':
121271fc104fSHasso Tepper 			configfile = optarg;
121371fc104fSHasso Tepper 			break;
1214e348c2adSSascha Wildner 		case 'l':
1215e348c2adSSascha Wildner 			max_clients = MAX(1, strtoul(optarg, NULL, 0));
1216e348c2adSSascha Wildner 			break;
121771fc104fSHasso Tepper 		case 'n':
1218e348c2adSSascha Wildner 			daemonize_quick = 1;
1219e348c2adSSascha Wildner 			break;
1220e348c2adSSascha Wildner 		case 'q':
1221e348c2adSSascha Wildner 			quiet_mode = 1;
122271fc104fSHasso Tepper 			break;
122371fc104fSHasso Tepper 		default:
122471fc104fSHasso Tepper 			usage();
122571fc104fSHasso Tepper 		}
122671fc104fSHasso Tepper 	}
122771fc104fSHasso Tepper 
122871fc104fSHasso Tepper 	cfg.parse();
1229e348c2adSSascha Wildner 	if (!no_daemon && daemonize_quick) {
123071fc104fSHasso Tepper 		cfg.open_pidfile();
1231d316f7c9SJohn Marino 		daemon(0, 0);
1232d316f7c9SJohn Marino 		cfg.write_pidfile();
123371fc104fSHasso Tepper 	}
123471fc104fSHasso Tepper 	signal(SIGPIPE, SIG_IGN);
123571fc104fSHasso Tepper 	signal(SIGHUP, gensighand);
123671fc104fSHasso Tepper 	signal(SIGINT, gensighand);
123771fc104fSHasso Tepper 	signal(SIGTERM, gensighand);
1238e348c2adSSascha Wildner 	signal(SIGINFO, siginfohand);
123971fc104fSHasso Tepper 	event_loop();
124071fc104fSHasso Tepper 	return (0);
124171fc104fSHasso Tepper }
1242