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 #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;
408 for (i = 0; (unsigned) i < info.net_avg_samples; i++) {
409 curtmp1 += ns->net_rec[i];
410 curtmp2 += ns->net_trans[i];
418 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
419 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
420 if (info.net_avg_samples > 1) {
421 for (i = info.net_avg_samples; i > 1; i--) {
422 ns->net_rec[i - 1] = ns->net_rec[i - 2];
423 ns->net_trans[i - 1] = ns->net_trans[i - 2];
428 /* update wireless info */
429 winfo = malloc(sizeof(struct wireless_info));
430 memset(winfo, 0, sizeof(struct wireless_info));
432 skfd = iw_sockets_open();
433 if (iw_get_basic_config(skfd, s, &(winfo->b)) > -1) {
435 // set present winfo variables
436 if (iw_get_stats(skfd, s, &(winfo->stats),
437 &winfo->range, winfo->has_range) >= 0) {
438 winfo->has_stats = 1;
440 if (iw_get_range_info(skfd, s, &(winfo->range)) >= 0) {
441 winfo->has_range = 1;
443 if (iw_get_ext(skfd, s, SIOCGIWAP, &wrq) >= 0) {
444 winfo->has_ap_addr = 1;
445 memcpy(&(winfo->ap_addr), &(wrq.u.ap_addr), sizeof(sockaddr));
449 if (iw_get_ext(skfd, s, SIOCGIWRATE, &wrq) >= 0) {
450 memcpy(&(winfo->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
451 iw_print_bitrate(ns->bitrate, 16, winfo->bitrate.value);
456 if (winfo->has_range && winfo->has_stats
457 && ((winfo->stats.qual.level != 0)
458 || (winfo->stats.qual.updated & IW_QUAL_DBM))) {
459 if (!(winfo->stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
460 ns->link_qual = winfo->stats.qual.qual;
461 ns->link_qual_max = winfo->range.max_qual.qual;
466 if (winfo->has_ap_addr) {
467 iw_sawap_ntop(&winfo->ap_addr, ns->ap);
471 if (winfo->b.has_essid) {
472 if (winfo->b.essid_on) {
473 snprintf(ns->essid, 32, "%s", winfo->b.essid);
475 snprintf(ns->essid, 32, "off/any");
479 snprintf(ns->mode, 16, "%s", iw_operation_mode[winfo->b.mode]);
481 iw_sockets_close(skfd);
489 info.mask |= (1 << INFO_NET);
494 void update_total_processes(void)
498 struct sysinfo s_info;
501 info.procs = s_info.procs;
508 if (!(fp = open_file("/proc/loadavg", &rep))) {
512 fscanf(fp, "%*f %*f %*f %*d/%hu", &info.procs);
515 info.mask |= (1 << INFO_PROCS);
518 #define CPU_SAMPLE_COUNT 15
520 unsigned long long cpu_user;
521 unsigned long long cpu_system;
522 unsigned long long cpu_nice;
523 unsigned long long cpu_idle;
524 unsigned long long cpu_iowait;
525 unsigned long long cpu_irq;
526 unsigned long long cpu_softirq;
527 unsigned long long cpu_steal;
528 unsigned long long cpu_total;
529 unsigned long long cpu_active_total;
530 unsigned long long cpu_last_total;
531 unsigned long long cpu_last_active_total;
532 double cpu_val[CPU_SAMPLE_COUNT];
534 static short cpu_setup = 0;
536 /* Determine if this kernel gives us "extended" statistics information in
538 * Kernels around 2.5 and earlier only reported user, system, nice, and
539 * idle values in proc stat.
540 * Kernels around 2.6 and greater report these PLUS iowait, irq, softirq,
542 void determine_longstat(char *buf)
544 unsigned long long iowait = 0;
546 KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
547 /* scanf will either return -1 or 1 because there is only 1 assignment */
548 if (sscanf(buf, "%*s %*d %*d %*d %*d %llu", &iowait) > 0) {
549 KFLAG_SETON(KFLAG_IS_LONGSTAT);
553 void get_cpu_count(void)
559 if (info.cpu_usage) {
563 if (!(stat_fp = open_file("/proc/stat", &rep))) {
569 while (!feof(stat_fp)) {
570 if (fgets(buf, 255, stat_fp) == NULL) {
574 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
575 if (info.cpu_count == 0) {
576 determine_longstat(buf);
581 info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
586 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
587 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
589 inline static void update_stat(void)
593 static struct cpu_info *cpu = NULL;
598 const char *stat_template = NULL;
599 unsigned int malloc_cpu_size = 0;
601 /* add check for !info.cpu_usage since that mem is freed on a SIGUSR1 */
602 if (!cpu_setup || !info.cpu_usage) {
607 if (!stat_template) {
609 KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT;
613 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
614 cpu = malloc(malloc_cpu_size);
615 memset(cpu, 0, malloc_cpu_size);
618 if (!(stat_fp = open_file("/proc/stat", &rep))) {
620 if (info.cpu_usage) {
621 memset(info.cpu_usage, 0, info.cpu_count * sizeof(float));
627 while (!feof(stat_fp)) {
628 if (fgets(buf, 255, stat_fp) == NULL) {
632 if (strncmp(buf, "procs_running ", 14) == 0) {
633 sscanf(buf, "%*s %hu", &info.run_procs);
634 info.mask |= (1 << INFO_RUN_PROCS);
635 } else if (strncmp(buf, "cpu", 3) == 0) {
637 if (isdigit(buf[3])) {
638 idx = atoi(&buf[3]) + 1;
642 sscanf(buf, stat_template, &(cpu[idx].cpu_user),
643 &(cpu[idx].cpu_nice), &(cpu[idx].cpu_system),
644 &(cpu[idx].cpu_idle), &(cpu[idx].cpu_iowait),
645 &(cpu[idx].cpu_irq), &(cpu[idx].cpu_softirq),
646 &(cpu[idx].cpu_steal));
648 cpu[idx].cpu_total = cpu[idx].cpu_user + cpu[idx].cpu_nice +
649 cpu[idx].cpu_system + cpu[idx].cpu_idle +
650 cpu[idx].cpu_iowait + cpu[idx].cpu_irq +
651 cpu[idx].cpu_softirq + cpu[idx].cpu_steal;
653 cpu[idx].cpu_active_total = cpu[idx].cpu_total -
654 (cpu[idx].cpu_idle + cpu[idx].cpu_iowait);
655 info.mask |= (1 << INFO_CPU);
657 delta = current_update_time - last_update_time;
659 if (delta <= 0.001) {
663 cpu[idx].cpu_val[0] = (cpu[idx].cpu_active_total -
664 cpu[idx].cpu_last_active_total) /
665 (float) (cpu[idx].cpu_total - cpu[idx].cpu_last_total);
667 for (i = 0; i < info.cpu_avg_samples; i++) {
668 curtmp += cpu[idx].cpu_val[i];
670 /* TESTING -- I've removed this, because I don't think it is right.
671 * You shouldn't divide by the cpu count here ...
672 * removing for testing */
674 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples /
677 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples;
679 /* TESTING -- this line replaces the prev. "suspect" if/else */
680 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples;
682 cpu[idx].cpu_last_total = cpu[idx].cpu_total;
683 cpu[idx].cpu_last_active_total = cpu[idx].cpu_active_total;
684 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
685 cpu[idx].cpu_val[i] = cpu[idx].cpu_val[i - 1];
692 void update_running_processes(void)
697 void update_cpu_usage(void)
702 void update_load_average(void)
704 #ifdef HAVE_GETLOADAVG
709 info.loadavg[0] = (float) v[0];
710 info.loadavg[1] = (float) v[1];
711 info.loadavg[2] = (float) v[2];
718 if (!(fp = open_file("/proc/loadavg", &rep))) {
719 info.loadavg[0] = info.loadavg[1] = info.loadavg[2] = 0.0;
722 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1],
726 info.mask |= (1 << INFO_LOADAVG);
729 #define PROC_I8K "/proc/i8k"
730 #define I8K_DELIM " "
731 static char *i8k_procbuf = NULL;
732 void update_i8k(void)
737 i8k_procbuf = (char *) malloc(128 * sizeof(char));
739 if ((fp = fopen(PROC_I8K, "r")) == NULL) {
740 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel "
741 "driver is loaded...");
744 memset(&i8k_procbuf[0], 0, 128);
745 if (fread(&i8k_procbuf[0], sizeof(char), 128, fp) == 0) {
746 ERR("something wrong with /proc/i8k...");
751 i8k.version = strtok(&i8k_procbuf[0], I8K_DELIM);
752 i8k.bios = strtok(NULL, I8K_DELIM);
753 i8k.serial = strtok(NULL, I8K_DELIM);
754 i8k.cpu_temp = strtok(NULL, I8K_DELIM);
755 i8k.left_fan_status = strtok(NULL, I8K_DELIM);
756 i8k.right_fan_status = strtok(NULL, I8K_DELIM);
757 i8k.left_fan_rpm = strtok(NULL, I8K_DELIM);
758 i8k.right_fan_rpm = strtok(NULL, I8K_DELIM);
759 i8k.ac_status = strtok(NULL, I8K_DELIM);
760 i8k.buttons_status = strtok(NULL, I8K_DELIM);
763 /***********************************************************/
764 /***********************************************************/
765 /***********************************************************/
767 static int no_dots(const struct dirent *d)
769 if (d->d_name[0] == '.') {
775 static int get_first_file_in_a_directory(const char *dir, char *s, int *rep)
777 struct dirent **namelist;
780 n = scandir(dir, &namelist, no_dots, alphasort);
783 ERR("scandir for %s: %s", dir, strerror(errno));
794 strncpy(s, namelist[0]->d_name, 255);
797 for (i = 0; i < n; i++) {
806 int open_sysfs_sensor(const char *dir, const char *dev, const char *type, int n,
807 int *divisor, char *devtype)
814 memset(buf, 0, sizeof(buf));
816 /* if device is NULL or *, get first */
817 if (dev == NULL || strcmp(dev, "*") == 0) {
820 if (!get_first_file_in_a_directory(dir, buf, &rep)) {
826 if (strcmp(dir, "/sys/class/hwmon/") == 0) {
828 /* buf holds result from get_first_file_in_a_directory() above,
829 * e.g. "hwmon0" -- append "/device" */
830 strcat(buf, "/device");
832 /* dev holds device number N as a string,
833 * e.g. "0", -- convert to "hwmon0/device" */
834 sprintf(buf, "hwmon%s/device", dev);
839 /* change vol to in */
840 if (strcmp(type, "vol") == 0) {
844 if (strcmp(type, "tempf") == 0) {
845 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, "temp", n);
847 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, type, n);
849 strncpy(devtype, path, 255);
852 fd = open(path, O_RDONLY);
854 CRIT_ERR("can't open '%s': %s\nplease check your device or remove this "
855 "var from "PACKAGE_NAME, path, strerror(errno));
858 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
859 || strcmp(type, "tempf") == 0) {
864 /* fan does not use *_div as a read divisor */
865 if (strcmp("fan", type) == 0) {
869 /* test if *_div file exist, open it and use it as divisor */
870 if (strcmp(type, "tempf") == 0) {
871 snprintf(path, 255, "%s%s/%s%d_div", dir, "one", "two", n);
873 snprintf(path, 255, "%s%s/%s%d_div", dir, dev, type, n);
876 divfd = open(path, O_RDONLY);
882 divn = read(divfd, divbuf, 63);
883 /* should read until n == 0 but I doubt that kernel will give these
884 * in multiple pieces. :) */
886 ERR("open_sysfs_sensor(): can't read from sysfs");
889 *divisor = atoi(divbuf);
898 double get_sysfs_info(int *fd, int divisor, char *devtype, char *type)
906 lseek(*fd, 0, SEEK_SET);
912 n = read(*fd, buf, 63);
913 /* should read until n == 0 but I doubt that kernel will give these
914 * in multiple pieces. :) */
916 ERR("get_sysfs_info(): read from %s failed\n", devtype);
925 *fd = open(devtype, O_RDONLY);
927 ERR("can't open '%s': %s", devtype, strerror(errno));
930 /* My dirty hack for computing CPU value
931 * Filedil, from forums.gentoo.org */
932 /* if (strstr(devtype, "temp1_input") != NULL) {
933 return -15.096 + 1.4893 * (val / 1000.0);
936 /* divide voltage and temperature by 1000 */
937 /* or if any other divisor is given, use that */
938 if (strcmp(type, "tempf") == 0) {
940 return ((val / divisor + 40) * 9.0 / 5) - 40;
941 } else if (divisor) {
942 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
944 return ((val + 40) * 9.0 / 5) - 40;
948 return val / divisor;
949 } else if (divisor) {
957 /* Prior to kernel version 2.6.12, the CPU fan speed was available in
958 * ADT746X_FAN_OLD, whereas later kernel versions provide this information in
960 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
961 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
963 void get_adt746x_fan(char *p_client_buffer, size_t client_buffer_size)
966 char adt746x_fan_state[64];
969 if (!p_client_buffer || client_buffer_size <= 0) {
973 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
974 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL) {
975 sprintf(adt746x_fan_state, "adt746x not found");
977 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
978 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
982 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_fan_state);
985 /* Prior to kernel version 2.6.12, the CPU temperature was found in
986 * ADT746X_CPU_OLD, whereas later kernel versions provide this information in
988 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
989 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
991 void get_adt746x_cpu(char *p_client_buffer, size_t client_buffer_size)
994 char adt746x_cpu_state[64];
997 if (!p_client_buffer || client_buffer_size <= 0) {
1001 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
1002 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL) {
1003 sprintf(adt746x_cpu_state, "adt746x not found");
1005 fscanf(fp, "%2s", adt746x_cpu_state);
1009 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state);
1012 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
1013 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
1015 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1016 char get_freq(char *p_client_buffer, size_t client_buffer_size,
1017 const char *p_format, int divisor, unsigned int cpu)
1025 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1031 char current_freq_file[128];
1033 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu - 1,
1035 f = fopen(current_freq_file, "r");
1037 /* if there's a cpufreq /sys node, read the current frequency from
1038 * this node and divide by 1000 to get Mhz. */
1039 if (fgets(s, sizeof(s), f)) {
1040 s[strlen(s) - 1] = '\0';
1041 freq = strtod(s, NULL);
1044 snprintf(p_client_buffer, client_buffer_size, p_format,
1045 (freq / 1000) / divisor);
1050 // open the CPU information file
1051 f = open_file("/proc/cpuinfo", &rep);
1053 perror(PACKAGE_NAME": Failed to access '/proc/cpuinfo' at get_freq()");
1058 while (fgets(s, sizeof(s), f) != NULL) {
1060 #if defined(__i386) || defined(__x86_64)
1061 // and search for the cpu mhz
1062 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) {
1064 #if defined(__alpha)
1065 // different on alpha
1066 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) {
1068 // this is different on ppc for some reason
1069 if (strncmp(s, "clock", 5) == 0 && cpu == 0) {
1070 #endif // defined(__alpha)
1071 #endif // defined(__i386) || defined(__x86_64)
1073 // copy just the number
1074 strcpy(frequency, strchr(s, ':') + 2);
1075 #if defined(__alpha)
1077 frequency[strlen(frequency) - 6] = '\0';
1078 // kernel reports in Hz
1079 freq = strtod(frequency, NULL) / 1000000;
1082 frequency[strlen(frequency) - 1] = '\0';
1083 freq = strtod(frequency, NULL);
1087 if (strncmp(s, "processor", 9) == 0) {
1094 snprintf(p_client_buffer, client_buffer_size, p_format,
1095 (float) freq / divisor);
1099 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
1101 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks something
1111 * Peter Tarjan (ptarjan@citromail.hu) */
1113 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
1114 char get_voltage(char *p_client_buffer, size_t client_buffer_size,
1115 const char *p_format, int divisor, unsigned int cpu)
1121 char current_freq_file[128];
1124 /* build the voltage file name */
1126 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1129 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1134 /* read the current cpu frequency from the /sys node */
1135 f = fopen(current_freq_file, "r");
1137 if (fgets(s, sizeof(s), f)) {
1138 s[strlen(s) - 1] = '\0';
1139 freq = strtod(s, NULL);
1143 fprintf(stderr, PACKAGE_NAME": Failed to access '%s' at ", current_freq_file);
1144 perror("get_voltage()");
1151 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1154 /* use the current cpu frequency to find the corresponding voltage */
1155 f = fopen(current_freq_file, "r");
1161 if (fgets(line, 255, f) == NULL) {
1164 sscanf(line, "%d %d", &freq_comp, &voltage);
1165 if (freq_comp == freq) {
1171 fprintf(stderr, PACKAGE_NAME": Failed to access '%s' at ", current_freq_file);
1172 perror("get_voltage()");
1178 snprintf(p_client_buffer, client_buffer_size, p_format,
1179 (float) voltage / divisor);
1183 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1185 void get_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
1192 if (!p_client_buffer || client_buffer_size <= 0) {
1196 /* yeah, slow... :/ */
1197 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep)) {
1198 snprintf(p_client_buffer, client_buffer_size, "no fans?");
1202 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf);
1204 fp = open_file(buf2, &rep);
1206 snprintf(p_client_buffer, client_buffer_size,
1207 "can't open fan's state file");
1210 memset(buf, 0, sizeof(buf));
1211 fscanf(fp, "%*s %99s", buf);
1214 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1217 #define SYSFS_AC_ADAPTER_DIR "/sys/class/power_supply/AC"
1218 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1219 /* Linux 2.6.25 onwards ac adapter info is in
1220 /sys/class/power_supply/AC/
1221 On my system I get the following.
1222 /sys/class/power_supply/AC/uevent:
1223 PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A08:00/device:01/PNP0C09:00/ACPI0003:00
1226 POWER_SUPPLY_NAME=AC
1227 POWER_SUPPLY_TYPE=Mains
1228 POWER_SUPPLY_ONLINE=1
1231 void get_acpi_ac_adapter(char *p_client_buffer, size_t client_buffer_size)
1239 if (!p_client_buffer || client_buffer_size <= 0) {
1243 snprintf(buf2, sizeof(buf2), "%s/uevent", SYSFS_AC_ADAPTER_DIR);
1244 fp = open_file(buf2, &rep);
1246 /* sysfs processing */
1248 if (fgets(buf, sizeof(buf), fp) == NULL)
1251 if (strncmp(buf, "POWER_SUPPLY_ONLINE=", 20) == 0) {
1253 sscanf(buf, "POWER_SUPPLY_ONLINE=%d", &online);
1254 snprintf(p_client_buffer, client_buffer_size,
1255 "%s-line", (online ? "on" : "off"));
1261 /* yeah, slow... :/ */
1262 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep)) {
1263 snprintf(p_client_buffer, client_buffer_size, "no ac_adapters?");
1267 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf);
1269 fp = open_file(buf2, &rep);
1271 snprintf(p_client_buffer, client_buffer_size,
1272 "No ac adapter found.... where is it?");
1275 memset(buf, 0, sizeof(buf));
1276 fscanf(fp, "%*s %99s", buf);
1279 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1284 /proc/acpi/thermal_zone/THRM/cooling_mode
1285 cooling mode: active
1286 /proc/acpi/thermal_zone/THRM/polling_frequency
1288 /proc/acpi/thermal_zone/THRM/state
1290 /proc/acpi/thermal_zone/THRM/temperature
1292 /proc/acpi/thermal_zone/THRM/trip_points
1294 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1297 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1298 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1300 int open_acpi_temperature(const char *name)
1306 if (name == NULL || strcmp(name, "*") == 0) {
1309 if (!get_first_file_in_a_directory(ACPI_THERMAL_DIR, buf, &rep)) {
1315 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1317 fd = open(path, O_RDONLY);
1319 ERR("can't open '%s': %s", path, strerror(errno));
1325 static double last_acpi_temp;
1326 static double last_acpi_temp_time;
1328 double get_acpi_temperature(int fd)
1334 /* don't update acpi temperature too often */
1335 if (current_update_time - last_acpi_temp_time < 11.32) {
1336 return last_acpi_temp;
1338 last_acpi_temp_time = current_update_time;
1340 /* seek to beginning */
1341 lseek(fd, 0, SEEK_SET);
1348 n = read(fd, buf, 255);
1350 ERR("can't read fd %d: %s", fd, strerror(errno));
1353 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1357 return last_acpi_temp;
1361 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1363 design capacity: 4400 mAh
1364 last full capacity: 4064 mAh
1365 battery technology: rechargeable
1366 design voltage: 14800 mV
1367 design capacity warning: 300 mAh
1368 design capacity low: 200 mAh
1369 capacity granularity 1: 32 mAh
1370 capacity granularity 2: 32 mAh
1372 serial number: 16922
1378 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1381 charging state: unknown
1383 remaining capacity: 4064 mAh
1384 present voltage: 16608 mV
1388 2213<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1389 2213<@jupet�kellari��> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1390 2213<@jupet�kellari��> (-1 ollee ei akkua kiinni, koska akku on p�yd�ll�)
1391 2214<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1392 2214<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1394 2238<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1395 2239<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1397 2240<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori p��ll�
1398 2241<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori p��ll� mutta ilman verkkovirtaa
1401 /* Kapil Hari Paranjape <kapil@imsc.res.in>
1402 Linux 2.6.24 onwards battery info is in
1403 /sys/class/power_supply/BAT0/
1404 On my system I get the following.
1405 /sys/class/power_supply/BAT0/uevent:
1406 PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A03:00/device:01/PNP0C09:00/PNP0C0A:00
1408 PHYSDEVDRIVER=battery
1409 POWER_SUPPLY_NAME=BAT0
1410 POWER_SUPPLY_TYPE=Battery
1411 POWER_SUPPLY_STATUS=Discharging
1412 POWER_SUPPLY_PRESENT=1
1413 POWER_SUPPLY_TECHNOLOGY=Li-ion
1414 POWER_SUPPLY_VOLTAGE_MIN_DESIGN=10800000
1415 POWER_SUPPLY_VOLTAGE_NOW=10780000
1416 POWER_SUPPLY_CURRENT_NOW=13970000
1417 POWER_SUPPLY_ENERGY_FULL_DESIGN=47510000
1418 POWER_SUPPLY_ENERGY_FULL=27370000
1419 POWER_SUPPLY_ENERGY_NOW=11810000
1420 POWER_SUPPLY_MODEL_NAME=IBM-92P1060
1421 POWER_SUPPLY_MANUFACTURER=Panasonic
1422 On some systems POWER_SUPPLY_ENERGY_* is replaced by POWER_SUPPLY_CHARGE_*
1425 #define SYSFS_BATTERY_BASE_PATH "/sys/class/power_supply"
1426 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1427 #define APM_PATH "/proc/apm"
1428 #define MAX_BATTERY_COUNT 4
1430 static FILE *sysfs_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1431 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1432 static FILE *apm_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1434 static int batteries_initialized = 0;
1435 static char batteries[MAX_BATTERY_COUNT][32];
1437 static int acpi_last_full[MAX_BATTERY_COUNT];
1438 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1440 /* e.g. "charging 75%" */
1441 static char last_battery_str[MAX_BATTERY_COUNT][64];
1443 static char last_battery_time_str[MAX_BATTERY_COUNT][64];
1445 static double last_battery_time[MAX_BATTERY_COUNT];
1447 static int last_battery_perct[MAX_BATTERY_COUNT];
1448 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1450 void init_batteries(void)
1454 if (batteries_initialized) {
1457 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1458 batteries[idx][0] = '\0';
1460 batteries_initialized = 1;
1463 int get_battery_idx(const char *bat)
1467 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1468 if (!strlen(batteries[idx]) || !strcmp(batteries[idx], bat)) {
1473 /* if not found, enter a new entry */
1474 if (!strlen(batteries[idx])) {
1475 snprintf(batteries[idx], 31, "%s", bat);
1481 void set_return_value(char *buffer, unsigned int n, int item, int idx);
1483 void get_battery_stuff(char *buffer, unsigned int n, const char *bat, int item)
1485 static int idx, rep = 0, rep1 = 0, rep2 = 0;
1486 char acpi_path[128];
1487 char sysfs_path[128];
1489 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1490 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1494 idx = get_battery_idx(bat);
1496 /* don't update battery too often */
1497 if (current_update_time - last_battery_time[idx] < 29.5) {
1498 set_return_value(buffer, n, item, idx);
1502 last_battery_time[idx] = current_update_time;
1504 memset(last_battery_str[idx], 0, sizeof(last_battery_str[idx]));
1505 memset(last_battery_time_str[idx], 0, sizeof(last_battery_time_str[idx]));
1507 /* first try SYSFS if that fails try ACPI */
1509 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1510 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1513 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1514 acpi_bat_fp[idx] = open_file(acpi_path, &rep1);
1517 if (sysfs_bat_fp[idx] != NULL) {
1519 int present_rate = -1;
1520 int remaining_capacity = -1;
1521 char charging_state[64];
1524 strcpy(charging_state, "unknown");
1526 while (!feof(sysfs_bat_fp[idx])) {
1528 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1531 /* let's just hope units are ok */
1532 if (strncmp (buf, "POWER_SUPPLY_PRESENT=1", 22) == 0)
1533 strcpy(present, "yes");
1534 else if (strncmp (buf, "POWER_SUPPLY_PRESENT=0", 22) == 0)
1535 strcpy(present, "no");
1536 else if (strncmp (buf, "POWER_SUPPLY_STATUS=", 20) == 0)
1537 sscanf(buf, "POWER_SUPPLY_STATUS=%63s", charging_state);
1538 /* present_rate is not the same as the
1539 current flowing now but it is the same value
1540 which was used in the past. so we continue
1542 else if (strncmp(buf, "POWER_SUPPLY_CURRENT_NOW=", 25) == 0)
1543 sscanf(buf, "POWER_SUPPLY_CURRENT_NOW=%d", &present_rate);
1544 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0)
1545 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1546 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=", 25) == 0)
1547 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_last_full[idx]);
1548 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0)
1549 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1550 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=", 25) == 0)
1551 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_last_full[idx]);
1554 fclose(sysfs_bat_fp[idx]);
1555 sysfs_bat_fp[idx] = NULL;
1557 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1558 if (remaining_capacity > acpi_last_full[idx])
1559 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1562 if (strcmp(present, "No") == 0) {
1563 strncpy(last_battery_str[idx], "not present", 64);
1566 else if (strcmp(charging_state, "Charging") == 0) {
1567 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1568 /* e.g. charging 75% */
1569 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %i%%",
1570 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1572 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1573 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1574 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1575 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %d%%",
1576 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1577 snprintf(last_battery_time_str[idx],
1578 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1580 strncpy(last_battery_str[idx], "charging", sizeof(last_battery_str[idx])-1);
1581 snprintf(last_battery_time_str[idx],
1582 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1586 else if (strncmp(charging_state, "Discharging", 64) == 0) {
1587 if (present_rate > 0) {
1588 /* e.g. discharging 35% */
1589 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "discharging %i%%",
1590 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1592 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1593 (long) (((float) remaining_capacity / present_rate) * 3600));
1594 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1595 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "full");
1596 snprintf(last_battery_time_str[idx],
1597 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1599 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1601 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1602 snprintf(last_battery_time_str[idx],
1603 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1607 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1608 else if (strncmp(charging_state, "Charged", 64) == 0) {
1609 /* Below happens with the second battery on my X40,
1610 * when the second one is empty and the first one
1612 if (remaining_capacity == 0)
1613 strcpy(last_battery_str[idx], "empty");
1615 strcpy(last_battery_str[idx], "charged");
1617 /* unknown, probably full / AC */
1619 if (acpi_last_full[idx] != 0
1620 && remaining_capacity != acpi_last_full[idx])
1621 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1622 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1624 strncpy(last_battery_str[idx], "AC", 64);
1626 } else if (acpi_bat_fp[idx] != NULL) {
1628 int present_rate = -1;
1629 int remaining_capacity = -1;
1630 char charging_state[64];
1633 /* read last full capacity if it's zero */
1634 if (acpi_last_full[idx] == 0) {
1635 static int rep3 = 0;
1639 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1640 fp = open_file(path, &rep3);
1645 if (fgets(b, 256, fp) == NULL) {
1648 if (sscanf(b, "last full capacity: %d",
1649 &acpi_last_full[idx]) != 0) {
1658 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1660 strcpy(charging_state, "unknown");
1662 while (!feof(acpi_bat_fp[idx])) {
1665 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1669 /* let's just hope units are ok */
1670 if (strncmp(buf, "present:", 8) == 0) {
1671 sscanf(buf, "present: %4s", present);
1672 } else if (strncmp(buf, "charging state:", 15) == 0) {
1673 sscanf(buf, "charging state: %63s", charging_state);
1674 } else if (strncmp(buf, "present rate:", 13) == 0) {
1675 sscanf(buf, "present rate: %d", &present_rate);
1676 } else if (strncmp(buf, "remaining capacity:", 19) == 0) {
1677 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1680 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1681 if (remaining_capacity > acpi_last_full[idx]) {
1682 /* normalize to 100% */
1683 acpi_last_full[idx] = remaining_capacity;
1687 if (strcmp(present, "no") == 0) {
1688 strncpy(last_battery_str[idx], "not present", 64);
1690 } else if (strcmp(charging_state, "charging") == 0) {
1691 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1692 /* e.g. charging 75% */
1693 snprintf(last_battery_str[idx],
1694 sizeof(last_battery_str[idx]) - 1, "charging %i%%",
1695 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1697 format_seconds(last_battery_time_str[idx],
1698 sizeof(last_battery_time_str[idx]) - 1,
1699 (long) (((acpi_last_full[idx] - remaining_capacity) *
1700 3600) / present_rate));
1701 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1702 snprintf(last_battery_str[idx],
1703 sizeof(last_battery_str[idx]) - 1, "charging %d%%",
1704 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1705 snprintf(last_battery_time_str[idx],
1706 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1708 strncpy(last_battery_str[idx], "charging",
1709 sizeof(last_battery_str[idx]) - 1);
1710 snprintf(last_battery_time_str[idx],
1711 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1714 } else if (strncmp(charging_state, "discharging", 64) == 0) {
1715 if (present_rate > 0) {
1716 /* e.g. discharging 35% */
1717 snprintf(last_battery_str[idx],
1718 sizeof(last_battery_str[idx]) - 1, "discharging %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) ((remaining_capacity * 3600) / present_rate));
1724 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1725 snprintf(last_battery_str[idx],
1726 sizeof(last_battery_str[idx]) - 1, "full");
1727 snprintf(last_battery_time_str[idx],
1728 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1730 snprintf(last_battery_str[idx],
1731 sizeof(last_battery_str[idx]) - 1, "discharging %d%%",
1732 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1733 snprintf(last_battery_time_str[idx],
1734 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1737 } else if (strncmp(charging_state, "charged", 64) == 0) {
1738 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1739 /* Below happens with the second battery on my X40,
1740 * when the second one is empty and the first one being charged. */
1741 if (remaining_capacity == 0) {
1742 strcpy(last_battery_str[idx], "empty");
1744 strcpy(last_battery_str[idx], "charged");
1746 /* unknown, probably full / AC */
1748 if (strncmp(charging_state, "Full", 64) == 0) {
1749 strncpy(last_battery_str[idx], "full", 64);
1750 } else if (acpi_last_full[idx] != 0
1751 && remaining_capacity != acpi_last_full[idx]) {
1752 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1753 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1755 strncpy(last_battery_str[idx], "AC", 64);
1760 if (apm_bat_fp[idx] == NULL) {
1761 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1764 if (apm_bat_fp[idx] != NULL) {
1765 unsigned int ac, status, flag;
1768 fscanf(apm_bat_fp[idx], "%*s %*s %*x %x %x %x %d%%",
1769 &ac, &status, &flag, &life);
1772 /* could check now that there is ac */
1773 snprintf(last_battery_str[idx], 64, "AC");
1775 /* could check that status == 3 here? */
1776 } else if (ac && life != 100) {
1777 snprintf(last_battery_str[idx], 64, "charging %d%%", life);
1779 snprintf(last_battery_str[idx], 64, "%d%%", life);
1782 /* it seemed to buffer it so file must be closed (or could use
1783 * syscalls directly but I don't feel like coding it now) */
1784 fclose(apm_bat_fp[idx]);
1785 apm_bat_fp[idx] = NULL;
1788 set_return_value(buffer, n, item, idx);
1791 void set_return_value(char *buffer, unsigned int n, int item, int idx)
1794 case BATTERY_STATUS:
1795 snprintf(buffer, n, "%s", last_battery_str[idx]);
1798 snprintf(buffer, n, "%s", last_battery_time_str[idx]);
1805 void get_battery_short_status(char *buffer, unsigned int n, const char *bat)
1807 get_battery_stuff(buffer, n, bat, BATTERY_STATUS);
1808 if (0 == strncmp("charging", buffer, 8)) {
1810 memmove(buffer + 1, buffer + 8, n - 8);
1811 } else if (0 == strncmp("discharging", buffer, 11)) {
1813 memmove(buffer + 1, buffer + 11, n - 11);
1817 int get_battery_perct(const char *bat)
1821 char acpi_path[128];
1822 char sysfs_path[128];
1823 int remaining_capacity = -1;
1825 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1826 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1830 idx = get_battery_idx(bat);
1832 /* don't update battery too often */
1833 if (current_update_time - last_battery_perct_time[idx] < 30) {
1834 return last_battery_perct[idx];
1836 last_battery_perct_time[idx] = current_update_time;
1838 /* Only check for SYSFS or ACPI */
1840 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1841 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1845 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1846 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1849 if (sysfs_bat_fp[idx] != NULL) {
1851 while (!feof(sysfs_bat_fp[idx])) {
1853 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1856 if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0) {
1857 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1858 } else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=",25) == 0) {
1859 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_design_capacity[idx]);
1860 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0) {
1861 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1862 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=",25) == 0) {
1863 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_design_capacity[idx]);
1867 fclose(sysfs_bat_fp[idx]);
1868 sysfs_bat_fp[idx] = NULL;
1870 } else if (acpi_bat_fp[idx] != NULL) {
1872 /* read last full capacity if it's zero */
1873 if (acpi_design_capacity[idx] == 0) {
1878 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1879 fp = open_file(path, &rep2);
1884 if (fgets(b, 256, fp) == NULL) {
1887 if (sscanf(b, "last full capacity: %d",
1888 &acpi_design_capacity[idx]) != 0) {
1896 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1898 while (!feof(acpi_bat_fp[idx])) {
1901 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1905 if (buf[0] == 'r') {
1906 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1910 if (remaining_capacity < 0) {
1913 /* compute the battery percentage */
1914 last_battery_perct[idx] =
1915 (int) (((float) remaining_capacity / acpi_design_capacity[idx]) * 100);
1916 if (last_battery_perct[idx] > 100) last_battery_perct[idx] = 100;
1917 return last_battery_perct[idx];
1920 int get_battery_perct_bar(const char *bar)
1924 get_battery_perct(bar);
1925 idx = get_battery_idx(bar);
1926 return (int) (last_battery_perct[idx] * 2.56 - 1);
1929 /* On Apple powerbook and ibook:
1930 $ cat /proc/pmu/battery_0
1937 $ cat /proc/pmu/info
1938 PMU driver version : 2
1939 PMU firmware version : 0c
1944 /* defines as in <linux/pmu.h> */
1945 #define PMU_BATT_PRESENT 0x00000001
1946 #define PMU_BATT_CHARGING 0x00000002
1948 static FILE *pmu_battery_fp;
1949 static FILE *pmu_info_fp;
1950 static char pb_battery_info[3][32];
1951 static double pb_battery_info_update;
1953 #define PMU_PATH "/proc/pmu"
1954 void get_powerbook_batt_info(char *buffer, size_t n, int i)
1957 const char *batt_path = PMU_PATH "/battery_0";
1958 const char *info_path = PMU_PATH "/info";
1960 int charge, max_charge, ac = -1;
1963 /* don't update battery too often */
1964 if (current_update_time - pb_battery_info_update < 29.5) {
1965 snprintf(buffer, n, "%s", pb_battery_info[i]);
1968 pb_battery_info_update = current_update_time;
1970 if (pmu_battery_fp == NULL) {
1971 pmu_battery_fp = open_file(batt_path, &rep);
1972 if (pmu_battery_fp == NULL) {
1977 if (pmu_battery_fp != NULL) {
1978 rewind(pmu_battery_fp);
1979 while (!feof(pmu_battery_fp)) {
1982 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL) {
1986 if (buf[0] == 'f') {
1987 sscanf(buf, "flags : %8x", &flags);
1988 } else if (buf[0] == 'c' && buf[1] == 'h') {
1989 sscanf(buf, "charge : %d", &charge);
1990 } else if (buf[0] == 'm') {
1991 sscanf(buf, "max_charge : %d", &max_charge);
1992 } else if (buf[0] == 't') {
1993 sscanf(buf, "time rem. : %ld", &timeval);
1997 if (pmu_info_fp == NULL) {
1998 pmu_info_fp = open_file(info_path, &rep);
1999 if (pmu_info_fp == NULL) {
2004 if (pmu_info_fp != NULL) {
2005 rewind(pmu_info_fp);
2006 while (!feof(pmu_info_fp)) {
2009 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL) {
2012 if (buf[0] == 'A') {
2013 sscanf(buf, "AC Power : %d", &ac);
2017 /* update status string */
2018 if ((ac && !(flags & PMU_BATT_PRESENT))) {
2019 strncpy(pb_battery_info[PB_BATT_STATUS], "AC", sizeof(pb_battery_info[PB_BATT_STATUS]));
2020 } else if (ac && (flags & PMU_BATT_PRESENT)
2021 && !(flags & PMU_BATT_CHARGING)) {
2022 strncpy(pb_battery_info[PB_BATT_STATUS], "charged", sizeof(pb_battery_info[PB_BATT_STATUS]));
2023 } else if ((flags & PMU_BATT_PRESENT) && (flags & PMU_BATT_CHARGING)) {
2024 strncpy(pb_battery_info[PB_BATT_STATUS], "charging", sizeof(pb_battery_info[PB_BATT_STATUS]));
2026 strncpy(pb_battery_info[PB_BATT_STATUS], "discharging", sizeof(pb_battery_info[PB_BATT_STATUS]));
2029 /* update percentage string */
2030 if (timeval == 0 && ac && (flags & PMU_BATT_PRESENT)
2031 && !(flags & PMU_BATT_CHARGING)) {
2032 snprintf(pb_battery_info[PB_BATT_PERCENT],
2033 sizeof(pb_battery_info[PB_BATT_PERCENT]), "100%%");
2034 } else if (timeval == 0) {
2035 snprintf(pb_battery_info[PB_BATT_PERCENT],
2036 sizeof(pb_battery_info[PB_BATT_PERCENT]), "unknown");
2038 snprintf(pb_battery_info[PB_BATT_PERCENT],
2039 sizeof(pb_battery_info[PB_BATT_PERCENT]), "%d%%",
2040 (charge * 100) / max_charge);
2043 /* update time string */
2044 if (timeval == 0) { /* fully charged or battery not present */
2045 snprintf(pb_battery_info[PB_BATT_TIME],
2046 sizeof(pb_battery_info[PB_BATT_TIME]), "unknown");
2047 } else if (timeval < 60 * 60) { /* don't show secs */
2048 format_seconds_short(pb_battery_info[PB_BATT_TIME],
2049 sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2051 format_seconds(pb_battery_info[PB_BATT_TIME],
2052 sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2055 snprintf(buffer, n, "%s", pb_battery_info[i]);
2058 void update_top(void)
2060 show_nice_processes = 1;
2061 process_find_top(info.cpu, info.memu, info.time);
2062 info.first_process = get_first_process();
2065 void update_entropy(void)
2068 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
2069 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
2072 info.entropy.entropy_avail = 0;
2073 info.entropy.poolsize = 0;
2075 if ((fp1 = open_file(entropy_avail, &rep)) == NULL) {
2079 if ((fp2 = open_file(entropy_poolsize, &rep)) == NULL) {
2084 fscanf(fp1, "%u", &info.entropy.entropy_avail);
2085 fscanf(fp2, "%u", &info.entropy.poolsize);
2090 info.mask |= (1 << INFO_ENTROPY);
2093 const char *get_disk_protect_queue(const char *disk)
2099 snprintf(path, 127, "/sys/block/%s/device/unload_heads", disk);
2100 if (access(path, F_OK)) {
2101 snprintf(path, 127, "/sys/block/%s/queue/protect", disk);
2103 if ((fp = fopen(path, "r")) == NULL)
2105 if (fscanf(fp, "%d\n", &state) != 1) {
2110 return (state > 0) ? "frozen" : "free ";