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