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-2007 Brenden Matthews, Philip Kovacs, et. al.
13 * All rights reserved.
15 * This program is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation, either version 3 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program. If not, see <http://www.gnu.org/licenses/>.
37 #include <sys/types.h>
38 #include <sys/sysinfo.h>
40 #ifndef HAVE_CLOCK_GETTIME
45 // #include <assert.h>
49 #include <sys/ioctl.h>
50 #include <sys/socket.h>
51 #include <netinet/in.h>
52 #include <linux/sockios.h>
60 #define SHORTSTAT_TEMPL "%*s %llu %llu %llu"
61 #define LONGSTAT_TEMPL "%*s %llu %llu %llu "
63 static int show_nice_processes;
65 /* This flag tells the linux routines to use the /proc system where possible,
66 * even if other api's are available, e.g. sysinfo() or getloadavg().
67 * the reason for this is to allow for /proc-based distributed monitoring.
68 * using a flag in this manner creates less confusing code. */
69 static int prefer_proc = 0;
79 struct sysinfo s_info;
82 info.uptime = (double) s_info.uptime;
89 if (!(fp = open_file("/proc/uptime", &rep))) {
93 fscanf(fp, "%lf", &info.uptime);
96 info.mask |= (1 << INFO_UPTIME);
99 int check_mount(char *s)
102 FILE *mtab = fopen("/etc/mtab", "r");
105 char buf1[256], buf2[128];
107 while (fgets(buf1, 256, mtab)) {
108 sscanf(buf1, "%*s %128s", buf2);
109 if (!strcmp(s, buf2)) {
116 ERR("Could not open mtab");
121 /* these things are also in sysinfo except Buffers:
122 * (that's why I'm reading them from proc) */
124 void update_meminfo()
129 /* unsigned int a; */
132 info.mem = info.memmax = info.swap = info.swapmax = info.bufmem =
133 info.buffers = info.cached = 0;
135 if (!(meminfo_fp = open_file("/proc/meminfo", &rep))) {
139 while (!feof(meminfo_fp)) {
140 if (fgets(buf, 255, meminfo_fp) == NULL) {
144 if (strncmp(buf, "MemTotal:", 9) == 0) {
145 sscanf(buf, "%*s %Lu", &info.memmax);
146 } else if (strncmp(buf, "MemFree:", 8) == 0) {
147 sscanf(buf, "%*s %Lu", &info.mem);
148 } else if (strncmp(buf, "SwapTotal:", 10) == 0) {
149 sscanf(buf, "%*s %Lu", &info.swapmax);
150 } else if (strncmp(buf, "SwapFree:", 9) == 0) {
151 sscanf(buf, "%*s %Lu", &info.swap);
152 } else if (strncmp(buf, "Buffers:", 8) == 0) {
153 sscanf(buf, "%*s %Lu", &info.buffers);
154 } else if (strncmp(buf, "Cached:", 7) == 0) {
155 sscanf(buf, "%*s %Lu", &info.cached);
159 info.mem = info.memmax - info.mem;
160 info.swap = info.swapmax - info.swap;
162 info.bufmem = info.cached + info.buffers;
164 info.mask |= (1 << INFO_MEM) | (1 << INFO_BUFFERS);
169 int interface_up(const char *dev)
174 if((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
175 CRIT_ERR("could not create sockfd");
178 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
179 if(ioctl(fd, SIOCGIFFLAGS, &ifr)) {
180 /* if device does not exist, treat like not up */
182 perror("SIOCGIFFLAGS");
185 return (ifr.ifr_flags & IFF_UP);
191 inline void update_net_stats()
196 // FIXME: arbitrary size chosen to keep code simple.
198 unsigned int curtmp1, curtmp2;
205 // wireless info variables
206 int skfd, has_bitrate = 0;
207 struct wireless_info *winfo;
212 delta = current_update_time - last_update_time;
213 if (delta <= 0.0001) {
217 /* open file and ignore first two lines */
218 if (!(net_dev_fp = open_file("/proc/net/dev", &rep))) {
223 fgets(buf, 255, net_dev_fp); /* garbage */
224 fgets(buf, 255, net_dev_fp); /* garbage (field names) */
226 /* read each interface */
227 for (i2 = 0; i2 < 16; i2++) {
231 long long r, t, last_recv, last_trans;
233 if (fgets(buf, 255, net_dev_fp) == NULL) {
237 while (isspace((int) *p)) {
243 while (*p && *p != ':') {
252 ns = get_net_stat(s);
254 memset(&(ns->addr.sa_data), 0, 14);
256 if(NULL == ns->addrs)
257 ns->addrs = (char*) malloc(17 * 16);
258 if(NULL != ns->addrs)
259 memset(ns->addrs, 0, 17 * 16); /* Up to 17 chars per ip, max 16 interfaces. Nasty memory usage... */
261 last_recv = ns->recv;
262 last_trans = ns->trans;
264 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
265 sscanf(p, "%Ld %*d %*d %*d %*d %*d %*d %*d %Ld",
268 /* if recv or trans is less than last time, an overflow happened */
269 if (r < ns->last_read_recv) {
272 ns->recv += (r - ns->last_read_recv);
274 ns->last_read_recv = r;
276 if (t < ns->last_read_trans) {
279 ns->trans += (t - ns->last_read_trans);
281 ns->last_read_trans = t;
283 /*** ip addr patch ***/
284 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
286 conf.ifc_buf = malloc(sizeof(struct ifreq) * 16);
288 conf.ifc_len = sizeof(struct ifreq) * 16;
290 ioctl((long) i, SIOCGIFCONF, &conf);
292 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
296 ((struct ifreq *) conf.ifc_buf)[k].ifr_ifrn.ifrn_name);
297 ns->addr = ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.ifru_addr;
298 if(NULL != ns->addrs)
300 sprintf(temp_addr, "%u.%u.%u.%u, ",
301 ns->addr.sa_data[2] & 255,
302 ns->addr.sa_data[3] & 255,
303 ns->addr.sa_data[4] & 255,
304 ns->addr.sa_data[5] & 255);
305 if(NULL == strstr(ns->addrs, temp_addr))
306 strncpy(ns->addrs + strlen(ns->addrs), temp_addr, 17);
314 /*** end ip addr patch ***/
316 /* calculate speeds */
317 ns->net_rec[0] = (ns->recv - last_recv) / delta;
318 ns->net_trans[0] = (ns->trans - last_trans) / delta;
322 for (i = 0; (unsigned) i < info.net_avg_samples; i++) {
323 curtmp1 += ns->net_rec[i];
324 curtmp2 += ns->net_trans[i];
332 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
333 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
334 if (info.net_avg_samples > 1) {
335 for (i = info.net_avg_samples; i > 1; i--) {
336 ns->net_rec[i - 1] = ns->net_rec[i - 2];
337 ns->net_trans[i - 1] = ns->net_trans[i - 2];
342 /* update wireless info */
343 winfo = malloc(sizeof(struct wireless_info));
344 memset(winfo, 0, sizeof(struct wireless_info));
346 skfd = iw_sockets_open();
347 if (iw_get_basic_config(skfd, s, &(winfo->b)) > -1) {
349 // set present winfo variables
350 if (iw_get_stats(skfd, s, &(winfo->stats),
351 &winfo->range, winfo->has_range) >= 0) {
352 winfo->has_stats = 1;
354 if (iw_get_range_info(skfd, s, &(winfo->range)) >= 0) {
355 winfo->has_range = 1;
357 if (iw_get_ext(skfd, s, SIOCGIWAP, &wrq) >= 0) {
358 winfo->has_ap_addr = 1;
359 memcpy(&(winfo->ap_addr), &(wrq.u.ap_addr), sizeof(sockaddr));
363 if (iw_get_ext(skfd, s, SIOCGIWRATE, &wrq) >= 0) {
364 memcpy(&(winfo->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
365 iw_print_bitrate(ns->bitrate, 16, winfo->bitrate.value);
370 if (winfo->has_range && winfo->has_stats
371 && ((winfo->stats.qual.level != 0)
372 || (winfo->stats.qual.updated & IW_QUAL_DBM))) {
373 if (!(winfo->stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
374 ns->link_qual = winfo->stats.qual.qual;
375 ns->link_qual_max = winfo->range.max_qual.qual;
380 if (winfo->has_ap_addr) {
381 iw_sawap_ntop(&winfo->ap_addr, ns->ap);
385 if (winfo->b.has_essid) {
386 if (winfo->b.essid_on) {
387 snprintf(ns->essid, 32, "%s", winfo->b.essid);
389 snprintf(ns->essid, 32, "off/any");
393 snprintf(ns->mode, 16, "%s", iw_operation_mode[winfo->b.mode]);
395 iw_sockets_close(skfd);
402 info.mask |= (1 << INFO_NET);
407 void update_total_processes()
411 struct sysinfo s_info;
414 info.procs = s_info.procs;
421 if (!(fp = open_file("/proc/loadavg", &rep))) {
425 fscanf(fp, "%*f %*f %*f %*d/%hd", &info.procs);
428 info.mask |= (1 << INFO_PROCS);
431 #define CPU_SAMPLE_COUNT 15
433 unsigned long long cpu_user;
434 unsigned long long cpu_system;
435 unsigned long long cpu_nice;
436 unsigned long long cpu_idle;
437 unsigned long long cpu_iowait;
438 unsigned long long cpu_irq;
439 unsigned long long cpu_softirq;
440 unsigned long long cpu_steal;
441 unsigned long long cpu_total;
442 unsigned long long cpu_active_total;
443 unsigned long long cpu_last_total;
444 unsigned long long cpu_last_active_total;
445 double cpu_val[CPU_SAMPLE_COUNT];
447 static short cpu_setup = 0;
449 /* Determine if this kernel gives us "extended" statistics information in
451 * Kernels around 2.5 and earlier only reported user, system, nice, and
452 * idle values in proc stat.
453 * Kernels around 2.6 and greater report these PLUS iowait, irq, softirq,
455 void determine_longstat(char *buf)
457 unsigned long long iowait = 0;
459 KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
460 /* scanf will either return -1 or 1 because there is only 1 assignment */
461 if (sscanf(buf, "%*s %*d %*d %*d %*d %llu", &iowait) > 0) {
462 KFLAG_SETON(KFLAG_IS_LONGSTAT);
471 if (info.cpu_usage) {
476 if (!(stat_fp = open_file("/proc/stat", &rep))) {
482 while (!feof(stat_fp)) {
483 if (fgets(buf, 255, stat_fp) == NULL) {
487 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
488 if (info.cpu_count == 0) {
489 determine_longstat(buf);
494 info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
499 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
500 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
502 inline static void update_stat()
506 static struct cpu_info *cpu = NULL;
511 char *stat_template = NULL;
512 unsigned int malloc_cpu_size = 0;
514 /* add check for !info.cpu_usage since that mem is freed on a SIGUSR1 */
515 if (!cpu_setup || !info.cpu_usage) {
520 if (!stat_template) {
522 KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT;
526 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
527 cpu = malloc(malloc_cpu_size);
528 memset(cpu, 0, malloc_cpu_size);
531 if (!(stat_fp = open_file("/proc/stat", &rep))) {
533 if (info.cpu_usage) {
534 memset(info.cpu_usage, 0, info.cpu_count * sizeof(float));
540 while (!feof(stat_fp)) {
541 if (fgets(buf, 255, stat_fp) == NULL) {
545 if (strncmp(buf, "procs_running ", 14) == 0) {
546 sscanf(buf, "%*s %hu", &info.run_procs);
547 info.mask |= (1 << INFO_RUN_PROCS);
548 } else if (strncmp(buf, "cpu", 3) == 0) {
549 index = isdigit(buf[3]) ? ((int) buf[3]) - 0x2F : 0;
550 sscanf(buf, stat_template, &(cpu[index].cpu_user),
551 &(cpu[index].cpu_nice), &(cpu[index].cpu_system),
552 &(cpu[index].cpu_idle), &(cpu[index].cpu_iowait),
553 &(cpu[index].cpu_irq), &(cpu[index].cpu_softirq),
554 &(cpu[index].cpu_steal));
556 cpu[index].cpu_total = cpu[index].cpu_user + cpu[index].cpu_nice +
557 cpu[index].cpu_system + cpu[index].cpu_idle +
558 cpu[index].cpu_iowait + cpu[index].cpu_irq +
559 cpu[index].cpu_softirq + cpu[index].cpu_steal;
561 cpu[index].cpu_active_total = cpu[index].cpu_total -
562 (cpu[index].cpu_idle + cpu[index].cpu_iowait);
563 info.mask |= (1 << INFO_CPU);
565 double delta = current_update_time - last_update_time;
567 if (delta <= 0.001) {
571 cpu[index].cpu_val[0] = (cpu[index].cpu_active_total -
572 cpu[index].cpu_last_active_total) /
573 (float) (cpu[index].cpu_total - cpu[index].cpu_last_total);
575 for (i = 0; i < info.cpu_avg_samples; i++) {
576 curtmp += cpu[index].cpu_val[i];
578 /* TESTING -- I've removed this, because I don't think it is right.
579 * You shouldn't divide by the cpu count here ...
580 * removing for testing */
582 info.cpu_usage[index] = curtmp / info.cpu_avg_samples /
585 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
587 /* TESTING -- this line replaces the prev. "suspect" if/else */
588 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
590 cpu[index].cpu_last_total = cpu[index].cpu_total;
591 cpu[index].cpu_last_active_total = cpu[index].cpu_active_total;
592 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
593 cpu[index].cpu_val[i] = cpu[index].cpu_val[i - 1];
600 void update_running_processes()
605 void update_cpu_usage()
610 void update_load_average()
612 #ifdef HAVE_GETLOADAVG
617 info.loadavg[0] = (float) v[0];
618 info.loadavg[1] = (float) v[1];
619 info.loadavg[2] = (float) v[2];
626 if (!(fp = open_file("/proc/loadavg", &rep))) {
627 info.loadavg[0] = info.loadavg[1] = info.loadavg[2] = 0.0;
630 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1],
634 info.mask |= (1 << INFO_LOADAVG);
637 #define PROC_I8K "/proc/i8k"
638 #define I8K_DELIM " "
639 static char *i8k_procbuf = NULL;
645 i8k_procbuf = (char *) malloc(128 * sizeof(char));
647 if ((fp = fopen(PROC_I8K, "r")) == NULL) {
648 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel "
649 "driver is loaded...");
652 memset(&i8k_procbuf[0], 0, 128);
653 if (fread(&i8k_procbuf[0], sizeof(char), 128, fp) == 0) {
654 ERR("something wrong with /proc/i8k...");
659 i8k.version = strtok(&i8k_procbuf[0], I8K_DELIM);
660 i8k.bios = strtok(NULL, I8K_DELIM);
661 i8k.serial = strtok(NULL, I8K_DELIM);
662 i8k.cpu_temp = strtok(NULL, I8K_DELIM);
663 i8k.left_fan_status = strtok(NULL, I8K_DELIM);
664 i8k.right_fan_status = strtok(NULL, I8K_DELIM);
665 i8k.left_fan_rpm = strtok(NULL, I8K_DELIM);
666 i8k.right_fan_rpm = strtok(NULL, I8K_DELIM);
667 i8k.ac_status = strtok(NULL, I8K_DELIM);
668 i8k.buttons_status = strtok(NULL, I8K_DELIM);
671 /***********************************************************/
672 /***********************************************************/
673 /***********************************************************/
675 static int no_dots(const struct dirent *d)
677 if (d->d_name[0] == '.') {
683 static int get_first_file_in_a_directory(const char *dir, char *s, int *rep)
685 struct dirent **namelist;
688 n = scandir(dir, &namelist, no_dots, alphasort);
691 ERR("scandir for %s: %s", dir, strerror(errno));
702 strncpy(s, namelist[0]->d_name, 255);
705 for (i = 0; i < n; i++) {
714 int open_sysfs_sensor(const char *dir, const char *dev, const char *type, int n,
715 int *div, char *devtype)
722 memset(buf, 0, sizeof(buf));
724 /* if device is NULL or *, get first */
725 if (dev == NULL || strcmp(dev, "*") == 0) {
728 if (!get_first_file_in_a_directory(dir, buf, &rep)) {
734 if (strcmp(dir, "/sys/class/hwmon/") == 0) {
736 /* buf holds result from get_first_file_in_a_directory() above,
737 * e.g. "hwmon0" -- append "/device" */
738 strcat(buf, "/device");
740 /* dev holds device number N as a string,
741 * e.g. "0", -- convert to "hwmon0/device" */
742 sprintf(buf, "hwmon%s/device", dev);
747 /* change vol to in */
748 if (strcmp(type, "vol") == 0) {
752 if (strcmp(type, "tempf") == 0) {
753 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, "temp", n);
755 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, type, n);
757 strncpy(devtype, path, 255);
760 fd = open(path, O_RDONLY);
762 CRIT_ERR("can't open '%s': %s\nplease check your device or remove this "
763 "var from Conky", path, strerror(errno));
766 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
767 || strcmp(type, "tempf") == 0) {
772 /* fan does not use *_div as a read divisor */
773 if (strcmp("fan", type) == 0) {
777 /* test if *_div file exist, open it and use it as divisor */
778 if (strcmp(type, "tempf") == 0) {
779 snprintf(path, 255, "%s%s/%s%d_div", dir, "one", "two", n);
781 snprintf(path, 255, "%s%s/%s%d_div", dir, dev, type, n);
784 divfd = open(path, O_RDONLY);
790 divn = read(divfd, divbuf, 63);
791 /* should read until n == 0 but I doubt that kernel will give these
792 * in multiple pieces. :) */
794 ERR("open_sysfs_sensor(): can't read from sysfs");
806 double get_sysfs_info(int *fd, int div, char *devtype, char *type)
814 lseek(*fd, 0, SEEK_SET);
820 n = read(*fd, buf, 63);
821 /* should read until n == 0 but I doubt that kernel will give these
822 * in multiple pieces. :) */
824 ERR("get_sysfs_info(): read from %s failed\n", devtype);
833 *fd = open(devtype, O_RDONLY);
835 ERR("can't open '%s': %s", devtype, strerror(errno));
838 /* My dirty hack for computing CPU value
839 * Filedil, from forums.gentoo.org */
840 /* if (strstr(devtype, "temp1_input") != NULL) {
841 return -15.096 + 1.4893 * (val / 1000.0);
844 /* divide voltage and temperature by 1000 */
845 /* or if any other divisor is given, use that */
846 if (strcmp(type, "tempf") == 0) {
848 return ((val / div + 40) * 9.0 / 5) - 40;
850 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
852 return ((val + 40) * 9.0 / 5) - 40;
865 /* Prior to kernel version 2.6.12, the CPU fan speed was available in
866 * ADT746X_FAN_OLD, whereas later kernel versions provide this information in
868 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
869 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
871 void get_adt746x_fan(char *p_client_buffer, size_t client_buffer_size)
874 char adt746x_fan_state[64];
877 if (!p_client_buffer || client_buffer_size <= 0) {
881 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
882 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL) {
883 sprintf(adt746x_fan_state, "adt746x not found");
885 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
886 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
890 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_fan_state);
893 /* Prior to kernel version 2.6.12, the CPU temperature was found in
894 * ADT746X_CPU_OLD, whereas later kernel versions provide this information in
896 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
897 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
899 void get_adt746x_cpu(char *p_client_buffer, size_t client_buffer_size)
902 char adt746x_cpu_state[64];
905 if (!p_client_buffer || client_buffer_size <= 0) {
909 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
910 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL) {
911 sprintf(adt746x_cpu_state, "adt746x not found");
913 fscanf(fp, "%2s", adt746x_cpu_state);
917 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state);
920 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
922 /***********************************************************************/
923 /* This file is part of x86info.
924 * (C) 2001 Dave Jones.
926 * Licensed under the terms of the GNU GPL License version 2.
928 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
929 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz> */
931 #if defined(__i386) || defined(__x86_64)
932 __inline__ unsigned long long int rdtsc()
934 unsigned long long int x;
936 __asm__ volatile(".byte 0x0f, 0x31":"=A" (x));
941 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
942 void get_freq_dynamic(char *p_client_buffer, size_t client_buffer_size,
943 char *p_format, int divisor)
945 #if defined(__i386) || defined(__x86_64)
947 struct timeval tvstart, tvstop;
948 unsigned long long cycles[2]; /* gotta be 64 bit */
949 unsigned int microseconds; /* total time taken */
951 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
956 memset(&tz, 0, sizeof(tz));
958 /* get this function in cached memory */
959 gettimeofday(&tvstart, &tz);
961 gettimeofday(&tvstart, &tz);
963 /* we don't trust that this is any specific length of time */
966 gettimeofday(&tvstop, &tz);
967 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
968 (tvstop.tv_usec - tvstart.tv_usec);
970 snprintf(p_client_buffer, client_buffer_size, p_format,
971 (float) ((cycles[1] - cycles[0]) / microseconds) / divisor);
974 /* FIXME: hardwired: get freq for first cpu!
975 * this whole function needs to be rethought and redone for
976 * multi-cpu/multi-core/multi-threaded environments and
977 * arbitrary combinations thereof */
978 get_freq(p_client_buffer, client_buffer_size, p_format, divisor, 1);
983 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
984 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
986 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
987 char get_freq(char *p_client_buffer, size_t client_buffer_size, char *p_format,
988 int divisor, unsigned int cpu)
996 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1002 char current_freq_file[128];
1004 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu - 1,
1006 f = fopen(current_freq_file, "r");
1008 /* if there's a cpufreq /sys node, read the current frequency from
1009 * this node and divide by 1000 to get Mhz. */
1010 if (fgets(s, sizeof(s), f)) {
1011 s[strlen(s) - 1] = '\0';
1012 freq = strtod(s, NULL);
1015 snprintf(p_client_buffer, client_buffer_size, p_format,
1016 (freq / 1000) / divisor);
1021 // open the CPU information file
1022 f = open_file("/proc/cpuinfo", &rep);
1024 perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
1029 while (fgets(s, sizeof(s), f) != NULL) {
1031 #if defined(__i386) || defined(__x86_64)
1032 // and search for the cpu mhz
1033 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) {
1035 #if defined(__alpha)
1036 // different on alpha
1037 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) {
1039 // this is different on ppc for some reason
1040 if (strncmp(s, "clock", 5) == 0 && cpu == 0) {
1041 #endif // defined(__alpha)
1042 #endif // defined(__i386) || defined(__x86_64)
1044 // copy just the number
1045 strcpy(frequency, strchr(s, ':') + 2);
1046 #if defined(__alpha)
1048 frequency[strlen(frequency) - 6] = '\0';
1049 // kernel reports in Hz
1050 freq = strtod(frequency, NULL) / 1000000;
1053 frequency[strlen(frequency) - 1] = '\0';
1054 freq = strtod(frequency, NULL);
1058 if (strncmp(s, "processor", 9) == 0) {
1065 snprintf(p_client_buffer, client_buffer_size, p_format,
1066 (float) freq / divisor);
1070 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
1072 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks something
1082 * Peter Tarjan (ptarjan@citromail.hu) */
1084 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
1085 char get_voltage(char *p_client_buffer, size_t client_buffer_size,
1086 char *p_format, int divisor, unsigned int cpu)
1092 char current_freq_file[128];
1095 /* build the voltage file name */
1097 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1100 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1105 /* read the current cpu frequency from the /sys node */
1106 f = fopen(current_freq_file, "r");
1108 if (fgets(s, sizeof(s), f)) {
1109 s[strlen(s) - 1] = '\0';
1110 freq = strtod(s, NULL);
1114 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1115 perror("get_voltage()");
1122 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1125 /* use the current cpu frequency to find the corresponding voltage */
1126 f = fopen(current_freq_file, "r");
1132 if (fgets(line, 255, f) == NULL) {
1135 sscanf(line, "%d %d", &freq_comp, &voltage);
1136 if (freq_comp == freq) {
1142 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1143 perror("get_voltage()");
1149 snprintf(p_client_buffer, client_buffer_size, p_format,
1150 (float) voltage / divisor);
1154 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1156 void get_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
1163 if (!p_client_buffer || client_buffer_size <= 0) {
1167 /* yeah, slow... :/ */
1168 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep)) {
1169 snprintf(p_client_buffer, client_buffer_size, "no fans?");
1173 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf);
1175 fp = open_file(buf2, &rep);
1177 snprintf(p_client_buffer, client_buffer_size,
1178 "can't open fan's state file");
1181 memset(buf, 0, sizeof(buf));
1182 fscanf(fp, "%*s %99s", buf);
1185 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1188 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1190 void get_acpi_ac_adapter(char *p_client_buffer, size_t client_buffer_size)
1197 if (!p_client_buffer || client_buffer_size <= 0) {
1201 /* yeah, slow... :/ */
1202 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep)) {
1203 snprintf(p_client_buffer, client_buffer_size, "no ac_adapters?");
1207 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf);
1209 fp = open_file(buf2, &rep);
1211 snprintf(p_client_buffer, client_buffer_size,
1212 "No ac adapter found.... where is it?");
1215 memset(buf, 0, sizeof(buf));
1216 fscanf(fp, "%*s %99s", buf);
1219 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1223 /proc/acpi/thermal_zone/THRM/cooling_mode
1224 cooling mode: active
1225 /proc/acpi/thermal_zone/THRM/polling_frequency
1227 /proc/acpi/thermal_zone/THRM/state
1229 /proc/acpi/thermal_zone/THRM/temperature
1231 /proc/acpi/thermal_zone/THRM/trip_points
1233 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1236 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1237 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1239 int open_acpi_temperature(const char *name)
1245 if (name == NULL || strcmp(name, "*") == 0) {
1248 if (!get_first_file_in_a_directory(ACPI_THERMAL_DIR, buf, &rep)) {
1254 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1256 fd = open(path, O_RDONLY);
1258 ERR("can't open '%s': %s", path, strerror(errno));
1264 static double last_acpi_temp;
1265 static double last_acpi_temp_time;
1267 double get_acpi_temperature(int fd)
1273 /* don't update acpi temperature too often */
1274 if (current_update_time - last_acpi_temp_time < 11.32) {
1275 return last_acpi_temp;
1277 last_acpi_temp_time = current_update_time;
1279 /* seek to beginning */
1280 lseek(fd, 0, SEEK_SET);
1287 n = read(fd, buf, 255);
1289 ERR("can't read fd %d: %s", fd, strerror(errno));
1292 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1296 return last_acpi_temp;
1300 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1302 design capacity: 4400 mAh
1303 last full capacity: 4064 mAh
1304 battery technology: rechargeable
1305 design voltage: 14800 mV
1306 design capacity warning: 300 mAh
1307 design capacity low: 200 mAh
1308 capacity granularity 1: 32 mAh
1309 capacity granularity 2: 32 mAh
1311 serial number: 16922
1317 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1320 charging state: unknown
1322 remaining capacity: 4064 mAh
1323 present voltage: 16608 mV
1327 2213<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1328 2213<@jupet�kellari��> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1329 2213<@jupet�kellari��> (-1 ollee ei akkua kiinni, koska akku on p�yd�ll�)
1330 2214<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1331 2214<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1333 2238<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1334 2239<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1336 2240<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori p��ll�
1337 2241<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori p��ll� mutta ilman verkkovirtaa
1340 /* Kapil Hari Paranjape <kapil@imsc.res.in>
1341 Linux 2.6.24 onwards battery info is in
1342 /sys/class/power_supply/BAT0/
1343 On my system I get the following.
1344 /sys/class/power_supply/BAT0/uevent:
1345 PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A03:00/device:01/PNP0C09:00/PNP0C0A:00
1347 PHYSDEVDRIVER=battery
1348 POWER_SUPPLY_NAME=BAT0
1349 POWER_SUPPLY_TYPE=Battery
1350 POWER_SUPPLY_STATUS=Discharging
1351 POWER_SUPPLY_PRESENT=1
1352 POWER_SUPPLY_TECHNOLOGY=Li-ion
1353 POWER_SUPPLY_VOLTAGE_MIN_DESIGN=10800000
1354 POWER_SUPPLY_VOLTAGE_NOW=10780000
1355 POWER_SUPPLY_CURRENT_NOW=13970000
1356 POWER_SUPPLY_ENERGY_FULL_DESIGN=47510000
1357 POWER_SUPPLY_ENERGY_FULL=27370000
1358 POWER_SUPPLY_ENERGY_NOW=11810000
1359 POWER_SUPPLY_MODEL_NAME=IBM-92P1060
1360 POWER_SUPPLY_MANUFACTURER=Panasonic
1361 On some systems POWER_SUPPLY_ENERGY_* is replaced by POWER_SUPPLY_CHARGE_*
1364 #define SYSFS_BATTERY_BASE_PATH "/sys/class/power_supply"
1365 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1366 #define APM_PATH "/proc/apm"
1367 #define MAX_BATTERY_COUNT 4
1369 static FILE *sysfs_bat_fp[MAX_BATTERY_COUNT];
1370 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT];
1371 static FILE *apm_bat_fp[MAX_BATTERY_COUNT];
1373 static int batteries_initialized = 0;
1374 static char batteries[MAX_BATTERY_COUNT][32];
1376 static int acpi_last_full[MAX_BATTERY_COUNT];
1377 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1379 /* e.g. "charging 75%" */
1380 static char last_battery_str[MAX_BATTERY_COUNT][64];
1382 static char last_battery_time_str[MAX_BATTERY_COUNT][64];
1384 static double last_battery_time[MAX_BATTERY_COUNT];
1386 static int last_battery_perct[MAX_BATTERY_COUNT];
1387 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1389 void init_batteries(void)
1393 if (batteries_initialized) {
1396 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1397 batteries[idx][0] = '\0';
1399 batteries_initialized = 1;
1402 int get_battery_idx(const char *bat)
1406 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1407 if (!strlen(batteries[idx]) || !strcmp(batteries[idx], bat)) {
1412 /* if not found, enter a new entry */
1413 if (!strlen(batteries[idx])) {
1414 snprintf(batteries[idx], 31, "%s", bat);
1420 void get_battery_stuff(char *buf, unsigned int n, const char *bat, int item)
1422 static int idx, rep = 0, rep2 = 0;
1423 char acpi_path[128];
1425 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1426 char sysfs_path[128];
1427 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1431 idx = get_battery_idx(bat);
1433 /* don't update battery too often */
1434 if (current_update_time - last_battery_time[idx] < 29.5) {
1435 goto set_return_value;
1438 last_battery_time[idx] = current_update_time;
1440 memset(last_battery_str[idx], 0, sizeof(last_battery_str[idx]));
1441 memset(last_battery_time_str[idx], 0, sizeof(last_battery_time_str[idx]));
1443 /* first try SYSFS if that fails try ACPI */
1445 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1446 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1448 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1449 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1451 if (sysfs_bat_fp[idx] != NULL) {
1453 int present_rate = -1;
1454 int remaining_capacity = -1;
1455 char charging_state[64];
1458 strcpy(charging_state, "Unknown");
1460 while (!feof(sysfs_bat_fp[idx])) {
1462 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1465 /* let's just hope units are ok */
1466 if (strncmp (buf, "POWER_SUPPLY_PRESENT=1", 22) == 0)
1467 strcpy(present, "Yes");
1468 else if (strncmp (buf, "POWER_SUPPLY_PRESENT=0", 22) == 0)
1469 strcpy(present, "No");
1470 else if (strncmp (buf, "POWER_SUPPLY_STATUS=", 20) == 0)
1471 sscanf(buf, "POWER_SUPPLY_STATUS=%63s", charging_state);
1472 /* present_rate is not the same as the
1473 current flowing now but it is the same value
1474 which was used in the past. so we continue
1476 else if (strncmp(buf, "POWER_SUPPLY_CURRENT_NOW=", 25) == 0)
1477 sscanf(buf, "POWER_SUPPLY_CURRENT_NOW=%d", &present_rate);
1478 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0)
1479 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1480 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=", 25) == 0)
1481 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_last_full[idx]);
1482 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0)
1483 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1484 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=", 25) == 0)
1485 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_last_full[idx]);
1488 fclose(sysfs_bat_fp[idx]);
1489 sysfs_bat_fp[idx] = NULL;
1491 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1492 if (remaining_capacity > acpi_last_full[idx])
1493 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1496 if (strcmp(present, "No") == 0) {
1497 strncpy(last_battery_str[idx], "not present", 64);
1500 else if (strcmp(charging_state, "Charging") == 0) {
1501 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1502 /* e.g. charging 75% */
1503 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Charging %i%%",
1504 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1506 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1507 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1508 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1509 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Charging %d%%",
1510 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1512 strncpy(last_battery_str[idx], "Charging", sizeof(last_battery_str[idx])-1);
1516 else if (strncmp(charging_state, "Discharging", 64) == 0) {
1517 if (present_rate > 0) {
1518 /* e.g. discharging 35% */
1519 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Discharging %i%%",
1520 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1522 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1523 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1524 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1525 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Full");
1527 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1529 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1533 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1534 else if (strncmp(charging_state, "Charged", 64) == 0) {
1535 /* Below happens with the second battery on my X40,
1536 * when the second one is empty and the first one
1538 if (remaining_capacity == 0)
1539 strcpy(last_battery_str[idx], "Empty");
1541 strcpy(last_battery_str[idx], "Charged");
1543 /* unknown, probably full / AC */
1545 if (acpi_last_full[idx] != 0
1546 && remaining_capacity != acpi_last_full[idx])
1547 snprintf(last_battery_str[idx], 64, "Unknown %d%%",
1548 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1550 strncpy(last_battery_str[idx], "AC", 64);
1552 } else if (acpi_bat_fp[idx] != NULL) {
1554 int present_rate = -1;
1555 int remaining_capacity = -1;
1556 char charging_state[64];
1559 /* read last full capacity if it's zero */
1560 if (acpi_last_full[idx] == 0) {
1565 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1566 fp = open_file(path, &rep);
1571 if (fgets(b, 256, fp) == NULL) {
1574 if (sscanf(b, "last full capacity: %d",
1575 &acpi_last_full[idx]) != 0) {
1584 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1586 strcpy(charging_state, "unknown");
1588 while (!feof(acpi_bat_fp[idx])) {
1591 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1595 /* let's just hope units are ok */
1596 if (strncmp(buf, "present:", 8) == 0) {
1597 sscanf(buf, "present: %4s", present);
1598 } else if (strncmp(buf, "charging state:", 15) == 0) {
1599 sscanf(buf, "charging state: %63s", charging_state);
1600 } else if (strncmp(buf, "present rate:", 13) == 0) {
1601 sscanf(buf, "present rate: %d", &present_rate);
1602 } else if (strncmp(buf, "remaining capacity:", 19) == 0) {
1603 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1606 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1607 if (remaining_capacity > acpi_last_full[idx]) {
1608 /* normalize to 100% */
1609 acpi_last_full[idx] = remaining_capacity;
1613 if (strcmp(present, "no") == 0) {
1614 strncpy(last_battery_str[idx], "not present", 64);
1616 } else if (strcmp(charging_state, "charging") == 0) {
1617 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1618 /* e.g. charging 75% */
1619 snprintf(last_battery_str[idx],
1620 sizeof(last_battery_str[idx]) - 1, "charging %i%%",
1621 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1623 format_seconds(last_battery_time_str[idx],
1624 sizeof(last_battery_time_str[idx]) - 1,
1625 (long) (((acpi_last_full[idx] - remaining_capacity) *
1626 3600) / present_rate));
1627 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1628 snprintf(last_battery_str[idx],
1629 sizeof(last_battery_str[idx]) - 1, "charging %d%%",
1630 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1632 strncpy(last_battery_str[idx], "charging",
1633 sizeof(last_battery_str[idx]) - 1);
1636 } else if (strncmp(charging_state, "discharging", 64) == 0) {
1637 if (present_rate > 0) {
1638 /* e.g. discharging 35% */
1639 snprintf(last_battery_str[idx],
1640 sizeof(last_battery_str[idx]) - 1, "discharging %i%%",
1641 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1643 format_seconds(last_battery_time_str[idx],
1644 sizeof(last_battery_time_str[idx]) - 1,
1645 (long) ((remaining_capacity * 3600) / present_rate));
1646 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1647 snprintf(last_battery_str[idx],
1648 sizeof(last_battery_str[idx]) - 1, "full");
1650 snprintf(last_battery_str[idx],
1651 sizeof(last_battery_str[idx]) - 1, "discharging %d%%",
1652 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1655 } else if (strncmp(charging_state, "charged", 64) == 0) {
1656 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1657 /* Below happens with the second battery on my X40,
1658 * when the second one is empty and the first one being charged. */
1659 if (remaining_capacity == 0) {
1660 strcpy(last_battery_str[idx], "empty");
1662 strcpy(last_battery_str[idx], "charged");
1664 /* unknown, probably full / AC */
1666 if (acpi_last_full[idx] != 0
1667 && remaining_capacity != acpi_last_full[idx]) {
1668 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1669 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1671 strncpy(last_battery_str[idx], "AC", 64);
1676 if (apm_bat_fp[idx] == NULL) {
1677 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1680 if (apm_bat_fp[idx] != NULL) {
1681 int ac, status, flag, life;
1683 fscanf(apm_bat_fp[idx], "%*s %*s %*x %x %x %x %d%%",
1684 &ac, &status, &flag, &life);
1687 /* could check now that there is ac */
1688 snprintf(last_battery_str[idx], 64, "AC");
1690 /* could check that status == 3 here? */
1691 } else if (ac && life != 100) {
1692 snprintf(last_battery_str[idx], 64, "charging %d%%", life);
1694 snprintf(last_battery_str[idx], 64, "%d%%", life);
1697 /* it seemed to buffer it so file must be closed (or could use
1698 * syscalls directly but I don't feel like coding it now) */
1699 fclose(apm_bat_fp[idx]);
1700 apm_bat_fp[idx] = NULL;
1706 case BATTERY_STATUS:
1707 snprintf(buf, n, "%s", last_battery_str[idx]);
1710 snprintf(buf, n, "%s", last_battery_time_str[idx]);
1717 int get_battery_perct(const char *bat)
1721 char acpi_path[128];
1723 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1724 char sysfs_path[128];
1725 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1729 idx = get_battery_idx(bat);
1731 /* don't update battery too often */
1732 if (current_update_time - last_battery_perct_time[idx] < 30) {
1733 return last_battery_perct[idx];
1735 last_battery_perct_time[idx] = current_update_time;
1737 /* Only check for SYSFS or ACPI */
1739 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1740 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1742 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1743 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1745 int remaining_capacity = -1;
1747 if (sysfs_bat_fp[idx] != NULL) {
1749 while (!feof(sysfs_bat_fp[idx])) {
1751 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1754 if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0)
1755 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1756 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=",25) != 0)
1757 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_last_full[idx]);
1758 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0)
1759 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1760 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=",25) != 0)
1761 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_last_full[idx]);
1764 fclose(sysfs_bat_fp[idx]);
1765 sysfs_bat_fp[idx] = NULL;
1767 } else if (acpi_bat_fp[idx] != NULL) {
1769 /* read last full capacity if it's zero */
1770 if (acpi_design_capacity[idx] == 0) {
1775 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1776 fp = open_file(path, &rep);
1781 if (fgets(b, 256, fp) == NULL) {
1784 if (sscanf(b, "last full capacity: %d",
1785 &acpi_design_capacity[idx]) != 0) {
1793 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1795 while (!feof(acpi_bat_fp[idx])) {
1798 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1802 if (buf[0] == 'r') {
1803 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1807 if (remaining_capacity < 0) {
1810 /* compute the battery percentage */
1811 last_battery_perct[idx] =
1812 (int) (((float) remaining_capacity / acpi_design_capacity[idx]) * 100);
1813 return last_battery_perct[idx];
1816 int get_battery_perct_bar(const char *bar)
1820 get_battery_perct(bar);
1821 idx = get_battery_idx(bar);
1822 return (int) (last_battery_perct[idx] * 2.56 - 1);
1825 /* On Apple powerbook and ibook:
1826 $ cat /proc/pmu/battery_0
1833 $ cat /proc/pmu/info
1834 PMU driver version : 2
1835 PMU firmware version : 0c
1840 /* defines as in <linux/pmu.h> */
1841 #define PMU_BATT_PRESENT 0x00000001
1842 #define PMU_BATT_CHARGING 0x00000002
1844 static FILE *pmu_battery_fp;
1845 static FILE *pmu_info_fp;
1846 static char pb_battery_info[3][32];
1847 static double pb_battery_info_update;
1849 #define PMU_PATH "/proc/pmu"
1850 void get_powerbook_batt_info(char *buf, size_t n, int i)
1853 const char *batt_path = PMU_PATH "/battery_0";
1854 const char *info_path = PMU_PATH "/info";
1855 int flags, charge, max_charge, ac = -1;
1858 /* don't update battery too often */
1859 if (current_update_time - pb_battery_info_update < 29.5) {
1860 snprintf(buf, n, "%s", pb_battery_info[i]);
1863 pb_battery_info_update = current_update_time;
1865 if (pmu_battery_fp == NULL) {
1866 pmu_battery_fp = open_file(batt_path, &rep);
1869 if (pmu_battery_fp != NULL) {
1870 rewind(pmu_battery_fp);
1871 while (!feof(pmu_battery_fp)) {
1874 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL) {
1878 if (buf[0] == 'f') {
1879 sscanf(buf, "flags : %8x", &flags);
1880 } else if (buf[0] == 'c' && buf[1] == 'h') {
1881 sscanf(buf, "charge : %d", &charge);
1882 } else if (buf[0] == 'm') {
1883 sscanf(buf, "max_charge : %d", &max_charge);
1884 } else if (buf[0] == 't') {
1885 sscanf(buf, "time rem. : %ld", &time);
1889 if (pmu_info_fp == NULL) {
1890 pmu_info_fp = open_file(info_path, &rep);
1893 if (pmu_info_fp != NULL) {
1894 rewind(pmu_info_fp);
1895 while (!feof(pmu_info_fp)) {
1898 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL) {
1901 if (buf[0] == 'A') {
1902 sscanf(buf, "AC Power : %d", &ac);
1906 /* update status string */
1907 if ((ac && !(flags & PMU_BATT_PRESENT))) {
1908 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
1909 } else if (ac && (flags & PMU_BATT_PRESENT)
1910 && !(flags & PMU_BATT_CHARGING)) {
1911 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
1912 } else if ((flags & PMU_BATT_PRESENT) && (flags & PMU_BATT_CHARGING)) {
1913 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
1915 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
1918 /* update percentage string */
1920 pb_battery_info[PB_BATT_PERCENT][0] = 0;
1922 snprintf(pb_battery_info[PB_BATT_PERCENT],
1923 sizeof(pb_battery_info[PB_BATT_PERCENT]), "%d%%",
1924 (charge * 100) / max_charge);
1927 /* update time string */
1928 if (time == 0) { /* fully charged or battery not present */
1929 pb_battery_info[PB_BATT_TIME][0] = 0;
1930 } else if (time < 60 * 60) { /* don't show secs */
1931 format_seconds_short(pb_battery_info[PB_BATT_TIME],
1932 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1934 format_seconds(pb_battery_info[PB_BATT_TIME],
1935 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1938 snprintf(buf, n, "%s", pb_battery_info[i]);
1943 show_nice_processes = 1;
1944 process_find_top(info.cpu, info.memu);
1945 info.first_process = get_first_process();
1948 /* The following ifdefs were adapted from gkrellm */
1949 #include <linux/major.h>
1951 #if !defined(MD_MAJOR)
1955 #if !defined(LVM_BLK_MAJOR)
1956 #define LVM_BLK_MAJOR 58
1959 #if !defined(NBD_MAJOR)
1960 #define NBD_MAJOR 43
1963 void update_diskio()
1965 static unsigned int last = UINT_MAX;
1966 static unsigned int last_read = UINT_MAX;
1967 static unsigned int last_write = UINT_MAX;
1971 char buf[512], devbuf[64];
1972 int major, minor, i;
1973 unsigned int current = 0;
1974 unsigned int current_read = 0;
1975 unsigned int current_write = 0;
1976 unsigned int reads, writes = 0;
1979 if (!(fp = open_file("/proc/diskstats", &rep))) {
1984 /* read reads and writes from all disks (minor = 0), including cd-roms
1985 * and floppies, and sum them up */
1987 fgets(buf, 512, fp);
1988 col_count = sscanf(buf, "%u %u %s %*u %*u %u %*u %*u %*u %u", &major,
1989 &minor, devbuf, &reads, &writes);
1990 /* ignore subdevices (they have only 3 matching entries in their line)
1991 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
1993 * XXX: ignore devices which are part of a SW RAID (MD_MAJOR) */
1994 if (col_count == 5 && major != LVM_BLK_MAJOR && major != NBD_MAJOR
1995 && major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
1996 current += reads + writes;
1997 current_read += reads;
1998 current_write += writes;
2000 col_count = sscanf(buf, "%u %u %s %*u %u %*u %u",
2001 &major, &minor, devbuf, &reads, &writes);
2002 if (col_count != 5) {
2006 for (i = 0; i < MAX_DISKIO_STATS; i++) {
2007 if (diskio_stats[i].dev &&
2008 strcmp(devbuf, diskio_stats[i].dev) == 0) {
2009 diskio_stats[i].current =
2010 (reads + writes - diskio_stats[i].last) / 2;
2011 diskio_stats[i].current_read =
2012 (reads - diskio_stats[i].last_read) / 2;
2013 diskio_stats[i].current_write =
2014 (writes - diskio_stats[i].last_write) / 2;
2015 if (reads + writes < diskio_stats[i].last) {
2016 diskio_stats[i].current = 0;
2018 if (reads < diskio_stats[i].last_read) {
2019 diskio_stats[i].current_read = 0;
2020 diskio_stats[i].current = diskio_stats[i].current_write;
2022 if (writes < diskio_stats[i].last_write) {
2023 diskio_stats[i].current_write = 0;
2024 diskio_stats[i].current = diskio_stats[i].current_read;
2026 diskio_stats[i].last = reads + writes;
2027 diskio_stats[i].last_read = reads;
2028 diskio_stats[i].last_write = writes;
2033 /* since the values in /proc/diststats are absolute, we have to substract
2034 * our last reading. The numbers stand for "sectors read", and we therefore
2035 * have to divide by two to get KB */
2036 int tot = ((double) (current - last) / 2);
2037 int tot_read = ((double) (current_read - last_read) / 2);
2038 int tot_write = ((double) (current_write - last_write) / 2);
2040 if (last_read > current_read) {
2043 if (last_write > current_write) {
2047 if (last > current) {
2048 /* we hit this either if it's the very first time we run this, or
2049 * when /proc/diskstats overflows; while 0 is not correct, it's at
2050 * least not way off */
2054 last_read = current_read;
2055 last_write = current_write;
2058 diskio_read_value = tot_read;
2059 diskio_write_value = tot_write;
2064 /* Here come the IBM ACPI-specific things. For reference, see
2065 * http://ibm-acpi.sourceforge.net/README
2066 * If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
2082 * The content of these files is described in detail in the aforementioned
2083 * README - some of them also in the following functions accessing them.
2084 * Peter Tarjan (ptarjan@citromail.hu) */
2086 #define IBM_ACPI_DIR "/proc/acpi/ibm"
2088 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
2089 * /proc/acpi/ibm/fan looks like this (3 lines):
2092 commands: enable, disable
2093 * Peter Tarjan (ptarjan@citromail.hu) */
2095 void get_ibm_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
2097 if (!p_client_buffer || client_buffer_size <= 0) {
2102 unsigned int speed = 0;
2105 snprintf(fan, 127, "%s/fan", IBM_ACPI_DIR);
2107 fp = fopen(fan, "r");
2112 if (fgets(line, 255, fp) == NULL) {
2115 if (sscanf(line, "speed: %d", &speed)) {
2120 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2121 "ibm* from your Conky config file.", fan, strerror(errno));
2125 snprintf(p_client_buffer, client_buffer_size, "%d", speed);
2128 /* get the measured temperatures from the temperature sensors
2129 * on IBM/Lenovo laptops running the ibm acpi.
2130 * There are 8 values in /proc/acpi/ibm/thermal, and according to
2131 * http://ibm-acpi.sourceforge.net/README
2132 * these mean the following (at least on an IBM R51...)
2133 * 0: CPU (also on the T series laptops)
2134 * 1: Mini PCI Module (?)
2136 * 3: GPU (also on the T series laptops)
2141 * I'm not too sure about those with the question mark, but the values I'm
2142 * reading from *my* thermal file (on a T42p) look realistic for the
2143 * hdd and the battery.
2144 * #5 and #7 are always -128.
2145 * /proc/acpi/ibm/thermal looks like this (1 line):
2146 temperatures: 41 43 31 46 33 -128 29 -128
2147 * Peter Tarjan (ptarjan@citromail.hu) */
2149 static double last_ibm_acpi_temp_time;
2150 void get_ibm_acpi_temps()
2153 /* don't update too often */
2154 if (current_update_time - last_ibm_acpi_temp_time < 10.00) {
2157 last_ibm_acpi_temp_time = current_update_time;
2159 /* if (!p_client_buffer || client_buffer_size <= 0) {
2167 snprintf(thermal, 127, "%s/thermal", IBM_ACPI_DIR);
2168 fp = fopen(thermal, "r");
2174 if (fgets(line, 255, fp) == NULL) {
2177 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
2178 &ibm_acpi.temps[0], &ibm_acpi.temps[1], &ibm_acpi.temps[2],
2179 &ibm_acpi.temps[3], &ibm_acpi.temps[4], &ibm_acpi.temps[5],
2180 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) {
2185 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2186 "ibm* from your Conky config file.", thermal, strerror(errno));
2192 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
2193 * "Volume" here is none of the mixer volumes, but a "master of masters"
2194 * volume adjusted by the IBM volume keys.
2195 * /proc/acpi/ibm/fan looks like this (4 lines):
2198 commands: up, down, mute
2199 commands: level <level> (<level> is 0-15)
2200 * Peter Tarjan (ptarjan@citromail.hu) */
2202 void get_ibm_acpi_volume(char *p_client_buffer, size_t client_buffer_size)
2204 if (!p_client_buffer || client_buffer_size <= 0) {
2212 snprintf(volume, 127, "%s/volume", IBM_ACPI_DIR);
2213 unsigned int vol = -1;
2216 fp = fopen(volume, "r");
2220 unsigned int read_vol = -1;
2222 if (fgets(line, 255, fp) == NULL) {
2225 if (sscanf(line, "level: %d", &read_vol)) {
2229 if (sscanf(line, "mute: %s", mute)) {
2234 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2235 "ibm* from your Conky config file.", volume, strerror(errno));
2240 if (strcmp(mute, "on") == 0) {
2241 snprintf(p_client_buffer, client_buffer_size, "%s", "mute");
2244 snprintf(p_client_buffer, client_buffer_size, "%d", vol);
2249 /* static FILE *fp = NULL; */
2251 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
2252 * /proc/acpi/ibm/brightness looks like this (3 lines):
2255 commands: level <level> (<level> is 0-7)
2256 * Peter Tarjan (ptarjan@citromail.hu) */
2258 void get_ibm_acpi_brightness(char *p_client_buffer, size_t client_buffer_size)
2260 if (!p_client_buffer || client_buffer_size <= 0) {
2265 unsigned int brightness = 0;
2268 snprintf(filename, 127, "%s/brightness", IBM_ACPI_DIR);
2270 fp = fopen(filename, "r");
2275 if (fgets(line, 255, fp) == NULL) {
2278 if (sscanf(line, "level: %d", &brightness)) {
2283 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2284 "ibm* from your Conky config file.", filename, strerror(errno));
2289 snprintf(p_client_buffer, client_buffer_size, "%d", brightness);
2292 void update_entropy(void)
2295 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
2296 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
2299 info.entropy.entropy_avail = 0;
2300 info.entropy.poolsize = 0;
2302 if ((fp1 = open_file(entropy_avail, &rep)) == NULL) {
2306 if ((fp2 = open_file(entropy_poolsize, &rep)) == NULL) {
2311 fscanf(fp1, "%u", &info.entropy.entropy_avail);
2312 fscanf(fp2, "%u", &info.entropy.poolsize);
2317 info.mask |= (1 << INFO_ENTROPY);