From a536ab821b9ea241e31d101e54da3e7d33e9211b Mon Sep 17 00:00:00 2001 From: imp Date: Sat, 7 Dec 2002 08:04:36 +0000 Subject: MFp4 (imp_freebsd branch): snapshot of devd work: o improve parsing and lexing o create data structures based on the parsed file now. o Still need to rewrite main loop and add regex (still uses hard coded devd-generic) o minor man page updates. # There should be one more commit before rc2 Approved by: re (blanket) --- sbin/devd/Makefile | 6 +- sbin/devd/devd.c | 223 ------------------- sbin/devd/devd.cc | 591 ++++++++++++++++++++++++++++++++++++++++++++++++++ sbin/devd/devd.conf | 76 ++++--- sbin/devd/devd.conf.5 | 10 +- sbin/devd/devd.h | 33 +-- sbin/devd/parse.y | 43 ++-- sbin/devd/token.l | 35 ++- 8 files changed, 701 insertions(+), 316 deletions(-) delete mode 100644 sbin/devd/devd.c create mode 100644 sbin/devd/devd.cc (limited to 'sbin/devd') diff --git a/sbin/devd/Makefile b/sbin/devd/Makefile index 5177c56..ff11fb2 100644 --- a/sbin/devd/Makefile +++ b/sbin/devd/Makefile @@ -1,9 +1,9 @@ # $FreeBSD$ -PROG= devd -SRCS= devd.c token.l parse.y y.tab.h +PROG_CXX=devd +SRCS= devd.cc token.l parse.y y.tab.h MAN= devd.8 devd.conf.5 -WARNS?= 5 +#WARNS?= 5 DPADD= ${LIBL} LDADD= -ll diff --git a/sbin/devd/devd.c b/sbin/devd/devd.c deleted file mode 100644 index d607232..0000000 --- a/sbin/devd/devd.c +++ /dev/null @@ -1,223 +0,0 @@ -/*- - * Copyright (c) 2002 M. Warner Losh. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * DEVD control daemon. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "devd.h" - -#define CF "/etc/devd.conf" - -extern FILE *yyin; -extern int lineno; - -int dflag; -int romeo_must_die = 0; -struct file_list_head dirlist = TAILQ_HEAD_INITIALIZER(dirlist); - -static void event_loop(void); -static void parse(void); -static void parse_config_file(const char *fn); -static void parse_files_in_dir(const char *dirname); -static void reset_config(void); -static void usage(void); - -void -add_directory(const char *dir) -{ - struct file_list *elm; - - elm = malloc(sizeof(*elm)); - elm->path = strdup(dir); - TAILQ_INSERT_TAIL(&dirlist, elm, fl_link); -} - -static void -reset_config(void) -{ - struct file_list *flp; - - TAILQ_FOREACH(flp, &dirlist, fl_link) { - free(flp->path); - free(flp); - } -} - -static void -parse_config_file(const char *fn) -{ - if (dflag) - printf("Parsing %s\n", fn); - yyin = fopen(fn, "r"); - if (yyin == NULL) - err(1, "Cannot open config file %s", fn); - if (yyparse() != 0) - errx(1, "Cannot parse %s at line %d", fn, lineno); - fclose(yyin); -} - -static void -parse_files_in_dir(const char *dirname) -{ - DIR *dirp; - struct dirent *dp; - char path[PATH_MAX]; - - if (dflag) - printf("Parsing files in %s\n", dirname); - dirp = opendir(dirname); - if (dirp == NULL) - return; - readdir(dirp); /* Skip . */ - readdir(dirp); /* Skip .. */ - while ((dp = readdir(dirp)) != NULL) { - if (strcmp(dp->d_name + dp->d_namlen - 5, ".conf") == 0) { - snprintf(path, sizeof(path), "%s/%s", - dirname, dp->d_name); - parse_config_file(path); - } - } -} - -static void -parse(void) -{ - struct file_list *flp; - - parse_config_file(CF); - TAILQ_FOREACH(flp, &dirlist, fl_link) { - parse_files_in_dir(flp->path); - } -} - -static void -process_event(const char *buffer) -{ - char type; - char cmd[1024]; - char *sp; - - // Ignore unknown devices for now. - if (*buffer == '?') - return; - type = *buffer++; - sp = strchr(buffer, ' '); - if (sp == NULL) - return; /* Can't happen? */ - *sp = '\0'; - snprintf(cmd, sizeof(cmd), "/etc/devd-generic %s %s", buffer, - type == '+' ? "start" : "stop"); - if (dflag) - printf("Trying '%s'\n", cmd); - system(cmd); -} - -static void -event_loop(void) -{ - int rv; - int fd; - char buffer[1024 + 1]; /* XXX */ - - fd = open("/dev/devctl", O_RDONLY); /* XXX */ - if (fd == -1) - err(1, "Can't open devctl"); - if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) - err(1, "Can't set close-on-exec flag"); - while (1) { - if (romeo_must_die) - break; - rv = read(fd, buffer, sizeof(buffer) - 1); - if (rv > 0) { - buffer[rv] = '\0'; - while (buffer[--rv] == '\n') - buffer[rv] = '\0'; - process_event(buffer); - } else if (rv < 0) { - if (errno != EINTR) - break; - } else { - /* EOF */ - break; - } - } - close(fd); -} - -static void -gensighand(int foo __unused) -{ - romeo_must_die++; -} - -static void -usage() -{ - fprintf(stderr, "usage: %s [-d]", getprogname()); - exit(1); -} - -int -main(int argc, char **argv) -{ - int ch; - - while ((ch = getopt(argc, argv, "d")) != -1) { - switch (ch) { - case 'd': - dflag++; - break; - default: - usage(); - } - } - - reset_config(); - parse(); - if (!dflag) - daemon(0, 0); - event_loop(); - signal(SIGHUP, gensighand); - signal(SIGINT, gensighand); - signal(SIGTERM, gensighand); - return (0); -} diff --git a/sbin/devd/devd.cc b/sbin/devd/devd.cc new file mode 100644 index 0000000..1265b75 --- /dev/null +++ b/sbin/devd/devd.cc @@ -0,0 +1,591 @@ +/*- + * Copyright (c) 2002 M. Warner Losh. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * DEVD control daemon. + */ + +// TODO list: +// o rewrite the main loop: +// - expand variables +// - find best match +// - execute it. +// o need to insert the event_proc structures in order of priority. +// bigger numbers mean higher priority. +// o devd.conf and devd man pages need a lot of help: +// - devd.conf needs to lose the warning about zone files. +// - devd.conf needs more details on the supported statements. +// - devd.conf needs an example or two. + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "devd.h" + +#define CF "/etc/devd.conf" + +using namespace std; + +extern FILE *yyin; +extern int lineno; + +int dflag; +int romeo_must_die = 0; + +static void event_loop(void); +static void usage(void); + +class config; + + +class var_list +{ +public: + var_list() {} + virtual ~var_list() {} + void set_variable(const string &var, const string &val); + const string &get_variable(const string &var) const; + bool is_set(const string &var) const; + static const string bogus; + static const string nothing; +private: + map _vars; +}; + +class eps +{ +public: + eps() {} + virtual ~eps() {} + virtual bool do_match(config &) = 0; + virtual bool do_action(config &) = 0; +}; + +class match : public eps +{ +public: + match(const char *var, const char *re); + virtual ~match(); + virtual bool do_match(config &); + virtual bool do_action(config &) { return true; } +private: + string _var; + string _re; +}; + +class action : public eps +{ +public: + action(const char *cmd); + virtual ~action(); + virtual bool do_match(config &) { return true; } + virtual bool do_action(config &); +private: + string _cmd; +}; + +class event_proc +{ +public: + event_proc(); + virtual ~event_proc(); + int get_priority() { return (_prio); } + void set_priority(int prio) { _prio = prio; } + void add(eps *); + bool matches(config &); + bool run(config &); +private: + int _prio; + vector _epsvec; +}; + +class config +{ +public: + config() : _pidfile("") { push_var_table(); } + virtual ~config() { reset(); } + void add_attach(int, event_proc *); + void add_detach(int, event_proc *); + void add_directory(const char *); + void add_nomatch(int, event_proc *); + void set_pidfile(const char *); + void reset(); + void parse(); + void drop_pidfile(); + void push_var_table(); + void pop_var_table(); + void set_variable(const char *var, const char *val); + const string &get_variable(const string &var); + const string &expand_string(const string &var); +protected: + void parse_one_file(const char *fn); + void parse_files_in_dir(const char *dirname); +private: + vector _dir_list; + string _pidfile; + vector _var_list_table; + vector _attach_list; + vector _detach_list; + vector _nomatch_list; +}; + +config cfg; + +event_proc::event_proc() : _prio(-1) +{ + // nothing +} + +event_proc::~event_proc() +{ + vector::const_iterator i; + + for (i = _epsvec.begin(); i != _epsvec.end(); i++) + delete *i; + _epsvec.clear(); +} + +void +event_proc::add(eps *eps) +{ + _epsvec.push_back(eps); +} + +bool +event_proc::matches(config &c) +{ + vector::const_iterator i; + + for (i = _epsvec.begin(); i != _epsvec.end(); i++) + if (!(*i)->do_match(c)) + return (false); + return (true); +} + +bool +event_proc::run(config &c) +{ + vector::const_iterator i; + + for (i = _epsvec.begin(); i != _epsvec.end(); i++) + if (!(*i)->do_action(c)) + return (false); + return (true); +} + +action::action(const char *cmd) + : _cmd(cmd) +{ + // nothing +} + +action::~action() +{ + // nothing +} + +bool +action::do_action(config &) +{ + // this is lame because we don't expand variables. + // xxx + ::system(_cmd.c_str()); + return (true); +} + +match::match(const char *var, const char *re) + : _var(var), _re(re) +{ + // nothing +} + +match::~match() +{ + // nothing +} + +bool +match::do_match(config &) +{ + // XXX + return false; +} + +const string var_list::bogus = "_$_$_$_$_B_O_G_U_S_$_$_$_$_"; +const string var_list::nothing = ""; + +const string & +var_list::get_variable(const string &var) const +{ + map::const_iterator i; + + i = _vars.find(var); + if (i == _vars.end()) + return var_list::bogus; + return (i->second); +} + +bool +var_list::is_set(const string &var) const +{ + return (_vars.find(var) != _vars.end()); +} + +void +var_list::set_variable(const string &var, const string &val) +{ + _vars[var] = val; +} + +void +config::reset(void) +{ + _dir_list.clear(); + _var_list_table.clear(); + // XXX need to cleanup _{attach,detach,nomatch}_list +} + +void +config::parse_one_file(const char *fn) +{ + if (dflag) + printf("Parsing %s\n", fn); + yyin = fopen(fn, "r"); + if (yyin == NULL) + err(1, "Cannot open config file %s", fn); + if (yyparse() != 0) + errx(1, "Cannot parse %s at line %d", fn, lineno); + fclose(yyin); +} + +void +config::parse_files_in_dir(const char *dirname) +{ + DIR *dirp; + struct dirent *dp; + char path[PATH_MAX]; + + if (dflag) + printf("Parsing files in %s\n", dirname); + dirp = opendir(dirname); + if (dirp == NULL) + return; + readdir(dirp); /* Skip . */ + readdir(dirp); /* Skip .. */ + while ((dp = readdir(dirp)) != NULL) { + if (strcmp(dp->d_name + dp->d_namlen - 5, ".conf") == 0) { + snprintf(path, sizeof(path), "%s/%s", + dirname, dp->d_name); + parse_one_file(path); + } + } +} + +void +config::parse(void) +{ + vector::const_iterator i; + + parse_one_file(CF); + for (i = _dir_list.begin(); i != _dir_list.end(); i++) + parse_files_in_dir((*i).c_str()); +} + +void +config::drop_pidfile() +{ + FILE *fp; + + if (_pidfile == "") + return; + fp = fopen(_pidfile.c_str(), "w"); + if (fp == NULL) + return; + fprintf(fp, "%d\n", getpid()); + fclose(fp); +} + +void +config::add_attach(int prio, event_proc *p) +{ + p->set_priority(prio); + _attach_list.push_back(p); +} + +void +config::add_detach(int prio, event_proc *p) +{ + p->set_priority(prio); + _detach_list.push_back(p); +} + +void +config::add_directory(const char *dir) +{ + _dir_list.push_back(string(dir)); +} + +void +config::add_nomatch(int prio, event_proc *p) +{ + p->set_priority(prio); + _nomatch_list.push_back(p); +} + +void +config::set_pidfile(const char *fn) +{ + _pidfile = string(fn); +} + +void +config::push_var_table() +{ + var_list *vl; + + vl = new var_list(); + _var_list_table.push_back(vl); +} + +void +config::pop_var_table() +{ + delete _var_list_table.back(); + _var_list_table.pop_back(); +} + +void +config::set_variable(const char *var, const char *val) +{ + _var_list_table.back()->set_variable(var, val); +} + +const string & +config::get_variable(const string &var) +{ + vector::reverse_iterator i; + + for (i = _var_list_table.rbegin(); i != _var_list_table.rend(); i++) { + if ((*i)->is_set(var)) + return (var); + } + return (var_list::nothing); +} + +const string & +config::expand_string(const string &) +{ + return var_list::bogus; +} + + +static void +process_event(const char *buffer) +{ + char type; + char cmd[1024]; + char *sp; + + // XXX should involve config + // XXX and set some variables + // XXX run the list and so forth + + // Ignore unknown devices for now. + if (*buffer == '?') + return; + type = *buffer++; + sp = strchr(buffer, ' '); + if (sp == NULL) + return; /* Can't happen? */ + *sp = '\0'; + snprintf(cmd, sizeof(cmd), "/etc/devd-generic %s %s", buffer, + type == '+' ? "start" : "stop"); + if (dflag) + printf("Trying '%s'\n", cmd); + system(cmd); +} + +static void +event_loop(void) +{ + int rv; + int fd; + char buffer[DEVCTL_MAXBUF]; + + fd = open(PATH_DEVCTL, O_RDONLY); + if (fd == -1) + err(1, "Can't open devctl"); + if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) + err(1, "Can't set close-on-exec flag"); + while (1) { + if (romeo_must_die) + break; + rv = read(fd, buffer, sizeof(buffer) - 1); + if (rv > 0) { + buffer[rv] = '\0'; + while (buffer[--rv] == '\n') + buffer[rv] = '\0'; + process_event(buffer); + } else if (rv < 0) { + if (errno != EINTR) + break; + } else { + /* EOF */ + break; + } + } + close(fd); +} + +/* + * functions that the parser uses. + */ +void +add_attach(int prio, event_proc *p) +{ + cfg.add_attach(prio, p); +} + +void +add_detach(int prio, event_proc *p) +{ + cfg.add_detach(prio, p); +} + +void +add_directory(const char *dir) +{ + cfg.add_directory(dir); + free(const_cast(dir)); +} + +void +add_nomatch(int prio, event_proc *p) +{ + cfg.add_nomatch(prio, p); +} + +event_proc * +add_to_event_proc(event_proc *ep, eps *eps) +{ + if (ep == NULL) + ep = new event_proc(); + ep->add(eps); + return (ep); +} + +eps * +new_action(const char *cmd) +{ + eps *e = new action(cmd); + free(const_cast(cmd)); + return (e); +} + +eps * +new_match(const char *var, const char *re) +{ + eps *e = new match(var, re); + free(const_cast(var)); + free(const_cast(re)); + return (e); +} + +void +set_pidfile(const char *name) +{ + cfg.set_pidfile(name); + free(const_cast(name)); +} + +void +set_variable(const char *var, const char *val) +{ + cfg.set_variable(var, val); + free(const_cast(var)); + free(const_cast(val)); +} + + + +static void +gensighand(int) +{ + romeo_must_die++; + _exit(0); +} + +static void +usage() +{ + fprintf(stderr, "usage: %s [-d]", getprogname()); + exit(1); +} + +/* + * main + */ +int +main(int argc, char **argv) +{ + int ch; + + while ((ch = getopt(argc, argv, "d")) != -1) { + switch (ch) { + case 'd': + dflag++; + break; + default: + usage(); + } + } + + cfg.parse(); + if (!dflag) + daemon(0, 0); + cfg.drop_pidfile(); + signal(SIGHUP, gensighand); + signal(SIGINT, gensighand); + signal(SIGTERM, gensighand); + event_loop(); + return (0); +} diff --git a/sbin/devd/devd.conf b/sbin/devd/devd.conf index e5f6cda..c97a395 100644 --- a/sbin/devd/devd.conf +++ b/sbin/devd/devd.conf @@ -1,21 +1,22 @@ -// $FreeBSD$ -// -// Refer to devd.conf(5) and devd(8) man pages for the details on how to -// run and configure devd. -// +# $FreeBSD$ +# +# Refer to devd.conf(5) and devd(8) man pages for the details on how to +# run and configure devd. +# -// NB: All regular expressions have an implicit ^$ around them. +# NB: All regular expressions have an implicit ^$ around them. +# NB: device-name is shorthand for 'match device-name' options { - // Each directory directive adds a directory the list of directories - // that we scan for files. Files are read-in in the order that they - // are returned from readdir(3). The rule-sets are combined to - // create a DFA that's used to match events to actions. + # Each directory directive adds a directory the list of directories + # that we scan for files. Files are read-in in the order that they + # are returned from readdir(3). The rule-sets are combined to + # create a DFA that's used to match events to actions. directory "/etc/devd"; directory "/usr/local/etc/devd"; pid-file "/var/run/devd.pid"; - // Setup some shorthand for regex that we use later in the file. + # Setup some shorthand for regex that we use later in the file. set ethernet-nic-regex "(an|ar|aue|awi|bge|cm|cnw|cs|cue|dc|de|ed|el|em|ep|ex|\ fe|fxp|gem|gx|hme|ie|kue|lge|lnc|my|nge|pcn|ray|rl|\ @@ -25,15 +26,13 @@ options { stg|sym|wds)[0-9]+"; }; -// Note that the attach/detach with the highest value wins, so that one can -// override these general rules. +# Note that the attach/detach with the highest value wins, so that one can +# override these general rules. -// NB: device-name is shorthand for 'match device-name' - -// -// For ethernet like devices, the default is to run dhclient. Due to -// a historical accident, the name of this script it called pccard_ether -// +# +# For ethernet like devices, the default is to run dhclient. Due to +# a historical accident, the name of this script it called pccard_ether +# attach 0 { device-name "$ethernet-nic-regex"; action "/etc/pccard_ether $device-name start"; @@ -44,10 +43,10 @@ detach 0 { action "/etc/pccard_ether $device-name stop"; }; -// An entry like this might be in a different file, but is included here -// as an example of how to override things. Normally 'ed20' would match -// the above attach/detach stuff, but the value of 100 makes it -// ed20 is hard wired to 1.2.3.4 +# An entry like this might be in a different file, but is included here +# as an example of how to override things. Normally 'ed20' would match +# the above attach/detach stuff, but the value of 100 makes it +# ed20 is hard wired to 1.2.3.4 attach 100 { device-name "ed20"; action "ifconfig $device-name inet 1.2.3.4 netmask 0xffff0000"; @@ -56,26 +55,26 @@ detach 100 { device-name "ed20"; }; -// -// Rescan scsi device-names on attach, but not detach. -// +# +# Rescan scsi device-names on attach, but not detach. +# attach 0 { device-name "$scsi-controller-regex"; action "camcontrol rescan all"; }; -// Don't even try to second guess what to do about drivers that don't -// match here. Instead, pass it off to a smart script to deal. +# Don't even try to second guess what to do about drivers that don't +# match here. Instead, pass it off to a smart script to deal. nomatch 0 { action "/usr/local/bin/smart-loader $pnpinfo $location $bus"; }; -// The following might be an example of something that a vendor might -// install if you were to add their device. This might reside in -// /usr/local/etc/devd/deqna.conf. A deqna is, in this hypothetical -// example, a pccard ethernet-like device. Students of history may -// know other devices by this name, and will get the in-jokes in this -// entry. +# The following might be an example of something that a vendor might +# install if you were to add their device. This might reside in +# /usr/local/etc/devd/deqna.conf. A deqna is, in this hypothetical +# example, a pccard ethernet-like device. Students of history may +# know other devices by this name, and will get the in-jokes in this +# entry. nomatch 10 { match "bus" "pccard[0-9]+"; match "manufacturer" "0x1234"; @@ -90,3 +89,12 @@ detach 10 { device-name "deqna[0-9]+"; action "/etc/pccard_ether $device-name stop"; }; + +// Single line comment, alternate style +/* + * This is a multiline comment + * 96 + * 97 + * 98 + * 99 */ +# error uncomment this line to test, should be line 100. diff --git a/sbin/devd/devd.conf.5 b/sbin/devd/devd.conf.5 index 7d998b7..63cb4ad 100644 --- a/sbin/devd/devd.conf.5 +++ b/sbin/devd/devd.conf.5 @@ -79,7 +79,7 @@ repated as often as required. Further details on the syntax and meaning of each statement, and their substatements is explained below. .Pp -Comments may appear anywhere that whitespace may appear in a BIND +Comments may appear anywhere that whitespace may appear in a configuration file. To appeal to programmers of all kinds, they can be written in C, C++, or shell/perl constructs. .Pp @@ -114,14 +114,6 @@ pair. For example: // is a new comment, even though it is logically // part of the previous comment. .Ed -.Pp -.Em WARNING : -you cannot use the -.Li ; -(semicolon) character to start a comment such as you would in a zone -file. The semicolon indicates the end of a configuration statement, -so whatever follows it will be interpreted as the start of the next -statement. .Sh FILES .Bl -tag -width /etc/devd.conf -compact .It Pa /etc/devd.conf diff --git a/sbin/devd/devd.h b/sbin/devd/devd.h index b35b16c..1319664 100644 --- a/sbin/devd/devd.h +++ b/sbin/devd/devd.h @@ -28,21 +28,22 @@ * $FreeBSD$ */ -#include - -int yylex(void); -void yyerror(const char *s); -int yyparse(void); +struct event_proc; +struct eps; +__BEGIN_DECLS +void add_attach(int, struct event_proc *); +void add_detach(int, struct event_proc *); void add_directory(const char *); +void add_nomatch(int, struct event_proc *); +struct event_proc *add_to_event_proc(struct event_proc *, struct eps *); +struct eps *new_match(const char *, const char *); +struct eps *new_action(const char *); +void set_pidfile(const char *); +void set_variable(const char *, const char *); +void yyerror(const char *s); +int yylex(void); +int yyparse(void); +__END_DECLS -struct file_list -{ - char *path; - TAILQ_ENTRY(file_list) fl_link; -}; - -TAILQ_HEAD(file_list_head, file_list); - -extern struct file_list_head dirlist; - - +#define PATH_DEVCTL "/dev/devctl" +#define DEVCTL_MAXBUF 1025 diff --git a/sbin/devd/parse.y b/sbin/devd/parse.y index 53c9a05..4a8f4dd 100644 --- a/sbin/devd/parse.y +++ b/sbin/devd/parse.y @@ -31,12 +31,15 @@ #include "devd.h" #include +#include %} %union { char *str; int i; + struct eps *eps; /* EventProcStatement */ + struct event_proc *eventproc; } %token SEMICOLON BEGINBLOCK ENDBLOCK COMMA @@ -46,14 +49,14 @@ %token OPTIONS SET DIRECTORY PID_FILE DEVICE_NAME ACTION MATCH %token ATTACH DETACH NOMATCH -%type id -%type number -%type string +%type match_or_action_list +%type match_or_action match action %% config_file : config_list + | ; config_list @@ -83,32 +86,36 @@ option ; directory_option - : DIRECTORY string SEMICOLON { add_directory($2); } + : DIRECTORY STRING SEMICOLON { add_directory($2); } ; pid_file_option - : PID_FILE string SEMICOLON + : PID_FILE STRING SEMICOLON { set_pidfile($2); } ; set_option - : SET id string SEMICOLON + : SET ID STRING SEMICOLON { set_variable($2, $3); } ; attach_block - : ATTACH number BEGINBLOCK match_or_action_list ENDBLOCK SEMICOLON + : ATTACH NUMBER BEGINBLOCK match_or_action_list ENDBLOCK SEMICOLON + { add_attach($2, $4); } ; detach_block - : DETACH number BEGINBLOCK match_or_action_list ENDBLOCK SEMICOLON + : DETACH NUMBER BEGINBLOCK match_or_action_list ENDBLOCK SEMICOLON + { add_detach($2, $4); } ; nomatch_block - : NOMATCH number BEGINBLOCK match_or_action_list ENDBLOCK SEMICOLON + : NOMATCH NUMBER BEGINBLOCK match_or_action_list ENDBLOCK SEMICOLON + { add_nomatch($2, $4); } ; match_or_action_list - : match_or_action + : match_or_action { $$ = add_to_event_proc( NULL, $1); } | match_or_action_list match_or_action + { $$ = add_to_event_proc($1, $2); } ; match_or_action @@ -117,21 +124,13 @@ match_or_action ; match - : MATCH string string SEMICOLON - | DEVICE_NAME string SEMICOLON + : MATCH STRING STRING SEMICOLON { $$ = new_match($2, $3); } + | DEVICE_NAME STRING SEMICOLON + { $$ = new_match(strdup("device-name"), $2); } ; action - : ACTION string SEMICOLON + : ACTION STRING SEMICOLON { $$ = new_action($2); } ; -number - : NUMBER { $$ = $1; } - -string - : STRING { $$ = $1; } - -id - : ID { $$ = $1; } - %% diff --git a/sbin/devd/token.l b/sbin/devd/token.l index 233abec..c2b89b9 100644 --- a/sbin/devd/token.l +++ b/sbin/devd/token.l @@ -29,6 +29,7 @@ * $FreeBSD$ */ +#include #include #include #include @@ -38,6 +39,14 @@ int lineno = 1; #define YY_NO_UNPUT +static void +update_lineno(const char *cp) +{ + while (*cp) + if (*cp++ == '\n') + lineno++; +} + %} %% @@ -45,17 +54,30 @@ int lineno = 1; [ \t]+ ; \n lineno++; ; { return SEMICOLON; } +#.*$ ; \/\/.*$ ; -\/\*(.|\n)*\*\/ ; +\/\*(.|\n)*\*\/ { update_lineno(yytext); } \{ { return BEGINBLOCK; } \} { return ENDBLOCK; } [0-9]+ { yylval.i = atoi(yytext); return NUMBER; } \"[^"]+\" { + update_lineno(yytext); int len = strlen(yytext) - 2; + char *walker; + int i; if ((yylval.str = (char *) malloc(len + 1)) == NULL) goto out; - memcpy(yylval.str, yytext + 1, len); - yylval.str[len] = '\0'; + walker = yylval.str; + for (i = 1; i <= len; i++) { + if (yytext[i] == '\\' && + yytext[i + 1] == '\n') { + i += 2; + while(isspace(yytext[i])) + i++; + } + *walker++ = yytext[i]; + } + *walker++ = '\0'; out:; return STRING; } @@ -72,12 +94,7 @@ action { return ACTION; } match { return MATCH; } nomatch { return NOMATCH; } [A-Za-z][A-Za-z0-9-]* { - int len = strlen(yytext); - if ((yylval.str = (char *) malloc(len + 1)) == NULL) - goto out2; - memcpy(yylval.str, yytext + 1, len); - yylval.str[len] = '\0'; - out2:; + yylval.str = strdup(yytext); return ID; } %% -- cgit v1.1