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_sysbus_sensor(const char *dir, const char *dev, const char *type, int n, int *div, char *devtype)
669 /* if i2c device is NULL or *, get first */
670 if (dev == NULL || strcmp(dev, "*") == 0) {
672 if (!get_first_file_in_a_directory(dir, buf, &rep))
677 /* change vol to in */
678 if (strcmp(type, "vol") == 0)
681 if (strcmp(type, "tempf") == 0) {
682 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, "temp", n);
684 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, type, n);
686 strncpy(devtype, path, 255);
689 fd = open(path, O_RDONLY);
691 CRIT_ERR("can't open '%s': %s\nplease check your device or remove this var from Conky", path, strerror(errno));
694 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
695 || strcmp(type, "tempf") == 0)
699 /* fan does not use *_div as a read divisor */
700 if (strcmp("fan", type) == 0)
703 /* test if *_div file exist, open it and use it as divisor */
704 if (strcmp(type, "tempf") == 0) {
705 snprintf(path, 255, "%s%s/%s%d_div", dir, "one", "two",
708 snprintf(path, 255, "%s%s/%s%d_div", dir, dev, type, n);
711 divfd = open(path, O_RDONLY);
716 divn = read(divfd, divbuf, 63);
717 /* should read until n == 0 but I doubt that kernel will give these
718 * in multiple pieces. :) */
728 double get_sysbus_info(int *fd, int div, char *devtype, char *type)
735 lseek(*fd, 0, SEEK_SET);
741 n = read(*fd, buf, 63);
742 /* should read until n == 0 but I doubt that kernel will give these
743 * in multiple pieces. :) */
750 *fd = open(devtype, O_RDONLY);
752 ERR("can't open '%s': %s", devtype, strerror(errno));
754 /* My dirty hack for computing CPU value
755 * Filedil, from forums.gentoo.org
757 /* if (strstr(devtype, "temp1_input") != NULL)
758 return -15.096+1.4893*(val / 1000.0); */
761 /* divide voltage and temperature by 1000 */
762 /* or if any other divisor is given, use that */
763 if (strcmp(type, "tempf") == 0) {
765 return ((val / div + 40) * 9.0 / 5) - 40;
767 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
769 return ((val + 40) * 9.0 / 5) - 40;
780 /* Prior to kernel version 2.6.12, the CPU fan speed was available
781 * in ADT746X_FAN_OLD, whereas later kernel versions provide this
782 * information in ADT746X_FAN.
784 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
785 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
787 void get_adt746x_fan( char * p_client_buffer, size_t client_buffer_size )
790 char adt746x_fan_state[64];
793 if ( !p_client_buffer || client_buffer_size <= 0 )
796 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
797 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL)
800 sprintf(adt746x_fan_state, "adt746x not found");
804 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
805 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
809 snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_fan_state );
813 /* Prior to kernel version 2.6.12, the CPU temperature was found
814 * in ADT746X_CPU_OLD, whereas later kernel versions provide this
815 * information in ADT746X_CPU.
817 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
818 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
820 void get_adt746x_cpu( char * p_client_buffer, size_t client_buffer_size )
823 char adt746x_cpu_state[64];
826 if ( !p_client_buffer || client_buffer_size <= 0 )
829 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
830 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL)
832 sprintf(adt746x_cpu_state, "adt746x not found");
836 fscanf(fp, "%2s", adt746x_cpu_state);
840 snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state );
844 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
846 /***********************************************************************/
848 * This file is part of x86info.
849 * (C) 2001 Dave Jones.
851 * Licensed under the terms of the GNU GPL License version 2.
853 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
854 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz>
857 #if defined(__i386) || defined(__x86_64)
858 __inline__ unsigned long long int rdtsc()
860 unsigned long long int x;
861 __asm__ volatile (".byte 0x0f, 0x31":"=A" (x));
866 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
867 void get_freq_dynamic( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor )
869 #if defined(__i386) || defined(__x86_64)
871 struct timeval tvstart, tvstop;
872 unsigned long long cycles[2]; /* gotta be 64 bit */
873 unsigned int microseconds; /* total time taken */
875 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
878 memset(&tz, 0, sizeof(tz));
880 /* get this function in cached memory */
881 gettimeofday(&tvstart, &tz);
883 gettimeofday(&tvstart, &tz);
885 /* we don't trust that this is any specific length of time */
888 gettimeofday(&tvstop, &tz);
889 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
890 (tvstop.tv_usec - tvstart.tv_usec);
892 snprintf( p_client_buffer, client_buffer_size, p_format, (float)((cycles[1] - cycles[0]) / microseconds) / divisor );
895 /* FIXME: hardwired: get freq for first cpu!
896 this whole function needs to be rethought and redone for
897 multi-cpu/multi-core/multi-threaded environments and
898 arbitrary combinations thereof
900 get_freq( p_client_buffer, client_buffer_size, p_format, divisor, 1 );
906 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
907 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
909 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
910 char get_freq( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
918 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
923 char current_freq_file[128];
924 snprintf(current_freq_file, 127, "%s/cpu%d/%s",CPUFREQ_PREFIX, cpu-1, CPUFREQ_POSTFIX);
925 f = fopen(current_freq_file, "r");
928 /* if there's a cpufreq /sys node, read the current frequency from this node;
929 * divide by 1000 to get Mhz. */
930 if (fgets(s, sizeof(s), f)) {
931 s[strlen(s)-1] = '\0';
932 freq = strtod(s, NULL);
935 snprintf( p_client_buffer, client_buffer_size, p_format, (freq/1000)/divisor );
940 f = open_file("/proc/cpuinfo", &rep); //open the CPU information file
942 perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
946 while (fgets(s, sizeof(s), f) != NULL){ //read the file
948 #if defined(__i386) || defined(__x86_64)
949 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) { //and search for the cpu mhz
952 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) { // different on alpha
954 if (strncmp(s, "clock", 5) == 0 && cpu == 0) { // this is different on ppc for some reason
955 #endif // defined(__alpha)
956 #endif // defined(__i386) || defined(__x86_64)
958 strcpy(frequency, strchr(s, ':') + 2); //copy just the number
960 frequency[strlen(frequency) - 6] = '\0';// strip " est.\n"
961 freq = strtod(frequency, NULL)/1000000; // kernel reports in Hz
963 frequency[strlen(frequency) - 1] = '\0'; // strip \n
964 freq = strtod(frequency, NULL);
968 if (strncmp(s, "processor", 9) == 0) {
976 snprintf( p_client_buffer, client_buffer_size, p_format, (float)freq/divisor );
980 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
982 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
983 char get_voltage( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
985 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks
997 /* Peter Tarjan (ptarjan@citromail.hu) */
1002 char current_freq_file[128];
1006 /* build the voltage file name */
1008 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
1009 CPUFREQ_PREFIX, cpu, CPUFREQ_POSTFIX);
1011 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
1014 /* read the current cpu frequency from the /sys node */
1015 f = fopen(current_freq_file, "r");
1017 if (fgets(s, sizeof(s), f)) {
1018 s[strlen(s)-1] = '\0';
1019 freq = strtod(s, NULL);
1023 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1024 perror("get_voltage()");
1031 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
1032 CPUFREQ_PREFIX, cpu, CPUFREQ_VOLTAGE);
1034 /* use the current cpu frequency to find the corresponding voltage */
1035 f = fopen(current_freq_file, "r");
1040 if (fgets(line, 255, f) == NULL) break;
1041 sscanf(line, "%d %d", &freq_comp, &voltage);
1042 if(freq_comp == freq) break;
1046 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1047 perror("get_voltage()");
1053 snprintf( p_client_buffer, client_buffer_size, p_format, (float)voltage/divisor );
1058 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1060 void get_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1067 if ( !p_client_buffer || client_buffer_size <= 0 )
1070 /* yeah, slow... :/ */
1071 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep))
1073 snprintf( p_client_buffer, client_buffer_size, "no fans?" );
1077 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf );
1079 fp = open_file(buf2, &rep);
1081 snprintf( p_client_buffer, client_buffer_size, "can't open fan's state file" );
1084 memset(buf,0,sizeof(buf));
1085 fscanf(fp, "%*s %99s", buf);
1088 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1093 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1095 void get_acpi_ac_adapter( char * p_client_buffer, size_t client_buffer_size )
1102 if ( !p_client_buffer || client_buffer_size <= 0 )
1105 /* yeah, slow... :/ */
1106 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep))
1108 snprintf( p_client_buffer, client_buffer_size, "no ac_adapters?" );
1112 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf );
1115 fp = open_file(buf2, &rep);
1117 snprintf( p_client_buffer, client_buffer_size, "No ac adapter found.... where is it?" );
1120 memset(buf,0,sizeof(buf));
1121 fscanf(fp, "%*s %99s", buf );
1124 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1130 /proc/acpi/thermal_zone/THRM/cooling_mode
1131 cooling mode: active
1132 /proc/acpi/thermal_zone/THRM/polling_frequency
1134 /proc/acpi/thermal_zone/THRM/state
1136 /proc/acpi/thermal_zone/THRM/temperature
1138 /proc/acpi/thermal_zone/THRM/trip_points
1140 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1143 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1144 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1146 int open_acpi_temperature(const char *name)
1152 if (name == NULL || strcmp(name, "*") == 0) {
1154 if (!get_first_file_in_a_directory
1155 (ACPI_THERMAL_DIR, buf, &rep))
1160 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1162 fd = open(path, O_RDONLY);
1164 ERR("can't open '%s': %s", path, strerror(errno));
1169 static double last_acpi_temp;
1170 static double last_acpi_temp_time;
1172 double get_acpi_temperature(int fd)
1177 /* don't update acpi temperature too often */
1178 if (current_update_time - last_acpi_temp_time < 11.32) {
1179 return last_acpi_temp;
1181 last_acpi_temp_time = current_update_time;
1183 /* seek to beginning */
1184 lseek(fd, 0, SEEK_SET);
1190 n = read(fd, buf, 255);
1192 ERR("can't read fd %d: %s", fd, strerror(errno));
1195 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1199 return last_acpi_temp;
1203 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1205 design capacity: 4400 mAh
1206 last full capacity: 4064 mAh
1207 battery technology: rechargeable
1208 design voltage: 14800 mV
1209 design capacity warning: 300 mAh
1210 design capacity low: 200 mAh
1211 capacity granularity 1: 32 mAh
1212 capacity granularity 2: 32 mAh
1214 serial number: 16922
1220 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1223 charging state: unknown
1225 remaining capacity: 4064 mAh
1226 present voltage: 16608 mV
1230 2213<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1231 2213<@jupet kellari ö> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1232 2213<@jupet kellari ö> (-1 ollee ei akkua kiinni, koska akku on pöydällä)
1233 2214<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1234 2214<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1236 2238<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1237 2239<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1239 2240<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori päällä
1240 2241<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori päällä mutta ilman verkkovirtaa
1243 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1244 #define APM_PATH "/proc/apm"
1245 #define MAX_BATTERY_COUNT 4
1247 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT];
1248 static FILE *apm_bat_fp[MAX_BATTERY_COUNT];
1250 static int batteries_initialized = 0;
1251 static char batteries[MAX_BATTERY_COUNT][32];
1253 static int acpi_last_full[MAX_BATTERY_COUNT];
1254 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1256 static char last_battery_str[MAX_BATTERY_COUNT][64]; /* e.g. "charging 75%" */
1257 static char last_battery_time_str[MAX_BATTERY_COUNT][64]; /* e.g. "3h 15m" */
1259 static double last_battery_time[MAX_BATTERY_COUNT];
1261 static int last_battery_perct[MAX_BATTERY_COUNT];
1262 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1265 void init_batteries(void)
1268 if(batteries_initialized)
1270 for(idx = 0; idx < MAX_BATTERY_COUNT; idx++)
1271 batteries[idx][0] = '\0';
1272 batteries_initialized = 1;
1275 int get_battery_idx(const char *bat)
1278 for(idx = 0; idx < MAX_BATTERY_COUNT; idx++)
1279 if(!strlen(batteries[idx]) || !strcmp(batteries[idx], bat))
1282 /* if not found, enter a new entry */
1283 if(!strlen(batteries[idx]))
1284 snprintf(batteries[idx], 31, "%s", bat);
1289 void get_battery_stuff(char *buf, unsigned int n, const char *bat, int item)
1291 static int idx, rep = 0, rep2 = 0;
1292 char acpi_path[128];
1293 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1297 idx = get_battery_idx(bat);
1299 /* don't update battery too often */
1300 if (current_update_time - last_battery_time[idx] < 29.5)
1301 goto set_return_value;
1303 last_battery_time[idx] = current_update_time;
1305 memset (last_battery_str[idx], 0, sizeof (last_battery_str[idx]));
1306 memset (last_battery_time_str[idx], 0, sizeof (last_battery_time_str[idx]));
1308 /* first try ACPI */
1310 if (acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1311 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1313 if (acpi_bat_fp[idx] != NULL) {
1314 int present_rate = -1;
1315 int remaining_capacity = -1;
1316 char charging_state[64];
1319 /* read last full capacity if it's zero */
1320 if (acpi_last_full[idx] == 0) {
1325 ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1326 fp = open_file(path, &rep);
1330 if (fgets(b, 256, fp) == NULL)
1332 if (sscanf(b, "last full capacity: %d", &acpi_last_full[idx]) != 0) {
1341 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1343 strcpy(charging_state, "unknown");
1345 while (!feof(acpi_bat_fp[idx])) {
1347 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL)
1350 /* let's just hope units are ok */
1351 if (strncmp (buf, "present:", 8) == 0)
1352 sscanf(buf, "present: %4s", present);
1353 else if (strncmp (buf, "charging state:", 15) == 0)
1354 sscanf(buf, "charging state: %63s", charging_state);
1355 else if (strncmp (buf, "present rate:", 13) == 0)
1356 sscanf(buf, "present rate: %d", &present_rate);
1357 else if (strncmp(buf, "remaining capacity:", 19) == 0)
1358 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1361 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1362 if (remaining_capacity > acpi_last_full[idx])
1363 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1366 if (strcmp(present, "no") == 0) {
1367 strncpy(last_battery_str[idx], "not present", 64);
1370 else if (strcmp(charging_state, "charging") == 0) {
1371 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1372 /* e.g. charging 75% */
1373 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %i%%",
1374 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1376 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1377 (long) (((acpi_last_full[idx] - remaining_capacity) * 3600) /
1379 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1380 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %d%%",
1381 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1383 strncpy(last_battery_str[idx], "charging", sizeof(last_battery_str[idx])-1);
1387 else if (strncmp(charging_state, "discharging", 64) == 0) {
1388 if (present_rate > 0) {
1389 /* e.g. discharging 35% */
1390 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "discharging %i%%",
1391 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1393 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1394 (long) ((remaining_capacity * 3600) / present_rate));
1395 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1396 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "full");
1398 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1400 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1404 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1405 else if (strncmp(charging_state, "charged", 64) == 0) {
1406 /* Below happens with the second battery on my X40,
1407 * when the second one is empty and the first one
1409 if (remaining_capacity == 0)
1410 strcpy(last_battery_str[idx], "empty");
1412 strcpy(last_battery_str[idx], "charged");
1414 /* unknown, probably full / AC */
1416 if (acpi_last_full[idx] != 0
1417 && remaining_capacity != acpi_last_full[idx])
1418 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1419 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1421 strncpy(last_battery_str[idx], "AC", 64);
1425 if (apm_bat_fp[idx] == NULL)
1426 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1428 if (apm_bat_fp[idx] != NULL) {
1429 int ac, status, flag, life;
1431 fscanf(apm_bat_fp[idx],
1432 "%*s %*s %*x %x %x %x %d%%",
1433 &ac, &status, &flag, &life);
1436 /* could check now that there is ac */
1437 snprintf(last_battery_str[idx], 64, "AC");
1438 } else if (ac && life != 100) { /* could check that status==3 here? */
1439 snprintf(last_battery_str[idx], 64,
1440 "charging %d%%", life);
1442 snprintf(last_battery_str[idx], 64, "%d%%",
1446 /* it seemed to buffer it so file must be closed (or could use syscalls
1447 * directly but I don't feel like coding it now) */
1448 fclose(apm_bat_fp[idx]);
1449 apm_bat_fp[idx] = NULL;
1455 case BATTERY_STATUS:
1457 snprintf(buf, n, "%s", last_battery_str[idx]);
1462 snprintf(buf, n, "%s", last_battery_time_str[idx]);
1471 int get_battery_perct(const char *bat)
1475 char acpi_path[128];
1476 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1480 idx = get_battery_idx(bat);
1482 /* don't update battery too often */
1483 if (current_update_time - last_battery_perct_time[idx] < 30) {
1484 return last_battery_perct[idx];
1486 last_battery_perct_time[idx] = current_update_time;
1488 /* Only check for ACPI */
1490 if (acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1491 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1493 int remaining_capacity = -1;
1494 if (acpi_bat_fp[idx] != NULL) {
1495 /* read last full capacity if it's zero */
1496 if (acpi_design_capacity[idx] == 0) {
1501 ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1502 fp = open_file(path, &rep);
1506 if (fgets(b, 256, fp) == NULL)
1508 if (sscanf(b, "last full capacity: %d", &acpi_design_capacity[idx]) != 0) {
1516 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1518 while (!feof(acpi_bat_fp[idx])) {
1520 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL)
1524 sscanf(buf, "remaining capacity: %d",
1525 &remaining_capacity);
1528 if(remaining_capacity < 0)
1530 /* compute the battery percentage */
1531 last_battery_perct[idx] =
1532 (int) (((float)remaining_capacity/acpi_design_capacity[idx]) * 100);
1533 return last_battery_perct[idx];
1536 int get_battery_perct_bar(const char *bar)
1539 get_battery_perct(bar);
1540 idx = get_battery_idx(bar);
1541 return (int) (last_battery_perct[idx] * 2.56 - 1);
1546 /* On Apple powerbook and ibook:
1547 $ cat /proc/pmu/battery_0
1554 $ cat /proc/pmu/info
1555 PMU driver version : 2
1556 PMU firmware version : 0c
1561 /* defines as in <linux/pmu.h> */
1562 #define PMU_BATT_PRESENT 0x00000001
1563 #define PMU_BATT_CHARGING 0x00000002
1565 static FILE* pmu_battery_fp;
1566 static FILE* pmu_info_fp;
1567 static char pb_battery_info[3][32];
1568 static double pb_battery_info_update;
1570 #define PMU_PATH "/proc/pmu"
1571 void get_powerbook_batt_info(char *buf, size_t n, int i)
1574 const char* batt_path = PMU_PATH "/battery_0";
1575 const char* info_path = PMU_PATH "/info";
1576 int flags, charge, max_charge, ac = -1;
1579 /* don't update battery too often */
1580 if (current_update_time - pb_battery_info_update < 29.5) {
1581 snprintf(buf, n, "%s", pb_battery_info[i]);
1584 pb_battery_info_update = current_update_time;
1586 if (pmu_battery_fp == NULL)
1587 pmu_battery_fp = open_file(batt_path, &rep);
1589 if (pmu_battery_fp != NULL) {
1590 rewind(pmu_battery_fp);
1591 while (!feof(pmu_battery_fp)) {
1593 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL)
1597 sscanf(buf, "flags : %8x", &flags);
1598 else if (buf[0] == 'c' && buf[1] == 'h')
1599 sscanf(buf, "charge : %d", &charge);
1600 else if (buf[0] == 'm')
1601 sscanf(buf, "max_charge : %d", &max_charge);
1602 else if (buf[0] == 't')
1603 sscanf(buf, "time rem. : %ld", &time);
1606 if (pmu_info_fp == NULL)
1607 pmu_info_fp = open_file(info_path, &rep);
1609 if (pmu_info_fp != NULL) {
1610 rewind(pmu_info_fp);
1611 while (!feof(pmu_info_fp)) {
1613 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL)
1616 sscanf(buf, "AC Power : %d", &ac);
1619 /* update status string */
1620 if ((ac && !(flags & PMU_BATT_PRESENT)))
1621 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
1622 else if (ac && (flags & PMU_BATT_PRESENT)
1623 && !(flags & PMU_BATT_CHARGING))
1624 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
1625 else if ((flags & PMU_BATT_PRESENT)
1626 && (flags & PMU_BATT_CHARGING))
1627 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
1629 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
1631 /* update percentage string */
1633 pb_battery_info[PB_BATT_PERCENT][0] = 0;
1635 snprintf(pb_battery_info[PB_BATT_PERCENT],
1636 sizeof(pb_battery_info[PB_BATT_PERCENT]),
1637 "%d%%", (charge * 100)/max_charge);
1639 /* update time string */
1640 if (time == 0) /* fully charged or battery not present */
1641 pb_battery_info[PB_BATT_TIME][0] = 0;
1642 else if (time < 60*60) /* don't show secs */
1643 format_seconds_short(pb_battery_info[PB_BATT_TIME],
1644 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1646 format_seconds(pb_battery_info[PB_BATT_TIME],
1647 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1649 snprintf(buf, n, "%s", pb_battery_info[i]);
1654 show_nice_processes = 1;
1655 process_find_top(info.cpu, info.memu);
1656 info.first_process = get_first_process();
1661 * The following ifdefs were adapted from gkrellm
1663 #include <linux/major.h>
1665 #if ! defined (MD_MAJOR)
1669 #if !defined(LVM_BLK_MAJOR)
1670 #define LVM_BLK_MAJOR 58
1673 #if !defined(NBD_MAJOR)
1674 #define NBD_MAJOR 43
1677 void update_diskio()
1679 static unsigned int last = UINT_MAX;
1680 static unsigned int last_read = UINT_MAX;
1681 static unsigned int last_write = UINT_MAX;
1687 unsigned int current = 0;
1688 unsigned int current_read = 0;
1689 unsigned int current_write = 0;
1690 unsigned int reads, writes = 0;
1693 if (!(fp =open_file("/proc/diskstats", &rep))) {
1698 /* read reads and writes from all disks (minor = 0), including
1699 * cd-roms and floppies, and summ them up
1702 fgets(buf, 512, fp);
1703 col_count = sscanf(buf, "%u %u %*s %*u %*u %u %*u %*u %*u %u",
1704 &major, &minor, &reads, &writes);
1705 /* ignore subdevices (they have only 3 matching entries in their line)
1706 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
1708 * XXX ignore devices which are part of a SW RAID (MD_MAJOR)
1710 if (col_count > 3 &&
1711 major != LVM_BLK_MAJOR && major != NBD_MAJOR &&
1712 major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
1713 current += reads + writes;
1714 current_read += reads;
1715 current_write += writes;
1719 /* since the values in /proc/diststats are absolute, we have
1720 * to substract our last reading. The numbers stand for
1721 * "sectors read", and we therefore have to divide by two to
1723 int tot = ((double)(current-last)/2);
1724 int tot_read = ((double)(current_read-last_read)/2);
1725 int tot_write = ((double)(current_write-last_write)/2);
1727 if (last_read > current_read)
1729 if (last_write > current_write)
1732 if (last > current) {
1733 /* we hit this either if it's the very first time we
1734 * run this, or when /proc/diskstats overflows; while
1735 * 0 is not correct, it's at least not way off */
1739 last_read = current_read;
1740 last_write = current_write;
1743 diskio_read_value = tot_read;
1744 diskio_write_value = tot_write;
1749 /* Here come the IBM ACPI-specific things. For reference, see
1750 http://ibm-acpi.sourceforge.net/README
1751 If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
1767 The content of these files is described in detail in the aforementioned
1768 README - some of them also in the following functions accessing them.
1769 Peter Tarjan (ptarjan@citromail.hu)
1772 #define IBM_ACPI_DIR "/proc/acpi/ibm"
1774 void get_ibm_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1776 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
1777 /proc/acpi/ibm/fan looks like this (3 lines):
1780 commands: enable, disable
1781 Peter Tarjan (ptarjan@citromail.hu)
1784 if ( !p_client_buffer || client_buffer_size <= 0 )
1788 unsigned int speed=0;
1790 snprintf(fan, 127, "%s/fan",IBM_ACPI_DIR);
1792 fp = fopen(fan, "r");
1798 if (fgets(line, 255, fp) == NULL) break;
1799 if (sscanf(line, "speed: %d", &speed)) break;
1804 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", fan, strerror(errno));
1808 snprintf( p_client_buffer, client_buffer_size, "%d", speed );
1813 static double last_ibm_acpi_temp_time;
1814 void get_ibm_acpi_temps()
1816 /* get the measured temperatures from the temperature sensors
1817 on IBM/Lenovo laptops running the ibm acpi.
1818 There are 8 values in /proc/acpi/ibm/thermal, and according to
1819 http://ibm-acpi.sourceforge.net/README
1820 these mean the following (at least on an IBM R51...)
1821 0: CPU (also on the T series laptops)
1822 1: Mini PCI Module (?)
1824 3: GPU (also on the T series laptops)
1829 I'm not too sure about those with the question mark, but the values I'm
1830 reading from *my* thermal file (on a T42p) look realistic for the
1831 hdd and the battery.
1832 #5 and #7 are always -128.
1833 /proc/acpi/ibm/thermal looks like this (1 line):
1834 temperatures: 41 43 31 46 33 -128 29 -128
1835 Peter Tarjan (ptarjan@citromail.hu)
1838 /* don't update too often */
1839 if (current_update_time - last_ibm_acpi_temp_time < 10.00)
1843 last_ibm_acpi_temp_time = current_update_time;
1845 /* if ( !p_client_buffer || client_buffer_size <= 0 )
1851 snprintf(thermal, 127, "%s/thermal",IBM_ACPI_DIR);
1852 fp = fopen(thermal, "r");
1859 if (fgets(line, 255, fp) == NULL) break;
1860 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
1861 &ibm_acpi.temps[0], &ibm_acpi.temps[1],
1862 &ibm_acpi.temps[2], &ibm_acpi.temps[3],
1863 &ibm_acpi.temps[4], &ibm_acpi.temps[5],
1864 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) break;
1869 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", thermal, strerror(errno));
1877 void get_ibm_acpi_volume( char * p_client_buffer, size_t client_buffer_size )
1880 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
1881 "Volume" here is none of the mixer volumes, but a "master of masters"
1882 volume adjusted by the IBM volume keys.
1883 /proc/acpi/ibm/fan looks like this (4 lines):
1886 commands: up, down, mute
1887 commands: level <level> (<level> is 0-15)
1888 Peter Tarjan (ptarjan@citromail.hu)
1891 if ( !p_client_buffer || client_buffer_size <= 0 )
1897 snprintf(volume, 127, "%s/volume",IBM_ACPI_DIR);
1898 unsigned int vol=-1;
1901 fp = fopen(volume, "r");
1907 if (fgets(line, 255, fp) == NULL) break;
1908 if (sscanf(line, "level: %d", &vol)) continue;
1909 if (sscanf(line, "mute: %s", mute)) break;
1914 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", volume, strerror(errno));
1919 if (strcmp(mute, "on")==0)
1921 snprintf( p_client_buffer, client_buffer_size, "%s", "mute" );
1926 snprintf( p_client_buffer, client_buffer_size, "%d", vol );
1932 /*static FILE *fp=NULL;*/
1934 void get_ibm_acpi_brightness(char * p_client_buffer, size_t client_buffer_size)
1936 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
1937 /proc/acpi/ibm/brightness looks like this (3 lines):
1940 commands: level <level> (<level> is 0-7)
1941 Peter Tarjan (ptarjan@citromail.hu)
1944 if ( !p_client_buffer || client_buffer_size <= 0 )
1948 unsigned int brightness=0;
1950 snprintf(filename, 127, "%s/brightness",IBM_ACPI_DIR);
1952 fp = fopen(filename, "r");
1958 if (fgets(line, 255, fp) == NULL) break;
1959 if (sscanf(line, "level: %d", &brightness)) break;
1964 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", filename, strerror(errno));
1969 snprintf( p_client_buffer, client_buffer_size, "%d", brightness );
1974 void update_entropy (void)
1977 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
1978 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
1981 info.entropy.entropy_avail=0;
1982 info.entropy.poolsize=0;
1984 if ((fp1 = open_file (entropy_avail, &rep))==NULL)
1987 if ((fp2 = open_file (entropy_poolsize, &rep))==NULL)
1993 fscanf (fp1, "%u", &info.entropy.entropy_avail);
1994 fscanf (fp2, "%u", &info.entropy.poolsize);
1999 info.mask |= (1 << INFO_ENTROPY);