Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name apmd.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -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 -fno-rounding-math -mconstructor-aliases -munwind-tables -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/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/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 -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/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/apmd/apmd.c
1/* $OpenBSD: apmd.c,v 1.106 2021/07/12 15:09:20 beck 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
78/* ARGSUSED */
79void
80sigexit(int signo)
81{
82 _exit(1);
83}
84
85void
86logmsg(int prio, const char *msg, ...)
87{
88 va_list ap;
89
90 va_start(ap, msg)__builtin_va_start(ap, msg);
91 if (debug) {
92 vfprintf(stderr(&__sF[2]), msg, ap);
93 fprintf(stderr(&__sF[2]), "\n");
94 } else {
95 vsyslog(prio, msg, ap);
96 }
97 va_end(ap)__builtin_va_end(ap);
98}
99
100void
101usage(void)
102{
103 fprintf(stderr(&__sF[2]),
104 "usage: %s [-AadHLs] [-f devname] [-S sockname] [-t seconds] "
105 "[-Z percent] [-z percent]\n", __progname);
106 exit(1);
107}
108
109void
110error(const char *fmt, const char *arg)
111{
112 char buf[128];
113
114 if (debug)
115 err(1, fmt, arg);
116 else {
117 strlcpy(buf, fmt, sizeof(buf));
118 strlcat(buf, ": %m", sizeof(buf));
119 syslog(LOG_ERR3, buf, arg);
120 exit(1);
121 }
122}
123
124
125/*
126 * tell the driver if it should display messages or not.
127 */
128void
129set_driver_messages(int fd, int mode)
130{
131 if (ioctl(fd, APM_IOC_PRN_CTL((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('A')) << 8) | ((6)))
, &mode) == -1)
132 logmsg(LOG_DEBUG7, "can't disable driver messages, error: %s",
133 strerror(errno(*__errno())));
134}
135
136int
137power_status(int fd, int force, struct apm_power_info *pinfo)
138{
139 struct apm_power_info bstate;
140 static struct apm_power_info last;
141 int acon = 0, priority = LOG_NOTICE5;
142
143 if (fd == -1) {
144 if (pinfo) {
145 bstate.battery_state = 255;
146 bstate.ac_state = 255;
147 bstate.battery_life = 0;
148 bstate.minutes_left = -1;
149 *pinfo = bstate;
150 }
151
152 return 0;
153 }
154
155 if (ioctl(fd, APM_IOC_GETPOWER((unsigned long)0x40000000 | ((sizeof(struct apm_power_info) &
0x1fff) << 16) | ((('A')) << 8) | ((3)))
, &bstate) == 0) {
156 /* various conditions under which we report status: something changed
157 * enough since last report, or asked to force a print */
158 if (bstate.ac_state == APM_AC_ON0x01)
159 acon = 1;
160 if (bstate.battery_state == APM_BATT_CRITICAL0x02 &&
161 bstate.battery_state != last.battery_state)
162 priority = LOG_EMERG0;
163 if (force ||
164 bstate.ac_state != last.ac_state ||
165 bstate.battery_state != last.battery_state ||
166 (bstate.minutes_left && bstate.minutes_left < 15) ||
167 abs(bstate.battery_life - last.battery_life) >= 10) {
168#ifdef __powerpc__
169 /*
170 * When the battery is charging, the estimated life
171 * time is in fact the estimated remaining charge time
172 * on Apple machines, so lie in the stats.
173 * We still want an useful message if the battery or
174 * ac status changes, however.
175 */
176 if (bstate.minutes_left != 0 &&
177 bstate.battery_state != APM_BATT_CHARGING0x03)
178#else
179 if ((int)bstate.minutes_left > 0)
180#endif
181 logmsg(priority, "battery status: %s. "
182 "external power status: %s. "
183 "estimated battery life %d%% (%u minutes)",
184 battstate(bstate.battery_state),
185 ac_state(bstate.ac_state),
186 bstate.battery_life,
187 bstate.minutes_left);
188 else
189 logmsg(priority, "battery status: %s. "
190 "external power status: %s. "
191 "estimated battery life %d%%",
192 battstate(bstate.battery_state),
193 ac_state(bstate.ac_state),
194 bstate.battery_life);
195 last = bstate;
196 }
197 if (pinfo)
198 *pinfo = bstate;
199 } else
200 logmsg(LOG_ERR3, "cannot fetch power status: %s", strerror(errno(*__errno())));
201
202 return acon;
203}
204
205int
206bind_socket(const char *sockname)
207{
208 struct sockaddr_un s_un;
209 mode_t old_umask;
210 int sock;
211
212 sock = socket(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000, 0);
213 if (sock == -1)
214 error("cannot create local socket", NULL((void *)0));
215
216 s_un.sun_family = AF_UNIX1;
217 strlcpy(s_un.sun_path, sockname, sizeof(s_un.sun_path));
218
219 /* remove it if present, we're moving in */
220 (void) remove(sockname);
221
222 old_umask = umask(077);
223 if (bind(sock, (struct sockaddr *)&s_un, sizeof(s_un)) == -1)
224 error("cannot bind on APM socket", NULL((void *)0));
225 umask(old_umask);
226 if (chmod(sockname, 0660) == -1 || chown(sockname, 0, 0) == -1)
227 error("cannot set socket mode/owner/group to 660/0/0", NULL((void *)0));
228
229 listen(sock, 1);
230
231 return sock;
232}
233
234void
235handle_client(int sock_fd, int ctl_fd)
236{
237 /* accept a handle from the client, process it, then clean up */
238 int cli_fd;
239 struct sockaddr_un from;
240 socklen_t fromlen;
241 struct apm_command cmd;
242 struct apm_reply reply;
243 int perfpol_mib[] = { CTL_HW6, HW_PERFPOLICY23 };
244 char perfpol[32];
245 size_t perfpol_sz = sizeof(perfpol);
246 int cpuspeed_mib[] = { CTL_HW6, HW_CPUSPEED12 };
247 int cpuspeed = 0;
248 size_t cpuspeed_sz = sizeof(cpuspeed);
249
250 fromlen = sizeof(from);
251 cli_fd = accept(sock_fd, (struct sockaddr *)&from, &fromlen);
252 if (cli_fd == -1) {
253 logmsg(LOG_INFO6, "client accept failure: %s", strerror(errno(*__errno())));
254 return;
255 }
256
257 if (recv(cli_fd, &cmd, sizeof(cmd), 0) != sizeof(cmd)) {
258 (void) close(cli_fd);
259 logmsg(LOG_INFO6, "client size botch");
260 return;
261 }
262
263 if (cmd.vno != APMD_VNO4) {
264 close(cli_fd); /* terminate client */
265 /* no error message, just drop it. */
266 return;
267 }
268
269 bzero(&reply, sizeof(reply));
270 power_status(ctl_fd, 0, &reply.batterystate);
271 switch (cmd.action) {
272 case SUSPEND:
273 reply.newstate = SUSPENDING;
274 reply.error = suspend(ctl_fd);
275 break;
276 case STANDBY:
277 reply.newstate = STANDING_BY;
278 reply.error = stand_by(ctl_fd);
279 break;
280 case HIBERNATE:
281 reply.newstate = HIBERNATING;
282 reply.error = hibernate(ctl_fd);
283 break;
284 case SETPERF_LOW:
285 reply.newstate = NORMAL;
286 logmsg(LOG_NOTICE5, "setting hw.perfpolicy to low");
287 setperfpolicy("low");
288 break;
289 case SETPERF_HIGH:
290 reply.newstate = NORMAL;
291 logmsg(LOG_NOTICE5, "setting hw.perfpolicy to high");
292 setperfpolicy("high");
293 break;
294 case SETPERF_AUTO:
295 reply.newstate = NORMAL;
296 logmsg(LOG_NOTICE5, "setting hw.perfpolicy to auto");
297 setperfpolicy("auto");
298 break;
299 default:
300 reply.newstate = NORMAL;
301 break;
302 }
303
304 reply.perfmode = PERF_NONE;
305 if (sysctl(perfpol_mib, 2, perfpol, &perfpol_sz, NULL((void *)0), 0) == -1)
306 logmsg(LOG_INFO6, "cannot read hw.perfpolicy");
307 else {
308 if (strcmp(perfpol, "manual") == 0 ||
309 strcmp(perfpol, "high") == 0) {
310 reply.perfmode = PERF_MANUAL;
311 } else if (strcmp(perfpol, "auto") == 0)
312 reply.perfmode = PERF_AUTO;
313 }
314
315 if (sysctl(cpuspeed_mib, 2, &cpuspeed, &cpuspeed_sz, NULL((void *)0), 0) == -1) {
316 logmsg(LOG_INFO6, "cannot read hw.cpuspeed");
317 cpuspeed = 0;
318 }
319 reply.cpuspeed = cpuspeed;
320 reply.vno = APMD_VNO4;
321 if (send(cli_fd, &reply, sizeof(reply), 0) != sizeof(reply))
322 logmsg(LOG_INFO6, "reply to client botched");
323 close(cli_fd);
324}
325
326int
327suspend(int ctl_fd)
328{
329 int error = 0;
330
331 logmsg(LOG_NOTICE5, "system suspending");
332 power_status(ctl_fd, 1, NULL((void *)0));
333 do_etc_file(_PATH_APM_ETC_SUSPEND"/etc/apm""/suspend");
334 sync();
335 sleep(1);
336
337 if (ioctl(ctl_fd, APM_IOC_SUSPEND((unsigned long)0x20000000 | ((0 & 0x1fff) << 16) |
((('A')) << 8) | ((2)))
, 0) == -1) {
338 error = errno(*__errno());
339 logmsg(LOG_WARNING4, "%s: %s", __func__, strerror(errno(*__errno())));
340 }
341
342 return error;
343}
344
345int
346stand_by(int ctl_fd)
347{
348 int error = 0;
349
350 logmsg(LOG_NOTICE5, "system entering standby");
351 power_status(ctl_fd, 1, NULL((void *)0));
352 do_etc_file(_PATH_APM_ETC_STANDBY"/etc/apm""/standby");
353 sync();
354 sleep(1);
355
356 if (ioctl(ctl_fd, APM_IOC_STANDBY((unsigned long)0x20000000 | ((0 & 0x1fff) << 16) |
((('A')) << 8) | ((1)))
, 0) == -1) {
357 error = errno(*__errno());
358 logmsg(LOG_WARNING4, "%s: %s", __func__, strerror(errno(*__errno())));
359 }
360
361 return error;
362}
363
364int
365hibernate(int ctl_fd)
366{
367 int error = 0;
368
369 logmsg(LOG_NOTICE5, "system hibernating");
370 power_status(ctl_fd, 1, NULL((void *)0));
371 do_etc_file(_PATH_APM_ETC_HIBERNATE"/etc/apm""/hibernate");
372 sync();
373 sleep(1);
374
375 if (ioctl(ctl_fd, APM_IOC_HIBERNATE((unsigned long)0x20000000 | ((0 & 0x1fff) << 16) |
((('A')) << 8) | ((9)))
, 0) == -1) {
376 error = errno(*__errno());
377 logmsg(LOG_WARNING4, "%s: %s", __func__, strerror(errno(*__errno())));
378 }
379
380 return error;
381}
382
383void
384resumed(int ctl_fd)
385{
386 do_etc_file(_PATH_APM_ETC_RESUME"/etc/apm""/resume");
387 logmsg(LOG_NOTICE5, "system resumed from sleep");
388 power_status(ctl_fd, 1, NULL((void *)0));
389}
390
391#define TIMO(10*60) (10*60) /* 10 minutes */
392#define AUTOACTION_GRACE_PERIOD(60) (60) /* 1mn after resume */
393
394int
395main(int argc, char *argv[])
396{
397 const char *fname = _PATH_APM_CTLDEV"/dev/apmctl";
398 int ctl_fd, sock_fd, ch, suspends, standbys, hibernates, resumes;
399 int autoaction = 0, autoaction_inflight = 0;
400 int autolimit = 0;
401 int statonly = 0;
402 int powerstatus = 0, powerbak = 0, powerchange = 0;
403 int noacsleep = 0;
404 struct timespec ts = {TIMO(10*60), 0}, sts = {0, 0};
405 struct timespec last_resume = { 0, 0 };
406 struct apm_power_info pinfo;
407 const char *sockname = _PATH_APM_SOCKET"/var/run/apmdev";
408 const char *errstr;
409 int kq, nchanges;
410 struct kevent ev[2];
411 int doperf = PERF_NONE;
412
413 while ((ch = getopt(argc, argv, "aACdHLsf:t:S:z:Z:")) != -1)
414 switch(ch) {
415 case 'a':
416 noacsleep = 1;
417 break;
418 case 'd':
419 debug = 1;
420 break;
421 case 'f':
422 fname = optarg;
423 break;
424 case 'S':
425 sockname = optarg;
426 break;
427 case 't':
428 ts.tv_sec = strtonum(optarg, 1, LLONG_MAX9223372036854775807LL, &errstr);
429 if (errstr != NULL((void *)0))
430 errx(1, "number of seconds is %s: %s", errstr,
431 optarg);
432 break;
433 case 's': /* status only */
434 statonly = 1;
435 break;
436 case 'A':
437 case 'C':
438 if (doperf != PERF_NONE)
439 usage();
440 doperf = PERF_AUTO;
441 setperfpolicy("auto");
442 break;
443 case 'L':
444 if (doperf != PERF_NONE)
445 usage();
446 doperf = PERF_MANUAL;
447 setperfpolicy("low");
448 break;
449 case 'H':
450 if (doperf != PERF_NONE)
451 usage();
452 doperf = PERF_MANUAL;
453 setperfpolicy("high");
454 break;
455 case 'Z':
456 autoaction = AUTO_HIBERNATE2;
457 autolimit = strtonum(optarg, 1, 100, &errstr);
458 if (errstr != NULL((void *)0))
459 errx(1, "battery percentage is %s: %s", errstr,
460 optarg);
461 break;
462 case 'z':
463 autoaction = AUTO_SUSPEND1;
464 autolimit = strtonum(optarg, 1, 100, &errstr);
465 if (errstr != NULL((void *)0))
466 errx(1, "battery percentage is %s: %s", errstr,
467 optarg);
468 break;
469 case '?':
470 default:
471 usage();
472 }
473
474 argc -= optind;
475 argv += optind;
476
477 if (argc != 0)
478 usage();
479
480 if (doperf == PERF_NONE)
481 doperf = PERF_MANUAL;
Value stored to 'doperf' is never read
482
483 if (debug == 0) {
484 if (daemon(0, 0) == -1)
485 error("failed to daemonize", NULL((void *)0));
486 openlog(__progname, LOG_CONS0x02, LOG_DAEMON(3<<3));
487 setlogmask(LOG_UPTO(LOG_NOTICE)((1 << ((5)+1)) - 1));
488 }
489
490 (void) signal(SIGTERM15, sigexit);
491 (void) signal(SIGHUP1, sigexit);
492 (void) signal(SIGINT2, sigexit);
493
494 if ((ctl_fd = open(fname, O_RDWR0x0002 | O_CLOEXEC0x10000)) == -1) {
495 if (errno(*__errno()) != ENXIO6 && errno(*__errno()) != ENOENT2)
496 error("cannot open device file `%s'", fname);
497 }
498
499 sock_fd = bind_socket(sockname);
500
501 power_status(ctl_fd, 1, &pinfo);
502
503 if (statonly)
504 exit(0);
505
506 if (unveil(_PATH_APM_ETC_DIR"/etc/apm", "rx") == -1)
507 err(1, "unveil %s", _PATH_APM_ETC_DIR"/etc/apm");
508 if (unveil(NULL((void *)0), NULL((void *)0)) == -1)
509 err(1, "unveil");
510
511 set_driver_messages(ctl_fd, APM_PRINT_OFF1);
512
513 kq = kqueue();
514 if (kq <= 0)
515 error("kqueue", NULL((void *)0));
516
517 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)
518 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)
;
519 if (ctl_fd == -1)
520 nchanges = 1;
521 else {
522 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)
523 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)
;
524 nchanges = 2;
525 }
526 if (kevent(kq, ev, nchanges, NULL((void *)0), 0, &sts) == -1)
527 error("kevent", NULL((void *)0));
528
529 for (;;) {
530 int rv, event, index;
531
532 sts = ts;
533
534 if ((rv = kevent(kq, NULL((void *)0), 0, ev, 1, &sts)) == -1)
535 break;
536
537 if (rv == 1 && ev->ident == sock_fd) {
538 handle_client(sock_fd, ctl_fd);
539 continue;
540 }
541
542 suspends = standbys = hibernates = resumes = 0;
543
544 if (rv == 0 && ctl_fd == -1) {
545 /* timeout and no way to query status */
546 continue;
547 } else if (rv == 0) {
548 /* wakeup for timeout: take status */
549 event = APM_POWER_CHANGE0x0006;
550 index = -1;
551 } else {
552 assert(rv == 1 && ev->ident == ctl_fd)((rv == 1 && ev->ident == ctl_fd) ? (void)0 : __assert2
("/usr/src/usr.sbin/apmd/apmd.c", 552, __func__, "rv == 1 && ev->ident == ctl_fd"
))
;
553 event = APM_EVENT_TYPE(ev->data)((ev->data) & 0xffff);
554 index = APM_EVENT_INDEX(ev->data)((ev->data) >> 16);
555 }
556
557 logmsg(LOG_DEBUG7, "apmevent %04x index %d", event, index);
558
559 switch (event) {
560 case APM_SUSPEND_REQ0x0002:
561 case APM_USER_SUSPEND_REQ0x000A:
562 case APM_CRIT_SUSPEND_REQ0x0008:
563 case APM_BATTERY_LOW0x0005:
564 suspends++;
565 break;
566 case APM_USER_STANDBY_REQ0x0009:
567 case APM_STANDBY_REQ0x0001:
568 standbys++;
569 break;
570 case APM_USER_HIBERNATE_REQ0x000D:
571 hibernates++;
572 break;
573#if 0
574 case APM_CANCEL:
575 suspends = standbys = 0;
576 break;
577#endif
578 case APM_NORMAL_RESUME0x0003:
579 case APM_CRIT_RESUME0x0004:
580 case APM_SYS_STANDBY_RESUME0x000B:
581 powerbak = power_status(ctl_fd, 0, &pinfo);
582 if (powerstatus != powerbak) {
583 powerstatus = powerbak;
584 powerchange = 1;
585 }
586 clock_gettime(CLOCK_MONOTONIC3, &last_resume);
587 autoaction_inflight = 0;
588 resumes++;
589 break;
590 case APM_POWER_CHANGE0x0006:
591 powerbak = power_status(ctl_fd, 0, &pinfo);
592 if (powerstatus != powerbak) {
593 powerstatus = powerbak;
594 powerchange = 1;
595 }
596
597 if (!powerstatus && autoaction &&
598 autolimit > (int)pinfo.battery_life) {
599 struct timespec graceperiod, now;
600
601 graceperiod = last_resume;
602 graceperiod.tv_sec += AUTOACTION_GRACE_PERIOD(60);
603 clock_gettime(CLOCK_MONOTONIC3, &now);
604
605 logmsg(LOG_NOTICE5,
606 "estimated battery life %d%%"
607 " below configured limit %d%%%s%s",
608 pinfo.battery_life, autolimit,
609 !autoaction_inflight ? "" : ", in flight",
610 timespeccmp(&now, &graceperiod, >)(((&now)->tv_sec == (&graceperiod)->tv_sec) ? (
(&now)->tv_nsec > (&graceperiod)->tv_nsec) :
((&now)->tv_sec > (&graceperiod)->tv_sec))
?
611 "" : ", grace period"
612 );
613
614 if (!autoaction_inflight &&
615 timespeccmp(&now, &graceperiod, >)(((&now)->tv_sec == (&graceperiod)->tv_sec) ? (
(&now)->tv_nsec > (&graceperiod)->tv_nsec) :
((&now)->tv_sec > (&graceperiod)->tv_sec))
) {
616 if (autoaction == AUTO_SUSPEND1)
617 suspends++;
618 else
619 hibernates++;
620 /* Block autoaction until next resume */
621 autoaction_inflight = 1;
622 }
623 }
624 break;
625 default:
626 ;
627 }
628
629 if ((standbys || suspends) && noacsleep &&
630 power_status(ctl_fd, 0, &pinfo))
631 logmsg(LOG_DEBUG7, "no! sleep! till brooklyn!");
632 else if (suspends)
633 suspend(ctl_fd);
634 else if (standbys)
635 stand_by(ctl_fd);
636 else if (hibernates)
637 hibernate(ctl_fd);
638 else if (resumes) {
639 resumed(ctl_fd);
640 }
641
642 if (powerchange) {
643 if (powerstatus)
644 do_etc_file(_PATH_APM_ETC_POWERUP"/etc/apm""/powerup");
645 else
646 do_etc_file(_PATH_APM_ETC_POWERDOWN"/etc/apm""/powerdown");
647 powerchange = 0;
648 }
649 }
650 error("kevent loop", NULL((void *)0));
651
652 return 1;
653}
654
655void
656setperfpolicy(char *policy)
657{
658 int hw_perfpol_mib[] = { CTL_HW6, HW_PERFPOLICY23 };
659 int hw_perf_mib[] = { CTL_HW6, HW_SETPERF13 };
660 int new_perf = -1;
661
662 if (strcmp(policy, "low") == 0) {
663 policy = "manual";
664 new_perf = 0;
665 } else if (strcmp(policy, "high") == 0) {
666 policy = "manual";
667 new_perf = 100;
668 }
669
670 if (sysctl(hw_perfpol_mib, 2, NULL((void *)0), NULL((void *)0),
671 policy, strlen(policy) + 1) == -1)
672 logmsg(LOG_INFO6, "cannot set hw.perfpolicy");
673
674 if (new_perf == -1)
675 return;
676
677 if (sysctl(hw_perf_mib, 2, NULL((void *)0), NULL((void *)0),
678 &new_perf, sizeof(new_perf)) == -1)
679 logmsg(LOG_INFO6, "cannot set hw.setperf");
680}
681
682void
683do_etc_file(const char *file)
684{
685 pid_t pid;
686 int status;
687 const char *prog;
688
689 /* If file doesn't exist, do nothing. */
690 if (access(file, X_OK0x01|R_OK0x04)) {
691 logmsg(LOG_DEBUG7, "do_etc_file(): cannot access file %s", file);
692 return;
693 }
694
695 prog = strrchr(file, '/');
696 if (prog)
697 prog++;
698 else
699 prog = file;
700
701 pid = fork();
702 switch (pid) {
703 case -1:
704 logmsg(LOG_ERR3, "failed to fork(): %s", strerror(errno(*__errno())));
705 return;
706 case 0:
707 /* We are the child. */
708 execl(file, prog, (char *)NULL((void *)0));
709 logmsg(LOG_ERR3, "failed to exec %s: %s", file, strerror(errno(*__errno())));
710 _exit(1);
711 /* NOTREACHED */
712 default:
713 /* We are the parent. */
714 wait4(pid, &status, 0, 0);
715 if (WIFEXITED(status)(((status) & 0177) == 0))
716 logmsg(LOG_DEBUG7, "%s exited with status %d", file,
717 WEXITSTATUS(status)(int)(((unsigned)(status) >> 8) & 0xff));
718 else
719 logmsg(LOG_ERR3, "%s exited abnormally.", file);
720 }
721}