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