2 * Conky, a system monitor, based on torsmo
4 * Any original torsmo code is licensed under the BSD license
6 * All code written since the fork of torsmo is licensed under the GPL
8 * Please see COPYING for details
10 * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
11 * Copyright (c) 2007 Toni Spets
12 * Copyright (c) 2005-2007 Brenden Matthews, Philip Kovacs, et. al. (see AUTHORS)
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/>.
38 #include <sys/types.h>
39 #include <sys/sysinfo.h>
41 #ifndef HAVE_CLOCK_GETTIME
46 // #include <assert.h>
50 #include <sys/ioctl.h>
51 #include <sys/socket.h>
52 #include <netinet/in.h>
53 #include <linux/sockios.h>
61 #define SHORTSTAT_TEMPL "%*s %llu %llu %llu"
62 #define LONGSTAT_TEMPL "%*s %llu %llu %llu "
64 static int show_nice_processes;
66 /* this flags tells the linux routines to use the /proc system
67 * where possible, even if other api's are available, e.g. sysinfo()
68 * or getloadavg(). the reason for this is to allow for /proc-based
69 * distributed monitoring. using a flag in this manner creates less
72 static int prefer_proc = 0;
83 struct sysinfo s_info;
85 info.uptime = (double) s_info.uptime;
93 if (!(fp = open_file("/proc/uptime", &rep)))
98 fscanf(fp, "%lf", &info.uptime);
101 info.mask |= (1 << INFO_UPTIME);
104 int check_mount(char *s)
107 FILE *mtab = fopen("/etc/mtab", "r");
109 char buf1[256], buf2[128];
110 while (fgets(buf1, 256, mtab)) {
111 sscanf(buf1, "%*s %128s", buf2);
112 if (!strcmp(s, buf2)) {
119 ERR("Could not open mtab");
124 /* these things are also in sysinfo except Buffers:, that's why I'm reading
127 void update_meminfo()
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)))
140 while (!feof(meminfo_fp)) {
141 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 inline void update_net_stats()
173 // FIXME: arbitrary size chosen to keep code simple.
175 unsigned int curtmp1, curtmp2;
182 // wireless info variables
183 int skfd, has_bitrate = 0;
184 struct wireless_info *winfo;
189 delta = current_update_time - last_update_time;
193 /* open file and ignore first two lines */
194 if (!(net_dev_fp = open_file("/proc/net/dev", &rep)))
200 fgets(buf, 255, net_dev_fp); /* garbage */
201 fgets(buf, 255, net_dev_fp); /* garbage (field names) */
203 /* read each interface */
204 for (i2 = 0; i2 < 16; i2++) {
207 long long r, t, last_recv, last_trans;
209 if (fgets(buf, 255, net_dev_fp) == NULL) {
213 while (isspace((int) *p))
218 while (*p && *p != ':')
225 ns = get_net_stat(s);
227 memset(&(ns->addr.sa_data), 0, 14);
228 last_recv = ns->recv;
229 last_trans = ns->trans;
232 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
233 "%Ld %*d %*d %*d %*d %*d %*d %*d %Ld",
236 /* if recv or trans is less than last time, an overflow happened */
238 if (r < ns->last_read_recv)
241 ns->recv += (r - ns->last_read_recv);
242 ns->last_read_recv = r;
244 if (t < ns->last_read_trans)
247 ns->trans += (t - ns->last_read_trans);
248 ns->last_read_trans = t;
250 /*** ip addr patch ***/
251 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
253 conf.ifc_buf = malloc(sizeof(struct ifreq) * 16);
255 conf.ifc_len = sizeof(struct ifreq) * 16;
257 ioctl((long) i, SIOCGIFCONF, &conf);
259 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
261 ns = get_net_stat(((struct ifreq *) conf.
262 ifc_buf)[k].ifr_ifrn.ifrn_name);
264 ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.
273 /*** end ip addr patch ***/
276 /* calculate speeds */
277 ns->net_rec[0] = (ns->recv - last_recv) / delta;
278 ns->net_trans[0] = (ns->trans - last_trans) / delta;
282 for (i = 0; (unsigned) i < info.net_avg_samples; i++) {
283 curtmp1 += ns->net_rec[i];
284 curtmp2 += ns->net_trans[i];
286 if (curtmp1 == 0) curtmp1 = 1;
287 if (curtmp2 == 0) curtmp2 = 1;
288 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
289 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
290 if (info.net_avg_samples > 1) {
291 for (i = info.net_avg_samples; i > 1; i--) {
292 ns->net_rec[i - 1] = ns->net_rec[i - 2];
293 ns->net_trans[i - 1] =
294 ns->net_trans[i - 2];
299 /* update wireless info */
300 winfo = malloc(sizeof(struct wireless_info));
301 memset(winfo, 0, sizeof(struct wireless_info));
303 skfd = iw_sockets_open();
304 if(iw_get_basic_config(skfd, s, &(winfo->b)) > -1) {
306 // set present winfo variables
307 if(iw_get_stats(skfd, s, &(winfo->stats), &winfo->range, winfo->has_range) >= 0)
308 winfo->has_stats = 1;
309 if(iw_get_range_info(skfd, s, &(winfo->range)) >= 0)
310 winfo->has_range = 1;
311 if(iw_get_ext(skfd, s, SIOCGIWAP, &wrq) >= 0) {
312 winfo->has_ap_addr = 1;
313 memcpy(&(winfo->ap_addr), &(wrq.u.ap_addr), sizeof (sockaddr));
317 if(iw_get_ext(skfd, s, SIOCGIWRATE, &wrq) >= 0) {
318 memcpy(&(winfo->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
319 iw_print_bitrate(ns->bitrate, 16, winfo->bitrate.value);
324 if(winfo->has_range && winfo->has_stats && ((winfo->stats.qual.level != 0) || (winfo->stats.qual.updated & IW_QUAL_DBM))) {
325 if(!(winfo->stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
326 ns->link_qual = winfo->stats.qual.qual;
327 ns->link_qual_max = winfo->range.max_qual.qual;
332 if(winfo->has_ap_addr) {
333 iw_sawap_ntop(&winfo->ap_addr, ns->ap);
337 if(winfo->b.has_essid) {
338 if(winfo->b.essid_on)
339 snprintf(ns->essid, 32, "%s", winfo->b.essid);
341 snprintf(ns->essid, 32, "off/any");
344 snprintf(ns->mode, 16, "%s", iw_operation_mode[winfo->b.mode]);
346 iw_sockets_close(skfd);
353 info.mask |= (1 << INFO_NET);
358 void update_total_processes()
363 struct sysinfo s_info;
365 info.procs = s_info.procs;
373 if (!(fp = open_file("/proc/loadavg", &rep)))
378 fscanf(fp, "%*f %*f %*f %*d/%hd", &info.procs );
381 info.mask |= (1 << INFO_PROCS);
384 #define CPU_SAMPLE_COUNT 15
386 unsigned long long cpu_user;
387 unsigned long long cpu_system;
388 unsigned long long cpu_nice;
389 unsigned long long cpu_idle;
390 unsigned long long cpu_iowait;
391 unsigned long long cpu_irq;
392 unsigned long long cpu_softirq;
393 unsigned long long cpu_steal;
394 unsigned long long cpu_total;
395 unsigned long long cpu_active_total;
396 unsigned long long cpu_last_total;
397 unsigned long long cpu_last_active_total;
398 double cpu_val[CPU_SAMPLE_COUNT];
400 static short cpu_setup = 0;
403 determine if this kernel gives us "extended" statistics information in /proc/stat.
404 Kernels around 2.5 and earlier only reported user, system, nice and idle values in proc stat.
405 Kernels around 2.6 and greater report these PLUS iowait, irq, softirq, and steal
407 void determine_longstat(char * buf) {
408 unsigned long long iowait=0;
409 KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
410 /* scanf will either return -1 or 1 because there is only 1 assignment */
411 if (sscanf(buf, "%*s %*d %*d %*d %*d %llu",&iowait)>0) KFLAG_SETON(KFLAG_IS_LONGSTAT);
419 if (info.cpu_usage) {
424 if (!(stat_fp = open_file("/proc/stat", &rep)))
429 while (!feof(stat_fp)) {
430 if (fgets(buf, 255, stat_fp) == NULL)
433 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
434 if (info.cpu_count == 0) {
435 determine_longstat(buf);
440 info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
445 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
446 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
448 inline static void update_stat()
452 static struct cpu_info *cpu = NULL;
457 char * stat_template=NULL;
458 unsigned int malloc_cpu_size=0;
461 /* add check for !info.cpu_usage since that mem is freed on a SIGUSR1 */
462 if (!cpu_setup || !info.cpu_usage) {
467 if (!stat_template) {
468 stat_template = KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT ;
472 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
473 cpu = malloc(malloc_cpu_size);
474 memset(cpu, 0, malloc_cpu_size);
477 if (!(stat_fp = open_file("/proc/stat", &rep)))
482 memset(info.cpu_usage, 0, info.cpu_count * sizeof (float));
488 while (!feof(stat_fp)) {
489 if (fgets(buf, 255, stat_fp) == NULL)
492 if (strncmp(buf, "procs_running ", 14) == 0) {
493 sscanf(buf, "%*s %hu", &info.run_procs);
494 info.mask |= (1 << INFO_RUN_PROCS);
495 } else if (strncmp(buf, "cpu", 3) == 0) {
496 index = isdigit(buf[3]) ? ((int)buf[3]) - 0x2F : 0;
497 sscanf(buf, stat_template
498 , &(cpu[index].cpu_user)
499 , &(cpu[index].cpu_nice)
500 , &(cpu[index].cpu_system)
501 , &(cpu[index].cpu_idle)
502 , &(cpu[index].cpu_iowait)
503 , &(cpu[index].cpu_irq)
504 , &(cpu[index].cpu_softirq)
505 , &(cpu[index].cpu_steal)
508 cpu[index].cpu_total = cpu[index].cpu_user
509 + cpu[index].cpu_nice
510 + cpu[index].cpu_system
511 + cpu[index].cpu_idle
512 + cpu[index].cpu_iowait
514 + cpu[index].cpu_softirq
515 + cpu[index].cpu_steal
518 cpu[index].cpu_active_total = cpu[index].cpu_total - (cpu[index].cpu_idle + cpu[index].cpu_iowait);
519 info.mask |= (1 << INFO_CPU);
521 double delta = current_update_time - last_update_time;
522 if (delta <= 0.001) break;
524 cpu[index].cpu_val[0] = (cpu[index].cpu_active_total - cpu[index].cpu_last_active_total) /
525 (float )(cpu[index].cpu_total - cpu[index].cpu_last_total);
527 for (i=0; i < info.cpu_avg_samples; i++ ) {
528 curtmp += cpu[index].cpu_val[i];
530 /* TESTING -- I've removed this, because I don't think it is right. You shouldn't divide
531 by the cpu count here ... removing for testing */
533 info.cpu_usage[index] = curtmp / info.cpu_avg_samples / info.cpu_count;
535 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
537 /* TESTING -- this line replaces the prev. "suspect" if/else */
538 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
540 cpu[index].cpu_last_total = cpu[index].cpu_total;
541 cpu[index].cpu_last_active_total = cpu[index].cpu_active_total;
542 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
543 cpu[index].cpu_val[i] = cpu[index].cpu_val[i - 1];
551 void update_running_processes()
556 void update_cpu_usage()
561 void update_load_average()
563 #ifdef HAVE_GETLOADAVG
568 info.loadavg[0] = (float) v[0];
569 info.loadavg[1] = (float) v[1];
570 info.loadavg[2] = (float) v[2];
578 if (!(fp = open_file("/proc/loadavg", &rep)))
580 info.loadavg[0] = info.loadavg[1] = info.loadavg[2] = 0.0;
583 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1], &info.loadavg[2]);
586 info.mask |= (1 << INFO_LOADAVG);
589 #define PROC_I8K "/proc/i8k"
590 #define I8K_DELIM " "
591 static char *i8k_procbuf = NULL;
596 i8k_procbuf = (char*)malloc(128*sizeof(char));
598 if ((fp = fopen(PROC_I8K,"r")) == NULL) {
599 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel driver is loaded...");
602 memset(&i8k_procbuf[0],0,128);
603 if (fread(&i8k_procbuf[0],sizeof(char),128,fp) == 0) {
604 ERR("something wrong with /proc/i8k...");
609 i8k.version = strtok(&i8k_procbuf[0],I8K_DELIM);
610 i8k.bios = strtok(NULL,I8K_DELIM);
611 i8k.serial = strtok(NULL,I8K_DELIM);
612 i8k.cpu_temp = strtok(NULL,I8K_DELIM);
613 i8k.left_fan_status = strtok(NULL,I8K_DELIM);
614 i8k.right_fan_status = strtok(NULL,I8K_DELIM);
615 i8k.left_fan_rpm = strtok(NULL,I8K_DELIM);
616 i8k.right_fan_rpm = strtok(NULL,I8K_DELIM);
617 i8k.ac_status = strtok(NULL,I8K_DELIM);
618 i8k.buttons_status = strtok(NULL,I8K_DELIM);
622 /***********************************************************/
623 /***********************************************************/
624 /***********************************************************/
626 static int no_dots(const struct dirent *d)
628 if (d->d_name[0] == '.')
634 get_first_file_in_a_directory(const char *dir, char *s, int *rep)
636 struct dirent **namelist;
639 n = scandir(dir, &namelist, no_dots, alphasort);
642 ERR("scandir for %s: %s", dir, strerror(errno));
651 strncpy(s, namelist[0]->d_name, 255);
654 for (i = 0; i < n; i++)
662 int open_i2c_sensor(const char *dev, const char *type, int n, int *div, char *devtype)
665 if (post_21_kernel) {
666 strncpy(i2c_dir, "/sys/bus/platform/devices/", 64);
668 strncpy(i2c_dir, "/sys/bus/i2c/devices/", 64);
675 /* if i2c device is NULL or *, get first */
676 if (dev == NULL || strcmp(dev, "*") == 0) {
678 if (!get_first_file_in_a_directory(i2c_dir, buf, &rep))
683 /* change vol to in */
684 if (strcmp(type, "vol") == 0)
687 if (strcmp(type, "tempf") == 0) {
688 snprintf(path, 255, "%s%s/%s%d_input", i2c_dir, dev, "temp", n);
690 snprintf(path, 255, "%s%s/%s%d_input", i2c_dir, dev, type, n);
692 strncpy(devtype, path, 255);
695 fd = open(path, O_RDONLY);
697 CRIT_ERR("can't open '%s': %s\nplease fix i2c or remove it from Conky", path, strerror(errno));
700 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
701 || strcmp(type, "tempf") == 0)
705 /* fan does not use *_div as a read divisor */
706 if (strcmp("fan", type) == 0)
709 /* test if *_div file exist, open it and use it as divisor */
710 if (strcmp(type, "tempf") == 0) {
711 snprintf(path, 255, "%s%s/%s%d_div", i2c_dir, "one", "two",
714 snprintf(path, 255, "%s%s/%s%d_div", i2c_dir, dev, type, n);
717 divfd = open(path, O_RDONLY);
722 divn = read(divfd, divbuf, 63);
723 /* should read until n == 0 but I doubt that kernel will give these
724 * in multiple pieces. :) */
734 double get_i2c_info(int *fd, int div, char *devtype, char *type)
741 lseek(*fd, 0, SEEK_SET);
747 n = read(*fd, buf, 63);
748 /* should read until n == 0 but I doubt that kernel will give these
749 * in multiple pieces. :) */
756 *fd = open(devtype, O_RDONLY);
758 ERR("can't open '%s': %s", devtype, strerror(errno));
760 /* My dirty hack for computing CPU value
761 * Filedil, from forums.gentoo.org
763 /* if (strstr(devtype, "temp1_input") != NULL)
764 return -15.096+1.4893*(val / 1000.0); */
767 /* divide voltage and temperature by 1000 */
768 /* or if any other divisor is given, use that */
769 if (strcmp(type, "tempf") == 0) {
771 return ((val / div + 40) * 9.0 / 5) - 40;
773 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
775 return ((val + 40) * 9.0 / 5) - 40;
786 /* Prior to kernel version 2.6.12, the CPU fan speed was available
787 * in ADT746X_FAN_OLD, whereas later kernel versions provide this
788 * information in ADT746X_FAN.
790 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
791 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
793 void get_adt746x_fan( char * p_client_buffer, size_t client_buffer_size )
796 char adt746x_fan_state[64];
799 if ( !p_client_buffer || client_buffer_size <= 0 )
802 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
803 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL)
806 sprintf(adt746x_fan_state, "adt746x not found");
810 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
811 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
815 snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_fan_state );
819 /* Prior to kernel version 2.6.12, the CPU temperature was found
820 * in ADT746X_CPU_OLD, whereas later kernel versions provide this
821 * information in ADT746X_CPU.
823 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
824 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
826 void get_adt746x_cpu( char * p_client_buffer, size_t client_buffer_size )
829 char adt746x_cpu_state[64];
832 if ( !p_client_buffer || client_buffer_size <= 0 )
835 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
836 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL)
838 sprintf(adt746x_cpu_state, "adt746x not found");
842 fscanf(fp, "%2s", adt746x_cpu_state);
846 snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state );
850 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
852 /***********************************************************************/
854 * This file is part of x86info.
855 * (C) 2001 Dave Jones.
857 * Licensed under the terms of the GNU GPL License version 2.
859 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
860 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz>
863 #if defined(__i386) || defined(__x86_64)
864 __inline__ unsigned long long int rdtsc()
866 unsigned long long int x;
867 __asm__ volatile (".byte 0x0f, 0x31":"=A" (x));
872 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
873 void get_freq_dynamic( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor )
875 #if defined(__i386) || defined(__x86_64)
877 struct timeval tvstart, tvstop;
878 unsigned long long cycles[2]; /* gotta be 64 bit */
879 unsigned int microseconds; /* total time taken */
881 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
884 memset(&tz, 0, sizeof(tz));
886 /* get this function in cached memory */
887 gettimeofday(&tvstart, &tz);
889 gettimeofday(&tvstart, &tz);
891 /* we don't trust that this is any specific length of time */
894 gettimeofday(&tvstop, &tz);
895 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
896 (tvstop.tv_usec - tvstart.tv_usec);
898 snprintf( p_client_buffer, client_buffer_size, p_format, (float)((cycles[1] - cycles[0]) / microseconds) / divisor );
901 /* FIXME: hardwired: get freq for first cpu!
902 this whole function needs to be rethought and redone for
903 multi-cpu/multi-core/multi-threaded environments and
904 arbitrary combinations thereof
906 get_freq( p_client_buffer, client_buffer_size, p_format, divisor, 1 );
912 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
913 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
915 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
916 char get_freq( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
924 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
929 char current_freq_file[128];
930 snprintf(current_freq_file, 127, "%s/cpu%d/%s",CPUFREQ_PREFIX, cpu-1, CPUFREQ_POSTFIX);
931 f = fopen(current_freq_file, "r");
934 /* if there's a cpufreq /sys node, read the current frequency from this node;
935 * divide by 1000 to get Mhz. */
936 if (fgets(s, sizeof(s), f)) {
937 s[strlen(s)-1] = '\0';
938 freq = strtod(s, NULL);
941 snprintf( p_client_buffer, client_buffer_size, p_format, (freq/1000)/divisor );
946 f = open_file("/proc/cpuinfo", &rep); //open the CPU information file
948 perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
952 while (fgets(s, sizeof(s), f) != NULL){ //read the file
954 #if defined(__i386) || defined(__x86_64)
955 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) { //and search for the cpu mhz
958 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) { // different on alpha
960 if (strncmp(s, "clock", 5) == 0 && cpu == 0) { // this is different on ppc for some reason
961 #endif // defined(__alpha)
962 #endif // defined(__i386) || defined(__x86_64)
964 strcpy(frequency, strchr(s, ':') + 2); //copy just the number
966 frequency[strlen(frequency) - 6] = '\0';// strip " est.\n"
967 freq = strtod(frequency, NULL)/1000000; // kernel reports in Hz
969 frequency[strlen(frequency) - 1] = '\0'; // strip \n
970 freq = strtod(frequency, NULL);
974 if (strncmp(s, "processor", 9) == 0) {
982 snprintf( p_client_buffer, client_buffer_size, p_format, (float)freq/divisor );
986 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
988 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
989 char get_voltage( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
991 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks
1003 /* Peter Tarjan (ptarjan@citromail.hu) */
1008 char current_freq_file[128];
1012 /* build the voltage file name */
1014 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
1015 CPUFREQ_PREFIX, cpu, CPUFREQ_POSTFIX);
1017 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
1020 /* read the current cpu frequency from the /sys node */
1021 f = fopen(current_freq_file, "r");
1023 if (fgets(s, sizeof(s), f)) {
1024 s[strlen(s)-1] = '\0';
1025 freq = strtod(s, NULL);
1029 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1030 perror("get_voltage()");
1037 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
1038 CPUFREQ_PREFIX, cpu, CPUFREQ_VOLTAGE);
1040 /* use the current cpu frequency to find the corresponding voltage */
1041 f = fopen(current_freq_file, "r");
1046 if (fgets(line, 255, f) == NULL) break;
1047 sscanf(line, "%d %d", &freq_comp, &voltage);
1048 if(freq_comp == freq) break;
1052 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1053 perror("get_voltage()");
1059 snprintf( p_client_buffer, client_buffer_size, p_format, (float)voltage/divisor );
1064 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1066 void get_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1073 if ( !p_client_buffer || client_buffer_size <= 0 )
1076 /* yeah, slow... :/ */
1077 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep))
1079 snprintf( p_client_buffer, client_buffer_size, "no fans?" );
1083 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf );
1085 fp = open_file(buf2, &rep);
1087 snprintf( p_client_buffer, client_buffer_size, "can't open fan's state file" );
1090 memset(buf,0,sizeof(buf));
1091 fscanf(fp, "%*s %99s", buf);
1094 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1099 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1101 void get_acpi_ac_adapter( char * p_client_buffer, size_t client_buffer_size )
1108 if ( !p_client_buffer || client_buffer_size <= 0 )
1111 /* yeah, slow... :/ */
1112 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep))
1114 snprintf( p_client_buffer, client_buffer_size, "no ac_adapters?" );
1118 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf );
1121 fp = open_file(buf2, &rep);
1123 snprintf( p_client_buffer, client_buffer_size, "No ac adapter found.... where is it?" );
1126 memset(buf,0,sizeof(buf));
1127 fscanf(fp, "%*s %99s", buf );
1130 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1136 /proc/acpi/thermal_zone/THRM/cooling_mode
1137 cooling mode: active
1138 /proc/acpi/thermal_zone/THRM/polling_frequency
1140 /proc/acpi/thermal_zone/THRM/state
1142 /proc/acpi/thermal_zone/THRM/temperature
1144 /proc/acpi/thermal_zone/THRM/trip_points
1146 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1149 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1150 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1152 int open_acpi_temperature(const char *name)
1158 if (name == NULL || strcmp(name, "*") == 0) {
1160 if (!get_first_file_in_a_directory
1161 (ACPI_THERMAL_DIR, buf, &rep))
1166 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1168 fd = open(path, O_RDONLY);
1170 ERR("can't open '%s': %s", path, strerror(errno));
1175 static double last_acpi_temp;
1176 static double last_acpi_temp_time;
1178 double get_acpi_temperature(int fd)
1183 /* don't update acpi temperature too often */
1184 if (current_update_time - last_acpi_temp_time < 11.32) {
1185 return last_acpi_temp;
1187 last_acpi_temp_time = current_update_time;
1189 /* seek to beginning */
1190 lseek(fd, 0, SEEK_SET);
1196 n = read(fd, buf, 255);
1198 ERR("can't read fd %d: %s", fd, strerror(errno));
1201 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1205 return last_acpi_temp;
1209 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1211 design capacity: 4400 mAh
1212 last full capacity: 4064 mAh
1213 battery technology: rechargeable
1214 design voltage: 14800 mV
1215 design capacity warning: 300 mAh
1216 design capacity low: 200 mAh
1217 capacity granularity 1: 32 mAh
1218 capacity granularity 2: 32 mAh
1220 serial number: 16922
1226 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1229 charging state: unknown
1231 remaining capacity: 4064 mAh
1232 present voltage: 16608 mV
1236 2213<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1237 2213<@jupet kellari ö> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1238 2213<@jupet kellari ö> (-1 ollee ei akkua kiinni, koska akku on pöydällä)
1239 2214<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1240 2214<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1242 2238<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1243 2239<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1245 2240<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori päällä
1246 2241<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori päällä mutta ilman verkkovirtaa
1249 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1250 #define APM_PATH "/proc/apm"
1251 #define MAX_BATTERY_COUNT 4
1253 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT];
1254 static FILE *apm_bat_fp[MAX_BATTERY_COUNT];
1256 static int batteries_initialized = 0;
1257 static char batteries[MAX_BATTERY_COUNT][32];
1259 static int acpi_last_full[MAX_BATTERY_COUNT];
1260 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1262 static char last_battery_str[MAX_BATTERY_COUNT][64]; /* e.g. "charging 75%" */
1263 static char last_battery_time_str[MAX_BATTERY_COUNT][64]; /* e.g. "3h 15m" */
1265 static double last_battery_time[MAX_BATTERY_COUNT];
1267 static int last_battery_perct[MAX_BATTERY_COUNT];
1268 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1271 void init_batteries(void)
1274 if(batteries_initialized)
1276 for(idx = 0; idx < MAX_BATTERY_COUNT; idx++)
1277 batteries[idx][0] = '\0';
1278 batteries_initialized = 1;
1281 int get_battery_idx(const char *bat)
1284 for(idx = 0; idx < MAX_BATTERY_COUNT; idx++)
1285 if(!strlen(batteries[idx]) || !strcmp(batteries[idx], bat))
1288 /* if not found, enter a new entry */
1289 if(!strlen(batteries[idx]))
1290 snprintf(batteries[idx], 31, "%s", bat);
1295 void get_battery_stuff(char *buf, unsigned int n, const char *bat, int item)
1297 static int idx, rep = 0, rep2 = 0;
1298 char acpi_path[128];
1299 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1303 idx = get_battery_idx(bat);
1305 /* don't update battery too often */
1306 if (current_update_time - last_battery_time[idx] < 29.5)
1307 goto set_return_value;
1309 last_battery_time[idx] = current_update_time;
1311 memset (last_battery_str[idx], 0, sizeof (last_battery_str[idx]));
1312 memset (last_battery_time_str[idx], 0, sizeof (last_battery_time_str[idx]));
1314 /* first try ACPI */
1316 if (acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1317 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1319 if (acpi_bat_fp[idx] != NULL) {
1320 int present_rate = -1;
1321 int remaining_capacity = -1;
1322 char charging_state[64];
1325 /* read last full capacity if it's zero */
1326 if (acpi_last_full[idx] == 0) {
1331 ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1332 fp = open_file(path, &rep);
1336 if (fgets(b, 256, fp) == NULL)
1338 if (sscanf(b, "last full capacity: %d", &acpi_last_full[idx]) != 0) {
1347 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1349 strcpy(charging_state, "unknown");
1351 while (!feof(acpi_bat_fp[idx])) {
1353 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL)
1356 /* let's just hope units are ok */
1357 if (strncmp (buf, "present:", 8) == 0)
1358 sscanf(buf, "present: %4s", present);
1359 else if (strncmp (buf, "charging state:", 15) == 0)
1360 sscanf(buf, "charging state: %63s", charging_state);
1361 else if (strncmp (buf, "present rate:", 13) == 0)
1362 sscanf(buf, "present rate: %d", &present_rate);
1363 else if (strncmp(buf, "remaining capacity:", 19) == 0)
1364 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1367 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1368 if (remaining_capacity > acpi_last_full[idx])
1369 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1372 if (strcmp(present, "no") == 0) {
1373 strncpy(last_battery_str[idx], "not present", 64);
1376 else if (strcmp(charging_state, "charging") == 0) {
1377 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1378 /* e.g. charging 75% */
1379 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %i%%",
1380 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1382 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1383 (long) (((acpi_last_full[idx] - remaining_capacity) * 3600) /
1385 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1386 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %d%%",
1387 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1389 strncpy(last_battery_str[idx], "charging", sizeof(last_battery_str[idx])-1);
1393 else if (strncmp(charging_state, "discharging", 64) == 0) {
1394 if (present_rate > 0) {
1395 /* e.g. discharging 35% */
1396 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "discharging %i%%",
1397 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1399 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1400 (long) ((remaining_capacity * 3600) / present_rate));
1401 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1402 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "full");
1404 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1406 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1410 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1411 else if (strncmp(charging_state, "charged", 64) == 0) {
1412 /* Below happens with the second battery on my X40,
1413 * when the second one is empty and the first one
1415 if (remaining_capacity == 0)
1416 strcpy(last_battery_str[idx], "empty");
1418 strcpy(last_battery_str[idx], "charged");
1420 /* unknown, probably full / AC */
1422 if (acpi_last_full[idx] != 0
1423 && remaining_capacity != acpi_last_full[idx])
1424 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1425 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1427 strncpy(last_battery_str[idx], "AC", 64);
1431 if (apm_bat_fp[idx] == NULL)
1432 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1434 if (apm_bat_fp[idx] != NULL) {
1435 int ac, status, flag, life;
1437 fscanf(apm_bat_fp[idx],
1438 "%*s %*s %*x %x %x %x %d%%",
1439 &ac, &status, &flag, &life);
1442 /* could check now that there is ac */
1443 snprintf(last_battery_str[idx], 64, "AC");
1444 } else if (ac && life != 100) { /* could check that status==3 here? */
1445 snprintf(last_battery_str[idx], 64,
1446 "charging %d%%", life);
1448 snprintf(last_battery_str[idx], 64, "%d%%",
1452 /* it seemed to buffer it so file must be closed (or could use syscalls
1453 * directly but I don't feel like coding it now) */
1454 fclose(apm_bat_fp[idx]);
1455 apm_bat_fp[idx] = NULL;
1461 case BATTERY_STATUS:
1463 snprintf(buf, n, "%s", last_battery_str[idx]);
1468 snprintf(buf, n, "%s", last_battery_time_str[idx]);
1477 int get_battery_perct(const char *bat)
1481 char acpi_path[128];
1482 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1486 idx = get_battery_idx(bat);
1488 /* don't update battery too often */
1489 if (current_update_time - last_battery_perct_time[idx] < 30) {
1490 return last_battery_perct[idx];
1492 last_battery_perct_time[idx] = current_update_time;
1494 /* Only check for ACPI */
1496 if (acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1497 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1499 int remaining_capacity = -1;
1500 if (acpi_bat_fp[idx] != NULL) {
1501 /* read last full capacity if it's zero */
1502 if (acpi_design_capacity[idx] == 0) {
1507 ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1508 fp = open_file(path, &rep);
1512 if (fgets(b, 256, fp) == NULL)
1514 if (sscanf(b, "last full capacity: %d", &acpi_design_capacity[idx]) != 0) {
1522 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1524 while (!feof(acpi_bat_fp[idx])) {
1526 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL)
1530 sscanf(buf, "remaining capacity: %d",
1531 &remaining_capacity);
1534 if(remaining_capacity < 0)
1536 /* compute the battery percentage */
1537 last_battery_perct[idx] =
1538 (int) (((float)remaining_capacity/acpi_design_capacity[idx]) * 100);
1539 return last_battery_perct[idx];
1542 int get_battery_perct_bar(const char *bar)
1545 get_battery_perct(bar);
1546 idx = get_battery_idx(bar);
1547 return (int) (last_battery_perct[idx] * 2.56 - 1);
1552 /* On Apple powerbook and ibook:
1553 $ cat /proc/pmu/battery_0
1560 $ cat /proc/pmu/info
1561 PMU driver version : 2
1562 PMU firmware version : 0c
1567 /* defines as in <linux/pmu.h> */
1568 #define PMU_BATT_PRESENT 0x00000001
1569 #define PMU_BATT_CHARGING 0x00000002
1571 static FILE* pmu_battery_fp;
1572 static FILE* pmu_info_fp;
1573 static char pb_battery_info[3][32];
1574 static double pb_battery_info_update;
1576 #define PMU_PATH "/proc/pmu"
1577 void get_powerbook_batt_info(char *buf, size_t n, int i)
1580 const char* batt_path = PMU_PATH "/battery_0";
1581 const char* info_path = PMU_PATH "/info";
1582 int flags, charge, max_charge, ac = -1;
1585 /* don't update battery too often */
1586 if (current_update_time - pb_battery_info_update < 29.5) {
1587 snprintf(buf, n, "%s", pb_battery_info[i]);
1590 pb_battery_info_update = current_update_time;
1592 if (pmu_battery_fp == NULL)
1593 pmu_battery_fp = open_file(batt_path, &rep);
1595 if (pmu_battery_fp != NULL) {
1596 rewind(pmu_battery_fp);
1597 while (!feof(pmu_battery_fp)) {
1599 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL)
1603 sscanf(buf, "flags : %8x", &flags);
1604 else if (buf[0] == 'c' && buf[1] == 'h')
1605 sscanf(buf, "charge : %d", &charge);
1606 else if (buf[0] == 'm')
1607 sscanf(buf, "max_charge : %d", &max_charge);
1608 else if (buf[0] == 't')
1609 sscanf(buf, "time rem. : %ld", &time);
1612 if (pmu_info_fp == NULL)
1613 pmu_info_fp = open_file(info_path, &rep);
1615 if (pmu_info_fp != NULL) {
1616 rewind(pmu_info_fp);
1617 while (!feof(pmu_info_fp)) {
1619 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL)
1622 sscanf(buf, "AC Power : %d", &ac);
1625 /* update status string */
1626 if ((ac && !(flags & PMU_BATT_PRESENT)))
1627 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
1628 else if (ac && (flags & PMU_BATT_PRESENT)
1629 && !(flags & PMU_BATT_CHARGING))
1630 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
1631 else if ((flags & PMU_BATT_PRESENT)
1632 && (flags & PMU_BATT_CHARGING))
1633 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
1635 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
1637 /* update percentage string */
1639 pb_battery_info[PB_BATT_PERCENT][0] = 0;
1641 snprintf(pb_battery_info[PB_BATT_PERCENT],
1642 sizeof(pb_battery_info[PB_BATT_PERCENT]),
1643 "%d%%", (charge * 100)/max_charge);
1645 /* update time string */
1646 if (time == 0) /* fully charged or battery not present */
1647 pb_battery_info[PB_BATT_TIME][0] = 0;
1648 else if (time < 60*60) /* don't show secs */
1649 format_seconds_short(pb_battery_info[PB_BATT_TIME],
1650 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1652 format_seconds(pb_battery_info[PB_BATT_TIME],
1653 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1655 snprintf(buf, n, "%s", pb_battery_info[i]);
1660 show_nice_processes = 1;
1661 process_find_top(info.cpu, info.memu);
1662 info.first_process = get_first_process();
1667 * The following ifdefs were adapted from gkrellm
1669 #include <linux/major.h>
1671 #if ! defined (MD_MAJOR)
1675 #if !defined(LVM_BLK_MAJOR)
1676 #define LVM_BLK_MAJOR 58
1679 #if !defined(NBD_MAJOR)
1680 #define NBD_MAJOR 43
1683 void update_diskio()
1685 static unsigned int last = UINT_MAX;
1686 static unsigned int last_read = UINT_MAX;
1687 static unsigned int last_write = UINT_MAX;
1693 unsigned int current = 0;
1694 unsigned int current_read = 0;
1695 unsigned int current_write = 0;
1696 unsigned int reads, writes = 0;
1699 if (!(fp =open_file("/proc/diskstats", &rep))) {
1704 /* read reads and writes from all disks (minor = 0), including
1705 * cd-roms and floppies, and summ them up
1708 fgets(buf, 512, fp);
1709 col_count = sscanf(buf, "%u %u %*s %*u %*u %u %*u %*u %*u %u",
1710 &major, &minor, &reads, &writes);
1711 /* ignore subdevices (they have only 3 matching entries in their line)
1712 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
1714 * XXX ignore devices which are part of a SW RAID (MD_MAJOR)
1716 if (col_count > 3 &&
1717 major != LVM_BLK_MAJOR && major != NBD_MAJOR &&
1718 major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
1719 current += reads + writes;
1720 current_read += reads;
1721 current_write += writes;
1725 /* since the values in /proc/diststats are absolute, we have
1726 * to substract our last reading. The numbers stand for
1727 * "sectors read", and we therefore have to divide by two to
1729 int tot = ((double)(current-last)/2);
1730 int tot_read = ((double)(current_read-last_read)/2);
1731 int tot_write = ((double)(current_write-last_write)/2);
1733 if (last_read > current_read)
1735 if (last_write > current_write)
1738 if (last > current) {
1739 /* we hit this either if it's the very first time we
1740 * run this, or when /proc/diskstats overflows; while
1741 * 0 is not correct, it's at least not way off */
1745 last_read = current_read;
1746 last_write = current_write;
1749 diskio_read_value = tot_read;
1750 diskio_write_value = tot_write;
1755 /* Here come the IBM ACPI-specific things. For reference, see
1756 http://ibm-acpi.sourceforge.net/README
1757 If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
1773 The content of these files is described in detail in the aforementioned
1774 README - some of them also in the following functions accessing them.
1775 Peter Tarjan (ptarjan@citromail.hu)
1778 #define IBM_ACPI_DIR "/proc/acpi/ibm"
1780 void get_ibm_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1782 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
1783 /proc/acpi/ibm/fan looks like this (3 lines):
1786 commands: enable, disable
1787 Peter Tarjan (ptarjan@citromail.hu)
1790 if ( !p_client_buffer || client_buffer_size <= 0 )
1794 unsigned int speed=0;
1796 snprintf(fan, 127, "%s/fan",IBM_ACPI_DIR);
1798 fp = fopen(fan, "r");
1804 if (fgets(line, 255, fp) == NULL) break;
1805 if (sscanf(line, "speed: %d", &speed)) break;
1810 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", fan, strerror(errno));
1814 snprintf( p_client_buffer, client_buffer_size, "%d", speed );
1819 static double last_ibm_acpi_temp_time;
1820 void get_ibm_acpi_temps()
1822 /* get the measured temperatures from the temperature sensors
1823 on IBM/Lenovo laptops running the ibm acpi.
1824 There are 8 values in /proc/acpi/ibm/thermal, and according to
1825 http://ibm-acpi.sourceforge.net/README
1826 these mean the following (at least on an IBM R51...)
1827 0: CPU (also on the T series laptops)
1828 1: Mini PCI Module (?)
1830 3: GPU (also on the T series laptops)
1835 I'm not too sure about those with the question mark, but the values I'm
1836 reading from *my* thermal file (on a T42p) look realistic for the
1837 hdd and the battery.
1838 #5 and #7 are always -128.
1839 /proc/acpi/ibm/thermal looks like this (1 line):
1840 temperatures: 41 43 31 46 33 -128 29 -128
1841 Peter Tarjan (ptarjan@citromail.hu)
1844 /* don't update too often */
1845 if (current_update_time - last_ibm_acpi_temp_time < 10.00)
1849 last_ibm_acpi_temp_time = current_update_time;
1851 /* if ( !p_client_buffer || client_buffer_size <= 0 )
1857 snprintf(thermal, 127, "%s/thermal",IBM_ACPI_DIR);
1858 fp = fopen(thermal, "r");
1865 if (fgets(line, 255, fp) == NULL) break;
1866 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
1867 &ibm_acpi.temps[0], &ibm_acpi.temps[1],
1868 &ibm_acpi.temps[2], &ibm_acpi.temps[3],
1869 &ibm_acpi.temps[4], &ibm_acpi.temps[5],
1870 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) break;
1875 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", thermal, strerror(errno));
1883 void get_ibm_acpi_volume( char * p_client_buffer, size_t client_buffer_size )
1886 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
1887 "Volume" here is none of the mixer volumes, but a "master of masters"
1888 volume adjusted by the IBM volume keys.
1889 /proc/acpi/ibm/fan looks like this (4 lines):
1892 commands: up, down, mute
1893 commands: level <level> (<level> is 0-15)
1894 Peter Tarjan (ptarjan@citromail.hu)
1897 if ( !p_client_buffer || client_buffer_size <= 0 )
1903 snprintf(volume, 127, "%s/volume",IBM_ACPI_DIR);
1904 unsigned int vol=-1;
1907 fp = fopen(volume, "r");
1913 if (fgets(line, 255, fp) == NULL) break;
1914 if (sscanf(line, "level: %d", &vol)) continue;
1915 if (sscanf(line, "mute: %s", mute)) break;
1920 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", volume, strerror(errno));
1925 if (strcmp(mute, "on")==0)
1927 snprintf( p_client_buffer, client_buffer_size, "%s", "mute" );
1932 snprintf( p_client_buffer, client_buffer_size, "%d", vol );
1938 /*static FILE *fp=NULL;*/
1940 void get_ibm_acpi_brightness(char * p_client_buffer, size_t client_buffer_size)
1942 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
1943 /proc/acpi/ibm/brightness looks like this (3 lines):
1946 commands: level <level> (<level> is 0-7)
1947 Peter Tarjan (ptarjan@citromail.hu)
1950 if ( !p_client_buffer || client_buffer_size <= 0 )
1954 unsigned int brightness=0;
1956 snprintf(filename, 127, "%s/brightness",IBM_ACPI_DIR);
1958 fp = fopen(filename, "r");
1964 if (fgets(line, 255, fp) == NULL) break;
1965 if (sscanf(line, "level: %d", &brightness)) break;
1970 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", filename, strerror(errno));
1975 snprintf( p_client_buffer, client_buffer_size, "%d", brightness );
1980 void update_entropy (void)
1983 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
1984 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
1987 info.entropy.entropy_avail=0;
1988 info.entropy.poolsize=0;
1990 if ((fp1 = open_file (entropy_avail, &rep))==NULL)
1993 if ((fp2 = open_file (entropy_poolsize, &rep))==NULL)
1999 fscanf (fp1, "%u", &info.entropy.entropy_avail);
2000 fscanf (fp2, "%u", &info.entropy.poolsize);
2005 info.mask |= (1 << INFO_ENTROPY);