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