Merge commit 'upstream/2.0.9'
Michael Meskes
13 years ago
0 | * Tue Feb 15 2010 Ted Felix <http://www.tedfelix.com> | |
0 | * Fri Apr 15 2011 Ted Felix <http://www.tedfelix.com> | |
1 | - 2.0.9 release | |
2 | - Removed newlines from acpid_log() calls and modified acpid_log() to | |
3 | no longer need newlines. This change to acpid prevents blank lines in | |
4 | the log for versions of syslogd that preserve newlines. (acpid.c | |
5 | connection_list.c event.c inotify_handler.c input_layer.c netlink.c | |
6 | proc.c sock.c) (Michael Meskes, Ted Felix) | |
7 | - Added fcntl() for O_NONBLOCK on the client sockets. This prevents acpid | |
8 | from hanging if a client behaves badly. (sock.c) (Vasiliy Kulikov) | |
9 | From: http://www.openwall.com/lists/oss-security/2011/01/19/4 | |
10 | - Improvements to error handling. (sock.c) (Ted Felix) | |
11 | ||
12 | * Tue Feb 15 2011 Ted Felix <http://www.tedfelix.com> | |
1 | 13 | - 2.0.8 release |
2 | 14 | - Fixed "comparison between signed and unsigned integer expressions" |
3 | 15 | error with gcc 4.6. (libnetlink.c) (Eugeni Dodonov) |
0 | 0 | # Makefile for ACPI daemon |
1 | 1 | |
2 | 2 | # update these numbers for new releases |
3 | VERSION = 2.0.8 | |
3 | VERSION = 2.0.9 | |
4 | 4 | |
5 | 5 | OPT = -O2 |
6 | 6 |
4 | 4 | - Run all these tests with valgrind to detect memory leaks. |
5 | 5 | - It's best to test without a window manager running (such as GNOME or KDE) as they tend to handle acpi events on their own and override acpid. To bring down X on a system that is configured with a graphical login, there's usually an "init" script you can run. As an example, with Debian/GNOME, log off of your X/GNOME session, switch to another tty (e.g. Alt-Ctrl-F1), login, and do this: |
6 | 6 | sudo /etc/init.d/gdm stop |
7 | [need instructions for upstart, maybe this: sudo initctl gdm stop] | |
7 | 8 | Now X is out of the way and you can test from the console. |
8 | 9 | - You can kill acpid with "sudo killall acpid". |
9 | 10 | - To make testing more convenient, you can run acpid from a shell as "acpid -ld" to get maximum logging. Use Ctrl-C to stop acpid. |
115 | 115 | exit(EXIT_FAILURE); |
116 | 116 | } |
117 | 117 | |
118 | acpid_log(LOG_INFO, "starting up with %s\n", | |
118 | acpid_log(LOG_INFO, "starting up with %s", | |
119 | 119 | netlink ? "netlink and the input layer" : "proc fs"); |
120 | 120 | |
121 | 121 | /* trap key signals */ |
135 | 135 | exit(EXIT_FAILURE); |
136 | 136 | } |
137 | 137 | |
138 | acpid_log(LOG_INFO, "waiting for events: event logging is %s\n", | |
138 | acpid_log(LOG_INFO, "waiting for events: event logging is %s", | |
139 | 139 | logevents ? "on" : "off"); |
140 | 140 | |
141 | 141 | /* main loop */ |
155 | 155 | if (nready < 0 && errno == EINTR) { |
156 | 156 | continue; |
157 | 157 | } else if (nready < 0) { |
158 | acpid_log(LOG_ERR, "select(): %s\n", strerror(errno)); | |
158 | acpid_log(LOG_ERR, "select(): %s", strerror(errno)); | |
159 | 159 | continue; |
160 | 160 | } |
161 | 161 | |
334 | 334 | /* fork off the parent process */ |
335 | 335 | pid = fork(); |
336 | 336 | if (pid < 0) { |
337 | acpid_log(LOG_ERR, "fork: %s\n", strerror(errno)); | |
337 | acpid_log(LOG_ERR, "fork: %s", strerror(errno)); | |
338 | 338 | return -1; |
339 | 339 | } |
340 | 340 | /* if we got a good PID, then we can exit the parent process */ |
352 | 352 | /* detach the process from the parent (normally a shell) */ |
353 | 353 | sid = setsid(); |
354 | 354 | if (sid < 0) { |
355 | acpid_log(LOG_ERR, "setsid: %s\n", strerror(errno)); | |
355 | acpid_log(LOG_ERR, "setsid: %s", strerror(errno)); | |
356 | 356 | return -1; |
357 | 357 | } |
358 | 358 | |
359 | 359 | /* Change the current working directory. This prevents the current |
360 | 360 | directory from being locked; hence not being able to remove it. */ |
361 | 361 | if (chdir("/") < 0) { |
362 | acpid_log(LOG_ERR, "chdir(\"/\"): %s\n", strerror(errno)); | |
362 | acpid_log(LOG_ERR, "chdir(\"/\"): %s", strerror(errno)); | |
363 | 363 | return -1; |
364 | 364 | } |
365 | 365 | |
387 | 387 | /* open /dev/null */ |
388 | 388 | nullfd = open("/dev/null", O_RDWR); |
389 | 389 | if (nullfd < 0) { |
390 | acpid_log(LOG_ERR, "can't open /dev/null: %s\n", strerror(errno)); | |
390 | acpid_log(LOG_ERR, "can't open /dev/null: %s", strerror(errno)); | |
391 | 391 | return -1; |
392 | 392 | } |
393 | 393 | |
394 | 394 | /* set up stdin, stdout, stderr to /dev/null */ |
395 | 395 | if (dup2(nullfd, STDIN_FILENO) != STDIN_FILENO) { |
396 | acpid_log(LOG_ERR, "dup2() stdin: %s\n", strerror(errno)); | |
396 | acpid_log(LOG_ERR, "dup2() stdin: %s", strerror(errno)); | |
397 | 397 | return -1; |
398 | 398 | } |
399 | 399 | if (!acpid_debug && dup2(nullfd, STDOUT_FILENO) != STDOUT_FILENO) { |
400 | acpid_log(LOG_ERR, "dup2() stdout: %s\n", strerror(errno)); | |
400 | acpid_log(LOG_ERR, "dup2() stdout: %s", strerror(errno)); | |
401 | 401 | return -1; |
402 | 402 | } |
403 | 403 | if (!acpid_debug && dup2(nullfd, STDERR_FILENO) != STDERR_FILENO) { |
404 | acpid_log(LOG_ERR, "dup2() stderr: %s\n", strerror(errno)); | |
404 | acpid_log(LOG_ERR, "dup2() stderr: %s", strerror(errno)); | |
405 | 405 | return -1; |
406 | 406 | } |
407 | 407 | |
435 | 435 | } |
436 | 436 | |
437 | 437 | /* something went wrong */ |
438 | acpid_log(LOG_ERR, "can't create pidfile %s: %s\n", | |
438 | acpid_log(LOG_ERR, "can't create pidfile %s: %s", | |
439 | 439 | pidfile, strerror(errno)); |
440 | 440 | return -1; |
441 | 441 | } |
444 | 444 | clean_exit_with_status(int status) |
445 | 445 | { |
446 | 446 | acpid_cleanup_rules(1); |
447 | acpid_log(LOG_NOTICE, "exiting\n"); | |
447 | acpid_log(LOG_NOTICE, "exiting"); | |
448 | 448 | unlink(pidfile); |
449 | 449 | exit(status); |
450 | 450 | } |
458 | 458 | static void |
459 | 459 | reload_conf(int sig __attribute__((unused))) |
460 | 460 | { |
461 | acpid_log(LOG_NOTICE, "reloading configuration\n"); | |
461 | acpid_log(LOG_NOTICE, "reloading configuration"); | |
462 | 462 | acpid_cleanup_rules(0); |
463 | 463 | acpid_read_conf(confdir); |
464 | 464 | } |
478 | 478 | va_start(args, fmt); |
479 | 479 | vfprintf(stderr, fmt, args); |
480 | 480 | va_end(args); |
481 | ||
482 | fprintf(stderr, "\n"); | |
481 | 483 | } |
482 | 484 | } else { |
483 | 485 | va_start(args, fmt); |
53 | 53 | if (nconnections < 0) |
54 | 54 | return; |
55 | 55 | if (nconnections >= MAX_CONNECTIONS) { |
56 | acpid_log(LOG_ERR, "Too many connections.\n"); | |
56 | acpid_log(LOG_ERR, "Too many connections."); | |
57 | 57 | /* ??? This routine should return -1 in this situation so that */ |
58 | 58 | /* callers can clean up any open fds and whatnot. */ |
59 | 59 | return; |
0 | acpid (1:2.0.9-1) unstable; urgency=low | |
1 | ||
2 | * Imported Upstream version 2.0.9 | |
3 | ||
4 | -- Michael Meskes <meskes@debian.org> Sun, 17 Apr 2011 16:33:17 +0200 | |
5 | ||
0 | 6 | acpid (1:2.0.8-4) unstable; urgency=low |
1 | 7 | |
2 | 8 | * Updated homepage filed to point to new URL. (Closes: #618537) |
99 | 99 | |
100 | 100 | dir = opendir(confdir); |
101 | 101 | if (!dir) { |
102 | acpid_log(LOG_ERR, "opendir(%s): %s\n", | |
102 | acpid_log(LOG_ERR, "opendir(%s): %s", | |
103 | 103 | confdir, strerror(errno)); |
104 | 104 | unlock_rules(); |
105 | 105 | return -1; |
108 | 108 | /* Compile the regular expression. This is based on run-parts(8). */ |
109 | 109 | rc = regcomp(&preg, "^[a-zA-Z0-9_-]+$", RULE_REGEX_FLAGS); |
110 | 110 | if (rc) { |
111 | acpid_log(LOG_ERR, "regcomp(): %d\n", rc); | |
111 | acpid_log(LOG_ERR, "regcomp(): %d", rc); | |
112 | 112 | unlock_rules(); |
113 | 113 | return -1; |
114 | 114 | } |
129 | 129 | |
130 | 130 | /* skip any files that don't match the run-parts convention */ |
131 | 131 | if (regexec(&preg, dirent->d_name, 0, NULL, 0) != 0) { |
132 | acpid_log(LOG_INFO, "skipping conf file %s/%s\n", | |
132 | acpid_log(LOG_INFO, "skipping conf file %s/%s", | |
133 | 133 | confdir, dirent->d_name); |
134 | 134 | continue; |
135 | 135 | } |
140 | 140 | |
141 | 141 | file = malloc(len); |
142 | 142 | if (!file) { |
143 | acpid_log(LOG_ERR, "malloc(): %s\n", strerror(errno)); | |
143 | acpid_log(LOG_ERR, "malloc(): %s", strerror(errno)); | |
144 | 144 | unlock_rules(); |
145 | 145 | return -1; |
146 | 146 | } |
148 | 148 | |
149 | 149 | /* allow only regular files and symlinks to files */ |
150 | 150 | if (stat(file, &stat_buf) != 0) { |
151 | acpid_log(LOG_ERR, "stat(%s): %s\n", file, | |
151 | acpid_log(LOG_ERR, "stat(%s): %s", file, | |
152 | 152 | strerror(errno)); |
153 | 153 | free(file); |
154 | 154 | continue; /* keep trying the rest of the files */ |
155 | 155 | } |
156 | 156 | if (!S_ISREG(stat_buf.st_mode)) { |
157 | acpid_log(LOG_INFO, "skipping non-file %s\n", file); | |
157 | acpid_log(LOG_INFO, "skipping non-file %s", file); | |
158 | 158 | free(file); |
159 | 159 | continue; /* skip non-regular files */ |
160 | 160 | } |
169 | 169 | closedir(dir); |
170 | 170 | unlock_rules(); |
171 | 171 | |
172 | acpid_log(LOG_INFO, "%d rule%s loaded\n", | |
172 | acpid_log(LOG_INFO, "%d rule%s loaded", | |
173 | 173 | nrules, (nrules == 1)?"":"s"); |
174 | 174 | |
175 | 175 | return 0; |
187 | 187 | lock_rules(); |
188 | 188 | |
189 | 189 | if (acpid_debug >= 3) { |
190 | acpid_log(LOG_DEBUG, "cleaning up rules\n"); | |
190 | acpid_log(LOG_DEBUG, "cleaning up rules"); | |
191 | 191 | } |
192 | 192 | |
193 | 193 | if (do_detach) { |
224 | 224 | int line = 0; |
225 | 225 | struct rule *r; |
226 | 226 | |
227 | acpid_log(LOG_DEBUG, "parsing conf file %s\n", file); | |
227 | acpid_log(LOG_DEBUG, "parsing conf file %s", file); | |
228 | 228 | |
229 | 229 | fp = fopen(file, "r"); |
230 | 230 | if (!fp) { |
231 | acpid_log(LOG_ERR, "fopen(%s): %s\n", file, strerror(errno)); | |
231 | acpid_log(LOG_ERR, "fopen(%s): %s", file, strerror(errno)); | |
232 | 232 | return NULL; |
233 | 233 | } |
234 | 234 | |
241 | 241 | r->type = RULE_CMD; |
242 | 242 | r->origin = strdup(file); |
243 | 243 | if (!r->origin) { |
244 | acpid_log(LOG_ERR, "strdup(): %s\n", strerror(errno)); | |
244 | acpid_log(LOG_ERR, "strdup(): %s", strerror(errno)); | |
245 | 245 | free_rule(r); |
246 | 246 | fclose(fp); |
247 | 247 | return NULL; |
274 | 274 | /* quick parse */ |
275 | 275 | n = sscanf(p, "%63[^=\n]=%255[^\n]", key, val); |
276 | 276 | if (n != 2) { |
277 | acpid_log(LOG_WARNING, "can't parse %s at line %d\n", | |
277 | acpid_log(LOG_WARNING, "can't parse %s at line %d", | |
278 | 278 | file, line); |
279 | 279 | continue; |
280 | 280 | } |
281 | 281 | if (acpid_debug >= 3) { |
282 | acpid_log(LOG_DEBUG, " key=\"%s\" val=\"%s\"\n", | |
282 | acpid_log(LOG_DEBUG, " key=\"%s\" val=\"%s\"", | |
283 | 283 | key, val); |
284 | 284 | } |
285 | 285 | /* handle the parsed line */ |
287 | 287 | int rv; |
288 | 288 | r->event = malloc(sizeof(regex_t)); |
289 | 289 | if (!r->event) { |
290 | acpid_log(LOG_ERR, "malloc(): %s\n", | |
290 | acpid_log(LOG_ERR, "malloc(): %s", | |
291 | 291 | strerror(errno)); |
292 | 292 | free_rule(r); |
293 | 293 | fclose(fp); |
297 | 297 | if (rv) { |
298 | 298 | char rbuf[128]; |
299 | 299 | regerror(rv, r->event, rbuf, sizeof(rbuf)); |
300 | acpid_log(LOG_ERR, "regcomp(): %s\n", rbuf); | |
300 | acpid_log(LOG_ERR, "regcomp(): %s", rbuf); | |
301 | 301 | free_rule(r); |
302 | 302 | fclose(fp); |
303 | 303 | return NULL; |
304 | 304 | } |
305 | 305 | } else if (!strcasecmp(key, "action")) { |
306 | 306 | if (check_escapes(val) < 0) { |
307 | acpid_log(LOG_ERR, "can't load file %s\n", | |
307 | acpid_log(LOG_ERR, "can't load file %s", | |
308 | 308 | file); |
309 | 309 | free_rule(r); |
310 | 310 | fclose(fp); |
312 | 312 | } |
313 | 313 | r->action.cmd = strdup(val); |
314 | 314 | if (!r->action.cmd) { |
315 | acpid_log(LOG_ERR, "strdup(): %s\n", | |
315 | acpid_log(LOG_ERR, "strdup(): %s", | |
316 | 316 | strerror(errno)); |
317 | 317 | free_rule(r); |
318 | 318 | fclose(fp); |
320 | 320 | } |
321 | 321 | } else { |
322 | 322 | acpid_log(LOG_WARNING, |
323 | "unknown option '%s' in %s at line %d\n", | |
323 | "unknown option '%s' in %s at line %d", | |
324 | 324 | key, file, line); |
325 | 325 | continue; |
326 | 326 | } |
327 | 327 | } |
328 | 328 | if (!r->event || !r->action.cmd) { |
329 | acpid_log(LOG_INFO, "skipping incomplete file %s\n", file); | |
329 | acpid_log(LOG_INFO, "skipping incomplete file %s", file); | |
330 | 330 | free_rule(r); |
331 | 331 | fclose(fp); |
332 | 332 | return NULL; |
342 | 342 | struct rule *r; |
343 | 343 | int nrules = 0; |
344 | 344 | |
345 | acpid_log(LOG_NOTICE, "client connected from %s\n", origin); | |
345 | acpid_log(LOG_NOTICE, "client connected from %s", origin); | |
346 | 346 | |
347 | 347 | r = parse_client(clifd); |
348 | 348 | if (r) { |
351 | 351 | nrules++; |
352 | 352 | } |
353 | 353 | |
354 | acpid_log(LOG_INFO, "%d client rule%s loaded\n", | |
354 | acpid_log(LOG_INFO, "%d client rule%s loaded", | |
355 | 355 | nrules, (nrules == 1)?"":"s"); |
356 | 356 | |
357 | 357 | return 0; |
372 | 372 | r->action.fd = client; |
373 | 373 | r->event = malloc(sizeof(regex_t)); |
374 | 374 | if (!r->event) { |
375 | acpid_log(LOG_ERR, "malloc(): %s\n", strerror(errno)); | |
375 | acpid_log(LOG_ERR, "malloc(): %s", strerror(errno)); | |
376 | 376 | free_rule(r); |
377 | 377 | return NULL; |
378 | 378 | } |
380 | 380 | if (rv) { |
381 | 381 | char buf[128]; |
382 | 382 | regerror(rv, r->event, buf, sizeof(buf)); |
383 | acpid_log(LOG_ERR, "regcomp(): %s\n", buf); | |
383 | acpid_log(LOG_ERR, "regcomp(): %s", buf); | |
384 | 384 | free_rule(r); |
385 | 385 | return NULL; |
386 | 386 | } |
430 | 430 | |
431 | 431 | r = malloc(sizeof(*r)); |
432 | 432 | if (!r) { |
433 | acpid_log(LOG_ERR, "malloc(): %s\n", strerror(errno)); | |
433 | acpid_log(LOG_ERR, "malloc(): %s", strerror(errno)); | |
434 | 434 | return NULL; |
435 | 435 | } |
436 | 436 | |
476 | 476 | r = poll(&pfd, 1, 0); |
477 | 477 | |
478 | 478 | if (r < 0) { |
479 | acpid_log(LOG_ERR, "poll(): %s\n", strerror(errno)); | |
479 | acpid_log(LOG_ERR, "poll(): %s", strerror(errno)); | |
480 | 480 | return 0; |
481 | 481 | } |
482 | 482 | |
498 | 498 | struct ucred cred; |
499 | 499 | /* closed */ |
500 | 500 | acpid_log(LOG_NOTICE, |
501 | "client %s has disconnected\n", p->origin); | |
501 | "client %s has disconnected", p->origin); | |
502 | 502 | delist_rule(&client_list, p); |
503 | 503 | ud_get_peercred(p->action.fd, &cred); |
504 | 504 | if (cred.uid != 0) { |
538 | 538 | /* a match! */ |
539 | 539 | if (logevents) { |
540 | 540 | acpid_log(LOG_INFO, |
541 | "rule from %s matched\n", | |
541 | "rule from %s matched", | |
542 | 542 | p->origin); |
543 | 543 | } |
544 | 544 | nrules++; |
548 | 548 | do_client_rule(p, event); |
549 | 549 | } else { |
550 | 550 | acpid_log(LOG_WARNING, |
551 | "unknown rule type: %d\n", | |
551 | "unknown rule type: %d", | |
552 | 552 | p->type); |
553 | 553 | } |
554 | 554 | } else { |
555 | 555 | if (acpid_debug >= 3 && logevents) { |
556 | 556 | acpid_log(LOG_INFO, |
557 | "rule from %s did not match\n", | |
557 | "rule from %s did not match", | |
558 | 558 | p->origin); |
559 | 559 | } |
560 | 560 | } |
565 | 565 | unlock_rules(); |
566 | 566 | |
567 | 567 | if (logevents) { |
568 | acpid_log(LOG_INFO, "%d total rule%s matched\n", | |
568 | acpid_log(LOG_INFO, "%d total rule%s matched", | |
569 | 569 | nrules, (nrules == 1)?"":"s"); |
570 | 570 | } |
571 | 571 | |
591 | 591 | lock_rules(void) |
592 | 592 | { |
593 | 593 | if (acpid_debug >= 4) { |
594 | acpid_log(LOG_DEBUG, "blocking signals for rule lock\n"); | |
594 | acpid_log(LOG_DEBUG, "blocking signals for rule lock"); | |
595 | 595 | } |
596 | 596 | sigprocmask(SIG_BLOCK, signals_handled(), NULL); |
597 | 597 | } |
600 | 600 | unlock_rules(void) |
601 | 601 | { |
602 | 602 | if (acpid_debug >= 4) { |
603 | acpid_log(LOG_DEBUG, "unblocking signals for rule lock\n"); | |
603 | acpid_log(LOG_DEBUG, "unblocking signals for rule lock"); | |
604 | 604 | } |
605 | 605 | sigprocmask(SIG_UNBLOCK, signals_handled(), NULL); |
606 | 606 | } |
619 | 619 | pid = fork(); |
620 | 620 | switch (pid) { |
621 | 621 | case -1: |
622 | acpid_log(LOG_ERR, "fork(): %s\n", strerror(errno)); | |
622 | acpid_log(LOG_ERR, "fork(): %s", strerror(errno)); | |
623 | 623 | return -1; |
624 | 624 | case 0: /* child */ |
625 | 625 | /* parse the commandline, doing any substitutions needed */ |
626 | 626 | action = parse_cmd(rule->action.cmd, event); |
627 | 627 | if (logevents) { |
628 | 628 | acpid_log(LOG_INFO, |
629 | "executing action \"%s\"\n", action); | |
629 | "executing action \"%s\"", action); | |
630 | 630 | } |
631 | 631 | |
632 | 632 | /* reset signals */ |
642 | 642 | } |
643 | 643 | execl("/bin/sh", "/bin/sh", "-c", action, NULL); |
644 | 644 | /* should not get here */ |
645 | acpid_log(LOG_ERR, "execl(): %s\n", strerror(errno)); | |
645 | acpid_log(LOG_ERR, "execl(): %s", strerror(errno)); | |
646 | 646 | exit(EXIT_FAILURE); |
647 | 647 | } |
648 | 648 | |
654 | 654 | |
655 | 655 | if (logevents) { |
656 | 656 | if (WIFEXITED(status)) { |
657 | acpid_log(LOG_INFO, "action exited with status %d\n", | |
657 | acpid_log(LOG_INFO, "action exited with status %d", | |
658 | 658 | WEXITSTATUS(status)); |
659 | 659 | } else if (WIFSIGNALED(status)) { |
660 | acpid_log(LOG_INFO, "action exited on signal %d\n", | |
660 | acpid_log(LOG_INFO, "action exited on signal %d", | |
661 | 661 | WTERMSIG(status)); |
662 | 662 | } else { |
663 | acpid_log(LOG_INFO, "action exited with status %d\n", | |
663 | acpid_log(LOG_INFO, "action exited with status %d", | |
664 | 664 | status); |
665 | 665 | } |
666 | 666 | } |
675 | 675 | int client = rule->action.fd; |
676 | 676 | |
677 | 677 | if (logevents) { |
678 | acpid_log(LOG_INFO, "notifying client %s\n", rule->origin); | |
678 | acpid_log(LOG_INFO, "notifying client %s", rule->origin); | |
679 | 679 | } |
680 | 680 | |
681 | 681 | r = safe_write(client, event, strlen(event)); |
683 | 683 | struct ucred cred; |
684 | 684 | /* closed */ |
685 | 685 | acpid_log(LOG_NOTICE, |
686 | "client %s has disconnected\n", rule->origin); | |
686 | "client %s has disconnected", rule->origin); | |
687 | 687 | delist_rule(&client_list, rule); |
688 | 688 | ud_get_peercred(rule->action.fd, &cred); |
689 | 689 | if (cred.uid != 0) { |
722 | 722 | } while (ttl < len && ntries); |
723 | 723 | |
724 | 724 | if (!ntries) { |
725 | /* crap */ | |
726 | 725 | if (acpid_debug >= 2) { |
727 | acpid_log(LOG_ERR, "uh-oh! safe_write() timed out\n"); | |
726 | acpid_log(LOG_ERR, "safe_write() timed out"); | |
728 | 727 | } |
729 | 728 | return r; |
730 | 729 | } |
761 | 760 | buf[i++] = *p++; |
762 | 761 | } |
763 | 762 | if (acpid_debug >= 2) { |
764 | acpid_log(LOG_DEBUG, "expanded \"%s\" -> \"%s\"\n", cmd, buf); | |
763 | acpid_log(LOG_DEBUG, "expanded \"%s\" -> \"%s\"", cmd, buf); | |
765 | 764 | } |
766 | 765 | |
767 | 766 | return buf; |
780 | 779 | p++; |
781 | 780 | if (!*p) { |
782 | 781 | acpid_log(LOG_WARNING, |
783 | "invalid escape at EOL\n"); | |
782 | "invalid escape at EOL"); | |
784 | 783 | return -1; |
785 | 784 | } else if (*p != '%' && *p != 'e') { |
786 | 785 | acpid_log(LOG_WARNING, |
787 | "invalid escape \"%%%c\"\n", *p); | |
786 | "invalid escape \"%%%c\"", *p); | |
788 | 787 | r = -1; |
789 | 788 | } |
790 | 789 | } |
48 | 48 | |
49 | 49 | bytes = read(fd, &eventbuf.buffer, sizeof(eventbuf.buffer)); |
50 | 50 | |
51 | acpid_log(LOG_DEBUG, "inotify read bytes: %d\n", bytes); | |
51 | acpid_log(LOG_DEBUG, "inotify read bytes: %d", bytes); | |
52 | 52 | |
53 | 53 | /* eof is not expected */ |
54 | 54 | if (bytes == 0) |
55 | 55 | { |
56 | acpid_log(LOG_WARNING, "inotify fd eof encountered\n"); | |
56 | acpid_log(LOG_WARNING, "inotify fd eof encountered"); | |
57 | 57 | return; |
58 | 58 | } |
59 | 59 | else if (bytes < 0) |
60 | 60 | { |
61 | 61 | /* EINVAL means buffer wasn't big enough. See inotify(7). */ |
62 | acpid_log(LOG_ERR, "inotify read error: %s (%d)\n", | |
62 | acpid_log(LOG_ERR, "inotify read error: %s (%d)", | |
63 | 63 | strerror(errno), errno); |
64 | acpid_log(LOG_ERR, "disconnecting from inotify\n"); | |
64 | acpid_log(LOG_ERR, "disconnecting from inotify"); | |
65 | 65 | delete_connection(fd); |
66 | 66 | return; |
67 | 67 | } |
68 | 68 | |
69 | acpid_log(LOG_DEBUG, "inotify name len: %d\n", eventbuf.event.len); | |
69 | acpid_log(LOG_DEBUG, "inotify name len: %d", eventbuf.event.len); | |
70 | 70 | |
71 | 71 | /* if a name is included */ |
72 | 72 | if (eventbuf.event.len > 0) |
79 | 79 | strcat(devname, "/"); |
80 | 80 | strncat(devname, eventbuf.event.name, dnsize - strlen(devname) - 1); |
81 | 81 | |
82 | acpid_log(LOG_DEBUG, "inotify about to open: %s\n", devname); | |
82 | acpid_log(LOG_DEBUG, "inotify about to open: %s", devname); | |
83 | 83 | |
84 | 84 | open_inputfile(devname); |
85 | 85 | } |
97 | 97 | fd = inotify_init(); |
98 | 98 | |
99 | 99 | if (fd < 0) { |
100 | acpid_log(LOG_ERR, "inotify_init() failed: %s (%d)\n", | |
100 | acpid_log(LOG_ERR, "inotify_init() failed: %s (%d)", | |
101 | 101 | strerror(errno), errno); |
102 | 102 | return; |
103 | 103 | } |
104 | 104 | |
105 | acpid_log(LOG_DEBUG, "inotify fd: %d\n", fd); | |
105 | acpid_log(LOG_DEBUG, "inotify fd: %d", fd); | |
106 | 106 | |
107 | 107 | /* watch for new files being created in /dev/input */ |
108 | 108 | wd = inotify_add_watch(fd, ACPID_INPUTLAYERDIR, IN_CREATE); |
109 | 109 | |
110 | 110 | if (wd < 0) { |
111 | acpid_log(LOG_ERR, "inotify_add_watch() failed: %s (%d)\n", | |
111 | acpid_log(LOG_ERR, "inotify_add_watch() failed: %s (%d)", | |
112 | 112 | strerror(errno), errno); |
113 | 113 | close(fd); |
114 | 114 | return; |
115 | 115 | } |
116 | 116 | |
117 | acpid_log(LOG_DEBUG, "inotify wd: %d\n", wd); | |
117 | acpid_log(LOG_DEBUG, "inotify wd: %d", wd); | |
118 | 118 | |
119 | 119 | /* add a connection to the list */ |
120 | 120 | c.fd = fd; |
190 | 190 | nbytes = read(fd, &event, sizeof(event)); |
191 | 191 | |
192 | 192 | if (nbytes == 0) { |
193 | acpid_log(LOG_WARNING, "input layer connection closed\n"); | |
193 | acpid_log(LOG_WARNING, "input layer connection closed"); | |
194 | 194 | exit(EXIT_FAILURE); |
195 | 195 | } |
196 | 196 | |
199 | 199 | if (errno == EINTR) |
200 | 200 | return; |
201 | 201 | if (errno == ENODEV) { |
202 | acpid_log(LOG_WARNING, "input device has been disconnected\n"); | |
202 | acpid_log(LOG_WARNING, "input device has been disconnected"); | |
203 | 203 | delete_connection(fd); |
204 | 204 | return; |
205 | 205 | } |
206 | acpid_log(LOG_ERR, "input layer read error: %s (%d)\n", | |
206 | acpid_log(LOG_ERR, "input layer read error: %s (%d)", | |
207 | 207 | strerror(errno), errno); |
208 | 208 | if (++nerrs >= ACPID_MAX_ERRS) { |
209 | 209 | acpid_log(LOG_ERR, |
210 | 210 | "too many errors reading " |
211 | "input layer - aborting\n"); | |
211 | "input layer - aborting"); | |
212 | 212 | exit(EXIT_FAILURE); |
213 | 213 | } |
214 | 214 | return; |
219 | 219 | |
220 | 220 | if (nbytes != sizeof(event)) { |
221 | 221 | acpid_log(LOG_WARNING, "input layer unexpected length: " |
222 | "%d expected: %d\n", nbytes, sizeof(event)); | |
222 | "%d expected: %d", nbytes, sizeof(event)); | |
223 | 223 | return; |
224 | 224 | } |
225 | 225 | |
234 | 234 | if (logevents) { |
235 | 235 | acpid_log(LOG_INFO, |
236 | 236 | "lockfile present, not processing " |
237 | "input layer event \"%s\"\n", str); | |
237 | "input layer event \"%s\"", str); | |
238 | 238 | } |
239 | 239 | return; |
240 | 240 | } |
241 | 241 | |
242 | 242 | if (logevents) |
243 | 243 | acpid_log(LOG_INFO, |
244 | "received input layer event \"%s\"\n", str); | |
244 | "received input layer event \"%s\"", str); | |
245 | 245 | |
246 | 246 | /* send the event off to the handler */ |
247 | 247 | acpid_handle_event(str); |
248 | 248 | |
249 | 249 | if (logevents) |
250 | 250 | acpid_log(LOG_INFO, |
251 | "completed input layer event \"%s\"\n", str); | |
251 | "completed input layer event \"%s\"", str); | |
252 | 252 | } |
253 | 253 | |
254 | 254 | #define BITS_PER_LONG (sizeof(long) * 8) |
313 | 313 | } |
314 | 314 | |
315 | 315 | acpid_log(LOG_DEBUG, "input layer %s " |
316 | "opened successfully\n", filename); | |
316 | "opened successfully", filename); | |
317 | 317 | |
318 | 318 | /* add a connection to the list */ |
319 | 319 | c.fd = fd; |
349 | 349 | } |
350 | 350 | |
351 | 351 | if (!success) |
352 | acpid_log(LOG_ERR, "cannot open input layer\n"); | |
352 | acpid_log(LOG_ERR, "cannot open input layer"); | |
353 | 353 | |
354 | 354 | globfree(&globbuf); |
355 | 355 | } |
56 | 56 | /* if this message doesn't have the proper family ID, drop it */ |
57 | 57 | if (msg->nlmsg_type != acpi_ids_getfamily()) { |
58 | 58 | if (logevents) { |
59 | acpid_log(LOG_INFO, "wrong netlink family ID.\n"); | |
59 | acpid_log(LOG_INFO, "wrong netlink family ID."); | |
60 | 60 | } |
61 | 61 | return; |
62 | 62 | } |
65 | 65 | |
66 | 66 | if (len < 0) { |
67 | 67 | acpid_log(LOG_WARNING, |
68 | "wrong netlink controller message len: %d\n", len); | |
68 | "wrong netlink controller message len: %d", len); | |
69 | 69 | return; |
70 | 70 | } |
71 | 71 | |
89 | 89 | if (logevents) { |
90 | 90 | acpid_log(LOG_INFO, |
91 | 91 | "lockfile present, not processing " |
92 | "netlink event \"%s\"\n", buf); | |
92 | "netlink event \"%s\"", buf); | |
93 | 93 | } |
94 | 94 | return; |
95 | 95 | } |
96 | 96 | |
97 | 97 | if (logevents) |
98 | 98 | acpid_log(LOG_INFO, |
99 | "received netlink event \"%s\"\n", buf); | |
99 | "received netlink event \"%s\"", buf); | |
100 | 100 | |
101 | 101 | /* send the event off to the handler */ |
102 | 102 | acpid_handle_event(buf); |
103 | 103 | |
104 | 104 | if (logevents) |
105 | 105 | acpid_log(LOG_INFO, |
106 | "completed netlink event \"%s\"\n", buf); | |
106 | "completed netlink event \"%s\"", buf); | |
107 | 107 | } |
108 | 108 | } |
109 | 109 | |
147 | 147 | if (errno == EINTR) |
148 | 148 | return; |
149 | 149 | |
150 | acpid_log(LOG_ERR, "netlink read error: %s (%d)\n", | |
150 | acpid_log(LOG_ERR, "netlink read error: %s (%d)", | |
151 | 151 | strerror(errno), errno); |
152 | 152 | if (++nerrs >= ACPID_MAX_ERRS) { |
153 | 153 | acpid_log(LOG_ERR, |
154 | 154 | "too many errors reading via " |
155 | "netlink - aborting\n"); | |
155 | "netlink - aborting"); | |
156 | 156 | exit(EXIT_FAILURE); |
157 | 157 | } |
158 | 158 | return; |
159 | 159 | } |
160 | 160 | /* if an orderly shutdown has occurred, we're done */ |
161 | 161 | if (status == 0) { |
162 | acpid_log(LOG_WARNING, "netlink connection closed\n"); | |
162 | acpid_log(LOG_WARNING, "netlink connection closed"); | |
163 | 163 | exit(EXIT_FAILURE); |
164 | 164 | } |
165 | 165 | /* check to see if the address length has changed */ |
166 | 166 | if (msg.msg_namelen != sizeof(nladdr)) { |
167 | 167 | acpid_log(LOG_WARNING, "netlink unexpected length: " |
168 | "%d expected: %d\n", msg.msg_namelen, sizeof(nladdr)); | |
168 | "%d expected: %d", msg.msg_namelen, sizeof(nladdr)); | |
169 | 169 | return; |
170 | 170 | } |
171 | 171 | |
176 | 176 | |
177 | 177 | if (l < 0 || len > status) { |
178 | 178 | if (msg.msg_flags & MSG_TRUNC) { |
179 | acpid_log(LOG_WARNING, "netlink msg truncated (1)\n"); | |
179 | acpid_log(LOG_WARNING, "netlink msg truncated (1)"); | |
180 | 180 | return; |
181 | 181 | } |
182 | 182 | acpid_log(LOG_WARNING, |
183 | "malformed netlink msg, length %d\n", len); | |
183 | "malformed netlink msg, length %d", len); | |
184 | 184 | return; |
185 | 185 | } |
186 | 186 | |
191 | 191 | h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); |
192 | 192 | } |
193 | 193 | if (msg.msg_flags & MSG_TRUNC) { |
194 | acpid_log(LOG_WARNING, "netlink msg truncated (2)\n"); | |
194 | acpid_log(LOG_WARNING, "netlink msg truncated (2)"); | |
195 | 195 | return; |
196 | 196 | } |
197 | 197 | if (status) { |
198 | acpid_log(LOG_WARNING, "netlink remnant of size %d\n", status); | |
198 | acpid_log(LOG_WARNING, "netlink remnant of size %d", status); | |
199 | 199 | return; |
200 | 200 | } |
201 | 201 | |
208 | 208 | nl_mgrp(__u32 group) |
209 | 209 | { |
210 | 210 | if (group > 31) { |
211 | acpid_log(LOG_ERR, "Unexpected group number %d\n", group); | |
211 | acpid_log(LOG_ERR, "Unexpected group number %d", group); | |
212 | 212 | return 0; |
213 | 213 | } |
214 | 214 | return group ? (1 << (group - 1)) : 0; |
222 | 222 | /* open the appropriate netlink socket for input */ |
223 | 223 | if (rtnl_open_byproto( |
224 | 224 | &rth, nl_mgrp(acpi_ids_getgroup()), NETLINK_GENERIC) < 0) { |
225 | acpid_log(LOG_ERR, "cannot open generic netlink socket\n"); | |
226 | return; | |
227 | } | |
228 | ||
229 | acpid_log(LOG_DEBUG, "netlink opened successfully\n"); | |
225 | acpid_log(LOG_ERR, "cannot open generic netlink socket"); | |
226 | return; | |
227 | } | |
228 | ||
229 | acpid_log(LOG_DEBUG, "netlink opened successfully"); | |
230 | 230 | |
231 | 231 | /* add a connection to the list */ |
232 | 232 | c.fd = rth.fd; |
47 | 47 | if (logevents && event != NULL) { |
48 | 48 | acpid_log(LOG_INFO, |
49 | 49 | "lockfile present, not processing " |
50 | "event \"%s\"\n", event); | |
50 | "event \"%s\"", event); | |
51 | 51 | } |
52 | 52 | return; |
53 | 53 | } |
56 | 56 | if (event) { |
57 | 57 | if (logevents) { |
58 | 58 | acpid_log(LOG_INFO, |
59 | "procfs received event \"%s\"\n", event); | |
59 | "procfs received event \"%s\"", event); | |
60 | 60 | } |
61 | 61 | acpid_handle_event(event); |
62 | 62 | if (logevents) { |
63 | 63 | acpid_log(LOG_INFO, |
64 | "procfs completed event \"%s\"\n", event); | |
64 | "procfs completed event \"%s\"", event); | |
65 | 65 | } |
66 | 66 | } else if (errno == EPIPE) { |
67 | 67 | acpid_log(LOG_WARNING, |
68 | "events file connection closed\n"); | |
68 | "events file connection closed"); | |
69 | 69 | exit(EXIT_FAILURE); |
70 | 70 | } else { |
71 | 71 | static int nerrs; |
72 | 72 | if (++nerrs >= ACPID_MAX_ERRS) { |
73 | 73 | acpid_log(LOG_ERR, |
74 | 74 | "too many errors reading " |
75 | "events file - aborting\n"); | |
75 | "events file - aborting"); | |
76 | 76 | exit(EXIT_FAILURE); |
77 | 77 | } |
78 | 78 | } |
88 | 88 | if (fd < 0) { |
89 | 89 | if (errno == ENOENT) { |
90 | 90 | acpid_log(LOG_DEBUG, "Deprecated %s was not found. " |
91 | "Trying netlink and the input layer...\n", eventfile); | |
91 | "Trying netlink and the input layer...", eventfile); | |
92 | 92 | } else { |
93 | acpid_log(LOG_ERR, "can't open %s: %s (%d)\n", eventfile, | |
93 | acpid_log(LOG_ERR, "can't open %s: %s (%d)", eventfile, | |
94 | 94 | strerror(errno), errno); |
95 | 95 | } |
96 | 96 | return -1; |
101 | 101 | descriptors. */ |
102 | 102 | fcntl(fd, F_SETFD, FD_CLOEXEC); |
103 | 103 | |
104 | acpid_log(LOG_DEBUG, "proc fs opened successfully\n"); | |
104 | acpid_log(LOG_DEBUG, "proc fs opened successfully"); | |
105 | 105 | |
106 | 106 | /* add a connection to the list */ |
107 | 107 | c.fd = fd; |
131 | 131 | r = read(fd, buf+i, 1); |
132 | 132 | if (r < 0 && errno != EINTR) { |
133 | 133 | /* we should do something with the data */ |
134 | acpid_log(LOG_ERR, "read(): %s\n", | |
134 | acpid_log(LOG_ERR, "read(): %s", | |
135 | 135 | strerror(errno)); |
136 | 136 | return NULL; |
137 | 137 | } else if (r == 0) { |
175 | 175 | /* ??? This memory is leaked since it is never freed */ |
176 | 176 | buf = realloc(buf, buflen); |
177 | 177 | if (!buf) { |
178 | acpid_log(LOG_ERR, "malloc(%d): %s\n", | |
178 | acpid_log(LOG_ERR, "malloc(%d): %s", | |
179 | 179 | buflen, strerror(errno)); |
180 | 180 | return NULL; |
181 | 181 | } |
185 | 185 | r = read(fd, buf+i, 1); |
186 | 186 | if (r < 0 && errno != EINTR) { |
187 | 187 | /* we should do something with the data */ |
188 | acpid_log(LOG_ERR, "read(): %s\n", | |
188 | acpid_log(LOG_ERR, "read(): %s", | |
189 | 189 | strerror(errno)); |
190 | 190 | return NULL; |
191 | 191 | } else if (r == 0) { |
41 | 41 | /* the number of non-root clients that are connected */ |
42 | 42 | int non_root_clients; |
43 | 43 | |
44 | /* accept a new client connection */ | |
44 | 45 | static void |
45 | 46 | process_sock(int fd) |
46 | 47 | { |
52 | 53 | /* accept and add to our lists */ |
53 | 54 | cli_fd = ud_accept(fd, &creds); |
54 | 55 | if (cli_fd < 0) { |
55 | acpid_log(LOG_ERR, "can't accept client: %s\n", | |
56 | acpid_log(LOG_ERR, "can't accept client: %s", | |
56 | 57 | strerror(errno)); |
57 | 58 | accept_errors++; |
58 | 59 | if (accept_errors >= 5) { |
59 | acpid_log(LOG_ERR, "giving up\n"); | |
60 | acpid_log(LOG_ERR, "giving up"); | |
60 | 61 | clean_exit_with_status(EXIT_FAILURE); |
61 | 62 | } |
62 | 63 | return; |
63 | 64 | } |
64 | 65 | accept_errors = 0; |
65 | /* This check against clientmax is from the non-netlink 1.0.10. */ | |
66 | ||
67 | /* don't allow too many non-root clients */ | |
66 | 68 | if (creds.uid != 0 && non_root_clients >= clientmax) { |
67 | 69 | close(cli_fd); |
68 | acpid_log(LOG_ERR, | |
69 | "too many non-root clients\n"); | |
70 | acpid_log(LOG_ERR, "too many non-root clients"); | |
70 | 71 | return; |
71 | 72 | } |
72 | 73 | if (creds.uid != 0) { |
73 | 74 | non_root_clients++; |
74 | 75 | } |
75 | fcntl(cli_fd, F_SETFD, FD_CLOEXEC); | |
76 | snprintf(buf, sizeof(buf)-1, "%d[%d:%d]", | |
76 | ||
77 | /* don't leak fds when execing */ | |
78 | if (fcntl(cli_fd, F_SETFD, FD_CLOEXEC) < 0) { | |
79 | close(cli_fd); | |
80 | acpid_log(LOG_ERR, "fcntl() on client for FD_CLOEXEC: %s", | |
81 | strerror(errno)); | |
82 | return; | |
83 | } | |
84 | ||
85 | /* don't allow clients to block this */ | |
86 | if (fcntl(cli_fd, F_SETFL, O_NONBLOCK) < 0) { | |
87 | close(cli_fd); | |
88 | acpid_log(LOG_ERR, "fcntl() on client for O_NONBLOCK: %s", | |
89 | strerror(errno)); | |
90 | return; | |
91 | } | |
92 | ||
93 | snprintf(buf, sizeof(buf)-1, "%d[%d:%d]", | |
77 | 94 | creds.pid, creds.uid, creds.gid); |
78 | 95 | acpid_add_client(cli_fd, buf); |
79 | 96 | } |
80 | 97 | |
98 | /* set up the socket for client connections */ | |
81 | 99 | void |
82 | 100 | open_sock() |
83 | 101 | { |
86 | 104 | |
87 | 105 | fd = ud_create_socket(socketfile); |
88 | 106 | if (fd < 0) { |
89 | acpid_log(LOG_ERR, "can't open socket %s: %s\n", | |
107 | acpid_log(LOG_ERR, "can't open socket %s: %s", | |
90 | 108 | socketfile, strerror(errno)); |
91 | 109 | exit(EXIT_FAILURE); |
92 | 110 | } |
93 | fcntl(fd, F_SETFD, FD_CLOEXEC); | |
94 | chmod(socketfile, socketmode); | |
111 | ||
112 | /* don't leak fds when execing */ | |
113 | if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) { | |
114 | close(fd); | |
115 | acpid_log(LOG_ERR, "fcntl() on socket %s for FD_CLOEXEC: %s", | |
116 | socketfile, strerror(errno)); | |
117 | return; | |
118 | } | |
119 | ||
120 | /* avoid a potential hang */ | |
121 | if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { | |
122 | close(fd); | |
123 | acpid_log(LOG_ERR, "fcntl() on socket %s for O_NONBLOCK: %s", | |
124 | socketfile, strerror(errno)); | |
125 | return; | |
126 | } | |
127 | ||
128 | if (chmod(socketfile, socketmode) < 0) { | |
129 | close(fd); | |
130 | acpid_log(LOG_ERR, "chmod() on socket %s: %s", | |
131 | socketfile, strerror(errno)); | |
132 | return; | |
133 | } | |
134 | ||
135 | /* if we need to change the socket's group, do so */ | |
95 | 136 | if (socketgroup) { |
96 | 137 | struct group *gr; |
97 | 138 | struct stat buf; |
98 | gr = getgrnam(socketgroup); | |
139 | ||
140 | gr = getgrnam(socketgroup); | |
99 | 141 | if (!gr) { |
100 | acpid_log(LOG_ERR, "group %s does not exist\n", socketgroup); | |
142 | acpid_log(LOG_ERR, "group %s does not exist", socketgroup); | |
101 | 143 | exit(EXIT_FAILURE); |
102 | 144 | } |
103 | 145 | if (stat(socketfile, &buf) < 0) { |
104 | acpid_log(LOG_ERR, "can't stat %s\n", socketfile); | |
146 | acpid_log(LOG_ERR, "can't stat %s: %s", | |
147 | socketfile, strerror(errno)); | |
105 | 148 | exit(EXIT_FAILURE); |
106 | 149 | } |
107 | 150 | if (chown(socketfile, buf.st_uid, gr->gr_gid) < 0) { |
108 | acpid_log(LOG_ERR, "can't chown: %s\n", strerror(errno)); | |
151 | acpid_log(LOG_ERR, "can't chown %s: %s", | |
152 | socketfile, strerror(errno)); | |
109 | 153 | exit(EXIT_FAILURE); |
110 | 154 | } |
111 | 155 | } |
115 | 159 | c.process = process_sock; |
116 | 160 | add_connection(&c); |
117 | 161 | } |
118 |