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 = 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.mem);
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.mem;
162 info.swap = info.swapmax - info.swap;
164 info.bufmem = info.cached + info.buffers;
166 info.mask |= (1 << INFO_MEM) | (1 << INFO_BUFFERS);
171 int get_laptop_mode(void)
176 if ((fp = fopen("/proc/sys/vm/laptop_mode", "r")) != NULL)
177 fscanf(fp, "%d\n", &val);
183 * # cat /sys/block/sda/queue/scheduler
184 * noop [anticipatory] cfq
186 char *get_ioscheduler(char *disk)
192 return strndup("n/a", text_buffer_size);
194 snprintf(buf, 127, "/sys/block/%s/queue/scheduler", disk);
195 if ((fp = fopen(buf, "r")) == NULL) {
196 return strndup("n/a", text_buffer_size);
199 fscanf(fp, "%127s", buf);
201 buf[strlen(buf) - 1] = '\0';
203 return strndup(buf + 1, text_buffer_size);
207 return strndup("n/a", text_buffer_size);
210 int interface_up(const char *dev)
215 if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
216 CRIT_ERR("could not create sockfd");
219 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
220 if (ioctl(fd, SIOCGIFFLAGS, &ifr)) {
221 /* if device does not exist, treat like not up */
223 perror("SIOCGIFFLAGS");
227 if (!(ifr.ifr_flags & IFF_UP)) /* iface is not up */
229 if (ifup_strictness == IFUP_UP)
232 if (!(ifr.ifr_flags & IFF_RUNNING))
234 if (ifup_strictness == IFUP_LINK)
237 if (ioctl(fd, SIOCGIFADDR, &ifr)) {
238 perror("SIOCGIFADDR");
241 if (((struct sockaddr_in *)&(ifr.ifr_ifru.ifru_addr))->sin_addr.s_addr)
252 #define COND_FREE(x) if(x) free(x); x = 0
253 #define SAVE_SET_STRING(x, y) \
254 if (x && strcmp((char *)x, (char *)y)) { \
256 x = strndup("multiple", text_buffer_size); \
258 x = strndup(y, text_buffer_size); \
261 void update_gateway_info_failure(const char *reason)
266 //2 pointers to 1 location causes a crash when we try to free them both
267 info.gw_info.iface = strndup("failed", text_buffer_size);
268 info.gw_info.ip = strndup("failed", text_buffer_size);
271 void update_gateway_info(void)
276 unsigned long dest, gate, mask;
278 short ref, use, metric, mtu, win, irtt;
280 struct gateway_info *gw_info = &info.gw_info;
282 COND_FREE(gw_info->iface);
283 COND_FREE(gw_info->ip);
286 if ((fp = fopen("/proc/net/route", "r")) == NULL) {
287 update_gateway_info_failure("fopen()");
290 if (fscanf(fp, "%*[^\n]\n") == EOF) {
291 //NULL because a empty table is not a error
292 update_gateway_info_failure(NULL);
297 // Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
298 if(fscanf(fp, "%63s %lx %lx %x %hd %hd %hd %lx %hd %hd %hd\n",
299 iface, &dest, &gate, &flags, &ref, &use,
300 &metric, &mask, &mtu, &win, &irtt) != 11) {
301 update_gateway_info_failure("fscanf()");
305 if (flags & RTF_GATEWAY && dest == 0 && mask == 0) {
307 SAVE_SET_STRING(gw_info->iface, iface)
309 SAVE_SET_STRING(gw_info->ip, inet_ntoa(ina))
316 inline void update_net_stats(void)
321 // FIXME: arbitrary size chosen to keep code simple.
323 unsigned int curtmp1, curtmp2;
330 // wireless info variables
331 int skfd, has_bitrate = 0;
332 struct wireless_info *winfo;
337 delta = current_update_time - last_update_time;
338 if (delta <= 0.0001) {
342 /* open file and ignore first two lines */
343 if (!(net_dev_fp = open_file("/proc/net/dev", &rep))) {
348 fgets(buf, 255, net_dev_fp); /* garbage */
349 fgets(buf, 255, net_dev_fp); /* garbage (field names) */
351 /* read each interface */
352 for (i2 = 0; i2 < 16; i2++) {
356 long long r, t, last_recv, last_trans;
358 if (fgets(buf, 255, net_dev_fp) == NULL) {
362 while (isspace((int) *p)) {
368 while (*p && *p != ':') {
377 ns = get_net_stat(s);
379 memset(&(ns->addr.sa_data), 0, 14);
381 if(NULL == ns->addrs)
382 ns->addrs = (char*) malloc(17 * 16);
383 if(NULL != ns->addrs)
384 memset(ns->addrs, 0, 17 * 16); /* Up to 17 chars per ip, max 16 interfaces. Nasty memory usage... */
386 last_recv = ns->recv;
387 last_trans = ns->trans;
389 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
390 sscanf(p, "%lld %*d %*d %*d %*d %*d %*d %*d %lld",
393 /* if recv or trans is less than last time, an overflow happened */
394 if (r < ns->last_read_recv) {
397 ns->recv += (r - ns->last_read_recv);
399 ns->last_read_recv = r;
401 if (t < ns->last_read_trans) {
404 ns->trans += (t - ns->last_read_trans);
406 ns->last_read_trans = t;
408 /*** ip addr patch ***/
409 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
411 conf.ifc_buf = malloc(sizeof(struct ifreq) * 16);
412 conf.ifc_len = sizeof(struct ifreq) * 16;
413 memset(conf.ifc_buf, 0, conf.ifc_len);
415 ioctl((long) i, SIOCGIFCONF, &conf);
417 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
418 struct net_stat *ns2;
420 if (!(((struct ifreq *) conf.ifc_buf) + k))
424 ((struct ifreq *) conf.ifc_buf)[k].ifr_ifrn.ifrn_name);
425 ns2->addr = ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.ifru_addr;
426 if(NULL != ns2->addrs) {
427 sprintf(temp_addr, "%u.%u.%u.%u, ",
428 ns2->addr.sa_data[2] & 255,
429 ns2->addr.sa_data[3] & 255,
430 ns2->addr.sa_data[4] & 255,
431 ns2->addr.sa_data[5] & 255);
432 if(NULL == strstr(ns2->addrs, temp_addr))
433 strncpy(ns2->addrs + strlen(ns2->addrs), temp_addr, 17);
441 /*** end ip addr patch ***/
443 /* calculate speeds */
444 ns->net_rec[0] = (ns->recv - last_recv) / delta;
445 ns->net_trans[0] = (ns->trans - last_trans) / delta;
449 for (i = 0; (unsigned) i < info.net_avg_samples; i++) {
450 curtmp1 += ns->net_rec[i];
451 curtmp2 += ns->net_trans[i];
459 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
460 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
461 if (info.net_avg_samples > 1) {
462 for (i = info.net_avg_samples; i > 1; i--) {
463 ns->net_rec[i - 1] = ns->net_rec[i - 2];
464 ns->net_trans[i - 1] = ns->net_trans[i - 2];
469 /* update wireless info */
470 winfo = malloc(sizeof(struct wireless_info));
471 memset(winfo, 0, sizeof(struct wireless_info));
473 skfd = iw_sockets_open();
474 if (iw_get_basic_config(skfd, s, &(winfo->b)) > -1) {
476 // set present winfo variables
477 if (iw_get_stats(skfd, s, &(winfo->stats),
478 &winfo->range, winfo->has_range) >= 0) {
479 winfo->has_stats = 1;
481 if (iw_get_range_info(skfd, s, &(winfo->range)) >= 0) {
482 winfo->has_range = 1;
484 if (iw_get_ext(skfd, s, SIOCGIWAP, &wrq) >= 0) {
485 winfo->has_ap_addr = 1;
486 memcpy(&(winfo->ap_addr), &(wrq.u.ap_addr), sizeof(sockaddr));
490 if (iw_get_ext(skfd, s, SIOCGIWRATE, &wrq) >= 0) {
491 memcpy(&(winfo->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
492 iw_print_bitrate(ns->bitrate, 16, winfo->bitrate.value);
497 if (winfo->has_range && winfo->has_stats
498 && ((winfo->stats.qual.level != 0)
499 || (winfo->stats.qual.updated & IW_QUAL_DBM))) {
500 if (!(winfo->stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
501 ns->link_qual = winfo->stats.qual.qual;
502 ns->link_qual_max = winfo->range.max_qual.qual;
507 if (winfo->has_ap_addr) {
508 iw_sawap_ntop(&winfo->ap_addr, ns->ap);
512 if (winfo->b.has_essid) {
513 if (winfo->b.essid_on) {
514 snprintf(ns->essid, 32, "%s", winfo->b.essid);
516 snprintf(ns->essid, 32, "off/any");
520 snprintf(ns->mode, 16, "%s", iw_operation_mode[winfo->b.mode]);
522 iw_sockets_close(skfd);
529 info.mask |= (1 << INFO_NET);
534 void update_total_processes(void)
538 struct sysinfo s_info;
541 info.procs = s_info.procs;
548 if (!(fp = open_file("/proc/loadavg", &rep))) {
552 fscanf(fp, "%*f %*f %*f %*d/%hu", &info.procs);
555 info.mask |= (1 << INFO_PROCS);
558 #define CPU_SAMPLE_COUNT 15
560 unsigned long long cpu_user;
561 unsigned long long cpu_system;
562 unsigned long long cpu_nice;
563 unsigned long long cpu_idle;
564 unsigned long long cpu_iowait;
565 unsigned long long cpu_irq;
566 unsigned long long cpu_softirq;
567 unsigned long long cpu_steal;
568 unsigned long long cpu_total;
569 unsigned long long cpu_active_total;
570 unsigned long long cpu_last_total;
571 unsigned long long cpu_last_active_total;
572 double cpu_val[CPU_SAMPLE_COUNT];
574 static short cpu_setup = 0;
576 /* Determine if this kernel gives us "extended" statistics information in
578 * Kernels around 2.5 and earlier only reported user, system, nice, and
579 * idle values in proc stat.
580 * Kernels around 2.6 and greater report these PLUS iowait, irq, softirq,
582 void determine_longstat(char *buf)
584 unsigned long long iowait = 0;
586 KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
587 /* scanf will either return -1 or 1 because there is only 1 assignment */
588 if (sscanf(buf, "%*s %*d %*d %*d %*d %llu", &iowait) > 0) {
589 KFLAG_SETON(KFLAG_IS_LONGSTAT);
593 void get_cpu_count(void)
599 if (info.cpu_usage) {
603 if (!(stat_fp = open_file("/proc/stat", &rep))) {
609 while (!feof(stat_fp)) {
610 if (fgets(buf, 255, stat_fp) == NULL) {
614 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
615 if (info.cpu_count == 0) {
616 determine_longstat(buf);
621 info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
626 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
627 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
629 inline static void update_stat(void)
633 static struct cpu_info *cpu = NULL;
638 const char *stat_template = NULL;
639 unsigned int malloc_cpu_size = 0;
641 /* add check for !info.cpu_usage since that mem is freed on a SIGUSR1 */
642 if (!cpu_setup || !info.cpu_usage) {
647 if (!stat_template) {
649 KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT;
653 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
654 cpu = malloc(malloc_cpu_size);
655 memset(cpu, 0, malloc_cpu_size);
658 if (!(stat_fp = open_file("/proc/stat", &rep))) {
660 if (info.cpu_usage) {
661 memset(info.cpu_usage, 0, info.cpu_count * sizeof(float));
667 while (!feof(stat_fp)) {
668 if (fgets(buf, 255, stat_fp) == NULL) {
672 if (strncmp(buf, "procs_running ", 14) == 0) {
673 sscanf(buf, "%*s %hu", &info.run_procs);
674 info.mask |= (1 << INFO_RUN_PROCS);
675 } else if (strncmp(buf, "cpu", 3) == 0) {
677 idx = isdigit(buf[3]) ? ((int) buf[3]) - 0x2F : 0;
678 sscanf(buf, stat_template, &(cpu[idx].cpu_user),
679 &(cpu[idx].cpu_nice), &(cpu[idx].cpu_system),
680 &(cpu[idx].cpu_idle), &(cpu[idx].cpu_iowait),
681 &(cpu[idx].cpu_irq), &(cpu[idx].cpu_softirq),
682 &(cpu[idx].cpu_steal));
684 cpu[idx].cpu_total = cpu[idx].cpu_user + cpu[idx].cpu_nice +
685 cpu[idx].cpu_system + cpu[idx].cpu_idle +
686 cpu[idx].cpu_iowait + cpu[idx].cpu_irq +
687 cpu[idx].cpu_softirq + cpu[idx].cpu_steal;
689 cpu[idx].cpu_active_total = cpu[idx].cpu_total -
690 (cpu[idx].cpu_idle + cpu[idx].cpu_iowait);
691 info.mask |= (1 << INFO_CPU);
693 delta = current_update_time - last_update_time;
695 if (delta <= 0.001) {
699 cpu[idx].cpu_val[0] = (cpu[idx].cpu_active_total -
700 cpu[idx].cpu_last_active_total) /
701 (float) (cpu[idx].cpu_total - cpu[idx].cpu_last_total);
703 for (i = 0; i < info.cpu_avg_samples; i++) {
704 curtmp += cpu[idx].cpu_val[i];
706 /* TESTING -- I've removed this, because I don't think it is right.
707 * You shouldn't divide by the cpu count here ...
708 * removing for testing */
710 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples /
713 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples;
715 /* TESTING -- this line replaces the prev. "suspect" if/else */
716 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples;
718 cpu[idx].cpu_last_total = cpu[idx].cpu_total;
719 cpu[idx].cpu_last_active_total = cpu[idx].cpu_active_total;
720 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
721 cpu[idx].cpu_val[i] = cpu[idx].cpu_val[i - 1];
728 void update_running_processes(void)
733 void update_cpu_usage(void)
738 void update_load_average(void)
740 #ifdef HAVE_GETLOADAVG
745 info.loadavg[0] = (float) v[0];
746 info.loadavg[1] = (float) v[1];
747 info.loadavg[2] = (float) v[2];
754 if (!(fp = open_file("/proc/loadavg", &rep))) {
755 info.loadavg[0] = info.loadavg[1] = info.loadavg[2] = 0.0;
758 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1],
762 info.mask |= (1 << INFO_LOADAVG);
765 #define PROC_I8K "/proc/i8k"
766 #define I8K_DELIM " "
767 static char *i8k_procbuf = NULL;
768 void update_i8k(void)
773 i8k_procbuf = (char *) malloc(128 * sizeof(char));
775 if ((fp = fopen(PROC_I8K, "r")) == NULL) {
776 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel "
777 "driver is loaded...");
780 memset(&i8k_procbuf[0], 0, 128);
781 if (fread(&i8k_procbuf[0], sizeof(char), 128, fp) == 0) {
782 ERR("something wrong with /proc/i8k...");
787 i8k.version = strtok(&i8k_procbuf[0], I8K_DELIM);
788 i8k.bios = strtok(NULL, I8K_DELIM);
789 i8k.serial = strtok(NULL, I8K_DELIM);
790 i8k.cpu_temp = strtok(NULL, I8K_DELIM);
791 i8k.left_fan_status = strtok(NULL, I8K_DELIM);
792 i8k.right_fan_status = strtok(NULL, I8K_DELIM);
793 i8k.left_fan_rpm = strtok(NULL, I8K_DELIM);
794 i8k.right_fan_rpm = strtok(NULL, I8K_DELIM);
795 i8k.ac_status = strtok(NULL, I8K_DELIM);
796 i8k.buttons_status = strtok(NULL, I8K_DELIM);
799 /***********************************************************/
800 /***********************************************************/
801 /***********************************************************/
803 static int no_dots(const struct dirent *d)
805 if (d->d_name[0] == '.') {
811 static int get_first_file_in_a_directory(const char *dir, char *s, int *rep)
813 struct dirent **namelist;
816 n = scandir(dir, &namelist, no_dots, alphasort);
819 ERR("scandir for %s: %s", dir, strerror(errno));
830 strncpy(s, namelist[0]->d_name, 255);
833 for (i = 0; i < n; i++) {
842 int open_sysfs_sensor(const char *dir, const char *dev, const char *type, int n,
843 int *divisor, char *devtype)
850 memset(buf, 0, sizeof(buf));
852 /* if device is NULL or *, get first */
853 if (dev == NULL || strcmp(dev, "*") == 0) {
856 if (!get_first_file_in_a_directory(dir, buf, &rep)) {
862 if (strcmp(dir, "/sys/class/hwmon/") == 0) {
864 /* buf holds result from get_first_file_in_a_directory() above,
865 * e.g. "hwmon0" -- append "/device" */
866 strcat(buf, "/device");
868 /* dev holds device number N as a string,
869 * e.g. "0", -- convert to "hwmon0/device" */
870 sprintf(buf, "hwmon%s/device", dev);
875 /* change vol to in */
876 if (strcmp(type, "vol") == 0) {
880 if (strcmp(type, "tempf") == 0) {
881 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, "temp", n);
883 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, type, n);
885 strncpy(devtype, path, 255);
888 fd = open(path, O_RDONLY);
890 CRIT_ERR("can't open '%s': %s\nplease check your device or remove this "
891 "var from Conky", path, strerror(errno));
894 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
895 || strcmp(type, "tempf") == 0) {
900 /* fan does not use *_div as a read divisor */
901 if (strcmp("fan", type) == 0) {
905 /* test if *_div file exist, open it and use it as divisor */
906 if (strcmp(type, "tempf") == 0) {
907 snprintf(path, 255, "%s%s/%s%d_div", dir, "one", "two", n);
909 snprintf(path, 255, "%s%s/%s%d_div", dir, dev, type, n);
912 divfd = open(path, O_RDONLY);
918 divn = read(divfd, divbuf, 63);
919 /* should read until n == 0 but I doubt that kernel will give these
920 * in multiple pieces. :) */
922 ERR("open_sysfs_sensor(): can't read from sysfs");
925 *divisor = atoi(divbuf);
934 double get_sysfs_info(int *fd, int divisor, char *devtype, char *type)
942 lseek(*fd, 0, SEEK_SET);
948 n = read(*fd, buf, 63);
949 /* should read until n == 0 but I doubt that kernel will give these
950 * in multiple pieces. :) */
952 ERR("get_sysfs_info(): read from %s failed\n", devtype);
961 *fd = open(devtype, O_RDONLY);
963 ERR("can't open '%s': %s", devtype, strerror(errno));
966 /* My dirty hack for computing CPU value
967 * Filedil, from forums.gentoo.org */
968 /* if (strstr(devtype, "temp1_input") != NULL) {
969 return -15.096 + 1.4893 * (val / 1000.0);
972 /* divide voltage and temperature by 1000 */
973 /* or if any other divisor is given, use that */
974 if (strcmp(type, "tempf") == 0) {
976 return ((val / divisor + 40) * 9.0 / 5) - 40;
977 } else if (divisor) {
978 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
980 return ((val + 40) * 9.0 / 5) - 40;
984 return val / divisor;
985 } else if (divisor) {
993 /* Prior to kernel version 2.6.12, the CPU fan speed was available in
994 * ADT746X_FAN_OLD, whereas later kernel versions provide this information in
996 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
997 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
999 void get_adt746x_fan(char *p_client_buffer, size_t client_buffer_size)
1002 char adt746x_fan_state[64];
1005 if (!p_client_buffer || client_buffer_size <= 0) {
1009 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
1010 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL) {
1011 sprintf(adt746x_fan_state, "adt746x not found");
1013 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
1014 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
1018 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_fan_state);
1021 /* Prior to kernel version 2.6.12, the CPU temperature was found in
1022 * ADT746X_CPU_OLD, whereas later kernel versions provide this information in
1024 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
1025 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
1027 void get_adt746x_cpu(char *p_client_buffer, size_t client_buffer_size)
1030 char adt746x_cpu_state[64];
1033 if (!p_client_buffer || client_buffer_size <= 0) {
1037 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
1038 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL) {
1039 sprintf(adt746x_cpu_state, "adt746x not found");
1041 fscanf(fp, "%2s", adt746x_cpu_state);
1045 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state);
1048 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
1050 /***********************************************************************/
1051 /* This file is part of x86info.
1052 * (C) 2001 Dave Jones.
1054 * Licensed under the terms of the GNU GPL License version 2.
1056 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
1057 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz> */
1059 #if defined(__i386) || defined(__x86_64)
1060 __inline__ unsigned long long int rdtsc(void)
1062 unsigned long long int x;
1064 __asm__ volatile(".byte 0x0f, 0x31":"=A" (x));
1069 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1070 void get_freq_dynamic(char *p_client_buffer, size_t client_buffer_size,
1071 const char *p_format, int divisor)
1073 #if defined(__i386) || defined(__x86_64)
1075 struct timeval tvstart, tvstop;
1076 unsigned long long cycles[2]; /* gotta be 64 bit */
1077 unsigned int microseconds; /* total time taken */
1079 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1084 memset(&tz, 0, sizeof(tz));
1086 /* get this function in cached memory */
1087 gettimeofday(&tvstart, &tz);
1088 cycles[0] = rdtsc();
1089 gettimeofday(&tvstart, &tz);
1091 /* we don't trust that this is any specific length of time */
1093 cycles[1] = rdtsc();
1094 gettimeofday(&tvstop, &tz);
1095 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
1096 (tvstop.tv_usec - tvstart.tv_usec);
1098 snprintf(p_client_buffer, client_buffer_size, p_format,
1099 (float) ((cycles[1] - cycles[0]) / microseconds) / divisor);
1102 /* FIXME: hardwired: get freq for first cpu!
1103 * this whole function needs to be rethought and redone for
1104 * multi-cpu/multi-core/multi-threaded environments and
1105 * arbitrary combinations thereof */
1106 get_freq(p_client_buffer, client_buffer_size, p_format, divisor, 1);
1111 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
1112 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
1114 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1115 char get_freq(char *p_client_buffer, size_t client_buffer_size,
1116 const char *p_format, int divisor, unsigned int cpu)
1124 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1130 char current_freq_file[128];
1132 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu - 1,
1134 f = fopen(current_freq_file, "r");
1136 /* if there's a cpufreq /sys node, read the current frequency from
1137 * this node and divide by 1000 to get Mhz. */
1138 if (fgets(s, sizeof(s), f)) {
1139 s[strlen(s) - 1] = '\0';
1140 freq = strtod(s, NULL);
1143 snprintf(p_client_buffer, client_buffer_size, p_format,
1144 (freq / 1000) / divisor);
1149 // open the CPU information file
1150 f = open_file("/proc/cpuinfo", &rep);
1152 perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
1157 while (fgets(s, sizeof(s), f) != NULL) {
1159 #if defined(__i386) || defined(__x86_64)
1160 // and search for the cpu mhz
1161 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) {
1163 #if defined(__alpha)
1164 // different on alpha
1165 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) {
1167 // this is different on ppc for some reason
1168 if (strncmp(s, "clock", 5) == 0 && cpu == 0) {
1169 #endif // defined(__alpha)
1170 #endif // defined(__i386) || defined(__x86_64)
1172 // copy just the number
1173 strcpy(frequency, strchr(s, ':') + 2);
1174 #if defined(__alpha)
1176 frequency[strlen(frequency) - 6] = '\0';
1177 // kernel reports in Hz
1178 freq = strtod(frequency, NULL) / 1000000;
1181 frequency[strlen(frequency) - 1] = '\0';
1182 freq = strtod(frequency, NULL);
1186 if (strncmp(s, "processor", 9) == 0) {
1193 snprintf(p_client_buffer, client_buffer_size, p_format,
1194 (float) freq / divisor);
1198 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
1200 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks something
1210 * Peter Tarjan (ptarjan@citromail.hu) */
1212 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
1213 char get_voltage(char *p_client_buffer, size_t client_buffer_size,
1214 const char *p_format, int divisor, unsigned int cpu)
1220 char current_freq_file[128];
1223 /* build the voltage file name */
1225 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1228 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1233 /* read the current cpu frequency from the /sys node */
1234 f = fopen(current_freq_file, "r");
1236 if (fgets(s, sizeof(s), f)) {
1237 s[strlen(s) - 1] = '\0';
1238 freq = strtod(s, NULL);
1242 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1243 perror("get_voltage()");
1250 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1253 /* use the current cpu frequency to find the corresponding voltage */
1254 f = fopen(current_freq_file, "r");
1260 if (fgets(line, 255, f) == NULL) {
1263 sscanf(line, "%d %d", &freq_comp, &voltage);
1264 if (freq_comp == freq) {
1270 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1271 perror("get_voltage()");
1277 snprintf(p_client_buffer, client_buffer_size, p_format,
1278 (float) voltage / divisor);
1282 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1284 void get_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
1291 if (!p_client_buffer || client_buffer_size <= 0) {
1295 /* yeah, slow... :/ */
1296 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep)) {
1297 snprintf(p_client_buffer, client_buffer_size, "no fans?");
1301 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf);
1303 fp = open_file(buf2, &rep);
1305 snprintf(p_client_buffer, client_buffer_size,
1306 "can't open fan's state file");
1309 memset(buf, 0, sizeof(buf));
1310 fscanf(fp, "%*s %99s", buf);
1313 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1316 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1318 void get_acpi_ac_adapter(char *p_client_buffer, size_t client_buffer_size)
1325 if (!p_client_buffer || client_buffer_size <= 0) {
1329 /* yeah, slow... :/ */
1330 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep)) {
1331 snprintf(p_client_buffer, client_buffer_size, "no ac_adapters?");
1335 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf);
1337 fp = open_file(buf2, &rep);
1339 snprintf(p_client_buffer, client_buffer_size,
1340 "No ac adapter found.... where is it?");
1343 memset(buf, 0, sizeof(buf));
1344 fscanf(fp, "%*s %99s", buf);
1347 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1351 /proc/acpi/thermal_zone/THRM/cooling_mode
1352 cooling mode: active
1353 /proc/acpi/thermal_zone/THRM/polling_frequency
1355 /proc/acpi/thermal_zone/THRM/state
1357 /proc/acpi/thermal_zone/THRM/temperature
1359 /proc/acpi/thermal_zone/THRM/trip_points
1361 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1364 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1365 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1367 int open_acpi_temperature(const char *name)
1373 if (name == NULL || strcmp(name, "*") == 0) {
1376 if (!get_first_file_in_a_directory(ACPI_THERMAL_DIR, buf, &rep)) {
1382 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1384 fd = open(path, O_RDONLY);
1386 ERR("can't open '%s': %s", path, strerror(errno));
1392 static double last_acpi_temp;
1393 static double last_acpi_temp_time;
1395 double get_acpi_temperature(int fd)
1401 /* don't update acpi temperature too often */
1402 if (current_update_time - last_acpi_temp_time < 11.32) {
1403 return last_acpi_temp;
1405 last_acpi_temp_time = current_update_time;
1407 /* seek to beginning */
1408 lseek(fd, 0, SEEK_SET);
1415 n = read(fd, buf, 255);
1417 ERR("can't read fd %d: %s", fd, strerror(errno));
1420 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1424 return last_acpi_temp;
1428 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1430 design capacity: 4400 mAh
1431 last full capacity: 4064 mAh
1432 battery technology: rechargeable
1433 design voltage: 14800 mV
1434 design capacity warning: 300 mAh
1435 design capacity low: 200 mAh
1436 capacity granularity 1: 32 mAh
1437 capacity granularity 2: 32 mAh
1439 serial number: 16922
1445 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1448 charging state: unknown
1450 remaining capacity: 4064 mAh
1451 present voltage: 16608 mV
1455 2213<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1456 2213<@jupet�kellari��> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1457 2213<@jupet�kellari��> (-1 ollee ei akkua kiinni, koska akku on p�yd�ll�)
1458 2214<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1459 2214<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1461 2238<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1462 2239<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1464 2240<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori p��ll�
1465 2241<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori p��ll� mutta ilman verkkovirtaa
1468 /* Kapil Hari Paranjape <kapil@imsc.res.in>
1469 Linux 2.6.24 onwards battery info is in
1470 /sys/class/power_supply/BAT0/
1471 On my system I get the following.
1472 /sys/class/power_supply/BAT0/uevent:
1473 PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A03:00/device:01/PNP0C09:00/PNP0C0A:00
1475 PHYSDEVDRIVER=battery
1476 POWER_SUPPLY_NAME=BAT0
1477 POWER_SUPPLY_TYPE=Battery
1478 POWER_SUPPLY_STATUS=Discharging
1479 POWER_SUPPLY_PRESENT=1
1480 POWER_SUPPLY_TECHNOLOGY=Li-ion
1481 POWER_SUPPLY_VOLTAGE_MIN_DESIGN=10800000
1482 POWER_SUPPLY_VOLTAGE_NOW=10780000
1483 POWER_SUPPLY_CURRENT_NOW=13970000
1484 POWER_SUPPLY_ENERGY_FULL_DESIGN=47510000
1485 POWER_SUPPLY_ENERGY_FULL=27370000
1486 POWER_SUPPLY_ENERGY_NOW=11810000
1487 POWER_SUPPLY_MODEL_NAME=IBM-92P1060
1488 POWER_SUPPLY_MANUFACTURER=Panasonic
1489 On some systems POWER_SUPPLY_ENERGY_* is replaced by POWER_SUPPLY_CHARGE_*
1492 #define SYSFS_BATTERY_BASE_PATH "/sys/class/power_supply"
1493 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1494 #define APM_PATH "/proc/apm"
1495 #define MAX_BATTERY_COUNT 4
1497 static FILE *sysfs_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1498 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1499 static FILE *apm_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1501 static int batteries_initialized = 0;
1502 static char batteries[MAX_BATTERY_COUNT][32];
1504 static int acpi_last_full[MAX_BATTERY_COUNT];
1505 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1507 /* e.g. "charging 75%" */
1508 static char last_battery_str[MAX_BATTERY_COUNT][64];
1510 static char last_battery_time_str[MAX_BATTERY_COUNT][64];
1512 static double last_battery_time[MAX_BATTERY_COUNT];
1514 static int last_battery_perct[MAX_BATTERY_COUNT];
1515 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1517 void init_batteries(void)
1521 if (batteries_initialized) {
1524 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1525 batteries[idx][0] = '\0';
1527 batteries_initialized = 1;
1530 int get_battery_idx(const char *bat)
1534 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1535 if (!strlen(batteries[idx]) || !strcmp(batteries[idx], bat)) {
1540 /* if not found, enter a new entry */
1541 if (!strlen(batteries[idx])) {
1542 snprintf(batteries[idx], 31, "%s", bat);
1548 void set_return_value(char *buffer, unsigned int n, int item, int idx);
1550 void get_battery_stuff(char *buffer, unsigned int n, const char *bat, int item)
1552 static int idx, rep = 0, rep2 = 0;
1553 char acpi_path[128];
1554 char sysfs_path[128];
1556 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1557 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1561 idx = get_battery_idx(bat);
1563 /* don't update battery too often */
1564 if (current_update_time - last_battery_time[idx] < 29.5) {
1565 set_return_value(buffer, n, item, idx);
1569 last_battery_time[idx] = current_update_time;
1571 memset(last_battery_str[idx], 0, sizeof(last_battery_str[idx]));
1572 memset(last_battery_time_str[idx], 0, sizeof(last_battery_time_str[idx]));
1574 /* first try SYSFS if that fails try ACPI */
1576 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1577 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1581 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1582 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1585 if (sysfs_bat_fp[idx] != NULL) {
1587 int present_rate = -1;
1588 int remaining_capacity = -1;
1589 char charging_state[64];
1592 strcpy(charging_state, "unknown");
1594 while (!feof(sysfs_bat_fp[idx])) {
1596 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1599 /* let's just hope units are ok */
1600 if (strncmp (buf, "POWER_SUPPLY_PRESENT=1", 22) == 0)
1601 strcpy(present, "yes");
1602 else if (strncmp (buf, "POWER_SUPPLY_PRESENT=0", 22) == 0)
1603 strcpy(present, "no");
1604 else if (strncmp (buf, "POWER_SUPPLY_STATUS=", 20) == 0)
1605 sscanf(buf, "POWER_SUPPLY_STATUS=%63s", charging_state);
1606 /* present_rate is not the same as the
1607 current flowing now but it is the same value
1608 which was used in the past. so we continue
1610 else if (strncmp(buf, "POWER_SUPPLY_CURRENT_NOW=", 25) == 0)
1611 sscanf(buf, "POWER_SUPPLY_CURRENT_NOW=%d", &present_rate);
1612 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0)
1613 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1614 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=", 25) == 0)
1615 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_last_full[idx]);
1616 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0)
1617 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1618 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=", 25) == 0)
1619 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_last_full[idx]);
1622 fclose(sysfs_bat_fp[idx]);
1623 sysfs_bat_fp[idx] = NULL;
1625 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1626 if (remaining_capacity > acpi_last_full[idx])
1627 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1630 if (strcmp(present, "No") == 0) {
1631 strncpy(last_battery_str[idx], "not present", 64);
1634 else if (strcmp(charging_state, "Charging") == 0) {
1635 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1636 /* e.g. charging 75% */
1637 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %i%%",
1638 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1640 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1641 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1642 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1643 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %d%%",
1644 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1645 snprintf(last_battery_time_str[idx],
1646 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1648 strncpy(last_battery_str[idx], "charging", sizeof(last_battery_str[idx])-1);
1649 snprintf(last_battery_time_str[idx],
1650 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1654 else if (strncmp(charging_state, "Discharging", 64) == 0) {
1655 if (present_rate > 0) {
1656 /* e.g. discharging 35% */
1657 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "discharging %i%%",
1658 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1660 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1661 (long) (((float) remaining_capacity / present_rate) * 3600));
1662 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1663 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "full");
1664 snprintf(last_battery_time_str[idx],
1665 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1667 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1669 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1670 snprintf(last_battery_time_str[idx],
1671 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1675 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1676 else if (strncmp(charging_state, "Charged", 64) == 0) {
1677 /* Below happens with the second battery on my X40,
1678 * when the second one is empty and the first one
1680 if (remaining_capacity == 0)
1681 strcpy(last_battery_str[idx], "empty");
1683 strcpy(last_battery_str[idx], "charged");
1685 /* unknown, probably full / AC */
1687 if (acpi_last_full[idx] != 0
1688 && remaining_capacity != acpi_last_full[idx])
1689 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1690 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1692 strncpy(last_battery_str[idx], "AC", 64);
1694 } else if (acpi_bat_fp[idx] != NULL) {
1696 int present_rate = -1;
1697 int remaining_capacity = -1;
1698 char charging_state[64];
1701 /* read last full capacity if it's zero */
1702 if (acpi_last_full[idx] == 0) {
1703 static int rep3 = 0;
1707 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1708 fp = open_file(path, &rep3);
1713 if (fgets(b, 256, fp) == NULL) {
1716 if (sscanf(b, "last full capacity: %d",
1717 &acpi_last_full[idx]) != 0) {
1726 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1728 strcpy(charging_state, "unknown");
1730 while (!feof(acpi_bat_fp[idx])) {
1733 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1737 /* let's just hope units are ok */
1738 if (strncmp(buf, "present:", 8) == 0) {
1739 sscanf(buf, "present: %4s", present);
1740 } else if (strncmp(buf, "charging state:", 15) == 0) {
1741 sscanf(buf, "charging state: %63s", charging_state);
1742 } else if (strncmp(buf, "present rate:", 13) == 0) {
1743 sscanf(buf, "present rate: %d", &present_rate);
1744 } else if (strncmp(buf, "remaining capacity:", 19) == 0) {
1745 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1748 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1749 if (remaining_capacity > acpi_last_full[idx]) {
1750 /* normalize to 100% */
1751 acpi_last_full[idx] = remaining_capacity;
1755 if (strcmp(present, "no") == 0) {
1756 strncpy(last_battery_str[idx], "not present", 64);
1758 } else if (strcmp(charging_state, "charging") == 0) {
1759 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1760 /* e.g. charging 75% */
1761 snprintf(last_battery_str[idx],
1762 sizeof(last_battery_str[idx]) - 1, "charging %i%%",
1763 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1765 format_seconds(last_battery_time_str[idx],
1766 sizeof(last_battery_time_str[idx]) - 1,
1767 (long) (((acpi_last_full[idx] - remaining_capacity) *
1768 3600) / present_rate));
1769 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1770 snprintf(last_battery_str[idx],
1771 sizeof(last_battery_str[idx]) - 1, "charging %d%%",
1772 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1773 snprintf(last_battery_time_str[idx],
1774 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1776 strncpy(last_battery_str[idx], "charging",
1777 sizeof(last_battery_str[idx]) - 1);
1778 snprintf(last_battery_time_str[idx],
1779 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1782 } else if (strncmp(charging_state, "discharging", 64) == 0) {
1783 if (present_rate > 0) {
1784 /* e.g. discharging 35% */
1785 snprintf(last_battery_str[idx],
1786 sizeof(last_battery_str[idx]) - 1, "discharging %i%%",
1787 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1789 format_seconds(last_battery_time_str[idx],
1790 sizeof(last_battery_time_str[idx]) - 1,
1791 (long) ((remaining_capacity * 3600) / present_rate));
1792 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1793 snprintf(last_battery_str[idx],
1794 sizeof(last_battery_str[idx]) - 1, "full");
1795 snprintf(last_battery_time_str[idx],
1796 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1798 snprintf(last_battery_str[idx],
1799 sizeof(last_battery_str[idx]) - 1, "discharging %d%%",
1800 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1801 snprintf(last_battery_time_str[idx],
1802 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1805 } else if (strncmp(charging_state, "charged", 64) == 0) {
1806 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1807 /* Below happens with the second battery on my X40,
1808 * when the second one is empty and the first one being charged. */
1809 if (remaining_capacity == 0) {
1810 strcpy(last_battery_str[idx], "empty");
1812 strcpy(last_battery_str[idx], "charged");
1814 /* unknown, probably full / AC */
1816 if (acpi_last_full[idx] != 0
1817 && remaining_capacity != acpi_last_full[idx]) {
1818 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1819 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1821 strncpy(last_battery_str[idx], "AC", 64);
1826 if (apm_bat_fp[idx] == NULL) {
1827 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1830 if (apm_bat_fp[idx] != NULL) {
1831 unsigned int ac, status, flag;
1834 fscanf(apm_bat_fp[idx], "%*s %*s %*x %x %x %x %d%%",
1835 &ac, &status, &flag, &life);
1838 /* could check now that there is ac */
1839 snprintf(last_battery_str[idx], 64, "AC");
1841 /* could check that status == 3 here? */
1842 } else if (ac && life != 100) {
1843 snprintf(last_battery_str[idx], 64, "charging %d%%", life);
1845 snprintf(last_battery_str[idx], 64, "%d%%", life);
1848 /* it seemed to buffer it so file must be closed (or could use
1849 * syscalls directly but I don't feel like coding it now) */
1850 fclose(apm_bat_fp[idx]);
1851 apm_bat_fp[idx] = NULL;
1854 set_return_value(buffer, n, item, idx);
1857 void set_return_value(char *buffer, unsigned int n, int item, int idx)
1860 case BATTERY_STATUS:
1861 snprintf(buffer, n, "%s", last_battery_str[idx]);
1864 snprintf(buffer, n, "%s", last_battery_time_str[idx]);
1871 int get_battery_perct(const char *bat)
1875 char acpi_path[128];
1876 char sysfs_path[128];
1877 int remaining_capacity = -1;
1879 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1880 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1884 idx = get_battery_idx(bat);
1886 /* don't update battery too often */
1887 if (current_update_time - last_battery_perct_time[idx] < 30) {
1888 return last_battery_perct[idx];
1890 last_battery_perct_time[idx] = current_update_time;
1892 /* Only check for SYSFS or ACPI */
1894 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1895 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1899 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1900 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1903 if (sysfs_bat_fp[idx] != NULL) {
1905 while (!feof(sysfs_bat_fp[idx])) {
1907 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1910 if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0) {
1911 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1912 } else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=",25) == 0) {
1913 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_design_capacity[idx]);
1914 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0) {
1915 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1916 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=",25) == 0) {
1917 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_design_capacity[idx]);
1921 fclose(sysfs_bat_fp[idx]);
1922 sysfs_bat_fp[idx] = NULL;
1924 } else if (acpi_bat_fp[idx] != NULL) {
1926 /* read last full capacity if it's zero */
1927 if (acpi_design_capacity[idx] == 0) {
1932 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1933 fp = open_file(path, &rep2);
1938 if (fgets(b, 256, fp) == NULL) {
1941 if (sscanf(b, "last full capacity: %d",
1942 &acpi_design_capacity[idx]) != 0) {
1950 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1952 while (!feof(acpi_bat_fp[idx])) {
1955 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1959 if (buf[0] == 'r') {
1960 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1964 if (remaining_capacity < 0) {
1967 /* compute the battery percentage */
1968 last_battery_perct[idx] =
1969 (int) (((float) remaining_capacity / acpi_design_capacity[idx]) * 100);
1970 return last_battery_perct[idx];
1973 int get_battery_perct_bar(const char *bar)
1977 get_battery_perct(bar);
1978 idx = get_battery_idx(bar);
1979 return (int) (last_battery_perct[idx] * 2.56 - 1);
1982 /* On Apple powerbook and ibook:
1983 $ cat /proc/pmu/battery_0
1990 $ cat /proc/pmu/info
1991 PMU driver version : 2
1992 PMU firmware version : 0c
1997 /* defines as in <linux/pmu.h> */
1998 #define PMU_BATT_PRESENT 0x00000001
1999 #define PMU_BATT_CHARGING 0x00000002
2001 static FILE *pmu_battery_fp;
2002 static FILE *pmu_info_fp;
2003 static char pb_battery_info[3][32];
2004 static double pb_battery_info_update;
2006 #define PMU_PATH "/proc/pmu"
2007 void get_powerbook_batt_info(char *buffer, size_t n, int i)
2010 const char *batt_path = PMU_PATH "/battery_0";
2011 const char *info_path = PMU_PATH "/info";
2013 int charge, max_charge, ac = -1;
2016 /* don't update battery too often */
2017 if (current_update_time - pb_battery_info_update < 29.5) {
2018 snprintf(buffer, n, "%s", pb_battery_info[i]);
2021 pb_battery_info_update = current_update_time;
2023 if (pmu_battery_fp == NULL) {
2024 pmu_battery_fp = open_file(batt_path, &rep);
2027 if (pmu_battery_fp != NULL) {
2028 rewind(pmu_battery_fp);
2029 while (!feof(pmu_battery_fp)) {
2032 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL) {
2036 if (buf[0] == 'f') {
2037 sscanf(buf, "flags : %8x", &flags);
2038 } else if (buf[0] == 'c' && buf[1] == 'h') {
2039 sscanf(buf, "charge : %d", &charge);
2040 } else if (buf[0] == 'm') {
2041 sscanf(buf, "max_charge : %d", &max_charge);
2042 } else if (buf[0] == 't') {
2043 sscanf(buf, "time rem. : %ld", &timeval);
2047 if (pmu_info_fp == NULL) {
2048 pmu_info_fp = open_file(info_path, &rep);
2051 if (pmu_info_fp != NULL) {
2052 rewind(pmu_info_fp);
2053 while (!feof(pmu_info_fp)) {
2056 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL) {
2059 if (buf[0] == 'A') {
2060 sscanf(buf, "AC Power : %d", &ac);
2064 /* update status string */
2065 if ((ac && !(flags & PMU_BATT_PRESENT))) {
2066 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
2067 } else if (ac && (flags & PMU_BATT_PRESENT)
2068 && !(flags & PMU_BATT_CHARGING)) {
2069 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
2070 } else if ((flags & PMU_BATT_PRESENT) && (flags & PMU_BATT_CHARGING)) {
2071 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
2073 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
2076 /* update percentage string */
2078 pb_battery_info[PB_BATT_PERCENT][0] = 0;
2080 snprintf(pb_battery_info[PB_BATT_PERCENT],
2081 sizeof(pb_battery_info[PB_BATT_PERCENT]), "%d%%",
2082 (charge * 100) / max_charge);
2085 /* update time string */
2086 if (timeval == 0) { /* fully charged or battery not present */
2087 pb_battery_info[PB_BATT_TIME][0] = 0;
2088 } else if (timeval < 60 * 60) { /* don't show secs */
2089 format_seconds_short(pb_battery_info[PB_BATT_TIME],
2090 sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2092 format_seconds(pb_battery_info[PB_BATT_TIME],
2093 sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2096 snprintf(buffer, n, "%s", pb_battery_info[i]);
2099 void update_top(void)
2101 show_nice_processes = 1;
2102 process_find_top(info.cpu, info.memu);
2103 info.first_process = get_first_process();
2106 /* Here come the IBM ACPI-specific things. For reference, see
2107 * http://ibm-acpi.sourceforge.net/README
2108 * If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
2124 * The content of these files is described in detail in the aforementioned
2125 * README - some of them also in the following functions accessing them.
2126 * Peter Tarjan (ptarjan@citromail.hu) */
2128 #define IBM_ACPI_DIR "/proc/acpi/ibm"
2130 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
2131 * /proc/acpi/ibm/fan looks like this (3 lines):
2134 commands: enable, disable
2135 * Peter Tarjan (ptarjan@citromail.hu) */
2137 void get_ibm_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
2140 unsigned int speed = 0;
2143 if (!p_client_buffer || client_buffer_size <= 0) {
2147 snprintf(fan, 127, "%s/fan", IBM_ACPI_DIR);
2149 fp = fopen(fan, "r");
2154 if (fgets(line, 255, fp) == NULL) {
2157 if (sscanf(line, "speed: %u", &speed)) {
2162 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2163 "ibm* from your Conky config file.", fan, strerror(errno));
2167 snprintf(p_client_buffer, client_buffer_size, "%d", speed);
2170 /* get the measured temperatures from the temperature sensors
2171 * on IBM/Lenovo laptops running the ibm acpi.
2172 * There are 8 values in /proc/acpi/ibm/thermal, and according to
2173 * http://ibm-acpi.sourceforge.net/README
2174 * these mean the following (at least on an IBM R51...)
2175 * 0: CPU (also on the T series laptops)
2176 * 1: Mini PCI Module (?)
2178 * 3: GPU (also on the T series laptops)
2183 * I'm not too sure about those with the question mark, but the values I'm
2184 * reading from *my* thermal file (on a T42p) look realistic for the
2185 * hdd and the battery.
2186 * #5 and #7 are always -128.
2187 * /proc/acpi/ibm/thermal looks like this (1 line):
2188 temperatures: 41 43 31 46 33 -128 29 -128
2189 * Peter Tarjan (ptarjan@citromail.hu) */
2191 static double last_ibm_acpi_temp_time;
2192 void get_ibm_acpi_temps(void)
2198 /* don't update too often */
2199 if (current_update_time - last_ibm_acpi_temp_time < 10.00) {
2202 last_ibm_acpi_temp_time = current_update_time;
2204 /* if (!p_client_buffer || client_buffer_size <= 0) {
2208 snprintf(thermal, 127, "%s/thermal", IBM_ACPI_DIR);
2209 fp = fopen(thermal, "r");
2215 if (fgets(line, 255, fp) == NULL) {
2218 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
2219 &ibm_acpi.temps[0], &ibm_acpi.temps[1], &ibm_acpi.temps[2],
2220 &ibm_acpi.temps[3], &ibm_acpi.temps[4], &ibm_acpi.temps[5],
2221 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) {
2226 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2227 "ibm* from your Conky config file.", thermal, strerror(errno));
2233 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
2234 * "Volume" here is none of the mixer volumes, but a "master of masters"
2235 * volume adjusted by the IBM volume keys.
2236 * /proc/acpi/ibm/fan looks like this (4 lines):
2239 commands: up, down, mute
2240 commands: level <level> (<level> is 0-15)
2241 * Peter Tarjan (ptarjan@citromail.hu) */
2243 void get_ibm_acpi_volume(char *p_client_buffer, size_t client_buffer_size)
2247 unsigned int vol = -1;
2250 if (!p_client_buffer || client_buffer_size <= 0) {
2254 snprintf(volume, 127, "%s/volume", IBM_ACPI_DIR);
2256 fp = fopen(volume, "r");
2260 unsigned int read_vol = -1;
2262 if (fgets(line, 255, fp) == NULL) {
2265 if (sscanf(line, "level: %u", &read_vol)) {
2269 if (sscanf(line, "mute: %s", mute)) {
2274 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2275 "ibm* from your Conky config file.", volume, strerror(errno));
2280 if (strcmp(mute, "on") == 0) {
2281 snprintf(p_client_buffer, client_buffer_size, "%s", "mute");
2284 snprintf(p_client_buffer, client_buffer_size, "%d", vol);
2289 /* static FILE *fp = NULL; */
2291 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
2292 * /proc/acpi/ibm/brightness looks like this (3 lines):
2295 commands: level <level> (<level> is 0-7)
2296 * Peter Tarjan (ptarjan@citromail.hu) */
2298 void get_ibm_acpi_brightness(char *p_client_buffer, size_t client_buffer_size)
2301 unsigned int brightness = 0;
2304 if (!p_client_buffer || client_buffer_size <= 0) {
2308 snprintf(filename, 127, "%s/brightness", IBM_ACPI_DIR);
2310 fp = fopen(filename, "r");
2315 if (fgets(line, 255, fp) == NULL) {
2318 if (sscanf(line, "level: %u", &brightness)) {
2323 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2324 "ibm* from your Conky config file.", filename, strerror(errno));
2329 snprintf(p_client_buffer, client_buffer_size, "%d", brightness);
2332 void update_entropy(void)
2335 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
2336 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
2339 info.entropy.entropy_avail = 0;
2340 info.entropy.poolsize = 0;
2342 if ((fp1 = open_file(entropy_avail, &rep)) == NULL) {
2346 if ((fp2 = open_file(entropy_poolsize, &rep)) == NULL) {
2351 fscanf(fp1, "%u", &info.entropy.entropy_avail);
2352 fscanf(fp2, "%u", &info.entropy.poolsize);
2357 info.mask |= (1 << INFO_ENTROPY);
2360 const char *get_disk_protect_queue(const char *disk)
2366 snprintf(path, 127, "/sys/block/%s/queue/protect", disk);
2367 if ((fp = fopen(path, "r")) == NULL)
2369 if (fscanf(fp, "%d\n", &state) != 1) {
2374 return state ? "frozen" : "free ";