devd.cc (250186) | devd.cc (252481) |
---|---|
1/*- 2 * Copyright (c) 2002-2010 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 --- 49 unchanged lines hidden (view full) --- 58 */ 59 60// TODO list: 61// o devd.conf and devd man pages need a lot of help: 62// - devd needs to document the unix domain socket 63// - devd.conf needs more details on the supported statements. 64 65#include <sys/cdefs.h> | 1/*- 2 * Copyright (c) 2002-2010 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 --- 49 unchanged lines hidden (view full) --- 58 */ 59 60// TODO list: 61// o devd.conf and devd man pages need a lot of help: 62// - devd needs to document the unix domain socket 63// - devd.conf needs more details on the supported statements. 64 65#include <sys/cdefs.h> |
66__FBSDID("$FreeBSD: head/sbin/devd/devd.cc 250186 2013-05-02 17:02:50Z eadler $"); | 66__FBSDID("$FreeBSD: head/sbin/devd/devd.cc 252481 2013-07-01 21:20:17Z asomers $"); |
67 68#include <sys/param.h> 69#include <sys/socket.h> 70#include <sys/stat.h> 71#include <sys/sysctl.h> 72#include <sys/types.h> 73#include <sys/wait.h> 74#include <sys/un.h> --- 7 unchanged lines hidden (view full) --- 82 83#include <dirent.h> 84#include <err.h> 85#include <fcntl.h> 86#include <libutil.h> 87#include <paths.h> 88#include <poll.h> 89#include <regex.h> | 67 68#include <sys/param.h> 69#include <sys/socket.h> 70#include <sys/stat.h> 71#include <sys/sysctl.h> 72#include <sys/types.h> 73#include <sys/wait.h> 74#include <sys/un.h> --- 7 unchanged lines hidden (view full) --- 82 83#include <dirent.h> 84#include <err.h> 85#include <fcntl.h> 86#include <libutil.h> 87#include <paths.h> 88#include <poll.h> 89#include <regex.h> |
90#include <syslog.h> |
|
90#include <unistd.h> 91 92#include <algorithm> 93#include <map> 94#include <string> 95#include <list> 96#include <vector> 97 --- 11 unchanged lines hidden (view full) --- 109 110static const char notify = '!'; 111static const char nomatch = '?'; 112static const char attach = '+'; 113static const char detach = '-'; 114 115static struct pidfh *pfh; 116 | 91#include <unistd.h> 92 93#include <algorithm> 94#include <map> 95#include <string> 96#include <list> 97#include <vector> 98 --- 11 unchanged lines hidden (view full) --- 110 111static const char notify = '!'; 112static const char nomatch = '?'; 113static const char attach = '+'; 114static const char detach = '-'; 115 116static struct pidfh *pfh; 117 |
117int Dflag; | |
118int dflag; 119int nflag; 120static volatile sig_atomic_t romeo_must_die = 0; 121 122static const char *configfile = CF; 123 | 118int dflag; 119int nflag; 120static volatile sig_atomic_t romeo_must_die = 0; 121 122static const char *configfile = CF; 123 |
124static void devdlog(int priority, const char* message, ...); |
|
124static void event_loop(void); 125static void usage(void); 126 127template <class T> void 128delete_and_clear(vector<T *> &v) 129{ 130 typename vector<T *>::const_iterator i; 131 --- 106 unchanged lines hidden (view full) --- 238 ::sigprocmask(SIG_SETMASK, &oldsigblock, NULL); 239 return (pid == -1 ? -1 : pstat); 240} 241 242bool 243action::do_action(config &c) 244{ 245 string s = c.expand_string(_cmd.c_str()); | 125static void event_loop(void); 126static void usage(void); 127 128template <class T> void 129delete_and_clear(vector<T *> &v) 130{ 131 typename vector<T *>::const_iterator i; 132 --- 106 unchanged lines hidden (view full) --- 239 ::sigprocmask(SIG_SETMASK, &oldsigblock, NULL); 240 return (pid == -1 ? -1 : pstat); 241} 242 243bool 244action::do_action(config &c) 245{ 246 string s = c.expand_string(_cmd.c_str()); |
246 if (Dflag) 247 fprintf(stderr, "Executing '%s'\n", s.c_str()); | 247 devdlog(LOG_NOTICE, "Executing '%s'\n", s.c_str()); |
248 my_system(s.c_str()); 249 return (true); 250} 251 252match::match(config &c, const char *var, const char *re) : 253 _inv(re[0] == '!'), 254 _var(var), 255 _re(c.expand_string(_inv ? re + 1 : re, "^", "$")) --- 7 unchanged lines hidden (view full) --- 263} 264 265bool 266match::do_match(config &c) 267{ 268 const string &value = c.get_variable(_var); 269 bool retval; 270 | 248 my_system(s.c_str()); 249 return (true); 250} 251 252match::match(config &c, const char *var, const char *re) : 253 _inv(re[0] == '!'), 254 _var(var), 255 _re(c.expand_string(_inv ? re + 1 : re, "^", "$")) --- 7 unchanged lines hidden (view full) --- 263} 264 265bool 266match::do_match(config &c) 267{ 268 const string &value = c.get_variable(_var); 269 bool retval; 270 |
271 if (Dflag) 272 fprintf(stderr, "Testing %s=%s against %s, invert=%d\n", | 271 /* 272 * This function gets called WAY too often to justify calling syslog() 273 * each time, even at LOG_DEBUG. Because if syslogd isn't running, it 274 * can consume excessive amounts of systime inside of connect(). Only 275 * log when we're in -d mode. 276 */ 277 if (dflag) { 278 devdlog(LOG_DEBUG, "Testing %s=%s against %s, invert=%d\n", |
273 _var.c_str(), value.c_str(), _re.c_str(), _inv); | 279 _var.c_str(), value.c_str(), _re.c_str(), _inv); |
280 } |
|
274 275 retval = (regexec(&_regex, value.c_str(), 0, NULL, 0) == 0); 276 if (_inv == 1) 277 retval = (retval == 0) ? 1 : 0; 278 279 return retval; 280} 281 --- 35 unchanged lines hidden (view full) --- 317 // Since we can be called from both a device attach/detach 318 // context where device-name is defined and what we want, 319 // as well as from a link status context, where subsystem is 320 // the name of interest, first try device-name and fall back 321 // to subsystem if none exists. 322 value = c.get_variable("device-name"); 323 if (value.empty()) 324 value = c.get_variable("subsystem"); | 281 282 retval = (regexec(&_regex, value.c_str(), 0, NULL, 0) == 0); 283 if (_inv == 1) 284 retval = (retval == 0) ? 1 : 0; 285 286 return retval; 287} 288 --- 35 unchanged lines hidden (view full) --- 324 // Since we can be called from both a device attach/detach 325 // context where device-name is defined and what we want, 326 // as well as from a link status context, where subsystem is 327 // the name of interest, first try device-name and fall back 328 // to subsystem if none exists. 329 value = c.get_variable("device-name"); 330 if (value.empty()) 331 value = c.get_variable("subsystem"); |
325 if (Dflag) 326 fprintf(stderr, "Testing media type of %s against 0x%x\n", | 332 devdlog(LOG_DEBUG, "Testing media type of %s against 0x%x\n", |
327 value.c_str(), _type); 328 329 retval = false; 330 331 s = socket(PF_INET, SOCK_DGRAM, 0); 332 if (s >= 0) { 333 memset(&ifmr, 0, sizeof(ifmr)); 334 strncpy(ifmr.ifm_name, value.c_str(), sizeof(ifmr.ifm_name)); 335 336 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0 && 337 ifmr.ifm_status & IFM_AVALID) { | 333 value.c_str(), _type); 334 335 retval = false; 336 337 s = socket(PF_INET, SOCK_DGRAM, 0); 338 if (s >= 0) { 339 memset(&ifmr, 0, sizeof(ifmr)); 340 strncpy(ifmr.ifm_name, value.c_str(), sizeof(ifmr.ifm_name)); 341 342 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0 && 343 ifmr.ifm_status & IFM_AVALID) { |
338 if (Dflag) 339 fprintf(stderr, "%s has media type 0x%x\n", | 344 devdlog(LOG_DEBUG, "%s has media type 0x%x\n", |
340 value.c_str(), IFM_TYPE(ifmr.ifm_active)); 341 retval = (IFM_TYPE(ifmr.ifm_active) == _type); 342 } else if (_type == -1) { | 345 value.c_str(), IFM_TYPE(ifmr.ifm_active)); 346 retval = (IFM_TYPE(ifmr.ifm_active) == _type); 347 } else if (_type == -1) { |
343 if (Dflag) 344 fprintf(stderr, "%s has unknown media type\n", | 348 devdlog(LOG_DEBUG, "%s has unknown media type\n", |
345 value.c_str()); 346 retval = true; 347 } 348 close(s); 349 } 350 351 return retval; 352} --- 16 unchanged lines hidden (view full) --- 369var_list::is_set(const string &var) const 370{ 371 return (_vars.find(var) != _vars.end()); 372} 373 374void 375var_list::set_variable(const string &var, const string &val) 376{ | 349 value.c_str()); 350 retval = true; 351 } 352 close(s); 353 } 354 355 return retval; 356} --- 16 unchanged lines hidden (view full) --- 373var_list::is_set(const string &var) const 374{ 375 return (_vars.find(var) != _vars.end()); 376} 377 378void 379var_list::set_variable(const string &var, const string &val) 380{ |
377 if (Dflag) 378 fprintf(stderr, "setting %s=%s\n", var.c_str(), val.c_str()); | 381 /* 382 * This function gets called WAY too often to justify calling syslog() 383 * each time, even at LOG_DEBUG. Because if syslogd isn't running, it 384 * can consume excessive amounts of systime inside of connect(). Only 385 * log when we're in -d mode. 386 */ 387 if (dflag) 388 devdlog(LOG_DEBUG, "setting %s=%s\n", var.c_str(), val.c_str()); |
379 _vars[var] = val; 380} 381 382void 383config::reset(void) 384{ 385 _dir_list.clear(); 386 delete_and_clear(_var_list_table); 387 delete_and_clear(_attach_list); 388 delete_and_clear(_detach_list); 389 delete_and_clear(_nomatch_list); 390 delete_and_clear(_notify_list); 391} 392 393void 394config::parse_one_file(const char *fn) 395{ | 389 _vars[var] = val; 390} 391 392void 393config::reset(void) 394{ 395 _dir_list.clear(); 396 delete_and_clear(_var_list_table); 397 delete_and_clear(_attach_list); 398 delete_and_clear(_detach_list); 399 delete_and_clear(_nomatch_list); 400 delete_and_clear(_notify_list); 401} 402 403void 404config::parse_one_file(const char *fn) 405{ |
396 if (Dflag) 397 fprintf(stderr, "Parsing %s\n", fn); | 406 devdlog(LOG_DEBUG, "Parsing %s\n", fn); |
398 yyin = fopen(fn, "r"); 399 if (yyin == NULL) 400 err(1, "Cannot open config file %s", fn); 401 lineno = 1; 402 if (yyparse() != 0) 403 errx(1, "Cannot parse %s at line %d", fn, lineno); 404 fclose(yyin); 405} 406 407void 408config::parse_files_in_dir(const char *dirname) 409{ 410 DIR *dirp; 411 struct dirent *dp; 412 char path[PATH_MAX]; 413 | 407 yyin = fopen(fn, "r"); 408 if (yyin == NULL) 409 err(1, "Cannot open config file %s", fn); 410 lineno = 1; 411 if (yyparse() != 0) 412 errx(1, "Cannot parse %s at line %d", fn, lineno); 413 fclose(yyin); 414} 415 416void 417config::parse_files_in_dir(const char *dirname) 418{ 419 DIR *dirp; 420 struct dirent *dp; 421 char path[PATH_MAX]; 422 |
414 if (Dflag) 415 fprintf(stderr, "Parsing files in %s\n", dirname); | 423 devdlog(LOG_DEBUG, "Parsing files in %s\n", dirname); |
416 dirp = opendir(dirname); 417 if (dirp == NULL) 418 return; 419 readdir(dirp); /* Skip . */ 420 readdir(dirp); /* Skip .. */ 421 while ((dp = readdir(dirp)) != NULL) { 422 if (strcmp(dp->d_name + dp->d_namlen - 5, ".conf") == 0) { 423 snprintf(path, sizeof(path), "%s/%s", --- 110 unchanged lines hidden (view full) --- 534 535void 536config::push_var_table() 537{ 538 var_list *vl; 539 540 vl = new var_list(); 541 _var_list_table.push_back(vl); | 424 dirp = opendir(dirname); 425 if (dirp == NULL) 426 return; 427 readdir(dirp); /* Skip . */ 428 readdir(dirp); /* Skip .. */ 429 while ((dp = readdir(dirp)) != NULL) { 430 if (strcmp(dp->d_name + dp->d_namlen - 5, ".conf") == 0) { 431 snprintf(path, sizeof(path), "%s/%s", --- 110 unchanged lines hidden (view full) --- 542 543void 544config::push_var_table() 545{ 546 var_list *vl; 547 548 vl = new var_list(); 549 _var_list_table.push_back(vl); |
542 if (Dflag) 543 fprintf(stderr, "Pushing table\n"); | 550 devdlog(LOG_DEBUG, "Pushing table\n"); |
544} 545 546void 547config::pop_var_table() 548{ 549 delete _var_list_table.back(); 550 _var_list_table.pop_back(); | 551} 552 553void 554config::pop_var_table() 555{ 556 delete _var_list_table.back(); 557 _var_list_table.pop_back(); |
551 if (Dflag) 552 fprintf(stderr, "Popping table\n"); | 558 devdlog(LOG_DEBUG, "Popping table\n"); |
553} 554 555void 556config::set_variable(const char *var, const char *val) 557{ 558 _var_list_table.back()->set_variable(var, val); 559} 560 --- 165 unchanged lines hidden (view full) --- 726 l = &_attach_list; 727 s = "attach"; 728 break; 729 case detach: 730 l = &_detach_list; 731 s = "detach"; 732 break; 733 } | 559} 560 561void 562config::set_variable(const char *var, const char *val) 563{ 564 _var_list_table.back()->set_variable(var, val); 565} 566 --- 165 unchanged lines hidden (view full) --- 732 l = &_attach_list; 733 s = "attach"; 734 break; 735 case detach: 736 l = &_detach_list; 737 s = "detach"; 738 break; 739 } |
734 if (Dflag) 735 fprintf(stderr, "Processing %s event\n", s); | 740 devdlog(LOG_DEBUG, "Processing %s event\n", s); |
736 for (i = l->begin(); i != l->end(); ++i) { 737 if ((*i)->matches(*this)) { 738 (*i)->run(*this); 739 break; 740 } 741 } 742 743} 744 745 746static void 747process_event(char *buffer) 748{ 749 char type; 750 char *sp; 751 752 sp = buffer + 1; | 741 for (i = l->begin(); i != l->end(); ++i) { 742 if ((*i)->matches(*this)) { 743 (*i)->run(*this); 744 break; 745 } 746 } 747 748} 749 750 751static void 752process_event(char *buffer) 753{ 754 char type; 755 char *sp; 756 757 sp = buffer + 1; |
753 if (Dflag) 754 fprintf(stderr, "Processing event '%s'\n", buffer); | 758 devdlog(LOG_DEBUG, "Processing event '%s'\n", buffer); |
755 type = *buffer++; 756 cfg.push_var_table(); 757 // No match doesn't have a device, and the format is a little 758 // different, so handle it separately. 759 switch (type) { 760 case notify: 761 sp = cfg.set_vars(sp); 762 break; --- 75 unchanged lines hidden (view full) --- 838 * (or who are maliciously not reading, to consume buffer space in 839 * kernel memory or tie up the limited number of available connections). 840 */ 841 for (i = clients.begin(); i != clients.end(); ) { 842 if (write(*i, data, len) != len) { 843 --num_clients; 844 close(*i); 845 i = clients.erase(i); | 759 type = *buffer++; 760 cfg.push_var_table(); 761 // No match doesn't have a device, and the format is a little 762 // different, so handle it separately. 763 switch (type) { 764 case notify: 765 sp = cfg.set_vars(sp); 766 break; --- 75 unchanged lines hidden (view full) --- 842 * (or who are maliciously not reading, to consume buffer space in 843 * kernel memory or tie up the limited number of available connections). 844 */ 845 for (i = clients.begin(); i != clients.end(); ) { 846 if (write(*i, data, len) != len) { 847 --num_clients; 848 close(*i); 849 i = clients.erase(i); |
850 devdlog(LOG_WARNING, "notify_clients: write() failed; " 851 "dropping unresponsive client\n"); |
|
846 } else 847 ++i; 848 } 849} 850 851void 852check_clients(void) 853{ --- 12 unchanged lines hidden (view full) --- 866 for (i = clients.begin(); i != clients.end(); ) { 867 pfd.fd = *i; 868 s = poll(&pfd, 1, 0); 869 if ((s < 0 && s != EINTR ) || 870 (s > 0 && (pfd.revents & POLLHUP))) { 871 --num_clients; 872 close(*i); 873 i = clients.erase(i); | 852 } else 853 ++i; 854 } 855} 856 857void 858check_clients(void) 859{ --- 12 unchanged lines hidden (view full) --- 872 for (i = clients.begin(); i != clients.end(); ) { 873 pfd.fd = *i; 874 s = poll(&pfd, 1, 0); 875 if ((s < 0 && s != EINTR ) || 876 (s > 0 && (pfd.revents & POLLHUP))) { 877 --num_clients; 878 close(*i); 879 i = clients.erase(i); |
880 devdlog(LOG_NOTICE, "check_clients: " 881 "dropping disconnected client\n"); |
|
874 } else 875 ++i; 876 } 877} 878 879void 880new_client(int fd) 881{ --- 36 unchanged lines hidden (view full) --- 918 // Check to see if we have any events pending. 919 tv.tv_sec = 0; 920 tv.tv_usec = 0; 921 FD_ZERO(&fds); 922 FD_SET(fd, &fds); 923 rv = select(fd + 1, &fds, &fds, &fds, &tv); 924 // No events -> we've processed all pending events 925 if (rv == 0) { | 882 } else 883 ++i; 884 } 885} 886 887void 888new_client(int fd) 889{ --- 36 unchanged lines hidden (view full) --- 926 // Check to see if we have any events pending. 927 tv.tv_sec = 0; 928 tv.tv_usec = 0; 929 FD_ZERO(&fds); 930 FD_SET(fd, &fds); 931 rv = select(fd + 1, &fds, &fds, &fds, &tv); 932 // No events -> we've processed all pending events 933 if (rv == 0) { |
926 if (Dflag) 927 fprintf(stderr, "Calling daemon\n"); | 934 devdlog(LOG_DEBUG, "Calling daemon\n"); |
928 cfg.remove_pidfile(); 929 cfg.open_pidfile(); 930 daemon(0, 0); 931 cfg.write_pidfile(); 932 once++; 933 } 934 } 935 /* --- 26 unchanged lines hidden (view full) --- 962 if (errno == EINTR) 963 continue; 964 err(1, "select"); 965 } else if (rv == 0) 966 check_clients(); 967 if (FD_ISSET(fd, &fds)) { 968 rv = read(fd, buffer, sizeof(buffer) - 1); 969 if (rv > 0) { | 935 cfg.remove_pidfile(); 936 cfg.open_pidfile(); 937 daemon(0, 0); 938 cfg.write_pidfile(); 939 once++; 940 } 941 } 942 /* --- 26 unchanged lines hidden (view full) --- 969 if (errno == EINTR) 970 continue; 971 err(1, "select"); 972 } else if (rv == 0) 973 check_clients(); 974 if (FD_ISSET(fd, &fds)) { 975 rv = read(fd, buffer, sizeof(buffer) - 1); 976 if (rv > 0) { |
977 if (rv == sizeof(buffer) - 1) { 978 devdlog(LOG_WARNING, "Warning: " 979 "available event data exceeded " 980 "buffer space\n"); 981 } |
|
970 notify_clients(buffer, rv); 971 buffer[rv] = '\0'; 972 while (buffer[--rv] == '\n') 973 buffer[rv] = '\0'; 974 process_event(buffer); 975 } else if (rv < 0) { 976 if (errno != EINTR) 977 break; --- 95 unchanged lines hidden (view full) --- 1073 1074 1075static void 1076gensighand(int) 1077{ 1078 romeo_must_die = 1; 1079} 1080 | 982 notify_clients(buffer, rv); 983 buffer[rv] = '\0'; 984 while (buffer[--rv] == '\n') 985 buffer[rv] = '\0'; 986 process_event(buffer); 987 } else if (rv < 0) { 988 if (errno != EINTR) 989 break; --- 95 unchanged lines hidden (view full) --- 1085 1086 1087static void 1088gensighand(int) 1089{ 1090 romeo_must_die = 1; 1091} 1092 |
1093/* 1094 * Local logging function. Prints to syslog if we're daemonized; syslog 1095 * otherwise. 1096 */ |
|
1081static void | 1097static void |
1098devdlog(int priority, const char* fmt, ...) 1099{ 1100 va_list argp; 1101 1102 va_start(argp, fmt); 1103 if (dflag) 1104 vfprintf(stderr, fmt, argp); 1105 else 1106 vsyslog(priority, fmt, argp); 1107 va_end(argp); 1108} 1109 1110static void |
|
1082usage() 1083{ | 1111usage() 1112{ |
1084 fprintf(stderr, "usage: %s [-Ddn] [-l connlimit] [-f file]\n", | 1113 fprintf(stderr, "usage: %s [-dn] [-l connlimit] [-f file]\n", |
1085 getprogname()); 1086 exit(1); 1087} 1088 1089static void 1090check_devd_enabled() 1091{ 1092 int val = 0; --- 13 unchanged lines hidden (view full) --- 1106 * main 1107 */ 1108int 1109main(int argc, char **argv) 1110{ 1111 int ch; 1112 1113 check_devd_enabled(); | 1114 getprogname()); 1115 exit(1); 1116} 1117 1118static void 1119check_devd_enabled() 1120{ 1121 int val = 0; --- 13 unchanged lines hidden (view full) --- 1135 * main 1136 */ 1137int 1138main(int argc, char **argv) 1139{ 1140 int ch; 1141 1142 check_devd_enabled(); |
1114 while ((ch = getopt(argc, argv, "Ddf:l:n")) != -1) { | 1143 while ((ch = getopt(argc, argv, "df:l:n")) != -1) { |
1115 switch (ch) { | 1144 switch (ch) { |
1116 case 'D': 1117 Dflag++; 1118 break; | |
1119 case 'd': 1120 dflag++; 1121 break; 1122 case 'f': 1123 configfile = optarg; 1124 break; 1125 case 'l': 1126 max_clients = MAX(1, strtoul(optarg, NULL, 0)); --- 22 unchanged lines hidden --- | 1145 case 'd': 1146 dflag++; 1147 break; 1148 case 'f': 1149 configfile = optarg; 1150 break; 1151 case 'l': 1152 max_clients = MAX(1, strtoul(optarg, NULL, 0)); --- 22 unchanged lines hidden --- |