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