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