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

event.c File Reference

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include <ctype.h>
#include <regex.h>
#include <signal.h>
#include "acpid.h"

Go to the source code of this file.

Classes

struct  rule
struct  rule_list

Defines

#define RULE_REGEX_FLAGS   (REG_EXTENDED | REG_ICASE | REG_NOSUB | REG_NEWLINE)
#define NTRIES   100

Functions

static void enlist_rule (struct rule_list *list, struct rule *r)
static void delist_rule (struct rule_list *list, struct rule *r)
static struct rulenew_rule (void)
static void free_rule (struct rule *r)
static void lock_rules (void)
static void unlock_rules (void)
static sigset_t * signals_handled (void)
static struct ruleparse_file (const char *file)
static struct ruleparse_client (int client)
static int do_cmd_rule (struct rule *r, const char *event)
static int do_client_rule (struct rule *r, const char *event)
static int safe_write (int fd, const char *buf, int len)
static char * parse_cmd (const char *cmd, const char *event)
static int check_escapes (const char *str)
static int path_is_dir (const char *path)
int acpid_read_conf (const char *confdir)
int acpid_cleanup_rules (void)
int acpid_add_client (int clifd, const char *origin)
int acpid_handle_event (const char *event)

Variables

static struct rule_list cmd_list
static struct rule_list client_list


Define Documentation

#define NTRIES   100
 

Definition at line 599 of file event.c.

Referenced by safe_write().

#define RULE_REGEX_FLAGS   (REG_EXTENDED | REG_ICASE | REG_NOSUB | REG_NEWLINE)
 

Definition at line 41 of file event.c.

Referenced by parse_client(), and parse_file().


Function Documentation

int acpid_add_client int  clifd,
const char *  origin
 

Definition at line 313 of file event.c.

References acpid_log(), enlist_rule(), rule::origin, and parse_client().

Referenced by main().

00314 {
00315         struct rule *r;
00316         int nrules = 0;
00317 
00318         acpid_log("client connected from %s\n", origin);
00319 
00320         r = parse_client(clifd);
00321         if (r) {
00322                 r->origin = strdup(origin);
00323                 enlist_rule(&client_list, r);
00324                 nrules++;
00325         }
00326 
00327         acpid_log("%d client rule%s loaded\n", nrules, (nrules == 1)?"":"s");
00328 
00329         return 0;
00330 }

int acpid_cleanup_rules void   ) 
 

Definition at line 157 of file event.c.

References acpid_debug, acpid_log(), rule::action, delist_rule(), free_rule(), rule_list::head, lock_rules(), rule::next, and unlock_rules().

Referenced by clean_exit(), and reload_conf().

00158 {
00159         struct rule *p;
00160         struct rule *next;
00161 
00162         lock_rules();
00163 
00164         if (acpid_debug >= 3) {
00165                 acpid_log("DBG: cleaning up rules\n");
00166         }
00167 
00168         /* tell our clients to buzz off */
00169         p = client_list.head;
00170         while (p) {
00171                 next = p->next;
00172                 delist_rule(&client_list, p);
00173                 close(p->action.fd);
00174                 free_rule(p);
00175                 p = next;
00176         }
00177 
00178         /* clear out our conf rules */
00179         p = cmd_list.head;
00180         while (p) {
00181                 next = p->next;
00182                 delist_rule(&cmd_list, p);
00183                 free_rule(p);
00184                 p = next;
00185         }
00186 
00187         unlock_rules();
00188 
00189         return 0;
00190 }

int acpid_handle_event const char *  event  ) 
 

Definition at line 443 of file event.c.

References acpid_debug, acpid_log(), do_client_rule(), do_cmd_rule(), rule::event, rule_list::head, lock_rules(), rule::next, rule::origin, rule::RULE_CLIENT, rule::RULE_CMD, rule::type, and unlock_rules().

Referenced by main().

00444 {
00445         struct rule *p;
00446         int nrules = 0;
00447         struct rule_list *ar[] = { &client_list, &cmd_list, NULL };
00448         struct rule_list **lp;
00449 
00450         /* make an event be atomic wrt known signals */
00451         lock_rules();
00452 
00453         /* scan each rule list for any rules that care about this event */
00454         for (lp = ar; *lp; lp++) {
00455                 struct rule_list *l = *lp;
00456                 p = l->head;
00457                 while (p) {
00458                         /* the list can change underneath us */
00459                         struct rule *pnext = p->next;
00460                         if (!regexec(p->event, event, 0, NULL, 0)) {
00461                                 /* a match! */
00462                                 if (acpid_debug) {
00463                                         acpid_log("DBG: rule from %s matched\n",
00464                                                 p->origin);
00465                                 }
00466                                 nrules++;
00467                                 if (p->type == RULE_CMD) {
00468                                         do_cmd_rule(p, event);
00469                                 } else if (p->type == RULE_CLIENT) {
00470                                         do_client_rule(p, event);
00471                                 } else {
00472                                         acpid_log("unknown rule type: %d\n",
00473                                                 p->type);
00474                                 }
00475                         } else {
00476                                 if (acpid_debug >= 3) {
00477                                         acpid_log("DBG: rule from %s did not "
00478                                                 "match\n", p->origin);
00479                                 }
00480                         }
00481                         p = pnext;
00482                 }
00483         }
00484 
00485         unlock_rules();
00486 
00487         if (acpid_debug) {
00488                 acpid_log("DBG: %d total rule%s matched\n",
00489                         nrules, (nrules == 1)?"":"s");
00490         }
00491 
00492         return 0;
00493 }

int acpid_read_conf const char *  confdir  ) 
 

Definition at line 99 of file event.c.

References acpid_log(), enlist_rule(), lock_rules(), parse_file(), path_is_dir(), and unlock_rules().

Referenced by main(), and reload_conf().

00100 {
00101         DIR *dir;
00102         struct dirent *dirent;
00103         char *file = NULL;
00104         int nrules = 0;
00105 
00106         lock_rules();
00107 
00108         dir = opendir(confdir);
00109         if (!dir) {
00110                 acpid_log("ERR: opendir(%s): %s\n",
00111                         confdir, strerror(errno));
00112                 unlock_rules();
00113                 return -1;
00114         }
00115 
00116         /* scan all the files */
00117         while ((dirent = readdir(dir))) {
00118                 int len;
00119                 struct rule *r;
00120 
00121                 if (dirent->d_name[0] == '.')
00122                         continue; /* skip dotfiles */
00123 
00124                 len = strlen(dirent->d_name) + strlen(confdir) + 2;
00125                 file = (char *)malloc(len);
00126                 if (!file) {
00127                         acpid_log("ERR: malloc(): %s\n", strerror(errno));
00128                         unlock_rules();
00129                         return -1;
00130                 }
00131                 snprintf(file, len, "%s/%s", confdir, dirent->d_name);
00132 
00133                 if (path_is_dir(file)) {
00134                         free(file);
00135                         continue; /* skip subdirs */
00136                 }
00137 
00138                 r = parse_file(file);
00139                 if (r) {
00140                         enlist_rule(&cmd_list, r);
00141                         nrules++;
00142                 }
00143                 free(file);
00144         }
00145         closedir(dir);
00146         unlock_rules();
00147 
00148         acpid_log("%d rule%s loaded\n", nrules, (nrules == 1)?"":"s");
00149 
00150         return 0;
00151 }

static int check_escapes const char *  str  )  [static]
 

Definition at line 669 of file event.c.

References acpid_log().

Referenced by parse_file().

00670 {
00671         const char *p;
00672         int r = 0;
00673 
00674         p = str;
00675         while (*p) {
00676                 /* found an escape */
00677                 if (*p == '%') {
00678                         p++;
00679                         if (!*p) {
00680                                 acpid_log("invalid escape at EOL\n");
00681                                 return -1;
00682                         } else if (*p != '%' && *p != 'e') {
00683                                 acpid_log("invalid escape \"%%%c\"\n", *p);
00684                                 r = -1;
00685                         }
00686                 }
00687                 p++;
00688         }
00689         return r;
00690 }

static void delist_rule struct rule_list list,
struct rule r
[static]
 

Definition at line 381 of file event.c.

References rule_list::head, rule::next, rule::prev, and rule_list::tail.

Referenced by acpid_cleanup_rules(), and do_client_rule().

00382 {
00383         if (r->next) {
00384                 r->next->prev = r->prev;
00385         } else {
00386                 list->tail = r->prev;
00387         }
00388 
00389         if (r->prev) {
00390                 r->prev->next = r->next;
00391         } else {
00392                 list->head = r->next;;
00393         }
00394 
00395         r->next = r->prev = NULL;
00396 }

static int do_client_rule struct rule r,
const char *  event
[static]
 

Definition at line 580 of file event.c.

References acpid_log(), rule::action, delist_rule(), rule::origin, and safe_write().

Referenced by acpid_handle_event().

00581 {
00582         int r;
00583         int client = rule->action.fd;
00584 
00585         acpid_log("notifying client %s\n", rule->origin);
00586 
00587         r = safe_write(client, event, strlen(event));
00588         if (r < 0 && errno == EPIPE) {
00589                 /* closed */
00590                 acpid_log("client has disconnected\n");
00591                 delist_rule(&client_list, rule);
00592                 return -1;
00593         }
00594         safe_write(client, "\n", 1);
00595 
00596         return 0;
00597 }

static int do_cmd_rule struct rule r,
const char *  event
[static]
 

Definition at line 533 of file event.c.

References acpid_log(), rule::action, parse_cmd(), and signals_handled().

Referenced by acpid_handle_event().

00534 {
00535         pid_t pid;
00536         int status;
00537         const char *action;
00538 
00539         pid = fork();
00540         switch (pid) {
00541         case -1:
00542                 acpid_log("ERR: fork(): %s\n", strerror(errno));
00543                 return -1;
00544         case 0: /* child */
00545                 /* parse the commandline, doing any substitutions needed */
00546                 action = parse_cmd(rule->action.cmd, event);
00547                 acpid_log("executing action \"%s\"\n", action);
00548 
00549                 /* reset signals */
00550                 signal(SIGHUP, SIG_DFL);
00551                 signal(SIGTERM, SIG_DFL);
00552                 signal(SIGINT, SIG_DFL);
00553                 signal(SIGQUIT, SIG_DFL);
00554                 signal(SIGPIPE, SIG_DFL);
00555                 sigprocmask(SIG_UNBLOCK, signals_handled(), NULL);
00556 
00557                 acpid_log("BEGIN HANDLER MESSAGES\n");
00558                 execl("/bin/sh", "/bin/sh", "-c", action, NULL);
00559                 /* should not get here */
00560                 acpid_log("ERR: execl(): %s\n", strerror(errno));
00561                 exit(EXIT_FAILURE);
00562         }
00563 
00564         /* parent */
00565         waitpid(pid, &status, 0);
00566         acpid_log("END HANDLER MESSAGES\n");
00567         if (WIFEXITED(status)) {
00568                 acpid_log("action exited with status %d\n",
00569                         WEXITSTATUS(status));
00570         } else if (WIFSIGNALED(status)) {
00571                 acpid_log("action exited on signal %d\n", WTERMSIG(status));
00572         } else {
00573                 acpid_log("action exited with status %d\n", status);
00574         }
00575 
00576         return 0;
00577 }

static void enlist_rule struct rule_list list,
struct rule r
[static]
 

Definition at line 368 of file event.c.

References rule_list::head, rule::next, rule::prev, and rule_list::tail.

Referenced by acpid_add_client(), and acpid_read_conf().

00369 {
00370         r->next = r->prev = NULL;
00371         if (!list->head) {
00372                 list->head = list->tail = r;
00373         } else {
00374                 list->tail->next = r;
00375                 r->prev = list->tail;
00376                 list->tail = r;
00377         }
00378 }

static void free_rule struct rule r  )  [static]
 

Definition at line 420 of file event.c.

References rule::action, rule::event, rule::origin, rule::RULE_CMD, and rule::type.

Referenced by acpid_cleanup_rules(), parse_client(), and parse_file().

00421 {
00422         if (r->type == RULE_CMD) {
00423                 if (r->action.cmd) {
00424                         free(r->action.cmd);
00425                 }
00426         }
00427 
00428         if (r->origin) {
00429                 free(r->origin);
00430         }
00431         if (r->event) {
00432                 regfree(r->event);
00433                 free(r->event);
00434         }
00435 
00436         free(r);
00437 }

static void lock_rules void   )  [static]
 

Definition at line 511 of file event.c.

References acpid_debug, acpid_log(), and signals_handled().

Referenced by acpid_cleanup_rules(), acpid_handle_event(), and acpid_read_conf().

00512 {
00513         if (acpid_debug >= 4) {
00514                 acpid_log("DBG: blocking signals for rule lock\n");
00515         }
00516         sigprocmask(SIG_BLOCK, signals_handled(), NULL);
00517 }

static struct rule * new_rule void   )  [static]
 

Definition at line 399 of file event.c.

References acpid_log(), and rule::RULE_NONE.

Referenced by parse_client(), and parse_file().

00400 {
00401         struct rule *r;
00402 
00403         r = malloc(sizeof(*r));
00404         if (!r) {
00405                 acpid_log("ERR: malloc(): %s\n", strerror(errno));
00406                 return NULL;
00407         }
00408 
00409         r->type = RULE_NONE;
00410         r->origin = NULL;
00411         r->event = NULL;
00412         r->action.cmd = NULL;
00413         r->prev = r->next = NULL;
00414 
00415         return r;
00416 }

static struct rule * parse_client int  client  )  [static]
 

Definition at line 333 of file event.c.

References acpid_log(), rule::action, rule::event, free_rule(), new_rule(), rule::RULE_CLIENT, RULE_REGEX_FLAGS, and rule::type.

Referenced by acpid_add_client().

00334 {
00335         struct rule *r;
00336         int rv;
00337 
00338         /* make a new rule */
00339         r = new_rule();
00340         if (!r) {
00341                 return NULL;
00342         }
00343         r->type = RULE_CLIENT;
00344         r->action.fd = client;
00345         r->event = malloc(sizeof(regex_t));
00346         if (!r) {
00347                 acpid_log("ERR: malloc(): %s\n", strerror(errno));
00348                 free_rule(r);
00349                 return NULL;
00350         }
00351         rv = regcomp(r->event, ".*", RULE_REGEX_FLAGS);
00352         if (rv) {
00353                 char buf[128];
00354                 regerror(rv, r->event, buf, sizeof(buf));
00355                 acpid_log("ERR: regcomp(): %s\n", buf);
00356                 free_rule(r);
00357                 return NULL;
00358         }
00359 
00360         return r;
00361 }

static char * parse_cmd const char *  cmd,
const char *  event
[static]
 

Definition at line 634 of file event.c.

References acpid_debug, and acpid_log().

Referenced by do_cmd_rule().

00635 {
00636         static char buf[4096];
00637         int i;
00638         const char *p;
00639 
00640         p = cmd;
00641         i = 0;
00642 
00643         memset(buf, 0, sizeof(buf));
00644         while (i < (sizeof(buf)-1)) {
00645                 if (*p == '%') {
00646                         p++;
00647                         if (*p == 'e') {
00648                                 /* handle an event expansion */
00649                                 int size = sizeof(buf) - i;
00650                                 size = snprintf(buf+i, size, "%s", event);
00651                                 i += size;
00652                                 p++;
00653                                 continue;
00654                         }
00655                 }
00656                 if (!*p) {
00657                         break;
00658                 }
00659                 buf[i++] = *p++;
00660         }
00661         if (acpid_debug >= 2) {
00662                 acpid_log("DBG: expanded \"%s\" -> \"%s\"\n", cmd, buf);
00663         }
00664 
00665         return buf;
00666 }

static struct rule * parse_file const char *  file  )  [static]
 

Definition at line 193 of file event.c.

References acpid_debug, acpid_log(), rule::action, check_escapes(), rule::event, free_rule(), new_rule(), rule::origin, rule::RULE_CMD, RULE_REGEX_FLAGS, and rule::type.

Referenced by acpid_read_conf().

00194 {
00195         FILE *fp;
00196         char buf[512];
00197         int line = 0;
00198         struct rule *r;
00199 
00200         if (acpid_debug) {
00201                 acpid_log("DBG: parsing conf file %s\n", file);
00202         }
00203 
00204         fp = fopen(file, "r");
00205         if (!fp) {
00206                 acpid_log("ERR: fopen(%s): %s\n", file, strerror(errno));
00207                 return NULL;
00208         }
00209 
00210         /* make a new rule */
00211         r = new_rule();
00212         if (!r) {
00213                 fclose(fp);
00214                 return NULL;
00215         }
00216         r->type = RULE_CMD;
00217         r->origin = strdup(file);
00218         if (!r->origin) {
00219                 acpid_log("ERR: strdup(): %s\n", strerror(errno));
00220                 free_rule(r);
00221                 fclose(fp);
00222                 return NULL;
00223         }
00224 
00225         /* read each line */
00226         while (!feof(fp)) {
00227                 char *p = buf;
00228                 char key[64];
00229                 char val[512];
00230                 int n;
00231 
00232                 line++;
00233                 memset(key, 0, sizeof(key));
00234                 memset(val, 0, sizeof(val));
00235 
00236                 if (fgets(buf, sizeof(buf)-1, fp) == NULL) {
00237                         continue;
00238                 }
00239 
00240                 /* skip leading whitespace */
00241                 while (*p && isspace((int)*p)) {
00242                         p++;
00243                 }
00244                 /* blank lines and comments get ignored */
00245                 if (!*p || *p == '#') {
00246                         continue;
00247                 }
00248 
00249                 /* quick parse */
00250                 n = sscanf(p, "%63[^=\n]=%255[^\n]", key, val);
00251                 if (n != 2) {
00252                         acpid_log("can't parse %s at line %d\n",
00253                                 file, line);
00254                         continue;
00255                 }
00256                 if (acpid_debug >= 3) {
00257                         acpid_log("DBG:    key=\"%s\" val=\"%s\"\n", key, val);
00258                 }
00259                 /* handle the parsed line */
00260                 if (!strcasecmp(key, "event")) {
00261                         int rv;
00262                         r->event = malloc(sizeof(regex_t));
00263                         if (!r) {
00264                                 acpid_log("ERR: malloc(): %s\n",
00265                                         strerror(errno));
00266                                 free_rule(r);
00267                                 fclose(fp);
00268                                 return NULL;
00269                         }
00270                         rv = regcomp(r->event, val, RULE_REGEX_FLAGS);
00271                         if (rv) {
00272                                 char buf[128];
00273                                 regerror(rv, r->event, buf, sizeof(buf));
00274                                 acpid_log("ERR: regcomp(): %s\n", buf);
00275                                 free_rule(r);
00276                                 fclose(fp);
00277                                 return NULL;
00278                         }
00279                 } else if (!strcasecmp(key, "action")) {
00280                         if (check_escapes(val) < 0) {
00281                                 acpid_log("ERR: can't load file %s\n", file);
00282                                 free_rule(r);
00283                                 fclose(fp);
00284                                 return NULL;
00285                         }
00286                         r->action.cmd = strdup(val);
00287                         if (!r->action.cmd) {
00288                                 acpid_log("ERR: strdup(): %s\n",
00289                                         strerror(errno));
00290                                 free_rule(r);
00291                                 fclose(fp);
00292                                 return NULL;
00293                         }
00294                 } else {
00295                         acpid_log("unknown option '%s' in %s at line %d\n",
00296                                 key, file, line);
00297                         continue;
00298                 }
00299         }
00300         if (!r->event || !r->action.cmd) {
00301                 if (acpid_debug) {
00302                         acpid_log("DBG: skipping incomplete file %s\n", file);
00303                 }
00304                 free_rule(r);
00305                 return NULL;
00306         }
00307         fclose(fp);
00308 
00309         return r;
00310 }

static int path_is_dir const char *  path  )  [static]
 

Definition at line 84 of file event.c.

References acpid_log().

Referenced by acpid_read_conf().

00085 {
00086         struct stat s;
00087 
00088         if (stat(path, &s)) {
00089                 acpid_log("ERR: stat(\"%s\"): %s\n", path, strerror(errno));
00090                 return 0;
00091         }
00092         return S_ISDIR(s.st_mode);
00093 }

static int safe_write int  fd,
const char *  buf,
int  len
[static]
 

Definition at line 601 of file event.c.

References acpid_debug, acpid_log(), and NTRIES.

Referenced by do_client_rule().

00602 {
00603         int r;
00604         int ttl = 0;
00605         int ntries = NTRIES;
00606 
00607         do {
00608                 r = write(fd, buf+ttl, len-ttl);
00609                 if (r < 0) {
00610                         if (errno != EAGAIN && errno != EINTR) {
00611                                 /* a legit error */
00612                                 return r;
00613                         }
00614                         ntries--;
00615                 } else if (r > 0) {
00616                         /* as long as we make forward progress, reset ntries */
00617                         ntries = NTRIES;
00618                         ttl += r;
00619                 }
00620         } while (ttl < len && ntries);
00621 
00622         if (!ntries) {
00623                 /* crap */
00624                 if (acpid_debug >= 2) {
00625                         acpid_log("uh-oh! safe_write() timed out\n");
00626                 }
00627                 return r;
00628         }
00629 
00630         return ttl;
00631 }

static sigset_t * signals_handled void   )  [static]
 

Definition at line 497 of file event.c.

Referenced by do_cmd_rule(), lock_rules(), and unlock_rules().

00498 {
00499         static sigset_t sigset;
00500 
00501         sigemptyset(&sigset);
00502         sigaddset(&sigset, SIGHUP);
00503         sigaddset(&sigset, SIGTERM);
00504         sigaddset(&sigset, SIGQUIT);
00505         sigaddset(&sigset, SIGINT);
00506 
00507         return &sigset;
00508 }

static void unlock_rules void   )  [static]
 

Definition at line 520 of file event.c.

References acpid_debug, acpid_log(), and signals_handled().

Referenced by acpid_cleanup_rules(), acpid_handle_event(), and acpid_read_conf().

00521 {
00522         if (acpid_debug >= 4) {
00523                 acpid_log("DBG: unblocking signals for rule lock\n");
00524         }
00525         sigprocmask(SIG_UNBLOCK, signals_handled(), NULL);
00526 }


Variable Documentation

struct rule_list client_list [static]
 

Definition at line 62 of file event.c.

struct rule_list cmd_list [static]
 

Definition at line 61 of file event.c.


© sourcejam.com 2005-2008