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