Deleted Added
full compact
devd.cc (108014) devd.cc (108783)
1/*-
2 * Copyright (c) 2002 M. Warner Losh.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 15 unchanged lines hidden (view full) ---

24 * SUCH DAMAGE.
25 */
26
27/*
28 * DEVD control daemon.
29 */
30
31// TODO list:
1/*-
2 * Copyright (c) 2002 M. Warner Losh.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 15 unchanged lines hidden (view full) ---

24 * SUCH DAMAGE.
25 */
26
27/*
28 * DEVD control daemon.
29 */
30
31// TODO list:
32// o rewrite the main loop:
33// - find best match
34// - execute it.
35// o need to insert the event_proc structures in order of priority.
36// bigger numbers mean higher priority.
37// o devd.conf and devd man pages need a lot of help:
38// - devd.conf needs to lose the warning about zone files.
39// - devd.conf needs more details on the supported statements.
40// - devd.conf needs an example or two.
41
42#include <sys/cdefs.h>
32// o devd.conf and devd man pages need a lot of help:
33// - devd.conf needs to lose the warning about zone files.
34// - devd.conf needs more details on the supported statements.
35// - devd.conf needs an example or two.
36
37#include <sys/cdefs.h>
43__FBSDID("$FreeBSD: head/sbin/devd/devd.cc 108014 2002-12-18 07:08:01Z imp $");
38__FBSDID("$FreeBSD: head/sbin/devd/devd.cc 108783 2003-01-06 08:09:41Z imp $");
44
45#include <sys/param.h>
46#include <sys/types.h>
47
48#include <ctype.h>
49#include <dirent.h>
50#include <errno.h>
51#include <err.h>
52#include <fcntl.h>
53#include <regex.h>
54#include <stdlib.h>
55#include <stdio.h>
56#include <string.h>
57#include <unistd.h>
58
39
40#include <sys/param.h>
41#include <sys/types.h>
42
43#include <ctype.h>
44#include <dirent.h>
45#include <errno.h>
46#include <err.h>
47#include <fcntl.h>
48#include <regex.h>
49#include <stdlib.h>
50#include <stdio.h>
51#include <string.h>
52#include <unistd.h>
53
54#include <algorithm>
59#include <map>
60#include <string>
61#include <vector>
62
63#include "devd.h"
64
65#define CF "/etc/devd.conf"
66
67using namespace std;
68
69extern FILE *yyin;
70extern int lineno;
71
55#include <map>
56#include <string>
57#include <vector>
58
59#include "devd.h"
60
61#define CF "/etc/devd.conf"
62
63using namespace std;
64
65extern FILE *yyin;
66extern int lineno;
67
68static const char nomatch = '?';
69static const char attach = '+';
70static const char detach = '-';
71
72int dflag;
73int romeo_must_die = 0;
74
75static void event_loop(void);
76static void usage(void);
77
72int dflag;
73int romeo_must_die = 0;
74
75static void event_loop(void);
76static void usage(void);
77
78class config;
78template <class T> void
79delete_and_clear(vector<T *> &v)
80{
81 typename vector<T *>::const_iterator i;
79
82
83 for (i = v.begin(); i != v.end(); i++)
84 delete *i;
85 v.clear();
86}
80
87
88class config;
89
81class var_list
82{
83public:
84 var_list() {}
85 virtual ~var_list() {}
86 void set_variable(const string &var, const string &val);
87 const string &get_variable(const string &var) const;
88 bool is_set(const string &var) const;

--- 36 unchanged lines hidden (view full) ---

125 string _cmd;
126};
127
128class event_proc
129{
130public:
131 event_proc();
132 virtual ~event_proc();
90class var_list
91{
92public:
93 var_list() {}
94 virtual ~var_list() {}
95 void set_variable(const string &var, const string &val);
96 const string &get_variable(const string &var) const;
97 bool is_set(const string &var) const;

--- 36 unchanged lines hidden (view full) ---

134 string _cmd;
135};
136
137class event_proc
138{
139public:
140 event_proc();
141 virtual ~event_proc();
133 int get_priority() { return (_prio); }
142 int get_priority() const { return (_prio); }
134 void set_priority(int prio) { _prio = prio; }
135 void add(eps *);
136 bool matches(config &);
137 bool run(config &);
138private:
139 int _prio;
140 vector<eps *> _epsvec;
141};

--- 11 unchanged lines hidden (view full) ---

153 void reset();
154 void parse();
155 void drop_pidfile();
156 void push_var_table();
157 void pop_var_table();
158 void set_variable(const char *var, const char *val);
159 const string &get_variable(const string &var);
160 const string expand_string(const string &var);
143 void set_priority(int prio) { _prio = prio; }
144 void add(eps *);
145 bool matches(config &);
146 bool run(config &);
147private:
148 int _prio;
149 vector<eps *> _epsvec;
150};

--- 11 unchanged lines hidden (view full) ---

162 void reset();
163 void parse();
164 void drop_pidfile();
165 void push_var_table();
166 void pop_var_table();
167 void set_variable(const char *var, const char *val);
168 const string &get_variable(const string &var);
169 const string expand_string(const string &var);
170 char *set_vars(char *);
171 void find_and_execute(char);
161protected:
172protected:
173 void sort_vector(vector<event_proc *> &);
162 void parse_one_file(const char *fn);
163 void parse_files_in_dir(const char *dirname);
164 void expand_one(const char *&src, char *&dst, char *eod);
174 void parse_one_file(const char *fn);
175 void parse_files_in_dir(const char *dirname);
176 void expand_one(const char *&src, char *&dst, char *eod);
177 bool is_id_char(char);
178 bool chop_var(char *&buffer, char *&lhs, char *&rhs);
165private:
166 vector<string> _dir_list;
167 string _pidfile;
168 vector<var_list *> _var_list_table;
169 vector<event_proc *> _attach_list;
170 vector<event_proc *> _detach_list;
171 vector<event_proc *> _nomatch_list;
172};

--- 51 unchanged lines hidden (view full) ---

224action::~action()
225{
226 // nothing
227}
228
229bool
230action::do_action(config &c)
231{
179private:
180 vector<string> _dir_list;
181 string _pidfile;
182 vector<var_list *> _var_list_table;
183 vector<event_proc *> _attach_list;
184 vector<event_proc *> _detach_list;
185 vector<event_proc *> _nomatch_list;
186};

--- 51 unchanged lines hidden (view full) ---

238action::~action()
239{
240 // nothing
241}
242
243bool
244action::do_action(config &c)
245{
232 // xxx
233 ::system(c.expand_string(_cmd).c_str());
246 string s = c.expand_string(_cmd);
247 if (dflag)
248 fprintf(stderr, "Executing '%s'\n", s.c_str());
249 ::system(s.c_str());
234 return (true);
235}
236
237match::match(config &c, const char *var, const char *re)
250 return (true);
251}
252
253match::match(config &c, const char *var, const char *re)
238 : _var(var), _re(re)
254 : _var(var)
239{
255{
240 string pattern = "^";
241 pattern.append(c.expand_string(_re));
242 pattern.append("$");
243 regcomp(&_regex, pattern.c_str(), REG_EXTENDED | REG_NOSUB);
256 string pattern = re;
257 _re = "^";
258 _re.append(c.expand_string(string(re)));
259 _re.append("$");
260 regcomp(&_regex, _re.c_str(), REG_EXTENDED | REG_NOSUB);
244}
245
246match::~match()
247{
248 regfree(&_regex);
249}
250
251bool
252match::do_match(config &c)
253{
254 string value = c.get_variable(_var);
255 bool retval;
256
261}
262
263match::~match()
264{
265 regfree(&_regex);
266}
267
268bool
269match::do_match(config &c)
270{
271 string value = c.get_variable(_var);
272 bool retval;
273
274 if (dflag)
275 fprintf(stderr, "Testing %s=%s against %s\n", _var.c_str(),
276 value.c_str(), _re.c_str());
277
257 retval = (regexec(&_regex, value.c_str(), 0, NULL, 0) == 0);
258 return retval;
259}
260
261const string var_list::bogus = "_$_$_$_$_B_O_G_U_S_$_$_$_$_";
262const string var_list::nothing = "";
263
264const string &
265var_list::get_variable(const string &var) const
266{
267 map<string, string>::const_iterator i;
268
269 i = _vars.find(var);
270 if (i == _vars.end())
278 retval = (regexec(&_regex, value.c_str(), 0, NULL, 0) == 0);
279 return retval;
280}
281
282const string var_list::bogus = "_$_$_$_$_B_O_G_U_S_$_$_$_$_";
283const string var_list::nothing = "";
284
285const string &
286var_list::get_variable(const string &var) const
287{
288 map<string, string>::const_iterator i;
289
290 i = _vars.find(var);
291 if (i == _vars.end())
271 return var_list::bogus;
292 return (var_list::bogus);
272 return (i->second);
273}
274
275bool
276var_list::is_set(const string &var) const
277{
278 return (_vars.find(var) != _vars.end());
279}
280
281void
282var_list::set_variable(const string &var, const string &val)
283{
293 return (i->second);
294}
295
296bool
297var_list::is_set(const string &var) const
298{
299 return (_vars.find(var) != _vars.end());
300}
301
302void
303var_list::set_variable(const string &var, const string &val)
304{
305 if (dflag)
306 fprintf(stderr, "%s=%s\n", var.c_str(), val.c_str());
284 _vars[var] = val;
285}
286
287void
288config::reset(void)
289{
290 _dir_list.clear();
307 _vars[var] = val;
308}
309
310void
311config::reset(void)
312{
313 _dir_list.clear();
291 _var_list_table.clear();
292 // XXX need to cleanup _{attach,detach,nomatch}_list
314 delete_and_clear(_var_list_table);
315 delete_and_clear(_attach_list);
316 delete_and_clear(_detach_list);
317 delete_and_clear(_nomatch_list);
293}
294
295void
296config::parse_one_file(const char *fn)
297{
298 if (dflag)
299 printf("Parsing %s\n", fn);
300 yyin = fopen(fn, "r");

--- 22 unchanged lines hidden (view full) ---

323 if (strcmp(dp->d_name + dp->d_namlen - 5, ".conf") == 0) {
324 snprintf(path, sizeof(path), "%s/%s",
325 dirname, dp->d_name);
326 parse_one_file(path);
327 }
328 }
329}
330
318}
319
320void
321config::parse_one_file(const char *fn)
322{
323 if (dflag)
324 printf("Parsing %s\n", fn);
325 yyin = fopen(fn, "r");

--- 22 unchanged lines hidden (view full) ---

348 if (strcmp(dp->d_name + dp->d_namlen - 5, ".conf") == 0) {
349 snprintf(path, sizeof(path), "%s/%s",
350 dirname, dp->d_name);
351 parse_one_file(path);
352 }
353 }
354}
355
356class epv_greater {
357public:
358 int operator()(event_proc *const&l1, event_proc *const&l2)
359 {
360 return (l1->get_priority() > l2->get_priority());
361 }
362};
363
331void
364void
365config::sort_vector(vector<event_proc *> &v)
366{
367 sort(v.begin(), v.end(), epv_greater());
368}
369
370void
332config::parse(void)
333{
334 vector<string>::const_iterator i;
335
336 parse_one_file(CF);
337 for (i = _dir_list.begin(); i != _dir_list.end(); i++)
338 parse_files_in_dir((*i).c_str());
371config::parse(void)
372{
373 vector<string>::const_iterator i;
374
375 parse_one_file(CF);
376 for (i = _dir_list.begin(); i != _dir_list.end(); i++)
377 parse_files_in_dir((*i).c_str());
378 sort_vector(_attach_list);
379 sort_vector(_detach_list);
380 sort_vector(_nomatch_list);
339}
340
341void
342config::drop_pidfile()
343{
344 FILE *fp;
345
346 if (_pidfile == "")

--- 40 unchanged lines hidden (view full) ---

387
388void
389config::push_var_table()
390{
391 var_list *vl;
392
393 vl = new var_list();
394 _var_list_table.push_back(vl);
381}
382
383void
384config::drop_pidfile()
385{
386 FILE *fp;
387
388 if (_pidfile == "")

--- 40 unchanged lines hidden (view full) ---

429
430void
431config::push_var_table()
432{
433 var_list *vl;
434
435 vl = new var_list();
436 _var_list_table.push_back(vl);
437 if (dflag)
438 fprintf(stderr, "Pushing table\n");
395}
396
397void
398config::pop_var_table()
399{
400 delete _var_list_table.back();
401 _var_list_table.pop_back();
439}
440
441void
442config::pop_var_table()
443{
444 delete _var_list_table.back();
445 _var_list_table.pop_back();
446 if (dflag)
447 fprintf(stderr, "Popping table\n");
402}
403
404void
405config::set_variable(const char *var, const char *val)
406{
407 _var_list_table.back()->set_variable(var, val);
408}
409
410const string &
411config::get_variable(const string &var)
412{
413 vector<var_list *>::reverse_iterator i;
414
415 for (i = _var_list_table.rbegin(); i != _var_list_table.rend(); i++) {
416 if ((*i)->is_set(var))
448}
449
450void
451config::set_variable(const char *var, const char *val)
452{
453 _var_list_table.back()->set_variable(var, val);
454}
455
456const string &
457config::get_variable(const string &var)
458{
459 vector<var_list *>::reverse_iterator i;
460
461 for (i = _var_list_table.rbegin(); i != _var_list_table.rend(); i++) {
462 if ((*i)->is_set(var))
417 return (var);
463 return ((*i)->get_variable(var));
418 }
419 return (var_list::nothing);
420}
421
464 }
465 return (var_list::nothing);
466}
467
422// Hey script |<idz, here's a routine chock-full-o-buffer-overflows.
468bool
469config::is_id_char(char ch)
470{
471 return (ch != '\0' && (isalpha(ch) || isdigit(ch) || ch == '_' ||
472 ch == '-'));
473}
474
423// XXX
475// XXX
424// imp should learn how to make effective use of the string class for the shit.
476// imp should learn how to make effective use of the string class.
425void
426config::expand_one(const char *&src, char *&dst, char *)
427{
428 int count;
429 const char *var;
430 char buffer[1024];
431 string varstr;
432
477void
478config::expand_one(const char *&src, char *&dst, char *)
479{
480 int count;
481 const char *var;
482 char buffer[1024];
483 string varstr;
484
485 src++;
433 // $$ -> $
434 if (*src == '$') {
435 *dst++ = *src++;
436 return;
437 }
438
439 // $(foo) -> $(foo)
486 // $$ -> $
487 if (*src == '$') {
488 *dst++ = *src++;
489 return;
490 }
491
492 // $(foo) -> $(foo)
440 // Not sure if I want to support this or not, so for now we just pass it through.
493 // Not sure if I want to support this or not, so for now we just pass
494 // it through.
441 if (*src == '(') {
442 *dst++ = '$';
443 count = 1;
444 while (count > 0) {
445 if (*src == ')')
446 count--;
447 else if (*src == '(')
448 count++;

--- 6 unchanged lines hidden (view full) ---

455 if (!isalpha(*src)) {
456 *dst++ = '$';
457 *dst++ = *src++;
458 return;
459 }
460
461 // $var -> replace with value
462 var = src++;
495 if (*src == '(') {
496 *dst++ = '$';
497 count = 1;
498 while (count > 0) {
499 if (*src == ')')
500 count--;
501 else if (*src == '(')
502 count++;

--- 6 unchanged lines hidden (view full) ---

509 if (!isalpha(*src)) {
510 *dst++ = '$';
511 *dst++ = *src++;
512 return;
513 }
514
515 // $var -> replace with value
516 var = src++;
463 while (*src && isalpha(*src) || isdigit(*src) || *src == '_' || *src == '-')
517 while (is_id_char(*src))
464 src++;
465 memcpy(buffer, var, src - var);
466 buffer[src - var] = '\0';
467 varstr = get_variable(buffer);
468 strcpy(dst, varstr.c_str());
469 dst += strlen(dst);
470}
471
472const string
473config::expand_string(const string &s)
474{
475 const char *src;
476 char *dst;
477 char buffer[1024];
478
479 src = s.c_str();
480 dst = buffer;
481 while (*src) {
482 if (*src == '$')
518 src++;
519 memcpy(buffer, var, src - var);
520 buffer[src - var] = '\0';
521 varstr = get_variable(buffer);
522 strcpy(dst, varstr.c_str());
523 dst += strlen(dst);
524}
525
526const string
527config::expand_string(const string &s)
528{
529 const char *src;
530 char *dst;
531 char buffer[1024];
532
533 src = s.c_str();
534 dst = buffer;
535 while (*src) {
536 if (*src == '$')
483 expand_one(++src, dst, buffer + sizeof(buffer));
537 expand_one(src, dst, buffer + sizeof(buffer));
484 else
485 *dst++ = *src++;
486 }
487 *dst++ = '\0';
488
489 return (buffer);
490}
491
538 else
539 *dst++ = *src++;
540 }
541 *dst++ = '\0';
542
543 return (buffer);
544}
545
546bool
547config::chop_var(char *&buffer, char *&lhs, char *&rhs)
548{
549 char *walker;
550
551 if (*buffer == '\0')
552 return (false);
553 walker = lhs = buffer;
554 while (is_id_char(*walker))
555 walker++;
556 if (*walker != '=')
557 return (false);
558 walker++; // skip =
559 if (*walker == '"') {
560 walker++; // skip "
561 rhs = walker;
562 while (*walker && *walker != '"')
563 walker++;
564 if (*walker != '"')
565 return (false);
566 rhs[-2] = '\0';
567 *walker++ = '\0';
568 } else {
569 rhs = walker;
570 while (*walker && !isspace(*walker))
571 walker++;
572 if (*walker != '\0')
573 *walker++ = '\0';
574 rhs[-1] = '\0';
575 }
576 buffer = walker;
577 return (true);
578}
579
580
581char *
582config::set_vars(char *buffer)
583{
584 char *lhs;
585 char *rhs;
586
587 while (1) {
588 if (!chop_var(buffer, lhs, rhs))
589 break;
590 set_variable(lhs, rhs);
591 }
592 return (buffer);
593}
594
595void
596config::find_and_execute(char type)
597{
598 vector<event_proc *> *l;
599 vector<event_proc *>::const_iterator i;
600 char *s;
601
602 switch (type) {
603 default:
604 return;
605 case nomatch:
606 l = &_nomatch_list;
607 s = "nomatch";
608 break;
609 case attach:
610 l = &_attach_list;
611 s = "attach";
612 break;
613 case detach:
614 l = &_detach_list;
615 s = "detach";
616 break;
617 }
618 if (dflag)
619 fprintf(stderr, "Processing %s event\n", s);
620 for (i = l->begin(); i != l->end(); i++) {
621 if ((*i)->matches(*this)) {
622 (*i)->run(*this);
623 break;
624 }
625 }
626
627}
628
492
493static void
629
630static void
494process_event(const char *buffer)
631process_event(char *buffer)
495{
496 char type;
632{
633 char type;
497 char cmd[1024];
498 char *sp;
499
634 char *sp;
635
500 // XXX should involve config
501 // XXX and set some variables
502 // XXX run the list and so forth
503
504 // Ignore unknown devices for now.
505 if (*buffer == '?')
506 return;
507 type = *buffer++;
508 sp = strchr(buffer, ' ');
509 if (sp == NULL)
510 return; /* Can't happen? */
511 *sp = '\0';
512 snprintf(cmd, sizeof(cmd), "/etc/devd-generic %s %s", buffer,
513 type == '+' ? "start" : "stop");
636 sp = buffer + 1;
514 if (dflag)
637 if (dflag)
515 printf("Trying '%s'\n", cmd);
516 system(cmd);
638 fprintf(stderr, "Processing event '%s'\n", buffer);
639 type = *buffer++;
640 cfg.push_var_table();
641 // No match doesn't have a device, and the format is a little
642 // different, so handle it separately.
643 if (type != nomatch) {
644 sp = strchr(sp, ' ');
645 if (sp == NULL)
646 return; /* Can't happen? */
647 *sp++ = '\0';
648 cfg.set_variable("device-name", buffer);
649 }
650 if (strncmp(sp, "at ", 3) == 0)
651 sp += 3;
652 sp = cfg.set_vars(sp);
653 if (strncmp(sp, "on ", 3) == 0)
654 cfg.set_variable("bus", sp + 3);
655 cfg.find_and_execute(type);
656 cfg.pop_var_table();
517}
518
519static void
520event_loop(void)
521{
522 int rv;
523 int fd;
524 char buffer[DEVCTL_MAXBUF];

--- 139 unchanged lines hidden ---
657}
658
659static void
660event_loop(void)
661{
662 int rv;
663 int fd;
664 char buffer[DEVCTL_MAXBUF];

--- 139 unchanged lines hidden ---