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