xref: /freebsd-14.2/sbin/devd/devd.cc (revision 5102ef84)
13054f218SWarner Losh /*-
23054f218SWarner Losh  * Copyright (c) 2002 M. Warner Losh.
33054f218SWarner Losh  * All rights reserved.
43054f218SWarner Losh  *
53054f218SWarner Losh  * Redistribution and use in source and binary forms, with or without
63054f218SWarner Losh  * modification, are permitted provided that the following conditions
73054f218SWarner Losh  * are met:
83054f218SWarner Losh  * 1. Redistributions of source code must retain the above copyright
93054f218SWarner Losh  *    notice, this list of conditions and the following disclaimer.
103054f218SWarner Losh  * 2. Redistributions in binary form must reproduce the above copyright
113054f218SWarner Losh  *    notice, this list of conditions and the following disclaimer in the
123054f218SWarner Losh  *    documentation and/or other materials provided with the distribution.
133054f218SWarner Losh  *
143054f218SWarner Losh  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
153054f218SWarner Losh  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
163054f218SWarner Losh  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
173054f218SWarner Losh  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
183054f218SWarner Losh  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
193054f218SWarner Losh  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
203054f218SWarner Losh  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
213054f218SWarner Losh  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
223054f218SWarner Losh  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
233054f218SWarner Losh  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
243054f218SWarner Losh  * SUCH DAMAGE.
253054f218SWarner Losh  */
263054f218SWarner Losh 
273054f218SWarner Losh /*
283054f218SWarner Losh  * DEVD control daemon.
293054f218SWarner Losh  */
303054f218SWarner Losh 
313054f218SWarner Losh // TODO list:
323054f218SWarner Losh //	o rewrite the main loop:
333054f218SWarner Losh //	  - find best match
343054f218SWarner Losh //	  - execute it.
353054f218SWarner Losh //	o need to insert the event_proc structures in order of priority.
363054f218SWarner Losh //        bigger numbers mean higher priority.
373054f218SWarner Losh //	o devd.conf and devd man pages need a lot of help:
383054f218SWarner Losh //	  - devd.conf needs to lose the warning about zone files.
393054f218SWarner Losh //	  - devd.conf needs more details on the supported statements.
403054f218SWarner Losh //	  - devd.conf needs an example or two.
413054f218SWarner Losh 
423054f218SWarner Losh #include <sys/cdefs.h>
433054f218SWarner Losh __FBSDID("$FreeBSD$");
443054f218SWarner Losh 
453054f218SWarner Losh #include <sys/param.h>
463054f218SWarner Losh #include <sys/types.h>
473054f218SWarner Losh 
48*5102ef84SWarner Losh #include <ctype.h>
493054f218SWarner Losh #include <dirent.h>
503054f218SWarner Losh #include <errno.h>
513054f218SWarner Losh #include <err.h>
523054f218SWarner Losh #include <fcntl.h>
53*5102ef84SWarner Losh #include <regex.h>
543054f218SWarner Losh #include <stdlib.h>
553054f218SWarner Losh #include <stdio.h>
563054f218SWarner Losh #include <string.h>
573054f218SWarner Losh #include <unistd.h>
583054f218SWarner Losh 
593054f218SWarner Losh #include <map>
603054f218SWarner Losh #include <string>
613054f218SWarner Losh #include <vector>
623054f218SWarner Losh 
633054f218SWarner Losh #include "devd.h"
643054f218SWarner Losh 
653054f218SWarner Losh #define CF "/etc/devd.conf"
663054f218SWarner Losh 
673054f218SWarner Losh using namespace std;
683054f218SWarner Losh 
693054f218SWarner Losh extern FILE *yyin;
703054f218SWarner Losh extern int lineno;
713054f218SWarner Losh 
723054f218SWarner Losh int dflag;
733054f218SWarner Losh int romeo_must_die = 0;
743054f218SWarner Losh 
753054f218SWarner Losh static void event_loop(void);
763054f218SWarner Losh static void usage(void);
773054f218SWarner Losh 
783054f218SWarner Losh class config;
793054f218SWarner Losh 
803054f218SWarner Losh 
813054f218SWarner Losh class var_list
823054f218SWarner Losh {
833054f218SWarner Losh public:
843054f218SWarner Losh 	var_list() {}
853054f218SWarner Losh 	virtual ~var_list() {}
863054f218SWarner Losh 	void set_variable(const string &var, const string &val);
873054f218SWarner Losh 	const string &get_variable(const string &var) const;
883054f218SWarner Losh 	bool is_set(const string &var) const;
893054f218SWarner Losh 	static const string bogus;
903054f218SWarner Losh 	static const string nothing;
913054f218SWarner Losh private:
923054f218SWarner Losh 	map<string, string> _vars;
933054f218SWarner Losh };
943054f218SWarner Losh 
953054f218SWarner Losh class eps
963054f218SWarner Losh {
973054f218SWarner Losh public:
983054f218SWarner Losh 	eps() {}
993054f218SWarner Losh 	virtual ~eps() {}
1003054f218SWarner Losh 	virtual bool do_match(config &) = 0;
1013054f218SWarner Losh 	virtual bool do_action(config &) = 0;
1023054f218SWarner Losh };
1033054f218SWarner Losh 
1043054f218SWarner Losh class match : public eps
1053054f218SWarner Losh {
1063054f218SWarner Losh public:
107*5102ef84SWarner Losh 	match(config &, const char *var, const char *re);
1083054f218SWarner Losh 	virtual ~match();
1093054f218SWarner Losh 	virtual bool do_match(config &);
1103054f218SWarner Losh 	virtual bool do_action(config &) { return true; }
1113054f218SWarner Losh private:
1123054f218SWarner Losh 	string _var;
1133054f218SWarner Losh 	string _re;
114*5102ef84SWarner Losh 	regex_t _regex;
1153054f218SWarner Losh };
1163054f218SWarner Losh 
1173054f218SWarner Losh class action : public eps
1183054f218SWarner Losh {
1193054f218SWarner Losh public:
1203054f218SWarner Losh 	action(const char *cmd);
1213054f218SWarner Losh 	virtual ~action();
1223054f218SWarner Losh 	virtual bool do_match(config &) { return true; }
1233054f218SWarner Losh 	virtual bool do_action(config &);
1243054f218SWarner Losh private:
1253054f218SWarner Losh 	string _cmd;
1263054f218SWarner Losh };
1273054f218SWarner Losh 
1283054f218SWarner Losh class event_proc
1293054f218SWarner Losh {
1303054f218SWarner Losh public:
1313054f218SWarner Losh 	event_proc();
1323054f218SWarner Losh 	virtual ~event_proc();
1333054f218SWarner Losh 	int get_priority() { return (_prio); }
1343054f218SWarner Losh 	void set_priority(int prio) { _prio = prio; }
1353054f218SWarner Losh 	void add(eps *);
1363054f218SWarner Losh 	bool matches(config &);
1373054f218SWarner Losh 	bool run(config &);
1383054f218SWarner Losh private:
1393054f218SWarner Losh 	int _prio;
1403054f218SWarner Losh 	vector<eps *> _epsvec;
1413054f218SWarner Losh };
1423054f218SWarner Losh 
1433054f218SWarner Losh class config
1443054f218SWarner Losh {
1453054f218SWarner Losh public:
1463054f218SWarner Losh 	config() : _pidfile("") { push_var_table(); }
1473054f218SWarner Losh 	virtual ~config() { reset(); }
1483054f218SWarner Losh 	void add_attach(int, event_proc *);
1493054f218SWarner Losh 	void add_detach(int, event_proc *);
1503054f218SWarner Losh 	void add_directory(const char *);
1513054f218SWarner Losh 	void add_nomatch(int, event_proc *);
1523054f218SWarner Losh 	void set_pidfile(const char *);
1533054f218SWarner Losh 	void reset();
1543054f218SWarner Losh 	void parse();
1553054f218SWarner Losh 	void drop_pidfile();
1563054f218SWarner Losh 	void push_var_table();
1573054f218SWarner Losh 	void pop_var_table();
1583054f218SWarner Losh 	void set_variable(const char *var, const char *val);
1593054f218SWarner Losh 	const string &get_variable(const string &var);
160*5102ef84SWarner Losh 	const string expand_string(const string &var);
1613054f218SWarner Losh protected:
1623054f218SWarner Losh 	void parse_one_file(const char *fn);
1633054f218SWarner Losh 	void parse_files_in_dir(const char *dirname);
164*5102ef84SWarner Losh 	void expand_one(const char *&src, char *&dst, char *eod);
1653054f218SWarner Losh private:
1663054f218SWarner Losh 	vector<string> _dir_list;
1673054f218SWarner Losh 	string _pidfile;
1683054f218SWarner Losh 	vector<var_list *> _var_list_table;
1693054f218SWarner Losh 	vector<event_proc *> _attach_list;
1703054f218SWarner Losh 	vector<event_proc *> _detach_list;
1713054f218SWarner Losh 	vector<event_proc *> _nomatch_list;
1723054f218SWarner Losh };
1733054f218SWarner Losh 
1743054f218SWarner Losh config cfg;
1753054f218SWarner Losh 
1763054f218SWarner Losh event_proc::event_proc() : _prio(-1)
1773054f218SWarner Losh {
1783054f218SWarner Losh 	// nothing
1793054f218SWarner Losh }
1803054f218SWarner Losh 
1813054f218SWarner Losh event_proc::~event_proc()
1823054f218SWarner Losh {
1833054f218SWarner Losh 	vector<eps *>::const_iterator i;
1843054f218SWarner Losh 
1853054f218SWarner Losh 	for (i = _epsvec.begin(); i != _epsvec.end(); i++)
1863054f218SWarner Losh 		delete *i;
1873054f218SWarner Losh 	_epsvec.clear();
1883054f218SWarner Losh }
1893054f218SWarner Losh 
1903054f218SWarner Losh void
1913054f218SWarner Losh event_proc::add(eps *eps)
1923054f218SWarner Losh {
1933054f218SWarner Losh 	_epsvec.push_back(eps);
1943054f218SWarner Losh }
1953054f218SWarner Losh 
1963054f218SWarner Losh bool
1973054f218SWarner Losh event_proc::matches(config &c)
1983054f218SWarner Losh {
1993054f218SWarner Losh 	vector<eps *>::const_iterator i;
2003054f218SWarner Losh 
2013054f218SWarner Losh 	for (i = _epsvec.begin(); i != _epsvec.end(); i++)
2023054f218SWarner Losh 		if (!(*i)->do_match(c))
2033054f218SWarner Losh 			return (false);
2043054f218SWarner Losh 	return (true);
2053054f218SWarner Losh }
2063054f218SWarner Losh 
2073054f218SWarner Losh bool
2083054f218SWarner Losh event_proc::run(config &c)
2093054f218SWarner Losh {
2103054f218SWarner Losh 	vector<eps *>::const_iterator i;
2113054f218SWarner Losh 
2123054f218SWarner Losh 	for (i = _epsvec.begin(); i != _epsvec.end(); i++)
2133054f218SWarner Losh 		if (!(*i)->do_action(c))
2143054f218SWarner Losh 			return (false);
2153054f218SWarner Losh 	return (true);
2163054f218SWarner Losh }
2173054f218SWarner Losh 
2183054f218SWarner Losh action::action(const char *cmd)
2193054f218SWarner Losh 	: _cmd(cmd)
2203054f218SWarner Losh {
2213054f218SWarner Losh 	// nothing
2223054f218SWarner Losh }
2233054f218SWarner Losh 
2243054f218SWarner Losh action::~action()
2253054f218SWarner Losh {
2263054f218SWarner Losh 	// nothing
2273054f218SWarner Losh }
2283054f218SWarner Losh 
2293054f218SWarner Losh bool
230*5102ef84SWarner Losh action::do_action(config &c)
2313054f218SWarner Losh {
2323054f218SWarner Losh 	// xxx
233*5102ef84SWarner Losh 	::system(c.expand_string(_cmd).c_str());
2343054f218SWarner Losh 	return (true);
2353054f218SWarner Losh }
2363054f218SWarner Losh 
237*5102ef84SWarner Losh match::match(config &c, const char *var, const char *re)
2383054f218SWarner Losh 	: _var(var), _re(re)
2393054f218SWarner Losh {
240*5102ef84SWarner Losh 	string pattern = "^";
241*5102ef84SWarner Losh 	pattern.append(c.expand_string(_re));
242*5102ef84SWarner Losh 	pattern.append("$");
243*5102ef84SWarner Losh 	regcomp(&_regex, pattern.c_str(), REG_EXTENDED | REG_NOSUB);
2443054f218SWarner Losh }
2453054f218SWarner Losh 
2463054f218SWarner Losh match::~match()
2473054f218SWarner Losh {
248*5102ef84SWarner Losh 	regfree(&_regex);
2493054f218SWarner Losh }
2503054f218SWarner Losh 
2513054f218SWarner Losh bool
252*5102ef84SWarner Losh match::do_match(config &c)
2533054f218SWarner Losh {
254*5102ef84SWarner Losh 	string value = c.get_variable(_var);
255*5102ef84SWarner Losh 	bool retval;
256*5102ef84SWarner Losh 
257*5102ef84SWarner Losh 	retval = (regexec(&_regex, value.c_str(), 0, NULL, 0) == 0);
258*5102ef84SWarner Losh 	return retval;
2593054f218SWarner Losh }
2603054f218SWarner Losh 
2613054f218SWarner Losh const string var_list::bogus = "_$_$_$_$_B_O_G_U_S_$_$_$_$_";
2623054f218SWarner Losh const string var_list::nothing = "";
2633054f218SWarner Losh 
2643054f218SWarner Losh const string &
2653054f218SWarner Losh var_list::get_variable(const string &var) const
2663054f218SWarner Losh {
2673054f218SWarner Losh 	map<string, string>::const_iterator i;
2683054f218SWarner Losh 
2693054f218SWarner Losh 	i = _vars.find(var);
2703054f218SWarner Losh 	if (i == _vars.end())
2713054f218SWarner Losh 		return var_list::bogus;
2723054f218SWarner Losh 	return (i->second);
2733054f218SWarner Losh }
2743054f218SWarner Losh 
2753054f218SWarner Losh bool
2763054f218SWarner Losh var_list::is_set(const string &var) const
2773054f218SWarner Losh {
2783054f218SWarner Losh 	return (_vars.find(var) != _vars.end());
2793054f218SWarner Losh }
2803054f218SWarner Losh 
2813054f218SWarner Losh void
2823054f218SWarner Losh var_list::set_variable(const string &var, const string &val)
2833054f218SWarner Losh {
2843054f218SWarner Losh 	_vars[var] = val;
2853054f218SWarner Losh }
2863054f218SWarner Losh 
2873054f218SWarner Losh void
2883054f218SWarner Losh config::reset(void)
2893054f218SWarner Losh {
2903054f218SWarner Losh 	_dir_list.clear();
2913054f218SWarner Losh 	_var_list_table.clear();
2923054f218SWarner Losh 	// XXX need to cleanup _{attach,detach,nomatch}_list
2933054f218SWarner Losh }
2943054f218SWarner Losh 
2953054f218SWarner Losh void
2963054f218SWarner Losh config::parse_one_file(const char *fn)
2973054f218SWarner Losh {
2983054f218SWarner Losh 	if (dflag)
2993054f218SWarner Losh 		printf("Parsing %s\n", fn);
3003054f218SWarner Losh 	yyin = fopen(fn, "r");
3013054f218SWarner Losh 	if (yyin == NULL)
3023054f218SWarner Losh 		err(1, "Cannot open config file %s", fn);
3033054f218SWarner Losh 	if (yyparse() != 0)
3043054f218SWarner Losh 		errx(1, "Cannot parse %s at line %d", fn, lineno);
3053054f218SWarner Losh 	fclose(yyin);
3063054f218SWarner Losh }
3073054f218SWarner Losh 
3083054f218SWarner Losh void
3093054f218SWarner Losh config::parse_files_in_dir(const char *dirname)
3103054f218SWarner Losh {
3113054f218SWarner Losh 	DIR *dirp;
3123054f218SWarner Losh 	struct dirent *dp;
3133054f218SWarner Losh 	char path[PATH_MAX];
3143054f218SWarner Losh 
3153054f218SWarner Losh 	if (dflag)
3163054f218SWarner Losh 		printf("Parsing files in %s\n", dirname);
3173054f218SWarner Losh 	dirp = opendir(dirname);
3183054f218SWarner Losh 	if (dirp == NULL)
3193054f218SWarner Losh 		return;
3203054f218SWarner Losh 	readdir(dirp);		/* Skip . */
3213054f218SWarner Losh 	readdir(dirp);		/* Skip .. */
3223054f218SWarner Losh 	while ((dp = readdir(dirp)) != NULL) {
3233054f218SWarner Losh 		if (strcmp(dp->d_name + dp->d_namlen - 5, ".conf") == 0) {
3243054f218SWarner Losh 			snprintf(path, sizeof(path), "%s/%s",
3253054f218SWarner Losh 			    dirname, dp->d_name);
3263054f218SWarner Losh 			parse_one_file(path);
3273054f218SWarner Losh 		}
3283054f218SWarner Losh 	}
3293054f218SWarner Losh }
3303054f218SWarner Losh 
3313054f218SWarner Losh void
3323054f218SWarner Losh config::parse(void)
3333054f218SWarner Losh {
3343054f218SWarner Losh 	vector<string>::const_iterator i;
3353054f218SWarner Losh 
3363054f218SWarner Losh 	parse_one_file(CF);
3373054f218SWarner Losh 	for (i = _dir_list.begin(); i != _dir_list.end(); i++)
3383054f218SWarner Losh 		parse_files_in_dir((*i).c_str());
3393054f218SWarner Losh }
3403054f218SWarner Losh 
3413054f218SWarner Losh void
3423054f218SWarner Losh config::drop_pidfile()
3433054f218SWarner Losh {
3443054f218SWarner Losh 	FILE *fp;
3453054f218SWarner Losh 
3463054f218SWarner Losh 	if (_pidfile == "")
3473054f218SWarner Losh 		return;
3483054f218SWarner Losh 	fp = fopen(_pidfile.c_str(), "w");
3493054f218SWarner Losh 	if (fp == NULL)
3503054f218SWarner Losh 		return;
3513054f218SWarner Losh 	fprintf(fp, "%d\n", getpid());
3523054f218SWarner Losh 	fclose(fp);
3533054f218SWarner Losh }
3543054f218SWarner Losh 
3553054f218SWarner Losh void
3563054f218SWarner Losh config::add_attach(int prio, event_proc *p)
3573054f218SWarner Losh {
3583054f218SWarner Losh 	p->set_priority(prio);
3593054f218SWarner Losh 	_attach_list.push_back(p);
3603054f218SWarner Losh }
3613054f218SWarner Losh 
3623054f218SWarner Losh void
3633054f218SWarner Losh config::add_detach(int prio, event_proc *p)
3643054f218SWarner Losh {
3653054f218SWarner Losh 	p->set_priority(prio);
3663054f218SWarner Losh 	_detach_list.push_back(p);
3673054f218SWarner Losh }
3683054f218SWarner Losh 
3693054f218SWarner Losh void
3703054f218SWarner Losh config::add_directory(const char *dir)
3713054f218SWarner Losh {
3723054f218SWarner Losh 	_dir_list.push_back(string(dir));
3733054f218SWarner Losh }
3743054f218SWarner Losh 
3753054f218SWarner Losh void
3763054f218SWarner Losh config::add_nomatch(int prio, event_proc *p)
3773054f218SWarner Losh {
3783054f218SWarner Losh 	p->set_priority(prio);
3793054f218SWarner Losh 	_nomatch_list.push_back(p);
3803054f218SWarner Losh }
3813054f218SWarner Losh 
3823054f218SWarner Losh void
3833054f218SWarner Losh config::set_pidfile(const char *fn)
3843054f218SWarner Losh {
3853054f218SWarner Losh 	_pidfile = string(fn);
3863054f218SWarner Losh }
3873054f218SWarner Losh 
3883054f218SWarner Losh void
3893054f218SWarner Losh config::push_var_table()
3903054f218SWarner Losh {
3913054f218SWarner Losh 	var_list *vl;
3923054f218SWarner Losh 
3933054f218SWarner Losh 	vl = new var_list();
3943054f218SWarner Losh 	_var_list_table.push_back(vl);
3953054f218SWarner Losh }
3963054f218SWarner Losh 
3973054f218SWarner Losh void
3983054f218SWarner Losh config::pop_var_table()
3993054f218SWarner Losh {
4003054f218SWarner Losh 	delete _var_list_table.back();
4013054f218SWarner Losh 	_var_list_table.pop_back();
4023054f218SWarner Losh }
4033054f218SWarner Losh 
4043054f218SWarner Losh void
4053054f218SWarner Losh config::set_variable(const char *var, const char *val)
4063054f218SWarner Losh {
4073054f218SWarner Losh 	_var_list_table.back()->set_variable(var, val);
4083054f218SWarner Losh }
4093054f218SWarner Losh 
4103054f218SWarner Losh const string &
4113054f218SWarner Losh config::get_variable(const string &var)
4123054f218SWarner Losh {
4133054f218SWarner Losh 	vector<var_list *>::reverse_iterator i;
4143054f218SWarner Losh 
4153054f218SWarner Losh 	for (i = _var_list_table.rbegin(); i != _var_list_table.rend(); i++) {
4163054f218SWarner Losh 		if ((*i)->is_set(var))
4173054f218SWarner Losh 			return (var);
4183054f218SWarner Losh 	}
4193054f218SWarner Losh 	return (var_list::nothing);
4203054f218SWarner Losh }
4213054f218SWarner Losh 
422*5102ef84SWarner Losh // Hey script |<idz, here's a routine chock-full-o-buffer-overflows.
423*5102ef84SWarner Losh // XXX
424*5102ef84SWarner Losh // imp should learn how to make effective use of the string class for the shit.
425*5102ef84SWarner Losh void
426*5102ef84SWarner Losh config::expand_one(const char *&src, char *&dst, char *)
4273054f218SWarner Losh {
428*5102ef84SWarner Losh 	int count;
429*5102ef84SWarner Losh 	const char *var;
430*5102ef84SWarner Losh 	char buffer[1024];
431*5102ef84SWarner Losh 	string varstr;
432*5102ef84SWarner Losh 
433*5102ef84SWarner Losh 	// $$ -> $
434*5102ef84SWarner Losh 	if (*src == '$') {
435*5102ef84SWarner Losh 		*dst++ = *src++;
436*5102ef84SWarner Losh 		return;
437*5102ef84SWarner Losh 	}
438*5102ef84SWarner Losh 
439*5102ef84SWarner Losh 	// $(foo) -> $(foo)
440*5102ef84SWarner Losh 	// Not sure if I want to support this or not, so for now we just pass it through.
441*5102ef84SWarner Losh 	if (*src == '(') {
442*5102ef84SWarner Losh 		*dst++ = '$';
443*5102ef84SWarner Losh 		count = 1;
444*5102ef84SWarner Losh 		while (count > 0) {
445*5102ef84SWarner Losh 			if (*src == ')')
446*5102ef84SWarner Losh 				count--;
447*5102ef84SWarner Losh 			else if (*src == '(')
448*5102ef84SWarner Losh 				count++;
449*5102ef84SWarner Losh 			*dst++ = *src++;
450*5102ef84SWarner Losh 		}
451*5102ef84SWarner Losh 		return;
452*5102ef84SWarner Losh 	}
453*5102ef84SWarner Losh 
454*5102ef84SWarner Losh 	// ${^A-Za-z] -> $\1
455*5102ef84SWarner Losh 	if (!isalpha(*src)) {
456*5102ef84SWarner Losh 		*dst++ = '$';
457*5102ef84SWarner Losh 		*dst++ = *src++;
458*5102ef84SWarner Losh 		return;
459*5102ef84SWarner Losh 	}
460*5102ef84SWarner Losh 
461*5102ef84SWarner Losh 	// $var -> replace with value
462*5102ef84SWarner Losh 	var = src++;
463*5102ef84SWarner Losh 	while (*src && isalpha(*src) || isdigit(*src) || *src == '_' || *src == '-')
464*5102ef84SWarner Losh 		src++;
465*5102ef84SWarner Losh 	memcpy(buffer, var, src - var);
466*5102ef84SWarner Losh 	buffer[src - var] = '\0';
467*5102ef84SWarner Losh 	varstr = get_variable(buffer);
468*5102ef84SWarner Losh 	strcpy(dst, varstr.c_str());
469*5102ef84SWarner Losh 	dst += strlen(dst);
470*5102ef84SWarner Losh }
471*5102ef84SWarner Losh 
472*5102ef84SWarner Losh const string
473*5102ef84SWarner Losh config::expand_string(const string &s)
474*5102ef84SWarner Losh {
475*5102ef84SWarner Losh 	const char *src;
476*5102ef84SWarner Losh 	char *dst;
477*5102ef84SWarner Losh 	char buffer[1024];
478*5102ef84SWarner Losh 
479*5102ef84SWarner Losh 	src = s.c_str();
480*5102ef84SWarner Losh 	dst = buffer;
481*5102ef84SWarner Losh 	while (*src) {
482*5102ef84SWarner Losh 		if (*src == '$')
483*5102ef84SWarner Losh 			expand_one(++src, dst, buffer + sizeof(buffer));
484*5102ef84SWarner Losh 		else
485*5102ef84SWarner Losh 			*dst++ = *src++;
486*5102ef84SWarner Losh 	}
487*5102ef84SWarner Losh 	*dst++ = '\0';
488*5102ef84SWarner Losh 
489*5102ef84SWarner Losh 	return (buffer);
4903054f218SWarner Losh }
4913054f218SWarner Losh 
4923054f218SWarner Losh 
4933054f218SWarner Losh static void
4943054f218SWarner Losh process_event(const char *buffer)
4953054f218SWarner Losh {
4963054f218SWarner Losh 	char type;
4973054f218SWarner Losh 	char cmd[1024];
4983054f218SWarner Losh 	char *sp;
4993054f218SWarner Losh 
5003054f218SWarner Losh 	// XXX should involve config
5013054f218SWarner Losh 	// XXX and set some variables
5023054f218SWarner Losh 	// XXX run the list and so forth
5033054f218SWarner Losh 
5043054f218SWarner Losh 	// Ignore unknown devices for now.
5053054f218SWarner Losh 	if (*buffer == '?')
5063054f218SWarner Losh 		return;
5073054f218SWarner Losh 	type = *buffer++;
5083054f218SWarner Losh 	sp = strchr(buffer, ' ');
5093054f218SWarner Losh 	if (sp == NULL)
5103054f218SWarner Losh 		return;	/* Can't happen? */
5113054f218SWarner Losh 	*sp = '\0';
5123054f218SWarner Losh 	snprintf(cmd, sizeof(cmd), "/etc/devd-generic %s %s", buffer,
5133054f218SWarner Losh 	    type == '+' ? "start" : "stop");
5143054f218SWarner Losh 	if (dflag)
5153054f218SWarner Losh 		printf("Trying '%s'\n", cmd);
5163054f218SWarner Losh 	system(cmd);
5173054f218SWarner Losh }
5183054f218SWarner Losh 
5193054f218SWarner Losh static void
5203054f218SWarner Losh event_loop(void)
5213054f218SWarner Losh {
5223054f218SWarner Losh 	int rv;
5233054f218SWarner Losh 	int fd;
5243054f218SWarner Losh 	char buffer[DEVCTL_MAXBUF];
5253054f218SWarner Losh 
5263054f218SWarner Losh 	fd = open(PATH_DEVCTL, O_RDONLY);
5273054f218SWarner Losh 	if (fd == -1)
5283054f218SWarner Losh 		err(1, "Can't open devctl");
5293054f218SWarner Losh 	if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0)
5303054f218SWarner Losh 		err(1, "Can't set close-on-exec flag");
5313054f218SWarner Losh 	while (1) {
5323054f218SWarner Losh 		if (romeo_must_die)
5333054f218SWarner Losh 			break;
5343054f218SWarner Losh 		rv = read(fd, buffer, sizeof(buffer) - 1);
5353054f218SWarner Losh 		if (rv > 0) {
5363054f218SWarner Losh 			buffer[rv] = '\0';
5373054f218SWarner Losh 			while (buffer[--rv] == '\n')
5383054f218SWarner Losh 				buffer[rv] = '\0';
5393054f218SWarner Losh 			process_event(buffer);
5403054f218SWarner Losh 		} else if (rv < 0) {
5413054f218SWarner Losh 			if (errno != EINTR)
5423054f218SWarner Losh 				break;
5433054f218SWarner Losh 		} else {
5443054f218SWarner Losh 			/* EOF */
5453054f218SWarner Losh 			break;
5463054f218SWarner Losh 		}
5473054f218SWarner Losh 	}
5483054f218SWarner Losh 	close(fd);
5493054f218SWarner Losh }
5503054f218SWarner Losh 
5513054f218SWarner Losh /*
5523054f218SWarner Losh  * functions that the parser uses.
5533054f218SWarner Losh  */
5543054f218SWarner Losh void
5553054f218SWarner Losh add_attach(int prio, event_proc *p)
5563054f218SWarner Losh {
5573054f218SWarner Losh 	cfg.add_attach(prio, p);
5583054f218SWarner Losh }
5593054f218SWarner Losh 
5603054f218SWarner Losh void
5613054f218SWarner Losh add_detach(int prio, event_proc *p)
5623054f218SWarner Losh {
5633054f218SWarner Losh 	cfg.add_detach(prio, p);
5643054f218SWarner Losh }
5653054f218SWarner Losh 
5663054f218SWarner Losh void
5673054f218SWarner Losh add_directory(const char *dir)
5683054f218SWarner Losh {
5693054f218SWarner Losh 	cfg.add_directory(dir);
5703054f218SWarner Losh 	free(const_cast<char *>(dir));
5713054f218SWarner Losh }
5723054f218SWarner Losh 
5733054f218SWarner Losh void
5743054f218SWarner Losh add_nomatch(int prio, event_proc *p)
5753054f218SWarner Losh {
5763054f218SWarner Losh 	cfg.add_nomatch(prio, p);
5773054f218SWarner Losh }
5783054f218SWarner Losh 
5793054f218SWarner Losh event_proc *
5803054f218SWarner Losh add_to_event_proc(event_proc *ep, eps *eps)
5813054f218SWarner Losh {
5823054f218SWarner Losh 	if (ep == NULL)
5833054f218SWarner Losh 		ep = new event_proc();
5843054f218SWarner Losh 	ep->add(eps);
5853054f218SWarner Losh 	return (ep);
5863054f218SWarner Losh }
5873054f218SWarner Losh 
5883054f218SWarner Losh eps *
5893054f218SWarner Losh new_action(const char *cmd)
5903054f218SWarner Losh {
5913054f218SWarner Losh 	eps *e = new action(cmd);
5923054f218SWarner Losh 	free(const_cast<char *>(cmd));
5933054f218SWarner Losh 	return (e);
5943054f218SWarner Losh }
5953054f218SWarner Losh 
5963054f218SWarner Losh eps *
5973054f218SWarner Losh new_match(const char *var, const char *re)
5983054f218SWarner Losh {
599*5102ef84SWarner Losh 	eps *e = new match(cfg, var, re);
6003054f218SWarner Losh 	free(const_cast<char *>(var));
6013054f218SWarner Losh 	free(const_cast<char *>(re));
6023054f218SWarner Losh 	return (e);
6033054f218SWarner Losh }
6043054f218SWarner Losh 
6053054f218SWarner Losh void
6063054f218SWarner Losh set_pidfile(const char *name)
6073054f218SWarner Losh {
6083054f218SWarner Losh 	cfg.set_pidfile(name);
6093054f218SWarner Losh 	free(const_cast<char *>(name));
6103054f218SWarner Losh }
6113054f218SWarner Losh 
6123054f218SWarner Losh void
6133054f218SWarner Losh set_variable(const char *var, const char *val)
6143054f218SWarner Losh {
6153054f218SWarner Losh 	cfg.set_variable(var, val);
6163054f218SWarner Losh 	free(const_cast<char *>(var));
6173054f218SWarner Losh 	free(const_cast<char *>(val));
6183054f218SWarner Losh }
6193054f218SWarner Losh 
6203054f218SWarner Losh 
6213054f218SWarner Losh 
6223054f218SWarner Losh static void
6233054f218SWarner Losh gensighand(int)
6243054f218SWarner Losh {
6253054f218SWarner Losh 	romeo_must_die++;
6263054f218SWarner Losh 	_exit(0);
6273054f218SWarner Losh }
6283054f218SWarner Losh 
6293054f218SWarner Losh static void
6303054f218SWarner Losh usage()
6313054f218SWarner Losh {
6323054f218SWarner Losh 	fprintf(stderr, "usage: %s [-d]", getprogname());
6333054f218SWarner Losh 	exit(1);
6343054f218SWarner Losh }
6353054f218SWarner Losh 
6363054f218SWarner Losh /*
6373054f218SWarner Losh  * main
6383054f218SWarner Losh  */
6393054f218SWarner Losh int
6403054f218SWarner Losh main(int argc, char **argv)
6413054f218SWarner Losh {
6423054f218SWarner Losh 	int ch;
6433054f218SWarner Losh 
6443054f218SWarner Losh 	while ((ch = getopt(argc, argv, "d")) != -1) {
6453054f218SWarner Losh 		switch (ch) {
6463054f218SWarner Losh 		case 'd':
6473054f218SWarner Losh 			dflag++;
6483054f218SWarner Losh 			break;
6493054f218SWarner Losh 		default:
6503054f218SWarner Losh 			usage();
6513054f218SWarner Losh 		}
6523054f218SWarner Losh 	}
6533054f218SWarner Losh 
6543054f218SWarner Losh 	cfg.parse();
6553054f218SWarner Losh 	if (!dflag)
6563054f218SWarner Losh 		daemon(0, 0);
6573054f218SWarner Losh 	cfg.drop_pidfile();
6583054f218SWarner Losh 	signal(SIGHUP, gensighand);
6593054f218SWarner Losh 	signal(SIGINT, gensighand);
6603054f218SWarner Losh 	signal(SIGTERM, gensighand);
6613054f218SWarner Losh 	event_loop();
6623054f218SWarner Losh 	return (0);
6633054f218SWarner Losh }
664