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 reduction(+:curtmp1, curtmp2)
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)
830 memset(buf, 0, sizeof(buf));
832 /* if device is NULL or *, get first */
833 if (dev == NULL || strcmp(dev, "*") == 0) {
836 if (!get_first_file_in_a_directory(dir, buf, &rep)) {
842 if (strcmp(dir, "/sys/class/hwmon/") == 0) {
844 /* buf holds result from get_first_file_in_a_directory() above,
845 * e.g. "hwmon0" -- append "/device" */
846 strcat(buf, "/device");
848 /* dev holds device number N as a string,
849 * e.g. "0", -- convert to "hwmon0/device" */
850 sprintf(buf, "hwmon%s/device", dev);
855 /* At least the acpitz hwmon doesn't have a 'device' subdir,
856 * so check it's existence and strip it from buf otherwise. */
857 snprintf(path, 255, "%s%s", dir, dev);
858 if (stat(path, &st)) {
859 buf[strlen(buf) - 7] = 0;
862 /* change vol to in, tempf to temp */
863 if (strcmp(type, "vol") == 0) {
865 } else if (strcmp(type, "tempf") == 0) {
869 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, type, n);
870 strncpy(devtype, path, 255);
873 fd = open(path, O_RDONLY);
875 CRIT_ERR("can't open '%s': %s\nplease check your device or remove this "
876 "var from "PACKAGE_NAME, path, strerror(errno));
879 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
880 || strcmp(type, "tempf") == 0) {
885 /* fan does not use *_div as a read divisor */
886 if (strcmp("fan", type) == 0) {
890 /* test if *_div file exist, open it and use it as divisor */
891 if (strcmp(type, "tempf") == 0) {
892 snprintf(path, 255, "%s%s/%s%d_div", dir, "one", "two", n);
894 snprintf(path, 255, "%s%s/%s%d_div", dir, dev, type, n);
897 divfd = open(path, O_RDONLY);
903 divn = read(divfd, divbuf, 63);
904 /* should read until n == 0 but I doubt that kernel will give these
905 * in multiple pieces. :) */
907 ERR("open_sysfs_sensor(): can't read from sysfs");
910 *divisor = atoi(divbuf);
919 double get_sysfs_info(int *fd, int divisor, char *devtype, char *type)
927 lseek(*fd, 0, SEEK_SET);
933 n = read(*fd, buf, 63);
934 /* should read until n == 0 but I doubt that kernel will give these
935 * in multiple pieces. :) */
937 ERR("get_sysfs_info(): read from %s failed\n", devtype);
946 *fd = open(devtype, O_RDONLY);
948 ERR("can't open '%s': %s", devtype, strerror(errno));
951 /* My dirty hack for computing CPU value
952 * Filedil, from forums.gentoo.org */
953 /* if (strstr(devtype, "temp1_input") != NULL) {
954 return -15.096 + 1.4893 * (val / 1000.0);
957 /* divide voltage and temperature by 1000 */
958 /* or if any other divisor is given, use that */
959 if (strcmp(type, "tempf") == 0) {
961 return ((val / divisor + 40) * 9.0 / 5) - 40;
962 } else if (divisor) {
963 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
965 return ((val + 40) * 9.0 / 5) - 40;
969 return val / divisor;
970 } else if (divisor) {
978 /* Prior to kernel version 2.6.12, the CPU fan speed was available in
979 * ADT746X_FAN_OLD, whereas later kernel versions provide this information in
981 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
982 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
984 void get_adt746x_fan(char *p_client_buffer, size_t client_buffer_size)
987 char adt746x_fan_state[64];
990 if (!p_client_buffer || client_buffer_size <= 0) {
994 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
995 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL) {
996 sprintf(adt746x_fan_state, "adt746x not found");
998 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
999 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
1003 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_fan_state);
1006 /* Prior to kernel version 2.6.12, the CPU temperature was found in
1007 * ADT746X_CPU_OLD, whereas later kernel versions provide this information in
1009 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
1010 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
1012 void get_adt746x_cpu(char *p_client_buffer, size_t client_buffer_size)
1015 char adt746x_cpu_state[64];
1018 if (!p_client_buffer || client_buffer_size <= 0) {
1022 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
1023 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL) {
1024 sprintf(adt746x_cpu_state, "adt746x not found");
1026 fscanf(fp, "%2s", adt746x_cpu_state);
1030 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state);
1033 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
1034 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
1036 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1037 char get_freq(char *p_client_buffer, size_t client_buffer_size,
1038 const char *p_format, int divisor, unsigned int cpu)
1046 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1052 char current_freq_file[128];
1054 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu - 1,
1056 f = fopen(current_freq_file, "r");
1058 /* if there's a cpufreq /sys node, read the current frequency from
1059 * this node and divide by 1000 to get Mhz. */
1060 if (fgets(s, sizeof(s), f)) {
1061 s[strlen(s) - 1] = '\0';
1062 freq = strtod(s, NULL);
1065 snprintf(p_client_buffer, client_buffer_size, p_format,
1066 (freq / 1000) / divisor);
1071 // open the CPU information file
1072 f = open_file("/proc/cpuinfo", &rep);
1074 perror(PACKAGE_NAME": Failed to access '/proc/cpuinfo' at get_freq()");
1079 while (fgets(s, sizeof(s), f) != NULL) {
1081 #if defined(__i386) || defined(__x86_64)
1082 // and search for the cpu mhz
1083 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) {
1085 #if defined(__alpha)
1086 // different on alpha
1087 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) {
1089 // this is different on ppc for some reason
1090 if (strncmp(s, "clock", 5) == 0 && cpu == 0) {
1091 #endif // defined(__alpha)
1092 #endif // defined(__i386) || defined(__x86_64)
1094 // copy just the number
1095 strcpy(frequency, strchr(s, ':') + 2);
1096 #if defined(__alpha)
1098 frequency[strlen(frequency) - 6] = '\0';
1099 // kernel reports in Hz
1100 freq = strtod(frequency, NULL) / 1000000;
1103 frequency[strlen(frequency) - 1] = '\0';
1104 freq = strtod(frequency, NULL);
1108 if (strncmp(s, "processor", 9) == 0) {
1115 snprintf(p_client_buffer, client_buffer_size, p_format,
1116 (float) freq / divisor);
1120 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
1122 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks something
1132 * Peter Tarjan (ptarjan@citromail.hu) */
1134 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
1135 char get_voltage(char *p_client_buffer, size_t client_buffer_size,
1136 const char *p_format, int divisor, unsigned int cpu)
1142 char current_freq_file[128];
1145 /* build the voltage file name */
1147 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1150 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1155 /* read the current cpu frequency from the /sys node */
1156 f = fopen(current_freq_file, "r");
1158 if (fgets(s, sizeof(s), f)) {
1159 s[strlen(s) - 1] = '\0';
1160 freq = strtod(s, NULL);
1164 fprintf(stderr, PACKAGE_NAME": Failed to access '%s' at ", current_freq_file);
1165 perror("get_voltage()");
1172 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1175 /* use the current cpu frequency to find the corresponding voltage */
1176 f = fopen(current_freq_file, "r");
1182 if (fgets(line, 255, f) == NULL) {
1185 sscanf(line, "%d %d", &freq_comp, &voltage);
1186 if (freq_comp == freq) {
1192 fprintf(stderr, PACKAGE_NAME": Failed to access '%s' at ", current_freq_file);
1193 perror("get_voltage()");
1199 snprintf(p_client_buffer, client_buffer_size, p_format,
1200 (float) voltage / divisor);
1204 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1206 void get_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
1213 if (!p_client_buffer || client_buffer_size <= 0) {
1217 /* yeah, slow... :/ */
1218 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep)) {
1219 snprintf(p_client_buffer, client_buffer_size, "no fans?");
1223 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf);
1225 fp = open_file(buf2, &rep);
1227 snprintf(p_client_buffer, client_buffer_size,
1228 "can't open fan's state file");
1231 memset(buf, 0, sizeof(buf));
1232 fscanf(fp, "%*s %99s", buf);
1235 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1238 #define SYSFS_AC_ADAPTER_DIR "/sys/class/power_supply/AC"
1239 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1240 /* Linux 2.6.25 onwards ac adapter info is in
1241 /sys/class/power_supply/AC/
1242 On my system I get the following.
1243 /sys/class/power_supply/AC/uevent:
1244 PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A08:00/device:01/PNP0C09:00/ACPI0003:00
1247 POWER_SUPPLY_NAME=AC
1248 POWER_SUPPLY_TYPE=Mains
1249 POWER_SUPPLY_ONLINE=1
1252 void get_acpi_ac_adapter(char *p_client_buffer, size_t client_buffer_size)
1260 if (!p_client_buffer || client_buffer_size <= 0) {
1264 snprintf(buf2, sizeof(buf2), "%s/uevent", SYSFS_AC_ADAPTER_DIR);
1265 fp = open_file(buf2, &rep);
1267 /* sysfs processing */
1269 if (fgets(buf, sizeof(buf), fp) == NULL)
1272 if (strncmp(buf, "POWER_SUPPLY_ONLINE=", 20) == 0) {
1274 sscanf(buf, "POWER_SUPPLY_ONLINE=%d", &online);
1275 snprintf(p_client_buffer, client_buffer_size,
1276 "%s-line", (online ? "on" : "off"));
1282 /* yeah, slow... :/ */
1283 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep)) {
1284 snprintf(p_client_buffer, client_buffer_size, "no ac_adapters?");
1288 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf);
1290 fp = open_file(buf2, &rep);
1292 snprintf(p_client_buffer, client_buffer_size,
1293 "No ac adapter found.... where is it?");
1296 memset(buf, 0, sizeof(buf));
1297 fscanf(fp, "%*s %99s", buf);
1300 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1305 /proc/acpi/thermal_zone/THRM/cooling_mode
1306 cooling mode: active
1307 /proc/acpi/thermal_zone/THRM/polling_frequency
1309 /proc/acpi/thermal_zone/THRM/state
1311 /proc/acpi/thermal_zone/THRM/temperature
1313 /proc/acpi/thermal_zone/THRM/trip_points
1315 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1318 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1319 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1321 int open_acpi_temperature(const char *name)
1327 if (name == NULL || strcmp(name, "*") == 0) {
1330 if (!get_first_file_in_a_directory(ACPI_THERMAL_DIR, buf, &rep)) {
1336 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1338 fd = open(path, O_RDONLY);
1340 ERR("can't open '%s': %s", path, strerror(errno));
1346 static double last_acpi_temp;
1347 static double last_acpi_temp_time;
1349 double get_acpi_temperature(int fd)
1355 /* don't update acpi temperature too often */
1356 if (current_update_time - last_acpi_temp_time < 11.32) {
1357 return last_acpi_temp;
1359 last_acpi_temp_time = current_update_time;
1361 /* seek to beginning */
1362 lseek(fd, 0, SEEK_SET);
1369 n = read(fd, buf, 255);
1371 ERR("can't read fd %d: %s", fd, strerror(errno));
1374 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1378 return last_acpi_temp;
1382 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1384 design capacity: 4400 mAh
1385 last full capacity: 4064 mAh
1386 battery technology: rechargeable
1387 design voltage: 14800 mV
1388 design capacity warning: 300 mAh
1389 design capacity low: 200 mAh
1390 capacity granularity 1: 32 mAh
1391 capacity granularity 2: 32 mAh
1393 serial number: 16922
1399 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1402 charging state: unknown
1404 remaining capacity: 4064 mAh
1405 present voltage: 16608 mV
1409 2213<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1410 2213<@jupet�kellari��> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1411 2213<@jupet�kellari��> (-1 ollee ei akkua kiinni, koska akku on p�yd�ll�)
1412 2214<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1413 2214<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1415 2238<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1416 2239<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1418 2240<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori p��ll�
1419 2241<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori p��ll� mutta ilman verkkovirtaa
1422 /* Kapil Hari Paranjape <kapil@imsc.res.in>
1423 Linux 2.6.24 onwards battery info is in
1424 /sys/class/power_supply/BAT0/
1425 On my system I get the following.
1426 /sys/class/power_supply/BAT0/uevent:
1427 PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A03:00/device:01/PNP0C09:00/PNP0C0A:00
1429 PHYSDEVDRIVER=battery
1430 POWER_SUPPLY_NAME=BAT0
1431 POWER_SUPPLY_TYPE=Battery
1432 POWER_SUPPLY_STATUS=Discharging
1433 POWER_SUPPLY_PRESENT=1
1434 POWER_SUPPLY_TECHNOLOGY=Li-ion
1435 POWER_SUPPLY_VOLTAGE_MIN_DESIGN=10800000
1436 POWER_SUPPLY_VOLTAGE_NOW=10780000
1437 POWER_SUPPLY_CURRENT_NOW=13970000
1438 POWER_SUPPLY_ENERGY_FULL_DESIGN=47510000
1439 POWER_SUPPLY_ENERGY_FULL=27370000
1440 POWER_SUPPLY_ENERGY_NOW=11810000
1441 POWER_SUPPLY_MODEL_NAME=IBM-92P1060
1442 POWER_SUPPLY_MANUFACTURER=Panasonic
1443 On some systems POWER_SUPPLY_ENERGY_* is replaced by POWER_SUPPLY_CHARGE_*
1446 #define SYSFS_BATTERY_BASE_PATH "/sys/class/power_supply"
1447 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1448 #define APM_PATH "/proc/apm"
1449 #define MAX_BATTERY_COUNT 4
1451 static FILE *sysfs_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1452 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1453 static FILE *apm_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1455 static int batteries_initialized = 0;
1456 static char batteries[MAX_BATTERY_COUNT][32];
1458 static int acpi_last_full[MAX_BATTERY_COUNT];
1459 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1461 /* e.g. "charging 75%" */
1462 static char last_battery_str[MAX_BATTERY_COUNT][64];
1464 static char last_battery_time_str[MAX_BATTERY_COUNT][64];
1466 static double last_battery_time[MAX_BATTERY_COUNT];
1468 static int last_battery_perct[MAX_BATTERY_COUNT];
1469 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1471 void init_batteries(void)
1475 if (batteries_initialized) {
1479 #pragma omp parallel for
1480 #endif /* HAVE_OPENMP */
1481 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1482 batteries[idx][0] = '\0';
1484 batteries_initialized = 1;
1487 int get_battery_idx(const char *bat)
1491 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1492 if (!strlen(batteries[idx]) || !strcmp(batteries[idx], bat)) {
1497 /* if not found, enter a new entry */
1498 if (!strlen(batteries[idx])) {
1499 snprintf(batteries[idx], 31, "%s", bat);
1505 void set_return_value(char *buffer, unsigned int n, int item, int idx);
1507 void get_battery_stuff(char *buffer, unsigned int n, const char *bat, int item)
1509 static int idx, rep = 0, rep1 = 0, rep2 = 0;
1510 char acpi_path[128];
1511 char sysfs_path[128];
1513 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1514 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1518 idx = get_battery_idx(bat);
1520 /* don't update battery too often */
1521 if (current_update_time - last_battery_time[idx] < 29.5) {
1522 set_return_value(buffer, n, item, idx);
1526 last_battery_time[idx] = current_update_time;
1528 memset(last_battery_str[idx], 0, sizeof(last_battery_str[idx]));
1529 memset(last_battery_time_str[idx], 0, sizeof(last_battery_time_str[idx]));
1531 /* first try SYSFS if that fails try ACPI */
1533 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1534 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1537 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1538 acpi_bat_fp[idx] = open_file(acpi_path, &rep1);
1541 if (sysfs_bat_fp[idx] != NULL) {
1543 int present_rate = -1;
1544 int remaining_capacity = -1;
1545 char charging_state[64];
1548 strcpy(charging_state, "unknown");
1550 while (!feof(sysfs_bat_fp[idx])) {
1552 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1555 /* let's just hope units are ok */
1556 if (strncmp (buf, "POWER_SUPPLY_PRESENT=1", 22) == 0)
1557 strcpy(present, "yes");
1558 else if (strncmp (buf, "POWER_SUPPLY_PRESENT=0", 22) == 0)
1559 strcpy(present, "no");
1560 else if (strncmp (buf, "POWER_SUPPLY_STATUS=", 20) == 0)
1561 sscanf(buf, "POWER_SUPPLY_STATUS=%63s", charging_state);
1562 /* present_rate is not the same as the
1563 current flowing now but it is the same value
1564 which was used in the past. so we continue
1566 else if (strncmp(buf, "POWER_SUPPLY_CURRENT_NOW=", 25) == 0)
1567 sscanf(buf, "POWER_SUPPLY_CURRENT_NOW=%d", &present_rate);
1568 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0)
1569 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1570 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=", 25) == 0)
1571 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_last_full[idx]);
1572 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0)
1573 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1574 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=", 25) == 0)
1575 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_last_full[idx]);
1578 fclose(sysfs_bat_fp[idx]);
1579 sysfs_bat_fp[idx] = NULL;
1581 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1582 if (remaining_capacity > acpi_last_full[idx])
1583 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1586 if (strcmp(present, "No") == 0) {
1587 strncpy(last_battery_str[idx], "not present", 64);
1590 else if (strcmp(charging_state, "Charging") == 0) {
1591 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1592 /* e.g. charging 75% */
1593 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %i%%",
1594 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1596 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1597 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1598 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1599 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %d%%",
1600 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1601 snprintf(last_battery_time_str[idx],
1602 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1604 strncpy(last_battery_str[idx], "charging", sizeof(last_battery_str[idx])-1);
1605 snprintf(last_battery_time_str[idx],
1606 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1610 else if (strncmp(charging_state, "Discharging", 64) == 0) {
1611 if (present_rate > 0) {
1612 /* e.g. discharging 35% */
1613 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "discharging %i%%",
1614 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1616 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1617 (long) (((float) remaining_capacity / present_rate) * 3600));
1618 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1619 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "full");
1620 snprintf(last_battery_time_str[idx],
1621 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1623 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1625 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1626 snprintf(last_battery_time_str[idx],
1627 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1631 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1632 else if (strncmp(charging_state, "Charged", 64) == 0) {
1633 /* Below happens with the second battery on my X40,
1634 * when the second one is empty and the first one
1636 if (remaining_capacity == 0)
1637 strcpy(last_battery_str[idx], "empty");
1639 strcpy(last_battery_str[idx], "charged");
1641 /* unknown, probably full / AC */
1643 if (acpi_last_full[idx] != 0
1644 && remaining_capacity != acpi_last_full[idx])
1645 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1646 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1648 strncpy(last_battery_str[idx], "AC", 64);
1650 } else if (acpi_bat_fp[idx] != NULL) {
1652 int present_rate = -1;
1653 int remaining_capacity = -1;
1654 char charging_state[64];
1657 /* read last full capacity if it's zero */
1658 if (acpi_last_full[idx] == 0) {
1659 static int rep3 = 0;
1663 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1664 fp = open_file(path, &rep3);
1669 if (fgets(b, 256, fp) == NULL) {
1672 if (sscanf(b, "last full capacity: %d",
1673 &acpi_last_full[idx]) != 0) {
1682 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1684 strcpy(charging_state, "unknown");
1686 while (!feof(acpi_bat_fp[idx])) {
1689 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1693 /* let's just hope units are ok */
1694 if (strncmp(buf, "present:", 8) == 0) {
1695 sscanf(buf, "present: %4s", present);
1696 } else if (strncmp(buf, "charging state:", 15) == 0) {
1697 sscanf(buf, "charging state: %63s", charging_state);
1698 } else if (strncmp(buf, "present rate:", 13) == 0) {
1699 sscanf(buf, "present rate: %d", &present_rate);
1700 } else if (strncmp(buf, "remaining capacity:", 19) == 0) {
1701 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1704 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1705 if (remaining_capacity > acpi_last_full[idx]) {
1706 /* normalize to 100% */
1707 acpi_last_full[idx] = remaining_capacity;
1711 if (strcmp(present, "no") == 0) {
1712 strncpy(last_battery_str[idx], "not present", 64);
1714 } else if (strcmp(charging_state, "charging") == 0) {
1715 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1716 /* e.g. charging 75% */
1717 snprintf(last_battery_str[idx],
1718 sizeof(last_battery_str[idx]) - 1, "charging %i%%",
1719 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1721 format_seconds(last_battery_time_str[idx],
1722 sizeof(last_battery_time_str[idx]) - 1,
1723 (long) (((acpi_last_full[idx] - remaining_capacity) *
1724 3600) / present_rate));
1725 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1726 snprintf(last_battery_str[idx],
1727 sizeof(last_battery_str[idx]) - 1, "charging %d%%",
1728 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1729 snprintf(last_battery_time_str[idx],
1730 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1732 strncpy(last_battery_str[idx], "charging",
1733 sizeof(last_battery_str[idx]) - 1);
1734 snprintf(last_battery_time_str[idx],
1735 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1738 } else if (strncmp(charging_state, "discharging", 64) == 0) {
1739 if (present_rate > 0) {
1740 /* e.g. discharging 35% */
1741 snprintf(last_battery_str[idx],
1742 sizeof(last_battery_str[idx]) - 1, "discharging %i%%",
1743 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1745 format_seconds(last_battery_time_str[idx],
1746 sizeof(last_battery_time_str[idx]) - 1,
1747 (long) ((remaining_capacity * 3600) / present_rate));
1748 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1749 snprintf(last_battery_str[idx],
1750 sizeof(last_battery_str[idx]) - 1, "full");
1751 snprintf(last_battery_time_str[idx],
1752 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1754 snprintf(last_battery_str[idx],
1755 sizeof(last_battery_str[idx]) - 1, "discharging %d%%",
1756 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1757 snprintf(last_battery_time_str[idx],
1758 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1761 } else if (strncmp(charging_state, "charged", 64) == 0) {
1762 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1763 /* Below happens with the second battery on my X40,
1764 * when the second one is empty and the first one being charged. */
1765 if (remaining_capacity == 0) {
1766 strcpy(last_battery_str[idx], "empty");
1768 strcpy(last_battery_str[idx], "charged");
1770 /* unknown, probably full / AC */
1772 if (strncmp(charging_state, "Full", 64) == 0) {
1773 strncpy(last_battery_str[idx], "full", 64);
1774 } else if (acpi_last_full[idx] != 0
1775 && remaining_capacity != acpi_last_full[idx]) {
1776 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1777 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1779 strncpy(last_battery_str[idx], "AC", 64);
1784 if (apm_bat_fp[idx] == NULL) {
1785 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1788 if (apm_bat_fp[idx] != NULL) {
1789 unsigned int ac, status, flag;
1792 fscanf(apm_bat_fp[idx], "%*s %*s %*x %x %x %x %d%%",
1793 &ac, &status, &flag, &life);
1796 /* could check now that there is ac */
1797 snprintf(last_battery_str[idx], 64, "AC");
1799 /* could check that status == 3 here? */
1800 } else if (ac && life != 100) {
1801 snprintf(last_battery_str[idx], 64, "charging %d%%", life);
1803 snprintf(last_battery_str[idx], 64, "%d%%", life);
1806 /* it seemed to buffer it so file must be closed (or could use
1807 * syscalls directly but I don't feel like coding it now) */
1808 fclose(apm_bat_fp[idx]);
1809 apm_bat_fp[idx] = NULL;
1812 set_return_value(buffer, n, item, idx);
1815 void set_return_value(char *buffer, unsigned int n, int item, int idx)
1818 case BATTERY_STATUS:
1819 snprintf(buffer, n, "%s", last_battery_str[idx]);
1822 snprintf(buffer, n, "%s", last_battery_time_str[idx]);
1829 void get_battery_short_status(char *buffer, unsigned int n, const char *bat)
1831 get_battery_stuff(buffer, n, bat, BATTERY_STATUS);
1832 if (0 == strncmp("charging", buffer, 8)) {
1834 memmove(buffer + 1, buffer + 8, n - 8);
1835 } else if (0 == strncmp("discharging", buffer, 11)) {
1837 memmove(buffer + 1, buffer + 11, n - 11);
1841 int get_battery_perct(const char *bat)
1845 char acpi_path[128];
1846 char sysfs_path[128];
1847 int remaining_capacity = -1;
1849 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1850 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1854 idx = get_battery_idx(bat);
1856 /* don't update battery too often */
1857 if (current_update_time - last_battery_perct_time[idx] < 30) {
1858 return last_battery_perct[idx];
1860 last_battery_perct_time[idx] = current_update_time;
1862 /* Only check for SYSFS or ACPI */
1864 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1865 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1869 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1870 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1873 if (sysfs_bat_fp[idx] != NULL) {
1875 while (!feof(sysfs_bat_fp[idx])) {
1877 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1880 if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0) {
1881 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1882 } else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=",25) == 0) {
1883 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_design_capacity[idx]);
1884 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0) {
1885 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1886 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=",25) == 0) {
1887 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_design_capacity[idx]);
1891 fclose(sysfs_bat_fp[idx]);
1892 sysfs_bat_fp[idx] = NULL;
1894 } else if (acpi_bat_fp[idx] != NULL) {
1896 /* read last full capacity if it's zero */
1897 if (acpi_design_capacity[idx] == 0) {
1902 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1903 fp = open_file(path, &rep2);
1908 if (fgets(b, 256, fp) == NULL) {
1911 if (sscanf(b, "last full capacity: %d",
1912 &acpi_design_capacity[idx]) != 0) {
1920 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1922 while (!feof(acpi_bat_fp[idx])) {
1925 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1929 if (buf[0] == 'r') {
1930 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1934 if (remaining_capacity < 0) {
1937 /* compute the battery percentage */
1938 last_battery_perct[idx] =
1939 (int) (((float) remaining_capacity / acpi_design_capacity[idx]) * 100);
1940 if (last_battery_perct[idx] > 100) last_battery_perct[idx] = 100;
1941 return last_battery_perct[idx];
1944 int get_battery_perct_bar(const char *bar)
1948 get_battery_perct(bar);
1949 idx = get_battery_idx(bar);
1950 return (int) (last_battery_perct[idx] * 2.56 - 1);
1953 /* On Apple powerbook and ibook:
1954 $ cat /proc/pmu/battery_0
1961 $ cat /proc/pmu/info
1962 PMU driver version : 2
1963 PMU firmware version : 0c
1968 /* defines as in <linux/pmu.h> */
1969 #define PMU_BATT_PRESENT 0x00000001
1970 #define PMU_BATT_CHARGING 0x00000002
1972 static FILE *pmu_battery_fp;
1973 static FILE *pmu_info_fp;
1974 static char pb_battery_info[3][32];
1975 static double pb_battery_info_update;
1977 #define PMU_PATH "/proc/pmu"
1978 void get_powerbook_batt_info(char *buffer, size_t n, int i)
1981 const char *batt_path = PMU_PATH "/battery_0";
1982 const char *info_path = PMU_PATH "/info";
1984 int charge, max_charge, ac = -1;
1987 /* don't update battery too often */
1988 if (current_update_time - pb_battery_info_update < 29.5) {
1989 snprintf(buffer, n, "%s", pb_battery_info[i]);
1992 pb_battery_info_update = current_update_time;
1994 if (pmu_battery_fp == NULL) {
1995 pmu_battery_fp = open_file(batt_path, &rep);
1996 if (pmu_battery_fp == NULL) {
2001 if (pmu_battery_fp != NULL) {
2002 rewind(pmu_battery_fp);
2003 while (!feof(pmu_battery_fp)) {
2006 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL) {
2010 if (buf[0] == 'f') {
2011 sscanf(buf, "flags : %8x", &flags);
2012 } else if (buf[0] == 'c' && buf[1] == 'h') {
2013 sscanf(buf, "charge : %d", &charge);
2014 } else if (buf[0] == 'm') {
2015 sscanf(buf, "max_charge : %d", &max_charge);
2016 } else if (buf[0] == 't') {
2017 sscanf(buf, "time rem. : %ld", &timeval);
2021 if (pmu_info_fp == NULL) {
2022 pmu_info_fp = open_file(info_path, &rep);
2023 if (pmu_info_fp == NULL) {
2028 if (pmu_info_fp != NULL) {
2029 rewind(pmu_info_fp);
2030 while (!feof(pmu_info_fp)) {
2033 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL) {
2036 if (buf[0] == 'A') {
2037 sscanf(buf, "AC Power : %d", &ac);
2041 /* update status string */
2042 if ((ac && !(flags & PMU_BATT_PRESENT))) {
2043 strncpy(pb_battery_info[PB_BATT_STATUS], "AC", sizeof(pb_battery_info[PB_BATT_STATUS]));
2044 } else if (ac && (flags & PMU_BATT_PRESENT)
2045 && !(flags & PMU_BATT_CHARGING)) {
2046 strncpy(pb_battery_info[PB_BATT_STATUS], "charged", sizeof(pb_battery_info[PB_BATT_STATUS]));
2047 } else if ((flags & PMU_BATT_PRESENT) && (flags & PMU_BATT_CHARGING)) {
2048 strncpy(pb_battery_info[PB_BATT_STATUS], "charging", sizeof(pb_battery_info[PB_BATT_STATUS]));
2050 strncpy(pb_battery_info[PB_BATT_STATUS], "discharging", sizeof(pb_battery_info[PB_BATT_STATUS]));
2053 /* update percentage string */
2054 if (timeval == 0 && ac && (flags & PMU_BATT_PRESENT)
2055 && !(flags & PMU_BATT_CHARGING)) {
2056 snprintf(pb_battery_info[PB_BATT_PERCENT],
2057 sizeof(pb_battery_info[PB_BATT_PERCENT]), "100%%");
2058 } else if (timeval == 0) {
2059 snprintf(pb_battery_info[PB_BATT_PERCENT],
2060 sizeof(pb_battery_info[PB_BATT_PERCENT]), "unknown");
2062 snprintf(pb_battery_info[PB_BATT_PERCENT],
2063 sizeof(pb_battery_info[PB_BATT_PERCENT]), "%d%%",
2064 (charge * 100) / max_charge);
2067 /* update time string */
2068 if (timeval == 0) { /* fully charged or battery not present */
2069 snprintf(pb_battery_info[PB_BATT_TIME],
2070 sizeof(pb_battery_info[PB_BATT_TIME]), "unknown");
2071 } else if (timeval < 60 * 60) { /* don't show secs */
2072 format_seconds_short(pb_battery_info[PB_BATT_TIME],
2073 sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2075 format_seconds(pb_battery_info[PB_BATT_TIME],
2076 sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2079 snprintf(buffer, n, "%s", pb_battery_info[i]);
2082 void update_top(void)
2084 show_nice_processes = 1;
2085 process_find_top(info.cpu, info.memu, info.time);
2086 info.first_process = get_first_process();
2089 void update_entropy(void)
2092 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
2093 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
2096 info.entropy.entropy_avail = 0;
2097 info.entropy.poolsize = 0;
2099 if ((fp1 = open_file(entropy_avail, &rep)) == NULL) {
2103 if ((fp2 = open_file(entropy_poolsize, &rep)) == NULL) {
2108 fscanf(fp1, "%u", &info.entropy.entropy_avail);
2109 fscanf(fp2, "%u", &info.entropy.poolsize);
2114 info.mask |= (1 << INFO_ENTROPY);
2117 const char *get_disk_protect_queue(const char *disk)
2123 snprintf(path, 127, "/sys/block/%s/device/unload_heads", disk);
2124 if (access(path, F_OK)) {
2125 snprintf(path, 127, "/sys/block/%s/queue/protect", disk);
2127 if ((fp = fopen(path, "r")) == NULL)
2129 if (fscanf(fp, "%d\n", &state) != 1) {
2134 return (state > 0) ? "frozen" : "free ";