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 --- |