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-2008 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 int interface_up(const char *dev)
219 if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
220 CRIT_ERR("could not create sockfd");
223 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
224 if (ioctl(fd, SIOCGIFFLAGS, &ifr)) {
225 /* if device does not exist, treat like not up */
227 perror("SIOCGIFFLAGS");
231 if (!(ifr.ifr_flags & IFF_UP)) /* iface is not up */
233 if (ifup_strictness == IFUP_UP)
236 if (!(ifr.ifr_flags & IFF_RUNNING))
238 if (ifup_strictness == IFUP_LINK)
241 if (ioctl(fd, SIOCGIFADDR, &ifr)) {
242 perror("SIOCGIFADDR");
245 if (((struct sockaddr_in *)&(ifr.ifr_ifru.ifru_addr))->sin_addr.s_addr)
256 #define COND_FREE(x) if(x) free(x); x = 0
257 #define SAVE_SET_STRING(x, y) \
258 if (x && strcmp((char *)x, (char *)y)) { \
260 x = strndup("multiple", text_buffer_size); \
262 x = strndup(y, text_buffer_size); \
265 void update_gateway_info_failure(const char *reason)
270 //2 pointers to 1 location causes a crash when we try to free them both
271 info.gw_info.iface = strndup("failed", text_buffer_size);
272 info.gw_info.ip = strndup("failed", text_buffer_size);
276 /* Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT */
277 #define RT_ENTRY_FORMAT "%63s %lx %lx %x %*d %*d %*d %lx %*d %*d %*d\n"
279 void update_gateway_info(void)
284 unsigned long dest, gate, mask;
287 struct gateway_info *gw_info = &info.gw_info;
289 COND_FREE(gw_info->iface);
290 COND_FREE(gw_info->ip);
293 if ((fp = fopen("/proc/net/route", "r")) == NULL) {
294 update_gateway_info_failure("fopen()");
298 /* skip over the table header line, which is always present */
299 fscanf(fp, "%*[^\n]\n");
302 if(fscanf(fp, RT_ENTRY_FORMAT,
303 iface, &dest, &gate, &flags, &mask) != 5) {
304 update_gateway_info_failure("fscanf()");
307 if (!(dest || mask) && ((flags & RTF_GATEWAY) || !gate) ) {
309 SAVE_SET_STRING(gw_info->iface, iface)
311 SAVE_SET_STRING(gw_info->ip, inet_ntoa(ina))
318 void update_net_stats(void)
322 static char first = 1;
324 // FIXME: arbitrary size chosen to keep code simple.
326 unsigned int curtmp1, curtmp2;
333 // wireless info variables
334 int skfd, has_bitrate = 0;
335 struct wireless_info *winfo;
340 delta = current_update_time - last_update_time;
341 if (delta <= 0.0001) {
345 /* open file and ignore first two lines */
346 if (!(net_dev_fp = open_file("/proc/net/dev", &rep))) {
351 fgets(buf, 255, net_dev_fp); /* garbage */
352 fgets(buf, 255, net_dev_fp); /* garbage (field names) */
354 /* read each interface */
355 for (i2 = 0; i2 < 16; i2++) {
359 long long r, t, last_recv, last_trans;
361 if (fgets(buf, 255, net_dev_fp) == NULL) {
365 while (isspace((int) *p)) {
371 while (*p && *p != ':') {
380 ns = get_net_stat(s);
382 memset(&(ns->addr.sa_data), 0, 14);
384 if(NULL == ns->addrs)
385 ns->addrs = (char*) malloc(17 * 16 + 1);
386 if(NULL != ns->addrs)
387 memset(ns->addrs, 0, 17 * 16 + 1); /* Up to 17 chars per ip, max 16 interfaces. Nasty memory usage... */
389 last_recv = ns->recv;
390 last_trans = ns->trans;
392 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
393 sscanf(p, "%lld %*d %*d %*d %*d %*d %*d %*d %lld",
396 /* if recv or trans is less than last time, an overflow happened */
397 if (r < ns->last_read_recv) {
400 ns->recv += (r - ns->last_read_recv);
402 ns->last_read_recv = r;
404 if (t < ns->last_read_trans) {
407 ns->trans += (t - ns->last_read_trans);
409 ns->last_read_trans = t;
411 /*** ip addr patch ***/
412 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
414 conf.ifc_buf = malloc(sizeof(struct ifreq) * 16);
415 conf.ifc_len = sizeof(struct ifreq) * 16;
416 memset(conf.ifc_buf, 0, conf.ifc_len);
418 ioctl((long) i, SIOCGIFCONF, &conf);
420 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
421 struct net_stat *ns2;
423 if (!(((struct ifreq *) conf.ifc_buf) + k))
427 ((struct ifreq *) conf.ifc_buf)[k].ifr_ifrn.ifrn_name);
428 ns2->addr = ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.ifru_addr;
429 if(NULL != ns2->addrs) {
430 sprintf(temp_addr, "%u.%u.%u.%u, ",
431 ns2->addr.sa_data[2] & 255,
432 ns2->addr.sa_data[3] & 255,
433 ns2->addr.sa_data[4] & 255,
434 ns2->addr.sa_data[5] & 255);
435 if(NULL == strstr(ns2->addrs, temp_addr))
436 strncpy(ns2->addrs + strlen(ns2->addrs), temp_addr, 17);
444 /*** end ip addr patch ***/
447 /* calculate speeds */
448 ns->net_rec[0] = (ns->recv - last_recv) / delta;
449 ns->net_trans[0] = (ns->trans - last_trans) / delta;
455 for (i = 0; (unsigned) i < info.net_avg_samples; i++) {
456 curtmp1 += ns->net_rec[i];
457 curtmp2 += ns->net_trans[i];
465 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
466 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
467 if (info.net_avg_samples > 1) {
468 for (i = info.net_avg_samples; i > 1; i--) {
469 ns->net_rec[i - 1] = ns->net_rec[i - 2];
470 ns->net_trans[i - 1] = ns->net_trans[i - 2];
475 /* update wireless info */
476 winfo = malloc(sizeof(struct wireless_info));
477 memset(winfo, 0, sizeof(struct wireless_info));
479 skfd = iw_sockets_open();
480 if (iw_get_basic_config(skfd, s, &(winfo->b)) > -1) {
482 // set present winfo variables
483 if (iw_get_stats(skfd, s, &(winfo->stats),
484 &winfo->range, winfo->has_range) >= 0) {
485 winfo->has_stats = 1;
487 if (iw_get_range_info(skfd, s, &(winfo->range)) >= 0) {
488 winfo->has_range = 1;
490 if (iw_get_ext(skfd, s, SIOCGIWAP, &wrq) >= 0) {
491 winfo->has_ap_addr = 1;
492 memcpy(&(winfo->ap_addr), &(wrq.u.ap_addr), sizeof(sockaddr));
496 if (iw_get_ext(skfd, s, SIOCGIWRATE, &wrq) >= 0) {
497 memcpy(&(winfo->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
498 iw_print_bitrate(ns->bitrate, 16, winfo->bitrate.value);
503 if (winfo->has_range && winfo->has_stats
504 && ((winfo->stats.qual.level != 0)
505 || (winfo->stats.qual.updated & IW_QUAL_DBM))) {
506 if (!(winfo->stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
507 ns->link_qual = winfo->stats.qual.qual;
508 ns->link_qual_max = winfo->range.max_qual.qual;
513 if (winfo->has_ap_addr) {
514 iw_sawap_ntop(&winfo->ap_addr, ns->ap);
518 if (winfo->b.has_essid) {
519 if (winfo->b.essid_on) {
520 snprintf(ns->essid, 32, "%s", winfo->b.essid);
522 snprintf(ns->essid, 32, "off/any");
526 snprintf(ns->mode, 16, "%s", iw_operation_mode[winfo->b.mode]);
528 iw_sockets_close(skfd);
536 info.mask |= (1 << INFO_NET);
541 void update_total_processes(void)
545 struct sysinfo s_info;
548 info.procs = s_info.procs;
555 if (!(fp = open_file("/proc/loadavg", &rep))) {
559 fscanf(fp, "%*f %*f %*f %*d/%hu", &info.procs);
562 info.mask |= (1 << INFO_PROCS);
565 #define CPU_SAMPLE_COUNT 15
567 unsigned long long cpu_user;
568 unsigned long long cpu_system;
569 unsigned long long cpu_nice;
570 unsigned long long cpu_idle;
571 unsigned long long cpu_iowait;
572 unsigned long long cpu_irq;
573 unsigned long long cpu_softirq;
574 unsigned long long cpu_steal;
575 unsigned long long cpu_total;
576 unsigned long long cpu_active_total;
577 unsigned long long cpu_last_total;
578 unsigned long long cpu_last_active_total;
579 double cpu_val[CPU_SAMPLE_COUNT];
581 static short cpu_setup = 0;
583 /* Determine if this kernel gives us "extended" statistics information in
585 * Kernels around 2.5 and earlier only reported user, system, nice, and
586 * idle values in proc stat.
587 * Kernels around 2.6 and greater report these PLUS iowait, irq, softirq,
589 void determine_longstat(char *buf)
591 unsigned long long iowait = 0;
593 KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
594 /* scanf will either return -1 or 1 because there is only 1 assignment */
595 if (sscanf(buf, "%*s %*d %*d %*d %*d %llu", &iowait) > 0) {
596 KFLAG_SETON(KFLAG_IS_LONGSTAT);
600 void get_cpu_count(void)
606 if (info.cpu_usage) {
610 if (!(stat_fp = open_file("/proc/stat", &rep))) {
616 while (!feof(stat_fp)) {
617 if (fgets(buf, 255, stat_fp) == NULL) {
621 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
622 if (info.cpu_count == 0) {
623 determine_longstat(buf);
628 info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
633 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
634 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
636 inline static void update_stat(void)
640 static struct cpu_info *cpu = NULL;
645 const char *stat_template = NULL;
646 unsigned int malloc_cpu_size = 0;
648 /* add check for !info.cpu_usage since that mem is freed on a SIGUSR1 */
649 if (!cpu_setup || !info.cpu_usage) {
654 if (!stat_template) {
656 KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT;
660 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
661 cpu = malloc(malloc_cpu_size);
662 memset(cpu, 0, malloc_cpu_size);
665 if (!(stat_fp = open_file("/proc/stat", &rep))) {
667 if (info.cpu_usage) {
668 memset(info.cpu_usage, 0, info.cpu_count * sizeof(float));
674 while (!feof(stat_fp)) {
675 if (fgets(buf, 255, stat_fp) == NULL) {
679 if (strncmp(buf, "procs_running ", 14) == 0) {
680 sscanf(buf, "%*s %hu", &info.run_procs);
681 info.mask |= (1 << INFO_RUN_PROCS);
682 } else if (strncmp(buf, "cpu", 3) == 0) {
684 if (isdigit(buf[3])) {
685 idx = atoi(&buf[3]) + 1;
689 sscanf(buf, stat_template, &(cpu[idx].cpu_user),
690 &(cpu[idx].cpu_nice), &(cpu[idx].cpu_system),
691 &(cpu[idx].cpu_idle), &(cpu[idx].cpu_iowait),
692 &(cpu[idx].cpu_irq), &(cpu[idx].cpu_softirq),
693 &(cpu[idx].cpu_steal));
695 cpu[idx].cpu_total = cpu[idx].cpu_user + cpu[idx].cpu_nice +
696 cpu[idx].cpu_system + cpu[idx].cpu_idle +
697 cpu[idx].cpu_iowait + cpu[idx].cpu_irq +
698 cpu[idx].cpu_softirq + cpu[idx].cpu_steal;
700 cpu[idx].cpu_active_total = cpu[idx].cpu_total -
701 (cpu[idx].cpu_idle + cpu[idx].cpu_iowait);
702 info.mask |= (1 << INFO_CPU);
704 delta = current_update_time - last_update_time;
706 if (delta <= 0.001) {
710 cpu[idx].cpu_val[0] = (cpu[idx].cpu_active_total -
711 cpu[idx].cpu_last_active_total) /
712 (float) (cpu[idx].cpu_total - cpu[idx].cpu_last_total);
714 for (i = 0; i < info.cpu_avg_samples; i++) {
715 curtmp += cpu[idx].cpu_val[i];
717 /* TESTING -- I've removed this, because I don't think it is right.
718 * You shouldn't divide by the cpu count here ...
719 * removing for testing */
721 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples /
724 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples;
726 /* TESTING -- this line replaces the prev. "suspect" if/else */
727 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples;
729 cpu[idx].cpu_last_total = cpu[idx].cpu_total;
730 cpu[idx].cpu_last_active_total = cpu[idx].cpu_active_total;
731 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
732 cpu[idx].cpu_val[i] = cpu[idx].cpu_val[i - 1];
739 void update_running_processes(void)
744 void update_cpu_usage(void)
749 void update_load_average(void)
751 #ifdef HAVE_GETLOADAVG
756 info.loadavg[0] = (float) v[0];
757 info.loadavg[1] = (float) v[1];
758 info.loadavg[2] = (float) v[2];
765 if (!(fp = open_file("/proc/loadavg", &rep))) {
766 info.loadavg[0] = info.loadavg[1] = info.loadavg[2] = 0.0;
769 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1],
773 info.mask |= (1 << INFO_LOADAVG);
776 #define PROC_I8K "/proc/i8k"
777 #define I8K_DELIM " "
778 static char *i8k_procbuf = NULL;
779 void update_i8k(void)
784 i8k_procbuf = (char *) malloc(128 * sizeof(char));
786 if ((fp = fopen(PROC_I8K, "r")) == NULL) {
787 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel "
788 "driver is loaded...");
791 memset(&i8k_procbuf[0], 0, 128);
792 if (fread(&i8k_procbuf[0], sizeof(char), 128, fp) == 0) {
793 ERR("something wrong with /proc/i8k...");
798 i8k.version = strtok(&i8k_procbuf[0], I8K_DELIM);
799 i8k.bios = strtok(NULL, I8K_DELIM);
800 i8k.serial = strtok(NULL, I8K_DELIM);
801 i8k.cpu_temp = strtok(NULL, I8K_DELIM);
802 i8k.left_fan_status = strtok(NULL, I8K_DELIM);
803 i8k.right_fan_status = strtok(NULL, I8K_DELIM);
804 i8k.left_fan_rpm = strtok(NULL, I8K_DELIM);
805 i8k.right_fan_rpm = strtok(NULL, I8K_DELIM);
806 i8k.ac_status = strtok(NULL, I8K_DELIM);
807 i8k.buttons_status = strtok(NULL, I8K_DELIM);
810 /***********************************************************/
811 /***********************************************************/
812 /***********************************************************/
814 static int no_dots(const struct dirent *d)
816 if (d->d_name[0] == '.') {
822 static int get_first_file_in_a_directory(const char *dir, char *s, int *rep)
824 struct dirent **namelist;
827 n = scandir(dir, &namelist, no_dots, alphasort);
830 ERR("scandir for %s: %s", dir, strerror(errno));
841 strncpy(s, namelist[0]->d_name, 255);
844 for (i = 0; i < n; i++) {
853 int open_sysfs_sensor(const char *dir, const char *dev, const char *type, int n,
854 int *divisor, char *devtype)
861 memset(buf, 0, sizeof(buf));
863 /* if device is NULL or *, get first */
864 if (dev == NULL || strcmp(dev, "*") == 0) {
867 if (!get_first_file_in_a_directory(dir, buf, &rep)) {
873 if (strcmp(dir, "/sys/class/hwmon/") == 0) {
875 /* buf holds result from get_first_file_in_a_directory() above,
876 * e.g. "hwmon0" -- append "/device" */
877 strcat(buf, "/device");
879 /* dev holds device number N as a string,
880 * e.g. "0", -- convert to "hwmon0/device" */
881 sprintf(buf, "hwmon%s/device", dev);
886 /* change vol to in */
887 if (strcmp(type, "vol") == 0) {
891 if (strcmp(type, "tempf") == 0) {
892 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, "temp", n);
894 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, type, n);
896 strncpy(devtype, path, 255);
899 fd = open(path, O_RDONLY);
901 CRIT_ERR("can't open '%s': %s\nplease check your device or remove this "
902 "var from "PACKAGE_NAME, path, strerror(errno));
905 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
906 || strcmp(type, "tempf") == 0) {
911 /* fan does not use *_div as a read divisor */
912 if (strcmp("fan", type) == 0) {
916 /* test if *_div file exist, open it and use it as divisor */
917 if (strcmp(type, "tempf") == 0) {
918 snprintf(path, 255, "%s%s/%s%d_div", dir, "one", "two", n);
920 snprintf(path, 255, "%s%s/%s%d_div", dir, dev, type, n);
923 divfd = open(path, O_RDONLY);
929 divn = read(divfd, divbuf, 63);
930 /* should read until n == 0 but I doubt that kernel will give these
931 * in multiple pieces. :) */
933 ERR("open_sysfs_sensor(): can't read from sysfs");
936 *divisor = atoi(divbuf);
945 double get_sysfs_info(int *fd, int divisor, char *devtype, char *type)
953 lseek(*fd, 0, SEEK_SET);
959 n = read(*fd, buf, 63);
960 /* should read until n == 0 but I doubt that kernel will give these
961 * in multiple pieces. :) */
963 ERR("get_sysfs_info(): read from %s failed\n", devtype);
972 *fd = open(devtype, O_RDONLY);
974 ERR("can't open '%s': %s", devtype, strerror(errno));
977 /* My dirty hack for computing CPU value
978 * Filedil, from forums.gentoo.org */
979 /* if (strstr(devtype, "temp1_input") != NULL) {
980 return -15.096 + 1.4893 * (val / 1000.0);
983 /* divide voltage and temperature by 1000 */
984 /* or if any other divisor is given, use that */
985 if (strcmp(type, "tempf") == 0) {
987 return ((val / divisor + 40) * 9.0 / 5) - 40;
988 } else if (divisor) {
989 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
991 return ((val + 40) * 9.0 / 5) - 40;
995 return val / divisor;
996 } else if (divisor) {
1004 /* Prior to kernel version 2.6.12, the CPU fan speed was available in
1005 * ADT746X_FAN_OLD, whereas later kernel versions provide this information in
1007 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
1008 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
1010 void get_adt746x_fan(char *p_client_buffer, size_t client_buffer_size)
1013 char adt746x_fan_state[64];
1016 if (!p_client_buffer || client_buffer_size <= 0) {
1020 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
1021 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL) {
1022 sprintf(adt746x_fan_state, "adt746x not found");
1024 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
1025 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
1029 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_fan_state);
1032 /* Prior to kernel version 2.6.12, the CPU temperature was found in
1033 * ADT746X_CPU_OLD, whereas later kernel versions provide this information in
1035 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
1036 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
1038 void get_adt746x_cpu(char *p_client_buffer, size_t client_buffer_size)
1041 char adt746x_cpu_state[64];
1044 if (!p_client_buffer || client_buffer_size <= 0) {
1048 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
1049 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL) {
1050 sprintf(adt746x_cpu_state, "adt746x not found");
1052 fscanf(fp, "%2s", adt746x_cpu_state);
1056 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state);
1059 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
1060 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
1062 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1063 char get_freq(char *p_client_buffer, size_t client_buffer_size,
1064 const char *p_format, int divisor, unsigned int cpu)
1072 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1078 char current_freq_file[128];
1080 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu - 1,
1082 f = fopen(current_freq_file, "r");
1084 /* if there's a cpufreq /sys node, read the current frequency from
1085 * this node and divide by 1000 to get Mhz. */
1086 if (fgets(s, sizeof(s), f)) {
1087 s[strlen(s) - 1] = '\0';
1088 freq = strtod(s, NULL);
1091 snprintf(p_client_buffer, client_buffer_size, p_format,
1092 (freq / 1000) / divisor);
1097 // open the CPU information file
1098 f = open_file("/proc/cpuinfo", &rep);
1100 perror(PACKAGE_NAME": Failed to access '/proc/cpuinfo' at get_freq()");
1105 while (fgets(s, sizeof(s), f) != NULL) {
1107 #if defined(__i386) || defined(__x86_64)
1108 // and search for the cpu mhz
1109 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) {
1111 #if defined(__alpha)
1112 // different on alpha
1113 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) {
1115 // this is different on ppc for some reason
1116 if (strncmp(s, "clock", 5) == 0 && cpu == 0) {
1117 #endif // defined(__alpha)
1118 #endif // defined(__i386) || defined(__x86_64)
1120 // copy just the number
1121 strcpy(frequency, strchr(s, ':') + 2);
1122 #if defined(__alpha)
1124 frequency[strlen(frequency) - 6] = '\0';
1125 // kernel reports in Hz
1126 freq = strtod(frequency, NULL) / 1000000;
1129 frequency[strlen(frequency) - 1] = '\0';
1130 freq = strtod(frequency, NULL);
1134 if (strncmp(s, "processor", 9) == 0) {
1141 snprintf(p_client_buffer, client_buffer_size, p_format,
1142 (float) freq / divisor);
1146 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
1148 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks something
1158 * Peter Tarjan (ptarjan@citromail.hu) */
1160 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
1161 char get_voltage(char *p_client_buffer, size_t client_buffer_size,
1162 const char *p_format, int divisor, unsigned int cpu)
1168 char current_freq_file[128];
1171 /* build the voltage file name */
1173 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1176 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1181 /* read the current cpu frequency from the /sys node */
1182 f = fopen(current_freq_file, "r");
1184 if (fgets(s, sizeof(s), f)) {
1185 s[strlen(s) - 1] = '\0';
1186 freq = strtod(s, NULL);
1190 fprintf(stderr, PACKAGE_NAME": Failed to access '%s' at ", current_freq_file);
1191 perror("get_voltage()");
1198 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1201 /* use the current cpu frequency to find the corresponding voltage */
1202 f = fopen(current_freq_file, "r");
1208 if (fgets(line, 255, f) == NULL) {
1211 sscanf(line, "%d %d", &freq_comp, &voltage);
1212 if (freq_comp == freq) {
1218 fprintf(stderr, PACKAGE_NAME": Failed to access '%s' at ", current_freq_file);
1219 perror("get_voltage()");
1225 snprintf(p_client_buffer, client_buffer_size, p_format,
1226 (float) voltage / divisor);
1230 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1232 void get_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
1239 if (!p_client_buffer || client_buffer_size <= 0) {
1243 /* yeah, slow... :/ */
1244 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep)) {
1245 snprintf(p_client_buffer, client_buffer_size, "no fans?");
1249 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf);
1251 fp = open_file(buf2, &rep);
1253 snprintf(p_client_buffer, client_buffer_size,
1254 "can't open fan's state file");
1257 memset(buf, 0, sizeof(buf));
1258 fscanf(fp, "%*s %99s", buf);
1261 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1264 #define SYSFS_AC_ADAPTER_DIR "/sys/class/power_supply/AC"
1265 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1266 /* Linux 2.6.25 onwards ac adapter info is in
1267 /sys/class/power_supply/AC/
1268 On my system I get the following.
1269 /sys/class/power_supply/AC/uevent:
1270 PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A08:00/device:01/PNP0C09:00/ACPI0003:00
1273 POWER_SUPPLY_NAME=AC
1274 POWER_SUPPLY_TYPE=Mains
1275 POWER_SUPPLY_ONLINE=1
1278 void get_acpi_ac_adapter(char *p_client_buffer, size_t client_buffer_size)
1286 if (!p_client_buffer || client_buffer_size <= 0) {
1290 snprintf(buf2, sizeof(buf2), "%s/uevent", SYSFS_AC_ADAPTER_DIR);
1291 fp = open_file(buf2, &rep);
1293 /* sysfs processing */
1295 if (fgets(buf, sizeof(buf), fp) == NULL)
1298 if (strncmp(buf, "POWER_SUPPLY_ONLINE=", 20) == 0) {
1300 sscanf(buf, "POWER_SUPPLY_ONLINE=%d", &online);
1301 snprintf(p_client_buffer, client_buffer_size,
1302 "%s-line", (online ? "on" : "off"));
1308 /* yeah, slow... :/ */
1309 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep)) {
1310 snprintf(p_client_buffer, client_buffer_size, "no ac_adapters?");
1314 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf);
1316 fp = open_file(buf2, &rep);
1318 snprintf(p_client_buffer, client_buffer_size,
1319 "No ac adapter found.... where is it?");
1322 memset(buf, 0, sizeof(buf));
1323 fscanf(fp, "%*s %99s", buf);
1326 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1331 /proc/acpi/thermal_zone/THRM/cooling_mode
1332 cooling mode: active
1333 /proc/acpi/thermal_zone/THRM/polling_frequency
1335 /proc/acpi/thermal_zone/THRM/state
1337 /proc/acpi/thermal_zone/THRM/temperature
1339 /proc/acpi/thermal_zone/THRM/trip_points
1341 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1344 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1345 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1347 int open_acpi_temperature(const char *name)
1353 if (name == NULL || strcmp(name, "*") == 0) {
1356 if (!get_first_file_in_a_directory(ACPI_THERMAL_DIR, buf, &rep)) {
1362 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1364 fd = open(path, O_RDONLY);
1366 ERR("can't open '%s': %s", path, strerror(errno));
1372 static double last_acpi_temp;
1373 static double last_acpi_temp_time;
1375 double get_acpi_temperature(int fd)
1381 /* don't update acpi temperature too often */
1382 if (current_update_time - last_acpi_temp_time < 11.32) {
1383 return last_acpi_temp;
1385 last_acpi_temp_time = current_update_time;
1387 /* seek to beginning */
1388 lseek(fd, 0, SEEK_SET);
1395 n = read(fd, buf, 255);
1397 ERR("can't read fd %d: %s", fd, strerror(errno));
1400 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1404 return last_acpi_temp;
1408 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1410 design capacity: 4400 mAh
1411 last full capacity: 4064 mAh
1412 battery technology: rechargeable
1413 design voltage: 14800 mV
1414 design capacity warning: 300 mAh
1415 design capacity low: 200 mAh
1416 capacity granularity 1: 32 mAh
1417 capacity granularity 2: 32 mAh
1419 serial number: 16922
1425 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1428 charging state: unknown
1430 remaining capacity: 4064 mAh
1431 present voltage: 16608 mV
1435 2213<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1436 2213<@jupet�kellari��> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1437 2213<@jupet�kellari��> (-1 ollee ei akkua kiinni, koska akku on p�yd�ll�)
1438 2214<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1439 2214<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1441 2238<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1442 2239<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1444 2240<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori p��ll�
1445 2241<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori p��ll� mutta ilman verkkovirtaa
1448 /* Kapil Hari Paranjape <kapil@imsc.res.in>
1449 Linux 2.6.24 onwards battery info is in
1450 /sys/class/power_supply/BAT0/
1451 On my system I get the following.
1452 /sys/class/power_supply/BAT0/uevent:
1453 PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A03:00/device:01/PNP0C09:00/PNP0C0A:00
1455 PHYSDEVDRIVER=battery
1456 POWER_SUPPLY_NAME=BAT0
1457 POWER_SUPPLY_TYPE=Battery
1458 POWER_SUPPLY_STATUS=Discharging
1459 POWER_SUPPLY_PRESENT=1
1460 POWER_SUPPLY_TECHNOLOGY=Li-ion
1461 POWER_SUPPLY_VOLTAGE_MIN_DESIGN=10800000
1462 POWER_SUPPLY_VOLTAGE_NOW=10780000
1463 POWER_SUPPLY_CURRENT_NOW=13970000
1464 POWER_SUPPLY_ENERGY_FULL_DESIGN=47510000
1465 POWER_SUPPLY_ENERGY_FULL=27370000
1466 POWER_SUPPLY_ENERGY_NOW=11810000
1467 POWER_SUPPLY_MODEL_NAME=IBM-92P1060
1468 POWER_SUPPLY_MANUFACTURER=Panasonic
1469 On some systems POWER_SUPPLY_ENERGY_* is replaced by POWER_SUPPLY_CHARGE_*
1472 #define SYSFS_BATTERY_BASE_PATH "/sys/class/power_supply"
1473 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1474 #define APM_PATH "/proc/apm"
1475 #define MAX_BATTERY_COUNT 4
1477 static FILE *sysfs_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1478 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1479 static FILE *apm_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1481 static int batteries_initialized = 0;
1482 static char batteries[MAX_BATTERY_COUNT][32];
1484 static int acpi_last_full[MAX_BATTERY_COUNT];
1485 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1487 /* e.g. "charging 75%" */
1488 static char last_battery_str[MAX_BATTERY_COUNT][64];
1490 static char last_battery_time_str[MAX_BATTERY_COUNT][64];
1492 static double last_battery_time[MAX_BATTERY_COUNT];
1494 static int last_battery_perct[MAX_BATTERY_COUNT];
1495 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1497 void init_batteries(void)
1501 if (batteries_initialized) {
1504 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1505 batteries[idx][0] = '\0';
1507 batteries_initialized = 1;
1510 int get_battery_idx(const char *bat)
1514 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1515 if (!strlen(batteries[idx]) || !strcmp(batteries[idx], bat)) {
1520 /* if not found, enter a new entry */
1521 if (!strlen(batteries[idx])) {
1522 snprintf(batteries[idx], 31, "%s", bat);
1528 void set_return_value(char *buffer, unsigned int n, int item, int idx);
1530 void get_battery_stuff(char *buffer, unsigned int n, const char *bat, int item)
1532 static int idx, rep = 0, rep1 = 0, rep2 = 0;
1533 char acpi_path[128];
1534 char sysfs_path[128];
1536 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1537 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1541 idx = get_battery_idx(bat);
1543 /* don't update battery too often */
1544 if (current_update_time - last_battery_time[idx] < 29.5) {
1545 set_return_value(buffer, n, item, idx);
1549 last_battery_time[idx] = current_update_time;
1551 memset(last_battery_str[idx], 0, sizeof(last_battery_str[idx]));
1552 memset(last_battery_time_str[idx], 0, sizeof(last_battery_time_str[idx]));
1554 /* first try SYSFS if that fails try ACPI */
1556 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1557 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1560 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1561 acpi_bat_fp[idx] = open_file(acpi_path, &rep1);
1564 if (sysfs_bat_fp[idx] != NULL) {
1566 int present_rate = -1;
1567 int remaining_capacity = -1;
1568 char charging_state[64];
1571 strcpy(charging_state, "unknown");
1573 while (!feof(sysfs_bat_fp[idx])) {
1575 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1578 /* let's just hope units are ok */
1579 if (strncmp (buf, "POWER_SUPPLY_PRESENT=1", 22) == 0)
1580 strcpy(present, "yes");
1581 else if (strncmp (buf, "POWER_SUPPLY_PRESENT=0", 22) == 0)
1582 strcpy(present, "no");
1583 else if (strncmp (buf, "POWER_SUPPLY_STATUS=", 20) == 0)
1584 sscanf(buf, "POWER_SUPPLY_STATUS=%63s", charging_state);
1585 /* present_rate is not the same as the
1586 current flowing now but it is the same value
1587 which was used in the past. so we continue
1589 else if (strncmp(buf, "POWER_SUPPLY_CURRENT_NOW=", 25) == 0)
1590 sscanf(buf, "POWER_SUPPLY_CURRENT_NOW=%d", &present_rate);
1591 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0)
1592 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1593 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=", 25) == 0)
1594 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_last_full[idx]);
1595 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0)
1596 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1597 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=", 25) == 0)
1598 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_last_full[idx]);
1601 fclose(sysfs_bat_fp[idx]);
1602 sysfs_bat_fp[idx] = NULL;
1604 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1605 if (remaining_capacity > acpi_last_full[idx])
1606 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1609 if (strcmp(present, "No") == 0) {
1610 strncpy(last_battery_str[idx], "not present", 64);
1613 else if (strcmp(charging_state, "Charging") == 0) {
1614 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1615 /* e.g. charging 75% */
1616 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %i%%",
1617 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1619 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1620 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1621 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1622 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %d%%",
1623 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1624 snprintf(last_battery_time_str[idx],
1625 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1627 strncpy(last_battery_str[idx], "charging", sizeof(last_battery_str[idx])-1);
1628 snprintf(last_battery_time_str[idx],
1629 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1633 else if (strncmp(charging_state, "Discharging", 64) == 0) {
1634 if (present_rate > 0) {
1635 /* e.g. discharging 35% */
1636 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "discharging %i%%",
1637 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1639 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1640 (long) (((float) remaining_capacity / present_rate) * 3600));
1641 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1642 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "full");
1643 snprintf(last_battery_time_str[idx],
1644 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1646 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1648 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1649 snprintf(last_battery_time_str[idx],
1650 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1654 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1655 else if (strncmp(charging_state, "Charged", 64) == 0) {
1656 /* Below happens with the second battery on my X40,
1657 * when the second one is empty and the first one
1659 if (remaining_capacity == 0)
1660 strcpy(last_battery_str[idx], "empty");
1662 strcpy(last_battery_str[idx], "charged");
1664 /* unknown, probably full / AC */
1666 if (acpi_last_full[idx] != 0
1667 && remaining_capacity != acpi_last_full[idx])
1668 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1669 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1671 strncpy(last_battery_str[idx], "AC", 64);
1673 } else if (acpi_bat_fp[idx] != NULL) {
1675 int present_rate = -1;
1676 int remaining_capacity = -1;
1677 char charging_state[64];
1680 /* read last full capacity if it's zero */
1681 if (acpi_last_full[idx] == 0) {
1682 static int rep3 = 0;
1686 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1687 fp = open_file(path, &rep3);
1692 if (fgets(b, 256, fp) == NULL) {
1695 if (sscanf(b, "last full capacity: %d",
1696 &acpi_last_full[idx]) != 0) {
1705 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1707 strcpy(charging_state, "unknown");
1709 while (!feof(acpi_bat_fp[idx])) {
1712 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1716 /* let's just hope units are ok */
1717 if (strncmp(buf, "present:", 8) == 0) {
1718 sscanf(buf, "present: %4s", present);
1719 } else if (strncmp(buf, "charging state:", 15) == 0) {
1720 sscanf(buf, "charging state: %63s", charging_state);
1721 } else if (strncmp(buf, "present rate:", 13) == 0) {
1722 sscanf(buf, "present rate: %d", &present_rate);
1723 } else if (strncmp(buf, "remaining capacity:", 19) == 0) {
1724 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1727 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1728 if (remaining_capacity > acpi_last_full[idx]) {
1729 /* normalize to 100% */
1730 acpi_last_full[idx] = remaining_capacity;
1734 if (strcmp(present, "no") == 0) {
1735 strncpy(last_battery_str[idx], "not present", 64);
1737 } else if (strcmp(charging_state, "charging") == 0) {
1738 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1739 /* e.g. charging 75% */
1740 snprintf(last_battery_str[idx],
1741 sizeof(last_battery_str[idx]) - 1, "charging %i%%",
1742 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1744 format_seconds(last_battery_time_str[idx],
1745 sizeof(last_battery_time_str[idx]) - 1,
1746 (long) (((acpi_last_full[idx] - remaining_capacity) *
1747 3600) / present_rate));
1748 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1749 snprintf(last_battery_str[idx],
1750 sizeof(last_battery_str[idx]) - 1, "charging %d%%",
1751 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1752 snprintf(last_battery_time_str[idx],
1753 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1755 strncpy(last_battery_str[idx], "charging",
1756 sizeof(last_battery_str[idx]) - 1);
1757 snprintf(last_battery_time_str[idx],
1758 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1761 } else if (strncmp(charging_state, "discharging", 64) == 0) {
1762 if (present_rate > 0) {
1763 /* e.g. discharging 35% */
1764 snprintf(last_battery_str[idx],
1765 sizeof(last_battery_str[idx]) - 1, "discharging %i%%",
1766 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1768 format_seconds(last_battery_time_str[idx],
1769 sizeof(last_battery_time_str[idx]) - 1,
1770 (long) ((remaining_capacity * 3600) / present_rate));
1771 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1772 snprintf(last_battery_str[idx],
1773 sizeof(last_battery_str[idx]) - 1, "full");
1774 snprintf(last_battery_time_str[idx],
1775 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1777 snprintf(last_battery_str[idx],
1778 sizeof(last_battery_str[idx]) - 1, "discharging %d%%",
1779 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1780 snprintf(last_battery_time_str[idx],
1781 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1784 } else if (strncmp(charging_state, "charged", 64) == 0) {
1785 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1786 /* Below happens with the second battery on my X40,
1787 * when the second one is empty and the first one being charged. */
1788 if (remaining_capacity == 0) {
1789 strcpy(last_battery_str[idx], "empty");
1791 strcpy(last_battery_str[idx], "charged");
1793 /* unknown, probably full / AC */
1795 if (strncmp(charging_state, "Full", 64) == 0) {
1796 strncpy(last_battery_str[idx], "full", 64);
1797 } else if (acpi_last_full[idx] != 0
1798 && remaining_capacity != acpi_last_full[idx]) {
1799 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1800 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1802 strncpy(last_battery_str[idx], "AC", 64);
1807 if (apm_bat_fp[idx] == NULL) {
1808 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1811 if (apm_bat_fp[idx] != NULL) {
1812 unsigned int ac, status, flag;
1815 fscanf(apm_bat_fp[idx], "%*s %*s %*x %x %x %x %d%%",
1816 &ac, &status, &flag, &life);
1819 /* could check now that there is ac */
1820 snprintf(last_battery_str[idx], 64, "AC");
1822 /* could check that status == 3 here? */
1823 } else if (ac && life != 100) {
1824 snprintf(last_battery_str[idx], 64, "charging %d%%", life);
1826 snprintf(last_battery_str[idx], 64, "%d%%", life);
1829 /* it seemed to buffer it so file must be closed (or could use
1830 * syscalls directly but I don't feel like coding it now) */
1831 fclose(apm_bat_fp[idx]);
1832 apm_bat_fp[idx] = NULL;
1835 set_return_value(buffer, n, item, idx);
1838 void set_return_value(char *buffer, unsigned int n, int item, int idx)
1841 case BATTERY_STATUS:
1842 snprintf(buffer, n, "%s", last_battery_str[idx]);
1845 snprintf(buffer, n, "%s", last_battery_time_str[idx]);
1852 void get_battery_short_status(char *buffer, unsigned int n, const char *bat)
1854 get_battery_stuff(buffer, n, bat, BATTERY_STATUS);
1855 if (0 == strncmp("charging", buffer, 8)) {
1857 memmove(buffer + 1, buffer + 8, n - 8);
1858 } else if (0 == strncmp("discharging", buffer, 11)) {
1860 memmove(buffer + 1, buffer + 11, n - 11);
1864 int get_battery_perct(const char *bat)
1868 char acpi_path[128];
1869 char sysfs_path[128];
1870 int remaining_capacity = -1;
1872 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1873 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1877 idx = get_battery_idx(bat);
1879 /* don't update battery too often */
1880 if (current_update_time - last_battery_perct_time[idx] < 30) {
1881 return last_battery_perct[idx];
1883 last_battery_perct_time[idx] = current_update_time;
1885 /* Only check for SYSFS or ACPI */
1887 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1888 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1892 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1893 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1896 if (sysfs_bat_fp[idx] != NULL) {
1898 while (!feof(sysfs_bat_fp[idx])) {
1900 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1903 if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0) {
1904 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1905 } else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=",25) == 0) {
1906 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_design_capacity[idx]);
1907 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0) {
1908 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1909 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=",25) == 0) {
1910 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_design_capacity[idx]);
1914 fclose(sysfs_bat_fp[idx]);
1915 sysfs_bat_fp[idx] = NULL;
1917 } else if (acpi_bat_fp[idx] != NULL) {
1919 /* read last full capacity if it's zero */
1920 if (acpi_design_capacity[idx] == 0) {
1925 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1926 fp = open_file(path, &rep2);
1931 if (fgets(b, 256, fp) == NULL) {
1934 if (sscanf(b, "last full capacity: %d",
1935 &acpi_design_capacity[idx]) != 0) {
1943 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1945 while (!feof(acpi_bat_fp[idx])) {
1948 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1952 if (buf[0] == 'r') {
1953 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1957 if (remaining_capacity < 0) {
1960 /* compute the battery percentage */
1961 last_battery_perct[idx] =
1962 (int) (((float) remaining_capacity / acpi_design_capacity[idx]) * 100);
1963 if (last_battery_perct[idx] > 100) last_battery_perct[idx] = 100;
1964 return last_battery_perct[idx];
1967 int get_battery_perct_bar(const char *bar)
1971 get_battery_perct(bar);
1972 idx = get_battery_idx(bar);
1973 return (int) (last_battery_perct[idx] * 2.56 - 1);
1976 /* On Apple powerbook and ibook:
1977 $ cat /proc/pmu/battery_0
1984 $ cat /proc/pmu/info
1985 PMU driver version : 2
1986 PMU firmware version : 0c
1991 /* defines as in <linux/pmu.h> */
1992 #define PMU_BATT_PRESENT 0x00000001
1993 #define PMU_BATT_CHARGING 0x00000002
1995 static FILE *pmu_battery_fp;
1996 static FILE *pmu_info_fp;
1997 static char pb_battery_info[3][32];
1998 static double pb_battery_info_update;
2000 #define PMU_PATH "/proc/pmu"
2001 void get_powerbook_batt_info(char *buffer, size_t n, int i)
2004 const char *batt_path = PMU_PATH "/battery_0";
2005 const char *info_path = PMU_PATH "/info";
2007 int charge, max_charge, ac = -1;
2010 /* don't update battery too often */
2011 if (current_update_time - pb_battery_info_update < 29.5) {
2012 snprintf(buffer, n, "%s", pb_battery_info[i]);
2015 pb_battery_info_update = current_update_time;
2017 if (pmu_battery_fp == NULL) {
2018 pmu_battery_fp = open_file(batt_path, &rep);
2019 if (pmu_battery_fp == NULL) {
2024 if (pmu_battery_fp != NULL) {
2025 rewind(pmu_battery_fp);
2026 while (!feof(pmu_battery_fp)) {
2029 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL) {
2033 if (buf[0] == 'f') {
2034 sscanf(buf, "flags : %8x", &flags);
2035 } else if (buf[0] == 'c' && buf[1] == 'h') {
2036 sscanf(buf, "charge : %d", &charge);
2037 } else if (buf[0] == 'm') {
2038 sscanf(buf, "max_charge : %d", &max_charge);
2039 } else if (buf[0] == 't') {
2040 sscanf(buf, "time rem. : %ld", &timeval);
2044 if (pmu_info_fp == NULL) {
2045 pmu_info_fp = open_file(info_path, &rep);
2046 if (pmu_info_fp == NULL) {
2051 if (pmu_info_fp != NULL) {
2052 rewind(pmu_info_fp);
2053 while (!feof(pmu_info_fp)) {
2056 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL) {
2059 if (buf[0] == 'A') {
2060 sscanf(buf, "AC Power : %d", &ac);
2064 /* update status string */
2065 if ((ac && !(flags & PMU_BATT_PRESENT))) {
2066 strncpy(pb_battery_info[PB_BATT_STATUS], "AC", sizeof(pb_battery_info[PB_BATT_STATUS]));
2067 } else if (ac && (flags & PMU_BATT_PRESENT)
2068 && !(flags & PMU_BATT_CHARGING)) {
2069 strncpy(pb_battery_info[PB_BATT_STATUS], "charged", sizeof(pb_battery_info[PB_BATT_STATUS]));
2070 } else if ((flags & PMU_BATT_PRESENT) && (flags & PMU_BATT_CHARGING)) {
2071 strncpy(pb_battery_info[PB_BATT_STATUS], "charging", sizeof(pb_battery_info[PB_BATT_STATUS]));
2073 strncpy(pb_battery_info[PB_BATT_STATUS], "discharging", sizeof(pb_battery_info[PB_BATT_STATUS]));
2076 /* update percentage string */
2077 if (timeval == 0 && ac && (flags & PMU_BATT_PRESENT)
2078 && !(flags & PMU_BATT_CHARGING)) {
2079 snprintf(pb_battery_info[PB_BATT_PERCENT],
2080 sizeof(pb_battery_info[PB_BATT_PERCENT]), "100%%");
2081 } else if (timeval == 0) {
2082 snprintf(pb_battery_info[PB_BATT_PERCENT],
2083 sizeof(pb_battery_info[PB_BATT_PERCENT]), "unknown");
2085 snprintf(pb_battery_info[PB_BATT_PERCENT],
2086 sizeof(pb_battery_info[PB_BATT_PERCENT]), "%d%%",
2087 (charge * 100) / max_charge);
2090 /* update time string */
2091 if (timeval == 0) { /* fully charged or battery not present */
2092 snprintf(pb_battery_info[PB_BATT_TIME],
2093 sizeof(pb_battery_info[PB_BATT_TIME]), "unknown");
2094 } else if (timeval < 60 * 60) { /* don't show secs */
2095 format_seconds_short(pb_battery_info[PB_BATT_TIME],
2096 sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2098 format_seconds(pb_battery_info[PB_BATT_TIME],
2099 sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2102 snprintf(buffer, n, "%s", pb_battery_info[i]);
2105 void update_top(void)
2107 show_nice_processes = 1;
2108 process_find_top(info.cpu, info.memu, info.time);
2109 info.first_process = get_first_process();
2112 void update_entropy(void)
2115 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
2116 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
2119 info.entropy.entropy_avail = 0;
2120 info.entropy.poolsize = 0;
2122 if ((fp1 = open_file(entropy_avail, &rep)) == NULL) {
2126 if ((fp2 = open_file(entropy_poolsize, &rep)) == NULL) {
2131 fscanf(fp1, "%u", &info.entropy.entropy_avail);
2132 fscanf(fp2, "%u", &info.entropy.poolsize);
2137 info.mask |= (1 << INFO_ENTROPY);
2140 const char *get_disk_protect_queue(const char *disk)
2146 snprintf(path, 127, "/sys/block/%s/device/unload_heads", disk);
2147 if (access(path, F_OK)) {
2148 snprintf(path, 127, "/sys/block/%s/queue/protect", disk);
2150 if ((fp = fopen(path, "r")) == NULL)
2152 if (fscanf(fp, "%d\n", &state) != 1) {
2157 return (state > 0) ? "frozen" : "free ";