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> 419c180898SWarner 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 596aeeca8eSWarner Losh #include "devd.h" /* C compatible definitions */ 606aeeca8eSWarner Losh #include "devd.hh" /* C++ class definitions */ 613054f218SWarner Losh 623054f218SWarner Losh #define CF "/etc/devd.conf" 639c180898SWarner Losh #define SYSCTL "hw.bus.devctl_disable" 643054f218SWarner Losh 653054f218SWarner Losh using namespace std; 663054f218SWarner Losh 673054f218SWarner Losh extern FILE *yyin; 683054f218SWarner Losh extern int lineno; 693054f218SWarner Losh 70*842ccec5SWarner Losh static const char notify = '!'; 718b823408SWarner Losh static const char nomatch = '?'; 728b823408SWarner Losh static const char attach = '+'; 738b823408SWarner Losh static const char detach = '-'; 748b823408SWarner Losh 755a882d77SWarner Losh int Dflag; 763054f218SWarner Losh int dflag; 77812f53a7SWarner Losh int nflag; 783054f218SWarner Losh int romeo_must_die = 0; 793054f218SWarner Losh 803054f218SWarner Losh static void event_loop(void); 813054f218SWarner Losh static void usage(void); 823054f218SWarner Losh 838b823408SWarner Losh template <class T> void 848b823408SWarner Losh delete_and_clear(vector<T *> &v) 858b823408SWarner Losh { 868b823408SWarner Losh typename vector<T *>::const_iterator i; 873054f218SWarner Losh 888b823408SWarner Losh for (i = v.begin(); i != v.end(); i++) 898b823408SWarner Losh delete *i; 908b823408SWarner Losh v.clear(); 918b823408SWarner Losh } 928b823408SWarner Losh 933054f218SWarner Losh config cfg; 943054f218SWarner Losh 953054f218SWarner Losh event_proc::event_proc() : _prio(-1) 963054f218SWarner Losh { 973054f218SWarner Losh // nothing 983054f218SWarner Losh } 993054f218SWarner Losh 1003054f218SWarner Losh event_proc::~event_proc() 1013054f218SWarner Losh { 1023054f218SWarner Losh vector<eps *>::const_iterator i; 1033054f218SWarner Losh 1043054f218SWarner Losh for (i = _epsvec.begin(); i != _epsvec.end(); i++) 1053054f218SWarner Losh delete *i; 1063054f218SWarner Losh _epsvec.clear(); 1073054f218SWarner Losh } 1083054f218SWarner Losh 1093054f218SWarner Losh void 1103054f218SWarner Losh event_proc::add(eps *eps) 1113054f218SWarner Losh { 1123054f218SWarner Losh _epsvec.push_back(eps); 1133054f218SWarner Losh } 1143054f218SWarner Losh 1153054f218SWarner Losh bool 1163054f218SWarner Losh event_proc::matches(config &c) 1173054f218SWarner Losh { 1183054f218SWarner Losh vector<eps *>::const_iterator i; 1193054f218SWarner Losh 1203054f218SWarner Losh for (i = _epsvec.begin(); i != _epsvec.end(); i++) 1213054f218SWarner Losh if (!(*i)->do_match(c)) 1223054f218SWarner Losh return (false); 1233054f218SWarner Losh return (true); 1243054f218SWarner Losh } 1253054f218SWarner Losh 1263054f218SWarner Losh bool 1273054f218SWarner Losh event_proc::run(config &c) 1283054f218SWarner Losh { 1293054f218SWarner Losh vector<eps *>::const_iterator i; 1303054f218SWarner Losh 1313054f218SWarner Losh for (i = _epsvec.begin(); i != _epsvec.end(); i++) 1323054f218SWarner Losh if (!(*i)->do_action(c)) 1333054f218SWarner Losh return (false); 1343054f218SWarner Losh return (true); 1353054f218SWarner Losh } 1363054f218SWarner Losh 1373054f218SWarner Losh action::action(const char *cmd) 1383054f218SWarner Losh : _cmd(cmd) 1393054f218SWarner Losh { 1403054f218SWarner Losh // nothing 1413054f218SWarner Losh } 1423054f218SWarner Losh 1433054f218SWarner Losh action::~action() 1443054f218SWarner Losh { 1453054f218SWarner Losh // nothing 1463054f218SWarner Losh } 1473054f218SWarner Losh 1483054f218SWarner Losh bool 1495102ef84SWarner Losh action::do_action(config &c) 1503054f218SWarner Losh { 1518b823408SWarner Losh string s = c.expand_string(_cmd); 1525a882d77SWarner Losh if (Dflag) 1538b823408SWarner Losh fprintf(stderr, "Executing '%s'\n", s.c_str()); 1548b823408SWarner Losh ::system(s.c_str()); 1553054f218SWarner Losh return (true); 1563054f218SWarner Losh } 1573054f218SWarner Losh 1585102ef84SWarner Losh match::match(config &c, const char *var, const char *re) 1598b823408SWarner Losh : _var(var) 1603054f218SWarner Losh { 1618b823408SWarner Losh string pattern = re; 1628b823408SWarner Losh _re = "^"; 1638b823408SWarner Losh _re.append(c.expand_string(string(re))); 1648b823408SWarner Losh _re.append("$"); 1658b823408SWarner Losh regcomp(&_regex, _re.c_str(), REG_EXTENDED | REG_NOSUB); 1663054f218SWarner Losh } 1673054f218SWarner Losh 1683054f218SWarner Losh match::~match() 1693054f218SWarner Losh { 1705102ef84SWarner Losh regfree(&_regex); 1713054f218SWarner Losh } 1723054f218SWarner Losh 1733054f218SWarner Losh bool 1745102ef84SWarner Losh match::do_match(config &c) 1753054f218SWarner Losh { 1765102ef84SWarner Losh string value = c.get_variable(_var); 1775102ef84SWarner Losh bool retval; 1785102ef84SWarner Losh 1795a882d77SWarner Losh if (Dflag) 1808b823408SWarner Losh fprintf(stderr, "Testing %s=%s against %s\n", _var.c_str(), 1818b823408SWarner Losh value.c_str(), _re.c_str()); 1828b823408SWarner Losh 1835102ef84SWarner Losh retval = (regexec(&_regex, value.c_str(), 0, NULL, 0) == 0); 1845102ef84SWarner Losh return retval; 1853054f218SWarner Losh } 1863054f218SWarner Losh 1873054f218SWarner Losh const string var_list::bogus = "_$_$_$_$_B_O_G_U_S_$_$_$_$_"; 1883054f218SWarner Losh const string var_list::nothing = ""; 1893054f218SWarner Losh 1903054f218SWarner Losh const string & 1913054f218SWarner Losh var_list::get_variable(const string &var) const 1923054f218SWarner Losh { 1933054f218SWarner Losh map<string, string>::const_iterator i; 1943054f218SWarner Losh 1953054f218SWarner Losh i = _vars.find(var); 1963054f218SWarner Losh if (i == _vars.end()) 1978b823408SWarner Losh return (var_list::bogus); 1983054f218SWarner Losh return (i->second); 1993054f218SWarner Losh } 2003054f218SWarner Losh 2013054f218SWarner Losh bool 2023054f218SWarner Losh var_list::is_set(const string &var) const 2033054f218SWarner Losh { 2043054f218SWarner Losh return (_vars.find(var) != _vars.end()); 2053054f218SWarner Losh } 2063054f218SWarner Losh 2073054f218SWarner Losh void 2083054f218SWarner Losh var_list::set_variable(const string &var, const string &val) 2093054f218SWarner Losh { 2105a882d77SWarner Losh if (Dflag) 2118b823408SWarner Losh fprintf(stderr, "%s=%s\n", var.c_str(), val.c_str()); 2123054f218SWarner Losh _vars[var] = val; 2133054f218SWarner Losh } 2143054f218SWarner Losh 2153054f218SWarner Losh void 2163054f218SWarner Losh config::reset(void) 2173054f218SWarner Losh { 2183054f218SWarner Losh _dir_list.clear(); 2198b823408SWarner Losh delete_and_clear(_var_list_table); 2208b823408SWarner Losh delete_and_clear(_attach_list); 2218b823408SWarner Losh delete_and_clear(_detach_list); 2228b823408SWarner Losh delete_and_clear(_nomatch_list); 223*842ccec5SWarner Losh delete_and_clear(_notify_list); 2243054f218SWarner Losh } 2253054f218SWarner Losh 2263054f218SWarner Losh void 2273054f218SWarner Losh config::parse_one_file(const char *fn) 2283054f218SWarner Losh { 2295a882d77SWarner Losh if (Dflag) 2303054f218SWarner Losh printf("Parsing %s\n", fn); 2313054f218SWarner Losh yyin = fopen(fn, "r"); 2323054f218SWarner Losh if (yyin == NULL) 2333054f218SWarner Losh err(1, "Cannot open config file %s", fn); 2343054f218SWarner Losh if (yyparse() != 0) 2353054f218SWarner Losh errx(1, "Cannot parse %s at line %d", fn, lineno); 2363054f218SWarner Losh fclose(yyin); 2373054f218SWarner Losh } 2383054f218SWarner Losh 2393054f218SWarner Losh void 2403054f218SWarner Losh config::parse_files_in_dir(const char *dirname) 2413054f218SWarner Losh { 2423054f218SWarner Losh DIR *dirp; 2433054f218SWarner Losh struct dirent *dp; 2443054f218SWarner Losh char path[PATH_MAX]; 2453054f218SWarner Losh 2465a882d77SWarner Losh if (Dflag) 2473054f218SWarner Losh printf("Parsing files in %s\n", dirname); 2483054f218SWarner Losh dirp = opendir(dirname); 2493054f218SWarner Losh if (dirp == NULL) 2503054f218SWarner Losh return; 2513054f218SWarner Losh readdir(dirp); /* Skip . */ 2523054f218SWarner Losh readdir(dirp); /* Skip .. */ 2533054f218SWarner Losh while ((dp = readdir(dirp)) != NULL) { 2543054f218SWarner Losh if (strcmp(dp->d_name + dp->d_namlen - 5, ".conf") == 0) { 2553054f218SWarner Losh snprintf(path, sizeof(path), "%s/%s", 2563054f218SWarner Losh dirname, dp->d_name); 2573054f218SWarner Losh parse_one_file(path); 2583054f218SWarner Losh } 2593054f218SWarner Losh } 2603054f218SWarner Losh } 2613054f218SWarner Losh 2628b823408SWarner Losh class epv_greater { 2638b823408SWarner Losh public: 2648b823408SWarner Losh int operator()(event_proc *const&l1, event_proc *const&l2) 2658b823408SWarner Losh { 2668b823408SWarner Losh return (l1->get_priority() > l2->get_priority()); 2678b823408SWarner Losh } 2688b823408SWarner Losh }; 2698b823408SWarner Losh 2708b823408SWarner Losh void 2718b823408SWarner Losh config::sort_vector(vector<event_proc *> &v) 2728b823408SWarner Losh { 2738b823408SWarner Losh sort(v.begin(), v.end(), epv_greater()); 2748b823408SWarner Losh } 2758b823408SWarner Losh 2763054f218SWarner Losh void 2773054f218SWarner Losh config::parse(void) 2783054f218SWarner Losh { 2793054f218SWarner Losh vector<string>::const_iterator i; 2803054f218SWarner Losh 2813054f218SWarner Losh parse_one_file(CF); 2823054f218SWarner Losh for (i = _dir_list.begin(); i != _dir_list.end(); i++) 2833054f218SWarner Losh parse_files_in_dir((*i).c_str()); 2848b823408SWarner Losh sort_vector(_attach_list); 2858b823408SWarner Losh sort_vector(_detach_list); 2868b823408SWarner Losh sort_vector(_nomatch_list); 287*842ccec5SWarner Losh sort_vector(_notify_list); 2883054f218SWarner Losh } 2893054f218SWarner Losh 2903054f218SWarner Losh void 2913054f218SWarner Losh config::drop_pidfile() 2923054f218SWarner Losh { 2933054f218SWarner Losh FILE *fp; 2943054f218SWarner Losh 2953054f218SWarner Losh if (_pidfile == "") 2963054f218SWarner Losh return; 2973054f218SWarner Losh fp = fopen(_pidfile.c_str(), "w"); 2983054f218SWarner Losh if (fp == NULL) 2993054f218SWarner Losh return; 3003054f218SWarner Losh fprintf(fp, "%d\n", getpid()); 3013054f218SWarner Losh fclose(fp); 3023054f218SWarner Losh } 3033054f218SWarner Losh 3043054f218SWarner Losh void 3053054f218SWarner Losh config::add_attach(int prio, event_proc *p) 3063054f218SWarner Losh { 3073054f218SWarner Losh p->set_priority(prio); 3083054f218SWarner Losh _attach_list.push_back(p); 3093054f218SWarner Losh } 3103054f218SWarner Losh 3113054f218SWarner Losh void 3123054f218SWarner Losh config::add_detach(int prio, event_proc *p) 3133054f218SWarner Losh { 3143054f218SWarner Losh p->set_priority(prio); 3153054f218SWarner Losh _detach_list.push_back(p); 3163054f218SWarner Losh } 3173054f218SWarner Losh 3183054f218SWarner Losh void 3193054f218SWarner Losh config::add_directory(const char *dir) 3203054f218SWarner Losh { 3213054f218SWarner Losh _dir_list.push_back(string(dir)); 3223054f218SWarner Losh } 3233054f218SWarner Losh 3243054f218SWarner Losh void 3253054f218SWarner Losh config::add_nomatch(int prio, event_proc *p) 3263054f218SWarner Losh { 3273054f218SWarner Losh p->set_priority(prio); 3283054f218SWarner Losh _nomatch_list.push_back(p); 3293054f218SWarner Losh } 3303054f218SWarner Losh 3313054f218SWarner Losh void 332*842ccec5SWarner Losh config::add_notify(int prio, event_proc *p) 333*842ccec5SWarner Losh { 334*842ccec5SWarner Losh p->set_priority(prio); 335*842ccec5SWarner Losh _notify_list.push_back(p); 336*842ccec5SWarner Losh } 337*842ccec5SWarner Losh 338*842ccec5SWarner Losh void 3393054f218SWarner Losh config::set_pidfile(const char *fn) 3403054f218SWarner Losh { 3413054f218SWarner Losh _pidfile = string(fn); 3423054f218SWarner Losh } 3433054f218SWarner Losh 3443054f218SWarner Losh void 3453054f218SWarner Losh config::push_var_table() 3463054f218SWarner Losh { 3473054f218SWarner Losh var_list *vl; 3483054f218SWarner Losh 3493054f218SWarner Losh vl = new var_list(); 3503054f218SWarner Losh _var_list_table.push_back(vl); 3515a882d77SWarner Losh if (Dflag) 3528b823408SWarner Losh fprintf(stderr, "Pushing table\n"); 3533054f218SWarner Losh } 3543054f218SWarner Losh 3553054f218SWarner Losh void 3563054f218SWarner Losh config::pop_var_table() 3573054f218SWarner Losh { 3583054f218SWarner Losh delete _var_list_table.back(); 3593054f218SWarner Losh _var_list_table.pop_back(); 3605a882d77SWarner Losh if (Dflag) 3618b823408SWarner Losh fprintf(stderr, "Popping table\n"); 3623054f218SWarner Losh } 3633054f218SWarner Losh 3643054f218SWarner Losh void 3653054f218SWarner Losh config::set_variable(const char *var, const char *val) 3663054f218SWarner Losh { 3673054f218SWarner Losh _var_list_table.back()->set_variable(var, val); 3683054f218SWarner Losh } 3693054f218SWarner Losh 3703054f218SWarner Losh const string & 3713054f218SWarner Losh config::get_variable(const string &var) 3723054f218SWarner Losh { 3733054f218SWarner Losh vector<var_list *>::reverse_iterator i; 3743054f218SWarner Losh 3753054f218SWarner Losh for (i = _var_list_table.rbegin(); i != _var_list_table.rend(); i++) { 3763054f218SWarner Losh if ((*i)->is_set(var)) 3778b823408SWarner Losh return ((*i)->get_variable(var)); 3783054f218SWarner Losh } 3793054f218SWarner Losh return (var_list::nothing); 3803054f218SWarner Losh } 3813054f218SWarner Losh 3828b823408SWarner Losh bool 3838b823408SWarner Losh config::is_id_char(char ch) 3848b823408SWarner Losh { 3858b823408SWarner Losh return (ch != '\0' && (isalpha(ch) || isdigit(ch) || ch == '_' || 3868b823408SWarner Losh ch == '-')); 3878b823408SWarner Losh } 3888b823408SWarner Losh 3895102ef84SWarner Losh void 3906cabd675SWarner Losh config::expand_one(const char *&src, string &dst) 3913054f218SWarner Losh { 3925102ef84SWarner Losh int count; 3936cabd675SWarner Losh string buffer, varstr; 3945102ef84SWarner Losh 3958b823408SWarner Losh src++; 3965102ef84SWarner Losh // $$ -> $ 3975102ef84SWarner Losh if (*src == '$') { 3986cabd675SWarner Losh dst.append(src++, 1); 3995102ef84SWarner Losh return; 4005102ef84SWarner Losh } 4015102ef84SWarner Losh 4025102ef84SWarner Losh // $(foo) -> $(foo) 4038b823408SWarner Losh // Not sure if I want to support this or not, so for now we just pass 4048b823408SWarner Losh // it through. 4055102ef84SWarner Losh if (*src == '(') { 4066cabd675SWarner Losh dst.append("$"); 4075102ef84SWarner Losh count = 1; 4086cabd675SWarner Losh /* If the string ends before ) is matched , return. */ 4096cabd675SWarner Losh while (count > 0 && *src) { 4105102ef84SWarner Losh if (*src == ')') 4115102ef84SWarner Losh count--; 4125102ef84SWarner Losh else if (*src == '(') 4135102ef84SWarner Losh count++; 4146cabd675SWarner Losh dst.append(src++, 1); 4155102ef84SWarner Losh } 4165102ef84SWarner Losh return; 4175102ef84SWarner Losh } 4185102ef84SWarner Losh 4195102ef84SWarner Losh // ${^A-Za-z] -> $\1 4205102ef84SWarner Losh if (!isalpha(*src)) { 4216cabd675SWarner Losh dst.append("$"); 4226cabd675SWarner Losh dst.append(src++, 1); 4235102ef84SWarner Losh return; 4245102ef84SWarner Losh } 4255102ef84SWarner Losh 4265102ef84SWarner Losh // $var -> replace with value 4276cabd675SWarner Losh do { 4286cabd675SWarner Losh buffer.append(src++, 1); 42966ff6821SWarner Losh } while (is_id_char(*src)); 4306cabd675SWarner Losh buffer.append("", 1); 4316cabd675SWarner Losh varstr = get_variable(buffer.c_str()); 4326cabd675SWarner Losh dst.append(varstr); 4335102ef84SWarner Losh } 4345102ef84SWarner Losh 4355102ef84SWarner Losh const string 4365102ef84SWarner Losh config::expand_string(const string &s) 4375102ef84SWarner Losh { 4385102ef84SWarner Losh const char *src; 4396cabd675SWarner Losh string dst; 4405102ef84SWarner Losh 4415102ef84SWarner Losh src = s.c_str(); 4425102ef84SWarner Losh while (*src) { 4435102ef84SWarner Losh if (*src == '$') 4446cabd675SWarner Losh expand_one(src, dst); 4455102ef84SWarner Losh else 4466cabd675SWarner Losh dst.append(src++, 1); 4475102ef84SWarner Losh } 4486cabd675SWarner Losh dst.append("", 1); 4495102ef84SWarner Losh 4506cabd675SWarner Losh return (dst); 4513054f218SWarner Losh } 4523054f218SWarner Losh 4538b823408SWarner Losh bool 4548b823408SWarner Losh config::chop_var(char *&buffer, char *&lhs, char *&rhs) 4558b823408SWarner Losh { 4568b823408SWarner Losh char *walker; 4578b823408SWarner Losh 4588b823408SWarner Losh if (*buffer == '\0') 4598b823408SWarner Losh return (false); 4608b823408SWarner Losh walker = lhs = buffer; 4618b823408SWarner Losh while (is_id_char(*walker)) 4628b823408SWarner Losh walker++; 4638b823408SWarner Losh if (*walker != '=') 4648b823408SWarner Losh return (false); 4658b823408SWarner Losh walker++; // skip = 4668b823408SWarner Losh if (*walker == '"') { 4678b823408SWarner Losh walker++; // skip " 4688b823408SWarner Losh rhs = walker; 4698b823408SWarner Losh while (*walker && *walker != '"') 4708b823408SWarner Losh walker++; 4718b823408SWarner Losh if (*walker != '"') 4728b823408SWarner Losh return (false); 4738b823408SWarner Losh rhs[-2] = '\0'; 4748b823408SWarner Losh *walker++ = '\0'; 4758b823408SWarner Losh } else { 4768b823408SWarner Losh rhs = walker; 4778b823408SWarner Losh while (*walker && !isspace(*walker)) 4788b823408SWarner Losh walker++; 4798b823408SWarner Losh if (*walker != '\0') 4808b823408SWarner Losh *walker++ = '\0'; 4818b823408SWarner Losh rhs[-1] = '\0'; 4828b823408SWarner Losh } 483b1ee04b1SWarner Losh while (isspace(*walker)) 484b1ee04b1SWarner Losh walker++; 4858b823408SWarner Losh buffer = walker; 4868b823408SWarner Losh return (true); 4878b823408SWarner Losh } 4888b823408SWarner Losh 4898b823408SWarner Losh 4908b823408SWarner Losh char * 4918b823408SWarner Losh config::set_vars(char *buffer) 4928b823408SWarner Losh { 4938b823408SWarner Losh char *lhs; 4948b823408SWarner Losh char *rhs; 4958b823408SWarner Losh 4968b823408SWarner Losh while (1) { 4978b823408SWarner Losh if (!chop_var(buffer, lhs, rhs)) 4988b823408SWarner Losh break; 4998b823408SWarner Losh set_variable(lhs, rhs); 5008b823408SWarner Losh } 5018b823408SWarner Losh return (buffer); 5028b823408SWarner Losh } 5038b823408SWarner Losh 5048b823408SWarner Losh void 5058b823408SWarner Losh config::find_and_execute(char type) 5068b823408SWarner Losh { 5078b823408SWarner Losh vector<event_proc *> *l; 5088b823408SWarner Losh vector<event_proc *>::const_iterator i; 5098b823408SWarner Losh char *s; 5108b823408SWarner Losh 5118b823408SWarner Losh switch (type) { 5128b823408SWarner Losh default: 5138b823408SWarner Losh return; 514*842ccec5SWarner Losh case notify: 515*842ccec5SWarner Losh l = &_notify_list; 516*842ccec5SWarner Losh s = "notify"; 517*842ccec5SWarner Losh break; 5188b823408SWarner Losh case nomatch: 5198b823408SWarner Losh l = &_nomatch_list; 5208b823408SWarner Losh s = "nomatch"; 5218b823408SWarner Losh break; 5228b823408SWarner Losh case attach: 5238b823408SWarner Losh l = &_attach_list; 5248b823408SWarner Losh s = "attach"; 5258b823408SWarner Losh break; 5268b823408SWarner Losh case detach: 5278b823408SWarner Losh l = &_detach_list; 5288b823408SWarner Losh s = "detach"; 5298b823408SWarner Losh break; 5308b823408SWarner Losh } 5315a882d77SWarner Losh if (Dflag) 5328b823408SWarner Losh fprintf(stderr, "Processing %s event\n", s); 5338b823408SWarner Losh for (i = l->begin(); i != l->end(); i++) { 5348b823408SWarner Losh if ((*i)->matches(*this)) { 5358b823408SWarner Losh (*i)->run(*this); 5368b823408SWarner Losh break; 5378b823408SWarner Losh } 5388b823408SWarner Losh } 5398b823408SWarner Losh 5408b823408SWarner Losh } 5418b823408SWarner Losh 5423054f218SWarner Losh 5433054f218SWarner Losh static void 5448b823408SWarner Losh process_event(char *buffer) 5453054f218SWarner Losh { 5463054f218SWarner Losh char type; 5473054f218SWarner Losh char *sp; 5483054f218SWarner Losh 5498b823408SWarner Losh sp = buffer + 1; 5505a882d77SWarner Losh if (Dflag) 5518b823408SWarner Losh fprintf(stderr, "Processing event '%s'\n", buffer); 5523054f218SWarner Losh type = *buffer++; 5538b823408SWarner Losh cfg.push_var_table(); 5548b823408SWarner Losh // No match doesn't have a device, and the format is a little 5558b823408SWarner Losh // different, so handle it separately. 556*842ccec5SWarner Losh switch (type) { 557*842ccec5SWarner Losh case notify: 558*842ccec5SWarner Losh sp = cfg.set_vars(sp); 559*842ccec5SWarner Losh break; 560*842ccec5SWarner Losh case nomatch: 561*842ccec5SWarner Losh //?vars at location on bus 562*842ccec5SWarner Losh sp = cfg.set_vars(sp); 563*842ccec5SWarner Losh if (strncmp(sp, "at ", 3) == 0) 564*842ccec5SWarner Losh sp += 3; 565*842ccec5SWarner Losh sp = cfg.set_vars(sp); 566*842ccec5SWarner Losh if (strncmp(sp, "on ", 3) == 0) 567*842ccec5SWarner Losh cfg.set_variable("bus", sp + 3); 568*842ccec5SWarner Losh break; 569*842ccec5SWarner Losh case attach: /*FALLTHROUGH*/ 570*842ccec5SWarner Losh case detach: 5718b823408SWarner Losh sp = strchr(sp, ' '); 5723054f218SWarner Losh if (sp == NULL) 5733054f218SWarner Losh return; /* Can't happen? */ 5748b823408SWarner Losh *sp++ = '\0'; 5758b823408SWarner Losh cfg.set_variable("device-name", buffer); 5768b823408SWarner Losh if (strncmp(sp, "at ", 3) == 0) 5778b823408SWarner Losh sp += 3; 5788b823408SWarner Losh sp = cfg.set_vars(sp); 5798b823408SWarner Losh if (strncmp(sp, "on ", 3) == 0) 5808b823408SWarner Losh cfg.set_variable("bus", sp + 3); 581*842ccec5SWarner Losh break; 582b1ee04b1SWarner Losh } 583b1ee04b1SWarner Losh 5848b823408SWarner Losh cfg.find_and_execute(type); 5858b823408SWarner Losh cfg.pop_var_table(); 5863054f218SWarner Losh } 5873054f218SWarner Losh 5883054f218SWarner Losh static void 5893054f218SWarner Losh event_loop(void) 5903054f218SWarner Losh { 5913054f218SWarner Losh int rv; 5923054f218SWarner Losh int fd; 5933054f218SWarner Losh char buffer[DEVCTL_MAXBUF]; 5945a882d77SWarner Losh int once = 0; 5955a882d77SWarner Losh timeval tv; 5965a882d77SWarner Losh fd_set fds; 5973054f218SWarner Losh 5983054f218SWarner Losh fd = open(PATH_DEVCTL, O_RDONLY); 5993054f218SWarner Losh if (fd == -1) 6003054f218SWarner Losh err(1, "Can't open devctl"); 6013054f218SWarner Losh if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) 6023054f218SWarner Losh err(1, "Can't set close-on-exec flag"); 6033054f218SWarner Losh while (1) { 6043054f218SWarner Losh if (romeo_must_die) 6053054f218SWarner Losh break; 6065a882d77SWarner Losh if (!once && !dflag && !nflag) { 6075a882d77SWarner Losh // Check to see if we have any events pending. 6085a882d77SWarner Losh tv.tv_sec = 0; 6095a882d77SWarner Losh tv.tv_usec = 0; 6105a882d77SWarner Losh FD_ZERO(&fds); 6115a882d77SWarner Losh FD_SET(fd, &fds); 6125a882d77SWarner Losh rv = select(fd + 1, &fds, &fds, &fds, &tv); 6135a882d77SWarner Losh // No events -> we've processed all pending events 614f3059505SWarner Losh if (rv == 0) { 6155a882d77SWarner Losh if (Dflag) 6165a882d77SWarner Losh fprintf(stderr, "Calling daemon\n"); 6175a882d77SWarner Losh daemon(0, 0); 618fd6a8f23SWarner Losh cfg.drop_pidfile(); 6195a882d77SWarner Losh once++; 6205a882d77SWarner Losh } 6215a882d77SWarner Losh } 6223054f218SWarner Losh rv = read(fd, buffer, sizeof(buffer) - 1); 6233054f218SWarner Losh if (rv > 0) { 6243054f218SWarner Losh buffer[rv] = '\0'; 6253054f218SWarner Losh while (buffer[--rv] == '\n') 6263054f218SWarner Losh buffer[rv] = '\0'; 6273054f218SWarner Losh process_event(buffer); 6283054f218SWarner Losh } else if (rv < 0) { 6293054f218SWarner Losh if (errno != EINTR) 6303054f218SWarner Losh break; 6313054f218SWarner Losh } else { 6323054f218SWarner Losh /* EOF */ 6333054f218SWarner Losh break; 6343054f218SWarner Losh } 6353054f218SWarner Losh } 6363054f218SWarner Losh close(fd); 6373054f218SWarner Losh } 6383054f218SWarner Losh 6393054f218SWarner Losh /* 6403054f218SWarner Losh * functions that the parser uses. 6413054f218SWarner Losh */ 6423054f218SWarner Losh void 6433054f218SWarner Losh add_attach(int prio, event_proc *p) 6443054f218SWarner Losh { 6453054f218SWarner Losh cfg.add_attach(prio, p); 6463054f218SWarner Losh } 6473054f218SWarner Losh 6483054f218SWarner Losh void 6493054f218SWarner Losh add_detach(int prio, event_proc *p) 6503054f218SWarner Losh { 6513054f218SWarner Losh cfg.add_detach(prio, p); 6523054f218SWarner Losh } 6533054f218SWarner Losh 6543054f218SWarner Losh void 6553054f218SWarner Losh add_directory(const char *dir) 6563054f218SWarner Losh { 6573054f218SWarner Losh cfg.add_directory(dir); 6583054f218SWarner Losh free(const_cast<char *>(dir)); 6593054f218SWarner Losh } 6603054f218SWarner Losh 6613054f218SWarner Losh void 6623054f218SWarner Losh add_nomatch(int prio, event_proc *p) 6633054f218SWarner Losh { 6643054f218SWarner Losh cfg.add_nomatch(prio, p); 6653054f218SWarner Losh } 6663054f218SWarner Losh 667*842ccec5SWarner Losh void 668*842ccec5SWarner Losh add_notify(int prio, event_proc *p) 669*842ccec5SWarner Losh { 670*842ccec5SWarner Losh cfg.add_notify(prio, p); 671*842ccec5SWarner Losh } 672*842ccec5SWarner Losh 6733054f218SWarner Losh event_proc * 6743054f218SWarner Losh add_to_event_proc(event_proc *ep, eps *eps) 6753054f218SWarner Losh { 6763054f218SWarner Losh if (ep == NULL) 6773054f218SWarner Losh ep = new event_proc(); 6783054f218SWarner Losh ep->add(eps); 6793054f218SWarner Losh return (ep); 6803054f218SWarner Losh } 6813054f218SWarner Losh 6823054f218SWarner Losh eps * 6833054f218SWarner Losh new_action(const char *cmd) 6843054f218SWarner Losh { 6853054f218SWarner Losh eps *e = new action(cmd); 6863054f218SWarner Losh free(const_cast<char *>(cmd)); 6873054f218SWarner Losh return (e); 6883054f218SWarner Losh } 6893054f218SWarner Losh 6903054f218SWarner Losh eps * 6913054f218SWarner Losh new_match(const char *var, const char *re) 6923054f218SWarner Losh { 6935102ef84SWarner Losh eps *e = new match(cfg, var, re); 6943054f218SWarner Losh free(const_cast<char *>(var)); 6953054f218SWarner Losh free(const_cast<char *>(re)); 6963054f218SWarner Losh return (e); 6973054f218SWarner Losh } 6983054f218SWarner Losh 6993054f218SWarner Losh void 7003054f218SWarner Losh set_pidfile(const char *name) 7013054f218SWarner Losh { 7023054f218SWarner Losh cfg.set_pidfile(name); 7033054f218SWarner Losh free(const_cast<char *>(name)); 7043054f218SWarner Losh } 7053054f218SWarner Losh 7063054f218SWarner Losh void 7073054f218SWarner Losh set_variable(const char *var, const char *val) 7083054f218SWarner Losh { 7093054f218SWarner Losh cfg.set_variable(var, val); 7103054f218SWarner Losh free(const_cast<char *>(var)); 7113054f218SWarner Losh free(const_cast<char *>(val)); 7123054f218SWarner Losh } 7133054f218SWarner Losh 7143054f218SWarner Losh 7153054f218SWarner Losh 7163054f218SWarner Losh static void 7173054f218SWarner Losh gensighand(int) 7183054f218SWarner Losh { 7193054f218SWarner Losh romeo_must_die++; 7203054f218SWarner Losh _exit(0); 7213054f218SWarner Losh } 7223054f218SWarner Losh 7233054f218SWarner Losh static void 7243054f218SWarner Losh usage() 7253054f218SWarner Losh { 7269f9bcbdeSWarner Losh fprintf(stderr, "usage: %s [-d]\n", getprogname()); 7273054f218SWarner Losh exit(1); 7283054f218SWarner Losh } 7293054f218SWarner Losh 7309c180898SWarner Losh static void 7319c180898SWarner Losh check_devd_enabled() 7329c180898SWarner Losh { 7339c180898SWarner Losh int val = 0; 7349c180898SWarner Losh size_t len; 7359c180898SWarner Losh 7369c180898SWarner Losh len = sizeof(val); 73779f92e25SWarner Losh if (sysctlbyname(SYSCTL, &val, &len, NULL, 0) != 0) 7389c180898SWarner Losh errx(1, "devctl sysctl missing from kernel!"); 7399c180898SWarner Losh if (val) { 7409c180898SWarner Losh warnx("Setting " SYSCTL " to 0"); 7419c180898SWarner Losh val = 0; 7429c180898SWarner Losh sysctlbyname(SYSCTL, NULL, NULL, &val, sizeof(val)); 7439c180898SWarner Losh } 7449c180898SWarner Losh } 7459c180898SWarner Losh 7463054f218SWarner Losh /* 7473054f218SWarner Losh * main 7483054f218SWarner Losh */ 7493054f218SWarner Losh int 7503054f218SWarner Losh main(int argc, char **argv) 7513054f218SWarner Losh { 7523054f218SWarner Losh int ch; 7533054f218SWarner Losh 7549c180898SWarner Losh check_devd_enabled(); 7555a882d77SWarner Losh while ((ch = getopt(argc, argv, "Ddn")) != -1) { 7563054f218SWarner Losh switch (ch) { 7575a882d77SWarner Losh case 'D': 7585a882d77SWarner Losh Dflag++; 7595a882d77SWarner Losh break; 7603054f218SWarner Losh case 'd': 7613054f218SWarner Losh dflag++; 7623054f218SWarner Losh break; 7635a882d77SWarner Losh case 'n': 7645a882d77SWarner Losh nflag++; 7655a882d77SWarner Losh break; 7663054f218SWarner Losh default: 7673054f218SWarner Losh usage(); 7683054f218SWarner Losh } 7693054f218SWarner Losh } 7703054f218SWarner Losh 7713054f218SWarner Losh cfg.parse(); 772fd6a8f23SWarner Losh if (!dflag && nflag) { 7733054f218SWarner Losh daemon(0, 0); 7743054f218SWarner Losh cfg.drop_pidfile(); 775fd6a8f23SWarner Losh } 7763054f218SWarner Losh signal(SIGHUP, gensighand); 7773054f218SWarner Losh signal(SIGINT, gensighand); 7783054f218SWarner Losh signal(SIGTERM, gensighand); 7793054f218SWarner Losh event_loop(); 7803054f218SWarner Losh return (0); 7813054f218SWarner Losh } 782