diff --git a/kacpimon/connection_list.c b/kacpimon/connection_list.c index 9b0b0a8..f228186 100644 --- a/kacpimon/connection_list.c +++ b/kacpimon/connection_list.c @@ -22,6 +22,7 @@ #include #include +#include #include "connection_list.h" @@ -30,9 +31,9 @@ /*---------------------------------------------------------------*/ /* private objects */ -#define MAX_CONNECTIONS 20 +static int capacity = 0; -static struct connection connection_list[MAX_CONNECTIONS]; +static struct connection *connection_list = NULL; static int nconnections = 0; @@ -51,9 +52,19 @@ add_connection(struct connection *p) { if (nconnections < 0) return; - if (nconnections >= MAX_CONNECTIONS) { - printf("add_connection(): Too many connections.\n"); - return; + + /* if the list is full, allocate more space */ + if (nconnections >= capacity) { + /* no more than 1024 */ + if (capacity > 1024) { + printf("add_connection(): Too many connections.\n"); + return; + } + + /* another 20 */ + capacity += 20; + connection_list = + realloc(connection_list, sizeof(struct connection) * capacity); } if (nconnections == 0) @@ -70,6 +81,30 @@ add_connection(struct connection *p) /*---------------------------------------------------------------*/ +void +delete_all_connections(void) +{ + int i = 0; + + /* For each connection */ + for (i = 0; i <= get_number_of_connections(); ++i) + { + struct connection *p; + + p = get_connection(i); + + /* If this connection is invalid, try the next. */ + if (p == 0) + continue; + + close(p -> fd); + } + free(connection_list); + connection_list = NULL; +} + +/*---------------------------------------------------------------*/ + struct connection * find_connection(int fd) { diff --git a/kacpimon/connection_list.c.kacpimon-dynamic-connections b/kacpimon/connection_list.c.kacpimon-dynamic-connections new file mode 100644 index 0000000..9b0b0a8 --- /dev/null +++ b/kacpimon/connection_list.c.kacpimon-dynamic-connections @@ -0,0 +1,121 @@ +/* + * connection_list.c - ACPI daemon connection list + * + * Copyright (C) 2008, Ted Felix (www.tedfelix.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Tabs at 4 + */ + +#include +#include + +#include "connection_list.h" + +#define max(a, b) (((a)>(b))?(a):(b)) + +/*---------------------------------------------------------------*/ +/* private objects */ + +#define MAX_CONNECTIONS 20 + +static struct connection connection_list[MAX_CONNECTIONS]; + +static int nconnections = 0; + +/* fd_set containing all the fd's that come in */ +static fd_set allfds; + +/* highest fd that is opened */ +/* (-2 + 1) causes select() to return immediately */ +static int highestfd = -2; + +/*---------------------------------------------------------------*/ +/* public functions */ + +void +add_connection(struct connection *p) +{ + if (nconnections < 0) + return; + if (nconnections >= MAX_CONNECTIONS) { + printf("add_connection(): Too many connections.\n"); + return; + } + + if (nconnections == 0) + FD_ZERO(&allfds); + + /* add the connection to the connection list */ + connection_list[nconnections] = *p; + ++nconnections; + + /* add to the fd set */ + FD_SET(p->fd, &allfds); + highestfd = max(highestfd, p->fd); +} + +/*---------------------------------------------------------------*/ + +struct connection * +find_connection(int fd) +{ + int i; + + /* for each connection */ + for (i = 0; i < nconnections; ++i) { + /* if the file descriptors match, return the connection */ + if (connection_list[i].fd == fd) + return &connection_list[i]; + } + + return NULL; +} + +/*---------------------------------------------------------------*/ + +int +get_number_of_connections(void) +{ + return nconnections; +} + +/*---------------------------------------------------------------*/ + +struct connection * +get_connection(int i) +{ + if (i < 0 || i >= nconnections) + return NULL; + + return &connection_list[i]; +} + +/*---------------------------------------------------------------*/ + +const fd_set * +get_fdset(void) +{ + return &allfds; +} + +/*---------------------------------------------------------------*/ + +int +get_highestfd(void) +{ + return highestfd; +} diff --git a/kacpimon/connection_list.h b/kacpimon/connection_list.h index 1d037cf..a787637 100644 --- a/kacpimon/connection_list.h +++ b/kacpimon/connection_list.h @@ -56,4 +56,7 @@ extern const fd_set *get_fdset(void); /* get the highest fd that was added to the list */ extern int get_highestfd(void); +/* delete all connections, closing the fds */ +extern void delete_all_connections(void); + #endif /* CONNECTION_LIST_H__ */ diff --git a/kacpimon/connection_list.h.kacpimon-dynamic-connections b/kacpimon/connection_list.h.kacpimon-dynamic-connections new file mode 100644 index 0000000..1d037cf --- /dev/null +++ b/kacpimon/connection_list.h.kacpimon-dynamic-connections @@ -0,0 +1,59 @@ +/* + * connection_list.h - connection list + * + * Copyright (C) 2008, Ted Felix (www.tedfelix.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Tabs at 4 + */ + +#ifndef CONNECTION_LIST_H__ +#define CONNECTION_LIST_H__ + +#include + +/***************************************************************** + * Connection List Public Members + *****************************************************************/ + +struct connection +{ + /* file descriptor */ + int fd; + + /* process incoming data on the connection */ + void (* process)(int fd); +}; + +/* add a connection to the list */ +extern void add_connection(struct connection *p); + +/* find a connection in the list by file descriptor */ +extern struct connection *find_connection(int fd); + +/* get the number of connections in the list */ +extern int get_number_of_connections(void); + +/* get a specific connection by index from the list */ +extern struct connection *get_connection(int i); + +/* get an fd_set with all the fd's that have been added to the list */ +extern const fd_set *get_fdset(void); + +/* get the highest fd that was added to the list */ +extern int get_highestfd(void); + +#endif /* CONNECTION_LIST_H__ */ diff --git a/kacpimon/kacpimon.c b/kacpimon/kacpimon.c index 1ddb9aa..253d270 100644 --- a/kacpimon/kacpimon.c +++ b/kacpimon/kacpimon.c @@ -164,27 +164,6 @@ static void monitor(void) // --------------------------------------------------------------- -static void close_all(void) -{ - int i = 0; - - /* For each connection */ - for (i = 0; i <= get_number_of_connections(); ++i) - { - struct connection *p; - - p = get_connection(i); - - /* If this connection is invalid, try the next. */ - if (p == 0) - continue; - - close(p -> fd); - } -} - -// --------------------------------------------------------------- - int main(void) { printf("Kernel ACPI Event Monitor...\n"); @@ -199,7 +178,7 @@ int main(void) printf("Closing files...\n"); - close_all(); + delete_all_connections(); printf("Goodbye\n"); diff --git a/kacpimon/kacpimon.c.kacpimon-dynamic-connections b/kacpimon/kacpimon.c.kacpimon-dynamic-connections new file mode 100644 index 0000000..1ddb9aa --- /dev/null +++ b/kacpimon/kacpimon.c.kacpimon-dynamic-connections @@ -0,0 +1,207 @@ +/* + * kacpimon - Kernel ACPI Event Monitor + * + * Monitors kernel ACPI events from multiple interfaces and reports them + * to the console. + * + * Inspired by (and in some cases blatantly lifted from) Vojtech Pavlik's + * evtest.c, Zhang Rui's acpi_genl, and Alexey Kuznetsov's libnetlink. + * + * Copyright (C) 2008, Ted Felix (www.tedfelix.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * (tabs at 4) + */ + +/* system */ +#include +#include +#include +#include +#include +#include +#include + +/* local */ +#include "libnetlink.h" +#include "genetlink.h" +#include "acpi_genetlink.h" + +#include "acpi_ids.h" +#include "connection_list.h" +#include "input_layer.h" +#include "netlink.h" + +#include "kacpimon.h" + +/* ??? Isn't this in a system header someplace? */ +#define max(a, b) (((a)>(b))?(a):(b)) + +/*********************************************************************/ + +/* Exit flag that can be set by any of the functions to cause the */ +/* program to exit. */ +int exitflag = 0; + +/**************************************************************** + * Old /proc/acpi/event interface + ****************************************************************/ + +static void process_proc(int fd) +{ + const int buffsize = 1024; + char buffer[buffsize]; + ssize_t nbytes; + + for (;;) + { + nbytes = read(fd, buffer, buffsize - 1); + + /* ??? Do we need to worry about partial messages? */ + + /* If there are no data to read, bail. */ + if (nbytes <= 0) + break; + + /* Ensure we have a zero terminator */ + buffer[nbytes] = 0; + + printf("/proc/acpi/event: %s", buffer); + } +} + +// --------------------------------------------------------------- + +static void open_proc(void) +{ + char *filename = "/proc/acpi/event"; + int fd; + struct connection c; + + fd = open(filename, O_RDONLY | O_NONBLOCK); + if (fd >= 0) + { + printf("%s opened successfully\n", filename); + + /* Add a connection to the list. */ + c.fd = fd; + c.process = process_proc; + add_connection(&c); + } + else + { + int errno2 = errno; + printf("open for %s: %s (%d)\n", + filename, strerror(errno2), errno2); + if (errno2 == EACCES) + printf(" (try running as root)\n"); + if (errno2 == ENOENT) + printf(" (ACPI proc filesystem may not be present)\n"); + if (errno2 == EBUSY) + printf(" (ACPI proc filesystem is in use. " + "You might need to kill acpid.)\n"); + } +} + +/**************************************************************** + * Main Program Functions + ****************************************************************/ + +static void monitor(void) +{ + while (exitflag == 0) + { + fd_set readfds; + int nready; + int i; + + /* It's going to get clobbered, so use a copy. */ + readfds = *get_fdset(); + + /* Wait on data. */ + nready = select(get_highestfd() + 1, &readfds, NULL, NULL, NULL); + + /* If something goes wrong, bail. */ + if (nready <= 0) + break; + + /* For each connection */ + for (i = 0; i <= get_number_of_connections(); ++i) + { + int fd; + struct connection *p; + + p = get_connection(i); + + /* If this connection is invalid, bail. */ + if (!p) + break; + + /* Get the file descriptor */ + fd = p -> fd; + + /* If this file descriptor has data waiting, */ + if (FD_ISSET(fd, &readfds)) + { + p->process(fd); + } + } + } +} + +// --------------------------------------------------------------- + +static void close_all(void) +{ + int i = 0; + + /* For each connection */ + for (i = 0; i <= get_number_of_connections(); ++i) + { + struct connection *p; + + p = get_connection(i); + + /* If this connection is invalid, try the next. */ + if (p == 0) + continue; + + close(p -> fd); + } +} + +// --------------------------------------------------------------- + +int main(void) +{ + printf("Kernel ACPI Event Monitor...\n"); + + open_proc(); + open_input(); + open_netlink(); + + printf("Press Escape to exit, or Ctrl-C if that doesn't work.\n"); + + monitor(); + + printf("Closing files...\n"); + + close_all(); + + printf("Goodbye\n"); + + return 0; +}