1 /* $NetBSD: powerd.c,v 1.12 2007/10/06 22:12:04 xtraeme Exp $ */
4 * Copyright (c) 2003 Wasabi Systems, Inc.
7 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
39 * Power management daemon for sysmon.
42 #include <sys/cdefs.h>
43 #include <sys/param.h>
44 #include <sys/event.h>
45 #include <sys/power.h>
55 #include <prop/proplib.h>
61 #define _PATH_DEV_POWER "/dev/power"
62 #define _PATH_POWERD_SCRIPTS "/etc/powerd/scripts"
64 static void usage(void) __dead
;
65 static void run_script(const char *[]);
66 static struct kevent
*allocchange(void);
67 static int wait_for_events(struct kevent
*, size_t);
68 static void dispatch_dev_power(struct kevent
*);
69 static void dispatch_power_event_state_change(int, power_event_t
*);
71 static const char *script_paths
[] = {
77 main(int argc
, char *argv
[])
79 struct kevent
*ev
, events
[16];
80 struct power_type power_type
;
86 while ((ch
= getopt(argc
, argv
, "d")) != -1) {
105 openlog("powerd", LOG_PID
| LOG_NOWAIT
, LOG_DAEMON
);
108 if ((kq
= kqueue()) == -1) {
109 syslog(LOG_ERR
, "kqueue: %m");
113 if ((fd
= open(_PATH_DEV_POWER
, O_RDONLY
|O_NONBLOCK
, 0600)) == -1) {
114 syslog(LOG_ERR
, "open %s: %m", _PATH_DEV_POWER
);
118 if (fcntl(fd
, F_SETFD
, FD_CLOEXEC
) == -1) {
119 syslog(LOG_ERR
, "Cannot set close on exec in power fd: %m");
123 if (ioctl(fd
, POWER_IOC_GET_TYPE
, &power_type
) == -1) {
124 syslog(LOG_ERR
, "POWER_IOC_GET_TYPE: %m");
128 (void)asprintf(&cp
, "%s/%s", _PATH_POWERD_SCRIPTS
,
129 power_type
.power_type
);
131 syslog(LOG_ERR
, "allocating script path: %m");
134 script_paths
[0] = cp
;
137 EV_SET(ev
, fd
, EVFILT_READ
, EV_ADD
| EV_ENABLE
,
138 0, 0, (intptr_t) dispatch_dev_power
);
141 void (*handler
)(struct kevent
*);
144 rv
= wait_for_events(events
, __arraycount(events
));
145 for (i
= 0; i
< rv
; i
++) {
146 handler
= (void *) events
[i
].udata
;
147 (*handler
)(&events
[i
]);
156 (void)fprintf(stderr
, "usage: %s [-d]\n", getprogname());
161 run_script(const char *argv
[])
163 char path
[MAXPATHLEN
+1];
166 for (i
= 0; i
< __arraycount(script_paths
); i
++) {
167 (void)snprintf(path
, sizeof(path
), "%s/%s", script_paths
[i
],
169 if (access(path
, R_OK
|X_OK
) == 0) {
176 (void)fprintf(stderr
, "running script: %s",
178 for (j
= 1; argv
[j
] != NULL
; j
++)
179 (void)fprintf(stderr
, " %s", argv
[j
]);
180 (void)fprintf(stderr
, "\n");
183 switch ((pid
= vfork())) {
185 syslog(LOG_ERR
, "fork to run script: %m");
190 (void) execv(path
, __UNCONST(argv
));
196 if (waitpid(pid
, &status
, 0) == -1) {
197 syslog(LOG_ERR
, "waitpid for %s: %m",
201 if (WIFEXITED(status
) &&
202 WEXITSTATUS(status
) != 0) {
204 "%s exited with status %d",
205 path
, WEXITSTATUS(status
));
206 } else if (!WIFEXITED(status
)) {
208 "%s terminated abnormally", path
);
217 syslog(LOG_ERR
, "no script for %s", argv
[0]);
219 (void)fprintf(stderr
, "no script for %s\n", argv
[0]);
222 static struct kevent changebuf
[8];
223 static size_t nchanges
;
225 static struct kevent
*
229 if (nchanges
== __arraycount(changebuf
)) {
230 (void)wait_for_events(NULL
, 0);
234 return &changebuf
[nchanges
++];
238 wait_for_events(struct kevent
*events
, size_t nevents
)
242 while ((rv
= kevent(kq
, nchanges
? changebuf
: NULL
, nchanges
,
243 events
, nevents
, NULL
)) < 0) {
245 if (errno
!= EINTR
) {
246 syslog(LOG_ERR
, "kevent: %m");
255 dispatch_dev_power(struct kevent
*ev
)
261 (void)fprintf(stderr
, "%s: %" PRId64
262 " event%s available\n", __func__
,
263 ev
->data
, ev
->data
> 1 ? "s" : "");
266 if (read(fd
, &pev
, sizeof(pev
)) != sizeof(pev
)) {
267 if (errno
== EWOULDBLOCK
)
269 syslog(LOG_ERR
, "read of %s: %m", _PATH_DEV_POWER
);
274 (void)fprintf(stderr
, "%s: event type %d\n",
275 __func__
, pev
.pev_type
);
277 switch (pev
.pev_type
) {
278 case POWER_EVENT_ENVSYS_STATE_CHANGE
:
279 case POWER_EVENT_SWITCH_STATE_CHANGE
:
280 dispatch_power_event_state_change(fd
, &pev
);
283 syslog(LOG_INFO
, "unknown %s event type: %d",
284 _PATH_DEV_POWER
, pev
.pev_type
);
291 dispatch_power_event_state_change(int fd
, power_event_t
*pev
)
293 prop_dictionary_t dict
;
299 error
= prop_dictionary_recv_ioctl(fd
, POWER_EVENT_RECVDICT
, &dict
);
302 printf("%s: prop_dictionary_recv_ioctl error=%d\n",
308 buf
= prop_dictionary_externalize(dict
);
313 obj
= prop_dictionary_get(dict
, "powerd-script-name");
314 argv
[0] = prop_string_cstring_nocopy(obj
);
316 obj
= prop_dictionary_get(dict
, "driver-name");
317 argv
[1] = prop_string_cstring_nocopy(obj
);
319 obj
= prop_dictionary_get(dict
, "powerd-event-name");
320 argv
[2] = prop_string_cstring_nocopy(obj
);
322 obj
= prop_dictionary_get(dict
, "sensor-name");
323 argv
[3] = prop_string_cstring_nocopy(obj
);
325 obj
= prop_dictionary_get(dict
, "state-description");
326 argv
[4] = prop_string_cstring_nocopy(obj
);