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 static FILE *net_wireless_fp;
171 inline void update_net_stats()
175 // FIXME: arbitrary size chosen to keep code simple.
177 unsigned int curtmp1, curtmp2;
184 // wireless info variables
185 int skfd, has_bitrate = 0;
186 struct wireless_info *winfo;
191 delta = current_update_time - last_update_time;
195 /* open file and ignore first two lines */
196 if (!(net_dev_fp = open_file("/proc/net/dev", &rep)))
202 fgets(buf, 255, net_dev_fp); /* garbage */
203 fgets(buf, 255, net_dev_fp); /* garbage (field names) */
205 /* read each interface */
206 for (i2 = 0; i2 < 16; i2++) {
209 long long r, t, last_recv, last_trans;
211 if (fgets(buf, 255, net_dev_fp) == NULL) {
215 while (isspace((int) *p))
220 while (*p && *p != ':')
227 ns = get_net_stat(s);
229 memset(&(ns->addr.sa_data), 0, 14);
230 last_recv = ns->recv;
231 last_trans = ns->trans;
234 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
235 "%Ld %*d %*d %*d %*d %*d %*d %*d %Ld",
238 /* if recv or trans is less than last time, an overflow happened */
240 if (r < ns->last_read_recv)
243 ns->recv += (r - ns->last_read_recv);
244 ns->last_read_recv = r;
246 if (t < ns->last_read_trans)
249 ns->trans += (t - ns->last_read_trans);
250 ns->last_read_trans = t;
252 /*** ip addr patch ***/
253 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
255 conf.ifc_buf = malloc(sizeof(struct ifreq) * 16);
257 conf.ifc_len = sizeof(struct ifreq) * 16;
259 ioctl((long) i, SIOCGIFCONF, &conf);
261 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
263 ns = get_net_stat(((struct ifreq *) conf.
264 ifc_buf)[k].ifr_ifrn.ifrn_name);
266 ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.
275 /*** end ip addr patch ***/
278 /* calculate speeds */
279 ns->net_rec[0] = (ns->recv - last_recv) / delta;
280 ns->net_trans[0] = (ns->trans - last_trans) / delta;
284 for (i = 0; (unsigned) i < info.net_avg_samples; i++) {
285 curtmp1 += ns->net_rec[i];
286 curtmp2 += ns->net_trans[i];
288 if (curtmp1 == 0) curtmp1 = 1;
289 if (curtmp2 == 0) curtmp2 = 1;
290 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
291 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
292 if (info.net_avg_samples > 1) {
293 for (i = info.net_avg_samples; i > 1; i--) {
294 ns->net_rec[i - 1] = ns->net_rec[i - 2];
295 ns->net_trans[i - 1] =
296 ns->net_trans[i - 2];
301 /* update wireless info */
302 winfo = malloc(sizeof(struct wireless_info));
303 memset(winfo, 0, sizeof(struct wireless_info));
305 skfd = iw_sockets_open();
306 if(iw_get_basic_config(skfd, s, &(winfo->b)) > -1) {
308 // set present winfo variables
309 if(iw_get_stats(skfd, s, &(winfo->stats), &winfo->range, winfo->has_range) >= 0)
310 winfo->has_stats = 1;
311 if(iw_get_range_info(skfd, s, &(winfo->range)) >= 0)
312 winfo->has_range = 1;
313 if(iw_get_ext(skfd, s, SIOCGIWAP, &wrq) >= 0) {
314 winfo->has_ap_addr = 1;
315 memcpy(&(winfo->ap_addr), &(wrq.u.ap_addr), sizeof (sockaddr));
319 if(iw_get_ext(skfd, s, SIOCGIWRATE, &wrq) >= 0) {
320 memcpy(&(winfo->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
321 iw_print_bitrate(ns->bitrate, 16, winfo->bitrate.value);
326 if(winfo->has_range && winfo->has_stats && ((winfo->stats.qual.level != 0) || (winfo->stats.qual.updated & IW_QUAL_DBM))) {
327 if(!(winfo->stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
328 ns->link_qual = winfo->stats.qual.qual;
329 ns->link_qual_max = winfo->range.max_qual.qual;
334 if(winfo->has_ap_addr) {
335 iw_sawap_ntop(&winfo->ap_addr, ns->ap);
339 if(winfo->b.has_essid) {
340 if(winfo->b.essid_on)
341 snprintf(ns->essid, 32, "%s", winfo->b.essid);
343 snprintf(ns->essid, 32, "off/any");
346 snprintf(ns->mode, 16, "%s", iw_operation_mode[winfo->b.mode]);
348 iw_sockets_close(skfd);
355 info.mask |= (1 << INFO_NET);
360 inline void update_wifi_stats()
362 /** wireless stats patch by Bobby Beckmann **/
366 /*open file and ignore first two lines sorry, this code sucks ass right now, i'll clean it up later */
367 if (net_wireless_fp == NULL)
368 net_wireless_fp = open_file("/proc/net/wireless", &rep);
370 fseek(net_wireless_fp, 0, SEEK_SET);
371 if (net_wireless_fp == NULL)
374 fgets(buf, 255, net_wireless_fp); /* garbage */
375 fgets(buf, 255, net_wireless_fp); /* garbage (field names) */
377 /* read each interface */
378 for (i = 0; i < 16; i++) {
383 if (fgets(buf, 255, net_wireless_fp) == NULL)
386 while (isspace((int) *p))
391 while (*p && *p != ':')
398 ns = get_net_stat(s);
400 sscanf(p, "%*d %d. %d. %d", &l, &m, &n);
402 ns->linkstatus = (int) (log(MIN(MAX(l,1),92)) / log(92) * 100);
405 /*** end wireless patch ***/
411 void update_total_processes()
416 struct sysinfo s_info;
418 info.procs = s_info.procs;
426 if (!(fp = open_file("/proc/loadavg", &rep)))
431 fscanf(fp, "%*f %*f %*f %*d/%hd", &info.procs );
434 info.mask |= (1 << INFO_PROCS);
437 #define CPU_SAMPLE_COUNT 15
439 unsigned long long cpu_user;
440 unsigned long long cpu_system;
441 unsigned long long cpu_nice;
442 unsigned long long cpu_idle;
443 unsigned long long cpu_iowait;
444 unsigned long long cpu_irq;
445 unsigned long long cpu_softirq;
446 unsigned long long cpu_steal;
447 unsigned long long cpu_total;
448 unsigned long long cpu_active_total;
449 unsigned long long cpu_last_total;
450 unsigned long long cpu_last_active_total;
451 double cpu_val[CPU_SAMPLE_COUNT];
453 static short cpu_setup = 0;
456 determine if this kernel gives us "extended" statistics information in /proc/stat.
457 Kernels around 2.5 and earlier only reported user, system, nice and idle values in proc stat.
458 Kernels around 2.6 and greater report these PLUS iowait, irq, softirq, and steal
460 void determine_longstat(char * buf) {
461 unsigned long long iowait=0;
462 KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
463 /* scanf will either return -1 or 1 because there is only 1 assignment */
464 if (sscanf(buf, "%*s %*d %*d %*d %*d %llu",&iowait)>0) KFLAG_SETON(KFLAG_IS_LONGSTAT);
472 if (info.cpu_usage) {
477 if (!(stat_fp = open_file("/proc/stat", &rep)))
482 while (!feof(stat_fp)) {
483 if (fgets(buf, 255, stat_fp) == NULL)
486 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
487 if (info.cpu_count == 0) {
488 determine_longstat(buf);
493 info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
498 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
499 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
501 inline static void update_stat()
505 static struct cpu_info *cpu = NULL;
510 char * stat_template=NULL;
511 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) {
521 stat_template = KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT ;
525 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
526 cpu = malloc(malloc_cpu_size);
527 memset(cpu, 0, malloc_cpu_size);
530 if (!(stat_fp = open_file("/proc/stat", &rep)))
535 memset(info.cpu_usage, 0, info.cpu_count * sizeof (float));
541 while (!feof(stat_fp)) {
542 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
551 , &(cpu[index].cpu_user)
552 , &(cpu[index].cpu_nice)
553 , &(cpu[index].cpu_system)
554 , &(cpu[index].cpu_idle)
555 , &(cpu[index].cpu_iowait)
556 , &(cpu[index].cpu_irq)
557 , &(cpu[index].cpu_softirq)
558 , &(cpu[index].cpu_steal)
561 cpu[index].cpu_total = cpu[index].cpu_user
562 + cpu[index].cpu_nice
563 + cpu[index].cpu_system
564 + cpu[index].cpu_idle
565 + cpu[index].cpu_iowait
567 + cpu[index].cpu_softirq
568 + cpu[index].cpu_steal
571 cpu[index].cpu_active_total = cpu[index].cpu_total - (cpu[index].cpu_idle + cpu[index].cpu_iowait);
572 info.mask |= (1 << INFO_CPU);
574 double delta = current_update_time - last_update_time;
575 if (delta <= 0.001) break;
577 cpu[index].cpu_val[0] = (cpu[index].cpu_active_total - cpu[index].cpu_last_active_total) /
578 (float )(cpu[index].cpu_total - cpu[index].cpu_last_total);
580 for (i=0; i < info.cpu_avg_samples; i++ ) {
581 curtmp += cpu[index].cpu_val[i];
583 /* TESTING -- I've removed this, because I don't think it is right. You shouldn't divide
584 by the cpu count here ... removing for testing */
586 info.cpu_usage[index] = curtmp / info.cpu_avg_samples / info.cpu_count;
588 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
590 /* TESTING -- this line replaces the prev. "suspect" if/else */
591 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
593 cpu[index].cpu_last_total = cpu[index].cpu_total;
594 cpu[index].cpu_last_active_total = cpu[index].cpu_active_total;
595 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
596 cpu[index].cpu_val[i] = cpu[index].cpu_val[i - 1];
604 void update_running_processes()
609 void update_cpu_usage()
614 void update_load_average()
616 #ifdef HAVE_GETLOADAVG
621 info.loadavg[0] = (float) v[0];
622 info.loadavg[1] = (float) v[1];
623 info.loadavg[2] = (float) v[2];
631 if (!(fp = open_file("/proc/loadavg", &rep)))
633 info.loadavg[0] = info.loadavg[1] = info.loadavg[2] = 0.0;
636 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1], &info.loadavg[2]);
639 info.mask |= (1 << INFO_LOADAVG);
642 #define PROC_I8K "/proc/i8k"
643 #define I8K_DELIM " "
644 static char *i8k_procbuf = NULL;
649 i8k_procbuf = (char*)malloc(128*sizeof(char));
651 if ((fp = fopen(PROC_I8K,"r")) == NULL) {
652 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel driver is loaded...");
655 memset(&i8k_procbuf[0],0,128);
656 if (fread(&i8k_procbuf[0],sizeof(char),128,fp) == 0) {
657 ERR("something wrong with /proc/i8k...");
662 i8k.version = strtok(&i8k_procbuf[0],I8K_DELIM);
663 i8k.bios = strtok(NULL,I8K_DELIM);
664 i8k.serial = strtok(NULL,I8K_DELIM);
665 i8k.cpu_temp = strtok(NULL,I8K_DELIM);
666 i8k.left_fan_status = strtok(NULL,I8K_DELIM);
667 i8k.right_fan_status = strtok(NULL,I8K_DELIM);
668 i8k.left_fan_rpm = strtok(NULL,I8K_DELIM);
669 i8k.right_fan_rpm = strtok(NULL,I8K_DELIM);
670 i8k.ac_status = strtok(NULL,I8K_DELIM);
671 i8k.buttons_status = strtok(NULL,I8K_DELIM);
675 /***********************************************************/
676 /***********************************************************/
677 /***********************************************************/
679 static int no_dots(const struct dirent *d)
681 if (d->d_name[0] == '.')
687 get_first_file_in_a_directory(const char *dir, char *s, int *rep)
689 struct dirent **namelist;
692 n = scandir(dir, &namelist, no_dots, alphasort);
695 ERR("scandir for %s: %s", dir, strerror(errno));
704 strncpy(s, namelist[0]->d_name, 255);
707 for (i = 0; i < n; i++)
715 int open_i2c_sensor(const char *dev, const char *type, int n, int *div, char *devtype)
718 if (post_21_kernel) {
719 strncpy(i2c_dir, "/sys/bus/platform/devices/", 64);
721 strncpy(i2c_dir, "/sys/bus/i2c/devices/", 64);
728 /* if i2c device is NULL or *, get first */
729 if (dev == NULL || strcmp(dev, "*") == 0) {
731 if (!get_first_file_in_a_directory(i2c_dir, buf, &rep))
736 /* change vol to in */
737 if (strcmp(type, "vol") == 0)
740 if (strcmp(type, "tempf") == 0) {
741 snprintf(path, 255, "%s%s/%s%d_input", i2c_dir, dev, "temp", n);
743 snprintf(path, 255, "%s%s/%s%d_input", i2c_dir, dev, type, n);
745 strncpy(devtype, path, 255);
748 fd = open(path, O_RDONLY);
750 CRIT_ERR("can't open '%s': %s\nplease fix i2c or remove it from Conky", path, strerror(errno));
753 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
754 || strcmp(type, "tempf") == 0)
758 /* fan does not use *_div as a read divisor */
759 if (strcmp("fan", type) == 0)
762 /* test if *_div file exist, open it and use it as divisor */
763 if (strcmp(type, "tempf") == 0) {
764 snprintf(path, 255, "%s%s/%s%d_div", i2c_dir, "one", "two",
767 snprintf(path, 255, "%s%s/%s%d_div", i2c_dir, dev, type, n);
770 divfd = open(path, O_RDONLY);
775 divn = read(divfd, divbuf, 63);
776 /* should read until n == 0 but I doubt that kernel will give these
777 * in multiple pieces. :) */
787 double get_i2c_info(int *fd, int div, char *devtype, char *type)
794 lseek(*fd, 0, SEEK_SET);
800 n = read(*fd, buf, 63);
801 /* should read until n == 0 but I doubt that kernel will give these
802 * in multiple pieces. :) */
809 *fd = open(devtype, O_RDONLY);
811 ERR("can't open '%s': %s", devtype, strerror(errno));
813 /* My dirty hack for computing CPU value
814 * Filedil, from forums.gentoo.org
816 /* if (strstr(devtype, "temp1_input") != NULL)
817 return -15.096+1.4893*(val / 1000.0); */
820 /* divide voltage and temperature by 1000 */
821 /* or if any other divisor is given, use that */
822 if (strcmp(type, "tempf") == 0) {
824 return ((val / div + 40) * 9.0 / 5) - 40;
826 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
828 return ((val + 40) * 9.0 / 5) - 40;
839 /* Prior to kernel version 2.6.12, the CPU fan speed was available
840 * in ADT746X_FAN_OLD, whereas later kernel versions provide this
841 * information in ADT746X_FAN.
843 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
844 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
846 void get_adt746x_fan( char * p_client_buffer, size_t client_buffer_size )
849 char adt746x_fan_state[64];
852 if ( !p_client_buffer || client_buffer_size <= 0 )
855 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
856 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL)
859 sprintf(adt746x_fan_state, "adt746x not found");
863 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
864 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
868 snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_fan_state );
872 /* Prior to kernel version 2.6.12, the CPU temperature was found
873 * in ADT746X_CPU_OLD, whereas later kernel versions provide this
874 * information in ADT746X_CPU.
876 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
877 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
879 void get_adt746x_cpu( char * p_client_buffer, size_t client_buffer_size )
882 char adt746x_cpu_state[64];
885 if ( !p_client_buffer || client_buffer_size <= 0 )
888 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
889 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL)
891 sprintf(adt746x_cpu_state, "adt746x not found");
895 fscanf(fp, "%2s", adt746x_cpu_state);
899 snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state );
903 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
905 /***********************************************************************/
907 * This file is part of x86info.
908 * (C) 2001 Dave Jones.
910 * Licensed under the terms of the GNU GPL License version 2.
912 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
913 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz>
916 #if defined(__i386) || defined(__x86_64)
917 __inline__ unsigned long long int rdtsc()
919 unsigned long long int x;
920 __asm__ volatile (".byte 0x0f, 0x31":"=A" (x));
925 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
926 void get_freq_dynamic( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor )
928 #if defined(__i386) || defined(__x86_64)
930 struct timeval tvstart, tvstop;
931 unsigned long long cycles[2]; /* gotta be 64 bit */
932 unsigned int microseconds; /* total time taken */
934 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
937 memset(&tz, 0, sizeof(tz));
939 /* get this function in cached memory */
940 gettimeofday(&tvstart, &tz);
942 gettimeofday(&tvstart, &tz);
944 /* we don't trust that this is any specific length of time */
947 gettimeofday(&tvstop, &tz);
948 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
949 (tvstop.tv_usec - tvstart.tv_usec);
951 snprintf( p_client_buffer, client_buffer_size, p_format, (float)((cycles[1] - cycles[0]) / microseconds) / divisor );
954 /* FIXME: hardwired: get freq for first cpu!
955 this whole function needs to be rethought and redone for
956 multi-cpu/multi-core/multi-threaded environments and
957 arbitrary combinations thereof
959 get_freq( p_client_buffer, client_buffer_size, p_format, divisor, 1 );
965 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
966 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
968 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
969 char get_freq( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
977 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
982 char current_freq_file[128];
983 snprintf(current_freq_file, 127, "%s/cpu%d/%s",CPUFREQ_PREFIX, cpu-1, CPUFREQ_POSTFIX);
984 f = fopen(current_freq_file, "r");
987 /* if there's a cpufreq /sys node, read the current frequency from this node;
988 * divide by 1000 to get Mhz. */
989 if (fgets(s, sizeof(s), f)) {
990 s[strlen(s)-1] = '\0';
991 freq = strtod(s, NULL);
994 snprintf( p_client_buffer, client_buffer_size, p_format, (freq/1000)/divisor );
999 f = open_file("/proc/cpuinfo", &rep); //open the CPU information file
1001 perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
1005 while (fgets(s, sizeof(s), f) != NULL){ //read the file
1007 #if defined(__i386) || defined(__x86_64)
1008 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) { //and search for the cpu mhz
1010 #if defined(__alpha)
1011 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) { // different on alpha
1013 if (strncmp(s, "clock", 5) == 0 && cpu == 0) { // this is different on ppc for some reason
1014 #endif // defined(__alpha)
1015 #endif // defined(__i386) || defined(__x86_64)
1017 strcpy(frequency, strchr(s, ':') + 2); //copy just the number
1018 #if defined(__alpha)
1019 frequency[strlen(frequency) - 6] = '\0';// strip " est.\n"
1020 freq = strtod(frequency, NULL)/1000000; // kernel reports in Hz
1022 frequency[strlen(frequency) - 1] = '\0'; // strip \n
1023 freq = strtod(frequency, NULL);
1027 if (strncmp(s, "processor", 9) == 0) {
1035 snprintf( p_client_buffer, client_buffer_size, p_format, (float)freq/divisor );
1039 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
1041 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
1042 char get_voltage( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
1044 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks
1045 something like this:
1056 /* Peter Tarjan (ptarjan@citromail.hu) */
1061 char current_freq_file[128];
1065 /* build the voltage file name */
1067 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
1068 CPUFREQ_PREFIX, cpu, CPUFREQ_POSTFIX);
1070 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
1073 /* read the current cpu frequency from the /sys node */
1074 f = fopen(current_freq_file, "r");
1076 if (fgets(s, sizeof(s), f)) {
1077 s[strlen(s)-1] = '\0';
1078 freq = strtod(s, NULL);
1082 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1083 perror("get_voltage()");
1090 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
1091 CPUFREQ_PREFIX, cpu, CPUFREQ_VOLTAGE);
1093 /* use the current cpu frequency to find the corresponding voltage */
1094 f = fopen(current_freq_file, "r");
1099 if (fgets(line, 255, f) == NULL) break;
1100 sscanf(line, "%d %d", &freq_comp, &voltage);
1101 if(freq_comp == freq) break;
1105 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1106 perror("get_voltage()");
1112 snprintf( p_client_buffer, client_buffer_size, p_format, (float)voltage/divisor );
1117 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1119 void get_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1126 if ( !p_client_buffer || client_buffer_size <= 0 )
1129 /* yeah, slow... :/ */
1130 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep))
1132 snprintf( p_client_buffer, client_buffer_size, "no fans?" );
1136 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf );
1138 fp = open_file(buf2, &rep);
1140 snprintf( p_client_buffer, client_buffer_size, "can't open fan's state file" );
1143 memset(buf,0,sizeof(buf));
1144 fscanf(fp, "%*s %99s", buf);
1147 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1152 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1154 void get_acpi_ac_adapter( char * p_client_buffer, size_t client_buffer_size )
1161 if ( !p_client_buffer || client_buffer_size <= 0 )
1164 /* yeah, slow... :/ */
1165 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep))
1167 snprintf( p_client_buffer, client_buffer_size, "no ac_adapters?" );
1171 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf );
1174 fp = open_file(buf2, &rep);
1176 snprintf( p_client_buffer, client_buffer_size, "No ac adapter found.... where is it?" );
1179 memset(buf,0,sizeof(buf));
1180 fscanf(fp, "%*s %99s", buf );
1183 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1189 /proc/acpi/thermal_zone/THRM/cooling_mode
1190 cooling mode: active
1191 /proc/acpi/thermal_zone/THRM/polling_frequency
1193 /proc/acpi/thermal_zone/THRM/state
1195 /proc/acpi/thermal_zone/THRM/temperature
1197 /proc/acpi/thermal_zone/THRM/trip_points
1199 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1202 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1203 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1205 int open_acpi_temperature(const char *name)
1211 if (name == NULL || strcmp(name, "*") == 0) {
1213 if (!get_first_file_in_a_directory
1214 (ACPI_THERMAL_DIR, buf, &rep))
1219 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1221 fd = open(path, O_RDONLY);
1223 ERR("can't open '%s': %s", path, strerror(errno));
1228 static double last_acpi_temp;
1229 static double last_acpi_temp_time;
1231 double get_acpi_temperature(int fd)
1236 /* don't update acpi temperature too often */
1237 if (current_update_time - last_acpi_temp_time < 11.32) {
1238 return last_acpi_temp;
1240 last_acpi_temp_time = current_update_time;
1242 /* seek to beginning */
1243 lseek(fd, 0, SEEK_SET);
1249 n = read(fd, buf, 255);
1251 ERR("can't read fd %d: %s", fd, strerror(errno));
1254 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1258 return last_acpi_temp;
1262 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1264 design capacity: 4400 mAh
1265 last full capacity: 4064 mAh
1266 battery technology: rechargeable
1267 design voltage: 14800 mV
1268 design capacity warning: 300 mAh
1269 design capacity low: 200 mAh
1270 capacity granularity 1: 32 mAh
1271 capacity granularity 2: 32 mAh
1273 serial number: 16922
1279 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1282 charging state: unknown
1284 remaining capacity: 4064 mAh
1285 present voltage: 16608 mV
1289 2213<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1290 2213<@jupet kellari ö> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1291 2213<@jupet kellari ö> (-1 ollee ei akkua kiinni, koska akku on pöydällä)
1292 2214<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1293 2214<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1295 2238<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1296 2239<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1298 2240<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori päällä
1299 2241<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori päällä mutta ilman verkkovirtaa
1302 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1303 #define APM_PATH "/proc/apm"
1304 #define MAX_BATTERY_COUNT 4
1306 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT];
1307 static FILE *apm_bat_fp[MAX_BATTERY_COUNT];
1309 static int batteries_initialized = 0;
1310 static char batteries[MAX_BATTERY_COUNT][32];
1312 static int acpi_last_full[MAX_BATTERY_COUNT];
1313 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1315 static char last_battery_str[MAX_BATTERY_COUNT][64]; /* e.g. "charging 75%" */
1316 static char last_battery_time_str[MAX_BATTERY_COUNT][64]; /* e.g. "3h 15m" */
1318 static double last_battery_time[MAX_BATTERY_COUNT];
1320 static int last_battery_perct[MAX_BATTERY_COUNT];
1321 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1324 void init_batteries(void)
1327 if(batteries_initialized)
1329 for(idx = 0; idx < MAX_BATTERY_COUNT; idx++)
1330 batteries[idx][0] = '\0';
1331 batteries_initialized = 1;
1334 int get_battery_idx(const char *bat)
1337 for(idx = 0; idx < MAX_BATTERY_COUNT; idx++)
1338 if(!strlen(batteries[idx]) || !strcmp(batteries[idx], bat))
1341 /* if not found, enter a new entry */
1342 if(!strlen(batteries[idx]))
1343 snprintf(batteries[idx], 31, "%s", bat);
1348 void get_battery_stuff(char *buf, unsigned int n, const char *bat, int item)
1350 static int idx, rep = 0, rep2 = 0;
1351 char acpi_path[128];
1352 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1356 idx = get_battery_idx(bat);
1358 /* don't update battery too often */
1359 if (current_update_time - last_battery_time[idx] < 29.5)
1360 goto set_return_value;
1362 last_battery_time[idx] = current_update_time;
1364 memset (last_battery_str[idx], 0, sizeof (last_battery_str[idx]));
1365 memset (last_battery_time_str[idx], 0, sizeof (last_battery_time_str[idx]));
1367 /* first try ACPI */
1369 if (acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1370 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1372 if (acpi_bat_fp[idx] != NULL) {
1373 int present_rate = -1;
1374 int remaining_capacity = -1;
1375 char charging_state[64];
1378 /* read last full capacity if it's zero */
1379 if (acpi_last_full[idx] == 0) {
1384 ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1385 fp = open_file(path, &rep);
1389 if (fgets(b, 256, fp) == NULL)
1391 if (sscanf(b, "last full capacity: %d", &acpi_last_full[idx]) != 0) {
1400 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1402 strcpy(charging_state, "unknown");
1404 while (!feof(acpi_bat_fp[idx])) {
1406 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL)
1409 /* let's just hope units are ok */
1410 if (strncmp (buf, "present:", 8) == 0)
1411 sscanf(buf, "present: %4s", present);
1412 else if (strncmp (buf, "charging state:", 15) == 0)
1413 sscanf(buf, "charging state: %63s", charging_state);
1414 else if (strncmp (buf, "present rate:", 13) == 0)
1415 sscanf(buf, "present rate: %d", &present_rate);
1416 else if (strncmp(buf, "remaining capacity:", 19) == 0)
1417 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1420 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1421 if (remaining_capacity > acpi_last_full[idx])
1422 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1425 if (strcmp(present, "no") == 0) {
1426 strncpy(last_battery_str[idx], "not present", 64);
1429 else if (strcmp(charging_state, "charging") == 0) {
1430 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1431 /* e.g. charging 75% */
1432 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %i%%",
1433 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1435 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1436 (long) (((acpi_last_full[idx] - remaining_capacity) * 3600) /
1438 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1439 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %d%%",
1440 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1442 strncpy(last_battery_str[idx], "charging", sizeof(last_battery_str[idx])-1);
1446 else if (strncmp(charging_state, "discharging", 64) == 0) {
1447 if (present_rate > 0) {
1448 /* e.g. discharging 35% */
1449 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "discharging %i%%",
1450 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1452 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1453 (long) ((remaining_capacity * 3600) / present_rate));
1454 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1455 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "full");
1457 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1459 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1463 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1464 else if (strncmp(charging_state, "charged", 64) == 0) {
1465 /* Below happens with the second battery on my X40,
1466 * when the second one is empty and the first one
1468 if (remaining_capacity == 0)
1469 strcpy(last_battery_str[idx], "empty");
1471 strcpy(last_battery_str[idx], "charged");
1473 /* unknown, probably full / AC */
1475 if (acpi_last_full[idx] != 0
1476 && remaining_capacity != acpi_last_full[idx])
1477 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1478 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1480 strncpy(last_battery_str[idx], "AC", 64);
1484 if (apm_bat_fp[idx] == NULL)
1485 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1487 if (apm_bat_fp[idx] != NULL) {
1488 int ac, status, flag, life;
1490 fscanf(apm_bat_fp[idx],
1491 "%*s %*s %*x %x %x %x %d%%",
1492 &ac, &status, &flag, &life);
1495 /* could check now that there is ac */
1496 snprintf(last_battery_str[idx], 64, "AC");
1497 } else if (ac && life != 100) { /* could check that status==3 here? */
1498 snprintf(last_battery_str[idx], 64,
1499 "charging %d%%", life);
1501 snprintf(last_battery_str[idx], 64, "%d%%",
1505 /* it seemed to buffer it so file must be closed (or could use syscalls
1506 * directly but I don't feel like coding it now) */
1507 fclose(apm_bat_fp[idx]);
1508 apm_bat_fp[idx] = NULL;
1514 case BATTERY_STATUS:
1516 snprintf(buf, n, "%s", last_battery_str[idx]);
1521 snprintf(buf, n, "%s", last_battery_time_str[idx]);
1530 int get_battery_perct(const char *bat)
1534 char acpi_path[128];
1535 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1539 idx = get_battery_idx(bat);
1541 /* don't update battery too often */
1542 if (current_update_time - last_battery_perct_time[idx] < 30) {
1543 return last_battery_perct[idx];
1545 last_battery_perct_time[idx] = current_update_time;
1547 /* Only check for ACPI */
1549 if (acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1550 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1552 int remaining_capacity = -1;
1553 if (acpi_bat_fp[idx] != NULL) {
1554 /* read last full capacity if it's zero */
1555 if (acpi_design_capacity[idx] == 0) {
1560 ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1561 fp = open_file(path, &rep);
1565 if (fgets(b, 256, fp) == NULL)
1567 if (sscanf(b, "last full capacity: %d", &acpi_design_capacity[idx]) != 0) {
1575 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1577 while (!feof(acpi_bat_fp[idx])) {
1579 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL)
1583 sscanf(buf, "remaining capacity: %d",
1584 &remaining_capacity);
1587 if(remaining_capacity < 0)
1589 /* compute the battery percentage */
1590 last_battery_perct[idx] =
1591 (int) (((float)remaining_capacity/acpi_design_capacity[idx]) * 100);
1592 return last_battery_perct[idx];
1595 int get_battery_perct_bar(const char *bar)
1598 get_battery_perct(bar);
1599 idx = get_battery_idx(bar);
1600 return (int) (last_battery_perct[idx] * 2.56 - 1);
1605 /* On Apple powerbook and ibook:
1606 $ cat /proc/pmu/battery_0
1613 $ cat /proc/pmu/info
1614 PMU driver version : 2
1615 PMU firmware version : 0c
1620 /* defines as in <linux/pmu.h> */
1621 #define PMU_BATT_PRESENT 0x00000001
1622 #define PMU_BATT_CHARGING 0x00000002
1624 static FILE* pmu_battery_fp;
1625 static FILE* pmu_info_fp;
1626 static char pb_battery_info[3][32];
1627 static double pb_battery_info_update;
1629 #define PMU_PATH "/proc/pmu"
1630 void get_powerbook_batt_info(char *buf, size_t n, int i)
1633 const char* batt_path = PMU_PATH "/battery_0";
1634 const char* info_path = PMU_PATH "/info";
1635 int flags, charge, max_charge, ac = -1;
1638 /* don't update battery too often */
1639 if (current_update_time - pb_battery_info_update < 29.5) {
1640 snprintf(buf, n, "%s", pb_battery_info[i]);
1643 pb_battery_info_update = current_update_time;
1645 if (pmu_battery_fp == NULL)
1646 pmu_battery_fp = open_file(batt_path, &rep);
1648 if (pmu_battery_fp != NULL) {
1649 rewind(pmu_battery_fp);
1650 while (!feof(pmu_battery_fp)) {
1652 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL)
1656 sscanf(buf, "flags : %8x", &flags);
1657 else if (buf[0] == 'c' && buf[1] == 'h')
1658 sscanf(buf, "charge : %d", &charge);
1659 else if (buf[0] == 'm')
1660 sscanf(buf, "max_charge : %d", &max_charge);
1661 else if (buf[0] == 't')
1662 sscanf(buf, "time rem. : %ld", &time);
1665 if (pmu_info_fp == NULL)
1666 pmu_info_fp = open_file(info_path, &rep);
1668 if (pmu_info_fp != NULL) {
1669 rewind(pmu_info_fp);
1670 while (!feof(pmu_info_fp)) {
1672 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL)
1675 sscanf(buf, "AC Power : %d", &ac);
1678 /* update status string */
1679 if ((ac && !(flags & PMU_BATT_PRESENT)))
1680 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
1681 else if (ac && (flags & PMU_BATT_PRESENT)
1682 && !(flags & PMU_BATT_CHARGING))
1683 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
1684 else if ((flags & PMU_BATT_PRESENT)
1685 && (flags & PMU_BATT_CHARGING))
1686 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
1688 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
1690 /* update percentage string */
1692 pb_battery_info[PB_BATT_PERCENT][0] = 0;
1694 snprintf(pb_battery_info[PB_BATT_PERCENT],
1695 sizeof(pb_battery_info[PB_BATT_PERCENT]),
1696 "%d%%", (charge * 100)/max_charge);
1698 /* update time string */
1699 if (time == 0) /* fully charged or battery not present */
1700 pb_battery_info[PB_BATT_TIME][0] = 0;
1701 else if (time < 60*60) /* don't show secs */
1702 format_seconds_short(pb_battery_info[PB_BATT_TIME],
1703 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1705 format_seconds(pb_battery_info[PB_BATT_TIME],
1706 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1708 snprintf(buf, n, "%s", pb_battery_info[i]);
1713 show_nice_processes = 1;
1714 process_find_top(info.cpu, info.memu);
1715 info.first_process = get_first_process();
1720 * The following ifdefs were adapted from gkrellm
1722 #include <linux/major.h>
1724 #if ! defined (MD_MAJOR)
1728 #if !defined(LVM_BLK_MAJOR)
1729 #define LVM_BLK_MAJOR 58
1732 #if !defined(NBD_MAJOR)
1733 #define NBD_MAJOR 43
1736 void update_diskio()
1738 static unsigned int last = UINT_MAX;
1739 static unsigned int last_read = UINT_MAX;
1740 static unsigned int last_write = UINT_MAX;
1746 unsigned int current = 0;
1747 unsigned int current_read = 0;
1748 unsigned int current_write = 0;
1749 unsigned int reads, writes = 0;
1752 if (!(fp =open_file("/proc/diskstats", &rep))) {
1757 /* read reads and writes from all disks (minor = 0), including
1758 * cd-roms and floppies, and summ them up
1761 fgets(buf, 512, fp);
1762 col_count = sscanf(buf, "%u %u %*s %*u %*u %u %*u %*u %*u %u",
1763 &major, &minor, &reads, &writes);
1764 /* ignore subdevices (they have only 3 matching entries in their line)
1765 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
1767 * XXX ignore devices which are part of a SW RAID (MD_MAJOR)
1769 if (col_count > 3 &&
1770 major != LVM_BLK_MAJOR && major != NBD_MAJOR &&
1771 major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
1772 current += reads + writes;
1773 current_read += reads;
1774 current_write += writes;
1778 /* since the values in /proc/diststats are absolute, we have
1779 * to substract our last reading. The numbers stand for
1780 * "sectors read", and we therefore have to divide by two to
1782 int tot = ((double)(current-last)/2);
1783 int tot_read = ((double)(current_read-last_read)/2);
1784 int tot_write = ((double)(current_write-last_write)/2);
1786 if (last_read > current_read)
1788 if (last_write > current_write)
1791 if (last > current) {
1792 /* we hit this either if it's the very first time we
1793 * run this, or when /proc/diskstats overflows; while
1794 * 0 is not correct, it's at least not way off */
1798 last_read = current_read;
1799 last_write = current_write;
1802 diskio_read_value = tot_read;
1803 diskio_write_value = tot_write;
1808 /* Here come the IBM ACPI-specific things. For reference, see
1809 http://ibm-acpi.sourceforge.net/README
1810 If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
1826 The content of these files is described in detail in the aforementioned
1827 README - some of them also in the following functions accessing them.
1828 Peter Tarjan (ptarjan@citromail.hu)
1831 #define IBM_ACPI_DIR "/proc/acpi/ibm"
1833 void get_ibm_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1835 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
1836 /proc/acpi/ibm/fan looks like this (3 lines):
1839 commands: enable, disable
1840 Peter Tarjan (ptarjan@citromail.hu)
1843 if ( !p_client_buffer || client_buffer_size <= 0 )
1847 unsigned int speed=0;
1849 snprintf(fan, 127, "%s/fan",IBM_ACPI_DIR);
1851 fp = fopen(fan, "r");
1857 if (fgets(line, 255, fp) == NULL) break;
1858 if (sscanf(line, "speed: %d", &speed)) break;
1863 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", fan, strerror(errno));
1867 snprintf( p_client_buffer, client_buffer_size, "%d", speed );
1872 static double last_ibm_acpi_temp_time;
1873 void get_ibm_acpi_temps()
1875 /* get the measured temperatures from the temperature sensors
1876 on IBM/Lenovo laptops running the ibm acpi.
1877 There are 8 values in /proc/acpi/ibm/thermal, and according to
1878 http://ibm-acpi.sourceforge.net/README
1879 these mean the following (at least on an IBM R51...)
1880 0: CPU (also on the T series laptops)
1881 1: Mini PCI Module (?)
1883 3: GPU (also on the T series laptops)
1888 I'm not too sure about those with the question mark, but the values I'm
1889 reading from *my* thermal file (on a T42p) look realistic for the
1890 hdd and the battery.
1891 #5 and #7 are always -128.
1892 /proc/acpi/ibm/thermal looks like this (1 line):
1893 temperatures: 41 43 31 46 33 -128 29 -128
1894 Peter Tarjan (ptarjan@citromail.hu)
1897 /* don't update too often */
1898 if (current_update_time - last_ibm_acpi_temp_time < 10.00)
1902 last_ibm_acpi_temp_time = current_update_time;
1904 /* if ( !p_client_buffer || client_buffer_size <= 0 )
1910 snprintf(thermal, 127, "%s/thermal",IBM_ACPI_DIR);
1911 fp = fopen(thermal, "r");
1918 if (fgets(line, 255, fp) == NULL) break;
1919 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
1920 &ibm_acpi.temps[0], &ibm_acpi.temps[1],
1921 &ibm_acpi.temps[2], &ibm_acpi.temps[3],
1922 &ibm_acpi.temps[4], &ibm_acpi.temps[5],
1923 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) break;
1928 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", thermal, strerror(errno));
1936 void get_ibm_acpi_volume( char * p_client_buffer, size_t client_buffer_size )
1939 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
1940 "Volume" here is none of the mixer volumes, but a "master of masters"
1941 volume adjusted by the IBM volume keys.
1942 /proc/acpi/ibm/fan looks like this (4 lines):
1945 commands: up, down, mute
1946 commands: level <level> (<level> is 0-15)
1947 Peter Tarjan (ptarjan@citromail.hu)
1950 if ( !p_client_buffer || client_buffer_size <= 0 )
1956 snprintf(volume, 127, "%s/volume",IBM_ACPI_DIR);
1957 unsigned int vol=-1;
1960 fp = fopen(volume, "r");
1966 if (fgets(line, 255, fp) == NULL) break;
1967 if (sscanf(line, "level: %d", &vol)) continue;
1968 if (sscanf(line, "mute: %s", mute)) break;
1973 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", volume, strerror(errno));
1978 if (strcmp(mute, "on")==0)
1980 snprintf( p_client_buffer, client_buffer_size, "%s", "mute" );
1985 snprintf( p_client_buffer, client_buffer_size, "%d", vol );
1991 /*static FILE *fp=NULL;*/
1993 void get_ibm_acpi_brightness(char * p_client_buffer, size_t client_buffer_size)
1995 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
1996 /proc/acpi/ibm/brightness looks like this (3 lines):
1999 commands: level <level> (<level> is 0-7)
2000 Peter Tarjan (ptarjan@citromail.hu)
2003 if ( !p_client_buffer || client_buffer_size <= 0 )
2007 unsigned int brightness=0;
2009 snprintf(filename, 127, "%s/brightness",IBM_ACPI_DIR);
2011 fp = fopen(filename, "r");
2017 if (fgets(line, 255, fp) == NULL) break;
2018 if (sscanf(line, "level: %d", &brightness)) break;
2023 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", filename, strerror(errno));
2028 snprintf( p_client_buffer, client_buffer_size, "%d", brightness );
2033 void update_entropy (void)
2036 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
2037 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
2040 info.entropy.entropy_avail=0;
2041 info.entropy.poolsize=0;
2043 if ((fp1 = open_file (entropy_avail, &rep))==NULL)
2046 if ((fp2 = open_file (entropy_poolsize, &rep))==NULL)
2052 fscanf (fp1, "%u", &info.entropy.entropy_avail);
2053 fscanf (fp2, "%u", &info.entropy.poolsize);
2058 info.mask |= (1 << INFO_ENTROPY);