#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 rule * | new_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 rule * | parse_file (const char *file) |
| static struct rule * | parse_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 |
|
|
Definition at line 599 of file event.c. Referenced by safe_write(). |
|
|
Definition at line 41 of file event.c. Referenced by parse_client(), and parse_file(). |
|
||||||||||||
|
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 }
|
|
|
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 }
|
|
|
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 }
|
|
|
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 }
|
|
|
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 }
|
|
||||||||||||
|
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 }
|
|
||||||||||||
|
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 }
|
|
||||||||||||
|
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 }
|
|
||||||||||||
|
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 }
|
|
|
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 }
|
|
|
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 }
|
|
|
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 }
|
|
|
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 }
|
|
||||||||||||
|
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 }
|
|
|
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 }
|
|
|
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 }
|
|
||||||||||||||||
|
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 }
|
|
|
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 }
|
|
|
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 }
|
|
|
|
|
|
|