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