1 /*
2 * The olsr.org Optimized Link-State Routing daemon (olsrd)
3 *
4 * (c) by the OLSR project
5 *
6 * See our Git repository to find out who worked on this file
7 * and thus is a copyright holder on it.
8 *
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 *
15 * * Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * * Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in
19 * the documentation and/or other materials provided with the
20 * distribution.
21 * * Neither the name of olsr.org, olsrd nor the names of its
22 * contributors may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 *
38 * Visit http://www.olsr.org for more information.
39 *
40 * If you find this software useful feel free to make a donation
41 * to the project. For more information see the website or contact
42 * the copyright holders.
43 *
44 */
45
46 /*
47 * Much of the ACPI code is taken from Florian Schaefers
48 * Acpi-Power Enlightenment epplet
49 */
50
51 #ifdef __linux__
52
53 #include "apm.h"
54 #include "defs.h"
55 #include <stdio.h>
56 #include <string.h>
57 #include <stdlib.h>
58
59 /* APM related stuff */
60
61 #define APM_PROC "/proc/apm"
62
63 struct linux_apm_info {
64 char driver_version[10];
65 int apm_version_major;
66 int apm_version_minor;
67 int apm_flags;
68 int ac_line_status;
69 int battery_status;
70 int battery_flags;
71 int battery_percentage;
72 int battery_time;
73 int using_minutes;
74 };
75
76 /* ACPI related stuff */
77 static const char *const acpi_info[] = {
78 "/proc/acpi/battery/0/info",
79 "/proc/acpi/battery/1/info",
80 "/proc/acpi/battery/BATA/info",
81 "/proc/acpi/battery/BAT0/info",
82 "/proc/acpi/battery/BAT1/info"
83 };
84
85 static const char *const acpi_state[] = {
86 "/proc/acpi/battery/0/status",
87 "/proc/acpi/battery/1/status",
88 "/proc/acpi/battery/BATA/state",
89 "/proc/acpi/battery/BAT0/state",
90 "/proc/acpi/battery/BAT1/state"
91 };
92
93 #define ACPI_BT_CNT ARRAYSIZE(acpi_state)
94
95 static const char *const acpi_ac[] = {
96 "/proc/acpi/ac_adapter/0/status",
97 "/proc/acpi/ac_adapter/AC/state",
98 "/proc/acpi/ac_adapter/ACAD/state"
99 };
100
101 #define ACPI_AC_CNT ARRAYSIZE(acpi_ac)
102
103 #define USE_APM 1
104 #define USE_ACPI 2
105
106 static int method;
107
108 static int fd_index;
109
110 static int ac_power_on;
111
112 /* Prototypes */
113
114 static int apm_read_apm(struct olsr_apm_info *);
115
116 static int apm_read_acpi(struct olsr_apm_info *);
117
118 static int acpi_probe(void);
119
120 int
apm_init(void)121 apm_init(void)
122 {
123 struct olsr_apm_info ainfo;
124
125 method = -1;
126 OLSR_PRINTF(3, "Initializing APM\n");
127
128 if ((((fd_index = acpi_probe()) >= 0) || ac_power_on) && apm_read_acpi(&ainfo))
129 method = USE_ACPI;
130 else if (apm_read_apm(&ainfo))
131 method = USE_APM;
132
133 if (method != -1)
134 apm_printinfo(&ainfo);
135
136 return method;
137 }
138
139 void
apm_printinfo(struct olsr_apm_info * ainfo)140 apm_printinfo(struct olsr_apm_info *ainfo)
141 {
142 OLSR_PRINTF(5, "APM info:\n\tAC status %d\n\tBattery percentage %d%%\n\tBattery time left %d mins\n\n", ainfo->ac_line_status,
143 ainfo->battery_percentage, ainfo->battery_time_left);
144
145 ainfo = NULL; /* squelch compiler warnings */
146 }
147
148 int
apm_read(struct olsr_apm_info * ainfo)149 apm_read(struct olsr_apm_info *ainfo)
150 {
151 switch (method) {
152 case USE_APM:
153 return apm_read_apm(ainfo);
154 case USE_ACPI:
155 return apm_read_acpi(ainfo);
156 default:
157 break;
158 }
159 return 0;
160 }
161
162 static int
apm_read_apm(struct olsr_apm_info * ainfo)163 apm_read_apm(struct olsr_apm_info *ainfo)
164 {
165 char buffer[100];
166 char units[10];
167 FILE *apm_procfile;
168 struct linux_apm_info lainfo;
169
170 /* Open procfile */
171 if ((apm_procfile = fopen(APM_PROC, "r")) == NULL)
172 return 0;
173
174 if (fgets(buffer, sizeof(buffer), apm_procfile) == NULL) {
175 fclose(apm_procfile);
176 /* Try re-opening the file */
177 if ((apm_procfile = fopen(APM_PROC, "r")) == NULL)
178 return 0;
179
180 if (fgets(buffer, sizeof(buffer), apm_procfile) == NULL) {
181 /* Giving up */
182 fprintf(stderr, "OLSRD: Could not read APM info - setting willingness to default");
183 fclose(apm_procfile);
184 return 0;
185 }
186 }
187 fclose(apm_procfile);
188
189 //printf("READ: %s\n", buffer);
190
191 /* Get the info */
192 sscanf(buffer, "%10s %d.%d %x %x %x %x %d%% %d %10s\n", lainfo.driver_version, &lainfo.apm_version_major, &lainfo.apm_version_minor,
193 &lainfo.apm_flags, &lainfo.ac_line_status, &lainfo.battery_status, &lainfo.battery_flags, &lainfo.battery_percentage,
194 &lainfo.battery_time, units);
195
196 lainfo.using_minutes = strncmp(units, "min", 3) ? 0 : 1;
197
198 /*
199 * Should take care of old APM type info here
200 */
201
202 /*
203 * Fix possible percentage error
204 */
205 if (lainfo.battery_percentage > 100)
206 lainfo.battery_percentage = -1;
207
208 /* Fill the provided struct */
209
210 if (lainfo.ac_line_status)
211 ainfo->ac_line_status = OLSR_AC_POWERED;
212 else
213 ainfo->ac_line_status = OLSR_BATTERY_POWERED;
214
215 ainfo->battery_percentage = lainfo.battery_percentage;
216 ainfo->battery_time_left = lainfo.battery_time;
217
218 return 1;
219 }
220
221 static int
apm_read_acpi(struct olsr_apm_info * ainfo)222 apm_read_acpi(struct olsr_apm_info *ainfo)
223 {
224 FILE *fd;
225 int bat_max = 5000; /* Find some sane value */
226 int bat_val = 0;
227
228 /* reporbe in case ac status changed */
229 fd_index = acpi_probe();
230
231 /* No battery was found */
232 if (fd_index < 0) {
233 /* but we have ac */
234 if (ac_power_on) {
235 ainfo->ac_line_status = OLSR_AC_POWERED;
236
237 ainfo->battery_percentage = -1;
238
239 return 1;
240 }
241
242 /* not enough info */
243 return 0;
244 }
245
246 /* Get maxvalue */
247 if ((fd = fopen(acpi_info[fd_index], "r")) == NULL)
248 return 0;
249
250 for (;;) {
251 char s1[32], s2[32], s3[32], s4[32], inbuff[127];
252 if (fgets(inbuff, sizeof(inbuff), fd) == NULL)
253 break;
254
255 sscanf(inbuff, "%32s %32s %32s %32s", s1, s2, s3, s4);
256 if (!strcasecmp(s2, "full"))
257 bat_max = atoi(s4);
258 }
259 fclose(fd);
260
261 if ((fd = fopen(acpi_state[fd_index], "r")) == NULL)
262 return 0;
263
264 /* Extract battery status */
265 for (;;) {
266 char s1[32], s2[32], s3[32], s4[32], inbuff[127];
267 if (fgets(inbuff, sizeof(inbuff), fd) == NULL)
268 break;
269 sscanf(inbuff, "%32s %32s %32s %32s", s1, s2, s3, s4);
270
271 /* find remaining juice */
272 if (!strcasecmp(s1, "Remaining"))
273 bat_val = atoi(s3);
274 }
275 fclose(fd);
276
277 ainfo->ac_line_status = ac_power_on ? OLSR_AC_POWERED : OLSR_BATTERY_POWERED;
278
279 /* sanitise ACPI battery data */
280 bat_max = abs(bat_max);
281 bat_val = abs(bat_val);
282 if (bat_val > bat_max) {
283 bat_val = bat_max;
284 }
285
286 if (bat_max == 0) {
287 /* protection against stupid acpi data */
288 ainfo->battery_percentage = 0;
289 }
290 else {
291 ainfo->battery_percentage = (bat_val >= bat_max) ? 100 : (bat_val * 100 / bat_max);
292 }
293
294 return 1;
295 }
296
297 static int
acpi_probe(void)298 acpi_probe(void)
299 {
300 unsigned int i;
301
302 /* First check for AC power */
303 ac_power_on = 0;
304
305 for (i = 0; i < ACPI_AC_CNT; i++) {
306 char s1[32], s2[32];
307 int rc;
308 FILE *fd = fopen(acpi_ac[i], "r");
309
310 /* Try opening the info file */
311 if (fd == NULL)
312 continue;
313
314 /* Extract info */
315 rc = fscanf(fd, "%32s %32s", s1, s2);
316
317 /* Close info entry */
318 fclose(fd);
319
320 if (rc < 2)
321 continue;
322
323 /* Running on AC power */
324 if (!strcasecmp(s2, "on-line")) {
325
326 /* ac power enabled */
327 ac_power_on = 1;
328
329 break;
330 }
331 }
332
333 /* Only checking the first found battery entry... */
334 for (i = 0; i < ACPI_BT_CNT; i++) {
335 char s1[32], s2[32];
336 int rc;
337 FILE *fd = fopen(acpi_info[i], "r");
338
339 /* Try opening the info file */
340 if (fd == NULL)
341 continue;
342
343 /* Extract info */
344 rc = fscanf(fd, "%32s %32s", s1, s2);
345
346 /* Close info entry */
347 fclose(fd);
348
349 if (rc < 2)
350 continue;
351
352 /* Check if battery is present */
353 if ((!strcasecmp(s1, "present:")) && (!strcasecmp(s2, "no")))
354 continue;
355
356 /* Open the corresponding state file */
357 if ((fd = fopen(acpi_state[i], "r")) == NULL)
358 continue;
359
360 fclose(fd);
361 return i;
362 }
363
364 /* No battery found */
365 return -1;
366 }
367 #endif /* __linux__ */
368
369 /*
370 * Local Variables:
371 * c-basic-offset: 2
372 * indent-tabs-mode: nil
373 * End:
374 */
375