1 /*- 2 * Copyright (c) 2002-2010 M. Warner Losh. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * my_system is a variation on lib/libc/stdlib/system.c: 27 * 28 * Copyright (c) 1988, 1993 29 * The Regents of the University of California. All rights reserved. 30 * 31 * Redistribution and use in source and binary forms, with or without 32 * modification, are permitted provided that the following conditions 33 * are met: 34 * 1. Redistributions of source code must retain the above copyright 35 * notice, this list of conditions and the following disclaimer. 36 * 2. Redistributions in binary form must reproduce the above copyright 37 * notice, this list of conditions and the following disclaimer in the 38 * documentation and/or other materials provided with the distribution. 39 * 4. Neither the name of the University nor the names of its contributors 40 * may be used to endorse or promote products derived from this software 41 * without specific prior written permission. 42 * 43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 53 * SUCH DAMAGE. 54 */ 55 56 /* 57 * DEVD control daemon. 58 */ 59 60 // TODO list: 61 // o devd.conf and devd man pages need a lot of help: 62 // - devd needs to document the unix domain socket 63 // - devd.conf needs more details on the supported statements. 64 65 #include <sys/cdefs.h> 66 __FBSDID("$FreeBSD$"); 67 68 #include <sys/param.h> 69 #include <sys/socket.h> 70 #include <sys/stat.h> 71 #include <sys/sysctl.h> 72 #include <sys/types.h> 73 #include <sys/wait.h> 74 #include <sys/un.h> 75 76 #include <cctype> 77 #include <cerrno> 78 #include <cstdlib> 79 #include <cstdio> 80 #include <csignal> 81 #include <cstring> 82 #include <cstdarg> 83 84 #include <dirent.h> 85 #include <err.h> 86 #include <fcntl.h> 87 #include <libutil.h> 88 #include <paths.h> 89 #include <poll.h> 90 #include <regex.h> 91 #include <syslog.h> 92 #include <unistd.h> 93 94 #include <algorithm> 95 #include <map> 96 #include <string> 97 #include <list> 98 #include <vector> 99 100 #include "devd.h" /* C compatible definitions */ 101 #include "devd.hh" /* C++ class definitions */ 102 103 #define PIPE "/var/run/devd.pipe" 104 #define CF "/etc/devd.conf" 105 #define SYSCTL "hw.bus.devctl_disable" 106 107 using namespace std; 108 109 extern FILE *yyin; 110 extern int lineno; 111 112 static const char notify = '!'; 113 static const char nomatch = '?'; 114 static const char attach = '+'; 115 static const char detach = '-'; 116 117 static struct pidfh *pfh; 118 119 int dflag; 120 int nflag; 121 static unsigned total_events = 0; 122 static volatile sig_atomic_t got_siginfo = 0; 123 static volatile sig_atomic_t romeo_must_die = 0; 124 125 static const char *configfile = CF; 126 127 static void devdlog(int priority, const char* message, ...); 128 static void event_loop(void); 129 static void usage(void); 130 131 template <class T> void 132 delete_and_clear(vector<T *> &v) 133 { 134 typename vector<T *>::const_iterator i; 135 136 for (i = v.begin(); i != v.end(); ++i) 137 delete *i; 138 v.clear(); 139 } 140 141 config cfg; 142 143 event_proc::event_proc() : _prio(-1) 144 { 145 _epsvec.reserve(4); 146 } 147 148 event_proc::~event_proc() 149 { 150 delete_and_clear(_epsvec); 151 } 152 153 void 154 event_proc::add(eps *eps) 155 { 156 _epsvec.push_back(eps); 157 } 158 159 bool 160 event_proc::matches(config &c) const 161 { 162 vector<eps *>::const_iterator i; 163 164 for (i = _epsvec.begin(); i != _epsvec.end(); ++i) 165 if (!(*i)->do_match(c)) 166 return (false); 167 return (true); 168 } 169 170 bool 171 event_proc::run(config &c) const 172 { 173 vector<eps *>::const_iterator i; 174 175 for (i = _epsvec.begin(); i != _epsvec.end(); ++i) 176 if (!(*i)->do_action(c)) 177 return (false); 178 return (true); 179 } 180 181 action::action(const char *cmd) 182 : _cmd(cmd) 183 { 184 // nothing 185 } 186 187 action::~action() 188 { 189 // nothing 190 } 191 192 static int 193 my_system(const char *command) 194 { 195 pid_t pid, savedpid; 196 int pstat; 197 struct sigaction ign, intact, quitact; 198 sigset_t newsigblock, oldsigblock; 199 200 if (!command) /* just checking... */ 201 return (1); 202 203 /* 204 * Ignore SIGINT and SIGQUIT, block SIGCHLD. Remember to save 205 * existing signal dispositions. 206 */ 207 ign.sa_handler = SIG_IGN; 208 ::sigemptyset(&ign.sa_mask); 209 ign.sa_flags = 0; 210 ::sigaction(SIGINT, &ign, &intact); 211 ::sigaction(SIGQUIT, &ign, &quitact); 212 ::sigemptyset(&newsigblock); 213 ::sigaddset(&newsigblock, SIGCHLD); 214 ::sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock); 215 switch (pid = ::fork()) { 216 case -1: /* error */ 217 break; 218 case 0: /* child */ 219 /* 220 * Restore original signal dispositions and exec the command. 221 */ 222 ::sigaction(SIGINT, &intact, NULL); 223 ::sigaction(SIGQUIT, &quitact, NULL); 224 ::sigprocmask(SIG_SETMASK, &oldsigblock, NULL); 225 /* 226 * Close the PID file, and all other open descriptors. 227 * Inherit std{in,out,err} only. 228 */ 229 cfg.close_pidfile(); 230 ::closefrom(3); 231 ::execl(_PATH_BSHELL, "sh", "-c", command, (char *)NULL); 232 ::_exit(127); 233 default: /* parent */ 234 savedpid = pid; 235 do { 236 pid = ::wait4(savedpid, &pstat, 0, (struct rusage *)0); 237 } while (pid == -1 && errno == EINTR); 238 break; 239 } 240 ::sigaction(SIGINT, &intact, NULL); 241 ::sigaction(SIGQUIT, &quitact, NULL); 242 ::sigprocmask(SIG_SETMASK, &oldsigblock, NULL); 243 return (pid == -1 ? -1 : pstat); 244 } 245 246 bool 247 action::do_action(config &c) 248 { 249 string s = c.expand_string(_cmd.c_str()); 250 devdlog(LOG_NOTICE, "Executing '%s'\n", s.c_str()); 251 my_system(s.c_str()); 252 return (true); 253 } 254 255 match::match(config &c, const char *var, const char *re) : 256 _inv(re[0] == '!'), 257 _var(var), 258 _re(c.expand_string(_inv ? re + 1 : re, "^", "$")) 259 { 260 regcomp(&_regex, _re.c_str(), REG_EXTENDED | REG_NOSUB | REG_ICASE); 261 } 262 263 match::~match() 264 { 265 regfree(&_regex); 266 } 267 268 bool 269 match::do_match(config &c) 270 { 271 const string &value = c.get_variable(_var); 272 bool retval; 273 274 /* 275 * This function gets called WAY too often to justify calling syslog() 276 * each time, even at LOG_DEBUG. Because if syslogd isn't running, it 277 * can consume excessive amounts of systime inside of connect(). Only 278 * log when we're in -d mode. 279 */ 280 if (dflag) { 281 devdlog(LOG_DEBUG, "Testing %s=%s against %s, invert=%d\n", 282 _var.c_str(), value.c_str(), _re.c_str(), _inv); 283 } 284 285 retval = (regexec(&_regex, value.c_str(), 0, NULL, 0) == 0); 286 if (_inv == 1) 287 retval = (retval == 0) ? 1 : 0; 288 289 return (retval); 290 } 291 292 #include <sys/sockio.h> 293 #include <net/if.h> 294 #include <net/if_media.h> 295 296 media::media(config &, const char *var, const char *type) 297 : _var(var), _type(-1) 298 { 299 static struct ifmedia_description media_types[] = { 300 { IFM_ETHER, "Ethernet" }, 301 { IFM_TOKEN, "Tokenring" }, 302 { IFM_FDDI, "FDDI" }, 303 { IFM_IEEE80211, "802.11" }, 304 { IFM_ATM, "ATM" }, 305 { -1, "unknown" }, 306 { 0, NULL }, 307 }; 308 for (int i = 0; media_types[i].ifmt_string != NULL; ++i) 309 if (strcasecmp(type, media_types[i].ifmt_string) == 0) { 310 _type = media_types[i].ifmt_word; 311 break; 312 } 313 } 314 315 media::~media() 316 { 317 } 318 319 bool 320 media::do_match(config &c) 321 { 322 string value; 323 struct ifmediareq ifmr; 324 bool retval; 325 int s; 326 327 // Since we can be called from both a device attach/detach 328 // context where device-name is defined and what we want, 329 // as well as from a link status context, where subsystem is 330 // the name of interest, first try device-name and fall back 331 // to subsystem if none exists. 332 value = c.get_variable("device-name"); 333 if (value.empty()) 334 value = c.get_variable("subsystem"); 335 devdlog(LOG_DEBUG, "Testing media type of %s against 0x%x\n", 336 value.c_str(), _type); 337 338 retval = false; 339 340 s = socket(PF_INET, SOCK_DGRAM, 0); 341 if (s >= 0) { 342 memset(&ifmr, 0, sizeof(ifmr)); 343 strncpy(ifmr.ifm_name, value.c_str(), sizeof(ifmr.ifm_name)); 344 345 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0 && 346 ifmr.ifm_status & IFM_AVALID) { 347 devdlog(LOG_DEBUG, "%s has media type 0x%x\n", 348 value.c_str(), IFM_TYPE(ifmr.ifm_active)); 349 retval = (IFM_TYPE(ifmr.ifm_active) == _type); 350 } else if (_type == -1) { 351 devdlog(LOG_DEBUG, "%s has unknown media type\n", 352 value.c_str()); 353 retval = true; 354 } 355 close(s); 356 } 357 358 return (retval); 359 } 360 361 const string var_list::bogus = "_$_$_$_$_B_O_G_U_S_$_$_$_$_"; 362 const string var_list::nothing = ""; 363 364 const string & 365 var_list::get_variable(const string &var) const 366 { 367 map<string, string>::const_iterator i; 368 369 i = _vars.find(var); 370 if (i == _vars.end()) 371 return (var_list::bogus); 372 return (i->second); 373 } 374 375 bool 376 var_list::is_set(const string &var) const 377 { 378 return (_vars.find(var) != _vars.end()); 379 } 380 381 void 382 var_list::set_variable(const string &var, const string &val) 383 { 384 /* 385 * This function gets called WAY too often to justify calling syslog() 386 * each time, even at LOG_DEBUG. Because if syslogd isn't running, it 387 * can consume excessive amounts of systime inside of connect(). Only 388 * log when we're in -d mode. 389 */ 390 if (dflag) 391 devdlog(LOG_DEBUG, "setting %s=%s\n", var.c_str(), val.c_str()); 392 _vars[var] = val; 393 } 394 395 void 396 config::reset(void) 397 { 398 _dir_list.clear(); 399 delete_and_clear(_var_list_table); 400 delete_and_clear(_attach_list); 401 delete_and_clear(_detach_list); 402 delete_and_clear(_nomatch_list); 403 delete_and_clear(_notify_list); 404 } 405 406 void 407 config::parse_one_file(const char *fn) 408 { 409 devdlog(LOG_DEBUG, "Parsing %s\n", fn); 410 yyin = fopen(fn, "r"); 411 if (yyin == NULL) 412 err(1, "Cannot open config file %s", fn); 413 lineno = 1; 414 if (yyparse() != 0) 415 errx(1, "Cannot parse %s at line %d", fn, lineno); 416 fclose(yyin); 417 } 418 419 void 420 config::parse_files_in_dir(const char *dirname) 421 { 422 DIR *dirp; 423 struct dirent *dp; 424 char path[PATH_MAX]; 425 426 devdlog(LOG_DEBUG, "Parsing files in %s\n", dirname); 427 dirp = opendir(dirname); 428 if (dirp == NULL) 429 return; 430 readdir(dirp); /* Skip . */ 431 readdir(dirp); /* Skip .. */ 432 while ((dp = readdir(dirp)) != NULL) { 433 if (strcmp(dp->d_name + dp->d_namlen - 5, ".conf") == 0) { 434 snprintf(path, sizeof(path), "%s/%s", 435 dirname, dp->d_name); 436 parse_one_file(path); 437 } 438 } 439 closedir(dirp); 440 } 441 442 class epv_greater { 443 public: 444 int operator()(event_proc *const&l1, event_proc *const&l2) const 445 { 446 return (l1->get_priority() > l2->get_priority()); 447 } 448 }; 449 450 void 451 config::sort_vector(vector<event_proc *> &v) 452 { 453 stable_sort(v.begin(), v.end(), epv_greater()); 454 } 455 456 void 457 config::parse(void) 458 { 459 vector<string>::const_iterator i; 460 461 parse_one_file(configfile); 462 for (i = _dir_list.begin(); i != _dir_list.end(); ++i) 463 parse_files_in_dir((*i).c_str()); 464 sort_vector(_attach_list); 465 sort_vector(_detach_list); 466 sort_vector(_nomatch_list); 467 sort_vector(_notify_list); 468 } 469 470 void 471 config::open_pidfile() 472 { 473 pid_t otherpid; 474 475 if (_pidfile.empty()) 476 return; 477 pfh = pidfile_open(_pidfile.c_str(), 0600, &otherpid); 478 if (pfh == NULL) { 479 if (errno == EEXIST) 480 errx(1, "devd already running, pid: %d", (int)otherpid); 481 warn("cannot open pid file"); 482 } 483 } 484 485 void 486 config::write_pidfile() 487 { 488 489 pidfile_write(pfh); 490 } 491 492 void 493 config::close_pidfile() 494 { 495 496 pidfile_close(pfh); 497 } 498 499 void 500 config::remove_pidfile() 501 { 502 503 pidfile_remove(pfh); 504 } 505 506 void 507 config::add_attach(int prio, event_proc *p) 508 { 509 p->set_priority(prio); 510 _attach_list.push_back(p); 511 } 512 513 void 514 config::add_detach(int prio, event_proc *p) 515 { 516 p->set_priority(prio); 517 _detach_list.push_back(p); 518 } 519 520 void 521 config::add_directory(const char *dir) 522 { 523 _dir_list.push_back(string(dir)); 524 } 525 526 void 527 config::add_nomatch(int prio, event_proc *p) 528 { 529 p->set_priority(prio); 530 _nomatch_list.push_back(p); 531 } 532 533 void 534 config::add_notify(int prio, event_proc *p) 535 { 536 p->set_priority(prio); 537 _notify_list.push_back(p); 538 } 539 540 void 541 config::set_pidfile(const char *fn) 542 { 543 _pidfile = fn; 544 } 545 546 void 547 config::push_var_table() 548 { 549 var_list *vl; 550 551 vl = new var_list(); 552 _var_list_table.push_back(vl); 553 devdlog(LOG_DEBUG, "Pushing table\n"); 554 } 555 556 void 557 config::pop_var_table() 558 { 559 delete _var_list_table.back(); 560 _var_list_table.pop_back(); 561 devdlog(LOG_DEBUG, "Popping table\n"); 562 } 563 564 void 565 config::set_variable(const char *var, const char *val) 566 { 567 _var_list_table.back()->set_variable(var, val); 568 } 569 570 const string & 571 config::get_variable(const string &var) 572 { 573 vector<var_list *>::reverse_iterator i; 574 575 for (i = _var_list_table.rbegin(); i != _var_list_table.rend(); ++i) { 576 if ((*i)->is_set(var)) 577 return ((*i)->get_variable(var)); 578 } 579 return (var_list::nothing); 580 } 581 582 bool 583 config::is_id_char(char ch) const 584 { 585 return (ch != '\0' && (isalpha(ch) || isdigit(ch) || ch == '_' || 586 ch == '-')); 587 } 588 589 void 590 config::expand_one(const char *&src, string &dst) 591 { 592 int count; 593 string buffer; 594 595 src++; 596 // $$ -> $ 597 if (*src == '$') { 598 dst += *src++; 599 return; 600 } 601 602 // $(foo) -> $(foo) 603 // Not sure if I want to support this or not, so for now we just pass 604 // it through. 605 if (*src == '(') { 606 dst += '$'; 607 count = 1; 608 /* If the string ends before ) is matched , return. */ 609 while (count > 0 && *src) { 610 if (*src == ')') 611 count--; 612 else if (*src == '(') 613 count++; 614 dst += *src++; 615 } 616 return; 617 } 618 619 // $[^A-Za-z] -> $\1 620 if (!isalpha(*src)) { 621 dst += '$'; 622 dst += *src++; 623 return; 624 } 625 626 // $var -> replace with value 627 do { 628 buffer += *src++; 629 } while (is_id_char(*src)); 630 dst.append(get_variable(buffer)); 631 } 632 633 const string 634 config::expand_string(const char *src, const char *prepend, const char *append) 635 { 636 const char *var_at; 637 string dst; 638 639 /* 640 * 128 bytes is enough for 2427 of 2438 expansions that happen 641 * while parsing config files, as tested on 2013-01-30. 642 */ 643 dst.reserve(128); 644 645 if (prepend != NULL) 646 dst = prepend; 647 648 for (;;) { 649 var_at = strchr(src, '$'); 650 if (var_at == NULL) { 651 dst.append(src); 652 break; 653 } 654 dst.append(src, var_at - src); 655 src = var_at; 656 expand_one(src, dst); 657 } 658 659 if (append != NULL) 660 dst.append(append); 661 662 return (dst); 663 } 664 665 bool 666 config::chop_var(char *&buffer, char *&lhs, char *&rhs) const 667 { 668 char *walker; 669 670 if (*buffer == '\0') 671 return (false); 672 walker = lhs = buffer; 673 while (is_id_char(*walker)) 674 walker++; 675 if (*walker != '=') 676 return (false); 677 walker++; // skip = 678 if (*walker == '"') { 679 walker++; // skip " 680 rhs = walker; 681 while (*walker && *walker != '"') 682 walker++; 683 if (*walker != '"') 684 return (false); 685 rhs[-2] = '\0'; 686 *walker++ = '\0'; 687 } else { 688 rhs = walker; 689 while (*walker && !isspace(*walker)) 690 walker++; 691 if (*walker != '\0') 692 *walker++ = '\0'; 693 rhs[-1] = '\0'; 694 } 695 while (isspace(*walker)) 696 walker++; 697 buffer = walker; 698 return (true); 699 } 700 701 702 char * 703 config::set_vars(char *buffer) 704 { 705 char *lhs; 706 char *rhs; 707 708 while (1) { 709 if (!chop_var(buffer, lhs, rhs)) 710 break; 711 set_variable(lhs, rhs); 712 } 713 return (buffer); 714 } 715 716 void 717 config::find_and_execute(char type) 718 { 719 vector<event_proc *> *l; 720 vector<event_proc *>::const_iterator i; 721 const char *s; 722 723 switch (type) { 724 default: 725 return; 726 case notify: 727 l = &_notify_list; 728 s = "notify"; 729 break; 730 case nomatch: 731 l = &_nomatch_list; 732 s = "nomatch"; 733 break; 734 case attach: 735 l = &_attach_list; 736 s = "attach"; 737 break; 738 case detach: 739 l = &_detach_list; 740 s = "detach"; 741 break; 742 } 743 devdlog(LOG_DEBUG, "Processing %s event\n", s); 744 for (i = l->begin(); i != l->end(); ++i) { 745 if ((*i)->matches(*this)) { 746 (*i)->run(*this); 747 break; 748 } 749 } 750 751 } 752 753 754 static void 755 process_event(char *buffer) 756 { 757 char type; 758 char *sp; 759 760 sp = buffer + 1; 761 devdlog(LOG_DEBUG, "Processing event '%s'\n", buffer); 762 type = *buffer++; 763 cfg.push_var_table(); 764 // No match doesn't have a device, and the format is a little 765 // different, so handle it separately. 766 switch (type) { 767 case notify: 768 sp = cfg.set_vars(sp); 769 break; 770 case nomatch: 771 //? at location pnp-info on bus 772 sp = strchr(sp, ' '); 773 if (sp == NULL) 774 return; /* Can't happen? */ 775 *sp++ = '\0'; 776 while (isspace(*sp)) 777 sp++; 778 if (strncmp(sp, "at ", 3) == 0) 779 sp += 3; 780 sp = cfg.set_vars(sp); 781 while (isspace(*sp)) 782 sp++; 783 if (strncmp(sp, "on ", 3) == 0) 784 cfg.set_variable("bus", sp + 3); 785 break; 786 case attach: /*FALLTHROUGH*/ 787 case detach: 788 sp = strchr(sp, ' '); 789 if (sp == NULL) 790 return; /* Can't happen? */ 791 *sp++ = '\0'; 792 cfg.set_variable("device-name", buffer); 793 while (isspace(*sp)) 794 sp++; 795 if (strncmp(sp, "at ", 3) == 0) 796 sp += 3; 797 sp = cfg.set_vars(sp); 798 while (isspace(*sp)) 799 sp++; 800 if (strncmp(sp, "on ", 3) == 0) 801 cfg.set_variable("bus", sp + 3); 802 break; 803 } 804 805 cfg.find_and_execute(type); 806 cfg.pop_var_table(); 807 } 808 809 int 810 create_socket(const char *name) 811 { 812 int fd, slen; 813 struct sockaddr_un sun; 814 815 if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) 816 err(1, "socket"); 817 bzero(&sun, sizeof(sun)); 818 sun.sun_family = AF_UNIX; 819 strlcpy(sun.sun_path, name, sizeof(sun.sun_path)); 820 slen = SUN_LEN(&sun); 821 unlink(name); 822 if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) 823 err(1, "fcntl"); 824 if (::bind(fd, (struct sockaddr *) & sun, slen) < 0) 825 err(1, "bind"); 826 listen(fd, 4); 827 chown(name, 0, 0); /* XXX - root.wheel */ 828 chmod(name, 0666); 829 return (fd); 830 } 831 832 unsigned int max_clients = 10; /* Default, can be overriden on cmdline. */ 833 unsigned int num_clients; 834 list<int> clients; 835 836 void 837 notify_clients(const char *data, int len) 838 { 839 list<int>::iterator i; 840 841 /* 842 * Deliver the data to all clients. Throw clients overboard at the 843 * first sign of trouble. This reaps clients who've died or closed 844 * their sockets, and also clients who are alive but failing to keep up 845 * (or who are maliciously not reading, to consume buffer space in 846 * kernel memory or tie up the limited number of available connections). 847 */ 848 for (i = clients.begin(); i != clients.end(); ) { 849 if (write(*i, data, len) != len) { 850 --num_clients; 851 close(*i); 852 i = clients.erase(i); 853 devdlog(LOG_WARNING, "notify_clients: write() failed; " 854 "dropping unresponsive client\n"); 855 } else 856 ++i; 857 } 858 } 859 860 void 861 check_clients(void) 862 { 863 int s; 864 struct pollfd pfd; 865 list<int>::iterator i; 866 867 /* 868 * Check all existing clients to see if any of them have disappeared. 869 * Normally we reap clients when we get an error trying to send them an 870 * event. This check eliminates the problem of an ever-growing list of 871 * zombie clients because we're never writing to them on a system 872 * without frequent device-change activity. 873 */ 874 pfd.events = 0; 875 for (i = clients.begin(); i != clients.end(); ) { 876 pfd.fd = *i; 877 s = poll(&pfd, 1, 0); 878 if ((s < 0 && s != EINTR ) || 879 (s > 0 && (pfd.revents & POLLHUP))) { 880 --num_clients; 881 close(*i); 882 i = clients.erase(i); 883 devdlog(LOG_NOTICE, "check_clients: " 884 "dropping disconnected client\n"); 885 } else 886 ++i; 887 } 888 } 889 890 void 891 new_client(int fd) 892 { 893 int s; 894 895 /* 896 * First go reap any zombie clients, then accept the connection, and 897 * shut down the read side to stop clients from consuming kernel memory 898 * by sending large buffers full of data we'll never read. 899 */ 900 check_clients(); 901 s = accept(fd, NULL, NULL); 902 if (s != -1) { 903 shutdown(s, SHUT_RD); 904 clients.push_back(s); 905 ++num_clients; 906 } 907 } 908 909 static void 910 event_loop(void) 911 { 912 int rv; 913 int fd; 914 char buffer[DEVCTL_MAXBUF]; 915 int once = 0; 916 int server_fd, max_fd; 917 int accepting; 918 timeval tv; 919 fd_set fds; 920 921 fd = open(PATH_DEVCTL, O_RDONLY | O_CLOEXEC); 922 if (fd == -1) 923 err(1, "Can't open devctl device %s", PATH_DEVCTL); 924 server_fd = create_socket(PIPE); 925 accepting = 1; 926 max_fd = max(fd, server_fd) + 1; 927 while (!romeo_must_die) { 928 if (!once && !dflag && !nflag) { 929 // Check to see if we have any events pending. 930 tv.tv_sec = 0; 931 tv.tv_usec = 0; 932 FD_ZERO(&fds); 933 FD_SET(fd, &fds); 934 rv = select(fd + 1, &fds, &fds, &fds, &tv); 935 // No events -> we've processed all pending events 936 if (rv == 0) { 937 devdlog(LOG_DEBUG, "Calling daemon\n"); 938 cfg.remove_pidfile(); 939 cfg.open_pidfile(); 940 daemon(0, 0); 941 cfg.write_pidfile(); 942 once++; 943 } 944 } 945 /* 946 * When we've already got the max number of clients, stop 947 * accepting new connections (don't put server_fd in the set), 948 * shrink the accept() queue to reject connections quickly, and 949 * poll the existing clients more often, so that we notice more 950 * quickly when any of them disappear to free up client slots. 951 */ 952 FD_ZERO(&fds); 953 FD_SET(fd, &fds); 954 if (num_clients < max_clients) { 955 if (!accepting) { 956 listen(server_fd, max_clients); 957 accepting = 1; 958 } 959 FD_SET(server_fd, &fds); 960 tv.tv_sec = 60; 961 tv.tv_usec = 0; 962 } else { 963 if (accepting) { 964 listen(server_fd, 0); 965 accepting = 0; 966 } 967 tv.tv_sec = 2; 968 tv.tv_usec = 0; 969 } 970 rv = select(max_fd, &fds, NULL, NULL, &tv); 971 if (got_siginfo) { 972 devdlog(LOG_INFO, "Events received so far=%ld\n", 973 total_events); 974 got_siginfo = 0; 975 } 976 if (rv == -1) { 977 if (errno == EINTR) 978 continue; 979 err(1, "select"); 980 } else if (rv == 0) 981 check_clients(); 982 if (FD_ISSET(fd, &fds)) { 983 rv = read(fd, buffer, sizeof(buffer) - 1); 984 if (rv > 0) { 985 total_events++; 986 if (rv == sizeof(buffer) - 1) { 987 devdlog(LOG_WARNING, "Warning: " 988 "available event data exceeded " 989 "buffer space\n"); 990 } 991 notify_clients(buffer, rv); 992 buffer[rv] = '\0'; 993 while (buffer[--rv] == '\n') 994 buffer[rv] = '\0'; 995 process_event(buffer); 996 } else if (rv < 0) { 997 if (errno != EINTR) 998 break; 999 } else { 1000 /* EOF */ 1001 break; 1002 } 1003 } 1004 if (FD_ISSET(server_fd, &fds)) 1005 new_client(server_fd); 1006 } 1007 close(fd); 1008 } 1009 1010 /* 1011 * functions that the parser uses. 1012 */ 1013 void 1014 add_attach(int prio, event_proc *p) 1015 { 1016 cfg.add_attach(prio, p); 1017 } 1018 1019 void 1020 add_detach(int prio, event_proc *p) 1021 { 1022 cfg.add_detach(prio, p); 1023 } 1024 1025 void 1026 add_directory(const char *dir) 1027 { 1028 cfg.add_directory(dir); 1029 free(const_cast<char *>(dir)); 1030 } 1031 1032 void 1033 add_nomatch(int prio, event_proc *p) 1034 { 1035 cfg.add_nomatch(prio, p); 1036 } 1037 1038 void 1039 add_notify(int prio, event_proc *p) 1040 { 1041 cfg.add_notify(prio, p); 1042 } 1043 1044 event_proc * 1045 add_to_event_proc(event_proc *ep, eps *eps) 1046 { 1047 if (ep == NULL) 1048 ep = new event_proc(); 1049 ep->add(eps); 1050 return (ep); 1051 } 1052 1053 eps * 1054 new_action(const char *cmd) 1055 { 1056 eps *e = new action(cmd); 1057 free(const_cast<char *>(cmd)); 1058 return (e); 1059 } 1060 1061 eps * 1062 new_match(const char *var, const char *re) 1063 { 1064 eps *e = new match(cfg, var, re); 1065 free(const_cast<char *>(var)); 1066 free(const_cast<char *>(re)); 1067 return (e); 1068 } 1069 1070 eps * 1071 new_media(const char *var, const char *re) 1072 { 1073 eps *e = new media(cfg, var, re); 1074 free(const_cast<char *>(var)); 1075 free(const_cast<char *>(re)); 1076 return (e); 1077 } 1078 1079 void 1080 set_pidfile(const char *name) 1081 { 1082 cfg.set_pidfile(name); 1083 free(const_cast<char *>(name)); 1084 } 1085 1086 void 1087 set_variable(const char *var, const char *val) 1088 { 1089 cfg.set_variable(var, val); 1090 free(const_cast<char *>(var)); 1091 free(const_cast<char *>(val)); 1092 } 1093 1094 1095 1096 static void 1097 gensighand(int) 1098 { 1099 romeo_must_die = 1; 1100 } 1101 1102 /* 1103 * SIGINFO handler. Will print useful statistics to the syslog or stderr 1104 * as appropriate 1105 */ 1106 static void 1107 siginfohand(int) 1108 { 1109 got_siginfo = 1; 1110 } 1111 1112 /* 1113 * Local logging function. Prints to syslog if we're daemonized; syslog 1114 * otherwise. 1115 */ 1116 static void 1117 devdlog(int priority, const char* fmt, ...) 1118 { 1119 va_list argp; 1120 1121 va_start(argp, fmt); 1122 if (dflag) 1123 vfprintf(stderr, fmt, argp); 1124 else 1125 vsyslog(priority, fmt, argp); 1126 va_end(argp); 1127 } 1128 1129 static void 1130 usage() 1131 { 1132 fprintf(stderr, "usage: %s [-dn] [-l connlimit] [-f file]\n", 1133 getprogname()); 1134 exit(1); 1135 } 1136 1137 static void 1138 check_devd_enabled() 1139 { 1140 int val = 0; 1141 size_t len; 1142 1143 len = sizeof(val); 1144 if (sysctlbyname(SYSCTL, &val, &len, NULL, 0) != 0) 1145 errx(1, "devctl sysctl missing from kernel!"); 1146 if (val) { 1147 warnx("Setting " SYSCTL " to 0"); 1148 val = 0; 1149 sysctlbyname(SYSCTL, NULL, NULL, &val, sizeof(val)); 1150 } 1151 } 1152 1153 /* 1154 * main 1155 */ 1156 int 1157 main(int argc, char **argv) 1158 { 1159 int ch; 1160 1161 check_devd_enabled(); 1162 while ((ch = getopt(argc, argv, "df:l:n")) != -1) { 1163 switch (ch) { 1164 case 'd': 1165 dflag++; 1166 break; 1167 case 'f': 1168 configfile = optarg; 1169 break; 1170 case 'l': 1171 max_clients = MAX(1, strtoul(optarg, NULL, 0)); 1172 break; 1173 case 'n': 1174 nflag++; 1175 break; 1176 default: 1177 usage(); 1178 } 1179 } 1180 1181 cfg.parse(); 1182 if (!dflag && nflag) { 1183 cfg.open_pidfile(); 1184 daemon(0, 0); 1185 cfg.write_pidfile(); 1186 } 1187 signal(SIGPIPE, SIG_IGN); 1188 signal(SIGHUP, gensighand); 1189 signal(SIGINT, gensighand); 1190 signal(SIGTERM, gensighand); 1191 signal(SIGINFO, siginfohand); 1192 event_loop(); 1193 return (0); 1194 } 1195