devd.cc revision 131397
1107665Simp/*-
2113785Simp * Copyright (c) 2002-2003 M. Warner Losh.
3107665Simp * All rights reserved.
4107665Simp *
5107665Simp * Redistribution and use in source and binary forms, with or without
6107665Simp * modification, are permitted provided that the following conditions
7107665Simp * are met:
8107665Simp * 1. Redistributions of source code must retain the above copyright
9107665Simp *    notice, this list of conditions and the following disclaimer.
10107665Simp * 2. Redistributions in binary form must reproduce the above copyright
11107665Simp *    notice, this list of conditions and the following disclaimer in the
12107665Simp *    documentation and/or other materials provided with the distribution.
13107665Simp *
14107665Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15107665Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16107665Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17107665Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18107665Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19107665Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20107665Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21107665Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22107665Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23107665Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24107665Simp * SUCH DAMAGE.
25107665Simp */
26107665Simp
27107665Simp/*
28107665Simp * DEVD control daemon.
29107665Simp */
30107665Simp
31107665Simp// TODO list:
32107665Simp//	o devd.conf and devd man pages need a lot of help:
33131397Simp//	  - devd needs to document the unix domain socket
34107665Simp//	  - devd.conf needs more details on the supported statements.
35107665Simp
36107665Simp#include <sys/cdefs.h>
37107665Simp__FBSDID("$FreeBSD: head/sbin/devd/devd.cc 131397 2004-07-01 07:24:18Z imp $");
38107665Simp
39107665Simp#include <sys/param.h>
40131397Simp#include <sys/socket.h>
41131397Simp#include <sys/stat.h>
42131397Simp#include <sys/sysctl.h>
43107665Simp#include <sys/types.h>
44131397Simp#include <sys/un.h>
45107665Simp
46108014Simp#include <ctype.h>
47107665Simp#include <dirent.h>
48107665Simp#include <errno.h>
49107665Simp#include <err.h>
50107665Simp#include <fcntl.h>
51108014Simp#include <regex.h>
52107665Simp#include <stdlib.h>
53107665Simp#include <stdio.h>
54107665Simp#include <string.h>
55107665Simp#include <unistd.h>
56107665Simp
57108783Simp#include <algorithm>
58107665Simp#include <map>
59107665Simp#include <string>
60131397Simp#include <list>
61107665Simp#include <vector>
62107665Simp
63114086Simp#include "devd.h"		/* C compatible definitions */
64114086Simp#include "devd.hh"		/* C++ class definitions */
65107665Simp
66131397Simp#define PIPE "/var/run/devd.pipe"
67107665Simp#define CF "/etc/devd.conf"
68113787Simp#define SYSCTL "hw.bus.devctl_disable"
69107665Simp
70107665Simpusing namespace std;
71107665Simp
72107665Simpextern FILE *yyin;
73107665Simpextern int lineno;
74107665Simp
75121487Simpstatic const char notify = '!';
76108783Simpstatic const char nomatch = '?';
77108783Simpstatic const char attach = '+';
78108783Simpstatic const char detach = '-';
79108783Simp
80113790Simpint Dflag;
81107665Simpint dflag;
82114000Simpint nflag;
83107665Simpint romeo_must_die = 0;
84107665Simp
85107665Simpstatic void event_loop(void);
86107665Simpstatic void usage(void);
87107665Simp
88108783Simptemplate <class T> void
89108783Simpdelete_and_clear(vector<T *> &v)
90108783Simp{
91108783Simp	typename vector<T *>::const_iterator i;
92108783Simp
93108783Simp	for (i = v.begin(); i != v.end(); i++)
94108783Simp		delete *i;
95108783Simp	v.clear();
96108783Simp}
97108783Simp
98107665Simpconfig cfg;
99107665Simp
100107665Simpevent_proc::event_proc() : _prio(-1)
101107665Simp{
102107665Simp	// nothing
103107665Simp}
104107665Simp
105107665Simpevent_proc::~event_proc()
106107665Simp{
107107665Simp	vector<eps *>::const_iterator i;
108107665Simp
109107665Simp	for (i = _epsvec.begin(); i != _epsvec.end(); i++)
110107665Simp		delete *i;
111107665Simp	_epsvec.clear();
112107665Simp}
113107665Simp
114107665Simpvoid
115107665Simpevent_proc::add(eps *eps)
116107665Simp{
117107665Simp	_epsvec.push_back(eps);
118107665Simp}
119107665Simp
120107665Simpbool
121107665Simpevent_proc::matches(config &c)
122107665Simp{
123107665Simp	vector<eps *>::const_iterator i;
124107665Simp
125107665Simp	for (i = _epsvec.begin(); i != _epsvec.end(); i++)
126107665Simp		if (!(*i)->do_match(c))
127107665Simp			return (false);
128107665Simp	return (true);
129107665Simp}
130107665Simp
131107665Simpbool
132107665Simpevent_proc::run(config &c)
133107665Simp{
134107665Simp	vector<eps *>::const_iterator i;
135107665Simp
136107665Simp	for (i = _epsvec.begin(); i != _epsvec.end(); i++)
137107665Simp		if (!(*i)->do_action(c))
138107665Simp			return (false);
139107665Simp	return (true);
140107665Simp}
141107665Simp
142107665Simpaction::action(const char *cmd)
143107665Simp	: _cmd(cmd)
144107665Simp{
145107665Simp	// nothing
146107665Simp}
147107665Simp
148107665Simpaction::~action()
149107665Simp{
150107665Simp	// nothing
151107665Simp}
152107665Simp
153107665Simpbool
154108014Simpaction::do_action(config &c)
155107665Simp{
156108783Simp	string s = c.expand_string(_cmd);
157113790Simp	if (Dflag)
158108783Simp		fprintf(stderr, "Executing '%s'\n", s.c_str());
159108783Simp	::system(s.c_str());
160107665Simp	return (true);
161107665Simp}
162107665Simp
163108014Simpmatch::match(config &c, const char *var, const char *re)
164108783Simp	: _var(var)
165107665Simp{
166108783Simp	string pattern = re;
167108783Simp	_re = "^";
168108783Simp	_re.append(c.expand_string(string(re)));
169108783Simp	_re.append("$");
170108783Simp	regcomp(&_regex, _re.c_str(), REG_EXTENDED | REG_NOSUB);
171107665Simp}
172107665Simp
173107665Simpmatch::~match()
174107665Simp{
175108014Simp	regfree(&_regex);
176107665Simp}
177107665Simp
178107665Simpbool
179108014Simpmatch::do_match(config &c)
180107665Simp{
181108014Simp	string value = c.get_variable(_var);
182108014Simp	bool retval;
183108014Simp
184113790Simp	if (Dflag)
185108783Simp		fprintf(stderr, "Testing %s=%s against %s\n", _var.c_str(),
186108783Simp		    value.c_str(), _re.c_str());
187108783Simp
188108014Simp	retval = (regexec(&_regex, value.c_str(), 0, NULL, 0) == 0);
189108014Simp	return retval;
190107665Simp}
191107665Simp
192107665Simpconst string var_list::bogus = "_$_$_$_$_B_O_G_U_S_$_$_$_$_";
193107665Simpconst string var_list::nothing = "";
194107665Simp
195107665Simpconst string &
196107665Simpvar_list::get_variable(const string &var) const
197107665Simp{
198107665Simp	map<string, string>::const_iterator i;
199107665Simp
200107665Simp	i = _vars.find(var);
201107665Simp	if (i == _vars.end())
202108783Simp		return (var_list::bogus);
203107665Simp	return (i->second);
204107665Simp}
205107665Simp
206107665Simpbool
207107665Simpvar_list::is_set(const string &var) const
208107665Simp{
209107665Simp	return (_vars.find(var) != _vars.end());
210107665Simp}
211107665Simp
212107665Simpvoid
213107665Simpvar_list::set_variable(const string &var, const string &val)
214107665Simp{
215113790Simp	if (Dflag)
216108783Simp		fprintf(stderr, "%s=%s\n", var.c_str(), val.c_str());
217107665Simp	_vars[var] = val;
218107665Simp}
219107665Simp
220107665Simpvoid
221107665Simpconfig::reset(void)
222107665Simp{
223107665Simp	_dir_list.clear();
224108783Simp	delete_and_clear(_var_list_table);
225108783Simp	delete_and_clear(_attach_list);
226108783Simp	delete_and_clear(_detach_list);
227108783Simp	delete_and_clear(_nomatch_list);
228121487Simp	delete_and_clear(_notify_list);
229107665Simp}
230107665Simp
231107665Simpvoid
232107665Simpconfig::parse_one_file(const char *fn)
233107665Simp{
234113790Simp	if (Dflag)
235107665Simp		printf("Parsing %s\n", fn);
236107665Simp	yyin = fopen(fn, "r");
237107665Simp	if (yyin == NULL)
238107665Simp		err(1, "Cannot open config file %s", fn);
239107665Simp	if (yyparse() != 0)
240107665Simp		errx(1, "Cannot parse %s at line %d", fn, lineno);
241107665Simp	fclose(yyin);
242107665Simp}
243107665Simp
244107665Simpvoid
245107665Simpconfig::parse_files_in_dir(const char *dirname)
246107665Simp{
247107665Simp	DIR *dirp;
248107665Simp	struct dirent *dp;
249107665Simp	char path[PATH_MAX];
250107665Simp
251113790Simp	if (Dflag)
252107665Simp		printf("Parsing files in %s\n", dirname);
253107665Simp	dirp = opendir(dirname);
254107665Simp	if (dirp == NULL)
255107665Simp		return;
256107665Simp	readdir(dirp);		/* Skip . */
257107665Simp	readdir(dirp);		/* Skip .. */
258107665Simp	while ((dp = readdir(dirp)) != NULL) {
259107665Simp		if (strcmp(dp->d_name + dp->d_namlen - 5, ".conf") == 0) {
260107665Simp			snprintf(path, sizeof(path), "%s/%s",
261107665Simp			    dirname, dp->d_name);
262107665Simp			parse_one_file(path);
263107665Simp		}
264107665Simp	}
265107665Simp}
266107665Simp
267108783Simpclass epv_greater {
268108783Simppublic:
269108783Simp	int operator()(event_proc *const&l1, event_proc *const&l2)
270108783Simp	{
271108783Simp		return (l1->get_priority() > l2->get_priority());
272108783Simp	}
273108783Simp};
274108783Simp
275107665Simpvoid
276108783Simpconfig::sort_vector(vector<event_proc *> &v)
277108783Simp{
278108783Simp	sort(v.begin(), v.end(), epv_greater());
279108783Simp}
280108783Simp
281108783Simpvoid
282107665Simpconfig::parse(void)
283107665Simp{
284107665Simp	vector<string>::const_iterator i;
285107665Simp
286107665Simp	parse_one_file(CF);
287107665Simp	for (i = _dir_list.begin(); i != _dir_list.end(); i++)
288107665Simp		parse_files_in_dir((*i).c_str());
289108783Simp	sort_vector(_attach_list);
290108783Simp	sort_vector(_detach_list);
291108783Simp	sort_vector(_nomatch_list);
292121487Simp	sort_vector(_notify_list);
293107665Simp}
294107665Simp
295107665Simpvoid
296107665Simpconfig::drop_pidfile()
297107665Simp{
298107665Simp	FILE *fp;
299107665Simp
300107665Simp	if (_pidfile == "")
301107665Simp		return;
302107665Simp	fp = fopen(_pidfile.c_str(), "w");
303107665Simp	if (fp == NULL)
304107665Simp		return;
305107665Simp	fprintf(fp, "%d\n", getpid());
306107665Simp	fclose(fp);
307107665Simp}
308107665Simp
309107665Simpvoid
310107665Simpconfig::add_attach(int prio, event_proc *p)
311107665Simp{
312107665Simp	p->set_priority(prio);
313107665Simp	_attach_list.push_back(p);
314107665Simp}
315107665Simp
316107665Simpvoid
317107665Simpconfig::add_detach(int prio, event_proc *p)
318107665Simp{
319107665Simp	p->set_priority(prio);
320107665Simp	_detach_list.push_back(p);
321107665Simp}
322107665Simp
323107665Simpvoid
324107665Simpconfig::add_directory(const char *dir)
325107665Simp{
326107665Simp	_dir_list.push_back(string(dir));
327107665Simp}
328107665Simp
329107665Simpvoid
330107665Simpconfig::add_nomatch(int prio, event_proc *p)
331107665Simp{
332107665Simp	p->set_priority(prio);
333107665Simp	_nomatch_list.push_back(p);
334107665Simp}
335107665Simp
336107665Simpvoid
337121487Simpconfig::add_notify(int prio, event_proc *p)
338121487Simp{
339121487Simp	p->set_priority(prio);
340121487Simp	_notify_list.push_back(p);
341121487Simp}
342121487Simp
343121487Simpvoid
344107665Simpconfig::set_pidfile(const char *fn)
345107665Simp{
346107665Simp	_pidfile = string(fn);
347107665Simp}
348107665Simp
349107665Simpvoid
350107665Simpconfig::push_var_table()
351107665Simp{
352107665Simp	var_list *vl;
353107665Simp
354107665Simp	vl = new var_list();
355107665Simp	_var_list_table.push_back(vl);
356113790Simp	if (Dflag)
357108783Simp		fprintf(stderr, "Pushing table\n");
358107665Simp}
359107665Simp
360107665Simpvoid
361107665Simpconfig::pop_var_table()
362107665Simp{
363107665Simp	delete _var_list_table.back();
364107665Simp	_var_list_table.pop_back();
365113790Simp	if (Dflag)
366108783Simp		fprintf(stderr, "Popping table\n");
367107665Simp}
368107665Simp
369107665Simpvoid
370107665Simpconfig::set_variable(const char *var, const char *val)
371107665Simp{
372107665Simp	_var_list_table.back()->set_variable(var, val);
373107665Simp}
374107665Simp
375107665Simpconst string &
376107665Simpconfig::get_variable(const string &var)
377107665Simp{
378107665Simp	vector<var_list *>::reverse_iterator i;
379107665Simp
380107665Simp	for (i = _var_list_table.rbegin(); i != _var_list_table.rend(); i++) {
381107665Simp		if ((*i)->is_set(var))
382108783Simp			return ((*i)->get_variable(var));
383107665Simp	}
384107665Simp	return (var_list::nothing);
385107665Simp}
386107665Simp
387108783Simpbool
388108783Simpconfig::is_id_char(char ch)
389108783Simp{
390108783Simp	return (ch != '\0' && (isalpha(ch) || isdigit(ch) || ch == '_' ||
391108783Simp	    ch == '-'));
392108783Simp}
393108783Simp
394108014Simpvoid
395114081Simpconfig::expand_one(const char *&src, string &dst)
396107665Simp{
397108014Simp	int count;
398114081Simp	string buffer, varstr;
399108014Simp
400108783Simp	src++;
401108014Simp	// $$ -> $
402108014Simp	if (*src == '$') {
403114081Simp		dst.append(src++, 1);
404108014Simp		return;
405108014Simp	}
406108014Simp
407108014Simp	// $(foo) -> $(foo)
408108783Simp	// Not sure if I want to support this or not, so for now we just pass
409108783Simp	// it through.
410108014Simp	if (*src == '(') {
411114081Simp		dst.append("$");
412108014Simp		count = 1;
413114081Simp		/* If the string ends before ) is matched , return. */
414114081Simp		while (count > 0 && *src) {
415108014Simp			if (*src == ')')
416108014Simp				count--;
417108014Simp			else if (*src == '(')
418108014Simp				count++;
419114081Simp			dst.append(src++, 1);
420108014Simp		}
421108014Simp		return;
422108014Simp	}
423108014Simp
424108014Simp	// ${^A-Za-z] -> $\1
425108014Simp	if (!isalpha(*src)) {
426114081Simp		dst.append("$");
427114081Simp		dst.append(src++, 1);
428108014Simp		return;
429108014Simp	}
430108014Simp
431108014Simp	// $var -> replace with value
432114081Simp	do {
433114081Simp		buffer.append(src++, 1);
434114084Simp	} while (is_id_char(*src));
435114081Simp	buffer.append("", 1);
436114081Simp	varstr = get_variable(buffer.c_str());
437114081Simp	dst.append(varstr);
438107665Simp}
439107665Simp
440108014Simpconst string
441108014Simpconfig::expand_string(const string &s)
442108014Simp{
443108014Simp	const char *src;
444114081Simp	string dst;
445108014Simp
446108014Simp	src = s.c_str();
447108014Simp	while (*src) {
448108014Simp		if (*src == '$')
449114081Simp			expand_one(src, dst);
450108014Simp		else
451114081Simp			dst.append(src++, 1);
452108014Simp	}
453114081Simp	dst.append("", 1);
454108014Simp
455114081Simp	return (dst);
456108014Simp}
457108014Simp
458108783Simpbool
459108783Simpconfig::chop_var(char *&buffer, char *&lhs, char *&rhs)
460108783Simp{
461108783Simp	char *walker;
462108783Simp
463108783Simp	if (*buffer == '\0')
464108783Simp		return (false);
465108783Simp	walker = lhs = buffer;
466108783Simp	while (is_id_char(*walker))
467108783Simp		walker++;
468108783Simp	if (*walker != '=')
469108783Simp		return (false);
470108783Simp	walker++;		// skip =
471108783Simp	if (*walker == '"') {
472108783Simp		walker++;	// skip "
473108783Simp		rhs = walker;
474108783Simp		while (*walker && *walker != '"')
475108783Simp			walker++;
476108783Simp		if (*walker != '"')
477108783Simp			return (false);
478108783Simp		rhs[-2] = '\0';
479108783Simp		*walker++ = '\0';
480108783Simp	} else {
481108783Simp		rhs = walker;
482108783Simp		while (*walker && !isspace(*walker))
483108783Simp			walker++;
484108783Simp		if (*walker != '\0')
485108783Simp			*walker++ = '\0';
486108783Simp		rhs[-1] = '\0';
487108783Simp	}
488113785Simp	while (isspace(*walker))
489113785Simp		walker++;
490108783Simp	buffer = walker;
491108783Simp	return (true);
492108783Simp}
493108783Simp
494108783Simp
495108783Simpchar *
496108783Simpconfig::set_vars(char *buffer)
497108783Simp{
498108783Simp	char *lhs;
499108783Simp	char *rhs;
500108783Simp
501108783Simp	while (1) {
502108783Simp		if (!chop_var(buffer, lhs, rhs))
503108783Simp			break;
504108783Simp		set_variable(lhs, rhs);
505108783Simp	}
506108783Simp	return (buffer);
507108783Simp}
508108783Simp
509108783Simpvoid
510108783Simpconfig::find_and_execute(char type)
511108783Simp{
512108783Simp	vector<event_proc *> *l;
513108783Simp	vector<event_proc *>::const_iterator i;
514108783Simp	char *s;
515108783Simp
516108783Simp	switch (type) {
517108783Simp	default:
518108783Simp		return;
519121487Simp	case notify:
520121487Simp		l = &_notify_list;
521121487Simp		s = "notify";
522121487Simp		break;
523108783Simp	case nomatch:
524108783Simp		l = &_nomatch_list;
525108783Simp		s = "nomatch";
526108783Simp		break;
527108783Simp	case attach:
528108783Simp		l = &_attach_list;
529108783Simp		s = "attach";
530108783Simp		break;
531108783Simp	case detach:
532108783Simp		l = &_detach_list;
533108783Simp		s = "detach";
534108783Simp		break;
535108783Simp	}
536113790Simp	if (Dflag)
537108783Simp		fprintf(stderr, "Processing %s event\n", s);
538108783Simp	for (i = l->begin(); i != l->end(); i++) {
539108783Simp		if ((*i)->matches(*this)) {
540108783Simp			(*i)->run(*this);
541108783Simp			break;
542108783Simp		}
543108783Simp	}
544108783Simp
545108783Simp}
546108783Simp
547107665Simp
548107665Simpstatic void
549108783Simpprocess_event(char *buffer)
550107665Simp{
551107665Simp	char type;
552107665Simp	char *sp;
553107665Simp
554108783Simp	sp = buffer + 1;
555113790Simp	if (Dflag)
556108783Simp		fprintf(stderr, "Processing event '%s'\n", buffer);
557107665Simp	type = *buffer++;
558108783Simp	cfg.push_var_table();
559108783Simp	// No match doesn't have a device, and the format is a little
560108783Simp	// different, so handle it separately.
561121487Simp	switch (type) {
562121487Simp	case notify:
563121487Simp		sp = cfg.set_vars(sp);
564121487Simp		break;
565121487Simp	case nomatch:
566121487Simp		//?vars at location on bus
567121487Simp		sp = cfg.set_vars(sp);
568121487Simp		if (strncmp(sp, "at ", 3) == 0)
569121487Simp			sp += 3;
570121487Simp		sp = cfg.set_vars(sp);
571121487Simp		if (strncmp(sp, "on ", 3) == 0)
572121487Simp			cfg.set_variable("bus", sp + 3);
573121487Simp		break;
574121487Simp	case attach:	/*FALLTHROUGH*/
575121487Simp	case detach:
576108783Simp		sp = strchr(sp, ' ');
577108783Simp		if (sp == NULL)
578108783Simp			return;	/* Can't happen? */
579108783Simp		*sp++ = '\0';
580108783Simp		cfg.set_variable("device-name", buffer);
581113785Simp		if (strncmp(sp, "at ", 3) == 0)
582113785Simp			sp += 3;
583113785Simp		sp = cfg.set_vars(sp);
584113785Simp		if (strncmp(sp, "on ", 3) == 0)
585113785Simp			cfg.set_variable("bus", sp + 3);
586121487Simp		break;
587108783Simp	}
588113785Simp
589108783Simp	cfg.find_and_execute(type);
590108783Simp	cfg.pop_var_table();
591107665Simp}
592107665Simp
593131397Simpint
594131397Simpcreate_socket(const char *name)
595131397Simp{
596131397Simp	int fd, slen;
597131397Simp	struct sockaddr_un sun;
598131397Simp
599131397Simp	if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0)
600131397Simp		err(1, "socket");
601131397Simp	bzero(&sun, sizeof(sun));
602131397Simp	sun.sun_family = AF_UNIX;
603131397Simp	strlcpy(sun.sun_path, name, sizeof(sun.sun_path));
604131397Simp	slen = SUN_LEN(&sun);
605131397Simp	unlink(name);
606131397Simp	if (bind(fd, (struct sockaddr *) & sun, slen) < 0)
607131397Simp		err(1, "bind");
608131397Simp	listen(fd, 4);
609131397Simp	fchown(fd, 0, 0);	/* XXX - root.wheel */
610131397Simp	fchmod(fd, 0660);
611131397Simp	return (fd);
612131397Simp}
613131397Simp
614131397Simplist<int> clients;
615131397Simp
616131397Simpvoid
617131397Simpnotify_clients(const char *data, int len)
618131397Simp{
619131397Simp	list<int> bad;
620131397Simp	list<int>::const_iterator i;
621131397Simp
622131397Simp	for (i = clients.begin(); i != clients.end(); i++) {
623131397Simp		if (write(*i, data, len) <= 0) {
624131397Simp			bad.push_back(*i);
625131397Simp			close(*i);
626131397Simp		}
627131397Simp	}
628131397Simp
629131397Simp	for (i = bad.begin(); i != bad.end(); i++)
630131397Simp		clients.erase(find(clients.begin(), clients.end(), *i));
631131397Simp}
632131397Simp
633131397Simpvoid
634131397Simpnew_client(int fd)
635131397Simp{
636131397Simp	int s;
637131397Simp
638131397Simp	s = accept(fd, NULL, NULL);
639131397Simp	if (s != -1)
640131397Simp		clients.push_back(s);
641131397Simp}
642131397Simp
643107665Simpstatic void
644107665Simpevent_loop(void)
645107665Simp{
646107665Simp	int rv;
647107665Simp	int fd;
648107665Simp	char buffer[DEVCTL_MAXBUF];
649113790Simp	int once = 0;
650131397Simp	int server_fd, max_fd;
651113790Simp	timeval tv;
652113790Simp	fd_set fds;
653107665Simp
654107665Simp	fd = open(PATH_DEVCTL, O_RDONLY);
655107665Simp	if (fd == -1)
656131397Simp		err(1, "Can't open devctl device %s", PATH_DEVCTL);
657107665Simp	if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0)
658131397Simp		err(1, "Can't set close-on-exec flag on devctl");
659131397Simp	server_fd = create_socket(PIPE);
660131397Simp	max_fd = max(fd, server_fd) + 1;
661107665Simp	while (1) {
662107665Simp		if (romeo_must_die)
663107665Simp			break;
664113790Simp		if (!once && !dflag && !nflag) {
665113790Simp			// Check to see if we have any events pending.
666113790Simp			tv.tv_sec = 0;
667113790Simp			tv.tv_usec = 0;
668113790Simp			FD_ZERO(&fds);
669113790Simp			FD_SET(fd, &fds);
670113790Simp			rv = select(fd + 1, &fds, &fds, &fds, &tv);
671113790Simp			// No events -> we've processed all pending events
672117944Simp			if (rv == 0) {
673113790Simp				if (Dflag)
674113790Simp					fprintf(stderr, "Calling daemon\n");
675113790Simp				daemon(0, 0);
676117246Simp				cfg.drop_pidfile();
677113790Simp				once++;
678113790Simp			}
679113790Simp		}
680131397Simp		FD_ZERO(&fds);
681131397Simp		FD_SET(fd, &fds);
682131397Simp		FD_SET(server_fd, &fds);
683131397Simp		rv = select(max_fd, &fds, NULL, NULL, NULL);
684131397Simp		if (rv == -1) {
685131397Simp			if (errno == EINTR)
686131397Simp				continue;
687131397Simp			err(1, "select");
688131397Simp		}
689131397Simp		if (FD_ISSET(fd, &fds)) {
690131397Simp			rv = read(fd, buffer, sizeof(buffer) - 1);
691131397Simp			if (rv > 0) {
692131397Simp				notify_clients(buffer, rv);
693107665Simp				buffer[rv] = '\0';
694131397Simp				while (buffer[--rv] == '\n')
695131397Simp					buffer[rv] = '\0';
696131397Simp				process_event(buffer);
697131397Simp			} else if (rv < 0) {
698131397Simp				if (errno != EINTR)
699131397Simp					break;
700131397Simp			} else {
701131397Simp				/* EOF */
702107665Simp				break;
703131397Simp			}
704107665Simp		}
705131397Simp		if (FD_ISSET(server_fd, &fds))
706131397Simp			new_client(server_fd);
707107665Simp	}
708107665Simp	close(fd);
709107665Simp}
710107665Simp
711107665Simp/*
712107665Simp * functions that the parser uses.
713107665Simp */
714107665Simpvoid
715107665Simpadd_attach(int prio, event_proc *p)
716107665Simp{
717107665Simp	cfg.add_attach(prio, p);
718107665Simp}
719107665Simp
720107665Simpvoid
721107665Simpadd_detach(int prio, event_proc *p)
722107665Simp{
723107665Simp	cfg.add_detach(prio, p);
724107665Simp}
725107665Simp
726107665Simpvoid
727107665Simpadd_directory(const char *dir)
728107665Simp{
729107665Simp	cfg.add_directory(dir);
730107665Simp	free(const_cast<char *>(dir));
731107665Simp}
732107665Simp
733107665Simpvoid
734107665Simpadd_nomatch(int prio, event_proc *p)
735107665Simp{
736107665Simp	cfg.add_nomatch(prio, p);
737107665Simp}
738107665Simp
739121487Simpvoid
740121487Simpadd_notify(int prio, event_proc *p)
741121487Simp{
742121487Simp	cfg.add_notify(prio, p);
743121487Simp}
744121487Simp
745107665Simpevent_proc *
746107665Simpadd_to_event_proc(event_proc *ep, eps *eps)
747107665Simp{
748107665Simp	if (ep == NULL)
749107665Simp		ep = new event_proc();
750107665Simp	ep->add(eps);
751107665Simp	return (ep);
752107665Simp}
753107665Simp
754107665Simpeps *
755107665Simpnew_action(const char *cmd)
756107665Simp{
757107665Simp	eps *e = new action(cmd);
758107665Simp	free(const_cast<char *>(cmd));
759107665Simp	return (e);
760107665Simp}
761107665Simp
762107665Simpeps *
763107665Simpnew_match(const char *var, const char *re)
764107665Simp{
765108014Simp	eps *e = new match(cfg, var, re);
766107665Simp	free(const_cast<char *>(var));
767107665Simp	free(const_cast<char *>(re));
768107665Simp	return (e);
769107665Simp}
770107665Simp
771107665Simpvoid
772107665Simpset_pidfile(const char *name)
773107665Simp{
774107665Simp	cfg.set_pidfile(name);
775107665Simp	free(const_cast<char *>(name));
776107665Simp}
777107665Simp
778107665Simpvoid
779107665Simpset_variable(const char *var, const char *val)
780107665Simp{
781107665Simp	cfg.set_variable(var, val);
782107665Simp	free(const_cast<char *>(var));
783107665Simp	free(const_cast<char *>(val));
784107665Simp}
785107665Simp
786107665Simp
787107665Simp
788107665Simpstatic void
789107665Simpgensighand(int)
790107665Simp{
791107665Simp	romeo_must_die++;
792107665Simp	_exit(0);
793107665Simp}
794107665Simp
795107665Simpstatic void
796107665Simpusage()
797107665Simp{
798108799Simp	fprintf(stderr, "usage: %s [-d]\n", getprogname());
799107665Simp	exit(1);
800107665Simp}
801107665Simp
802113787Simpstatic void
803113787Simpcheck_devd_enabled()
804113787Simp{
805113787Simp	int val = 0;
806113787Simp	size_t len;
807113787Simp
808113787Simp	len = sizeof(val);
809114541Simp	if (sysctlbyname(SYSCTL, &val, &len, NULL, 0) != 0)
810113787Simp		errx(1, "devctl sysctl missing from kernel!");
811113787Simp	if (val) {
812113787Simp		warnx("Setting " SYSCTL " to 0");
813113787Simp		val = 0;
814113787Simp		sysctlbyname(SYSCTL, NULL, NULL, &val, sizeof(val));
815113787Simp	}
816113787Simp}
817113787Simp
818107665Simp/*
819107665Simp * main
820107665Simp */
821107665Simpint
822107665Simpmain(int argc, char **argv)
823107665Simp{
824107665Simp	int ch;
825107665Simp
826113787Simp	check_devd_enabled();
827113790Simp	while ((ch = getopt(argc, argv, "Ddn")) != -1) {
828107665Simp		switch (ch) {
829113790Simp		case 'D':
830113790Simp			Dflag++;
831113790Simp			break;
832107665Simp		case 'd':
833107665Simp			dflag++;
834107665Simp			break;
835113790Simp		case 'n':
836113790Simp			nflag++;
837113790Simp			break;
838107665Simp		default:
839107665Simp			usage();
840107665Simp		}
841107665Simp	}
842107665Simp
843107665Simp	cfg.parse();
844117246Simp	if (!dflag && nflag) {
845107665Simp		daemon(0, 0);
846117246Simp		cfg.drop_pidfile();
847117246Simp	}
848107665Simp	signal(SIGHUP, gensighand);
849107665Simp	signal(SIGINT, gensighand);
850107665Simp	signal(SIGTERM, gensighand);
851107665Simp	event_loop();
852107665Simp	return (0);
853107665Simp}
854