Deleted Added
full compact
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 ---