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