Exemple #1
0
int
ud_create_socket(const char *name, mode_t socketmode)
{
	int fd;
	int r;
	struct sockaddr_un uds_addr;

    if (strnlen(name, sizeof(uds_addr.sun_path)) > 
        sizeof(uds_addr.sun_path) - 1) {
        acpid_log(LOG_ERR, "ud_create_socket(): "
            "socket filename longer than %zu characters: %s",
            sizeof(uds_addr.sun_path) - 1, name);
        errno = EINVAL;
        return -1;
    }

    /* JIC */
	unlink(name);

	fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
	if (fd < 0) {
		return fd;
	}

	/* Clear the umask to guarantee predictable results from fchmod(). */
	umask(0);

	if (fchmod(fd, socketmode) < 0) {
		close(fd);
		acpid_log(LOG_ERR, "fchmod() on socket %s: %s",
	        name, strerror(errno));
		return -1;
	}

	/* setup address struct */
	memset(&uds_addr, 0, sizeof(uds_addr));
	uds_addr.sun_family = AF_UNIX;
    strncpy(uds_addr.sun_path, name, sizeof(uds_addr.sun_path) - 1);
	
	/* bind it to the socket */
	r = bind(fd, (struct sockaddr *)&uds_addr, sizeof(uds_addr));
	if (r < 0) {
		close (fd);
		return r;
	}

	/* listen - allow 10 to queue */
	r = listen(fd, 10);
	if (r < 0) {
		close(fd);
		return r;
	}

	return fd;
}
Exemple #2
0
static char *
read_line(int fd)
{
	static char *buf;
	int buflen = 64;
	int i = 0;
	int r;
	int searching = 1;

	while (searching) {
		/* ??? This memory is leaked since it is never freed */
		buf = realloc(buf, buflen);
		if (!buf) {
			acpid_log(LOG_ERR, "malloc(%d): %s",
				buflen, strerror(errno));
			return NULL;
		}
		memset(buf+i, 0, buflen-i);

		while (i < buflen) {
			r = read(fd, buf+i, 1);
			if (r < 0 && errno != EINTR) {
				/* we should do something with the data */
				acpid_log(LOG_ERR, "read(): %s",
					strerror(errno));
				return NULL;
			} else if (r == 0) {
				/* signal this in an almost standard way */
				errno = EPIPE;
				return NULL;
			} else if (r == 1) {
				/* scan for a newline */
				if (buf[i] == '\n') {
					searching = 0;
					buf[i] = '\0';
					break;
				}
				i++;
			}
		}
		if (buflen >= MAX_BUFLEN) {
			break;
		} 
		buflen *= 2;
	}

	return buf;
}
Exemple #3
0
static int
create_pidfile(void)
{
	int fd;

	/* JIC */
	unlink(pidfile);

	/* open the pidfile */
	fd = open(pidfile, O_WRONLY|O_CREAT|O_EXCL, 0644);
	if (fd >= 0) {
		FILE *f;

		/* write our pid to it */
		f = fdopen(fd, "w");
		if (f != NULL) {
			fprintf(f, "%d\n", getpid());
			fclose(f);
			/* leave the fd open */
			return 0;
		}
		close(fd);
	}

	/* something went wrong */
	acpid_log(LOG_ERR, "can't create pidfile %s: %s\n",
		    pidfile, strerror(errno));
	return -1;
}
Exemple #4
0
int
ud_connect(const char *name)
{
	int fd;
	int r;
	struct sockaddr_un addr;

    if (strnlen(name, sizeof(addr.sun_path)) > sizeof(addr.sun_path) - 1) {
        acpid_log(LOG_ERR, "ud_connect(): "
            "socket filename longer than %zu characters: %s",
            sizeof(addr.sun_path) - 1, name);
        errno = EINVAL;
        return -1;
    }
    
	fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
	if (fd < 0) {
		return fd;
	}

	memset(&addr, 0, sizeof(addr));
	addr.sun_family = AF_UNIX;
	sprintf(addr.sun_path, "%s", name);
    /* safer: */
    /*strncpy(addr.sun_path, name, sizeof(addr.sun_path) - 1);*/

	r = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
	if (r < 0) {
		close(fd);
		return r;
	}

	return fd;
}
Exemple #5
0
static void
reload_conf(int sig __attribute__((unused)))
{
	acpid_log(LOG_NOTICE, "reloading configuration\n");
	acpid_cleanup_rules(0);
	acpid_read_conf(confdir);
}
Exemple #6
0
static void
clean_exit_with_status(int status)
{
	acpid_cleanup_rules(1);
	acpid_log(LOG_NOTICE, "exiting\n");
	unlink(pidfile);
	exit(status);
}
Exemple #7
0
static void
process_proc(int fd)
{
	char *event;

	/* read an event */
	event = read_line(fd);

	/* if we're locked, don't process the event */
	if (locked()) {
		if (logevents  &&  event != NULL) {
			acpid_log(LOG_INFO,
				"lockfile present, not processing "
				"event \"%s\"", event);
		}
		return;
	}

	/* handle the event */
	if (event) {
		if (logevents) {
			acpid_log(LOG_INFO,
			          "procfs received event \"%s\"", event);
		}
		acpid_handle_event(event);
		if (logevents) {
			acpid_log(LOG_INFO,
				"procfs completed event \"%s\"", event);
		}
	} else if (errno == EPIPE) {
		acpid_log(LOG_WARNING,
			"events file connection closed");
		exit(EXIT_FAILURE);
	} else {
		static int nerrs;
		if (++nerrs >= ACPID_MAX_ERRS) {
			acpid_log(LOG_ERR,
				"too many errors reading "
				"events file - aborting");
			exit(EXIT_FAILURE);
		}
	}
}
Exemple #8
0
/* accept a new client connection */
static void
process_sock(int fd)
{
	int cli_fd;
	struct ucred creds;
	char *buf;
	static int accept_errors;

	/* accept and add to our lists */
	cli_fd = ud_accept(fd, &creds);
	if (cli_fd < 0) {
		acpid_log(LOG_ERR, "can't accept client: %s",
			  strerror(errno));
		accept_errors++;
		if (accept_errors >= 5) {
			acpid_log(LOG_ERR, "giving up");
			clean_exit_with_status(EXIT_FAILURE);
		}
		return;
	}
	accept_errors = 0;

	/* don't allow too many non-root clients  */
	if (creds.uid != 0 && non_root_clients >= clientmax) {
		close(cli_fd);
		acpid_log(LOG_ERR, "too many non-root clients");
		return;
	}
	if (creds.uid != 0) {
		non_root_clients++;
	}

    if(asprintf(&buf, "%d[%d:%d]", creds.pid, creds.uid, creds.gid) < 0) {
        close(cli_fd);
        acpid_log(LOG_ERR, "asprintf: %s", strerror(errno));
        return;
     }
        acpid_add_client(cli_fd, buf);
        free(buf);
}
/* Set up an inotify watch on /dev/input. */
void open_inotify(void)
{
	int fd = -1;
	int wd = -1;
	struct connection c;

	/* set up inotify */
	fd = inotify_init1(IN_CLOEXEC);
	
	if (fd < 0) {
		acpid_log(LOG_ERR, "inotify_init() failed: %s (%d)",
			strerror(errno), errno);
		return;
	}
	
	acpid_log(LOG_DEBUG, "inotify fd: %d", fd);

	/* watch for files being created or deleted in /dev/input */
	wd = inotify_add_watch(fd, ACPID_INPUTLAYERDIR, IN_CREATE | IN_DELETE);

	if (wd < 0) {
		acpid_log(LOG_ERR, "inotify_add_watch() failed: %s (%d)",
			strerror(errno), errno);
		close(fd);			
		return;
	}

	acpid_log(LOG_DEBUG, "inotify wd: %d", wd);

	/* add a connection to the list */
	c.fd = fd;
	c.process = process_inotify;
	c.pathname = NULL;
	c.kybd = 0;
	add_connection(&c);
}
Exemple #10
0
int
open_proc()
{
	int fd;
	struct connection c;
	
	/* O_CLOEXEC: Make sure scripts we exec() (in event.c) don't get our file 
       descriptors. */
	fd = open(eventfile, O_RDONLY | O_CLOEXEC);
	if (fd < 0) {
		if (errno == ENOENT) {
			acpid_log(LOG_DEBUG, "Deprecated %s was not found.  "
				"Trying netlink and the input layer...", eventfile);
		} else {
			acpid_log(LOG_ERR, "can't open %s: %s (%d)", eventfile, 
				strerror(errno), errno);
		}
		return -1;
		
	}
	acpid_log(LOG_DEBUG, "proc fs opened successfully");

	/* add a connection to the list */
	c.fd = fd;
	c.process = process_proc;
	c.pathname = NULL;
	c.kybd = 0;

	if (add_connection(&c) < 0) {
		close(fd);
		acpid_log(LOG_ERR, "can't add connection for %s", eventfile);
		return -1;
	}

	return 0;
}
Exemple #11
0
static char *
read_line(int fd)
{
	static char buf[BUFLEN];
	int i = 0;
	int r;
	int searching = 1;

	while (searching) {
		memset(buf+i, 0, BUFLEN-i);

		/* only go to BUFLEN-1 so there will always be a 0 at the end */
		while (i < BUFLEN-1) {
			r = TEMP_FAILURE_RETRY(read(fd, buf+i, 1));
			if (r < 0) {
				/* we should do something with the data */
				acpid_log(LOG_ERR, "read(): %s",
					strerror(errno));
				return NULL;
			} else if (r == 0) {
				/* signal this in an almost standard way */
				errno = EPIPE;
				return NULL;
			} else if (r == 1) {
				/* scan for a newline */
				if (buf[i] == '\n') {
					searching = 0;
					buf[i] = '\0';
					break;
				}
				i++;
			}
		}
		if (i >= BUFLEN - 1)
			break;
	}

	return buf;
}
Exemple #12
0
void
add_connection(struct connection *p)
{
	if (nconnections < 0)
		return;
	if (nconnections >= MAX_CONNECTIONS) {
		acpid_log(LOG_ERR, "Too many connections.\n");
		/* ??? This routine should return -1 in this situation so that */
		/*   callers can clean up any open fds and whatnot.  */
		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);
}
Exemple #13
0
/* set up the socket for client connections */
void
open_sock()
{
	int fd;
	struct connection c;

	/* if this is a socket passed in via stdin by systemd */
	if (is_socket(STDIN_FILENO)) {
		fd = STDIN_FILENO;
		/* ??? Move CLOEXEC and NONBLOCK settings below up to here? */
	} else {
		/* create our own socket */
		fd = ud_create_socket(socketfile, socketmode);
		if (fd < 0) {
			acpid_log(LOG_ERR, "can't open socket %s: %s",
				socketfile, strerror(errno));
			exit(EXIT_FAILURE);
		}

		/* if we need to change the socket's group, do so */
		if (socketgroup) {
			struct group *gr;
			struct stat buf;

		    gr = getgrnam(socketgroup);
			if (!gr) {
				acpid_log(LOG_ERR, "group %s does not exist", socketgroup);
				exit(EXIT_FAILURE);
			}
			if (fstat(fd, &buf) < 0) {
				acpid_log(LOG_ERR, "can't stat %s: %s", 
		            socketfile, strerror(errno));
				exit(EXIT_FAILURE);
			}
			/* ??? I've tried using fchown(), however it doesn't work here.
			 *     It also doesn't work before bind().  The GNU docs seem to
			 *     indicate it isn't supposed to work with sockets. */
			/* if (fchown(fd, buf.st_uid, gr->gr_gid) < 0) { */
			if (chown(socketfile, buf.st_uid, gr->gr_gid) < 0) {
				acpid_log(LOG_ERR, "can't chown %s: %s", 
		            socketfile, strerror(errno));
				exit(EXIT_FAILURE);
			}
		}
	}

	/* Don't leak fds when execing.
	 * ud_create_socket() already does this, but there is no guarantee that
	 * a socket sent in via STDIN will have this set. */
	if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
		close(fd);
		acpid_log(LOG_ERR, "fcntl() on socket %s for FD_CLOEXEC: %s", 
		          socketfile, strerror(errno));
		return;
	}

	/* Avoid a potential hang.
	 * ud_create_socket() already does this, but there is no guarantee that
	 * a socket sent in via STDIN will have this set. */
	if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
		close(fd);
		acpid_log(LOG_ERR, "fcntl() on socket %s for O_NONBLOCK: %s", 
		          socketfile, strerror(errno));
		return;
	}
	
	/* add a connection to the list */
	c.fd = fd;
	c.process = process_sock;
	c.pathname = NULL;
	c.kybd = 0;

	if (add_connection(&c) < 0) {
		close(fd);
		acpid_log(LOG_ERR, "can't add connection for socket %s",
		          socketfile);
		return;
	}
}
Exemple #14
0
static void
format_netlink(struct nlmsghdr *msg)
{
	struct rtattr *tb[ACPI_GENL_ATTR_MAX + 1];
	struct genlmsghdr *ghdr = NLMSG_DATA(msg);
	int len;
	struct rtattr *attrs;
	
	len = msg->nlmsg_len;
	
	/* if this message doesn't have the proper family ID, drop it */
	if (msg->nlmsg_type != acpi_ids_getfamily()) {
		if (logevents) {
			acpid_log(LOG_INFO, "wrong netlink family ID.\n");
		}
		return;
	}

	len -= NLMSG_LENGTH(GENL_HDRLEN);

	if (len < 0) {
		acpid_log(LOG_WARNING,
			"wrong netlink controller message len: %d\n", len);
		return;
	}

	attrs = (struct rtattr *)((char *)ghdr + GENL_HDRLEN);
	/* parse the attributes in this message */
	parse_rtattr(tb, ACPI_GENL_ATTR_MAX, attrs, len);

	/* if there's an ACPI event attribute... */
	if (tb[ACPI_GENL_ATTR_EVENT]) {
		/* get the actual event struct */
		struct acpi_genl_event *event =
				RTA_DATA(tb[ACPI_GENL_ATTR_EVENT]);
		char buf[64];

		/* format it */
		snprintf(buf, sizeof(buf), "%s %s %08x %08x",
			event->device_class, event->bus_id, event->type, event->data);

		/* if we're locked, don't process the event */
		if (locked()) {
			if (logevents) {
				acpid_log(LOG_INFO,
					"lockfile present, not processing "
					"netlink event \"%s\"\n", buf);
			}
			return;
		}

		if (logevents)
			acpid_log(LOG_INFO,
				"received netlink event \"%s\"\n", buf);

		/* send the event off to the handler */
		acpid_handle_event(buf);

		if (logevents)
			acpid_log(LOG_INFO,
				"completed netlink event \"%s\"\n", buf);
	}
}
Exemple #15
0
/* (based on rtnl_listen() in libnetlink.c) */
void
process_netlink(int fd)
{
	int status;
	struct nlmsghdr *h;
	/* the address for recvmsg() */
	struct sockaddr_nl nladdr;
	/* the io vector for recvmsg() */
	struct iovec iov;
	/* recvmsg() parameters */
	struct msghdr msg = {
		.msg_name = &nladdr,
		.msg_namelen = sizeof(nladdr),
		.msg_iov = &iov,
		.msg_iovlen = 1,
	};
	/* buffer for the incoming data */
	char buf[8192];
	static int nerrs;

	/* set up the netlink address */
	memset(&nladdr, 0, sizeof(nladdr));
	nladdr.nl_family = AF_NETLINK;
	nladdr.nl_pid = 0;
	nladdr.nl_groups = 0;

	/* set up the I/O vector */
	iov.iov_base = buf;
	iov.iov_len = sizeof(buf);
	
	/* read the data into the buffer */
	status = recvmsg(fd, &msg, 0);

	/* if there was a problem, print a message and keep trying */
	if (status < 0) {
		/* if we were interrupted by a signal, bail */
		if (errno == EINTR)
			return;
		
		acpid_log(LOG_ERR, "netlink read error: %s (%d)\n",
			strerror(errno), errno);
		if (++nerrs >= ACPID_MAX_ERRS) {
			acpid_log(LOG_ERR,
				"too many errors reading via "
				"netlink - aborting\n");
			exit(EXIT_FAILURE);
		}
		return;
	}
	/* if an orderly shutdown has occurred, we're done */
	if (status == 0) {
		acpid_log(LOG_WARNING, "netlink connection closed\n");
		exit(EXIT_FAILURE);
	}
	/* check to see if the address length has changed */
	if (msg.msg_namelen != sizeof(nladdr)) {
		acpid_log(LOG_WARNING, "netlink unexpected length: "
			"%d   expected: %d\n", msg.msg_namelen, sizeof(nladdr));
		return;
	}
	
	/* for each message received */
	for (h = (struct nlmsghdr*)buf; (unsigned)status >= sizeof(*h); ) {
		int len = h->nlmsg_len;
		int l = len - sizeof(*h);

		if (l < 0  ||  len > status) {
			if (msg.msg_flags & MSG_TRUNC) {
				acpid_log(LOG_WARNING, "netlink msg truncated (1)\n");
				return;
			}
			acpid_log(LOG_WARNING,
				"malformed netlink msg, length %d\n", len);
			return;
		}

		/* format the message */
		format_netlink(h);

		status -= NLMSG_ALIGN(len);
		h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
	}
	if (msg.msg_flags & MSG_TRUNC) {
		acpid_log(LOG_WARNING, "netlink msg truncated (2)\n");
		return;
	}
	if (status) {
		acpid_log(LOG_WARNING, "netlink remnant of size %d\n", status);
		return;
	}

	return;
}

/* convert the netlink multicast group number into a bit map */
/* (e.g. 4 => 16, 5 => 32) */
static __u32
nl_mgrp(__u32 group)
{
	if (group > 31) {
		acpid_log(LOG_ERR, "Unexpected group number %d\n", group);
		return 0;
	}
	return group ? (1 << (group - 1)) : 0;
}

void open_netlink(void)
{
	struct rtnl_handle rth;
	struct connection c;

	/* open the appropriate netlink socket for input */
	if (rtnl_open_byproto(
		&rth, nl_mgrp(acpi_ids_getgroup()), NETLINK_GENERIC) < 0) {
		acpid_log(LOG_ERR, "cannot open generic netlink socket\n");
		return;
	}

	acpid_log(LOG_DEBUG, "netlink opened successfully\n");

	/* add a connection to the list */
	c.fd = rth.fd;
	c.process = process_netlink;
	add_connection(&c);
}
Exemple #16
0
int
main(int argc, char **argv)
{
	int event_fd;
	int sock_fd = -1; /* init to avoid a compiler warning */

	/* learn who we really are */
	progname = (const char *)strrchr(argv[0], '/');
	progname = progname ? (progname + 1) : argv[0];

	/* handle the commandline  */
	handle_cmdline(&argc, &argv);

	/* close any extra file descriptors */
	close_fds();

	/* actually open the event file */
	event_fd = open(eventfile, O_RDONLY);
	if (event_fd < 0) {
		fprintf(stderr, "%s: can't open %s: %s\n", progname, 
			eventfile, strerror(errno));
		exit(EXIT_FAILURE);
	}
	fcntl(event_fd, F_SETFD, FD_CLOEXEC);

/*
 * if there is data, and the kernel is NOT broken, this eats 1 byte.  We
 * can't have that.  This is ifdef'ed out on the assumption that old kernels
 * are out of popular use, by now.
 */
#ifdef TEST_FOR_BAD_KERNELS
	/*
	 * Older kernels did not support read() properly or poll() at all
	 * Check that the kernel supports the proper semantics, or die.
	 *
	 * Good kernels will respect O_NONBLOCK and return -1.  Bad kernels
	 * will ignore O_NONBLOCK and return 0.  Really bad kernels will block
	 * and overflow the buffer.  Can't deal with the really bad ones.
	 */
	{
		int fl;
		char buf;

		fl = fcntl(event_fd, F_GETFL);
		fcntl(event_fd, F_SETFL, fl | O_NONBLOCK);
		if (read(event_fd, &buf, 1) == 0) {
			fprintf(stderr, 
				"%s: this kernel does not support proper "
				"event file handling.\n"
				"Please get the patch from "
				"http://acpid.sourceforge.net\n", 
				progname);
			exit(EXIT_FAILURE);
		}
		fcntl(event_fd, F_SETFL, fl);
	}
#endif

	/* open our socket */
	if (!nosocket) {
		sock_fd = ud_create_socket(socketfile);
		if (sock_fd < 0) {
			fprintf(stderr, "%s: can't open socket %s: %s\n",
				progname, socketfile, strerror(errno));
			exit(EXIT_FAILURE);
		}
		fcntl(sock_fd, F_SETFD, FD_CLOEXEC);
		chmod(socketfile, socketmode);
		if (socketgroup) {
			struct group *gr;
			struct stat buf;
			gr = getgrnam(socketgroup);
			if (!gr) {
				fprintf(stderr, "%s: group %s does not exist\n",
					progname, socketgroup);
				exit(EXIT_FAILURE);
			}
			if (stat(socketfile, &buf) < 0) {
				fprintf(stderr, "%s: can't stat %s\n",
					progname, socketfile);
				exit(EXIT_FAILURE);
			}
			if (chown(socketfile, buf.st_uid, gr->gr_gid) < 0) {
				fprintf(stderr, "%s: chown(): %s\n",
					progname, strerror(errno));
				exit(EXIT_FAILURE);
			}
		}
	}

	/* if we're running in foreground, we don't daemonize */
	if (!foreground) {
		if (daemonize() < 0)
			exit(EXIT_FAILURE);
	}

	/* open the log */
	if (open_log() < 0) {
		exit(EXIT_FAILURE);
	}
	acpid_log(LOG_INFO, "starting up\n");

	/* trap key signals */
	signal(SIGHUP, reload_conf);
	signal(SIGINT, clean_exit);
	signal(SIGQUIT, clean_exit);
	signal(SIGTERM, clean_exit);
	signal(SIGPIPE, SIG_IGN);

	/* read in our configuration */
	if (acpid_read_conf(confdir)) {
		exit(EXIT_FAILURE);
	}

	/* create our pidfile */
	if (create_pidfile() < 0) {
		exit(EXIT_FAILURE);
	}

	/* main loop */
	acpid_log(LOG_INFO, "waiting for events: event logging is %s\n",
	    logevents ? "on" : "off");
	while (1) {
		struct pollfd ar[2];
		int r;
		int fds = 0;

		/* poll for the socket and the event file */
		ar[0].fd = event_fd; ar[0].events = POLLIN; fds++;
		if (!nosocket) {
			ar[1].fd = sock_fd; ar[1].events = POLLIN; fds++;
		}
		r = poll(ar, fds, -1);

		if (r < 0 && errno == EINTR) {
			continue;
		} else if (r < 0) {
			acpid_log(LOG_ERR, "poll(): %s\n", strerror(errno));
			continue;
		}

		/* house keeping */
		acpid_close_dead_clients();

		/* was it an event? */
		if (ar[0].revents) {
			char *event;
			struct stat trash;
			int fexists;

			/* check for existence of a lockfile */
			fexists = (stat(lockfile, &trash) == 0);

			/* this shouldn't happen */
			if (!ar[0].revents & POLLIN) {
				acpid_log(LOG_DEBUG,
				    "odd, poll set flags 0x%x\n",
				    ar[0].revents);
				continue;
			}

			/* read an event */
			event = read_line(event_fd);

			/* if we're locked, don't process the event */
			if (fexists) {
				if (logevents) {
					acpid_log(LOG_INFO,
					    "lockfile present, not processing "
					    "event \"%s\"\n", event);
				}
				continue;
			}

			/* handle the event */
			if (event) {
				if (logevents) {
					acpid_log(LOG_INFO,
					    "received event \"%s\"\n", event);
				}
				acpid_handle_event(event);
				if (logevents) {
					acpid_log(LOG_INFO,
					    "completed event \"%s\"\n", event);
				}
			} else if (errno == EPIPE) {
				acpid_log(LOG_WARNING,
				    "events file connection closed\n");
				break;
			} else {
				static int nerrs;
				if (++nerrs >= ACPID_MAX_ERRS) {
					acpid_log(LOG_ERR,
					    "too many errors reading "
					    "events file - aborting\n");
					break;
				}
			}
		}

		/* was it a new connection? */
		if (!nosocket && ar[1].revents) {
			int cli_fd;
			struct ucred creds;
			char buf[32];
			static int accept_errors;

			/* this shouldn't happen */
			if (!ar[1].revents & POLLIN) {
				acpid_log(LOG_DEBUG,
				    "odd, poll set flags 0x%x\n",
				    ar[1].revents);
				continue;
			}

			/* accept and add to our lists */
			cli_fd = ud_accept(sock_fd, &creds);
			if (cli_fd < 0) {
				acpid_log(LOG_ERR, "can't accept client: %s\n",
				    strerror(errno));
				accept_errors++;
				if (accept_errors >= 5) {
					acpid_log(LOG_ERR, "giving up\n");
					clean_exit_with_status(EXIT_FAILURE);
				}
				continue;
			}
			accept_errors = 0;
			if (creds.uid != 0 && non_root_clients >= clientmax) {
				close(cli_fd);
				acpid_log(LOG_ERR,
				    "too many non-root clients\n");
				continue;
			}
			if (creds.uid != 0) {
				non_root_clients++;
			}
			fcntl(cli_fd, F_SETFD, FD_CLOEXEC);
			snprintf(buf, sizeof(buf)-1, "%d[%d:%d]",
				creds.pid, creds.uid, creds.gid);
			acpid_add_client(cli_fd, buf);
		}
	}

	clean_exit_with_status(EXIT_SUCCESS);

	return 0;
}
/* called when an inotify event is received */
static void process_inotify(int fd)
{
	int bytes;
	/* union to avoid strict-aliasing problems */
	union {
		char buffer[256];  /* a tad large */
		struct inotify_event event;
	} eventbuf;

	bytes = read(fd, &eventbuf.buffer, sizeof(eventbuf.buffer));

	acpid_log(LOG_DEBUG, "inotify read bytes: %d", bytes);

	/* eof is not expected */	
	if (bytes == 0) {
		acpid_log(LOG_WARNING, "inotify fd eof encountered");
		return;
	}
	else if (bytes < 0) {
		/* EINVAL means buffer wasn't big enough.  See inotify(7). */
		acpid_log(LOG_ERR, "inotify read error: %s (%d)",
			strerror(errno), errno);
		acpid_log(LOG_ERR, "disconnecting from inotify");
		delete_connection(fd);
		return;
	}

	acpid_log(LOG_DEBUG, "inotify name len: %d", eventbuf.event.len);

	const int dnsize = 256;
	char devname[dnsize];

	/* if a name is included */
	if (eventbuf.event.len > 0) {
		/* devname = ACPID_INPUTLAYERDIR + "/" + pevent -> name */
		strcpy(devname, ACPID_INPUTLAYERDIR);
		strcat(devname, "/");
		strncat(devname, eventbuf.event.name, dnsize - strlen(devname) - 1);
	}
		
	/* if this is a create */
	if (eventbuf.event.mask & IN_CREATE) {
		acpid_log(LOG_DEBUG, "inotify about to open: %s", devname);

		open_inputfile(devname);
	}

	/* if this is a delete */
	if (eventbuf.event.mask & IN_DELETE) {
		/* struct connection *c; */
		
		acpid_log(LOG_DEBUG, "inotify received a delete for: %s", devname);

#if 0
/* Switching back to the original ENODEV detection scheme.  See 
   process_input() in input_layer.c. */
/* keeping this for future reference */
		/* search for the event file in the connection list */
		/* ??? Or should we just have a delete_connection_name()? */
		c = find_connection_name(devname);
		
		/* close that connection if found */
		if (c)
			delete_connection(c->fd);
#endif
	}
}