Beispiel #1
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);
		}
	}
}
Beispiel #2
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);
	}
}
Beispiel #3
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;
}