Main Page | Class List | File List | Class Members | File Members

acpid.c

Go to the documentation of this file.
00001 /*
00002  *  acpid.c - ACPI daemon
00003  *
00004  *  Portions Copyright (C) 2000 Andrew Henroid
00005  *  Portions Copyright (C) 2001 Sun Microsystems (thockin@sun.com)
00006  *
00007  *  This program is free software; you can redistribute it and/or modify
00008  *  it under the terms of the GNU General Public License as published by
00009  *  the Free Software Foundation; either version 2 of the License, or
00010  *  (at your option) any later version.
00011  *
00012  *  This program is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *  GNU General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU General Public License
00018  *  along with this program; if not, write to the Free Software
00019  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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 /* global debug level */
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         /* learn who we really are */
00067         progname = (const char *)strrchr(argv[0], '/');
00068         progname = progname ? (progname + 1) : argv[0];
00069 
00070         /* handle the commandline  */
00071         handle_cmdline(&argc, &argv);
00072 
00073         /* close any extra file descriptors */
00074         close_fds();
00075 
00076         /* actually open the event file */
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  * if there is data, and the kernel is NOT broken, this eats 1 byte.  We
00087  * can't have that.  This is ifdef'ed out on the assumption that old kernels
00088  * are out of popular use, by now.
00089  */
00090 #ifdef TEST_FOR_BAD_KERNELS
00091         /*
00092          * Older kernels did not support read() properly or poll() at all
00093          * Check that the kernel supports the proper semantics, or die.
00094          *
00095          * Good kernels will respect O_NONBLOCK and return -1.  Bad kernels
00096          * will ignore O_NONBLOCK and return 0.  Really bad kernels will block
00097          * and overflow the buffer.  Can't deal with the really bad ones.
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         /* open our socket */
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         /* if we're running in foreground, we don't daemonize */
00151         if (!foreground) {
00152                 if (daemonize() < 0)
00153                         exit(EXIT_FAILURE);
00154         }
00155 
00156         /* normal logging unless debugging */
00157         if (!acpid_debug) {
00158                 if (open_logs() < 0)
00159                         exit(EXIT_FAILURE);
00160         }
00161         acpid_log("starting up\n");
00162 
00163         /* trap key signals */
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         /* read in our configuration */
00171         acpid_read_conf(confdir);
00172 
00173         /* main loop */
00174         while (1) {
00175                 struct pollfd ar[2];
00176                 int r;
00177                 int fds = 0;
00178                 
00179                 /* poll for the socket and the event file */
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                 /* was it an event? */
00194                 if (ar[0].revents) {
00195                         char *event;
00196                         
00197                         /* this shouldn't happen */
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                         /* read and handle an event */
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                 /* was it a new connection? */
00224                 if (!nosocket && ar[1].revents) {
00225                         int cli_fd;
00226                         struct ucred creds;
00227                         char buf[32];
00228 
00229                         /* this shouldn't happen */
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                         /* accept and add to our lists */
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  * Parse command line arguments
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.",     /* confdir */
00276                 "Increase debugging level (implies -f).",/* debug */
00277                 "Use the specified file for events.",   /* eventfile */
00278                 "Run in the foreground.",               /* foreground */
00279                 "Set the group on the socket file.",    /* socketgroup */
00280                 "Use the specified log file.",          /* logfile */
00281                 "Set the permissions on the socket file.",/* socketmode */
00282                 "Use the specified socket file.",       /* socketfile */
00283                 "Do not listen on a UNIX socket (overrides -s).",/* nosocket */
00284                 "Print version information.",           /* version */
00285                 "Print this message.",                  /* help */
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                 /* child */
00378                 break;
00379         default:
00380                 /* parent */
00381                 exit(EXIT_SUCCESS);
00382         }
00383 
00384         /* disconnect */
00385         setsid();
00386         umask(0);
00387 
00388         /* get outta the way */
00389         chdir("/");
00390 
00391         return 0;
00392 }
00393 
00394 static int
00395 open_logs(void)
00396 {
00397         int logfd;
00398         int nullfd;
00399 
00400         /* set up stdout, stderr to log and stdin to /dev/null */
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  * This depends on fixes in linux ACPI after 2.4.8
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                                 /* we should do something with the data */
00494                                 acpid_log("ERR: read(): %s\n",
00495                                         strerror(errno));
00496                                 return NULL;
00497                         } else if (r == 0) {
00498                                 /* signal this in an almost standard way */
00499                                 errno = EPIPE;
00500                                 return NULL;
00501                         } else if (r == 1) {
00502                                 /* scan for a newline */
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 }

© sourcejam.com 2005-2008