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