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