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

acpid.c File Reference

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <time.h>
#include <sys/poll.h>
#include <grp.h>
#include "acpid.h"
#include "ud_socket.h"

Go to the source code of this file.

Defines

#define MAX_BUFLEN   1024

Functions

static int handle_cmdline (int *argc, char ***argv)
static void close_fds (void)
static int daemonize (void)
static int open_logs (void)
static void clean_exit (int sig)
static void reload_conf (int sig)
static char * read_line (int fd)
int main (int argc, char **argv)
int acpid_log (const char *fmt,...)

Variables

int acpid_debug
static const char * progname
static const char * confdir = ACPI_CONFDIR
static const char * logfile = ACPI_LOGFILE
static const char * eventfile = ACPI_EVENTFILE
static const char * socketfile = ACPI_SOCKETFILE
static int nosocket
static const char * socketgroup
static mode_t socketmode = ACPI_SOCKETMODE
static int foreground


Define Documentation

#define MAX_BUFLEN   1024
 

Definition at line 471 of file acpid.c.


Function Documentation

int acpid_log const char *  fmt,
  ...
 

Definition at line 450 of file acpid.c.

Referenced by acpid_add_client(), acpid_cleanup_rules(), acpid_handle_event(), acpid_read_conf(), check_escapes(), clean_exit(), do_client_rule(), do_cmd_rule(), lock_rules(), main(), new_rule(), parse_client(), parse_cmd(), parse_file(), path_is_dir(), read_line(), reload_conf(), safe_write(), and unlock_rules().

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 }

static void clean_exit int  sig  )  [static]
 

Definition at line 434 of file acpid.c.

References acpid_cleanup_rules(), and acpid_log().

Referenced by main().

00435 {
00436         acpid_cleanup_rules();
00437         acpid_log("exiting\n");
00438         exit(EXIT_SUCCESS);
00439 }

static void close_fds void   )  [static]
 

Definition at line 361 of file acpid.c.

Referenced by main().

00362 {
00363         int fd, max;
00364         max = sysconf(_SC_OPEN_MAX);
00365         for (fd = 3; fd < max; fd++)
00366                 close(fd);
00367 }

static int daemonize void   )  [static]
 

Definition at line 370 of file acpid.c.

References progname.

Referenced by main().

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 }

static int handle_cmdline int *  argc,
char ***  argv
[static]
 

Definition at line 258 of file acpid.c.

References acpid_debug, confdir, eventfile, foreground, logfile, nosocket, opts_help, PACKAGE, progname, socketfile, socketgroup, and socketmode.

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 }

int main int  argc,
char **  argv
 

Definition at line 61 of file acpid.c.

References ACPI_MAX_ERRS, acpid_add_client(), acpid_debug, acpid_handle_event(), acpid_log(), acpid_read_conf(), clean_exit(), close_fds(), confdir, daemonize(), eventfile, foreground, handle_cmdline(), nosocket, open_logs(), progname, read_line(), reload_conf(), socketfile, socketgroup, socketmode, ud_accept(), and ud_create_socket().

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 }

static int open_logs void   )  [static]
 

Definition at line 395 of file acpid.c.

References logfile, and progname.

Referenced by main().

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 }

static char * read_line int  fd  )  [static]
 

Definition at line 473 of file acpid.c.

References acpid_log(), and MAX_BUFLEN.

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 }

static void reload_conf int  sig  )  [static]
 

Definition at line 442 of file acpid.c.

References acpid_cleanup_rules(), acpid_log(), acpid_read_conf(), and confdir.

Referenced by main().

00443 {
00444         acpid_log("reloading configuration\n");
00445         acpid_cleanup_rules();
00446         acpid_read_conf(confdir);
00447 }


Variable Documentation

int acpid_debug
 

Definition at line 48 of file acpid.c.

Referenced by acpid_cleanup_rules(), acpid_handle_event(), handle_cmdline(), lock_rules(), main(), parse_cmd(), parse_file(), safe_write(), and unlock_rules().

const char* confdir = ACPI_CONFDIR [static]
 

Definition at line 51 of file acpid.c.

Referenced by handle_cmdline(), main(), and reload_conf().

const char* eventfile = ACPI_EVENTFILE [static]
 

Definition at line 53 of file acpid.c.

Referenced by handle_cmdline(), and main().

int foreground [static]
 

Definition at line 58 of file acpid.c.

Referenced by handle_cmdline(), and main().

const char* logfile = ACPI_LOGFILE [static]
 

Definition at line 52 of file acpid.c.

Referenced by handle_cmdline(), and open_logs().

int nosocket [static]
 

Definition at line 55 of file acpid.c.

Referenced by handle_cmdline(), and main().

const char* progname [static]
 

Definition at line 50 of file acpid.c.

const char* socketfile = ACPI_SOCKETFILE [static]
 

Definition at line 54 of file acpid.c.

const char* socketgroup [static]
 

Definition at line 56 of file acpid.c.

Referenced by handle_cmdline(), and main().

mode_t socketmode = ACPI_SOCKETMODE [static]
 

Definition at line 57 of file acpid.c.

Referenced by handle_cmdline(), and main().


© sourcejam.com 2005-2008