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-2009 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>
67 /* The following ifdefs were adapted from gkrellm */
68 #include <linux/major.h>
70 #if !defined(MD_MAJOR)
74 #if !defined(LVM_BLK_MAJOR)
75 #define LVM_BLK_MAJOR 58
78 #if !defined(NBD_MAJOR)
94 #define SHORTSTAT_TEMPL "%*s %llu %llu %llu"
95 #define LONGSTAT_TEMPL "%*s %llu %llu %llu "
97 /* This flag tells the linux routines to use the /proc system where possible,
98 * even if other api's are available, e.g. sysinfo() or getloadavg().
99 * the reason for this is to allow for /proc-based distributed monitoring.
100 * using a flag in this manner creates less confusing code. */
101 static int prefer_proc = 0;
103 void prepare_update(void)
107 void update_uptime(void)
111 struct sysinfo s_info;
114 info.uptime = (double) s_info.uptime;
121 if (!(fp = open_file("/proc/uptime", &rep))) {
125 fscanf(fp, "%lf", &info.uptime);
130 int check_mount(char *s)
133 FILE *mtab = fopen("/etc/mtab", "r");
136 char buf1[256], buf2[128];
138 while (fgets(buf1, 256, mtab)) {
139 sscanf(buf1, "%*s %128s", buf2);
140 if (!strcmp(s, buf2)) {
147 NORM_ERR("Could not open mtab");
152 /* these things are also in sysinfo except Buffers:
153 * (that's why I'm reading them from proc) */
155 void update_meminfo(void)
160 /* unsigned int a; */
163 info.mem = info.memmax = info.swap = info.swapfree = info.swapmax = info.bufmem =
164 info.buffers = info.cached = info.memfree = info.memeasyfree = 0;
166 if (!(meminfo_fp = open_file("/proc/meminfo", &rep))) {
170 while (!feof(meminfo_fp)) {
171 if (fgets(buf, 255, meminfo_fp) == NULL) {
175 if (strncmp(buf, "MemTotal:", 9) == 0) {
176 sscanf(buf, "%*s %llu", &info.memmax);
177 } else if (strncmp(buf, "MemFree:", 8) == 0) {
178 sscanf(buf, "%*s %llu", &info.memfree);
179 } else if (strncmp(buf, "SwapTotal:", 10) == 0) {
180 sscanf(buf, "%*s %llu", &info.swapmax);
181 } else if (strncmp(buf, "SwapFree:", 9) == 0) {
182 sscanf(buf, "%*s %llu", &info.swapfree);
183 } else if (strncmp(buf, "Buffers:", 8) == 0) {
184 sscanf(buf, "%*s %llu", &info.buffers);
185 } else if (strncmp(buf, "Cached:", 7) == 0) {
186 sscanf(buf, "%*s %llu", &info.cached);
190 info.mem = info.memmax - info.memfree;
191 info.memeasyfree = info.memfree;
192 info.swap = info.swapmax - info.swapfree;
194 info.bufmem = info.cached + info.buffers;
199 int get_laptop_mode(void)
204 if ((fp = fopen("/proc/sys/vm/laptop_mode", "r")) != NULL)
205 fscanf(fp, "%d\n", &val);
211 * # cat /sys/block/sda/queue/scheduler
212 * noop [anticipatory] cfq
214 char *get_ioscheduler(char *disk)
220 return strndup("n/a", text_buffer_size);
222 snprintf(buf, 127, "/sys/block/%s/queue/scheduler", disk);
223 if ((fp = fopen(buf, "r")) == NULL) {
224 return strndup("n/a", text_buffer_size);
227 fscanf(fp, "%127s", buf);
229 buf[strlen(buf) - 1] = '\0';
231 return strndup(buf + 1, text_buffer_size);
235 return strndup("n/a", text_buffer_size);
244 #define COND_FREE(x) if(x) free(x); x = 0
245 #define SAVE_SET_STRING(x, y) \
246 if (x && strcmp((char *)x, (char *)y)) { \
248 x = strndup("multiple", text_buffer_size); \
250 x = strndup(y, text_buffer_size); \
253 void update_gateway_info_failure(const char *reason)
258 //2 pointers to 1 location causes a crash when we try to free them both
259 gw_info.iface = strndup("failed", text_buffer_size);
260 gw_info.ip = strndup("failed", text_buffer_size);
264 /* Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT */
265 #define RT_ENTRY_FORMAT "%63s %lx %lx %x %*d %*d %*d %lx %*d %*d %*d\n"
267 void update_gateway_info(void)
272 unsigned long dest, gate, mask;
275 COND_FREE(gw_info.iface);
276 COND_FREE(gw_info.ip);
279 if ((fp = fopen("/proc/net/route", "r")) == NULL) {
280 update_gateway_info_failure("fopen()");
284 /* skip over the table header line, which is always present */
285 fscanf(fp, "%*[^\n]\n");
288 if(fscanf(fp, RT_ENTRY_FORMAT,
289 iface, &dest, &gate, &flags, &mask) != 5) {
290 update_gateway_info_failure("fscanf()");
293 if (!(dest || mask) && ((flags & RTF_GATEWAY) || !gate) ) {
295 SAVE_SET_STRING(gw_info.iface, iface)
297 SAVE_SET_STRING(gw_info.ip, inet_ntoa(ina))
304 void free_gateway_info(void)
310 memset(&gw_info, 0, sizeof(gw_info));
313 int gateway_exists(void)
315 return !!gw_info.count;
318 void print_gateway_iface(char *p, int p_max_size)
320 snprintf(p, p_max_size, "%s", gw_info.iface);
323 void print_gateway_ip(char *p, int p_max_size)
325 snprintf(p, p_max_size, "%s", gw_info.ip);
328 void update_net_stats(void)
332 static char first = 1;
334 // FIXME: arbitrary size chosen to keep code simple.
336 unsigned int curtmp1, curtmp2;
343 // wireless info variables
344 int skfd, has_bitrate = 0;
345 struct wireless_info *winfo;
350 delta = current_update_time - last_update_time;
351 if (delta <= 0.0001) {
355 /* open file and ignore first two lines */
356 if (!(net_dev_fp = open_file("/proc/net/dev", &rep))) {
361 fgets(buf, 255, net_dev_fp); /* garbage */
362 fgets(buf, 255, net_dev_fp); /* garbage (field names) */
364 /* read each interface */
365 for (i2 = 0; i2 < MAX_NET_INTERFACES; i2++) {
369 long long r, t, last_recv, last_trans;
371 if (fgets(buf, 255, net_dev_fp) == NULL) {
375 while (isspace((int) *p)) {
381 while (*p && *p != ':') {
390 ns = get_net_stat(s, NULL, NULL);
392 memset(&(ns->addr.sa_data), 0, 14);
394 memset(ns->addrs, 0, 17 * MAX_NET_INTERFACES + 1); /* Up to 17 chars per ip, max MAX_NET_INTERFACES interfaces. Nasty memory usage... */
396 last_recv = ns->recv;
397 last_trans = ns->trans;
399 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
400 sscanf(p, "%lld %*d %*d %*d %*d %*d %*d %*d %lld",
403 /* if recv or trans is less than last time, an overflow happened */
404 if (r < ns->last_read_recv) {
407 ns->recv += (r - ns->last_read_recv);
409 ns->last_read_recv = r;
411 if (t < ns->last_read_trans) {
414 ns->trans += (t - ns->last_read_trans);
416 ns->last_read_trans = t;
418 /*** ip addr patch ***/
419 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
421 conf.ifc_buf = malloc(sizeof(struct ifreq) * MAX_NET_INTERFACES);
422 conf.ifc_len = sizeof(struct ifreq) * MAX_NET_INTERFACES;
423 memset(conf.ifc_buf, 0, conf.ifc_len);
425 ioctl((long) i, SIOCGIFCONF, &conf);
427 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
428 struct net_stat *ns2;
430 if (!(((struct ifreq *) conf.ifc_buf) + k))
434 ((struct ifreq *) conf.ifc_buf)[k].ifr_ifrn.ifrn_name, NULL, NULL);
435 ns2->addr = ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.ifru_addr;
436 sprintf(temp_addr, "%u.%u.%u.%u, ",
437 ns2->addr.sa_data[2] & 255,
438 ns2->addr.sa_data[3] & 255,
439 ns2->addr.sa_data[4] & 255,
440 ns2->addr.sa_data[5] & 255);
441 if(NULL == strstr(ns2->addrs, temp_addr))
442 strncpy(ns2->addrs + strlen(ns2->addrs), temp_addr, 17);
449 /*** end ip addr patch ***/
452 /* calculate speeds */
453 ns->net_rec[0] = (ns->recv - last_recv) / delta;
454 ns->net_trans[0] = (ns->trans - last_trans) / delta;
461 #pragma omp parallel for reduction(+:curtmp1, curtmp2) schedule(dynamic,10)
462 #endif /* HAVE_OPENMP */
463 for (i = 0; i < info.net_avg_samples; i++) {
464 curtmp1 = curtmp1 + ns->net_rec[i];
465 curtmp2 = curtmp2 + ns->net_trans[i];
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) {
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];
486 /* update wireless info */
487 winfo = malloc(sizeof(struct wireless_info));
488 memset(winfo, 0, sizeof(struct wireless_info));
490 skfd = iw_sockets_open();
491 if (iw_get_basic_config(skfd, s, &(winfo->b)) > -1) {
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;
498 if (iw_get_range_info(skfd, s, &(winfo->range)) >= 0) {
499 winfo->has_range = 1;
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));
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);
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;
524 if (winfo->has_ap_addr) {
525 iw_sawap_ntop(&winfo->ap_addr, ns->ap);
529 if (winfo->b.has_essid) {
530 if (winfo->b.essid_on) {
531 snprintf(ns->essid, 32, "%s", winfo->b.essid);
533 snprintf(ns->essid, 32, "off/any");
537 snprintf(ns->mode, 16, "%s", iw_operation_mode[winfo->b.mode]);
539 iw_sockets_close(skfd);
550 void update_total_processes(void)
553 struct dirent *entry;
558 if (!(dir = opendir("/proc"))) {
561 while ((entry = readdir(dir))) {
563 /* Problem reading list of processes */
568 if (sscanf(entry->d_name, "%d%c", &ignore1, &ignore2) == 1) {
575 void update_threads(void)
579 struct sysinfo s_info;
582 info.threads = s_info.procs;
589 if (!(fp = open_file("/proc/loadavg", &rep))) {
593 fscanf(fp, "%*f %*f %*f %*d/%hu", &info.threads);
598 #define CPU_SAMPLE_COUNT 15
600 unsigned long long cpu_user;
601 unsigned long long cpu_system;
602 unsigned long long cpu_nice;
603 unsigned long long cpu_idle;
604 unsigned long long cpu_iowait;
605 unsigned long long cpu_irq;
606 unsigned long long cpu_softirq;
607 unsigned long long cpu_steal;
608 unsigned long long cpu_total;
609 unsigned long long cpu_active_total;
610 unsigned long long cpu_last_total;
611 unsigned long long cpu_last_active_total;
612 double cpu_val[CPU_SAMPLE_COUNT];
614 static short cpu_setup = 0;
616 /* Determine if this kernel gives us "extended" statistics information in
618 * Kernels around 2.5 and earlier only reported user, system, nice, and
619 * idle values in proc stat.
620 * Kernels around 2.6 and greater report these PLUS iowait, irq, softirq,
622 void determine_longstat(char *buf)
624 unsigned long long iowait = 0;
626 KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
627 /* scanf will either return -1 or 1 because there is only 1 assignment */
628 if (sscanf(buf, "%*s %*d %*d %*d %*d %llu", &iowait) > 0) {
629 KFLAG_SETON(KFLAG_IS_LONGSTAT);
633 void get_cpu_count(void)
639 if (info.cpu_usage) {
643 if (!(stat_fp = open_file("/proc/stat", &rep))) {
649 while (!feof(stat_fp)) {
650 if (fgets(buf, 255, stat_fp) == NULL) {
654 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
655 if (info.cpu_count == 0) {
656 determine_longstat(buf);
661 info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
666 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
667 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
669 void update_stat(void)
673 static struct cpu_info *cpu = NULL;
678 const char *stat_template = NULL;
679 unsigned int malloc_cpu_size = 0;
680 extern void* global_cpu;
681 static double last_stat_update = 0.0;
683 /* since we use wrappers for this function, the update machinery
684 * can't eliminate double invocations of this function. Check for
685 * them here, otherwise cpu_usage counters are freaking out. */
686 if (last_stat_update == current_update_time)
688 last_stat_update = current_update_time;
690 /* add check for !info.cpu_usage since that mem is freed on a SIGUSR1 */
691 if (!cpu_setup || !info.cpu_usage) {
696 if (!stat_template) {
698 KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT;
702 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
703 cpu = malloc(malloc_cpu_size);
704 memset(cpu, 0, malloc_cpu_size);
708 if (!(stat_fp = open_file("/proc/stat", &rep))) {
709 info.run_threads = 0;
710 if (info.cpu_usage) {
711 memset(info.cpu_usage, 0, info.cpu_count * sizeof(float));
717 while (!feof(stat_fp)) {
718 if (fgets(buf, 255, stat_fp) == NULL) {
722 if (strncmp(buf, "procs_running ", 14) == 0) {
723 sscanf(buf, "%*s %hu", &info.run_threads);
724 } else if (strncmp(buf, "cpu", 3) == 0) {
726 if (isdigit(buf[3])) {
727 idx = atoi(&buf[3]) + 1;
731 sscanf(buf, stat_template, &(cpu[idx].cpu_user),
732 &(cpu[idx].cpu_nice), &(cpu[idx].cpu_system),
733 &(cpu[idx].cpu_idle), &(cpu[idx].cpu_iowait),
734 &(cpu[idx].cpu_irq), &(cpu[idx].cpu_softirq),
735 &(cpu[idx].cpu_steal));
737 cpu[idx].cpu_total = cpu[idx].cpu_user + cpu[idx].cpu_nice +
738 cpu[idx].cpu_system + cpu[idx].cpu_idle +
739 cpu[idx].cpu_iowait + cpu[idx].cpu_irq +
740 cpu[idx].cpu_softirq + cpu[idx].cpu_steal;
742 cpu[idx].cpu_active_total = cpu[idx].cpu_total -
743 (cpu[idx].cpu_idle + cpu[idx].cpu_iowait);
745 delta = current_update_time - last_update_time;
747 if (delta <= 0.001) {
751 cpu[idx].cpu_val[0] = (cpu[idx].cpu_active_total -
752 cpu[idx].cpu_last_active_total) /
753 (float) (cpu[idx].cpu_total - cpu[idx].cpu_last_total);
756 #pragma omp parallel for reduction(+:curtmp) schedule(dynamic,10)
757 #endif /* HAVE_OPENMP */
758 for (i = 0; i < info.cpu_avg_samples; i++) {
759 curtmp = curtmp + cpu[idx].cpu_val[i];
761 /* TESTING -- I've removed this, because I don't think it is right.
762 * You shouldn't divide by the cpu count here ...
763 * removing for testing */
765 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples /
768 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples;
770 /* TESTING -- this line replaces the prev. "suspect" if/else */
771 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples;
773 cpu[idx].cpu_last_total = cpu[idx].cpu_total;
774 cpu[idx].cpu_last_active_total = cpu[idx].cpu_active_total;
776 #pragma omp parallel for schedule(dynamic,10)
777 #endif /* HAVE_OPENMP */
778 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
779 cpu[idx].cpu_val[i] = cpu[idx].cpu_val[i - 1];
786 void update_running_processes(void)
791 void update_cpu_usage(void)
796 void update_load_average(void)
798 #ifdef HAVE_GETLOADAVG
803 info.loadavg[0] = (float) v[0];
804 info.loadavg[1] = (float) v[1];
805 info.loadavg[2] = (float) v[2];
812 if (!(fp = open_file("/proc/loadavg", &rep))) {
813 info.loadavg[0] = info.loadavg[1] = info.loadavg[2] = 0.0;
816 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1],
822 /***********************************************************/
823 /***********************************************************/
824 /***********************************************************/
826 static int no_dots(const struct dirent *d)
828 if (d->d_name[0] == '.') {
834 static int get_first_file_in_a_directory(const char *dir, char *s, int *rep)
836 struct dirent **namelist;
839 n = scandir(dir, &namelist, no_dots, alphasort);
842 NORM_ERR("scandir for %s: %s", dir, strerror(errno));
853 strncpy(s, namelist[0]->d_name, 255);
857 #pragma omp parallel for schedule(dynamic,10)
858 #endif /* HAVE_OPENMP */
859 for (i = 0; i < n; i++) {
868 static int open_sysfs_sensor(const char *dir, const char *dev, const char *type, int n,
869 int *divisor, char *devtype)
876 memset(buf, 0, sizeof(buf));
878 /* if device is NULL or *, get first */
879 if (dev == NULL || strcmp(dev, "*") == 0) {
882 if (!get_first_file_in_a_directory(dir, buf, &rep)) {
888 if (strcmp(dir, "/sys/class/hwmon/") == 0) {
890 /* buf holds result from get_first_file_in_a_directory() above,
891 * e.g. "hwmon0" -- append "/device" */
892 strcat(buf, "/device");
894 /* dev holds device number N as a string,
895 * e.g. "0", -- convert to "hwmon0/device" */
896 sprintf(buf, "hwmon%s/device", dev);
901 /* change vol to in, tempf to temp */
902 if (strcmp(type, "vol") == 0) {
904 } else if (strcmp(type, "tempf") == 0) {
909 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, type, n);
911 /* first, attempt to open file in /device */
912 fd = open(path, O_RDONLY);
915 /* if it fails, strip the /device from dev and attempt again */
916 buf[strlen(buf) - 7] = 0;
917 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, type, n);
918 fd = open(path, O_RDONLY);
920 CRIT_ERR(NULL, NULL, "can't open '%s': %s\nplease check your device or remove this "
921 "var from "PACKAGE_NAME, path, strerror(errno));
925 strncpy(devtype, path, 255);
927 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
928 || strcmp(type, "tempf") == 0) {
933 /* fan does not use *_div as a read divisor */
934 if (strcmp("fan", type) == 0) {
938 /* test if *_div file exist, open it and use it as divisor */
939 if (strcmp(type, "tempf") == 0) {
940 snprintf(path, 255, "%s%s/%s%d_div", dir, "one", "two", n);
942 snprintf(path, 255, "%s%s/%s%d_div", dir, dev, type, n);
945 divfd = open(path, O_RDONLY);
951 divn = read(divfd, divbuf, 63);
952 /* should read until n == 0 but I doubt that kernel will give these
953 * in multiple pieces. :) */
955 NORM_ERR("open_sysfs_sensor(): can't read from sysfs");
958 *divisor = atoi(divbuf);
966 static double get_sysfs_info(int *fd, int divisor, char *devtype, char *type)
974 lseek(*fd, 0, SEEK_SET);
980 n = read(*fd, buf, 63);
981 /* should read until n == 0 but I doubt that kernel will give these
982 * in multiple pieces. :) */
984 NORM_ERR("get_sysfs_info(): read from %s failed\n", devtype);
993 *fd = open(devtype, O_RDONLY);
995 NORM_ERR("can't open '%s': %s", devtype, strerror(errno));
998 /* My dirty hack for computing CPU value
999 * Filedil, from forums.gentoo.org */
1000 /* if (strstr(devtype, "temp1_input") != NULL) {
1001 return -15.096 + 1.4893 * (val / 1000.0);
1004 /* divide voltage and temperature by 1000 */
1005 /* or if any other divisor is given, use that */
1006 if (strcmp(type, "tempf") == 0) {
1008 return ((val / divisor + 40) * 9.0 / 5) - 40;
1009 } else if (divisor) {
1010 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
1012 return ((val + 40) * 9.0 / 5) - 40;
1016 return val / divisor;
1017 } else if (divisor) {
1018 return val / 1000.0;
1025 #define HWMON_RESET() {\
1030 static void parse_sysfs_sensor(struct text_object *obj, const char *arg, const char *path, const char *type)
1032 char buf1[64], buf2[64];
1033 float factor, offset;
1037 if (sscanf(arg, "%63s %d %f %f", buf2, &n, &factor, &offset) == 4) found = 1; else HWMON_RESET();
1038 if (!found && sscanf(arg, "%63s %63s %d %f %f", buf1, buf2, &n, &factor, &offset) == 5) found = 1; else if (!found) HWMON_RESET();
1039 if (!found && sscanf(arg, "%63s %63s %d", buf1, buf2, &n) == 3) found = 1; else if (!found) HWMON_RESET();
1040 if (!found && sscanf(arg, "%63s %d", buf2, &n) == 2) found = 1; else if (!found) HWMON_RESET();
1043 NORM_ERR("i2c failed to parse arguments");
1044 obj->type = OBJ_text;
1047 DBGP("parsed %s args: '%s' '%s' %d %f %f\n", type, buf1, buf2, n, factor, offset);
1048 sf = malloc(sizeof(struct sysfs));
1049 memset(sf, 0, sizeof(struct sysfs));
1050 sf->fd = open_sysfs_sensor(path, (*buf1) ? buf1 : 0, buf2, n,
1051 &sf->arg, sf->devtype);
1052 strncpy(sf->type, buf2, 63);
1053 sf->factor = factor;
1054 sf->offset = offset;
1055 obj->data.opaque = sf;
1058 #define PARSER_GENERATOR(name, path) \
1059 void parse_##name##_sensor(struct text_object *obj, const char *arg) \
1061 parse_sysfs_sensor(obj, arg, path, #name); \
1064 PARSER_GENERATOR(i2c, "/sys/bus/i2c/devices/")
1065 PARSER_GENERATOR(hwmon, "/sys/class/hwmon/")
1066 PARSER_GENERATOR(platform, "/sys/bus/platform/devices/")
1068 void print_sysfs_sensor(struct text_object *obj, char *p, int p_max_size)
1071 struct sysfs *sf = obj->data.opaque;
1076 r = get_sysfs_info(&sf->fd, sf->arg,
1077 sf->devtype, sf->type);
1079 r = r * sf->factor + sf->offset;
1081 if (!strncmp(sf->type, "temp", 4)) {
1082 temp_print(p, p_max_size, r, TEMP_CELSIUS);
1083 } else if (r >= 100.0 || r == 0) {
1084 snprintf(p, p_max_size, "%d", (int) r);
1086 snprintf(p, p_max_size, "%.1f", r);
1090 void free_sysfs_sensor(struct text_object *obj)
1092 struct sysfs *sf = obj->data.opaque;
1098 free(obj->data.opaque);
1099 obj->data.opaque = NULL;
1102 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
1103 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
1105 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1106 char get_freq(char *p_client_buffer, size_t client_buffer_size,
1107 const char *p_format, int divisor, unsigned int cpu)
1115 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1121 char current_freq_file[128];
1123 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu - 1,
1125 f = fopen(current_freq_file, "r");
1127 /* if there's a cpufreq /sys node, read the current frequency from
1128 * this node and divide by 1000 to get Mhz. */
1129 if (fgets(s, sizeof(s), f)) {
1130 s[strlen(s) - 1] = '\0';
1131 freq = strtod(s, NULL);
1134 snprintf(p_client_buffer, client_buffer_size, p_format,
1135 (freq / 1000) / divisor);
1140 // open the CPU information file
1141 f = open_file("/proc/cpuinfo", &rep);
1143 perror(PACKAGE_NAME": Failed to access '/proc/cpuinfo' at get_freq()");
1148 while (fgets(s, sizeof(s), f) != NULL) {
1150 #if defined(__i386) || defined(__x86_64)
1151 // and search for the cpu mhz
1152 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) {
1154 #if defined(__alpha)
1155 // different on alpha
1156 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) {
1158 // this is different on ppc for some reason
1159 if (strncmp(s, "clock", 5) == 0 && cpu == 0) {
1160 #endif // defined(__alpha)
1161 #endif // defined(__i386) || defined(__x86_64)
1163 // copy just the number
1164 strcpy(frequency, strchr(s, ':') + 2);
1165 #if defined(__alpha)
1167 frequency[strlen(frequency) - 6] = '\0';
1168 // kernel reports in Hz
1169 freq = strtod(frequency, NULL) / 1000000;
1172 frequency[strlen(frequency) - 1] = '\0';
1173 freq = strtod(frequency, NULL);
1177 if (strncmp(s, "processor", 9) == 0) {
1184 snprintf(p_client_buffer, client_buffer_size, p_format,
1185 (float) freq / divisor);
1189 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
1191 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks something
1201 * Peter Tarjan (ptarjan@citromail.hu) */
1203 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
1204 static char get_voltage(char *p_client_buffer, size_t client_buffer_size,
1205 const char *p_format, int divisor, unsigned int cpu)
1211 char current_freq_file[128];
1214 /* build the voltage file name */
1216 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1219 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1224 /* read the current cpu frequency from the /sys node */
1225 f = fopen(current_freq_file, "r");
1227 if (fgets(s, sizeof(s), f)) {
1228 s[strlen(s) - 1] = '\0';
1229 freq = strtod(s, NULL);
1233 fprintf(stderr, PACKAGE_NAME": Failed to access '%s' at ", current_freq_file);
1234 perror("get_voltage()");
1241 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1244 /* use the current cpu frequency to find the corresponding voltage */
1245 f = fopen(current_freq_file, "r");
1251 if (fgets(line, 255, f) == NULL) {
1254 sscanf(line, "%d %d", &freq_comp, &voltage);
1255 if (freq_comp == freq) {
1261 fprintf(stderr, PACKAGE_NAME": Failed to access '%s' at ", current_freq_file);
1262 perror("get_voltage()");
1268 snprintf(p_client_buffer, client_buffer_size, p_format,
1269 (float) voltage / divisor);
1273 void print_voltage_mv(struct text_object *obj, char *p, int p_max_size)
1277 ok = get_voltage(p, p_max_size, "%.0f", 1, obj->data.i);
1281 void print_voltage_v(struct text_object *obj, char *p, int p_max_size)
1285 ok = get_voltage(p, p_max_size, "%'.3f", 1000, obj->data.i);
1289 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1291 void get_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
1298 if (!p_client_buffer || client_buffer_size <= 0) {
1302 /* yeah, slow... :/ */
1303 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep)) {
1304 snprintf(p_client_buffer, client_buffer_size, "no fans?");
1308 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf);
1310 fp = open_file(buf2, &rep);
1312 snprintf(p_client_buffer, client_buffer_size,
1313 "can't open fan's state file");
1316 memset(buf, 0, sizeof(buf));
1317 fscanf(fp, "%*s %99s", buf);
1320 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1323 #define SYSFS_AC_ADAPTER_DIR "/sys/class/power_supply/AC"
1324 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1325 /* Linux 2.6.25 onwards ac adapter info is in
1326 /sys/class/power_supply/AC/
1327 On my system I get the following.
1328 /sys/class/power_supply/AC/uevent:
1329 PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A08:00/device:01/PNP0C09:00/ACPI0003:00
1332 POWER_SUPPLY_NAME=AC
1333 POWER_SUPPLY_TYPE=Mains
1334 POWER_SUPPLY_ONLINE=1
1337 void get_acpi_ac_adapter(char *p_client_buffer, size_t client_buffer_size)
1345 if (!p_client_buffer || client_buffer_size <= 0) {
1349 snprintf(buf2, sizeof(buf2), "%s/uevent", SYSFS_AC_ADAPTER_DIR);
1350 fp = open_file(buf2, &rep);
1352 /* sysfs processing */
1354 if (fgets(buf, sizeof(buf), fp) == NULL)
1357 if (strncmp(buf, "POWER_SUPPLY_ONLINE=", 20) == 0) {
1359 sscanf(buf, "POWER_SUPPLY_ONLINE=%d", &online);
1360 snprintf(p_client_buffer, client_buffer_size,
1361 "%s-line", (online ? "on" : "off"));
1367 /* yeah, slow... :/ */
1368 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep)) {
1369 snprintf(p_client_buffer, client_buffer_size, "no ac_adapters?");
1373 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf);
1375 fp = open_file(buf2, &rep);
1377 snprintf(p_client_buffer, client_buffer_size,
1378 "No ac adapter found.... where is it?");
1381 memset(buf, 0, sizeof(buf));
1382 fscanf(fp, "%*s %99s", buf);
1385 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1390 /proc/acpi/thermal_zone/THRM/cooling_mode
1391 cooling mode: active
1392 /proc/acpi/thermal_zone/THRM/polling_frequency
1394 /proc/acpi/thermal_zone/THRM/state
1396 /proc/acpi/thermal_zone/THRM/temperature
1398 /proc/acpi/thermal_zone/THRM/trip_points
1400 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1403 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1404 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1406 int open_acpi_temperature(const char *name)
1412 if (name == NULL || strcmp(name, "*") == 0) {
1415 if (!get_first_file_in_a_directory(ACPI_THERMAL_DIR, buf, &rep)) {
1421 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1423 fd = open(path, O_RDONLY);
1425 NORM_ERR("can't open '%s': %s", path, strerror(errno));
1431 static double last_acpi_temp;
1432 static double last_acpi_temp_time;
1434 double get_acpi_temperature(int fd)
1440 /* don't update acpi temperature too often */
1441 if (current_update_time - last_acpi_temp_time < 11.32) {
1442 return last_acpi_temp;
1444 last_acpi_temp_time = current_update_time;
1446 /* seek to beginning */
1447 lseek(fd, 0, SEEK_SET);
1454 n = read(fd, buf, 255);
1456 NORM_ERR("can't read fd %d: %s", fd, strerror(errno));
1459 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1463 return last_acpi_temp;
1467 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1469 design capacity: 4400 mAh
1470 last full capacity: 4064 mAh
1471 battery technology: rechargeable
1472 design voltage: 14800 mV
1473 design capacity warning: 300 mAh
1474 design capacity low: 200 mAh
1475 capacity granularity 1: 32 mAh
1476 capacity granularity 2: 32 mAh
1478 serial number: 16922
1484 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1487 charging state: unknown
1489 remaining capacity: 4064 mAh
1490 present voltage: 16608 mV
1494 2213<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1495 2213<@jupet�kellari��> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1496 2213<@jupet�kellari��> (-1 ollee ei akkua kiinni, koska akku on p�yd�ll�)
1497 2214<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1498 2214<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1500 2238<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1501 2239<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1503 2240<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori p��ll�
1504 2241<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori p��ll� mutta ilman verkkovirtaa
1507 /* Kapil Hari Paranjape <kapil@imsc.res.in>
1508 Linux 2.6.24 onwards battery info is in
1509 /sys/class/power_supply/BAT0/
1510 On my system I get the following.
1511 /sys/class/power_supply/BAT0/uevent:
1512 PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A03:00/device:01/PNP0C09:00/PNP0C0A:00
1514 PHYSDEVDRIVER=battery
1515 POWER_SUPPLY_NAME=BAT0
1516 POWER_SUPPLY_TYPE=Battery
1517 POWER_SUPPLY_STATUS=Discharging
1518 POWER_SUPPLY_PRESENT=1
1519 POWER_SUPPLY_TECHNOLOGY=Li-ion
1520 POWER_SUPPLY_VOLTAGE_MIN_DESIGN=10800000
1521 POWER_SUPPLY_VOLTAGE_NOW=10780000
1522 POWER_SUPPLY_CURRENT_NOW=13970000
1523 POWER_SUPPLY_ENERGY_FULL_DESIGN=47510000
1524 POWER_SUPPLY_ENERGY_FULL=27370000
1525 POWER_SUPPLY_ENERGY_NOW=11810000
1526 POWER_SUPPLY_MODEL_NAME=IBM-92P1060
1527 POWER_SUPPLY_MANUFACTURER=Panasonic
1528 On some systems POWER_SUPPLY_ENERGY_* is replaced by POWER_SUPPLY_CHARGE_*
1531 #define SYSFS_BATTERY_BASE_PATH "/sys/class/power_supply"
1532 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1533 #define APM_PATH "/proc/apm"
1534 #define MAX_BATTERY_COUNT 4
1536 static FILE *sysfs_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1537 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1538 static FILE *apm_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1540 static int batteries_initialized = 0;
1541 static char batteries[MAX_BATTERY_COUNT][32];
1543 static int acpi_last_full[MAX_BATTERY_COUNT];
1544 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1546 /* e.g. "charging 75%" */
1547 static char last_battery_str[MAX_BATTERY_COUNT][64];
1549 static char last_battery_time_str[MAX_BATTERY_COUNT][64];
1551 static double last_battery_time[MAX_BATTERY_COUNT];
1553 static int last_battery_perct[MAX_BATTERY_COUNT];
1554 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1556 void init_batteries(void)
1560 if (batteries_initialized) {
1564 #pragma omp parallel for schedule(dynamic,10)
1565 #endif /* HAVE_OPENMP */
1566 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1567 batteries[idx][0] = '\0';
1569 batteries_initialized = 1;
1572 int get_battery_idx(const char *bat)
1576 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1577 if (!strlen(batteries[idx]) || !strcmp(batteries[idx], bat)) {
1582 /* if not found, enter a new entry */
1583 if (!strlen(batteries[idx])) {
1584 snprintf(batteries[idx], 31, "%s", bat);
1590 void set_return_value(char *buffer, unsigned int n, int item, int idx);
1592 void get_battery_stuff(char *buffer, unsigned int n, const char *bat, int item)
1594 static int idx, rep = 0, rep1 = 0, rep2 = 0;
1595 char acpi_path[128];
1596 char sysfs_path[128];
1598 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1599 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1603 idx = get_battery_idx(bat);
1605 /* don't update battery too often */
1606 if (current_update_time - last_battery_time[idx] < 29.5) {
1607 set_return_value(buffer, n, item, idx);
1611 last_battery_time[idx] = current_update_time;
1613 memset(last_battery_str[idx], 0, sizeof(last_battery_str[idx]));
1614 memset(last_battery_time_str[idx], 0, sizeof(last_battery_time_str[idx]));
1616 /* first try SYSFS if that fails try ACPI */
1618 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1619 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1622 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1623 acpi_bat_fp[idx] = open_file(acpi_path, &rep1);
1626 if (sysfs_bat_fp[idx] != NULL) {
1628 int present_rate = -1;
1629 int remaining_capacity = -1;
1630 char charging_state[64];
1633 strcpy(charging_state, "unknown");
1635 while (!feof(sysfs_bat_fp[idx])) {
1637 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1640 /* let's just hope units are ok */
1641 if (strncmp (buf, "POWER_SUPPLY_PRESENT=1", 22) == 0)
1642 strcpy(present, "yes");
1643 else if (strncmp (buf, "POWER_SUPPLY_PRESENT=0", 22) == 0)
1644 strcpy(present, "no");
1645 else if (strncmp (buf, "POWER_SUPPLY_STATUS=", 20) == 0)
1646 sscanf(buf, "POWER_SUPPLY_STATUS=%63s", charging_state);
1647 /* present_rate is not the same as the
1648 current flowing now but it is the same value
1649 which was used in the past. so we continue
1651 else if (strncmp(buf, "POWER_SUPPLY_CURRENT_NOW=", 25) == 0)
1652 sscanf(buf, "POWER_SUPPLY_CURRENT_NOW=%d", &present_rate);
1653 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0)
1654 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1655 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=", 25) == 0)
1656 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_last_full[idx]);
1657 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0)
1658 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1659 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=", 25) == 0)
1660 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_last_full[idx]);
1663 fclose(sysfs_bat_fp[idx]);
1664 sysfs_bat_fp[idx] = NULL;
1666 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1667 if (remaining_capacity > acpi_last_full[idx])
1668 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1671 if (strcmp(present, "No") == 0) {
1672 strncpy(last_battery_str[idx], "not present", 64);
1675 else if (strcmp(charging_state, "Charging") == 0) {
1676 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1677 /* e.g. charging 75% */
1678 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %i%%",
1679 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1681 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1682 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1683 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1684 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %d%%",
1685 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1686 snprintf(last_battery_time_str[idx],
1687 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1689 strncpy(last_battery_str[idx], "charging", sizeof(last_battery_str[idx])-1);
1690 snprintf(last_battery_time_str[idx],
1691 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1695 else if (strncmp(charging_state, "Discharging", 64) == 0) {
1696 if (present_rate > 0) {
1697 /* e.g. discharging 35% */
1698 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "discharging %i%%",
1699 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1701 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1702 (long) (((float) remaining_capacity / present_rate) * 3600));
1703 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1704 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "full");
1705 snprintf(last_battery_time_str[idx],
1706 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1708 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1710 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1711 snprintf(last_battery_time_str[idx],
1712 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1716 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1717 else if (strncmp(charging_state, "Charged", 64) == 0 || strncmp(charging_state, "Full", 64) == 0) {
1718 /* Below happens with the second battery on my X40,
1719 * when the second one is empty and the first one
1721 if (remaining_capacity == 0)
1722 strcpy(last_battery_str[idx], "empty");
1724 strcpy(last_battery_str[idx], "charged");
1726 /* unknown, probably full / AC */
1728 if (acpi_last_full[idx] != 0
1729 && remaining_capacity != acpi_last_full[idx])
1730 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1731 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1733 strncpy(last_battery_str[idx], "AC", 64);
1735 } else if (acpi_bat_fp[idx] != NULL) {
1737 int present_rate = -1;
1738 int remaining_capacity = -1;
1739 char charging_state[64];
1742 /* read last full capacity if it's zero */
1743 if (acpi_last_full[idx] == 0) {
1744 static int rep3 = 0;
1748 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1749 fp = open_file(path, &rep3);
1754 if (fgets(b, 256, fp) == NULL) {
1757 if (sscanf(b, "last full capacity: %d",
1758 &acpi_last_full[idx]) != 0) {
1767 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1769 strcpy(charging_state, "unknown");
1771 while (!feof(acpi_bat_fp[idx])) {
1774 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1778 /* let's just hope units are ok */
1779 if (strncmp(buf, "present:", 8) == 0) {
1780 sscanf(buf, "present: %4s", present);
1781 } else if (strncmp(buf, "charging state:", 15) == 0) {
1782 sscanf(buf, "charging state: %63s", charging_state);
1783 } else if (strncmp(buf, "present rate:", 13) == 0) {
1784 sscanf(buf, "present rate: %d", &present_rate);
1785 } else if (strncmp(buf, "remaining capacity:", 19) == 0) {
1786 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1789 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1790 if (remaining_capacity > acpi_last_full[idx]) {
1791 /* normalize to 100% */
1792 acpi_last_full[idx] = remaining_capacity;
1796 if (strcmp(present, "no") == 0) {
1797 strncpy(last_battery_str[idx], "not present", 64);
1799 } else if (strcmp(charging_state, "charging") == 0) {
1800 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1801 /* e.g. charging 75% */
1802 snprintf(last_battery_str[idx],
1803 sizeof(last_battery_str[idx]) - 1, "charging %i%%",
1804 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1806 format_seconds(last_battery_time_str[idx],
1807 sizeof(last_battery_time_str[idx]) - 1,
1808 (long) (((acpi_last_full[idx] - remaining_capacity) *
1809 3600) / present_rate));
1810 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1811 snprintf(last_battery_str[idx],
1812 sizeof(last_battery_str[idx]) - 1, "charging %d%%",
1813 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1814 snprintf(last_battery_time_str[idx],
1815 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1817 strncpy(last_battery_str[idx], "charging",
1818 sizeof(last_battery_str[idx]) - 1);
1819 snprintf(last_battery_time_str[idx],
1820 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1823 } else if (strncmp(charging_state, "discharging", 64) == 0) {
1824 if (present_rate > 0) {
1825 /* e.g. discharging 35% */
1826 snprintf(last_battery_str[idx],
1827 sizeof(last_battery_str[idx]) - 1, "discharging %i%%",
1828 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1830 format_seconds(last_battery_time_str[idx],
1831 sizeof(last_battery_time_str[idx]) - 1,
1832 (long) ((remaining_capacity * 3600) / present_rate));
1833 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1834 snprintf(last_battery_str[idx],
1835 sizeof(last_battery_str[idx]) - 1, "full");
1836 snprintf(last_battery_time_str[idx],
1837 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1839 snprintf(last_battery_str[idx],
1840 sizeof(last_battery_str[idx]) - 1, "discharging %d%%",
1841 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1842 snprintf(last_battery_time_str[idx],
1843 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1846 } else if (strncmp(charging_state, "charged", 64) == 0) {
1847 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1848 /* Below happens with the second battery on my X40,
1849 * when the second one is empty and the first one being charged. */
1850 if (remaining_capacity == 0) {
1851 strcpy(last_battery_str[idx], "empty");
1853 strcpy(last_battery_str[idx], "charged");
1855 /* unknown, probably full / AC */
1857 if (strncmp(charging_state, "Full", 64) == 0) {
1858 strncpy(last_battery_str[idx], "full", 64);
1859 } else if (acpi_last_full[idx] != 0
1860 && remaining_capacity != acpi_last_full[idx]) {
1861 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1862 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1864 strncpy(last_battery_str[idx], "AC", 64);
1867 fclose(acpi_bat_fp[idx]);
1868 acpi_bat_fp[idx] = NULL;
1871 if (apm_bat_fp[idx] == NULL) {
1872 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1875 if (apm_bat_fp[idx] != NULL) {
1876 unsigned int ac, status, flag;
1879 fscanf(apm_bat_fp[idx], "%*s %*s %*x %x %x %x %d%%",
1880 &ac, &status, &flag, &life);
1883 /* could check now that there is ac */
1884 snprintf(last_battery_str[idx], 64, "AC");
1886 /* could check that status == 3 here? */
1887 } else if (ac && life != 100) {
1888 snprintf(last_battery_str[idx], 64, "charging %d%%", life);
1890 snprintf(last_battery_str[idx], 64, "%d%%", life);
1893 /* it seemed to buffer it so file must be closed (or could use
1894 * syscalls directly but I don't feel like coding it now) */
1895 fclose(apm_bat_fp[idx]);
1896 apm_bat_fp[idx] = NULL;
1899 set_return_value(buffer, n, item, idx);
1902 void set_return_value(char *buffer, unsigned int n, int item, int idx)
1905 case BATTERY_STATUS:
1906 snprintf(buffer, n, "%s", last_battery_str[idx]);
1909 snprintf(buffer, n, "%s", last_battery_time_str[idx]);
1916 void get_battery_short_status(char *buffer, unsigned int n, const char *bat)
1918 get_battery_stuff(buffer, n, bat, BATTERY_STATUS);
1919 if (0 == strncmp("charging", buffer, 8)) {
1921 memmove(buffer + 1, buffer + 8, n - 8);
1922 } else if (0 == strncmp("discharging", buffer, 11)) {
1924 memmove(buffer + 1, buffer + 11, n - 11);
1925 } else if (0 == strncmp("charged", buffer, 7)) {
1927 memmove(buffer + 1, buffer + 7, n - 7);
1928 } else if (0 == strncmp("not present", buffer, 11)) {
1930 memmove(buffer + 1, buffer + 11, n - 11);
1931 } else if (0 == strncmp("empty", buffer, 5)) {
1933 memmove(buffer + 1, buffer + 5, n - 5);
1934 } else if (0 != strncmp("AC", buffer, 2)) {
1936 memmove(buffer + 1, buffer + 11, n - 11);
1940 int get_battery_perct(const char *bat)
1944 char acpi_path[128];
1945 char sysfs_path[128];
1946 int remaining_capacity = -1;
1948 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1949 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1953 idx = get_battery_idx(bat);
1955 /* don't update battery too often */
1956 if (current_update_time - last_battery_perct_time[idx] < 30) {
1957 return last_battery_perct[idx];
1959 last_battery_perct_time[idx] = current_update_time;
1961 /* Only check for SYSFS or ACPI */
1963 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1964 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1968 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1969 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1972 if (sysfs_bat_fp[idx] != NULL) {
1974 while (!feof(sysfs_bat_fp[idx])) {
1976 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1979 if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0) {
1980 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1981 } else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=",25) == 0) {
1982 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_design_capacity[idx]);
1983 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0) {
1984 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1985 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=",25) == 0) {
1986 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_design_capacity[idx]);
1990 fclose(sysfs_bat_fp[idx]);
1991 sysfs_bat_fp[idx] = NULL;
1993 } else if (acpi_bat_fp[idx] != NULL) {
1995 /* read last full capacity if it's zero */
1996 if (acpi_design_capacity[idx] == 0) {
2001 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
2002 fp = open_file(path, &rep2);
2007 if (fgets(b, 256, fp) == NULL) {
2010 if (sscanf(b, "last full capacity: %d",
2011 &acpi_design_capacity[idx]) != 0) {
2019 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
2021 while (!feof(acpi_bat_fp[idx])) {
2024 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
2028 if (buf[0] == 'r') {
2029 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
2033 if (remaining_capacity < 0) {
2036 /* compute the battery percentage */
2037 last_battery_perct[idx] =
2038 (int) (((float) remaining_capacity / acpi_design_capacity[idx]) * 100);
2039 if (last_battery_perct[idx] > 100) last_battery_perct[idx] = 100;
2040 return last_battery_perct[idx];
2043 int get_battery_perct_bar(const char *bar)
2047 get_battery_perct(bar);
2048 idx = get_battery_idx(bar);
2049 return (int) (last_battery_perct[idx] * 2.56 - 1);
2052 /* On Apple powerbook and ibook:
2053 $ cat /proc/pmu/battery_0
2060 $ cat /proc/pmu/info
2061 PMU driver version : 2
2062 PMU firmware version : 0c
2067 /* defines as in <linux/pmu.h> */
2068 #define PMU_BATT_PRESENT 0x00000001
2069 #define PMU_BATT_CHARGING 0x00000002
2071 static FILE *pmu_battery_fp;
2072 static FILE *pmu_info_fp;
2073 static char pb_battery_info[3][32];
2074 static double pb_battery_info_update;
2076 #define PMU_PATH "/proc/pmu"
2077 void get_powerbook_batt_info(char *buffer, size_t n, int i)
2080 const char *batt_path = PMU_PATH "/battery_0";
2081 const char *info_path = PMU_PATH "/info";
2083 int charge, max_charge, ac = -1;
2086 /* don't update battery too often */
2087 if (current_update_time - pb_battery_info_update < 29.5) {
2088 snprintf(buffer, n, "%s", pb_battery_info[i]);
2091 pb_battery_info_update = current_update_time;
2093 if (pmu_battery_fp == NULL) {
2094 pmu_battery_fp = open_file(batt_path, &rep);
2095 if (pmu_battery_fp == NULL) {
2100 if (pmu_battery_fp != NULL) {
2101 rewind(pmu_battery_fp);
2102 while (!feof(pmu_battery_fp)) {
2105 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL) {
2109 if (buf[0] == 'f') {
2110 sscanf(buf, "flags : %8x", &flags);
2111 } else if (buf[0] == 'c' && buf[1] == 'h') {
2112 sscanf(buf, "charge : %d", &charge);
2113 } else if (buf[0] == 'm') {
2114 sscanf(buf, "max_charge : %d", &max_charge);
2115 } else if (buf[0] == 't') {
2116 sscanf(buf, "time rem. : %ld", &timeval);
2120 if (pmu_info_fp == NULL) {
2121 pmu_info_fp = open_file(info_path, &rep);
2122 if (pmu_info_fp == NULL) {
2127 if (pmu_info_fp != NULL) {
2128 rewind(pmu_info_fp);
2129 while (!feof(pmu_info_fp)) {
2132 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL) {
2135 if (buf[0] == 'A') {
2136 sscanf(buf, "AC Power : %d", &ac);
2140 /* update status string */
2141 if ((ac && !(flags & PMU_BATT_PRESENT))) {
2142 strncpy(pb_battery_info[PB_BATT_STATUS], "AC", sizeof(pb_battery_info[PB_BATT_STATUS]));
2143 } else if (ac && (flags & PMU_BATT_PRESENT)
2144 && !(flags & PMU_BATT_CHARGING)) {
2145 strncpy(pb_battery_info[PB_BATT_STATUS], "charged", sizeof(pb_battery_info[PB_BATT_STATUS]));
2146 } else if ((flags & PMU_BATT_PRESENT) && (flags & PMU_BATT_CHARGING)) {
2147 strncpy(pb_battery_info[PB_BATT_STATUS], "charging", sizeof(pb_battery_info[PB_BATT_STATUS]));
2149 strncpy(pb_battery_info[PB_BATT_STATUS], "discharging", sizeof(pb_battery_info[PB_BATT_STATUS]));
2152 /* update percentage string */
2153 if (timeval == 0 && ac && (flags & PMU_BATT_PRESENT)
2154 && !(flags & PMU_BATT_CHARGING)) {
2155 snprintf(pb_battery_info[PB_BATT_PERCENT],
2156 sizeof(pb_battery_info[PB_BATT_PERCENT]), "100%%");
2157 } else if (timeval == 0) {
2158 snprintf(pb_battery_info[PB_BATT_PERCENT],
2159 sizeof(pb_battery_info[PB_BATT_PERCENT]), "unknown");
2161 snprintf(pb_battery_info[PB_BATT_PERCENT],
2162 sizeof(pb_battery_info[PB_BATT_PERCENT]), "%d%%",
2163 (charge * 100) / max_charge);
2166 /* update time string */
2167 if (timeval == 0) { /* fully charged or battery not present */
2168 snprintf(pb_battery_info[PB_BATT_TIME],
2169 sizeof(pb_battery_info[PB_BATT_TIME]), "unknown");
2170 } else if (timeval < 60 * 60) { /* don't show secs */
2171 format_seconds_short(pb_battery_info[PB_BATT_TIME],
2172 sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2174 format_seconds(pb_battery_info[PB_BATT_TIME],
2175 sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2178 snprintf(buffer, n, "%s", pb_battery_info[i]);
2181 void update_top(void)
2183 process_find_top(info.cpu, info.memu, info.time
2188 info.first_process = get_first_process();
2191 #define ENTROPY_AVAIL_PATH "/proc/sys/kernel/random/entropy_avail"
2193 int get_entropy_avail(unsigned int *val)
2198 if (!(fp = open_file(ENTROPY_AVAIL_PATH, &rep)))
2201 if (fscanf(fp, "%u", val) != 1)
2208 #define ENTROPY_POOLSIZE_PATH "/proc/sys/kernel/random/poolsize"
2210 int get_entropy_poolsize(unsigned int *val)
2215 if (!(fp = open_file(ENTROPY_POOLSIZE_PATH, &rep)))
2218 if (fscanf(fp, "%u", val) != 1)
2225 const char *get_disk_protect_queue(const char *disk)
2231 snprintf(path, 127, "/sys/block/%s/device/unload_heads", disk);
2232 if (access(path, F_OK)) {
2233 snprintf(path, 127, "/sys/block/%s/queue/protect", disk);
2235 if ((fp = fopen(path, "r")) == NULL)
2237 if (fscanf(fp, "%d\n", &state) != 1) {
2242 return (state > 0) ? "frozen" : "free ";
2245 void update_diskio(void)
2249 char buf[512], devbuf[64];
2250 unsigned int major, minor;
2252 struct diskio_stat *cur;
2253 unsigned int reads, writes;
2254 unsigned int total_reads = 0, total_writes = 0;
2257 stats.current_read = 0;
2258 stats.current_write = 0;
2260 if (!(fp = open_file("/proc/diskstats", &rep))) {
2264 /* read reads and writes from all disks (minor = 0), including cd-roms
2265 * and floppies, and sum them up */
2266 while (fgets(buf, 512, fp)) {
2267 col_count = sscanf(buf, "%u %u %s %*u %*u %u %*u %*u %*u %u", &major,
2268 &minor, devbuf, &reads, &writes);
2269 /* ignore subdevices (they have only 3 matching entries in their line)
2270 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
2272 * XXX: ignore devices which are part of a SW RAID (MD_MAJOR) */
2273 if (col_count == 5 && major != LVM_BLK_MAJOR && major != NBD_MAJOR
2274 && major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
2275 total_reads += reads;
2276 total_writes += writes;
2278 col_count = sscanf(buf, "%u %u %s %*u %u %*u %u",
2279 &major, &minor, devbuf, &reads, &writes);
2280 if (col_count != 5) {
2285 while (cur && strcmp(devbuf, cur->dev))
2289 update_diskio_values(cur, reads, writes);
2291 update_diskio_values(&stats, total_reads, total_writes);