00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <sys/types.h>
00023 #include <sys/stat.h>
00024 #include <fcntl.h>
00025 #include <signal.h>
00026 #include <unistd.h>
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include <errno.h>
00031 #include <getopt.h>
00032 #include <time.h>
00033 #include <sys/poll.h>
00034 #include <grp.h>
00035
00036 #include "acpid.h"
00037 #include "ud_socket.h"
00038
00039 static int handle_cmdline(int *argc, char ***argv);
00040 static void close_fds(void);
00041 static int daemonize(void);
00042 static int open_logs(void);
00043 static void clean_exit(int sig);
00044 static void reload_conf(int sig);
00045 static char *read_line(int fd);
00046
00047
00048 int acpid_debug;
00049
00050 static const char *progname;
00051 static const char *confdir = ACPI_CONFDIR;
00052 static const char *logfile = ACPI_LOGFILE;
00053 static const char *eventfile = ACPI_EVENTFILE;
00054 static const char *socketfile = ACPI_SOCKETFILE;
00055 static int nosocket;
00056 static const char *socketgroup;
00057 static mode_t socketmode = ACPI_SOCKETMODE;
00058 static int foreground;
00059
00060 int
00061 main(int argc, char **argv)
00062 {
00063 int event_fd;
00064 int sock_fd;
00065
00066
00067 progname = (const char *)strrchr(argv[0], '/');
00068 progname = progname ? (progname + 1) : argv[0];
00069
00070
00071 handle_cmdline(&argc, &argv);
00072
00073
00074 close_fds();
00075
00076
00077 event_fd = open(eventfile, O_RDONLY);
00078 if (event_fd < 0) {
00079 fprintf(stderr, "%s: can't open %s: %s\n", progname,
00080 eventfile, strerror(errno));
00081 exit(EXIT_FAILURE);
00082 }
00083 fcntl(event_fd, F_SETFD, FD_CLOEXEC);
00084
00085
00086
00087
00088
00089
00090 #ifdef TEST_FOR_BAD_KERNELS
00091
00092
00093
00094
00095
00096
00097
00098
00099 {
00100 int fl;
00101 char buf;
00102
00103 fl = fcntl(event_fd, F_GETFL);
00104 fcntl(event_fd, F_SETFL, fl | O_NONBLOCK);
00105 if (read(event_fd, &buf, 1) == 0) {
00106 fprintf(stderr,
00107 "%s: this kernel does not support proper "
00108 "event file handling.\n"
00109 "Please get the patch from "
00110 "http://acpid.sourceforge.net\n",
00111 progname);
00112 exit(EXIT_FAILURE);
00113 }
00114 fcntl(event_fd, F_SETFL, fl);
00115 }
00116 #endif
00117
00118
00119 if (!nosocket) {
00120 sock_fd = ud_create_socket(socketfile);
00121 if (sock_fd < 0) {
00122 fprintf(stderr, "%s: can't open socket %s: %s\n",
00123 progname, socketfile, strerror(errno));
00124 exit(EXIT_FAILURE);
00125 }
00126 fcntl(sock_fd, F_SETFD, FD_CLOEXEC);
00127 chmod(socketfile, socketmode);
00128 if (socketgroup) {
00129 struct group *gr;
00130 struct stat buf;
00131 gr = getgrnam(socketgroup);
00132 if (!gr) {
00133 fprintf(stderr, "%s: group %s does not exist\n",
00134 progname, socketgroup);
00135 exit(EXIT_FAILURE);
00136 }
00137 if (stat(socketfile, &buf) < 0) {
00138 fprintf(stderr, "%s: can't stat %s\n",
00139 progname, socketfile);
00140 exit(EXIT_FAILURE);
00141 }
00142 if (chown(socketfile, buf.st_uid, gr->gr_gid) < 0) {
00143 fprintf(stderr, "%s: chown(): %s\n",
00144 progname, strerror(errno));
00145 exit(EXIT_FAILURE);
00146 }
00147 }
00148 }
00149
00150
00151 if (!foreground) {
00152 if (daemonize() < 0)
00153 exit(EXIT_FAILURE);
00154 }
00155
00156
00157 if (!acpid_debug) {
00158 if (open_logs() < 0)
00159 exit(EXIT_FAILURE);
00160 }
00161 acpid_log("starting up\n");
00162
00163
00164 signal(SIGHUP, reload_conf);
00165 signal(SIGINT, clean_exit);
00166 signal(SIGQUIT, clean_exit);
00167 signal(SIGTERM, clean_exit);
00168 signal(SIGPIPE, SIG_IGN);
00169
00170
00171 acpid_read_conf(confdir);
00172
00173
00174 while (1) {
00175 struct pollfd ar[2];
00176 int r;
00177 int fds = 0;
00178
00179
00180 ar[0].fd = event_fd; ar[0].events = POLLIN; fds++;
00181 if (!nosocket) {
00182 ar[1].fd = sock_fd; ar[1].events = POLLIN; fds++;
00183 }
00184 r = poll(ar, fds, -1);
00185
00186 if (r < 0 && errno == EINTR) {
00187 continue;
00188 } else if (r < 0) {
00189 acpid_log("ERR: poll(): %s\n", strerror(errno));
00190 continue;
00191 }
00192
00193
00194 if (ar[0].revents) {
00195 char *event;
00196
00197
00198 if (!ar[0].revents & POLLIN) {
00199 acpid_log("odd, poll set flags 0x%x\n",
00200 ar[0].revents);
00201 continue;
00202 }
00203
00204
00205 event = read_line(event_fd);
00206 if (event) {
00207 acpid_log("received event \"%s\"\n", event);
00208 acpid_handle_event(event);
00209 acpid_log("completed event \"%s\"\n", event);
00210 } else if (errno == EPIPE) {
00211 acpid_log("events file connection closed\n");
00212 break;
00213 } else {
00214 static int nerrs;
00215 if (++nerrs >= ACPI_MAX_ERRS) {
00216 acpid_log("too many errors reading "
00217 "events file - aborting\n");
00218 break;
00219 }
00220 }
00221 }
00222
00223
00224 if (!nosocket && ar[1].revents) {
00225 int cli_fd;
00226 struct ucred creds;
00227 char buf[32];
00228
00229
00230 if (!ar[1].revents & POLLIN) {
00231 acpid_log("odd, poll set flags 0x%x\n",
00232 ar[1].revents);
00233 continue;
00234 }
00235
00236
00237 cli_fd = ud_accept(sock_fd, &creds);
00238 if (cli_fd < 0) {
00239 acpid_log("ERR: can't accept client: %s\n",
00240 strerror(errno));
00241 continue;
00242 }
00243 snprintf(buf, sizeof(buf)-1, "%d[%d:%d]",
00244 creds.pid, creds.uid, creds.gid);
00245 acpid_add_client(cli_fd, buf);
00246 }
00247 }
00248
00249 clean_exit(EXIT_SUCCESS);
00250
00251 return 0;
00252 }
00253
00254
00255
00256
00257 static int
00258 handle_cmdline(int *argc, char ***argv)
00259 {
00260 struct option opts[] = {
00261 {"confdir", 1, 0, 'c'},
00262 {"debug", 0, 0, 'd'},
00263 {"eventfile", 1, 0, 'e'},
00264 {"foreground", 0, 0, 'f'},
00265 {"socketgroup", 1, 0, 'g'},
00266 {"logfile", 1, 0, 'l'},
00267 {"socketmode", 1, 0, 'm'},
00268 {"socketfile", 1, 0, 's'},
00269 {"nosocket", 1, 0, 'S'},
00270 {"version", 0, 0, 'v'},
00271 {"help", 0, 0, 'h'},
00272 {NULL, 0, 0, 0},
00273 };
00274 const char *opts_help[] = {
00275 "Set the configuration directory.",
00276 "Increase debugging level (implies -f).",
00277 "Use the specified file for events.",
00278 "Run in the foreground.",
00279 "Set the group on the socket file.",
00280 "Use the specified log file.",
00281 "Set the permissions on the socket file.",
00282 "Use the specified socket file.",
00283 "Do not listen on a UNIX socket (overrides -s).",
00284 "Print version information.",
00285 "Print this message.",
00286 };
00287 struct option *opt;
00288 const char **hlp;
00289 int max, size;
00290
00291 for (;;) {
00292 int i;
00293 i = getopt_long(*argc, *argv, "c:de:fg:l:m:s:Svh", opts, NULL);
00294 if (i == -1) {
00295 break;
00296 }
00297 switch (i) {
00298 case 'c':
00299 confdir = optarg;
00300 break;
00301 case 'd':
00302 foreground = 1;
00303 acpid_debug++;
00304 break;
00305 case 'e':
00306 eventfile = optarg;
00307 break;
00308 case 'f':
00309 foreground = 1;
00310 break;
00311 case 'g':
00312 socketgroup = optarg;
00313 break;
00314 case 'l':
00315 logfile = optarg;
00316 break;
00317 case 'm':
00318 socketmode = strtol(optarg, NULL, 8);
00319 break;
00320 case 's':
00321 socketfile = optarg;
00322 break;
00323 case 'S':
00324 nosocket = 1;
00325 break;
00326 case 'v':
00327 printf(PACKAGE "-" VERSION "\n");
00328 exit(EXIT_SUCCESS);
00329 case 'h':
00330 default:
00331 fprintf(stderr, "Usage: %s [OPTIONS]\n", progname);
00332 max = 0;
00333 for (opt = opts; opt->name; opt++) {
00334 size = strlen(opt->name);
00335 if (size > max)
00336 max = size;
00337 }
00338 for (opt = opts, hlp = opts_help;
00339 opt->name;
00340 opt++, hlp++)
00341 {
00342 fprintf(stderr, " -%c, --%s",
00343 opt->val, opt->name);
00344 size = strlen(opt->name);
00345 for (; size < max; size++)
00346 fprintf(stderr, " ");
00347 fprintf(stderr, " %s\n", *hlp);
00348 }
00349 exit(EXIT_FAILURE);
00350 break;
00351 }
00352 }
00353
00354 *argc -= optind;
00355 *argv += optind;
00356
00357 return 0;
00358 }
00359
00360 static void
00361 close_fds(void)
00362 {
00363 int fd, max;
00364 max = sysconf(_SC_OPEN_MAX);
00365 for (fd = 3; fd < max; fd++)
00366 close(fd);
00367 }
00368
00369 static int
00370 daemonize(void)
00371 {
00372 switch(fork()) {
00373 case -1:
00374 fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
00375 return -1;
00376 case 0:
00377
00378 break;
00379 default:
00380
00381 exit(EXIT_SUCCESS);
00382 }
00383
00384
00385 setsid();
00386 umask(0);
00387
00388
00389 chdir("/");
00390
00391 return 0;
00392 }
00393
00394 static int
00395 open_logs(void)
00396 {
00397 int logfd;
00398 int nullfd;
00399
00400
00401 nullfd = open("/dev/null", O_RDONLY, 0640);
00402 if (nullfd < 0) {
00403 fprintf(stderr, "%s: can't open %s: %s\n", progname,
00404 "/dev/null", strerror(errno));
00405 return -1;
00406 }
00407 logfd = open(logfile, O_WRONLY|O_CREAT|O_APPEND);
00408 if (logfd < 0) {
00409 fprintf(stderr, "%s: can't open %s: %s\n", progname,
00410 logfile, strerror(errno));
00411 return -1;
00412 }
00413
00414 if (dup2(nullfd, STDIN_FILENO) != STDIN_FILENO) {
00415 fprintf(stderr, "%s: dup2: %s\n", progname, strerror(errno));
00416 return -1;
00417 }
00418 if (dup2(logfd, STDOUT_FILENO) != STDOUT_FILENO) {
00419 fprintf(stderr, "%s: dup2: %s\n", progname, strerror(errno));
00420 return -1;
00421 }
00422 if (dup2(logfd, STDERR_FILENO) != STDERR_FILENO) {
00423 fprintf(stderr, "%s: dup2: %s\n", progname, strerror(errno));
00424 return -1;
00425 }
00426
00427 close(nullfd);
00428 close(logfd);
00429
00430 return 0;
00431 }
00432
00433 static void
00434 clean_exit(int sig)
00435 {
00436 acpid_cleanup_rules();
00437 acpid_log("exiting\n");
00438 exit(EXIT_SUCCESS);
00439 }
00440
00441 static void
00442 reload_conf(int sig)
00443 {
00444 acpid_log("reloading configuration\n");
00445 acpid_cleanup_rules();
00446 acpid_read_conf(confdir);
00447 }
00448
00449 int
00450 acpid_log(const char *fmt, ...)
00451 {
00452 va_list args;
00453 int len = 0;
00454 time_t curtime;
00455 char *timestr;
00456
00457 va_start(args, fmt);
00458 curtime = time(NULL);
00459 timestr = ctime(&curtime);
00460 timestr[strlen(timestr)-1] = '\0';
00461 len += fprintf(stderr, "[%s] ", timestr);
00462 len += vfprintf(stderr, fmt, args);
00463 va_end(args);
00464
00465 return 0;
00466 }
00467
00468
00469
00470
00471 #define MAX_BUFLEN 1024
00472 static char *
00473 read_line(int fd)
00474 {
00475 static char *buf;
00476 int buflen = 64;
00477 int i = 0;
00478 int r;
00479 int searching = 1;
00480
00481 while (searching) {
00482 buf = realloc(buf, buflen);
00483 if (!buf) {
00484 acpid_log("ERR: malloc(%d): %s\n",
00485 buflen, strerror(errno));
00486 return NULL;
00487 }
00488 memset(buf+i, 0, buflen-i);
00489
00490 while (i < buflen) {
00491 r = read(fd, buf+i, 1);
00492 if (r < 0 && errno != EINTR) {
00493
00494 acpid_log("ERR: read(): %s\n",
00495 strerror(errno));
00496 return NULL;
00497 } else if (r == 0) {
00498
00499 errno = EPIPE;
00500 return NULL;
00501 } else if (r == 1) {
00502
00503 if (buf[i] == '\n') {
00504 searching = 0;
00505 buf[i] = '\0';
00506 break;
00507 }
00508 i++;
00509 }
00510 }
00511 if (buflen >= MAX_BUFLEN) {
00512 break;
00513 }
00514 buflen *= 2;
00515 }
00516
00517 return buf;
00518 }