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: 333054f218SWarner Losh // - devd.conf needs to lose the warning about zone files. 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> 403054f218SWarner Losh #include <sys/types.h> 41*9c180898SWarner Losh #include <sys/sysctl.h> 423054f218SWarner Losh 435102ef84SWarner Losh #include <ctype.h> 443054f218SWarner Losh #include <dirent.h> 453054f218SWarner Losh #include <errno.h> 463054f218SWarner Losh #include <err.h> 473054f218SWarner Losh #include <fcntl.h> 485102ef84SWarner Losh #include <regex.h> 493054f218SWarner Losh #include <stdlib.h> 503054f218SWarner Losh #include <stdio.h> 513054f218SWarner Losh #include <string.h> 523054f218SWarner Losh #include <unistd.h> 533054f218SWarner Losh 548b823408SWarner Losh #include <algorithm> 553054f218SWarner Losh #include <map> 563054f218SWarner Losh #include <string> 573054f218SWarner Losh #include <vector> 583054f218SWarner Losh 593054f218SWarner Losh #include "devd.h" 603054f218SWarner Losh 613054f218SWarner Losh #define CF "/etc/devd.conf" 62*9c180898SWarner Losh #define SYSCTL "hw.bus.devctl_disable" 633054f218SWarner Losh 643054f218SWarner Losh using namespace std; 653054f218SWarner Losh 663054f218SWarner Losh extern FILE *yyin; 673054f218SWarner Losh extern int lineno; 683054f218SWarner Losh 698b823408SWarner Losh static const char nomatch = '?'; 708b823408SWarner Losh static const char attach = '+'; 718b823408SWarner Losh static const char detach = '-'; 728b823408SWarner Losh 733054f218SWarner Losh int dflag; 743054f218SWarner Losh int romeo_must_die = 0; 753054f218SWarner Losh 763054f218SWarner Losh static void event_loop(void); 773054f218SWarner Losh static void usage(void); 783054f218SWarner Losh 798b823408SWarner Losh template <class T> void 808b823408SWarner Losh delete_and_clear(vector<T *> &v) 818b823408SWarner Losh { 828b823408SWarner Losh typename vector<T *>::const_iterator i; 833054f218SWarner Losh 848b823408SWarner Losh for (i = v.begin(); i != v.end(); i++) 858b823408SWarner Losh delete *i; 868b823408SWarner Losh v.clear(); 878b823408SWarner Losh } 888b823408SWarner Losh 898b823408SWarner Losh class config; 903054f218SWarner Losh 913054f218SWarner Losh class var_list 923054f218SWarner Losh { 933054f218SWarner Losh public: 943054f218SWarner Losh var_list() {} 953054f218SWarner Losh virtual ~var_list() {} 963054f218SWarner Losh void set_variable(const string &var, const string &val); 973054f218SWarner Losh const string &get_variable(const string &var) const; 983054f218SWarner Losh bool is_set(const string &var) const; 993054f218SWarner Losh static const string bogus; 1003054f218SWarner Losh static const string nothing; 1013054f218SWarner Losh private: 1023054f218SWarner Losh map<string, string> _vars; 1033054f218SWarner Losh }; 1043054f218SWarner Losh 1053054f218SWarner Losh class eps 1063054f218SWarner Losh { 1073054f218SWarner Losh public: 1083054f218SWarner Losh eps() {} 1093054f218SWarner Losh virtual ~eps() {} 1103054f218SWarner Losh virtual bool do_match(config &) = 0; 1113054f218SWarner Losh virtual bool do_action(config &) = 0; 1123054f218SWarner Losh }; 1133054f218SWarner Losh 1143054f218SWarner Losh class match : public eps 1153054f218SWarner Losh { 1163054f218SWarner Losh public: 1175102ef84SWarner Losh match(config &, const char *var, const char *re); 1183054f218SWarner Losh virtual ~match(); 1193054f218SWarner Losh virtual bool do_match(config &); 1203054f218SWarner Losh virtual bool do_action(config &) { return true; } 1213054f218SWarner Losh private: 1223054f218SWarner Losh string _var; 1233054f218SWarner Losh string _re; 1245102ef84SWarner Losh regex_t _regex; 1253054f218SWarner Losh }; 1263054f218SWarner Losh 1273054f218SWarner Losh class action : public eps 1283054f218SWarner Losh { 1293054f218SWarner Losh public: 1303054f218SWarner Losh action(const char *cmd); 1313054f218SWarner Losh virtual ~action(); 1323054f218SWarner Losh virtual bool do_match(config &) { return true; } 1333054f218SWarner Losh virtual bool do_action(config &); 1343054f218SWarner Losh private: 1353054f218SWarner Losh string _cmd; 1363054f218SWarner Losh }; 1373054f218SWarner Losh 1383054f218SWarner Losh class event_proc 1393054f218SWarner Losh { 1403054f218SWarner Losh public: 1413054f218SWarner Losh event_proc(); 1423054f218SWarner Losh virtual ~event_proc(); 1438b823408SWarner Losh int get_priority() const { return (_prio); } 1443054f218SWarner Losh void set_priority(int prio) { _prio = prio; } 1453054f218SWarner Losh void add(eps *); 1463054f218SWarner Losh bool matches(config &); 1473054f218SWarner Losh bool run(config &); 1483054f218SWarner Losh private: 1493054f218SWarner Losh int _prio; 1503054f218SWarner Losh vector<eps *> _epsvec; 1513054f218SWarner Losh }; 1523054f218SWarner Losh 1533054f218SWarner Losh class config 1543054f218SWarner Losh { 1553054f218SWarner Losh public: 1563054f218SWarner Losh config() : _pidfile("") { push_var_table(); } 1573054f218SWarner Losh virtual ~config() { reset(); } 1583054f218SWarner Losh void add_attach(int, event_proc *); 1593054f218SWarner Losh void add_detach(int, event_proc *); 1603054f218SWarner Losh void add_directory(const char *); 1613054f218SWarner Losh void add_nomatch(int, event_proc *); 1623054f218SWarner Losh void set_pidfile(const char *); 1633054f218SWarner Losh void reset(); 1643054f218SWarner Losh void parse(); 1653054f218SWarner Losh void drop_pidfile(); 1663054f218SWarner Losh void push_var_table(); 1673054f218SWarner Losh void pop_var_table(); 1683054f218SWarner Losh void set_variable(const char *var, const char *val); 1693054f218SWarner Losh const string &get_variable(const string &var); 1705102ef84SWarner Losh const string expand_string(const string &var); 1718b823408SWarner Losh char *set_vars(char *); 1728b823408SWarner Losh void find_and_execute(char); 1733054f218SWarner Losh protected: 1748b823408SWarner Losh void sort_vector(vector<event_proc *> &); 1753054f218SWarner Losh void parse_one_file(const char *fn); 1763054f218SWarner Losh void parse_files_in_dir(const char *dirname); 1775102ef84SWarner Losh void expand_one(const char *&src, char *&dst, char *eod); 1788b823408SWarner Losh bool is_id_char(char); 1798b823408SWarner Losh bool chop_var(char *&buffer, char *&lhs, char *&rhs); 1803054f218SWarner Losh private: 1813054f218SWarner Losh vector<string> _dir_list; 1823054f218SWarner Losh string _pidfile; 1833054f218SWarner Losh vector<var_list *> _var_list_table; 1843054f218SWarner Losh vector<event_proc *> _attach_list; 1853054f218SWarner Losh vector<event_proc *> _detach_list; 1863054f218SWarner Losh vector<event_proc *> _nomatch_list; 1873054f218SWarner Losh }; 1883054f218SWarner Losh 1893054f218SWarner Losh config cfg; 1903054f218SWarner Losh 1913054f218SWarner Losh event_proc::event_proc() : _prio(-1) 1923054f218SWarner Losh { 1933054f218SWarner Losh // nothing 1943054f218SWarner Losh } 1953054f218SWarner Losh 1963054f218SWarner Losh event_proc::~event_proc() 1973054f218SWarner Losh { 1983054f218SWarner Losh vector<eps *>::const_iterator i; 1993054f218SWarner Losh 2003054f218SWarner Losh for (i = _epsvec.begin(); i != _epsvec.end(); i++) 2013054f218SWarner Losh delete *i; 2023054f218SWarner Losh _epsvec.clear(); 2033054f218SWarner Losh } 2043054f218SWarner Losh 2053054f218SWarner Losh void 2063054f218SWarner Losh event_proc::add(eps *eps) 2073054f218SWarner Losh { 2083054f218SWarner Losh _epsvec.push_back(eps); 2093054f218SWarner Losh } 2103054f218SWarner Losh 2113054f218SWarner Losh bool 2123054f218SWarner Losh event_proc::matches(config &c) 2133054f218SWarner Losh { 2143054f218SWarner Losh vector<eps *>::const_iterator i; 2153054f218SWarner Losh 2163054f218SWarner Losh for (i = _epsvec.begin(); i != _epsvec.end(); i++) 2173054f218SWarner Losh if (!(*i)->do_match(c)) 2183054f218SWarner Losh return (false); 2193054f218SWarner Losh return (true); 2203054f218SWarner Losh } 2213054f218SWarner Losh 2223054f218SWarner Losh bool 2233054f218SWarner Losh event_proc::run(config &c) 2243054f218SWarner Losh { 2253054f218SWarner Losh vector<eps *>::const_iterator i; 2263054f218SWarner Losh 2273054f218SWarner Losh for (i = _epsvec.begin(); i != _epsvec.end(); i++) 2283054f218SWarner Losh if (!(*i)->do_action(c)) 2293054f218SWarner Losh return (false); 2303054f218SWarner Losh return (true); 2313054f218SWarner Losh } 2323054f218SWarner Losh 2333054f218SWarner Losh action::action(const char *cmd) 2343054f218SWarner Losh : _cmd(cmd) 2353054f218SWarner Losh { 2363054f218SWarner Losh // nothing 2373054f218SWarner Losh } 2383054f218SWarner Losh 2393054f218SWarner Losh action::~action() 2403054f218SWarner Losh { 2413054f218SWarner Losh // nothing 2423054f218SWarner Losh } 2433054f218SWarner Losh 2443054f218SWarner Losh bool 2455102ef84SWarner Losh action::do_action(config &c) 2463054f218SWarner Losh { 2478b823408SWarner Losh string s = c.expand_string(_cmd); 2488b823408SWarner Losh if (dflag) 2498b823408SWarner Losh fprintf(stderr, "Executing '%s'\n", s.c_str()); 2508b823408SWarner Losh ::system(s.c_str()); 2513054f218SWarner Losh return (true); 2523054f218SWarner Losh } 2533054f218SWarner Losh 2545102ef84SWarner Losh match::match(config &c, const char *var, const char *re) 2558b823408SWarner Losh : _var(var) 2563054f218SWarner Losh { 2578b823408SWarner Losh string pattern = re; 2588b823408SWarner Losh _re = "^"; 2598b823408SWarner Losh _re.append(c.expand_string(string(re))); 2608b823408SWarner Losh _re.append("$"); 2618b823408SWarner Losh regcomp(&_regex, _re.c_str(), REG_EXTENDED | REG_NOSUB); 2623054f218SWarner Losh } 2633054f218SWarner Losh 2643054f218SWarner Losh match::~match() 2653054f218SWarner Losh { 2665102ef84SWarner Losh regfree(&_regex); 2673054f218SWarner Losh } 2683054f218SWarner Losh 2693054f218SWarner Losh bool 2705102ef84SWarner Losh match::do_match(config &c) 2713054f218SWarner Losh { 2725102ef84SWarner Losh string value = c.get_variable(_var); 2735102ef84SWarner Losh bool retval; 2745102ef84SWarner Losh 2758b823408SWarner Losh if (dflag) 2768b823408SWarner Losh fprintf(stderr, "Testing %s=%s against %s\n", _var.c_str(), 2778b823408SWarner Losh value.c_str(), _re.c_str()); 2788b823408SWarner Losh 2795102ef84SWarner Losh retval = (regexec(&_regex, value.c_str(), 0, NULL, 0) == 0); 2805102ef84SWarner Losh return retval; 2813054f218SWarner Losh } 2823054f218SWarner Losh 2833054f218SWarner Losh const string var_list::bogus = "_$_$_$_$_B_O_G_U_S_$_$_$_$_"; 2843054f218SWarner Losh const string var_list::nothing = ""; 2853054f218SWarner Losh 2863054f218SWarner Losh const string & 2873054f218SWarner Losh var_list::get_variable(const string &var) const 2883054f218SWarner Losh { 2893054f218SWarner Losh map<string, string>::const_iterator i; 2903054f218SWarner Losh 2913054f218SWarner Losh i = _vars.find(var); 2923054f218SWarner Losh if (i == _vars.end()) 2938b823408SWarner Losh return (var_list::bogus); 2943054f218SWarner Losh return (i->second); 2953054f218SWarner Losh } 2963054f218SWarner Losh 2973054f218SWarner Losh bool 2983054f218SWarner Losh var_list::is_set(const string &var) const 2993054f218SWarner Losh { 3003054f218SWarner Losh return (_vars.find(var) != _vars.end()); 3013054f218SWarner Losh } 3023054f218SWarner Losh 3033054f218SWarner Losh void 3043054f218SWarner Losh var_list::set_variable(const string &var, const string &val) 3053054f218SWarner Losh { 3068b823408SWarner Losh if (dflag) 3078b823408SWarner Losh fprintf(stderr, "%s=%s\n", var.c_str(), val.c_str()); 3083054f218SWarner Losh _vars[var] = val; 3093054f218SWarner Losh } 3103054f218SWarner Losh 3113054f218SWarner Losh void 3123054f218SWarner Losh config::reset(void) 3133054f218SWarner Losh { 3143054f218SWarner Losh _dir_list.clear(); 3158b823408SWarner Losh delete_and_clear(_var_list_table); 3168b823408SWarner Losh delete_and_clear(_attach_list); 3178b823408SWarner Losh delete_and_clear(_detach_list); 3188b823408SWarner Losh delete_and_clear(_nomatch_list); 3193054f218SWarner Losh } 3203054f218SWarner Losh 3213054f218SWarner Losh void 3223054f218SWarner Losh config::parse_one_file(const char *fn) 3233054f218SWarner Losh { 3243054f218SWarner Losh if (dflag) 3253054f218SWarner Losh printf("Parsing %s\n", fn); 3263054f218SWarner Losh yyin = fopen(fn, "r"); 3273054f218SWarner Losh if (yyin == NULL) 3283054f218SWarner Losh err(1, "Cannot open config file %s", fn); 3293054f218SWarner Losh if (yyparse() != 0) 3303054f218SWarner Losh errx(1, "Cannot parse %s at line %d", fn, lineno); 3313054f218SWarner Losh fclose(yyin); 3323054f218SWarner Losh } 3333054f218SWarner Losh 3343054f218SWarner Losh void 3353054f218SWarner Losh config::parse_files_in_dir(const char *dirname) 3363054f218SWarner Losh { 3373054f218SWarner Losh DIR *dirp; 3383054f218SWarner Losh struct dirent *dp; 3393054f218SWarner Losh char path[PATH_MAX]; 3403054f218SWarner Losh 3413054f218SWarner Losh if (dflag) 3423054f218SWarner Losh printf("Parsing files in %s\n", dirname); 3433054f218SWarner Losh dirp = opendir(dirname); 3443054f218SWarner Losh if (dirp == NULL) 3453054f218SWarner Losh return; 3463054f218SWarner Losh readdir(dirp); /* Skip . */ 3473054f218SWarner Losh readdir(dirp); /* Skip .. */ 3483054f218SWarner Losh while ((dp = readdir(dirp)) != NULL) { 3493054f218SWarner Losh if (strcmp(dp->d_name + dp->d_namlen - 5, ".conf") == 0) { 3503054f218SWarner Losh snprintf(path, sizeof(path), "%s/%s", 3513054f218SWarner Losh dirname, dp->d_name); 3523054f218SWarner Losh parse_one_file(path); 3533054f218SWarner Losh } 3543054f218SWarner Losh } 3553054f218SWarner Losh } 3563054f218SWarner Losh 3578b823408SWarner Losh class epv_greater { 3588b823408SWarner Losh public: 3598b823408SWarner Losh int operator()(event_proc *const&l1, event_proc *const&l2) 3608b823408SWarner Losh { 3618b823408SWarner Losh return (l1->get_priority() > l2->get_priority()); 3628b823408SWarner Losh } 3638b823408SWarner Losh }; 3648b823408SWarner Losh 3658b823408SWarner Losh void 3668b823408SWarner Losh config::sort_vector(vector<event_proc *> &v) 3678b823408SWarner Losh { 3688b823408SWarner Losh sort(v.begin(), v.end(), epv_greater()); 3698b823408SWarner Losh } 3708b823408SWarner Losh 3713054f218SWarner Losh void 3723054f218SWarner Losh config::parse(void) 3733054f218SWarner Losh { 3743054f218SWarner Losh vector<string>::const_iterator i; 3753054f218SWarner Losh 3763054f218SWarner Losh parse_one_file(CF); 3773054f218SWarner Losh for (i = _dir_list.begin(); i != _dir_list.end(); i++) 3783054f218SWarner Losh parse_files_in_dir((*i).c_str()); 3798b823408SWarner Losh sort_vector(_attach_list); 3808b823408SWarner Losh sort_vector(_detach_list); 3818b823408SWarner Losh sort_vector(_nomatch_list); 3823054f218SWarner Losh } 3833054f218SWarner Losh 3843054f218SWarner Losh void 3853054f218SWarner Losh config::drop_pidfile() 3863054f218SWarner Losh { 3873054f218SWarner Losh FILE *fp; 3883054f218SWarner Losh 3893054f218SWarner Losh if (_pidfile == "") 3903054f218SWarner Losh return; 3913054f218SWarner Losh fp = fopen(_pidfile.c_str(), "w"); 3923054f218SWarner Losh if (fp == NULL) 3933054f218SWarner Losh return; 3943054f218SWarner Losh fprintf(fp, "%d\n", getpid()); 3953054f218SWarner Losh fclose(fp); 3963054f218SWarner Losh } 3973054f218SWarner Losh 3983054f218SWarner Losh void 3993054f218SWarner Losh config::add_attach(int prio, event_proc *p) 4003054f218SWarner Losh { 4013054f218SWarner Losh p->set_priority(prio); 4023054f218SWarner Losh _attach_list.push_back(p); 4033054f218SWarner Losh } 4043054f218SWarner Losh 4053054f218SWarner Losh void 4063054f218SWarner Losh config::add_detach(int prio, event_proc *p) 4073054f218SWarner Losh { 4083054f218SWarner Losh p->set_priority(prio); 4093054f218SWarner Losh _detach_list.push_back(p); 4103054f218SWarner Losh } 4113054f218SWarner Losh 4123054f218SWarner Losh void 4133054f218SWarner Losh config::add_directory(const char *dir) 4143054f218SWarner Losh { 4153054f218SWarner Losh _dir_list.push_back(string(dir)); 4163054f218SWarner Losh } 4173054f218SWarner Losh 4183054f218SWarner Losh void 4193054f218SWarner Losh config::add_nomatch(int prio, event_proc *p) 4203054f218SWarner Losh { 4213054f218SWarner Losh p->set_priority(prio); 4223054f218SWarner Losh _nomatch_list.push_back(p); 4233054f218SWarner Losh } 4243054f218SWarner Losh 4253054f218SWarner Losh void 4263054f218SWarner Losh config::set_pidfile(const char *fn) 4273054f218SWarner Losh { 4283054f218SWarner Losh _pidfile = string(fn); 4293054f218SWarner Losh } 4303054f218SWarner Losh 4313054f218SWarner Losh void 4323054f218SWarner Losh config::push_var_table() 4333054f218SWarner Losh { 4343054f218SWarner Losh var_list *vl; 4353054f218SWarner Losh 4363054f218SWarner Losh vl = new var_list(); 4373054f218SWarner Losh _var_list_table.push_back(vl); 4388b823408SWarner Losh if (dflag) 4398b823408SWarner Losh fprintf(stderr, "Pushing table\n"); 4403054f218SWarner Losh } 4413054f218SWarner Losh 4423054f218SWarner Losh void 4433054f218SWarner Losh config::pop_var_table() 4443054f218SWarner Losh { 4453054f218SWarner Losh delete _var_list_table.back(); 4463054f218SWarner Losh _var_list_table.pop_back(); 4478b823408SWarner Losh if (dflag) 4488b823408SWarner Losh fprintf(stderr, "Popping table\n"); 4493054f218SWarner Losh } 4503054f218SWarner Losh 4513054f218SWarner Losh void 4523054f218SWarner Losh config::set_variable(const char *var, const char *val) 4533054f218SWarner Losh { 4543054f218SWarner Losh _var_list_table.back()->set_variable(var, val); 4553054f218SWarner Losh } 4563054f218SWarner Losh 4573054f218SWarner Losh const string & 4583054f218SWarner Losh config::get_variable(const string &var) 4593054f218SWarner Losh { 4603054f218SWarner Losh vector<var_list *>::reverse_iterator i; 4613054f218SWarner Losh 4623054f218SWarner Losh for (i = _var_list_table.rbegin(); i != _var_list_table.rend(); i++) { 4633054f218SWarner Losh if ((*i)->is_set(var)) 4648b823408SWarner Losh return ((*i)->get_variable(var)); 4653054f218SWarner Losh } 4663054f218SWarner Losh return (var_list::nothing); 4673054f218SWarner Losh } 4683054f218SWarner Losh 4698b823408SWarner Losh bool 4708b823408SWarner Losh config::is_id_char(char ch) 4718b823408SWarner Losh { 4728b823408SWarner Losh return (ch != '\0' && (isalpha(ch) || isdigit(ch) || ch == '_' || 4738b823408SWarner Losh ch == '-')); 4748b823408SWarner Losh } 4758b823408SWarner Losh 4765102ef84SWarner Losh // XXX 4778b823408SWarner Losh // imp should learn how to make effective use of the string class. 4785102ef84SWarner Losh void 4795102ef84SWarner Losh config::expand_one(const char *&src, char *&dst, char *) 4803054f218SWarner Losh { 4815102ef84SWarner Losh int count; 4825102ef84SWarner Losh const char *var; 4835102ef84SWarner Losh char buffer[1024]; 4845102ef84SWarner Losh string varstr; 4855102ef84SWarner Losh 4868b823408SWarner Losh src++; 4875102ef84SWarner Losh // $$ -> $ 4885102ef84SWarner Losh if (*src == '$') { 4895102ef84SWarner Losh *dst++ = *src++; 4905102ef84SWarner Losh return; 4915102ef84SWarner Losh } 4925102ef84SWarner Losh 4935102ef84SWarner Losh // $(foo) -> $(foo) 4948b823408SWarner Losh // Not sure if I want to support this or not, so for now we just pass 4958b823408SWarner Losh // it through. 4965102ef84SWarner Losh if (*src == '(') { 4975102ef84SWarner Losh *dst++ = '$'; 4985102ef84SWarner Losh count = 1; 4995102ef84SWarner Losh while (count > 0) { 5005102ef84SWarner Losh if (*src == ')') 5015102ef84SWarner Losh count--; 5025102ef84SWarner Losh else if (*src == '(') 5035102ef84SWarner Losh count++; 5045102ef84SWarner Losh *dst++ = *src++; 5055102ef84SWarner Losh } 5065102ef84SWarner Losh return; 5075102ef84SWarner Losh } 5085102ef84SWarner Losh 5095102ef84SWarner Losh // ${^A-Za-z] -> $\1 5105102ef84SWarner Losh if (!isalpha(*src)) { 5115102ef84SWarner Losh *dst++ = '$'; 5125102ef84SWarner Losh *dst++ = *src++; 5135102ef84SWarner Losh return; 5145102ef84SWarner Losh } 5155102ef84SWarner Losh 5165102ef84SWarner Losh // $var -> replace with value 5175102ef84SWarner Losh var = src++; 5188b823408SWarner Losh while (is_id_char(*src)) 5195102ef84SWarner Losh src++; 5205102ef84SWarner Losh memcpy(buffer, var, src - var); 5215102ef84SWarner Losh buffer[src - var] = '\0'; 5225102ef84SWarner Losh varstr = get_variable(buffer); 5235102ef84SWarner Losh strcpy(dst, varstr.c_str()); 5245102ef84SWarner Losh dst += strlen(dst); 5255102ef84SWarner Losh } 5265102ef84SWarner Losh 5275102ef84SWarner Losh const string 5285102ef84SWarner Losh config::expand_string(const string &s) 5295102ef84SWarner Losh { 5305102ef84SWarner Losh const char *src; 5315102ef84SWarner Losh char *dst; 5325102ef84SWarner Losh char buffer[1024]; 5335102ef84SWarner Losh 5345102ef84SWarner Losh src = s.c_str(); 5355102ef84SWarner Losh dst = buffer; 5365102ef84SWarner Losh while (*src) { 5375102ef84SWarner Losh if (*src == '$') 5388b823408SWarner Losh expand_one(src, dst, buffer + sizeof(buffer)); 5395102ef84SWarner Losh else 5405102ef84SWarner Losh *dst++ = *src++; 5415102ef84SWarner Losh } 5425102ef84SWarner Losh *dst++ = '\0'; 5435102ef84SWarner Losh 5445102ef84SWarner Losh return (buffer); 5453054f218SWarner Losh } 5463054f218SWarner Losh 5478b823408SWarner Losh bool 5488b823408SWarner Losh config::chop_var(char *&buffer, char *&lhs, char *&rhs) 5498b823408SWarner Losh { 5508b823408SWarner Losh char *walker; 5518b823408SWarner Losh 5528b823408SWarner Losh if (*buffer == '\0') 5538b823408SWarner Losh return (false); 5548b823408SWarner Losh walker = lhs = buffer; 5558b823408SWarner Losh while (is_id_char(*walker)) 5568b823408SWarner Losh walker++; 5578b823408SWarner Losh if (*walker != '=') 5588b823408SWarner Losh return (false); 5598b823408SWarner Losh walker++; // skip = 5608b823408SWarner Losh if (*walker == '"') { 5618b823408SWarner Losh walker++; // skip " 5628b823408SWarner Losh rhs = walker; 5638b823408SWarner Losh while (*walker && *walker != '"') 5648b823408SWarner Losh walker++; 5658b823408SWarner Losh if (*walker != '"') 5668b823408SWarner Losh return (false); 5678b823408SWarner Losh rhs[-2] = '\0'; 5688b823408SWarner Losh *walker++ = '\0'; 5698b823408SWarner Losh } else { 5708b823408SWarner Losh rhs = walker; 5718b823408SWarner Losh while (*walker && !isspace(*walker)) 5728b823408SWarner Losh walker++; 5738b823408SWarner Losh if (*walker != '\0') 5748b823408SWarner Losh *walker++ = '\0'; 5758b823408SWarner Losh rhs[-1] = '\0'; 5768b823408SWarner Losh } 577b1ee04b1SWarner Losh while (isspace(*walker)) 578b1ee04b1SWarner Losh walker++; 5798b823408SWarner Losh buffer = walker; 5808b823408SWarner Losh return (true); 5818b823408SWarner Losh } 5828b823408SWarner Losh 5838b823408SWarner Losh 5848b823408SWarner Losh char * 5858b823408SWarner Losh config::set_vars(char *buffer) 5868b823408SWarner Losh { 5878b823408SWarner Losh char *lhs; 5888b823408SWarner Losh char *rhs; 5898b823408SWarner Losh 5908b823408SWarner Losh while (1) { 5918b823408SWarner Losh if (!chop_var(buffer, lhs, rhs)) 5928b823408SWarner Losh break; 5938b823408SWarner Losh set_variable(lhs, rhs); 5948b823408SWarner Losh } 5958b823408SWarner Losh return (buffer); 5968b823408SWarner Losh } 5978b823408SWarner Losh 5988b823408SWarner Losh void 5998b823408SWarner Losh config::find_and_execute(char type) 6008b823408SWarner Losh { 6018b823408SWarner Losh vector<event_proc *> *l; 6028b823408SWarner Losh vector<event_proc *>::const_iterator i; 6038b823408SWarner Losh char *s; 6048b823408SWarner Losh 6058b823408SWarner Losh switch (type) { 6068b823408SWarner Losh default: 6078b823408SWarner Losh return; 6088b823408SWarner Losh case nomatch: 6098b823408SWarner Losh l = &_nomatch_list; 6108b823408SWarner Losh s = "nomatch"; 6118b823408SWarner Losh break; 6128b823408SWarner Losh case attach: 6138b823408SWarner Losh l = &_attach_list; 6148b823408SWarner Losh s = "attach"; 6158b823408SWarner Losh break; 6168b823408SWarner Losh case detach: 6178b823408SWarner Losh l = &_detach_list; 6188b823408SWarner Losh s = "detach"; 6198b823408SWarner Losh break; 6208b823408SWarner Losh } 6218b823408SWarner Losh if (dflag) 6228b823408SWarner Losh fprintf(stderr, "Processing %s event\n", s); 6238b823408SWarner Losh for (i = l->begin(); i != l->end(); i++) { 6248b823408SWarner Losh if ((*i)->matches(*this)) { 6258b823408SWarner Losh (*i)->run(*this); 6268b823408SWarner Losh break; 6278b823408SWarner Losh } 6288b823408SWarner Losh } 6298b823408SWarner Losh 6308b823408SWarner Losh } 6318b823408SWarner Losh 6323054f218SWarner Losh 6333054f218SWarner Losh static void 6348b823408SWarner Losh process_event(char *buffer) 6353054f218SWarner Losh { 6363054f218SWarner Losh char type; 6373054f218SWarner Losh char *sp; 6383054f218SWarner Losh 6398b823408SWarner Losh sp = buffer + 1; 6408b823408SWarner Losh if (dflag) 6418b823408SWarner Losh fprintf(stderr, "Processing event '%s'\n", buffer); 6423054f218SWarner Losh type = *buffer++; 6438b823408SWarner Losh cfg.push_var_table(); 6448b823408SWarner Losh // No match doesn't have a device, and the format is a little 6458b823408SWarner Losh // different, so handle it separately. 6468b823408SWarner Losh if (type != nomatch) { 6478b823408SWarner Losh sp = strchr(sp, ' '); 6483054f218SWarner Losh if (sp == NULL) 6493054f218SWarner Losh return; /* Can't happen? */ 6508b823408SWarner Losh *sp++ = '\0'; 6518b823408SWarner Losh cfg.set_variable("device-name", buffer); 6528b823408SWarner Losh if (strncmp(sp, "at ", 3) == 0) 6538b823408SWarner Losh sp += 3; 6548b823408SWarner Losh sp = cfg.set_vars(sp); 6558b823408SWarner Losh if (strncmp(sp, "on ", 3) == 0) 6568b823408SWarner Losh cfg.set_variable("bus", sp + 3); 657b1ee04b1SWarner Losh } else { 658b1ee04b1SWarner Losh //?vars at location on bus 659b1ee04b1SWarner Losh sp = cfg.set_vars(sp); 660b1ee04b1SWarner Losh if (strncmp(sp, "at ", 3) == 0) 661b1ee04b1SWarner Losh sp += 3; 662b1ee04b1SWarner Losh sp = cfg.set_vars(sp); 663b1ee04b1SWarner Losh if (strncmp(sp, "on ", 3) == 0) 664b1ee04b1SWarner Losh cfg.set_variable("bus", sp + 3); 665b1ee04b1SWarner Losh } 666b1ee04b1SWarner Losh 6678b823408SWarner Losh cfg.find_and_execute(type); 6688b823408SWarner Losh cfg.pop_var_table(); 6693054f218SWarner Losh } 6703054f218SWarner Losh 6713054f218SWarner Losh static void 6723054f218SWarner Losh event_loop(void) 6733054f218SWarner Losh { 6743054f218SWarner Losh int rv; 6753054f218SWarner Losh int fd; 6763054f218SWarner Losh char buffer[DEVCTL_MAXBUF]; 6773054f218SWarner Losh 6783054f218SWarner Losh fd = open(PATH_DEVCTL, O_RDONLY); 6793054f218SWarner Losh if (fd == -1) 6803054f218SWarner Losh err(1, "Can't open devctl"); 6813054f218SWarner Losh if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) 6823054f218SWarner Losh err(1, "Can't set close-on-exec flag"); 6833054f218SWarner Losh while (1) { 6843054f218SWarner Losh if (romeo_must_die) 6853054f218SWarner Losh break; 6863054f218SWarner Losh rv = read(fd, buffer, sizeof(buffer) - 1); 6873054f218SWarner Losh if (rv > 0) { 6883054f218SWarner Losh buffer[rv] = '\0'; 6893054f218SWarner Losh while (buffer[--rv] == '\n') 6903054f218SWarner Losh buffer[rv] = '\0'; 6913054f218SWarner Losh process_event(buffer); 6923054f218SWarner Losh } else if (rv < 0) { 6933054f218SWarner Losh if (errno != EINTR) 6943054f218SWarner Losh break; 6953054f218SWarner Losh } else { 6963054f218SWarner Losh /* EOF */ 6973054f218SWarner Losh break; 6983054f218SWarner Losh } 6993054f218SWarner Losh } 7003054f218SWarner Losh close(fd); 7013054f218SWarner Losh } 7023054f218SWarner Losh 7033054f218SWarner Losh /* 7043054f218SWarner Losh * functions that the parser uses. 7053054f218SWarner Losh */ 7063054f218SWarner Losh void 7073054f218SWarner Losh add_attach(int prio, event_proc *p) 7083054f218SWarner Losh { 7093054f218SWarner Losh cfg.add_attach(prio, p); 7103054f218SWarner Losh } 7113054f218SWarner Losh 7123054f218SWarner Losh void 7133054f218SWarner Losh add_detach(int prio, event_proc *p) 7143054f218SWarner Losh { 7153054f218SWarner Losh cfg.add_detach(prio, p); 7163054f218SWarner Losh } 7173054f218SWarner Losh 7183054f218SWarner Losh void 7193054f218SWarner Losh add_directory(const char *dir) 7203054f218SWarner Losh { 7213054f218SWarner Losh cfg.add_directory(dir); 7223054f218SWarner Losh free(const_cast<char *>(dir)); 7233054f218SWarner Losh } 7243054f218SWarner Losh 7253054f218SWarner Losh void 7263054f218SWarner Losh add_nomatch(int prio, event_proc *p) 7273054f218SWarner Losh { 7283054f218SWarner Losh cfg.add_nomatch(prio, p); 7293054f218SWarner Losh } 7303054f218SWarner Losh 7313054f218SWarner Losh event_proc * 7323054f218SWarner Losh add_to_event_proc(event_proc *ep, eps *eps) 7333054f218SWarner Losh { 7343054f218SWarner Losh if (ep == NULL) 7353054f218SWarner Losh ep = new event_proc(); 7363054f218SWarner Losh ep->add(eps); 7373054f218SWarner Losh return (ep); 7383054f218SWarner Losh } 7393054f218SWarner Losh 7403054f218SWarner Losh eps * 7413054f218SWarner Losh new_action(const char *cmd) 7423054f218SWarner Losh { 7433054f218SWarner Losh eps *e = new action(cmd); 7443054f218SWarner Losh free(const_cast<char *>(cmd)); 7453054f218SWarner Losh return (e); 7463054f218SWarner Losh } 7473054f218SWarner Losh 7483054f218SWarner Losh eps * 7493054f218SWarner Losh new_match(const char *var, const char *re) 7503054f218SWarner Losh { 7515102ef84SWarner Losh eps *e = new match(cfg, var, re); 7523054f218SWarner Losh free(const_cast<char *>(var)); 7533054f218SWarner Losh free(const_cast<char *>(re)); 7543054f218SWarner Losh return (e); 7553054f218SWarner Losh } 7563054f218SWarner Losh 7573054f218SWarner Losh void 7583054f218SWarner Losh set_pidfile(const char *name) 7593054f218SWarner Losh { 7603054f218SWarner Losh cfg.set_pidfile(name); 7613054f218SWarner Losh free(const_cast<char *>(name)); 7623054f218SWarner Losh } 7633054f218SWarner Losh 7643054f218SWarner Losh void 7653054f218SWarner Losh set_variable(const char *var, const char *val) 7663054f218SWarner Losh { 7673054f218SWarner Losh cfg.set_variable(var, val); 7683054f218SWarner Losh free(const_cast<char *>(var)); 7693054f218SWarner Losh free(const_cast<char *>(val)); 7703054f218SWarner Losh } 7713054f218SWarner Losh 7723054f218SWarner Losh 7733054f218SWarner Losh 7743054f218SWarner Losh static void 7753054f218SWarner Losh gensighand(int) 7763054f218SWarner Losh { 7773054f218SWarner Losh romeo_must_die++; 7783054f218SWarner Losh _exit(0); 7793054f218SWarner Losh } 7803054f218SWarner Losh 7813054f218SWarner Losh static void 7823054f218SWarner Losh usage() 7833054f218SWarner Losh { 7849f9bcbdeSWarner Losh fprintf(stderr, "usage: %s [-d]\n", getprogname()); 7853054f218SWarner Losh exit(1); 7863054f218SWarner Losh } 7873054f218SWarner Losh 788*9c180898SWarner Losh static void 789*9c180898SWarner Losh check_devd_enabled() 790*9c180898SWarner Losh { 791*9c180898SWarner Losh int val = 0; 792*9c180898SWarner Losh size_t len; 793*9c180898SWarner Losh 794*9c180898SWarner Losh len = sizeof(val); 795*9c180898SWarner Losh if (sysctlbyname(SYSCTL, &val, &len, NULL, NULL) != 0) 796*9c180898SWarner Losh errx(1, "devctl sysctl missing from kernel!"); 797*9c180898SWarner Losh if (val) { 798*9c180898SWarner Losh warnx("Setting " SYSCTL " to 0"); 799*9c180898SWarner Losh val = 0; 800*9c180898SWarner Losh sysctlbyname(SYSCTL, NULL, NULL, &val, sizeof(val)); 801*9c180898SWarner Losh } 802*9c180898SWarner Losh } 803*9c180898SWarner Losh 8043054f218SWarner Losh /* 8053054f218SWarner Losh * main 8063054f218SWarner Losh */ 8073054f218SWarner Losh int 8083054f218SWarner Losh main(int argc, char **argv) 8093054f218SWarner Losh { 8103054f218SWarner Losh int ch; 8113054f218SWarner Losh 812*9c180898SWarner Losh check_devd_enabled(); 8133054f218SWarner Losh while ((ch = getopt(argc, argv, "d")) != -1) { 8143054f218SWarner Losh switch (ch) { 8153054f218SWarner Losh case 'd': 8163054f218SWarner Losh dflag++; 8173054f218SWarner Losh break; 8183054f218SWarner Losh default: 8193054f218SWarner Losh usage(); 8203054f218SWarner Losh } 8213054f218SWarner Losh } 8223054f218SWarner Losh 8233054f218SWarner Losh cfg.parse(); 8243054f218SWarner Losh if (!dflag) 8253054f218SWarner Losh daemon(0, 0); 8263054f218SWarner Losh cfg.drop_pidfile(); 8273054f218SWarner Losh signal(SIGHUP, gensighand); 8283054f218SWarner Losh signal(SIGINT, gensighand); 8293054f218SWarner Losh signal(SIGTERM, gensighand); 8303054f218SWarner Losh event_loop(); 8313054f218SWarner Losh return (0); 8323054f218SWarner Losh } 833