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