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/>.
34 #include <sys/types.h>
35 #include <sys/sysinfo.h>
37 #ifndef HAVE_CLOCK_GETTIME
42 // #include <assert.h>
46 #include <sys/ioctl.h>
47 #include <sys/socket.h>
48 #include <netinet/in.h>
49 #include <linux/sockios.h>
51 #include <arpa/inet.h>
55 #include <linux/route.h>
62 #define SHORTSTAT_TEMPL "%*s %llu %llu %llu"
63 #define LONGSTAT_TEMPL "%*s %llu %llu %llu "
65 static int show_nice_processes;
67 /* This flag tells the linux routines to use the /proc system where possible,
68 * even if other api's are available, e.g. sysinfo() or getloadavg().
69 * the reason for this is to allow for /proc-based distributed monitoring.
70 * using a flag in this manner creates less confusing code. */
71 static int prefer_proc = 0;
73 void prepare_update(void)
77 void update_uptime(void)
81 struct sysinfo s_info;
84 info.uptime = (double) s_info.uptime;
91 if (!(fp = open_file("/proc/uptime", &rep))) {
95 fscanf(fp, "%lf", &info.uptime);
98 info.mask |= (1 << INFO_UPTIME);
101 int check_mount(char *s)
104 FILE *mtab = fopen("/etc/mtab", "r");
107 char buf1[256], buf2[128];
109 while (fgets(buf1, 256, mtab)) {
110 sscanf(buf1, "%*s %128s", buf2);
111 if (!strcmp(s, buf2)) {
118 ERR("Could not open mtab");
123 /* these things are also in sysinfo except Buffers:
124 * (that's why I'm reading them from proc) */
126 void update_meminfo(void)
131 /* unsigned int a; */
134 info.mem = info.memmax = info.swap = info.swapmax = info.bufmem =
135 info.buffers = info.cached = info.memfree = info.memeasyfree = 0;
137 if (!(meminfo_fp = open_file("/proc/meminfo", &rep))) {
141 while (!feof(meminfo_fp)) {
142 if (fgets(buf, 255, meminfo_fp) == NULL) {
146 if (strncmp(buf, "MemTotal:", 9) == 0) {
147 sscanf(buf, "%*s %llu", &info.memmax);
148 } else if (strncmp(buf, "MemFree:", 8) == 0) {
149 sscanf(buf, "%*s %llu", &info.memfree);
150 } else if (strncmp(buf, "SwapTotal:", 10) == 0) {
151 sscanf(buf, "%*s %llu", &info.swapmax);
152 } else if (strncmp(buf, "SwapFree:", 9) == 0) {
153 sscanf(buf, "%*s %llu", &info.swap);
154 } else if (strncmp(buf, "Buffers:", 8) == 0) {
155 sscanf(buf, "%*s %llu", &info.buffers);
156 } else if (strncmp(buf, "Cached:", 7) == 0) {
157 sscanf(buf, "%*s %llu", &info.cached);
161 info.mem = info.memmax - info.memfree;
162 info.memeasyfree = info.memfree;
163 info.swap = info.swapmax - info.swap;
165 info.bufmem = info.cached + info.buffers;
167 info.mask |= (1 << INFO_MEM) | (1 << INFO_BUFFERS);
172 int get_laptop_mode(void)
177 if ((fp = fopen("/proc/sys/vm/laptop_mode", "r")) != NULL)
178 fscanf(fp, "%d\n", &val);
184 * # cat /sys/block/sda/queue/scheduler
185 * noop [anticipatory] cfq
187 char *get_ioscheduler(char *disk)
193 return strndup("n/a", text_buffer_size);
195 snprintf(buf, 127, "/sys/block/%s/queue/scheduler", disk);
196 if ((fp = fopen(buf, "r")) == NULL) {
197 return strndup("n/a", text_buffer_size);
200 fscanf(fp, "%127s", buf);
202 buf[strlen(buf) - 1] = '\0';
204 return strndup(buf + 1, text_buffer_size);
208 return strndup("n/a", text_buffer_size);
211 int interface_up(const char *dev)
216 if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
217 CRIT_ERR("could not create sockfd");
220 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
221 if (ioctl(fd, SIOCGIFFLAGS, &ifr)) {
222 /* if device does not exist, treat like not up */
224 perror("SIOCGIFFLAGS");
228 if (!(ifr.ifr_flags & IFF_UP)) /* iface is not up */
230 if (ifup_strictness == IFUP_UP)
233 if (!(ifr.ifr_flags & IFF_RUNNING))
235 if (ifup_strictness == IFUP_LINK)
238 if (ioctl(fd, SIOCGIFADDR, &ifr)) {
239 perror("SIOCGIFADDR");
242 if (((struct sockaddr_in *)&(ifr.ifr_ifru.ifru_addr))->sin_addr.s_addr)
253 #define COND_FREE(x) if(x) free(x); x = 0
254 #define SAVE_SET_STRING(x, y) \
255 if (x && strcmp((char *)x, (char *)y)) { \
257 x = strndup("multiple", text_buffer_size); \
259 x = strndup(y, text_buffer_size); \
262 void update_gateway_info_failure(const char *reason)
267 //2 pointers to 1 location causes a crash when we try to free them both
268 info.gw_info.iface = strndup("failed", text_buffer_size);
269 info.gw_info.ip = strndup("failed", text_buffer_size);
272 void update_gateway_info(void)
277 unsigned long dest, gate, mask;
279 short ref, use, metric, mtu, win, irtt;
281 struct gateway_info *gw_info = &info.gw_info;
283 COND_FREE(gw_info->iface);
284 COND_FREE(gw_info->ip);
287 if ((fp = fopen("/proc/net/route", "r")) == NULL) {
288 update_gateway_info_failure("fopen()");
291 if (fscanf(fp, "%*[^\n]\n") == EOF) {
292 //NULL because a empty table is not a error
293 update_gateway_info_failure(NULL);
298 // Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
299 if(fscanf(fp, "%63s %lx %lx %x %hd %hd %hd %lx %hd %hd %hd\n",
300 iface, &dest, &gate, &flags, &ref, &use,
301 &metric, &mask, &mtu, &win, &irtt) != 11) {
302 update_gateway_info_failure("fscanf()");
306 if (flags & RTF_GATEWAY && dest == 0 && mask == 0) {
308 SAVE_SET_STRING(gw_info->iface, iface)
310 SAVE_SET_STRING(gw_info->ip, inet_ntoa(ina))
317 void update_net_stats(void)
322 // FIXME: arbitrary size chosen to keep code simple.
324 unsigned int curtmp1, curtmp2;
331 // wireless info variables
332 int skfd, has_bitrate = 0;
333 struct wireless_info *winfo;
338 delta = current_update_time - last_update_time;
339 if (delta <= 0.0001) {
343 /* open file and ignore first two lines */
344 if (!(net_dev_fp = open_file("/proc/net/dev", &rep))) {
349 fgets(buf, 255, net_dev_fp); /* garbage */
350 fgets(buf, 255, net_dev_fp); /* garbage (field names) */
352 /* read each interface */
353 for (i2 = 0; i2 < 16; i2++) {
357 long long r, t, last_recv, last_trans;
359 if (fgets(buf, 255, net_dev_fp) == NULL) {
363 while (isspace((int) *p)) {
369 while (*p && *p != ':') {
378 ns = get_net_stat(s);
380 memset(&(ns->addr.sa_data), 0, 14);
382 if(NULL == ns->addrs)
383 ns->addrs = (char*) malloc(17 * 16);
384 if(NULL != ns->addrs)
385 memset(ns->addrs, 0, 17 * 16); /* Up to 17 chars per ip, max 16 interfaces. Nasty memory usage... */
387 last_recv = ns->recv;
388 last_trans = ns->trans;
390 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
391 sscanf(p, "%lld %*d %*d %*d %*d %*d %*d %*d %lld",
394 /* if recv or trans is less than last time, an overflow happened */
395 if (r < ns->last_read_recv) {
398 ns->recv += (r - ns->last_read_recv);
400 ns->last_read_recv = r;
402 if (t < ns->last_read_trans) {
405 ns->trans += (t - ns->last_read_trans);
407 ns->last_read_trans = t;
409 /*** ip addr patch ***/
410 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
412 conf.ifc_buf = malloc(sizeof(struct ifreq) * 16);
413 conf.ifc_len = sizeof(struct ifreq) * 16;
414 memset(conf.ifc_buf, 0, conf.ifc_len);
416 ioctl((long) i, SIOCGIFCONF, &conf);
418 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
419 struct net_stat *ns2;
421 if (!(((struct ifreq *) conf.ifc_buf) + k))
425 ((struct ifreq *) conf.ifc_buf)[k].ifr_ifrn.ifrn_name);
426 ns2->addr = ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.ifru_addr;
427 if(NULL != ns2->addrs) {
428 sprintf(temp_addr, "%u.%u.%u.%u, ",
429 ns2->addr.sa_data[2] & 255,
430 ns2->addr.sa_data[3] & 255,
431 ns2->addr.sa_data[4] & 255,
432 ns2->addr.sa_data[5] & 255);
433 if(NULL == strstr(ns2->addrs, temp_addr))
434 strncpy(ns2->addrs + strlen(ns2->addrs), temp_addr, 17);
442 /*** end ip addr patch ***/
444 /* calculate speeds */
445 ns->net_rec[0] = (ns->recv - last_recv) / delta;
446 ns->net_trans[0] = (ns->trans - last_trans) / delta;
450 for (i = 0; (unsigned) i < info.net_avg_samples; i++) {
451 curtmp1 += ns->net_rec[i];
452 curtmp2 += ns->net_trans[i];
460 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
461 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
462 if (info.net_avg_samples > 1) {
463 for (i = info.net_avg_samples; i > 1; i--) {
464 ns->net_rec[i - 1] = ns->net_rec[i - 2];
465 ns->net_trans[i - 1] = ns->net_trans[i - 2];
470 /* update wireless info */
471 winfo = malloc(sizeof(struct wireless_info));
472 memset(winfo, 0, sizeof(struct wireless_info));
474 skfd = iw_sockets_open();
475 if (iw_get_basic_config(skfd, s, &(winfo->b)) > -1) {
477 // set present winfo variables
478 if (iw_get_stats(skfd, s, &(winfo->stats),
479 &winfo->range, winfo->has_range) >= 0) {
480 winfo->has_stats = 1;
482 if (iw_get_range_info(skfd, s, &(winfo->range)) >= 0) {
483 winfo->has_range = 1;
485 if (iw_get_ext(skfd, s, SIOCGIWAP, &wrq) >= 0) {
486 winfo->has_ap_addr = 1;
487 memcpy(&(winfo->ap_addr), &(wrq.u.ap_addr), sizeof(sockaddr));
491 if (iw_get_ext(skfd, s, SIOCGIWRATE, &wrq) >= 0) {
492 memcpy(&(winfo->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
493 iw_print_bitrate(ns->bitrate, 16, winfo->bitrate.value);
498 if (winfo->has_range && winfo->has_stats
499 && ((winfo->stats.qual.level != 0)
500 || (winfo->stats.qual.updated & IW_QUAL_DBM))) {
501 if (!(winfo->stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
502 ns->link_qual = winfo->stats.qual.qual;
503 ns->link_qual_max = winfo->range.max_qual.qual;
508 if (winfo->has_ap_addr) {
509 iw_sawap_ntop(&winfo->ap_addr, ns->ap);
513 if (winfo->b.has_essid) {
514 if (winfo->b.essid_on) {
515 snprintf(ns->essid, 32, "%s", winfo->b.essid);
517 snprintf(ns->essid, 32, "off/any");
521 snprintf(ns->mode, 16, "%s", iw_operation_mode[winfo->b.mode]);
523 iw_sockets_close(skfd);
530 info.mask |= (1 << INFO_NET);
535 void update_total_processes(void)
539 struct sysinfo s_info;
542 info.procs = s_info.procs;
549 if (!(fp = open_file("/proc/loadavg", &rep))) {
553 fscanf(fp, "%*f %*f %*f %*d/%hu", &info.procs);
556 info.mask |= (1 << INFO_PROCS);
559 #define CPU_SAMPLE_COUNT 15
561 unsigned long long cpu_user;
562 unsigned long long cpu_system;
563 unsigned long long cpu_nice;
564 unsigned long long cpu_idle;
565 unsigned long long cpu_iowait;
566 unsigned long long cpu_irq;
567 unsigned long long cpu_softirq;
568 unsigned long long cpu_steal;
569 unsigned long long cpu_total;
570 unsigned long long cpu_active_total;
571 unsigned long long cpu_last_total;
572 unsigned long long cpu_last_active_total;
573 double cpu_val[CPU_SAMPLE_COUNT];
575 static short cpu_setup = 0;
577 /* Determine if this kernel gives us "extended" statistics information in
579 * Kernels around 2.5 and earlier only reported user, system, nice, and
580 * idle values in proc stat.
581 * Kernels around 2.6 and greater report these PLUS iowait, irq, softirq,
583 void determine_longstat(char *buf)
585 unsigned long long iowait = 0;
587 KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
588 /* scanf will either return -1 or 1 because there is only 1 assignment */
589 if (sscanf(buf, "%*s %*d %*d %*d %*d %llu", &iowait) > 0) {
590 KFLAG_SETON(KFLAG_IS_LONGSTAT);
594 void get_cpu_count(void)
600 if (info.cpu_usage) {
604 if (!(stat_fp = open_file("/proc/stat", &rep))) {
610 while (!feof(stat_fp)) {
611 if (fgets(buf, 255, stat_fp) == NULL) {
615 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
616 if (info.cpu_count == 0) {
617 determine_longstat(buf);
622 info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
627 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
628 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
630 inline static void update_stat(void)
634 static struct cpu_info *cpu = NULL;
639 const char *stat_template = NULL;
640 unsigned int malloc_cpu_size = 0;
642 /* add check for !info.cpu_usage since that mem is freed on a SIGUSR1 */
643 if (!cpu_setup || !info.cpu_usage) {
648 if (!stat_template) {
650 KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT;
654 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
655 cpu = malloc(malloc_cpu_size);
656 memset(cpu, 0, malloc_cpu_size);
659 if (!(stat_fp = open_file("/proc/stat", &rep))) {
661 if (info.cpu_usage) {
662 memset(info.cpu_usage, 0, info.cpu_count * sizeof(float));
668 while (!feof(stat_fp)) {
669 if (fgets(buf, 255, stat_fp) == NULL) {
673 if (strncmp(buf, "procs_running ", 14) == 0) {
674 sscanf(buf, "%*s %hu", &info.run_procs);
675 info.mask |= (1 << INFO_RUN_PROCS);
676 } else if (strncmp(buf, "cpu", 3) == 0) {
678 idx = isdigit(buf[3]) ? ((int) buf[3]) - 0x2F : 0;
679 sscanf(buf, stat_template, &(cpu[idx].cpu_user),
680 &(cpu[idx].cpu_nice), &(cpu[idx].cpu_system),
681 &(cpu[idx].cpu_idle), &(cpu[idx].cpu_iowait),
682 &(cpu[idx].cpu_irq), &(cpu[idx].cpu_softirq),
683 &(cpu[idx].cpu_steal));
685 cpu[idx].cpu_total = cpu[idx].cpu_user + cpu[idx].cpu_nice +
686 cpu[idx].cpu_system + cpu[idx].cpu_idle +
687 cpu[idx].cpu_iowait + cpu[idx].cpu_irq +
688 cpu[idx].cpu_softirq + cpu[idx].cpu_steal;
690 cpu[idx].cpu_active_total = cpu[idx].cpu_total -
691 (cpu[idx].cpu_idle + cpu[idx].cpu_iowait);
692 info.mask |= (1 << INFO_CPU);
694 delta = current_update_time - last_update_time;
696 if (delta <= 0.001) {
700 cpu[idx].cpu_val[0] = (cpu[idx].cpu_active_total -
701 cpu[idx].cpu_last_active_total) /
702 (float) (cpu[idx].cpu_total - cpu[idx].cpu_last_total);
704 for (i = 0; i < info.cpu_avg_samples; i++) {
705 curtmp += cpu[idx].cpu_val[i];
707 /* TESTING -- I've removed this, because I don't think it is right.
708 * You shouldn't divide by the cpu count here ...
709 * removing for testing */
711 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples /
714 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples;
716 /* TESTING -- this line replaces the prev. "suspect" if/else */
717 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples;
719 cpu[idx].cpu_last_total = cpu[idx].cpu_total;
720 cpu[idx].cpu_last_active_total = cpu[idx].cpu_active_total;
721 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
722 cpu[idx].cpu_val[i] = cpu[idx].cpu_val[i - 1];
729 void update_running_processes(void)
734 void update_cpu_usage(void)
739 void update_load_average(void)
741 #ifdef HAVE_GETLOADAVG
746 info.loadavg[0] = (float) v[0];
747 info.loadavg[1] = (float) v[1];
748 info.loadavg[2] = (float) v[2];
755 if (!(fp = open_file("/proc/loadavg", &rep))) {
756 info.loadavg[0] = info.loadavg[1] = info.loadavg[2] = 0.0;
759 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1],
763 info.mask |= (1 << INFO_LOADAVG);
766 #define PROC_I8K "/proc/i8k"
767 #define I8K_DELIM " "
768 static char *i8k_procbuf = NULL;
769 void update_i8k(void)
774 i8k_procbuf = (char *) malloc(128 * sizeof(char));
776 if ((fp = fopen(PROC_I8K, "r")) == NULL) {
777 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel "
778 "driver is loaded...");
781 memset(&i8k_procbuf[0], 0, 128);
782 if (fread(&i8k_procbuf[0], sizeof(char), 128, fp) == 0) {
783 ERR("something wrong with /proc/i8k...");
788 i8k.version = strtok(&i8k_procbuf[0], I8K_DELIM);
789 i8k.bios = strtok(NULL, I8K_DELIM);
790 i8k.serial = strtok(NULL, I8K_DELIM);
791 i8k.cpu_temp = strtok(NULL, I8K_DELIM);
792 i8k.left_fan_status = strtok(NULL, I8K_DELIM);
793 i8k.right_fan_status = strtok(NULL, I8K_DELIM);
794 i8k.left_fan_rpm = strtok(NULL, I8K_DELIM);
795 i8k.right_fan_rpm = strtok(NULL, I8K_DELIM);
796 i8k.ac_status = strtok(NULL, I8K_DELIM);
797 i8k.buttons_status = strtok(NULL, I8K_DELIM);
800 /***********************************************************/
801 /***********************************************************/
802 /***********************************************************/
804 static int no_dots(const struct dirent *d)
806 if (d->d_name[0] == '.') {
812 static int get_first_file_in_a_directory(const char *dir, char *s, int *rep)
814 struct dirent **namelist;
817 n = scandir(dir, &namelist, no_dots, alphasort);
820 ERR("scandir for %s: %s", dir, strerror(errno));
831 strncpy(s, namelist[0]->d_name, 255);
834 for (i = 0; i < n; i++) {
843 int open_sysfs_sensor(const char *dir, const char *dev, const char *type, int n,
844 int *divisor, char *devtype)
851 memset(buf, 0, sizeof(buf));
853 /* if device is NULL or *, get first */
854 if (dev == NULL || strcmp(dev, "*") == 0) {
857 if (!get_first_file_in_a_directory(dir, buf, &rep)) {
863 if (strcmp(dir, "/sys/class/hwmon/") == 0) {
865 /* buf holds result from get_first_file_in_a_directory() above,
866 * e.g. "hwmon0" -- append "/device" */
867 strcat(buf, "/device");
869 /* dev holds device number N as a string,
870 * e.g. "0", -- convert to "hwmon0/device" */
871 sprintf(buf, "hwmon%s/device", dev);
876 /* change vol to in */
877 if (strcmp(type, "vol") == 0) {
881 if (strcmp(type, "tempf") == 0) {
882 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, "temp", n);
884 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, type, n);
886 strncpy(devtype, path, 255);
889 fd = open(path, O_RDONLY);
891 CRIT_ERR("can't open '%s': %s\nplease check your device or remove this "
892 "var from Conky", path, strerror(errno));
895 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
896 || strcmp(type, "tempf") == 0) {
901 /* fan does not use *_div as a read divisor */
902 if (strcmp("fan", type) == 0) {
906 /* test if *_div file exist, open it and use it as divisor */
907 if (strcmp(type, "tempf") == 0) {
908 snprintf(path, 255, "%s%s/%s%d_div", dir, "one", "two", n);
910 snprintf(path, 255, "%s%s/%s%d_div", dir, dev, type, n);
913 divfd = open(path, O_RDONLY);
919 divn = read(divfd, divbuf, 63);
920 /* should read until n == 0 but I doubt that kernel will give these
921 * in multiple pieces. :) */
923 ERR("open_sysfs_sensor(): can't read from sysfs");
926 *divisor = atoi(divbuf);
935 double get_sysfs_info(int *fd, int divisor, char *devtype, char *type)
943 lseek(*fd, 0, SEEK_SET);
949 n = read(*fd, buf, 63);
950 /* should read until n == 0 but I doubt that kernel will give these
951 * in multiple pieces. :) */
953 ERR("get_sysfs_info(): read from %s failed\n", devtype);
962 *fd = open(devtype, O_RDONLY);
964 ERR("can't open '%s': %s", devtype, strerror(errno));
967 /* My dirty hack for computing CPU value
968 * Filedil, from forums.gentoo.org */
969 /* if (strstr(devtype, "temp1_input") != NULL) {
970 return -15.096 + 1.4893 * (val / 1000.0);
973 /* divide voltage and temperature by 1000 */
974 /* or if any other divisor is given, use that */
975 if (strcmp(type, "tempf") == 0) {
977 return ((val / divisor + 40) * 9.0 / 5) - 40;
978 } else if (divisor) {
979 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
981 return ((val + 40) * 9.0 / 5) - 40;
985 return val / divisor;
986 } else if (divisor) {
994 /* Prior to kernel version 2.6.12, the CPU fan speed was available in
995 * ADT746X_FAN_OLD, whereas later kernel versions provide this information in
997 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
998 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
1000 void get_adt746x_fan(char *p_client_buffer, size_t client_buffer_size)
1003 char adt746x_fan_state[64];
1006 if (!p_client_buffer || client_buffer_size <= 0) {
1010 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
1011 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL) {
1012 sprintf(adt746x_fan_state, "adt746x not found");
1014 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
1015 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
1019 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_fan_state);
1022 /* Prior to kernel version 2.6.12, the CPU temperature was found in
1023 * ADT746X_CPU_OLD, whereas later kernel versions provide this information in
1025 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
1026 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
1028 void get_adt746x_cpu(char *p_client_buffer, size_t client_buffer_size)
1031 char adt746x_cpu_state[64];
1034 if (!p_client_buffer || client_buffer_size <= 0) {
1038 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
1039 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL) {
1040 sprintf(adt746x_cpu_state, "adt746x not found");
1042 fscanf(fp, "%2s", adt746x_cpu_state);
1046 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state);
1049 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
1051 /***********************************************************************/
1052 /* This file is part of x86info.
1053 * (C) 2001 Dave Jones.
1055 * Licensed under the terms of the GNU GPL License version 2.
1057 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
1058 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz> */
1060 #if defined(__i386) || defined(__x86_64)
1061 unsigned long long int rdtsc(void)
1063 unsigned long long int x;
1065 __asm__ volatile(".byte 0x0f, 0x31":"=A" (x));
1070 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1071 void get_freq_dynamic(char *p_client_buffer, size_t client_buffer_size,
1072 const char *p_format, int divisor)
1074 #if defined(__i386) || defined(__x86_64)
1076 struct timeval tvstart, tvstop;
1077 unsigned long long cycles[2]; /* gotta be 64 bit */
1078 unsigned int microseconds; /* total time taken */
1080 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1085 memset(&tz, 0, sizeof(tz));
1087 /* get this function in cached memory */
1088 gettimeofday(&tvstart, &tz);
1089 cycles[0] = rdtsc();
1090 gettimeofday(&tvstart, &tz);
1092 /* we don't trust that this is any specific length of time */
1094 cycles[1] = rdtsc();
1095 gettimeofday(&tvstop, &tz);
1096 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
1097 (tvstop.tv_usec - tvstart.tv_usec);
1099 snprintf(p_client_buffer, client_buffer_size, p_format,
1100 (float) ((cycles[1] - cycles[0]) / microseconds) / divisor);
1103 /* FIXME: hardwired: get freq for first cpu!
1104 * this whole function needs to be rethought and redone for
1105 * multi-cpu/multi-core/multi-threaded environments and
1106 * arbitrary combinations thereof */
1107 get_freq(p_client_buffer, client_buffer_size, p_format, divisor, 1);
1112 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
1113 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
1115 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1116 char get_freq(char *p_client_buffer, size_t client_buffer_size,
1117 const char *p_format, int divisor, unsigned int cpu)
1125 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1131 char current_freq_file[128];
1133 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu - 1,
1135 f = fopen(current_freq_file, "r");
1137 /* if there's a cpufreq /sys node, read the current frequency from
1138 * this node and divide by 1000 to get Mhz. */
1139 if (fgets(s, sizeof(s), f)) {
1140 s[strlen(s) - 1] = '\0';
1141 freq = strtod(s, NULL);
1144 snprintf(p_client_buffer, client_buffer_size, p_format,
1145 (freq / 1000) / divisor);
1150 // open the CPU information file
1151 f = open_file("/proc/cpuinfo", &rep);
1153 perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
1158 while (fgets(s, sizeof(s), f) != NULL) {
1160 #if defined(__i386) || defined(__x86_64)
1161 // and search for the cpu mhz
1162 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) {
1164 #if defined(__alpha)
1165 // different on alpha
1166 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) {
1168 // this is different on ppc for some reason
1169 if (strncmp(s, "clock", 5) == 0 && cpu == 0) {
1170 #endif // defined(__alpha)
1171 #endif // defined(__i386) || defined(__x86_64)
1173 // copy just the number
1174 strcpy(frequency, strchr(s, ':') + 2);
1175 #if defined(__alpha)
1177 frequency[strlen(frequency) - 6] = '\0';
1178 // kernel reports in Hz
1179 freq = strtod(frequency, NULL) / 1000000;
1182 frequency[strlen(frequency) - 1] = '\0';
1183 freq = strtod(frequency, NULL);
1187 if (strncmp(s, "processor", 9) == 0) {
1194 snprintf(p_client_buffer, client_buffer_size, p_format,
1195 (float) freq / divisor);
1199 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
1201 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks something
1211 * Peter Tarjan (ptarjan@citromail.hu) */
1213 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
1214 char get_voltage(char *p_client_buffer, size_t client_buffer_size,
1215 const char *p_format, int divisor, unsigned int cpu)
1221 char current_freq_file[128];
1224 /* build the voltage file name */
1226 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1229 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1234 /* read the current cpu frequency from the /sys node */
1235 f = fopen(current_freq_file, "r");
1237 if (fgets(s, sizeof(s), f)) {
1238 s[strlen(s) - 1] = '\0';
1239 freq = strtod(s, NULL);
1243 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1244 perror("get_voltage()");
1251 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1254 /* use the current cpu frequency to find the corresponding voltage */
1255 f = fopen(current_freq_file, "r");
1261 if (fgets(line, 255, f) == NULL) {
1264 sscanf(line, "%d %d", &freq_comp, &voltage);
1265 if (freq_comp == freq) {
1271 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1272 perror("get_voltage()");
1278 snprintf(p_client_buffer, client_buffer_size, p_format,
1279 (float) voltage / divisor);
1283 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1285 void get_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
1292 if (!p_client_buffer || client_buffer_size <= 0) {
1296 /* yeah, slow... :/ */
1297 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep)) {
1298 snprintf(p_client_buffer, client_buffer_size, "no fans?");
1302 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf);
1304 fp = open_file(buf2, &rep);
1306 snprintf(p_client_buffer, client_buffer_size,
1307 "can't open fan's state file");
1310 memset(buf, 0, sizeof(buf));
1311 fscanf(fp, "%*s %99s", buf);
1314 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1317 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1319 void get_acpi_ac_adapter(char *p_client_buffer, size_t client_buffer_size)
1326 if (!p_client_buffer || client_buffer_size <= 0) {
1330 /* yeah, slow... :/ */
1331 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep)) {
1332 snprintf(p_client_buffer, client_buffer_size, "no ac_adapters?");
1336 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf);
1338 fp = open_file(buf2, &rep);
1340 snprintf(p_client_buffer, client_buffer_size,
1341 "No ac adapter found.... where is it?");
1344 memset(buf, 0, sizeof(buf));
1345 fscanf(fp, "%*s %99s", buf);
1348 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1352 /proc/acpi/thermal_zone/THRM/cooling_mode
1353 cooling mode: active
1354 /proc/acpi/thermal_zone/THRM/polling_frequency
1356 /proc/acpi/thermal_zone/THRM/state
1358 /proc/acpi/thermal_zone/THRM/temperature
1360 /proc/acpi/thermal_zone/THRM/trip_points
1362 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1365 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1366 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1368 int open_acpi_temperature(const char *name)
1374 if (name == NULL || strcmp(name, "*") == 0) {
1377 if (!get_first_file_in_a_directory(ACPI_THERMAL_DIR, buf, &rep)) {
1383 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1385 fd = open(path, O_RDONLY);
1387 ERR("can't open '%s': %s", path, strerror(errno));
1393 static double last_acpi_temp;
1394 static double last_acpi_temp_time;
1396 double get_acpi_temperature(int fd)
1402 /* don't update acpi temperature too often */
1403 if (current_update_time - last_acpi_temp_time < 11.32) {
1404 return last_acpi_temp;
1406 last_acpi_temp_time = current_update_time;
1408 /* seek to beginning */
1409 lseek(fd, 0, SEEK_SET);
1416 n = read(fd, buf, 255);
1418 ERR("can't read fd %d: %s", fd, strerror(errno));
1421 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1425 return last_acpi_temp;
1429 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1431 design capacity: 4400 mAh
1432 last full capacity: 4064 mAh
1433 battery technology: rechargeable
1434 design voltage: 14800 mV
1435 design capacity warning: 300 mAh
1436 design capacity low: 200 mAh
1437 capacity granularity 1: 32 mAh
1438 capacity granularity 2: 32 mAh
1440 serial number: 16922
1446 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1449 charging state: unknown
1451 remaining capacity: 4064 mAh
1452 present voltage: 16608 mV
1456 2213<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1457 2213<@jupet�kellari��> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1458 2213<@jupet�kellari��> (-1 ollee ei akkua kiinni, koska akku on p�yd�ll�)
1459 2214<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1460 2214<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1462 2238<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1463 2239<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1465 2240<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori p��ll�
1466 2241<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori p��ll� mutta ilman verkkovirtaa
1469 /* Kapil Hari Paranjape <kapil@imsc.res.in>
1470 Linux 2.6.24 onwards battery info is in
1471 /sys/class/power_supply/BAT0/
1472 On my system I get the following.
1473 /sys/class/power_supply/BAT0/uevent:
1474 PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A03:00/device:01/PNP0C09:00/PNP0C0A:00
1476 PHYSDEVDRIVER=battery
1477 POWER_SUPPLY_NAME=BAT0
1478 POWER_SUPPLY_TYPE=Battery
1479 POWER_SUPPLY_STATUS=Discharging
1480 POWER_SUPPLY_PRESENT=1
1481 POWER_SUPPLY_TECHNOLOGY=Li-ion
1482 POWER_SUPPLY_VOLTAGE_MIN_DESIGN=10800000
1483 POWER_SUPPLY_VOLTAGE_NOW=10780000
1484 POWER_SUPPLY_CURRENT_NOW=13970000
1485 POWER_SUPPLY_ENERGY_FULL_DESIGN=47510000
1486 POWER_SUPPLY_ENERGY_FULL=27370000
1487 POWER_SUPPLY_ENERGY_NOW=11810000
1488 POWER_SUPPLY_MODEL_NAME=IBM-92P1060
1489 POWER_SUPPLY_MANUFACTURER=Panasonic
1490 On some systems POWER_SUPPLY_ENERGY_* is replaced by POWER_SUPPLY_CHARGE_*
1493 #define SYSFS_BATTERY_BASE_PATH "/sys/class/power_supply"
1494 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1495 #define APM_PATH "/proc/apm"
1496 #define MAX_BATTERY_COUNT 4
1498 static FILE *sysfs_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1499 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1500 static FILE *apm_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1502 static int batteries_initialized = 0;
1503 static char batteries[MAX_BATTERY_COUNT][32];
1505 static int acpi_last_full[MAX_BATTERY_COUNT];
1506 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1508 /* e.g. "charging 75%" */
1509 static char last_battery_str[MAX_BATTERY_COUNT][64];
1511 static char last_battery_time_str[MAX_BATTERY_COUNT][64];
1513 static double last_battery_time[MAX_BATTERY_COUNT];
1515 static int last_battery_perct[MAX_BATTERY_COUNT];
1516 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1518 void init_batteries(void)
1522 if (batteries_initialized) {
1525 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1526 batteries[idx][0] = '\0';
1528 batteries_initialized = 1;
1531 int get_battery_idx(const char *bat)
1535 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1536 if (!strlen(batteries[idx]) || !strcmp(batteries[idx], bat)) {
1541 /* if not found, enter a new entry */
1542 if (!strlen(batteries[idx])) {
1543 snprintf(batteries[idx], 31, "%s", bat);
1549 void set_return_value(char *buffer, unsigned int n, int item, int idx);
1551 void get_battery_stuff(char *buffer, unsigned int n, const char *bat, int item)
1553 static int idx, rep = 0, rep2 = 0;
1554 char acpi_path[128];
1555 char sysfs_path[128];
1557 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1558 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1562 idx = get_battery_idx(bat);
1564 /* don't update battery too often */
1565 if (current_update_time - last_battery_time[idx] < 29.5) {
1566 set_return_value(buffer, n, item, idx);
1570 last_battery_time[idx] = current_update_time;
1572 memset(last_battery_str[idx], 0, sizeof(last_battery_str[idx]));
1573 memset(last_battery_time_str[idx], 0, sizeof(last_battery_time_str[idx]));
1575 /* first try SYSFS if that fails try ACPI */
1577 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1578 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1582 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1583 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1586 if (sysfs_bat_fp[idx] != NULL) {
1588 int present_rate = -1;
1589 int remaining_capacity = -1;
1590 char charging_state[64];
1593 strcpy(charging_state, "unknown");
1595 while (!feof(sysfs_bat_fp[idx])) {
1597 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1600 /* let's just hope units are ok */
1601 if (strncmp (buf, "POWER_SUPPLY_PRESENT=1", 22) == 0)
1602 strcpy(present, "yes");
1603 else if (strncmp (buf, "POWER_SUPPLY_PRESENT=0", 22) == 0)
1604 strcpy(present, "no");
1605 else if (strncmp (buf, "POWER_SUPPLY_STATUS=", 20) == 0)
1606 sscanf(buf, "POWER_SUPPLY_STATUS=%63s", charging_state);
1607 /* present_rate is not the same as the
1608 current flowing now but it is the same value
1609 which was used in the past. so we continue
1611 else if (strncmp(buf, "POWER_SUPPLY_CURRENT_NOW=", 25) == 0)
1612 sscanf(buf, "POWER_SUPPLY_CURRENT_NOW=%d", &present_rate);
1613 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0)
1614 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1615 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=", 25) == 0)
1616 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_last_full[idx]);
1617 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0)
1618 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1619 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=", 25) == 0)
1620 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_last_full[idx]);
1623 fclose(sysfs_bat_fp[idx]);
1624 sysfs_bat_fp[idx] = NULL;
1626 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1627 if (remaining_capacity > acpi_last_full[idx])
1628 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1631 if (strcmp(present, "No") == 0) {
1632 strncpy(last_battery_str[idx], "not present", 64);
1635 else if (strcmp(charging_state, "Charging") == 0) {
1636 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1637 /* e.g. charging 75% */
1638 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %i%%",
1639 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1641 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1642 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1643 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1644 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %d%%",
1645 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1646 snprintf(last_battery_time_str[idx],
1647 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1649 strncpy(last_battery_str[idx], "charging", sizeof(last_battery_str[idx])-1);
1650 snprintf(last_battery_time_str[idx],
1651 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1655 else if (strncmp(charging_state, "Discharging", 64) == 0) {
1656 if (present_rate > 0) {
1657 /* e.g. discharging 35% */
1658 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "discharging %i%%",
1659 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1661 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1662 (long) (((float) remaining_capacity / present_rate) * 3600));
1663 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1664 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "full");
1665 snprintf(last_battery_time_str[idx],
1666 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1668 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1670 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1671 snprintf(last_battery_time_str[idx],
1672 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1676 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1677 else if (strncmp(charging_state, "Charged", 64) == 0) {
1678 /* Below happens with the second battery on my X40,
1679 * when the second one is empty and the first one
1681 if (remaining_capacity == 0)
1682 strcpy(last_battery_str[idx], "empty");
1684 strcpy(last_battery_str[idx], "charged");
1686 /* unknown, probably full / AC */
1688 if (acpi_last_full[idx] != 0
1689 && remaining_capacity != acpi_last_full[idx])
1690 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1691 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1693 strncpy(last_battery_str[idx], "AC", 64);
1695 } else if (acpi_bat_fp[idx] != NULL) {
1697 int present_rate = -1;
1698 int remaining_capacity = -1;
1699 char charging_state[64];
1702 /* read last full capacity if it's zero */
1703 if (acpi_last_full[idx] == 0) {
1704 static int rep3 = 0;
1708 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1709 fp = open_file(path, &rep3);
1714 if (fgets(b, 256, fp) == NULL) {
1717 if (sscanf(b, "last full capacity: %d",
1718 &acpi_last_full[idx]) != 0) {
1727 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1729 strcpy(charging_state, "unknown");
1731 while (!feof(acpi_bat_fp[idx])) {
1734 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1738 /* let's just hope units are ok */
1739 if (strncmp(buf, "present:", 8) == 0) {
1740 sscanf(buf, "present: %4s", present);
1741 } else if (strncmp(buf, "charging state:", 15) == 0) {
1742 sscanf(buf, "charging state: %63s", charging_state);
1743 } else if (strncmp(buf, "present rate:", 13) == 0) {
1744 sscanf(buf, "present rate: %d", &present_rate);
1745 } else if (strncmp(buf, "remaining capacity:", 19) == 0) {
1746 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1749 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1750 if (remaining_capacity > acpi_last_full[idx]) {
1751 /* normalize to 100% */
1752 acpi_last_full[idx] = remaining_capacity;
1756 if (strcmp(present, "no") == 0) {
1757 strncpy(last_battery_str[idx], "not present", 64);
1759 } else if (strcmp(charging_state, "charging") == 0) {
1760 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1761 /* e.g. charging 75% */
1762 snprintf(last_battery_str[idx],
1763 sizeof(last_battery_str[idx]) - 1, "charging %i%%",
1764 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1766 format_seconds(last_battery_time_str[idx],
1767 sizeof(last_battery_time_str[idx]) - 1,
1768 (long) (((acpi_last_full[idx] - remaining_capacity) *
1769 3600) / present_rate));
1770 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1771 snprintf(last_battery_str[idx],
1772 sizeof(last_battery_str[idx]) - 1, "charging %d%%",
1773 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1774 snprintf(last_battery_time_str[idx],
1775 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1777 strncpy(last_battery_str[idx], "charging",
1778 sizeof(last_battery_str[idx]) - 1);
1779 snprintf(last_battery_time_str[idx],
1780 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1783 } else if (strncmp(charging_state, "discharging", 64) == 0) {
1784 if (present_rate > 0) {
1785 /* e.g. discharging 35% */
1786 snprintf(last_battery_str[idx],
1787 sizeof(last_battery_str[idx]) - 1, "discharging %i%%",
1788 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1790 format_seconds(last_battery_time_str[idx],
1791 sizeof(last_battery_time_str[idx]) - 1,
1792 (long) ((remaining_capacity * 3600) / present_rate));
1793 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1794 snprintf(last_battery_str[idx],
1795 sizeof(last_battery_str[idx]) - 1, "full");
1796 snprintf(last_battery_time_str[idx],
1797 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1799 snprintf(last_battery_str[idx],
1800 sizeof(last_battery_str[idx]) - 1, "discharging %d%%",
1801 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1802 snprintf(last_battery_time_str[idx],
1803 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1806 } else if (strncmp(charging_state, "charged", 64) == 0) {
1807 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1808 /* Below happens with the second battery on my X40,
1809 * when the second one is empty and the first one being charged. */
1810 if (remaining_capacity == 0) {
1811 strcpy(last_battery_str[idx], "empty");
1813 strcpy(last_battery_str[idx], "charged");
1815 /* unknown, probably full / AC */
1817 if (acpi_last_full[idx] != 0
1818 && remaining_capacity != acpi_last_full[idx]) {
1819 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1820 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1822 strncpy(last_battery_str[idx], "AC", 64);
1827 if (apm_bat_fp[idx] == NULL) {
1828 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1831 if (apm_bat_fp[idx] != NULL) {
1832 unsigned int ac, status, flag;
1835 fscanf(apm_bat_fp[idx], "%*s %*s %*x %x %x %x %d%%",
1836 &ac, &status, &flag, &life);
1839 /* could check now that there is ac */
1840 snprintf(last_battery_str[idx], 64, "AC");
1842 /* could check that status == 3 here? */
1843 } else if (ac && life != 100) {
1844 snprintf(last_battery_str[idx], 64, "charging %d%%", life);
1846 snprintf(last_battery_str[idx], 64, "%d%%", life);
1849 /* it seemed to buffer it so file must be closed (or could use
1850 * syscalls directly but I don't feel like coding it now) */
1851 fclose(apm_bat_fp[idx]);
1852 apm_bat_fp[idx] = NULL;
1855 set_return_value(buffer, n, item, idx);
1858 void set_return_value(char *buffer, unsigned int n, int item, int idx)
1861 case BATTERY_STATUS:
1862 snprintf(buffer, n, "%s", last_battery_str[idx]);
1865 snprintf(buffer, n, "%s", last_battery_time_str[idx]);
1872 int get_battery_perct(const char *bat)
1876 char acpi_path[128];
1877 char sysfs_path[128];
1878 int remaining_capacity = -1;
1880 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1881 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1885 idx = get_battery_idx(bat);
1887 /* don't update battery too often */
1888 if (current_update_time - last_battery_perct_time[idx] < 30) {
1889 return last_battery_perct[idx];
1891 last_battery_perct_time[idx] = current_update_time;
1893 /* Only check for SYSFS or ACPI */
1895 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1896 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1900 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1901 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1904 if (sysfs_bat_fp[idx] != NULL) {
1906 while (!feof(sysfs_bat_fp[idx])) {
1908 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1911 if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0) {
1912 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1913 } else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=",25) == 0) {
1914 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_design_capacity[idx]);
1915 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0) {
1916 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1917 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=",25) == 0) {
1918 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_design_capacity[idx]);
1922 fclose(sysfs_bat_fp[idx]);
1923 sysfs_bat_fp[idx] = NULL;
1925 } else if (acpi_bat_fp[idx] != NULL) {
1927 /* read last full capacity if it's zero */
1928 if (acpi_design_capacity[idx] == 0) {
1933 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1934 fp = open_file(path, &rep2);
1939 if (fgets(b, 256, fp) == NULL) {
1942 if (sscanf(b, "last full capacity: %d",
1943 &acpi_design_capacity[idx]) != 0) {
1951 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1953 while (!feof(acpi_bat_fp[idx])) {
1956 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1960 if (buf[0] == 'r') {
1961 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1965 if (remaining_capacity < 0) {
1968 /* compute the battery percentage */
1969 last_battery_perct[idx] =
1970 (int) (((float) remaining_capacity / acpi_design_capacity[idx]) * 100);
1971 return last_battery_perct[idx];
1974 int get_battery_perct_bar(const char *bar)
1978 get_battery_perct(bar);
1979 idx = get_battery_idx(bar);
1980 return (int) (last_battery_perct[idx] * 2.56 - 1);
1983 /* On Apple powerbook and ibook:
1984 $ cat /proc/pmu/battery_0
1991 $ cat /proc/pmu/info
1992 PMU driver version : 2
1993 PMU firmware version : 0c
1998 /* defines as in <linux/pmu.h> */
1999 #define PMU_BATT_PRESENT 0x00000001
2000 #define PMU_BATT_CHARGING 0x00000002
2002 static FILE *pmu_battery_fp;
2003 static FILE *pmu_info_fp;
2004 static char pb_battery_info[3][32];
2005 static double pb_battery_info_update;
2007 #define PMU_PATH "/proc/pmu"
2008 void get_powerbook_batt_info(char *buffer, size_t n, int i)
2011 const char *batt_path = PMU_PATH "/battery_0";
2012 const char *info_path = PMU_PATH "/info";
2014 int charge, max_charge, ac = -1;
2017 /* don't update battery too often */
2018 if (current_update_time - pb_battery_info_update < 29.5) {
2019 snprintf(buffer, n, "%s", pb_battery_info[i]);
2022 pb_battery_info_update = current_update_time;
2024 if (pmu_battery_fp == NULL) {
2025 pmu_battery_fp = open_file(batt_path, &rep);
2028 if (pmu_battery_fp != NULL) {
2029 rewind(pmu_battery_fp);
2030 while (!feof(pmu_battery_fp)) {
2033 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL) {
2037 if (buf[0] == 'f') {
2038 sscanf(buf, "flags : %8x", &flags);
2039 } else if (buf[0] == 'c' && buf[1] == 'h') {
2040 sscanf(buf, "charge : %d", &charge);
2041 } else if (buf[0] == 'm') {
2042 sscanf(buf, "max_charge : %d", &max_charge);
2043 } else if (buf[0] == 't') {
2044 sscanf(buf, "time rem. : %ld", &timeval);
2048 if (pmu_info_fp == NULL) {
2049 pmu_info_fp = open_file(info_path, &rep);
2052 if (pmu_info_fp != NULL) {
2053 rewind(pmu_info_fp);
2054 while (!feof(pmu_info_fp)) {
2057 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL) {
2060 if (buf[0] == 'A') {
2061 sscanf(buf, "AC Power : %d", &ac);
2065 /* update status string */
2066 if ((ac && !(flags & PMU_BATT_PRESENT))) {
2067 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
2068 } else if (ac && (flags & PMU_BATT_PRESENT)
2069 && !(flags & PMU_BATT_CHARGING)) {
2070 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
2071 } else if ((flags & PMU_BATT_PRESENT) && (flags & PMU_BATT_CHARGING)) {
2072 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
2074 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
2077 /* update percentage string */
2079 pb_battery_info[PB_BATT_PERCENT][0] = 0;
2081 snprintf(pb_battery_info[PB_BATT_PERCENT],
2082 sizeof(pb_battery_info[PB_BATT_PERCENT]), "%d%%",
2083 (charge * 100) / max_charge);
2086 /* update time string */
2087 if (timeval == 0) { /* fully charged or battery not present */
2088 pb_battery_info[PB_BATT_TIME][0] = 0;
2089 } else if (timeval < 60 * 60) { /* don't show secs */
2090 format_seconds_short(pb_battery_info[PB_BATT_TIME],
2091 sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2093 format_seconds(pb_battery_info[PB_BATT_TIME],
2094 sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2097 snprintf(buffer, n, "%s", pb_battery_info[i]);
2100 void update_top(void)
2102 show_nice_processes = 1;
2103 process_find_top(info.cpu, info.memu);
2104 info.first_process = get_first_process();
2107 /* Here come the IBM ACPI-specific things. For reference, see
2108 * http://ibm-acpi.sourceforge.net/README
2109 * If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
2125 * The content of these files is described in detail in the aforementioned
2126 * README - some of them also in the following functions accessing them.
2127 * Peter Tarjan (ptarjan@citromail.hu) */
2129 #define IBM_ACPI_DIR "/proc/acpi/ibm"
2131 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
2132 * /proc/acpi/ibm/fan looks like this (3 lines):
2135 commands: enable, disable
2136 * Peter Tarjan (ptarjan@citromail.hu) */
2138 void get_ibm_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
2141 unsigned int speed = 0;
2144 if (!p_client_buffer || client_buffer_size <= 0) {
2148 snprintf(fan, 127, "%s/fan", IBM_ACPI_DIR);
2150 fp = fopen(fan, "r");
2155 if (fgets(line, 255, fp) == NULL) {
2158 if (sscanf(line, "speed: %u", &speed)) {
2163 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2164 "ibm* from your Conky config file.", fan, strerror(errno));
2168 snprintf(p_client_buffer, client_buffer_size, "%d", speed);
2171 /* get the measured temperatures from the temperature sensors
2172 * on IBM/Lenovo laptops running the ibm acpi.
2173 * There are 8 values in /proc/acpi/ibm/thermal, and according to
2174 * http://ibm-acpi.sourceforge.net/README
2175 * these mean the following (at least on an IBM R51...)
2176 * 0: CPU (also on the T series laptops)
2177 * 1: Mini PCI Module (?)
2179 * 3: GPU (also on the T series laptops)
2184 * I'm not too sure about those with the question mark, but the values I'm
2185 * reading from *my* thermal file (on a T42p) look realistic for the
2186 * hdd and the battery.
2187 * #5 and #7 are always -128.
2188 * /proc/acpi/ibm/thermal looks like this (1 line):
2189 temperatures: 41 43 31 46 33 -128 29 -128
2190 * Peter Tarjan (ptarjan@citromail.hu) */
2192 static double last_ibm_acpi_temp_time;
2193 void get_ibm_acpi_temps(void)
2199 /* don't update too often */
2200 if (current_update_time - last_ibm_acpi_temp_time < 10.00) {
2203 last_ibm_acpi_temp_time = current_update_time;
2205 /* if (!p_client_buffer || client_buffer_size <= 0) {
2209 snprintf(thermal, 127, "%s/thermal", IBM_ACPI_DIR);
2210 fp = fopen(thermal, "r");
2216 if (fgets(line, 255, fp) == NULL) {
2219 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
2220 &ibm_acpi.temps[0], &ibm_acpi.temps[1], &ibm_acpi.temps[2],
2221 &ibm_acpi.temps[3], &ibm_acpi.temps[4], &ibm_acpi.temps[5],
2222 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) {
2227 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2228 "ibm* from your Conky config file.", thermal, strerror(errno));
2234 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
2235 * "Volume" here is none of the mixer volumes, but a "master of masters"
2236 * volume adjusted by the IBM volume keys.
2237 * /proc/acpi/ibm/fan looks like this (4 lines):
2240 commands: up, down, mute
2241 commands: level <level> (<level> is 0-15)
2242 * Peter Tarjan (ptarjan@citromail.hu) */
2244 void get_ibm_acpi_volume(char *p_client_buffer, size_t client_buffer_size)
2248 unsigned int vol = -1;
2251 if (!p_client_buffer || client_buffer_size <= 0) {
2255 snprintf(volume, 127, "%s/volume", IBM_ACPI_DIR);
2257 fp = fopen(volume, "r");
2261 unsigned int read_vol = -1;
2263 if (fgets(line, 255, fp) == NULL) {
2266 if (sscanf(line, "level: %u", &read_vol)) {
2270 if (sscanf(line, "mute: %s", mute)) {
2275 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2276 "ibm* from your Conky config file.", volume, strerror(errno));
2281 if (strcmp(mute, "on") == 0) {
2282 snprintf(p_client_buffer, client_buffer_size, "%s", "mute");
2285 snprintf(p_client_buffer, client_buffer_size, "%d", vol);
2290 /* static FILE *fp = NULL; */
2292 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
2293 * /proc/acpi/ibm/brightness looks like this (3 lines):
2296 commands: level <level> (<level> is 0-7)
2297 * Peter Tarjan (ptarjan@citromail.hu) */
2299 void get_ibm_acpi_brightness(char *p_client_buffer, size_t client_buffer_size)
2302 unsigned int brightness = 0;
2305 if (!p_client_buffer || client_buffer_size <= 0) {
2309 snprintf(filename, 127, "%s/brightness", IBM_ACPI_DIR);
2311 fp = fopen(filename, "r");
2316 if (fgets(line, 255, fp) == NULL) {
2319 if (sscanf(line, "level: %u", &brightness)) {
2324 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2325 "ibm* from your Conky config file.", filename, strerror(errno));
2330 snprintf(p_client_buffer, client_buffer_size, "%d", brightness);
2333 void update_entropy(void)
2336 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
2337 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
2340 info.entropy.entropy_avail = 0;
2341 info.entropy.poolsize = 0;
2343 if ((fp1 = open_file(entropy_avail, &rep)) == NULL) {
2347 if ((fp2 = open_file(entropy_poolsize, &rep)) == NULL) {
2352 fscanf(fp1, "%u", &info.entropy.entropy_avail);
2353 fscanf(fp2, "%u", &info.entropy.poolsize);
2358 info.mask |= (1 << INFO_ENTROPY);
2361 const char *get_disk_protect_queue(const char *disk)
2367 snprintf(path, 127, "/sys/block/%s/queue/protect", disk);
2368 if ((fp = fopen(path, "r")) == NULL)
2370 if (fscanf(fp, "%d\n", &state) != 1) {
2375 return state ? "frozen" : "free ";