devd.cc revision 108799
1107665Simp/*-
2107665Simp * Copyright (c) 2002 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:
33107665Simp//	  - devd.conf needs to lose the warning about zone files.
34107665Simp//	  - devd.conf needs more details on the supported statements.
35107665Simp//	  - devd.conf needs an example or two.
36107665Simp
37107665Simp#include <sys/cdefs.h>
38107665Simp__FBSDID("$FreeBSD: head/sbin/devd/devd.cc 108799 2003-01-06 16:46:25Z imp $");
39107665Simp
40107665Simp#include <sys/param.h>
41107665Simp#include <sys/types.h>
42107665Simp
43108014Simp#include <ctype.h>
44107665Simp#include <dirent.h>
45107665Simp#include <errno.h>
46107665Simp#include <err.h>
47107665Simp#include <fcntl.h>
48108014Simp#include <regex.h>
49107665Simp#include <stdlib.h>
50107665Simp#include <stdio.h>
51107665Simp#include <string.h>
52107665Simp#include <unistd.h>
53107665Simp
54108783Simp#include <algorithm>
55107665Simp#include <map>
56107665Simp#include <string>
57107665Simp#include <vector>
58107665Simp
59107665Simp#include "devd.h"
60107665Simp
61107665Simp#define CF "/etc/devd.conf"
62107665Simp
63107665Simpusing namespace std;
64107665Simp
65107665Simpextern FILE *yyin;
66107665Simpextern int lineno;
67107665Simp
68108783Simpstatic const char nomatch = '?';
69108783Simpstatic const char attach = '+';
70108783Simpstatic const char detach = '-';
71108783Simp
72107665Simpint dflag;
73107665Simpint romeo_must_die = 0;
74107665Simp
75107665Simpstatic void event_loop(void);
76107665Simpstatic void usage(void);
77107665Simp
78108783Simptemplate <class T> void
79108783Simpdelete_and_clear(vector<T *> &v)
80108783Simp{
81108783Simp	typename vector<T *>::const_iterator i;
82108783Simp
83108783Simp	for (i = v.begin(); i != v.end(); i++)
84108783Simp		delete *i;
85108783Simp	v.clear();
86108783Simp}
87108783Simp
88107665Simpclass config;
89107665Simp
90107665Simpclass var_list
91107665Simp{
92107665Simppublic:
93107665Simp	var_list() {}
94107665Simp	virtual ~var_list() {}
95107665Simp	void set_variable(const string &var, const string &val);
96107665Simp	const string &get_variable(const string &var) const;
97107665Simp	bool is_set(const string &var) const;
98107665Simp	static const string bogus;
99107665Simp	static const string nothing;
100107665Simpprivate:
101107665Simp	map<string, string> _vars;
102107665Simp};
103107665Simp
104107665Simpclass eps
105107665Simp{
106107665Simppublic:
107107665Simp	eps() {}
108107665Simp	virtual ~eps() {}
109107665Simp	virtual bool do_match(config &) = 0;
110107665Simp	virtual bool do_action(config &) = 0;
111107665Simp};
112107665Simp
113107665Simpclass match : public eps
114107665Simp{
115107665Simppublic:
116108014Simp	match(config &, const char *var, const char *re);
117107665Simp	virtual ~match();
118107665Simp	virtual bool do_match(config &);
119107665Simp	virtual bool do_action(config &) { return true; }
120107665Simpprivate:
121107665Simp	string _var;
122107665Simp	string _re;
123108014Simp	regex_t _regex;
124107665Simp};
125107665Simp
126107665Simpclass action : public eps
127107665Simp{
128107665Simppublic:
129107665Simp	action(const char *cmd);
130107665Simp	virtual ~action();
131107665Simp	virtual bool do_match(config &) { return true; }
132107665Simp	virtual bool do_action(config &);
133107665Simpprivate:
134107665Simp	string _cmd;
135107665Simp};
136107665Simp
137107665Simpclass event_proc
138107665Simp{
139107665Simppublic:
140107665Simp	event_proc();
141107665Simp	virtual ~event_proc();
142108783Simp	int get_priority() const { return (_prio); }
143107665Simp	void set_priority(int prio) { _prio = prio; }
144107665Simp	void add(eps *);
145107665Simp	bool matches(config &);
146107665Simp	bool run(config &);
147107665Simpprivate:
148107665Simp	int _prio;
149107665Simp	vector<eps *> _epsvec;
150107665Simp};
151107665Simp
152107665Simpclass config
153107665Simp{
154107665Simppublic:
155107665Simp	config() : _pidfile("") { push_var_table(); }
156107665Simp	virtual ~config() { reset(); }
157107665Simp	void add_attach(int, event_proc *);
158107665Simp	void add_detach(int, event_proc *);
159107665Simp	void add_directory(const char *);
160107665Simp	void add_nomatch(int, event_proc *);
161107665Simp	void set_pidfile(const char *);
162107665Simp	void reset();
163107665Simp	void parse();
164107665Simp	void drop_pidfile();
165107665Simp	void push_var_table();
166107665Simp	void pop_var_table();
167107665Simp	void set_variable(const char *var, const char *val);
168107665Simp	const string &get_variable(const string &var);
169108014Simp	const string expand_string(const string &var);
170108783Simp	char *set_vars(char *);
171108783Simp	void find_and_execute(char);
172107665Simpprotected:
173108783Simp	void sort_vector(vector<event_proc *> &);
174107665Simp	void parse_one_file(const char *fn);
175107665Simp	void parse_files_in_dir(const char *dirname);
176108014Simp	void expand_one(const char *&src, char *&dst, char *eod);
177108783Simp	bool is_id_char(char);
178108783Simp	bool chop_var(char *&buffer, char *&lhs, char *&rhs);
179107665Simpprivate:
180107665Simp	vector<string> _dir_list;
181107665Simp	string _pidfile;
182107665Simp	vector<var_list *> _var_list_table;
183107665Simp	vector<event_proc *> _attach_list;
184107665Simp	vector<event_proc *> _detach_list;
185107665Simp	vector<event_proc *> _nomatch_list;
186107665Simp};
187107665Simp
188107665Simpconfig cfg;
189107665Simp
190107665Simpevent_proc::event_proc() : _prio(-1)
191107665Simp{
192107665Simp	// nothing
193107665Simp}
194107665Simp
195107665Simpevent_proc::~event_proc()
196107665Simp{
197107665Simp	vector<eps *>::const_iterator i;
198107665Simp
199107665Simp	for (i = _epsvec.begin(); i != _epsvec.end(); i++)
200107665Simp		delete *i;
201107665Simp	_epsvec.clear();
202107665Simp}
203107665Simp
204107665Simpvoid
205107665Simpevent_proc::add(eps *eps)
206107665Simp{
207107665Simp	_epsvec.push_back(eps);
208107665Simp}
209107665Simp
210107665Simpbool
211107665Simpevent_proc::matches(config &c)
212107665Simp{
213107665Simp	vector<eps *>::const_iterator i;
214107665Simp
215107665Simp	for (i = _epsvec.begin(); i != _epsvec.end(); i++)
216107665Simp		if (!(*i)->do_match(c))
217107665Simp			return (false);
218107665Simp	return (true);
219107665Simp}
220107665Simp
221107665Simpbool
222107665Simpevent_proc::run(config &c)
223107665Simp{
224107665Simp	vector<eps *>::const_iterator i;
225107665Simp
226107665Simp	for (i = _epsvec.begin(); i != _epsvec.end(); i++)
227107665Simp		if (!(*i)->do_action(c))
228107665Simp			return (false);
229107665Simp	return (true);
230107665Simp}
231107665Simp
232107665Simpaction::action(const char *cmd)
233107665Simp	: _cmd(cmd)
234107665Simp{
235107665Simp	// nothing
236107665Simp}
237107665Simp
238107665Simpaction::~action()
239107665Simp{
240107665Simp	// nothing
241107665Simp}
242107665Simp
243107665Simpbool
244108014Simpaction::do_action(config &c)
245107665Simp{
246108783Simp	string s = c.expand_string(_cmd);
247108783Simp	if (dflag)
248108783Simp		fprintf(stderr, "Executing '%s'\n", s.c_str());
249108783Simp	::system(s.c_str());
250107665Simp	return (true);
251107665Simp}
252107665Simp
253108014Simpmatch::match(config &c, const char *var, const char *re)
254108783Simp	: _var(var)
255107665Simp{
256108783Simp	string pattern = re;
257108783Simp	_re = "^";
258108783Simp	_re.append(c.expand_string(string(re)));
259108783Simp	_re.append("$");
260108783Simp	regcomp(&_regex, _re.c_str(), REG_EXTENDED | REG_NOSUB);
261107665Simp}
262107665Simp
263107665Simpmatch::~match()
264107665Simp{
265108014Simp	regfree(&_regex);
266107665Simp}
267107665Simp
268107665Simpbool
269108014Simpmatch::do_match(config &c)
270107665Simp{
271108014Simp	string value = c.get_variable(_var);
272108014Simp	bool retval;
273108014Simp
274108783Simp	if (dflag)
275108783Simp		fprintf(stderr, "Testing %s=%s against %s\n", _var.c_str(),
276108783Simp		    value.c_str(), _re.c_str());
277108783Simp
278108014Simp	retval = (regexec(&_regex, value.c_str(), 0, NULL, 0) == 0);
279108014Simp	return retval;
280107665Simp}
281107665Simp
282107665Simpconst string var_list::bogus = "_$_$_$_$_B_O_G_U_S_$_$_$_$_";
283107665Simpconst string var_list::nothing = "";
284107665Simp
285107665Simpconst string &
286107665Simpvar_list::get_variable(const string &var) const
287107665Simp{
288107665Simp	map<string, string>::const_iterator i;
289107665Simp
290107665Simp	i = _vars.find(var);
291107665Simp	if (i == _vars.end())
292108783Simp		return (var_list::bogus);
293107665Simp	return (i->second);
294107665Simp}
295107665Simp
296107665Simpbool
297107665Simpvar_list::is_set(const string &var) const
298107665Simp{
299107665Simp	return (_vars.find(var) != _vars.end());
300107665Simp}
301107665Simp
302107665Simpvoid
303107665Simpvar_list::set_variable(const string &var, const string &val)
304107665Simp{
305108783Simp	if (dflag)
306108783Simp		fprintf(stderr, "%s=%s\n", var.c_str(), val.c_str());
307107665Simp	_vars[var] = val;
308107665Simp}
309107665Simp
310107665Simpvoid
311107665Simpconfig::reset(void)
312107665Simp{
313107665Simp	_dir_list.clear();
314108783Simp	delete_and_clear(_var_list_table);
315108783Simp	delete_and_clear(_attach_list);
316108783Simp	delete_and_clear(_detach_list);
317108783Simp	delete_and_clear(_nomatch_list);
318107665Simp}
319107665Simp
320107665Simpvoid
321107665Simpconfig::parse_one_file(const char *fn)
322107665Simp{
323107665Simp	if (dflag)
324107665Simp		printf("Parsing %s\n", fn);
325107665Simp	yyin = fopen(fn, "r");
326107665Simp	if (yyin == NULL)
327107665Simp		err(1, "Cannot open config file %s", fn);
328107665Simp	if (yyparse() != 0)
329107665Simp		errx(1, "Cannot parse %s at line %d", fn, lineno);
330107665Simp	fclose(yyin);
331107665Simp}
332107665Simp
333107665Simpvoid
334107665Simpconfig::parse_files_in_dir(const char *dirname)
335107665Simp{
336107665Simp	DIR *dirp;
337107665Simp	struct dirent *dp;
338107665Simp	char path[PATH_MAX];
339107665Simp
340107665Simp	if (dflag)
341107665Simp		printf("Parsing files in %s\n", dirname);
342107665Simp	dirp = opendir(dirname);
343107665Simp	if (dirp == NULL)
344107665Simp		return;
345107665Simp	readdir(dirp);		/* Skip . */
346107665Simp	readdir(dirp);		/* Skip .. */
347107665Simp	while ((dp = readdir(dirp)) != NULL) {
348107665Simp		if (strcmp(dp->d_name + dp->d_namlen - 5, ".conf") == 0) {
349107665Simp			snprintf(path, sizeof(path), "%s/%s",
350107665Simp			    dirname, dp->d_name);
351107665Simp			parse_one_file(path);
352107665Simp		}
353107665Simp	}
354107665Simp}
355107665Simp
356108783Simpclass epv_greater {
357108783Simppublic:
358108783Simp	int operator()(event_proc *const&l1, event_proc *const&l2)
359108783Simp	{
360108783Simp		return (l1->get_priority() > l2->get_priority());
361108783Simp	}
362108783Simp};
363108783Simp
364107665Simpvoid
365108783Simpconfig::sort_vector(vector<event_proc *> &v)
366108783Simp{
367108783Simp	sort(v.begin(), v.end(), epv_greater());
368108783Simp}
369108783Simp
370108783Simpvoid
371107665Simpconfig::parse(void)
372107665Simp{
373107665Simp	vector<string>::const_iterator i;
374107665Simp
375107665Simp	parse_one_file(CF);
376107665Simp	for (i = _dir_list.begin(); i != _dir_list.end(); i++)
377107665Simp		parse_files_in_dir((*i).c_str());
378108783Simp	sort_vector(_attach_list);
379108783Simp	sort_vector(_detach_list);
380108783Simp	sort_vector(_nomatch_list);
381107665Simp}
382107665Simp
383107665Simpvoid
384107665Simpconfig::drop_pidfile()
385107665Simp{
386107665Simp	FILE *fp;
387107665Simp
388107665Simp	if (_pidfile == "")
389107665Simp		return;
390107665Simp	fp = fopen(_pidfile.c_str(), "w");
391107665Simp	if (fp == NULL)
392107665Simp		return;
393107665Simp	fprintf(fp, "%d\n", getpid());
394107665Simp	fclose(fp);
395107665Simp}
396107665Simp
397107665Simpvoid
398107665Simpconfig::add_attach(int prio, event_proc *p)
399107665Simp{
400107665Simp	p->set_priority(prio);
401107665Simp	_attach_list.push_back(p);
402107665Simp}
403107665Simp
404107665Simpvoid
405107665Simpconfig::add_detach(int prio, event_proc *p)
406107665Simp{
407107665Simp	p->set_priority(prio);
408107665Simp	_detach_list.push_back(p);
409107665Simp}
410107665Simp
411107665Simpvoid
412107665Simpconfig::add_directory(const char *dir)
413107665Simp{
414107665Simp	_dir_list.push_back(string(dir));
415107665Simp}
416107665Simp
417107665Simpvoid
418107665Simpconfig::add_nomatch(int prio, event_proc *p)
419107665Simp{
420107665Simp	p->set_priority(prio);
421107665Simp	_nomatch_list.push_back(p);
422107665Simp}
423107665Simp
424107665Simpvoid
425107665Simpconfig::set_pidfile(const char *fn)
426107665Simp{
427107665Simp	_pidfile = string(fn);
428107665Simp}
429107665Simp
430107665Simpvoid
431107665Simpconfig::push_var_table()
432107665Simp{
433107665Simp	var_list *vl;
434107665Simp
435107665Simp	vl = new var_list();
436107665Simp	_var_list_table.push_back(vl);
437108783Simp	if (dflag)
438108783Simp		fprintf(stderr, "Pushing table\n");
439107665Simp}
440107665Simp
441107665Simpvoid
442107665Simpconfig::pop_var_table()
443107665Simp{
444107665Simp	delete _var_list_table.back();
445107665Simp	_var_list_table.pop_back();
446108783Simp	if (dflag)
447108783Simp		fprintf(stderr, "Popping table\n");
448107665Simp}
449107665Simp
450107665Simpvoid
451107665Simpconfig::set_variable(const char *var, const char *val)
452107665Simp{
453107665Simp	_var_list_table.back()->set_variable(var, val);
454107665Simp}
455107665Simp
456107665Simpconst string &
457107665Simpconfig::get_variable(const string &var)
458107665Simp{
459107665Simp	vector<var_list *>::reverse_iterator i;
460107665Simp
461107665Simp	for (i = _var_list_table.rbegin(); i != _var_list_table.rend(); i++) {
462107665Simp		if ((*i)->is_set(var))
463108783Simp			return ((*i)->get_variable(var));
464107665Simp	}
465107665Simp	return (var_list::nothing);
466107665Simp}
467107665Simp
468108783Simpbool
469108783Simpconfig::is_id_char(char ch)
470108783Simp{
471108783Simp	return (ch != '\0' && (isalpha(ch) || isdigit(ch) || ch == '_' ||
472108783Simp	    ch == '-'));
473108783Simp}
474108783Simp
475108014Simp// XXX
476108783Simp// imp should learn how to make effective use of the string class.
477108014Simpvoid
478108014Simpconfig::expand_one(const char *&src, char *&dst, char *)
479107665Simp{
480108014Simp	int count;
481108014Simp	const char *var;
482108014Simp	char buffer[1024];
483108014Simp	string varstr;
484108014Simp
485108783Simp	src++;
486108014Simp	// $$ -> $
487108014Simp	if (*src == '$') {
488108014Simp		*dst++ = *src++;
489108014Simp		return;
490108014Simp	}
491108014Simp
492108014Simp	// $(foo) -> $(foo)
493108783Simp	// Not sure if I want to support this or not, so for now we just pass
494108783Simp	// it through.
495108014Simp	if (*src == '(') {
496108014Simp		*dst++ = '$';
497108014Simp		count = 1;
498108014Simp		while (count > 0) {
499108014Simp			if (*src == ')')
500108014Simp				count--;
501108014Simp			else if (*src == '(')
502108014Simp				count++;
503108014Simp			*dst++ = *src++;
504108014Simp		}
505108014Simp		return;
506108014Simp	}
507108014Simp
508108014Simp	// ${^A-Za-z] -> $\1
509108014Simp	if (!isalpha(*src)) {
510108014Simp		*dst++ = '$';
511108014Simp		*dst++ = *src++;
512108014Simp		return;
513108014Simp	}
514108014Simp
515108014Simp	// $var -> replace with value
516108014Simp	var = src++;
517108783Simp	while (is_id_char(*src))
518108014Simp		src++;
519108014Simp	memcpy(buffer, var, src - var);
520108014Simp	buffer[src - var] = '\0';
521108014Simp	varstr = get_variable(buffer);
522108014Simp	strcpy(dst, varstr.c_str());
523108014Simp	dst += strlen(dst);
524107665Simp}
525107665Simp
526108014Simpconst string
527108014Simpconfig::expand_string(const string &s)
528108014Simp{
529108014Simp	const char *src;
530108014Simp	char *dst;
531108014Simp	char buffer[1024];
532108014Simp
533108014Simp	src = s.c_str();
534108014Simp	dst = buffer;
535108014Simp	while (*src) {
536108014Simp		if (*src == '$')
537108783Simp			expand_one(src, dst, buffer + sizeof(buffer));
538108014Simp		else
539108014Simp			*dst++ = *src++;
540108014Simp	}
541108014Simp	*dst++ = '\0';
542108014Simp
543108014Simp	return (buffer);
544108014Simp}
545108014Simp
546108783Simpbool
547108783Simpconfig::chop_var(char *&buffer, char *&lhs, char *&rhs)
548108783Simp{
549108783Simp	char *walker;
550108783Simp
551108783Simp	if (*buffer == '\0')
552108783Simp		return (false);
553108783Simp	walker = lhs = buffer;
554108783Simp	while (is_id_char(*walker))
555108783Simp		walker++;
556108783Simp	if (*walker != '=')
557108783Simp		return (false);
558108783Simp	walker++;		// skip =
559108783Simp	if (*walker == '"') {
560108783Simp		walker++;	// skip "
561108783Simp		rhs = walker;
562108783Simp		while (*walker && *walker != '"')
563108783Simp			walker++;
564108783Simp		if (*walker != '"')
565108783Simp			return (false);
566108783Simp		rhs[-2] = '\0';
567108783Simp		*walker++ = '\0';
568108783Simp	} else {
569108783Simp		rhs = walker;
570108783Simp		while (*walker && !isspace(*walker))
571108783Simp			walker++;
572108783Simp		if (*walker != '\0')
573108783Simp			*walker++ = '\0';
574108783Simp		rhs[-1] = '\0';
575108783Simp	}
576108783Simp	buffer = walker;
577108783Simp	return (true);
578108783Simp}
579108783Simp
580108783Simp
581108783Simpchar *
582108783Simpconfig::set_vars(char *buffer)
583108783Simp{
584108783Simp	char *lhs;
585108783Simp	char *rhs;
586108783Simp
587108783Simp	while (1) {
588108783Simp		if (!chop_var(buffer, lhs, rhs))
589108783Simp			break;
590108783Simp		set_variable(lhs, rhs);
591108783Simp	}
592108783Simp	return (buffer);
593108783Simp}
594108783Simp
595108783Simpvoid
596108783Simpconfig::find_and_execute(char type)
597108783Simp{
598108783Simp	vector<event_proc *> *l;
599108783Simp	vector<event_proc *>::const_iterator i;
600108783Simp	char *s;
601108783Simp
602108783Simp	switch (type) {
603108783Simp	default:
604108783Simp		return;
605108783Simp	case nomatch:
606108783Simp		l = &_nomatch_list;
607108783Simp		s = "nomatch";
608108783Simp		break;
609108783Simp	case attach:
610108783Simp		l = &_attach_list;
611108783Simp		s = "attach";
612108783Simp		break;
613108783Simp	case detach:
614108783Simp		l = &_detach_list;
615108783Simp		s = "detach";
616108783Simp		break;
617108783Simp	}
618108783Simp	if (dflag)
619108783Simp		fprintf(stderr, "Processing %s event\n", s);
620108783Simp	for (i = l->begin(); i != l->end(); i++) {
621108783Simp		if ((*i)->matches(*this)) {
622108783Simp			(*i)->run(*this);
623108783Simp			break;
624108783Simp		}
625108783Simp	}
626108783Simp
627108783Simp}
628108783Simp
629107665Simp
630107665Simpstatic void
631108783Simpprocess_event(char *buffer)
632107665Simp{
633107665Simp	char type;
634107665Simp	char *sp;
635107665Simp
636108783Simp	sp = buffer + 1;
637108783Simp	if (dflag)
638108783Simp		fprintf(stderr, "Processing event '%s'\n", buffer);
639107665Simp	type = *buffer++;
640108783Simp	cfg.push_var_table();
641108783Simp	// No match doesn't have a device, and the format is a little
642108783Simp	// different, so handle it separately.
643108783Simp	if (type != nomatch) {
644108783Simp		sp = strchr(sp, ' ');
645108783Simp		if (sp == NULL)
646108783Simp			return;	/* Can't happen? */
647108783Simp		*sp++ = '\0';
648108783Simp		cfg.set_variable("device-name", buffer);
649108783Simp	}
650108783Simp	if (strncmp(sp, "at ", 3) == 0)
651108783Simp		sp += 3;
652108783Simp	sp = cfg.set_vars(sp);
653108783Simp	if (strncmp(sp, "on ", 3) == 0)
654108783Simp		cfg.set_variable("bus", sp + 3);
655108783Simp	cfg.find_and_execute(type);
656108783Simp	cfg.pop_var_table();
657107665Simp}
658107665Simp
659107665Simpstatic void
660107665Simpevent_loop(void)
661107665Simp{
662107665Simp	int rv;
663107665Simp	int fd;
664107665Simp	char buffer[DEVCTL_MAXBUF];
665107665Simp
666107665Simp	fd = open(PATH_DEVCTL, O_RDONLY);
667107665Simp	if (fd == -1)
668107665Simp		err(1, "Can't open devctl");
669107665Simp	if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0)
670107665Simp		err(1, "Can't set close-on-exec flag");
671107665Simp	while (1) {
672107665Simp		if (romeo_must_die)
673107665Simp			break;
674107665Simp		rv = read(fd, buffer, sizeof(buffer) - 1);
675107665Simp		if (rv > 0) {
676107665Simp			buffer[rv] = '\0';
677107665Simp			while (buffer[--rv] == '\n')
678107665Simp				buffer[rv] = '\0';
679107665Simp			process_event(buffer);
680107665Simp		} else if (rv < 0) {
681107665Simp			if (errno != EINTR)
682107665Simp				break;
683107665Simp		} else {
684107665Simp			/* EOF */
685107665Simp			break;
686107665Simp		}
687107665Simp	}
688107665Simp	close(fd);
689107665Simp}
690107665Simp
691107665Simp/*
692107665Simp * functions that the parser uses.
693107665Simp */
694107665Simpvoid
695107665Simpadd_attach(int prio, event_proc *p)
696107665Simp{
697107665Simp	cfg.add_attach(prio, p);
698107665Simp}
699107665Simp
700107665Simpvoid
701107665Simpadd_detach(int prio, event_proc *p)
702107665Simp{
703107665Simp	cfg.add_detach(prio, p);
704107665Simp}
705107665Simp
706107665Simpvoid
707107665Simpadd_directory(const char *dir)
708107665Simp{
709107665Simp	cfg.add_directory(dir);
710107665Simp	free(const_cast<char *>(dir));
711107665Simp}
712107665Simp
713107665Simpvoid
714107665Simpadd_nomatch(int prio, event_proc *p)
715107665Simp{
716107665Simp	cfg.add_nomatch(prio, p);
717107665Simp}
718107665Simp
719107665Simpevent_proc *
720107665Simpadd_to_event_proc(event_proc *ep, eps *eps)
721107665Simp{
722107665Simp	if (ep == NULL)
723107665Simp		ep = new event_proc();
724107665Simp	ep->add(eps);
725107665Simp	return (ep);
726107665Simp}
727107665Simp
728107665Simpeps *
729107665Simpnew_action(const char *cmd)
730107665Simp{
731107665Simp	eps *e = new action(cmd);
732107665Simp	free(const_cast<char *>(cmd));
733107665Simp	return (e);
734107665Simp}
735107665Simp
736107665Simpeps *
737107665Simpnew_match(const char *var, const char *re)
738107665Simp{
739108014Simp	eps *e = new match(cfg, var, re);
740107665Simp	free(const_cast<char *>(var));
741107665Simp	free(const_cast<char *>(re));
742107665Simp	return (e);
743107665Simp}
744107665Simp
745107665Simpvoid
746107665Simpset_pidfile(const char *name)
747107665Simp{
748107665Simp	cfg.set_pidfile(name);
749107665Simp	free(const_cast<char *>(name));
750107665Simp}
751107665Simp
752107665Simpvoid
753107665Simpset_variable(const char *var, const char *val)
754107665Simp{
755107665Simp	cfg.set_variable(var, val);
756107665Simp	free(const_cast<char *>(var));
757107665Simp	free(const_cast<char *>(val));
758107665Simp}
759107665Simp
760107665Simp
761107665Simp
762107665Simpstatic void
763107665Simpgensighand(int)
764107665Simp{
765107665Simp	romeo_must_die++;
766107665Simp	_exit(0);
767107665Simp}
768107665Simp
769107665Simpstatic void
770107665Simpusage()
771107665Simp{
772108799Simp	fprintf(stderr, "usage: %s [-d]\n", getprogname());
773107665Simp	exit(1);
774107665Simp}
775107665Simp
776107665Simp/*
777107665Simp * main
778107665Simp */
779107665Simpint
780107665Simpmain(int argc, char **argv)
781107665Simp{
782107665Simp	int ch;
783107665Simp
784107665Simp	while ((ch = getopt(argc, argv, "d")) != -1) {
785107665Simp		switch (ch) {
786107665Simp		case 'd':
787107665Simp			dflag++;
788107665Simp			break;
789107665Simp		default:
790107665Simp			usage();
791107665Simp		}
792107665Simp	}
793107665Simp
794107665Simp	cfg.parse();
795107665Simp	if (!dflag)
796107665Simp		daemon(0, 0);
797107665Simp	cfg.drop_pidfile();
798107665Simp	signal(SIGHUP, gensighand);
799107665Simp	signal(SIGINT, gensighand);
800107665Simp	signal(SIGTERM, gensighand);
801107665Simp	event_loop();
802107665Simp	return (0);
803107665Simp}
804