Bugfix: gw_iface with a empty routingtable no longer causes a crash
[monky] / src / linux.c
1 /* Conky, a system monitor, based on torsmo
2  *
3  * Any original torsmo code is licensed under the BSD license
4  *
5  * All code written since the fork of torsmo is licensed under the GPL
6  *
7  * Please see COPYING for details
8  *
9  * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
10  * Copyright (c) 2007 Toni Spets
11  * Copyright (c) 2005-2008 Brenden Matthews, Philip Kovacs, et. al.
12  *      (see AUTHORS)
13  * All rights reserved.
14  *
15  * This program is free software: you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation, either version 3 of the License, or
18  * (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  * You should have received a copy of the GNU General Public License
25  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
26  *
27  * $Id$ */
28
29 #include "conky.h"
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <dirent.h>
34 #include <ctype.h>
35 #include <errno.h>
36 #include <limits.h>
37 #include <sys/types.h>
38 #include <sys/sysinfo.h>
39 #include <sys/stat.h>
40 #ifndef HAVE_CLOCK_GETTIME
41 #include <sys/time.h>
42 #endif
43 #include <fcntl.h>
44 #include <unistd.h>
45 // #include <assert.h>
46 #include <time.h>
47 #include "top.h"
48
49 #include <sys/ioctl.h>
50 #include <sys/socket.h>
51 #include <netinet/in.h>
52 #include <linux/sockios.h>
53 #include <net/if.h>
54 #include <arpa/inet.h>
55 #ifdef _NET_IF_H
56 #define _LINUX_IF_H
57 #endif
58 #include <linux/route.h>
59 #include <math.h>
60
61 #ifdef HAVE_IWLIB
62 #include <iwlib.h>
63 #endif
64
65 #define SHORTSTAT_TEMPL "%*s %llu %llu %llu"
66 #define LONGSTAT_TEMPL "%*s %llu %llu %llu "
67
68 static int show_nice_processes;
69
70 /* This flag tells the linux routines to use the /proc system where possible,
71  * even if other api's are available, e.g. sysinfo() or getloadavg().
72  * the reason for this is to allow for /proc-based distributed monitoring.
73  * using a flag in this manner creates less confusing code. */
74 static int prefer_proc = 0;
75
76 void prepare_update(void)
77 {
78 }
79
80 void update_uptime(void)
81 {
82 #ifdef HAVE_SYSINFO
83         if (!prefer_proc) {
84                 struct sysinfo s_info;
85
86                 sysinfo(&s_info);
87                 info.uptime = (double) s_info.uptime;
88         } else
89 #endif
90         {
91                 static int rep = 0;
92                 FILE *fp;
93
94                 if (!(fp = open_file("/proc/uptime", &rep))) {
95                         info.uptime = 0.0;
96                         return;
97                 }
98                 fscanf(fp, "%lf", &info.uptime);
99                 fclose(fp);
100         }
101         info.mask |= (1 << INFO_UPTIME);
102 }
103
104 int check_mount(char *s)
105 {
106         int ret = 0;
107         FILE *mtab = fopen("/etc/mtab", "r");
108
109         if (mtab) {
110                 char buf1[256], buf2[128];
111
112                 while (fgets(buf1, 256, mtab)) {
113                         sscanf(buf1, "%*s %128s", buf2);
114                         if (!strcmp(s, buf2)) {
115                                 ret = 1;
116                                 break;
117                         }
118                 }
119                 fclose(mtab);
120         } else {
121                 ERR("Could not open mtab");
122         }
123         return ret;
124 }
125
126 /* these things are also in sysinfo except Buffers:
127  * (that's why I'm reading them from proc) */
128
129 void update_meminfo(void)
130 {
131         FILE *meminfo_fp;
132         static int rep = 0;
133
134         /* unsigned int a; */
135         char buf[256];
136
137         info.mem = info.memmax = info.swap = info.swapmax = info.bufmem =
138                 info.buffers = info.cached = 0;
139
140         if (!(meminfo_fp = open_file("/proc/meminfo", &rep))) {
141                 return;
142         }
143
144         while (!feof(meminfo_fp)) {
145                 if (fgets(buf, 255, meminfo_fp) == NULL) {
146                         break;
147                 }
148
149                 if (strncmp(buf, "MemTotal:", 9) == 0) {
150                         sscanf(buf, "%*s %llu", &info.memmax);
151                 } else if (strncmp(buf, "MemFree:", 8) == 0) {
152                         sscanf(buf, "%*s %llu", &info.mem);
153                 } else if (strncmp(buf, "SwapTotal:", 10) == 0) {
154                         sscanf(buf, "%*s %llu", &info.swapmax);
155                 } else if (strncmp(buf, "SwapFree:", 9) == 0) {
156                         sscanf(buf, "%*s %llu", &info.swap);
157                 } else if (strncmp(buf, "Buffers:", 8) == 0) {
158                         sscanf(buf, "%*s %llu", &info.buffers);
159                 } else if (strncmp(buf, "Cached:", 7) == 0) {
160                         sscanf(buf, "%*s %llu", &info.cached);
161                 }
162         }
163
164         info.mem = info.memmax - info.mem;
165         info.swap = info.swapmax - info.swap;
166
167         info.bufmem = info.cached + info.buffers;
168
169         info.mask |= (1 << INFO_MEM) | (1 << INFO_BUFFERS);
170
171         fclose(meminfo_fp);
172 }
173
174 int get_laptop_mode(void)
175 {
176         FILE *fp;
177         int val = -1;
178
179         if ((fp = fopen("/proc/sys/vm/laptop_mode", "r")) != NULL)
180                 fscanf(fp, "%d\n", &val);
181         fclose(fp);
182         return val;
183 }
184
185 /* my system says:
186  * # cat /sys/block/sda/queue/scheduler
187  * noop [anticipatory] cfq
188  */
189 char *get_ioscheduler(char *disk)
190 {
191         FILE *fp;
192         char buf[128];
193
194         if (!disk)
195                 return strndup("n/a", text_buffer_size);
196
197         snprintf(buf, 127, "/sys/block/%s/queue/scheduler", disk);
198         if ((fp = fopen(buf, "r")) == NULL) {
199                 return strndup("n/a", text_buffer_size);
200         }
201         while (!feof(fp)) {
202                 fscanf(fp, "%127s", buf);
203                 if (buf[0] == '[') {
204                         buf[strlen(buf) - 1] = '\0';
205                         fclose(fp);
206                         return strndup(buf + 1, text_buffer_size);
207                 }
208         }
209         fclose(fp);
210         return strndup("n/a", text_buffer_size);
211 }
212
213 int interface_up(const char *dev)
214 {
215         int fd;
216         struct ifreq ifr;
217
218         if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
219                 CRIT_ERR("could not create sockfd");
220                 return 0;
221         }
222         strncpy(ifr.ifr_name, dev, IFNAMSIZ);
223         if (ioctl(fd, SIOCGIFFLAGS, &ifr)) {
224                 /* if device does not exist, treat like not up */
225                 if (errno != ENODEV)
226                         perror("SIOCGIFFLAGS");
227                 goto END_FALSE;
228         }
229
230         if (!(ifr.ifr_flags & IFF_UP)) /* iface is not up */
231                 goto END_FALSE;
232         if (ifup_strictness == IFUP_UP)
233                 goto END_TRUE;
234
235         if (!(ifr.ifr_flags & IFF_RUNNING))
236                 goto END_FALSE;
237         if (ifup_strictness == IFUP_LINK)
238                 goto END_TRUE;
239
240         if (ioctl(fd, SIOCGIFADDR, &ifr)) {
241                 perror("SIOCGIFADDR");
242                 goto END_FALSE;
243         }
244         if (((struct sockaddr_in *)&(ifr.ifr_ifru.ifru_addr))->sin_addr.s_addr)
245                 goto END_TRUE;
246
247 END_FALSE:
248         close(fd);
249         return 0;
250 END_TRUE:
251         close(fd);
252         return 1;
253 }
254
255 #define COND_FREE(x) if(x) free(x); x = 0
256 #define SAVE_SET_STRING(x, y) \
257         if (x && strcmp((char *)x, (char *)y)) { \
258                 free(x); \
259                 x = strndup("multiple", text_buffer_size); \
260         } else if (!x) { \
261                 x = strndup(y, text_buffer_size); \
262         }
263
264 void update_gateway_info_failure(char *reason)
265 {
266         if(reason != NULL) {
267                 perror(reason);
268         }
269         //2 pointers to 1 location causes a crash when we try to free them both
270         info.gw_info.iface = strndup("failed", text_buffer_size);
271         info.gw_info.ip = strndup("failed", text_buffer_size);
272 }
273
274 void update_gateway_info(void)
275 {
276         FILE *fp;
277         struct in_addr ina;
278         char iface[64];
279         unsigned long dest, gate, mask;
280         unsigned int flags;
281         short ref, use, metric, mtu, win, irtt;
282
283         struct gateway_info *gw_info = &info.gw_info;
284
285         COND_FREE(gw_info->iface);
286         COND_FREE(gw_info->ip);
287         gw_info->count = 0;
288
289         if ((fp = fopen("/proc/net/route", "r")) == NULL) {
290                 update_gateway_info_failure("fopen()");
291                 return;
292         }
293         if (fscanf(fp, "%*[^\n]\n") == EOF) {
294                 //NULL because a empty table is not a error
295                 update_gateway_info_failure(NULL);
296                 fclose(fp);
297                 return;
298         }
299         while (!feof(fp)) {
300                 // Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
301                 if(fscanf(fp, "%63s %lx %lx %x %hd %hd %hd %lx %hd %hd %hd\n",
302                                         iface, &dest, &gate, &flags, &ref, &use,
303                                         &metric, &mask, &mtu, &win, &irtt) != 11) {
304                         update_gateway_info_failure("fscanf()");
305                         fclose(fp);
306                         return;
307                 }
308                 if (flags & RTF_GATEWAY && dest == 0 && mask == 0) {
309                         gw_info->count++;
310                         SAVE_SET_STRING(gw_info->iface, iface)
311                                 ina.s_addr = gate;
312                         SAVE_SET_STRING(gw_info->ip, inet_ntoa(ina))
313                 }
314         }
315         fclose(fp);
316         return;
317 }
318
319 inline void update_net_stats(void)
320 {
321         FILE *net_dev_fp;
322         static int rep = 0;
323
324         // FIXME: arbitrary size chosen to keep code simple.
325         int i, i2;
326         unsigned int curtmp1, curtmp2;
327         unsigned int k;
328         struct ifconf conf;
329         char buf[256];
330         double delta;
331
332 #ifdef HAVE_IWLIB
333         // wireless info variables
334         int skfd, has_bitrate = 0;
335         struct wireless_info *winfo;
336         struct iwreq wrq;
337 #endif
338
339         /* get delta */
340         delta = current_update_time - last_update_time;
341         if (delta <= 0.0001) {
342                 return;
343         }
344
345         /* open file and ignore first two lines */
346         if (!(net_dev_fp = open_file("/proc/net/dev", &rep))) {
347                 clear_net_stats();
348                 return;
349         }
350
351         fgets(buf, 255, net_dev_fp);    /* garbage */
352         fgets(buf, 255, net_dev_fp);    /* garbage (field names) */
353
354         /* read each interface */
355         for (i2 = 0; i2 < 16; i2++) {
356                 struct net_stat *ns;
357                 char *s, *p;
358                 char temp_addr[17];
359                 long long r, t, last_recv, last_trans;
360
361                 if (fgets(buf, 255, net_dev_fp) == NULL) {
362                         break;
363                 }
364                 p = buf;
365                 while (isspace((int) *p)) {
366                         p++;
367                 }
368
369                 s = p;
370
371                 while (*p && *p != ':') {
372                         p++;
373                 }
374                 if (*p == '\0') {
375                         continue;
376                 }
377                 *p = '\0';
378                 p++;
379
380                 ns = get_net_stat(s);
381                 ns->up = 1;
382                 memset(&(ns->addr.sa_data), 0, 14);
383
384                 if(NULL == ns->addrs)
385                         ns->addrs = (char*) malloc(17 * 16);
386                 if(NULL != ns->addrs)
387                         memset(ns->addrs, 0, 17 * 16); /* Up to 17 chars per ip, max 16 interfaces. Nasty memory usage... */
388
389                 last_recv = ns->recv;
390                 last_trans = ns->trans;
391
392                 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
393                 sscanf(p, "%lld  %*d     %*d  %*d  %*d  %*d   %*d        %*d       %lld",
394                         &r, &t);
395
396                 /* if recv or trans is less than last time, an overflow happened */
397                 if (r < ns->last_read_recv) {
398                         last_recv = 0;
399                 } else {
400                         ns->recv += (r - ns->last_read_recv);
401                 }
402                 ns->last_read_recv = r;
403
404                 if (t < ns->last_read_trans) {
405                         last_trans = 0;
406                 } else {
407                         ns->trans += (t - ns->last_read_trans);
408                 }
409                 ns->last_read_trans = t;
410
411                 /*** ip addr patch ***/
412                 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
413
414                 conf.ifc_buf = malloc(sizeof(struct ifreq) * 16);
415                 conf.ifc_len = sizeof(struct ifreq) * 16;
416                 memset(conf.ifc_buf, 0, conf.ifc_len);
417
418                 ioctl((long) i, SIOCGIFCONF, &conf);
419
420                 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
421                         struct net_stat *ns2;
422
423                         if (!(((struct ifreq *) conf.ifc_buf) + k))
424                                 break;
425
426                         ns2 = get_net_stat(
427                                 ((struct ifreq *) conf.ifc_buf)[k].ifr_ifrn.ifrn_name);
428                         ns2->addr = ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.ifru_addr;
429                         if(NULL != ns2->addrs) {
430                                 sprintf(temp_addr, "%u.%u.%u.%u, ",
431                                         ns2->addr.sa_data[2] & 255,
432                                         ns2->addr.sa_data[3] & 255,
433                                         ns2->addr.sa_data[4] & 255,
434                                         ns2->addr.sa_data[5] & 255);
435                                 if(NULL == strstr(ns2->addrs, temp_addr))
436                                         strncpy(ns2->addrs + strlen(ns2->addrs), temp_addr, 17);
437                         }
438                 }
439
440                 close((long) i);
441
442                 free(conf.ifc_buf);
443
444                 /*** end ip addr patch ***/
445
446                 /* calculate speeds */
447                 ns->net_rec[0] = (ns->recv - last_recv) / delta;
448                 ns->net_trans[0] = (ns->trans - last_trans) / delta;
449                 curtmp1 = 0;
450                 curtmp2 = 0;
451                 // get an average
452                 for (i = 0; (unsigned) i < info.net_avg_samples; i++) {
453                         curtmp1 += ns->net_rec[i];
454                         curtmp2 += ns->net_trans[i];
455                 }
456                 if (curtmp1 == 0) {
457                         curtmp1 = 1;
458                 }
459                 if (curtmp2 == 0) {
460                         curtmp2 = 1;
461                 }
462                 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
463                 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
464                 if (info.net_avg_samples > 1) {
465                         for (i = info.net_avg_samples; i > 1; i--) {
466                                 ns->net_rec[i - 1] = ns->net_rec[i - 2];
467                                 ns->net_trans[i - 1] = ns->net_trans[i - 2];
468                         }
469                 }
470
471 #ifdef HAVE_IWLIB
472                 /* update wireless info */
473                 winfo = malloc(sizeof(struct wireless_info));
474                 memset(winfo, 0, sizeof(struct wireless_info));
475
476                 skfd = iw_sockets_open();
477                 if (iw_get_basic_config(skfd, s, &(winfo->b)) > -1) {
478
479                         // set present winfo variables
480                         if (iw_get_stats(skfd, s, &(winfo->stats),
481                                         &winfo->range, winfo->has_range) >= 0) {
482                                 winfo->has_stats = 1;
483                         }
484                         if (iw_get_range_info(skfd, s, &(winfo->range)) >= 0) {
485                                 winfo->has_range = 1;
486                         }
487                         if (iw_get_ext(skfd, s, SIOCGIWAP, &wrq) >= 0) {
488                                 winfo->has_ap_addr = 1;
489                                 memcpy(&(winfo->ap_addr), &(wrq.u.ap_addr), sizeof(sockaddr));
490                         }
491
492                         // get bitrate
493                         if (iw_get_ext(skfd, s, SIOCGIWRATE, &wrq) >= 0) {
494                                 memcpy(&(winfo->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
495                                 iw_print_bitrate(ns->bitrate, 16, winfo->bitrate.value);
496                                 has_bitrate = 1;
497                         }
498
499                         // get link quality
500                         if (winfo->has_range && winfo->has_stats
501                                         && ((winfo->stats.qual.level != 0)
502                                         || (winfo->stats.qual.updated & IW_QUAL_DBM))) {
503                                 if (!(winfo->stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
504                                         ns->link_qual = winfo->stats.qual.qual;
505                                         ns->link_qual_max = winfo->range.max_qual.qual;
506                                 }
507                         }
508
509                         // get ap mac
510                         if (winfo->has_ap_addr) {
511                                 iw_sawap_ntop(&winfo->ap_addr, ns->ap);
512                         }
513
514                         // get essid
515                         if (winfo->b.has_essid) {
516                                 if (winfo->b.essid_on) {
517                                         snprintf(ns->essid, 32, "%s", winfo->b.essid);
518                                 } else {
519                                         snprintf(ns->essid, 32, "off/any");
520                                 }
521                         }
522
523                         snprintf(ns->mode, 16, "%s", iw_operation_mode[winfo->b.mode]);
524                 }
525                 iw_sockets_close(skfd);
526                 free(winfo);
527 #endif
528         }
529
530         fclose(net_dev_fp);
531
532         info.mask |= (1 << INFO_NET);
533 }
534
535 int result;
536
537 void update_total_processes(void)
538 {
539 #ifdef HAVE_SYSINFO
540         if (!prefer_proc) {
541                 struct sysinfo s_info;
542
543                 sysinfo(&s_info);
544                 info.procs = s_info.procs;
545         } else
546 #endif
547         {
548                 static int rep = 0;
549                 FILE *fp;
550
551                 if (!(fp = open_file("/proc/loadavg", &rep))) {
552                         info.procs = 0;
553                         return;
554                 }
555                 fscanf(fp, "%*f %*f %*f %*d/%hu", &info.procs);
556                 fclose(fp);
557         }
558         info.mask |= (1 << INFO_PROCS);
559 }
560
561 #define CPU_SAMPLE_COUNT 15
562 struct cpu_info {
563         unsigned long long cpu_user;
564         unsigned long long cpu_system;
565         unsigned long long cpu_nice;
566         unsigned long long cpu_idle;
567         unsigned long long cpu_iowait;
568         unsigned long long cpu_irq;
569         unsigned long long cpu_softirq;
570         unsigned long long cpu_steal;
571         unsigned long long cpu_total;
572         unsigned long long cpu_active_total;
573         unsigned long long cpu_last_total;
574         unsigned long long cpu_last_active_total;
575         double cpu_val[CPU_SAMPLE_COUNT];
576 };
577 static short cpu_setup = 0;
578
579 /* Determine if this kernel gives us "extended" statistics information in
580  * /proc/stat.
581  * Kernels around 2.5 and earlier only reported user, system, nice, and
582  * idle values in proc stat.
583  * Kernels around 2.6 and greater report these PLUS iowait, irq, softirq,
584  * and steal */
585 void determine_longstat(char *buf)
586 {
587         unsigned long long iowait = 0;
588
589         KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
590         /* scanf will either return -1 or 1 because there is only 1 assignment */
591         if (sscanf(buf, "%*s %*d %*d %*d %*d %llu", &iowait) > 0) {
592                 KFLAG_SETON(KFLAG_IS_LONGSTAT);
593         }
594 }
595
596 void get_cpu_count(void)
597 {
598         FILE *stat_fp;
599         static int rep = 0;
600         char buf[256];
601
602         if (info.cpu_usage) {
603                 return;
604         }
605
606         if (!(stat_fp = open_file("/proc/stat", &rep))) {
607                 return;
608         }
609
610         info.cpu_count = 0;
611
612         while (!feof(stat_fp)) {
613                 if (fgets(buf, 255, stat_fp) == NULL) {
614                         break;
615                 }
616
617                 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
618                         if (info.cpu_count == 0) {
619                                 determine_longstat(buf);
620                         }
621                         info.cpu_count++;
622                 }
623         }
624         info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
625
626         fclose(stat_fp);
627 }
628
629 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
630 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
631
632 inline static void update_stat(void)
633 {
634         FILE *stat_fp;
635         static int rep = 0;
636         static struct cpu_info *cpu = NULL;
637         char buf[256];
638         unsigned int i;
639         unsigned int idx;
640         double curtmp;
641         const char *stat_template = NULL;
642         unsigned int malloc_cpu_size = 0;
643
644         /* add check for !info.cpu_usage since that mem is freed on a SIGUSR1 */
645         if (!cpu_setup || !info.cpu_usage) {
646                 get_cpu_count();
647                 cpu_setup = 1;
648         }
649
650         if (!stat_template) {
651                 stat_template =
652                         KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT;
653         }
654
655         if (!cpu) {
656                 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
657                 cpu = malloc(malloc_cpu_size);
658                 memset(cpu, 0, malloc_cpu_size);
659         }
660
661         if (!(stat_fp = open_file("/proc/stat", &rep))) {
662                 info.run_procs = 0;
663                 if (info.cpu_usage) {
664                         memset(info.cpu_usage, 0, info.cpu_count * sizeof(float));
665                 }
666                 return;
667         }
668
669         idx = 0;
670         while (!feof(stat_fp)) {
671                 if (fgets(buf, 255, stat_fp) == NULL) {
672                         break;
673                 }
674
675                 if (strncmp(buf, "procs_running ", 14) == 0) {
676                         sscanf(buf, "%*s %hu", &info.run_procs);
677                         info.mask |= (1 << INFO_RUN_PROCS);
678                 } else if (strncmp(buf, "cpu", 3) == 0) {
679                         double delta;
680                         idx = isdigit(buf[3]) ? ((int) buf[3]) - 0x2F : 0;
681                         sscanf(buf, stat_template, &(cpu[idx].cpu_user),
682                                 &(cpu[idx].cpu_nice), &(cpu[idx].cpu_system),
683                                 &(cpu[idx].cpu_idle), &(cpu[idx].cpu_iowait),
684                                 &(cpu[idx].cpu_irq), &(cpu[idx].cpu_softirq),
685                                 &(cpu[idx].cpu_steal));
686
687                         cpu[idx].cpu_total = cpu[idx].cpu_user + cpu[idx].cpu_nice +
688                                 cpu[idx].cpu_system + cpu[idx].cpu_idle +
689                                 cpu[idx].cpu_iowait + cpu[idx].cpu_irq +
690                                 cpu[idx].cpu_softirq + cpu[idx].cpu_steal;
691
692                         cpu[idx].cpu_active_total = cpu[idx].cpu_total -
693                                 (cpu[idx].cpu_idle + cpu[idx].cpu_iowait);
694                         info.mask |= (1 << INFO_CPU);
695
696                         delta = current_update_time - last_update_time;
697
698                         if (delta <= 0.001) {
699                                 break;
700                         }
701
702                         cpu[idx].cpu_val[0] = (cpu[idx].cpu_active_total -
703                                 cpu[idx].cpu_last_active_total) /
704                                 (float) (cpu[idx].cpu_total - cpu[idx].cpu_last_total);
705                         curtmp = 0;
706                         for (i = 0; i < info.cpu_avg_samples; i++) {
707                                 curtmp += cpu[idx].cpu_val[i];
708                         }
709                         /* TESTING -- I've removed this, because I don't think it is right.
710                          * You shouldn't divide by the cpu count here ...
711                          * removing for testing */
712                         /* if (idx == 0) {
713                                 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples /
714                                         info.cpu_count;
715                         } else {
716                                 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples;
717                         } */
718                         /* TESTING -- this line replaces the prev. "suspect" if/else */
719                         info.cpu_usage[idx] = curtmp / info.cpu_avg_samples;
720
721                         cpu[idx].cpu_last_total = cpu[idx].cpu_total;
722                         cpu[idx].cpu_last_active_total = cpu[idx].cpu_active_total;
723                         for (i = info.cpu_avg_samples - 1; i > 0; i--) {
724                                 cpu[idx].cpu_val[i] = cpu[idx].cpu_val[i - 1];
725                         }
726                 }
727         }
728         fclose(stat_fp);
729 }
730
731 void update_running_processes(void)
732 {
733         update_stat();
734 }
735
736 void update_cpu_usage(void)
737 {
738         update_stat();
739 }
740
741 void update_load_average(void)
742 {
743 #ifdef HAVE_GETLOADAVG
744         if (!prefer_proc) {
745                 double v[3];
746
747                 getloadavg(v, 3);
748                 info.loadavg[0] = (float) v[0];
749                 info.loadavg[1] = (float) v[1];
750                 info.loadavg[2] = (float) v[2];
751         } else
752 #endif
753         {
754                 static int rep = 0;
755                 FILE *fp;
756
757                 if (!(fp = open_file("/proc/loadavg", &rep))) {
758                         info.loadavg[0] = info.loadavg[1] = info.loadavg[2] = 0.0;
759                         return;
760                 }
761                 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1],
762                         &info.loadavg[2]);
763                 fclose(fp);
764         }
765         info.mask |= (1 << INFO_LOADAVG);
766 }
767
768 #define PROC_I8K "/proc/i8k"
769 #define I8K_DELIM " "
770 static char *i8k_procbuf = NULL;
771 void update_i8k(void)
772 {
773         FILE *fp;
774
775         if (!i8k_procbuf) {
776                 i8k_procbuf = (char *) malloc(128 * sizeof(char));
777         }
778         if ((fp = fopen(PROC_I8K, "r")) == NULL) {
779                 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel "
780                         "driver is loaded...");
781         }
782
783         memset(&i8k_procbuf[0], 0, 128);
784         if (fread(&i8k_procbuf[0], sizeof(char), 128, fp) == 0) {
785                 ERR("something wrong with /proc/i8k...");
786         }
787
788         fclose(fp);
789
790         i8k.version = strtok(&i8k_procbuf[0], I8K_DELIM);
791         i8k.bios = strtok(NULL, I8K_DELIM);
792         i8k.serial = strtok(NULL, I8K_DELIM);
793         i8k.cpu_temp = strtok(NULL, I8K_DELIM);
794         i8k.left_fan_status = strtok(NULL, I8K_DELIM);
795         i8k.right_fan_status = strtok(NULL, I8K_DELIM);
796         i8k.left_fan_rpm = strtok(NULL, I8K_DELIM);
797         i8k.right_fan_rpm = strtok(NULL, I8K_DELIM);
798         i8k.ac_status = strtok(NULL, I8K_DELIM);
799         i8k.buttons_status = strtok(NULL, I8K_DELIM);
800 }
801
802 /***********************************************************/
803 /***********************************************************/
804 /***********************************************************/
805
806 static int no_dots(const struct dirent *d)
807 {
808         if (d->d_name[0] == '.') {
809                 return 0;
810         }
811         return 1;
812 }
813
814 static int get_first_file_in_a_directory(const char *dir, char *s, int *rep)
815 {
816         struct dirent **namelist;
817         int i, n;
818
819         n = scandir(dir, &namelist, no_dots, alphasort);
820         if (n < 0) {
821                 if (!rep || !*rep) {
822                         ERR("scandir for %s: %s", dir, strerror(errno));
823                         if (rep) {
824                                 *rep = 1;
825                         }
826                 }
827                 return 0;
828         } else {
829                 if (n == 0) {
830                         return 0;
831                 }
832
833                 strncpy(s, namelist[0]->d_name, 255);
834                 s[255] = '\0';
835
836                 for (i = 0; i < n; i++) {
837                         free(namelist[i]);
838                 }
839                 free(namelist);
840
841                 return 1;
842         }
843 }
844
845 int open_sysfs_sensor(const char *dir, const char *dev, const char *type, int n,
846                 int *divisor, char *devtype)
847 {
848         char path[256];
849         char buf[256];
850         int fd;
851         int divfd;
852
853         memset(buf, 0, sizeof(buf));
854
855         /* if device is NULL or *, get first */
856         if (dev == NULL || strcmp(dev, "*") == 0) {
857                 static int rep = 0;
858
859                 if (!get_first_file_in_a_directory(dir, buf, &rep)) {
860                         return -1;
861                 }
862                 dev = buf;
863         }
864
865         if (strcmp(dir, "/sys/class/hwmon/") == 0) {
866                 if (*buf) {
867                         /* buf holds result from get_first_file_in_a_directory() above,
868                          * e.g. "hwmon0" -- append "/device" */
869                         strcat(buf, "/device");
870                 } else {
871                         /* dev holds device number N as a string,
872                          * e.g. "0", -- convert to "hwmon0/device" */
873                         sprintf(buf, "hwmon%s/device", dev);
874                         dev = buf;
875                 }
876         }
877
878         /* change vol to in */
879         if (strcmp(type, "vol") == 0) {
880                 type = "in";
881         }
882
883         if (strcmp(type, "tempf") == 0) {
884                 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, "temp", n);
885         } else {
886                 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, type, n);
887         }
888         strncpy(devtype, path, 255);
889
890         /* open file */
891         fd = open(path, O_RDONLY);
892         if (fd < 0) {
893                 CRIT_ERR("can't open '%s': %s\nplease check your device or remove this "
894                         "var from Conky", path, strerror(errno));
895         }
896
897         if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
898                         || strcmp(type, "tempf") == 0) {
899                 *divisor = 1;
900         } else {
901                 *divisor = 0;
902         }
903         /* fan does not use *_div as a read divisor */
904         if (strcmp("fan", type) == 0) {
905                 return fd;
906         }
907
908         /* test if *_div file exist, open it and use it as divisor */
909         if (strcmp(type, "tempf") == 0) {
910                 snprintf(path, 255, "%s%s/%s%d_div", dir, "one", "two", n);
911         } else {
912                 snprintf(path, 255, "%s%s/%s%d_div", dir, dev, type, n);
913         }
914
915         divfd = open(path, O_RDONLY);
916         if (divfd > 0) {
917                 /* read integer */
918                 char divbuf[64];
919                 int divn;
920
921                 divn = read(divfd, divbuf, 63);
922                 /* should read until n == 0 but I doubt that kernel will give these
923                  * in multiple pieces. :) */
924                 if (divn < 0) {
925                         ERR("open_sysfs_sensor(): can't read from sysfs");
926                 } else {
927                         divbuf[divn] = '\0';
928                         *divisor = atoi(divbuf);
929                 }
930         }
931
932         close(divfd);
933
934         return fd;
935 }
936
937 double get_sysfs_info(int *fd, int divisor, char *devtype, char *type)
938 {
939         int val = 0;
940
941         if (*fd <= 0) {
942                 return 0;
943         }
944
945         lseek(*fd, 0, SEEK_SET);
946
947         /* read integer */
948         {
949                 char buf[64];
950                 int n;
951                 n = read(*fd, buf, 63);
952                 /* should read until n == 0 but I doubt that kernel will give these
953                  * in multiple pieces. :) */
954                 if (n < 0) {
955                         ERR("get_sysfs_info(): read from %s failed\n", devtype);
956                 } else {
957                         buf[n] = '\0';
958                         val = atoi(buf);
959                 }
960         }
961
962         close(*fd);
963         /* open file */
964         *fd = open(devtype, O_RDONLY);
965         if (*fd < 0) {
966                 ERR("can't open '%s': %s", devtype, strerror(errno));
967         }
968
969         /* My dirty hack for computing CPU value
970          * Filedil, from forums.gentoo.org */
971         /* if (strstr(devtype, "temp1_input") != NULL) {
972                 return -15.096 + 1.4893 * (val / 1000.0);
973         } */
974
975         /* divide voltage and temperature by 1000 */
976         /* or if any other divisor is given, use that */
977         if (strcmp(type, "tempf") == 0) {
978                 if (divisor > 1) {
979                         return ((val / divisor + 40) * 9.0 / 5) - 40;
980                 } else if (divisor) {
981                         return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
982                 } else {
983                         return ((val + 40) * 9.0 / 5) - 40;
984                 }
985         } else {
986                 if (divisor > 1) {
987                         return val / divisor;
988                 } else if (divisor) {
989                         return val / 1000.0;
990                 } else {
991                         return val;
992                 }
993         }
994 }
995
996 /* Prior to kernel version 2.6.12, the CPU fan speed was available in
997  * ADT746X_FAN_OLD, whereas later kernel versions provide this information in
998  * ADT746X_FAN. */
999 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
1000 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
1001
1002 void get_adt746x_fan(char *p_client_buffer, size_t client_buffer_size)
1003 {
1004         static int rep = 0;
1005         char adt746x_fan_state[64];
1006         FILE *fp;
1007
1008         if (!p_client_buffer || client_buffer_size <= 0) {
1009                 return;
1010         }
1011
1012         if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
1013                         && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL) {
1014                 sprintf(adt746x_fan_state, "adt746x not found");
1015         } else {
1016                 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
1017                 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
1018                 fclose(fp);
1019         }
1020
1021         snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_fan_state);
1022 }
1023
1024 /* Prior to kernel version 2.6.12, the CPU temperature was found in
1025  * ADT746X_CPU_OLD, whereas later kernel versions provide this information in
1026  * ADT746X_CPU. */
1027 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
1028 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
1029
1030 void get_adt746x_cpu(char *p_client_buffer, size_t client_buffer_size)
1031 {
1032         static int rep = 0;
1033         char adt746x_cpu_state[64];
1034         FILE *fp;
1035
1036         if (!p_client_buffer || client_buffer_size <= 0) {
1037                 return;
1038         }
1039
1040         if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
1041                         && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL) {
1042                 sprintf(adt746x_cpu_state, "adt746x not found");
1043         } else {
1044                 fscanf(fp, "%2s", adt746x_cpu_state);
1045                 fclose(fp);
1046         }
1047
1048         snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state);
1049 }
1050
1051 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
1052
1053 /***********************************************************************/
1054 /* This file is part of x86info.
1055  * (C) 2001 Dave Jones.
1056  *
1057  * Licensed under the terms of the GNU GPL License version 2.
1058  *
1059  * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
1060  * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz> */
1061
1062 #if  defined(__i386) || defined(__x86_64)
1063 __inline__ unsigned long long int rdtsc(void)
1064 {
1065         unsigned long long int x;
1066
1067         __asm__ volatile(".byte 0x0f, 0x31":"=A" (x));
1068         return x;
1069 }
1070 #endif
1071
1072 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1073 void get_freq_dynamic(char *p_client_buffer, size_t client_buffer_size,
1074                 const char *p_format, int divisor)
1075 {
1076 #if  defined(__i386) || defined(__x86_64)
1077         struct timezone tz;
1078         struct timeval tvstart, tvstop;
1079         unsigned long long cycles[2];   /* gotta be 64 bit */
1080         unsigned int microseconds;      /* total time taken */
1081
1082         if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1083                         || divisor <= 0) {
1084                 return;
1085         }
1086
1087         memset(&tz, 0, sizeof(tz));
1088
1089         /* get this function in cached memory */
1090         gettimeofday(&tvstart, &tz);
1091         cycles[0] = rdtsc();
1092         gettimeofday(&tvstart, &tz);
1093
1094         /* we don't trust that this is any specific length of time */
1095         usleep(100);
1096         cycles[1] = rdtsc();
1097         gettimeofday(&tvstop, &tz);
1098         microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
1099                 (tvstop.tv_usec - tvstart.tv_usec);
1100
1101         snprintf(p_client_buffer, client_buffer_size, p_format,
1102                 (float) ((cycles[1] - cycles[0]) / microseconds) / divisor);
1103         return;
1104 #else
1105         /* FIXME: hardwired: get freq for first cpu!
1106          * this whole function needs to be rethought and redone for
1107          * multi-cpu/multi-core/multi-threaded environments and
1108          * arbitrary combinations thereof */
1109         get_freq(p_client_buffer, client_buffer_size, p_format, divisor, 1);
1110         return;
1111 #endif
1112 }
1113
1114 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
1115 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
1116
1117 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1118 char get_freq(char *p_client_buffer, size_t client_buffer_size,
1119                 const char *p_format, int divisor, unsigned int cpu)
1120 {
1121         FILE *f;
1122         static int rep = 0;
1123         char frequency[32];
1124         char s[256];
1125         double freq = 0;
1126
1127         if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1128                         || divisor <= 0) {
1129                 return 0;
1130         }
1131
1132         if (!prefer_proc) {
1133                 char current_freq_file[128];
1134
1135                 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu - 1,
1136                         CPUFREQ_POSTFIX);
1137                 f = fopen(current_freq_file, "r");
1138                 if (f) {
1139                         /* if there's a cpufreq /sys node, read the current frequency from
1140                          * this node and divide by 1000 to get Mhz. */
1141                         if (fgets(s, sizeof(s), f)) {
1142                                 s[strlen(s) - 1] = '\0';
1143                                 freq = strtod(s, NULL);
1144                         }
1145                         fclose(f);
1146                         snprintf(p_client_buffer, client_buffer_size, p_format,
1147                                 (freq / 1000) / divisor);
1148                         return 1;
1149                 }
1150         }
1151
1152         // open the CPU information file
1153         f = open_file("/proc/cpuinfo", &rep);
1154         if (!f) {
1155                 perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
1156                 return 0;
1157         }
1158
1159         // read the file
1160         while (fgets(s, sizeof(s), f) != NULL) {
1161
1162 #if defined(__i386) || defined(__x86_64)
1163                 // and search for the cpu mhz
1164                 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) {
1165 #else
1166 #if defined(__alpha)
1167                 // different on alpha
1168                 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) {
1169 #else
1170                 // this is different on ppc for some reason
1171                 if (strncmp(s, "clock", 5) == 0 && cpu == 0) {
1172 #endif // defined(__alpha)
1173 #endif // defined(__i386) || defined(__x86_64)
1174
1175                         // copy just the number
1176                         strcpy(frequency, strchr(s, ':') + 2);
1177 #if defined(__alpha)
1178                         // strip " est.\n"
1179                         frequency[strlen(frequency) - 6] = '\0';
1180                         // kernel reports in Hz
1181                         freq = strtod(frequency, NULL) / 1000000;
1182 #else
1183                         // strip \n
1184                         frequency[strlen(frequency) - 1] = '\0';
1185                         freq = strtod(frequency, NULL);
1186 #endif
1187                         break;
1188                 }
1189                 if (strncmp(s, "processor", 9) == 0) {
1190                         cpu--;
1191                         continue;
1192                 }
1193         }
1194
1195         fclose(f);
1196         snprintf(p_client_buffer, client_buffer_size, p_format,
1197                 (float) freq / divisor);
1198         return 1;
1199 }
1200
1201 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
1202
1203 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks something
1204  * like this:
1205 # frequency voltage
1206 1800000 1340
1207 1600000 1292
1208 1400000 1100
1209 1200000 988
1210 1000000 1116
1211 800000 1004
1212 600000 988
1213  * Peter Tarjan (ptarjan@citromail.hu) */
1214
1215 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
1216 char get_voltage(char *p_client_buffer, size_t client_buffer_size,
1217                 const char *p_format, int divisor, unsigned int cpu)
1218 {
1219         FILE *f;
1220         char s[256];
1221         int freq = 0;
1222         int voltage = 0;
1223         char current_freq_file[128];
1224         int freq_comp = 0;
1225
1226         /* build the voltage file name */
1227         cpu--;
1228         snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1229                 CPUFREQ_POSTFIX);
1230
1231         if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1232                         || divisor <= 0) {
1233                 return 0;
1234         }
1235
1236         /* read the current cpu frequency from the /sys node */
1237         f = fopen(current_freq_file, "r");
1238         if (f) {
1239                 if (fgets(s, sizeof(s), f)) {
1240                         s[strlen(s) - 1] = '\0';
1241                         freq = strtod(s, NULL);
1242                 }
1243                 fclose(f);
1244         } else {
1245                 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1246                 perror("get_voltage()");
1247                 if (f) {
1248                         fclose(f);
1249                 }
1250                 return 0;
1251         }
1252
1253         snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1254                 CPUFREQ_VOLTAGE);
1255
1256         /* use the current cpu frequency to find the corresponding voltage */
1257         f = fopen(current_freq_file, "r");
1258
1259         if (f) {
1260                 while (!feof(f)) {
1261                         char line[256];
1262
1263                         if (fgets(line, 255, f) == NULL) {
1264                                 break;
1265                         }
1266                         sscanf(line, "%d %d", &freq_comp, &voltage);
1267                         if (freq_comp == freq) {
1268                                 break;
1269                         }
1270                 }
1271                 fclose(f);
1272         } else {
1273                 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1274                 perror("get_voltage()");
1275                 if (f) {
1276                         fclose(f);
1277                 }
1278                 return 0;
1279         }
1280         snprintf(p_client_buffer, client_buffer_size, p_format,
1281                 (float) voltage / divisor);
1282         return 1;
1283 }
1284
1285 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1286
1287 void get_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
1288 {
1289         static int rep = 0;
1290         char buf[256];
1291         char buf2[256];
1292         FILE *fp;
1293
1294         if (!p_client_buffer || client_buffer_size <= 0) {
1295                 return;
1296         }
1297
1298         /* yeah, slow... :/ */
1299         if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep)) {
1300                 snprintf(p_client_buffer, client_buffer_size, "no fans?");
1301                 return;
1302         }
1303
1304         snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf);
1305
1306         fp = open_file(buf2, &rep);
1307         if (!fp) {
1308                 snprintf(p_client_buffer, client_buffer_size,
1309                         "can't open fan's state file");
1310                 return;
1311         }
1312         memset(buf, 0, sizeof(buf));
1313         fscanf(fp, "%*s %99s", buf);
1314         fclose(fp);
1315
1316         snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1317 }
1318
1319 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1320
1321 void get_acpi_ac_adapter(char *p_client_buffer, size_t client_buffer_size)
1322 {
1323         static int rep = 0;
1324         char buf[256];
1325         char buf2[256];
1326         FILE *fp;
1327
1328         if (!p_client_buffer || client_buffer_size <= 0) {
1329                 return;
1330         }
1331
1332         /* yeah, slow... :/ */
1333         if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep)) {
1334                 snprintf(p_client_buffer, client_buffer_size, "no ac_adapters?");
1335                 return;
1336         }
1337
1338         snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf);
1339
1340         fp = open_file(buf2, &rep);
1341         if (!fp) {
1342                 snprintf(p_client_buffer, client_buffer_size,
1343                         "No ac adapter found.... where is it?");
1344                 return;
1345         }
1346         memset(buf, 0, sizeof(buf));
1347         fscanf(fp, "%*s %99s", buf);
1348         fclose(fp);
1349
1350         snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1351 }
1352
1353 /*
1354 /proc/acpi/thermal_zone/THRM/cooling_mode
1355 cooling mode:            active
1356 /proc/acpi/thermal_zone/THRM/polling_frequency
1357 <polling disabled>
1358 /proc/acpi/thermal_zone/THRM/state
1359 state:                   ok
1360 /proc/acpi/thermal_zone/THRM/temperature
1361 temperature:             45 C
1362 /proc/acpi/thermal_zone/THRM/trip_points
1363 critical (S5):           73 C
1364 passive:                 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1365 */
1366
1367 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1368 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1369
1370 int open_acpi_temperature(const char *name)
1371 {
1372         char path[256];
1373         char buf[256];
1374         int fd;
1375
1376         if (name == NULL || strcmp(name, "*") == 0) {
1377                 static int rep = 0;
1378
1379                 if (!get_first_file_in_a_directory(ACPI_THERMAL_DIR, buf, &rep)) {
1380                         return -1;
1381                 }
1382                 name = buf;
1383         }
1384
1385         snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1386
1387         fd = open(path, O_RDONLY);
1388         if (fd < 0) {
1389                 ERR("can't open '%s': %s", path, strerror(errno));
1390         }
1391
1392         return fd;
1393 }
1394
1395 static double last_acpi_temp;
1396 static double last_acpi_temp_time;
1397
1398 double get_acpi_temperature(int fd)
1399 {
1400         if (fd <= 0) {
1401                 return 0;
1402         }
1403
1404         /* don't update acpi temperature too often */
1405         if (current_update_time - last_acpi_temp_time < 11.32) {
1406                 return last_acpi_temp;
1407         }
1408         last_acpi_temp_time = current_update_time;
1409
1410         /* seek to beginning */
1411         lseek(fd, 0, SEEK_SET);
1412
1413         /* read */
1414         {
1415                 char buf[256];
1416                 int n;
1417
1418                 n = read(fd, buf, 255);
1419                 if (n < 0) {
1420                         ERR("can't read fd %d: %s", fd, strerror(errno));
1421                 } else {
1422                         buf[n] = '\0';
1423                         sscanf(buf, "temperature: %lf", &last_acpi_temp);
1424                 }
1425         }
1426
1427         return last_acpi_temp;
1428 }
1429
1430 /*
1431 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1432 present:                 yes
1433 design capacity:         4400 mAh
1434 last full capacity:      4064 mAh
1435 battery technology:      rechargeable
1436 design voltage:          14800 mV
1437 design capacity warning: 300 mAh
1438 design capacity low:     200 mAh
1439 capacity granularity 1:  32 mAh
1440 capacity granularity 2:  32 mAh
1441 model number:            02KT
1442 serial number:           16922
1443 battery type:            LION
1444 OEM info:                SANYO
1445 */
1446
1447 /*
1448 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1449 present:                 yes
1450 capacity state:          ok
1451 charging state:          unknown
1452 present rate:            0 mA
1453 remaining capacity:      4064 mAh
1454 present voltage:         16608 mV
1455 */
1456
1457 /*
1458 2213<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1459 2213<@jupet�kellari��> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1460 2213<@jupet�kellari��> (-1 ollee ei akkua kiinni, koska akku on p�yd�ll�)
1461 2214<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1462 2214<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1463
1464 2238<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1465 2239<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1466
1467 2240<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori p��ll�
1468 2241<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori p��ll� mutta ilman verkkovirtaa
1469 */
1470
1471 /* Kapil Hari Paranjape <kapil@imsc.res.in>
1472   Linux 2.6.24 onwards battery info is in
1473   /sys/class/power_supply/BAT0/
1474   On my system I get the following.
1475         /sys/class/power_supply/BAT0/uevent:
1476         PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A03:00/device:01/PNP0C09:00/PNP0C0A:00
1477         PHYSDEVBUS=acpi
1478         PHYSDEVDRIVER=battery
1479         POWER_SUPPLY_NAME=BAT0
1480         POWER_SUPPLY_TYPE=Battery
1481         POWER_SUPPLY_STATUS=Discharging
1482         POWER_SUPPLY_PRESENT=1
1483         POWER_SUPPLY_TECHNOLOGY=Li-ion
1484         POWER_SUPPLY_VOLTAGE_MIN_DESIGN=10800000
1485         POWER_SUPPLY_VOLTAGE_NOW=10780000
1486         POWER_SUPPLY_CURRENT_NOW=13970000
1487         POWER_SUPPLY_ENERGY_FULL_DESIGN=47510000
1488         POWER_SUPPLY_ENERGY_FULL=27370000
1489         POWER_SUPPLY_ENERGY_NOW=11810000
1490         POWER_SUPPLY_MODEL_NAME=IBM-92P1060
1491         POWER_SUPPLY_MANUFACTURER=Panasonic
1492   On some systems POWER_SUPPLY_ENERGY_* is replaced by POWER_SUPPLY_CHARGE_*
1493 */
1494
1495 #define SYSFS_BATTERY_BASE_PATH "/sys/class/power_supply"
1496 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1497 #define APM_PATH "/proc/apm"
1498 #define MAX_BATTERY_COUNT 4
1499
1500 static FILE *sysfs_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1501 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1502 static FILE *apm_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1503
1504 static int batteries_initialized = 0;
1505 static char batteries[MAX_BATTERY_COUNT][32];
1506
1507 static int acpi_last_full[MAX_BATTERY_COUNT];
1508 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1509
1510 /* e.g. "charging 75%" */
1511 static char last_battery_str[MAX_BATTERY_COUNT][64];
1512 /* e.g. "3h 15m" */
1513 static char last_battery_time_str[MAX_BATTERY_COUNT][64];
1514
1515 static double last_battery_time[MAX_BATTERY_COUNT];
1516
1517 static int last_battery_perct[MAX_BATTERY_COUNT];
1518 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1519
1520 void init_batteries(void)
1521 {
1522         int idx;
1523
1524         if (batteries_initialized) {
1525                 return;
1526         }
1527         for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1528                 batteries[idx][0] = '\0';
1529         }
1530         batteries_initialized = 1;
1531 }
1532
1533 int get_battery_idx(const char *bat)
1534 {
1535         int idx;
1536
1537         for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1538                 if (!strlen(batteries[idx]) || !strcmp(batteries[idx], bat)) {
1539                         break;
1540                 }
1541         }
1542
1543         /* if not found, enter a new entry */
1544         if (!strlen(batteries[idx])) {
1545                 snprintf(batteries[idx], 31, "%s", bat);
1546         }
1547
1548         return idx;
1549 }
1550
1551 void set_return_value(char *buffer, unsigned int n, int item, int idx);
1552
1553 void get_battery_stuff(char *buffer, unsigned int n, const char *bat, int item)
1554 {
1555         static int idx, rep = 0, rep2 = 0;
1556         char acpi_path[128];
1557         char sysfs_path[128];
1558
1559         snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1560         snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1561
1562         init_batteries();
1563
1564         idx = get_battery_idx(bat);
1565
1566         /* don't update battery too often */
1567         if (current_update_time - last_battery_time[idx] < 29.5) {
1568                 set_return_value(buffer, n, item, idx);
1569                 return;
1570         }
1571
1572         last_battery_time[idx] = current_update_time;
1573
1574         memset(last_battery_str[idx], 0, sizeof(last_battery_str[idx]));
1575         memset(last_battery_time_str[idx], 0, sizeof(last_battery_time_str[idx]));
1576
1577         /* first try SYSFS if that fails try ACPI */
1578  
1579         if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1580                 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1581                 rep = 0;
1582         }
1583   
1584         if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1585                 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1586         }
1587   
1588         if (sysfs_bat_fp[idx] != NULL) {
1589                 /* SYSFS */
1590                 int present_rate = -1;
1591                 int remaining_capacity = -1;
1592                 char charging_state[64];
1593                 char present[4];
1594  
1595                 strcpy(charging_state, "unknown");
1596  
1597                 while (!feof(sysfs_bat_fp[idx])) {
1598                         char buf[256];
1599                         if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1600                                 break;
1601  
1602                         /* let's just hope units are ok */
1603                         if (strncmp (buf, "POWER_SUPPLY_PRESENT=1", 22) == 0)
1604                                 strcpy(present, "yes");
1605                         else if (strncmp (buf, "POWER_SUPPLY_PRESENT=0", 22) == 0)
1606                                 strcpy(present, "no");
1607                         else if (strncmp (buf, "POWER_SUPPLY_STATUS=", 20) == 0)
1608                                 sscanf(buf, "POWER_SUPPLY_STATUS=%63s", charging_state);
1609                         /* present_rate is not the same as the
1610                         current flowing now but it is the same value
1611                         which was used in the past. so we continue
1612                         the tradition! */
1613                         else if (strncmp(buf, "POWER_SUPPLY_CURRENT_NOW=", 25) == 0)
1614                                 sscanf(buf, "POWER_SUPPLY_CURRENT_NOW=%d", &present_rate);
1615                         else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0)
1616                                 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1617                         else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=", 25) == 0)
1618                                 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_last_full[idx]);
1619                         else if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0)
1620                                 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1621                         else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=", 25) == 0)
1622                                 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_last_full[idx]);
1623                 }
1624  
1625                 fclose(sysfs_bat_fp[idx]);
1626                 sysfs_bat_fp[idx] = NULL;
1627  
1628                 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1629                 if (remaining_capacity > acpi_last_full[idx])
1630                         acpi_last_full[idx] = remaining_capacity;  /* normalize to 100% */
1631  
1632                 /* not present */
1633                 if (strcmp(present, "No") == 0) {
1634                         strncpy(last_battery_str[idx], "not present", 64);
1635                 }
1636                 /* charging */
1637                 else if (strcmp(charging_state, "Charging") == 0) {
1638                         if (acpi_last_full[idx] != 0 && present_rate > 0) {
1639                                 /* e.g. charging 75% */
1640                                 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %i%%",
1641                                         (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1642                                 /* e.g. 2h 37m */
1643                                 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1644                                               (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1645                         } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1646                                 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %d%%",
1647                                         (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1648                                 snprintf(last_battery_time_str[idx],
1649                                         sizeof(last_battery_time_str[idx]) - 1, "unknown");
1650                         } else {
1651                                 strncpy(last_battery_str[idx], "charging", sizeof(last_battery_str[idx])-1);
1652                                 snprintf(last_battery_time_str[idx],
1653                                         sizeof(last_battery_time_str[idx]) - 1, "unknown");
1654                         }
1655                 }
1656                 /* discharging */
1657                 else if (strncmp(charging_state, "Discharging", 64) == 0) {
1658                         if (present_rate > 0) {
1659                                 /* e.g. discharging 35% */
1660                                 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "discharging %i%%",
1661                                         (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1662                                 /* e.g. 1h 12m */
1663                                 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1664                                               (long) (((float) remaining_capacity / present_rate) * 3600));
1665                         } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1666                                 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "full");
1667                                 snprintf(last_battery_time_str[idx],
1668                                         sizeof(last_battery_time_str[idx]) - 1, "unknown");
1669                         } else {
1670                                 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1671                                         "discharging %d%%",
1672                                         (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1673                                 snprintf(last_battery_time_str[idx],
1674                                         sizeof(last_battery_time_str[idx]) - 1, "unknown");
1675                         }
1676                 }
1677                 /* charged */
1678                 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1679                 else if (strncmp(charging_state, "Charged", 64) == 0) {
1680                                 /* Below happens with the second battery on my X40,
1681                                  * when the second one is empty and the first one
1682                                  * being charged. */
1683                                 if (remaining_capacity == 0)
1684                                         strcpy(last_battery_str[idx], "empty");
1685                                 else
1686                                         strcpy(last_battery_str[idx], "charged");
1687                 }
1688                 /* unknown, probably full / AC */
1689                 else {
1690                         if (acpi_last_full[idx] != 0
1691                             && remaining_capacity != acpi_last_full[idx])
1692                                 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1693                                         (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1694                         else
1695                                 strncpy(last_battery_str[idx], "AC", 64);
1696                 }
1697         } else if (acpi_bat_fp[idx] != NULL) {
1698                 /* ACPI */
1699                 int present_rate = -1;
1700                 int remaining_capacity = -1;
1701                 char charging_state[64];
1702                 char present[4];
1703
1704                 /* read last full capacity if it's zero */
1705                 if (acpi_last_full[idx] == 0) {
1706                         static int rep3 = 0;
1707                         char path[128];
1708                         FILE *fp;
1709
1710                         snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1711                         fp = open_file(path, &rep3);
1712                         if (fp != NULL) {
1713                                 while (!feof(fp)) {
1714                                         char b[256];
1715
1716                                         if (fgets(b, 256, fp) == NULL) {
1717                                                 break;
1718                                         }
1719                                         if (sscanf(b, "last full capacity: %d",
1720                                                         &acpi_last_full[idx]) != 0) {
1721                                                 break;
1722                                         }
1723                                 }
1724
1725                                 fclose(fp);
1726                         }
1727                 }
1728
1729                 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1730
1731                 strcpy(charging_state, "unknown");
1732
1733                 while (!feof(acpi_bat_fp[idx])) {
1734                         char buf[256];
1735
1736                         if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1737                                 break;
1738                         }
1739
1740                         /* let's just hope units are ok */
1741                         if (strncmp(buf, "present:", 8) == 0) {
1742                                 sscanf(buf, "present: %4s", present);
1743                         } else if (strncmp(buf, "charging state:", 15) == 0) {
1744                                 sscanf(buf, "charging state: %63s", charging_state);
1745                         } else if (strncmp(buf, "present rate:", 13) == 0) {
1746                                 sscanf(buf, "present rate: %d", &present_rate);
1747                         } else if (strncmp(buf, "remaining capacity:", 19) == 0) {
1748                                 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1749                         }
1750                 }
1751                 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1752                 if (remaining_capacity > acpi_last_full[idx]) {
1753                         /* normalize to 100% */
1754                         acpi_last_full[idx] = remaining_capacity;
1755                 }
1756
1757                 /* not present */
1758                 if (strcmp(present, "no") == 0) {
1759                         strncpy(last_battery_str[idx], "not present", 64);
1760                 /* charging */
1761                 } else if (strcmp(charging_state, "charging") == 0) {
1762                         if (acpi_last_full[idx] != 0 && present_rate > 0) {
1763                                 /* e.g. charging 75% */
1764                                 snprintf(last_battery_str[idx],
1765                                         sizeof(last_battery_str[idx]) - 1, "charging %i%%",
1766                                         (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1767                                 /* e.g. 2h 37m */
1768                                 format_seconds(last_battery_time_str[idx],
1769                                         sizeof(last_battery_time_str[idx]) - 1,
1770                                         (long) (((acpi_last_full[idx] - remaining_capacity) *
1771                                         3600) / present_rate));
1772                         } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1773                                 snprintf(last_battery_str[idx],
1774                                         sizeof(last_battery_str[idx]) - 1, "charging %d%%",
1775                                         (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1776                                 snprintf(last_battery_time_str[idx],
1777                                         sizeof(last_battery_time_str[idx]) - 1, "unknown");
1778                         } else {
1779                                 strncpy(last_battery_str[idx], "charging",
1780                                         sizeof(last_battery_str[idx]) - 1);
1781                                 snprintf(last_battery_time_str[idx],
1782                                         sizeof(last_battery_time_str[idx]) - 1, "unknown");
1783                         }
1784                 /* discharging */
1785                 } else if (strncmp(charging_state, "discharging", 64) == 0) {
1786                         if (present_rate > 0) {
1787                                 /* e.g. discharging 35% */
1788                                 snprintf(last_battery_str[idx],
1789                                         sizeof(last_battery_str[idx]) - 1, "discharging %i%%",
1790                                         (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1791                                 /* e.g. 1h 12m */
1792                                 format_seconds(last_battery_time_str[idx],
1793                                         sizeof(last_battery_time_str[idx]) - 1,
1794                                         (long) ((remaining_capacity * 3600) / present_rate));
1795                         } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1796                                 snprintf(last_battery_str[idx],
1797                                         sizeof(last_battery_str[idx]) - 1, "full");
1798                                 snprintf(last_battery_time_str[idx],
1799                                         sizeof(last_battery_time_str[idx]) - 1, "unknown");
1800                         } else {
1801                                 snprintf(last_battery_str[idx],
1802                                         sizeof(last_battery_str[idx]) - 1, "discharging %d%%",
1803                                         (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1804                                 snprintf(last_battery_time_str[idx],
1805                                         sizeof(last_battery_time_str[idx]) - 1, "unknown");
1806                         }
1807                 /* charged */
1808                 } else if (strncmp(charging_state, "charged", 64) == 0) {
1809                         /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1810                         /* Below happens with the second battery on my X40,
1811                          * when the second one is empty and the first one being charged. */
1812                         if (remaining_capacity == 0) {
1813                                 strcpy(last_battery_str[idx], "empty");
1814                         } else {
1815                                 strcpy(last_battery_str[idx], "charged");
1816                         }
1817                 /* unknown, probably full / AC */
1818                 } else {
1819                         if (acpi_last_full[idx] != 0
1820                                         && remaining_capacity != acpi_last_full[idx]) {
1821                                 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1822                                         (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1823                         } else {
1824                                 strncpy(last_battery_str[idx], "AC", 64);
1825                         }
1826                 }
1827         } else {
1828                 /* APM */
1829                 if (apm_bat_fp[idx] == NULL) {
1830                         apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1831                 }
1832
1833                 if (apm_bat_fp[idx] != NULL) {
1834                         unsigned int ac, status, flag;
1835                         int life;
1836
1837                         fscanf(apm_bat_fp[idx], "%*s %*s %*x %x   %x       %x     %d%%",
1838                                 &ac, &status, &flag, &life);
1839
1840                         if (life == -1) {
1841                                 /* could check now that there is ac */
1842                                 snprintf(last_battery_str[idx], 64, "AC");
1843
1844                         /* could check that status == 3 here? */
1845                         } else if (ac && life != 100) {
1846                                 snprintf(last_battery_str[idx], 64, "charging %d%%", life);
1847                         } else {
1848                                 snprintf(last_battery_str[idx], 64, "%d%%", life);
1849                         }
1850
1851                         /* it seemed to buffer it so file must be closed (or could use
1852                          * syscalls directly but I don't feel like coding it now) */
1853                         fclose(apm_bat_fp[idx]);
1854                         apm_bat_fp[idx] = NULL;
1855                 }
1856         }
1857         set_return_value(buffer, n, item, idx);
1858 }
1859
1860 void set_return_value(char *buffer, unsigned int n, int item, int idx)
1861 {
1862         switch (item) {
1863                 case BATTERY_STATUS:
1864                         snprintf(buffer, n, "%s", last_battery_str[idx]);
1865                         break;
1866                 case BATTERY_TIME:
1867                         snprintf(buffer, n, "%s", last_battery_time_str[idx]);
1868                         break;
1869                 default:
1870                         break;
1871         }
1872 }
1873
1874 int get_battery_perct(const char *bat)
1875 {
1876         static int rep = 0;
1877         int idx;
1878         char acpi_path[128];
1879         char sysfs_path[128];
1880         int remaining_capacity = -1;
1881
1882         snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1883         snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1884
1885         init_batteries();
1886
1887         idx = get_battery_idx(bat);
1888
1889         /* don't update battery too often */
1890         if (current_update_time - last_battery_perct_time[idx] < 30) {
1891                 return last_battery_perct[idx];
1892         }
1893         last_battery_perct_time[idx] = current_update_time;
1894
1895         /* Only check for SYSFS or ACPI */
1896
1897         if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1898                 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1899                 rep = 0;
1900         }
1901
1902         if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1903                 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1904         }
1905
1906         if (sysfs_bat_fp[idx] != NULL) {
1907                 /* SYSFS */
1908                 while (!feof(sysfs_bat_fp[idx])) {
1909                         char buf[256];
1910                         if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1911                                 break;
1912
1913                         if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0) {
1914                                 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1915                         } else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=",25) == 0) {
1916                                 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_design_capacity[idx]);
1917                         } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0) {
1918                                 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1919                         } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=",25) == 0) {
1920                                 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_design_capacity[idx]);
1921                         }
1922                 }
1923
1924                 fclose(sysfs_bat_fp[idx]);
1925                 sysfs_bat_fp[idx] = NULL;
1926
1927         } else if (acpi_bat_fp[idx] != NULL) {
1928                 /* ACPI */
1929                 /* read last full capacity if it's zero */
1930                 if (acpi_design_capacity[idx] == 0) {
1931                         static int rep2;
1932                         char path[128];
1933                         FILE *fp;
1934
1935                         snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1936                         fp = open_file(path, &rep2);
1937                         if (fp != NULL) {
1938                                 while (!feof(fp)) {
1939                                         char b[256];
1940
1941                                         if (fgets(b, 256, fp) == NULL) {
1942                                                 break;
1943                                         }
1944                                         if (sscanf(b, "last full capacity: %d",
1945                                                                 &acpi_design_capacity[idx]) != 0) {
1946                                                 break;
1947                                         }
1948                                 }
1949                                 fclose(fp);
1950                         }
1951                 }
1952
1953                 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1954
1955                 while (!feof(acpi_bat_fp[idx])) {
1956                         char buf[256];
1957
1958                         if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1959                                 break;
1960                         }
1961
1962                         if (buf[0] == 'r') {
1963                                 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1964                         }
1965                 }
1966         }
1967         if (remaining_capacity < 0) {
1968                 return 0;
1969         }
1970         /* compute the battery percentage */
1971         last_battery_perct[idx] =
1972                 (int) (((float) remaining_capacity / acpi_design_capacity[idx]) * 100);
1973         return last_battery_perct[idx];
1974 }
1975
1976 int get_battery_perct_bar(const char *bar)
1977 {
1978         int idx;
1979
1980         get_battery_perct(bar);
1981         idx = get_battery_idx(bar);
1982         return (int) (last_battery_perct[idx] * 2.56 - 1);
1983 }
1984
1985 /* On Apple powerbook and ibook:
1986 $ cat /proc/pmu/battery_0
1987 flags      : 00000013
1988 charge     : 3623
1989 max_charge : 3720
1990 current    : 388
1991 voltage    : 16787
1992 time rem.  : 900
1993 $ cat /proc/pmu/info
1994 PMU driver version     : 2
1995 PMU firmware version   : 0c
1996 AC Power               : 1
1997 Battery count          : 1
1998 */
1999
2000 /* defines as in <linux/pmu.h> */
2001 #define PMU_BATT_PRESENT                0x00000001
2002 #define PMU_BATT_CHARGING               0x00000002
2003
2004 static FILE *pmu_battery_fp;
2005 static FILE *pmu_info_fp;
2006 static char pb_battery_info[3][32];
2007 static double pb_battery_info_update;
2008
2009 #define PMU_PATH "/proc/pmu"
2010 void get_powerbook_batt_info(char *buffer, size_t n, int i)
2011 {
2012         static int rep = 0;
2013         const char *batt_path = PMU_PATH "/battery_0";
2014         const char *info_path = PMU_PATH "/info";
2015         unsigned int flags;
2016         int charge, max_charge, ac = -1;
2017         long timeval = -1;
2018
2019         /* don't update battery too often */
2020         if (current_update_time - pb_battery_info_update < 29.5) {
2021                 snprintf(buffer, n, "%s", pb_battery_info[i]);
2022                 return;
2023         }
2024         pb_battery_info_update = current_update_time;
2025
2026         if (pmu_battery_fp == NULL) {
2027                 pmu_battery_fp = open_file(batt_path, &rep);
2028         }
2029
2030         if (pmu_battery_fp != NULL) {
2031                 rewind(pmu_battery_fp);
2032                 while (!feof(pmu_battery_fp)) {
2033                         char buf[32];
2034
2035                         if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL) {
2036                                 break;
2037                         }
2038
2039                         if (buf[0] == 'f') {
2040                                 sscanf(buf, "flags      : %8x", &flags);
2041                         } else if (buf[0] == 'c' && buf[1] == 'h') {
2042                                 sscanf(buf, "charge     : %d", &charge);
2043                         } else if (buf[0] == 'm') {
2044                                 sscanf(buf, "max_charge : %d", &max_charge);
2045                         } else if (buf[0] == 't') {
2046                                 sscanf(buf, "time rem.  : %ld", &timeval);
2047                         }
2048                 }
2049         }
2050         if (pmu_info_fp == NULL) {
2051                 pmu_info_fp = open_file(info_path, &rep);
2052         }
2053
2054         if (pmu_info_fp != NULL) {
2055                 rewind(pmu_info_fp);
2056                 while (!feof(pmu_info_fp)) {
2057                         char buf[32];
2058
2059                         if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL) {
2060                                 break;
2061                         }
2062                         if (buf[0] == 'A') {
2063                                 sscanf(buf, "AC Power               : %d", &ac);
2064                         }
2065                 }
2066         }
2067         /* update status string */
2068         if ((ac && !(flags & PMU_BATT_PRESENT))) {
2069                 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
2070         } else if (ac && (flags & PMU_BATT_PRESENT)
2071                         && !(flags & PMU_BATT_CHARGING)) {
2072                 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
2073         } else if ((flags & PMU_BATT_PRESENT) && (flags & PMU_BATT_CHARGING)) {
2074                 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
2075         } else {
2076                 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
2077         }
2078
2079         /* update percentage string */
2080         if (timeval == 0) {
2081                 pb_battery_info[PB_BATT_PERCENT][0] = 0;
2082         } else {
2083                 snprintf(pb_battery_info[PB_BATT_PERCENT],
2084                         sizeof(pb_battery_info[PB_BATT_PERCENT]), "%d%%",
2085                         (charge * 100) / max_charge);
2086         }
2087
2088         /* update time string */
2089         if (timeval == 0) {                     /* fully charged or battery not present */
2090                 pb_battery_info[PB_BATT_TIME][0] = 0;
2091         } else if (timeval < 60 * 60) { /* don't show secs */
2092                 format_seconds_short(pb_battery_info[PB_BATT_TIME],
2093                         sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2094         } else {
2095                 format_seconds(pb_battery_info[PB_BATT_TIME],
2096                         sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2097         }
2098
2099         snprintf(buffer, n, "%s", pb_battery_info[i]);
2100 }
2101
2102 void update_top(void)
2103 {
2104         show_nice_processes = 1;
2105         process_find_top(info.cpu, info.memu);
2106         info.first_process = get_first_process();
2107 }
2108
2109 /* Here come the IBM ACPI-specific things. For reference, see
2110  * http://ibm-acpi.sourceforge.net/README
2111  * If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
2112 bay
2113 beep
2114 bluetooth
2115 brightness
2116 cmos
2117 dock
2118 driver
2119 ecdump
2120 fan
2121 hotkey
2122 led
2123 light
2124 thermal
2125 video
2126 volume
2127  * The content of these files is described in detail in the aforementioned
2128  * README - some of them also in the following functions accessing them.
2129  * Peter Tarjan (ptarjan@citromail.hu) */
2130
2131 #define IBM_ACPI_DIR "/proc/acpi/ibm"
2132
2133 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
2134  * /proc/acpi/ibm/fan looks like this (3 lines):
2135 status:         disabled
2136 speed:          2944
2137 commands:       enable, disable
2138  * Peter Tarjan (ptarjan@citromail.hu) */
2139
2140 void get_ibm_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
2141 {
2142         FILE *fp;
2143         unsigned int speed = 0;
2144         char fan[128];
2145
2146         if (!p_client_buffer || client_buffer_size <= 0) {
2147                 return;
2148         }
2149
2150         snprintf(fan, 127, "%s/fan", IBM_ACPI_DIR);
2151
2152         fp = fopen(fan, "r");
2153         if (fp != NULL) {
2154                 while (!feof(fp)) {
2155                         char line[256];
2156
2157                         if (fgets(line, 255, fp) == NULL) {
2158                                 break;
2159                         }
2160                         if (sscanf(line, "speed: %u", &speed)) {
2161                                 break;
2162                         }
2163                 }
2164         } else {
2165                 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2166                         "ibm* from your Conky config file.", fan, strerror(errno));
2167         }
2168
2169         fclose(fp);
2170         snprintf(p_client_buffer, client_buffer_size, "%d", speed);
2171 }
2172
2173 /* get the measured temperatures from the temperature sensors
2174  * on IBM/Lenovo laptops running the ibm acpi.
2175  * There are 8 values in /proc/acpi/ibm/thermal, and according to
2176  * http://ibm-acpi.sourceforge.net/README
2177  * these mean the following (at least on an IBM R51...)
2178  * 0:  CPU (also on the T series laptops)
2179  * 1:  Mini PCI Module (?)
2180  * 2:  HDD (?)
2181  * 3:  GPU (also on the T series laptops)
2182  * 4:  Battery (?)
2183  * 5:  N/A
2184  * 6:  Battery (?)
2185  * 7:  N/A
2186  * I'm not too sure about those with the question mark, but the values I'm
2187  * reading from *my* thermal file (on a T42p) look realistic for the
2188  * hdd and the battery.
2189  * #5 and #7 are always -128.
2190  * /proc/acpi/ibm/thermal looks like this (1 line):
2191 temperatures:   41 43 31 46 33 -128 29 -128
2192  * Peter Tarjan (ptarjan@citromail.hu) */
2193
2194 static double last_ibm_acpi_temp_time;
2195 void get_ibm_acpi_temps(void)
2196 {
2197
2198         FILE *fp;
2199         char thermal[128];
2200
2201         /* don't update too often */
2202         if (current_update_time - last_ibm_acpi_temp_time < 10.00) {
2203                 return;
2204         }
2205         last_ibm_acpi_temp_time = current_update_time;
2206
2207         /* if (!p_client_buffer || client_buffer_size <= 0) {
2208                 return;
2209         } */
2210
2211         snprintf(thermal, 127, "%s/thermal", IBM_ACPI_DIR);
2212         fp = fopen(thermal, "r");
2213
2214         if (fp != NULL) {
2215                 while (!feof(fp)) {
2216                         char line[256];
2217
2218                         if (fgets(line, 255, fp) == NULL) {
2219                                 break;
2220                         }
2221                         if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
2222                                         &ibm_acpi.temps[0], &ibm_acpi.temps[1], &ibm_acpi.temps[2],
2223                                         &ibm_acpi.temps[3], &ibm_acpi.temps[4], &ibm_acpi.temps[5],
2224                                         &ibm_acpi.temps[6], &ibm_acpi.temps[7])) {
2225                                 break;
2226                         }
2227                 }
2228         } else {
2229                 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2230                         "ibm* from your Conky config file.", thermal, strerror(errno));
2231         }
2232
2233         fclose(fp);
2234 }
2235
2236 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
2237  * "Volume" here is none of the mixer volumes, but a "master of masters"
2238  * volume adjusted by the IBM volume keys.
2239  * /proc/acpi/ibm/fan looks like this (4 lines):
2240 level:          4
2241 mute:           off
2242 commands:       up, down, mute
2243 commands:       level <level> (<level> is 0-15)
2244  * Peter Tarjan (ptarjan@citromail.hu) */
2245
2246 void get_ibm_acpi_volume(char *p_client_buffer, size_t client_buffer_size)
2247 {
2248         FILE *fp;
2249         char volume[128];
2250         unsigned int vol = -1;
2251         char mute[3] = "";
2252
2253         if (!p_client_buffer || client_buffer_size <= 0) {
2254                 return;
2255         }
2256
2257         snprintf(volume, 127, "%s/volume", IBM_ACPI_DIR);
2258
2259         fp = fopen(volume, "r");
2260         if (fp != NULL) {
2261                 while (!feof(fp)) {
2262                         char line[256];
2263                         unsigned int read_vol = -1;
2264
2265                         if (fgets(line, 255, fp) == NULL) {
2266                                 break;
2267                         }
2268                         if (sscanf(line, "level: %u", &read_vol)) {
2269                                 vol = read_vol;
2270                                 continue;
2271                         }
2272                         if (sscanf(line, "mute: %s", mute)) {
2273                                 break;
2274                         }
2275                 }
2276         } else {
2277                 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2278                         "ibm* from your Conky config file.", volume, strerror(errno));
2279         }
2280
2281         fclose(fp);
2282
2283         if (strcmp(mute, "on") == 0) {
2284                 snprintf(p_client_buffer, client_buffer_size, "%s", "mute");
2285                 return;
2286         } else {
2287                 snprintf(p_client_buffer, client_buffer_size, "%d", vol);
2288                 return;
2289         }
2290 }
2291
2292 /* static FILE *fp = NULL; */
2293
2294 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
2295  * /proc/acpi/ibm/brightness looks like this (3 lines):
2296 level:          7
2297 commands:       up, down
2298 commands:       level <level> (<level> is 0-7)
2299  * Peter Tarjan (ptarjan@citromail.hu) */
2300
2301 void get_ibm_acpi_brightness(char *p_client_buffer, size_t client_buffer_size)
2302 {
2303         FILE *fp;
2304         unsigned int brightness = 0;
2305         char filename[128];
2306
2307         if (!p_client_buffer || client_buffer_size <= 0) {
2308                 return;
2309         }
2310
2311         snprintf(filename, 127, "%s/brightness", IBM_ACPI_DIR);
2312
2313         fp = fopen(filename, "r");
2314         if (fp != NULL) {
2315                 while (!feof(fp)) {
2316                         char line[256];
2317
2318                         if (fgets(line, 255, fp) == NULL) {
2319                                 break;
2320                         }
2321                         if (sscanf(line, "level: %u", &brightness)) {
2322                                 break;
2323                         }
2324                 }
2325         } else {
2326                 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2327                         "ibm* from your Conky config file.", filename, strerror(errno));
2328         }
2329
2330         fclose(fp);
2331
2332         snprintf(p_client_buffer, client_buffer_size, "%d", brightness);
2333 }
2334
2335 void update_entropy(void)
2336 {
2337         static int rep = 0;
2338         const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
2339         const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
2340         FILE *fp1, *fp2;
2341
2342         info.entropy.entropy_avail = 0;
2343         info.entropy.poolsize = 0;
2344
2345         if ((fp1 = open_file(entropy_avail, &rep)) == NULL) {
2346                 return;
2347         }
2348
2349         if ((fp2 = open_file(entropy_poolsize, &rep)) == NULL) {
2350                 fclose(fp1);
2351                 return;
2352         }
2353
2354         fscanf(fp1, "%u", &info.entropy.entropy_avail);
2355         fscanf(fp2, "%u", &info.entropy.poolsize);
2356
2357         fclose(fp1);
2358         fclose(fp2);
2359
2360         info.mask |= (1 << INFO_ENTROPY);
2361 }
2362
2363 const char *get_disk_protect_queue(const char *disk)
2364 {
2365         FILE *fp;
2366         char path[128];
2367         int state;
2368
2369         snprintf(path, 127, "/sys/block/%s/queue/protect", disk);
2370         if ((fp = fopen(path, "r")) == NULL)
2371                 return "n/a   ";
2372         if (fscanf(fp, "%d\n", &state) != 1) {
2373                 fclose(fp);
2374                 return "failed";
2375         }
2376         fclose(fp);
2377         return state ? "frozen" : "free  ";
2378 }
2379