devd.cc (243932) | devd.cc (246121) |
---|---|
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 243932 2012-12-06 01:25:21Z eadler $"); | 66__FBSDID("$FreeBSD: head/sbin/devd/devd.cc 246121 2013-01-30 15:21:18Z ian $"); |
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> 75 76#include <ctype.h> 77#include <dirent.h> 78#include <errno.h> 79#include <err.h> 80#include <fcntl.h> 81#include <libutil.h> 82#include <paths.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> 75 76#include <ctype.h> 77#include <dirent.h> 78#include <errno.h> 79#include <err.h> 80#include <fcntl.h> 81#include <libutil.h> 82#include <paths.h> |
83#include <poll.h> |
|
83#include <regex.h> 84#include <signal.h> 85#include <stdlib.h> 86#include <stdio.h> 87#include <string.h> 88#include <unistd.h> 89 90#include <algorithm> --- 718 unchanged lines hidden (view full) --- 809 if (::bind(fd, (struct sockaddr *) & sun, slen) < 0) 810 err(1, "bind"); 811 listen(fd, 4); 812 chown(name, 0, 0); /* XXX - root.wheel */ 813 chmod(name, 0666); 814 return (fd); 815} 816 | 84#include <regex.h> 85#include <signal.h> 86#include <stdlib.h> 87#include <stdio.h> 88#include <string.h> 89#include <unistd.h> 90 91#include <algorithm> --- 718 unchanged lines hidden (view full) --- 810 if (::bind(fd, (struct sockaddr *) & sun, slen) < 0) 811 err(1, "bind"); 812 listen(fd, 4); 813 chown(name, 0, 0); /* XXX - root.wheel */ 814 chmod(name, 0666); 815 return (fd); 816} 817 |
818unsigned int max_clients = 10; /* Default, can be overriden on cmdline. */ 819unsigned int num_clients; |
|
817list<int> clients; 818 819void 820notify_clients(const char *data, int len) 821{ | 820list<int> clients; 821 822void 823notify_clients(const char *data, int len) 824{ |
822 list<int> bad; 823 list<int>::const_iterator i; | 825 list<int>::iterator i; |
824 | 826 |
825 for (i = clients.begin(); i != clients.end(); ++i) { 826 if (write(*i, data, len) <= 0) { 827 bad.push_back(*i); | 827 /* 828 * Deliver the data to all clients. Throw clients overboard at the 829 * first sign of trouble. This reaps clients who've died or closed 830 * their sockets, and also clients who are alive but failing to keep up 831 * (or who are maliciously not reading, to consume buffer space in 832 * kernel memory or tie up the limited number of available connections). 833 */ 834 for (i = clients.begin(); i != clients.end(); ) { 835 if (write(*i, data, len) != len) { 836 --num_clients; |
828 close(*i); | 837 close(*i); |
829 } | 838 i = clients.erase(i); 839 } else 840 ++i; |
830 } | 841 } |
842} |
|
831 | 843 |
832 for (i = bad.begin(); i != bad.end(); ++i) 833 clients.erase(find(clients.begin(), clients.end(), *i)); | 844void 845check_clients(void) 846{ 847 int s; 848 struct pollfd pfd; 849 list<int>::iterator i; 850 851 /* 852 * Check all existing clients to see if any of them have disappeared. 853 * Normally we reap clients when we get an error trying to send them an 854 * event. This check eliminates the problem of an ever-growing list of 855 * zombie clients because we're never writing to them on a system 856 * without frequent device-change activity. 857 */ 858 pfd.events = 0; 859 for (i = clients.begin(); i != clients.end(); ) { 860 pfd.fd = *i; 861 s = poll(&pfd, 1, 0); 862 if ((s < 0 && s != EINTR ) || 863 (s > 0 && (pfd.revents & POLLHUP))) { 864 --num_clients; 865 close(*i); 866 i = clients.erase(i); 867 } else 868 ++i; 869 } |
834} 835 836void 837new_client(int fd) 838{ 839 int s; 840 | 870} 871 872void 873new_client(int fd) 874{ 875 int s; 876 |
877 /* 878 * First go reap any zombie clients, then accept the connection, and 879 * shut down the read side to stop clients from consuming kernel memory 880 * by sending large buffers full of data we'll never read. 881 */ 882 check_clients(); |
|
841 s = accept(fd, NULL, NULL); | 883 s = accept(fd, NULL, NULL); |
842 if (s != -1) | 884 if (s != -1) { 885 shutdown(s, SHUT_RD); |
843 clients.push_back(s); | 886 clients.push_back(s); |
887 ++num_clients; 888 } |
|
844} 845 846static void 847event_loop(void) 848{ 849 int rv; 850 int fd; 851 char buffer[DEVCTL_MAXBUF]; 852 int once = 0; 853 int server_fd, max_fd; | 889} 890 891static void 892event_loop(void) 893{ 894 int rv; 895 int fd; 896 char buffer[DEVCTL_MAXBUF]; 897 int once = 0; 898 int server_fd, max_fd; |
899 int accepting; |
|
854 timeval tv; 855 fd_set fds; 856 857 fd = open(PATH_DEVCTL, O_RDONLY | O_CLOEXEC); 858 if (fd == -1) 859 err(1, "Can't open devctl device %s", PATH_DEVCTL); 860 server_fd = create_socket(PIPE); | 900 timeval tv; 901 fd_set fds; 902 903 fd = open(PATH_DEVCTL, O_RDONLY | O_CLOEXEC); 904 if (fd == -1) 905 err(1, "Can't open devctl device %s", PATH_DEVCTL); 906 server_fd = create_socket(PIPE); |
907 accepting = 1; |
|
861 max_fd = max(fd, server_fd) + 1; 862 while (1) { 863 if (romeo_must_die) 864 break; 865 if (!once && !dflag && !nflag) { 866 // Check to see if we have any events pending. 867 tv.tv_sec = 0; 868 tv.tv_usec = 0; --- 6 unchanged lines hidden (view full) --- 875 fprintf(stderr, "Calling daemon\n"); 876 cfg.remove_pidfile(); 877 cfg.open_pidfile(); 878 daemon(0, 0); 879 cfg.write_pidfile(); 880 once++; 881 } 882 } | 908 max_fd = max(fd, server_fd) + 1; 909 while (1) { 910 if (romeo_must_die) 911 break; 912 if (!once && !dflag && !nflag) { 913 // Check to see if we have any events pending. 914 tv.tv_sec = 0; 915 tv.tv_usec = 0; --- 6 unchanged lines hidden (view full) --- 922 fprintf(stderr, "Calling daemon\n"); 923 cfg.remove_pidfile(); 924 cfg.open_pidfile(); 925 daemon(0, 0); 926 cfg.write_pidfile(); 927 once++; 928 } 929 } |
930 /* 931 * When we've already got the max number of clients, stop 932 * accepting new connections (don't put server_fd in the set), 933 * shrink the accept() queue to reject connections quickly, and 934 * poll the existing clients more often, so that we notice more 935 * quickly when any of them disappear to free up client slots. 936 */ |
|
883 FD_ZERO(&fds); 884 FD_SET(fd, &fds); | 937 FD_ZERO(&fds); 938 FD_SET(fd, &fds); |
885 FD_SET(server_fd, &fds); 886 rv = select(max_fd, &fds, NULL, NULL, NULL); | 939 if (num_clients < max_clients) { 940 if (!accepting) { 941 listen(server_fd, max_clients); 942 accepting = 1; 943 } 944 FD_SET(server_fd, &fds); 945 tv.tv_sec = 60; 946 tv.tv_usec = 0; 947 } else { 948 if (accepting) { 949 listen(server_fd, 0); 950 accepting = 0; 951 } 952 tv.tv_sec = 2; 953 tv.tv_usec = 0; 954 } 955 rv = select(max_fd, &fds, NULL, NULL, &tv); |
887 if (rv == -1) { 888 if (errno == EINTR) 889 continue; 890 err(1, "select"); | 956 if (rv == -1) { 957 if (errno == EINTR) 958 continue; 959 err(1, "select"); |
891 } | 960 } else if (rv == 0) 961 check_clients(); |
892 if (FD_ISSET(fd, &fds)) { 893 rv = read(fd, buffer, sizeof(buffer) - 1); 894 if (rv > 0) { 895 notify_clients(buffer, rv); 896 buffer[rv] = '\0'; 897 while (buffer[--rv] == '\n') 898 buffer[rv] = '\0'; 899 process_event(buffer); --- 102 unchanged lines hidden (view full) --- 1002{ 1003 romeo_must_die++; 1004 _exit(0); 1005} 1006 1007static void 1008usage() 1009{ | 962 if (FD_ISSET(fd, &fds)) { 963 rv = read(fd, buffer, sizeof(buffer) - 1); 964 if (rv > 0) { 965 notify_clients(buffer, rv); 966 buffer[rv] = '\0'; 967 while (buffer[--rv] == '\n') 968 buffer[rv] = '\0'; 969 process_event(buffer); --- 102 unchanged lines hidden (view full) --- 1072{ 1073 romeo_must_die++; 1074 _exit(0); 1075} 1076 1077static void 1078usage() 1079{ |
1010 fprintf(stderr, "usage: %s [-Ddn] [-f file]\n", getprogname()); | 1080 fprintf(stderr, "usage: %s [-Ddn] [-l connlimit] [-f file]\n", 1081 getprogname()); |
1011 exit(1); 1012} 1013 1014static void 1015check_devd_enabled() 1016{ 1017 int val = 0; 1018 size_t len; --- 12 unchanged lines hidden (view full) --- 1031 * main 1032 */ 1033int 1034main(int argc, char **argv) 1035{ 1036 int ch; 1037 1038 check_devd_enabled(); | 1082 exit(1); 1083} 1084 1085static void 1086check_devd_enabled() 1087{ 1088 int val = 0; 1089 size_t len; --- 12 unchanged lines hidden (view full) --- 1102 * main 1103 */ 1104int 1105main(int argc, char **argv) 1106{ 1107 int ch; 1108 1109 check_devd_enabled(); |
1039 while ((ch = getopt(argc, argv, "Ddf:n")) != -1) { | 1110 while ((ch = getopt(argc, argv, "Ddf:l:n")) != -1) { |
1040 switch (ch) { 1041 case 'D': 1042 Dflag++; 1043 break; 1044 case 'd': 1045 dflag++; 1046 break; 1047 case 'f': 1048 configfile = optarg; 1049 break; | 1111 switch (ch) { 1112 case 'D': 1113 Dflag++; 1114 break; 1115 case 'd': 1116 dflag++; 1117 break; 1118 case 'f': 1119 configfile = optarg; 1120 break; |
1121 case 'l': 1122 max_clients = MAX(1, strtoul(optarg, NULL, 0)); 1123 break; |
|
1050 case 'n': 1051 nflag++; 1052 break; 1053 default: 1054 usage(); 1055 } 1056 } 1057 --- 13 unchanged lines hidden --- | 1124 case 'n': 1125 nflag++; 1126 break; 1127 default: 1128 usage(); 1129 } 1130 } 1131 --- 13 unchanged lines hidden --- |