devd.cc revision 108799
1107665Simp/*- 2107665Simp * Copyright (c) 2002 M. Warner Losh. 3107665Simp * All rights reserved. 4107665Simp * 5107665Simp * Redistribution and use in source and binary forms, with or without 6107665Simp * modification, are permitted provided that the following conditions 7107665Simp * are met: 8107665Simp * 1. Redistributions of source code must retain the above copyright 9107665Simp * notice, this list of conditions and the following disclaimer. 10107665Simp * 2. Redistributions in binary form must reproduce the above copyright 11107665Simp * notice, this list of conditions and the following disclaimer in the 12107665Simp * documentation and/or other materials provided with the distribution. 13107665Simp * 14107665Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15107665Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16107665Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17107665Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18107665Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19107665Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20107665Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21107665Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22107665Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23107665Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24107665Simp * SUCH DAMAGE. 25107665Simp */ 26107665Simp 27107665Simp/* 28107665Simp * DEVD control daemon. 29107665Simp */ 30107665Simp 31107665Simp// TODO list: 32107665Simp// o devd.conf and devd man pages need a lot of help: 33107665Simp// - devd.conf needs to lose the warning about zone files. 34107665Simp// - devd.conf needs more details on the supported statements. 35107665Simp// - devd.conf needs an example or two. 36107665Simp 37107665Simp#include <sys/cdefs.h> 38107665Simp__FBSDID("$FreeBSD: head/sbin/devd/devd.cc 108799 2003-01-06 16:46:25Z imp $"); 39107665Simp 40107665Simp#include <sys/param.h> 41107665Simp#include <sys/types.h> 42107665Simp 43108014Simp#include <ctype.h> 44107665Simp#include <dirent.h> 45107665Simp#include <errno.h> 46107665Simp#include <err.h> 47107665Simp#include <fcntl.h> 48108014Simp#include <regex.h> 49107665Simp#include <stdlib.h> 50107665Simp#include <stdio.h> 51107665Simp#include <string.h> 52107665Simp#include <unistd.h> 53107665Simp 54108783Simp#include <algorithm> 55107665Simp#include <map> 56107665Simp#include <string> 57107665Simp#include <vector> 58107665Simp 59107665Simp#include "devd.h" 60107665Simp 61107665Simp#define CF "/etc/devd.conf" 62107665Simp 63107665Simpusing namespace std; 64107665Simp 65107665Simpextern FILE *yyin; 66107665Simpextern int lineno; 67107665Simp 68108783Simpstatic const char nomatch = '?'; 69108783Simpstatic const char attach = '+'; 70108783Simpstatic const char detach = '-'; 71108783Simp 72107665Simpint dflag; 73107665Simpint romeo_must_die = 0; 74107665Simp 75107665Simpstatic void event_loop(void); 76107665Simpstatic void usage(void); 77107665Simp 78108783Simptemplate <class T> void 79108783Simpdelete_and_clear(vector<T *> &v) 80108783Simp{ 81108783Simp typename vector<T *>::const_iterator i; 82108783Simp 83108783Simp for (i = v.begin(); i != v.end(); i++) 84108783Simp delete *i; 85108783Simp v.clear(); 86108783Simp} 87108783Simp 88107665Simpclass config; 89107665Simp 90107665Simpclass var_list 91107665Simp{ 92107665Simppublic: 93107665Simp var_list() {} 94107665Simp virtual ~var_list() {} 95107665Simp void set_variable(const string &var, const string &val); 96107665Simp const string &get_variable(const string &var) const; 97107665Simp bool is_set(const string &var) const; 98107665Simp static const string bogus; 99107665Simp static const string nothing; 100107665Simpprivate: 101107665Simp map<string, string> _vars; 102107665Simp}; 103107665Simp 104107665Simpclass eps 105107665Simp{ 106107665Simppublic: 107107665Simp eps() {} 108107665Simp virtual ~eps() {} 109107665Simp virtual bool do_match(config &) = 0; 110107665Simp virtual bool do_action(config &) = 0; 111107665Simp}; 112107665Simp 113107665Simpclass match : public eps 114107665Simp{ 115107665Simppublic: 116108014Simp match(config &, const char *var, const char *re); 117107665Simp virtual ~match(); 118107665Simp virtual bool do_match(config &); 119107665Simp virtual bool do_action(config &) { return true; } 120107665Simpprivate: 121107665Simp string _var; 122107665Simp string _re; 123108014Simp regex_t _regex; 124107665Simp}; 125107665Simp 126107665Simpclass action : public eps 127107665Simp{ 128107665Simppublic: 129107665Simp action(const char *cmd); 130107665Simp virtual ~action(); 131107665Simp virtual bool do_match(config &) { return true; } 132107665Simp virtual bool do_action(config &); 133107665Simpprivate: 134107665Simp string _cmd; 135107665Simp}; 136107665Simp 137107665Simpclass event_proc 138107665Simp{ 139107665Simppublic: 140107665Simp event_proc(); 141107665Simp virtual ~event_proc(); 142108783Simp int get_priority() const { return (_prio); } 143107665Simp void set_priority(int prio) { _prio = prio; } 144107665Simp void add(eps *); 145107665Simp bool matches(config &); 146107665Simp bool run(config &); 147107665Simpprivate: 148107665Simp int _prio; 149107665Simp vector<eps *> _epsvec; 150107665Simp}; 151107665Simp 152107665Simpclass config 153107665Simp{ 154107665Simppublic: 155107665Simp config() : _pidfile("") { push_var_table(); } 156107665Simp virtual ~config() { reset(); } 157107665Simp void add_attach(int, event_proc *); 158107665Simp void add_detach(int, event_proc *); 159107665Simp void add_directory(const char *); 160107665Simp void add_nomatch(int, event_proc *); 161107665Simp void set_pidfile(const char *); 162107665Simp void reset(); 163107665Simp void parse(); 164107665Simp void drop_pidfile(); 165107665Simp void push_var_table(); 166107665Simp void pop_var_table(); 167107665Simp void set_variable(const char *var, const char *val); 168107665Simp const string &get_variable(const string &var); 169108014Simp const string expand_string(const string &var); 170108783Simp char *set_vars(char *); 171108783Simp void find_and_execute(char); 172107665Simpprotected: 173108783Simp void sort_vector(vector<event_proc *> &); 174107665Simp void parse_one_file(const char *fn); 175107665Simp void parse_files_in_dir(const char *dirname); 176108014Simp void expand_one(const char *&src, char *&dst, char *eod); 177108783Simp bool is_id_char(char); 178108783Simp bool chop_var(char *&buffer, char *&lhs, char *&rhs); 179107665Simpprivate: 180107665Simp vector<string> _dir_list; 181107665Simp string _pidfile; 182107665Simp vector<var_list *> _var_list_table; 183107665Simp vector<event_proc *> _attach_list; 184107665Simp vector<event_proc *> _detach_list; 185107665Simp vector<event_proc *> _nomatch_list; 186107665Simp}; 187107665Simp 188107665Simpconfig cfg; 189107665Simp 190107665Simpevent_proc::event_proc() : _prio(-1) 191107665Simp{ 192107665Simp // nothing 193107665Simp} 194107665Simp 195107665Simpevent_proc::~event_proc() 196107665Simp{ 197107665Simp vector<eps *>::const_iterator i; 198107665Simp 199107665Simp for (i = _epsvec.begin(); i != _epsvec.end(); i++) 200107665Simp delete *i; 201107665Simp _epsvec.clear(); 202107665Simp} 203107665Simp 204107665Simpvoid 205107665Simpevent_proc::add(eps *eps) 206107665Simp{ 207107665Simp _epsvec.push_back(eps); 208107665Simp} 209107665Simp 210107665Simpbool 211107665Simpevent_proc::matches(config &c) 212107665Simp{ 213107665Simp vector<eps *>::const_iterator i; 214107665Simp 215107665Simp for (i = _epsvec.begin(); i != _epsvec.end(); i++) 216107665Simp if (!(*i)->do_match(c)) 217107665Simp return (false); 218107665Simp return (true); 219107665Simp} 220107665Simp 221107665Simpbool 222107665Simpevent_proc::run(config &c) 223107665Simp{ 224107665Simp vector<eps *>::const_iterator i; 225107665Simp 226107665Simp for (i = _epsvec.begin(); i != _epsvec.end(); i++) 227107665Simp if (!(*i)->do_action(c)) 228107665Simp return (false); 229107665Simp return (true); 230107665Simp} 231107665Simp 232107665Simpaction::action(const char *cmd) 233107665Simp : _cmd(cmd) 234107665Simp{ 235107665Simp // nothing 236107665Simp} 237107665Simp 238107665Simpaction::~action() 239107665Simp{ 240107665Simp // nothing 241107665Simp} 242107665Simp 243107665Simpbool 244108014Simpaction::do_action(config &c) 245107665Simp{ 246108783Simp string s = c.expand_string(_cmd); 247108783Simp if (dflag) 248108783Simp fprintf(stderr, "Executing '%s'\n", s.c_str()); 249108783Simp ::system(s.c_str()); 250107665Simp return (true); 251107665Simp} 252107665Simp 253108014Simpmatch::match(config &c, const char *var, const char *re) 254108783Simp : _var(var) 255107665Simp{ 256108783Simp string pattern = re; 257108783Simp _re = "^"; 258108783Simp _re.append(c.expand_string(string(re))); 259108783Simp _re.append("$"); 260108783Simp regcomp(&_regex, _re.c_str(), REG_EXTENDED | REG_NOSUB); 261107665Simp} 262107665Simp 263107665Simpmatch::~match() 264107665Simp{ 265108014Simp regfree(&_regex); 266107665Simp} 267107665Simp 268107665Simpbool 269108014Simpmatch::do_match(config &c) 270107665Simp{ 271108014Simp string value = c.get_variable(_var); 272108014Simp bool retval; 273108014Simp 274108783Simp if (dflag) 275108783Simp fprintf(stderr, "Testing %s=%s against %s\n", _var.c_str(), 276108783Simp value.c_str(), _re.c_str()); 277108783Simp 278108014Simp retval = (regexec(&_regex, value.c_str(), 0, NULL, 0) == 0); 279108014Simp return retval; 280107665Simp} 281107665Simp 282107665Simpconst string var_list::bogus = "_$_$_$_$_B_O_G_U_S_$_$_$_$_"; 283107665Simpconst string var_list::nothing = ""; 284107665Simp 285107665Simpconst string & 286107665Simpvar_list::get_variable(const string &var) const 287107665Simp{ 288107665Simp map<string, string>::const_iterator i; 289107665Simp 290107665Simp i = _vars.find(var); 291107665Simp if (i == _vars.end()) 292108783Simp return (var_list::bogus); 293107665Simp return (i->second); 294107665Simp} 295107665Simp 296107665Simpbool 297107665Simpvar_list::is_set(const string &var) const 298107665Simp{ 299107665Simp return (_vars.find(var) != _vars.end()); 300107665Simp} 301107665Simp 302107665Simpvoid 303107665Simpvar_list::set_variable(const string &var, const string &val) 304107665Simp{ 305108783Simp if (dflag) 306108783Simp fprintf(stderr, "%s=%s\n", var.c_str(), val.c_str()); 307107665Simp _vars[var] = val; 308107665Simp} 309107665Simp 310107665Simpvoid 311107665Simpconfig::reset(void) 312107665Simp{ 313107665Simp _dir_list.clear(); 314108783Simp delete_and_clear(_var_list_table); 315108783Simp delete_and_clear(_attach_list); 316108783Simp delete_and_clear(_detach_list); 317108783Simp delete_and_clear(_nomatch_list); 318107665Simp} 319107665Simp 320107665Simpvoid 321107665Simpconfig::parse_one_file(const char *fn) 322107665Simp{ 323107665Simp if (dflag) 324107665Simp printf("Parsing %s\n", fn); 325107665Simp yyin = fopen(fn, "r"); 326107665Simp if (yyin == NULL) 327107665Simp err(1, "Cannot open config file %s", fn); 328107665Simp if (yyparse() != 0) 329107665Simp errx(1, "Cannot parse %s at line %d", fn, lineno); 330107665Simp fclose(yyin); 331107665Simp} 332107665Simp 333107665Simpvoid 334107665Simpconfig::parse_files_in_dir(const char *dirname) 335107665Simp{ 336107665Simp DIR *dirp; 337107665Simp struct dirent *dp; 338107665Simp char path[PATH_MAX]; 339107665Simp 340107665Simp if (dflag) 341107665Simp printf("Parsing files in %s\n", dirname); 342107665Simp dirp = opendir(dirname); 343107665Simp if (dirp == NULL) 344107665Simp return; 345107665Simp readdir(dirp); /* Skip . */ 346107665Simp readdir(dirp); /* Skip .. */ 347107665Simp while ((dp = readdir(dirp)) != NULL) { 348107665Simp if (strcmp(dp->d_name + dp->d_namlen - 5, ".conf") == 0) { 349107665Simp snprintf(path, sizeof(path), "%s/%s", 350107665Simp dirname, dp->d_name); 351107665Simp parse_one_file(path); 352107665Simp } 353107665Simp } 354107665Simp} 355107665Simp 356108783Simpclass epv_greater { 357108783Simppublic: 358108783Simp int operator()(event_proc *const&l1, event_proc *const&l2) 359108783Simp { 360108783Simp return (l1->get_priority() > l2->get_priority()); 361108783Simp } 362108783Simp}; 363108783Simp 364107665Simpvoid 365108783Simpconfig::sort_vector(vector<event_proc *> &v) 366108783Simp{ 367108783Simp sort(v.begin(), v.end(), epv_greater()); 368108783Simp} 369108783Simp 370108783Simpvoid 371107665Simpconfig::parse(void) 372107665Simp{ 373107665Simp vector<string>::const_iterator i; 374107665Simp 375107665Simp parse_one_file(CF); 376107665Simp for (i = _dir_list.begin(); i != _dir_list.end(); i++) 377107665Simp parse_files_in_dir((*i).c_str()); 378108783Simp sort_vector(_attach_list); 379108783Simp sort_vector(_detach_list); 380108783Simp sort_vector(_nomatch_list); 381107665Simp} 382107665Simp 383107665Simpvoid 384107665Simpconfig::drop_pidfile() 385107665Simp{ 386107665Simp FILE *fp; 387107665Simp 388107665Simp if (_pidfile == "") 389107665Simp return; 390107665Simp fp = fopen(_pidfile.c_str(), "w"); 391107665Simp if (fp == NULL) 392107665Simp return; 393107665Simp fprintf(fp, "%d\n", getpid()); 394107665Simp fclose(fp); 395107665Simp} 396107665Simp 397107665Simpvoid 398107665Simpconfig::add_attach(int prio, event_proc *p) 399107665Simp{ 400107665Simp p->set_priority(prio); 401107665Simp _attach_list.push_back(p); 402107665Simp} 403107665Simp 404107665Simpvoid 405107665Simpconfig::add_detach(int prio, event_proc *p) 406107665Simp{ 407107665Simp p->set_priority(prio); 408107665Simp _detach_list.push_back(p); 409107665Simp} 410107665Simp 411107665Simpvoid 412107665Simpconfig::add_directory(const char *dir) 413107665Simp{ 414107665Simp _dir_list.push_back(string(dir)); 415107665Simp} 416107665Simp 417107665Simpvoid 418107665Simpconfig::add_nomatch(int prio, event_proc *p) 419107665Simp{ 420107665Simp p->set_priority(prio); 421107665Simp _nomatch_list.push_back(p); 422107665Simp} 423107665Simp 424107665Simpvoid 425107665Simpconfig::set_pidfile(const char *fn) 426107665Simp{ 427107665Simp _pidfile = string(fn); 428107665Simp} 429107665Simp 430107665Simpvoid 431107665Simpconfig::push_var_table() 432107665Simp{ 433107665Simp var_list *vl; 434107665Simp 435107665Simp vl = new var_list(); 436107665Simp _var_list_table.push_back(vl); 437108783Simp if (dflag) 438108783Simp fprintf(stderr, "Pushing table\n"); 439107665Simp} 440107665Simp 441107665Simpvoid 442107665Simpconfig::pop_var_table() 443107665Simp{ 444107665Simp delete _var_list_table.back(); 445107665Simp _var_list_table.pop_back(); 446108783Simp if (dflag) 447108783Simp fprintf(stderr, "Popping table\n"); 448107665Simp} 449107665Simp 450107665Simpvoid 451107665Simpconfig::set_variable(const char *var, const char *val) 452107665Simp{ 453107665Simp _var_list_table.back()->set_variable(var, val); 454107665Simp} 455107665Simp 456107665Simpconst string & 457107665Simpconfig::get_variable(const string &var) 458107665Simp{ 459107665Simp vector<var_list *>::reverse_iterator i; 460107665Simp 461107665Simp for (i = _var_list_table.rbegin(); i != _var_list_table.rend(); i++) { 462107665Simp if ((*i)->is_set(var)) 463108783Simp return ((*i)->get_variable(var)); 464107665Simp } 465107665Simp return (var_list::nothing); 466107665Simp} 467107665Simp 468108783Simpbool 469108783Simpconfig::is_id_char(char ch) 470108783Simp{ 471108783Simp return (ch != '\0' && (isalpha(ch) || isdigit(ch) || ch == '_' || 472108783Simp ch == '-')); 473108783Simp} 474108783Simp 475108014Simp// XXX 476108783Simp// imp should learn how to make effective use of the string class. 477108014Simpvoid 478108014Simpconfig::expand_one(const char *&src, char *&dst, char *) 479107665Simp{ 480108014Simp int count; 481108014Simp const char *var; 482108014Simp char buffer[1024]; 483108014Simp string varstr; 484108014Simp 485108783Simp src++; 486108014Simp // $$ -> $ 487108014Simp if (*src == '$') { 488108014Simp *dst++ = *src++; 489108014Simp return; 490108014Simp } 491108014Simp 492108014Simp // $(foo) -> $(foo) 493108783Simp // Not sure if I want to support this or not, so for now we just pass 494108783Simp // it through. 495108014Simp if (*src == '(') { 496108014Simp *dst++ = '$'; 497108014Simp count = 1; 498108014Simp while (count > 0) { 499108014Simp if (*src == ')') 500108014Simp count--; 501108014Simp else if (*src == '(') 502108014Simp count++; 503108014Simp *dst++ = *src++; 504108014Simp } 505108014Simp return; 506108014Simp } 507108014Simp 508108014Simp // ${^A-Za-z] -> $\1 509108014Simp if (!isalpha(*src)) { 510108014Simp *dst++ = '$'; 511108014Simp *dst++ = *src++; 512108014Simp return; 513108014Simp } 514108014Simp 515108014Simp // $var -> replace with value 516108014Simp var = src++; 517108783Simp while (is_id_char(*src)) 518108014Simp src++; 519108014Simp memcpy(buffer, var, src - var); 520108014Simp buffer[src - var] = '\0'; 521108014Simp varstr = get_variable(buffer); 522108014Simp strcpy(dst, varstr.c_str()); 523108014Simp dst += strlen(dst); 524107665Simp} 525107665Simp 526108014Simpconst string 527108014Simpconfig::expand_string(const string &s) 528108014Simp{ 529108014Simp const char *src; 530108014Simp char *dst; 531108014Simp char buffer[1024]; 532108014Simp 533108014Simp src = s.c_str(); 534108014Simp dst = buffer; 535108014Simp while (*src) { 536108014Simp if (*src == '$') 537108783Simp expand_one(src, dst, buffer + sizeof(buffer)); 538108014Simp else 539108014Simp *dst++ = *src++; 540108014Simp } 541108014Simp *dst++ = '\0'; 542108014Simp 543108014Simp return (buffer); 544108014Simp} 545108014Simp 546108783Simpbool 547108783Simpconfig::chop_var(char *&buffer, char *&lhs, char *&rhs) 548108783Simp{ 549108783Simp char *walker; 550108783Simp 551108783Simp if (*buffer == '\0') 552108783Simp return (false); 553108783Simp walker = lhs = buffer; 554108783Simp while (is_id_char(*walker)) 555108783Simp walker++; 556108783Simp if (*walker != '=') 557108783Simp return (false); 558108783Simp walker++; // skip = 559108783Simp if (*walker == '"') { 560108783Simp walker++; // skip " 561108783Simp rhs = walker; 562108783Simp while (*walker && *walker != '"') 563108783Simp walker++; 564108783Simp if (*walker != '"') 565108783Simp return (false); 566108783Simp rhs[-2] = '\0'; 567108783Simp *walker++ = '\0'; 568108783Simp } else { 569108783Simp rhs = walker; 570108783Simp while (*walker && !isspace(*walker)) 571108783Simp walker++; 572108783Simp if (*walker != '\0') 573108783Simp *walker++ = '\0'; 574108783Simp rhs[-1] = '\0'; 575108783Simp } 576108783Simp buffer = walker; 577108783Simp return (true); 578108783Simp} 579108783Simp 580108783Simp 581108783Simpchar * 582108783Simpconfig::set_vars(char *buffer) 583108783Simp{ 584108783Simp char *lhs; 585108783Simp char *rhs; 586108783Simp 587108783Simp while (1) { 588108783Simp if (!chop_var(buffer, lhs, rhs)) 589108783Simp break; 590108783Simp set_variable(lhs, rhs); 591108783Simp } 592108783Simp return (buffer); 593108783Simp} 594108783Simp 595108783Simpvoid 596108783Simpconfig::find_and_execute(char type) 597108783Simp{ 598108783Simp vector<event_proc *> *l; 599108783Simp vector<event_proc *>::const_iterator i; 600108783Simp char *s; 601108783Simp 602108783Simp switch (type) { 603108783Simp default: 604108783Simp return; 605108783Simp case nomatch: 606108783Simp l = &_nomatch_list; 607108783Simp s = "nomatch"; 608108783Simp break; 609108783Simp case attach: 610108783Simp l = &_attach_list; 611108783Simp s = "attach"; 612108783Simp break; 613108783Simp case detach: 614108783Simp l = &_detach_list; 615108783Simp s = "detach"; 616108783Simp break; 617108783Simp } 618108783Simp if (dflag) 619108783Simp fprintf(stderr, "Processing %s event\n", s); 620108783Simp for (i = l->begin(); i != l->end(); i++) { 621108783Simp if ((*i)->matches(*this)) { 622108783Simp (*i)->run(*this); 623108783Simp break; 624108783Simp } 625108783Simp } 626108783Simp 627108783Simp} 628108783Simp 629107665Simp 630107665Simpstatic void 631108783Simpprocess_event(char *buffer) 632107665Simp{ 633107665Simp char type; 634107665Simp char *sp; 635107665Simp 636108783Simp sp = buffer + 1; 637108783Simp if (dflag) 638108783Simp fprintf(stderr, "Processing event '%s'\n", buffer); 639107665Simp type = *buffer++; 640108783Simp cfg.push_var_table(); 641108783Simp // No match doesn't have a device, and the format is a little 642108783Simp // different, so handle it separately. 643108783Simp if (type != nomatch) { 644108783Simp sp = strchr(sp, ' '); 645108783Simp if (sp == NULL) 646108783Simp return; /* Can't happen? */ 647108783Simp *sp++ = '\0'; 648108783Simp cfg.set_variable("device-name", buffer); 649108783Simp } 650108783Simp if (strncmp(sp, "at ", 3) == 0) 651108783Simp sp += 3; 652108783Simp sp = cfg.set_vars(sp); 653108783Simp if (strncmp(sp, "on ", 3) == 0) 654108783Simp cfg.set_variable("bus", sp + 3); 655108783Simp cfg.find_and_execute(type); 656108783Simp cfg.pop_var_table(); 657107665Simp} 658107665Simp 659107665Simpstatic void 660107665Simpevent_loop(void) 661107665Simp{ 662107665Simp int rv; 663107665Simp int fd; 664107665Simp char buffer[DEVCTL_MAXBUF]; 665107665Simp 666107665Simp fd = open(PATH_DEVCTL, O_RDONLY); 667107665Simp if (fd == -1) 668107665Simp err(1, "Can't open devctl"); 669107665Simp if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) 670107665Simp err(1, "Can't set close-on-exec flag"); 671107665Simp while (1) { 672107665Simp if (romeo_must_die) 673107665Simp break; 674107665Simp rv = read(fd, buffer, sizeof(buffer) - 1); 675107665Simp if (rv > 0) { 676107665Simp buffer[rv] = '\0'; 677107665Simp while (buffer[--rv] == '\n') 678107665Simp buffer[rv] = '\0'; 679107665Simp process_event(buffer); 680107665Simp } else if (rv < 0) { 681107665Simp if (errno != EINTR) 682107665Simp break; 683107665Simp } else { 684107665Simp /* EOF */ 685107665Simp break; 686107665Simp } 687107665Simp } 688107665Simp close(fd); 689107665Simp} 690107665Simp 691107665Simp/* 692107665Simp * functions that the parser uses. 693107665Simp */ 694107665Simpvoid 695107665Simpadd_attach(int prio, event_proc *p) 696107665Simp{ 697107665Simp cfg.add_attach(prio, p); 698107665Simp} 699107665Simp 700107665Simpvoid 701107665Simpadd_detach(int prio, event_proc *p) 702107665Simp{ 703107665Simp cfg.add_detach(prio, p); 704107665Simp} 705107665Simp 706107665Simpvoid 707107665Simpadd_directory(const char *dir) 708107665Simp{ 709107665Simp cfg.add_directory(dir); 710107665Simp free(const_cast<char *>(dir)); 711107665Simp} 712107665Simp 713107665Simpvoid 714107665Simpadd_nomatch(int prio, event_proc *p) 715107665Simp{ 716107665Simp cfg.add_nomatch(prio, p); 717107665Simp} 718107665Simp 719107665Simpevent_proc * 720107665Simpadd_to_event_proc(event_proc *ep, eps *eps) 721107665Simp{ 722107665Simp if (ep == NULL) 723107665Simp ep = new event_proc(); 724107665Simp ep->add(eps); 725107665Simp return (ep); 726107665Simp} 727107665Simp 728107665Simpeps * 729107665Simpnew_action(const char *cmd) 730107665Simp{ 731107665Simp eps *e = new action(cmd); 732107665Simp free(const_cast<char *>(cmd)); 733107665Simp return (e); 734107665Simp} 735107665Simp 736107665Simpeps * 737107665Simpnew_match(const char *var, const char *re) 738107665Simp{ 739108014Simp eps *e = new match(cfg, var, re); 740107665Simp free(const_cast<char *>(var)); 741107665Simp free(const_cast<char *>(re)); 742107665Simp return (e); 743107665Simp} 744107665Simp 745107665Simpvoid 746107665Simpset_pidfile(const char *name) 747107665Simp{ 748107665Simp cfg.set_pidfile(name); 749107665Simp free(const_cast<char *>(name)); 750107665Simp} 751107665Simp 752107665Simpvoid 753107665Simpset_variable(const char *var, const char *val) 754107665Simp{ 755107665Simp cfg.set_variable(var, val); 756107665Simp free(const_cast<char *>(var)); 757107665Simp free(const_cast<char *>(val)); 758107665Simp} 759107665Simp 760107665Simp 761107665Simp 762107665Simpstatic void 763107665Simpgensighand(int) 764107665Simp{ 765107665Simp romeo_must_die++; 766107665Simp _exit(0); 767107665Simp} 768107665Simp 769107665Simpstatic void 770107665Simpusage() 771107665Simp{ 772108799Simp fprintf(stderr, "usage: %s [-d]\n", getprogname()); 773107665Simp exit(1); 774107665Simp} 775107665Simp 776107665Simp/* 777107665Simp * main 778107665Simp */ 779107665Simpint 780107665Simpmain(int argc, char **argv) 781107665Simp{ 782107665Simp int ch; 783107665Simp 784107665Simp while ((ch = getopt(argc, argv, "d")) != -1) { 785107665Simp switch (ch) { 786107665Simp case 'd': 787107665Simp dflag++; 788107665Simp break; 789107665Simp default: 790107665Simp usage(); 791107665Simp } 792107665Simp } 793107665Simp 794107665Simp cfg.parse(); 795107665Simp if (!dflag) 796107665Simp daemon(0, 0); 797107665Simp cfg.drop_pidfile(); 798107665Simp signal(SIGHUP, gensighand); 799107665Simp signal(SIGINT, gensighand); 800107665Simp signal(SIGTERM, gensighand); 801107665Simp event_loop(); 802107665Simp return (0); 803107665Simp} 804