Remove deprecated linkstatus completely from conky source
[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_i2c_sensor(const char *dev, const char *type, int n, int *div, char *devtype)
663 {
664         char i2c_dir[64];
665         if (post_21_kernel) {
666                 strncpy(i2c_dir, "/sys/bus/platform/devices/", 64);
667         } else {
668                 strncpy(i2c_dir, "/sys/bus/i2c/devices/", 64);
669         }
670         char path[256];
671         char buf[256];
672         int fd;
673         int divfd;
674
675         /* if i2c device is NULL or *, get first */
676         if (dev == NULL || strcmp(dev, "*") == 0) {
677                 static int rep = 0;
678                 if (!get_first_file_in_a_directory(i2c_dir, buf, &rep))
679                         return -1;
680                 dev = buf;
681         }
682
683         /* change vol to in */
684         if (strcmp(type, "vol") == 0)
685                 type = "in";
686
687         if (strcmp(type, "tempf") == 0) {
688                 snprintf(path, 255, "%s%s/%s%d_input", i2c_dir, dev, "temp", n);
689         } else {
690                 snprintf(path, 255, "%s%s/%s%d_input", i2c_dir, dev, type, n);
691         }
692         strncpy(devtype, path, 255);
693
694         /* open file */
695         fd = open(path, O_RDONLY);
696         if (fd < 0) {
697                 CRIT_ERR("can't open '%s': %s\nplease fix i2c or remove it from Conky", path, strerror(errno));
698         }
699
700         if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
701             || strcmp(type, "tempf") == 0)
702                 *div = 1;
703         else
704                 *div = 0;
705         /* fan does not use *_div as a read divisor */
706         if (strcmp("fan", type) == 0)
707                 return fd;
708
709         /* test if *_div file exist, open it and use it as divisor */
710         if (strcmp(type, "tempf") == 0) {
711                 snprintf(path, 255, "%s%s/%s%d_div", i2c_dir, "one", "two",
712                          n);
713         } else {
714                 snprintf(path, 255, "%s%s/%s%d_div", i2c_dir, dev, type, n);
715         }
716
717         divfd = open(path, O_RDONLY);
718         if (divfd > 0) {
719                 /* read integer */
720                 char divbuf[64];
721                 unsigned int divn;
722                 divn = read(divfd, divbuf, 63);
723                 /* should read until n == 0 but I doubt that kernel will give these
724                  * in multiple pieces. :) */
725                 divbuf[divn] = '\0';
726                 *div = atoi(divbuf);
727         }
728
729         close(divfd);
730
731         return fd;
732 }
733
734 double get_i2c_info(int *fd, int div, char *devtype, char *type)
735 {
736         int val = 0;
737
738         if (*fd <= 0)
739                 return 0;
740
741         lseek(*fd, 0, SEEK_SET);
742
743         /* read integer */
744         {
745                 char buf[64];
746                 unsigned int n;
747                 n = read(*fd, buf, 63);
748                 /* should read until n == 0 but I doubt that kernel will give these
749                  * in multiple pieces. :) */
750                 buf[n] = '\0';
751                 val = atoi(buf);
752         }
753
754         close(*fd);
755         /* open file */
756         *fd = open(devtype, O_RDONLY);
757         if (*fd < 0)
758                 ERR("can't open '%s': %s", devtype, strerror(errno));
759
760         /* My dirty hack for computing CPU value
761          * Filedil, from forums.gentoo.org
762          */
763 /*      if (strstr(devtype, "temp1_input") != NULL)
764         return -15.096+1.4893*(val / 1000.0); */
765
766
767         /* divide voltage and temperature by 1000 */
768         /* or if any other divisor is given, use that */
769         if (strcmp(type, "tempf") == 0) {
770                 if (div > 1)
771                         return ((val / div + 40) * 9.0 / 5) - 40;
772                 else if (div)
773                         return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
774                 else
775                         return ((val + 40) * 9.0 / 5) - 40;
776         } else {
777                 if (div > 1)
778                         return val / div;
779                 else if (div)
780                         return val / 1000.0;
781                 else
782                         return val;
783         }
784 }
785
786 /* Prior to kernel version 2.6.12, the CPU fan speed was available
787  * in ADT746X_FAN_OLD, whereas later kernel versions provide this
788  * information in ADT746X_FAN.
789  */
790 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
791 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
792
793 void get_adt746x_fan( char * p_client_buffer, size_t client_buffer_size )
794 {
795         static int rep = 0;
796         char adt746x_fan_state[64];
797         FILE *fp;
798
799         if ( !p_client_buffer || client_buffer_size <= 0 )
800                 return;
801
802         if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
803                  && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL)
804
805         {
806                 sprintf(adt746x_fan_state, "adt746x not found");
807         }
808         else
809         {
810                 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
811                 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
812                 fclose(fp);
813         }
814
815         snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_fan_state );
816         return;
817 }
818
819 /* Prior to kernel version 2.6.12, the CPU temperature was found
820  * in ADT746X_CPU_OLD, whereas later kernel versions provide this
821  * information in ADT746X_CPU.
822  */
823 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
824 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
825
826 void get_adt746x_cpu( char * p_client_buffer, size_t client_buffer_size )
827 {
828         static int rep = 0;
829         char adt746x_cpu_state[64];
830         FILE *fp;
831
832         if ( !p_client_buffer || client_buffer_size <= 0 )
833                 return;
834
835         if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
836                  && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL)
837         {
838                 sprintf(adt746x_cpu_state, "adt746x not found");
839         }
840         else
841         {
842                 fscanf(fp, "%2s", adt746x_cpu_state);
843                 fclose(fp);
844         }
845
846         snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state );
847         return;
848 }
849
850 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
851
852 /***********************************************************************/
853 /*
854  *  This file is part of x86info.
855  *  (C) 2001 Dave Jones.
856  *
857  *  Licensed under the terms of the GNU GPL License version 2.
858  *
859  * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
860  * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz>
861  *
862  */
863 #if  defined(__i386) || defined(__x86_64)
864 __inline__ unsigned long long int rdtsc()
865 {
866         unsigned long long int x;
867         __asm__ volatile (".byte 0x0f, 0x31":"=A" (x));
868         return x;
869 }
870 #endif
871
872 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
873 void get_freq_dynamic( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor )
874 {
875 #if  defined(__i386) || defined(__x86_64)
876         struct timezone tz;
877         struct timeval tvstart, tvstop;
878         unsigned long long cycles[2];   /* gotta be 64 bit */
879         unsigned int microseconds;      /* total time taken */
880
881         if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
882              return;
883
884         memset(&tz, 0, sizeof(tz));
885
886         /* get this function in cached memory */
887         gettimeofday(&tvstart, &tz);
888         cycles[0] = rdtsc();
889         gettimeofday(&tvstart, &tz);
890
891         /* we don't trust that this is any specific length of time */
892         usleep(100);
893         cycles[1] = rdtsc();
894         gettimeofday(&tvstop, &tz);
895         microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
896             (tvstop.tv_usec - tvstart.tv_usec);
897
898         snprintf( p_client_buffer, client_buffer_size, p_format, (float)((cycles[1] - cycles[0]) / microseconds) / divisor );
899         return;
900 #else
901 /* FIXME: hardwired: get freq for first cpu!
902    this whole function needs to be rethought and redone for
903    multi-cpu/multi-core/multi-threaded environments and
904    arbitrary combinations thereof
905 */
906         get_freq( p_client_buffer, client_buffer_size, p_format, divisor, 1 );
907         return;
908 #endif
909 }
910
911
912 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
913 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
914
915 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
916 char get_freq( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
917 {
918         FILE *f;
919   static int rep = 0;
920         char frequency[32];
921         char s[256];
922         double freq = 0;
923
924         if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
925                 return 0;
926
927   if (!prefer_proc)
928   {
929     char current_freq_file[128];
930     snprintf(current_freq_file, 127, "%s/cpu%d/%s",CPUFREQ_PREFIX, cpu-1, CPUFREQ_POSTFIX);
931           f = fopen(current_freq_file, "r");
932           if (f)
933     {
934                   /* if there's a cpufreq /sys node, read the current frequency from this node;
935                    * divide by 1000 to get Mhz. */
936                   if (fgets(s, sizeof(s), f)) {
937                             s[strlen(s)-1] = '\0';
938                             freq = strtod(s, NULL);
939                   }
940                   fclose(f);
941                   snprintf( p_client_buffer, client_buffer_size, p_format, (freq/1000)/divisor );
942                   return 1;
943     }
944         }
945
946         f = open_file("/proc/cpuinfo", &rep);           //open the CPU information file
947         if (!f) {
948                 perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
949                 return 0;
950         }
951
952         while (fgets(s, sizeof(s), f) != NULL){         //read the file
953
954 #if defined(__i386) || defined(__x86_64)
955                 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) {        //and search for the cpu mhz
956 #else
957 #if defined(__alpha)
958                 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) {          // different on alpha
959 #else
960                 if (strncmp(s, "clock", 5) == 0 && cpu == 0) {  // this is different on ppc for some reason
961 #endif // defined(__alpha)
962 #endif // defined(__i386) || defined(__x86_64)
963
964                 strcpy(frequency, strchr(s, ':') + 2);  //copy just the number
965 #if defined(__alpha)
966                 frequency[strlen(frequency) - 6] = '\0';// strip " est.\n"
967                 freq = strtod(frequency, NULL)/1000000; // kernel reports in Hz
968 #else
969                 frequency[strlen(frequency) - 1] = '\0'; // strip \n
970                 freq = strtod(frequency, NULL);
971 #endif
972                 break;
973                 }
974                 if (strncmp(s, "processor", 9) == 0) {
975                     cpu--;
976                     continue;
977                 }
978
979         }
980
981         fclose(f);
982         snprintf( p_client_buffer, client_buffer_size, p_format, (float)freq/divisor );
983         return 1;
984 }
985
986 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
987
988 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
989 char get_voltage( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
990 {
991 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks
992    something like this:
993 # frequency voltage
994 1800000 1340
995 1600000 1292
996 1400000 1100
997 1200000 988
998 1000000 1116
999 800000 1004
1000 600000 988
1001 */
1002
1003 /* Peter Tarjan (ptarjan@citromail.hu) */
1004         FILE *f;
1005         char s[256];
1006         int freq = 0;
1007         int voltage = 0;
1008         char current_freq_file[128];
1009         int freq_comp = 0;
1010
1011
1012 /* build the voltage file name */
1013         cpu--;
1014         snprintf(current_freq_file, 127, "%s/cpu%d/%s",
1015                  CPUFREQ_PREFIX, cpu, CPUFREQ_POSTFIX);
1016
1017         if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
1018                 return 0;
1019
1020         /* read the current cpu frequency from the /sys node */
1021         f = fopen(current_freq_file, "r");
1022         if (f) {
1023             if (fgets(s, sizeof(s), f)) {
1024                 s[strlen(s)-1] = '\0';
1025                 freq = strtod(s, NULL);
1026             }
1027             fclose(f);
1028         } else {
1029                 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1030                 perror("get_voltage()");
1031                 if (f) {
1032                         fclose(f);
1033                 }
1034                 return 0;
1035             }
1036
1037         snprintf(current_freq_file, 127, "%s/cpu%d/%s",
1038                  CPUFREQ_PREFIX, cpu, CPUFREQ_VOLTAGE);
1039
1040 /* use the current cpu frequency to find the corresponding voltage */
1041         f = fopen(current_freq_file, "r");
1042
1043         if (f) {
1044                 while (!feof(f)) {
1045                         char line[256];
1046                         if (fgets(line, 255, f) == NULL) break;
1047                         sscanf(line, "%d %d", &freq_comp, &voltage);
1048                         if(freq_comp == freq) break;
1049                 }
1050                 fclose(f);
1051         } else {
1052                 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1053                 perror("get_voltage()");
1054                 if (f) {
1055                         fclose(f);
1056                 }
1057                 return 0;
1058         }
1059         snprintf( p_client_buffer, client_buffer_size, p_format, (float)voltage/divisor );
1060         return 1;
1061
1062 }
1063
1064 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1065
1066 void get_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1067 {
1068         static int rep = 0;
1069         char buf[256];
1070         char buf2[256];
1071         FILE *fp;
1072
1073         if ( !p_client_buffer || client_buffer_size <= 0 )
1074                 return;
1075
1076         /* yeah, slow... :/ */
1077         if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep))
1078         {
1079                 snprintf( p_client_buffer, client_buffer_size, "no fans?" );
1080                 return;
1081         }
1082
1083         snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf );
1084
1085         fp = open_file(buf2, &rep);
1086         if (!fp) {
1087                 snprintf( p_client_buffer, client_buffer_size, "can't open fan's state file" );
1088                 return;
1089         }
1090         memset(buf,0,sizeof(buf));
1091         fscanf(fp, "%*s %99s", buf);
1092         fclose(fp);
1093
1094         snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1095
1096         return;
1097 }
1098
1099 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1100
1101 void get_acpi_ac_adapter( char * p_client_buffer, size_t client_buffer_size )
1102 {
1103         static int rep = 0;
1104         char buf[256];
1105         char buf2[256];
1106         FILE *fp;
1107
1108         if ( !p_client_buffer || client_buffer_size <= 0 )
1109                 return;
1110
1111         /* yeah, slow... :/ */
1112         if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep))
1113         {
1114                 snprintf( p_client_buffer, client_buffer_size, "no ac_adapters?" );
1115                 return;
1116         }
1117
1118         snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf );
1119
1120
1121         fp = open_file(buf2, &rep);
1122         if (!fp) {
1123                 snprintf( p_client_buffer, client_buffer_size, "No ac adapter found.... where is it?" );
1124                 return;
1125         }
1126         memset(buf,0,sizeof(buf));
1127         fscanf(fp, "%*s %99s", buf );
1128         fclose(fp);
1129
1130         snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1131
1132         return;
1133 }
1134
1135 /*
1136 /proc/acpi/thermal_zone/THRM/cooling_mode
1137 cooling mode:            active
1138 /proc/acpi/thermal_zone/THRM/polling_frequency
1139 <polling disabled>
1140 /proc/acpi/thermal_zone/THRM/state
1141 state:                   ok
1142 /proc/acpi/thermal_zone/THRM/temperature
1143 temperature:             45 C
1144 /proc/acpi/thermal_zone/THRM/trip_points
1145 critical (S5):           73 C
1146 passive:                 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1147 */
1148
1149 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1150 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1151
1152 int open_acpi_temperature(const char *name)
1153 {
1154         char path[256];
1155         char buf[256];
1156         int fd;
1157
1158         if (name == NULL || strcmp(name, "*") == 0) {
1159                 static int rep = 0;
1160                 if (!get_first_file_in_a_directory
1161                     (ACPI_THERMAL_DIR, buf, &rep))
1162                         return -1;
1163                 name = buf;
1164         }
1165
1166         snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1167
1168         fd = open(path, O_RDONLY);
1169         if (fd < 0)
1170                 ERR("can't open '%s': %s", path, strerror(errno));
1171
1172         return fd;
1173 }
1174
1175 static double last_acpi_temp;
1176 static double last_acpi_temp_time;
1177
1178 double get_acpi_temperature(int fd)
1179 {
1180         if (fd <= 0)
1181                 return 0;
1182
1183         /* don't update acpi temperature too often */
1184         if (current_update_time - last_acpi_temp_time < 11.32) {
1185                 return last_acpi_temp;
1186         }
1187         last_acpi_temp_time = current_update_time;
1188
1189         /* seek to beginning */
1190         lseek(fd, 0, SEEK_SET);
1191
1192         /* read */
1193         {
1194                 char buf[256];
1195                 int n;
1196                 n = read(fd, buf, 255);
1197                 if (n < 0)
1198                         ERR("can't read fd %d: %s", fd, strerror(errno));
1199                 else {
1200                         buf[n] = '\0';
1201                         sscanf(buf, "temperature: %lf", &last_acpi_temp);
1202                 }
1203         }
1204
1205         return last_acpi_temp;
1206 }
1207
1208 /*
1209 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1210 present:                 yes
1211 design capacity:         4400 mAh
1212 last full capacity:      4064 mAh
1213 battery technology:      rechargeable
1214 design voltage:          14800 mV
1215 design capacity warning: 300 mAh
1216 design capacity low:     200 mAh
1217 capacity granularity 1:  32 mAh
1218 capacity granularity 2:  32 mAh
1219 model number:            02KT
1220 serial number:           16922
1221 battery type:            LION
1222 OEM info:                SANYO
1223 */
1224
1225 /*
1226 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1227 present:                 yes
1228 capacity state:          ok
1229 charging state:          unknown
1230 present rate:            0 mA
1231 remaining capacity:      4064 mAh
1232 present voltage:         16608 mV
1233 */
1234
1235 /*
1236 2213<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1237 2213<@jupet kellari ö> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1238 2213<@jupet kellari ö> (-1 ollee ei akkua kiinni, koska akku on pöydällä)
1239 2214<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1240 2214<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1241
1242 2238<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1243 2239<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1244
1245 2240<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori päällä
1246 2241<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori päällä mutta ilman verkkovirtaa
1247 */
1248
1249 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1250 #define APM_PATH "/proc/apm"
1251 #define MAX_BATTERY_COUNT 4
1252
1253 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT];
1254 static FILE *apm_bat_fp[MAX_BATTERY_COUNT];
1255
1256 static int batteries_initialized = 0;
1257 static char batteries[MAX_BATTERY_COUNT][32];
1258
1259 static int acpi_last_full[MAX_BATTERY_COUNT];
1260 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1261
1262 static char last_battery_str[MAX_BATTERY_COUNT][64];    /* e.g. "charging 75%" */
1263 static char last_battery_time_str[MAX_BATTERY_COUNT][64];       /* e.g. "3h 15m" */
1264
1265 static double last_battery_time[MAX_BATTERY_COUNT];
1266
1267 static int last_battery_perct[MAX_BATTERY_COUNT];
1268 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1269
1270
1271 void init_batteries(void)
1272 {
1273         int idx;
1274         if(batteries_initialized)
1275                 return;
1276         for(idx = 0; idx < MAX_BATTERY_COUNT; idx++)
1277                 batteries[idx][0] = '\0';
1278         batteries_initialized = 1;
1279 }
1280
1281 int get_battery_idx(const char *bat)
1282 {
1283         int idx;
1284         for(idx = 0; idx < MAX_BATTERY_COUNT; idx++)
1285                 if(!strlen(batteries[idx]) || !strcmp(batteries[idx], bat))
1286                         break;
1287
1288         /* if not found, enter a new entry */
1289         if(!strlen(batteries[idx]))
1290                 snprintf(batteries[idx], 31, "%s", bat);
1291
1292         return idx;
1293 }
1294
1295 void get_battery_stuff(char *buf, unsigned int n, const char *bat, int item)
1296 {
1297         static int idx, rep = 0, rep2 = 0;
1298         char acpi_path[128];
1299         snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1300
1301         init_batteries();
1302
1303         idx = get_battery_idx(bat);
1304
1305         /* don't update battery too often */
1306         if (current_update_time - last_battery_time[idx] < 29.5)
1307                 goto set_return_value;
1308
1309         last_battery_time[idx] = current_update_time;
1310
1311         memset (last_battery_str[idx], 0, sizeof (last_battery_str[idx]));
1312         memset (last_battery_time_str[idx], 0, sizeof (last_battery_time_str[idx]));
1313
1314         /* first try ACPI */
1315
1316         if (acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1317                 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1318
1319         if (acpi_bat_fp[idx] != NULL) {
1320                 int present_rate = -1;
1321                 int remaining_capacity = -1;
1322                 char charging_state[64];
1323                 char present[4];
1324
1325                 /* read last full capacity if it's zero */
1326                 if (acpi_last_full[idx] == 0) {
1327                         static int rep = 0;
1328                         char path[128];
1329                         FILE *fp;
1330                         snprintf(path, 127,
1331                                  ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1332                         fp = open_file(path, &rep);
1333                         if (fp != NULL) {
1334                                 while (!feof(fp)) {
1335                                         char b[256];
1336                                         if (fgets(b, 256, fp) == NULL)
1337                                                 break;
1338                                         if (sscanf(b, "last full capacity: %d", &acpi_last_full[idx]) != 0) {
1339                                                 break;
1340                                         }
1341                                 }
1342
1343                                 fclose(fp);
1344                         }
1345                 }
1346
1347                 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1348
1349                 strcpy(charging_state, "unknown");
1350
1351                 while (!feof(acpi_bat_fp[idx])) {
1352                         char buf[256];
1353                         if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL)
1354                                 break;
1355
1356                         /* let's just hope units are ok */
1357                         if (strncmp (buf, "present:", 8) == 0)
1358                                 sscanf(buf, "present: %4s", present);
1359                         else if (strncmp (buf, "charging state:", 15) == 0)
1360                                 sscanf(buf, "charging state: %63s", charging_state);
1361                         else if (strncmp (buf, "present rate:", 13) == 0)
1362                                 sscanf(buf, "present rate: %d", &present_rate);
1363                         else if (strncmp(buf, "remaining capacity:", 19) == 0)
1364                                 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1365                 }
1366
1367                 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1368                 if (remaining_capacity > acpi_last_full[idx])
1369                         acpi_last_full[idx] = remaining_capacity;  /* normalize to 100% */
1370
1371                 /* not present */
1372                 if (strcmp(present, "no") == 0) {
1373                         strncpy(last_battery_str[idx], "not present", 64);
1374                 }
1375                 /* charging */
1376                 else if (strcmp(charging_state, "charging") == 0) {
1377                         if (acpi_last_full[idx] != 0 && present_rate > 0) {
1378                                 /* e.g. charging 75% */
1379                                 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %i%%",
1380                                         (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1381                                 /* e.g. 2h 37m */
1382                                 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1383                                               (long) (((acpi_last_full[idx] - remaining_capacity) * 3600) /
1384                                                       present_rate));
1385                         } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1386                                 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %d%%",
1387                                         (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1388                         } else {
1389                                 strncpy(last_battery_str[idx], "charging", sizeof(last_battery_str[idx])-1);
1390                         }
1391                 }
1392                 /* discharging */
1393                 else if (strncmp(charging_state, "discharging", 64) == 0) {
1394                         if (present_rate > 0) {
1395                                 /* e.g. discharging 35% */
1396                                 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "discharging %i%%",
1397                                         (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1398                                 /* e.g. 1h 12m */
1399                                 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1400                                               (long) ((remaining_capacity * 3600) / present_rate));
1401                         } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1402                                 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "full");
1403                         } else {
1404                                 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1405                                         "discharging %d%%",
1406                                         (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1407                         }
1408                 }
1409                 /* charged */
1410                 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1411                 else if (strncmp(charging_state, "charged", 64) == 0) {
1412                                 /* Below happens with the second battery on my X40,
1413                                  * when the second one is empty and the first one
1414                                  * being charged. */
1415                                 if (remaining_capacity == 0)
1416                                         strcpy(last_battery_str[idx], "empty");
1417                                 else
1418                                         strcpy(last_battery_str[idx], "charged");
1419                 }
1420                 /* unknown, probably full / AC */
1421                 else {
1422                         if (acpi_last_full[idx] != 0
1423                             && remaining_capacity != acpi_last_full[idx])
1424                                 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1425                                         (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1426                         else
1427                                 strncpy(last_battery_str[idx], "AC", 64);
1428                 }
1429         } else {
1430                 /* APM */
1431                 if (apm_bat_fp[idx] == NULL)
1432                         apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1433
1434                 if (apm_bat_fp[idx] != NULL) {
1435                         int ac, status, flag, life;
1436
1437                         fscanf(apm_bat_fp[idx],
1438                                "%*s %*s %*x %x   %x       %x     %d%%",
1439                                &ac, &status, &flag, &life);
1440
1441                         if (life == -1) {
1442                                 /* could check now that there is ac */
1443                                 snprintf(last_battery_str[idx], 64, "AC");
1444                         } else if (ac && life != 100) { /* could check that status==3 here? */
1445                                 snprintf(last_battery_str[idx], 64,
1446                                          "charging %d%%", life);
1447                         } else {
1448                                 snprintf(last_battery_str[idx], 64, "%d%%",
1449                                          life);
1450                         }
1451
1452                         /* it seemed to buffer it so file must be closed (or could use syscalls
1453                          * directly but I don't feel like coding it now) */
1454                         fclose(apm_bat_fp[idx]);
1455                         apm_bat_fp[idx] = NULL;
1456                 }
1457         }
1458
1459 set_return_value:
1460         switch (item) {
1461         case BATTERY_STATUS:
1462                 {
1463                         snprintf(buf, n, "%s", last_battery_str[idx]);
1464                         break;
1465                 }
1466         case BATTERY_TIME:
1467                 {
1468                         snprintf(buf, n, "%s", last_battery_time_str[idx]);
1469                         break;
1470                 }
1471         default:
1472                         break;
1473         }
1474         return;
1475 }
1476
1477 int get_battery_perct(const char *bat)
1478 {
1479         static int rep;
1480         int idx;
1481         char acpi_path[128];
1482         snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1483
1484         init_batteries();
1485
1486         idx = get_battery_idx(bat);
1487
1488         /* don't update battery too often */
1489         if (current_update_time - last_battery_perct_time[idx] < 30) {
1490                 return last_battery_perct[idx];
1491         }
1492         last_battery_perct_time[idx] = current_update_time;
1493
1494         /* Only check for ACPI */
1495
1496         if (acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1497                 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1498
1499         int remaining_capacity = -1;
1500         if (acpi_bat_fp[idx] != NULL) {
1501                 /* read last full capacity if it's zero */
1502                 if (acpi_design_capacity[idx] == 0) {
1503                         static int rep;
1504                         char path[128];
1505                         FILE *fp;
1506                         snprintf(path, 127,
1507                                  ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1508                         fp = open_file(path, &rep);
1509                         if (fp != NULL) {
1510                                 while (!feof(fp)) {
1511                                         char b[256];
1512                                         if (fgets(b, 256, fp) == NULL)
1513                                                 break;
1514                                         if (sscanf(b, "last full capacity: %d", &acpi_design_capacity[idx]) != 0) {
1515                                                 break;
1516                                         }
1517                                 }
1518                                 fclose(fp);
1519                         }
1520                 }
1521
1522                 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1523
1524                 while (!feof(acpi_bat_fp[idx])) {
1525                         char buf[256];
1526                         if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL)
1527                                 break;
1528
1529                         if (buf[0] == 'r')
1530                                 sscanf(buf, "remaining capacity: %d",
1531                                        &remaining_capacity);
1532                 }
1533         }
1534         if(remaining_capacity < 0)
1535                 return 0;
1536         /* compute the battery percentage */
1537         last_battery_perct[idx] =
1538                 (int) (((float)remaining_capacity/acpi_design_capacity[idx]) * 100);
1539         return last_battery_perct[idx];
1540 }
1541
1542 int get_battery_perct_bar(const char *bar)
1543 {
1544         int idx;
1545         get_battery_perct(bar);
1546         idx = get_battery_idx(bar);
1547         return (int) (last_battery_perct[idx] * 2.56 - 1);
1548 }
1549
1550
1551
1552 /* On Apple powerbook and ibook:
1553 $ cat /proc/pmu/battery_0
1554 flags      : 00000013
1555 charge     : 3623
1556 max_charge : 3720
1557 current    : 388
1558 voltage    : 16787
1559 time rem.  : 900
1560 $ cat /proc/pmu/info
1561 PMU driver version     : 2
1562 PMU firmware version   : 0c
1563 AC Power               : 1
1564 Battery count          : 1
1565 */
1566
1567 /* defines as in <linux/pmu.h> */
1568 #define PMU_BATT_PRESENT        0x00000001
1569 #define PMU_BATT_CHARGING       0x00000002
1570
1571 static FILE* pmu_battery_fp;
1572 static FILE* pmu_info_fp;
1573 static char pb_battery_info[3][32];
1574 static double pb_battery_info_update;
1575
1576 #define PMU_PATH "/proc/pmu"
1577 void get_powerbook_batt_info(char *buf, size_t n, int i)
1578 {
1579         static int rep = 0;
1580         const char* batt_path = PMU_PATH "/battery_0";
1581         const char* info_path = PMU_PATH "/info";
1582         int flags, charge, max_charge, ac = -1;
1583         long time = -1;
1584
1585         /* don't update battery too often */
1586         if (current_update_time - pb_battery_info_update < 29.5) {
1587                 snprintf(buf, n, "%s", pb_battery_info[i]);
1588                 return;
1589         }
1590         pb_battery_info_update = current_update_time;
1591
1592         if (pmu_battery_fp == NULL)
1593                 pmu_battery_fp = open_file(batt_path, &rep);
1594
1595         if (pmu_battery_fp != NULL) {
1596                 rewind(pmu_battery_fp);
1597                 while (!feof(pmu_battery_fp)) {
1598                         char buf[32];
1599                         if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL)
1600                                 break;
1601
1602                         if (buf[0] == 'f')
1603                                 sscanf(buf, "flags      : %8x", &flags);
1604                         else if (buf[0] == 'c' && buf[1] == 'h')
1605                                 sscanf(buf, "charge     : %d", &charge);
1606                         else if (buf[0] == 'm')
1607                                 sscanf(buf, "max_charge : %d", &max_charge);
1608                         else if (buf[0] == 't')
1609                                 sscanf(buf, "time rem.  : %ld", &time);
1610                 }
1611         }
1612         if (pmu_info_fp == NULL)
1613                 pmu_info_fp = open_file(info_path, &rep);
1614
1615         if (pmu_info_fp != NULL) {
1616                 rewind(pmu_info_fp);
1617                 while (!feof(pmu_info_fp)) {
1618                         char buf[32];
1619                         if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL)
1620                                 break;
1621                         if (buf[0] == 'A')
1622                                 sscanf(buf, "AC Power               : %d", &ac);
1623                 }
1624         }
1625         /* update status string */
1626         if ((ac && !(flags & PMU_BATT_PRESENT)))
1627                 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
1628         else if (ac && (flags & PMU_BATT_PRESENT)
1629                   && !(flags & PMU_BATT_CHARGING))
1630                 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
1631         else if ((flags & PMU_BATT_PRESENT)
1632                 && (flags & PMU_BATT_CHARGING))
1633                 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
1634         else
1635                 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
1636
1637         /* update percentage string */
1638         if (time == 0)
1639                 pb_battery_info[PB_BATT_PERCENT][0] = 0;
1640         else
1641                 snprintf(pb_battery_info[PB_BATT_PERCENT],
1642                         sizeof(pb_battery_info[PB_BATT_PERCENT]),
1643                         "%d%%", (charge * 100)/max_charge);
1644
1645         /* update time string */
1646         if (time == 0) /* fully charged or battery not present */
1647                 pb_battery_info[PB_BATT_TIME][0] = 0;
1648         else if (time < 60*60) /* don't show secs */
1649                 format_seconds_short(pb_battery_info[PB_BATT_TIME],
1650                         sizeof(pb_battery_info[PB_BATT_TIME]), time);
1651         else
1652                 format_seconds(pb_battery_info[PB_BATT_TIME],
1653                         sizeof(pb_battery_info[PB_BATT_TIME]), time);
1654
1655         snprintf(buf, n, "%s", pb_battery_info[i]);
1656 }
1657
1658 void update_top()
1659 {
1660         show_nice_processes = 1;
1661         process_find_top(info.cpu, info.memu);
1662         info.first_process = get_first_process();
1663 }
1664
1665
1666 /*
1667  *  The following ifdefs were adapted from gkrellm
1668  */
1669 #include <linux/major.h>
1670
1671 #if ! defined (MD_MAJOR)
1672 #define MD_MAJOR 9
1673 #endif
1674
1675 #if !defined(LVM_BLK_MAJOR)
1676 #define LVM_BLK_MAJOR 58
1677 #endif
1678
1679 #if !defined(NBD_MAJOR)
1680 #define NBD_MAJOR 43
1681 #endif
1682
1683 void update_diskio()
1684 {
1685         static unsigned int last = UINT_MAX;
1686         static unsigned int last_read = UINT_MAX;
1687         static unsigned int last_write = UINT_MAX;
1688         FILE* fp;
1689         static int rep=0;
1690
1691         char buf[512];
1692         int major, minor;
1693         unsigned int current = 0;
1694         unsigned int current_read = 0;
1695         unsigned int current_write = 0;
1696         unsigned int reads, writes = 0;
1697         int col_count = 0;
1698
1699         if (!(fp =open_file("/proc/diskstats", &rep))) {
1700                 diskio_value=0;
1701                 return;
1702         }
1703
1704         /* read reads and writes from all disks (minor = 0), including
1705          * cd-roms and floppies, and summ them up
1706          */
1707         while (!feof(fp)) {
1708                 fgets(buf, 512, fp);
1709                 col_count = sscanf(buf, "%u %u %*s %*u %*u %u %*u %*u %*u %u",
1710                                    &major, &minor, &reads, &writes);
1711                 /* ignore subdevices (they have only 3 matching entries in their line)
1712                  * and virtual devices (LVM, network block devices, RAM disks, Loopback)
1713                  *
1714                  * XXX ignore devices which are part of a SW RAID (MD_MAJOR)
1715                  */
1716                 if (col_count > 3 &&
1717                     major != LVM_BLK_MAJOR && major != NBD_MAJOR &&
1718                     major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
1719                         current += reads + writes;
1720                         current_read += reads;
1721                         current_write += writes;
1722                 }
1723         }
1724
1725         /* since the values in /proc/diststats are absolute, we have
1726          * to substract our last reading. The numbers stand for
1727          * "sectors read", and we therefore have to divide by two to
1728          * get KB */
1729         int tot = ((double)(current-last)/2);
1730         int tot_read = ((double)(current_read-last_read)/2);
1731         int tot_write = ((double)(current_write-last_write)/2);
1732
1733         if (last_read > current_read)
1734             tot_read = 0;
1735         if (last_write > current_write)
1736             tot_write = 0;
1737
1738         if (last > current) {
1739                 /* we hit this either if it's the very first time we
1740                  * run this, or when /proc/diskstats overflows; while
1741                  * 0 is not correct, it's at least not way off */
1742                 tot = 0;
1743         }
1744         last = current;
1745         last_read = current_read;
1746         last_write = current_write;
1747
1748         diskio_value = tot;
1749         diskio_read_value = tot_read;
1750         diskio_write_value = tot_write;
1751
1752         fclose(fp);
1753 }
1754
1755 /* Here come the IBM ACPI-specific things. For reference, see
1756  http://ibm-acpi.sourceforge.net/README
1757 If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
1758 bay
1759 beep
1760 bluetooth
1761 brightness
1762 cmos
1763 dock
1764 driver
1765 ecdump
1766 fan
1767 hotkey
1768 led
1769 light
1770 thermal
1771 video
1772 volume
1773 The content of these files is described in detail in the aforementioned
1774 README - some of them also in the following functions accessing them.
1775 Peter Tarjan (ptarjan@citromail.hu)
1776 */
1777
1778 #define IBM_ACPI_DIR "/proc/acpi/ibm"
1779
1780 void get_ibm_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1781 {
1782 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
1783    /proc/acpi/ibm/fan looks like this (3 lines):
1784 status:         disabled
1785 speed:          2944
1786 commands:       enable, disable
1787 Peter Tarjan (ptarjan@citromail.hu)
1788 */
1789
1790     if ( !p_client_buffer || client_buffer_size <= 0 )
1791         return;
1792
1793     FILE *fp;
1794     unsigned int speed=0;
1795     char fan[128];
1796     snprintf(fan, 127, "%s/fan",IBM_ACPI_DIR);
1797
1798     fp = fopen(fan, "r");
1799     if (fp != NULL)
1800     {
1801         while (!feof(fp))
1802         {
1803             char line[256];
1804             if (fgets(line, 255, fp) == NULL) break;
1805             if (sscanf(line, "speed: %d", &speed)) break;
1806         }
1807     }
1808     else
1809     {
1810         CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", fan, strerror(errno));
1811     }
1812
1813     fclose(fp);
1814     snprintf( p_client_buffer, client_buffer_size, "%d", speed );
1815     return;
1816
1817 }
1818
1819 static double last_ibm_acpi_temp_time;
1820 void get_ibm_acpi_temps()
1821 {
1822 /* get the measured temperatures from the temperature sensors
1823    on IBM/Lenovo laptops running the ibm acpi.
1824    There are 8 values in /proc/acpi/ibm/thermal, and according to
1825    http://ibm-acpi.sourceforge.net/README
1826    these mean the following (at least on an IBM R51...)
1827 0:  CPU (also on the T series laptops)
1828 1:  Mini PCI Module (?)
1829 2:  HDD (?)
1830 3:  GPU (also on the T series laptops)
1831 4:  Battery (?)
1832 5:  N/A
1833 6:  Battery (?)
1834 7:  N/A
1835    I'm not too sure about those with the question mark, but the values I'm
1836    reading from *my* thermal file (on a T42p) look realistic for the
1837    hdd and the battery.
1838    #5 and #7 are always -128.
1839    /proc/acpi/ibm/thermal looks like this (1 line):
1840 temperatures:   41 43 31 46 33 -128 29 -128
1841 Peter Tarjan (ptarjan@citromail.hu)
1842 */
1843
1844 /*    don't update too often */
1845     if (current_update_time - last_ibm_acpi_temp_time < 10.00)
1846     {
1847         return;
1848     }
1849     last_ibm_acpi_temp_time = current_update_time;
1850
1851 /*    if ( !p_client_buffer || client_buffer_size <= 0 )
1852       return; */
1853
1854     FILE *fp;
1855
1856     char thermal[128];
1857     snprintf(thermal, 127, "%s/thermal",IBM_ACPI_DIR);
1858     fp = fopen(thermal, "r");
1859
1860     if (fp != NULL)
1861     {
1862         while (!feof(fp))
1863         {
1864             char line[256];
1865             if (fgets(line, 255, fp) == NULL) break;
1866             if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
1867                        &ibm_acpi.temps[0], &ibm_acpi.temps[1],
1868                        &ibm_acpi.temps[2], &ibm_acpi.temps[3],
1869                        &ibm_acpi.temps[4], &ibm_acpi.temps[5],
1870                        &ibm_acpi.temps[6], &ibm_acpi.temps[7])) break;
1871         }
1872     }
1873     else
1874     {
1875         CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", thermal, strerror(errno));
1876     }
1877
1878     fclose(fp);
1879
1880 }
1881
1882
1883 void get_ibm_acpi_volume( char * p_client_buffer, size_t client_buffer_size )
1884 {
1885
1886 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
1887    "Volume" here is none of the mixer volumes, but a "master of masters"
1888    volume adjusted by the IBM volume keys.
1889    /proc/acpi/ibm/fan looks like this (4 lines):
1890 level:          4
1891 mute:           off
1892 commands:       up, down, mute
1893 commands:       level <level> (<level> is 0-15)
1894 Peter Tarjan (ptarjan@citromail.hu)
1895 */
1896
1897     if ( !p_client_buffer || client_buffer_size <= 0 )
1898         return;
1899
1900     FILE *fp;
1901
1902     char volume[128];
1903     snprintf(volume, 127, "%s/volume",IBM_ACPI_DIR);
1904     unsigned int vol=-1;
1905     char mute[3]="";
1906
1907     fp = fopen(volume, "r");
1908     if (fp != NULL)
1909     {
1910         while (!feof(fp))
1911         {
1912             char line[256];
1913             if (fgets(line, 255, fp) == NULL) break;
1914             if (sscanf(line, "level: %d", &vol)) continue;
1915             if (sscanf(line, "mute: %s", mute)) break;
1916         }
1917     }
1918     else
1919     {
1920         CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", volume, strerror(errno));
1921     }
1922
1923     fclose(fp);
1924
1925     if (strcmp(mute, "on")==0)
1926     {
1927         snprintf( p_client_buffer, client_buffer_size, "%s", "mute" );
1928         return;
1929     }
1930     else
1931     {
1932         snprintf( p_client_buffer, client_buffer_size, "%d", vol );
1933         return;
1934     }
1935
1936 }
1937
1938 /*static FILE *fp=NULL;*/
1939
1940 void get_ibm_acpi_brightness(char * p_client_buffer, size_t client_buffer_size)
1941 {
1942 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
1943    /proc/acpi/ibm/brightness looks like this (3 lines):
1944 level:          7
1945 commands:       up, down
1946 commands:       level <level> (<level> is 0-7)
1947 Peter Tarjan (ptarjan@citromail.hu)
1948 */
1949
1950     if ( !p_client_buffer || client_buffer_size <= 0 )
1951         return;
1952
1953     FILE *fp;
1954     unsigned int brightness=0;
1955     char filename[128];
1956     snprintf(filename, 127, "%s/brightness",IBM_ACPI_DIR);
1957
1958     fp = fopen(filename, "r");
1959     if (fp != NULL)
1960     {
1961         while (!feof(fp))
1962         {
1963             char line[256];
1964             if (fgets(line, 255, fp) == NULL) break;
1965             if (sscanf(line, "level: %d", &brightness)) break;
1966         }
1967     }
1968     else
1969     {
1970         CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", filename, strerror(errno));
1971     }
1972
1973     fclose(fp);
1974
1975     snprintf( p_client_buffer, client_buffer_size, "%d", brightness );
1976     return;
1977
1978 }
1979
1980 void update_entropy (void)
1981 {
1982   static int rep = 0;
1983   const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
1984   const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
1985   FILE *fp1, *fp2;
1986
1987   info.entropy.entropy_avail=0;
1988   info.entropy.poolsize=0;
1989
1990   if ((fp1 = open_file (entropy_avail, &rep))==NULL)
1991     return;
1992
1993   if ((fp2 = open_file (entropy_poolsize, &rep))==NULL)
1994   {
1995     fclose (fp1);
1996     return;
1997   }
1998
1999   fscanf (fp1, "%u", &info.entropy.entropy_avail);
2000   fscanf (fp2, "%u", &info.entropy.poolsize);
2001
2002   fclose (fp1);
2003   fclose (fp2);
2004
2005   info.mask |= (1 << INFO_ENTROPY);
2006 }