13054f218SWarner Losh /*- 2b8f92ce4SWarner Losh * Copyright (c) 2002-2010 M. Warner Losh. 33054f218SWarner Losh * All rights reserved. 43054f218SWarner Losh * 53054f218SWarner Losh * Redistribution and use in source and binary forms, with or without 63054f218SWarner Losh * modification, are permitted provided that the following conditions 73054f218SWarner Losh * are met: 83054f218SWarner Losh * 1. Redistributions of source code must retain the above copyright 93054f218SWarner Losh * notice, this list of conditions and the following disclaimer. 103054f218SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 113054f218SWarner Losh * notice, this list of conditions and the following disclaimer in the 123054f218SWarner Losh * documentation and/or other materials provided with the distribution. 133054f218SWarner Losh * 143054f218SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 153054f218SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 163054f218SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 173054f218SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 183054f218SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 193054f218SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 203054f218SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 213054f218SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 223054f218SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 233054f218SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 243054f218SWarner Losh * SUCH DAMAGE. 25b8f92ce4SWarner Losh * 26b8f92ce4SWarner Losh * my_system is a variation on lib/libc/stdlib/system.c: 27b8f92ce4SWarner Losh * 28b8f92ce4SWarner Losh * Copyright (c) 1988, 1993 29b8f92ce4SWarner Losh * The Regents of the University of California. All rights reserved. 30b8f92ce4SWarner Losh * 31b8f92ce4SWarner Losh * Redistribution and use in source and binary forms, with or without 32b8f92ce4SWarner Losh * modification, are permitted provided that the following conditions 33b8f92ce4SWarner Losh * are met: 34b8f92ce4SWarner Losh * 1. Redistributions of source code must retain the above copyright 35b8f92ce4SWarner Losh * notice, this list of conditions and the following disclaimer. 36b8f92ce4SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 37b8f92ce4SWarner Losh * notice, this list of conditions and the following disclaimer in the 38b8f92ce4SWarner Losh * documentation and/or other materials provided with the distribution. 39b8f92ce4SWarner Losh * 4. Neither the name of the University nor the names of its contributors 40b8f92ce4SWarner Losh * may be used to endorse or promote products derived from this software 41b8f92ce4SWarner Losh * without specific prior written permission. 42b8f92ce4SWarner Losh * 43b8f92ce4SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 44b8f92ce4SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 45b8f92ce4SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 46b8f92ce4SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 47b8f92ce4SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 48b8f92ce4SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 49b8f92ce4SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 50b8f92ce4SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 51b8f92ce4SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 52b8f92ce4SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 53b8f92ce4SWarner Losh * SUCH DAMAGE. 543054f218SWarner Losh */ 553054f218SWarner Losh 563054f218SWarner Losh /* 573054f218SWarner Losh * DEVD control daemon. 583054f218SWarner Losh */ 593054f218SWarner Losh 603054f218SWarner Losh // TODO list: 613054f218SWarner Losh // o devd.conf and devd man pages need a lot of help: 62251bedd1SWarner Losh // - devd needs to document the unix domain socket 633054f218SWarner Losh // - devd.conf needs more details on the supported statements. 643054f218SWarner Losh 653054f218SWarner Losh #include <sys/cdefs.h> 663054f218SWarner Losh __FBSDID("$FreeBSD$"); 673054f218SWarner Losh 683054f218SWarner Losh #include <sys/param.h> 69251bedd1SWarner Losh #include <sys/socket.h> 70251bedd1SWarner Losh #include <sys/stat.h> 719c180898SWarner Losh #include <sys/sysctl.h> 72251bedd1SWarner Losh #include <sys/types.h> 73b8f92ce4SWarner Losh #include <sys/wait.h> 74251bedd1SWarner Losh #include <sys/un.h> 753054f218SWarner Losh 765102ef84SWarner Losh #include <ctype.h> 773054f218SWarner Losh #include <dirent.h> 783054f218SWarner Losh #include <errno.h> 793054f218SWarner Losh #include <err.h> 803054f218SWarner Losh #include <fcntl.h> 811a0cc6b1SPawel Jakub Dawidek #include <libutil.h> 82b8f92ce4SWarner Losh #include <paths.h> 835102ef84SWarner Losh #include <regex.h> 84f32a7686SWarner Losh #include <signal.h> 853054f218SWarner Losh #include <stdlib.h> 863054f218SWarner Losh #include <stdio.h> 873054f218SWarner Losh #include <string.h> 883054f218SWarner Losh #include <unistd.h> 893054f218SWarner Losh 908b823408SWarner Losh #include <algorithm> 913054f218SWarner Losh #include <map> 923054f218SWarner Losh #include <string> 93251bedd1SWarner Losh #include <list> 943054f218SWarner Losh #include <vector> 953054f218SWarner Losh 966aeeca8eSWarner Losh #include "devd.h" /* C compatible definitions */ 976aeeca8eSWarner Losh #include "devd.hh" /* C++ class definitions */ 983054f218SWarner Losh 99251bedd1SWarner Losh #define PIPE "/var/run/devd.pipe" 1003054f218SWarner Losh #define CF "/etc/devd.conf" 1019c180898SWarner Losh #define SYSCTL "hw.bus.devctl_disable" 1023054f218SWarner Losh 1033054f218SWarner Losh using namespace std; 1043054f218SWarner Losh 1053054f218SWarner Losh extern FILE *yyin; 1063054f218SWarner Losh extern int lineno; 1073054f218SWarner Losh 108842ccec5SWarner Losh static const char notify = '!'; 1098b823408SWarner Losh static const char nomatch = '?'; 1108b823408SWarner Losh static const char attach = '+'; 1118b823408SWarner Losh static const char detach = '-'; 1128b823408SWarner Losh 1131a0cc6b1SPawel Jakub Dawidek static struct pidfh *pfh; 1141a0cc6b1SPawel Jakub Dawidek 1155a882d77SWarner Losh int Dflag; 1163054f218SWarner Losh int dflag; 117812f53a7SWarner Losh int nflag; 1183054f218SWarner Losh int romeo_must_die = 0; 1193054f218SWarner Losh 1208334958aSJoseph Koshy static const char *configfile = CF; 1218334958aSJoseph Koshy 1223054f218SWarner Losh static void event_loop(void); 1233054f218SWarner Losh static void usage(void); 1243054f218SWarner Losh 1258b823408SWarner Losh template <class T> void 1268b823408SWarner Losh delete_and_clear(vector<T *> &v) 1278b823408SWarner Losh { 1288b823408SWarner Losh typename vector<T *>::const_iterator i; 1293054f218SWarner Losh 1308b823408SWarner Losh for (i = v.begin(); i != v.end(); i++) 1318b823408SWarner Losh delete *i; 1328b823408SWarner Losh v.clear(); 1338b823408SWarner Losh } 1348b823408SWarner Losh 1353054f218SWarner Losh config cfg; 1363054f218SWarner Losh 1373054f218SWarner Losh event_proc::event_proc() : _prio(-1) 1383054f218SWarner Losh { 1393054f218SWarner Losh // nothing 1403054f218SWarner Losh } 1413054f218SWarner Losh 1423054f218SWarner Losh event_proc::~event_proc() 1433054f218SWarner Losh { 14413f8bb71SAlexander Nedotsukov delete_and_clear(_epsvec); 1453054f218SWarner Losh } 1463054f218SWarner Losh 1473054f218SWarner Losh void 1483054f218SWarner Losh event_proc::add(eps *eps) 1493054f218SWarner Losh { 1503054f218SWarner Losh _epsvec.push_back(eps); 1513054f218SWarner Losh } 1523054f218SWarner Losh 1533054f218SWarner Losh bool 1543054f218SWarner Losh event_proc::matches(config &c) 1553054f218SWarner Losh { 1563054f218SWarner Losh vector<eps *>::const_iterator i; 1573054f218SWarner Losh 1583054f218SWarner Losh for (i = _epsvec.begin(); i != _epsvec.end(); i++) 1593054f218SWarner Losh if (!(*i)->do_match(c)) 1603054f218SWarner Losh return (false); 1613054f218SWarner Losh return (true); 1623054f218SWarner Losh } 1633054f218SWarner Losh 1643054f218SWarner Losh bool 1653054f218SWarner Losh event_proc::run(config &c) 1663054f218SWarner Losh { 1673054f218SWarner Losh vector<eps *>::const_iterator i; 1683054f218SWarner Losh 1693054f218SWarner Losh for (i = _epsvec.begin(); i != _epsvec.end(); i++) 1703054f218SWarner Losh if (!(*i)->do_action(c)) 1713054f218SWarner Losh return (false); 1723054f218SWarner Losh return (true); 1733054f218SWarner Losh } 1743054f218SWarner Losh 1753054f218SWarner Losh action::action(const char *cmd) 1763054f218SWarner Losh : _cmd(cmd) 1773054f218SWarner Losh { 1783054f218SWarner Losh // nothing 1793054f218SWarner Losh } 1803054f218SWarner Losh 1813054f218SWarner Losh action::~action() 1823054f218SWarner Losh { 1833054f218SWarner Losh // nothing 1843054f218SWarner Losh } 1853054f218SWarner Losh 186b8f92ce4SWarner Losh static int 187b8f92ce4SWarner Losh my_system(const char *command) 188b8f92ce4SWarner Losh { 189b8f92ce4SWarner Losh pid_t pid, savedpid; 190b8f92ce4SWarner Losh int pstat; 191b8f92ce4SWarner Losh struct sigaction ign, intact, quitact; 192b8f92ce4SWarner Losh sigset_t newsigblock, oldsigblock; 193b8f92ce4SWarner Losh 194b8f92ce4SWarner Losh if (!command) /* just checking... */ 195b8f92ce4SWarner Losh return(1); 196b8f92ce4SWarner Losh 197b8f92ce4SWarner Losh /* 198b8f92ce4SWarner Losh * Ignore SIGINT and SIGQUIT, block SIGCHLD. Remember to save 199b8f92ce4SWarner Losh * existing signal dispositions. 200b8f92ce4SWarner Losh */ 201b8f92ce4SWarner Losh ign.sa_handler = SIG_IGN; 202b8f92ce4SWarner Losh ::sigemptyset(&ign.sa_mask); 203b8f92ce4SWarner Losh ign.sa_flags = 0; 204b8f92ce4SWarner Losh ::sigaction(SIGINT, &ign, &intact); 205b8f92ce4SWarner Losh ::sigaction(SIGQUIT, &ign, &quitact); 206b8f92ce4SWarner Losh ::sigemptyset(&newsigblock); 207b8f92ce4SWarner Losh ::sigaddset(&newsigblock, SIGCHLD); 208b8f92ce4SWarner Losh ::sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock); 209b8f92ce4SWarner Losh switch (pid = ::fork()) { 210b8f92ce4SWarner Losh case -1: /* error */ 211b8f92ce4SWarner Losh break; 212b8f92ce4SWarner Losh case 0: /* child */ 213b8f92ce4SWarner Losh /* 214b8f92ce4SWarner Losh * Restore original signal dispositions and exec the command. 215b8f92ce4SWarner Losh */ 216b8f92ce4SWarner Losh ::sigaction(SIGINT, &intact, NULL); 217b8f92ce4SWarner Losh ::sigaction(SIGQUIT, &quitact, NULL); 218b8f92ce4SWarner Losh ::sigprocmask(SIG_SETMASK, &oldsigblock, NULL); 219b8f92ce4SWarner Losh /* 220b8f92ce4SWarner Losh * Close the PID file, and all other open descriptors. 221b8f92ce4SWarner Losh * Inherit std{in,out,err} only. 222b8f92ce4SWarner Losh */ 223b8f92ce4SWarner Losh cfg.close_pidfile(); 224b8f92ce4SWarner Losh ::closefrom(3); 225b8f92ce4SWarner Losh ::execl(_PATH_BSHELL, "sh", "-c", command, (char *)NULL); 226b8f92ce4SWarner Losh ::_exit(127); 227b8f92ce4SWarner Losh default: /* parent */ 228b8f92ce4SWarner Losh savedpid = pid; 229b8f92ce4SWarner Losh do { 230b8f92ce4SWarner Losh pid = ::wait4(savedpid, &pstat, 0, (struct rusage *)0); 231b8f92ce4SWarner Losh } while (pid == -1 && errno == EINTR); 232b8f92ce4SWarner Losh break; 233b8f92ce4SWarner Losh } 234b8f92ce4SWarner Losh ::sigaction(SIGINT, &intact, NULL); 235b8f92ce4SWarner Losh ::sigaction(SIGQUIT, &quitact, NULL); 236b8f92ce4SWarner Losh ::sigprocmask(SIG_SETMASK, &oldsigblock, NULL); 237b8f92ce4SWarner Losh return (pid == -1 ? -1 : pstat); 238b8f92ce4SWarner Losh } 239b8f92ce4SWarner Losh 2403054f218SWarner Losh bool 2415102ef84SWarner Losh action::do_action(config &c) 2423054f218SWarner Losh { 2438b823408SWarner Losh string s = c.expand_string(_cmd); 2445a882d77SWarner Losh if (Dflag) 2458b823408SWarner Losh fprintf(stderr, "Executing '%s'\n", s.c_str()); 246b8f92ce4SWarner Losh my_system(s.c_str()); 2473054f218SWarner Losh return (true); 2483054f218SWarner Losh } 2493054f218SWarner Losh 2505102ef84SWarner Losh match::match(config &c, const char *var, const char *re) 2518b823408SWarner Losh : _var(var) 2523054f218SWarner Losh { 2538b823408SWarner Losh _re = "^"; 2548b823408SWarner Losh _re.append(c.expand_string(string(re))); 2558b823408SWarner Losh _re.append("$"); 2569cb4a7bdSWarner Losh regcomp(&_regex, _re.c_str(), REG_EXTENDED | REG_NOSUB | REG_ICASE); 2573054f218SWarner Losh } 2583054f218SWarner Losh 2593054f218SWarner Losh match::~match() 2603054f218SWarner Losh { 2615102ef84SWarner Losh regfree(&_regex); 2623054f218SWarner Losh } 2633054f218SWarner Losh 2643054f218SWarner Losh bool 2655102ef84SWarner Losh match::do_match(config &c) 2663054f218SWarner Losh { 2675bf08422SUlf Lilleengen const string &value = c.get_variable(_var); 2685102ef84SWarner Losh bool retval; 2695102ef84SWarner Losh 2705a882d77SWarner Losh if (Dflag) 2718b823408SWarner Losh fprintf(stderr, "Testing %s=%s against %s\n", _var.c_str(), 2728b823408SWarner Losh value.c_str(), _re.c_str()); 2738b823408SWarner Losh 2745102ef84SWarner Losh retval = (regexec(&_regex, value.c_str(), 0, NULL, 0) == 0); 2755102ef84SWarner Losh return retval; 2763054f218SWarner Losh } 2773054f218SWarner Losh 278cd70782bSWarner Losh #include <sys/sockio.h> 279cd70782bSWarner Losh #include <net/if.h> 280cd70782bSWarner Losh #include <net/if_media.h> 281cd70782bSWarner Losh 28294d2d4ebSBrooks Davis media::media(config &, const char *var, const char *type) 283cd70782bSWarner Losh : _var(var), _type(-1) 284cd70782bSWarner Losh { 285cd70782bSWarner Losh static struct ifmedia_description media_types[] = { 286cd70782bSWarner Losh { IFM_ETHER, "Ethernet" }, 287cd70782bSWarner Losh { IFM_TOKEN, "Tokenring" }, 288cd70782bSWarner Losh { IFM_FDDI, "FDDI" }, 289cd70782bSWarner Losh { IFM_IEEE80211, "802.11" }, 290cd70782bSWarner Losh { IFM_ATM, "ATM" }, 291cd70782bSWarner Losh { IFM_CARP, "CARP" }, 292cd70782bSWarner Losh { -1, "unknown" }, 293cd70782bSWarner Losh { 0, NULL }, 294cd70782bSWarner Losh }; 295cd70782bSWarner Losh for (int i = 0; media_types[i].ifmt_string != NULL; i++) 296cd70782bSWarner Losh if (strcasecmp(type, media_types[i].ifmt_string) == 0) { 297cd70782bSWarner Losh _type = media_types[i].ifmt_word; 298cd70782bSWarner Losh break; 299cd70782bSWarner Losh } 300cd70782bSWarner Losh } 301cd70782bSWarner Losh 302cd70782bSWarner Losh media::~media() 303cd70782bSWarner Losh { 304cd70782bSWarner Losh } 305cd70782bSWarner Losh 306cd70782bSWarner Losh bool 307cd70782bSWarner Losh media::do_match(config &c) 308cd70782bSWarner Losh { 30909c47e76SWarner Losh string value; 310cd70782bSWarner Losh struct ifmediareq ifmr; 311cd70782bSWarner Losh bool retval; 312cd70782bSWarner Losh int s; 313cd70782bSWarner Losh 31409c47e76SWarner Losh // Since we can be called from both a device attach/detach 31509c47e76SWarner Losh // context where device-name is defined and what we want, 31609c47e76SWarner Losh // as well as from a link status context, where subsystem is 31709c47e76SWarner Losh // the name of interest, first try device-name and fall back 31809c47e76SWarner Losh // to subsystem if none exists. 31909c47e76SWarner Losh value = c.get_variable("device-name"); 32009c47e76SWarner Losh if (value.length() == 0) 321de02eec8SWarner Losh value = c.get_variable("subsystem"); 322cd70782bSWarner Losh if (Dflag) 323cd70782bSWarner Losh fprintf(stderr, "Testing media type of %s against 0x%x\n", 324cd70782bSWarner Losh value.c_str(), _type); 325cd70782bSWarner Losh 326cd70782bSWarner Losh retval = false; 327cd70782bSWarner Losh 328cd70782bSWarner Losh s = socket(PF_INET, SOCK_DGRAM, 0); 329cd70782bSWarner Losh if (s >= 0) { 330cd70782bSWarner Losh memset(&ifmr, 0, sizeof(ifmr)); 331cd70782bSWarner Losh strncpy(ifmr.ifm_name, value.c_str(), sizeof(ifmr.ifm_name)); 332cd70782bSWarner Losh 333cd70782bSWarner Losh if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0 && 334cd70782bSWarner Losh ifmr.ifm_status & IFM_AVALID) { 335cd70782bSWarner Losh if (Dflag) 336cd70782bSWarner Losh fprintf(stderr, "%s has media type 0x%x\n", 337cd70782bSWarner Losh value.c_str(), IFM_TYPE(ifmr.ifm_active)); 338cd70782bSWarner Losh retval = (IFM_TYPE(ifmr.ifm_active) == _type); 339cd70782bSWarner Losh } else if (_type == -1) { 340cd70782bSWarner Losh if (Dflag) 341cd70782bSWarner Losh fprintf(stderr, "%s has unknown media type\n", 342cd70782bSWarner Losh value.c_str()); 343cd70782bSWarner Losh retval = true; 344cd70782bSWarner Losh } 345cd70782bSWarner Losh close(s); 346cd70782bSWarner Losh } 347cd70782bSWarner Losh 348cd70782bSWarner Losh return retval; 349cd70782bSWarner Losh } 350cd70782bSWarner Losh 3513054f218SWarner Losh const string var_list::bogus = "_$_$_$_$_B_O_G_U_S_$_$_$_$_"; 3523054f218SWarner Losh const string var_list::nothing = ""; 3533054f218SWarner Losh 3543054f218SWarner Losh const string & 3553054f218SWarner Losh var_list::get_variable(const string &var) const 3563054f218SWarner Losh { 3573054f218SWarner Losh map<string, string>::const_iterator i; 3583054f218SWarner Losh 3593054f218SWarner Losh i = _vars.find(var); 3603054f218SWarner Losh if (i == _vars.end()) 3618b823408SWarner Losh return (var_list::bogus); 3623054f218SWarner Losh return (i->second); 3633054f218SWarner Losh } 3643054f218SWarner Losh 3653054f218SWarner Losh bool 3663054f218SWarner Losh var_list::is_set(const string &var) const 3673054f218SWarner Losh { 3683054f218SWarner Losh return (_vars.find(var) != _vars.end()); 3693054f218SWarner Losh } 3703054f218SWarner Losh 3713054f218SWarner Losh void 3723054f218SWarner Losh var_list::set_variable(const string &var, const string &val) 3733054f218SWarner Losh { 3745a882d77SWarner Losh if (Dflag) 375528d3f79SWarner Losh fprintf(stderr, "setting %s=%s\n", var.c_str(), val.c_str()); 3763054f218SWarner Losh _vars[var] = val; 3773054f218SWarner Losh } 3783054f218SWarner Losh 3793054f218SWarner Losh void 3803054f218SWarner Losh config::reset(void) 3813054f218SWarner Losh { 3823054f218SWarner Losh _dir_list.clear(); 3838b823408SWarner Losh delete_and_clear(_var_list_table); 3848b823408SWarner Losh delete_and_clear(_attach_list); 3858b823408SWarner Losh delete_and_clear(_detach_list); 3868b823408SWarner Losh delete_and_clear(_nomatch_list); 387842ccec5SWarner Losh delete_and_clear(_notify_list); 3883054f218SWarner Losh } 3893054f218SWarner Losh 3903054f218SWarner Losh void 3913054f218SWarner Losh config::parse_one_file(const char *fn) 3923054f218SWarner Losh { 3935a882d77SWarner Losh if (Dflag) 3940f3311c5SPoul-Henning Kamp fprintf(stderr, "Parsing %s\n", fn); 3953054f218SWarner Losh yyin = fopen(fn, "r"); 3963054f218SWarner Losh if (yyin == NULL) 3973054f218SWarner Losh err(1, "Cannot open config file %s", fn); 3984a3050fcSMaxim Konovalov lineno = 1; 3993054f218SWarner Losh if (yyparse() != 0) 4003054f218SWarner Losh errx(1, "Cannot parse %s at line %d", fn, lineno); 4013054f218SWarner Losh fclose(yyin); 4023054f218SWarner Losh } 4033054f218SWarner Losh 4043054f218SWarner Losh void 4053054f218SWarner Losh config::parse_files_in_dir(const char *dirname) 4063054f218SWarner Losh { 4073054f218SWarner Losh DIR *dirp; 4083054f218SWarner Losh struct dirent *dp; 4093054f218SWarner Losh char path[PATH_MAX]; 4103054f218SWarner Losh 4115a882d77SWarner Losh if (Dflag) 4120f3311c5SPoul-Henning Kamp fprintf(stderr, "Parsing files in %s\n", dirname); 4133054f218SWarner Losh dirp = opendir(dirname); 4143054f218SWarner Losh if (dirp == NULL) 4153054f218SWarner Losh return; 4163054f218SWarner Losh readdir(dirp); /* Skip . */ 4173054f218SWarner Losh readdir(dirp); /* Skip .. */ 4183054f218SWarner Losh while ((dp = readdir(dirp)) != NULL) { 4193054f218SWarner Losh if (strcmp(dp->d_name + dp->d_namlen - 5, ".conf") == 0) { 4203054f218SWarner Losh snprintf(path, sizeof(path), "%s/%s", 4213054f218SWarner Losh dirname, dp->d_name); 4223054f218SWarner Losh parse_one_file(path); 4233054f218SWarner Losh } 4243054f218SWarner Losh } 4253054f218SWarner Losh } 4263054f218SWarner Losh 4278b823408SWarner Losh class epv_greater { 4288b823408SWarner Losh public: 4298b823408SWarner Losh int operator()(event_proc *const&l1, event_proc *const&l2) 4308b823408SWarner Losh { 4318b823408SWarner Losh return (l1->get_priority() > l2->get_priority()); 4328b823408SWarner Losh } 4338b823408SWarner Losh }; 4348b823408SWarner Losh 4358b823408SWarner Losh void 4368b823408SWarner Losh config::sort_vector(vector<event_proc *> &v) 4378b823408SWarner Losh { 4388b823408SWarner Losh sort(v.begin(), v.end(), epv_greater()); 4398b823408SWarner Losh } 4408b823408SWarner Losh 4413054f218SWarner Losh void 4423054f218SWarner Losh config::parse(void) 4433054f218SWarner Losh { 4443054f218SWarner Losh vector<string>::const_iterator i; 4453054f218SWarner Losh 4468334958aSJoseph Koshy parse_one_file(configfile); 4473054f218SWarner Losh for (i = _dir_list.begin(); i != _dir_list.end(); i++) 4483054f218SWarner Losh parse_files_in_dir((*i).c_str()); 4498b823408SWarner Losh sort_vector(_attach_list); 4508b823408SWarner Losh sort_vector(_detach_list); 4518b823408SWarner Losh sort_vector(_nomatch_list); 452842ccec5SWarner Losh sort_vector(_notify_list); 4533054f218SWarner Losh } 4543054f218SWarner Losh 4553054f218SWarner Losh void 4561a0cc6b1SPawel Jakub Dawidek config::open_pidfile() 4573054f218SWarner Losh { 4581a0cc6b1SPawel Jakub Dawidek pid_t otherpid; 4593054f218SWarner Losh 4603054f218SWarner Losh if (_pidfile == "") 4613054f218SWarner Losh return; 4621a0cc6b1SPawel Jakub Dawidek pfh = pidfile_open(_pidfile.c_str(), 0600, &otherpid); 4631a0cc6b1SPawel Jakub Dawidek if (pfh == NULL) { 4641a0cc6b1SPawel Jakub Dawidek if (errno == EEXIST) 4651a0cc6b1SPawel Jakub Dawidek errx(1, "devd already running, pid: %d", (int)otherpid); 4661a0cc6b1SPawel Jakub Dawidek warn("cannot open pid file"); 4671a0cc6b1SPawel Jakub Dawidek } 4681a0cc6b1SPawel Jakub Dawidek } 4691a0cc6b1SPawel Jakub Dawidek 4701a0cc6b1SPawel Jakub Dawidek void 4711a0cc6b1SPawel Jakub Dawidek config::write_pidfile() 4721a0cc6b1SPawel Jakub Dawidek { 4731a0cc6b1SPawel Jakub Dawidek 4741a0cc6b1SPawel Jakub Dawidek pidfile_write(pfh); 4751a0cc6b1SPawel Jakub Dawidek } 4761a0cc6b1SPawel Jakub Dawidek 4771a0cc6b1SPawel Jakub Dawidek void 478b8f92ce4SWarner Losh config::close_pidfile() 479b8f92ce4SWarner Losh { 480b8f92ce4SWarner Losh 481b8f92ce4SWarner Losh pidfile_close(pfh); 482b8f92ce4SWarner Losh } 483b8f92ce4SWarner Losh 484b8f92ce4SWarner Losh void 4851a0cc6b1SPawel Jakub Dawidek config::remove_pidfile() 4861a0cc6b1SPawel Jakub Dawidek { 4871a0cc6b1SPawel Jakub Dawidek 4881a0cc6b1SPawel Jakub Dawidek pidfile_remove(pfh); 4893054f218SWarner Losh } 4903054f218SWarner Losh 4913054f218SWarner Losh void 4923054f218SWarner Losh config::add_attach(int prio, event_proc *p) 4933054f218SWarner Losh { 4943054f218SWarner Losh p->set_priority(prio); 4953054f218SWarner Losh _attach_list.push_back(p); 4963054f218SWarner Losh } 4973054f218SWarner Losh 4983054f218SWarner Losh void 4993054f218SWarner Losh config::add_detach(int prio, event_proc *p) 5003054f218SWarner Losh { 5013054f218SWarner Losh p->set_priority(prio); 5023054f218SWarner Losh _detach_list.push_back(p); 5033054f218SWarner Losh } 5043054f218SWarner Losh 5053054f218SWarner Losh void 5063054f218SWarner Losh config::add_directory(const char *dir) 5073054f218SWarner Losh { 5083054f218SWarner Losh _dir_list.push_back(string(dir)); 5093054f218SWarner Losh } 5103054f218SWarner Losh 5113054f218SWarner Losh void 5123054f218SWarner Losh config::add_nomatch(int prio, event_proc *p) 5133054f218SWarner Losh { 5143054f218SWarner Losh p->set_priority(prio); 5153054f218SWarner Losh _nomatch_list.push_back(p); 5163054f218SWarner Losh } 5173054f218SWarner Losh 5183054f218SWarner Losh void 519842ccec5SWarner Losh config::add_notify(int prio, event_proc *p) 520842ccec5SWarner Losh { 521842ccec5SWarner Losh p->set_priority(prio); 522842ccec5SWarner Losh _notify_list.push_back(p); 523842ccec5SWarner Losh } 524842ccec5SWarner Losh 525842ccec5SWarner Losh void 5263054f218SWarner Losh config::set_pidfile(const char *fn) 5273054f218SWarner Losh { 5283054f218SWarner Losh _pidfile = string(fn); 5293054f218SWarner Losh } 5303054f218SWarner Losh 5313054f218SWarner Losh void 5323054f218SWarner Losh config::push_var_table() 5333054f218SWarner Losh { 5343054f218SWarner Losh var_list *vl; 5353054f218SWarner Losh 5363054f218SWarner Losh vl = new var_list(); 5373054f218SWarner Losh _var_list_table.push_back(vl); 5385a882d77SWarner Losh if (Dflag) 5398b823408SWarner Losh fprintf(stderr, "Pushing table\n"); 5403054f218SWarner Losh } 5413054f218SWarner Losh 5423054f218SWarner Losh void 5433054f218SWarner Losh config::pop_var_table() 5443054f218SWarner Losh { 5453054f218SWarner Losh delete _var_list_table.back(); 5463054f218SWarner Losh _var_list_table.pop_back(); 5475a882d77SWarner Losh if (Dflag) 5488b823408SWarner Losh fprintf(stderr, "Popping table\n"); 5493054f218SWarner Losh } 5503054f218SWarner Losh 5513054f218SWarner Losh void 5523054f218SWarner Losh config::set_variable(const char *var, const char *val) 5533054f218SWarner Losh { 5543054f218SWarner Losh _var_list_table.back()->set_variable(var, val); 5553054f218SWarner Losh } 5563054f218SWarner Losh 5573054f218SWarner Losh const string & 5583054f218SWarner Losh config::get_variable(const string &var) 5593054f218SWarner Losh { 5603054f218SWarner Losh vector<var_list *>::reverse_iterator i; 5613054f218SWarner Losh 5623054f218SWarner Losh for (i = _var_list_table.rbegin(); i != _var_list_table.rend(); i++) { 5633054f218SWarner Losh if ((*i)->is_set(var)) 5648b823408SWarner Losh return ((*i)->get_variable(var)); 5653054f218SWarner Losh } 5663054f218SWarner Losh return (var_list::nothing); 5673054f218SWarner Losh } 5683054f218SWarner Losh 5698b823408SWarner Losh bool 5708b823408SWarner Losh config::is_id_char(char ch) 5718b823408SWarner Losh { 5728b823408SWarner Losh return (ch != '\0' && (isalpha(ch) || isdigit(ch) || ch == '_' || 5738b823408SWarner Losh ch == '-')); 5748b823408SWarner Losh } 5758b823408SWarner Losh 5765102ef84SWarner Losh void 5776cabd675SWarner Losh config::expand_one(const char *&src, string &dst) 5783054f218SWarner Losh { 5795102ef84SWarner Losh int count; 5805bf08422SUlf Lilleengen string buffer; 5815102ef84SWarner Losh 5828b823408SWarner Losh src++; 5835102ef84SWarner Losh // $$ -> $ 5845102ef84SWarner Losh if (*src == '$') { 5856cabd675SWarner Losh dst.append(src++, 1); 5865102ef84SWarner Losh return; 5875102ef84SWarner Losh } 5885102ef84SWarner Losh 5895102ef84SWarner Losh // $(foo) -> $(foo) 5908b823408SWarner Losh // Not sure if I want to support this or not, so for now we just pass 5918b823408SWarner Losh // it through. 5925102ef84SWarner Losh if (*src == '(') { 5936cabd675SWarner Losh dst.append("$"); 5945102ef84SWarner Losh count = 1; 5956cabd675SWarner Losh /* If the string ends before ) is matched , return. */ 5966cabd675SWarner Losh while (count > 0 && *src) { 5975102ef84SWarner Losh if (*src == ')') 5985102ef84SWarner Losh count--; 5995102ef84SWarner Losh else if (*src == '(') 6005102ef84SWarner Losh count++; 6016cabd675SWarner Losh dst.append(src++, 1); 6025102ef84SWarner Losh } 6035102ef84SWarner Losh return; 6045102ef84SWarner Losh } 6055102ef84SWarner Losh 6065102ef84SWarner Losh // ${^A-Za-z] -> $\1 6075102ef84SWarner Losh if (!isalpha(*src)) { 6086cabd675SWarner Losh dst.append("$"); 6096cabd675SWarner Losh dst.append(src++, 1); 6105102ef84SWarner Losh return; 6115102ef84SWarner Losh } 6125102ef84SWarner Losh 6135102ef84SWarner Losh // $var -> replace with value 6146cabd675SWarner Losh do { 6156cabd675SWarner Losh buffer.append(src++, 1); 61666ff6821SWarner Losh } while (is_id_char(*src)); 6176cabd675SWarner Losh buffer.append("", 1); 6185bf08422SUlf Lilleengen dst.append(get_variable(buffer.c_str())); 6195102ef84SWarner Losh } 6205102ef84SWarner Losh 6215102ef84SWarner Losh const string 6225102ef84SWarner Losh config::expand_string(const string &s) 6235102ef84SWarner Losh { 6245102ef84SWarner Losh const char *src; 6256cabd675SWarner Losh string dst; 6265102ef84SWarner Losh 6275102ef84SWarner Losh src = s.c_str(); 6285102ef84SWarner Losh while (*src) { 6295102ef84SWarner Losh if (*src == '$') 6306cabd675SWarner Losh expand_one(src, dst); 6315102ef84SWarner Losh else 6326cabd675SWarner Losh dst.append(src++, 1); 6335102ef84SWarner Losh } 6346cabd675SWarner Losh dst.append("", 1); 6355102ef84SWarner Losh 6366cabd675SWarner Losh return (dst); 6373054f218SWarner Losh } 6383054f218SWarner Losh 6398b823408SWarner Losh bool 6408b823408SWarner Losh config::chop_var(char *&buffer, char *&lhs, char *&rhs) 6418b823408SWarner Losh { 6428b823408SWarner Losh char *walker; 6438b823408SWarner Losh 6448b823408SWarner Losh if (*buffer == '\0') 6458b823408SWarner Losh return (false); 6468b823408SWarner Losh walker = lhs = buffer; 6478b823408SWarner Losh while (is_id_char(*walker)) 6488b823408SWarner Losh walker++; 6498b823408SWarner Losh if (*walker != '=') 6508b823408SWarner Losh return (false); 6518b823408SWarner Losh walker++; // skip = 6528b823408SWarner Losh if (*walker == '"') { 6538b823408SWarner Losh walker++; // skip " 6548b823408SWarner Losh rhs = walker; 6558b823408SWarner Losh while (*walker && *walker != '"') 6568b823408SWarner Losh walker++; 6578b823408SWarner Losh if (*walker != '"') 6588b823408SWarner Losh return (false); 6598b823408SWarner Losh rhs[-2] = '\0'; 6608b823408SWarner Losh *walker++ = '\0'; 6618b823408SWarner Losh } else { 6628b823408SWarner Losh rhs = walker; 6638b823408SWarner Losh while (*walker && !isspace(*walker)) 6648b823408SWarner Losh walker++; 6658b823408SWarner Losh if (*walker != '\0') 6668b823408SWarner Losh *walker++ = '\0'; 6678b823408SWarner Losh rhs[-1] = '\0'; 6688b823408SWarner Losh } 669b1ee04b1SWarner Losh while (isspace(*walker)) 670b1ee04b1SWarner Losh walker++; 6718b823408SWarner Losh buffer = walker; 6728b823408SWarner Losh return (true); 6738b823408SWarner Losh } 6748b823408SWarner Losh 6758b823408SWarner Losh 6768b823408SWarner Losh char * 6778b823408SWarner Losh config::set_vars(char *buffer) 6788b823408SWarner Losh { 6798b823408SWarner Losh char *lhs; 6808b823408SWarner Losh char *rhs; 6818b823408SWarner Losh 6828b823408SWarner Losh while (1) { 6838b823408SWarner Losh if (!chop_var(buffer, lhs, rhs)) 6848b823408SWarner Losh break; 6858b823408SWarner Losh set_variable(lhs, rhs); 6868b823408SWarner Losh } 6878b823408SWarner Losh return (buffer); 6888b823408SWarner Losh } 6898b823408SWarner Losh 6908b823408SWarner Losh void 6918b823408SWarner Losh config::find_and_execute(char type) 6928b823408SWarner Losh { 6938b823408SWarner Losh vector<event_proc *> *l; 6948b823408SWarner Losh vector<event_proc *>::const_iterator i; 69594d2d4ebSBrooks Davis const char *s; 6968b823408SWarner Losh 6978b823408SWarner Losh switch (type) { 6988b823408SWarner Losh default: 6998b823408SWarner Losh return; 700842ccec5SWarner Losh case notify: 701842ccec5SWarner Losh l = &_notify_list; 702842ccec5SWarner Losh s = "notify"; 703842ccec5SWarner Losh break; 7048b823408SWarner Losh case nomatch: 7058b823408SWarner Losh l = &_nomatch_list; 7068b823408SWarner Losh s = "nomatch"; 7078b823408SWarner Losh break; 7088b823408SWarner Losh case attach: 7098b823408SWarner Losh l = &_attach_list; 7108b823408SWarner Losh s = "attach"; 7118b823408SWarner Losh break; 7128b823408SWarner Losh case detach: 7138b823408SWarner Losh l = &_detach_list; 7148b823408SWarner Losh s = "detach"; 7158b823408SWarner Losh break; 7168b823408SWarner Losh } 7175a882d77SWarner Losh if (Dflag) 7188b823408SWarner Losh fprintf(stderr, "Processing %s event\n", s); 7198b823408SWarner Losh for (i = l->begin(); i != l->end(); i++) { 7208b823408SWarner Losh if ((*i)->matches(*this)) { 7218b823408SWarner Losh (*i)->run(*this); 7228b823408SWarner Losh break; 7238b823408SWarner Losh } 7248b823408SWarner Losh } 7258b823408SWarner Losh 7268b823408SWarner Losh } 7278b823408SWarner Losh 7283054f218SWarner Losh 7293054f218SWarner Losh static void 7308b823408SWarner Losh process_event(char *buffer) 7313054f218SWarner Losh { 7323054f218SWarner Losh char type; 7333054f218SWarner Losh char *sp; 7343054f218SWarner Losh 7358b823408SWarner Losh sp = buffer + 1; 7365a882d77SWarner Losh if (Dflag) 7378b823408SWarner Losh fprintf(stderr, "Processing event '%s'\n", buffer); 7383054f218SWarner Losh type = *buffer++; 7398b823408SWarner Losh cfg.push_var_table(); 7408b823408SWarner Losh // No match doesn't have a device, and the format is a little 7418b823408SWarner Losh // different, so handle it separately. 742842ccec5SWarner Losh switch (type) { 743842ccec5SWarner Losh case notify: 744842ccec5SWarner Losh sp = cfg.set_vars(sp); 745842ccec5SWarner Losh break; 746842ccec5SWarner Losh case nomatch: 747528d3f79SWarner Losh //? at location pnp-info on bus 748528d3f79SWarner Losh sp = strchr(sp, ' '); 749528d3f79SWarner Losh if (sp == NULL) 750528d3f79SWarner Losh return; /* Can't happen? */ 751528d3f79SWarner Losh *sp++ = '\0'; 752*9b6cb520SWarner Losh while (isspace(*sp)) 753*9b6cb520SWarner Losh sp++; 754842ccec5SWarner Losh if (strncmp(sp, "at ", 3) == 0) 755842ccec5SWarner Losh sp += 3; 756842ccec5SWarner Losh sp = cfg.set_vars(sp); 757*9b6cb520SWarner Losh while (isspace(*sp)) 758*9b6cb520SWarner Losh sp++; 759842ccec5SWarner Losh if (strncmp(sp, "on ", 3) == 0) 760842ccec5SWarner Losh cfg.set_variable("bus", sp + 3); 761842ccec5SWarner Losh break; 762842ccec5SWarner Losh case attach: /*FALLTHROUGH*/ 763842ccec5SWarner Losh case detach: 7648b823408SWarner Losh sp = strchr(sp, ' '); 7653054f218SWarner Losh if (sp == NULL) 7663054f218SWarner Losh return; /* Can't happen? */ 7678b823408SWarner Losh *sp++ = '\0'; 7688b823408SWarner Losh cfg.set_variable("device-name", buffer); 769*9b6cb520SWarner Losh while (isspace(*sp)) 770*9b6cb520SWarner Losh sp++; 7718b823408SWarner Losh if (strncmp(sp, "at ", 3) == 0) 7728b823408SWarner Losh sp += 3; 7738b823408SWarner Losh sp = cfg.set_vars(sp); 774*9b6cb520SWarner Losh while (isspace(*sp)) 775*9b6cb520SWarner Losh sp++; 7768b823408SWarner Losh if (strncmp(sp, "on ", 3) == 0) 7778b823408SWarner Losh cfg.set_variable("bus", sp + 3); 778842ccec5SWarner Losh break; 779b1ee04b1SWarner Losh } 780b1ee04b1SWarner Losh 7818b823408SWarner Losh cfg.find_and_execute(type); 7828b823408SWarner Losh cfg.pop_var_table(); 7833054f218SWarner Losh } 7843054f218SWarner Losh 785251bedd1SWarner Losh int 786251bedd1SWarner Losh create_socket(const char *name) 787251bedd1SWarner Losh { 788251bedd1SWarner Losh int fd, slen; 789251bedd1SWarner Losh struct sockaddr_un sun; 790251bedd1SWarner Losh 791251bedd1SWarner Losh if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) 792251bedd1SWarner Losh err(1, "socket"); 793251bedd1SWarner Losh bzero(&sun, sizeof(sun)); 794251bedd1SWarner Losh sun.sun_family = AF_UNIX; 795251bedd1SWarner Losh strlcpy(sun.sun_path, name, sizeof(sun.sun_path)); 796251bedd1SWarner Losh slen = SUN_LEN(&sun); 797251bedd1SWarner Losh unlink(name); 798e60fa014SJoe Marcus Clarke if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) 799e60fa014SJoe Marcus Clarke err(1, "fcntl"); 800251bedd1SWarner Losh if (bind(fd, (struct sockaddr *) & sun, slen) < 0) 801251bedd1SWarner Losh err(1, "bind"); 802251bedd1SWarner Losh listen(fd, 4); 80383818929SJoe Marcus Clarke chown(name, 0, 0); /* XXX - root.wheel */ 804e60fa014SJoe Marcus Clarke chmod(name, 0666); 805251bedd1SWarner Losh return (fd); 806251bedd1SWarner Losh } 807251bedd1SWarner Losh 808251bedd1SWarner Losh list<int> clients; 809251bedd1SWarner Losh 810251bedd1SWarner Losh void 811251bedd1SWarner Losh notify_clients(const char *data, int len) 812251bedd1SWarner Losh { 813251bedd1SWarner Losh list<int> bad; 814251bedd1SWarner Losh list<int>::const_iterator i; 815251bedd1SWarner Losh 816251bedd1SWarner Losh for (i = clients.begin(); i != clients.end(); i++) { 817251bedd1SWarner Losh if (write(*i, data, len) <= 0) { 818251bedd1SWarner Losh bad.push_back(*i); 819251bedd1SWarner Losh close(*i); 820251bedd1SWarner Losh } 821251bedd1SWarner Losh } 822251bedd1SWarner Losh 823251bedd1SWarner Losh for (i = bad.begin(); i != bad.end(); i++) 824251bedd1SWarner Losh clients.erase(find(clients.begin(), clients.end(), *i)); 825251bedd1SWarner Losh } 826251bedd1SWarner Losh 827251bedd1SWarner Losh void 828251bedd1SWarner Losh new_client(int fd) 829251bedd1SWarner Losh { 830251bedd1SWarner Losh int s; 831251bedd1SWarner Losh 832251bedd1SWarner Losh s = accept(fd, NULL, NULL); 833251bedd1SWarner Losh if (s != -1) 834251bedd1SWarner Losh clients.push_back(s); 835251bedd1SWarner Losh } 836251bedd1SWarner Losh 8373054f218SWarner Losh static void 8383054f218SWarner Losh event_loop(void) 8393054f218SWarner Losh { 8403054f218SWarner Losh int rv; 8413054f218SWarner Losh int fd; 8423054f218SWarner Losh char buffer[DEVCTL_MAXBUF]; 8435a882d77SWarner Losh int once = 0; 844251bedd1SWarner Losh int server_fd, max_fd; 8455a882d77SWarner Losh timeval tv; 8465a882d77SWarner Losh fd_set fds; 8473054f218SWarner Losh 8483054f218SWarner Losh fd = open(PATH_DEVCTL, O_RDONLY); 8493054f218SWarner Losh if (fd == -1) 850251bedd1SWarner Losh err(1, "Can't open devctl device %s", PATH_DEVCTL); 8513054f218SWarner Losh if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) 852251bedd1SWarner Losh err(1, "Can't set close-on-exec flag on devctl"); 853251bedd1SWarner Losh server_fd = create_socket(PIPE); 854251bedd1SWarner Losh max_fd = max(fd, server_fd) + 1; 8553054f218SWarner Losh while (1) { 8563054f218SWarner Losh if (romeo_must_die) 8573054f218SWarner Losh break; 8585a882d77SWarner Losh if (!once && !dflag && !nflag) { 8595a882d77SWarner Losh // Check to see if we have any events pending. 8605a882d77SWarner Losh tv.tv_sec = 0; 8615a882d77SWarner Losh tv.tv_usec = 0; 8625a882d77SWarner Losh FD_ZERO(&fds); 8635a882d77SWarner Losh FD_SET(fd, &fds); 8645a882d77SWarner Losh rv = select(fd + 1, &fds, &fds, &fds, &tv); 8655a882d77SWarner Losh // No events -> we've processed all pending events 866f3059505SWarner Losh if (rv == 0) { 8675a882d77SWarner Losh if (Dflag) 8685a882d77SWarner Losh fprintf(stderr, "Calling daemon\n"); 8691a0cc6b1SPawel Jakub Dawidek cfg.remove_pidfile(); 8701a0cc6b1SPawel Jakub Dawidek cfg.open_pidfile(); 8715a882d77SWarner Losh daemon(0, 0); 8721a0cc6b1SPawel Jakub Dawidek cfg.write_pidfile(); 8735a882d77SWarner Losh once++; 8745a882d77SWarner Losh } 8755a882d77SWarner Losh } 876251bedd1SWarner Losh FD_ZERO(&fds); 877251bedd1SWarner Losh FD_SET(fd, &fds); 878251bedd1SWarner Losh FD_SET(server_fd, &fds); 879251bedd1SWarner Losh rv = select(max_fd, &fds, NULL, NULL, NULL); 880251bedd1SWarner Losh if (rv == -1) { 881251bedd1SWarner Losh if (errno == EINTR) 882251bedd1SWarner Losh continue; 883251bedd1SWarner Losh err(1, "select"); 884251bedd1SWarner Losh } 885251bedd1SWarner Losh if (FD_ISSET(fd, &fds)) { 8863054f218SWarner Losh rv = read(fd, buffer, sizeof(buffer) - 1); 8873054f218SWarner Losh if (rv > 0) { 888251bedd1SWarner Losh notify_clients(buffer, rv); 8893054f218SWarner Losh buffer[rv] = '\0'; 8903054f218SWarner Losh while (buffer[--rv] == '\n') 8913054f218SWarner Losh buffer[rv] = '\0'; 8923054f218SWarner Losh process_event(buffer); 8933054f218SWarner Losh } else if (rv < 0) { 8943054f218SWarner Losh if (errno != EINTR) 8953054f218SWarner Losh break; 8963054f218SWarner Losh } else { 8973054f218SWarner Losh /* EOF */ 8983054f218SWarner Losh break; 8993054f218SWarner Losh } 9003054f218SWarner Losh } 901251bedd1SWarner Losh if (FD_ISSET(server_fd, &fds)) 902251bedd1SWarner Losh new_client(server_fd); 903251bedd1SWarner Losh } 9043054f218SWarner Losh close(fd); 9053054f218SWarner Losh } 9063054f218SWarner Losh 9073054f218SWarner Losh /* 9083054f218SWarner Losh * functions that the parser uses. 9093054f218SWarner Losh */ 9103054f218SWarner Losh void 9113054f218SWarner Losh add_attach(int prio, event_proc *p) 9123054f218SWarner Losh { 9133054f218SWarner Losh cfg.add_attach(prio, p); 9143054f218SWarner Losh } 9153054f218SWarner Losh 9163054f218SWarner Losh void 9173054f218SWarner Losh add_detach(int prio, event_proc *p) 9183054f218SWarner Losh { 9193054f218SWarner Losh cfg.add_detach(prio, p); 9203054f218SWarner Losh } 9213054f218SWarner Losh 9223054f218SWarner Losh void 9233054f218SWarner Losh add_directory(const char *dir) 9243054f218SWarner Losh { 9253054f218SWarner Losh cfg.add_directory(dir); 9263054f218SWarner Losh free(const_cast<char *>(dir)); 9273054f218SWarner Losh } 9283054f218SWarner Losh 9293054f218SWarner Losh void 9303054f218SWarner Losh add_nomatch(int prio, event_proc *p) 9313054f218SWarner Losh { 9323054f218SWarner Losh cfg.add_nomatch(prio, p); 9333054f218SWarner Losh } 9343054f218SWarner Losh 935842ccec5SWarner Losh void 936842ccec5SWarner Losh add_notify(int prio, event_proc *p) 937842ccec5SWarner Losh { 938842ccec5SWarner Losh cfg.add_notify(prio, p); 939842ccec5SWarner Losh } 940842ccec5SWarner Losh 9413054f218SWarner Losh event_proc * 9423054f218SWarner Losh add_to_event_proc(event_proc *ep, eps *eps) 9433054f218SWarner Losh { 9443054f218SWarner Losh if (ep == NULL) 9453054f218SWarner Losh ep = new event_proc(); 9463054f218SWarner Losh ep->add(eps); 9473054f218SWarner Losh return (ep); 9483054f218SWarner Losh } 9493054f218SWarner Losh 9503054f218SWarner Losh eps * 9513054f218SWarner Losh new_action(const char *cmd) 9523054f218SWarner Losh { 9533054f218SWarner Losh eps *e = new action(cmd); 9543054f218SWarner Losh free(const_cast<char *>(cmd)); 9553054f218SWarner Losh return (e); 9563054f218SWarner Losh } 9573054f218SWarner Losh 9583054f218SWarner Losh eps * 9593054f218SWarner Losh new_match(const char *var, const char *re) 9603054f218SWarner Losh { 9615102ef84SWarner Losh eps *e = new match(cfg, var, re); 9623054f218SWarner Losh free(const_cast<char *>(var)); 9633054f218SWarner Losh free(const_cast<char *>(re)); 9643054f218SWarner Losh return (e); 9653054f218SWarner Losh } 9663054f218SWarner Losh 967cd70782bSWarner Losh eps * 968cd70782bSWarner Losh new_media(const char *var, const char *re) 969cd70782bSWarner Losh { 970cd70782bSWarner Losh eps *e = new media(cfg, var, re); 971cd70782bSWarner Losh free(const_cast<char *>(var)); 972cd70782bSWarner Losh free(const_cast<char *>(re)); 973cd70782bSWarner Losh return (e); 974cd70782bSWarner Losh } 975cd70782bSWarner Losh 9763054f218SWarner Losh void 9773054f218SWarner Losh set_pidfile(const char *name) 9783054f218SWarner Losh { 9793054f218SWarner Losh cfg.set_pidfile(name); 9803054f218SWarner Losh free(const_cast<char *>(name)); 9813054f218SWarner Losh } 9823054f218SWarner Losh 9833054f218SWarner Losh void 9843054f218SWarner Losh set_variable(const char *var, const char *val) 9853054f218SWarner Losh { 9863054f218SWarner Losh cfg.set_variable(var, val); 9873054f218SWarner Losh free(const_cast<char *>(var)); 9883054f218SWarner Losh free(const_cast<char *>(val)); 9893054f218SWarner Losh } 9903054f218SWarner Losh 9913054f218SWarner Losh 9923054f218SWarner Losh 9933054f218SWarner Losh static void 9943054f218SWarner Losh gensighand(int) 9953054f218SWarner Losh { 9963054f218SWarner Losh romeo_must_die++; 9973054f218SWarner Losh _exit(0); 9983054f218SWarner Losh } 9993054f218SWarner Losh 10003054f218SWarner Losh static void 10013054f218SWarner Losh usage() 10023054f218SWarner Losh { 10035ef35a98SRuslan Ermilov fprintf(stderr, "usage: %s [-Ddn] [-f file]\n", getprogname()); 10043054f218SWarner Losh exit(1); 10053054f218SWarner Losh } 10063054f218SWarner Losh 10079c180898SWarner Losh static void 10089c180898SWarner Losh check_devd_enabled() 10099c180898SWarner Losh { 10109c180898SWarner Losh int val = 0; 10119c180898SWarner Losh size_t len; 10129c180898SWarner Losh 10139c180898SWarner Losh len = sizeof(val); 101479f92e25SWarner Losh if (sysctlbyname(SYSCTL, &val, &len, NULL, 0) != 0) 10159c180898SWarner Losh errx(1, "devctl sysctl missing from kernel!"); 10169c180898SWarner Losh if (val) { 10179c180898SWarner Losh warnx("Setting " SYSCTL " to 0"); 10189c180898SWarner Losh val = 0; 10199c180898SWarner Losh sysctlbyname(SYSCTL, NULL, NULL, &val, sizeof(val)); 10209c180898SWarner Losh } 10219c180898SWarner Losh } 10229c180898SWarner Losh 10233054f218SWarner Losh /* 10243054f218SWarner Losh * main 10253054f218SWarner Losh */ 10263054f218SWarner Losh int 10273054f218SWarner Losh main(int argc, char **argv) 10283054f218SWarner Losh { 10293054f218SWarner Losh int ch; 10303054f218SWarner Losh 10319c180898SWarner Losh check_devd_enabled(); 10328334958aSJoseph Koshy while ((ch = getopt(argc, argv, "Ddf:n")) != -1) { 10333054f218SWarner Losh switch (ch) { 10345a882d77SWarner Losh case 'D': 10355a882d77SWarner Losh Dflag++; 10365a882d77SWarner Losh break; 10373054f218SWarner Losh case 'd': 10383054f218SWarner Losh dflag++; 10393054f218SWarner Losh break; 10408334958aSJoseph Koshy case 'f': 10418334958aSJoseph Koshy configfile = optarg; 10428334958aSJoseph Koshy break; 10435a882d77SWarner Losh case 'n': 10445a882d77SWarner Losh nflag++; 10455a882d77SWarner Losh break; 10463054f218SWarner Losh default: 10473054f218SWarner Losh usage(); 10483054f218SWarner Losh } 10493054f218SWarner Losh } 10503054f218SWarner Losh 10513054f218SWarner Losh cfg.parse(); 1052fd6a8f23SWarner Losh if (!dflag && nflag) { 10531a0cc6b1SPawel Jakub Dawidek cfg.open_pidfile(); 10543054f218SWarner Losh daemon(0, 0); 10551a0cc6b1SPawel Jakub Dawidek cfg.write_pidfile(); 1056fd6a8f23SWarner Losh } 1057f32a7686SWarner Losh signal(SIGPIPE, SIG_IGN); 10583054f218SWarner Losh signal(SIGHUP, gensighand); 10593054f218SWarner Losh signal(SIGINT, gensighand); 10603054f218SWarner Losh signal(SIGTERM, gensighand); 10613054f218SWarner Losh event_loop(); 10623054f218SWarner Losh return (0); 10633054f218SWarner Losh } 1064