xref: /freebsd-14.2/sbin/devd/devd.cc (revision 4a3050fc)
13054f218SWarner Losh /*-
2b1ee04b1SWarner Losh  * Copyright (c) 2002-2003 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 devd.conf and devd man pages need a lot of help:
33251bedd1SWarner Losh //	  - devd needs to document the unix domain socket
343054f218SWarner Losh //	  - devd.conf needs more details on the supported statements.
353054f218SWarner Losh 
363054f218SWarner Losh #include <sys/cdefs.h>
373054f218SWarner Losh __FBSDID("$FreeBSD$");
383054f218SWarner Losh 
393054f218SWarner Losh #include <sys/param.h>
40251bedd1SWarner Losh #include <sys/socket.h>
41251bedd1SWarner Losh #include <sys/stat.h>
429c180898SWarner Losh #include <sys/sysctl.h>
43251bedd1SWarner Losh #include <sys/types.h>
44251bedd1SWarner Losh #include <sys/un.h>
453054f218SWarner Losh 
465102ef84SWarner Losh #include <ctype.h>
473054f218SWarner Losh #include <dirent.h>
483054f218SWarner Losh #include <errno.h>
493054f218SWarner Losh #include <err.h>
503054f218SWarner Losh #include <fcntl.h>
511a0cc6b1SPawel Jakub Dawidek #include <libutil.h>
525102ef84SWarner Losh #include <regex.h>
53f32a7686SWarner Losh #include <signal.h>
543054f218SWarner Losh #include <stdlib.h>
553054f218SWarner Losh #include <stdio.h>
563054f218SWarner Losh #include <string.h>
573054f218SWarner Losh #include <unistd.h>
583054f218SWarner Losh 
598b823408SWarner Losh #include <algorithm>
603054f218SWarner Losh #include <map>
613054f218SWarner Losh #include <string>
62251bedd1SWarner Losh #include <list>
633054f218SWarner Losh #include <vector>
643054f218SWarner Losh 
656aeeca8eSWarner Losh #include "devd.h"		/* C compatible definitions */
666aeeca8eSWarner Losh #include "devd.hh"		/* C++ class definitions */
673054f218SWarner Losh 
68251bedd1SWarner Losh #define PIPE "/var/run/devd.pipe"
693054f218SWarner Losh #define CF "/etc/devd.conf"
709c180898SWarner Losh #define SYSCTL "hw.bus.devctl_disable"
713054f218SWarner Losh 
723054f218SWarner Losh using namespace std;
733054f218SWarner Losh 
743054f218SWarner Losh extern FILE *yyin;
753054f218SWarner Losh extern int lineno;
763054f218SWarner Losh 
77842ccec5SWarner Losh static const char notify = '!';
788b823408SWarner Losh static const char nomatch = '?';
798b823408SWarner Losh static const char attach = '+';
808b823408SWarner Losh static const char detach = '-';
818b823408SWarner Losh 
821a0cc6b1SPawel Jakub Dawidek static struct pidfh *pfh;
831a0cc6b1SPawel Jakub Dawidek 
845a882d77SWarner Losh int Dflag;
853054f218SWarner Losh int dflag;
86812f53a7SWarner Losh int nflag;
873054f218SWarner Losh int romeo_must_die = 0;
883054f218SWarner Losh 
898334958aSJoseph Koshy static const char *configfile = CF;
908334958aSJoseph Koshy 
913054f218SWarner Losh static void event_loop(void);
923054f218SWarner Losh static void usage(void);
933054f218SWarner Losh 
948b823408SWarner Losh template <class T> void
958b823408SWarner Losh delete_and_clear(vector<T *> &v)
968b823408SWarner Losh {
978b823408SWarner Losh 	typename vector<T *>::const_iterator i;
983054f218SWarner Losh 
998b823408SWarner Losh 	for (i = v.begin(); i != v.end(); i++)
1008b823408SWarner Losh 		delete *i;
1018b823408SWarner Losh 	v.clear();
1028b823408SWarner Losh }
1038b823408SWarner Losh 
1043054f218SWarner Losh config cfg;
1053054f218SWarner Losh 
1063054f218SWarner Losh event_proc::event_proc() : _prio(-1)
1073054f218SWarner Losh {
1083054f218SWarner Losh 	// nothing
1093054f218SWarner Losh }
1103054f218SWarner Losh 
1113054f218SWarner Losh event_proc::~event_proc()
1123054f218SWarner Losh {
11313f8bb71SAlexander Nedotsukov 	delete_and_clear(_epsvec);
1143054f218SWarner Losh }
1153054f218SWarner Losh 
1163054f218SWarner Losh void
1173054f218SWarner Losh event_proc::add(eps *eps)
1183054f218SWarner Losh {
1193054f218SWarner Losh 	_epsvec.push_back(eps);
1203054f218SWarner Losh }
1213054f218SWarner Losh 
1223054f218SWarner Losh bool
1233054f218SWarner Losh event_proc::matches(config &c)
1243054f218SWarner Losh {
1253054f218SWarner Losh 	vector<eps *>::const_iterator i;
1263054f218SWarner Losh 
1273054f218SWarner Losh 	for (i = _epsvec.begin(); i != _epsvec.end(); i++)
1283054f218SWarner Losh 		if (!(*i)->do_match(c))
1293054f218SWarner Losh 			return (false);
1303054f218SWarner Losh 	return (true);
1313054f218SWarner Losh }
1323054f218SWarner Losh 
1333054f218SWarner Losh bool
1343054f218SWarner Losh event_proc::run(config &c)
1353054f218SWarner Losh {
1363054f218SWarner Losh 	vector<eps *>::const_iterator i;
1373054f218SWarner Losh 
1383054f218SWarner Losh 	for (i = _epsvec.begin(); i != _epsvec.end(); i++)
1393054f218SWarner Losh 		if (!(*i)->do_action(c))
1403054f218SWarner Losh 			return (false);
1413054f218SWarner Losh 	return (true);
1423054f218SWarner Losh }
1433054f218SWarner Losh 
1443054f218SWarner Losh action::action(const char *cmd)
1453054f218SWarner Losh 	: _cmd(cmd)
1463054f218SWarner Losh {
1473054f218SWarner Losh 	// nothing
1483054f218SWarner Losh }
1493054f218SWarner Losh 
1503054f218SWarner Losh action::~action()
1513054f218SWarner Losh {
1523054f218SWarner Losh 	// nothing
1533054f218SWarner Losh }
1543054f218SWarner Losh 
1553054f218SWarner Losh bool
1565102ef84SWarner Losh action::do_action(config &c)
1573054f218SWarner Losh {
1588b823408SWarner Losh 	string s = c.expand_string(_cmd);
1595a882d77SWarner Losh 	if (Dflag)
1608b823408SWarner Losh 		fprintf(stderr, "Executing '%s'\n", s.c_str());
1618b823408SWarner Losh 	::system(s.c_str());
1623054f218SWarner Losh 	return (true);
1633054f218SWarner Losh }
1643054f218SWarner Losh 
1655102ef84SWarner Losh match::match(config &c, const char *var, const char *re)
1668b823408SWarner Losh 	: _var(var)
1673054f218SWarner Losh {
1688b823408SWarner Losh 	string pattern = re;
1698b823408SWarner Losh 	_re = "^";
1708b823408SWarner Losh 	_re.append(c.expand_string(string(re)));
1718b823408SWarner Losh 	_re.append("$");
1729cb4a7bdSWarner Losh 	regcomp(&_regex, _re.c_str(), REG_EXTENDED | REG_NOSUB | REG_ICASE);
1733054f218SWarner Losh }
1743054f218SWarner Losh 
1753054f218SWarner Losh match::~match()
1763054f218SWarner Losh {
1775102ef84SWarner Losh 	regfree(&_regex);
1783054f218SWarner Losh }
1793054f218SWarner Losh 
1803054f218SWarner Losh bool
1815102ef84SWarner Losh match::do_match(config &c)
1823054f218SWarner Losh {
1835102ef84SWarner Losh 	string value = c.get_variable(_var);
1845102ef84SWarner Losh 	bool retval;
1855102ef84SWarner Losh 
1865a882d77SWarner Losh 	if (Dflag)
1878b823408SWarner Losh 		fprintf(stderr, "Testing %s=%s against %s\n", _var.c_str(),
1888b823408SWarner Losh 		    value.c_str(), _re.c_str());
1898b823408SWarner Losh 
1905102ef84SWarner Losh 	retval = (regexec(&_regex, value.c_str(), 0, NULL, 0) == 0);
1915102ef84SWarner Losh 	return retval;
1923054f218SWarner Losh }
1933054f218SWarner Losh 
194cd70782bSWarner Losh #include <sys/sockio.h>
195cd70782bSWarner Losh #include <net/if.h>
196cd70782bSWarner Losh #include <net/if_media.h>
197cd70782bSWarner Losh 
19894d2d4ebSBrooks Davis media::media(config &, const char *var, const char *type)
199cd70782bSWarner Losh 	: _var(var), _type(-1)
200cd70782bSWarner Losh {
201cd70782bSWarner Losh 	static struct ifmedia_description media_types[] = {
202cd70782bSWarner Losh 		{ IFM_ETHER,		"Ethernet" },
203cd70782bSWarner Losh 		{ IFM_TOKEN,		"Tokenring" },
204cd70782bSWarner Losh 		{ IFM_FDDI,		"FDDI" },
205cd70782bSWarner Losh 		{ IFM_IEEE80211,	"802.11" },
206cd70782bSWarner Losh 		{ IFM_ATM,		"ATM" },
207cd70782bSWarner Losh 		{ IFM_CARP,		"CARP" },
208cd70782bSWarner Losh 		{ -1,			"unknown" },
209cd70782bSWarner Losh 		{ 0, NULL },
210cd70782bSWarner Losh 	};
211cd70782bSWarner Losh 	for (int i = 0; media_types[i].ifmt_string != NULL; i++)
212cd70782bSWarner Losh 		if (strcasecmp(type, media_types[i].ifmt_string) == 0) {
213cd70782bSWarner Losh 			_type = media_types[i].ifmt_word;
214cd70782bSWarner Losh 			break;
215cd70782bSWarner Losh 		}
216cd70782bSWarner Losh }
217cd70782bSWarner Losh 
218cd70782bSWarner Losh media::~media()
219cd70782bSWarner Losh {
220cd70782bSWarner Losh }
221cd70782bSWarner Losh 
222cd70782bSWarner Losh bool
223cd70782bSWarner Losh media::do_match(config &c)
224cd70782bSWarner Losh {
22509c47e76SWarner Losh 	string value;
226cd70782bSWarner Losh 	struct ifmediareq ifmr;
227cd70782bSWarner Losh 	bool retval;
228cd70782bSWarner Losh 	int s;
229cd70782bSWarner Losh 
23009c47e76SWarner Losh 	// Since we can be called from both a device attach/detach
23109c47e76SWarner Losh 	// context where device-name is defined and what we want,
23209c47e76SWarner Losh 	// as well as from a link status context, where subsystem is
23309c47e76SWarner Losh 	// the name of interest, first try device-name and fall back
23409c47e76SWarner Losh 	// to subsystem if none exists.
23509c47e76SWarner Losh 	value = c.get_variable("device-name");
23609c47e76SWarner Losh 	if (value.length() == 0)
237de02eec8SWarner Losh 		value = c.get_variable("subsystem");
238cd70782bSWarner Losh 	if (Dflag)
239cd70782bSWarner Losh 		fprintf(stderr, "Testing media type of %s against 0x%x\n",
240cd70782bSWarner Losh 		    value.c_str(), _type);
241cd70782bSWarner Losh 
242cd70782bSWarner Losh 	retval = false;
243cd70782bSWarner Losh 
244cd70782bSWarner Losh 	s = socket(PF_INET, SOCK_DGRAM, 0);
245cd70782bSWarner Losh 	if (s >= 0) {
246cd70782bSWarner Losh 		memset(&ifmr, 0, sizeof(ifmr));
247cd70782bSWarner Losh 		strncpy(ifmr.ifm_name, value.c_str(), sizeof(ifmr.ifm_name));
248cd70782bSWarner Losh 
249cd70782bSWarner Losh 		if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0 &&
250cd70782bSWarner Losh 		    ifmr.ifm_status & IFM_AVALID) {
251cd70782bSWarner Losh 			if (Dflag)
252cd70782bSWarner Losh 				fprintf(stderr, "%s has media type 0x%x\n",
253cd70782bSWarner Losh 				    value.c_str(), IFM_TYPE(ifmr.ifm_active));
254cd70782bSWarner Losh 			retval = (IFM_TYPE(ifmr.ifm_active) == _type);
255cd70782bSWarner Losh 		} else if (_type == -1) {
256cd70782bSWarner Losh 			if (Dflag)
257cd70782bSWarner Losh 				fprintf(stderr, "%s has unknown media type\n",
258cd70782bSWarner Losh 				    value.c_str());
259cd70782bSWarner Losh 			retval = true;
260cd70782bSWarner Losh 		}
261cd70782bSWarner Losh 		close(s);
262cd70782bSWarner Losh 	}
263cd70782bSWarner Losh 
264cd70782bSWarner Losh 	return retval;
265cd70782bSWarner Losh }
266cd70782bSWarner Losh 
2673054f218SWarner Losh const string var_list::bogus = "_$_$_$_$_B_O_G_U_S_$_$_$_$_";
2683054f218SWarner Losh const string var_list::nothing = "";
2693054f218SWarner Losh 
2703054f218SWarner Losh const string &
2713054f218SWarner Losh var_list::get_variable(const string &var) const
2723054f218SWarner Losh {
2733054f218SWarner Losh 	map<string, string>::const_iterator i;
2743054f218SWarner Losh 
2753054f218SWarner Losh 	i = _vars.find(var);
2763054f218SWarner Losh 	if (i == _vars.end())
2778b823408SWarner Losh 		return (var_list::bogus);
2783054f218SWarner Losh 	return (i->second);
2793054f218SWarner Losh }
2803054f218SWarner Losh 
2813054f218SWarner Losh bool
2823054f218SWarner Losh var_list::is_set(const string &var) const
2833054f218SWarner Losh {
2843054f218SWarner Losh 	return (_vars.find(var) != _vars.end());
2853054f218SWarner Losh }
2863054f218SWarner Losh 
2873054f218SWarner Losh void
2883054f218SWarner Losh var_list::set_variable(const string &var, const string &val)
2893054f218SWarner Losh {
2905a882d77SWarner Losh 	if (Dflag)
291528d3f79SWarner Losh 		fprintf(stderr, "setting %s=%s\n", var.c_str(), val.c_str());
2923054f218SWarner Losh 	_vars[var] = val;
2933054f218SWarner Losh }
2943054f218SWarner Losh 
2953054f218SWarner Losh void
2963054f218SWarner Losh config::reset(void)
2973054f218SWarner Losh {
2983054f218SWarner Losh 	_dir_list.clear();
2998b823408SWarner Losh 	delete_and_clear(_var_list_table);
3008b823408SWarner Losh 	delete_and_clear(_attach_list);
3018b823408SWarner Losh 	delete_and_clear(_detach_list);
3028b823408SWarner Losh 	delete_and_clear(_nomatch_list);
303842ccec5SWarner Losh 	delete_and_clear(_notify_list);
3043054f218SWarner Losh }
3053054f218SWarner Losh 
3063054f218SWarner Losh void
3073054f218SWarner Losh config::parse_one_file(const char *fn)
3083054f218SWarner Losh {
3095a882d77SWarner Losh 	if (Dflag)
3103054f218SWarner Losh 		printf("Parsing %s\n", fn);
3113054f218SWarner Losh 	yyin = fopen(fn, "r");
3123054f218SWarner Losh 	if (yyin == NULL)
3133054f218SWarner Losh 		err(1, "Cannot open config file %s", fn);
314*4a3050fcSMaxim Konovalov 	lineno = 1;
3153054f218SWarner Losh 	if (yyparse() != 0)
3163054f218SWarner Losh 		errx(1, "Cannot parse %s at line %d", fn, lineno);
3173054f218SWarner Losh 	fclose(yyin);
3183054f218SWarner Losh }
3193054f218SWarner Losh 
3203054f218SWarner Losh void
3213054f218SWarner Losh config::parse_files_in_dir(const char *dirname)
3223054f218SWarner Losh {
3233054f218SWarner Losh 	DIR *dirp;
3243054f218SWarner Losh 	struct dirent *dp;
3253054f218SWarner Losh 	char path[PATH_MAX];
3263054f218SWarner Losh 
3275a882d77SWarner Losh 	if (Dflag)
3283054f218SWarner Losh 		printf("Parsing files in %s\n", dirname);
3293054f218SWarner Losh 	dirp = opendir(dirname);
3303054f218SWarner Losh 	if (dirp == NULL)
3313054f218SWarner Losh 		return;
3323054f218SWarner Losh 	readdir(dirp);		/* Skip . */
3333054f218SWarner Losh 	readdir(dirp);		/* Skip .. */
3343054f218SWarner Losh 	while ((dp = readdir(dirp)) != NULL) {
3353054f218SWarner Losh 		if (strcmp(dp->d_name + dp->d_namlen - 5, ".conf") == 0) {
3363054f218SWarner Losh 			snprintf(path, sizeof(path), "%s/%s",
3373054f218SWarner Losh 			    dirname, dp->d_name);
3383054f218SWarner Losh 			parse_one_file(path);
3393054f218SWarner Losh 		}
3403054f218SWarner Losh 	}
3413054f218SWarner Losh }
3423054f218SWarner Losh 
3438b823408SWarner Losh class epv_greater {
3448b823408SWarner Losh public:
3458b823408SWarner Losh 	int operator()(event_proc *const&l1, event_proc *const&l2)
3468b823408SWarner Losh 	{
3478b823408SWarner Losh 		return (l1->get_priority() > l2->get_priority());
3488b823408SWarner Losh 	}
3498b823408SWarner Losh };
3508b823408SWarner Losh 
3518b823408SWarner Losh void
3528b823408SWarner Losh config::sort_vector(vector<event_proc *> &v)
3538b823408SWarner Losh {
3548b823408SWarner Losh 	sort(v.begin(), v.end(), epv_greater());
3558b823408SWarner Losh }
3568b823408SWarner Losh 
3573054f218SWarner Losh void
3583054f218SWarner Losh config::parse(void)
3593054f218SWarner Losh {
3603054f218SWarner Losh 	vector<string>::const_iterator i;
3613054f218SWarner Losh 
3628334958aSJoseph Koshy 	parse_one_file(configfile);
3633054f218SWarner Losh 	for (i = _dir_list.begin(); i != _dir_list.end(); i++)
3643054f218SWarner Losh 		parse_files_in_dir((*i).c_str());
3658b823408SWarner Losh 	sort_vector(_attach_list);
3668b823408SWarner Losh 	sort_vector(_detach_list);
3678b823408SWarner Losh 	sort_vector(_nomatch_list);
368842ccec5SWarner Losh 	sort_vector(_notify_list);
3693054f218SWarner Losh }
3703054f218SWarner Losh 
3713054f218SWarner Losh void
3721a0cc6b1SPawel Jakub Dawidek config::open_pidfile()
3733054f218SWarner Losh {
3741a0cc6b1SPawel Jakub Dawidek 	pid_t otherpid;
3753054f218SWarner Losh 
3763054f218SWarner Losh 	if (_pidfile == "")
3773054f218SWarner Losh 		return;
3781a0cc6b1SPawel Jakub Dawidek 	pfh = pidfile_open(_pidfile.c_str(), 0600, &otherpid);
3791a0cc6b1SPawel Jakub Dawidek 	if (pfh == NULL) {
3801a0cc6b1SPawel Jakub Dawidek 		if (errno == EEXIST)
3811a0cc6b1SPawel Jakub Dawidek 			errx(1, "devd already running, pid: %d", (int)otherpid);
3821a0cc6b1SPawel Jakub Dawidek 		warn("cannot open pid file");
3831a0cc6b1SPawel Jakub Dawidek 	}
3841a0cc6b1SPawel Jakub Dawidek }
3851a0cc6b1SPawel Jakub Dawidek 
3861a0cc6b1SPawel Jakub Dawidek void
3871a0cc6b1SPawel Jakub Dawidek config::write_pidfile()
3881a0cc6b1SPawel Jakub Dawidek {
3891a0cc6b1SPawel Jakub Dawidek 
3901a0cc6b1SPawel Jakub Dawidek 	pidfile_write(pfh);
3911a0cc6b1SPawel Jakub Dawidek }
3921a0cc6b1SPawel Jakub Dawidek 
3931a0cc6b1SPawel Jakub Dawidek void
3941a0cc6b1SPawel Jakub Dawidek config::remove_pidfile()
3951a0cc6b1SPawel Jakub Dawidek {
3961a0cc6b1SPawel Jakub Dawidek 
3971a0cc6b1SPawel Jakub Dawidek 	pidfile_remove(pfh);
3983054f218SWarner Losh }
3993054f218SWarner Losh 
4003054f218SWarner Losh void
4013054f218SWarner Losh config::add_attach(int prio, event_proc *p)
4023054f218SWarner Losh {
4033054f218SWarner Losh 	p->set_priority(prio);
4043054f218SWarner Losh 	_attach_list.push_back(p);
4053054f218SWarner Losh }
4063054f218SWarner Losh 
4073054f218SWarner Losh void
4083054f218SWarner Losh config::add_detach(int prio, event_proc *p)
4093054f218SWarner Losh {
4103054f218SWarner Losh 	p->set_priority(prio);
4113054f218SWarner Losh 	_detach_list.push_back(p);
4123054f218SWarner Losh }
4133054f218SWarner Losh 
4143054f218SWarner Losh void
4153054f218SWarner Losh config::add_directory(const char *dir)
4163054f218SWarner Losh {
4173054f218SWarner Losh 	_dir_list.push_back(string(dir));
4183054f218SWarner Losh }
4193054f218SWarner Losh 
4203054f218SWarner Losh void
4213054f218SWarner Losh config::add_nomatch(int prio, event_proc *p)
4223054f218SWarner Losh {
4233054f218SWarner Losh 	p->set_priority(prio);
4243054f218SWarner Losh 	_nomatch_list.push_back(p);
4253054f218SWarner Losh }
4263054f218SWarner Losh 
4273054f218SWarner Losh void
428842ccec5SWarner Losh config::add_notify(int prio, event_proc *p)
429842ccec5SWarner Losh {
430842ccec5SWarner Losh 	p->set_priority(prio);
431842ccec5SWarner Losh 	_notify_list.push_back(p);
432842ccec5SWarner Losh }
433842ccec5SWarner Losh 
434842ccec5SWarner Losh void
4353054f218SWarner Losh config::set_pidfile(const char *fn)
4363054f218SWarner Losh {
4373054f218SWarner Losh 	_pidfile = string(fn);
4383054f218SWarner Losh }
4393054f218SWarner Losh 
4403054f218SWarner Losh void
4413054f218SWarner Losh config::push_var_table()
4423054f218SWarner Losh {
4433054f218SWarner Losh 	var_list *vl;
4443054f218SWarner Losh 
4453054f218SWarner Losh 	vl = new var_list();
4463054f218SWarner Losh 	_var_list_table.push_back(vl);
4475a882d77SWarner Losh 	if (Dflag)
4488b823408SWarner Losh 		fprintf(stderr, "Pushing table\n");
4493054f218SWarner Losh }
4503054f218SWarner Losh 
4513054f218SWarner Losh void
4523054f218SWarner Losh config::pop_var_table()
4533054f218SWarner Losh {
4543054f218SWarner Losh 	delete _var_list_table.back();
4553054f218SWarner Losh 	_var_list_table.pop_back();
4565a882d77SWarner Losh 	if (Dflag)
4578b823408SWarner Losh 		fprintf(stderr, "Popping table\n");
4583054f218SWarner Losh }
4593054f218SWarner Losh 
4603054f218SWarner Losh void
4613054f218SWarner Losh config::set_variable(const char *var, const char *val)
4623054f218SWarner Losh {
4633054f218SWarner Losh 	_var_list_table.back()->set_variable(var, val);
4643054f218SWarner Losh }
4653054f218SWarner Losh 
4663054f218SWarner Losh const string &
4673054f218SWarner Losh config::get_variable(const string &var)
4683054f218SWarner Losh {
4693054f218SWarner Losh 	vector<var_list *>::reverse_iterator i;
4703054f218SWarner Losh 
4713054f218SWarner Losh 	for (i = _var_list_table.rbegin(); i != _var_list_table.rend(); i++) {
4723054f218SWarner Losh 		if ((*i)->is_set(var))
4738b823408SWarner Losh 			return ((*i)->get_variable(var));
4743054f218SWarner Losh 	}
4753054f218SWarner Losh 	return (var_list::nothing);
4763054f218SWarner Losh }
4773054f218SWarner Losh 
4788b823408SWarner Losh bool
4798b823408SWarner Losh config::is_id_char(char ch)
4808b823408SWarner Losh {
4818b823408SWarner Losh 	return (ch != '\0' && (isalpha(ch) || isdigit(ch) || ch == '_' ||
4828b823408SWarner Losh 	    ch == '-'));
4838b823408SWarner Losh }
4848b823408SWarner Losh 
4855102ef84SWarner Losh void
4866cabd675SWarner Losh config::expand_one(const char *&src, string &dst)
4873054f218SWarner Losh {
4885102ef84SWarner Losh 	int count;
4896cabd675SWarner Losh 	string buffer, varstr;
4905102ef84SWarner Losh 
4918b823408SWarner Losh 	src++;
4925102ef84SWarner Losh 	// $$ -> $
4935102ef84SWarner Losh 	if (*src == '$') {
4946cabd675SWarner Losh 		dst.append(src++, 1);
4955102ef84SWarner Losh 		return;
4965102ef84SWarner Losh 	}
4975102ef84SWarner Losh 
4985102ef84SWarner Losh 	// $(foo) -> $(foo)
4998b823408SWarner Losh 	// Not sure if I want to support this or not, so for now we just pass
5008b823408SWarner Losh 	// it through.
5015102ef84SWarner Losh 	if (*src == '(') {
5026cabd675SWarner Losh 		dst.append("$");
5035102ef84SWarner Losh 		count = 1;
5046cabd675SWarner Losh 		/* If the string ends before ) is matched , return. */
5056cabd675SWarner Losh 		while (count > 0 && *src) {
5065102ef84SWarner Losh 			if (*src == ')')
5075102ef84SWarner Losh 				count--;
5085102ef84SWarner Losh 			else if (*src == '(')
5095102ef84SWarner Losh 				count++;
5106cabd675SWarner Losh 			dst.append(src++, 1);
5115102ef84SWarner Losh 		}
5125102ef84SWarner Losh 		return;
5135102ef84SWarner Losh 	}
5145102ef84SWarner Losh 
5155102ef84SWarner Losh 	// ${^A-Za-z] -> $\1
5165102ef84SWarner Losh 	if (!isalpha(*src)) {
5176cabd675SWarner Losh 		dst.append("$");
5186cabd675SWarner Losh 		dst.append(src++, 1);
5195102ef84SWarner Losh 		return;
5205102ef84SWarner Losh 	}
5215102ef84SWarner Losh 
5225102ef84SWarner Losh 	// $var -> replace with value
5236cabd675SWarner Losh 	do {
5246cabd675SWarner Losh 		buffer.append(src++, 1);
52566ff6821SWarner Losh 	} while (is_id_char(*src));
5266cabd675SWarner Losh 	buffer.append("", 1);
5276cabd675SWarner Losh 	varstr = get_variable(buffer.c_str());
5286cabd675SWarner Losh 	dst.append(varstr);
5295102ef84SWarner Losh }
5305102ef84SWarner Losh 
5315102ef84SWarner Losh const string
5325102ef84SWarner Losh config::expand_string(const string &s)
5335102ef84SWarner Losh {
5345102ef84SWarner Losh 	const char *src;
5356cabd675SWarner Losh 	string dst;
5365102ef84SWarner Losh 
5375102ef84SWarner Losh 	src = s.c_str();
5385102ef84SWarner Losh 	while (*src) {
5395102ef84SWarner Losh 		if (*src == '$')
5406cabd675SWarner Losh 			expand_one(src, dst);
5415102ef84SWarner Losh 		else
5426cabd675SWarner Losh 			dst.append(src++, 1);
5435102ef84SWarner Losh 	}
5446cabd675SWarner Losh 	dst.append("", 1);
5455102ef84SWarner Losh 
5466cabd675SWarner Losh 	return (dst);
5473054f218SWarner Losh }
5483054f218SWarner Losh 
5498b823408SWarner Losh bool
5508b823408SWarner Losh config::chop_var(char *&buffer, char *&lhs, char *&rhs)
5518b823408SWarner Losh {
5528b823408SWarner Losh 	char *walker;
5538b823408SWarner Losh 
5548b823408SWarner Losh 	if (*buffer == '\0')
5558b823408SWarner Losh 		return (false);
5568b823408SWarner Losh 	walker = lhs = buffer;
5578b823408SWarner Losh 	while (is_id_char(*walker))
5588b823408SWarner Losh 		walker++;
5598b823408SWarner Losh 	if (*walker != '=')
5608b823408SWarner Losh 		return (false);
5618b823408SWarner Losh 	walker++;		// skip =
5628b823408SWarner Losh 	if (*walker == '"') {
5638b823408SWarner Losh 		walker++;	// skip "
5648b823408SWarner Losh 		rhs = walker;
5658b823408SWarner Losh 		while (*walker && *walker != '"')
5668b823408SWarner Losh 			walker++;
5678b823408SWarner Losh 		if (*walker != '"')
5688b823408SWarner Losh 			return (false);
5698b823408SWarner Losh 		rhs[-2] = '\0';
5708b823408SWarner Losh 		*walker++ = '\0';
5718b823408SWarner Losh 	} else {
5728b823408SWarner Losh 		rhs = walker;
5738b823408SWarner Losh 		while (*walker && !isspace(*walker))
5748b823408SWarner Losh 			walker++;
5758b823408SWarner Losh 		if (*walker != '\0')
5768b823408SWarner Losh 			*walker++ = '\0';
5778b823408SWarner Losh 		rhs[-1] = '\0';
5788b823408SWarner Losh 	}
579b1ee04b1SWarner Losh 	while (isspace(*walker))
580b1ee04b1SWarner Losh 		walker++;
5818b823408SWarner Losh 	buffer = walker;
5828b823408SWarner Losh 	return (true);
5838b823408SWarner Losh }
5848b823408SWarner Losh 
5858b823408SWarner Losh 
5868b823408SWarner Losh char *
5878b823408SWarner Losh config::set_vars(char *buffer)
5888b823408SWarner Losh {
5898b823408SWarner Losh 	char *lhs;
5908b823408SWarner Losh 	char *rhs;
5918b823408SWarner Losh 
5928b823408SWarner Losh 	while (1) {
5938b823408SWarner Losh 		if (!chop_var(buffer, lhs, rhs))
5948b823408SWarner Losh 			break;
5958b823408SWarner Losh 		set_variable(lhs, rhs);
5968b823408SWarner Losh 	}
5978b823408SWarner Losh 	return (buffer);
5988b823408SWarner Losh }
5998b823408SWarner Losh 
6008b823408SWarner Losh void
6018b823408SWarner Losh config::find_and_execute(char type)
6028b823408SWarner Losh {
6038b823408SWarner Losh 	vector<event_proc *> *l;
6048b823408SWarner Losh 	vector<event_proc *>::const_iterator i;
60594d2d4ebSBrooks Davis 	const char *s;
6068b823408SWarner Losh 
6078b823408SWarner Losh 	switch (type) {
6088b823408SWarner Losh 	default:
6098b823408SWarner Losh 		return;
610842ccec5SWarner Losh 	case notify:
611842ccec5SWarner Losh 		l = &_notify_list;
612842ccec5SWarner Losh 		s = "notify";
613842ccec5SWarner Losh 		break;
6148b823408SWarner Losh 	case nomatch:
6158b823408SWarner Losh 		l = &_nomatch_list;
6168b823408SWarner Losh 		s = "nomatch";
6178b823408SWarner Losh 		break;
6188b823408SWarner Losh 	case attach:
6198b823408SWarner Losh 		l = &_attach_list;
6208b823408SWarner Losh 		s = "attach";
6218b823408SWarner Losh 		break;
6228b823408SWarner Losh 	case detach:
6238b823408SWarner Losh 		l = &_detach_list;
6248b823408SWarner Losh 		s = "detach";
6258b823408SWarner Losh 		break;
6268b823408SWarner Losh 	}
6275a882d77SWarner Losh 	if (Dflag)
6288b823408SWarner Losh 		fprintf(stderr, "Processing %s event\n", s);
6298b823408SWarner Losh 	for (i = l->begin(); i != l->end(); i++) {
6308b823408SWarner Losh 		if ((*i)->matches(*this)) {
6318b823408SWarner Losh 			(*i)->run(*this);
6328b823408SWarner Losh 			break;
6338b823408SWarner Losh 		}
6348b823408SWarner Losh 	}
6358b823408SWarner Losh 
6368b823408SWarner Losh }
6378b823408SWarner Losh 
6383054f218SWarner Losh 
6393054f218SWarner Losh static void
6408b823408SWarner Losh process_event(char *buffer)
6413054f218SWarner Losh {
6423054f218SWarner Losh 	char type;
6433054f218SWarner Losh 	char *sp;
6443054f218SWarner Losh 
6458b823408SWarner Losh 	sp = buffer + 1;
6465a882d77SWarner Losh 	if (Dflag)
6478b823408SWarner Losh 		fprintf(stderr, "Processing event '%s'\n", buffer);
6483054f218SWarner Losh 	type = *buffer++;
6498b823408SWarner Losh 	cfg.push_var_table();
6508b823408SWarner Losh 	// No match doesn't have a device, and the format is a little
6518b823408SWarner Losh 	// different, so handle it separately.
652842ccec5SWarner Losh 	switch (type) {
653842ccec5SWarner Losh 	case notify:
654842ccec5SWarner Losh 		sp = cfg.set_vars(sp);
655842ccec5SWarner Losh 		break;
656842ccec5SWarner Losh 	case nomatch:
657528d3f79SWarner Losh 		//? at location pnp-info on bus
658528d3f79SWarner Losh 		sp = strchr(sp, ' ');
659528d3f79SWarner Losh 		if (sp == NULL)
660528d3f79SWarner Losh 			return;	/* Can't happen? */
661528d3f79SWarner Losh 		*sp++ = '\0';
662842ccec5SWarner Losh 		if (strncmp(sp, "at ", 3) == 0)
663842ccec5SWarner Losh 			sp += 3;
664842ccec5SWarner Losh 		sp = cfg.set_vars(sp);
665842ccec5SWarner Losh 		if (strncmp(sp, "on ", 3) == 0)
666842ccec5SWarner Losh 			cfg.set_variable("bus", sp + 3);
667842ccec5SWarner Losh 		break;
668842ccec5SWarner Losh 	case attach:	/*FALLTHROUGH*/
669842ccec5SWarner Losh 	case detach:
6708b823408SWarner Losh 		sp = strchr(sp, ' ');
6713054f218SWarner Losh 		if (sp == NULL)
6723054f218SWarner Losh 			return;	/* Can't happen? */
6738b823408SWarner Losh 		*sp++ = '\0';
6748b823408SWarner Losh 		cfg.set_variable("device-name", buffer);
6758b823408SWarner Losh 		if (strncmp(sp, "at ", 3) == 0)
6768b823408SWarner Losh 			sp += 3;
6778b823408SWarner Losh 		sp = cfg.set_vars(sp);
6788b823408SWarner Losh 		if (strncmp(sp, "on ", 3) == 0)
6798b823408SWarner Losh 			cfg.set_variable("bus", sp + 3);
680842ccec5SWarner Losh 		break;
681b1ee04b1SWarner Losh 	}
682b1ee04b1SWarner Losh 
6838b823408SWarner Losh 	cfg.find_and_execute(type);
6848b823408SWarner Losh 	cfg.pop_var_table();
6853054f218SWarner Losh }
6863054f218SWarner Losh 
687251bedd1SWarner Losh int
688251bedd1SWarner Losh create_socket(const char *name)
689251bedd1SWarner Losh {
690251bedd1SWarner Losh 	int fd, slen;
691251bedd1SWarner Losh 	struct sockaddr_un sun;
692251bedd1SWarner Losh 
693251bedd1SWarner Losh 	if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0)
694251bedd1SWarner Losh 		err(1, "socket");
695251bedd1SWarner Losh 	bzero(&sun, sizeof(sun));
696251bedd1SWarner Losh 	sun.sun_family = AF_UNIX;
697251bedd1SWarner Losh 	strlcpy(sun.sun_path, name, sizeof(sun.sun_path));
698251bedd1SWarner Losh 	slen = SUN_LEN(&sun);
699251bedd1SWarner Losh 	unlink(name);
700e60fa014SJoe Marcus Clarke 	if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
701e60fa014SJoe Marcus Clarke 	    	err(1, "fcntl");
702251bedd1SWarner Losh 	if (bind(fd, (struct sockaddr *) & sun, slen) < 0)
703251bedd1SWarner Losh 		err(1, "bind");
704251bedd1SWarner Losh 	listen(fd, 4);
70583818929SJoe Marcus Clarke 	chown(name, 0, 0);	/* XXX - root.wheel */
706e60fa014SJoe Marcus Clarke 	chmod(name, 0666);
707251bedd1SWarner Losh 	return (fd);
708251bedd1SWarner Losh }
709251bedd1SWarner Losh 
710251bedd1SWarner Losh list<int> clients;
711251bedd1SWarner Losh 
712251bedd1SWarner Losh void
713251bedd1SWarner Losh notify_clients(const char *data, int len)
714251bedd1SWarner Losh {
715251bedd1SWarner Losh 	list<int> bad;
716251bedd1SWarner Losh 	list<int>::const_iterator i;
717251bedd1SWarner Losh 
718251bedd1SWarner Losh 	for (i = clients.begin(); i != clients.end(); i++) {
719251bedd1SWarner Losh 		if (write(*i, data, len) <= 0) {
720251bedd1SWarner Losh 			bad.push_back(*i);
721251bedd1SWarner Losh 			close(*i);
722251bedd1SWarner Losh 		}
723251bedd1SWarner Losh 	}
724251bedd1SWarner Losh 
725251bedd1SWarner Losh 	for (i = bad.begin(); i != bad.end(); i++)
726251bedd1SWarner Losh 		clients.erase(find(clients.begin(), clients.end(), *i));
727251bedd1SWarner Losh }
728251bedd1SWarner Losh 
729251bedd1SWarner Losh void
730251bedd1SWarner Losh new_client(int fd)
731251bedd1SWarner Losh {
732251bedd1SWarner Losh 	int s;
733251bedd1SWarner Losh 
734251bedd1SWarner Losh 	s = accept(fd, NULL, NULL);
735251bedd1SWarner Losh 	if (s != -1)
736251bedd1SWarner Losh 		clients.push_back(s);
737251bedd1SWarner Losh }
738251bedd1SWarner Losh 
7393054f218SWarner Losh static void
7403054f218SWarner Losh event_loop(void)
7413054f218SWarner Losh {
7423054f218SWarner Losh 	int rv;
7433054f218SWarner Losh 	int fd;
7443054f218SWarner Losh 	char buffer[DEVCTL_MAXBUF];
7455a882d77SWarner Losh 	int once = 0;
746251bedd1SWarner Losh 	int server_fd, max_fd;
7475a882d77SWarner Losh 	timeval tv;
7485a882d77SWarner Losh 	fd_set fds;
7493054f218SWarner Losh 
7503054f218SWarner Losh 	fd = open(PATH_DEVCTL, O_RDONLY);
7513054f218SWarner Losh 	if (fd == -1)
752251bedd1SWarner Losh 		err(1, "Can't open devctl device %s", PATH_DEVCTL);
7533054f218SWarner Losh 	if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0)
754251bedd1SWarner Losh 		err(1, "Can't set close-on-exec flag on devctl");
755251bedd1SWarner Losh 	server_fd = create_socket(PIPE);
756251bedd1SWarner Losh 	max_fd = max(fd, server_fd) + 1;
7573054f218SWarner Losh 	while (1) {
7583054f218SWarner Losh 		if (romeo_must_die)
7593054f218SWarner Losh 			break;
7605a882d77SWarner Losh 		if (!once && !dflag && !nflag) {
7615a882d77SWarner Losh 			// Check to see if we have any events pending.
7625a882d77SWarner Losh 			tv.tv_sec = 0;
7635a882d77SWarner Losh 			tv.tv_usec = 0;
7645a882d77SWarner Losh 			FD_ZERO(&fds);
7655a882d77SWarner Losh 			FD_SET(fd, &fds);
7665a882d77SWarner Losh 			rv = select(fd + 1, &fds, &fds, &fds, &tv);
7675a882d77SWarner Losh 			// No events -> we've processed all pending events
768f3059505SWarner Losh 			if (rv == 0) {
7695a882d77SWarner Losh 				if (Dflag)
7705a882d77SWarner Losh 					fprintf(stderr, "Calling daemon\n");
7711a0cc6b1SPawel Jakub Dawidek 				cfg.remove_pidfile();
7721a0cc6b1SPawel Jakub Dawidek 				cfg.open_pidfile();
7735a882d77SWarner Losh 				daemon(0, 0);
7741a0cc6b1SPawel Jakub Dawidek 				cfg.write_pidfile();
7755a882d77SWarner Losh 				once++;
7765a882d77SWarner Losh 			}
7775a882d77SWarner Losh 		}
778251bedd1SWarner Losh 		FD_ZERO(&fds);
779251bedd1SWarner Losh 		FD_SET(fd, &fds);
780251bedd1SWarner Losh 		FD_SET(server_fd, &fds);
781251bedd1SWarner Losh 		rv = select(max_fd, &fds, NULL, NULL, NULL);
782251bedd1SWarner Losh 		if (rv == -1) {
783251bedd1SWarner Losh 			if (errno == EINTR)
784251bedd1SWarner Losh 				continue;
785251bedd1SWarner Losh 			err(1, "select");
786251bedd1SWarner Losh 		}
787251bedd1SWarner Losh 		if (FD_ISSET(fd, &fds)) {
7883054f218SWarner Losh 			rv = read(fd, buffer, sizeof(buffer) - 1);
7893054f218SWarner Losh 			if (rv > 0) {
790251bedd1SWarner Losh 				notify_clients(buffer, rv);
7913054f218SWarner Losh 				buffer[rv] = '\0';
7923054f218SWarner Losh 				while (buffer[--rv] == '\n')
7933054f218SWarner Losh 					buffer[rv] = '\0';
7943054f218SWarner Losh 				process_event(buffer);
7953054f218SWarner Losh 			} else if (rv < 0) {
7963054f218SWarner Losh 				if (errno != EINTR)
7973054f218SWarner Losh 					break;
7983054f218SWarner Losh 			} else {
7993054f218SWarner Losh 				/* EOF */
8003054f218SWarner Losh 				break;
8013054f218SWarner Losh 			}
8023054f218SWarner Losh 		}
803251bedd1SWarner Losh 		if (FD_ISSET(server_fd, &fds))
804251bedd1SWarner Losh 			new_client(server_fd);
805251bedd1SWarner Losh 	}
8063054f218SWarner Losh 	close(fd);
8073054f218SWarner Losh }
8083054f218SWarner Losh 
8093054f218SWarner Losh /*
8103054f218SWarner Losh  * functions that the parser uses.
8113054f218SWarner Losh  */
8123054f218SWarner Losh void
8133054f218SWarner Losh add_attach(int prio, event_proc *p)
8143054f218SWarner Losh {
8153054f218SWarner Losh 	cfg.add_attach(prio, p);
8163054f218SWarner Losh }
8173054f218SWarner Losh 
8183054f218SWarner Losh void
8193054f218SWarner Losh add_detach(int prio, event_proc *p)
8203054f218SWarner Losh {
8213054f218SWarner Losh 	cfg.add_detach(prio, p);
8223054f218SWarner Losh }
8233054f218SWarner Losh 
8243054f218SWarner Losh void
8253054f218SWarner Losh add_directory(const char *dir)
8263054f218SWarner Losh {
8273054f218SWarner Losh 	cfg.add_directory(dir);
8283054f218SWarner Losh 	free(const_cast<char *>(dir));
8293054f218SWarner Losh }
8303054f218SWarner Losh 
8313054f218SWarner Losh void
8323054f218SWarner Losh add_nomatch(int prio, event_proc *p)
8333054f218SWarner Losh {
8343054f218SWarner Losh 	cfg.add_nomatch(prio, p);
8353054f218SWarner Losh }
8363054f218SWarner Losh 
837842ccec5SWarner Losh void
838842ccec5SWarner Losh add_notify(int prio, event_proc *p)
839842ccec5SWarner Losh {
840842ccec5SWarner Losh 	cfg.add_notify(prio, p);
841842ccec5SWarner Losh }
842842ccec5SWarner Losh 
8433054f218SWarner Losh event_proc *
8443054f218SWarner Losh add_to_event_proc(event_proc *ep, eps *eps)
8453054f218SWarner Losh {
8463054f218SWarner Losh 	if (ep == NULL)
8473054f218SWarner Losh 		ep = new event_proc();
8483054f218SWarner Losh 	ep->add(eps);
8493054f218SWarner Losh 	return (ep);
8503054f218SWarner Losh }
8513054f218SWarner Losh 
8523054f218SWarner Losh eps *
8533054f218SWarner Losh new_action(const char *cmd)
8543054f218SWarner Losh {
8553054f218SWarner Losh 	eps *e = new action(cmd);
8563054f218SWarner Losh 	free(const_cast<char *>(cmd));
8573054f218SWarner Losh 	return (e);
8583054f218SWarner Losh }
8593054f218SWarner Losh 
8603054f218SWarner Losh eps *
8613054f218SWarner Losh new_match(const char *var, const char *re)
8623054f218SWarner Losh {
8635102ef84SWarner Losh 	eps *e = new match(cfg, var, re);
8643054f218SWarner Losh 	free(const_cast<char *>(var));
8653054f218SWarner Losh 	free(const_cast<char *>(re));
8663054f218SWarner Losh 	return (e);
8673054f218SWarner Losh }
8683054f218SWarner Losh 
869cd70782bSWarner Losh eps *
870cd70782bSWarner Losh new_media(const char *var, const char *re)
871cd70782bSWarner Losh {
872cd70782bSWarner Losh 	eps *e = new media(cfg, var, re);
873cd70782bSWarner Losh 	free(const_cast<char *>(var));
874cd70782bSWarner Losh 	free(const_cast<char *>(re));
875cd70782bSWarner Losh 	return (e);
876cd70782bSWarner Losh }
877cd70782bSWarner Losh 
8783054f218SWarner Losh void
8793054f218SWarner Losh set_pidfile(const char *name)
8803054f218SWarner Losh {
8813054f218SWarner Losh 	cfg.set_pidfile(name);
8823054f218SWarner Losh 	free(const_cast<char *>(name));
8833054f218SWarner Losh }
8843054f218SWarner Losh 
8853054f218SWarner Losh void
8863054f218SWarner Losh set_variable(const char *var, const char *val)
8873054f218SWarner Losh {
8883054f218SWarner Losh 	cfg.set_variable(var, val);
8893054f218SWarner Losh 	free(const_cast<char *>(var));
8903054f218SWarner Losh 	free(const_cast<char *>(val));
8913054f218SWarner Losh }
8923054f218SWarner Losh 
8933054f218SWarner Losh 
8943054f218SWarner Losh 
8953054f218SWarner Losh static void
8963054f218SWarner Losh gensighand(int)
8973054f218SWarner Losh {
8983054f218SWarner Losh 	romeo_must_die++;
8993054f218SWarner Losh 	_exit(0);
9003054f218SWarner Losh }
9013054f218SWarner Losh 
9023054f218SWarner Losh static void
9033054f218SWarner Losh usage()
9043054f218SWarner Losh {
9058d646af5SRuslan Ermilov 	fprintf(stderr, "usage: %s [-Ddn]\n", getprogname());
9063054f218SWarner Losh 	exit(1);
9073054f218SWarner Losh }
9083054f218SWarner Losh 
9099c180898SWarner Losh static void
9109c180898SWarner Losh check_devd_enabled()
9119c180898SWarner Losh {
9129c180898SWarner Losh 	int val = 0;
9139c180898SWarner Losh 	size_t len;
9149c180898SWarner Losh 
9159c180898SWarner Losh 	len = sizeof(val);
91679f92e25SWarner Losh 	if (sysctlbyname(SYSCTL, &val, &len, NULL, 0) != 0)
9179c180898SWarner Losh 		errx(1, "devctl sysctl missing from kernel!");
9189c180898SWarner Losh 	if (val) {
9199c180898SWarner Losh 		warnx("Setting " SYSCTL " to 0");
9209c180898SWarner Losh 		val = 0;
9219c180898SWarner Losh 		sysctlbyname(SYSCTL, NULL, NULL, &val, sizeof(val));
9229c180898SWarner Losh 	}
9239c180898SWarner Losh }
9249c180898SWarner Losh 
9253054f218SWarner Losh /*
9263054f218SWarner Losh  * main
9273054f218SWarner Losh  */
9283054f218SWarner Losh int
9293054f218SWarner Losh main(int argc, char **argv)
9303054f218SWarner Losh {
9313054f218SWarner Losh 	int ch;
9323054f218SWarner Losh 
9339c180898SWarner Losh 	check_devd_enabled();
9348334958aSJoseph Koshy 	while ((ch = getopt(argc, argv, "Ddf:n")) != -1) {
9353054f218SWarner Losh 		switch (ch) {
9365a882d77SWarner Losh 		case 'D':
9375a882d77SWarner Losh 			Dflag++;
9385a882d77SWarner Losh 			break;
9393054f218SWarner Losh 		case 'd':
9403054f218SWarner Losh 			dflag++;
9413054f218SWarner Losh 			break;
9428334958aSJoseph Koshy 		case 'f':
9438334958aSJoseph Koshy 			configfile = optarg;
9448334958aSJoseph Koshy 			break;
9455a882d77SWarner Losh 		case 'n':
9465a882d77SWarner Losh 			nflag++;
9475a882d77SWarner Losh 			break;
9483054f218SWarner Losh 		default:
9493054f218SWarner Losh 			usage();
9503054f218SWarner Losh 		}
9513054f218SWarner Losh 	}
9523054f218SWarner Losh 
9533054f218SWarner Losh 	cfg.parse();
954fd6a8f23SWarner Losh 	if (!dflag && nflag) {
9551a0cc6b1SPawel Jakub Dawidek 		cfg.open_pidfile();
9563054f218SWarner Losh 		daemon(0, 0);
9571a0cc6b1SPawel Jakub Dawidek 		cfg.write_pidfile();
958fd6a8f23SWarner Losh 	}
959f32a7686SWarner Losh 	signal(SIGPIPE, SIG_IGN);
9603054f218SWarner Losh 	signal(SIGHUP, gensighand);
9613054f218SWarner Losh 	signal(SIGINT, gensighand);
9623054f218SWarner Losh 	signal(SIGTERM, gensighand);
9633054f218SWarner Losh 	event_loop();
9643054f218SWarner Losh 	return (0);
9653054f218SWarner Losh }
966