devd.cc revision 131397
1107665Simp/*- 2113785Simp * Copyright (c) 2002-2003 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: 33131397Simp// - devd needs to document the unix domain socket 34107665Simp// - devd.conf needs more details on the supported statements. 35107665Simp 36107665Simp#include <sys/cdefs.h> 37107665Simp__FBSDID("$FreeBSD: head/sbin/devd/devd.cc 131397 2004-07-01 07:24:18Z imp $"); 38107665Simp 39107665Simp#include <sys/param.h> 40131397Simp#include <sys/socket.h> 41131397Simp#include <sys/stat.h> 42131397Simp#include <sys/sysctl.h> 43107665Simp#include <sys/types.h> 44131397Simp#include <sys/un.h> 45107665Simp 46108014Simp#include <ctype.h> 47107665Simp#include <dirent.h> 48107665Simp#include <errno.h> 49107665Simp#include <err.h> 50107665Simp#include <fcntl.h> 51108014Simp#include <regex.h> 52107665Simp#include <stdlib.h> 53107665Simp#include <stdio.h> 54107665Simp#include <string.h> 55107665Simp#include <unistd.h> 56107665Simp 57108783Simp#include <algorithm> 58107665Simp#include <map> 59107665Simp#include <string> 60131397Simp#include <list> 61107665Simp#include <vector> 62107665Simp 63114086Simp#include "devd.h" /* C compatible definitions */ 64114086Simp#include "devd.hh" /* C++ class definitions */ 65107665Simp 66131397Simp#define PIPE "/var/run/devd.pipe" 67107665Simp#define CF "/etc/devd.conf" 68113787Simp#define SYSCTL "hw.bus.devctl_disable" 69107665Simp 70107665Simpusing namespace std; 71107665Simp 72107665Simpextern FILE *yyin; 73107665Simpextern int lineno; 74107665Simp 75121487Simpstatic const char notify = '!'; 76108783Simpstatic const char nomatch = '?'; 77108783Simpstatic const char attach = '+'; 78108783Simpstatic const char detach = '-'; 79108783Simp 80113790Simpint Dflag; 81107665Simpint dflag; 82114000Simpint nflag; 83107665Simpint romeo_must_die = 0; 84107665Simp 85107665Simpstatic void event_loop(void); 86107665Simpstatic void usage(void); 87107665Simp 88108783Simptemplate <class T> void 89108783Simpdelete_and_clear(vector<T *> &v) 90108783Simp{ 91108783Simp typename vector<T *>::const_iterator i; 92108783Simp 93108783Simp for (i = v.begin(); i != v.end(); i++) 94108783Simp delete *i; 95108783Simp v.clear(); 96108783Simp} 97108783Simp 98107665Simpconfig cfg; 99107665Simp 100107665Simpevent_proc::event_proc() : _prio(-1) 101107665Simp{ 102107665Simp // nothing 103107665Simp} 104107665Simp 105107665Simpevent_proc::~event_proc() 106107665Simp{ 107107665Simp vector<eps *>::const_iterator i; 108107665Simp 109107665Simp for (i = _epsvec.begin(); i != _epsvec.end(); i++) 110107665Simp delete *i; 111107665Simp _epsvec.clear(); 112107665Simp} 113107665Simp 114107665Simpvoid 115107665Simpevent_proc::add(eps *eps) 116107665Simp{ 117107665Simp _epsvec.push_back(eps); 118107665Simp} 119107665Simp 120107665Simpbool 121107665Simpevent_proc::matches(config &c) 122107665Simp{ 123107665Simp vector<eps *>::const_iterator i; 124107665Simp 125107665Simp for (i = _epsvec.begin(); i != _epsvec.end(); i++) 126107665Simp if (!(*i)->do_match(c)) 127107665Simp return (false); 128107665Simp return (true); 129107665Simp} 130107665Simp 131107665Simpbool 132107665Simpevent_proc::run(config &c) 133107665Simp{ 134107665Simp vector<eps *>::const_iterator i; 135107665Simp 136107665Simp for (i = _epsvec.begin(); i != _epsvec.end(); i++) 137107665Simp if (!(*i)->do_action(c)) 138107665Simp return (false); 139107665Simp return (true); 140107665Simp} 141107665Simp 142107665Simpaction::action(const char *cmd) 143107665Simp : _cmd(cmd) 144107665Simp{ 145107665Simp // nothing 146107665Simp} 147107665Simp 148107665Simpaction::~action() 149107665Simp{ 150107665Simp // nothing 151107665Simp} 152107665Simp 153107665Simpbool 154108014Simpaction::do_action(config &c) 155107665Simp{ 156108783Simp string s = c.expand_string(_cmd); 157113790Simp if (Dflag) 158108783Simp fprintf(stderr, "Executing '%s'\n", s.c_str()); 159108783Simp ::system(s.c_str()); 160107665Simp return (true); 161107665Simp} 162107665Simp 163108014Simpmatch::match(config &c, const char *var, const char *re) 164108783Simp : _var(var) 165107665Simp{ 166108783Simp string pattern = re; 167108783Simp _re = "^"; 168108783Simp _re.append(c.expand_string(string(re))); 169108783Simp _re.append("$"); 170108783Simp regcomp(&_regex, _re.c_str(), REG_EXTENDED | REG_NOSUB); 171107665Simp} 172107665Simp 173107665Simpmatch::~match() 174107665Simp{ 175108014Simp regfree(&_regex); 176107665Simp} 177107665Simp 178107665Simpbool 179108014Simpmatch::do_match(config &c) 180107665Simp{ 181108014Simp string value = c.get_variable(_var); 182108014Simp bool retval; 183108014Simp 184113790Simp if (Dflag) 185108783Simp fprintf(stderr, "Testing %s=%s against %s\n", _var.c_str(), 186108783Simp value.c_str(), _re.c_str()); 187108783Simp 188108014Simp retval = (regexec(&_regex, value.c_str(), 0, NULL, 0) == 0); 189108014Simp return retval; 190107665Simp} 191107665Simp 192107665Simpconst string var_list::bogus = "_$_$_$_$_B_O_G_U_S_$_$_$_$_"; 193107665Simpconst string var_list::nothing = ""; 194107665Simp 195107665Simpconst string & 196107665Simpvar_list::get_variable(const string &var) const 197107665Simp{ 198107665Simp map<string, string>::const_iterator i; 199107665Simp 200107665Simp i = _vars.find(var); 201107665Simp if (i == _vars.end()) 202108783Simp return (var_list::bogus); 203107665Simp return (i->second); 204107665Simp} 205107665Simp 206107665Simpbool 207107665Simpvar_list::is_set(const string &var) const 208107665Simp{ 209107665Simp return (_vars.find(var) != _vars.end()); 210107665Simp} 211107665Simp 212107665Simpvoid 213107665Simpvar_list::set_variable(const string &var, const string &val) 214107665Simp{ 215113790Simp if (Dflag) 216108783Simp fprintf(stderr, "%s=%s\n", var.c_str(), val.c_str()); 217107665Simp _vars[var] = val; 218107665Simp} 219107665Simp 220107665Simpvoid 221107665Simpconfig::reset(void) 222107665Simp{ 223107665Simp _dir_list.clear(); 224108783Simp delete_and_clear(_var_list_table); 225108783Simp delete_and_clear(_attach_list); 226108783Simp delete_and_clear(_detach_list); 227108783Simp delete_and_clear(_nomatch_list); 228121487Simp delete_and_clear(_notify_list); 229107665Simp} 230107665Simp 231107665Simpvoid 232107665Simpconfig::parse_one_file(const char *fn) 233107665Simp{ 234113790Simp if (Dflag) 235107665Simp printf("Parsing %s\n", fn); 236107665Simp yyin = fopen(fn, "r"); 237107665Simp if (yyin == NULL) 238107665Simp err(1, "Cannot open config file %s", fn); 239107665Simp if (yyparse() != 0) 240107665Simp errx(1, "Cannot parse %s at line %d", fn, lineno); 241107665Simp fclose(yyin); 242107665Simp} 243107665Simp 244107665Simpvoid 245107665Simpconfig::parse_files_in_dir(const char *dirname) 246107665Simp{ 247107665Simp DIR *dirp; 248107665Simp struct dirent *dp; 249107665Simp char path[PATH_MAX]; 250107665Simp 251113790Simp if (Dflag) 252107665Simp printf("Parsing files in %s\n", dirname); 253107665Simp dirp = opendir(dirname); 254107665Simp if (dirp == NULL) 255107665Simp return; 256107665Simp readdir(dirp); /* Skip . */ 257107665Simp readdir(dirp); /* Skip .. */ 258107665Simp while ((dp = readdir(dirp)) != NULL) { 259107665Simp if (strcmp(dp->d_name + dp->d_namlen - 5, ".conf") == 0) { 260107665Simp snprintf(path, sizeof(path), "%s/%s", 261107665Simp dirname, dp->d_name); 262107665Simp parse_one_file(path); 263107665Simp } 264107665Simp } 265107665Simp} 266107665Simp 267108783Simpclass epv_greater { 268108783Simppublic: 269108783Simp int operator()(event_proc *const&l1, event_proc *const&l2) 270108783Simp { 271108783Simp return (l1->get_priority() > l2->get_priority()); 272108783Simp } 273108783Simp}; 274108783Simp 275107665Simpvoid 276108783Simpconfig::sort_vector(vector<event_proc *> &v) 277108783Simp{ 278108783Simp sort(v.begin(), v.end(), epv_greater()); 279108783Simp} 280108783Simp 281108783Simpvoid 282107665Simpconfig::parse(void) 283107665Simp{ 284107665Simp vector<string>::const_iterator i; 285107665Simp 286107665Simp parse_one_file(CF); 287107665Simp for (i = _dir_list.begin(); i != _dir_list.end(); i++) 288107665Simp parse_files_in_dir((*i).c_str()); 289108783Simp sort_vector(_attach_list); 290108783Simp sort_vector(_detach_list); 291108783Simp sort_vector(_nomatch_list); 292121487Simp sort_vector(_notify_list); 293107665Simp} 294107665Simp 295107665Simpvoid 296107665Simpconfig::drop_pidfile() 297107665Simp{ 298107665Simp FILE *fp; 299107665Simp 300107665Simp if (_pidfile == "") 301107665Simp return; 302107665Simp fp = fopen(_pidfile.c_str(), "w"); 303107665Simp if (fp == NULL) 304107665Simp return; 305107665Simp fprintf(fp, "%d\n", getpid()); 306107665Simp fclose(fp); 307107665Simp} 308107665Simp 309107665Simpvoid 310107665Simpconfig::add_attach(int prio, event_proc *p) 311107665Simp{ 312107665Simp p->set_priority(prio); 313107665Simp _attach_list.push_back(p); 314107665Simp} 315107665Simp 316107665Simpvoid 317107665Simpconfig::add_detach(int prio, event_proc *p) 318107665Simp{ 319107665Simp p->set_priority(prio); 320107665Simp _detach_list.push_back(p); 321107665Simp} 322107665Simp 323107665Simpvoid 324107665Simpconfig::add_directory(const char *dir) 325107665Simp{ 326107665Simp _dir_list.push_back(string(dir)); 327107665Simp} 328107665Simp 329107665Simpvoid 330107665Simpconfig::add_nomatch(int prio, event_proc *p) 331107665Simp{ 332107665Simp p->set_priority(prio); 333107665Simp _nomatch_list.push_back(p); 334107665Simp} 335107665Simp 336107665Simpvoid 337121487Simpconfig::add_notify(int prio, event_proc *p) 338121487Simp{ 339121487Simp p->set_priority(prio); 340121487Simp _notify_list.push_back(p); 341121487Simp} 342121487Simp 343121487Simpvoid 344107665Simpconfig::set_pidfile(const char *fn) 345107665Simp{ 346107665Simp _pidfile = string(fn); 347107665Simp} 348107665Simp 349107665Simpvoid 350107665Simpconfig::push_var_table() 351107665Simp{ 352107665Simp var_list *vl; 353107665Simp 354107665Simp vl = new var_list(); 355107665Simp _var_list_table.push_back(vl); 356113790Simp if (Dflag) 357108783Simp fprintf(stderr, "Pushing table\n"); 358107665Simp} 359107665Simp 360107665Simpvoid 361107665Simpconfig::pop_var_table() 362107665Simp{ 363107665Simp delete _var_list_table.back(); 364107665Simp _var_list_table.pop_back(); 365113790Simp if (Dflag) 366108783Simp fprintf(stderr, "Popping table\n"); 367107665Simp} 368107665Simp 369107665Simpvoid 370107665Simpconfig::set_variable(const char *var, const char *val) 371107665Simp{ 372107665Simp _var_list_table.back()->set_variable(var, val); 373107665Simp} 374107665Simp 375107665Simpconst string & 376107665Simpconfig::get_variable(const string &var) 377107665Simp{ 378107665Simp vector<var_list *>::reverse_iterator i; 379107665Simp 380107665Simp for (i = _var_list_table.rbegin(); i != _var_list_table.rend(); i++) { 381107665Simp if ((*i)->is_set(var)) 382108783Simp return ((*i)->get_variable(var)); 383107665Simp } 384107665Simp return (var_list::nothing); 385107665Simp} 386107665Simp 387108783Simpbool 388108783Simpconfig::is_id_char(char ch) 389108783Simp{ 390108783Simp return (ch != '\0' && (isalpha(ch) || isdigit(ch) || ch == '_' || 391108783Simp ch == '-')); 392108783Simp} 393108783Simp 394108014Simpvoid 395114081Simpconfig::expand_one(const char *&src, string &dst) 396107665Simp{ 397108014Simp int count; 398114081Simp string buffer, varstr; 399108014Simp 400108783Simp src++; 401108014Simp // $$ -> $ 402108014Simp if (*src == '$') { 403114081Simp dst.append(src++, 1); 404108014Simp return; 405108014Simp } 406108014Simp 407108014Simp // $(foo) -> $(foo) 408108783Simp // Not sure if I want to support this or not, so for now we just pass 409108783Simp // it through. 410108014Simp if (*src == '(') { 411114081Simp dst.append("$"); 412108014Simp count = 1; 413114081Simp /* If the string ends before ) is matched , return. */ 414114081Simp while (count > 0 && *src) { 415108014Simp if (*src == ')') 416108014Simp count--; 417108014Simp else if (*src == '(') 418108014Simp count++; 419114081Simp dst.append(src++, 1); 420108014Simp } 421108014Simp return; 422108014Simp } 423108014Simp 424108014Simp // ${^A-Za-z] -> $\1 425108014Simp if (!isalpha(*src)) { 426114081Simp dst.append("$"); 427114081Simp dst.append(src++, 1); 428108014Simp return; 429108014Simp } 430108014Simp 431108014Simp // $var -> replace with value 432114081Simp do { 433114081Simp buffer.append(src++, 1); 434114084Simp } while (is_id_char(*src)); 435114081Simp buffer.append("", 1); 436114081Simp varstr = get_variable(buffer.c_str()); 437114081Simp dst.append(varstr); 438107665Simp} 439107665Simp 440108014Simpconst string 441108014Simpconfig::expand_string(const string &s) 442108014Simp{ 443108014Simp const char *src; 444114081Simp string dst; 445108014Simp 446108014Simp src = s.c_str(); 447108014Simp while (*src) { 448108014Simp if (*src == '$') 449114081Simp expand_one(src, dst); 450108014Simp else 451114081Simp dst.append(src++, 1); 452108014Simp } 453114081Simp dst.append("", 1); 454108014Simp 455114081Simp return (dst); 456108014Simp} 457108014Simp 458108783Simpbool 459108783Simpconfig::chop_var(char *&buffer, char *&lhs, char *&rhs) 460108783Simp{ 461108783Simp char *walker; 462108783Simp 463108783Simp if (*buffer == '\0') 464108783Simp return (false); 465108783Simp walker = lhs = buffer; 466108783Simp while (is_id_char(*walker)) 467108783Simp walker++; 468108783Simp if (*walker != '=') 469108783Simp return (false); 470108783Simp walker++; // skip = 471108783Simp if (*walker == '"') { 472108783Simp walker++; // skip " 473108783Simp rhs = walker; 474108783Simp while (*walker && *walker != '"') 475108783Simp walker++; 476108783Simp if (*walker != '"') 477108783Simp return (false); 478108783Simp rhs[-2] = '\0'; 479108783Simp *walker++ = '\0'; 480108783Simp } else { 481108783Simp rhs = walker; 482108783Simp while (*walker && !isspace(*walker)) 483108783Simp walker++; 484108783Simp if (*walker != '\0') 485108783Simp *walker++ = '\0'; 486108783Simp rhs[-1] = '\0'; 487108783Simp } 488113785Simp while (isspace(*walker)) 489113785Simp walker++; 490108783Simp buffer = walker; 491108783Simp return (true); 492108783Simp} 493108783Simp 494108783Simp 495108783Simpchar * 496108783Simpconfig::set_vars(char *buffer) 497108783Simp{ 498108783Simp char *lhs; 499108783Simp char *rhs; 500108783Simp 501108783Simp while (1) { 502108783Simp if (!chop_var(buffer, lhs, rhs)) 503108783Simp break; 504108783Simp set_variable(lhs, rhs); 505108783Simp } 506108783Simp return (buffer); 507108783Simp} 508108783Simp 509108783Simpvoid 510108783Simpconfig::find_and_execute(char type) 511108783Simp{ 512108783Simp vector<event_proc *> *l; 513108783Simp vector<event_proc *>::const_iterator i; 514108783Simp char *s; 515108783Simp 516108783Simp switch (type) { 517108783Simp default: 518108783Simp return; 519121487Simp case notify: 520121487Simp l = &_notify_list; 521121487Simp s = "notify"; 522121487Simp break; 523108783Simp case nomatch: 524108783Simp l = &_nomatch_list; 525108783Simp s = "nomatch"; 526108783Simp break; 527108783Simp case attach: 528108783Simp l = &_attach_list; 529108783Simp s = "attach"; 530108783Simp break; 531108783Simp case detach: 532108783Simp l = &_detach_list; 533108783Simp s = "detach"; 534108783Simp break; 535108783Simp } 536113790Simp if (Dflag) 537108783Simp fprintf(stderr, "Processing %s event\n", s); 538108783Simp for (i = l->begin(); i != l->end(); i++) { 539108783Simp if ((*i)->matches(*this)) { 540108783Simp (*i)->run(*this); 541108783Simp break; 542108783Simp } 543108783Simp } 544108783Simp 545108783Simp} 546108783Simp 547107665Simp 548107665Simpstatic void 549108783Simpprocess_event(char *buffer) 550107665Simp{ 551107665Simp char type; 552107665Simp char *sp; 553107665Simp 554108783Simp sp = buffer + 1; 555113790Simp if (Dflag) 556108783Simp fprintf(stderr, "Processing event '%s'\n", buffer); 557107665Simp type = *buffer++; 558108783Simp cfg.push_var_table(); 559108783Simp // No match doesn't have a device, and the format is a little 560108783Simp // different, so handle it separately. 561121487Simp switch (type) { 562121487Simp case notify: 563121487Simp sp = cfg.set_vars(sp); 564121487Simp break; 565121487Simp case nomatch: 566121487Simp //?vars at location on bus 567121487Simp sp = cfg.set_vars(sp); 568121487Simp if (strncmp(sp, "at ", 3) == 0) 569121487Simp sp += 3; 570121487Simp sp = cfg.set_vars(sp); 571121487Simp if (strncmp(sp, "on ", 3) == 0) 572121487Simp cfg.set_variable("bus", sp + 3); 573121487Simp break; 574121487Simp case attach: /*FALLTHROUGH*/ 575121487Simp case detach: 576108783Simp sp = strchr(sp, ' '); 577108783Simp if (sp == NULL) 578108783Simp return; /* Can't happen? */ 579108783Simp *sp++ = '\0'; 580108783Simp cfg.set_variable("device-name", buffer); 581113785Simp if (strncmp(sp, "at ", 3) == 0) 582113785Simp sp += 3; 583113785Simp sp = cfg.set_vars(sp); 584113785Simp if (strncmp(sp, "on ", 3) == 0) 585113785Simp cfg.set_variable("bus", sp + 3); 586121487Simp break; 587108783Simp } 588113785Simp 589108783Simp cfg.find_and_execute(type); 590108783Simp cfg.pop_var_table(); 591107665Simp} 592107665Simp 593131397Simpint 594131397Simpcreate_socket(const char *name) 595131397Simp{ 596131397Simp int fd, slen; 597131397Simp struct sockaddr_un sun; 598131397Simp 599131397Simp if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) 600131397Simp err(1, "socket"); 601131397Simp bzero(&sun, sizeof(sun)); 602131397Simp sun.sun_family = AF_UNIX; 603131397Simp strlcpy(sun.sun_path, name, sizeof(sun.sun_path)); 604131397Simp slen = SUN_LEN(&sun); 605131397Simp unlink(name); 606131397Simp if (bind(fd, (struct sockaddr *) & sun, slen) < 0) 607131397Simp err(1, "bind"); 608131397Simp listen(fd, 4); 609131397Simp fchown(fd, 0, 0); /* XXX - root.wheel */ 610131397Simp fchmod(fd, 0660); 611131397Simp return (fd); 612131397Simp} 613131397Simp 614131397Simplist<int> clients; 615131397Simp 616131397Simpvoid 617131397Simpnotify_clients(const char *data, int len) 618131397Simp{ 619131397Simp list<int> bad; 620131397Simp list<int>::const_iterator i; 621131397Simp 622131397Simp for (i = clients.begin(); i != clients.end(); i++) { 623131397Simp if (write(*i, data, len) <= 0) { 624131397Simp bad.push_back(*i); 625131397Simp close(*i); 626131397Simp } 627131397Simp } 628131397Simp 629131397Simp for (i = bad.begin(); i != bad.end(); i++) 630131397Simp clients.erase(find(clients.begin(), clients.end(), *i)); 631131397Simp} 632131397Simp 633131397Simpvoid 634131397Simpnew_client(int fd) 635131397Simp{ 636131397Simp int s; 637131397Simp 638131397Simp s = accept(fd, NULL, NULL); 639131397Simp if (s != -1) 640131397Simp clients.push_back(s); 641131397Simp} 642131397Simp 643107665Simpstatic void 644107665Simpevent_loop(void) 645107665Simp{ 646107665Simp int rv; 647107665Simp int fd; 648107665Simp char buffer[DEVCTL_MAXBUF]; 649113790Simp int once = 0; 650131397Simp int server_fd, max_fd; 651113790Simp timeval tv; 652113790Simp fd_set fds; 653107665Simp 654107665Simp fd = open(PATH_DEVCTL, O_RDONLY); 655107665Simp if (fd == -1) 656131397Simp err(1, "Can't open devctl device %s", PATH_DEVCTL); 657107665Simp if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) 658131397Simp err(1, "Can't set close-on-exec flag on devctl"); 659131397Simp server_fd = create_socket(PIPE); 660131397Simp max_fd = max(fd, server_fd) + 1; 661107665Simp while (1) { 662107665Simp if (romeo_must_die) 663107665Simp break; 664113790Simp if (!once && !dflag && !nflag) { 665113790Simp // Check to see if we have any events pending. 666113790Simp tv.tv_sec = 0; 667113790Simp tv.tv_usec = 0; 668113790Simp FD_ZERO(&fds); 669113790Simp FD_SET(fd, &fds); 670113790Simp rv = select(fd + 1, &fds, &fds, &fds, &tv); 671113790Simp // No events -> we've processed all pending events 672117944Simp if (rv == 0) { 673113790Simp if (Dflag) 674113790Simp fprintf(stderr, "Calling daemon\n"); 675113790Simp daemon(0, 0); 676117246Simp cfg.drop_pidfile(); 677113790Simp once++; 678113790Simp } 679113790Simp } 680131397Simp FD_ZERO(&fds); 681131397Simp FD_SET(fd, &fds); 682131397Simp FD_SET(server_fd, &fds); 683131397Simp rv = select(max_fd, &fds, NULL, NULL, NULL); 684131397Simp if (rv == -1) { 685131397Simp if (errno == EINTR) 686131397Simp continue; 687131397Simp err(1, "select"); 688131397Simp } 689131397Simp if (FD_ISSET(fd, &fds)) { 690131397Simp rv = read(fd, buffer, sizeof(buffer) - 1); 691131397Simp if (rv > 0) { 692131397Simp notify_clients(buffer, rv); 693107665Simp buffer[rv] = '\0'; 694131397Simp while (buffer[--rv] == '\n') 695131397Simp buffer[rv] = '\0'; 696131397Simp process_event(buffer); 697131397Simp } else if (rv < 0) { 698131397Simp if (errno != EINTR) 699131397Simp break; 700131397Simp } else { 701131397Simp /* EOF */ 702107665Simp break; 703131397Simp } 704107665Simp } 705131397Simp if (FD_ISSET(server_fd, &fds)) 706131397Simp new_client(server_fd); 707107665Simp } 708107665Simp close(fd); 709107665Simp} 710107665Simp 711107665Simp/* 712107665Simp * functions that the parser uses. 713107665Simp */ 714107665Simpvoid 715107665Simpadd_attach(int prio, event_proc *p) 716107665Simp{ 717107665Simp cfg.add_attach(prio, p); 718107665Simp} 719107665Simp 720107665Simpvoid 721107665Simpadd_detach(int prio, event_proc *p) 722107665Simp{ 723107665Simp cfg.add_detach(prio, p); 724107665Simp} 725107665Simp 726107665Simpvoid 727107665Simpadd_directory(const char *dir) 728107665Simp{ 729107665Simp cfg.add_directory(dir); 730107665Simp free(const_cast<char *>(dir)); 731107665Simp} 732107665Simp 733107665Simpvoid 734107665Simpadd_nomatch(int prio, event_proc *p) 735107665Simp{ 736107665Simp cfg.add_nomatch(prio, p); 737107665Simp} 738107665Simp 739121487Simpvoid 740121487Simpadd_notify(int prio, event_proc *p) 741121487Simp{ 742121487Simp cfg.add_notify(prio, p); 743121487Simp} 744121487Simp 745107665Simpevent_proc * 746107665Simpadd_to_event_proc(event_proc *ep, eps *eps) 747107665Simp{ 748107665Simp if (ep == NULL) 749107665Simp ep = new event_proc(); 750107665Simp ep->add(eps); 751107665Simp return (ep); 752107665Simp} 753107665Simp 754107665Simpeps * 755107665Simpnew_action(const char *cmd) 756107665Simp{ 757107665Simp eps *e = new action(cmd); 758107665Simp free(const_cast<char *>(cmd)); 759107665Simp return (e); 760107665Simp} 761107665Simp 762107665Simpeps * 763107665Simpnew_match(const char *var, const char *re) 764107665Simp{ 765108014Simp eps *e = new match(cfg, var, re); 766107665Simp free(const_cast<char *>(var)); 767107665Simp free(const_cast<char *>(re)); 768107665Simp return (e); 769107665Simp} 770107665Simp 771107665Simpvoid 772107665Simpset_pidfile(const char *name) 773107665Simp{ 774107665Simp cfg.set_pidfile(name); 775107665Simp free(const_cast<char *>(name)); 776107665Simp} 777107665Simp 778107665Simpvoid 779107665Simpset_variable(const char *var, const char *val) 780107665Simp{ 781107665Simp cfg.set_variable(var, val); 782107665Simp free(const_cast<char *>(var)); 783107665Simp free(const_cast<char *>(val)); 784107665Simp} 785107665Simp 786107665Simp 787107665Simp 788107665Simpstatic void 789107665Simpgensighand(int) 790107665Simp{ 791107665Simp romeo_must_die++; 792107665Simp _exit(0); 793107665Simp} 794107665Simp 795107665Simpstatic void 796107665Simpusage() 797107665Simp{ 798108799Simp fprintf(stderr, "usage: %s [-d]\n", getprogname()); 799107665Simp exit(1); 800107665Simp} 801107665Simp 802113787Simpstatic void 803113787Simpcheck_devd_enabled() 804113787Simp{ 805113787Simp int val = 0; 806113787Simp size_t len; 807113787Simp 808113787Simp len = sizeof(val); 809114541Simp if (sysctlbyname(SYSCTL, &val, &len, NULL, 0) != 0) 810113787Simp errx(1, "devctl sysctl missing from kernel!"); 811113787Simp if (val) { 812113787Simp warnx("Setting " SYSCTL " to 0"); 813113787Simp val = 0; 814113787Simp sysctlbyname(SYSCTL, NULL, NULL, &val, sizeof(val)); 815113787Simp } 816113787Simp} 817113787Simp 818107665Simp/* 819107665Simp * main 820107665Simp */ 821107665Simpint 822107665Simpmain(int argc, char **argv) 823107665Simp{ 824107665Simp int ch; 825107665Simp 826113787Simp check_devd_enabled(); 827113790Simp while ((ch = getopt(argc, argv, "Ddn")) != -1) { 828107665Simp switch (ch) { 829113790Simp case 'D': 830113790Simp Dflag++; 831113790Simp break; 832107665Simp case 'd': 833107665Simp dflag++; 834107665Simp break; 835113790Simp case 'n': 836113790Simp nflag++; 837113790Simp break; 838107665Simp default: 839107665Simp usage(); 840107665Simp } 841107665Simp } 842107665Simp 843107665Simp cfg.parse(); 844117246Simp if (!dflag && nflag) { 845107665Simp daemon(0, 0); 846117246Simp cfg.drop_pidfile(); 847117246Simp } 848107665Simp signal(SIGHUP, gensighand); 849107665Simp signal(SIGINT, gensighand); 850107665Simp signal(SIGTERM, gensighand); 851107665Simp event_loop(); 852107665Simp return (0); 853107665Simp} 854