stable now, graphs might need some tweaks
[monky] / src / linux.c
1 /* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
2  * vim: ts=4 sw=4 noet ai cindent syntax=c
3  *
4  * Conky, a system monitor, based on torsmo
5  *
6  * Any original torsmo code is licensed under the BSD license
7  *
8  * All code written since the fork of torsmo is licensed under the GPL
9  *
10  * Please see COPYING for details
11  *
12  * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
13  * Copyright (c) 2007 Toni Spets
14  * Copyright (c) 2005-2010 Brenden Matthews, Philip Kovacs, et. al.
15  *      (see AUTHORS)
16  * All rights reserved.
17  *
18  * This program is free software: you can redistribute it and/or modify
19  * it under the terms of the GNU General Public License as published by
20  * the Free Software Foundation, either version 3 of the License, or
21  * (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  * GNU General Public License for more details.
27  * You should have received a copy of the GNU General Public License
28  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
29  *
30  */
31
32 #include "conky.h"
33 #include "logging.h"
34 #include "common.h"
35 #include "linux.h"
36 #include "net_stat.h"
37 #include "diskio.h"
38 #include "bme.c"
39 #include "temphelper.h"
40 #include <dirent.h>
41 #include <ctype.h>
42 #include <errno.h>
43 #include <limits.h>
44 #include <sys/types.h>
45 #include <sys/sysinfo.h>
46 #include <sys/stat.h>
47 #ifndef HAVE_CLOCK_GETTIME
48 #include <sys/time.h>
49 #endif
50 #include <fcntl.h>
51 #include <unistd.h>
52 // #include <assert.h>
53 #include <time.h>
54 #include "top.h"
55
56 #include <sys/ioctl.h>
57 #include <sys/socket.h>
58 #include <netinet/in.h>
59 #include <linux/sockios.h>
60 #include <net/if.h>
61 #include <arpa/inet.h>
62 #ifdef _NET_IF_H
63 #define _LINUX_IF_H
64 #endif
65 #include <linux/route.h>
66 #include <math.h>
67 #include <pthread.h>
68
69 /* The following ifdefs were adapted from gkrellm */
70 #include <linux/major.h>
71
72 #if !defined(MD_MAJOR)
73 #define MD_MAJOR 9
74 #endif
75
76 #if !defined(LVM_BLK_MAJOR)
77 #define LVM_BLK_MAJOR 58
78 #endif
79
80 #if !defined(NBD_MAJOR)
81 #define NBD_MAJOR 43
82 #endif
83
84 #ifdef HAVE_IWLIB
85 #include <iwlib.h>
86 #endif
87
88 #include <dbus/dbus.h>
89
90 struct sysfs {
91         int fd;
92         int arg;
93         char devtype[256];
94         char type[64];
95         float factor, offset;
96 };
97
98 #define SHORTSTAT_TEMPL "%*s %llu %llu %llu"
99 #define LONGSTAT_TEMPL "%*s %llu %llu %llu "
100
101 /* This flag tells the linux routines to use the /proc system where possible,
102  * even if other api's are available, e.g. sysinfo() or getloadavg().
103  * the reason for this is to allow for /proc-based distributed monitoring.
104  * using a flag in this manner creates less confusing code. */
105 static int prefer_proc = 0;
106
107 void prepare_update(void)
108 {
109 }
110
111 int update_uptime(void)
112 {
113 #ifdef HAVE_SYSINFO
114         if (!prefer_proc) {
115                 struct sysinfo s_info;
116
117                 sysinfo(&s_info);
118                 info.uptime = (double) s_info.uptime;
119         } else
120 #endif
121         {
122                 static int rep = 0;
123                 FILE *fp;
124
125                 if (!(fp = open_file("/proc/uptime", &rep))) {
126                         info.uptime = 0.0;
127                         return 0;
128                 }
129                 fscanf(fp, "%lf", &info.uptime);
130                 fclose(fp);
131         }
132         return 0;
133 }
134
135 int check_mount(char *s)
136 {
137         int ret = 0;
138         FILE *mtab = fopen("/etc/mtab", "r");
139
140         if (mtab) {
141                 char buf1[256], buf2[128];
142
143                 while (fgets(buf1, 256, mtab)) {
144                         sscanf(buf1, "%*s %128s", buf2);
145                         if (!strcmp(s, buf2)) {
146                                 ret = 1;
147                                 break;
148                         }
149                 }
150                 fclose(mtab);
151         } else {
152                 NORM_ERR("Could not open mtab");
153         }
154         return ret;
155 }
156
157 /* these things are also in sysinfo except Buffers:
158  * (that's why I'm reading them from proc) */
159
160 int update_meminfo(void)
161 {
162         FILE *meminfo_fp;
163         static int rep = 0;
164
165         /* unsigned int a; */
166         char buf[256];
167
168         info.mem = info.memmax = info.swap = info.swapfree = info.swapmax = info.bufmem =
169                 info.buffers = info.cached = info.memfree = info.memeasyfree = 0;
170
171         if (!(meminfo_fp = open_file("/proc/meminfo", &rep))) {
172                 return 0;
173         }
174
175         while (!feof(meminfo_fp)) {
176                 if (fgets(buf, 255, meminfo_fp) == NULL) {
177                         break;
178                 }
179
180                 if (strncmp(buf, "MemTotal:", 9) == 0) {
181                         sscanf(buf, "%*s %llu", &info.memmax);
182                 } else if (strncmp(buf, "MemFree:", 8) == 0) {
183                         sscanf(buf, "%*s %llu", &info.memfree);
184                 } else if (strncmp(buf, "SwapTotal:", 10) == 0) {
185                         sscanf(buf, "%*s %llu", &info.swapmax);
186                 } else if (strncmp(buf, "SwapFree:", 9) == 0) {
187                         sscanf(buf, "%*s %llu", &info.swapfree);
188                 } else if (strncmp(buf, "Buffers:", 8) == 0) {
189                         sscanf(buf, "%*s %llu", &info.buffers);
190                 } else if (strncmp(buf, "Cached:", 7) == 0) {
191                         sscanf(buf, "%*s %llu", &info.cached);
192                 }
193         }
194
195         info.mem = info.memmax - info.memfree;
196         info.memeasyfree = info.memfree;
197         info.swap = info.swapmax - info.swapfree;
198
199         info.bufmem = info.cached + info.buffers;
200
201         fclose(meminfo_fp);
202         return 0;
203 }
204
205 int get_laptop_mode(void)
206 {
207         FILE *fp;
208         int val = -1;
209
210         if ((fp = fopen("/proc/sys/vm/laptop_mode", "r")) != NULL)
211                 fscanf(fp, "%d\n", &val);
212         fclose(fp);
213         return val;
214 }
215
216 /* my system says:
217  * # cat /sys/block/sda/queue/scheduler
218  * noop [anticipatory] cfq
219  */
220 char *get_ioscheduler(char *disk)
221 {
222         FILE *fp;
223         char buf[128];
224
225         if (!disk)
226                 return strndup("n/a", text_buffer_size);
227
228         snprintf(buf, 127, "/sys/block/%s/queue/scheduler", disk);
229         if ((fp = fopen(buf, "r")) == NULL) {
230                 return strndup("n/a", text_buffer_size);
231         }
232         while (!feof(fp)) {
233                 fscanf(fp, "%127s", buf);
234                 if (buf[0] == '[') {
235                         buf[strlen(buf) - 1] = '\0';
236                         fclose(fp);
237                         return strndup(buf + 1, text_buffer_size);
238                 }
239         }
240         fclose(fp);
241         return strndup("n/a", text_buffer_size);
242 }
243
244 static struct {
245         char *iface;
246         char *ip;
247         int count;
248 } gw_info;
249
250 #define COND_FREE(x) if(x) free(x); x = 0
251 #define SAVE_SET_STRING(x, y) \
252         if (x && strcmp((char *)x, (char *)y)) { \
253                 free(x); \
254                 x = strndup("multiple", text_buffer_size); \
255         } else if (!x) { \
256                 x = strndup(y, text_buffer_size); \
257         }
258
259 void update_gateway_info_failure(const char *reason)
260 {
261         if(reason != NULL) {
262                 perror(reason);
263         }
264         //2 pointers to 1 location causes a crash when we try to free them both
265         gw_info.iface = strndup("failed", text_buffer_size);
266         gw_info.ip = strndup("failed", text_buffer_size);
267 }
268
269
270 /* Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT */
271 #define RT_ENTRY_FORMAT "%63s %lx %lx %x %*d %*d %*d %lx %*d %*d %*d\n"
272
273 int update_gateway_info(void)
274 {
275         FILE *fp;
276         struct in_addr ina;
277         char iface[64];
278         unsigned long dest, gate, mask;
279         unsigned int flags;
280
281         COND_FREE(gw_info.iface);
282         COND_FREE(gw_info.ip);
283         gw_info.count = 0;
284
285         if ((fp = fopen("/proc/net/route", "r")) == NULL) {
286                 update_gateway_info_failure("fopen()");
287                 return 0;
288         }
289
290         /* skip over the table header line, which is always present */
291         fscanf(fp, "%*[^\n]\n");
292
293         while (!feof(fp)) {
294                 if(fscanf(fp, RT_ENTRY_FORMAT,
295                           iface, &dest, &gate, &flags, &mask) != 5) {
296                         update_gateway_info_failure("fscanf()");
297                         break;
298                 }
299                 if (!(dest || mask) && ((flags & RTF_GATEWAY) || !gate) ) {
300                         gw_info.count++;
301                         SAVE_SET_STRING(gw_info.iface, iface)
302                         ina.s_addr = gate;
303                         SAVE_SET_STRING(gw_info.ip, inet_ntoa(ina))
304                 }
305         }
306         fclose(fp);
307         return 0;
308 }
309
310 void free_gateway_info(void)
311 {
312         if (gw_info.iface)
313                 free(gw_info.iface);
314         if (gw_info.ip)
315                 free(gw_info.ip);
316         memset(&gw_info, 0, sizeof(gw_info));
317 }
318
319 int gateway_exists(void)
320 {
321         return !!gw_info.count;
322 }
323
324 void print_gateway_iface(char *p, int p_max_size)
325 {
326         snprintf(p, p_max_size, "%s", gw_info.iface);
327 }
328
329 void print_gateway_ip(char *p, int p_max_size)
330 {
331         snprintf(p, p_max_size, "%s", gw_info.ip);
332 }
333
334 int update_net_stats(void)
335 {
336         FILE *net_dev_fp;
337         static int rep = 0;
338         static char first = 1;
339
340         // FIXME: arbitrary size chosen to keep code simple.
341         int i, i2;
342         unsigned int curtmp1, curtmp2;
343         unsigned int k;
344         struct ifconf conf;
345         char buf[256];
346         double delta;
347
348 #ifdef HAVE_IWLIB
349         // wireless info variables
350         int skfd, has_bitrate = 0;
351         struct wireless_info *winfo;
352         struct iwreq wrq;
353 #endif
354
355         /* get delta */
356         delta = current_update_time - last_update_time;
357         if (delta <= 0.0001) {
358                 return 0;
359         }
360
361         /* open file and ignore first two lines */
362         if (!(net_dev_fp = open_file("/proc/net/dev", &rep))) {
363                 clear_net_stats();
364                 return 0;
365         }
366
367         fgets(buf, 255, net_dev_fp);    /* garbage */
368         fgets(buf, 255, net_dev_fp);    /* garbage (field names) */
369
370         /* read each interface */
371         for (i2 = 0; i2 < MAX_NET_INTERFACES; i2++) {
372                 struct net_stat *ns;
373                 char *s, *p;
374                 char temp_addr[18];
375                 long long r, t, last_recv, last_trans;
376
377                 if (fgets(buf, 255, net_dev_fp) == NULL) {
378                         break;
379                 }
380                 p = buf;
381                 while (isspace((int) *p)) {
382                         p++;
383                 }
384
385                 s = p;
386
387                 while (*p && *p != ':') {
388                         p++;
389                 }
390                 if (*p == '\0') {
391                         continue;
392                 }
393                 *p = '\0';
394                 p++;
395
396                 ns = get_net_stat(s, NULL, NULL);
397                 ns->up = 1;
398                 memset(&(ns->addr.sa_data), 0, 14);
399
400                 memset(ns->addrs, 0, 17 * MAX_NET_INTERFACES + 1); /* Up to 17 chars per ip, max MAX_NET_INTERFACES interfaces. Nasty memory usage... */
401
402                 last_recv = ns->recv;
403                 last_trans = ns->trans;
404
405                 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
406                 sscanf(p, "%lld  %*d     %*d  %*d  %*d  %*d   %*d        %*d       %lld",
407                         &r, &t);
408
409                 /* if recv or trans is less than last time, an overflow happened */
410                 if (r < ns->last_read_recv) {
411                         last_recv = 0;
412                 } else {
413                         ns->recv += (r - ns->last_read_recv);
414                 }
415                 ns->last_read_recv = r;
416
417                 if (t < ns->last_read_trans) {
418                         last_trans = 0;
419                 } else {
420                         ns->trans += (t - ns->last_read_trans);
421                 }
422                 ns->last_read_trans = t;
423
424                 /*** ip addr patch ***/
425                 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
426
427                 conf.ifc_buf = malloc(sizeof(struct ifreq) * MAX_NET_INTERFACES);
428                 conf.ifc_len = sizeof(struct ifreq) * MAX_NET_INTERFACES;
429                 memset(conf.ifc_buf, 0, conf.ifc_len);
430
431                 ioctl((long) i, SIOCGIFCONF, &conf);
432
433                 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
434                         struct net_stat *ns2;
435
436                         if (!(((struct ifreq *) conf.ifc_buf) + k))
437                                 break;
438
439                         ns2 = get_net_stat(
440                                         ((struct ifreq *) conf.ifc_buf)[k].ifr_ifrn.ifrn_name, NULL, NULL);
441                         ns2->addr = ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.ifru_addr;
442                         sprintf(temp_addr, "%u.%u.%u.%u, ",
443                                         ns2->addr.sa_data[2] & 255,
444                                         ns2->addr.sa_data[3] & 255,
445                                         ns2->addr.sa_data[4] & 255,
446                                         ns2->addr.sa_data[5] & 255);
447                         if(NULL == strstr(ns2->addrs, temp_addr))
448                                 strncpy(ns2->addrs + strlen(ns2->addrs), temp_addr, 17);
449                 }
450
451                 close((long) i);
452
453                 free(conf.ifc_buf);
454
455                 /*** end ip addr patch ***/
456
457                 if (!first) {
458                         /* calculate speeds */
459                         ns->net_rec[0] = (ns->recv - last_recv) / delta;
460                         ns->net_trans[0] = (ns->trans - last_trans) / delta;
461                 }
462
463                 curtmp1 = 0;
464                 curtmp2 = 0;
465                 // get an average
466 #ifdef HAVE_OPENMP
467 #pragma omp parallel for reduction(+:curtmp1, curtmp2) schedule(dynamic,10)
468 #endif /* HAVE_OPENMP */
469                 for (i = 0; i < info.net_avg_samples; i++) {
470                         curtmp1 = curtmp1 + ns->net_rec[i];
471                         curtmp2 = curtmp2 + ns->net_trans[i];
472                 }
473                 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
474                 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
475                 if (info.net_avg_samples > 1) {
476 #ifdef HAVE_OPENMP
477 #pragma omp parallel for schedule(dynamic,10)
478 #endif /* HAVE_OPENMP */
479                         for (i = info.net_avg_samples; i > 1; i--) {
480                                 ns->net_rec[i - 1] = ns->net_rec[i - 2];
481                                 ns->net_trans[i - 1] = ns->net_trans[i - 2];
482                         }
483                 }
484
485 #ifdef HAVE_IWLIB
486                 /* update wireless info */
487                 winfo = malloc(sizeof(struct wireless_info));
488                 memset(winfo, 0, sizeof(struct wireless_info));
489
490                 skfd = iw_sockets_open();
491                 if (iw_get_basic_config(skfd, s, &(winfo->b)) > -1) {
492
493                         // set present winfo variables
494                         if (iw_get_stats(skfd, s, &(winfo->stats),
495                                         &winfo->range, winfo->has_range) >= 0) {
496                                 winfo->has_stats = 1;
497                         }
498                         if (iw_get_range_info(skfd, s, &(winfo->range)) >= 0) {
499                                 winfo->has_range = 1;
500                         }
501                         if (iw_get_ext(skfd, s, SIOCGIWAP, &wrq) >= 0) {
502                                 winfo->has_ap_addr = 1;
503                                 memcpy(&(winfo->ap_addr), &(wrq.u.ap_addr), sizeof(sockaddr));
504                         }
505
506                         // get bitrate
507                         if (iw_get_ext(skfd, s, SIOCGIWRATE, &wrq) >= 0) {
508                                 memcpy(&(winfo->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
509                                 iw_print_bitrate(ns->bitrate, 16, winfo->bitrate.value);
510                                 has_bitrate = 1;
511                         }
512
513                         // get link quality
514                         if (winfo->has_range && winfo->has_stats
515                                         && ((winfo->stats.qual.level != 0)
516                                         || (winfo->stats.qual.updated & IW_QUAL_DBM))) {
517                                 if (!(winfo->stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
518                                         ns->link_qual = winfo->stats.qual.qual;
519                                         ns->link_qual_max = winfo->range.max_qual.qual;
520                                 }
521                         }
522
523                         // get ap mac
524                         if (winfo->has_ap_addr) {
525                                 iw_sawap_ntop(&winfo->ap_addr, ns->ap);
526                         }
527
528                         // get essid
529                         if (winfo->b.has_essid) {
530                                 if (winfo->b.essid_on) {
531                                         snprintf(ns->essid, 32, "%s", winfo->b.essid);
532                                 } else {
533                                         snprintf(ns->essid, 32, "off/any");
534                                 }
535                         }
536
537                         snprintf(ns->mode, 16, "%s", iw_operation_mode[winfo->b.mode]);
538                 }
539                 iw_sockets_close(skfd);
540                 free(winfo);
541 #endif
542         }
543         first = 0;
544
545         fclose(net_dev_fp);
546         return 0;
547 }
548
549 int result;
550
551 int update_total_processes(void)
552 {
553         DIR *dir;
554         struct dirent *entry;
555         int ignore1;
556         char ignore2;
557
558         info.procs = 0;
559         if (!(dir = opendir("/proc"))) {
560                 return 0;
561         }
562         while ((entry = readdir(dir))) {
563                 if (!entry) {
564                         /* Problem reading list of processes */
565                         closedir(dir);
566                         info.procs = 0;
567                         return 0;
568                 }
569                 if (sscanf(entry->d_name, "%d%c", &ignore1, &ignore2) == 1) {
570                         info.procs++;
571                 }
572         }
573         closedir(dir);
574         return 0;
575 }
576
577 int update_threads(void)
578 {
579 #ifdef HAVE_SYSINFO
580         if (!prefer_proc) {
581                 struct sysinfo s_info;
582
583                 sysinfo(&s_info);
584                 info.threads = s_info.procs;
585         } else
586 #endif
587         {
588                 static int rep = 0;
589                 FILE *fp;
590
591                 if (!(fp = open_file("/proc/loadavg", &rep))) {
592                         info.threads = 0;
593                         return 0;
594                 }
595                 fscanf(fp, "%*f %*f %*f %*d/%hu", &info.threads);
596                 fclose(fp);
597         }
598         return 0;
599 }
600
601 #define CPU_SAMPLE_COUNT 15
602 struct cpu_info {
603         unsigned long long cpu_user;
604         unsigned long long cpu_system;
605         unsigned long long cpu_nice;
606         unsigned long long cpu_idle;
607         unsigned long long cpu_iowait;
608         unsigned long long cpu_irq;
609         unsigned long long cpu_softirq;
610         unsigned long long cpu_steal;
611         unsigned long long cpu_total;
612         unsigned long long cpu_active_total;
613         unsigned long long cpu_last_total;
614         unsigned long long cpu_last_active_total;
615         double cpu_val[CPU_SAMPLE_COUNT];
616 };
617 static short cpu_setup = 0;
618
619 /* Determine if this kernel gives us "extended" statistics information in
620  * /proc/stat.
621  * Kernels around 2.5 and earlier only reported user, system, nice, and
622  * idle values in proc stat.
623  * Kernels around 2.6 and greater report these PLUS iowait, irq, softirq,
624  * and steal */
625 void determine_longstat(char *buf)
626 {
627         unsigned long long iowait = 0;
628
629         KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
630         /* scanf will either return -1 or 1 because there is only 1 assignment */
631         if (sscanf(buf, "%*s %*d %*d %*d %*d %llu", &iowait) > 0) {
632                 KFLAG_SETON(KFLAG_IS_LONGSTAT);
633         }
634 }
635
636 void get_cpu_count(void)
637 {
638         FILE *stat_fp;
639         static int rep = 0;
640         char buf[256];
641
642         if (info.cpu_usage) {
643                 return;
644         }
645
646         if (!(stat_fp = open_file("/proc/stat", &rep))) {
647                 return;
648         }
649
650         info.cpu_count = 0;
651
652         while (!feof(stat_fp)) {
653                 if (fgets(buf, 255, stat_fp) == NULL) {
654                         break;
655                 }
656
657                 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
658                         if (info.cpu_count == 0) {
659                                 determine_longstat(buf);
660                         }
661                         info.cpu_count++;
662                 }
663         }
664         info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
665
666         fclose(stat_fp);
667 }
668
669 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
670 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
671
672 int update_stat(void)
673 {
674         FILE *stat_fp;
675         static int rep = 0;
676         static struct cpu_info *cpu = NULL;
677         char buf[256];
678         int i;
679         unsigned int idx;
680         double curtmp;
681         const char *stat_template = NULL;
682         unsigned int malloc_cpu_size = 0;
683         extern void* global_cpu;
684
685         static pthread_mutex_t last_stat_update_mutex = PTHREAD_MUTEX_INITIALIZER;
686         static double last_stat_update = 0.0;
687
688         /* since we use wrappers for this function, the update machinery
689          * can't eliminate double invocations of this function. Check for
690          * them here, otherwise cpu_usage counters are freaking out. */
691         pthread_mutex_lock(&last_stat_update_mutex);
692         if (last_stat_update == current_update_time) {
693                 pthread_mutex_unlock(&last_stat_update_mutex);
694                 return 0;
695         }
696         last_stat_update = current_update_time;
697         pthread_mutex_unlock(&last_stat_update_mutex);
698
699         /* add check for !info.cpu_usage since that mem is freed on a SIGUSR1 */
700         if (!cpu_setup || !info.cpu_usage) {
701                 get_cpu_count();
702                 cpu_setup = 1;
703         }
704
705         if (!stat_template) {
706                 stat_template =
707                         KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT;
708         }
709
710         if (!global_cpu) {
711                 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
712                 cpu = malloc(malloc_cpu_size);
713                 memset(cpu, 0, malloc_cpu_size);
714                 global_cpu = cpu;
715         }
716
717         if (!(stat_fp = open_file("/proc/stat", &rep))) {
718                 info.run_threads = 0;
719                 if (info.cpu_usage) {
720                         memset(info.cpu_usage, 0, info.cpu_count * sizeof(float));
721                 }
722                 return 0;
723         }
724
725         idx = 0;
726         while (!feof(stat_fp)) {
727                 if (fgets(buf, 255, stat_fp) == NULL) {
728                         break;
729                 }
730
731                 if (strncmp(buf, "procs_running ", 14) == 0) {
732                         sscanf(buf, "%*s %hu", &info.run_threads);
733                 } else if (strncmp(buf, "cpu", 3) == 0) {
734                         double delta;
735                         if (isdigit(buf[3])) {
736                                 idx = atoi(&buf[3]) + 1;
737                         } else {
738                                 idx = 0;
739                         }
740                         sscanf(buf, stat_template, &(cpu[idx].cpu_user),
741                                 &(cpu[idx].cpu_nice), &(cpu[idx].cpu_system),
742                                 &(cpu[idx].cpu_idle), &(cpu[idx].cpu_iowait),
743                                 &(cpu[idx].cpu_irq), &(cpu[idx].cpu_softirq),
744                                 &(cpu[idx].cpu_steal));
745
746                         cpu[idx].cpu_total = cpu[idx].cpu_user + cpu[idx].cpu_nice +
747                                 cpu[idx].cpu_system + cpu[idx].cpu_idle +
748                                 cpu[idx].cpu_iowait + cpu[idx].cpu_irq +
749                                 cpu[idx].cpu_softirq + cpu[idx].cpu_steal;
750
751                         cpu[idx].cpu_active_total = cpu[idx].cpu_total -
752                                 (cpu[idx].cpu_idle + cpu[idx].cpu_iowait);
753
754                         delta = current_update_time - last_update_time;
755
756                         if (delta <= 0.001) {
757                                 break;
758                         }
759
760                         cpu[idx].cpu_val[0] = (cpu[idx].cpu_active_total -
761                                 cpu[idx].cpu_last_active_total) /
762                                 (float) (cpu[idx].cpu_total - cpu[idx].cpu_last_total);
763                         curtmp = 0;
764 #ifdef HAVE_OPENMP
765 #pragma omp parallel for reduction(+:curtmp) schedule(dynamic,10)
766 #endif /* HAVE_OPENMP */
767                         for (i = 0; i < info.cpu_avg_samples; i++) {
768                                 curtmp = curtmp + cpu[idx].cpu_val[i];
769                         }
770                         /* TESTING -- I've removed this, because I don't think it is right.
771                          * You shouldn't divide by the cpu count here ...
772                          * removing for testing */
773                         /* if (idx == 0) {
774                                 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples /
775                                         info.cpu_count;
776                         } else {
777                                 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples;
778                         } */
779                         /* TESTING -- this line replaces the prev. "suspect" if/else */
780                         info.cpu_usage[idx] = curtmp / info.cpu_avg_samples;
781
782                         cpu[idx].cpu_last_total = cpu[idx].cpu_total;
783                         cpu[idx].cpu_last_active_total = cpu[idx].cpu_active_total;
784 #ifdef HAVE_OPENMP
785 #pragma omp parallel for schedule(dynamic,10)
786 #endif /* HAVE_OPENMP */
787                         for (i = info.cpu_avg_samples - 1; i > 0; i--) {
788                                 cpu[idx].cpu_val[i] = cpu[idx].cpu_val[i - 1];
789                         }
790                 }
791         }
792         fclose(stat_fp);
793         return 0;
794 }
795
796 int update_running_processes(void)
797 {
798         update_stat();
799         return 0;
800 }
801
802 int update_cpu_usage(void)
803 {
804         update_stat();
805         return 0;
806 }
807
808 int update_load_average(void)
809 {
810 #ifdef HAVE_GETLOADAVG
811         if (!prefer_proc) {
812                 double v[3];
813
814                 getloadavg(v, 3);
815                 info.loadavg[0] = (float) v[0];
816                 info.loadavg[1] = (float) v[1];
817                 info.loadavg[2] = (float) v[2];
818         } else
819 #endif
820         {
821                 static int rep = 0;
822                 FILE *fp;
823
824                 if (!(fp = open_file("/proc/loadavg", &rep))) {
825                         info.loadavg[0] = info.loadavg[1] = info.loadavg[2] = 0.0;
826                         return 0;
827                 }
828                 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1],
829                         &info.loadavg[2]);
830                 fclose(fp);
831         }
832         return 0;
833 }
834
835 /***********************************************************/
836 /***********************************************************/
837 /***********************************************************/
838
839 static int no_dots(const struct dirent *d)
840 {
841         if (d->d_name[0] == '.') {
842                 return 0;
843         }
844         return 1;
845 }
846
847 static int get_first_file_in_a_directory(const char *dir, char *s, int *rep)
848 {
849         struct dirent **namelist;
850         int i, n;
851
852         n = scandir(dir, &namelist, no_dots, alphasort);
853         if (n < 0) {
854                 if (!rep || !*rep) {
855                         NORM_ERR("scandir for %s: %s", dir, strerror(errno));
856                         if (rep) {
857                                 *rep = 1;
858                         }
859                 }
860                 return 0;
861         } else {
862                 if (n == 0) {
863                         return 0;
864                 }
865
866                 strncpy(s, namelist[0]->d_name, 255);
867                 s[255] = '\0';
868
869 #ifdef HAVE_OPENMP
870 #pragma omp parallel for schedule(dynamic,10)
871 #endif /* HAVE_OPENMP */
872                 for (i = 0; i < n; i++) {
873                         free(namelist[i]);
874                 }
875                 free(namelist);
876
877                 return 1;
878         }
879 }
880
881 static int open_sysfs_sensor(const char *dir, const char *dev, const char *type, int n,
882                 int *divisor, char *devtype)
883 {
884         char path[256];
885         char buf[256];
886         int fd;
887         int divfd;
888
889         memset(buf, 0, sizeof(buf));
890
891         /* if device is NULL or *, get first */
892         if (dev == NULL || strcmp(dev, "*") == 0) {
893                 static int rep = 0;
894
895                 if (!get_first_file_in_a_directory(dir, buf, &rep)) {
896                         return -1;
897                 }
898                 dev = buf;
899         }
900
901         if (strcmp(dir, "/sys/class/hwmon/") == 0) {
902                 if (*buf) {
903                         /* buf holds result from get_first_file_in_a_directory() above,
904                          * e.g. "hwmon0" -- append "/device" */
905                         strcat(buf, "/device");
906                 } else {
907                         /* dev holds device number N as a string,
908                          * e.g. "0", -- convert to "hwmon0/device" */
909                         sprintf(buf, "hwmon%s/device", dev);
910                         dev = buf;
911                 }
912         }
913
914         /* change vol to in, tempf to temp */
915         if (strcmp(type, "vol") == 0) {
916                 type = "in";
917         } else if (strcmp(type, "tempf") == 0) {
918                 type = "temp";
919         }
920
921         /* construct path */
922         snprintf(path, 255, "%s%s/%s%d_input", dir, dev, type, n);
923
924         /* first, attempt to open file in /device */
925         fd = open(path, O_RDONLY);
926         if (fd < 0) {
927
928                 /* if it fails, strip the /device from dev and attempt again */
929                 buf[strlen(buf) - 7] = 0;
930                 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, type, n);
931                 fd = open(path, O_RDONLY);
932                 if (fd < 0) {
933                         CRIT_ERR(NULL, NULL, "can't open '%s': %s\nplease check your device or remove this "
934                                          "var from "PACKAGE_NAME, path, strerror(errno));
935                 }
936         }
937
938         strncpy(devtype, path, 255);
939
940         if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
941                         || strcmp(type, "tempf") == 0) {
942                 *divisor = 1;
943         } else {
944                 *divisor = 0;
945         }
946         /* fan does not use *_div as a read divisor */
947         if (strcmp("fan", type) == 0) {
948                 return fd;
949         }
950
951         /* test if *_div file exist, open it and use it as divisor */
952         if (strcmp(type, "tempf") == 0) {
953                 snprintf(path, 255, "%s%s/%s%d_div", dir, "one", "two", n);
954         } else {
955                 snprintf(path, 255, "%s%s/%s%d_div", dir, dev, type, n);
956         }
957
958         divfd = open(path, O_RDONLY);
959         if (divfd > 0) {
960                 /* read integer */
961                 char divbuf[64];
962                 int divn;
963
964                 divn = read(divfd, divbuf, 63);
965                 /* should read until n == 0 but I doubt that kernel will give these
966                  * in multiple pieces. :) */
967                 if (divn < 0) {
968                         NORM_ERR("open_sysfs_sensor(): can't read from sysfs");
969                 } else {
970                         divbuf[divn] = '\0';
971                         *divisor = atoi(divbuf);
972                 }
973                 close(divfd);
974         }
975
976         return fd;
977 }
978
979 static double get_sysfs_info(int *fd, int divisor, char *devtype, char *type)
980 {
981         int val = 0;
982
983         if (*fd <= 0) {
984                 return 0;
985         }
986
987         lseek(*fd, 0, SEEK_SET);
988
989         /* read integer */
990         {
991                 char buf[64];
992                 int n;
993                 n = read(*fd, buf, 63);
994                 /* should read until n == 0 but I doubt that kernel will give these
995                  * in multiple pieces. :) */
996                 if (n < 0) {
997                         NORM_ERR("get_sysfs_info(): read from %s failed\n", devtype);
998                 } else {
999                         buf[n] = '\0';
1000                         val = atoi(buf);
1001                 }
1002         }
1003
1004         close(*fd);
1005         /* open file */
1006         *fd = open(devtype, O_RDONLY);
1007         if (*fd < 0) {
1008                 NORM_ERR("can't open '%s': %s", devtype, strerror(errno));
1009         }
1010
1011         /* My dirty hack for computing CPU value
1012          * Filedil, from forums.gentoo.org */
1013         /* if (strstr(devtype, "temp1_input") != NULL) {
1014                 return -15.096 + 1.4893 * (val / 1000.0);
1015         } */
1016
1017         /* divide voltage and temperature by 1000 */
1018         /* or if any other divisor is given, use that */
1019         if (strcmp(type, "tempf") == 0) {
1020                 if (divisor > 1) {
1021                         return ((val / divisor + 40) * 9.0 / 5) - 40;
1022                 } else if (divisor) {
1023                         return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
1024                 } else {
1025                         return ((val + 40) * 9.0 / 5) - 40;
1026                 }
1027         } else {
1028                 if (divisor > 1) {
1029                         return val / divisor;
1030                 } else if (divisor) {
1031                         return val / 1000.0;
1032                 } else {
1033                         return val;
1034                 }
1035         }
1036 }
1037
1038 #define HWMON_RESET() {\
1039                 buf1[0] = 0; \
1040                 factor = 1.0; \
1041                 offset = 0.0; }
1042
1043 static void parse_sysfs_sensor(struct text_object *obj, const char *arg, const char *path, const char *type)
1044 {
1045         char buf1[64], buf2[64];
1046         float factor, offset;
1047         int n, found = 0;
1048         struct sysfs *sf;
1049
1050         if (sscanf(arg, "%63s %d %f %f", buf2, &n, &factor, &offset) == 4) found = 1; else HWMON_RESET();
1051         if (!found && sscanf(arg, "%63s %63s %d %f %f", buf1, buf2, &n, &factor, &offset) == 5) found = 1; else if (!found) HWMON_RESET();
1052         if (!found && sscanf(arg, "%63s %63s %d", buf1, buf2, &n) == 3) found = 1; else if (!found) HWMON_RESET();
1053         if (!found && sscanf(arg, "%63s %d", buf2, &n) == 2) found = 1; else if (!found) HWMON_RESET();
1054
1055         if (!found) {
1056                 NORM_ERR("i2c failed to parse arguments");
1057                 obj->type = OBJ_text;
1058                 return;
1059         }
1060         DBGP("parsed %s args: '%s' '%s' %d %f %f\n", type, buf1, buf2, n, factor, offset);
1061         sf = malloc(sizeof(struct sysfs));
1062         memset(sf, 0, sizeof(struct sysfs));
1063         sf->fd = open_sysfs_sensor(path, (*buf1) ? buf1 : 0, buf2, n,
1064                         &sf->arg, sf->devtype);
1065         strncpy(sf->type, buf2, 63);
1066         sf->factor = factor;
1067         sf->offset = offset;
1068         obj->data.opaque = sf;
1069 }
1070
1071 #define PARSER_GENERATOR(name, path)                                \
1072 void parse_##name##_sensor(struct text_object *obj, const char *arg) \
1073 {                                                                   \
1074         parse_sysfs_sensor(obj, arg, path, #name);           \
1075 }
1076
1077 PARSER_GENERATOR(i2c, "/sys/bus/i2c/devices/")
1078 PARSER_GENERATOR(hwmon, "/sys/class/hwmon/")
1079 PARSER_GENERATOR(platform, "/sys/bus/platform/devices/")
1080
1081 void print_sysfs_sensor(struct text_object *obj, char *p, int p_max_size)
1082 {
1083         double r;
1084         struct sysfs *sf = obj->data.opaque;
1085
1086         if (!sf)
1087                 return;
1088
1089         r = get_sysfs_info(&sf->fd, sf->arg,
1090                         sf->devtype, sf->type);
1091
1092         r = r * sf->factor + sf->offset;
1093
1094         if (!strncmp(sf->type, "temp", 4)) {
1095                 temp_print(p, p_max_size, r, TEMP_CELSIUS);
1096         } else if (r >= 100.0 || r == 0) {
1097                 snprintf(p, p_max_size, "%d", (int) r);
1098         } else {
1099                 snprintf(p, p_max_size, "%.1f", r);
1100         }
1101 }
1102
1103 void free_sysfs_sensor(struct text_object *obj)
1104 {
1105         struct sysfs *sf = obj->data.opaque;
1106
1107         if (!sf)
1108                 return;
1109
1110         close(sf->fd);
1111         free(obj->data.opaque);
1112         obj->data.opaque = NULL;
1113 }
1114
1115 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
1116 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
1117
1118 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1119 char get_freq(char *p_client_buffer, size_t client_buffer_size,
1120                 const char *p_format, int divisor, unsigned int cpu)
1121 {
1122         FILE *f;
1123         static int rep = 0;
1124         char frequency[32];
1125         char s[256];
1126         double freq = 0;
1127
1128         if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1129                         || divisor <= 0) {
1130                 return 0;
1131         }
1132
1133         if (!prefer_proc) {
1134                 char current_freq_file[128];
1135
1136                 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu - 1,
1137                         CPUFREQ_POSTFIX);
1138                 f = fopen(current_freq_file, "r");
1139                 if (f) {
1140                         /* if there's a cpufreq /sys node, read the current frequency from
1141                          * this node and divide by 1000 to get Mhz. */
1142                         if (fgets(s, sizeof(s), f)) {
1143                                 s[strlen(s) - 1] = '\0';
1144                                 freq = strtod(s, NULL);
1145                         }
1146                         fclose(f);
1147                         snprintf(p_client_buffer, client_buffer_size, p_format,
1148                                 (freq / 1000) / divisor);
1149                         return 1;
1150                 }
1151         }
1152
1153         // open the CPU information file
1154         f = open_file("/proc/cpuinfo", &rep);
1155         if (!f) {
1156                 perror(PACKAGE_NAME": Failed to access '/proc/cpuinfo' at get_freq()");
1157                 return 0;
1158         }
1159
1160         // read the file
1161         while (fgets(s, sizeof(s), f) != NULL) {
1162
1163 #if defined(__i386) || defined(__x86_64)
1164                 // and search for the cpu mhz
1165                 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) {
1166 #else
1167 #if defined(__alpha)
1168                 // different on alpha
1169                 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) {
1170 #else
1171                 // this is different on ppc for some reason
1172                 if (strncmp(s, "clock", 5) == 0 && cpu == 0) {
1173 #endif // defined(__alpha)
1174 #endif // defined(__i386) || defined(__x86_64)
1175
1176                         // copy just the number
1177                         strcpy(frequency, strchr(s, ':') + 2);
1178 #if defined(__alpha)
1179                         // strip " est.\n"
1180                         frequency[strlen(frequency) - 6] = '\0';
1181                         // kernel reports in Hz
1182                         freq = strtod(frequency, NULL) / 1000000;
1183 #else
1184                         // strip \n
1185                         frequency[strlen(frequency) - 1] = '\0';
1186                         freq = strtod(frequency, NULL);
1187 #endif
1188                         break;
1189                 }
1190                 if (strncmp(s, "processor", 9) == 0) {
1191                         cpu--;
1192                         continue;
1193                 }
1194         }
1195
1196         fclose(f);
1197         snprintf(p_client_buffer, client_buffer_size, p_format,
1198                 (float) freq / divisor);
1199         return 1;
1200 }
1201
1202 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
1203
1204 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks something
1205  * like this:
1206 # frequency voltage
1207 1800000 1340
1208 1600000 1292
1209 1400000 1100
1210 1200000 988
1211 1000000 1116
1212 800000 1004
1213 600000 988
1214  * Peter Tarjan (ptarjan@citromail.hu) */
1215
1216 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
1217 static char get_voltage(char *p_client_buffer, size_t client_buffer_size,
1218                 const char *p_format, int divisor, unsigned int cpu)
1219 {
1220         FILE *f;
1221         char s[256];
1222         int freq = 0;
1223         int voltage = 0;
1224         char current_freq_file[128];
1225         int freq_comp = 0;
1226
1227         /* build the voltage file name */
1228         cpu--;
1229         snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1230                 CPUFREQ_POSTFIX);
1231
1232         if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1233                         || divisor <= 0) {
1234                 return 0;
1235         }
1236
1237         /* read the current cpu frequency from the /sys node */
1238         f = fopen(current_freq_file, "r");
1239         if (f) {
1240                 if (fgets(s, sizeof(s), f)) {
1241                         s[strlen(s) - 1] = '\0';
1242                         freq = strtod(s, NULL);
1243                 }
1244                 fclose(f);
1245         } else {
1246                 fprintf(stderr, PACKAGE_NAME": Failed to access '%s' at ", current_freq_file);
1247                 perror("get_voltage()");
1248                 if (f) {
1249                         fclose(f);
1250                 }
1251                 return 0;
1252         }
1253
1254         snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1255                 CPUFREQ_VOLTAGE);
1256
1257         /* use the current cpu frequency to find the corresponding voltage */
1258         f = fopen(current_freq_file, "r");
1259
1260         if (f) {
1261                 while (!feof(f)) {
1262                         char line[256];
1263
1264                         if (fgets(line, 255, f) == NULL) {
1265                                 break;
1266                         }
1267                         sscanf(line, "%d %d", &freq_comp, &voltage);
1268                         if (freq_comp == freq) {
1269                                 break;
1270                         }
1271                 }
1272                 fclose(f);
1273         } else {
1274                 fprintf(stderr, PACKAGE_NAME": Failed to access '%s' at ", current_freq_file);
1275                 perror("get_voltage()");
1276                 if (f) {
1277                         fclose(f);
1278                 }
1279                 return 0;
1280         }
1281         snprintf(p_client_buffer, client_buffer_size, p_format,
1282                 (float) voltage / divisor);
1283         return 1;
1284 }
1285
1286 void print_voltage_mv(struct text_object *obj, char *p, int p_max_size)
1287 {
1288         static int ok = 1;
1289         if (ok) {
1290                 ok = get_voltage(p, p_max_size, "%.0f", 1, obj->data.i);
1291         }
1292 }
1293
1294 void print_voltage_v(struct text_object *obj, char *p, int p_max_size)
1295 {
1296         static int ok = 1;
1297         if (ok) {
1298                 ok = get_voltage(p, p_max_size, "%'.3f", 1000, obj->data.i);
1299         }
1300 }
1301
1302 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1303
1304 void get_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
1305 {
1306         static int rep = 0;
1307         char buf[256];
1308         char buf2[256];
1309         FILE *fp;
1310
1311         if (!p_client_buffer || client_buffer_size <= 0) {
1312                 return;
1313         }
1314
1315         /* yeah, slow... :/ */
1316         if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep)) {
1317                 snprintf(p_client_buffer, client_buffer_size, "no fans?");
1318                 return;
1319         }
1320
1321         snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf);
1322
1323         fp = open_file(buf2, &rep);
1324         if (!fp) {
1325                 snprintf(p_client_buffer, client_buffer_size,
1326                         "can't open fan's state file");
1327                 return;
1328         }
1329         memset(buf, 0, sizeof(buf));
1330         fscanf(fp, "%*s %99s", buf);
1331         fclose(fp);
1332
1333         snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1334 }
1335
1336 #define SYSFS_AC_ADAPTER_DIR "/sys/class/power_supply"
1337 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1338 /* Linux 2.6.25 onwards ac adapter info is in
1339    /sys/class/power_supply/AC/
1340    On my system I get the following.
1341      /sys/class/power_supply/AC/uevent:
1342      PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A08:00/device:01/PNP0C09:00/ACPI0003:00
1343      PHYSDEVBUS=acpi
1344      PHYSDEVDRIVER=ac
1345      POWER_SUPPLY_NAME=AC
1346      POWER_SUPPLY_TYPE=Mains
1347      POWER_SUPPLY_ONLINE=1
1348
1349    Update: it seems the folder name is hardware-dependent. We add an aditional adapter
1350    argument, specifying the folder name.
1351
1352    Update: on some systems it's /sys/class/power_supply/ADP1 instead of /sys/class/power_supply/AC
1353 */
1354
1355 void get_acpi_ac_adapter(char *p_client_buffer, size_t client_buffer_size, const char *adapter)
1356 {
1357         static int rep = 0;
1358
1359         char buf[256];
1360         char buf2[256];
1361         struct stat sb;
1362         FILE *fp;
1363
1364         if (!p_client_buffer || client_buffer_size <= 0) {
1365                 return;
1366         }
1367
1368         if(adapter)
1369                 snprintf(buf2, sizeof(buf2), "%s/%s/uevent", SYSFS_AC_ADAPTER_DIR, adapter);
1370         else{
1371                 snprintf(buf2, sizeof(buf2), "%s/AC/uevent", SYSFS_AC_ADAPTER_DIR);
1372                 if(stat(buf2, &sb) == -1) snprintf(buf2, sizeof(buf2), "%s/ADP1/uevent", SYSFS_AC_ADAPTER_DIR);
1373         }
1374         if(stat(buf2, &sb) == 0) fp = open_file(buf2, &rep); else fp = 0;
1375         if (fp) {
1376                 /* sysfs processing */
1377                 while (!feof(fp)) {
1378                         if (fgets(buf, sizeof(buf), fp) == NULL)
1379                                 break;
1380
1381                         if (strncmp(buf, "POWER_SUPPLY_ONLINE=", 20) == 0) {
1382                                 int online = 0;
1383                                 sscanf(buf, "POWER_SUPPLY_ONLINE=%d", &online);
1384                                 snprintf(p_client_buffer, client_buffer_size,
1385                                          "%s-line", (online ? "on" : "off"));
1386                                 break;
1387                         }
1388                 }
1389                 fclose(fp);
1390         } else {
1391                 /* yeah, slow... :/ */
1392                 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep)) {
1393                         snprintf(p_client_buffer, client_buffer_size, "no ac_adapters?");
1394                         return;
1395                 }
1396
1397                 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf);
1398
1399                 fp = open_file(buf2, &rep);
1400                 if (!fp) {
1401                         snprintf(p_client_buffer, client_buffer_size,
1402                                  "No ac adapter found.... where is it?");
1403                         return;
1404                 }
1405                 memset(buf, 0, sizeof(buf));
1406                 fscanf(fp, "%*s %99s", buf);
1407                 fclose(fp);
1408
1409                 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1410         }
1411 }
1412
1413 /*
1414 /proc/acpi/thermal_zone/THRM/cooling_mode
1415 cooling mode:            active
1416 /proc/acpi/thermal_zone/THRM/polling_frequency
1417 <polling disabled>
1418 /proc/acpi/thermal_zone/THRM/state
1419 state:                   ok
1420 /proc/acpi/thermal_zone/THRM/temperature
1421 temperature:             45 C
1422 /proc/acpi/thermal_zone/THRM/trip_points
1423 critical (S5):           73 C
1424 passive:                 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1425 */
1426
1427 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1428 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1429
1430 int open_acpi_temperature(const char *name)
1431 {
1432         char path[256];
1433         char buf[256];
1434         int fd;
1435
1436         if (name == NULL || strcmp(name, "*") == 0) {
1437                 static int rep = 0;
1438
1439                 if (!get_first_file_in_a_directory(ACPI_THERMAL_DIR, buf, &rep)) {
1440                         return -1;
1441                 }
1442                 name = buf;
1443         }
1444
1445         snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1446
1447         fd = open(path, O_RDONLY);
1448         if (fd < 0) {
1449                 NORM_ERR("can't open '%s': %s", path, strerror(errno));
1450         }
1451
1452         return fd;
1453 }
1454
1455 static double last_acpi_temp;
1456 static double last_acpi_temp_time;
1457
1458 double get_acpi_temperature(int fd)
1459 {
1460         if (fd <= 0) {
1461                 return 0;
1462         }
1463
1464         /* don't update acpi temperature too often */
1465         if (current_update_time - last_acpi_temp_time < 11.32) {
1466                 return last_acpi_temp;
1467         }
1468         last_acpi_temp_time = current_update_time;
1469
1470         /* seek to beginning */
1471         lseek(fd, 0, SEEK_SET);
1472
1473         /* read */
1474         {
1475                 char buf[256];
1476                 int n;
1477
1478                 n = read(fd, buf, 255);
1479                 if (n < 0) {
1480                         NORM_ERR("can't read fd %d: %s", fd, strerror(errno));
1481                 } else {
1482                         buf[n] = '\0';
1483                         sscanf(buf, "temperature: %lf", &last_acpi_temp);
1484                 }
1485         }
1486
1487         return last_acpi_temp;
1488 }
1489
1490 /*
1491 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1492 present:                 yes
1493 design capacity:         4400 mAh
1494 last full capacity:      4064 mAh
1495 battery technology:      rechargeable
1496 design voltage:          14800 mV
1497 design capacity warning: 300 mAh
1498 design capacity low:     200 mAh
1499 capacity granularity 1:  32 mAh
1500 capacity granularity 2:  32 mAh
1501 model number:            02KT
1502 serial number:           16922
1503 battery type:            LION
1504 OEM info:                SANYO
1505 */
1506
1507 /*
1508 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1509 present:                 yes
1510 capacity state:          ok
1511 charging state:          unknown
1512 present rate:            0 mA
1513 remaining capacity:      4064 mAh
1514 present voltage:         16608 mV
1515 */
1516
1517 /*
1518 2213<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1519 2213<@jupet�kellari��> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1520 2213<@jupet�kellari��> (-1 ollee ei akkua kiinni, koska akku on p�yd�ll�)
1521 2214<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1522 2214<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1523
1524 2238<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1525 2239<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1526
1527 2240<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori p��ll�
1528 2241<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori p��ll� mutta ilman verkkovirtaa
1529 */
1530
1531 /* Kapil Hari Paranjape <kapil@imsc.res.in>
1532   Linux 2.6.24 onwards battery info is in
1533   /sys/class/power_supply/BAT0/
1534   On my system I get the following.
1535         /sys/class/power_supply/BAT0/uevent:
1536         PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A03:00/device:01/PNP0C09:00/PNP0C0A:00
1537         PHYSDEVBUS=acpi
1538         PHYSDEVDRIVER=battery
1539         POWER_SUPPLY_NAME=BAT0
1540         POWER_SUPPLY_TYPE=Battery
1541         POWER_SUPPLY_STATUS=Discharging
1542         POWER_SUPPLY_PRESENT=1
1543         POWER_SUPPLY_TECHNOLOGY=Li-ion
1544         POWER_SUPPLY_VOLTAGE_MIN_DESIGN=10800000
1545         POWER_SUPPLY_VOLTAGE_NOW=10780000
1546         POWER_SUPPLY_CURRENT_NOW=13970000
1547         POWER_SUPPLY_ENERGY_FULL_DESIGN=47510000
1548         POWER_SUPPLY_ENERGY_FULL=27370000
1549         POWER_SUPPLY_ENERGY_NOW=11810000
1550         POWER_SUPPLY_MODEL_NAME=IBM-92P1060
1551         POWER_SUPPLY_MANUFACTURER=Panasonic
1552   On some systems POWER_SUPPLY_ENERGY_* is replaced by POWER_SUPPLY_CHARGE_*
1553 */
1554
1555 /*on n900 with power kernel: (non power kernel could use "hal-device bme" and do something else)
1556 /sys/class/power_supply/bq27200-0/uevent
1557 PHYSDEVPATH=/class/i2c-adapter/i2c-2/2-0055
1558 PHYSDEVBUS=i2c
1559 PHYSDEVDRIVER=bq27200-battery
1560 POWER_SUPPLY_NAME=bq27200-0
1561 POWER_SUPPLY_TYPE=Battery
1562 POWER_SUPPLY_PRESENT=1                          << this is always 1, it means the battery is inserted
1563 POWER_SUPPLY_VOLTAGE_NOW=4039           << this keeps updating during charging, both here and in dbus
1564 POWER_SUPPLY_CURRENT_NOW=1960       << this goes negative when charging!
1565 POWER_SUPPLY_CAPACITY=98                        << supposed to be the %, it keeps updating while charging, unlike the dbus vals that freeze
1566 POWER_SUPPLY_TEMP=39                            << only temperature sensor in n900 :(
1567 */
1568
1569 #define SYSFS_BATTERY_BASE_PATH "/sys/class/power_supply"
1570 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery" //not for n900
1571 #define APM_PATH "/proc/apm"  //not for n900
1572 #define MAX_BATTERY_COUNT 4 //more like 1
1573
1574 static FILE *sysfs_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1575 //static FILE *acpi_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1576 //static FILE *apm_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1577
1578 static int batteries_initialized = 0;
1579 static char batteries[MAX_BATTERY_COUNT][32];
1580
1581 //static int acpi_last_full[MAX_BATTERY_COUNT];
1582 //static int acpi_design_capacity[MAX_BATTERY_COUNT];
1583
1584 //eg 4100
1585 static int last_battery_volts[MAX_BATTERY_COUNT];
1586
1587 //eg -78
1588 static dbus_int32_t last_cell_radio_dbm;
1589
1590 //eg 100
1591 static dbus_int32_t last_cell_radio_percent;
1592
1593 //eg 'full' 'on' 'off'
1594 static char last_batt_charge_status[16];
1595
1596 //eg 100 or -100
1597 static int last_battery_rate[MAX_BATTERY_COUNT];
1598
1599 //eg 35.5
1600 static float last_battery_temp[MAX_BATTERY_COUNT];
1601
1602 /* e.g. "charging 75%" */
1603 static char last_battery_str[MAX_BATTERY_COUNT][64];
1604 /* e.g. "3h 15m" */
1605 static char last_battery_time_str[MAX_BATTERY_COUNT][64];
1606
1607 static double last_battery_time[MAX_BATTERY_COUNT];
1608
1609 static int last_battery_perct[MAX_BATTERY_COUNT];
1610 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1611
1612 void init_batteries(void)
1613 {
1614         int idx;
1615
1616         if (batteries_initialized) {
1617                 return;
1618         }
1619 #ifdef HAVE_OPENMP
1620 #pragma omp parallel for schedule(dynamic,10)
1621 #endif /* HAVE_OPENMP */
1622         for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1623                 batteries[idx][0] = '\0';
1624         }
1625         batteries_initialized = 1;
1626 }
1627
1628 int get_battery_idx(const char *bat)
1629 {
1630 //      int idx;
1631 //
1632 //      for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1633 //              if (!strlen(batteries[idx]) || !strcmp(batteries[idx], bat)) {
1634 //                      break;
1635 //              }
1636 //      }
1637 //
1638 //      /* if not found, enter a new entry */
1639 //      if (!strlen(batteries[idx])) {
1640 //              snprintf(batteries[idx], 31, "%s", bat);
1641 //      }
1642
1643         return 0;
1644 }
1645
1646 static int dbus_queue = 0;
1647
1648 void set_dbus_retval(char *buffer, unsigned int n, int item);
1649
1650 DBusConnection *connection;
1651 DBusError error;
1652 DBusMessage *message;
1653 DBusMessageIter iter;
1654 DBusBusType type;
1655 int message_type;
1656 DBusMessage *reply;
1657
1658 void dbus_exit_app_view()
1659 {
1660         //not needed in harmattan - swipe down or away and close (although it doesn't seem to be reliable to swipe)
1661         
1662         
1663         //dbus-send --type=signal --session     /com/nokia/hildon_desktop .
1664
1665 //      type = DBUS_BUS_SESSION;
1666 //      //message_type = DBUS_MESSAGE_TYPE_SIGNAL;
1667 //      dbus_error_init (&error);
1668 //      connection = dbus_bus_get (type, &error);
1669 //    message = dbus_message_new_signal ("/com/nokia/hildon_desktop", "com.nokia.hildon_desktop", "exit_app_view");
1670 //    // send the message and flush the connection
1671 //    if (!dbus_connection_send(connection, message, NULL)) {
1672 //       fprintf(stderr, "Out Of Memory!\n");
1673 //       exit(1);
1674 //    }
1675 //    dbus_connection_flush(connection);
1676 //
1677 //    // free the message
1678 //    dbus_message_unref(message);
1679
1680 }
1681
1682 void get_dbus_stuff(char *buffer,unsigned int intMax_length, int item)
1683 {
1684         char method[128];
1685         char path[128];
1686         char dest[128];
1687         char *args = "";
1688         char *args2 = "";
1689         if (dbus_queue > 10)
1690         {
1691                 fprintf (stderr, "too much dbus queuing\n");
1692                 exit(1);
1693 //              set_dbus_retval(buffer, intMax_length, item);
1694 //              return;
1695         }
1696         dbus_queue++;//prevent a queue from forming on these requests...
1697 //fetch data from dbus, store in here as last_cell_radio_dbm
1698 //return into buffer
1699
1700         type = DBUS_BUS_SYSTEM;
1701         message_type = DBUS_MESSAGE_TYPE_METHOD_CALL;
1702 //      print_reply = TRUE;
1703 //      print_reply_literal = FALSE;
1704         int reply_timeout_ms = 5000;
1705         dbus_error_init (&error);
1706         connection = dbus_bus_get (type, &error);
1707         if (connection == NULL)
1708     {
1709                 fprintf (stderr, "Failed to open connection to %s message bus: %s\n",
1710                (type == DBUS_BUS_SYSTEM) ? "system" : "session",
1711                error.message);
1712       dbus_error_free (&error);
1713       exit (1);
1714     }
1715         switch(item){
1716         case DBUS_CELL_DBM:             
1717                 snprintf(method,127,"Get");
1718                 args = "com.nokia.csd.CSNet.SignalStrength";
1719                 args2 = "SignalDecibels";
1720                 snprintf(path,127,"/com/nokia/csd/csnet");
1721                 snprintf(dest,127,"com.nokia.csd.CSNet"); //service name
1722                 message = dbus_message_new_method_call (dest,path,"org.freedesktop.DBus.Properties",method);//dest,path,interface,method
1723                 dbus_message_set_auto_start (message, TRUE);
1724                 if (!dbus_message_append_args(message,
1725                         DBUS_TYPE_STRING, &args,
1726                         DBUS_TYPE_STRING, &args2,
1727                         DBUS_TYPE_INVALID))
1728                                 fprintf (stderr, "OOM appending args\n");
1729                 //dbus_message_iter_init_append(message, &iter);
1730                 //if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &args))
1731                 //      fprintf (stderr, "OOM appending args\n");
1732                 break;
1733         case DBUS_CELL_PERCENT:
1734                 snprintf(method,127,"Get");
1735                 args = "com.nokia.csd.CSNet.SignalStrength";
1736                 args2 = "SignalPercent";
1737                 snprintf(path,127,"/com/nokia/csd/csnet");
1738                 snprintf(dest,127,"com.nokia.csd.CSNet"); //service name
1739                 message = dbus_message_new_method_call (dest,path,"org.freedesktop.DBus.Properties",method);//dest,path,interface,method
1740                 dbus_message_set_auto_start (message, TRUE);
1741                 if (!dbus_message_append_args(message,
1742                         DBUS_TYPE_STRING, &args,
1743                         DBUS_TYPE_STRING, &args2,
1744                         DBUS_TYPE_INVALID))
1745                                 fprintf (stderr, "OOM appending args\n");
1746                 //dbus_message_iter_init_append(message, &iter);
1747                 //if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &args))
1748                 //      fprintf (stderr, "OOM appending args\n");
1749                 break;
1750         case DBUS_HAL_BATTERY_CHRG_STATUS:
1751                 // 'full' 'on' 'off'
1752                 snprintf(method,127,"GetProperty");
1753                 args = "maemo.rechargeable.charging_status";
1754                 snprintf(path,127,"/org/freedesktop/Hal/devices/bme");
1755                 snprintf(dest,127,"org.freedesktop.Hal");
1756                 message = dbus_message_new_method_call (dest,path,"org.freedesktop.Hal.Device",method);
1757                 dbus_message_set_auto_start (message, TRUE);
1758                 dbus_message_iter_init_append(message, &iter);
1759                 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &args))
1760                         fprintf (stderr, "OOM appending args\n");
1761                 break;
1762         case DBUS_HAL_BATTERY_PERCENT:
1763                 // '96'
1764                 snprintf(method,127,"GetProperty");
1765                 args = "battery.charge_level.percentage";
1766                 snprintf(path,127,"/org/freedesktop/Hal/devices/bme");
1767                 snprintf(dest,127,"org.freedesktop.Hal");
1768                 message = dbus_message_new_method_call (dest,path,"org.freedesktop.Hal.Device",method);
1769                 dbus_message_set_auto_start (message, TRUE);
1770                 dbus_message_iter_init_append(message, &iter);
1771                 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &args))
1772                         fprintf (stderr, "OOM appending args\n");
1773                 break;
1774         case DBUS_HAL_BATTERY_VOLTS_CURRENT:
1775                 // '3600' - '4200'
1776                 snprintf(method,127,"GetProperty");
1777                 args = "battery.voltage.current"; //battery.reporting.current gets battery mA, not charge/discharge rate
1778                 snprintf(path,127,"/org/freedesktop/Hal/devices/bme");
1779                 snprintf(dest,127,"org.freedesktop.Hal");
1780                 message = dbus_message_new_method_call (dest,path,"org.freedesktop.Hal.Device",method);
1781                 dbus_message_set_auto_start (message, TRUE);
1782                 dbus_message_iter_init_append(message, &iter);
1783                 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &args))
1784                         fprintf (stderr, "OOM appending args\n");
1785                 break;
1786         default:
1787                 fprintf (stderr, "invalid item type in get_dbus_stuff");
1788                 break;
1789         }
1790         if (message == NULL)
1791         {
1792           fprintf (stderr, "Couldn't allocate D-Bus message\n");
1793           exit (1);
1794         }
1795         if (!dbus_message_set_destination (message, dest))
1796         {
1797           fprintf (stderr, "Not enough memory\n");
1798           exit (1);
1799         }
1800
1801         dbus_error_init (&error);
1802         reply = dbus_connection_send_with_reply_and_block (connection, message, reply_timeout_ms, &error);
1803         if (dbus_error_is_set (&error))
1804         {
1805           fprintf (stderr, "Error %s: %s\n",error.name,error.message);
1806           //exit (1);//if we set timeout to 30s or something i guess it's okay to exit on "no reply" cuz something is fu*ked;
1807         }
1808         if (reply)
1809         {
1810                 DBusMessageIter iter;
1811                 DBusMessageIter subiter;
1812                 dbus_message_iter_init (reply, &iter);
1813                 int current_fieldnumber = 0;
1814                 while (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INVALID)
1815                 {
1816                         
1817                         current_fieldnumber++;
1818                         switch(item){
1819                         case DBUS_CELL_DBM:
1820                                 if (current_fieldnumber == 1)
1821                                 {//this is a variant
1822                                         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT){
1823                                                 fprintf (stderr,"DBUS_CELL_DBM got type '%c'; expected variant!\n", dbus_message_iter_get_arg_type(&iter));
1824                                                 break;
1825                                         }
1826                                         dbus_message_iter_recurse (&iter, &subiter);                            
1827                                         dbus_int32_t val = 0;
1828                                         if (dbus_message_iter_get_arg_type(&subiter) != DBUS_TYPE_INT32){
1829                                                 fprintf (stderr,"DBUS_CELL_DBM subiter got type '%c'; expected INT32!\n", dbus_message_iter_get_arg_type(&subiter));
1830                                                 break;
1831                                         }
1832                                         dbus_message_iter_get_basic(&subiter, &val);
1833                                         last_cell_radio_dbm = val;
1834                                 }
1835                                 break;
1836                         case DBUS_CELL_PERCENT:
1837                                 if (current_fieldnumber == 1)
1838                                 {//this is a variant
1839                                         dbus_message_iter_recurse (&iter, &subiter);
1840                                         dbus_int32_t val = 0;
1841                                         dbus_message_iter_get_basic(&subiter, &val);
1842                                         last_cell_radio_percent = val;
1843                                 }
1844                                 break;
1845                         case DBUS_HAL_BATTERY_CHRG_STATUS:
1846                                 if (current_fieldnumber == 1)
1847                                 {
1848                                         char *val;
1849                                         dbus_message_iter_get_basic(&iter, &val);
1850                                         snprintf(last_batt_charge_status,16,"%s",val);
1851                                 }
1852                                 break;
1853                         case DBUS_HAL_BATTERY_PERCENT:
1854                                 if (current_fieldnumber == 1)
1855                                 {
1856                                         dbus_uint32_t val;
1857                                         dbus_message_iter_get_basic(&iter, &val);
1858                                         last_battery_perct[0] = val;
1859                                 }
1860                                 break;
1861                         case DBUS_HAL_BATTERY_VOLTS_CURRENT:
1862                                 if (current_fieldnumber == 1)
1863                                 {
1864                                         dbus_uint32_t val;
1865                                         dbus_message_iter_get_basic(&iter, &val);
1866                                         last_battery_volts[0] = val;
1867                                 }
1868                                 break;
1869                         default:
1870                                 fprintf (stderr, "invalid item type in get_dbus_stuff reply loop");
1871                                 break;
1872                         }
1873                         dbus_message_iter_next (&iter);
1874                 }
1875                 dbus_message_unref (reply);
1876         }
1877         set_dbus_retval(buffer, intMax_length, item);
1878         dbus_message_unref (message);
1879         dbus_connection_unref (connection);
1880         dbus_queue = 0;//reset to zero now that complete
1881 }
1882
1883 void set_dbus_retval(char *buffer, unsigned int intMax_length, int item)
1884 {
1885         switch (item) {
1886                 case DBUS_CELL_DBM:
1887                         snprintf(buffer, intMax_length, "%d", last_cell_radio_dbm);
1888                         break;
1889                 case DBUS_CELL_PERCENT:
1890                         snprintf(buffer, intMax_length, "%d", last_cell_radio_percent);
1891                         break;
1892                 case DBUS_HAL_BATTERY_CHRG_STATUS:
1893                         snprintf(buffer, intMax_length, "%s", last_batt_charge_status);
1894                         break;
1895                 case DBUS_HAL_BATTERY_PERCENT:
1896                         snprintf(buffer, intMax_length, "%i", last_battery_perct[0]);
1897                         break;
1898                 case DBUS_HAL_BATTERY_VOLTS_CURRENT:
1899                         snprintf(buffer, intMax_length, "%i", last_battery_volts[0]);
1900                         break;
1901                 default:
1902                         fprintf (stderr, "invalid item type in set_dbus_retval");
1903                         break;
1904         }
1905 }
1906
1907 void set_return_value(char *buffer, unsigned int n, int item, int idx);
1908
1909 void get_battery_stuff(char *buffer, unsigned int n, const char *bat, int item)
1910 {
1911         static int idx, rep = 0;
1912         char acpi_path[128];
1913         char sysfs_path[128];
1914
1915         snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1916         snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1917
1918         init_batteries();
1919
1920         idx = get_battery_idx(bat);
1921
1922         /* don't update battery too often */
1923         if (current_update_time - last_battery_time[idx] < 2) {
1924                 set_return_value(buffer, n, item, idx);
1925                 return;
1926         }
1927
1928         last_battery_time[idx] = current_update_time;
1929
1930         memset(last_battery_str[idx], 0, sizeof(last_battery_str[idx]));
1931         memset(last_battery_time_str[idx], 0, sizeof(last_battery_time_str[idx]));
1932
1933         /* first try SYSFS if that fails try DBUS */
1934
1935         if (sysfs_bat_fp[idx] == NULL) {
1936                 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1937         }
1938
1939         if (sysfs_bat_fp[idx] != NULL) {
1940                 /* SYSFS */
1941                 int present_rate = -9999; //we will put "current now" into this. negative when charging!
1942                 int remaining_capacity = -1; //in %
1943                 char charging_state[64];//can't get this without hal bme
1944                 int voltage = -1;
1945                 int temp = 9999;
1946                 char present[4];
1947                 strcpy(present, "no");
1948                 strcpy(charging_state, "unknown");
1949
1950                 while (!feof(sysfs_bat_fp[idx])) {
1951                         //we are looping through the data here
1952                         char buf[256];
1953                         if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1954                                 break;
1955                         if (strncmp (buf, "POWER_SUPPLY_PRESENT=1", 22) == 0)//does current row match this?
1956                                 strcpy(present, "yes");//n900 always yes
1957                         else if (strncmp(buf, "POWER_SUPPLY_VOLTAGE_NOW=", 25) == 0)//keep checking possible matches
1958                                 sscanf(buf, "POWER_SUPPLY_VOLTAGE_NOW=%d", &voltage);
1959                         else if (strncmp(buf, "POWER_SUPPLY_CURRENT_NOW=", 25) == 0)
1960                                 sscanf(buf, "POWER_SUPPLY_CURRENT_NOW=%d", &present_rate);
1961                         else if (strncmp(buf, "POWER_SUPPLY_CAPACITY=", 22) == 0)
1962                                 sscanf(buf, "POWER_SUPPLY_CAPACITY=%d", &remaining_capacity);
1963                         else if (strncmp(buf, "POWER_SUPPLY_TEMP=", 18) == 0)
1964                                 sscanf(buf, "POWER_SUPPLY_TEMP=%d", &temp);
1965                 }
1966                 fclose(sysfs_bat_fp[idx]);
1967                 sysfs_bat_fp[idx] = NULL;
1968                 if (voltage > 10000) voltage = voltage / 1000;  //fix for n900 power kernel 47
1969                 last_battery_volts[idx] = voltage;
1970                 if (temp < 100)
1971                         last_battery_temp[idx] = temp;
1972                 else //fix for n900 power kernel 47
1973                         last_battery_temp[idx] = (float) temp / 10;
1974                 /* charging */
1975                 if (present_rate <= 0) {
1976                                 /* e.g. charging 75% */
1977                                 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %i%%", remaining_capacity);
1978                                 snprintf(last_battery_time_str[idx], sizeof(last_battery_time_str[idx]) - 1, "unknown");
1979                 }
1980                 /* discharging */
1981                 else if (present_rate > 0) {
1982                                 /* e.g. discharging 35% */
1983                                 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "discharging %i%%", remaining_capacity);
1984                                 snprintf(last_battery_time_str[idx], sizeof(last_battery_time_str[idx]) - 1, "unknown");
1985                 }
1986                 /* charged */
1987                  if (remaining_capacity == 100)
1988                                 strcpy(last_battery_str[idx], "charged 100%");
1989         } else {
1990                 //if don't have power kernel, use HAL / dbus
1991                 int remaining_capacity = -1; //in %
1992                 int temp = -1;
1993                 remaining_capacity = get_battery_perct(bat);
1994                 get_dbus_stuff(buffer,n,DBUS_HAL_BATTERY_VOLTS_CURRENT);
1995                 get_dbus_stuff(buffer,n,DBUS_HAL_BATTERY_CHRG_STATUS);
1996                 if (strncmp(buffer, "on", 2) == 0) {
1997                         snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %i%%", remaining_capacity);
1998                 }
1999                 else if (strncmp(buffer, "off", 3) == 0) {
2000                         snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "discharging %i%%", remaining_capacity);
2001                 }
2002                 else if (strncmp(buffer, "full", 4) == 0) {//no, it won't always be 100%. stupid dbus.
2003                         snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charged %i%%", remaining_capacity);
2004                  }
2005                 
2006                 struct bme_reply bmeInfo = getBattInfoFromBME();
2007                 last_battery_temp[idx] = ((float)bmeInfo.battery_temperature) - 273.15f;
2008                 last_battery_rate[idx] = bmeInfo.battery_current;
2009                 //last_battery_temp[idx] = temp;                
2010         }
2011         set_return_value(buffer, n, item, idx);
2012 }
2013
2014 void set_return_value(char *buffer, unsigned int n, int item, int idx)
2015 {
2016         switch (item) {
2017                 case BATTERY_STATUS:
2018                         snprintf(buffer, n, "%s", last_battery_str[idx]);
2019                         break;
2020                 case BATTERY_TIME:
2021                         snprintf(buffer, n, "%s", last_battery_time_str[idx]);
2022                         break;
2023                 case BATTERY_VOLTS:
2024                         snprintf(buffer, n, "%i", last_battery_volts[idx]); // voltage
2025                         break;
2026                 case BATTERY_TEMP:
2027                         snprintf(buffer, n, "%3.1f", last_battery_temp[idx]); // temperature
2028                         break;
2029                 case BATTERY_RATE:
2030                         snprintf(buffer, n, "%i", last_battery_rate[idx]); // charge/discharge rate
2031                         break;                  
2032                 default:
2033                         fprintf (stderr, "invalid item type in set_return_value");
2034                         break;
2035         }
2036 }
2037
2038 void get_battery_short_status(char *buffer, unsigned int n, const char *bat)
2039 {
2040         get_battery_stuff(buffer, n, bat, BATTERY_STATUS);
2041         if (0 == strncmp("charging", buffer, 8)) {
2042                 buffer[0] = 'C';
2043                 memmove(buffer + 1, buffer + 8, n - 8);
2044         } else if (0 == strncmp("discharging", buffer, 11)) {
2045                 buffer[0] = 'D';
2046                 memmove(buffer + 1, buffer + 11, n - 11);
2047         } else if (0 == strncmp("charged", buffer, 7)) {
2048                 buffer[0] = 'F';
2049                 memmove(buffer + 1, buffer + 7, n - 7);
2050         } else if (0 == strncmp("not present", buffer, 11)) {
2051                 buffer[0] = 'N';
2052                 memmove(buffer + 1, buffer + 11, n - 11);
2053         } else if (0 == strncmp("empty", buffer, 5)) {
2054                 buffer[0] = 'E';
2055                 memmove(buffer + 1, buffer + 5, n - 5);
2056         } else if (0 != strncmp("AC", buffer, 2)) {
2057                 buffer[0] = 'U';
2058                 memmove(buffer + 1, buffer + 11, n - 11);
2059         } else fprintf (stderr, "invalid input buffer in get_battery_short_status");
2060 }
2061
2062 int get_battery_perct(const char *bat)
2063 {
2064         static int rep = 0;
2065         int idx;
2066         char sysfs_path[128];
2067         int remaining_capacity = -1;
2068         snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
2069
2070         init_batteries();
2071         idx = get_battery_idx(bat);
2072
2073         /* don't update battery too often */
2074         if (current_update_time - last_battery_perct_time[idx] < 29.5) {
2075                 return last_battery_perct[idx];
2076         }
2077         last_battery_perct_time[idx] = current_update_time;
2078
2079         /* try  SYSFS first */
2080         sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
2081         if (sysfs_bat_fp[idx] != NULL) {
2082                 /* SYSFS */
2083                 while (!feof(sysfs_bat_fp[idx])) {
2084                         char buf[256];
2085                         if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
2086                                 break;
2087                         if (strncmp(buf, "POWER_SUPPLY_CAPACITY=", 22) == 0) {
2088                                 sscanf(buf, "POWER_SUPPLY_CAPACITY=%d", &remaining_capacity);
2089
2090 //                      if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0) {
2091 //                              sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
2092 //                      } else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=",25) == 0) {
2093 //                              sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_design_capacity[idx]);
2094 //                      } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0) {
2095 //                              sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
2096 //                      } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=",25) == 0) {
2097 //                              sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_design_capacity[idx]);
2098 //                      }
2099                         }
2100                 }
2101                 fclose(sysfs_bat_fp[idx]);
2102                 sysfs_bat_fp[idx] = NULL;
2103                 last_battery_perct[idx] = remaining_capacity;
2104
2105         }
2106         else
2107         {
2108                 char *useless;
2109                 useless = malloc(128 * sizeof(char));
2110                 get_dbus_stuff(useless,128,DBUS_HAL_BATTERY_PERCENT);
2111                 //i told you it's useless...
2112                 //snprintf(last_battery_perct[idx], 127, "%i", useless);
2113                 //guess what? dbus battery % doesn't update while charging
2114 //              get_dbus_stuff(useless,n,DBUS_HAL_BATTERY_CHRG_STATUS);
2115 //              if (strncmp(useless, "full", 4) == 0)
2116 //              {
2117 //
2118 //              }
2119         }
2120 //      else if (acpi_bat_fp[idx] != NULL) {
2121 //              /* ACPI */
2122 //              /* read last full capacity if it's zero */
2123 //              if (acpi_design_capacity[idx] == 0) {
2124 //                      static int rep2;
2125 //                      char path[128];
2126 //                      FILE *fp;
2127 //
2128 //                      snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
2129 //                      fp = open_file(path, &rep2);
2130 //                      if (fp != NULL) {
2131 //                              while (!feof(fp)) {
2132 //                                      char b[256];
2133 //
2134 //                                      if (fgets(b, 256, fp) == NULL) {
2135 //                                              break;
2136 //                                      }
2137 //                                      if (sscanf(b, "last full capacity: %d",
2138 //                                                              &acpi_design_capacity[idx]) != 0) {
2139 //                                              break;
2140 //                                      }
2141 //                              }
2142 //                              fclose(fp);
2143 //                      }
2144 //              }
2145 //
2146 //              fseek(acpi_bat_fp[idx], 0, SEEK_SET);
2147 //
2148 //              while (!feof(acpi_bat_fp[idx])) {
2149 //                      char buf[256];
2150 //
2151 //                      if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
2152 //                              break;
2153 //                      }
2154 //
2155 //                      if (buf[0] == 'r') {
2156 //                              sscanf(buf, "remaining capacity: %d", &remaining_capacity);
2157 //                      }
2158 //              }
2159 //      }
2160
2161         /* compute the battery percentage */
2162
2163                 //(int) (((float) remaining_capacity / acpi_design_capacity[idx]) * 100);
2164         //if (last_battery_perct[idx] > 100) last_battery_perct[idx] = 100;
2165         return last_battery_perct[idx];
2166 }
2167
2168 int get_battery_perct_bar(const char *bat)
2169 {
2170         int idx;
2171
2172         get_battery_perct(bat);
2173         idx = get_battery_idx(bat);
2174         return (int) (last_battery_perct[idx] * 2.56 - 1);
2175 }
2176
2177 /* On Apple powerbook and ibook:
2178 $ cat /proc/pmu/battery_0
2179 flags      : 00000013
2180 charge     : 3623
2181 max_charge : 3720
2182 current    : 388
2183 voltage    : 16787
2184 time rem.  : 900
2185 $ cat /proc/pmu/info
2186 PMU driver version     : 2
2187 PMU firmware version   : 0c
2188 AC Power               : 1
2189 Battery count          : 1
2190 */
2191
2192 /* defines as in <linux/pmu.h> */
2193 #define PMU_BATT_PRESENT                0x00000001
2194 #define PMU_BATT_CHARGING               0x00000002
2195
2196 static FILE *pmu_battery_fp;
2197 static FILE *pmu_info_fp;
2198 static char pb_battery_info[3][32];
2199 static double pb_battery_info_update;
2200
2201 #define PMU_PATH "/proc/pmu"
2202 void get_powerbook_batt_info(char *buffer, size_t n, int i)
2203 {
2204         static int rep = 0;
2205         const char *batt_path = PMU_PATH "/battery_0";
2206         const char *info_path = PMU_PATH "/info";
2207         unsigned int flags;
2208         int charge, max_charge, ac = -1;
2209         long timeval = -1;
2210
2211         /* don't update battery too often */
2212         if (current_update_time - pb_battery_info_update < 29.5) {
2213                 snprintf(buffer, n, "%s", pb_battery_info[i]);
2214                 return;
2215         }
2216         pb_battery_info_update = current_update_time;
2217
2218         if (pmu_battery_fp == NULL) {
2219                 pmu_battery_fp = open_file(batt_path, &rep);
2220                 if (pmu_battery_fp == NULL) {
2221                         return;
2222                 }
2223         }
2224
2225         if (pmu_battery_fp != NULL) {
2226                 rewind(pmu_battery_fp);
2227                 while (!feof(pmu_battery_fp)) {
2228                         char buf[32];
2229
2230                         if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL) {
2231                                 break;
2232                         }
2233
2234                         if (buf[0] == 'f') {
2235                                 sscanf(buf, "flags      : %8x", &flags);
2236                         } else if (buf[0] == 'c' && buf[1] == 'h') {
2237                                 sscanf(buf, "charge     : %d", &charge);
2238                         } else if (buf[0] == 'm') {
2239                                 sscanf(buf, "max_charge : %d", &max_charge);
2240                         } else if (buf[0] == 't') {
2241                                 sscanf(buf, "time rem.  : %ld", &timeval);
2242                         }
2243                 }
2244         }
2245         if (pmu_info_fp == NULL) {
2246                 pmu_info_fp = open_file(info_path, &rep);
2247                 if (pmu_info_fp == NULL) {
2248                         return;
2249                 }
2250         }
2251
2252         if (pmu_info_fp != NULL) {
2253                 rewind(pmu_info_fp);
2254                 while (!feof(pmu_info_fp)) {
2255                         char buf[32];
2256
2257                         if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL) {
2258                                 break;
2259                         }
2260                         if (buf[0] == 'A') {
2261                                 sscanf(buf, "AC Power               : %d", &ac);
2262                         }
2263                 }
2264         }
2265         /* update status string */
2266         if ((ac && !(flags & PMU_BATT_PRESENT))) {
2267                 strncpy(pb_battery_info[PB_BATT_STATUS], "AC", sizeof(pb_battery_info[PB_BATT_STATUS]));
2268         } else if (ac && (flags & PMU_BATT_PRESENT)
2269                         && !(flags & PMU_BATT_CHARGING)) {
2270                 strncpy(pb_battery_info[PB_BATT_STATUS], "charged", sizeof(pb_battery_info[PB_BATT_STATUS]));
2271         } else if ((flags & PMU_BATT_PRESENT) && (flags & PMU_BATT_CHARGING)) {
2272                 strncpy(pb_battery_info[PB_BATT_STATUS], "charging", sizeof(pb_battery_info[PB_BATT_STATUS]));
2273         } else {
2274                 strncpy(pb_battery_info[PB_BATT_STATUS], "discharging", sizeof(pb_battery_info[PB_BATT_STATUS]));
2275         }
2276
2277         /* update percentage string */
2278         if (timeval == 0 && ac && (flags & PMU_BATT_PRESENT)
2279                         && !(flags & PMU_BATT_CHARGING)) {
2280                 snprintf(pb_battery_info[PB_BATT_PERCENT],
2281                         sizeof(pb_battery_info[PB_BATT_PERCENT]), "100%%");
2282         } else if (timeval == 0) {
2283                 snprintf(pb_battery_info[PB_BATT_PERCENT],
2284                         sizeof(pb_battery_info[PB_BATT_PERCENT]), "unknown");
2285         } else {
2286                 snprintf(pb_battery_info[PB_BATT_PERCENT],
2287                         sizeof(pb_battery_info[PB_BATT_PERCENT]), "%d%%",
2288                         (charge * 100) / max_charge);
2289         }
2290
2291         /* update time string */
2292         if (timeval == 0) {                     /* fully charged or battery not present */
2293                 snprintf(pb_battery_info[PB_BATT_TIME],
2294                         sizeof(pb_battery_info[PB_BATT_TIME]), "unknown");
2295         } else if (timeval < 60 * 60) { /* don't show secs */
2296                 format_seconds_short(pb_battery_info[PB_BATT_TIME],
2297                         sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2298         } else {
2299                 format_seconds(pb_battery_info[PB_BATT_TIME],
2300                         sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2301         }
2302
2303         snprintf(buffer, n, "%s", pb_battery_info[i]);
2304 }
2305
2306 int update_top(void)
2307 {
2308         process_find_top(info.cpu, info.memu, info.time
2309 #ifdef IOSTATS
2310                 , info.io
2311 #endif
2312                 );
2313         info.first_process = get_first_process();
2314         return 0;
2315 }
2316
2317 #define ENTROPY_AVAIL_PATH "/proc/sys/kernel/random/entropy_avail"
2318
2319 int get_entropy_avail(unsigned int *val)
2320 {
2321         static int rep = 0;
2322         FILE *fp;
2323
2324         if (!(fp = open_file(ENTROPY_AVAIL_PATH, &rep)))
2325                 return 1;
2326
2327         if (fscanf(fp, "%u", val) != 1)
2328                 return 1;
2329
2330         fclose(fp);
2331         return 0;
2332 }
2333
2334 #define ENTROPY_POOLSIZE_PATH "/proc/sys/kernel/random/poolsize"
2335
2336 int get_entropy_poolsize(unsigned int *val)
2337 {
2338         static int rep = 0;
2339         FILE *fp;
2340
2341         if (!(fp = open_file(ENTROPY_POOLSIZE_PATH, &rep)))
2342                 return 1;
2343
2344         if (fscanf(fp, "%u", val) != 1)
2345                 return 1;
2346
2347         fclose(fp);
2348         return 0;
2349 }
2350
2351 const char *get_disk_protect_queue(const char *disk)
2352 {
2353         FILE *fp;
2354         char path[128];
2355         int state;
2356
2357         snprintf(path, 127, "/sys/block/%s/device/unload_heads", disk);
2358         if (access(path, F_OK)) {
2359                 snprintf(path, 127, "/sys/block/%s/queue/protect", disk);
2360         }
2361         if ((fp = fopen(path, "r")) == NULL)
2362                 return "n/a   ";
2363         if (fscanf(fp, "%d\n", &state) != 1) {
2364                 fclose(fp);
2365                 return "failed";
2366         }
2367         fclose(fp);
2368         return (state > 0) ? "frozen" : "free  ";
2369 }
2370
2371 typedef struct DEV_LIST_TYPE
2372 {
2373         char *dev_name;
2374         int memoized;
2375         struct DEV_LIST_TYPE *next;
2376
2377 } DEV_LIST, *DEV_LIST_PTR;
2378
2379 /* Same as sf #2942117 but memoized using a linked list */
2380 int is_disk(char *dev)
2381 {
2382         char syspath[PATH_MAX];
2383         char *slash;
2384         static DEV_LIST_PTR dev_head = NULL;
2385         DEV_LIST_PTR dev_cur, dev_last;
2386
2387         dev_cur = dev_head;
2388
2389         while (dev_cur) {
2390                 if (strcmp(dev_cur->dev_name, dev) == 0)
2391                         return dev_cur->memoized;
2392                 dev_last = dev_cur;
2393                 dev_cur  = dev_cur->next;
2394         }
2395
2396         dev_cur = (DEV_LIST_PTR)malloc(sizeof(DEV_LIST));
2397         dev_cur->dev_name = (char *)malloc((strlen(dev)+1)*sizeof(char));
2398         strcpy(dev_cur->dev_name,dev);
2399         dev_cur->next = NULL;
2400
2401         while ((slash = strchr(dev, '/')))
2402                 *slash = '!';
2403         snprintf(syspath, sizeof(syspath), "/sys/block/%s", dev);
2404         dev_cur->memoized = !(access(syspath, F_OK));
2405
2406         if (dev_head)
2407                 dev_last->next = dev_cur;
2408         else
2409                 dev_head = dev_cur;
2410
2411         return dev_cur->memoized;
2412 }
2413
2414 int update_diskio(void)
2415 {
2416         FILE *fp;
2417         static int rep = 0;
2418         char buf[512], devbuf[64];
2419         unsigned int major, minor;
2420         int col_count = 0;
2421         struct diskio_stat *cur;
2422         unsigned int reads, writes;
2423         unsigned int total_reads = 0, total_writes = 0;
2424
2425         stats.current = 0;
2426         stats.current_read = 0;
2427         stats.current_write = 0;
2428
2429         if (!(fp = open_file("/proc/diskstats", &rep))) {
2430                 return 0;
2431         }
2432
2433         /* read reads and writes from all disks (minor = 0), including cd-roms
2434          * and floppies, and sum them up */
2435         while (fgets(buf, 512, fp)) {
2436                 col_count = sscanf(buf, "%u %u %s %*u %*u %u %*u %*u %*u %u", &major,
2437                         &minor, devbuf, &reads, &writes);
2438                 /* ignore subdevices (they have only 3 matching entries in their line)
2439                  * and virtual devices (LVM, network block devices, RAM disks, Loopback)
2440                  *
2441                  * XXX: ignore devices which are part of a SW RAID (MD_MAJOR) */
2442                 if (col_count == 5 && major != LVM_BLK_MAJOR && major != NBD_MAJOR
2443                                 && major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
2444                         /* check needed for kernel >= 2.6.31, see sf #2942117 */
2445                         if (is_disk(devbuf)) {
2446                                 total_reads += reads;
2447                                 total_writes += writes;
2448                         }
2449                 } else {
2450                         col_count = sscanf(buf, "%u %u %s %*u %u %*u %u",
2451                                 &major, &minor, devbuf, &reads, &writes);
2452                         if (col_count != 5) {
2453                                 continue;
2454                         }
2455                 }
2456                 cur = stats.next;
2457                 while (cur && strcmp(devbuf, cur->dev))
2458                         cur = cur->next;
2459
2460                 if (cur)
2461                         update_diskio_values(cur, reads, writes);
2462         }
2463         update_diskio_values(&stats, total_reads, total_writes);
2464         fclose(fp);
2465         return 0;
2466 }