devd.cc revision 147972
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 147972 2005-07-13 17:10:47Z marcus $"); 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> 52146306Simp#include <signal.h> 53107665Simp#include <stdlib.h> 54107665Simp#include <stdio.h> 55107665Simp#include <string.h> 56107665Simp#include <unistd.h> 57107665Simp 58108783Simp#include <algorithm> 59107665Simp#include <map> 60107665Simp#include <string> 61131397Simp#include <list> 62107665Simp#include <vector> 63107665Simp 64114086Simp#include "devd.h" /* C compatible definitions */ 65114086Simp#include "devd.hh" /* C++ class definitions */ 66107665Simp 67131397Simp#define PIPE "/var/run/devd.pipe" 68107665Simp#define CF "/etc/devd.conf" 69113787Simp#define SYSCTL "hw.bus.devctl_disable" 70107665Simp 71107665Simpusing namespace std; 72107665Simp 73107665Simpextern FILE *yyin; 74107665Simpextern int lineno; 75107665Simp 76121487Simpstatic const char notify = '!'; 77108783Simpstatic const char nomatch = '?'; 78108783Simpstatic const char attach = '+'; 79108783Simpstatic const char detach = '-'; 80108783Simp 81113790Simpint Dflag; 82107665Simpint dflag; 83114000Simpint nflag; 84107665Simpint romeo_must_die = 0; 85107665Simp 86107665Simpstatic void event_loop(void); 87107665Simpstatic void usage(void); 88107665Simp 89108783Simptemplate <class T> void 90108783Simpdelete_and_clear(vector<T *> &v) 91108783Simp{ 92108783Simp typename vector<T *>::const_iterator i; 93108783Simp 94108783Simp for (i = v.begin(); i != v.end(); i++) 95108783Simp delete *i; 96108783Simp v.clear(); 97108783Simp} 98108783Simp 99107665Simpconfig cfg; 100107665Simp 101107665Simpevent_proc::event_proc() : _prio(-1) 102107665Simp{ 103107665Simp // nothing 104107665Simp} 105107665Simp 106107665Simpevent_proc::~event_proc() 107107665Simp{ 108107665Simp vector<eps *>::const_iterator i; 109107665Simp 110107665Simp for (i = _epsvec.begin(); i != _epsvec.end(); i++) 111107665Simp delete *i; 112107665Simp _epsvec.clear(); 113107665Simp} 114107665Simp 115107665Simpvoid 116107665Simpevent_proc::add(eps *eps) 117107665Simp{ 118107665Simp _epsvec.push_back(eps); 119107665Simp} 120107665Simp 121107665Simpbool 122107665Simpevent_proc::matches(config &c) 123107665Simp{ 124107665Simp vector<eps *>::const_iterator i; 125107665Simp 126107665Simp for (i = _epsvec.begin(); i != _epsvec.end(); i++) 127107665Simp if (!(*i)->do_match(c)) 128107665Simp return (false); 129107665Simp return (true); 130107665Simp} 131107665Simp 132107665Simpbool 133107665Simpevent_proc::run(config &c) 134107665Simp{ 135107665Simp vector<eps *>::const_iterator i; 136107665Simp 137107665Simp for (i = _epsvec.begin(); i != _epsvec.end(); i++) 138107665Simp if (!(*i)->do_action(c)) 139107665Simp return (false); 140107665Simp return (true); 141107665Simp} 142107665Simp 143107665Simpaction::action(const char *cmd) 144107665Simp : _cmd(cmd) 145107665Simp{ 146107665Simp // nothing 147107665Simp} 148107665Simp 149107665Simpaction::~action() 150107665Simp{ 151107665Simp // nothing 152107665Simp} 153107665Simp 154107665Simpbool 155108014Simpaction::do_action(config &c) 156107665Simp{ 157108783Simp string s = c.expand_string(_cmd); 158113790Simp if (Dflag) 159108783Simp fprintf(stderr, "Executing '%s'\n", s.c_str()); 160108783Simp ::system(s.c_str()); 161107665Simp return (true); 162107665Simp} 163107665Simp 164108014Simpmatch::match(config &c, const char *var, const char *re) 165108783Simp : _var(var) 166107665Simp{ 167108783Simp string pattern = re; 168108783Simp _re = "^"; 169108783Simp _re.append(c.expand_string(string(re))); 170108783Simp _re.append("$"); 171108783Simp regcomp(&_regex, _re.c_str(), REG_EXTENDED | REG_NOSUB); 172107665Simp} 173107665Simp 174107665Simpmatch::~match() 175107665Simp{ 176108014Simp regfree(&_regex); 177107665Simp} 178107665Simp 179107665Simpbool 180108014Simpmatch::do_match(config &c) 181107665Simp{ 182108014Simp string value = c.get_variable(_var); 183108014Simp bool retval; 184108014Simp 185113790Simp if (Dflag) 186108783Simp fprintf(stderr, "Testing %s=%s against %s\n", _var.c_str(), 187108783Simp value.c_str(), _re.c_str()); 188108783Simp 189108014Simp retval = (regexec(&_regex, value.c_str(), 0, NULL, 0) == 0); 190108014Simp return retval; 191107665Simp} 192107665Simp 193147874Simp#include <sys/sockio.h> 194147874Simp#include <net/if.h> 195147874Simp#include <net/if_media.h> 196147874Simp 197147874Simpmedia::media(config &c, const char *var, const char *type) 198147874Simp : _var(var), _type(-1) 199147874Simp{ 200147874Simp static struct ifmedia_description media_types[] = { 201147874Simp { IFM_ETHER, "Ethernet" }, 202147874Simp { IFM_TOKEN, "Tokenring" }, 203147874Simp { IFM_FDDI, "FDDI" }, 204147874Simp { IFM_IEEE80211, "802.11" }, 205147874Simp { IFM_ATM, "ATM" }, 206147874Simp { IFM_CARP, "CARP" }, 207147874Simp { -1, "unknown" }, 208147874Simp { 0, NULL }, 209147874Simp }; 210147874Simp for (int i = 0; media_types[i].ifmt_string != NULL; i++) 211147874Simp if (strcasecmp(type, media_types[i].ifmt_string) == 0) { 212147874Simp _type = media_types[i].ifmt_word; 213147874Simp break; 214147874Simp } 215147874Simp} 216147874Simp 217147874Simpmedia::~media() 218147874Simp{ 219147874Simp} 220147874Simp 221147874Simpbool 222147874Simpmedia::do_match(config &c) 223147874Simp{ 224147874Simp string value = c.get_variable("device-name"); 225147874Simp struct ifmediareq ifmr; 226147874Simp bool retval; 227147874Simp int s; 228147874Simp 229147874Simp if (Dflag) 230147874Simp fprintf(stderr, "Testing media type of %s against 0x%x\n", 231147874Simp value.c_str(), _type); 232147874Simp 233147874Simp retval = false; 234147874Simp 235147874Simp s = socket(PF_INET, SOCK_DGRAM, 0); 236147874Simp if (s >= 0) { 237147874Simp memset(&ifmr, 0, sizeof(ifmr)); 238147874Simp strncpy(ifmr.ifm_name, value.c_str(), sizeof(ifmr.ifm_name)); 239147874Simp 240147874Simp if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0 && 241147874Simp ifmr.ifm_status & IFM_AVALID) { 242147874Simp if (Dflag) 243147874Simp fprintf(stderr, "%s has media type 0x%x\n", 244147874Simp value.c_str(), IFM_TYPE(ifmr.ifm_active)); 245147874Simp retval = (IFM_TYPE(ifmr.ifm_active) == _type); 246147874Simp } else if (_type == -1) { 247147874Simp if (Dflag) 248147874Simp fprintf(stderr, "%s has unknown media type\n", 249147874Simp value.c_str()); 250147874Simp retval = true; 251147874Simp } 252147874Simp close(s); 253147874Simp } 254147874Simp 255147874Simp return retval; 256147874Simp} 257147874Simp 258107665Simpconst string var_list::bogus = "_$_$_$_$_B_O_G_U_S_$_$_$_$_"; 259107665Simpconst string var_list::nothing = ""; 260107665Simp 261107665Simpconst string & 262107665Simpvar_list::get_variable(const string &var) const 263107665Simp{ 264107665Simp map<string, string>::const_iterator i; 265107665Simp 266107665Simp i = _vars.find(var); 267107665Simp if (i == _vars.end()) 268108783Simp return (var_list::bogus); 269107665Simp return (i->second); 270107665Simp} 271107665Simp 272107665Simpbool 273107665Simpvar_list::is_set(const string &var) const 274107665Simp{ 275107665Simp return (_vars.find(var) != _vars.end()); 276107665Simp} 277107665Simp 278107665Simpvoid 279107665Simpvar_list::set_variable(const string &var, const string &val) 280107665Simp{ 281113790Simp if (Dflag) 282145218Simp fprintf(stderr, "setting %s=%s\n", var.c_str(), val.c_str()); 283107665Simp _vars[var] = val; 284107665Simp} 285107665Simp 286107665Simpvoid 287107665Simpconfig::reset(void) 288107665Simp{ 289107665Simp _dir_list.clear(); 290108783Simp delete_and_clear(_var_list_table); 291108783Simp delete_and_clear(_attach_list); 292108783Simp delete_and_clear(_detach_list); 293108783Simp delete_and_clear(_nomatch_list); 294121487Simp delete_and_clear(_notify_list); 295107665Simp} 296107665Simp 297107665Simpvoid 298107665Simpconfig::parse_one_file(const char *fn) 299107665Simp{ 300113790Simp if (Dflag) 301107665Simp printf("Parsing %s\n", fn); 302107665Simp yyin = fopen(fn, "r"); 303107665Simp if (yyin == NULL) 304107665Simp err(1, "Cannot open config file %s", fn); 305107665Simp if (yyparse() != 0) 306107665Simp errx(1, "Cannot parse %s at line %d", fn, lineno); 307107665Simp fclose(yyin); 308107665Simp} 309107665Simp 310107665Simpvoid 311107665Simpconfig::parse_files_in_dir(const char *dirname) 312107665Simp{ 313107665Simp DIR *dirp; 314107665Simp struct dirent *dp; 315107665Simp char path[PATH_MAX]; 316107665Simp 317113790Simp if (Dflag) 318107665Simp printf("Parsing files in %s\n", dirname); 319107665Simp dirp = opendir(dirname); 320107665Simp if (dirp == NULL) 321107665Simp return; 322107665Simp readdir(dirp); /* Skip . */ 323107665Simp readdir(dirp); /* Skip .. */ 324107665Simp while ((dp = readdir(dirp)) != NULL) { 325107665Simp if (strcmp(dp->d_name + dp->d_namlen - 5, ".conf") == 0) { 326107665Simp snprintf(path, sizeof(path), "%s/%s", 327107665Simp dirname, dp->d_name); 328107665Simp parse_one_file(path); 329107665Simp } 330107665Simp } 331107665Simp} 332107665Simp 333108783Simpclass epv_greater { 334108783Simppublic: 335108783Simp int operator()(event_proc *const&l1, event_proc *const&l2) 336108783Simp { 337108783Simp return (l1->get_priority() > l2->get_priority()); 338108783Simp } 339108783Simp}; 340108783Simp 341107665Simpvoid 342108783Simpconfig::sort_vector(vector<event_proc *> &v) 343108783Simp{ 344108783Simp sort(v.begin(), v.end(), epv_greater()); 345108783Simp} 346108783Simp 347108783Simpvoid 348107665Simpconfig::parse(void) 349107665Simp{ 350107665Simp vector<string>::const_iterator i; 351107665Simp 352107665Simp parse_one_file(CF); 353107665Simp for (i = _dir_list.begin(); i != _dir_list.end(); i++) 354107665Simp parse_files_in_dir((*i).c_str()); 355108783Simp sort_vector(_attach_list); 356108783Simp sort_vector(_detach_list); 357108783Simp sort_vector(_nomatch_list); 358121487Simp sort_vector(_notify_list); 359107665Simp} 360107665Simp 361107665Simpvoid 362107665Simpconfig::drop_pidfile() 363107665Simp{ 364107665Simp FILE *fp; 365107665Simp 366107665Simp if (_pidfile == "") 367107665Simp return; 368107665Simp fp = fopen(_pidfile.c_str(), "w"); 369107665Simp if (fp == NULL) 370107665Simp return; 371107665Simp fprintf(fp, "%d\n", getpid()); 372107665Simp fclose(fp); 373107665Simp} 374107665Simp 375107665Simpvoid 376107665Simpconfig::add_attach(int prio, event_proc *p) 377107665Simp{ 378107665Simp p->set_priority(prio); 379107665Simp _attach_list.push_back(p); 380107665Simp} 381107665Simp 382107665Simpvoid 383107665Simpconfig::add_detach(int prio, event_proc *p) 384107665Simp{ 385107665Simp p->set_priority(prio); 386107665Simp _detach_list.push_back(p); 387107665Simp} 388107665Simp 389107665Simpvoid 390107665Simpconfig::add_directory(const char *dir) 391107665Simp{ 392107665Simp _dir_list.push_back(string(dir)); 393107665Simp} 394107665Simp 395107665Simpvoid 396107665Simpconfig::add_nomatch(int prio, event_proc *p) 397107665Simp{ 398107665Simp p->set_priority(prio); 399107665Simp _nomatch_list.push_back(p); 400107665Simp} 401107665Simp 402107665Simpvoid 403121487Simpconfig::add_notify(int prio, event_proc *p) 404121487Simp{ 405121487Simp p->set_priority(prio); 406121487Simp _notify_list.push_back(p); 407121487Simp} 408121487Simp 409121487Simpvoid 410107665Simpconfig::set_pidfile(const char *fn) 411107665Simp{ 412107665Simp _pidfile = string(fn); 413107665Simp} 414107665Simp 415107665Simpvoid 416107665Simpconfig::push_var_table() 417107665Simp{ 418107665Simp var_list *vl; 419107665Simp 420107665Simp vl = new var_list(); 421107665Simp _var_list_table.push_back(vl); 422113790Simp if (Dflag) 423108783Simp fprintf(stderr, "Pushing table\n"); 424107665Simp} 425107665Simp 426107665Simpvoid 427107665Simpconfig::pop_var_table() 428107665Simp{ 429107665Simp delete _var_list_table.back(); 430107665Simp _var_list_table.pop_back(); 431113790Simp if (Dflag) 432108783Simp fprintf(stderr, "Popping table\n"); 433107665Simp} 434107665Simp 435107665Simpvoid 436107665Simpconfig::set_variable(const char *var, const char *val) 437107665Simp{ 438107665Simp _var_list_table.back()->set_variable(var, val); 439107665Simp} 440107665Simp 441107665Simpconst string & 442107665Simpconfig::get_variable(const string &var) 443107665Simp{ 444107665Simp vector<var_list *>::reverse_iterator i; 445107665Simp 446107665Simp for (i = _var_list_table.rbegin(); i != _var_list_table.rend(); i++) { 447107665Simp if ((*i)->is_set(var)) 448108783Simp return ((*i)->get_variable(var)); 449107665Simp } 450107665Simp return (var_list::nothing); 451107665Simp} 452107665Simp 453108783Simpbool 454108783Simpconfig::is_id_char(char ch) 455108783Simp{ 456108783Simp return (ch != '\0' && (isalpha(ch) || isdigit(ch) || ch == '_' || 457108783Simp ch == '-')); 458108783Simp} 459108783Simp 460108014Simpvoid 461114081Simpconfig::expand_one(const char *&src, string &dst) 462107665Simp{ 463108014Simp int count; 464114081Simp string buffer, varstr; 465108014Simp 466108783Simp src++; 467108014Simp // $$ -> $ 468108014Simp if (*src == '$') { 469114081Simp dst.append(src++, 1); 470108014Simp return; 471108014Simp } 472108014Simp 473108014Simp // $(foo) -> $(foo) 474108783Simp // Not sure if I want to support this or not, so for now we just pass 475108783Simp // it through. 476108014Simp if (*src == '(') { 477114081Simp dst.append("$"); 478108014Simp count = 1; 479114081Simp /* If the string ends before ) is matched , return. */ 480114081Simp while (count > 0 && *src) { 481108014Simp if (*src == ')') 482108014Simp count--; 483108014Simp else if (*src == '(') 484108014Simp count++; 485114081Simp dst.append(src++, 1); 486108014Simp } 487108014Simp return; 488108014Simp } 489108014Simp 490108014Simp // ${^A-Za-z] -> $\1 491108014Simp if (!isalpha(*src)) { 492114081Simp dst.append("$"); 493114081Simp dst.append(src++, 1); 494108014Simp return; 495108014Simp } 496108014Simp 497108014Simp // $var -> replace with value 498114081Simp do { 499114081Simp buffer.append(src++, 1); 500114084Simp } while (is_id_char(*src)); 501114081Simp buffer.append("", 1); 502114081Simp varstr = get_variable(buffer.c_str()); 503114081Simp dst.append(varstr); 504107665Simp} 505107665Simp 506108014Simpconst string 507108014Simpconfig::expand_string(const string &s) 508108014Simp{ 509108014Simp const char *src; 510114081Simp string dst; 511108014Simp 512108014Simp src = s.c_str(); 513108014Simp while (*src) { 514108014Simp if (*src == '$') 515114081Simp expand_one(src, dst); 516108014Simp else 517114081Simp dst.append(src++, 1); 518108014Simp } 519114081Simp dst.append("", 1); 520108014Simp 521114081Simp return (dst); 522108014Simp} 523108014Simp 524108783Simpbool 525108783Simpconfig::chop_var(char *&buffer, char *&lhs, char *&rhs) 526108783Simp{ 527108783Simp char *walker; 528108783Simp 529108783Simp if (*buffer == '\0') 530108783Simp return (false); 531108783Simp walker = lhs = buffer; 532108783Simp while (is_id_char(*walker)) 533108783Simp walker++; 534108783Simp if (*walker != '=') 535108783Simp return (false); 536108783Simp walker++; // skip = 537108783Simp if (*walker == '"') { 538108783Simp walker++; // skip " 539108783Simp rhs = walker; 540108783Simp while (*walker && *walker != '"') 541108783Simp walker++; 542108783Simp if (*walker != '"') 543108783Simp return (false); 544108783Simp rhs[-2] = '\0'; 545108783Simp *walker++ = '\0'; 546108783Simp } else { 547108783Simp rhs = walker; 548108783Simp while (*walker && !isspace(*walker)) 549108783Simp walker++; 550108783Simp if (*walker != '\0') 551108783Simp *walker++ = '\0'; 552108783Simp rhs[-1] = '\0'; 553108783Simp } 554113785Simp while (isspace(*walker)) 555113785Simp walker++; 556108783Simp buffer = walker; 557108783Simp return (true); 558108783Simp} 559108783Simp 560108783Simp 561108783Simpchar * 562108783Simpconfig::set_vars(char *buffer) 563108783Simp{ 564108783Simp char *lhs; 565108783Simp char *rhs; 566108783Simp 567108783Simp while (1) { 568108783Simp if (!chop_var(buffer, lhs, rhs)) 569108783Simp break; 570108783Simp set_variable(lhs, rhs); 571108783Simp } 572108783Simp return (buffer); 573108783Simp} 574108783Simp 575108783Simpvoid 576108783Simpconfig::find_and_execute(char type) 577108783Simp{ 578108783Simp vector<event_proc *> *l; 579108783Simp vector<event_proc *>::const_iterator i; 580108783Simp char *s; 581108783Simp 582108783Simp switch (type) { 583108783Simp default: 584108783Simp return; 585121487Simp case notify: 586121487Simp l = &_notify_list; 587121487Simp s = "notify"; 588121487Simp break; 589108783Simp case nomatch: 590108783Simp l = &_nomatch_list; 591108783Simp s = "nomatch"; 592108783Simp break; 593108783Simp case attach: 594108783Simp l = &_attach_list; 595108783Simp s = "attach"; 596108783Simp break; 597108783Simp case detach: 598108783Simp l = &_detach_list; 599108783Simp s = "detach"; 600108783Simp break; 601108783Simp } 602113790Simp if (Dflag) 603108783Simp fprintf(stderr, "Processing %s event\n", s); 604108783Simp for (i = l->begin(); i != l->end(); i++) { 605108783Simp if ((*i)->matches(*this)) { 606108783Simp (*i)->run(*this); 607108783Simp break; 608108783Simp } 609108783Simp } 610108783Simp 611108783Simp} 612108783Simp 613107665Simp 614107665Simpstatic void 615108783Simpprocess_event(char *buffer) 616107665Simp{ 617107665Simp char type; 618107665Simp char *sp; 619107665Simp 620108783Simp sp = buffer + 1; 621113790Simp if (Dflag) 622108783Simp fprintf(stderr, "Processing event '%s'\n", buffer); 623107665Simp type = *buffer++; 624108783Simp cfg.push_var_table(); 625108783Simp // No match doesn't have a device, and the format is a little 626108783Simp // different, so handle it separately. 627121487Simp switch (type) { 628121487Simp case notify: 629121487Simp sp = cfg.set_vars(sp); 630121487Simp break; 631121487Simp case nomatch: 632145218Simp //? at location pnp-info on bus 633145218Simp sp = strchr(sp, ' '); 634145218Simp if (sp == NULL) 635145218Simp return; /* Can't happen? */ 636145218Simp *sp++ = '\0'; 637121487Simp if (strncmp(sp, "at ", 3) == 0) 638121487Simp sp += 3; 639121487Simp sp = cfg.set_vars(sp); 640121487Simp if (strncmp(sp, "on ", 3) == 0) 641121487Simp cfg.set_variable("bus", sp + 3); 642121487Simp break; 643121487Simp case attach: /*FALLTHROUGH*/ 644121487Simp case detach: 645108783Simp sp = strchr(sp, ' '); 646108783Simp if (sp == NULL) 647108783Simp return; /* Can't happen? */ 648108783Simp *sp++ = '\0'; 649108783Simp cfg.set_variable("device-name", buffer); 650113785Simp if (strncmp(sp, "at ", 3) == 0) 651113785Simp sp += 3; 652113785Simp sp = cfg.set_vars(sp); 653113785Simp if (strncmp(sp, "on ", 3) == 0) 654113785Simp cfg.set_variable("bus", sp + 3); 655121487Simp break; 656108783Simp } 657113785Simp 658108783Simp cfg.find_and_execute(type); 659108783Simp cfg.pop_var_table(); 660107665Simp} 661107665Simp 662131397Simpint 663131397Simpcreate_socket(const char *name) 664131397Simp{ 665131397Simp int fd, slen; 666131397Simp struct sockaddr_un sun; 667131397Simp 668131397Simp if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) 669131397Simp err(1, "socket"); 670131397Simp bzero(&sun, sizeof(sun)); 671131397Simp sun.sun_family = AF_UNIX; 672131397Simp strlcpy(sun.sun_path, name, sizeof(sun.sun_path)); 673131397Simp slen = SUN_LEN(&sun); 674131397Simp unlink(name); 675131397Simp if (bind(fd, (struct sockaddr *) & sun, slen) < 0) 676131397Simp err(1, "bind"); 677131397Simp listen(fd, 4); 678147972Smarcus chown(name, 0, 0); /* XXX - root.wheel */ 679147972Smarcus chmod(name, 0660); 680131397Simp return (fd); 681131397Simp} 682131397Simp 683131397Simplist<int> clients; 684131397Simp 685131397Simpvoid 686131397Simpnotify_clients(const char *data, int len) 687131397Simp{ 688131397Simp list<int> bad; 689131397Simp list<int>::const_iterator i; 690131397Simp 691131397Simp for (i = clients.begin(); i != clients.end(); i++) { 692131397Simp if (write(*i, data, len) <= 0) { 693131397Simp bad.push_back(*i); 694131397Simp close(*i); 695131397Simp } 696131397Simp } 697131397Simp 698131397Simp for (i = bad.begin(); i != bad.end(); i++) 699131397Simp clients.erase(find(clients.begin(), clients.end(), *i)); 700131397Simp} 701131397Simp 702131397Simpvoid 703131397Simpnew_client(int fd) 704131397Simp{ 705131397Simp int s; 706131397Simp 707131397Simp s = accept(fd, NULL, NULL); 708131397Simp if (s != -1) 709131397Simp clients.push_back(s); 710131397Simp} 711131397Simp 712107665Simpstatic void 713107665Simpevent_loop(void) 714107665Simp{ 715107665Simp int rv; 716107665Simp int fd; 717107665Simp char buffer[DEVCTL_MAXBUF]; 718113790Simp int once = 0; 719131397Simp int server_fd, max_fd; 720113790Simp timeval tv; 721113790Simp fd_set fds; 722107665Simp 723107665Simp fd = open(PATH_DEVCTL, O_RDONLY); 724107665Simp if (fd == -1) 725131397Simp err(1, "Can't open devctl device %s", PATH_DEVCTL); 726107665Simp if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) 727131397Simp err(1, "Can't set close-on-exec flag on devctl"); 728131397Simp server_fd = create_socket(PIPE); 729131397Simp max_fd = max(fd, server_fd) + 1; 730107665Simp while (1) { 731107665Simp if (romeo_must_die) 732107665Simp break; 733113790Simp if (!once && !dflag && !nflag) { 734113790Simp // Check to see if we have any events pending. 735113790Simp tv.tv_sec = 0; 736113790Simp tv.tv_usec = 0; 737113790Simp FD_ZERO(&fds); 738113790Simp FD_SET(fd, &fds); 739113790Simp rv = select(fd + 1, &fds, &fds, &fds, &tv); 740113790Simp // No events -> we've processed all pending events 741117944Simp if (rv == 0) { 742113790Simp if (Dflag) 743113790Simp fprintf(stderr, "Calling daemon\n"); 744113790Simp daemon(0, 0); 745117246Simp cfg.drop_pidfile(); 746113790Simp once++; 747113790Simp } 748113790Simp } 749131397Simp FD_ZERO(&fds); 750131397Simp FD_SET(fd, &fds); 751131397Simp FD_SET(server_fd, &fds); 752131397Simp rv = select(max_fd, &fds, NULL, NULL, NULL); 753131397Simp if (rv == -1) { 754131397Simp if (errno == EINTR) 755131397Simp continue; 756131397Simp err(1, "select"); 757131397Simp } 758131397Simp if (FD_ISSET(fd, &fds)) { 759131397Simp rv = read(fd, buffer, sizeof(buffer) - 1); 760131397Simp if (rv > 0) { 761131397Simp notify_clients(buffer, rv); 762107665Simp buffer[rv] = '\0'; 763131397Simp while (buffer[--rv] == '\n') 764131397Simp buffer[rv] = '\0'; 765131397Simp process_event(buffer); 766131397Simp } else if (rv < 0) { 767131397Simp if (errno != EINTR) 768131397Simp break; 769131397Simp } else { 770131397Simp /* EOF */ 771107665Simp break; 772131397Simp } 773107665Simp } 774131397Simp if (FD_ISSET(server_fd, &fds)) 775131397Simp new_client(server_fd); 776107665Simp } 777107665Simp close(fd); 778107665Simp} 779107665Simp 780107665Simp/* 781107665Simp * functions that the parser uses. 782107665Simp */ 783107665Simpvoid 784107665Simpadd_attach(int prio, event_proc *p) 785107665Simp{ 786107665Simp cfg.add_attach(prio, p); 787107665Simp} 788107665Simp 789107665Simpvoid 790107665Simpadd_detach(int prio, event_proc *p) 791107665Simp{ 792107665Simp cfg.add_detach(prio, p); 793107665Simp} 794107665Simp 795107665Simpvoid 796107665Simpadd_directory(const char *dir) 797107665Simp{ 798107665Simp cfg.add_directory(dir); 799107665Simp free(const_cast<char *>(dir)); 800107665Simp} 801107665Simp 802107665Simpvoid 803107665Simpadd_nomatch(int prio, event_proc *p) 804107665Simp{ 805107665Simp cfg.add_nomatch(prio, p); 806107665Simp} 807107665Simp 808121487Simpvoid 809121487Simpadd_notify(int prio, event_proc *p) 810121487Simp{ 811121487Simp cfg.add_notify(prio, p); 812121487Simp} 813121487Simp 814107665Simpevent_proc * 815107665Simpadd_to_event_proc(event_proc *ep, eps *eps) 816107665Simp{ 817107665Simp if (ep == NULL) 818107665Simp ep = new event_proc(); 819107665Simp ep->add(eps); 820107665Simp return (ep); 821107665Simp} 822107665Simp 823107665Simpeps * 824107665Simpnew_action(const char *cmd) 825107665Simp{ 826107665Simp eps *e = new action(cmd); 827107665Simp free(const_cast<char *>(cmd)); 828107665Simp return (e); 829107665Simp} 830107665Simp 831107665Simpeps * 832107665Simpnew_match(const char *var, const char *re) 833107665Simp{ 834108014Simp eps *e = new match(cfg, var, re); 835107665Simp free(const_cast<char *>(var)); 836107665Simp free(const_cast<char *>(re)); 837107665Simp return (e); 838107665Simp} 839107665Simp 840147874Simpeps * 841147874Simpnew_media(const char *var, const char *re) 842147874Simp{ 843147874Simp eps *e = new media(cfg, var, re); 844147874Simp free(const_cast<char *>(var)); 845147874Simp free(const_cast<char *>(re)); 846147874Simp return (e); 847147874Simp} 848147874Simp 849107665Simpvoid 850107665Simpset_pidfile(const char *name) 851107665Simp{ 852107665Simp cfg.set_pidfile(name); 853107665Simp free(const_cast<char *>(name)); 854107665Simp} 855107665Simp 856107665Simpvoid 857107665Simpset_variable(const char *var, const char *val) 858107665Simp{ 859107665Simp cfg.set_variable(var, val); 860107665Simp free(const_cast<char *>(var)); 861107665Simp free(const_cast<char *>(val)); 862107665Simp} 863107665Simp 864107665Simp 865107665Simp 866107665Simpstatic void 867107665Simpgensighand(int) 868107665Simp{ 869107665Simp romeo_must_die++; 870107665Simp _exit(0); 871107665Simp} 872107665Simp 873107665Simpstatic void 874107665Simpusage() 875107665Simp{ 876141611Sru fprintf(stderr, "usage: %s [-Ddn]\n", getprogname()); 877107665Simp exit(1); 878107665Simp} 879107665Simp 880113787Simpstatic void 881113787Simpcheck_devd_enabled() 882113787Simp{ 883113787Simp int val = 0; 884113787Simp size_t len; 885113787Simp 886113787Simp len = sizeof(val); 887114541Simp if (sysctlbyname(SYSCTL, &val, &len, NULL, 0) != 0) 888113787Simp errx(1, "devctl sysctl missing from kernel!"); 889113787Simp if (val) { 890113787Simp warnx("Setting " SYSCTL " to 0"); 891113787Simp val = 0; 892113787Simp sysctlbyname(SYSCTL, NULL, NULL, &val, sizeof(val)); 893113787Simp } 894113787Simp} 895113787Simp 896107665Simp/* 897107665Simp * main 898107665Simp */ 899107665Simpint 900107665Simpmain(int argc, char **argv) 901107665Simp{ 902107665Simp int ch; 903107665Simp 904113787Simp check_devd_enabled(); 905113790Simp while ((ch = getopt(argc, argv, "Ddn")) != -1) { 906107665Simp switch (ch) { 907113790Simp case 'D': 908113790Simp Dflag++; 909113790Simp break; 910107665Simp case 'd': 911107665Simp dflag++; 912107665Simp break; 913113790Simp case 'n': 914113790Simp nflag++; 915113790Simp break; 916107665Simp default: 917107665Simp usage(); 918107665Simp } 919107665Simp } 920107665Simp 921107665Simp cfg.parse(); 922117246Simp if (!dflag && nflag) { 923107665Simp daemon(0, 0); 924117246Simp cfg.drop_pidfile(); 925117246Simp } 926146306Simp signal(SIGPIPE, SIG_IGN); 927107665Simp signal(SIGHUP, gensighand); 928107665Simp signal(SIGINT, gensighand); 929107665Simp signal(SIGTERM, gensighand); 930107665Simp event_loop(); 931107665Simp return (0); 932107665Simp} 933