Bug Summary

File:src/usr.sbin/apmd/apmd.c
Warning:line 493, column 3
Value stored to 'doperf' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name apmd.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/apmd/obj -resource-dir /usr/local/llvm16/lib/clang/16 -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/apmd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.sbin/apmd/apmd.c
1/* $OpenBSD: apmd.c,v 1.112 2023/04/27 10:51:27 kn Exp $ */
2
3/*
4 * Copyright (c) 1995, 1996 John T. Kohl
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 *
30 */
31
32#include <sys/stat.h>
33#include <sys/ioctl.h>
34#include <sys/socket.h>
35#include <sys/un.h>
36#include <sys/wait.h>
37#include <sys/event.h>
38#include <sys/time.h>
39#include <sys/sysctl.h>
40#include <assert.h>
41#include <stdarg.h>
42#include <stdio.h>
43#include <syslog.h>
44#include <fcntl.h>
45#include <unistd.h>
46#include <stdlib.h>
47#include <string.h>
48#include <signal.h>
49#include <errno(*__errno()).h>
50#include <err.h>
51#include <limits.h>
52#include <machine/apmvar.h>
53
54#include "pathnames.h"
55#include "apm-proto.h"
56
57#define AUTO_SUSPEND1 1
58#define AUTO_HIBERNATE2 2
59
60int debug = 0;
61
62extern char *__progname;
63
64void usage(void);
65int power_status(int fd, int force, struct apm_power_info *pinfo);
66int bind_socket(const char *sn);
67void handle_client(int sock_fd, int ctl_fd);
68int suspend(int ctl_fd);
69int stand_by(int ctl_fd);
70int hibernate(int ctl_fd);
71void resumed(int ctl_fd);
72void setperfpolicy(char *policy);
73void sigexit(int signo);
74void do_etc_file(const char *file);
75void error(const char *fmt, const char *arg);
76void set_driver_messages(int fd, int mode);
77
78void
79sigexit(int signo)
80{
81 _exit(1);
82}
83
84void
85logmsg(int prio, const char *msg, ...)
86{
87 va_list ap;
88
89 va_start(ap, msg)__builtin_va_start((ap), msg);
90 if (debug) {
91 vfprintf(stderr(&__sF[2]), msg, ap);
92 fprintf(stderr(&__sF[2]), "\n");
93 } else {
94 vsyslog(prio, msg, ap);
95 }
96 va_end(ap)__builtin_va_end((ap));
97}
98
99void
100usage(void)
101{
102 fprintf(stderr(&__sF[2]),
103 "usage: %s [-AadHLs] [-f devname] [-S sockname] [-t seconds] "
104 "[-Z percent] [-z percent]\n", __progname);
105 exit(1);
106}
107
108void
109error(const char *fmt, const char *arg)
110{
111 char buf[128];
112
113 if (debug)
114 err(1, fmt, arg);
115 else {
116 strlcpy(buf, fmt, sizeof(buf));
117 strlcat(buf, ": %m", sizeof(buf));
118 syslog(LOG_ERR3, buf, arg);
119 exit(1);
120 }
121}
122
123
124/*
125 * tell the driver if it should display messages or not.
126 */
127void
128set_driver_messages(int fd, int mode)
129{
130 if (ioctl(fd, APM_IOC_PRN_CTL((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('A')) << 8) | ((6)))
, &mode) == -1)
131 logmsg(LOG_DEBUG7, "can't disable driver messages, error: %s",
132 strerror(errno(*__errno())));
133}
134
135int
136power_status(int fd, int force, struct apm_power_info *pinfo)
137{
138 struct apm_power_info bstate;
139 static struct apm_power_info last;
140 int acon = 0, priority = LOG_NOTICE5;
141
142 if (fd == -1) {
143 if (pinfo) {
144 bstate.battery_state = 255;
145 bstate.ac_state = 255;
146 bstate.battery_life = 0;
147 bstate.minutes_left = -1;
148 *pinfo = bstate;
149 }
150
151 return 0;
152 }
153
154 if (ioctl(fd, APM_IOC_GETPOWER((unsigned long)0x40000000 | ((sizeof(struct apm_power_info) &
0x1fff) << 16) | ((('A')) << 8) | ((3)))
, &bstate) == 0) {
155 /* various conditions under which we report status: something changed
156 * enough since last report, or asked to force a print */
157 if (bstate.ac_state == APM_AC_ON0x01)
158 acon = 1;
159 if (bstate.battery_state == APM_BATT_CRITICAL0x02 &&
160 bstate.battery_state != last.battery_state)
161 priority = LOG_EMERG0;
162 if (force ||
163 bstate.ac_state != last.ac_state ||
164 bstate.battery_state != last.battery_state ||
165 ((bstate.battery_state != APM_BATT_CHARGING0x03) &&
166 (bstate.minutes_left && bstate.minutes_left < 15)) ||
167 abs(bstate.battery_life - last.battery_life) >= 10) {
168 if ((int)bstate.minutes_left > 0)
169 logmsg(priority, "battery status: %s. "
170 "external power status: %s. "
171 "estimated battery life %d%% "
172 "(%u minutes %s time estimate)",
173 battstate(bstate.battery_state),
174 ac_state(bstate.ac_state),
175 bstate.battery_life,
176 bstate.minutes_left,
177 (bstate.battery_state == APM_BATT_CHARGING0x03)
178 ? "recharge" : "life");
179 else
180 logmsg(priority, "battery status: %s. "
181 "external power status: %s. "
182 "estimated battery life %d%%",
183 battstate(bstate.battery_state),
184 ac_state(bstate.ac_state),
185 bstate.battery_life);
186 last = bstate;
187 }
188 if (pinfo)
189 *pinfo = bstate;
190 } else
191 logmsg(LOG_ERR3, "cannot fetch power status: %s", strerror(errno(*__errno())));
192
193 return acon;
194}
195
196int
197bind_socket(const char *sockname)
198{
199 struct sockaddr_un s_un;
200 mode_t old_umask;
201 int sock;
202
203 sock = socket(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000, 0);
204 if (sock == -1)
205 error("cannot create local socket", NULL((void *)0));
206
207 s_un.sun_family = AF_UNIX1;
208 strlcpy(s_un.sun_path, sockname, sizeof(s_un.sun_path));
209
210 /* remove it if present, we're moving in */
211 (void) remove(sockname);
212
213 old_umask = umask(077);
214 if (bind(sock, (struct sockaddr *)&s_un, sizeof(s_un)) == -1)
215 error("cannot bind on APM socket", NULL((void *)0));
216 umask(old_umask);
217 if (chmod(sockname, 0660) == -1 || chown(sockname, 0, 0) == -1)
218 error("cannot set socket mode/owner/group to 660/0/0", NULL((void *)0));
219
220 listen(sock, 1);
221
222 return sock;
223}
224
225void
226handle_client(int sock_fd, int ctl_fd)
227{
228 /* accept a handle from the client, process it, then clean up */
229 int cli_fd;
230 struct sockaddr_un from;
231 socklen_t fromlen;
232 struct apm_command cmd;
233 struct apm_reply reply;
234 int perfpol_mib[] = { CTL_HW6, HW_PERFPOLICY23 };
235 char perfpol[32];
236 size_t perfpol_sz = sizeof(perfpol);
237 int cpuspeed_mib[] = { CTL_HW6, HW_CPUSPEED12 };
238 int cpuspeed = 0;
239 size_t cpuspeed_sz = sizeof(cpuspeed);
240
241 fromlen = sizeof(from);
242 cli_fd = accept(sock_fd, (struct sockaddr *)&from, &fromlen);
243 if (cli_fd == -1) {
244 logmsg(LOG_INFO6, "client accept failure: %s", strerror(errno(*__errno())));
245 return;
246 }
247
248 if (recv(cli_fd, &cmd, sizeof(cmd), 0) != sizeof(cmd)) {
249 (void) close(cli_fd);
250 logmsg(LOG_INFO6, "client size botch");
251 return;
252 }
253
254 if (cmd.vno != APMD_VNO4) {
255 close(cli_fd); /* terminate client */
256 /* no error message, just drop it. */
257 return;
258 }
259
260 bzero(&reply, sizeof(reply));
261 power_status(ctl_fd, 0, &reply.batterystate);
262 switch (cmd.action) {
263 case SUSPEND:
264 reply.newstate = SUSPENDING;
265 reply.error = suspend(ctl_fd);
266 break;
267 case STANDBY:
268 reply.newstate = STANDING_BY;
269 reply.error = stand_by(ctl_fd);
270 break;
271 case HIBERNATE:
272 reply.newstate = HIBERNATING;
273 reply.error = hibernate(ctl_fd);
274 break;
275 case SETPERF_LOW:
276 reply.newstate = NORMAL;
277 logmsg(LOG_NOTICE5, "setting hw.perfpolicy to low");
278 setperfpolicy("low");
279 break;
280 case SETPERF_HIGH:
281 reply.newstate = NORMAL;
282 logmsg(LOG_NOTICE5, "setting hw.perfpolicy to high");
283 setperfpolicy("high");
284 break;
285 case SETPERF_AUTO:
286 reply.newstate = NORMAL;
287 logmsg(LOG_NOTICE5, "setting hw.perfpolicy to auto");
288 setperfpolicy("auto");
289 break;
290 default:
291 reply.newstate = NORMAL;
292 break;
293 }
294
295 reply.perfmode = PERF_NONE;
296 if (sysctl(perfpol_mib, 2, perfpol, &perfpol_sz, NULL((void *)0), 0) == -1)
297 logmsg(LOG_INFO6, "cannot read hw.perfpolicy");
298 else {
299 if (strcmp(perfpol, "manual") == 0 ||
300 strcmp(perfpol, "high") == 0) {
301 reply.perfmode = PERF_MANUAL;
302 } else if (strcmp(perfpol, "auto") == 0)
303 reply.perfmode = PERF_AUTO;
304 }
305
306 if (sysctl(cpuspeed_mib, 2, &cpuspeed, &cpuspeed_sz, NULL((void *)0), 0) == -1) {
307 logmsg(LOG_INFO6, "cannot read hw.cpuspeed");
308 cpuspeed = 0;
309 }
310 reply.cpuspeed = cpuspeed;
311 reply.vno = APMD_VNO4;
312 if (send(cli_fd, &reply, sizeof(reply), 0) != sizeof(reply))
313 logmsg(LOG_INFO6, "reply to client botched");
314 close(cli_fd);
315}
316
317/*
318 * Refresh the random file read by the bootblocks, and remove the +t bit
319 * which the bootblock use to track "reuse of the file".
320 */
321void
322fixrandom(void)
323{
324 char buf[512];
325 int fd;
326
327 fd = open("/etc/random.seed", O_WRONLY0x0001);
328 if (fd != -1) {
329 arc4random_buf(buf, sizeof buf);
330 write(fd, buf, sizeof buf);
331 fchmod(fd, 0600);
332 close(fd);
333 }
334}
335
336int
337suspend(int ctl_fd)
338{
339 int error = 0;
340
341 logmsg(LOG_NOTICE5, "system suspending");
342 power_status(ctl_fd, 1, NULL((void *)0));
343 fixrandom();
344 do_etc_file(_PATH_APM_ETC_SUSPEND"/etc/apm""/suspend");
345 sync();
346 sleep(1);
347
348 if (ioctl(ctl_fd, APM_IOC_SUSPEND((unsigned long)0x20000000 | ((0 & 0x1fff) << 16) |
((('A')) << 8) | ((2)))
, 0) == -1) {
349 error = errno(*__errno());
350 logmsg(LOG_WARNING4, "%s: %s", __func__, strerror(errno(*__errno())));
351 }
352
353 return error;
354}
355
356int
357stand_by(int ctl_fd)
358{
359 int error = 0;
360
361 logmsg(LOG_NOTICE5, "system entering standby");
362 power_status(ctl_fd, 1, NULL((void *)0));
363 fixrandom();
364 do_etc_file(_PATH_APM_ETC_STANDBY"/etc/apm""/standby");
365 sync();
366 sleep(1);
367
368 if (ioctl(ctl_fd, APM_IOC_STANDBY((unsigned long)0x20000000 | ((0 & 0x1fff) << 16) |
((('A')) << 8) | ((1)))
, 0) == -1) {
369 error = errno(*__errno());
370 logmsg(LOG_WARNING4, "%s: %s", __func__, strerror(errno(*__errno())));
371 }
372
373 return error;
374}
375
376int
377hibernate(int ctl_fd)
378{
379 int error = 0;
380
381 logmsg(LOG_NOTICE5, "system hibernating");
382 power_status(ctl_fd, 1, NULL((void *)0));
383 fixrandom();
384 do_etc_file(_PATH_APM_ETC_HIBERNATE"/etc/apm""/hibernate");
385 sync();
386 sleep(1);
387
388 if (ioctl(ctl_fd, APM_IOC_HIBERNATE((unsigned long)0x20000000 | ((0 & 0x1fff) << 16) |
((('A')) << 8) | ((9)))
, 0) == -1) {
389 error = errno(*__errno());
390 logmsg(LOG_WARNING4, "%s: %s", __func__, strerror(errno(*__errno())));
391 }
392
393 return error;
394}
395
396void
397resumed(int ctl_fd)
398{
399 do_etc_file(_PATH_APM_ETC_RESUME"/etc/apm""/resume");
400 logmsg(LOG_NOTICE5, "system resumed from sleep");
401 power_status(ctl_fd, 1, NULL((void *)0));
402}
403
404#define TIMO(10*60) (10*60) /* 10 minutes */
405#define AUTOACTION_GRACE_PERIOD(60) (60) /* 1mn after resume */
406
407int
408main(int argc, char *argv[])
409{
410 const char *fname = _PATH_APM_CTLDEV"/dev/apmctl";
411 int ctl_fd, sock_fd, ch, suspends, standbys, hibernates, resumes;
412 int autoaction = 0, autoaction_inflight = 0;
413 int autolimit = 0;
414 int statonly = 0;
415 int powerstatus = 0, powerbak = 0, powerchange = 0;
416 int noacsleep = 0;
417 struct timespec ts = {TIMO(10*60), 0}, sts = {0, 0};
418 struct timespec last_resume = { 0, 0 };
419 struct apm_power_info pinfo;
420 const char *sockname = _PATH_APM_SOCKET"/var/run/apmdev";
421 const char *errstr;
422 int kq, nchanges;
423 struct kevent ev[2];
424 int doperf = PERF_NONE;
425
426 while ((ch = getopt(argc, argv, "aACdHLsf:t:S:z:Z:")) != -1)
427 switch(ch) {
428 case 'a':
429 noacsleep = 1;
430 break;
431 case 'd':
432 debug = 1;
433 break;
434 case 'f':
435 fname = optarg;
436 break;
437 case 'S':
438 sockname = optarg;
439 break;
440 case 't':
441 ts.tv_sec = strtonum(optarg, 1, LLONG_MAX0x7fffffffffffffffLL, &errstr);
442 if (errstr != NULL((void *)0))
443 errx(1, "number of seconds is %s: %s", errstr,
444 optarg);
445 break;
446 case 's': /* status only */
447 statonly = 1;
448 break;
449 case 'A':
450 case 'C':
451 if (doperf != PERF_NONE)
452 usage();
453 doperf = PERF_AUTO;
454 setperfpolicy("auto");
455 break;
456 case 'L':
457 if (doperf != PERF_NONE)
458 usage();
459 doperf = PERF_MANUAL;
460 setperfpolicy("low");
461 break;
462 case 'H':
463 if (doperf != PERF_NONE)
464 usage();
465 doperf = PERF_MANUAL;
466 setperfpolicy("high");
467 break;
468 case 'Z':
469 autoaction = AUTO_HIBERNATE2;
470 autolimit = strtonum(optarg, 1, 100, &errstr);
471 if (errstr != NULL((void *)0))
472 errx(1, "battery percentage is %s: %s", errstr,
473 optarg);
474 break;
475 case 'z':
476 autoaction = AUTO_SUSPEND1;
477 autolimit = strtonum(optarg, 1, 100, &errstr);
478 if (errstr != NULL((void *)0))
479 errx(1, "battery percentage is %s: %s", errstr,
480 optarg);
481 break;
482 default:
483 usage();
484 }
485
486 argc -= optind;
487 argv += optind;
488
489 if (argc != 0)
490 usage();
491
492 if (doperf == PERF_NONE)
493 doperf = PERF_MANUAL;
Value stored to 'doperf' is never read
494
495 if (debug == 0) {
496 if (daemon(0, 0) == -1)
497 error("failed to daemonize", NULL((void *)0));
498 openlog(__progname, LOG_CONS0x02, LOG_DAEMON(3<<3));
499 setlogmask(LOG_UPTO(LOG_NOTICE)((1 << ((5)+1)) - 1));
500 }
501
502 (void) signal(SIGTERM15, sigexit);
503 (void) signal(SIGHUP1, sigexit);
504 (void) signal(SIGINT2, sigexit);
505
506 if ((ctl_fd = open(fname, O_RDWR0x0002 | O_CLOEXEC0x10000)) == -1) {
507 if (errno(*__errno()) != ENXIO6 && errno(*__errno()) != ENOENT2)
508 error("cannot open device file `%s'", fname);
509 }
510
511 sock_fd = bind_socket(sockname);
512
513 power_status(ctl_fd, 1, &pinfo);
514
515 if (statonly)
516 exit(0);
517
518 if (unveil(_PATH_APM_ETC_DIR"/etc/apm", "rx") == -1)
519 err(1, "unveil %s", _PATH_APM_ETC_DIR"/etc/apm");
520 if (unveil("/etc/random.seed", "w") == -1)
521 err(1, "unveil /etc/random.seed");
522 if (unveil(NULL((void *)0), NULL((void *)0)) == -1)
523 err(1, "unveil");
524
525 set_driver_messages(ctl_fd, APM_PRINT_OFF1);
526
527 kq = kqueue();
528 if (kq <= 0)
529 error("kqueue", NULL((void *)0));
530
531 EV_SET(&ev[0], sock_fd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR,do { struct kevent *__kevp = (&ev[0]); (__kevp)->ident
= (sock_fd); (__kevp)->filter = ((-1)); (__kevp)->flags
= (0x0001 | 0x0004 | 0x0020); (__kevp)->fflags = (0); (__kevp
)->data = (0); (__kevp)->udata = (((void *)0)); } while
(0)
532 0, 0, NULL)do { struct kevent *__kevp = (&ev[0]); (__kevp)->ident
= (sock_fd); (__kevp)->filter = ((-1)); (__kevp)->flags
= (0x0001 | 0x0004 | 0x0020); (__kevp)->fflags = (0); (__kevp
)->data = (0); (__kevp)->udata = (((void *)0)); } while
(0)
;
533 if (ctl_fd == -1)
534 nchanges = 1;
535 else {
536 EV_SET(&ev[1], ctl_fd, EVFILT_READ, EV_ADD | EV_ENABLE |do { struct kevent *__kevp = (&ev[1]); (__kevp)->ident
= (ctl_fd); (__kevp)->filter = ((-1)); (__kevp)->flags
= (0x0001 | 0x0004 | 0x0020); (__kevp)->fflags = (0); (__kevp
)->data = (0); (__kevp)->udata = (((void *)0)); } while
(0)
537 EV_CLEAR, 0, 0, NULL)do { struct kevent *__kevp = (&ev[1]); (__kevp)->ident
= (ctl_fd); (__kevp)->filter = ((-1)); (__kevp)->flags
= (0x0001 | 0x0004 | 0x0020); (__kevp)->fflags = (0); (__kevp
)->data = (0); (__kevp)->udata = (((void *)0)); } while
(0)
;
538 nchanges = 2;
539 }
540 if (kevent(kq, ev, nchanges, NULL((void *)0), 0, &sts) == -1)
541 error("kevent", NULL((void *)0));
542
543 for (;;) {
544 int rv, event, index;
545
546 sts = ts;
547
548 if ((rv = kevent(kq, NULL((void *)0), 0, ev, 1, &sts)) == -1)
549 break;
550
551 if (rv == 1 && ev->ident == sock_fd) {
552 handle_client(sock_fd, ctl_fd);
553 continue;
554 }
555
556 suspends = standbys = hibernates = resumes = 0;
557
558 if (rv == 0 && ctl_fd == -1) {
559 /* timeout and no way to query status */
560 continue;
561 } else if (rv == 0) {
562 /* wakeup for timeout: take status */
563 event = APM_POWER_CHANGE0x0006;
564 index = -1;
565 } else {
566 assert(rv == 1 && ev->ident == ctl_fd)((rv == 1 && ev->ident == ctl_fd) ? (void)0 : __assert2
("/usr/src/usr.sbin/apmd/apmd.c", 566, __func__, "rv == 1 && ev->ident == ctl_fd"
))
;
567 event = APM_EVENT_TYPE(ev->data)((ev->data) & 0xffff);
568 index = APM_EVENT_INDEX(ev->data)((ev->data) >> 16);
569 }
570
571 logmsg(LOG_DEBUG7, "apmevent %04x index %d", event, index);
572
573 switch (event) {
574 case APM_SUSPEND_REQ0x0002:
575 case APM_USER_SUSPEND_REQ0x000A:
576 case APM_CRIT_SUSPEND_REQ0x0008:
577 case APM_BATTERY_LOW0x0005:
578 suspends++;
579 break;
580 case APM_USER_STANDBY_REQ0x0009:
581 case APM_STANDBY_REQ0x0001:
582 standbys++;
583 break;
584 case APM_USER_HIBERNATE_REQ0x000D:
585 hibernates++;
586 break;
587 case APM_NORMAL_RESUME0x0003:
588 case APM_CRIT_RESUME0x0004:
589 case APM_SYS_STANDBY_RESUME0x000B:
590 powerbak = power_status(ctl_fd, 0, &pinfo);
591 if (powerstatus != powerbak) {
592 powerstatus = powerbak;
593 powerchange = 1;
594 }
595 clock_gettime(CLOCK_MONOTONIC3, &last_resume);
596 autoaction_inflight = 0;
597 resumes++;
598 break;
599 case APM_POWER_CHANGE0x0006:
600 powerbak = power_status(ctl_fd, 0, &pinfo);
601 if (powerstatus != powerbak) {
602 powerstatus = powerbak;
603 powerchange = 1;
604 }
605
606 if (!powerstatus && autoaction &&
607 autolimit > (int)pinfo.battery_life) {
608 struct timespec graceperiod, now;
609
610 graceperiod = last_resume;
611 graceperiod.tv_sec += AUTOACTION_GRACE_PERIOD(60);
612 clock_gettime(CLOCK_MONOTONIC3, &now);
613
614 logmsg(LOG_NOTICE5,
615 "estimated battery life %d%%"
616 " below configured limit %d%%%s%s",
617 pinfo.battery_life, autolimit,
618 !autoaction_inflight ? "" : ", in flight",
619 timespeccmp(&now, &graceperiod, >)(((&now)->tv_sec == (&graceperiod)->tv_sec) ? (
(&now)->tv_nsec > (&graceperiod)->tv_nsec) :
((&now)->tv_sec > (&graceperiod)->tv_sec))
?
620 "" : ", grace period"
621 );
622
623 if (!autoaction_inflight &&
624 timespeccmp(&now, &graceperiod, >)(((&now)->tv_sec == (&graceperiod)->tv_sec) ? (
(&now)->tv_nsec > (&graceperiod)->tv_nsec) :
((&now)->tv_sec > (&graceperiod)->tv_sec))
) {
625 if (autoaction == AUTO_SUSPEND1)
626 suspends++;
627 else
628 hibernates++;
629 /* Block autoaction until next resume */
630 autoaction_inflight = 1;
631 }
632 }
633 break;
634 default:
635 ;
636 }
637
638 if ((standbys || suspends) && noacsleep &&
639 power_status(ctl_fd, 0, &pinfo))
640 logmsg(LOG_DEBUG7, "no! sleep! till brooklyn!");
641 else if (suspends)
642 suspend(ctl_fd);
643 else if (standbys)
644 stand_by(ctl_fd);
645 else if (hibernates)
646 hibernate(ctl_fd);
647 else if (resumes) {
648 resumed(ctl_fd);
649 }
650
651 if (powerchange) {
652 if (powerstatus)
653 do_etc_file(_PATH_APM_ETC_POWERUP"/etc/apm""/powerup");
654 else
655 do_etc_file(_PATH_APM_ETC_POWERDOWN"/etc/apm""/powerdown");
656 powerchange = 0;
657 }
658 }
659 error("kevent loop", NULL((void *)0));
660
661 return 1;
662}
663
664void
665setperfpolicy(char *policy)
666{
667 int hw_perfpol_mib[] = { CTL_HW6, HW_PERFPOLICY23 };
668 int hw_perf_mib[] = { CTL_HW6, HW_SETPERF13 };
669 int new_perf = -1;
670
671 if (strcmp(policy, "low") == 0) {
672 policy = "manual";
673 new_perf = 0;
674 } else if (strcmp(policy, "high") == 0) {
675 policy = "manual";
676 new_perf = 100;
677 }
678
679 if (sysctl(hw_perfpol_mib, 2, NULL((void *)0), NULL((void *)0),
680 policy, strlen(policy) + 1) == -1)
681 logmsg(LOG_INFO6, "cannot set hw.perfpolicy");
682
683 if (new_perf == -1)
684 return;
685
686 if (sysctl(hw_perf_mib, 2, NULL((void *)0), NULL((void *)0),
687 &new_perf, sizeof(new_perf)) == -1)
688 logmsg(LOG_INFO6, "cannot set hw.setperf");
689}
690
691void
692do_etc_file(const char *file)
693{
694 pid_t pid;
695 int status;
696 const char *prog;
697
698 /* If file doesn't exist, do nothing. */
699 if (access(file, X_OK0x01|R_OK0x04)) {
700 logmsg(LOG_DEBUG7, "do_etc_file(): cannot access file %s", file);
701 return;
702 }
703
704 prog = strrchr(file, '/');
705 if (prog)
706 prog++;
707 else
708 prog = file;
709
710 pid = fork();
711 switch (pid) {
712 case -1:
713 logmsg(LOG_ERR3, "failed to fork(): %s", strerror(errno(*__errno())));
714 return;
715 case 0:
716 /* We are the child. */
717 execl(file, prog, (char *)NULL((void *)0));
718 logmsg(LOG_ERR3, "failed to exec %s: %s", file, strerror(errno(*__errno())));
719 _exit(1);
720 /* NOTREACHED */
721 default:
722 /* We are the parent. */
723 wait4(pid, &status, 0, 0);
724 if (WIFEXITED(status)(((status) & 0177) == 0))
725 logmsg(LOG_DEBUG7, "%s exited with status %d", file,
726 WEXITSTATUS(status)(int)(((unsigned)(status) >> 8) & 0xff));
727 else
728 logmsg(LOG_ERR3, "%s exited abnormally.", file);
729 }
730}