2 * acpid.c - ACPI daemon
4 * Portions Copyright (C) 2000 Andrew Henroid
5 * Portions Copyright (C) 2001 Sun Microsystems
6 * Portions Copyright (C) 2004 Tim Hockin (thockin@hockin.org)
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include <sys/types.h>
37 #include "connection_list.h"
40 #include "input_layer.h"
41 #include "inotify_handler.h"
44 static int handle_cmdline(int *argc, char ***argv);
45 static void close_fds(void);
46 static int daemonize(void);
47 static void open_log(void);
48 static int std2null(void);
49 static int create_pidfile(void);
50 static void clean_exit(int sig);
51 static void reload_conf(int sig);
53 /* global debug level */
56 /* do we log event info? */
60 static const char *confdir = ACPID_CONFDIR;
61 static const char *lockfile = ACPID_LOCKFILE;
63 static int foreground;
64 static const char *pidfile = ACPID_PIDFILE;
68 main(int argc, char **argv)
70 /* learn who we really are */
71 progname = (const char *)strrchr(argv[0], '/');
72 progname = progname ? (progname + 1) : argv[0];
74 /* handle the commandline */
75 handle_cmdline(&argc, &argv);
77 /* close any extra file descriptors */
84 /* open the acpi event file in the proc fs */
85 /* if the open fails, try netlink */
91 /* open the input layer */
94 /* watch for new input layer devices */
101 /* open our socket */
106 /* if we're running in the background, and we're not being started */
108 if (!foreground && !is_socket(STDIN_FILENO)) {
113 /* redirect standard files to /dev/null */
114 if (std2null() < 0) {
118 acpid_log(LOG_INFO, "starting up with %s",
119 netlink ? "netlink and the input layer" : "proc fs");
121 /* trap key signals */
122 signal(SIGHUP, reload_conf);
123 signal(SIGINT, clean_exit);
124 signal(SIGQUIT, clean_exit);
125 signal(SIGTERM, clean_exit);
126 signal(SIGPIPE, SIG_IGN);
128 /* read in our configuration */
129 if (acpid_read_conf(confdir)) {
133 /* create our pidfile */
134 if (create_pidfile() < 0) {
138 acpid_log(LOG_INFO, "waiting for events: event logging is %s",
139 logevents ? "on" : "off");
146 struct connection *p;
148 /* it's going to get clobbered, so use a copy */
149 readfds = *get_fdset();
152 nready = select(get_highestfd() + 1, &readfds, NULL, NULL, NULL);
154 if (nready < 0 && errno == EINTR) {
156 } else if (nready < 0) {
157 acpid_log(LOG_ERR, "select(): %s", strerror(errno));
162 acpid_close_dead_clients();
164 /* for each connection */
165 for (i = 0; i <= get_number_of_connections(); ++i) {
168 p = get_connection(i);
170 /* if this connection is invalid, bail */
174 /* get the file descriptor */
177 /* if this file descriptor has data waiting */
178 if (FD_ISSET(fd, &readfds)) {
179 /* delegate to this connection's process function */
185 clean_exit_with_status(EXIT_SUCCESS);
191 * Parse command line arguments
194 handle_cmdline(int *argc, char ***argv)
196 struct option opts[] = {
197 {"confdir", 1, 0, 'c'},
198 {"clientmax", 1, 0, 'C'},
199 {"debug", 0, 0, 'd'},
200 {"eventfile", 1, 0, 'e'},
201 {"foreground", 0, 0, 'f'},
202 {"logevents", 0, 0, 'l'},
203 {"socketgroup", 1, 0, 'g'},
204 {"socketmode", 1, 0, 'm'},
205 {"socketfile", 1, 0, 's'},
206 {"nosocket", 1, 0, 'S'},
207 {"pidfile", 1, 0, 'p'},
208 {"lockfile", 1, 0, 'L'},
209 {"netlink", 0, 0, 'n'},
210 {"version", 0, 0, 'v'},
214 const char *opts_help[] = {
215 "Set the configuration directory.", /* confdir */
216 "Set the limit on non-root socket connections.",/* clientmax */
217 "Increase debugging level (implies -f).",/* debug */
218 "Use the specified file for events.", /* eventfile */
219 "Run in the foreground.", /* foreground */
220 "Log all event activity.", /* logevents */
221 "Set the group on the socket file.", /* socketgroup */
222 "Set the permissions on the socket file.",/* socketmode */
223 "Use the specified socket file.", /* socketfile */
224 "Do not listen on a UNIX socket (overrides -s).",/* nosocket */
225 "Use the specified PID file.", /* pidfile */
226 "Use the specified lockfile to stop processing.", /* lockfile */
227 "Force netlink/input layer mode. (overrides -e)", /* netlink */
228 "Print version information.", /* version */
229 "Print this message.", /* help */
237 i = getopt_long(*argc, *argv,
238 "c:C:de:flg:m:s:Sp:L:nvh", opts, NULL);
247 clientmax = strtol(optarg, NULL, 0);
252 log_debug_to_stderr = 1;
264 socketgroup = optarg;
267 socketmode = strtol(optarg, NULL, 8);
285 printf(PACKAGE "-" VERSION "\n");
289 fprintf(stderr, "Usage: %s [OPTIONS]\n", progname);
291 for (opt = opts; opt->name; opt++) {
292 size = strlen(opt->name);
296 for (opt = opts, hlp = opts_help;
299 fprintf(stderr, " -%c, --%s",
300 opt->val, opt->name);
301 size = strlen(opt->name);
302 for (; size < max; size++)
303 fprintf(stderr, " ");
304 fprintf(stderr, " %s\n", *hlp);
321 max = sysconf(_SC_OPEN_MAX);
322 for (fd = 3; fd < max; fd++)
331 /* fork off the parent process */
334 acpid_log(LOG_ERR, "fork: %s", strerror(errno));
337 /* if we got a good PID, then we can exit the parent process */
342 /* at this point we are executing as the child process */
344 /* change the umask to something predictable instead of inheriting */
345 /* whatever from the parent */
348 /* create a new SID for the child process and */
349 /* detach the process from the parent (normally a shell) */
352 acpid_log(LOG_ERR, "setsid: %s", strerror(errno));
356 /* Change the current working directory. This prevents the current
357 directory from being locked; hence not being able to remove it. */
358 if (chdir("/") < 0) {
359 acpid_log(LOG_ERR, "chdir(\"/\"): %s", strerror(errno));
371 /* open the syslog */
372 log_opts = LOG_CONS|LOG_NDELAY;
374 log_opts |= LOG_PERROR;
376 openlog(PACKAGE, log_opts, LOG_DAEMON);
385 nullfd = open("/dev/null", O_RDWR);
387 acpid_log(LOG_ERR, "can't open /dev/null: %s", strerror(errno));
391 /* set up stdin, stdout, stderr to /dev/null */
393 /* don't redirect stdin if we're being sent a socket by systemd */
394 if (!is_socket(STDIN_FILENO) &&
395 dup2(nullfd, STDIN_FILENO) != STDIN_FILENO) {
396 acpid_log(LOG_ERR, "dup2() stdin: %s", strerror(errno));
399 if (!acpid_debug && dup2(nullfd, STDOUT_FILENO) != STDOUT_FILENO) {
400 acpid_log(LOG_ERR, "dup2() stdout: %s", strerror(errno));
403 if (!acpid_debug && dup2(nullfd, STDERR_FILENO) != STDERR_FILENO) {
404 acpid_log(LOG_ERR, "dup2() stderr: %s", strerror(errno));
421 /* open the pidfile */
422 fd = open(pidfile, O_WRONLY|O_CREAT|O_EXCL, 0644);
426 /* write our pid to it */
429 fprintf(f, "%d\n", getpid());
431 /* leave the fd open */
437 /* something went wrong */
438 acpid_log(LOG_ERR, "can't create pidfile %s: %s",
439 pidfile, strerror(errno));
444 clean_exit_with_status(int status)
446 acpid_cleanup_rules(1);
447 acpid_log(LOG_NOTICE, "exiting");
453 clean_exit(int sig __attribute__((unused)))
455 clean_exit_with_status(EXIT_SUCCESS);
459 reload_conf(int sig __attribute__((unused)))
461 acpid_log(LOG_NOTICE, "reloading configuration");
462 acpid_cleanup_rules(0);
463 acpid_read_conf(confdir);
471 /* check for existence of a lockfile */
472 return (stat(lockfile, &trash) == 0);