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 = 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.mem);
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.mem;
165 info.swap = info.swapmax - info.swap;
167 info.bufmem = info.cached + info.buffers;
169 info.mask |= (1 << INFO_MEM) | (1 << INFO_BUFFERS);
174 int get_laptop_mode(void)
179 if ((fp = fopen("/proc/sys/vm/laptop_mode", "r")) != NULL)
180 fscanf(fp, "%d\n", &val);
186 * # cat /sys/block/sda/queue/scheduler
187 * noop [anticipatory] cfq
189 char *get_ioscheduler(char *disk)
195 return strndup("n/a", text_buffer_size);
197 snprintf(buf, 127, "/sys/block/%s/queue/scheduler", disk);
198 if ((fp = fopen(buf, "r")) == NULL) {
199 return strndup("n/a", text_buffer_size);
202 fscanf(fp, "%127s", buf);
204 buf[strlen(buf) - 1] = '\0';
206 return strndup(buf + 1, text_buffer_size);
210 return strndup("n/a", text_buffer_size);
213 int interface_up(const char *dev)
218 if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
219 CRIT_ERR("could not create sockfd");
222 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
223 if (ioctl(fd, SIOCGIFFLAGS, &ifr)) {
224 /* if device does not exist, treat like not up */
226 perror("SIOCGIFFLAGS");
230 if (!(ifr.ifr_flags & IFF_UP)) /* iface is not up */
232 if (ifup_strictness == IFUP_UP)
235 if (!(ifr.ifr_flags & IFF_RUNNING))
237 if (ifup_strictness == IFUP_LINK)
240 if (ioctl(fd, SIOCGIFADDR, &ifr)) {
241 perror("SIOCGIFADDR");
244 if (((struct sockaddr_in *)&(ifr.ifr_ifru.ifru_addr))->sin_addr.s_addr)
255 #define COND_FREE(x) if(x) free(x); x = 0
256 #define SAVE_SET_STRING(x, y) \
257 if (x && strcmp((char *)x, (char *)y)) { \
259 x = strndup("multiple", text_buffer_size); \
261 x = strndup(y, text_buffer_size); \
264 void update_gateway_info_failure(char *reason)
269 //2 pointers to 1 location causes a crash when we try to free them both
270 info.gw_info.iface = strndup("failed", text_buffer_size);
271 info.gw_info.ip = strndup("failed", text_buffer_size);
274 void update_gateway_info(void)
279 unsigned long dest, gate, mask;
281 short ref, use, metric, mtu, win, irtt;
283 struct gateway_info *gw_info = &info.gw_info;
285 COND_FREE(gw_info->iface);
286 COND_FREE(gw_info->ip);
289 if ((fp = fopen("/proc/net/route", "r")) == NULL) {
290 update_gateway_info_failure("fopen()");
293 if (fscanf(fp, "%*[^\n]\n") == EOF) {
294 //NULL because a empty table is not a error
295 update_gateway_info_failure(NULL);
300 // Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
301 if(fscanf(fp, "%63s %lx %lx %x %hd %hd %hd %lx %hd %hd %hd\n",
302 iface, &dest, &gate, &flags, &ref, &use,
303 &metric, &mask, &mtu, &win, &irtt) != 11) {
304 update_gateway_info_failure("fscanf()");
308 if (flags & RTF_GATEWAY && dest == 0 && mask == 0) {
310 SAVE_SET_STRING(gw_info->iface, iface)
312 SAVE_SET_STRING(gw_info->ip, inet_ntoa(ina))
319 inline void update_net_stats(void)
324 // FIXME: arbitrary size chosen to keep code simple.
326 unsigned int curtmp1, curtmp2;
333 // wireless info variables
334 int skfd, has_bitrate = 0;
335 struct wireless_info *winfo;
340 delta = current_update_time - last_update_time;
341 if (delta <= 0.0001) {
345 /* open file and ignore first two lines */
346 if (!(net_dev_fp = open_file("/proc/net/dev", &rep))) {
351 fgets(buf, 255, net_dev_fp); /* garbage */
352 fgets(buf, 255, net_dev_fp); /* garbage (field names) */
354 /* read each interface */
355 for (i2 = 0; i2 < 16; i2++) {
359 long long r, t, last_recv, last_trans;
361 if (fgets(buf, 255, net_dev_fp) == NULL) {
365 while (isspace((int) *p)) {
371 while (*p && *p != ':') {
380 ns = get_net_stat(s);
382 memset(&(ns->addr.sa_data), 0, 14);
384 if(NULL == ns->addrs)
385 ns->addrs = (char*) malloc(17 * 16);
386 if(NULL != ns->addrs)
387 memset(ns->addrs, 0, 17 * 16); /* Up to 17 chars per ip, max 16 interfaces. Nasty memory usage... */
389 last_recv = ns->recv;
390 last_trans = ns->trans;
392 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
393 sscanf(p, "%lld %*d %*d %*d %*d %*d %*d %*d %lld",
396 /* if recv or trans is less than last time, an overflow happened */
397 if (r < ns->last_read_recv) {
400 ns->recv += (r - ns->last_read_recv);
402 ns->last_read_recv = r;
404 if (t < ns->last_read_trans) {
407 ns->trans += (t - ns->last_read_trans);
409 ns->last_read_trans = t;
411 /*** ip addr patch ***/
412 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
414 conf.ifc_buf = malloc(sizeof(struct ifreq) * 16);
415 conf.ifc_len = sizeof(struct ifreq) * 16;
416 memset(conf.ifc_buf, 0, conf.ifc_len);
418 ioctl((long) i, SIOCGIFCONF, &conf);
420 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
421 struct net_stat *ns2;
423 if (!(((struct ifreq *) conf.ifc_buf) + k))
427 ((struct ifreq *) conf.ifc_buf)[k].ifr_ifrn.ifrn_name);
428 ns2->addr = ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.ifru_addr;
429 if(NULL != ns2->addrs) {
430 sprintf(temp_addr, "%u.%u.%u.%u, ",
431 ns2->addr.sa_data[2] & 255,
432 ns2->addr.sa_data[3] & 255,
433 ns2->addr.sa_data[4] & 255,
434 ns2->addr.sa_data[5] & 255);
435 if(NULL == strstr(ns2->addrs, temp_addr))
436 strncpy(ns2->addrs + strlen(ns2->addrs), temp_addr, 17);
444 /*** end ip addr patch ***/
446 /* calculate speeds */
447 ns->net_rec[0] = (ns->recv - last_recv) / delta;
448 ns->net_trans[0] = (ns->trans - last_trans) / delta;
452 for (i = 0; (unsigned) i < info.net_avg_samples; i++) {
453 curtmp1 += ns->net_rec[i];
454 curtmp2 += ns->net_trans[i];
462 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
463 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
464 if (info.net_avg_samples > 1) {
465 for (i = info.net_avg_samples; i > 1; i--) {
466 ns->net_rec[i - 1] = ns->net_rec[i - 2];
467 ns->net_trans[i - 1] = ns->net_trans[i - 2];
472 /* update wireless info */
473 winfo = malloc(sizeof(struct wireless_info));
474 memset(winfo, 0, sizeof(struct wireless_info));
476 skfd = iw_sockets_open();
477 if (iw_get_basic_config(skfd, s, &(winfo->b)) > -1) {
479 // set present winfo variables
480 if (iw_get_stats(skfd, s, &(winfo->stats),
481 &winfo->range, winfo->has_range) >= 0) {
482 winfo->has_stats = 1;
484 if (iw_get_range_info(skfd, s, &(winfo->range)) >= 0) {
485 winfo->has_range = 1;
487 if (iw_get_ext(skfd, s, SIOCGIWAP, &wrq) >= 0) {
488 winfo->has_ap_addr = 1;
489 memcpy(&(winfo->ap_addr), &(wrq.u.ap_addr), sizeof(sockaddr));
493 if (iw_get_ext(skfd, s, SIOCGIWRATE, &wrq) >= 0) {
494 memcpy(&(winfo->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
495 iw_print_bitrate(ns->bitrate, 16, winfo->bitrate.value);
500 if (winfo->has_range && winfo->has_stats
501 && ((winfo->stats.qual.level != 0)
502 || (winfo->stats.qual.updated & IW_QUAL_DBM))) {
503 if (!(winfo->stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
504 ns->link_qual = winfo->stats.qual.qual;
505 ns->link_qual_max = winfo->range.max_qual.qual;
510 if (winfo->has_ap_addr) {
511 iw_sawap_ntop(&winfo->ap_addr, ns->ap);
515 if (winfo->b.has_essid) {
516 if (winfo->b.essid_on) {
517 snprintf(ns->essid, 32, "%s", winfo->b.essid);
519 snprintf(ns->essid, 32, "off/any");
523 snprintf(ns->mode, 16, "%s", iw_operation_mode[winfo->b.mode]);
525 iw_sockets_close(skfd);
532 info.mask |= (1 << INFO_NET);
537 void update_total_processes(void)
541 struct sysinfo s_info;
544 info.procs = s_info.procs;
551 if (!(fp = open_file("/proc/loadavg", &rep))) {
555 fscanf(fp, "%*f %*f %*f %*d/%hu", &info.procs);
558 info.mask |= (1 << INFO_PROCS);
561 #define CPU_SAMPLE_COUNT 15
563 unsigned long long cpu_user;
564 unsigned long long cpu_system;
565 unsigned long long cpu_nice;
566 unsigned long long cpu_idle;
567 unsigned long long cpu_iowait;
568 unsigned long long cpu_irq;
569 unsigned long long cpu_softirq;
570 unsigned long long cpu_steal;
571 unsigned long long cpu_total;
572 unsigned long long cpu_active_total;
573 unsigned long long cpu_last_total;
574 unsigned long long cpu_last_active_total;
575 double cpu_val[CPU_SAMPLE_COUNT];
577 static short cpu_setup = 0;
579 /* Determine if this kernel gives us "extended" statistics information in
581 * Kernels around 2.5 and earlier only reported user, system, nice, and
582 * idle values in proc stat.
583 * Kernels around 2.6 and greater report these PLUS iowait, irq, softirq,
585 void determine_longstat(char *buf)
587 unsigned long long iowait = 0;
589 KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
590 /* scanf will either return -1 or 1 because there is only 1 assignment */
591 if (sscanf(buf, "%*s %*d %*d %*d %*d %llu", &iowait) > 0) {
592 KFLAG_SETON(KFLAG_IS_LONGSTAT);
596 void get_cpu_count(void)
602 if (info.cpu_usage) {
606 if (!(stat_fp = open_file("/proc/stat", &rep))) {
612 while (!feof(stat_fp)) {
613 if (fgets(buf, 255, stat_fp) == NULL) {
617 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
618 if (info.cpu_count == 0) {
619 determine_longstat(buf);
624 info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
629 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
630 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
632 inline static void update_stat(void)
636 static struct cpu_info *cpu = NULL;
641 const char *stat_template = NULL;
642 unsigned int malloc_cpu_size = 0;
644 /* add check for !info.cpu_usage since that mem is freed on a SIGUSR1 */
645 if (!cpu_setup || !info.cpu_usage) {
650 if (!stat_template) {
652 KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT;
656 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
657 cpu = malloc(malloc_cpu_size);
658 memset(cpu, 0, malloc_cpu_size);
661 if (!(stat_fp = open_file("/proc/stat", &rep))) {
663 if (info.cpu_usage) {
664 memset(info.cpu_usage, 0, info.cpu_count * sizeof(float));
670 while (!feof(stat_fp)) {
671 if (fgets(buf, 255, stat_fp) == NULL) {
675 if (strncmp(buf, "procs_running ", 14) == 0) {
676 sscanf(buf, "%*s %hu", &info.run_procs);
677 info.mask |= (1 << INFO_RUN_PROCS);
678 } else if (strncmp(buf, "cpu", 3) == 0) {
680 idx = isdigit(buf[3]) ? ((int) buf[3]) - 0x2F : 0;
681 sscanf(buf, stat_template, &(cpu[idx].cpu_user),
682 &(cpu[idx].cpu_nice), &(cpu[idx].cpu_system),
683 &(cpu[idx].cpu_idle), &(cpu[idx].cpu_iowait),
684 &(cpu[idx].cpu_irq), &(cpu[idx].cpu_softirq),
685 &(cpu[idx].cpu_steal));
687 cpu[idx].cpu_total = cpu[idx].cpu_user + cpu[idx].cpu_nice +
688 cpu[idx].cpu_system + cpu[idx].cpu_idle +
689 cpu[idx].cpu_iowait + cpu[idx].cpu_irq +
690 cpu[idx].cpu_softirq + cpu[idx].cpu_steal;
692 cpu[idx].cpu_active_total = cpu[idx].cpu_total -
693 (cpu[idx].cpu_idle + cpu[idx].cpu_iowait);
694 info.mask |= (1 << INFO_CPU);
696 delta = current_update_time - last_update_time;
698 if (delta <= 0.001) {
702 cpu[idx].cpu_val[0] = (cpu[idx].cpu_active_total -
703 cpu[idx].cpu_last_active_total) /
704 (float) (cpu[idx].cpu_total - cpu[idx].cpu_last_total);
706 for (i = 0; i < info.cpu_avg_samples; i++) {
707 curtmp += cpu[idx].cpu_val[i];
709 /* TESTING -- I've removed this, because I don't think it is right.
710 * You shouldn't divide by the cpu count here ...
711 * removing for testing */
713 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples /
716 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples;
718 /* TESTING -- this line replaces the prev. "suspect" if/else */
719 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples;
721 cpu[idx].cpu_last_total = cpu[idx].cpu_total;
722 cpu[idx].cpu_last_active_total = cpu[idx].cpu_active_total;
723 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
724 cpu[idx].cpu_val[i] = cpu[idx].cpu_val[i - 1];
731 void update_running_processes(void)
736 void update_cpu_usage(void)
741 void update_load_average(void)
743 #ifdef HAVE_GETLOADAVG
748 info.loadavg[0] = (float) v[0];
749 info.loadavg[1] = (float) v[1];
750 info.loadavg[2] = (float) v[2];
757 if (!(fp = open_file("/proc/loadavg", &rep))) {
758 info.loadavg[0] = info.loadavg[1] = info.loadavg[2] = 0.0;
761 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1],
765 info.mask |= (1 << INFO_LOADAVG);
768 #define PROC_I8K "/proc/i8k"
769 #define I8K_DELIM " "
770 static char *i8k_procbuf = NULL;
771 void update_i8k(void)
776 i8k_procbuf = (char *) malloc(128 * sizeof(char));
778 if ((fp = fopen(PROC_I8K, "r")) == NULL) {
779 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel "
780 "driver is loaded...");
783 memset(&i8k_procbuf[0], 0, 128);
784 if (fread(&i8k_procbuf[0], sizeof(char), 128, fp) == 0) {
785 ERR("something wrong with /proc/i8k...");
790 i8k.version = strtok(&i8k_procbuf[0], I8K_DELIM);
791 i8k.bios = strtok(NULL, I8K_DELIM);
792 i8k.serial = strtok(NULL, I8K_DELIM);
793 i8k.cpu_temp = strtok(NULL, I8K_DELIM);
794 i8k.left_fan_status = strtok(NULL, I8K_DELIM);
795 i8k.right_fan_status = strtok(NULL, I8K_DELIM);
796 i8k.left_fan_rpm = strtok(NULL, I8K_DELIM);
797 i8k.right_fan_rpm = strtok(NULL, I8K_DELIM);
798 i8k.ac_status = strtok(NULL, I8K_DELIM);
799 i8k.buttons_status = strtok(NULL, I8K_DELIM);
802 /***********************************************************/
803 /***********************************************************/
804 /***********************************************************/
806 static int no_dots(const struct dirent *d)
808 if (d->d_name[0] == '.') {
814 static int get_first_file_in_a_directory(const char *dir, char *s, int *rep)
816 struct dirent **namelist;
819 n = scandir(dir, &namelist, no_dots, alphasort);
822 ERR("scandir for %s: %s", dir, strerror(errno));
833 strncpy(s, namelist[0]->d_name, 255);
836 for (i = 0; i < n; i++) {
845 int open_sysfs_sensor(const char *dir, const char *dev, const char *type, int n,
846 int *divisor, char *devtype)
853 memset(buf, 0, sizeof(buf));
855 /* if device is NULL or *, get first */
856 if (dev == NULL || strcmp(dev, "*") == 0) {
859 if (!get_first_file_in_a_directory(dir, buf, &rep)) {
865 if (strcmp(dir, "/sys/class/hwmon/") == 0) {
867 /* buf holds result from get_first_file_in_a_directory() above,
868 * e.g. "hwmon0" -- append "/device" */
869 strcat(buf, "/device");
871 /* dev holds device number N as a string,
872 * e.g. "0", -- convert to "hwmon0/device" */
873 sprintf(buf, "hwmon%s/device", dev);
878 /* change vol to in */
879 if (strcmp(type, "vol") == 0) {
883 if (strcmp(type, "tempf") == 0) {
884 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, "temp", n);
886 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, type, n);
888 strncpy(devtype, path, 255);
891 fd = open(path, O_RDONLY);
893 CRIT_ERR("can't open '%s': %s\nplease check your device or remove this "
894 "var from Conky", path, strerror(errno));
897 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
898 || strcmp(type, "tempf") == 0) {
903 /* fan does not use *_div as a read divisor */
904 if (strcmp("fan", type) == 0) {
908 /* test if *_div file exist, open it and use it as divisor */
909 if (strcmp(type, "tempf") == 0) {
910 snprintf(path, 255, "%s%s/%s%d_div", dir, "one", "two", n);
912 snprintf(path, 255, "%s%s/%s%d_div", dir, dev, type, n);
915 divfd = open(path, O_RDONLY);
921 divn = read(divfd, divbuf, 63);
922 /* should read until n == 0 but I doubt that kernel will give these
923 * in multiple pieces. :) */
925 ERR("open_sysfs_sensor(): can't read from sysfs");
928 *divisor = atoi(divbuf);
937 double get_sysfs_info(int *fd, int divisor, char *devtype, char *type)
945 lseek(*fd, 0, SEEK_SET);
951 n = read(*fd, buf, 63);
952 /* should read until n == 0 but I doubt that kernel will give these
953 * in multiple pieces. :) */
955 ERR("get_sysfs_info(): read from %s failed\n", devtype);
964 *fd = open(devtype, O_RDONLY);
966 ERR("can't open '%s': %s", devtype, strerror(errno));
969 /* My dirty hack for computing CPU value
970 * Filedil, from forums.gentoo.org */
971 /* if (strstr(devtype, "temp1_input") != NULL) {
972 return -15.096 + 1.4893 * (val / 1000.0);
975 /* divide voltage and temperature by 1000 */
976 /* or if any other divisor is given, use that */
977 if (strcmp(type, "tempf") == 0) {
979 return ((val / divisor + 40) * 9.0 / 5) - 40;
980 } else if (divisor) {
981 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
983 return ((val + 40) * 9.0 / 5) - 40;
987 return val / divisor;
988 } else if (divisor) {
996 /* Prior to kernel version 2.6.12, the CPU fan speed was available in
997 * ADT746X_FAN_OLD, whereas later kernel versions provide this information in
999 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
1000 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
1002 void get_adt746x_fan(char *p_client_buffer, size_t client_buffer_size)
1005 char adt746x_fan_state[64];
1008 if (!p_client_buffer || client_buffer_size <= 0) {
1012 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
1013 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL) {
1014 sprintf(adt746x_fan_state, "adt746x not found");
1016 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
1017 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
1021 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_fan_state);
1024 /* Prior to kernel version 2.6.12, the CPU temperature was found in
1025 * ADT746X_CPU_OLD, whereas later kernel versions provide this information in
1027 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
1028 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
1030 void get_adt746x_cpu(char *p_client_buffer, size_t client_buffer_size)
1033 char adt746x_cpu_state[64];
1036 if (!p_client_buffer || client_buffer_size <= 0) {
1040 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
1041 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL) {
1042 sprintf(adt746x_cpu_state, "adt746x not found");
1044 fscanf(fp, "%2s", adt746x_cpu_state);
1048 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state);
1051 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
1053 /***********************************************************************/
1054 /* This file is part of x86info.
1055 * (C) 2001 Dave Jones.
1057 * Licensed under the terms of the GNU GPL License version 2.
1059 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
1060 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz> */
1062 #if defined(__i386) || defined(__x86_64)
1063 __inline__ unsigned long long int rdtsc(void)
1065 unsigned long long int x;
1067 __asm__ volatile(".byte 0x0f, 0x31":"=A" (x));
1072 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1073 void get_freq_dynamic(char *p_client_buffer, size_t client_buffer_size,
1074 const char *p_format, int divisor)
1076 #if defined(__i386) || defined(__x86_64)
1078 struct timeval tvstart, tvstop;
1079 unsigned long long cycles[2]; /* gotta be 64 bit */
1080 unsigned int microseconds; /* total time taken */
1082 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1087 memset(&tz, 0, sizeof(tz));
1089 /* get this function in cached memory */
1090 gettimeofday(&tvstart, &tz);
1091 cycles[0] = rdtsc();
1092 gettimeofday(&tvstart, &tz);
1094 /* we don't trust that this is any specific length of time */
1096 cycles[1] = rdtsc();
1097 gettimeofday(&tvstop, &tz);
1098 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
1099 (tvstop.tv_usec - tvstart.tv_usec);
1101 snprintf(p_client_buffer, client_buffer_size, p_format,
1102 (float) ((cycles[1] - cycles[0]) / microseconds) / divisor);
1105 /* FIXME: hardwired: get freq for first cpu!
1106 * this whole function needs to be rethought and redone for
1107 * multi-cpu/multi-core/multi-threaded environments and
1108 * arbitrary combinations thereof */
1109 get_freq(p_client_buffer, client_buffer_size, p_format, divisor, 1);
1114 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
1115 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
1117 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1118 char get_freq(char *p_client_buffer, size_t client_buffer_size,
1119 const char *p_format, int divisor, unsigned int cpu)
1127 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1133 char current_freq_file[128];
1135 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu - 1,
1137 f = fopen(current_freq_file, "r");
1139 /* if there's a cpufreq /sys node, read the current frequency from
1140 * this node and divide by 1000 to get Mhz. */
1141 if (fgets(s, sizeof(s), f)) {
1142 s[strlen(s) - 1] = '\0';
1143 freq = strtod(s, NULL);
1146 snprintf(p_client_buffer, client_buffer_size, p_format,
1147 (freq / 1000) / divisor);
1152 // open the CPU information file
1153 f = open_file("/proc/cpuinfo", &rep);
1155 perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
1160 while (fgets(s, sizeof(s), f) != NULL) {
1162 #if defined(__i386) || defined(__x86_64)
1163 // and search for the cpu mhz
1164 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) {
1166 #if defined(__alpha)
1167 // different on alpha
1168 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) {
1170 // this is different on ppc for some reason
1171 if (strncmp(s, "clock", 5) == 0 && cpu == 0) {
1172 #endif // defined(__alpha)
1173 #endif // defined(__i386) || defined(__x86_64)
1175 // copy just the number
1176 strcpy(frequency, strchr(s, ':') + 2);
1177 #if defined(__alpha)
1179 frequency[strlen(frequency) - 6] = '\0';
1180 // kernel reports in Hz
1181 freq = strtod(frequency, NULL) / 1000000;
1184 frequency[strlen(frequency) - 1] = '\0';
1185 freq = strtod(frequency, NULL);
1189 if (strncmp(s, "processor", 9) == 0) {
1196 snprintf(p_client_buffer, client_buffer_size, p_format,
1197 (float) freq / divisor);
1201 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
1203 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks something
1213 * Peter Tarjan (ptarjan@citromail.hu) */
1215 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
1216 char get_voltage(char *p_client_buffer, size_t client_buffer_size,
1217 const char *p_format, int divisor, unsigned int cpu)
1223 char current_freq_file[128];
1226 /* build the voltage file name */
1228 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1231 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1236 /* read the current cpu frequency from the /sys node */
1237 f = fopen(current_freq_file, "r");
1239 if (fgets(s, sizeof(s), f)) {
1240 s[strlen(s) - 1] = '\0';
1241 freq = strtod(s, NULL);
1245 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1246 perror("get_voltage()");
1253 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1256 /* use the current cpu frequency to find the corresponding voltage */
1257 f = fopen(current_freq_file, "r");
1263 if (fgets(line, 255, f) == NULL) {
1266 sscanf(line, "%d %d", &freq_comp, &voltage);
1267 if (freq_comp == freq) {
1273 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1274 perror("get_voltage()");
1280 snprintf(p_client_buffer, client_buffer_size, p_format,
1281 (float) voltage / divisor);
1285 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1287 void get_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
1294 if (!p_client_buffer || client_buffer_size <= 0) {
1298 /* yeah, slow... :/ */
1299 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep)) {
1300 snprintf(p_client_buffer, client_buffer_size, "no fans?");
1304 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf);
1306 fp = open_file(buf2, &rep);
1308 snprintf(p_client_buffer, client_buffer_size,
1309 "can't open fan's state file");
1312 memset(buf, 0, sizeof(buf));
1313 fscanf(fp, "%*s %99s", buf);
1316 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1319 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1321 void get_acpi_ac_adapter(char *p_client_buffer, size_t client_buffer_size)
1328 if (!p_client_buffer || client_buffer_size <= 0) {
1332 /* yeah, slow... :/ */
1333 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep)) {
1334 snprintf(p_client_buffer, client_buffer_size, "no ac_adapters?");
1338 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf);
1340 fp = open_file(buf2, &rep);
1342 snprintf(p_client_buffer, client_buffer_size,
1343 "No ac adapter found.... where is it?");
1346 memset(buf, 0, sizeof(buf));
1347 fscanf(fp, "%*s %99s", buf);
1350 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1354 /proc/acpi/thermal_zone/THRM/cooling_mode
1355 cooling mode: active
1356 /proc/acpi/thermal_zone/THRM/polling_frequency
1358 /proc/acpi/thermal_zone/THRM/state
1360 /proc/acpi/thermal_zone/THRM/temperature
1362 /proc/acpi/thermal_zone/THRM/trip_points
1364 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1367 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1368 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1370 int open_acpi_temperature(const char *name)
1376 if (name == NULL || strcmp(name, "*") == 0) {
1379 if (!get_first_file_in_a_directory(ACPI_THERMAL_DIR, buf, &rep)) {
1385 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1387 fd = open(path, O_RDONLY);
1389 ERR("can't open '%s': %s", path, strerror(errno));
1395 static double last_acpi_temp;
1396 static double last_acpi_temp_time;
1398 double get_acpi_temperature(int fd)
1404 /* don't update acpi temperature too often */
1405 if (current_update_time - last_acpi_temp_time < 11.32) {
1406 return last_acpi_temp;
1408 last_acpi_temp_time = current_update_time;
1410 /* seek to beginning */
1411 lseek(fd, 0, SEEK_SET);
1418 n = read(fd, buf, 255);
1420 ERR("can't read fd %d: %s", fd, strerror(errno));
1423 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1427 return last_acpi_temp;
1431 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1433 design capacity: 4400 mAh
1434 last full capacity: 4064 mAh
1435 battery technology: rechargeable
1436 design voltage: 14800 mV
1437 design capacity warning: 300 mAh
1438 design capacity low: 200 mAh
1439 capacity granularity 1: 32 mAh
1440 capacity granularity 2: 32 mAh
1442 serial number: 16922
1448 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1451 charging state: unknown
1453 remaining capacity: 4064 mAh
1454 present voltage: 16608 mV
1458 2213<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1459 2213<@jupet�kellari��> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1460 2213<@jupet�kellari��> (-1 ollee ei akkua kiinni, koska akku on p�yd�ll�)
1461 2214<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1462 2214<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1464 2238<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1465 2239<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1467 2240<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori p��ll�
1468 2241<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori p��ll� mutta ilman verkkovirtaa
1471 /* Kapil Hari Paranjape <kapil@imsc.res.in>
1472 Linux 2.6.24 onwards battery info is in
1473 /sys/class/power_supply/BAT0/
1474 On my system I get the following.
1475 /sys/class/power_supply/BAT0/uevent:
1476 PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A03:00/device:01/PNP0C09:00/PNP0C0A:00
1478 PHYSDEVDRIVER=battery
1479 POWER_SUPPLY_NAME=BAT0
1480 POWER_SUPPLY_TYPE=Battery
1481 POWER_SUPPLY_STATUS=Discharging
1482 POWER_SUPPLY_PRESENT=1
1483 POWER_SUPPLY_TECHNOLOGY=Li-ion
1484 POWER_SUPPLY_VOLTAGE_MIN_DESIGN=10800000
1485 POWER_SUPPLY_VOLTAGE_NOW=10780000
1486 POWER_SUPPLY_CURRENT_NOW=13970000
1487 POWER_SUPPLY_ENERGY_FULL_DESIGN=47510000
1488 POWER_SUPPLY_ENERGY_FULL=27370000
1489 POWER_SUPPLY_ENERGY_NOW=11810000
1490 POWER_SUPPLY_MODEL_NAME=IBM-92P1060
1491 POWER_SUPPLY_MANUFACTURER=Panasonic
1492 On some systems POWER_SUPPLY_ENERGY_* is replaced by POWER_SUPPLY_CHARGE_*
1495 #define SYSFS_BATTERY_BASE_PATH "/sys/class/power_supply"
1496 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1497 #define APM_PATH "/proc/apm"
1498 #define MAX_BATTERY_COUNT 4
1500 static FILE *sysfs_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1501 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1502 static FILE *apm_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1504 static int batteries_initialized = 0;
1505 static char batteries[MAX_BATTERY_COUNT][32];
1507 static int acpi_last_full[MAX_BATTERY_COUNT];
1508 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1510 /* e.g. "charging 75%" */
1511 static char last_battery_str[MAX_BATTERY_COUNT][64];
1513 static char last_battery_time_str[MAX_BATTERY_COUNT][64];
1515 static double last_battery_time[MAX_BATTERY_COUNT];
1517 static int last_battery_perct[MAX_BATTERY_COUNT];
1518 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1520 void init_batteries(void)
1524 if (batteries_initialized) {
1527 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1528 batteries[idx][0] = '\0';
1530 batteries_initialized = 1;
1533 int get_battery_idx(const char *bat)
1537 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1538 if (!strlen(batteries[idx]) || !strcmp(batteries[idx], bat)) {
1543 /* if not found, enter a new entry */
1544 if (!strlen(batteries[idx])) {
1545 snprintf(batteries[idx], 31, "%s", bat);
1551 void set_return_value(char *buffer, unsigned int n, int item, int idx);
1553 void get_battery_stuff(char *buffer, unsigned int n, const char *bat, int item)
1555 static int idx, rep = 0, rep2 = 0;
1556 char acpi_path[128];
1557 char sysfs_path[128];
1559 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1560 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1564 idx = get_battery_idx(bat);
1566 /* don't update battery too often */
1567 if (current_update_time - last_battery_time[idx] < 29.5) {
1568 set_return_value(buffer, n, item, idx);
1572 last_battery_time[idx] = current_update_time;
1574 memset(last_battery_str[idx], 0, sizeof(last_battery_str[idx]));
1575 memset(last_battery_time_str[idx], 0, sizeof(last_battery_time_str[idx]));
1577 /* first try SYSFS if that fails try ACPI */
1579 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1580 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1584 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1585 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1588 if (sysfs_bat_fp[idx] != NULL) {
1590 int present_rate = -1;
1591 int remaining_capacity = -1;
1592 char charging_state[64];
1595 strcpy(charging_state, "unknown");
1597 while (!feof(sysfs_bat_fp[idx])) {
1599 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1602 /* let's just hope units are ok */
1603 if (strncmp (buf, "POWER_SUPPLY_PRESENT=1", 22) == 0)
1604 strcpy(present, "yes");
1605 else if (strncmp (buf, "POWER_SUPPLY_PRESENT=0", 22) == 0)
1606 strcpy(present, "no");
1607 else if (strncmp (buf, "POWER_SUPPLY_STATUS=", 20) == 0)
1608 sscanf(buf, "POWER_SUPPLY_STATUS=%63s", charging_state);
1609 /* present_rate is not the same as the
1610 current flowing now but it is the same value
1611 which was used in the past. so we continue
1613 else if (strncmp(buf, "POWER_SUPPLY_CURRENT_NOW=", 25) == 0)
1614 sscanf(buf, "POWER_SUPPLY_CURRENT_NOW=%d", &present_rate);
1615 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0)
1616 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1617 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=", 25) == 0)
1618 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_last_full[idx]);
1619 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0)
1620 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1621 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=", 25) == 0)
1622 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_last_full[idx]);
1625 fclose(sysfs_bat_fp[idx]);
1626 sysfs_bat_fp[idx] = NULL;
1628 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1629 if (remaining_capacity > acpi_last_full[idx])
1630 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1633 if (strcmp(present, "No") == 0) {
1634 strncpy(last_battery_str[idx], "not present", 64);
1637 else if (strcmp(charging_state, "Charging") == 0) {
1638 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1639 /* e.g. charging 75% */
1640 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %i%%",
1641 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1643 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1644 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1645 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1646 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %d%%",
1647 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1648 snprintf(last_battery_time_str[idx],
1649 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1651 strncpy(last_battery_str[idx], "charging", sizeof(last_battery_str[idx])-1);
1652 snprintf(last_battery_time_str[idx],
1653 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1657 else if (strncmp(charging_state, "Discharging", 64) == 0) {
1658 if (present_rate > 0) {
1659 /* e.g. discharging 35% */
1660 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "discharging %i%%",
1661 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1663 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1664 (long) (((float) remaining_capacity / present_rate) * 3600));
1665 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1666 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "full");
1667 snprintf(last_battery_time_str[idx],
1668 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1670 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1672 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1673 snprintf(last_battery_time_str[idx],
1674 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1678 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1679 else if (strncmp(charging_state, "Charged", 64) == 0) {
1680 /* Below happens with the second battery on my X40,
1681 * when the second one is empty and the first one
1683 if (remaining_capacity == 0)
1684 strcpy(last_battery_str[idx], "empty");
1686 strcpy(last_battery_str[idx], "charged");
1688 /* unknown, probably full / AC */
1690 if (acpi_last_full[idx] != 0
1691 && remaining_capacity != acpi_last_full[idx])
1692 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1693 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1695 strncpy(last_battery_str[idx], "AC", 64);
1697 } else if (acpi_bat_fp[idx] != NULL) {
1699 int present_rate = -1;
1700 int remaining_capacity = -1;
1701 char charging_state[64];
1704 /* read last full capacity if it's zero */
1705 if (acpi_last_full[idx] == 0) {
1706 static int rep3 = 0;
1710 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1711 fp = open_file(path, &rep3);
1716 if (fgets(b, 256, fp) == NULL) {
1719 if (sscanf(b, "last full capacity: %d",
1720 &acpi_last_full[idx]) != 0) {
1729 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1731 strcpy(charging_state, "unknown");
1733 while (!feof(acpi_bat_fp[idx])) {
1736 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1740 /* let's just hope units are ok */
1741 if (strncmp(buf, "present:", 8) == 0) {
1742 sscanf(buf, "present: %4s", present);
1743 } else if (strncmp(buf, "charging state:", 15) == 0) {
1744 sscanf(buf, "charging state: %63s", charging_state);
1745 } else if (strncmp(buf, "present rate:", 13) == 0) {
1746 sscanf(buf, "present rate: %d", &present_rate);
1747 } else if (strncmp(buf, "remaining capacity:", 19) == 0) {
1748 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1751 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1752 if (remaining_capacity > acpi_last_full[idx]) {
1753 /* normalize to 100% */
1754 acpi_last_full[idx] = remaining_capacity;
1758 if (strcmp(present, "no") == 0) {
1759 strncpy(last_battery_str[idx], "not present", 64);
1761 } else if (strcmp(charging_state, "charging") == 0) {
1762 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1763 /* e.g. charging 75% */
1764 snprintf(last_battery_str[idx],
1765 sizeof(last_battery_str[idx]) - 1, "charging %i%%",
1766 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1768 format_seconds(last_battery_time_str[idx],
1769 sizeof(last_battery_time_str[idx]) - 1,
1770 (long) (((acpi_last_full[idx] - remaining_capacity) *
1771 3600) / present_rate));
1772 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1773 snprintf(last_battery_str[idx],
1774 sizeof(last_battery_str[idx]) - 1, "charging %d%%",
1775 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1776 snprintf(last_battery_time_str[idx],
1777 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1779 strncpy(last_battery_str[idx], "charging",
1780 sizeof(last_battery_str[idx]) - 1);
1781 snprintf(last_battery_time_str[idx],
1782 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1785 } else if (strncmp(charging_state, "discharging", 64) == 0) {
1786 if (present_rate > 0) {
1787 /* e.g. discharging 35% */
1788 snprintf(last_battery_str[idx],
1789 sizeof(last_battery_str[idx]) - 1, "discharging %i%%",
1790 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1792 format_seconds(last_battery_time_str[idx],
1793 sizeof(last_battery_time_str[idx]) - 1,
1794 (long) ((remaining_capacity * 3600) / present_rate));
1795 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1796 snprintf(last_battery_str[idx],
1797 sizeof(last_battery_str[idx]) - 1, "full");
1798 snprintf(last_battery_time_str[idx],
1799 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1801 snprintf(last_battery_str[idx],
1802 sizeof(last_battery_str[idx]) - 1, "discharging %d%%",
1803 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1804 snprintf(last_battery_time_str[idx],
1805 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1808 } else if (strncmp(charging_state, "charged", 64) == 0) {
1809 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1810 /* Below happens with the second battery on my X40,
1811 * when the second one is empty and the first one being charged. */
1812 if (remaining_capacity == 0) {
1813 strcpy(last_battery_str[idx], "empty");
1815 strcpy(last_battery_str[idx], "charged");
1817 /* unknown, probably full / AC */
1819 if (acpi_last_full[idx] != 0
1820 && remaining_capacity != acpi_last_full[idx]) {
1821 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1822 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1824 strncpy(last_battery_str[idx], "AC", 64);
1829 if (apm_bat_fp[idx] == NULL) {
1830 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1833 if (apm_bat_fp[idx] != NULL) {
1834 unsigned int ac, status, flag;
1837 fscanf(apm_bat_fp[idx], "%*s %*s %*x %x %x %x %d%%",
1838 &ac, &status, &flag, &life);
1841 /* could check now that there is ac */
1842 snprintf(last_battery_str[idx], 64, "AC");
1844 /* could check that status == 3 here? */
1845 } else if (ac && life != 100) {
1846 snprintf(last_battery_str[idx], 64, "charging %d%%", life);
1848 snprintf(last_battery_str[idx], 64, "%d%%", life);
1851 /* it seemed to buffer it so file must be closed (or could use
1852 * syscalls directly but I don't feel like coding it now) */
1853 fclose(apm_bat_fp[idx]);
1854 apm_bat_fp[idx] = NULL;
1857 set_return_value(buffer, n, item, idx);
1860 void set_return_value(char *buffer, unsigned int n, int item, int idx)
1863 case BATTERY_STATUS:
1864 snprintf(buffer, n, "%s", last_battery_str[idx]);
1867 snprintf(buffer, n, "%s", last_battery_time_str[idx]);
1874 int get_battery_perct(const char *bat)
1878 char acpi_path[128];
1879 char sysfs_path[128];
1880 int remaining_capacity = -1;
1882 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1883 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1887 idx = get_battery_idx(bat);
1889 /* don't update battery too often */
1890 if (current_update_time - last_battery_perct_time[idx] < 30) {
1891 return last_battery_perct[idx];
1893 last_battery_perct_time[idx] = current_update_time;
1895 /* Only check for SYSFS or ACPI */
1897 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1898 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1902 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1903 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1906 if (sysfs_bat_fp[idx] != NULL) {
1908 while (!feof(sysfs_bat_fp[idx])) {
1910 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1913 if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0) {
1914 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1915 } else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=",25) == 0) {
1916 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_design_capacity[idx]);
1917 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0) {
1918 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1919 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=",25) == 0) {
1920 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_design_capacity[idx]);
1924 fclose(sysfs_bat_fp[idx]);
1925 sysfs_bat_fp[idx] = NULL;
1927 } else if (acpi_bat_fp[idx] != NULL) {
1929 /* read last full capacity if it's zero */
1930 if (acpi_design_capacity[idx] == 0) {
1935 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1936 fp = open_file(path, &rep2);
1941 if (fgets(b, 256, fp) == NULL) {
1944 if (sscanf(b, "last full capacity: %d",
1945 &acpi_design_capacity[idx]) != 0) {
1953 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1955 while (!feof(acpi_bat_fp[idx])) {
1958 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1962 if (buf[0] == 'r') {
1963 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1967 if (remaining_capacity < 0) {
1970 /* compute the battery percentage */
1971 last_battery_perct[idx] =
1972 (int) (((float) remaining_capacity / acpi_design_capacity[idx]) * 100);
1973 return last_battery_perct[idx];
1976 int get_battery_perct_bar(const char *bar)
1980 get_battery_perct(bar);
1981 idx = get_battery_idx(bar);
1982 return (int) (last_battery_perct[idx] * 2.56 - 1);
1985 /* On Apple powerbook and ibook:
1986 $ cat /proc/pmu/battery_0
1993 $ cat /proc/pmu/info
1994 PMU driver version : 2
1995 PMU firmware version : 0c
2000 /* defines as in <linux/pmu.h> */
2001 #define PMU_BATT_PRESENT 0x00000001
2002 #define PMU_BATT_CHARGING 0x00000002
2004 static FILE *pmu_battery_fp;
2005 static FILE *pmu_info_fp;
2006 static char pb_battery_info[3][32];
2007 static double pb_battery_info_update;
2009 #define PMU_PATH "/proc/pmu"
2010 void get_powerbook_batt_info(char *buffer, size_t n, int i)
2013 const char *batt_path = PMU_PATH "/battery_0";
2014 const char *info_path = PMU_PATH "/info";
2016 int charge, max_charge, ac = -1;
2019 /* don't update battery too often */
2020 if (current_update_time - pb_battery_info_update < 29.5) {
2021 snprintf(buffer, n, "%s", pb_battery_info[i]);
2024 pb_battery_info_update = current_update_time;
2026 if (pmu_battery_fp == NULL) {
2027 pmu_battery_fp = open_file(batt_path, &rep);
2030 if (pmu_battery_fp != NULL) {
2031 rewind(pmu_battery_fp);
2032 while (!feof(pmu_battery_fp)) {
2035 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL) {
2039 if (buf[0] == 'f') {
2040 sscanf(buf, "flags : %8x", &flags);
2041 } else if (buf[0] == 'c' && buf[1] == 'h') {
2042 sscanf(buf, "charge : %d", &charge);
2043 } else if (buf[0] == 'm') {
2044 sscanf(buf, "max_charge : %d", &max_charge);
2045 } else if (buf[0] == 't') {
2046 sscanf(buf, "time rem. : %ld", &timeval);
2050 if (pmu_info_fp == NULL) {
2051 pmu_info_fp = open_file(info_path, &rep);
2054 if (pmu_info_fp != NULL) {
2055 rewind(pmu_info_fp);
2056 while (!feof(pmu_info_fp)) {
2059 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL) {
2062 if (buf[0] == 'A') {
2063 sscanf(buf, "AC Power : %d", &ac);
2067 /* update status string */
2068 if ((ac && !(flags & PMU_BATT_PRESENT))) {
2069 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
2070 } else if (ac && (flags & PMU_BATT_PRESENT)
2071 && !(flags & PMU_BATT_CHARGING)) {
2072 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
2073 } else if ((flags & PMU_BATT_PRESENT) && (flags & PMU_BATT_CHARGING)) {
2074 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
2076 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
2079 /* update percentage string */
2081 pb_battery_info[PB_BATT_PERCENT][0] = 0;
2083 snprintf(pb_battery_info[PB_BATT_PERCENT],
2084 sizeof(pb_battery_info[PB_BATT_PERCENT]), "%d%%",
2085 (charge * 100) / max_charge);
2088 /* update time string */
2089 if (timeval == 0) { /* fully charged or battery not present */
2090 pb_battery_info[PB_BATT_TIME][0] = 0;
2091 } else if (timeval < 60 * 60) { /* don't show secs */
2092 format_seconds_short(pb_battery_info[PB_BATT_TIME],
2093 sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2095 format_seconds(pb_battery_info[PB_BATT_TIME],
2096 sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2099 snprintf(buffer, n, "%s", pb_battery_info[i]);
2102 void update_top(void)
2104 show_nice_processes = 1;
2105 process_find_top(info.cpu, info.memu);
2106 info.first_process = get_first_process();
2109 /* Here come the IBM ACPI-specific things. For reference, see
2110 * http://ibm-acpi.sourceforge.net/README
2111 * If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
2127 * The content of these files is described in detail in the aforementioned
2128 * README - some of them also in the following functions accessing them.
2129 * Peter Tarjan (ptarjan@citromail.hu) */
2131 #define IBM_ACPI_DIR "/proc/acpi/ibm"
2133 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
2134 * /proc/acpi/ibm/fan looks like this (3 lines):
2137 commands: enable, disable
2138 * Peter Tarjan (ptarjan@citromail.hu) */
2140 void get_ibm_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
2143 unsigned int speed = 0;
2146 if (!p_client_buffer || client_buffer_size <= 0) {
2150 snprintf(fan, 127, "%s/fan", IBM_ACPI_DIR);
2152 fp = fopen(fan, "r");
2157 if (fgets(line, 255, fp) == NULL) {
2160 if (sscanf(line, "speed: %u", &speed)) {
2165 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2166 "ibm* from your Conky config file.", fan, strerror(errno));
2170 snprintf(p_client_buffer, client_buffer_size, "%d", speed);
2173 /* get the measured temperatures from the temperature sensors
2174 * on IBM/Lenovo laptops running the ibm acpi.
2175 * There are 8 values in /proc/acpi/ibm/thermal, and according to
2176 * http://ibm-acpi.sourceforge.net/README
2177 * these mean the following (at least on an IBM R51...)
2178 * 0: CPU (also on the T series laptops)
2179 * 1: Mini PCI Module (?)
2181 * 3: GPU (also on the T series laptops)
2186 * I'm not too sure about those with the question mark, but the values I'm
2187 * reading from *my* thermal file (on a T42p) look realistic for the
2188 * hdd and the battery.
2189 * #5 and #7 are always -128.
2190 * /proc/acpi/ibm/thermal looks like this (1 line):
2191 temperatures: 41 43 31 46 33 -128 29 -128
2192 * Peter Tarjan (ptarjan@citromail.hu) */
2194 static double last_ibm_acpi_temp_time;
2195 void get_ibm_acpi_temps(void)
2201 /* don't update too often */
2202 if (current_update_time - last_ibm_acpi_temp_time < 10.00) {
2205 last_ibm_acpi_temp_time = current_update_time;
2207 /* if (!p_client_buffer || client_buffer_size <= 0) {
2211 snprintf(thermal, 127, "%s/thermal", IBM_ACPI_DIR);
2212 fp = fopen(thermal, "r");
2218 if (fgets(line, 255, fp) == NULL) {
2221 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
2222 &ibm_acpi.temps[0], &ibm_acpi.temps[1], &ibm_acpi.temps[2],
2223 &ibm_acpi.temps[3], &ibm_acpi.temps[4], &ibm_acpi.temps[5],
2224 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) {
2229 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2230 "ibm* from your Conky config file.", thermal, strerror(errno));
2236 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
2237 * "Volume" here is none of the mixer volumes, but a "master of masters"
2238 * volume adjusted by the IBM volume keys.
2239 * /proc/acpi/ibm/fan looks like this (4 lines):
2242 commands: up, down, mute
2243 commands: level <level> (<level> is 0-15)
2244 * Peter Tarjan (ptarjan@citromail.hu) */
2246 void get_ibm_acpi_volume(char *p_client_buffer, size_t client_buffer_size)
2250 unsigned int vol = -1;
2253 if (!p_client_buffer || client_buffer_size <= 0) {
2257 snprintf(volume, 127, "%s/volume", IBM_ACPI_DIR);
2259 fp = fopen(volume, "r");
2263 unsigned int read_vol = -1;
2265 if (fgets(line, 255, fp) == NULL) {
2268 if (sscanf(line, "level: %u", &read_vol)) {
2272 if (sscanf(line, "mute: %s", mute)) {
2277 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2278 "ibm* from your Conky config file.", volume, strerror(errno));
2283 if (strcmp(mute, "on") == 0) {
2284 snprintf(p_client_buffer, client_buffer_size, "%s", "mute");
2287 snprintf(p_client_buffer, client_buffer_size, "%d", vol);
2292 /* static FILE *fp = NULL; */
2294 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
2295 * /proc/acpi/ibm/brightness looks like this (3 lines):
2298 commands: level <level> (<level> is 0-7)
2299 * Peter Tarjan (ptarjan@citromail.hu) */
2301 void get_ibm_acpi_brightness(char *p_client_buffer, size_t client_buffer_size)
2304 unsigned int brightness = 0;
2307 if (!p_client_buffer || client_buffer_size <= 0) {
2311 snprintf(filename, 127, "%s/brightness", IBM_ACPI_DIR);
2313 fp = fopen(filename, "r");
2318 if (fgets(line, 255, fp) == NULL) {
2321 if (sscanf(line, "level: %u", &brightness)) {
2326 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2327 "ibm* from your Conky config file.", filename, strerror(errno));
2332 snprintf(p_client_buffer, client_buffer_size, "%d", brightness);
2335 void update_entropy(void)
2338 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
2339 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
2342 info.entropy.entropy_avail = 0;
2343 info.entropy.poolsize = 0;
2345 if ((fp1 = open_file(entropy_avail, &rep)) == NULL) {
2349 if ((fp2 = open_file(entropy_poolsize, &rep)) == NULL) {
2354 fscanf(fp1, "%u", &info.entropy.entropy_avail);
2355 fscanf(fp2, "%u", &info.entropy.poolsize);
2360 info.mask |= (1 << INFO_ENTROPY);
2363 const char *get_disk_protect_queue(const char *disk)
2369 snprintf(path, 127, "/sys/block/%s/queue/protect", disk);
2370 if ((fp = fopen(path, "r")) == NULL)
2372 if (fscanf(fp, "%d\n", &state) != 1) {
2377 return state ? "frozen" : "free ";