1 /* Not particularly good interface to hal, for programs that used to use
10 #include <sys/types.h>
11 #include <sys/socket.h>
27 static void get_devinfo(gpointer device
, gpointer result
)
35 struct context
*ctx
= result
;
37 g_object_get(G_OBJECT(device
), "percentage", &percentage
,
41 "time-to-empty", &time_to_empty
,
42 "time-to-full", &time_to_full
,
44 if (kind
== UP_DEVICE_KIND_BATTERY
) {
45 if (ctx
->current
== ctx
->needed
) {
46 ctx
->percentage
= (int)percentage
;
49 ctx
->time
= time_to_empty
;
51 ctx
->time
= time_to_full
;
54 } else if (kind
== UP_DEVICE_KIND_LINE_POWER
) {
59 /* Fill the passed apm_info struct. */
60 static int upower_read_child(int battery
, apm_info
*info
)
63 GPtrArray
*devices
= NULL
;
70 #if !UP_CHECK_VERSION(0, 9, 99)
71 /* Allow a battery that was not present before to appear. */
72 up_client_enumerate_devices_sync(up
, NULL
, NULL
);
75 devices
= up_client_get_devices(up
);
80 info
->battery_flags
= 0;
81 info
->using_minutes
= 0;
83 struct context ctx
= {
85 .needed
= battery
- 1,
86 .state
= UP_DEVICE_STATE_UNKNOWN
,
92 g_ptr_array_foreach(devices
, &get_devinfo
, &ctx
);
94 info
->ac_line_status
= ctx
.ac
;
96 /* remaining_time and charge_level.percentage are not a mandatory
97 * keys, so if not present, -1 will be returned */
98 info
->battery_time
= ctx
.time
;
99 info
->battery_percentage
= ctx
.percentage
;
100 if (ctx
.state
== UP_DEVICE_STATE_DISCHARGING
) {
101 info
->battery_status
= BATTERY_STATUS_CHARGING
;
102 /* charge_level.warning and charge_level.low are not
103 * required to be available; this is good enough */
104 if (info
->battery_percentage
< 1)
105 info
->battery_status
= BATTERY_STATUS_CRITICAL
;
106 else if (info
->battery_percentage
< 10)
107 info
->battery_status
= BATTERY_STATUS_LOW
;
108 } else if (info
->ac_line_status
&& ctx
.state
== UP_DEVICE_STATE_CHARGING
) {
109 info
->battery_status
= BATTERY_STATUS_CHARGING
;
110 info
->battery_flags
= info
->battery_flags
| BATTERY_FLAGS_CHARGING
;
111 } else if (info
->ac_line_status
) {
112 /* Must be fully charged. */
113 info
->battery_status
= BATTERY_STATUS_HIGH
;
115 fprintf(stderr
, "unknown battery state\n");
118 if (ctx
.percentage
< 0) {
119 info
->battery_percentage
= 0;
120 info
->battery_time
= 0;
121 info
->battery_status
= BATTERY_STATUS_ABSENT
;
124 g_ptr_array_unref(devices
);
128 static int upower_read_work(int battery
, apm_info
*info
)
135 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, sp
) < 0) {
136 fprintf(stderr
, "socketpair: %s", strerror(errno
));
142 fprintf(stderr
, "fork: %s", strerror(errno
));
147 /* child process does work, writes failure or result back to parent */
149 status
= upower_read_child(battery
, info
);
151 cv
= send(sp
[1], &status
, sizeof(status
), 0);
154 cv
= send(sp
[1], info
, sizeof(*info
), 0);
160 child
= waitpid(child
, &status
, 0);
162 fprintf(stderr
, "waitpid: %s status=%d", strerror(errno
), status
);
166 cv
= recv(sp
[0], info
, sizeof(*info
), 0);
168 fprintf(stderr
, "recv: %s", strerror(errno
));
171 else if (cv
== sizeof(status
)) {
172 memcpy(&status
, info
, sizeof(status
));
175 else if (cv
!= sizeof(*info
)) {
176 fprintf(stderr
, "recv: unexpected size %zd", cv
);
191 int upower_supported(void)
194 return !(upower_read_work(1, &info
) < 0);
198 int upower_read(int battery
, apm_info
*info
)
200 static int retries
= 0;
202 if (upower_read_work(battery
, info
) < 0) {
204 if (retries
< MAX_RETRIES
)
205 return 0; /* fine immediately after hibernation */