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
4 * Conky, a system monitor, based on torsmo
6 * Any original torsmo code is licensed under the BSD license
8 * All code written since the fork of torsmo is licensed under the GPL
10 * Please see COPYING for details
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.
16 * All rights reserved.
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.
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/>.
38 #include "temphelper.h"
43 #include <sys/types.h>
44 #include <sys/sysinfo.h>
46 #ifndef HAVE_CLOCK_GETTIME
51 // #include <assert.h>
55 #include <sys/ioctl.h>
56 #include <sys/socket.h>
57 #include <netinet/in.h>
58 #include <linux/sockios.h>
60 #include <arpa/inet.h>
64 #include <linux/route.h>
68 /* The following ifdefs were adapted from gkrellm */
69 #include <linux/major.h>
71 #if !defined(MD_MAJOR)
75 #if !defined(LVM_BLK_MAJOR)
76 #define LVM_BLK_MAJOR 58
79 #if !defined(NBD_MAJOR)
95 #define SHORTSTAT_TEMPL "%*s %llu %llu %llu"
96 #define LONGSTAT_TEMPL "%*s %llu %llu %llu "
98 /* This flag tells the linux routines to use the /proc system where possible,
99 * even if other api's are available, e.g. sysinfo() or getloadavg().
100 * the reason for this is to allow for /proc-based distributed monitoring.
101 * using a flag in this manner creates less confusing code. */
102 static int prefer_proc = 0;
104 void prepare_update(void)
108 void update_uptime(void)
112 struct sysinfo s_info;
115 info.uptime = (double) s_info.uptime;
122 if (!(fp = open_file("/proc/uptime", &rep))) {
126 fscanf(fp, "%lf", &info.uptime);
131 int check_mount(char *s)
134 FILE *mtab = fopen("/etc/mtab", "r");
137 char buf1[256], buf2[128];
139 while (fgets(buf1, 256, mtab)) {
140 sscanf(buf1, "%*s %128s", buf2);
141 if (!strcmp(s, buf2)) {
148 NORM_ERR("Could not open mtab");
153 /* these things are also in sysinfo except Buffers:
154 * (that's why I'm reading them from proc) */
156 void update_meminfo(void)
161 /* unsigned int a; */
164 info.mem = info.memmax = info.swap = info.swapfree = info.swapmax = info.bufmem =
165 info.buffers = info.cached = info.memfree = info.memeasyfree = 0;
167 if (!(meminfo_fp = open_file("/proc/meminfo", &rep))) {
171 while (!feof(meminfo_fp)) {
172 if (fgets(buf, 255, meminfo_fp) == NULL) {
176 if (strncmp(buf, "MemTotal:", 9) == 0) {
177 sscanf(buf, "%*s %llu", &info.memmax);
178 } else if (strncmp(buf, "MemFree:", 8) == 0) {
179 sscanf(buf, "%*s %llu", &info.memfree);
180 } else if (strncmp(buf, "SwapTotal:", 10) == 0) {
181 sscanf(buf, "%*s %llu", &info.swapmax);
182 } else if (strncmp(buf, "SwapFree:", 9) == 0) {
183 sscanf(buf, "%*s %llu", &info.swapfree);
184 } else if (strncmp(buf, "Buffers:", 8) == 0) {
185 sscanf(buf, "%*s %llu", &info.buffers);
186 } else if (strncmp(buf, "Cached:", 7) == 0) {
187 sscanf(buf, "%*s %llu", &info.cached);
191 info.mem = info.memmax - info.memfree;
192 info.memeasyfree = info.memfree;
193 info.swap = info.swapmax - info.swapfree;
195 info.bufmem = info.cached + info.buffers;
200 int get_laptop_mode(void)
205 if ((fp = fopen("/proc/sys/vm/laptop_mode", "r")) != NULL)
206 fscanf(fp, "%d\n", &val);
212 * # cat /sys/block/sda/queue/scheduler
213 * noop [anticipatory] cfq
215 char *get_ioscheduler(char *disk)
221 return strndup("n/a", text_buffer_size);
223 snprintf(buf, 127, "/sys/block/%s/queue/scheduler", disk);
224 if ((fp = fopen(buf, "r")) == NULL) {
225 return strndup("n/a", text_buffer_size);
228 fscanf(fp, "%127s", buf);
230 buf[strlen(buf) - 1] = '\0';
232 return strndup(buf + 1, text_buffer_size);
236 return strndup("n/a", text_buffer_size);
245 #define COND_FREE(x) if(x) free(x); x = 0
246 #define SAVE_SET_STRING(x, y) \
247 if (x && strcmp((char *)x, (char *)y)) { \
249 x = strndup("multiple", text_buffer_size); \
251 x = strndup(y, text_buffer_size); \
254 void update_gateway_info_failure(const char *reason)
259 //2 pointers to 1 location causes a crash when we try to free them both
260 gw_info.iface = strndup("failed", text_buffer_size);
261 gw_info.ip = strndup("failed", text_buffer_size);
265 /* Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT */
266 #define RT_ENTRY_FORMAT "%63s %lx %lx %x %*d %*d %*d %lx %*d %*d %*d\n"
268 void update_gateway_info(void)
273 unsigned long dest, gate, mask;
276 COND_FREE(gw_info.iface);
277 COND_FREE(gw_info.ip);
280 if ((fp = fopen("/proc/net/route", "r")) == NULL) {
281 update_gateway_info_failure("fopen()");
285 /* skip over the table header line, which is always present */
286 fscanf(fp, "%*[^\n]\n");
289 if(fscanf(fp, RT_ENTRY_FORMAT,
290 iface, &dest, &gate, &flags, &mask) != 5) {
291 update_gateway_info_failure("fscanf()");
294 if (!(dest || mask) && ((flags & RTF_GATEWAY) || !gate) ) {
296 SAVE_SET_STRING(gw_info.iface, iface)
298 SAVE_SET_STRING(gw_info.ip, inet_ntoa(ina))
305 void free_gateway_info(void)
311 memset(&gw_info, 0, sizeof(gw_info));
314 int gateway_exists(void)
316 return !!gw_info.count;
319 void print_gateway_iface(char *p, int p_max_size)
321 snprintf(p, p_max_size, "%s", gw_info.iface);
324 void print_gateway_ip(char *p, int p_max_size)
326 snprintf(p, p_max_size, "%s", gw_info.ip);
329 void update_net_stats(void)
333 static char first = 1;
335 // FIXME: arbitrary size chosen to keep code simple.
337 unsigned int curtmp1, curtmp2;
344 // wireless info variables
345 int skfd, has_bitrate = 0;
346 struct wireless_info *winfo;
351 delta = current_update_time - last_update_time;
352 if (delta <= 0.0001) {
356 /* open file and ignore first two lines */
357 if (!(net_dev_fp = open_file("/proc/net/dev", &rep))) {
362 fgets(buf, 255, net_dev_fp); /* garbage */
363 fgets(buf, 255, net_dev_fp); /* garbage (field names) */
365 /* read each interface */
366 for (i2 = 0; i2 < MAX_NET_INTERFACES; i2++) {
370 long long r, t, last_recv, last_trans;
372 if (fgets(buf, 255, net_dev_fp) == NULL) {
376 while (isspace((int) *p)) {
382 while (*p && *p != ':') {
391 ns = get_net_stat(s, NULL, NULL);
393 memset(&(ns->addr.sa_data), 0, 14);
395 memset(ns->addrs, 0, 17 * MAX_NET_INTERFACES + 1); /* Up to 17 chars per ip, max MAX_NET_INTERFACES interfaces. Nasty memory usage... */
397 last_recv = ns->recv;
398 last_trans = ns->trans;
400 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
401 sscanf(p, "%lld %*d %*d %*d %*d %*d %*d %*d %lld",
404 /* if recv or trans is less than last time, an overflow happened */
405 if (r < ns->last_read_recv) {
408 ns->recv += (r - ns->last_read_recv);
410 ns->last_read_recv = r;
412 if (t < ns->last_read_trans) {
415 ns->trans += (t - ns->last_read_trans);
417 ns->last_read_trans = t;
419 /*** ip addr patch ***/
420 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
422 conf.ifc_buf = malloc(sizeof(struct ifreq) * MAX_NET_INTERFACES);
423 conf.ifc_len = sizeof(struct ifreq) * MAX_NET_INTERFACES;
424 memset(conf.ifc_buf, 0, conf.ifc_len);
426 ioctl((long) i, SIOCGIFCONF, &conf);
428 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
429 struct net_stat *ns2;
431 if (!(((struct ifreq *) conf.ifc_buf) + k))
435 ((struct ifreq *) conf.ifc_buf)[k].ifr_ifrn.ifrn_name, NULL, NULL);
436 ns2->addr = ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.ifru_addr;
437 sprintf(temp_addr, "%u.%u.%u.%u, ",
438 ns2->addr.sa_data[2] & 255,
439 ns2->addr.sa_data[3] & 255,
440 ns2->addr.sa_data[4] & 255,
441 ns2->addr.sa_data[5] & 255);
442 if(NULL == strstr(ns2->addrs, temp_addr))
443 strncpy(ns2->addrs + strlen(ns2->addrs), temp_addr, 17);
450 /*** end ip addr patch ***/
453 /* calculate speeds */
454 ns->net_rec[0] = (ns->recv - last_recv) / delta;
455 ns->net_trans[0] = (ns->trans - last_trans) / delta;
462 #pragma omp parallel for reduction(+:curtmp1, curtmp2) schedule(dynamic,10)
463 #endif /* HAVE_OPENMP */
464 for (i = 0; i < info.net_avg_samples; i++) {
465 curtmp1 = curtmp1 + ns->net_rec[i];
466 curtmp2 = curtmp2 + ns->net_trans[i];
468 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
469 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
470 if (info.net_avg_samples > 1) {
472 #pragma omp parallel for schedule(dynamic,10)
473 #endif /* HAVE_OPENMP */
474 for (i = info.net_avg_samples; i > 1; i--) {
475 ns->net_rec[i - 1] = ns->net_rec[i - 2];
476 ns->net_trans[i - 1] = ns->net_trans[i - 2];
481 /* update wireless info */
482 winfo = malloc(sizeof(struct wireless_info));
483 memset(winfo, 0, sizeof(struct wireless_info));
485 skfd = iw_sockets_open();
486 if (iw_get_basic_config(skfd, s, &(winfo->b)) > -1) {
488 // set present winfo variables
489 if (iw_get_stats(skfd, s, &(winfo->stats),
490 &winfo->range, winfo->has_range) >= 0) {
491 winfo->has_stats = 1;
493 if (iw_get_range_info(skfd, s, &(winfo->range)) >= 0) {
494 winfo->has_range = 1;
496 if (iw_get_ext(skfd, s, SIOCGIWAP, &wrq) >= 0) {
497 winfo->has_ap_addr = 1;
498 memcpy(&(winfo->ap_addr), &(wrq.u.ap_addr), sizeof(sockaddr));
502 if (iw_get_ext(skfd, s, SIOCGIWRATE, &wrq) >= 0) {
503 memcpy(&(winfo->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
504 iw_print_bitrate(ns->bitrate, 16, winfo->bitrate.value);
509 if (winfo->has_range && winfo->has_stats
510 && ((winfo->stats.qual.level != 0)
511 || (winfo->stats.qual.updated & IW_QUAL_DBM))) {
512 if (!(winfo->stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
513 ns->link_qual = winfo->stats.qual.qual;
514 ns->link_qual_max = winfo->range.max_qual.qual;
519 if (winfo->has_ap_addr) {
520 iw_sawap_ntop(&winfo->ap_addr, ns->ap);
524 if (winfo->b.has_essid) {
525 if (winfo->b.essid_on) {
526 snprintf(ns->essid, 32, "%s", winfo->b.essid);
528 snprintf(ns->essid, 32, "off/any");
532 snprintf(ns->mode, 16, "%s", iw_operation_mode[winfo->b.mode]);
534 iw_sockets_close(skfd);
545 void update_total_processes(void)
548 struct dirent *entry;
553 if (!(dir = opendir("/proc"))) {
556 while ((entry = readdir(dir))) {
558 /* Problem reading list of processes */
563 if (sscanf(entry->d_name, "%d%c", &ignore1, &ignore2) == 1) {
570 void update_threads(void)
574 struct sysinfo s_info;
577 info.threads = s_info.procs;
584 if (!(fp = open_file("/proc/loadavg", &rep))) {
588 fscanf(fp, "%*f %*f %*f %*d/%hu", &info.threads);
593 #define CPU_SAMPLE_COUNT 15
595 unsigned long long cpu_user;
596 unsigned long long cpu_system;
597 unsigned long long cpu_nice;
598 unsigned long long cpu_idle;
599 unsigned long long cpu_iowait;
600 unsigned long long cpu_irq;
601 unsigned long long cpu_softirq;
602 unsigned long long cpu_steal;
603 unsigned long long cpu_total;
604 unsigned long long cpu_active_total;
605 unsigned long long cpu_last_total;
606 unsigned long long cpu_last_active_total;
607 double cpu_val[CPU_SAMPLE_COUNT];
609 static short cpu_setup = 0;
611 /* Determine if this kernel gives us "extended" statistics information in
613 * Kernels around 2.5 and earlier only reported user, system, nice, and
614 * idle values in proc stat.
615 * Kernels around 2.6 and greater report these PLUS iowait, irq, softirq,
617 void determine_longstat(char *buf)
619 unsigned long long iowait = 0;
621 KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
622 /* scanf will either return -1 or 1 because there is only 1 assignment */
623 if (sscanf(buf, "%*s %*d %*d %*d %*d %llu", &iowait) > 0) {
624 KFLAG_SETON(KFLAG_IS_LONGSTAT);
628 void get_cpu_count(void)
634 if (info.cpu_usage) {
638 if (!(stat_fp = open_file("/proc/stat", &rep))) {
644 while (!feof(stat_fp)) {
645 if (fgets(buf, 255, stat_fp) == NULL) {
649 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
650 if (info.cpu_count == 0) {
651 determine_longstat(buf);
656 info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
661 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
662 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
664 void update_stat(void)
668 static struct cpu_info *cpu = NULL;
673 const char *stat_template = NULL;
674 unsigned int malloc_cpu_size = 0;
675 extern void* global_cpu;
677 static pthread_mutex_t last_stat_update_mutex = PTHREAD_MUTEX_INITIALIZER;
678 static double last_stat_update = 0.0;
680 /* since we use wrappers for this function, the update machinery
681 * can't eliminate double invocations of this function. Check for
682 * them here, otherwise cpu_usage counters are freaking out. */
683 pthread_mutex_lock(&last_stat_update_mutex);
684 if (last_stat_update == current_update_time) {
685 pthread_mutex_unlock(&last_stat_update_mutex);
688 last_stat_update = current_update_time;
689 pthread_mutex_unlock(&last_stat_update_mutex);
691 /* add check for !info.cpu_usage since that mem is freed on a SIGUSR1 */
692 if (!cpu_setup || !info.cpu_usage) {
697 if (!stat_template) {
699 KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT;
703 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
704 cpu = malloc(malloc_cpu_size);
705 memset(cpu, 0, malloc_cpu_size);
709 if (!(stat_fp = open_file("/proc/stat", &rep))) {
710 info.run_threads = 0;
711 if (info.cpu_usage) {
712 memset(info.cpu_usage, 0, info.cpu_count * sizeof(float));
718 while (!feof(stat_fp)) {
719 if (fgets(buf, 255, stat_fp) == NULL) {
723 if (strncmp(buf, "procs_running ", 14) == 0) {
724 sscanf(buf, "%*s %hu", &info.run_threads);
725 } else if (strncmp(buf, "cpu", 3) == 0) {
727 if (isdigit(buf[3])) {
728 idx = atoi(&buf[3]) + 1;
732 sscanf(buf, stat_template, &(cpu[idx].cpu_user),
733 &(cpu[idx].cpu_nice), &(cpu[idx].cpu_system),
734 &(cpu[idx].cpu_idle), &(cpu[idx].cpu_iowait),
735 &(cpu[idx].cpu_irq), &(cpu[idx].cpu_softirq),
736 &(cpu[idx].cpu_steal));
738 cpu[idx].cpu_total = cpu[idx].cpu_user + cpu[idx].cpu_nice +
739 cpu[idx].cpu_system + cpu[idx].cpu_idle +
740 cpu[idx].cpu_iowait + cpu[idx].cpu_irq +
741 cpu[idx].cpu_softirq + cpu[idx].cpu_steal;
743 cpu[idx].cpu_active_total = cpu[idx].cpu_total -
744 (cpu[idx].cpu_idle + cpu[idx].cpu_iowait);
746 delta = current_update_time - last_update_time;
748 if (delta <= 0.001) {
752 cpu[idx].cpu_val[0] = (cpu[idx].cpu_active_total -
753 cpu[idx].cpu_last_active_total) /
754 (float) (cpu[idx].cpu_total - cpu[idx].cpu_last_total);
757 #pragma omp parallel for reduction(+:curtmp) schedule(dynamic,10)
758 #endif /* HAVE_OPENMP */
759 for (i = 0; i < info.cpu_avg_samples; i++) {
760 curtmp = curtmp + cpu[idx].cpu_val[i];
762 /* TESTING -- I've removed this, because I don't think it is right.
763 * You shouldn't divide by the cpu count here ...
764 * removing for testing */
766 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples /
769 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples;
771 /* TESTING -- this line replaces the prev. "suspect" if/else */
772 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples;
774 cpu[idx].cpu_last_total = cpu[idx].cpu_total;
775 cpu[idx].cpu_last_active_total = cpu[idx].cpu_active_total;
777 #pragma omp parallel for schedule(dynamic,10)
778 #endif /* HAVE_OPENMP */
779 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
780 cpu[idx].cpu_val[i] = cpu[idx].cpu_val[i - 1];
787 void update_running_processes(void)
792 void update_cpu_usage(void)
797 void update_load_average(void)
799 #ifdef HAVE_GETLOADAVG
804 info.loadavg[0] = (float) v[0];
805 info.loadavg[1] = (float) v[1];
806 info.loadavg[2] = (float) v[2];
813 if (!(fp = open_file("/proc/loadavg", &rep))) {
814 info.loadavg[0] = info.loadavg[1] = info.loadavg[2] = 0.0;
817 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1],
823 /***********************************************************/
824 /***********************************************************/
825 /***********************************************************/
827 static int no_dots(const struct dirent *d)
829 if (d->d_name[0] == '.') {
835 static int get_first_file_in_a_directory(const char *dir, char *s, int *rep)
837 struct dirent **namelist;
840 n = scandir(dir, &namelist, no_dots, alphasort);
843 NORM_ERR("scandir for %s: %s", dir, strerror(errno));
854 strncpy(s, namelist[0]->d_name, 255);
858 #pragma omp parallel for schedule(dynamic,10)
859 #endif /* HAVE_OPENMP */
860 for (i = 0; i < n; i++) {
869 static int open_sysfs_sensor(const char *dir, const char *dev, const char *type, int n,
870 int *divisor, char *devtype)
877 memset(buf, 0, sizeof(buf));
879 /* if device is NULL or *, get first */
880 if (dev == NULL || strcmp(dev, "*") == 0) {
883 if (!get_first_file_in_a_directory(dir, buf, &rep)) {
889 if (strcmp(dir, "/sys/class/hwmon/") == 0) {
891 /* buf holds result from get_first_file_in_a_directory() above,
892 * e.g. "hwmon0" -- append "/device" */
893 strcat(buf, "/device");
895 /* dev holds device number N as a string,
896 * e.g. "0", -- convert to "hwmon0/device" */
897 sprintf(buf, "hwmon%s/device", dev);
902 /* change vol to in, tempf to temp */
903 if (strcmp(type, "vol") == 0) {
905 } else if (strcmp(type, "tempf") == 0) {
910 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, type, n);
912 /* first, attempt to open file in /device */
913 fd = open(path, O_RDONLY);
916 /* if it fails, strip the /device from dev and attempt again */
917 buf[strlen(buf) - 7] = 0;
918 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, type, n);
919 fd = open(path, O_RDONLY);
921 CRIT_ERR(NULL, NULL, "can't open '%s': %s\nplease check your device or remove this "
922 "var from "PACKAGE_NAME, path, strerror(errno));
926 strncpy(devtype, path, 255);
928 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
929 || strcmp(type, "tempf") == 0) {
934 /* fan does not use *_div as a read divisor */
935 if (strcmp("fan", type) == 0) {
939 /* test if *_div file exist, open it and use it as divisor */
940 if (strcmp(type, "tempf") == 0) {
941 snprintf(path, 255, "%s%s/%s%d_div", dir, "one", "two", n);
943 snprintf(path, 255, "%s%s/%s%d_div", dir, dev, type, n);
946 divfd = open(path, O_RDONLY);
952 divn = read(divfd, divbuf, 63);
953 /* should read until n == 0 but I doubt that kernel will give these
954 * in multiple pieces. :) */
956 NORM_ERR("open_sysfs_sensor(): can't read from sysfs");
959 *divisor = atoi(divbuf);
967 static double get_sysfs_info(int *fd, int divisor, char *devtype, char *type)
975 lseek(*fd, 0, SEEK_SET);
981 n = read(*fd, buf, 63);
982 /* should read until n == 0 but I doubt that kernel will give these
983 * in multiple pieces. :) */
985 NORM_ERR("get_sysfs_info(): read from %s failed\n", devtype);
994 *fd = open(devtype, O_RDONLY);
996 NORM_ERR("can't open '%s': %s", devtype, strerror(errno));
999 /* My dirty hack for computing CPU value
1000 * Filedil, from forums.gentoo.org */
1001 /* if (strstr(devtype, "temp1_input") != NULL) {
1002 return -15.096 + 1.4893 * (val / 1000.0);
1005 /* divide voltage and temperature by 1000 */
1006 /* or if any other divisor is given, use that */
1007 if (strcmp(type, "tempf") == 0) {
1009 return ((val / divisor + 40) * 9.0 / 5) - 40;
1010 } else if (divisor) {
1011 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
1013 return ((val + 40) * 9.0 / 5) - 40;
1017 return val / divisor;
1018 } else if (divisor) {
1019 return val / 1000.0;
1026 #define HWMON_RESET() {\
1031 static void parse_sysfs_sensor(struct text_object *obj, const char *arg, const char *path, const char *type)
1033 char buf1[64], buf2[64];
1034 float factor, offset;
1038 if (sscanf(arg, "%63s %d %f %f", buf2, &n, &factor, &offset) == 4) found = 1; else HWMON_RESET();
1039 if (!found && sscanf(arg, "%63s %63s %d %f %f", buf1, buf2, &n, &factor, &offset) == 5) found = 1; else if (!found) HWMON_RESET();
1040 if (!found && sscanf(arg, "%63s %63s %d", buf1, buf2, &n) == 3) found = 1; else if (!found) HWMON_RESET();
1041 if (!found && sscanf(arg, "%63s %d", buf2, &n) == 2) found = 1; else if (!found) HWMON_RESET();
1044 NORM_ERR("i2c failed to parse arguments");
1045 obj->type = OBJ_text;
1048 DBGP("parsed %s args: '%s' '%s' %d %f %f\n", type, buf1, buf2, n, factor, offset);
1049 sf = malloc(sizeof(struct sysfs));
1050 memset(sf, 0, sizeof(struct sysfs));
1051 sf->fd = open_sysfs_sensor(path, (*buf1) ? buf1 : 0, buf2, n,
1052 &sf->arg, sf->devtype);
1053 strncpy(sf->type, buf2, 63);
1054 sf->factor = factor;
1055 sf->offset = offset;
1056 obj->data.opaque = sf;
1059 #define PARSER_GENERATOR(name, path) \
1060 void parse_##name##_sensor(struct text_object *obj, const char *arg) \
1062 parse_sysfs_sensor(obj, arg, path, #name); \
1065 PARSER_GENERATOR(i2c, "/sys/bus/i2c/devices/")
1066 PARSER_GENERATOR(hwmon, "/sys/class/hwmon/")
1067 PARSER_GENERATOR(platform, "/sys/bus/platform/devices/")
1069 void print_sysfs_sensor(struct text_object *obj, char *p, int p_max_size)
1072 struct sysfs *sf = obj->data.opaque;
1077 r = get_sysfs_info(&sf->fd, sf->arg,
1078 sf->devtype, sf->type);
1080 r = r * sf->factor + sf->offset;
1082 if (!strncmp(sf->type, "temp", 4)) {
1083 temp_print(p, p_max_size, r, TEMP_CELSIUS);
1084 } else if (r >= 100.0 || r == 0) {
1085 snprintf(p, p_max_size, "%d", (int) r);
1087 snprintf(p, p_max_size, "%.1f", r);
1091 void free_sysfs_sensor(struct text_object *obj)
1093 struct sysfs *sf = obj->data.opaque;
1099 free(obj->data.opaque);
1100 obj->data.opaque = NULL;
1103 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
1104 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
1106 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1107 char get_freq(char *p_client_buffer, size_t client_buffer_size,
1108 const char *p_format, int divisor, unsigned int cpu)
1116 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1122 char current_freq_file[128];
1124 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu - 1,
1126 f = fopen(current_freq_file, "r");
1128 /* if there's a cpufreq /sys node, read the current frequency from
1129 * this node and divide by 1000 to get Mhz. */
1130 if (fgets(s, sizeof(s), f)) {
1131 s[strlen(s) - 1] = '\0';
1132 freq = strtod(s, NULL);
1135 snprintf(p_client_buffer, client_buffer_size, p_format,
1136 (freq / 1000) / divisor);
1141 // open the CPU information file
1142 f = open_file("/proc/cpuinfo", &rep);
1144 perror(PACKAGE_NAME": Failed to access '/proc/cpuinfo' at get_freq()");
1149 while (fgets(s, sizeof(s), f) != NULL) {
1151 #if defined(__i386) || defined(__x86_64)
1152 // and search for the cpu mhz
1153 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) {
1155 #if defined(__alpha)
1156 // different on alpha
1157 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) {
1159 // this is different on ppc for some reason
1160 if (strncmp(s, "clock", 5) == 0 && cpu == 0) {
1161 #endif // defined(__alpha)
1162 #endif // defined(__i386) || defined(__x86_64)
1164 // copy just the number
1165 strcpy(frequency, strchr(s, ':') + 2);
1166 #if defined(__alpha)
1168 frequency[strlen(frequency) - 6] = '\0';
1169 // kernel reports in Hz
1170 freq = strtod(frequency, NULL) / 1000000;
1173 frequency[strlen(frequency) - 1] = '\0';
1174 freq = strtod(frequency, NULL);
1178 if (strncmp(s, "processor", 9) == 0) {
1185 snprintf(p_client_buffer, client_buffer_size, p_format,
1186 (float) freq / divisor);
1190 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
1192 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks something
1202 * Peter Tarjan (ptarjan@citromail.hu) */
1204 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
1205 static char get_voltage(char *p_client_buffer, size_t client_buffer_size,
1206 const char *p_format, int divisor, unsigned int cpu)
1212 char current_freq_file[128];
1215 /* build the voltage file name */
1217 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1220 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1225 /* read the current cpu frequency from the /sys node */
1226 f = fopen(current_freq_file, "r");
1228 if (fgets(s, sizeof(s), f)) {
1229 s[strlen(s) - 1] = '\0';
1230 freq = strtod(s, NULL);
1234 fprintf(stderr, PACKAGE_NAME": Failed to access '%s' at ", current_freq_file);
1235 perror("get_voltage()");
1242 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1245 /* use the current cpu frequency to find the corresponding voltage */
1246 f = fopen(current_freq_file, "r");
1252 if (fgets(line, 255, f) == NULL) {
1255 sscanf(line, "%d %d", &freq_comp, &voltage);
1256 if (freq_comp == freq) {
1262 fprintf(stderr, PACKAGE_NAME": Failed to access '%s' at ", current_freq_file);
1263 perror("get_voltage()");
1269 snprintf(p_client_buffer, client_buffer_size, p_format,
1270 (float) voltage / divisor);
1274 void print_voltage_mv(struct text_object *obj, char *p, int p_max_size)
1278 ok = get_voltage(p, p_max_size, "%.0f", 1, obj->data.i);
1282 void print_voltage_v(struct text_object *obj, char *p, int p_max_size)
1286 ok = get_voltage(p, p_max_size, "%'.3f", 1000, obj->data.i);
1290 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1292 void get_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
1299 if (!p_client_buffer || client_buffer_size <= 0) {
1303 /* yeah, slow... :/ */
1304 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep)) {
1305 snprintf(p_client_buffer, client_buffer_size, "no fans?");
1309 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf);
1311 fp = open_file(buf2, &rep);
1313 snprintf(p_client_buffer, client_buffer_size,
1314 "can't open fan's state file");
1317 memset(buf, 0, sizeof(buf));
1318 fscanf(fp, "%*s %99s", buf);
1321 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1324 #define SYSFS_AC_ADAPTER_DIR "/sys/class/power_supply/AC"
1325 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1326 /* Linux 2.6.25 onwards ac adapter info is in
1327 /sys/class/power_supply/AC/
1328 On my system I get the following.
1329 /sys/class/power_supply/AC/uevent:
1330 PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A08:00/device:01/PNP0C09:00/ACPI0003:00
1333 POWER_SUPPLY_NAME=AC
1334 POWER_SUPPLY_TYPE=Mains
1335 POWER_SUPPLY_ONLINE=1
1338 void get_acpi_ac_adapter(char *p_client_buffer, size_t client_buffer_size)
1346 if (!p_client_buffer || client_buffer_size <= 0) {
1350 snprintf(buf2, sizeof(buf2), "%s/uevent", SYSFS_AC_ADAPTER_DIR);
1351 fp = open_file(buf2, &rep);
1353 /* sysfs processing */
1355 if (fgets(buf, sizeof(buf), fp) == NULL)
1358 if (strncmp(buf, "POWER_SUPPLY_ONLINE=", 20) == 0) {
1360 sscanf(buf, "POWER_SUPPLY_ONLINE=%d", &online);
1361 snprintf(p_client_buffer, client_buffer_size,
1362 "%s-line", (online ? "on" : "off"));
1368 /* yeah, slow... :/ */
1369 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep)) {
1370 snprintf(p_client_buffer, client_buffer_size, "no ac_adapters?");
1374 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf);
1376 fp = open_file(buf2, &rep);
1378 snprintf(p_client_buffer, client_buffer_size,
1379 "No ac adapter found.... where is it?");
1382 memset(buf, 0, sizeof(buf));
1383 fscanf(fp, "%*s %99s", buf);
1386 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1391 /proc/acpi/thermal_zone/THRM/cooling_mode
1392 cooling mode: active
1393 /proc/acpi/thermal_zone/THRM/polling_frequency
1395 /proc/acpi/thermal_zone/THRM/state
1397 /proc/acpi/thermal_zone/THRM/temperature
1399 /proc/acpi/thermal_zone/THRM/trip_points
1401 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1404 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1405 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1407 int open_acpi_temperature(const char *name)
1413 if (name == NULL || strcmp(name, "*") == 0) {
1416 if (!get_first_file_in_a_directory(ACPI_THERMAL_DIR, buf, &rep)) {
1422 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1424 fd = open(path, O_RDONLY);
1426 NORM_ERR("can't open '%s': %s", path, strerror(errno));
1432 static double last_acpi_temp;
1433 static double last_acpi_temp_time;
1435 double get_acpi_temperature(int fd)
1441 /* don't update acpi temperature too often */
1442 if (current_update_time - last_acpi_temp_time < 11.32) {
1443 return last_acpi_temp;
1445 last_acpi_temp_time = current_update_time;
1447 /* seek to beginning */
1448 lseek(fd, 0, SEEK_SET);
1455 n = read(fd, buf, 255);
1457 NORM_ERR("can't read fd %d: %s", fd, strerror(errno));
1460 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1464 return last_acpi_temp;
1468 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1470 design capacity: 4400 mAh
1471 last full capacity: 4064 mAh
1472 battery technology: rechargeable
1473 design voltage: 14800 mV
1474 design capacity warning: 300 mAh
1475 design capacity low: 200 mAh
1476 capacity granularity 1: 32 mAh
1477 capacity granularity 2: 32 mAh
1479 serial number: 16922
1485 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1488 charging state: unknown
1490 remaining capacity: 4064 mAh
1491 present voltage: 16608 mV
1495 2213<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1496 2213<@jupet�kellari��> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1497 2213<@jupet�kellari��> (-1 ollee ei akkua kiinni, koska akku on p�yd�ll�)
1498 2214<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1499 2214<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1501 2238<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1502 2239<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1504 2240<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori p��ll�
1505 2241<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori p��ll� mutta ilman verkkovirtaa
1508 /* Kapil Hari Paranjape <kapil@imsc.res.in>
1509 Linux 2.6.24 onwards battery info is in
1510 /sys/class/power_supply/BAT0/
1511 On my system I get the following.
1512 /sys/class/power_supply/BAT0/uevent:
1513 PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A03:00/device:01/PNP0C09:00/PNP0C0A:00
1515 PHYSDEVDRIVER=battery
1516 POWER_SUPPLY_NAME=BAT0
1517 POWER_SUPPLY_TYPE=Battery
1518 POWER_SUPPLY_STATUS=Discharging
1519 POWER_SUPPLY_PRESENT=1
1520 POWER_SUPPLY_TECHNOLOGY=Li-ion
1521 POWER_SUPPLY_VOLTAGE_MIN_DESIGN=10800000
1522 POWER_SUPPLY_VOLTAGE_NOW=10780000
1523 POWER_SUPPLY_CURRENT_NOW=13970000
1524 POWER_SUPPLY_ENERGY_FULL_DESIGN=47510000
1525 POWER_SUPPLY_ENERGY_FULL=27370000
1526 POWER_SUPPLY_ENERGY_NOW=11810000
1527 POWER_SUPPLY_MODEL_NAME=IBM-92P1060
1528 POWER_SUPPLY_MANUFACTURER=Panasonic
1529 On some systems POWER_SUPPLY_ENERGY_* is replaced by POWER_SUPPLY_CHARGE_*
1532 #define SYSFS_BATTERY_BASE_PATH "/sys/class/power_supply"
1533 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1534 #define APM_PATH "/proc/apm"
1535 #define MAX_BATTERY_COUNT 4
1537 static FILE *sysfs_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1538 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1539 static FILE *apm_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1541 static int batteries_initialized = 0;
1542 static char batteries[MAX_BATTERY_COUNT][32];
1544 static int acpi_last_full[MAX_BATTERY_COUNT];
1545 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1547 /* e.g. "charging 75%" */
1548 static char last_battery_str[MAX_BATTERY_COUNT][64];
1550 static char last_battery_time_str[MAX_BATTERY_COUNT][64];
1552 static double last_battery_time[MAX_BATTERY_COUNT];
1554 static int last_battery_perct[MAX_BATTERY_COUNT];
1555 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1557 void init_batteries(void)
1561 if (batteries_initialized) {
1565 #pragma omp parallel for schedule(dynamic,10)
1566 #endif /* HAVE_OPENMP */
1567 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1568 batteries[idx][0] = '\0';
1570 batteries_initialized = 1;
1573 int get_battery_idx(const char *bat)
1577 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1578 if (!strlen(batteries[idx]) || !strcmp(batteries[idx], bat)) {
1583 /* if not found, enter a new entry */
1584 if (!strlen(batteries[idx])) {
1585 snprintf(batteries[idx], 31, "%s", bat);
1591 void set_return_value(char *buffer, unsigned int n, int item, int idx);
1593 void get_battery_stuff(char *buffer, unsigned int n, const char *bat, int item)
1595 static int idx, rep = 0, rep1 = 0, rep2 = 0;
1596 char acpi_path[128];
1597 char sysfs_path[128];
1599 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1600 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1604 idx = get_battery_idx(bat);
1606 /* don't update battery too often */
1607 if (current_update_time - last_battery_time[idx] < 29.5) {
1608 set_return_value(buffer, n, item, idx);
1612 last_battery_time[idx] = current_update_time;
1614 memset(last_battery_str[idx], 0, sizeof(last_battery_str[idx]));
1615 memset(last_battery_time_str[idx], 0, sizeof(last_battery_time_str[idx]));
1617 /* first try SYSFS if that fails try ACPI */
1619 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1620 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1623 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1624 acpi_bat_fp[idx] = open_file(acpi_path, &rep1);
1627 if (sysfs_bat_fp[idx] != NULL) {
1629 int present_rate = -1;
1630 int remaining_capacity = -1;
1631 char charging_state[64];
1634 strcpy(charging_state, "unknown");
1636 while (!feof(sysfs_bat_fp[idx])) {
1638 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1641 /* let's just hope units are ok */
1642 if (strncmp (buf, "POWER_SUPPLY_PRESENT=1", 22) == 0)
1643 strcpy(present, "yes");
1644 else if (strncmp (buf, "POWER_SUPPLY_PRESENT=0", 22) == 0)
1645 strcpy(present, "no");
1646 else if (strncmp (buf, "POWER_SUPPLY_STATUS=", 20) == 0)
1647 sscanf(buf, "POWER_SUPPLY_STATUS=%63s", charging_state);
1648 /* present_rate is not the same as the
1649 current flowing now but it is the same value
1650 which was used in the past. so we continue
1652 else if (strncmp(buf, "POWER_SUPPLY_CURRENT_NOW=", 25) == 0)
1653 sscanf(buf, "POWER_SUPPLY_CURRENT_NOW=%d", &present_rate);
1654 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0)
1655 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1656 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=", 25) == 0)
1657 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_last_full[idx]);
1658 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0)
1659 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1660 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=", 25) == 0)
1661 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_last_full[idx]);
1664 fclose(sysfs_bat_fp[idx]);
1665 sysfs_bat_fp[idx] = NULL;
1667 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1668 if (remaining_capacity > acpi_last_full[idx])
1669 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1672 if (strcmp(present, "No") == 0) {
1673 strncpy(last_battery_str[idx], "not present", 64);
1676 else if (strcmp(charging_state, "Charging") == 0) {
1677 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1678 /* e.g. charging 75% */
1679 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %i%%",
1680 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1682 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1683 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1684 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1685 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %d%%",
1686 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1687 snprintf(last_battery_time_str[idx],
1688 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1690 strncpy(last_battery_str[idx], "charging", sizeof(last_battery_str[idx])-1);
1691 snprintf(last_battery_time_str[idx],
1692 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1696 else if (strncmp(charging_state, "Discharging", 64) == 0) {
1697 if (present_rate > 0) {
1698 /* e.g. discharging 35% */
1699 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "discharging %i%%",
1700 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1702 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1703 (long) (((float) remaining_capacity / present_rate) * 3600));
1704 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1705 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "full");
1706 snprintf(last_battery_time_str[idx],
1707 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1709 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1711 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1712 snprintf(last_battery_time_str[idx],
1713 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1717 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1718 else if (strncmp(charging_state, "Charged", 64) == 0 || strncmp(charging_state, "Full", 64) == 0) {
1719 /* Below happens with the second battery on my X40,
1720 * when the second one is empty and the first one
1722 if (remaining_capacity == 0)
1723 strcpy(last_battery_str[idx], "empty");
1725 strcpy(last_battery_str[idx], "charged");
1727 /* unknown, probably full / AC */
1729 if (acpi_last_full[idx] != 0
1730 && remaining_capacity != acpi_last_full[idx])
1731 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1732 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1734 strncpy(last_battery_str[idx], "AC", 64);
1736 } else if (acpi_bat_fp[idx] != NULL) {
1738 int present_rate = -1;
1739 int remaining_capacity = -1;
1740 char charging_state[64];
1743 /* read last full capacity if it's zero */
1744 if (acpi_last_full[idx] == 0) {
1745 static int rep3 = 0;
1749 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1750 fp = open_file(path, &rep3);
1755 if (fgets(b, 256, fp) == NULL) {
1758 if (sscanf(b, "last full capacity: %d",
1759 &acpi_last_full[idx]) != 0) {
1768 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1770 strcpy(charging_state, "unknown");
1772 while (!feof(acpi_bat_fp[idx])) {
1775 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1779 /* let's just hope units are ok */
1780 if (strncmp(buf, "present:", 8) == 0) {
1781 sscanf(buf, "present: %4s", present);
1782 } else if (strncmp(buf, "charging state:", 15) == 0) {
1783 sscanf(buf, "charging state: %63s", charging_state);
1784 } else if (strncmp(buf, "present rate:", 13) == 0) {
1785 sscanf(buf, "present rate: %d", &present_rate);
1786 } else if (strncmp(buf, "remaining capacity:", 19) == 0) {
1787 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1790 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1791 if (remaining_capacity > acpi_last_full[idx]) {
1792 /* normalize to 100% */
1793 acpi_last_full[idx] = remaining_capacity;
1797 if (strcmp(present, "no") == 0) {
1798 strncpy(last_battery_str[idx], "not present", 64);
1800 } else if (strcmp(charging_state, "charging") == 0) {
1801 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1802 /* e.g. charging 75% */
1803 snprintf(last_battery_str[idx],
1804 sizeof(last_battery_str[idx]) - 1, "charging %i%%",
1805 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1807 format_seconds(last_battery_time_str[idx],
1808 sizeof(last_battery_time_str[idx]) - 1,
1809 (long) (((acpi_last_full[idx] - remaining_capacity) *
1810 3600) / present_rate));
1811 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1812 snprintf(last_battery_str[idx],
1813 sizeof(last_battery_str[idx]) - 1, "charging %d%%",
1814 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1815 snprintf(last_battery_time_str[idx],
1816 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1818 strncpy(last_battery_str[idx], "charging",
1819 sizeof(last_battery_str[idx]) - 1);
1820 snprintf(last_battery_time_str[idx],
1821 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1824 } else if (strncmp(charging_state, "discharging", 64) == 0) {
1825 if (present_rate > 0) {
1826 /* e.g. discharging 35% */
1827 snprintf(last_battery_str[idx],
1828 sizeof(last_battery_str[idx]) - 1, "discharging %i%%",
1829 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1831 format_seconds(last_battery_time_str[idx],
1832 sizeof(last_battery_time_str[idx]) - 1,
1833 (long) ((remaining_capacity * 3600) / present_rate));
1834 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1835 snprintf(last_battery_str[idx],
1836 sizeof(last_battery_str[idx]) - 1, "full");
1837 snprintf(last_battery_time_str[idx],
1838 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1840 snprintf(last_battery_str[idx],
1841 sizeof(last_battery_str[idx]) - 1, "discharging %d%%",
1842 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1843 snprintf(last_battery_time_str[idx],
1844 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1847 } else if (strncmp(charging_state, "charged", 64) == 0) {
1848 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1849 /* Below happens with the second battery on my X40,
1850 * when the second one is empty and the first one being charged. */
1851 if (remaining_capacity == 0) {
1852 strcpy(last_battery_str[idx], "empty");
1854 strcpy(last_battery_str[idx], "charged");
1856 /* unknown, probably full / AC */
1858 if (strncmp(charging_state, "Full", 64) == 0) {
1859 strncpy(last_battery_str[idx], "full", 64);
1860 } else if (acpi_last_full[idx] != 0
1861 && remaining_capacity != acpi_last_full[idx]) {
1862 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1863 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1865 strncpy(last_battery_str[idx], "AC", 64);
1868 fclose(acpi_bat_fp[idx]);
1869 acpi_bat_fp[idx] = NULL;
1872 if (apm_bat_fp[idx] == NULL) {
1873 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1876 if (apm_bat_fp[idx] != NULL) {
1877 unsigned int ac, status, flag;
1880 fscanf(apm_bat_fp[idx], "%*s %*s %*x %x %x %x %d%%",
1881 &ac, &status, &flag, &life);
1884 /* could check now that there is ac */
1885 snprintf(last_battery_str[idx], 64, "AC");
1887 /* could check that status == 3 here? */
1888 } else if (ac && life != 100) {
1889 snprintf(last_battery_str[idx], 64, "charging %d%%", life);
1891 snprintf(last_battery_str[idx], 64, "%d%%", life);
1894 /* it seemed to buffer it so file must be closed (or could use
1895 * syscalls directly but I don't feel like coding it now) */
1896 fclose(apm_bat_fp[idx]);
1897 apm_bat_fp[idx] = NULL;
1900 set_return_value(buffer, n, item, idx);
1903 void set_return_value(char *buffer, unsigned int n, int item, int idx)
1906 case BATTERY_STATUS:
1907 snprintf(buffer, n, "%s", last_battery_str[idx]);
1910 snprintf(buffer, n, "%s", last_battery_time_str[idx]);
1917 void get_battery_short_status(char *buffer, unsigned int n, const char *bat)
1919 get_battery_stuff(buffer, n, bat, BATTERY_STATUS);
1920 if (0 == strncmp("charging", buffer, 8)) {
1922 memmove(buffer + 1, buffer + 8, n - 8);
1923 } else if (0 == strncmp("discharging", buffer, 11)) {
1925 memmove(buffer + 1, buffer + 11, n - 11);
1926 } else if (0 == strncmp("charged", buffer, 7)) {
1928 memmove(buffer + 1, buffer + 7, n - 7);
1929 } else if (0 == strncmp("not present", buffer, 11)) {
1931 memmove(buffer + 1, buffer + 11, n - 11);
1932 } else if (0 == strncmp("empty", buffer, 5)) {
1934 memmove(buffer + 1, buffer + 5, n - 5);
1935 } else if (0 != strncmp("AC", buffer, 2)) {
1937 memmove(buffer + 1, buffer + 11, n - 11);
1941 int get_battery_perct(const char *bat)
1945 char acpi_path[128];
1946 char sysfs_path[128];
1947 int remaining_capacity = -1;
1949 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1950 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1954 idx = get_battery_idx(bat);
1956 /* don't update battery too often */
1957 if (current_update_time - last_battery_perct_time[idx] < 30) {
1958 return last_battery_perct[idx];
1960 last_battery_perct_time[idx] = current_update_time;
1962 /* Only check for SYSFS or ACPI */
1964 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1965 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1969 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1970 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1973 if (sysfs_bat_fp[idx] != NULL) {
1975 while (!feof(sysfs_bat_fp[idx])) {
1977 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1980 if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0) {
1981 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1982 } else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=",25) == 0) {
1983 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_design_capacity[idx]);
1984 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0) {
1985 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1986 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=",25) == 0) {
1987 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_design_capacity[idx]);
1991 fclose(sysfs_bat_fp[idx]);
1992 sysfs_bat_fp[idx] = NULL;
1994 } else if (acpi_bat_fp[idx] != NULL) {
1996 /* read last full capacity if it's zero */
1997 if (acpi_design_capacity[idx] == 0) {
2002 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
2003 fp = open_file(path, &rep2);
2008 if (fgets(b, 256, fp) == NULL) {
2011 if (sscanf(b, "last full capacity: %d",
2012 &acpi_design_capacity[idx]) != 0) {
2020 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
2022 while (!feof(acpi_bat_fp[idx])) {
2025 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
2029 if (buf[0] == 'r') {
2030 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
2034 if (remaining_capacity < 0) {
2037 /* compute the battery percentage */
2038 last_battery_perct[idx] =
2039 (int) (((float) remaining_capacity / acpi_design_capacity[idx]) * 100);
2040 if (last_battery_perct[idx] > 100) last_battery_perct[idx] = 100;
2041 return last_battery_perct[idx];
2044 int get_battery_perct_bar(const char *bar)
2048 get_battery_perct(bar);
2049 idx = get_battery_idx(bar);
2050 return (int) (last_battery_perct[idx] * 2.56 - 1);
2053 /* On Apple powerbook and ibook:
2054 $ cat /proc/pmu/battery_0
2061 $ cat /proc/pmu/info
2062 PMU driver version : 2
2063 PMU firmware version : 0c
2068 /* defines as in <linux/pmu.h> */
2069 #define PMU_BATT_PRESENT 0x00000001
2070 #define PMU_BATT_CHARGING 0x00000002
2072 static FILE *pmu_battery_fp;
2073 static FILE *pmu_info_fp;
2074 static char pb_battery_info[3][32];
2075 static double pb_battery_info_update;
2077 #define PMU_PATH "/proc/pmu"
2078 void get_powerbook_batt_info(char *buffer, size_t n, int i)
2081 const char *batt_path = PMU_PATH "/battery_0";
2082 const char *info_path = PMU_PATH "/info";
2084 int charge, max_charge, ac = -1;
2087 /* don't update battery too often */
2088 if (current_update_time - pb_battery_info_update < 29.5) {
2089 snprintf(buffer, n, "%s", pb_battery_info[i]);
2092 pb_battery_info_update = current_update_time;
2094 if (pmu_battery_fp == NULL) {
2095 pmu_battery_fp = open_file(batt_path, &rep);
2096 if (pmu_battery_fp == NULL) {
2101 if (pmu_battery_fp != NULL) {
2102 rewind(pmu_battery_fp);
2103 while (!feof(pmu_battery_fp)) {
2106 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL) {
2110 if (buf[0] == 'f') {
2111 sscanf(buf, "flags : %8x", &flags);
2112 } else if (buf[0] == 'c' && buf[1] == 'h') {
2113 sscanf(buf, "charge : %d", &charge);
2114 } else if (buf[0] == 'm') {
2115 sscanf(buf, "max_charge : %d", &max_charge);
2116 } else if (buf[0] == 't') {
2117 sscanf(buf, "time rem. : %ld", &timeval);
2121 if (pmu_info_fp == NULL) {
2122 pmu_info_fp = open_file(info_path, &rep);
2123 if (pmu_info_fp == NULL) {
2128 if (pmu_info_fp != NULL) {
2129 rewind(pmu_info_fp);
2130 while (!feof(pmu_info_fp)) {
2133 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL) {
2136 if (buf[0] == 'A') {
2137 sscanf(buf, "AC Power : %d", &ac);
2141 /* update status string */
2142 if ((ac && !(flags & PMU_BATT_PRESENT))) {
2143 strncpy(pb_battery_info[PB_BATT_STATUS], "AC", sizeof(pb_battery_info[PB_BATT_STATUS]));
2144 } else if (ac && (flags & PMU_BATT_PRESENT)
2145 && !(flags & PMU_BATT_CHARGING)) {
2146 strncpy(pb_battery_info[PB_BATT_STATUS], "charged", sizeof(pb_battery_info[PB_BATT_STATUS]));
2147 } else if ((flags & PMU_BATT_PRESENT) && (flags & PMU_BATT_CHARGING)) {
2148 strncpy(pb_battery_info[PB_BATT_STATUS], "charging", sizeof(pb_battery_info[PB_BATT_STATUS]));
2150 strncpy(pb_battery_info[PB_BATT_STATUS], "discharging", sizeof(pb_battery_info[PB_BATT_STATUS]));
2153 /* update percentage string */
2154 if (timeval == 0 && ac && (flags & PMU_BATT_PRESENT)
2155 && !(flags & PMU_BATT_CHARGING)) {
2156 snprintf(pb_battery_info[PB_BATT_PERCENT],
2157 sizeof(pb_battery_info[PB_BATT_PERCENT]), "100%%");
2158 } else if (timeval == 0) {
2159 snprintf(pb_battery_info[PB_BATT_PERCENT],
2160 sizeof(pb_battery_info[PB_BATT_PERCENT]), "unknown");
2162 snprintf(pb_battery_info[PB_BATT_PERCENT],
2163 sizeof(pb_battery_info[PB_BATT_PERCENT]), "%d%%",
2164 (charge * 100) / max_charge);
2167 /* update time string */
2168 if (timeval == 0) { /* fully charged or battery not present */
2169 snprintf(pb_battery_info[PB_BATT_TIME],
2170 sizeof(pb_battery_info[PB_BATT_TIME]), "unknown");
2171 } else if (timeval < 60 * 60) { /* don't show secs */
2172 format_seconds_short(pb_battery_info[PB_BATT_TIME],
2173 sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2175 format_seconds(pb_battery_info[PB_BATT_TIME],
2176 sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2179 snprintf(buffer, n, "%s", pb_battery_info[i]);
2182 void update_top(void)
2184 process_find_top(info.cpu, info.memu, info.time
2189 info.first_process = get_first_process();
2192 #define ENTROPY_AVAIL_PATH "/proc/sys/kernel/random/entropy_avail"
2194 int get_entropy_avail(unsigned int *val)
2199 if (!(fp = open_file(ENTROPY_AVAIL_PATH, &rep)))
2202 if (fscanf(fp, "%u", val) != 1)
2209 #define ENTROPY_POOLSIZE_PATH "/proc/sys/kernel/random/poolsize"
2211 int get_entropy_poolsize(unsigned int *val)
2216 if (!(fp = open_file(ENTROPY_POOLSIZE_PATH, &rep)))
2219 if (fscanf(fp, "%u", val) != 1)
2226 const char *get_disk_protect_queue(const char *disk)
2232 snprintf(path, 127, "/sys/block/%s/device/unload_heads", disk);
2233 if (access(path, F_OK)) {
2234 snprintf(path, 127, "/sys/block/%s/queue/protect", disk);
2236 if ((fp = fopen(path, "r")) == NULL)
2238 if (fscanf(fp, "%d\n", &state) != 1) {
2243 return (state > 0) ? "frozen" : "free ";
2246 void update_diskio(void)
2250 char buf[512], devbuf[64];
2251 unsigned int major, minor;
2253 struct diskio_stat *cur;
2254 unsigned int reads, writes;
2255 unsigned int total_reads = 0, total_writes = 0;
2258 stats.current_read = 0;
2259 stats.current_write = 0;
2261 if (!(fp = open_file("/proc/diskstats", &rep))) {
2265 /* read reads and writes from all disks (minor = 0), including cd-roms
2266 * and floppies, and sum them up */
2267 while (fgets(buf, 512, fp)) {
2268 col_count = sscanf(buf, "%u %u %s %*u %*u %u %*u %*u %*u %u", &major,
2269 &minor, devbuf, &reads, &writes);
2270 /* ignore subdevices (they have only 3 matching entries in their line)
2271 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
2273 * XXX: ignore devices which are part of a SW RAID (MD_MAJOR) */
2274 if (col_count == 5 && major != LVM_BLK_MAJOR && major != NBD_MAJOR
2275 && major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
2276 total_reads += reads;
2277 total_writes += writes;
2279 col_count = sscanf(buf, "%u %u %s %*u %u %*u %u",
2280 &major, &minor, devbuf, &reads, &writes);
2281 if (col_count != 5) {
2286 while (cur && strcmp(devbuf, cur->dev))
2290 update_diskio_values(cur, reads, writes);
2292 update_diskio_values(&stats, total_reads, total_writes);