devd.cc revision 247762
1/*-
2 * Copyright (c) 2002-2010 M. Warner Losh.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * my_system is a variation on lib/libc/stdlib/system.c:
27 *
28 * Copyright (c) 1988, 1993
29 *	The Regents of the University of California.  All rights reserved.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 * 1. Redistributions of source code must retain the above copyright
35 *    notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 *    notice, this list of conditions and the following disclaimer in the
38 *    documentation and/or other materials provided with the distribution.
39 * 4. Neither the name of the University nor the names of its contributors
40 *    may be used to endorse or promote products derived from this software
41 *    without specific prior written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * SUCH DAMAGE.
54 */
55
56/*
57 * DEVD control daemon.
58 */
59
60// TODO list:
61//	o devd.conf and devd man pages need a lot of help:
62//	  - devd needs to document the unix domain socket
63//	  - devd.conf needs more details on the supported statements.
64
65#include <sys/cdefs.h>
66__FBSDID("$FreeBSD: head/sbin/devd/devd.cc 247762 2013-03-04 02:21:29Z eadler $");
67
68#include <sys/param.h>
69#include <sys/socket.h>
70#include <sys/stat.h>
71#include <sys/sysctl.h>
72#include <sys/types.h>
73#include <sys/wait.h>
74#include <sys/un.h>
75
76#include <ctype.h>
77#include <dirent.h>
78#include <errno.h>
79#include <err.h>
80#include <fcntl.h>
81#include <libutil.h>
82#include <paths.h>
83#include <poll.h>
84#include <regex.h>
85#include <signal.h>
86#include <stdlib.h>
87#include <stdio.h>
88#include <string.h>
89#include <unistd.h>
90
91#include <algorithm>
92#include <map>
93#include <string>
94#include <list>
95#include <vector>
96
97#include "devd.h"		/* C compatible definitions */
98#include "devd.hh"		/* C++ class definitions */
99
100#define PIPE "/var/run/devd.pipe"
101#define CF "/etc/devd.conf"
102#define SYSCTL "hw.bus.devctl_disable"
103
104using namespace std;
105
106extern FILE *yyin;
107extern int lineno;
108
109static const char notify = '!';
110static const char nomatch = '?';
111static const char attach = '+';
112static const char detach = '-';
113
114static struct pidfh *pfh;
115
116int Dflag;
117int dflag;
118int nflag;
119static volatile sig_atomic_t romeo_must_die = 0;
120
121static const char *configfile = CF;
122
123static void event_loop(void);
124static void usage(void);
125
126template <class T> void
127delete_and_clear(vector<T *> &v)
128{
129	typename vector<T *>::const_iterator i;
130
131	for (i = v.begin(); i != v.end(); ++i)
132		delete *i;
133	v.clear();
134}
135
136config cfg;
137
138event_proc::event_proc() : _prio(-1)
139{
140	_epsvec.reserve(4);
141}
142
143event_proc::~event_proc()
144{
145	delete_and_clear(_epsvec);
146}
147
148void
149event_proc::add(eps *eps)
150{
151	_epsvec.push_back(eps);
152}
153
154bool
155event_proc::matches(config &c) const
156{
157	vector<eps *>::const_iterator i;
158
159	for (i = _epsvec.begin(); i != _epsvec.end(); ++i)
160		if (!(*i)->do_match(c))
161			return (false);
162	return (true);
163}
164
165bool
166event_proc::run(config &c) const
167{
168	vector<eps *>::const_iterator i;
169
170	for (i = _epsvec.begin(); i != _epsvec.end(); ++i)
171		if (!(*i)->do_action(c))
172			return (false);
173	return (true);
174}
175
176action::action(const char *cmd)
177	: _cmd(cmd)
178{
179	// nothing
180}
181
182action::~action()
183{
184	// nothing
185}
186
187static int
188my_system(const char *command)
189{
190	pid_t pid, savedpid;
191	int pstat;
192	struct sigaction ign, intact, quitact;
193	sigset_t newsigblock, oldsigblock;
194
195	if (!command)		/* just checking... */
196		return(1);
197
198	/*
199	 * Ignore SIGINT and SIGQUIT, block SIGCHLD. Remember to save
200	 * existing signal dispositions.
201	 */
202	ign.sa_handler = SIG_IGN;
203	::sigemptyset(&ign.sa_mask);
204	ign.sa_flags = 0;
205	::sigaction(SIGINT, &ign, &intact);
206	::sigaction(SIGQUIT, &ign, &quitact);
207	::sigemptyset(&newsigblock);
208	::sigaddset(&newsigblock, SIGCHLD);
209	::sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock);
210	switch (pid = ::fork()) {
211	case -1:			/* error */
212		break;
213	case 0:				/* child */
214		/*
215		 * Restore original signal dispositions and exec the command.
216		 */
217		::sigaction(SIGINT, &intact, NULL);
218		::sigaction(SIGQUIT,  &quitact, NULL);
219		::sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
220		/*
221		 * Close the PID file, and all other open descriptors.
222		 * Inherit std{in,out,err} only.
223		 */
224		cfg.close_pidfile();
225		::closefrom(3);
226		::execl(_PATH_BSHELL, "sh", "-c", command, (char *)NULL);
227		::_exit(127);
228	default:			/* parent */
229		savedpid = pid;
230		do {
231			pid = ::wait4(savedpid, &pstat, 0, (struct rusage *)0);
232		} while (pid == -1 && errno == EINTR);
233		break;
234	}
235	::sigaction(SIGINT, &intact, NULL);
236	::sigaction(SIGQUIT,  &quitact, NULL);
237	::sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
238	return (pid == -1 ? -1 : pstat);
239}
240
241bool
242action::do_action(config &c)
243{
244	string s = c.expand_string(_cmd.c_str());
245	if (Dflag)
246		fprintf(stderr, "Executing '%s'\n", s.c_str());
247	my_system(s.c_str());
248	return (true);
249}
250
251match::match(config &c, const char *var, const char *re) :
252	_inv(re[0] == '!'),
253	_var(var),
254	_re(c.expand_string(_inv ? re + 1 : re, "^", "$"))
255{
256	regcomp(&_regex, _re.c_str(), REG_EXTENDED | REG_NOSUB | REG_ICASE);
257}
258
259match::~match()
260{
261	regfree(&_regex);
262}
263
264bool
265match::do_match(config &c)
266{
267	const string &value = c.get_variable(_var);
268	bool retval;
269
270	if (Dflag)
271		fprintf(stderr, "Testing %s=%s against %s, invert=%d\n",
272		    _var.c_str(), value.c_str(), _re.c_str(), _inv);
273
274	retval = (regexec(&_regex, value.c_str(), 0, NULL, 0) == 0);
275	if (_inv == 1)
276		retval = (retval == 0) ? 1 : 0;
277
278	return retval;
279}
280
281#include <sys/sockio.h>
282#include <net/if.h>
283#include <net/if_media.h>
284
285media::media(config &, const char *var, const char *type)
286	: _var(var), _type(-1)
287{
288	static struct ifmedia_description media_types[] = {
289		{ IFM_ETHER,		"Ethernet" },
290		{ IFM_TOKEN,		"Tokenring" },
291		{ IFM_FDDI,		"FDDI" },
292		{ IFM_IEEE80211,	"802.11" },
293		{ IFM_ATM,		"ATM" },
294		{ -1,			"unknown" },
295		{ 0, NULL },
296	};
297	for (int i = 0; media_types[i].ifmt_string != NULL; ++i)
298		if (strcasecmp(type, media_types[i].ifmt_string) == 0) {
299			_type = media_types[i].ifmt_word;
300			break;
301		}
302}
303
304media::~media()
305{
306}
307
308bool
309media::do_match(config &c)
310{
311	string value;
312	struct ifmediareq ifmr;
313	bool retval;
314	int s;
315
316	// Since we can be called from both a device attach/detach
317	// context where device-name is defined and what we want,
318	// as well as from a link status context, where subsystem is
319	// the name of interest, first try device-name and fall back
320	// to subsystem if none exists.
321	value = c.get_variable("device-name");
322	if (value.empty())
323		value = c.get_variable("subsystem");
324	if (Dflag)
325		fprintf(stderr, "Testing media type of %s against 0x%x\n",
326		    value.c_str(), _type);
327
328	retval = false;
329
330	s = socket(PF_INET, SOCK_DGRAM, 0);
331	if (s >= 0) {
332		memset(&ifmr, 0, sizeof(ifmr));
333		strncpy(ifmr.ifm_name, value.c_str(), sizeof(ifmr.ifm_name));
334
335		if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0 &&
336		    ifmr.ifm_status & IFM_AVALID) {
337			if (Dflag)
338				fprintf(stderr, "%s has media type 0x%x\n",
339				    value.c_str(), IFM_TYPE(ifmr.ifm_active));
340			retval = (IFM_TYPE(ifmr.ifm_active) == _type);
341		} else if (_type == -1) {
342			if (Dflag)
343				fprintf(stderr, "%s has unknown media type\n",
344				    value.c_str());
345			retval = true;
346		}
347		close(s);
348	}
349
350	return retval;
351}
352
353const string var_list::bogus = "_$_$_$_$_B_O_G_U_S_$_$_$_$_";
354const string var_list::nothing = "";
355
356const string &
357var_list::get_variable(const string &var) const
358{
359	map<string, string>::const_iterator i;
360
361	i = _vars.find(var);
362	if (i == _vars.end())
363		return (var_list::bogus);
364	return (i->second);
365}
366
367bool
368var_list::is_set(const string &var) const
369{
370	return (_vars.find(var) != _vars.end());
371}
372
373void
374var_list::set_variable(const string &var, const string &val)
375{
376	if (Dflag)
377		fprintf(stderr, "setting %s=%s\n", var.c_str(), val.c_str());
378	_vars[var] = val;
379}
380
381void
382config::reset(void)
383{
384	_dir_list.clear();
385	delete_and_clear(_var_list_table);
386	delete_and_clear(_attach_list);
387	delete_and_clear(_detach_list);
388	delete_and_clear(_nomatch_list);
389	delete_and_clear(_notify_list);
390}
391
392void
393config::parse_one_file(const char *fn)
394{
395	if (Dflag)
396		fprintf(stderr, "Parsing %s\n", fn);
397	yyin = fopen(fn, "r");
398	if (yyin == NULL)
399		err(1, "Cannot open config file %s", fn);
400	lineno = 1;
401	if (yyparse() != 0)
402		errx(1, "Cannot parse %s at line %d", fn, lineno);
403	fclose(yyin);
404}
405
406void
407config::parse_files_in_dir(const char *dirname)
408{
409	DIR *dirp;
410	struct dirent *dp;
411	char path[PATH_MAX];
412
413	if (Dflag)
414		fprintf(stderr, "Parsing files in %s\n", dirname);
415	dirp = opendir(dirname);
416	if (dirp == NULL)
417		return;
418	readdir(dirp);		/* Skip . */
419	readdir(dirp);		/* Skip .. */
420	while ((dp = readdir(dirp)) != NULL) {
421		if (strcmp(dp->d_name + dp->d_namlen - 5, ".conf") == 0) {
422			snprintf(path, sizeof(path), "%s/%s",
423			    dirname, dp->d_name);
424			parse_one_file(path);
425		}
426	}
427	closedir(dirp);
428}
429
430class epv_greater {
431public:
432	int operator()(event_proc *const&l1, event_proc *const&l2) const
433	{
434		return (l1->get_priority() > l2->get_priority());
435	}
436};
437
438void
439config::sort_vector(vector<event_proc *> &v)
440{
441	stable_sort(v.begin(), v.end(), epv_greater());
442}
443
444void
445config::parse(void)
446{
447	vector<string>::const_iterator i;
448
449	parse_one_file(configfile);
450	for (i = _dir_list.begin(); i != _dir_list.end(); ++i)
451		parse_files_in_dir((*i).c_str());
452	sort_vector(_attach_list);
453	sort_vector(_detach_list);
454	sort_vector(_nomatch_list);
455	sort_vector(_notify_list);
456}
457
458void
459config::open_pidfile()
460{
461	pid_t otherpid;
462
463	if (_pidfile.empty())
464		return;
465	pfh = pidfile_open(_pidfile.c_str(), 0600, &otherpid);
466	if (pfh == NULL) {
467		if (errno == EEXIST)
468			errx(1, "devd already running, pid: %d", (int)otherpid);
469		warn("cannot open pid file");
470	}
471}
472
473void
474config::write_pidfile()
475{
476
477	pidfile_write(pfh);
478}
479
480void
481config::close_pidfile()
482{
483
484	pidfile_close(pfh);
485}
486
487void
488config::remove_pidfile()
489{
490
491	pidfile_remove(pfh);
492}
493
494void
495config::add_attach(int prio, event_proc *p)
496{
497	p->set_priority(prio);
498	_attach_list.push_back(p);
499}
500
501void
502config::add_detach(int prio, event_proc *p)
503{
504	p->set_priority(prio);
505	_detach_list.push_back(p);
506}
507
508void
509config::add_directory(const char *dir)
510{
511	_dir_list.push_back(string(dir));
512}
513
514void
515config::add_nomatch(int prio, event_proc *p)
516{
517	p->set_priority(prio);
518	_nomatch_list.push_back(p);
519}
520
521void
522config::add_notify(int prio, event_proc *p)
523{
524	p->set_priority(prio);
525	_notify_list.push_back(p);
526}
527
528void
529config::set_pidfile(const char *fn)
530{
531	_pidfile = fn;
532}
533
534void
535config::push_var_table()
536{
537	var_list *vl;
538
539	vl = new var_list();
540	_var_list_table.push_back(vl);
541	if (Dflag)
542		fprintf(stderr, "Pushing table\n");
543}
544
545void
546config::pop_var_table()
547{
548	delete _var_list_table.back();
549	_var_list_table.pop_back();
550	if (Dflag)
551		fprintf(stderr, "Popping table\n");
552}
553
554void
555config::set_variable(const char *var, const char *val)
556{
557	_var_list_table.back()->set_variable(var, val);
558}
559
560const string &
561config::get_variable(const string &var)
562{
563	vector<var_list *>::reverse_iterator i;
564
565	for (i = _var_list_table.rbegin(); i != _var_list_table.rend(); ++i) {
566		if ((*i)->is_set(var))
567			return ((*i)->get_variable(var));
568	}
569	return (var_list::nothing);
570}
571
572bool
573config::is_id_char(char ch) const
574{
575	return (ch != '\0' && (isalpha(ch) || isdigit(ch) || ch == '_' ||
576	    ch == '-'));
577}
578
579void
580config::expand_one(const char *&src, string &dst)
581{
582	int count;
583	string buffer;
584
585	src++;
586	// $$ -> $
587	if (*src == '$') {
588		dst += *src++;
589		return;
590	}
591
592	// $(foo) -> $(foo)
593	// Not sure if I want to support this or not, so for now we just pass
594	// it through.
595	if (*src == '(') {
596		dst += '$';
597		count = 1;
598		/* If the string ends before ) is matched , return. */
599		while (count > 0 && *src) {
600			if (*src == ')')
601				count--;
602			else if (*src == '(')
603				count++;
604			dst += *src++;
605		}
606		return;
607	}
608
609	// ${^A-Za-z] -> $\1
610	if (!isalpha(*src)) {
611		dst += '$';
612		dst += *src++;
613		return;
614	}
615
616	// $var -> replace with value
617	do {
618		buffer += *src++;
619	} while (is_id_char(*src));
620	dst.append(get_variable(buffer));
621}
622
623const string
624config::expand_string(const char *src, const char *prepend, const char *append)
625{
626	const char *var_at;
627	string dst;
628
629	/*
630	 * 128 bytes is enough for 2427 of 2438 expansions that happen
631	 * while parsing config files, as tested on 2013-01-30.
632	 */
633	dst.reserve(128);
634
635	if (prepend != NULL)
636		dst = prepend;
637
638	for (;;) {
639		var_at = strchr(src, '$');
640		if (var_at == NULL) {
641			dst.append(src);
642			break;
643		}
644		dst.append(src, var_at - src);
645		src = var_at;
646		expand_one(src, dst);
647	}
648
649	if (append != NULL)
650		dst.append(append);
651
652	return (dst);
653}
654
655bool
656config::chop_var(char *&buffer, char *&lhs, char *&rhs) const
657{
658	char *walker;
659
660	if (*buffer == '\0')
661		return (false);
662	walker = lhs = buffer;
663	while (is_id_char(*walker))
664		walker++;
665	if (*walker != '=')
666		return (false);
667	walker++;		// skip =
668	if (*walker == '"') {
669		walker++;	// skip "
670		rhs = walker;
671		while (*walker && *walker != '"')
672			walker++;
673		if (*walker != '"')
674			return (false);
675		rhs[-2] = '\0';
676		*walker++ = '\0';
677	} else {
678		rhs = walker;
679		while (*walker && !isspace(*walker))
680			walker++;
681		if (*walker != '\0')
682			*walker++ = '\0';
683		rhs[-1] = '\0';
684	}
685	while (isspace(*walker))
686		walker++;
687	buffer = walker;
688	return (true);
689}
690
691
692char *
693config::set_vars(char *buffer)
694{
695	char *lhs;
696	char *rhs;
697
698	while (1) {
699		if (!chop_var(buffer, lhs, rhs))
700			break;
701		set_variable(lhs, rhs);
702	}
703	return (buffer);
704}
705
706void
707config::find_and_execute(char type)
708{
709	vector<event_proc *> *l;
710	vector<event_proc *>::const_iterator i;
711	const char *s;
712
713	switch (type) {
714	default:
715		return;
716	case notify:
717		l = &_notify_list;
718		s = "notify";
719		break;
720	case nomatch:
721		l = &_nomatch_list;
722		s = "nomatch";
723		break;
724	case attach:
725		l = &_attach_list;
726		s = "attach";
727		break;
728	case detach:
729		l = &_detach_list;
730		s = "detach";
731		break;
732	}
733	if (Dflag)
734		fprintf(stderr, "Processing %s event\n", s);
735	for (i = l->begin(); i != l->end(); ++i) {
736		if ((*i)->matches(*this)) {
737			(*i)->run(*this);
738			break;
739		}
740	}
741
742}
743
744
745static void
746process_event(char *buffer)
747{
748	char type;
749	char *sp;
750
751	sp = buffer + 1;
752	if (Dflag)
753		fprintf(stderr, "Processing event '%s'\n", buffer);
754	type = *buffer++;
755	cfg.push_var_table();
756	// No match doesn't have a device, and the format is a little
757	// different, so handle it separately.
758	switch (type) {
759	case notify:
760		sp = cfg.set_vars(sp);
761		break;
762	case nomatch:
763		//? at location pnp-info on bus
764		sp = strchr(sp, ' ');
765		if (sp == NULL)
766			return;	/* Can't happen? */
767		*sp++ = '\0';
768		while (isspace(*sp))
769			sp++;
770		if (strncmp(sp, "at ", 3) == 0)
771			sp += 3;
772		sp = cfg.set_vars(sp);
773		while (isspace(*sp))
774			sp++;
775		if (strncmp(sp, "on ", 3) == 0)
776			cfg.set_variable("bus", sp + 3);
777		break;
778	case attach:	/*FALLTHROUGH*/
779	case detach:
780		sp = strchr(sp, ' ');
781		if (sp == NULL)
782			return;	/* Can't happen? */
783		*sp++ = '\0';
784		cfg.set_variable("device-name", buffer);
785		while (isspace(*sp))
786			sp++;
787		if (strncmp(sp, "at ", 3) == 0)
788			sp += 3;
789		sp = cfg.set_vars(sp);
790		while (isspace(*sp))
791			sp++;
792		if (strncmp(sp, "on ", 3) == 0)
793			cfg.set_variable("bus", sp + 3);
794		break;
795	}
796
797	cfg.find_and_execute(type);
798	cfg.pop_var_table();
799}
800
801int
802create_socket(const char *name)
803{
804	int fd, slen;
805	struct sockaddr_un sun;
806
807	if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0)
808		err(1, "socket");
809	bzero(&sun, sizeof(sun));
810	sun.sun_family = AF_UNIX;
811	strlcpy(sun.sun_path, name, sizeof(sun.sun_path));
812	slen = SUN_LEN(&sun);
813	unlink(name);
814	if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
815	    	err(1, "fcntl");
816	if (::bind(fd, (struct sockaddr *) & sun, slen) < 0)
817		err(1, "bind");
818	listen(fd, 4);
819	chown(name, 0, 0);	/* XXX - root.wheel */
820	chmod(name, 0666);
821	return (fd);
822}
823
824unsigned int max_clients = 10;	/* Default, can be overriden on cmdline. */
825unsigned int num_clients;
826list<int> clients;
827
828void
829notify_clients(const char *data, int len)
830{
831	list<int>::iterator i;
832
833	/*
834	 * Deliver the data to all clients.  Throw clients overboard at the
835	 * first sign of trouble.  This reaps clients who've died or closed
836	 * their sockets, and also clients who are alive but failing to keep up
837	 * (or who are maliciously not reading, to consume buffer space in
838	 * kernel memory or tie up the limited number of available connections).
839	 */
840	for (i = clients.begin(); i != clients.end(); ) {
841		if (write(*i, data, len) != len) {
842			--num_clients;
843			close(*i);
844			i = clients.erase(i);
845		} else
846			++i;
847	}
848}
849
850void
851check_clients(void)
852{
853	int s;
854	struct pollfd pfd;
855	list<int>::iterator i;
856
857	/*
858	 * Check all existing clients to see if any of them have disappeared.
859	 * Normally we reap clients when we get an error trying to send them an
860	 * event.  This check eliminates the problem of an ever-growing list of
861	 * zombie clients because we're never writing to them on a system
862	 * without frequent device-change activity.
863	 */
864	pfd.events = 0;
865	for (i = clients.begin(); i != clients.end(); ) {
866		pfd.fd = *i;
867		s = poll(&pfd, 1, 0);
868		if ((s < 0 && s != EINTR ) ||
869		    (s > 0 && (pfd.revents & POLLHUP))) {
870			--num_clients;
871			close(*i);
872			i = clients.erase(i);
873		} else
874			++i;
875	}
876}
877
878void
879new_client(int fd)
880{
881	int s;
882
883	/*
884	 * First go reap any zombie clients, then accept the connection, and
885	 * shut down the read side to stop clients from consuming kernel memory
886	 * by sending large buffers full of data we'll never read.
887	 */
888	check_clients();
889	s = accept(fd, NULL, NULL);
890	if (s != -1) {
891		shutdown(s, SHUT_RD);
892		clients.push_back(s);
893		++num_clients;
894	}
895}
896
897static void
898event_loop(void)
899{
900	int rv;
901	int fd;
902	char buffer[DEVCTL_MAXBUF];
903	int once = 0;
904	int server_fd, max_fd;
905	int accepting;
906	timeval tv;
907	fd_set fds;
908
909	fd = open(PATH_DEVCTL, O_RDONLY | O_CLOEXEC);
910	if (fd == -1)
911		err(1, "Can't open devctl device %s", PATH_DEVCTL);
912	server_fd = create_socket(PIPE);
913	accepting = 1;
914	max_fd = max(fd, server_fd) + 1;
915	while (!romeo_must_die) {
916		if (!once && !dflag && !nflag) {
917			// Check to see if we have any events pending.
918			tv.tv_sec = 0;
919			tv.tv_usec = 0;
920			FD_ZERO(&fds);
921			FD_SET(fd, &fds);
922			rv = select(fd + 1, &fds, &fds, &fds, &tv);
923			// No events -> we've processed all pending events
924			if (rv == 0) {
925				if (Dflag)
926					fprintf(stderr, "Calling daemon\n");
927				cfg.remove_pidfile();
928				cfg.open_pidfile();
929				daemon(0, 0);
930				cfg.write_pidfile();
931				once++;
932			}
933		}
934		/*
935		 * When we've already got the max number of clients, stop
936		 * accepting new connections (don't put server_fd in the set),
937		 * shrink the accept() queue to reject connections quickly, and
938		 * poll the existing clients more often, so that we notice more
939		 * quickly when any of them disappear to free up client slots.
940		 */
941		FD_ZERO(&fds);
942		FD_SET(fd, &fds);
943		if (num_clients < max_clients) {
944			if (!accepting) {
945				listen(server_fd, max_clients);
946				accepting = 1;
947			}
948			FD_SET(server_fd, &fds);
949			tv.tv_sec = 60;
950			tv.tv_usec = 0;
951		} else {
952			if (accepting) {
953				listen(server_fd, 0);
954				accepting = 0;
955			}
956			tv.tv_sec = 2;
957			tv.tv_usec = 0;
958		}
959		rv = select(max_fd, &fds, NULL, NULL, &tv);
960		if (rv == -1) {
961			if (errno == EINTR)
962				continue;
963			err(1, "select");
964		} else if (rv == 0)
965			check_clients();
966		if (FD_ISSET(fd, &fds)) {
967			rv = read(fd, buffer, sizeof(buffer) - 1);
968			if (rv > 0) {
969				notify_clients(buffer, rv);
970				buffer[rv] = '\0';
971				while (buffer[--rv] == '\n')
972					buffer[rv] = '\0';
973				process_event(buffer);
974			} else if (rv < 0) {
975				if (errno != EINTR)
976					break;
977			} else {
978				/* EOF */
979				break;
980			}
981		}
982		if (FD_ISSET(server_fd, &fds))
983			new_client(server_fd);
984	}
985	close(fd);
986}
987
988/*
989 * functions that the parser uses.
990 */
991void
992add_attach(int prio, event_proc *p)
993{
994	cfg.add_attach(prio, p);
995}
996
997void
998add_detach(int prio, event_proc *p)
999{
1000	cfg.add_detach(prio, p);
1001}
1002
1003void
1004add_directory(const char *dir)
1005{
1006	cfg.add_directory(dir);
1007	free(const_cast<char *>(dir));
1008}
1009
1010void
1011add_nomatch(int prio, event_proc *p)
1012{
1013	cfg.add_nomatch(prio, p);
1014}
1015
1016void
1017add_notify(int prio, event_proc *p)
1018{
1019	cfg.add_notify(prio, p);
1020}
1021
1022event_proc *
1023add_to_event_proc(event_proc *ep, eps *eps)
1024{
1025	if (ep == NULL)
1026		ep = new event_proc();
1027	ep->add(eps);
1028	return (ep);
1029}
1030
1031eps *
1032new_action(const char *cmd)
1033{
1034	eps *e = new action(cmd);
1035	free(const_cast<char *>(cmd));
1036	return (e);
1037}
1038
1039eps *
1040new_match(const char *var, const char *re)
1041{
1042	eps *e = new match(cfg, var, re);
1043	free(const_cast<char *>(var));
1044	free(const_cast<char *>(re));
1045	return (e);
1046}
1047
1048eps *
1049new_media(const char *var, const char *re)
1050{
1051	eps *e = new media(cfg, var, re);
1052	free(const_cast<char *>(var));
1053	free(const_cast<char *>(re));
1054	return (e);
1055}
1056
1057void
1058set_pidfile(const char *name)
1059{
1060	cfg.set_pidfile(name);
1061	free(const_cast<char *>(name));
1062}
1063
1064void
1065set_variable(const char *var, const char *val)
1066{
1067	cfg.set_variable(var, val);
1068	free(const_cast<char *>(var));
1069	free(const_cast<char *>(val));
1070}
1071
1072
1073
1074static void
1075gensighand(int)
1076{
1077	romeo_must_die = 1;
1078}
1079
1080static void
1081usage()
1082{
1083	fprintf(stderr, "usage: %s [-Ddn] [-l connlimit] [-f file]\n",
1084	    getprogname());
1085	exit(1);
1086}
1087
1088static void
1089check_devd_enabled()
1090{
1091	int val = 0;
1092	size_t len;
1093
1094	len = sizeof(val);
1095	if (sysctlbyname(SYSCTL, &val, &len, NULL, 0) != 0)
1096		errx(1, "devctl sysctl missing from kernel!");
1097	if (val) {
1098		warnx("Setting " SYSCTL " to 0");
1099		val = 0;
1100		sysctlbyname(SYSCTL, NULL, NULL, &val, sizeof(val));
1101	}
1102}
1103
1104/*
1105 * main
1106 */
1107int
1108main(int argc, char **argv)
1109{
1110	int ch;
1111
1112	check_devd_enabled();
1113	while ((ch = getopt(argc, argv, "Ddf:l:n")) != -1) {
1114		switch (ch) {
1115		case 'D':
1116			Dflag++;
1117			break;
1118		case 'd':
1119			dflag++;
1120			break;
1121		case 'f':
1122			configfile = optarg;
1123			break;
1124		case 'l':
1125			max_clients = MAX(1, strtoul(optarg, NULL, 0));
1126			break;
1127		case 'n':
1128			nflag++;
1129			break;
1130		default:
1131			usage();
1132		}
1133	}
1134
1135	cfg.parse();
1136	if (!dflag && nflag) {
1137		cfg.open_pidfile();
1138		daemon(0, 0);
1139		cfg.write_pidfile();
1140	}
1141	signal(SIGPIPE, SIG_IGN);
1142	signal(SIGHUP, gensighand);
1143	signal(SIGINT, gensighand);
1144	signal(SIGTERM, gensighand);
1145	event_loop();
1146	return (0);
1147}
1148