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