1 /* Conky, a system monitor, based on torsmo
3 * Any original torsmo code is licensed under the BSD license
5 * All code written since the fork of torsmo is licensed under the GPL
7 * Please see COPYING for details
9 * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
10 * Copyright (c) 2007 Toni Spets
11 * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
13 * All rights reserved.
15 * This program is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation, either version 3 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program. If not, see <http://www.gnu.org/licenses/>.
37 #include <sys/types.h>
38 #include <sys/sysinfo.h>
40 #ifndef HAVE_CLOCK_GETTIME
45 // #include <assert.h>
49 #include <sys/ioctl.h>
50 #include <sys/socket.h>
51 #include <netinet/in.h>
52 #include <linux/sockios.h>
54 #include <arpa/inet.h>
58 #include <linux/route.h>
65 #define SHORTSTAT_TEMPL "%*s %llu %llu %llu"
66 #define LONGSTAT_TEMPL "%*s %llu %llu %llu "
68 static int show_nice_processes;
70 /* This flag tells the linux routines to use the /proc system where possible,
71 * even if other api's are available, e.g. sysinfo() or getloadavg().
72 * the reason for this is to allow for /proc-based distributed monitoring.
73 * using a flag in this manner creates less confusing code. */
74 static int prefer_proc = 0;
76 void prepare_update(void)
80 void update_uptime(void)
84 struct sysinfo s_info;
87 info.uptime = (double) s_info.uptime;
94 if (!(fp = open_file("/proc/uptime", &rep))) {
98 fscanf(fp, "%lf", &info.uptime);
101 info.mask |= (1 << INFO_UPTIME);
104 int check_mount(char *s)
107 FILE *mtab = fopen("/etc/mtab", "r");
110 char buf1[256], buf2[128];
112 while (fgets(buf1, 256, mtab)) {
113 sscanf(buf1, "%*s %128s", buf2);
114 if (!strcmp(s, buf2)) {
121 ERR("Could not open mtab");
126 /* these things are also in sysinfo except Buffers:
127 * (that's why I'm reading them from proc) */
129 void update_meminfo(void)
134 /* unsigned int a; */
137 info.mem = info.memmax = info.swap = info.swapmax = info.bufmem =
138 info.buffers = info.cached = info.memfree = info.memeasyfree = 0;
140 if (!(meminfo_fp = open_file("/proc/meminfo", &rep))) {
144 while (!feof(meminfo_fp)) {
145 if (fgets(buf, 255, meminfo_fp) == NULL) {
149 if (strncmp(buf, "MemTotal:", 9) == 0) {
150 sscanf(buf, "%*s %llu", &info.memmax);
151 } else if (strncmp(buf, "MemFree:", 8) == 0) {
152 sscanf(buf, "%*s %llu", &info.memfree);
153 } else if (strncmp(buf, "SwapTotal:", 10) == 0) {
154 sscanf(buf, "%*s %llu", &info.swapmax);
155 } else if (strncmp(buf, "SwapFree:", 9) == 0) {
156 sscanf(buf, "%*s %llu", &info.swap);
157 } else if (strncmp(buf, "Buffers:", 8) == 0) {
158 sscanf(buf, "%*s %llu", &info.buffers);
159 } else if (strncmp(buf, "Cached:", 7) == 0) {
160 sscanf(buf, "%*s %llu", &info.cached);
164 info.mem = info.memmax - info.memfree;
165 info.memeasyfree = info.memfree;
166 info.swap = info.swapmax - info.swap;
168 info.bufmem = info.cached + info.buffers;
170 info.mask |= (1 << INFO_MEM) | (1 << INFO_BUFFERS);
175 int get_laptop_mode(void)
180 if ((fp = fopen("/proc/sys/vm/laptop_mode", "r")) != NULL)
181 fscanf(fp, "%d\n", &val);
187 * # cat /sys/block/sda/queue/scheduler
188 * noop [anticipatory] cfq
190 char *get_ioscheduler(char *disk)
196 return strndup("n/a", text_buffer_size);
198 snprintf(buf, 127, "/sys/block/%s/queue/scheduler", disk);
199 if ((fp = fopen(buf, "r")) == NULL) {
200 return strndup("n/a", text_buffer_size);
203 fscanf(fp, "%127s", buf);
205 buf[strlen(buf) - 1] = '\0';
207 return strndup(buf + 1, text_buffer_size);
211 return strndup("n/a", text_buffer_size);
214 #define COND_FREE(x) if(x) free(x); x = 0
215 #define SAVE_SET_STRING(x, y) \
216 if (x && strcmp((char *)x, (char *)y)) { \
218 x = strndup("multiple", text_buffer_size); \
220 x = strndup(y, text_buffer_size); \
223 void update_gateway_info_failure(const char *reason)
228 //2 pointers to 1 location causes a crash when we try to free them both
229 info.gw_info.iface = strndup("failed", text_buffer_size);
230 info.gw_info.ip = strndup("failed", text_buffer_size);
234 /* Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT */
235 #define RT_ENTRY_FORMAT "%63s %lx %lx %x %*d %*d %*d %lx %*d %*d %*d\n"
237 void update_gateway_info(void)
242 unsigned long dest, gate, mask;
245 struct gateway_info *gw_info = &info.gw_info;
247 COND_FREE(gw_info->iface);
248 COND_FREE(gw_info->ip);
251 if ((fp = fopen("/proc/net/route", "r")) == NULL) {
252 update_gateway_info_failure("fopen()");
256 /* skip over the table header line, which is always present */
257 fscanf(fp, "%*[^\n]\n");
260 if(fscanf(fp, RT_ENTRY_FORMAT,
261 iface, &dest, &gate, &flags, &mask) != 5) {
262 update_gateway_info_failure("fscanf()");
265 if (!(dest || mask) && ((flags & RTF_GATEWAY) || !gate) ) {
267 SAVE_SET_STRING(gw_info->iface, iface)
269 SAVE_SET_STRING(gw_info->ip, inet_ntoa(ina))
276 void update_net_stats(void)
280 static char first = 1;
282 // FIXME: arbitrary size chosen to keep code simple.
284 unsigned int curtmp1, curtmp2;
291 // wireless info variables
292 int skfd, has_bitrate = 0;
293 struct wireless_info *winfo;
298 delta = current_update_time - last_update_time;
299 if (delta <= 0.0001) {
303 /* open file and ignore first two lines */
304 if (!(net_dev_fp = open_file("/proc/net/dev", &rep))) {
309 fgets(buf, 255, net_dev_fp); /* garbage */
310 fgets(buf, 255, net_dev_fp); /* garbage (field names) */
312 /* read each interface */
313 for (i2 = 0; i2 < 16; i2++) {
317 long long r, t, last_recv, last_trans;
319 if (fgets(buf, 255, net_dev_fp) == NULL) {
323 while (isspace((int) *p)) {
329 while (*p && *p != ':') {
338 ns = get_net_stat(s);
340 memset(&(ns->addr.sa_data), 0, 14);
342 memset(ns->addrs, 0, 17 * 16 + 1); /* Up to 17 chars per ip, max 16 interfaces. Nasty memory usage... */
344 last_recv = ns->recv;
345 last_trans = ns->trans;
347 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
348 sscanf(p, "%lld %*d %*d %*d %*d %*d %*d %*d %lld",
351 /* if recv or trans is less than last time, an overflow happened */
352 if (r < ns->last_read_recv) {
355 ns->recv += (r - ns->last_read_recv);
357 ns->last_read_recv = r;
359 if (t < ns->last_read_trans) {
362 ns->trans += (t - ns->last_read_trans);
364 ns->last_read_trans = t;
366 /*** ip addr patch ***/
367 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
369 conf.ifc_buf = malloc(sizeof(struct ifreq) * 16);
370 conf.ifc_len = sizeof(struct ifreq) * 16;
371 memset(conf.ifc_buf, 0, conf.ifc_len);
373 ioctl((long) i, SIOCGIFCONF, &conf);
375 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
376 struct net_stat *ns2;
378 if (!(((struct ifreq *) conf.ifc_buf) + k))
382 ((struct ifreq *) conf.ifc_buf)[k].ifr_ifrn.ifrn_name);
383 ns2->addr = ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.ifru_addr;
384 sprintf(temp_addr, "%u.%u.%u.%u, ",
385 ns2->addr.sa_data[2] & 255,
386 ns2->addr.sa_data[3] & 255,
387 ns2->addr.sa_data[4] & 255,
388 ns2->addr.sa_data[5] & 255);
389 if(NULL == strstr(ns2->addrs, temp_addr))
390 strncpy(ns2->addrs + strlen(ns2->addrs), temp_addr, 17);
397 /*** end ip addr patch ***/
400 /* calculate speeds */
401 ns->net_rec[0] = (ns->recv - last_recv) / delta;
402 ns->net_trans[0] = (ns->trans - last_trans) / delta;
409 #pragma omp parallel for
410 #endif /* HAVE_OPENMP */
411 for (i = 0; i < info.net_avg_samples; i++) {
412 curtmp1 = curtmp1 + ns->net_rec[i];
413 curtmp2 = curtmp2 + ns->net_trans[i];
421 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
422 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
423 if (info.net_avg_samples > 1) {
425 #pragma omp parallel for
426 #endif /* HAVE_OPENMP */
427 for (i = info.net_avg_samples; i > 1; i--) {
428 ns->net_rec[i - 1] = ns->net_rec[i - 2];
429 ns->net_trans[i - 1] = ns->net_trans[i - 2];
434 /* update wireless info */
435 winfo = malloc(sizeof(struct wireless_info));
436 memset(winfo, 0, sizeof(struct wireless_info));
438 skfd = iw_sockets_open();
439 if (iw_get_basic_config(skfd, s, &(winfo->b)) > -1) {
441 // set present winfo variables
442 if (iw_get_stats(skfd, s, &(winfo->stats),
443 &winfo->range, winfo->has_range) >= 0) {
444 winfo->has_stats = 1;
446 if (iw_get_range_info(skfd, s, &(winfo->range)) >= 0) {
447 winfo->has_range = 1;
449 if (iw_get_ext(skfd, s, SIOCGIWAP, &wrq) >= 0) {
450 winfo->has_ap_addr = 1;
451 memcpy(&(winfo->ap_addr), &(wrq.u.ap_addr), sizeof(sockaddr));
455 if (iw_get_ext(skfd, s, SIOCGIWRATE, &wrq) >= 0) {
456 memcpy(&(winfo->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
457 iw_print_bitrate(ns->bitrate, 16, winfo->bitrate.value);
462 if (winfo->has_range && winfo->has_stats
463 && ((winfo->stats.qual.level != 0)
464 || (winfo->stats.qual.updated & IW_QUAL_DBM))) {
465 if (!(winfo->stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
466 ns->link_qual = winfo->stats.qual.qual;
467 ns->link_qual_max = winfo->range.max_qual.qual;
472 if (winfo->has_ap_addr) {
473 iw_sawap_ntop(&winfo->ap_addr, ns->ap);
477 if (winfo->b.has_essid) {
478 if (winfo->b.essid_on) {
479 snprintf(ns->essid, 32, "%s", winfo->b.essid);
481 snprintf(ns->essid, 32, "off/any");
485 snprintf(ns->mode, 16, "%s", iw_operation_mode[winfo->b.mode]);
487 iw_sockets_close(skfd);
495 info.mask |= (1 << INFO_NET);
500 void update_total_processes(void)
504 struct sysinfo s_info;
507 info.procs = s_info.procs;
514 if (!(fp = open_file("/proc/loadavg", &rep))) {
518 fscanf(fp, "%*f %*f %*f %*d/%hu", &info.procs);
521 info.mask |= (1 << INFO_PROCS);
524 #define CPU_SAMPLE_COUNT 15
526 unsigned long long cpu_user;
527 unsigned long long cpu_system;
528 unsigned long long cpu_nice;
529 unsigned long long cpu_idle;
530 unsigned long long cpu_iowait;
531 unsigned long long cpu_irq;
532 unsigned long long cpu_softirq;
533 unsigned long long cpu_steal;
534 unsigned long long cpu_total;
535 unsigned long long cpu_active_total;
536 unsigned long long cpu_last_total;
537 unsigned long long cpu_last_active_total;
538 double cpu_val[CPU_SAMPLE_COUNT];
540 static short cpu_setup = 0;
542 /* Determine if this kernel gives us "extended" statistics information in
544 * Kernels around 2.5 and earlier only reported user, system, nice, and
545 * idle values in proc stat.
546 * Kernels around 2.6 and greater report these PLUS iowait, irq, softirq,
548 void determine_longstat(char *buf)
550 unsigned long long iowait = 0;
552 KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
553 /* scanf will either return -1 or 1 because there is only 1 assignment */
554 if (sscanf(buf, "%*s %*d %*d %*d %*d %llu", &iowait) > 0) {
555 KFLAG_SETON(KFLAG_IS_LONGSTAT);
559 void get_cpu_count(void)
565 if (info.cpu_usage) {
569 if (!(stat_fp = open_file("/proc/stat", &rep))) {
575 while (!feof(stat_fp)) {
576 if (fgets(buf, 255, stat_fp) == NULL) {
580 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
581 if (info.cpu_count == 0) {
582 determine_longstat(buf);
587 info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
592 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
593 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
595 inline static void update_stat(void)
599 static struct cpu_info *cpu = NULL;
604 const char *stat_template = NULL;
605 unsigned int malloc_cpu_size = 0;
607 /* add check for !info.cpu_usage since that mem is freed on a SIGUSR1 */
608 if (!cpu_setup || !info.cpu_usage) {
613 if (!stat_template) {
615 KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT;
619 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
620 cpu = malloc(malloc_cpu_size);
621 memset(cpu, 0, malloc_cpu_size);
624 if (!(stat_fp = open_file("/proc/stat", &rep))) {
626 if (info.cpu_usage) {
627 memset(info.cpu_usage, 0, info.cpu_count * sizeof(float));
633 while (!feof(stat_fp)) {
634 if (fgets(buf, 255, stat_fp) == NULL) {
638 if (strncmp(buf, "procs_running ", 14) == 0) {
639 sscanf(buf, "%*s %hu", &info.run_procs);
640 info.mask |= (1 << INFO_RUN_PROCS);
641 } else if (strncmp(buf, "cpu", 3) == 0) {
643 if (isdigit(buf[3])) {
644 idx = atoi(&buf[3]) + 1;
648 sscanf(buf, stat_template, &(cpu[idx].cpu_user),
649 &(cpu[idx].cpu_nice), &(cpu[idx].cpu_system),
650 &(cpu[idx].cpu_idle), &(cpu[idx].cpu_iowait),
651 &(cpu[idx].cpu_irq), &(cpu[idx].cpu_softirq),
652 &(cpu[idx].cpu_steal));
654 cpu[idx].cpu_total = cpu[idx].cpu_user + cpu[idx].cpu_nice +
655 cpu[idx].cpu_system + cpu[idx].cpu_idle +
656 cpu[idx].cpu_iowait + cpu[idx].cpu_irq +
657 cpu[idx].cpu_softirq + cpu[idx].cpu_steal;
659 cpu[idx].cpu_active_total = cpu[idx].cpu_total -
660 (cpu[idx].cpu_idle + cpu[idx].cpu_iowait);
661 info.mask |= (1 << INFO_CPU);
663 delta = current_update_time - last_update_time;
665 if (delta <= 0.001) {
669 cpu[idx].cpu_val[0] = (cpu[idx].cpu_active_total -
670 cpu[idx].cpu_last_active_total) /
671 (float) (cpu[idx].cpu_total - cpu[idx].cpu_last_total);
674 #pragma omp parallel for reduction(+:curtmp)
675 #endif /* HAVE_OPENMP */
676 for (i = 0; i < info.cpu_avg_samples; i++) {
677 curtmp = curtmp + cpu[idx].cpu_val[i];
679 /* TESTING -- I've removed this, because I don't think it is right.
680 * You shouldn't divide by the cpu count here ...
681 * removing for testing */
683 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples /
686 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples;
688 /* TESTING -- this line replaces the prev. "suspect" if/else */
689 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples;
691 cpu[idx].cpu_last_total = cpu[idx].cpu_total;
692 cpu[idx].cpu_last_active_total = cpu[idx].cpu_active_total;
694 #pragma omp parallel for
695 #endif /* HAVE_OPENMP */
696 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
697 cpu[idx].cpu_val[i] = cpu[idx].cpu_val[i - 1];
704 void update_running_processes(void)
709 void update_cpu_usage(void)
714 void update_load_average(void)
716 #ifdef HAVE_GETLOADAVG
721 info.loadavg[0] = (float) v[0];
722 info.loadavg[1] = (float) v[1];
723 info.loadavg[2] = (float) v[2];
730 if (!(fp = open_file("/proc/loadavg", &rep))) {
731 info.loadavg[0] = info.loadavg[1] = info.loadavg[2] = 0.0;
734 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1],
738 info.mask |= (1 << INFO_LOADAVG);
741 #define PROC_I8K "/proc/i8k"
742 #define I8K_DELIM " "
743 static char *i8k_procbuf = NULL;
744 void update_i8k(void)
749 i8k_procbuf = (char *) malloc(128 * sizeof(char));
751 if ((fp = fopen(PROC_I8K, "r")) == NULL) {
752 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel "
753 "driver is loaded...");
756 memset(&i8k_procbuf[0], 0, 128);
757 if (fread(&i8k_procbuf[0], sizeof(char), 128, fp) == 0) {
758 ERR("something wrong with /proc/i8k...");
763 i8k.version = strtok(&i8k_procbuf[0], I8K_DELIM);
764 i8k.bios = strtok(NULL, I8K_DELIM);
765 i8k.serial = strtok(NULL, I8K_DELIM);
766 i8k.cpu_temp = strtok(NULL, I8K_DELIM);
767 i8k.left_fan_status = strtok(NULL, I8K_DELIM);
768 i8k.right_fan_status = strtok(NULL, I8K_DELIM);
769 i8k.left_fan_rpm = strtok(NULL, I8K_DELIM);
770 i8k.right_fan_rpm = strtok(NULL, I8K_DELIM);
771 i8k.ac_status = strtok(NULL, I8K_DELIM);
772 i8k.buttons_status = strtok(NULL, I8K_DELIM);
775 /***********************************************************/
776 /***********************************************************/
777 /***********************************************************/
779 static int no_dots(const struct dirent *d)
781 if (d->d_name[0] == '.') {
787 static int get_first_file_in_a_directory(const char *dir, char *s, int *rep)
789 struct dirent **namelist;
792 n = scandir(dir, &namelist, no_dots, alphasort);
795 ERR("scandir for %s: %s", dir, strerror(errno));
806 strncpy(s, namelist[0]->d_name, 255);
810 #pragma omp parallel for
811 #endif /* HAVE_OPENMP */
812 for (i = 0; i < n; i++) {
821 int open_sysfs_sensor(const char *dir, const char *dev, const char *type, int n,
822 int *divisor, char *devtype)
829 memset(buf, 0, sizeof(buf));
831 /* if device is NULL or *, get first */
832 if (dev == NULL || strcmp(dev, "*") == 0) {
835 if (!get_first_file_in_a_directory(dir, buf, &rep)) {
841 if (strcmp(dir, "/sys/class/hwmon/") == 0) {
843 /* buf holds result from get_first_file_in_a_directory() above,
844 * e.g. "hwmon0" -- append "/device" */
845 strcat(buf, "/device");
847 /* dev holds device number N as a string,
848 * e.g. "0", -- convert to "hwmon0/device" */
849 sprintf(buf, "hwmon%s/device", dev);
854 /* change vol to in */
855 if (strcmp(type, "vol") == 0) {
859 if (strcmp(type, "tempf") == 0) {
860 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, "temp", n);
862 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, type, n);
864 strncpy(devtype, path, 255);
867 fd = open(path, O_RDONLY);
869 CRIT_ERR("can't open '%s': %s\nplease check your device or remove this "
870 "var from "PACKAGE_NAME, path, strerror(errno));
873 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
874 || strcmp(type, "tempf") == 0) {
879 /* fan does not use *_div as a read divisor */
880 if (strcmp("fan", type) == 0) {
884 /* test if *_div file exist, open it and use it as divisor */
885 if (strcmp(type, "tempf") == 0) {
886 snprintf(path, 255, "%s%s/%s%d_div", dir, "one", "two", n);
888 snprintf(path, 255, "%s%s/%s%d_div", dir, dev, type, n);
891 divfd = open(path, O_RDONLY);
897 divn = read(divfd, divbuf, 63);
898 /* should read until n == 0 but I doubt that kernel will give these
899 * in multiple pieces. :) */
901 ERR("open_sysfs_sensor(): can't read from sysfs");
904 *divisor = atoi(divbuf);
913 double get_sysfs_info(int *fd, int divisor, char *devtype, char *type)
921 lseek(*fd, 0, SEEK_SET);
927 n = read(*fd, buf, 63);
928 /* should read until n == 0 but I doubt that kernel will give these
929 * in multiple pieces. :) */
931 ERR("get_sysfs_info(): read from %s failed\n", devtype);
940 *fd = open(devtype, O_RDONLY);
942 ERR("can't open '%s': %s", devtype, strerror(errno));
945 /* My dirty hack for computing CPU value
946 * Filedil, from forums.gentoo.org */
947 /* if (strstr(devtype, "temp1_input") != NULL) {
948 return -15.096 + 1.4893 * (val / 1000.0);
951 /* divide voltage and temperature by 1000 */
952 /* or if any other divisor is given, use that */
953 if (strcmp(type, "tempf") == 0) {
955 return ((val / divisor + 40) * 9.0 / 5) - 40;
956 } else if (divisor) {
957 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
959 return ((val + 40) * 9.0 / 5) - 40;
963 return val / divisor;
964 } else if (divisor) {
972 /* Prior to kernel version 2.6.12, the CPU fan speed was available in
973 * ADT746X_FAN_OLD, whereas later kernel versions provide this information in
975 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
976 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
978 void get_adt746x_fan(char *p_client_buffer, size_t client_buffer_size)
981 char adt746x_fan_state[64];
984 if (!p_client_buffer || client_buffer_size <= 0) {
988 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
989 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL) {
990 sprintf(adt746x_fan_state, "adt746x not found");
992 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
993 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
997 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_fan_state);
1000 /* Prior to kernel version 2.6.12, the CPU temperature was found in
1001 * ADT746X_CPU_OLD, whereas later kernel versions provide this information in
1003 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
1004 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
1006 void get_adt746x_cpu(char *p_client_buffer, size_t client_buffer_size)
1009 char adt746x_cpu_state[64];
1012 if (!p_client_buffer || client_buffer_size <= 0) {
1016 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
1017 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL) {
1018 sprintf(adt746x_cpu_state, "adt746x not found");
1020 fscanf(fp, "%2s", adt746x_cpu_state);
1024 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state);
1027 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
1028 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
1030 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1031 char get_freq(char *p_client_buffer, size_t client_buffer_size,
1032 const char *p_format, int divisor, unsigned int cpu)
1040 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1046 char current_freq_file[128];
1048 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu - 1,
1050 f = fopen(current_freq_file, "r");
1052 /* if there's a cpufreq /sys node, read the current frequency from
1053 * this node and divide by 1000 to get Mhz. */
1054 if (fgets(s, sizeof(s), f)) {
1055 s[strlen(s) - 1] = '\0';
1056 freq = strtod(s, NULL);
1059 snprintf(p_client_buffer, client_buffer_size, p_format,
1060 (freq / 1000) / divisor);
1065 // open the CPU information file
1066 f = open_file("/proc/cpuinfo", &rep);
1068 perror(PACKAGE_NAME": Failed to access '/proc/cpuinfo' at get_freq()");
1073 while (fgets(s, sizeof(s), f) != NULL) {
1075 #if defined(__i386) || defined(__x86_64)
1076 // and search for the cpu mhz
1077 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) {
1079 #if defined(__alpha)
1080 // different on alpha
1081 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) {
1083 // this is different on ppc for some reason
1084 if (strncmp(s, "clock", 5) == 0 && cpu == 0) {
1085 #endif // defined(__alpha)
1086 #endif // defined(__i386) || defined(__x86_64)
1088 // copy just the number
1089 strcpy(frequency, strchr(s, ':') + 2);
1090 #if defined(__alpha)
1092 frequency[strlen(frequency) - 6] = '\0';
1093 // kernel reports in Hz
1094 freq = strtod(frequency, NULL) / 1000000;
1097 frequency[strlen(frequency) - 1] = '\0';
1098 freq = strtod(frequency, NULL);
1102 if (strncmp(s, "processor", 9) == 0) {
1109 snprintf(p_client_buffer, client_buffer_size, p_format,
1110 (float) freq / divisor);
1114 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
1116 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks something
1126 * Peter Tarjan (ptarjan@citromail.hu) */
1128 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
1129 char get_voltage(char *p_client_buffer, size_t client_buffer_size,
1130 const char *p_format, int divisor, unsigned int cpu)
1136 char current_freq_file[128];
1139 /* build the voltage file name */
1141 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1144 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1149 /* read the current cpu frequency from the /sys node */
1150 f = fopen(current_freq_file, "r");
1152 if (fgets(s, sizeof(s), f)) {
1153 s[strlen(s) - 1] = '\0';
1154 freq = strtod(s, NULL);
1158 fprintf(stderr, PACKAGE_NAME": Failed to access '%s' at ", current_freq_file);
1159 perror("get_voltage()");
1166 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1169 /* use the current cpu frequency to find the corresponding voltage */
1170 f = fopen(current_freq_file, "r");
1176 if (fgets(line, 255, f) == NULL) {
1179 sscanf(line, "%d %d", &freq_comp, &voltage);
1180 if (freq_comp == freq) {
1186 fprintf(stderr, PACKAGE_NAME": Failed to access '%s' at ", current_freq_file);
1187 perror("get_voltage()");
1193 snprintf(p_client_buffer, client_buffer_size, p_format,
1194 (float) voltage / divisor);
1198 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1200 void get_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
1207 if (!p_client_buffer || client_buffer_size <= 0) {
1211 /* yeah, slow... :/ */
1212 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep)) {
1213 snprintf(p_client_buffer, client_buffer_size, "no fans?");
1217 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf);
1219 fp = open_file(buf2, &rep);
1221 snprintf(p_client_buffer, client_buffer_size,
1222 "can't open fan's state file");
1225 memset(buf, 0, sizeof(buf));
1226 fscanf(fp, "%*s %99s", buf);
1229 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1232 #define SYSFS_AC_ADAPTER_DIR "/sys/class/power_supply/AC"
1233 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1234 /* Linux 2.6.25 onwards ac adapter info is in
1235 /sys/class/power_supply/AC/
1236 On my system I get the following.
1237 /sys/class/power_supply/AC/uevent:
1238 PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A08:00/device:01/PNP0C09:00/ACPI0003:00
1241 POWER_SUPPLY_NAME=AC
1242 POWER_SUPPLY_TYPE=Mains
1243 POWER_SUPPLY_ONLINE=1
1246 void get_acpi_ac_adapter(char *p_client_buffer, size_t client_buffer_size)
1254 if (!p_client_buffer || client_buffer_size <= 0) {
1258 snprintf(buf2, sizeof(buf2), "%s/uevent", SYSFS_AC_ADAPTER_DIR);
1259 fp = open_file(buf2, &rep);
1261 /* sysfs processing */
1263 if (fgets(buf, sizeof(buf), fp) == NULL)
1266 if (strncmp(buf, "POWER_SUPPLY_ONLINE=", 20) == 0) {
1268 sscanf(buf, "POWER_SUPPLY_ONLINE=%d", &online);
1269 snprintf(p_client_buffer, client_buffer_size,
1270 "%s-line", (online ? "on" : "off"));
1276 /* yeah, slow... :/ */
1277 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep)) {
1278 snprintf(p_client_buffer, client_buffer_size, "no ac_adapters?");
1282 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf);
1284 fp = open_file(buf2, &rep);
1286 snprintf(p_client_buffer, client_buffer_size,
1287 "No ac adapter found.... where is it?");
1290 memset(buf, 0, sizeof(buf));
1291 fscanf(fp, "%*s %99s", buf);
1294 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1299 /proc/acpi/thermal_zone/THRM/cooling_mode
1300 cooling mode: active
1301 /proc/acpi/thermal_zone/THRM/polling_frequency
1303 /proc/acpi/thermal_zone/THRM/state
1305 /proc/acpi/thermal_zone/THRM/temperature
1307 /proc/acpi/thermal_zone/THRM/trip_points
1309 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1312 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1313 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1315 int open_acpi_temperature(const char *name)
1321 if (name == NULL || strcmp(name, "*") == 0) {
1324 if (!get_first_file_in_a_directory(ACPI_THERMAL_DIR, buf, &rep)) {
1330 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1332 fd = open(path, O_RDONLY);
1334 ERR("can't open '%s': %s", path, strerror(errno));
1340 static double last_acpi_temp;
1341 static double last_acpi_temp_time;
1343 double get_acpi_temperature(int fd)
1349 /* don't update acpi temperature too often */
1350 if (current_update_time - last_acpi_temp_time < 11.32) {
1351 return last_acpi_temp;
1353 last_acpi_temp_time = current_update_time;
1355 /* seek to beginning */
1356 lseek(fd, 0, SEEK_SET);
1363 n = read(fd, buf, 255);
1365 ERR("can't read fd %d: %s", fd, strerror(errno));
1368 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1372 return last_acpi_temp;
1376 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1378 design capacity: 4400 mAh
1379 last full capacity: 4064 mAh
1380 battery technology: rechargeable
1381 design voltage: 14800 mV
1382 design capacity warning: 300 mAh
1383 design capacity low: 200 mAh
1384 capacity granularity 1: 32 mAh
1385 capacity granularity 2: 32 mAh
1387 serial number: 16922
1393 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1396 charging state: unknown
1398 remaining capacity: 4064 mAh
1399 present voltage: 16608 mV
1403 2213<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1404 2213<@jupet�kellari��> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1405 2213<@jupet�kellari��> (-1 ollee ei akkua kiinni, koska akku on p�yd�ll�)
1406 2214<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1407 2214<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1409 2238<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1410 2239<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1412 2240<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori p��ll�
1413 2241<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori p��ll� mutta ilman verkkovirtaa
1416 /* Kapil Hari Paranjape <kapil@imsc.res.in>
1417 Linux 2.6.24 onwards battery info is in
1418 /sys/class/power_supply/BAT0/
1419 On my system I get the following.
1420 /sys/class/power_supply/BAT0/uevent:
1421 PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A03:00/device:01/PNP0C09:00/PNP0C0A:00
1423 PHYSDEVDRIVER=battery
1424 POWER_SUPPLY_NAME=BAT0
1425 POWER_SUPPLY_TYPE=Battery
1426 POWER_SUPPLY_STATUS=Discharging
1427 POWER_SUPPLY_PRESENT=1
1428 POWER_SUPPLY_TECHNOLOGY=Li-ion
1429 POWER_SUPPLY_VOLTAGE_MIN_DESIGN=10800000
1430 POWER_SUPPLY_VOLTAGE_NOW=10780000
1431 POWER_SUPPLY_CURRENT_NOW=13970000
1432 POWER_SUPPLY_ENERGY_FULL_DESIGN=47510000
1433 POWER_SUPPLY_ENERGY_FULL=27370000
1434 POWER_SUPPLY_ENERGY_NOW=11810000
1435 POWER_SUPPLY_MODEL_NAME=IBM-92P1060
1436 POWER_SUPPLY_MANUFACTURER=Panasonic
1437 On some systems POWER_SUPPLY_ENERGY_* is replaced by POWER_SUPPLY_CHARGE_*
1440 #define SYSFS_BATTERY_BASE_PATH "/sys/class/power_supply"
1441 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1442 #define APM_PATH "/proc/apm"
1443 #define MAX_BATTERY_COUNT 4
1445 static FILE *sysfs_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1446 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1447 static FILE *apm_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1449 static int batteries_initialized = 0;
1450 static char batteries[MAX_BATTERY_COUNT][32];
1452 static int acpi_last_full[MAX_BATTERY_COUNT];
1453 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1455 /* e.g. "charging 75%" */
1456 static char last_battery_str[MAX_BATTERY_COUNT][64];
1458 static char last_battery_time_str[MAX_BATTERY_COUNT][64];
1460 static double last_battery_time[MAX_BATTERY_COUNT];
1462 static int last_battery_perct[MAX_BATTERY_COUNT];
1463 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1465 void init_batteries(void)
1469 if (batteries_initialized) {
1473 #pragma omp parallel for
1474 #endif /* HAVE_OPENMP */
1475 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1476 batteries[idx][0] = '\0';
1478 batteries_initialized = 1;
1481 int get_battery_idx(const char *bat)
1485 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1486 if (!strlen(batteries[idx]) || !strcmp(batteries[idx], bat)) {
1491 /* if not found, enter a new entry */
1492 if (!strlen(batteries[idx])) {
1493 snprintf(batteries[idx], 31, "%s", bat);
1499 void set_return_value(char *buffer, unsigned int n, int item, int idx);
1501 void get_battery_stuff(char *buffer, unsigned int n, const char *bat, int item)
1503 static int idx, rep = 0, rep1 = 0, rep2 = 0;
1504 char acpi_path[128];
1505 char sysfs_path[128];
1507 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1508 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1512 idx = get_battery_idx(bat);
1514 /* don't update battery too often */
1515 if (current_update_time - last_battery_time[idx] < 29.5) {
1516 set_return_value(buffer, n, item, idx);
1520 last_battery_time[idx] = current_update_time;
1522 memset(last_battery_str[idx], 0, sizeof(last_battery_str[idx]));
1523 memset(last_battery_time_str[idx], 0, sizeof(last_battery_time_str[idx]));
1525 /* first try SYSFS if that fails try ACPI */
1527 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1528 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1531 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1532 acpi_bat_fp[idx] = open_file(acpi_path, &rep1);
1535 if (sysfs_bat_fp[idx] != NULL) {
1537 int present_rate = -1;
1538 int remaining_capacity = -1;
1539 char charging_state[64];
1542 strcpy(charging_state, "unknown");
1544 while (!feof(sysfs_bat_fp[idx])) {
1546 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1549 /* let's just hope units are ok */
1550 if (strncmp (buf, "POWER_SUPPLY_PRESENT=1", 22) == 0)
1551 strcpy(present, "yes");
1552 else if (strncmp (buf, "POWER_SUPPLY_PRESENT=0", 22) == 0)
1553 strcpy(present, "no");
1554 else if (strncmp (buf, "POWER_SUPPLY_STATUS=", 20) == 0)
1555 sscanf(buf, "POWER_SUPPLY_STATUS=%63s", charging_state);
1556 /* present_rate is not the same as the
1557 current flowing now but it is the same value
1558 which was used in the past. so we continue
1560 else if (strncmp(buf, "POWER_SUPPLY_CURRENT_NOW=", 25) == 0)
1561 sscanf(buf, "POWER_SUPPLY_CURRENT_NOW=%d", &present_rate);
1562 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0)
1563 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1564 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=", 25) == 0)
1565 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_last_full[idx]);
1566 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0)
1567 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1568 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=", 25) == 0)
1569 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_last_full[idx]);
1572 fclose(sysfs_bat_fp[idx]);
1573 sysfs_bat_fp[idx] = NULL;
1575 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1576 if (remaining_capacity > acpi_last_full[idx])
1577 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1580 if (strcmp(present, "No") == 0) {
1581 strncpy(last_battery_str[idx], "not present", 64);
1584 else if (strcmp(charging_state, "Charging") == 0) {
1585 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1586 /* e.g. charging 75% */
1587 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %i%%",
1588 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1590 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1591 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1592 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1593 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %d%%",
1594 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1595 snprintf(last_battery_time_str[idx],
1596 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1598 strncpy(last_battery_str[idx], "charging", sizeof(last_battery_str[idx])-1);
1599 snprintf(last_battery_time_str[idx],
1600 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1604 else if (strncmp(charging_state, "Discharging", 64) == 0) {
1605 if (present_rate > 0) {
1606 /* e.g. discharging 35% */
1607 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "discharging %i%%",
1608 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1610 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1611 (long) (((float) remaining_capacity / present_rate) * 3600));
1612 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1613 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "full");
1614 snprintf(last_battery_time_str[idx],
1615 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1617 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1619 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1620 snprintf(last_battery_time_str[idx],
1621 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1625 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1626 else if (strncmp(charging_state, "Charged", 64) == 0) {
1627 /* Below happens with the second battery on my X40,
1628 * when the second one is empty and the first one
1630 if (remaining_capacity == 0)
1631 strcpy(last_battery_str[idx], "empty");
1633 strcpy(last_battery_str[idx], "charged");
1635 /* unknown, probably full / AC */
1637 if (acpi_last_full[idx] != 0
1638 && remaining_capacity != acpi_last_full[idx])
1639 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1640 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1642 strncpy(last_battery_str[idx], "AC", 64);
1644 } else if (acpi_bat_fp[idx] != NULL) {
1646 int present_rate = -1;
1647 int remaining_capacity = -1;
1648 char charging_state[64];
1651 /* read last full capacity if it's zero */
1652 if (acpi_last_full[idx] == 0) {
1653 static int rep3 = 0;
1657 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1658 fp = open_file(path, &rep3);
1663 if (fgets(b, 256, fp) == NULL) {
1666 if (sscanf(b, "last full capacity: %d",
1667 &acpi_last_full[idx]) != 0) {
1676 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1678 strcpy(charging_state, "unknown");
1680 while (!feof(acpi_bat_fp[idx])) {
1683 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1687 /* let's just hope units are ok */
1688 if (strncmp(buf, "present:", 8) == 0) {
1689 sscanf(buf, "present: %4s", present);
1690 } else if (strncmp(buf, "charging state:", 15) == 0) {
1691 sscanf(buf, "charging state: %63s", charging_state);
1692 } else if (strncmp(buf, "present rate:", 13) == 0) {
1693 sscanf(buf, "present rate: %d", &present_rate);
1694 } else if (strncmp(buf, "remaining capacity:", 19) == 0) {
1695 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1698 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1699 if (remaining_capacity > acpi_last_full[idx]) {
1700 /* normalize to 100% */
1701 acpi_last_full[idx] = remaining_capacity;
1705 if (strcmp(present, "no") == 0) {
1706 strncpy(last_battery_str[idx], "not present", 64);
1708 } else if (strcmp(charging_state, "charging") == 0) {
1709 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1710 /* e.g. charging 75% */
1711 snprintf(last_battery_str[idx],
1712 sizeof(last_battery_str[idx]) - 1, "charging %i%%",
1713 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1715 format_seconds(last_battery_time_str[idx],
1716 sizeof(last_battery_time_str[idx]) - 1,
1717 (long) (((acpi_last_full[idx] - remaining_capacity) *
1718 3600) / present_rate));
1719 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1720 snprintf(last_battery_str[idx],
1721 sizeof(last_battery_str[idx]) - 1, "charging %d%%",
1722 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1723 snprintf(last_battery_time_str[idx],
1724 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1726 strncpy(last_battery_str[idx], "charging",
1727 sizeof(last_battery_str[idx]) - 1);
1728 snprintf(last_battery_time_str[idx],
1729 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1732 } else if (strncmp(charging_state, "discharging", 64) == 0) {
1733 if (present_rate > 0) {
1734 /* e.g. discharging 35% */
1735 snprintf(last_battery_str[idx],
1736 sizeof(last_battery_str[idx]) - 1, "discharging %i%%",
1737 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1739 format_seconds(last_battery_time_str[idx],
1740 sizeof(last_battery_time_str[idx]) - 1,
1741 (long) ((remaining_capacity * 3600) / present_rate));
1742 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1743 snprintf(last_battery_str[idx],
1744 sizeof(last_battery_str[idx]) - 1, "full");
1745 snprintf(last_battery_time_str[idx],
1746 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1748 snprintf(last_battery_str[idx],
1749 sizeof(last_battery_str[idx]) - 1, "discharging %d%%",
1750 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1751 snprintf(last_battery_time_str[idx],
1752 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1755 } else if (strncmp(charging_state, "charged", 64) == 0) {
1756 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1757 /* Below happens with the second battery on my X40,
1758 * when the second one is empty and the first one being charged. */
1759 if (remaining_capacity == 0) {
1760 strcpy(last_battery_str[idx], "empty");
1762 strcpy(last_battery_str[idx], "charged");
1764 /* unknown, probably full / AC */
1766 if (strncmp(charging_state, "Full", 64) == 0) {
1767 strncpy(last_battery_str[idx], "full", 64);
1768 } else if (acpi_last_full[idx] != 0
1769 && remaining_capacity != acpi_last_full[idx]) {
1770 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1771 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1773 strncpy(last_battery_str[idx], "AC", 64);
1778 if (apm_bat_fp[idx] == NULL) {
1779 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1782 if (apm_bat_fp[idx] != NULL) {
1783 unsigned int ac, status, flag;
1786 fscanf(apm_bat_fp[idx], "%*s %*s %*x %x %x %x %d%%",
1787 &ac, &status, &flag, &life);
1790 /* could check now that there is ac */
1791 snprintf(last_battery_str[idx], 64, "AC");
1793 /* could check that status == 3 here? */
1794 } else if (ac && life != 100) {
1795 snprintf(last_battery_str[idx], 64, "charging %d%%", life);
1797 snprintf(last_battery_str[idx], 64, "%d%%", life);
1800 /* it seemed to buffer it so file must be closed (or could use
1801 * syscalls directly but I don't feel like coding it now) */
1802 fclose(apm_bat_fp[idx]);
1803 apm_bat_fp[idx] = NULL;
1806 set_return_value(buffer, n, item, idx);
1809 void set_return_value(char *buffer, unsigned int n, int item, int idx)
1812 case BATTERY_STATUS:
1813 snprintf(buffer, n, "%s", last_battery_str[idx]);
1816 snprintf(buffer, n, "%s", last_battery_time_str[idx]);
1823 void get_battery_short_status(char *buffer, unsigned int n, const char *bat)
1825 get_battery_stuff(buffer, n, bat, BATTERY_STATUS);
1826 if (0 == strncmp("charging", buffer, 8)) {
1828 memmove(buffer + 1, buffer + 8, n - 8);
1829 } else if (0 == strncmp("discharging", buffer, 11)) {
1831 memmove(buffer + 1, buffer + 11, n - 11);
1835 int get_battery_perct(const char *bat)
1839 char acpi_path[128];
1840 char sysfs_path[128];
1841 int remaining_capacity = -1;
1843 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1844 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1848 idx = get_battery_idx(bat);
1850 /* don't update battery too often */
1851 if (current_update_time - last_battery_perct_time[idx] < 30) {
1852 return last_battery_perct[idx];
1854 last_battery_perct_time[idx] = current_update_time;
1856 /* Only check for SYSFS or ACPI */
1858 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1859 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1863 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1864 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1867 if (sysfs_bat_fp[idx] != NULL) {
1869 while (!feof(sysfs_bat_fp[idx])) {
1871 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1874 if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0) {
1875 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1876 } else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=",25) == 0) {
1877 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_design_capacity[idx]);
1878 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0) {
1879 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1880 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=",25) == 0) {
1881 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_design_capacity[idx]);
1885 fclose(sysfs_bat_fp[idx]);
1886 sysfs_bat_fp[idx] = NULL;
1888 } else if (acpi_bat_fp[idx] != NULL) {
1890 /* read last full capacity if it's zero */
1891 if (acpi_design_capacity[idx] == 0) {
1896 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1897 fp = open_file(path, &rep2);
1902 if (fgets(b, 256, fp) == NULL) {
1905 if (sscanf(b, "last full capacity: %d",
1906 &acpi_design_capacity[idx]) != 0) {
1914 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1916 while (!feof(acpi_bat_fp[idx])) {
1919 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1923 if (buf[0] == 'r') {
1924 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1928 if (remaining_capacity < 0) {
1931 /* compute the battery percentage */
1932 last_battery_perct[idx] =
1933 (int) (((float) remaining_capacity / acpi_design_capacity[idx]) * 100);
1934 if (last_battery_perct[idx] > 100) last_battery_perct[idx] = 100;
1935 return last_battery_perct[idx];
1938 int get_battery_perct_bar(const char *bar)
1942 get_battery_perct(bar);
1943 idx = get_battery_idx(bar);
1944 return (int) (last_battery_perct[idx] * 2.56 - 1);
1947 /* On Apple powerbook and ibook:
1948 $ cat /proc/pmu/battery_0
1955 $ cat /proc/pmu/info
1956 PMU driver version : 2
1957 PMU firmware version : 0c
1962 /* defines as in <linux/pmu.h> */
1963 #define PMU_BATT_PRESENT 0x00000001
1964 #define PMU_BATT_CHARGING 0x00000002
1966 static FILE *pmu_battery_fp;
1967 static FILE *pmu_info_fp;
1968 static char pb_battery_info[3][32];
1969 static double pb_battery_info_update;
1971 #define PMU_PATH "/proc/pmu"
1972 void get_powerbook_batt_info(char *buffer, size_t n, int i)
1975 const char *batt_path = PMU_PATH "/battery_0";
1976 const char *info_path = PMU_PATH "/info";
1978 int charge, max_charge, ac = -1;
1981 /* don't update battery too often */
1982 if (current_update_time - pb_battery_info_update < 29.5) {
1983 snprintf(buffer, n, "%s", pb_battery_info[i]);
1986 pb_battery_info_update = current_update_time;
1988 if (pmu_battery_fp == NULL) {
1989 pmu_battery_fp = open_file(batt_path, &rep);
1990 if (pmu_battery_fp == NULL) {
1995 if (pmu_battery_fp != NULL) {
1996 rewind(pmu_battery_fp);
1997 while (!feof(pmu_battery_fp)) {
2000 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL) {
2004 if (buf[0] == 'f') {
2005 sscanf(buf, "flags : %8x", &flags);
2006 } else if (buf[0] == 'c' && buf[1] == 'h') {
2007 sscanf(buf, "charge : %d", &charge);
2008 } else if (buf[0] == 'm') {
2009 sscanf(buf, "max_charge : %d", &max_charge);
2010 } else if (buf[0] == 't') {
2011 sscanf(buf, "time rem. : %ld", &timeval);
2015 if (pmu_info_fp == NULL) {
2016 pmu_info_fp = open_file(info_path, &rep);
2017 if (pmu_info_fp == NULL) {
2022 if (pmu_info_fp != NULL) {
2023 rewind(pmu_info_fp);
2024 while (!feof(pmu_info_fp)) {
2027 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL) {
2030 if (buf[0] == 'A') {
2031 sscanf(buf, "AC Power : %d", &ac);
2035 /* update status string */
2036 if ((ac && !(flags & PMU_BATT_PRESENT))) {
2037 strncpy(pb_battery_info[PB_BATT_STATUS], "AC", sizeof(pb_battery_info[PB_BATT_STATUS]));
2038 } else if (ac && (flags & PMU_BATT_PRESENT)
2039 && !(flags & PMU_BATT_CHARGING)) {
2040 strncpy(pb_battery_info[PB_BATT_STATUS], "charged", sizeof(pb_battery_info[PB_BATT_STATUS]));
2041 } else if ((flags & PMU_BATT_PRESENT) && (flags & PMU_BATT_CHARGING)) {
2042 strncpy(pb_battery_info[PB_BATT_STATUS], "charging", sizeof(pb_battery_info[PB_BATT_STATUS]));
2044 strncpy(pb_battery_info[PB_BATT_STATUS], "discharging", sizeof(pb_battery_info[PB_BATT_STATUS]));
2047 /* update percentage string */
2048 if (timeval == 0 && ac && (flags & PMU_BATT_PRESENT)
2049 && !(flags & PMU_BATT_CHARGING)) {
2050 snprintf(pb_battery_info[PB_BATT_PERCENT],
2051 sizeof(pb_battery_info[PB_BATT_PERCENT]), "100%%");
2052 } else if (timeval == 0) {
2053 snprintf(pb_battery_info[PB_BATT_PERCENT],
2054 sizeof(pb_battery_info[PB_BATT_PERCENT]), "unknown");
2056 snprintf(pb_battery_info[PB_BATT_PERCENT],
2057 sizeof(pb_battery_info[PB_BATT_PERCENT]), "%d%%",
2058 (charge * 100) / max_charge);
2061 /* update time string */
2062 if (timeval == 0) { /* fully charged or battery not present */
2063 snprintf(pb_battery_info[PB_BATT_TIME],
2064 sizeof(pb_battery_info[PB_BATT_TIME]), "unknown");
2065 } else if (timeval < 60 * 60) { /* don't show secs */
2066 format_seconds_short(pb_battery_info[PB_BATT_TIME],
2067 sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2069 format_seconds(pb_battery_info[PB_BATT_TIME],
2070 sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2073 snprintf(buffer, n, "%s", pb_battery_info[i]);
2076 void update_top(void)
2078 show_nice_processes = 1;
2079 process_find_top(info.cpu, info.memu, info.time);
2080 info.first_process = get_first_process();
2083 void update_entropy(void)
2086 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
2087 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
2090 info.entropy.entropy_avail = 0;
2091 info.entropy.poolsize = 0;
2093 if ((fp1 = open_file(entropy_avail, &rep)) == NULL) {
2097 if ((fp2 = open_file(entropy_poolsize, &rep)) == NULL) {
2102 fscanf(fp1, "%u", &info.entropy.entropy_avail);
2103 fscanf(fp2, "%u", &info.entropy.poolsize);
2108 info.mask |= (1 << INFO_ENTROPY);
2111 const char *get_disk_protect_queue(const char *disk)
2117 snprintf(path, 127, "/sys/block/%s/device/unload_heads", disk);
2118 if (access(path, F_OK)) {
2119 snprintf(path, 127, "/sys/block/%s/queue/protect", disk);
2121 if ((fp = fopen(path, "r")) == NULL)
2123 if (fscanf(fp, "%d\n", &state) != 1) {
2128 return (state > 0) ? "frozen" : "free ";