13054f218SWarner Losh /*- 2b1ee04b1SWarner Losh * Copyright (c) 2002-2003 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. 253054f218SWarner Losh */ 263054f218SWarner Losh 273054f218SWarner Losh /* 283054f218SWarner Losh * DEVD control daemon. 293054f218SWarner Losh */ 303054f218SWarner Losh 313054f218SWarner Losh // TODO list: 323054f218SWarner Losh // o devd.conf and devd man pages need a lot of help: 33251bedd1SWarner Losh // - devd needs to document the unix domain socket 343054f218SWarner Losh // - devd.conf needs more details on the supported statements. 353054f218SWarner Losh 363054f218SWarner Losh #include <sys/cdefs.h> 373054f218SWarner Losh __FBSDID("$FreeBSD$"); 383054f218SWarner Losh 393054f218SWarner Losh #include <sys/param.h> 40251bedd1SWarner Losh #include <sys/socket.h> 41251bedd1SWarner Losh #include <sys/stat.h> 429c180898SWarner Losh #include <sys/sysctl.h> 43251bedd1SWarner Losh #include <sys/types.h> 44251bedd1SWarner Losh #include <sys/un.h> 453054f218SWarner Losh 465102ef84SWarner Losh #include <ctype.h> 473054f218SWarner Losh #include <dirent.h> 483054f218SWarner Losh #include <errno.h> 493054f218SWarner Losh #include <err.h> 503054f218SWarner Losh #include <fcntl.h> 511a0cc6b1SPawel Jakub Dawidek #include <libutil.h> 525102ef84SWarner Losh #include <regex.h> 53f32a7686SWarner Losh #include <signal.h> 543054f218SWarner Losh #include <stdlib.h> 553054f218SWarner Losh #include <stdio.h> 563054f218SWarner Losh #include <string.h> 573054f218SWarner Losh #include <unistd.h> 583054f218SWarner Losh 598b823408SWarner Losh #include <algorithm> 603054f218SWarner Losh #include <map> 613054f218SWarner Losh #include <string> 62251bedd1SWarner Losh #include <list> 633054f218SWarner Losh #include <vector> 643054f218SWarner Losh 656aeeca8eSWarner Losh #include "devd.h" /* C compatible definitions */ 666aeeca8eSWarner Losh #include "devd.hh" /* C++ class definitions */ 673054f218SWarner Losh 68251bedd1SWarner Losh #define PIPE "/var/run/devd.pipe" 693054f218SWarner Losh #define CF "/etc/devd.conf" 709c180898SWarner Losh #define SYSCTL "hw.bus.devctl_disable" 713054f218SWarner Losh 723054f218SWarner Losh using namespace std; 733054f218SWarner Losh 743054f218SWarner Losh extern FILE *yyin; 753054f218SWarner Losh extern int lineno; 763054f218SWarner Losh 77842ccec5SWarner Losh static const char notify = '!'; 788b823408SWarner Losh static const char nomatch = '?'; 798b823408SWarner Losh static const char attach = '+'; 808b823408SWarner Losh static const char detach = '-'; 818b823408SWarner Losh 821a0cc6b1SPawel Jakub Dawidek static struct pidfh *pfh; 831a0cc6b1SPawel Jakub Dawidek 845a882d77SWarner Losh int Dflag; 853054f218SWarner Losh int dflag; 86812f53a7SWarner Losh int nflag; 873054f218SWarner Losh int romeo_must_die = 0; 883054f218SWarner Losh 898334958aSJoseph Koshy static const char *configfile = CF; 908334958aSJoseph Koshy 913054f218SWarner Losh static void event_loop(void); 923054f218SWarner Losh static void usage(void); 933054f218SWarner Losh 948b823408SWarner Losh template <class T> void 958b823408SWarner Losh delete_and_clear(vector<T *> &v) 968b823408SWarner Losh { 978b823408SWarner Losh typename vector<T *>::const_iterator i; 983054f218SWarner Losh 998b823408SWarner Losh for (i = v.begin(); i != v.end(); i++) 1008b823408SWarner Losh delete *i; 1018b823408SWarner Losh v.clear(); 1028b823408SWarner Losh } 1038b823408SWarner Losh 1043054f218SWarner Losh config cfg; 1053054f218SWarner Losh 1063054f218SWarner Losh event_proc::event_proc() : _prio(-1) 1073054f218SWarner Losh { 1083054f218SWarner Losh // nothing 1093054f218SWarner Losh } 1103054f218SWarner Losh 1113054f218SWarner Losh event_proc::~event_proc() 1123054f218SWarner Losh { 11313f8bb71SAlexander Nedotsukov delete_and_clear(_epsvec); 1143054f218SWarner Losh } 1153054f218SWarner Losh 1163054f218SWarner Losh void 1173054f218SWarner Losh event_proc::add(eps *eps) 1183054f218SWarner Losh { 1193054f218SWarner Losh _epsvec.push_back(eps); 1203054f218SWarner Losh } 1213054f218SWarner Losh 1223054f218SWarner Losh bool 1233054f218SWarner Losh event_proc::matches(config &c) 1243054f218SWarner Losh { 1253054f218SWarner Losh vector<eps *>::const_iterator i; 1263054f218SWarner Losh 1273054f218SWarner Losh for (i = _epsvec.begin(); i != _epsvec.end(); i++) 1283054f218SWarner Losh if (!(*i)->do_match(c)) 1293054f218SWarner Losh return (false); 1303054f218SWarner Losh return (true); 1313054f218SWarner Losh } 1323054f218SWarner Losh 1333054f218SWarner Losh bool 1343054f218SWarner Losh event_proc::run(config &c) 1353054f218SWarner Losh { 1363054f218SWarner Losh vector<eps *>::const_iterator i; 1373054f218SWarner Losh 1383054f218SWarner Losh for (i = _epsvec.begin(); i != _epsvec.end(); i++) 1393054f218SWarner Losh if (!(*i)->do_action(c)) 1403054f218SWarner Losh return (false); 1413054f218SWarner Losh return (true); 1423054f218SWarner Losh } 1433054f218SWarner Losh 1443054f218SWarner Losh action::action(const char *cmd) 1453054f218SWarner Losh : _cmd(cmd) 1463054f218SWarner Losh { 1473054f218SWarner Losh // nothing 1483054f218SWarner Losh } 1493054f218SWarner Losh 1503054f218SWarner Losh action::~action() 1513054f218SWarner Losh { 1523054f218SWarner Losh // nothing 1533054f218SWarner Losh } 1543054f218SWarner Losh 1553054f218SWarner Losh bool 1565102ef84SWarner Losh action::do_action(config &c) 1573054f218SWarner Losh { 1588b823408SWarner Losh string s = c.expand_string(_cmd); 1595a882d77SWarner Losh if (Dflag) 1608b823408SWarner Losh fprintf(stderr, "Executing '%s'\n", s.c_str()); 1618b823408SWarner Losh ::system(s.c_str()); 1623054f218SWarner Losh return (true); 1633054f218SWarner Losh } 1643054f218SWarner Losh 1655102ef84SWarner Losh match::match(config &c, const char *var, const char *re) 1668b823408SWarner Losh : _var(var) 1673054f218SWarner Losh { 1688b823408SWarner Losh string pattern = re; 1698b823408SWarner Losh _re = "^"; 1708b823408SWarner Losh _re.append(c.expand_string(string(re))); 1718b823408SWarner Losh _re.append("$"); 1729cb4a7bdSWarner Losh regcomp(&_regex, _re.c_str(), REG_EXTENDED | REG_NOSUB | REG_ICASE); 1733054f218SWarner Losh } 1743054f218SWarner Losh 1753054f218SWarner Losh match::~match() 1763054f218SWarner Losh { 1775102ef84SWarner Losh regfree(&_regex); 1783054f218SWarner Losh } 1793054f218SWarner Losh 1803054f218SWarner Losh bool 1815102ef84SWarner Losh match::do_match(config &c) 1823054f218SWarner Losh { 1835102ef84SWarner Losh string value = c.get_variable(_var); 1845102ef84SWarner Losh bool retval; 1855102ef84SWarner Losh 1865a882d77SWarner Losh if (Dflag) 1878b823408SWarner Losh fprintf(stderr, "Testing %s=%s against %s\n", _var.c_str(), 1888b823408SWarner Losh value.c_str(), _re.c_str()); 1898b823408SWarner Losh 1905102ef84SWarner Losh retval = (regexec(&_regex, value.c_str(), 0, NULL, 0) == 0); 1915102ef84SWarner Losh return retval; 1923054f218SWarner Losh } 1933054f218SWarner Losh 194cd70782bSWarner Losh #include <sys/sockio.h> 195cd70782bSWarner Losh #include <net/if.h> 196cd70782bSWarner Losh #include <net/if_media.h> 197cd70782bSWarner Losh 19894d2d4ebSBrooks Davis media::media(config &, const char *var, const char *type) 199cd70782bSWarner Losh : _var(var), _type(-1) 200cd70782bSWarner Losh { 201cd70782bSWarner Losh static struct ifmedia_description media_types[] = { 202cd70782bSWarner Losh { IFM_ETHER, "Ethernet" }, 203cd70782bSWarner Losh { IFM_TOKEN, "Tokenring" }, 204cd70782bSWarner Losh { IFM_FDDI, "FDDI" }, 205cd70782bSWarner Losh { IFM_IEEE80211, "802.11" }, 206cd70782bSWarner Losh { IFM_ATM, "ATM" }, 207cd70782bSWarner Losh { IFM_CARP, "CARP" }, 208cd70782bSWarner Losh { -1, "unknown" }, 209cd70782bSWarner Losh { 0, NULL }, 210cd70782bSWarner Losh }; 211cd70782bSWarner Losh for (int i = 0; media_types[i].ifmt_string != NULL; i++) 212cd70782bSWarner Losh if (strcasecmp(type, media_types[i].ifmt_string) == 0) { 213cd70782bSWarner Losh _type = media_types[i].ifmt_word; 214cd70782bSWarner Losh break; 215cd70782bSWarner Losh } 216cd70782bSWarner Losh } 217cd70782bSWarner Losh 218cd70782bSWarner Losh media::~media() 219cd70782bSWarner Losh { 220cd70782bSWarner Losh } 221cd70782bSWarner Losh 222cd70782bSWarner Losh bool 223cd70782bSWarner Losh media::do_match(config &c) 224cd70782bSWarner Losh { 22509c47e76SWarner Losh string value; 226cd70782bSWarner Losh struct ifmediareq ifmr; 227cd70782bSWarner Losh bool retval; 228cd70782bSWarner Losh int s; 229cd70782bSWarner Losh 23009c47e76SWarner Losh // Since we can be called from both a device attach/detach 23109c47e76SWarner Losh // context where device-name is defined and what we want, 23209c47e76SWarner Losh // as well as from a link status context, where subsystem is 23309c47e76SWarner Losh // the name of interest, first try device-name and fall back 23409c47e76SWarner Losh // to subsystem if none exists. 23509c47e76SWarner Losh value = c.get_variable("device-name"); 23609c47e76SWarner Losh if (value.length() == 0) 237de02eec8SWarner Losh value = c.get_variable("subsystem"); 238cd70782bSWarner Losh if (Dflag) 239cd70782bSWarner Losh fprintf(stderr, "Testing media type of %s against 0x%x\n", 240cd70782bSWarner Losh value.c_str(), _type); 241cd70782bSWarner Losh 242cd70782bSWarner Losh retval = false; 243cd70782bSWarner Losh 244cd70782bSWarner Losh s = socket(PF_INET, SOCK_DGRAM, 0); 245cd70782bSWarner Losh if (s >= 0) { 246cd70782bSWarner Losh memset(&ifmr, 0, sizeof(ifmr)); 247cd70782bSWarner Losh strncpy(ifmr.ifm_name, value.c_str(), sizeof(ifmr.ifm_name)); 248cd70782bSWarner Losh 249cd70782bSWarner Losh if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0 && 250cd70782bSWarner Losh ifmr.ifm_status & IFM_AVALID) { 251cd70782bSWarner Losh if (Dflag) 252cd70782bSWarner Losh fprintf(stderr, "%s has media type 0x%x\n", 253cd70782bSWarner Losh value.c_str(), IFM_TYPE(ifmr.ifm_active)); 254cd70782bSWarner Losh retval = (IFM_TYPE(ifmr.ifm_active) == _type); 255cd70782bSWarner Losh } else if (_type == -1) { 256cd70782bSWarner Losh if (Dflag) 257cd70782bSWarner Losh fprintf(stderr, "%s has unknown media type\n", 258cd70782bSWarner Losh value.c_str()); 259cd70782bSWarner Losh retval = true; 260cd70782bSWarner Losh } 261cd70782bSWarner Losh close(s); 262cd70782bSWarner Losh } 263cd70782bSWarner Losh 264cd70782bSWarner Losh return retval; 265cd70782bSWarner Losh } 266cd70782bSWarner Losh 2673054f218SWarner Losh const string var_list::bogus = "_$_$_$_$_B_O_G_U_S_$_$_$_$_"; 2683054f218SWarner Losh const string var_list::nothing = ""; 2693054f218SWarner Losh 2703054f218SWarner Losh const string & 2713054f218SWarner Losh var_list::get_variable(const string &var) const 2723054f218SWarner Losh { 2733054f218SWarner Losh map<string, string>::const_iterator i; 2743054f218SWarner Losh 2753054f218SWarner Losh i = _vars.find(var); 2763054f218SWarner Losh if (i == _vars.end()) 2778b823408SWarner Losh return (var_list::bogus); 2783054f218SWarner Losh return (i->second); 2793054f218SWarner Losh } 2803054f218SWarner Losh 2813054f218SWarner Losh bool 2823054f218SWarner Losh var_list::is_set(const string &var) const 2833054f218SWarner Losh { 2843054f218SWarner Losh return (_vars.find(var) != _vars.end()); 2853054f218SWarner Losh } 2863054f218SWarner Losh 2873054f218SWarner Losh void 2883054f218SWarner Losh var_list::set_variable(const string &var, const string &val) 2893054f218SWarner Losh { 2905a882d77SWarner Losh if (Dflag) 291528d3f79SWarner Losh fprintf(stderr, "setting %s=%s\n", var.c_str(), val.c_str()); 2923054f218SWarner Losh _vars[var] = val; 2933054f218SWarner Losh } 2943054f218SWarner Losh 2953054f218SWarner Losh void 2963054f218SWarner Losh config::reset(void) 2973054f218SWarner Losh { 2983054f218SWarner Losh _dir_list.clear(); 2998b823408SWarner Losh delete_and_clear(_var_list_table); 3008b823408SWarner Losh delete_and_clear(_attach_list); 3018b823408SWarner Losh delete_and_clear(_detach_list); 3028b823408SWarner Losh delete_and_clear(_nomatch_list); 303842ccec5SWarner Losh delete_and_clear(_notify_list); 3043054f218SWarner Losh } 3053054f218SWarner Losh 3063054f218SWarner Losh void 3073054f218SWarner Losh config::parse_one_file(const char *fn) 3083054f218SWarner Losh { 3095a882d77SWarner Losh if (Dflag) 310*0f3311c5SPoul-Henning Kamp fprintf(stderr, "Parsing %s\n", fn); 3113054f218SWarner Losh yyin = fopen(fn, "r"); 3123054f218SWarner Losh if (yyin == NULL) 3133054f218SWarner Losh err(1, "Cannot open config file %s", fn); 3144a3050fcSMaxim Konovalov lineno = 1; 3153054f218SWarner Losh if (yyparse() != 0) 3163054f218SWarner Losh errx(1, "Cannot parse %s at line %d", fn, lineno); 3173054f218SWarner Losh fclose(yyin); 3183054f218SWarner Losh } 3193054f218SWarner Losh 3203054f218SWarner Losh void 3213054f218SWarner Losh config::parse_files_in_dir(const char *dirname) 3223054f218SWarner Losh { 3233054f218SWarner Losh DIR *dirp; 3243054f218SWarner Losh struct dirent *dp; 3253054f218SWarner Losh char path[PATH_MAX]; 3263054f218SWarner Losh 3275a882d77SWarner Losh if (Dflag) 328*0f3311c5SPoul-Henning Kamp fprintf(stderr, "Parsing files in %s\n", dirname); 3293054f218SWarner Losh dirp = opendir(dirname); 3303054f218SWarner Losh if (dirp == NULL) 3313054f218SWarner Losh return; 3323054f218SWarner Losh readdir(dirp); /* Skip . */ 3333054f218SWarner Losh readdir(dirp); /* Skip .. */ 3343054f218SWarner Losh while ((dp = readdir(dirp)) != NULL) { 3353054f218SWarner Losh if (strcmp(dp->d_name + dp->d_namlen - 5, ".conf") == 0) { 3363054f218SWarner Losh snprintf(path, sizeof(path), "%s/%s", 3373054f218SWarner Losh dirname, dp->d_name); 3383054f218SWarner Losh parse_one_file(path); 3393054f218SWarner Losh } 3403054f218SWarner Losh } 3413054f218SWarner Losh } 3423054f218SWarner Losh 3438b823408SWarner Losh class epv_greater { 3448b823408SWarner Losh public: 3458b823408SWarner Losh int operator()(event_proc *const&l1, event_proc *const&l2) 3468b823408SWarner Losh { 3478b823408SWarner Losh return (l1->get_priority() > l2->get_priority()); 3488b823408SWarner Losh } 3498b823408SWarner Losh }; 3508b823408SWarner Losh 3518b823408SWarner Losh void 3528b823408SWarner Losh config::sort_vector(vector<event_proc *> &v) 3538b823408SWarner Losh { 3548b823408SWarner Losh sort(v.begin(), v.end(), epv_greater()); 3558b823408SWarner Losh } 3568b823408SWarner Losh 3573054f218SWarner Losh void 3583054f218SWarner Losh config::parse(void) 3593054f218SWarner Losh { 3603054f218SWarner Losh vector<string>::const_iterator i; 3613054f218SWarner Losh 3628334958aSJoseph Koshy parse_one_file(configfile); 3633054f218SWarner Losh for (i = _dir_list.begin(); i != _dir_list.end(); i++) 3643054f218SWarner Losh parse_files_in_dir((*i).c_str()); 3658b823408SWarner Losh sort_vector(_attach_list); 3668b823408SWarner Losh sort_vector(_detach_list); 3678b823408SWarner Losh sort_vector(_nomatch_list); 368842ccec5SWarner Losh sort_vector(_notify_list); 3693054f218SWarner Losh } 3703054f218SWarner Losh 3713054f218SWarner Losh void 3721a0cc6b1SPawel Jakub Dawidek config::open_pidfile() 3733054f218SWarner Losh { 3741a0cc6b1SPawel Jakub Dawidek pid_t otherpid; 3753054f218SWarner Losh 3763054f218SWarner Losh if (_pidfile == "") 3773054f218SWarner Losh return; 3781a0cc6b1SPawel Jakub Dawidek pfh = pidfile_open(_pidfile.c_str(), 0600, &otherpid); 3791a0cc6b1SPawel Jakub Dawidek if (pfh == NULL) { 3801a0cc6b1SPawel Jakub Dawidek if (errno == EEXIST) 3811a0cc6b1SPawel Jakub Dawidek errx(1, "devd already running, pid: %d", (int)otherpid); 3821a0cc6b1SPawel Jakub Dawidek warn("cannot open pid file"); 3831a0cc6b1SPawel Jakub Dawidek } 3841a0cc6b1SPawel Jakub Dawidek } 3851a0cc6b1SPawel Jakub Dawidek 3861a0cc6b1SPawel Jakub Dawidek void 3871a0cc6b1SPawel Jakub Dawidek config::write_pidfile() 3881a0cc6b1SPawel Jakub Dawidek { 3891a0cc6b1SPawel Jakub Dawidek 3901a0cc6b1SPawel Jakub Dawidek pidfile_write(pfh); 3911a0cc6b1SPawel Jakub Dawidek } 3921a0cc6b1SPawel Jakub Dawidek 3931a0cc6b1SPawel Jakub Dawidek void 3941a0cc6b1SPawel Jakub Dawidek config::remove_pidfile() 3951a0cc6b1SPawel Jakub Dawidek { 3961a0cc6b1SPawel Jakub Dawidek 3971a0cc6b1SPawel Jakub Dawidek pidfile_remove(pfh); 3983054f218SWarner Losh } 3993054f218SWarner Losh 4003054f218SWarner Losh void 4013054f218SWarner Losh config::add_attach(int prio, event_proc *p) 4023054f218SWarner Losh { 4033054f218SWarner Losh p->set_priority(prio); 4043054f218SWarner Losh _attach_list.push_back(p); 4053054f218SWarner Losh } 4063054f218SWarner Losh 4073054f218SWarner Losh void 4083054f218SWarner Losh config::add_detach(int prio, event_proc *p) 4093054f218SWarner Losh { 4103054f218SWarner Losh p->set_priority(prio); 4113054f218SWarner Losh _detach_list.push_back(p); 4123054f218SWarner Losh } 4133054f218SWarner Losh 4143054f218SWarner Losh void 4153054f218SWarner Losh config::add_directory(const char *dir) 4163054f218SWarner Losh { 4173054f218SWarner Losh _dir_list.push_back(string(dir)); 4183054f218SWarner Losh } 4193054f218SWarner Losh 4203054f218SWarner Losh void 4213054f218SWarner Losh config::add_nomatch(int prio, event_proc *p) 4223054f218SWarner Losh { 4233054f218SWarner Losh p->set_priority(prio); 4243054f218SWarner Losh _nomatch_list.push_back(p); 4253054f218SWarner Losh } 4263054f218SWarner Losh 4273054f218SWarner Losh void 428842ccec5SWarner Losh config::add_notify(int prio, event_proc *p) 429842ccec5SWarner Losh { 430842ccec5SWarner Losh p->set_priority(prio); 431842ccec5SWarner Losh _notify_list.push_back(p); 432842ccec5SWarner Losh } 433842ccec5SWarner Losh 434842ccec5SWarner Losh void 4353054f218SWarner Losh config::set_pidfile(const char *fn) 4363054f218SWarner Losh { 4373054f218SWarner Losh _pidfile = string(fn); 4383054f218SWarner Losh } 4393054f218SWarner Losh 4403054f218SWarner Losh void 4413054f218SWarner Losh config::push_var_table() 4423054f218SWarner Losh { 4433054f218SWarner Losh var_list *vl; 4443054f218SWarner Losh 4453054f218SWarner Losh vl = new var_list(); 4463054f218SWarner Losh _var_list_table.push_back(vl); 4475a882d77SWarner Losh if (Dflag) 4488b823408SWarner Losh fprintf(stderr, "Pushing table\n"); 4493054f218SWarner Losh } 4503054f218SWarner Losh 4513054f218SWarner Losh void 4523054f218SWarner Losh config::pop_var_table() 4533054f218SWarner Losh { 4543054f218SWarner Losh delete _var_list_table.back(); 4553054f218SWarner Losh _var_list_table.pop_back(); 4565a882d77SWarner Losh if (Dflag) 4578b823408SWarner Losh fprintf(stderr, "Popping table\n"); 4583054f218SWarner Losh } 4593054f218SWarner Losh 4603054f218SWarner Losh void 4613054f218SWarner Losh config::set_variable(const char *var, const char *val) 4623054f218SWarner Losh { 4633054f218SWarner Losh _var_list_table.back()->set_variable(var, val); 4643054f218SWarner Losh } 4653054f218SWarner Losh 4663054f218SWarner Losh const string & 4673054f218SWarner Losh config::get_variable(const string &var) 4683054f218SWarner Losh { 4693054f218SWarner Losh vector<var_list *>::reverse_iterator i; 4703054f218SWarner Losh 4713054f218SWarner Losh for (i = _var_list_table.rbegin(); i != _var_list_table.rend(); i++) { 4723054f218SWarner Losh if ((*i)->is_set(var)) 4738b823408SWarner Losh return ((*i)->get_variable(var)); 4743054f218SWarner Losh } 4753054f218SWarner Losh return (var_list::nothing); 4763054f218SWarner Losh } 4773054f218SWarner Losh 4788b823408SWarner Losh bool 4798b823408SWarner Losh config::is_id_char(char ch) 4808b823408SWarner Losh { 4818b823408SWarner Losh return (ch != '\0' && (isalpha(ch) || isdigit(ch) || ch == '_' || 4828b823408SWarner Losh ch == '-')); 4838b823408SWarner Losh } 4848b823408SWarner Losh 4855102ef84SWarner Losh void 4866cabd675SWarner Losh config::expand_one(const char *&src, string &dst) 4873054f218SWarner Losh { 4885102ef84SWarner Losh int count; 4896cabd675SWarner Losh string buffer, varstr; 4905102ef84SWarner Losh 4918b823408SWarner Losh src++; 4925102ef84SWarner Losh // $$ -> $ 4935102ef84SWarner Losh if (*src == '$') { 4946cabd675SWarner Losh dst.append(src++, 1); 4955102ef84SWarner Losh return; 4965102ef84SWarner Losh } 4975102ef84SWarner Losh 4985102ef84SWarner Losh // $(foo) -> $(foo) 4998b823408SWarner Losh // Not sure if I want to support this or not, so for now we just pass 5008b823408SWarner Losh // it through. 5015102ef84SWarner Losh if (*src == '(') { 5026cabd675SWarner Losh dst.append("$"); 5035102ef84SWarner Losh count = 1; 5046cabd675SWarner Losh /* If the string ends before ) is matched , return. */ 5056cabd675SWarner Losh while (count > 0 && *src) { 5065102ef84SWarner Losh if (*src == ')') 5075102ef84SWarner Losh count--; 5085102ef84SWarner Losh else if (*src == '(') 5095102ef84SWarner Losh count++; 5106cabd675SWarner Losh dst.append(src++, 1); 5115102ef84SWarner Losh } 5125102ef84SWarner Losh return; 5135102ef84SWarner Losh } 5145102ef84SWarner Losh 5155102ef84SWarner Losh // ${^A-Za-z] -> $\1 5165102ef84SWarner Losh if (!isalpha(*src)) { 5176cabd675SWarner Losh dst.append("$"); 5186cabd675SWarner Losh dst.append(src++, 1); 5195102ef84SWarner Losh return; 5205102ef84SWarner Losh } 5215102ef84SWarner Losh 5225102ef84SWarner Losh // $var -> replace with value 5236cabd675SWarner Losh do { 5246cabd675SWarner Losh buffer.append(src++, 1); 52566ff6821SWarner Losh } while (is_id_char(*src)); 5266cabd675SWarner Losh buffer.append("", 1); 5276cabd675SWarner Losh varstr = get_variable(buffer.c_str()); 5286cabd675SWarner Losh dst.append(varstr); 5295102ef84SWarner Losh } 5305102ef84SWarner Losh 5315102ef84SWarner Losh const string 5325102ef84SWarner Losh config::expand_string(const string &s) 5335102ef84SWarner Losh { 5345102ef84SWarner Losh const char *src; 5356cabd675SWarner Losh string dst; 5365102ef84SWarner Losh 5375102ef84SWarner Losh src = s.c_str(); 5385102ef84SWarner Losh while (*src) { 5395102ef84SWarner Losh if (*src == '$') 5406cabd675SWarner Losh expand_one(src, dst); 5415102ef84SWarner Losh else 5426cabd675SWarner Losh dst.append(src++, 1); 5435102ef84SWarner Losh } 5446cabd675SWarner Losh dst.append("", 1); 5455102ef84SWarner Losh 5466cabd675SWarner Losh return (dst); 5473054f218SWarner Losh } 5483054f218SWarner Losh 5498b823408SWarner Losh bool 5508b823408SWarner Losh config::chop_var(char *&buffer, char *&lhs, char *&rhs) 5518b823408SWarner Losh { 5528b823408SWarner Losh char *walker; 5538b823408SWarner Losh 5548b823408SWarner Losh if (*buffer == '\0') 5558b823408SWarner Losh return (false); 5568b823408SWarner Losh walker = lhs = buffer; 5578b823408SWarner Losh while (is_id_char(*walker)) 5588b823408SWarner Losh walker++; 5598b823408SWarner Losh if (*walker != '=') 5608b823408SWarner Losh return (false); 5618b823408SWarner Losh walker++; // skip = 5628b823408SWarner Losh if (*walker == '"') { 5638b823408SWarner Losh walker++; // skip " 5648b823408SWarner Losh rhs = walker; 5658b823408SWarner Losh while (*walker && *walker != '"') 5668b823408SWarner Losh walker++; 5678b823408SWarner Losh if (*walker != '"') 5688b823408SWarner Losh return (false); 5698b823408SWarner Losh rhs[-2] = '\0'; 5708b823408SWarner Losh *walker++ = '\0'; 5718b823408SWarner Losh } else { 5728b823408SWarner Losh rhs = walker; 5738b823408SWarner Losh while (*walker && !isspace(*walker)) 5748b823408SWarner Losh walker++; 5758b823408SWarner Losh if (*walker != '\0') 5768b823408SWarner Losh *walker++ = '\0'; 5778b823408SWarner Losh rhs[-1] = '\0'; 5788b823408SWarner Losh } 579b1ee04b1SWarner Losh while (isspace(*walker)) 580b1ee04b1SWarner Losh walker++; 5818b823408SWarner Losh buffer = walker; 5828b823408SWarner Losh return (true); 5838b823408SWarner Losh } 5848b823408SWarner Losh 5858b823408SWarner Losh 5868b823408SWarner Losh char * 5878b823408SWarner Losh config::set_vars(char *buffer) 5888b823408SWarner Losh { 5898b823408SWarner Losh char *lhs; 5908b823408SWarner Losh char *rhs; 5918b823408SWarner Losh 5928b823408SWarner Losh while (1) { 5938b823408SWarner Losh if (!chop_var(buffer, lhs, rhs)) 5948b823408SWarner Losh break; 5958b823408SWarner Losh set_variable(lhs, rhs); 5968b823408SWarner Losh } 5978b823408SWarner Losh return (buffer); 5988b823408SWarner Losh } 5998b823408SWarner Losh 6008b823408SWarner Losh void 6018b823408SWarner Losh config::find_and_execute(char type) 6028b823408SWarner Losh { 6038b823408SWarner Losh vector<event_proc *> *l; 6048b823408SWarner Losh vector<event_proc *>::const_iterator i; 60594d2d4ebSBrooks Davis const char *s; 6068b823408SWarner Losh 6078b823408SWarner Losh switch (type) { 6088b823408SWarner Losh default: 6098b823408SWarner Losh return; 610842ccec5SWarner Losh case notify: 611842ccec5SWarner Losh l = &_notify_list; 612842ccec5SWarner Losh s = "notify"; 613842ccec5SWarner Losh break; 6148b823408SWarner Losh case nomatch: 6158b823408SWarner Losh l = &_nomatch_list; 6168b823408SWarner Losh s = "nomatch"; 6178b823408SWarner Losh break; 6188b823408SWarner Losh case attach: 6198b823408SWarner Losh l = &_attach_list; 6208b823408SWarner Losh s = "attach"; 6218b823408SWarner Losh break; 6228b823408SWarner Losh case detach: 6238b823408SWarner Losh l = &_detach_list; 6248b823408SWarner Losh s = "detach"; 6258b823408SWarner Losh break; 6268b823408SWarner Losh } 6275a882d77SWarner Losh if (Dflag) 6288b823408SWarner Losh fprintf(stderr, "Processing %s event\n", s); 6298b823408SWarner Losh for (i = l->begin(); i != l->end(); i++) { 6308b823408SWarner Losh if ((*i)->matches(*this)) { 6318b823408SWarner Losh (*i)->run(*this); 6328b823408SWarner Losh break; 6338b823408SWarner Losh } 6348b823408SWarner Losh } 6358b823408SWarner Losh 6368b823408SWarner Losh } 6378b823408SWarner Losh 6383054f218SWarner Losh 6393054f218SWarner Losh static void 6408b823408SWarner Losh process_event(char *buffer) 6413054f218SWarner Losh { 6423054f218SWarner Losh char type; 6433054f218SWarner Losh char *sp; 6443054f218SWarner Losh 6458b823408SWarner Losh sp = buffer + 1; 6465a882d77SWarner Losh if (Dflag) 6478b823408SWarner Losh fprintf(stderr, "Processing event '%s'\n", buffer); 6483054f218SWarner Losh type = *buffer++; 6498b823408SWarner Losh cfg.push_var_table(); 6508b823408SWarner Losh // No match doesn't have a device, and the format is a little 6518b823408SWarner Losh // different, so handle it separately. 652842ccec5SWarner Losh switch (type) { 653842ccec5SWarner Losh case notify: 654842ccec5SWarner Losh sp = cfg.set_vars(sp); 655842ccec5SWarner Losh break; 656842ccec5SWarner Losh case nomatch: 657528d3f79SWarner Losh //? at location pnp-info on bus 658528d3f79SWarner Losh sp = strchr(sp, ' '); 659528d3f79SWarner Losh if (sp == NULL) 660528d3f79SWarner Losh return; /* Can't happen? */ 661528d3f79SWarner Losh *sp++ = '\0'; 662842ccec5SWarner Losh if (strncmp(sp, "at ", 3) == 0) 663842ccec5SWarner Losh sp += 3; 664842ccec5SWarner Losh sp = cfg.set_vars(sp); 665842ccec5SWarner Losh if (strncmp(sp, "on ", 3) == 0) 666842ccec5SWarner Losh cfg.set_variable("bus", sp + 3); 667842ccec5SWarner Losh break; 668842ccec5SWarner Losh case attach: /*FALLTHROUGH*/ 669842ccec5SWarner Losh case detach: 6708b823408SWarner Losh sp = strchr(sp, ' '); 6713054f218SWarner Losh if (sp == NULL) 6723054f218SWarner Losh return; /* Can't happen? */ 6738b823408SWarner Losh *sp++ = '\0'; 6748b823408SWarner Losh cfg.set_variable("device-name", buffer); 6758b823408SWarner Losh if (strncmp(sp, "at ", 3) == 0) 6768b823408SWarner Losh sp += 3; 6778b823408SWarner Losh sp = cfg.set_vars(sp); 6788b823408SWarner Losh if (strncmp(sp, "on ", 3) == 0) 6798b823408SWarner Losh cfg.set_variable("bus", sp + 3); 680842ccec5SWarner Losh break; 681b1ee04b1SWarner Losh } 682b1ee04b1SWarner Losh 6838b823408SWarner Losh cfg.find_and_execute(type); 6848b823408SWarner Losh cfg.pop_var_table(); 6853054f218SWarner Losh } 6863054f218SWarner Losh 687251bedd1SWarner Losh int 688251bedd1SWarner Losh create_socket(const char *name) 689251bedd1SWarner Losh { 690251bedd1SWarner Losh int fd, slen; 691251bedd1SWarner Losh struct sockaddr_un sun; 692251bedd1SWarner Losh 693251bedd1SWarner Losh if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) 694251bedd1SWarner Losh err(1, "socket"); 695251bedd1SWarner Losh bzero(&sun, sizeof(sun)); 696251bedd1SWarner Losh sun.sun_family = AF_UNIX; 697251bedd1SWarner Losh strlcpy(sun.sun_path, name, sizeof(sun.sun_path)); 698251bedd1SWarner Losh slen = SUN_LEN(&sun); 699251bedd1SWarner Losh unlink(name); 700e60fa014SJoe Marcus Clarke if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) 701e60fa014SJoe Marcus Clarke err(1, "fcntl"); 702251bedd1SWarner Losh if (bind(fd, (struct sockaddr *) & sun, slen) < 0) 703251bedd1SWarner Losh err(1, "bind"); 704251bedd1SWarner Losh listen(fd, 4); 70583818929SJoe Marcus Clarke chown(name, 0, 0); /* XXX - root.wheel */ 706e60fa014SJoe Marcus Clarke chmod(name, 0666); 707251bedd1SWarner Losh return (fd); 708251bedd1SWarner Losh } 709251bedd1SWarner Losh 710251bedd1SWarner Losh list<int> clients; 711251bedd1SWarner Losh 712251bedd1SWarner Losh void 713251bedd1SWarner Losh notify_clients(const char *data, int len) 714251bedd1SWarner Losh { 715251bedd1SWarner Losh list<int> bad; 716251bedd1SWarner Losh list<int>::const_iterator i; 717251bedd1SWarner Losh 718251bedd1SWarner Losh for (i = clients.begin(); i != clients.end(); i++) { 719251bedd1SWarner Losh if (write(*i, data, len) <= 0) { 720251bedd1SWarner Losh bad.push_back(*i); 721251bedd1SWarner Losh close(*i); 722251bedd1SWarner Losh } 723251bedd1SWarner Losh } 724251bedd1SWarner Losh 725251bedd1SWarner Losh for (i = bad.begin(); i != bad.end(); i++) 726251bedd1SWarner Losh clients.erase(find(clients.begin(), clients.end(), *i)); 727251bedd1SWarner Losh } 728251bedd1SWarner Losh 729251bedd1SWarner Losh void 730251bedd1SWarner Losh new_client(int fd) 731251bedd1SWarner Losh { 732251bedd1SWarner Losh int s; 733251bedd1SWarner Losh 734251bedd1SWarner Losh s = accept(fd, NULL, NULL); 735251bedd1SWarner Losh if (s != -1) 736251bedd1SWarner Losh clients.push_back(s); 737251bedd1SWarner Losh } 738251bedd1SWarner Losh 7393054f218SWarner Losh static void 7403054f218SWarner Losh event_loop(void) 7413054f218SWarner Losh { 7423054f218SWarner Losh int rv; 7433054f218SWarner Losh int fd; 7443054f218SWarner Losh char buffer[DEVCTL_MAXBUF]; 7455a882d77SWarner Losh int once = 0; 746251bedd1SWarner Losh int server_fd, max_fd; 7475a882d77SWarner Losh timeval tv; 7485a882d77SWarner Losh fd_set fds; 7493054f218SWarner Losh 7503054f218SWarner Losh fd = open(PATH_DEVCTL, O_RDONLY); 7513054f218SWarner Losh if (fd == -1) 752251bedd1SWarner Losh err(1, "Can't open devctl device %s", PATH_DEVCTL); 7533054f218SWarner Losh if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) 754251bedd1SWarner Losh err(1, "Can't set close-on-exec flag on devctl"); 755251bedd1SWarner Losh server_fd = create_socket(PIPE); 756251bedd1SWarner Losh max_fd = max(fd, server_fd) + 1; 7573054f218SWarner Losh while (1) { 7583054f218SWarner Losh if (romeo_must_die) 7593054f218SWarner Losh break; 7605a882d77SWarner Losh if (!once && !dflag && !nflag) { 7615a882d77SWarner Losh // Check to see if we have any events pending. 7625a882d77SWarner Losh tv.tv_sec = 0; 7635a882d77SWarner Losh tv.tv_usec = 0; 7645a882d77SWarner Losh FD_ZERO(&fds); 7655a882d77SWarner Losh FD_SET(fd, &fds); 7665a882d77SWarner Losh rv = select(fd + 1, &fds, &fds, &fds, &tv); 7675a882d77SWarner Losh // No events -> we've processed all pending events 768f3059505SWarner Losh if (rv == 0) { 7695a882d77SWarner Losh if (Dflag) 7705a882d77SWarner Losh fprintf(stderr, "Calling daemon\n"); 7711a0cc6b1SPawel Jakub Dawidek cfg.remove_pidfile(); 7721a0cc6b1SPawel Jakub Dawidek cfg.open_pidfile(); 7735a882d77SWarner Losh daemon(0, 0); 7741a0cc6b1SPawel Jakub Dawidek cfg.write_pidfile(); 7755a882d77SWarner Losh once++; 7765a882d77SWarner Losh } 7775a882d77SWarner Losh } 778251bedd1SWarner Losh FD_ZERO(&fds); 779251bedd1SWarner Losh FD_SET(fd, &fds); 780251bedd1SWarner Losh FD_SET(server_fd, &fds); 781251bedd1SWarner Losh rv = select(max_fd, &fds, NULL, NULL, NULL); 782251bedd1SWarner Losh if (rv == -1) { 783251bedd1SWarner Losh if (errno == EINTR) 784251bedd1SWarner Losh continue; 785251bedd1SWarner Losh err(1, "select"); 786251bedd1SWarner Losh } 787251bedd1SWarner Losh if (FD_ISSET(fd, &fds)) { 7883054f218SWarner Losh rv = read(fd, buffer, sizeof(buffer) - 1); 7893054f218SWarner Losh if (rv > 0) { 790251bedd1SWarner Losh notify_clients(buffer, rv); 7913054f218SWarner Losh buffer[rv] = '\0'; 7923054f218SWarner Losh while (buffer[--rv] == '\n') 7933054f218SWarner Losh buffer[rv] = '\0'; 7943054f218SWarner Losh process_event(buffer); 7953054f218SWarner Losh } else if (rv < 0) { 7963054f218SWarner Losh if (errno != EINTR) 7973054f218SWarner Losh break; 7983054f218SWarner Losh } else { 7993054f218SWarner Losh /* EOF */ 8003054f218SWarner Losh break; 8013054f218SWarner Losh } 8023054f218SWarner Losh } 803251bedd1SWarner Losh if (FD_ISSET(server_fd, &fds)) 804251bedd1SWarner Losh new_client(server_fd); 805251bedd1SWarner Losh } 8063054f218SWarner Losh close(fd); 8073054f218SWarner Losh } 8083054f218SWarner Losh 8093054f218SWarner Losh /* 8103054f218SWarner Losh * functions that the parser uses. 8113054f218SWarner Losh */ 8123054f218SWarner Losh void 8133054f218SWarner Losh add_attach(int prio, event_proc *p) 8143054f218SWarner Losh { 8153054f218SWarner Losh cfg.add_attach(prio, p); 8163054f218SWarner Losh } 8173054f218SWarner Losh 8183054f218SWarner Losh void 8193054f218SWarner Losh add_detach(int prio, event_proc *p) 8203054f218SWarner Losh { 8213054f218SWarner Losh cfg.add_detach(prio, p); 8223054f218SWarner Losh } 8233054f218SWarner Losh 8243054f218SWarner Losh void 8253054f218SWarner Losh add_directory(const char *dir) 8263054f218SWarner Losh { 8273054f218SWarner Losh cfg.add_directory(dir); 8283054f218SWarner Losh free(const_cast<char *>(dir)); 8293054f218SWarner Losh } 8303054f218SWarner Losh 8313054f218SWarner Losh void 8323054f218SWarner Losh add_nomatch(int prio, event_proc *p) 8333054f218SWarner Losh { 8343054f218SWarner Losh cfg.add_nomatch(prio, p); 8353054f218SWarner Losh } 8363054f218SWarner Losh 837842ccec5SWarner Losh void 838842ccec5SWarner Losh add_notify(int prio, event_proc *p) 839842ccec5SWarner Losh { 840842ccec5SWarner Losh cfg.add_notify(prio, p); 841842ccec5SWarner Losh } 842842ccec5SWarner Losh 8433054f218SWarner Losh event_proc * 8443054f218SWarner Losh add_to_event_proc(event_proc *ep, eps *eps) 8453054f218SWarner Losh { 8463054f218SWarner Losh if (ep == NULL) 8473054f218SWarner Losh ep = new event_proc(); 8483054f218SWarner Losh ep->add(eps); 8493054f218SWarner Losh return (ep); 8503054f218SWarner Losh } 8513054f218SWarner Losh 8523054f218SWarner Losh eps * 8533054f218SWarner Losh new_action(const char *cmd) 8543054f218SWarner Losh { 8553054f218SWarner Losh eps *e = new action(cmd); 8563054f218SWarner Losh free(const_cast<char *>(cmd)); 8573054f218SWarner Losh return (e); 8583054f218SWarner Losh } 8593054f218SWarner Losh 8603054f218SWarner Losh eps * 8613054f218SWarner Losh new_match(const char *var, const char *re) 8623054f218SWarner Losh { 8635102ef84SWarner Losh eps *e = new match(cfg, var, re); 8643054f218SWarner Losh free(const_cast<char *>(var)); 8653054f218SWarner Losh free(const_cast<char *>(re)); 8663054f218SWarner Losh return (e); 8673054f218SWarner Losh } 8683054f218SWarner Losh 869cd70782bSWarner Losh eps * 870cd70782bSWarner Losh new_media(const char *var, const char *re) 871cd70782bSWarner Losh { 872cd70782bSWarner Losh eps *e = new media(cfg, var, re); 873cd70782bSWarner Losh free(const_cast<char *>(var)); 874cd70782bSWarner Losh free(const_cast<char *>(re)); 875cd70782bSWarner Losh return (e); 876cd70782bSWarner Losh } 877cd70782bSWarner Losh 8783054f218SWarner Losh void 8793054f218SWarner Losh set_pidfile(const char *name) 8803054f218SWarner Losh { 8813054f218SWarner Losh cfg.set_pidfile(name); 8823054f218SWarner Losh free(const_cast<char *>(name)); 8833054f218SWarner Losh } 8843054f218SWarner Losh 8853054f218SWarner Losh void 8863054f218SWarner Losh set_variable(const char *var, const char *val) 8873054f218SWarner Losh { 8883054f218SWarner Losh cfg.set_variable(var, val); 8893054f218SWarner Losh free(const_cast<char *>(var)); 8903054f218SWarner Losh free(const_cast<char *>(val)); 8913054f218SWarner Losh } 8923054f218SWarner Losh 8933054f218SWarner Losh 8943054f218SWarner Losh 8953054f218SWarner Losh static void 8963054f218SWarner Losh gensighand(int) 8973054f218SWarner Losh { 8983054f218SWarner Losh romeo_must_die++; 8993054f218SWarner Losh _exit(0); 9003054f218SWarner Losh } 9013054f218SWarner Losh 9023054f218SWarner Losh static void 9033054f218SWarner Losh usage() 9043054f218SWarner Losh { 9055ef35a98SRuslan Ermilov fprintf(stderr, "usage: %s [-Ddn] [-f file]\n", getprogname()); 9063054f218SWarner Losh exit(1); 9073054f218SWarner Losh } 9083054f218SWarner Losh 9099c180898SWarner Losh static void 9109c180898SWarner Losh check_devd_enabled() 9119c180898SWarner Losh { 9129c180898SWarner Losh int val = 0; 9139c180898SWarner Losh size_t len; 9149c180898SWarner Losh 9159c180898SWarner Losh len = sizeof(val); 91679f92e25SWarner Losh if (sysctlbyname(SYSCTL, &val, &len, NULL, 0) != 0) 9179c180898SWarner Losh errx(1, "devctl sysctl missing from kernel!"); 9189c180898SWarner Losh if (val) { 9199c180898SWarner Losh warnx("Setting " SYSCTL " to 0"); 9209c180898SWarner Losh val = 0; 9219c180898SWarner Losh sysctlbyname(SYSCTL, NULL, NULL, &val, sizeof(val)); 9229c180898SWarner Losh } 9239c180898SWarner Losh } 9249c180898SWarner Losh 9253054f218SWarner Losh /* 9263054f218SWarner Losh * main 9273054f218SWarner Losh */ 9283054f218SWarner Losh int 9293054f218SWarner Losh main(int argc, char **argv) 9303054f218SWarner Losh { 9313054f218SWarner Losh int ch; 9323054f218SWarner Losh 9339c180898SWarner Losh check_devd_enabled(); 9348334958aSJoseph Koshy while ((ch = getopt(argc, argv, "Ddf:n")) != -1) { 9353054f218SWarner Losh switch (ch) { 9365a882d77SWarner Losh case 'D': 9375a882d77SWarner Losh Dflag++; 9385a882d77SWarner Losh break; 9393054f218SWarner Losh case 'd': 9403054f218SWarner Losh dflag++; 9413054f218SWarner Losh break; 9428334958aSJoseph Koshy case 'f': 9438334958aSJoseph Koshy configfile = optarg; 9448334958aSJoseph Koshy break; 9455a882d77SWarner Losh case 'n': 9465a882d77SWarner Losh nflag++; 9475a882d77SWarner Losh break; 9483054f218SWarner Losh default: 9493054f218SWarner Losh usage(); 9503054f218SWarner Losh } 9513054f218SWarner Losh } 9523054f218SWarner Losh 9533054f218SWarner Losh cfg.parse(); 954fd6a8f23SWarner Losh if (!dflag && nflag) { 9551a0cc6b1SPawel Jakub Dawidek cfg.open_pidfile(); 9563054f218SWarner Losh daemon(0, 0); 9571a0cc6b1SPawel Jakub Dawidek cfg.write_pidfile(); 958fd6a8f23SWarner Losh } 959f32a7686SWarner Losh signal(SIGPIPE, SIG_IGN); 9603054f218SWarner Losh signal(SIGHUP, gensighand); 9613054f218SWarner Losh signal(SIGINT, gensighand); 9623054f218SWarner Losh signal(SIGTERM, gensighand); 9633054f218SWarner Losh event_loop(); 9643054f218SWarner Losh return (0); 9653054f218SWarner Losh } 966