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