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_sysfs_sensor(const char *dir, const char *dev, const char *type, int n, int *div, char *devtype)
669 memset (buf, 0, sizeof(buf));
671 /* if device is NULL or *, get first */
672 if (dev == NULL || strcmp(dev, "*") == 0) {
674 if (!get_first_file_in_a_directory(dir, buf, &rep))
679 if (strcmp (dir, "/sys/class/hwmon/")==0) {
681 /* buf holds result from get_first_file_in_a_directory() above,
682 * e.g. "hwmon0" -- append "/device" */
683 strcat (buf,"/device");
686 /* dev holds device number N as a string,
687 * e.g. "0", -- convert to "hwmon0/device" */
688 sprintf (buf,"hwmon%s/device",dev);
693 /* change vol to in */
694 if (strcmp(type, "vol") == 0)
697 if (strcmp(type, "tempf") == 0) {
698 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, "temp", n);
700 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, type, n);
702 strncpy(devtype, path, 255);
705 fd = open(path, O_RDONLY);
707 CRIT_ERR("can't open '%s': %s\nplease check your device or remove this var from Conky",
708 path, strerror(errno));
711 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
712 || strcmp(type, "tempf") == 0)
716 /* fan does not use *_div as a read divisor */
717 if (strcmp("fan", type) == 0)
720 /* test if *_div file exist, open it and use it as divisor */
721 if (strcmp(type, "tempf") == 0) {
722 snprintf(path, 255, "%s%s/%s%d_div", dir, "one", "two",
725 snprintf(path, 255, "%s%s/%s%d_div", dir, dev, type, n);
728 divfd = open(path, O_RDONLY);
733 divn = read(divfd, divbuf, 63);
734 /* should read until n == 0 but I doubt that kernel will give these
735 * in multiple pieces. :) */
745 double get_sysfs_info(int *fd, int div, char *devtype, char *type)
752 lseek(*fd, 0, SEEK_SET);
758 n = read(*fd, buf, 63);
759 /* should read until n == 0 but I doubt that kernel will give these
760 * in multiple pieces. :) */
767 *fd = open(devtype, O_RDONLY);
769 ERR("can't open '%s': %s", devtype, strerror(errno));
771 /* My dirty hack for computing CPU value
772 * Filedil, from forums.gentoo.org
774 /* if (strstr(devtype, "temp1_input") != NULL)
775 return -15.096+1.4893*(val / 1000.0); */
778 /* divide voltage and temperature by 1000 */
779 /* or if any other divisor is given, use that */
780 if (strcmp(type, "tempf") == 0) {
782 return ((val / div + 40) * 9.0 / 5) - 40;
784 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
786 return ((val + 40) * 9.0 / 5) - 40;
797 /* Prior to kernel version 2.6.12, the CPU fan speed was available
798 * in ADT746X_FAN_OLD, whereas later kernel versions provide this
799 * information in ADT746X_FAN.
801 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
802 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
804 void get_adt746x_fan( char * p_client_buffer, size_t client_buffer_size )
807 char adt746x_fan_state[64];
810 if ( !p_client_buffer || client_buffer_size <= 0 )
813 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
814 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL)
817 sprintf(adt746x_fan_state, "adt746x not found");
821 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
822 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
826 snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_fan_state );
830 /* Prior to kernel version 2.6.12, the CPU temperature was found
831 * in ADT746X_CPU_OLD, whereas later kernel versions provide this
832 * information in ADT746X_CPU.
834 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
835 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
837 void get_adt746x_cpu( char * p_client_buffer, size_t client_buffer_size )
840 char adt746x_cpu_state[64];
843 if ( !p_client_buffer || client_buffer_size <= 0 )
846 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
847 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL)
849 sprintf(adt746x_cpu_state, "adt746x not found");
853 fscanf(fp, "%2s", adt746x_cpu_state);
857 snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state );
861 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
863 /***********************************************************************/
865 * This file is part of x86info.
866 * (C) 2001 Dave Jones.
868 * Licensed under the terms of the GNU GPL License version 2.
870 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
871 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz>
874 #if defined(__i386) || defined(__x86_64)
875 __inline__ unsigned long long int rdtsc()
877 unsigned long long int x;
878 __asm__ volatile (".byte 0x0f, 0x31":"=A" (x));
883 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
884 void get_freq_dynamic( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor )
886 #if defined(__i386) || defined(__x86_64)
888 struct timeval tvstart, tvstop;
889 unsigned long long cycles[2]; /* gotta be 64 bit */
890 unsigned int microseconds; /* total time taken */
892 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
895 memset(&tz, 0, sizeof(tz));
897 /* get this function in cached memory */
898 gettimeofday(&tvstart, &tz);
900 gettimeofday(&tvstart, &tz);
902 /* we don't trust that this is any specific length of time */
905 gettimeofday(&tvstop, &tz);
906 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
907 (tvstop.tv_usec - tvstart.tv_usec);
909 snprintf( p_client_buffer, client_buffer_size, p_format, (float)((cycles[1] - cycles[0]) / microseconds) / divisor );
912 /* FIXME: hardwired: get freq for first cpu!
913 this whole function needs to be rethought and redone for
914 multi-cpu/multi-core/multi-threaded environments and
915 arbitrary combinations thereof
917 get_freq( p_client_buffer, client_buffer_size, p_format, divisor, 1 );
923 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
924 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
926 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
927 char get_freq( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
935 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
940 char current_freq_file[128];
941 snprintf(current_freq_file, 127, "%s/cpu%d/%s",CPUFREQ_PREFIX, cpu-1, CPUFREQ_POSTFIX);
942 f = fopen(current_freq_file, "r");
945 /* if there's a cpufreq /sys node, read the current frequency from this node;
946 * divide by 1000 to get Mhz. */
947 if (fgets(s, sizeof(s), f)) {
948 s[strlen(s)-1] = '\0';
949 freq = strtod(s, NULL);
952 snprintf( p_client_buffer, client_buffer_size, p_format, (freq/1000)/divisor );
957 f = open_file("/proc/cpuinfo", &rep); //open the CPU information file
959 perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
963 while (fgets(s, sizeof(s), f) != NULL){ //read the file
965 #if defined(__i386) || defined(__x86_64)
966 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) { //and search for the cpu mhz
969 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) { // different on alpha
971 if (strncmp(s, "clock", 5) == 0 && cpu == 0) { // this is different on ppc for some reason
972 #endif // defined(__alpha)
973 #endif // defined(__i386) || defined(__x86_64)
975 strcpy(frequency, strchr(s, ':') + 2); //copy just the number
977 frequency[strlen(frequency) - 6] = '\0';// strip " est.\n"
978 freq = strtod(frequency, NULL)/1000000; // kernel reports in Hz
980 frequency[strlen(frequency) - 1] = '\0'; // strip \n
981 freq = strtod(frequency, NULL);
985 if (strncmp(s, "processor", 9) == 0) {
993 snprintf( p_client_buffer, client_buffer_size, p_format, (float)freq/divisor );
997 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
999 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
1000 char get_voltage( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
1002 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks
1003 something like this:
1014 /* Peter Tarjan (ptarjan@citromail.hu) */
1019 char current_freq_file[128];
1023 /* build the voltage file name */
1025 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
1026 CPUFREQ_PREFIX, cpu, CPUFREQ_POSTFIX);
1028 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
1031 /* read the current cpu frequency from the /sys node */
1032 f = fopen(current_freq_file, "r");
1034 if (fgets(s, sizeof(s), f)) {
1035 s[strlen(s)-1] = '\0';
1036 freq = strtod(s, NULL);
1040 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1041 perror("get_voltage()");
1048 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
1049 CPUFREQ_PREFIX, cpu, CPUFREQ_VOLTAGE);
1051 /* use the current cpu frequency to find the corresponding voltage */
1052 f = fopen(current_freq_file, "r");
1057 if (fgets(line, 255, f) == NULL) break;
1058 sscanf(line, "%d %d", &freq_comp, &voltage);
1059 if(freq_comp == freq) break;
1063 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1064 perror("get_voltage()");
1070 snprintf( p_client_buffer, client_buffer_size, p_format, (float)voltage/divisor );
1075 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1077 void get_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1084 if ( !p_client_buffer || client_buffer_size <= 0 )
1087 /* yeah, slow... :/ */
1088 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep))
1090 snprintf( p_client_buffer, client_buffer_size, "no fans?" );
1094 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf );
1096 fp = open_file(buf2, &rep);
1098 snprintf( p_client_buffer, client_buffer_size, "can't open fan's state file" );
1101 memset(buf,0,sizeof(buf));
1102 fscanf(fp, "%*s %99s", buf);
1105 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1110 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1112 void get_acpi_ac_adapter( char * p_client_buffer, size_t client_buffer_size )
1119 if ( !p_client_buffer || client_buffer_size <= 0 )
1122 /* yeah, slow... :/ */
1123 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep))
1125 snprintf( p_client_buffer, client_buffer_size, "no ac_adapters?" );
1129 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf );
1132 fp = open_file(buf2, &rep);
1134 snprintf( p_client_buffer, client_buffer_size, "No ac adapter found.... where is it?" );
1137 memset(buf,0,sizeof(buf));
1138 fscanf(fp, "%*s %99s", buf );
1141 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1147 /proc/acpi/thermal_zone/THRM/cooling_mode
1148 cooling mode: active
1149 /proc/acpi/thermal_zone/THRM/polling_frequency
1151 /proc/acpi/thermal_zone/THRM/state
1153 /proc/acpi/thermal_zone/THRM/temperature
1155 /proc/acpi/thermal_zone/THRM/trip_points
1157 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1160 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1161 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1163 int open_acpi_temperature(const char *name)
1169 if (name == NULL || strcmp(name, "*") == 0) {
1171 if (!get_first_file_in_a_directory
1172 (ACPI_THERMAL_DIR, buf, &rep))
1177 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1179 fd = open(path, O_RDONLY);
1181 ERR("can't open '%s': %s", path, strerror(errno));
1186 static double last_acpi_temp;
1187 static double last_acpi_temp_time;
1189 double get_acpi_temperature(int fd)
1194 /* don't update acpi temperature too often */
1195 if (current_update_time - last_acpi_temp_time < 11.32) {
1196 return last_acpi_temp;
1198 last_acpi_temp_time = current_update_time;
1200 /* seek to beginning */
1201 lseek(fd, 0, SEEK_SET);
1207 n = read(fd, buf, 255);
1209 ERR("can't read fd %d: %s", fd, strerror(errno));
1212 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1216 return last_acpi_temp;
1220 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1222 design capacity: 4400 mAh
1223 last full capacity: 4064 mAh
1224 battery technology: rechargeable
1225 design voltage: 14800 mV
1226 design capacity warning: 300 mAh
1227 design capacity low: 200 mAh
1228 capacity granularity 1: 32 mAh
1229 capacity granularity 2: 32 mAh
1231 serial number: 16922
1237 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1240 charging state: unknown
1242 remaining capacity: 4064 mAh
1243 present voltage: 16608 mV
1247 2213<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1248 2213<@jupet kellari ö> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1249 2213<@jupet kellari ö> (-1 ollee ei akkua kiinni, koska akku on pöydällä)
1250 2214<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1251 2214<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1253 2238<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1254 2239<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1256 2240<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori päällä
1257 2241<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori päällä mutta ilman verkkovirtaa
1260 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1261 #define APM_PATH "/proc/apm"
1262 #define MAX_BATTERY_COUNT 4
1264 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT];
1265 static FILE *apm_bat_fp[MAX_BATTERY_COUNT];
1267 static int batteries_initialized = 0;
1268 static char batteries[MAX_BATTERY_COUNT][32];
1270 static int acpi_last_full[MAX_BATTERY_COUNT];
1271 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1273 static char last_battery_str[MAX_BATTERY_COUNT][64]; /* e.g. "charging 75%" */
1274 static char last_battery_time_str[MAX_BATTERY_COUNT][64]; /* e.g. "3h 15m" */
1276 static double last_battery_time[MAX_BATTERY_COUNT];
1278 static int last_battery_perct[MAX_BATTERY_COUNT];
1279 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1282 void init_batteries(void)
1285 if(batteries_initialized)
1287 for(idx = 0; idx < MAX_BATTERY_COUNT; idx++)
1288 batteries[idx][0] = '\0';
1289 batteries_initialized = 1;
1292 int get_battery_idx(const char *bat)
1295 for(idx = 0; idx < MAX_BATTERY_COUNT; idx++)
1296 if(!strlen(batteries[idx]) || !strcmp(batteries[idx], bat))
1299 /* if not found, enter a new entry */
1300 if(!strlen(batteries[idx]))
1301 snprintf(batteries[idx], 31, "%s", bat);
1306 void get_battery_stuff(char *buf, unsigned int n, const char *bat, int item)
1308 static int idx, rep = 0, rep2 = 0;
1309 char acpi_path[128];
1310 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1314 idx = get_battery_idx(bat);
1316 /* don't update battery too often */
1317 if (current_update_time - last_battery_time[idx] < 29.5)
1318 goto set_return_value;
1320 last_battery_time[idx] = current_update_time;
1322 memset (last_battery_str[idx], 0, sizeof (last_battery_str[idx]));
1323 memset (last_battery_time_str[idx], 0, sizeof (last_battery_time_str[idx]));
1325 /* first try ACPI */
1327 if (acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1328 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1330 if (acpi_bat_fp[idx] != NULL) {
1331 int present_rate = -1;
1332 int remaining_capacity = -1;
1333 char charging_state[64];
1336 /* read last full capacity if it's zero */
1337 if (acpi_last_full[idx] == 0) {
1342 ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1343 fp = open_file(path, &rep);
1347 if (fgets(b, 256, fp) == NULL)
1349 if (sscanf(b, "last full capacity: %d", &acpi_last_full[idx]) != 0) {
1358 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1360 strcpy(charging_state, "unknown");
1362 while (!feof(acpi_bat_fp[idx])) {
1364 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL)
1367 /* let's just hope units are ok */
1368 if (strncmp (buf, "present:", 8) == 0)
1369 sscanf(buf, "present: %4s", present);
1370 else if (strncmp (buf, "charging state:", 15) == 0)
1371 sscanf(buf, "charging state: %63s", charging_state);
1372 else if (strncmp (buf, "present rate:", 13) == 0)
1373 sscanf(buf, "present rate: %d", &present_rate);
1374 else if (strncmp(buf, "remaining capacity:", 19) == 0)
1375 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1378 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1379 if (remaining_capacity > acpi_last_full[idx])
1380 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1383 if (strcmp(present, "no") == 0) {
1384 strncpy(last_battery_str[idx], "not present", 64);
1387 else if (strcmp(charging_state, "charging") == 0) {
1388 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1389 /* e.g. charging 75% */
1390 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %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) (((acpi_last_full[idx] - remaining_capacity) * 3600) /
1396 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1397 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %d%%",
1398 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1400 strncpy(last_battery_str[idx], "charging", sizeof(last_battery_str[idx])-1);
1404 else if (strncmp(charging_state, "discharging", 64) == 0) {
1405 if (present_rate > 0) {
1406 /* e.g. discharging 35% */
1407 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "discharging %i%%",
1408 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1410 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1411 (long) ((remaining_capacity * 3600) / present_rate));
1412 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1413 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "full");
1415 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1417 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1421 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1422 else if (strncmp(charging_state, "charged", 64) == 0) {
1423 /* Below happens with the second battery on my X40,
1424 * when the second one is empty and the first one
1426 if (remaining_capacity == 0)
1427 strcpy(last_battery_str[idx], "empty");
1429 strcpy(last_battery_str[idx], "charged");
1431 /* unknown, probably full / AC */
1433 if (acpi_last_full[idx] != 0
1434 && remaining_capacity != acpi_last_full[idx])
1435 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1436 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1438 strncpy(last_battery_str[idx], "AC", 64);
1442 if (apm_bat_fp[idx] == NULL)
1443 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1445 if (apm_bat_fp[idx] != NULL) {
1446 int ac, status, flag, life;
1448 fscanf(apm_bat_fp[idx],
1449 "%*s %*s %*x %x %x %x %d%%",
1450 &ac, &status, &flag, &life);
1453 /* could check now that there is ac */
1454 snprintf(last_battery_str[idx], 64, "AC");
1455 } else if (ac && life != 100) { /* could check that status==3 here? */
1456 snprintf(last_battery_str[idx], 64,
1457 "charging %d%%", life);
1459 snprintf(last_battery_str[idx], 64, "%d%%",
1463 /* it seemed to buffer it so file must be closed (or could use syscalls
1464 * directly but I don't feel like coding it now) */
1465 fclose(apm_bat_fp[idx]);
1466 apm_bat_fp[idx] = NULL;
1472 case BATTERY_STATUS:
1474 snprintf(buf, n, "%s", last_battery_str[idx]);
1479 snprintf(buf, n, "%s", last_battery_time_str[idx]);
1488 int get_battery_perct(const char *bat)
1492 char acpi_path[128];
1493 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1497 idx = get_battery_idx(bat);
1499 /* don't update battery too often */
1500 if (current_update_time - last_battery_perct_time[idx] < 30) {
1501 return last_battery_perct[idx];
1503 last_battery_perct_time[idx] = current_update_time;
1505 /* Only check for ACPI */
1507 if (acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1508 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1510 int remaining_capacity = -1;
1511 if (acpi_bat_fp[idx] != NULL) {
1512 /* read last full capacity if it's zero */
1513 if (acpi_design_capacity[idx] == 0) {
1518 ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1519 fp = open_file(path, &rep);
1523 if (fgets(b, 256, fp) == NULL)
1525 if (sscanf(b, "last full capacity: %d", &acpi_design_capacity[idx]) != 0) {
1533 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1535 while (!feof(acpi_bat_fp[idx])) {
1537 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL)
1541 sscanf(buf, "remaining capacity: %d",
1542 &remaining_capacity);
1545 if(remaining_capacity < 0)
1547 /* compute the battery percentage */
1548 last_battery_perct[idx] =
1549 (int) (((float)remaining_capacity/acpi_design_capacity[idx]) * 100);
1550 return last_battery_perct[idx];
1553 int get_battery_perct_bar(const char *bar)
1556 get_battery_perct(bar);
1557 idx = get_battery_idx(bar);
1558 return (int) (last_battery_perct[idx] * 2.56 - 1);
1563 /* On Apple powerbook and ibook:
1564 $ cat /proc/pmu/battery_0
1571 $ cat /proc/pmu/info
1572 PMU driver version : 2
1573 PMU firmware version : 0c
1578 /* defines as in <linux/pmu.h> */
1579 #define PMU_BATT_PRESENT 0x00000001
1580 #define PMU_BATT_CHARGING 0x00000002
1582 static FILE* pmu_battery_fp;
1583 static FILE* pmu_info_fp;
1584 static char pb_battery_info[3][32];
1585 static double pb_battery_info_update;
1587 #define PMU_PATH "/proc/pmu"
1588 void get_powerbook_batt_info(char *buf, size_t n, int i)
1591 const char* batt_path = PMU_PATH "/battery_0";
1592 const char* info_path = PMU_PATH "/info";
1593 int flags, charge, max_charge, ac = -1;
1596 /* don't update battery too often */
1597 if (current_update_time - pb_battery_info_update < 29.5) {
1598 snprintf(buf, n, "%s", pb_battery_info[i]);
1601 pb_battery_info_update = current_update_time;
1603 if (pmu_battery_fp == NULL)
1604 pmu_battery_fp = open_file(batt_path, &rep);
1606 if (pmu_battery_fp != NULL) {
1607 rewind(pmu_battery_fp);
1608 while (!feof(pmu_battery_fp)) {
1610 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL)
1614 sscanf(buf, "flags : %8x", &flags);
1615 else if (buf[0] == 'c' && buf[1] == 'h')
1616 sscanf(buf, "charge : %d", &charge);
1617 else if (buf[0] == 'm')
1618 sscanf(buf, "max_charge : %d", &max_charge);
1619 else if (buf[0] == 't')
1620 sscanf(buf, "time rem. : %ld", &time);
1623 if (pmu_info_fp == NULL)
1624 pmu_info_fp = open_file(info_path, &rep);
1626 if (pmu_info_fp != NULL) {
1627 rewind(pmu_info_fp);
1628 while (!feof(pmu_info_fp)) {
1630 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL)
1633 sscanf(buf, "AC Power : %d", &ac);
1636 /* update status string */
1637 if ((ac && !(flags & PMU_BATT_PRESENT)))
1638 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
1639 else if (ac && (flags & PMU_BATT_PRESENT)
1640 && !(flags & PMU_BATT_CHARGING))
1641 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
1642 else if ((flags & PMU_BATT_PRESENT)
1643 && (flags & PMU_BATT_CHARGING))
1644 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
1646 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
1648 /* update percentage string */
1650 pb_battery_info[PB_BATT_PERCENT][0] = 0;
1652 snprintf(pb_battery_info[PB_BATT_PERCENT],
1653 sizeof(pb_battery_info[PB_BATT_PERCENT]),
1654 "%d%%", (charge * 100)/max_charge);
1656 /* update time string */
1657 if (time == 0) /* fully charged or battery not present */
1658 pb_battery_info[PB_BATT_TIME][0] = 0;
1659 else if (time < 60*60) /* don't show secs */
1660 format_seconds_short(pb_battery_info[PB_BATT_TIME],
1661 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1663 format_seconds(pb_battery_info[PB_BATT_TIME],
1664 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1666 snprintf(buf, n, "%s", pb_battery_info[i]);
1671 show_nice_processes = 1;
1672 process_find_top(info.cpu, info.memu);
1673 info.first_process = get_first_process();
1678 * The following ifdefs were adapted from gkrellm
1680 #include <linux/major.h>
1682 #if ! defined (MD_MAJOR)
1686 #if !defined(LVM_BLK_MAJOR)
1687 #define LVM_BLK_MAJOR 58
1690 #if !defined(NBD_MAJOR)
1691 #define NBD_MAJOR 43
1694 void update_diskio()
1696 static unsigned int last = UINT_MAX;
1697 static unsigned int last_read = UINT_MAX;
1698 static unsigned int last_write = UINT_MAX;
1704 unsigned int current = 0;
1705 unsigned int current_read = 0;
1706 unsigned int current_write = 0;
1707 unsigned int reads, writes = 0;
1710 if (!(fp =open_file("/proc/diskstats", &rep))) {
1715 /* read reads and writes from all disks (minor = 0), including
1716 * cd-roms and floppies, and summ them up
1719 fgets(buf, 512, fp);
1720 col_count = sscanf(buf, "%u %u %*s %*u %*u %u %*u %*u %*u %u",
1721 &major, &minor, &reads, &writes);
1722 /* ignore subdevices (they have only 3 matching entries in their line)
1723 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
1725 * XXX ignore devices which are part of a SW RAID (MD_MAJOR)
1727 if (col_count > 3 &&
1728 major != LVM_BLK_MAJOR && major != NBD_MAJOR &&
1729 major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
1730 current += reads + writes;
1731 current_read += reads;
1732 current_write += writes;
1736 /* since the values in /proc/diststats are absolute, we have
1737 * to substract our last reading. The numbers stand for
1738 * "sectors read", and we therefore have to divide by two to
1740 int tot = ((double)(current-last)/2);
1741 int tot_read = ((double)(current_read-last_read)/2);
1742 int tot_write = ((double)(current_write-last_write)/2);
1744 if (last_read > current_read)
1746 if (last_write > current_write)
1749 if (last > current) {
1750 /* we hit this either if it's the very first time we
1751 * run this, or when /proc/diskstats overflows; while
1752 * 0 is not correct, it's at least not way off */
1756 last_read = current_read;
1757 last_write = current_write;
1760 diskio_read_value = tot_read;
1761 diskio_write_value = tot_write;
1766 /* Here come the IBM ACPI-specific things. For reference, see
1767 http://ibm-acpi.sourceforge.net/README
1768 If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
1784 The content of these files is described in detail in the aforementioned
1785 README - some of them also in the following functions accessing them.
1786 Peter Tarjan (ptarjan@citromail.hu)
1789 #define IBM_ACPI_DIR "/proc/acpi/ibm"
1791 void get_ibm_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1793 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
1794 /proc/acpi/ibm/fan looks like this (3 lines):
1797 commands: enable, disable
1798 Peter Tarjan (ptarjan@citromail.hu)
1801 if ( !p_client_buffer || client_buffer_size <= 0 )
1805 unsigned int speed=0;
1807 snprintf(fan, 127, "%s/fan",IBM_ACPI_DIR);
1809 fp = fopen(fan, "r");
1815 if (fgets(line, 255, fp) == NULL) break;
1816 if (sscanf(line, "speed: %d", &speed)) break;
1821 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", fan, strerror(errno));
1825 snprintf( p_client_buffer, client_buffer_size, "%d", speed );
1830 static double last_ibm_acpi_temp_time;
1831 void get_ibm_acpi_temps()
1833 /* get the measured temperatures from the temperature sensors
1834 on IBM/Lenovo laptops running the ibm acpi.
1835 There are 8 values in /proc/acpi/ibm/thermal, and according to
1836 http://ibm-acpi.sourceforge.net/README
1837 these mean the following (at least on an IBM R51...)
1838 0: CPU (also on the T series laptops)
1839 1: Mini PCI Module (?)
1841 3: GPU (also on the T series laptops)
1846 I'm not too sure about those with the question mark, but the values I'm
1847 reading from *my* thermal file (on a T42p) look realistic for the
1848 hdd and the battery.
1849 #5 and #7 are always -128.
1850 /proc/acpi/ibm/thermal looks like this (1 line):
1851 temperatures: 41 43 31 46 33 -128 29 -128
1852 Peter Tarjan (ptarjan@citromail.hu)
1855 /* don't update too often */
1856 if (current_update_time - last_ibm_acpi_temp_time < 10.00)
1860 last_ibm_acpi_temp_time = current_update_time;
1862 /* if ( !p_client_buffer || client_buffer_size <= 0 )
1868 snprintf(thermal, 127, "%s/thermal",IBM_ACPI_DIR);
1869 fp = fopen(thermal, "r");
1876 if (fgets(line, 255, fp) == NULL) break;
1877 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
1878 &ibm_acpi.temps[0], &ibm_acpi.temps[1],
1879 &ibm_acpi.temps[2], &ibm_acpi.temps[3],
1880 &ibm_acpi.temps[4], &ibm_acpi.temps[5],
1881 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) break;
1886 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", thermal, strerror(errno));
1894 void get_ibm_acpi_volume( char * p_client_buffer, size_t client_buffer_size )
1897 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
1898 "Volume" here is none of the mixer volumes, but a "master of masters"
1899 volume adjusted by the IBM volume keys.
1900 /proc/acpi/ibm/fan looks like this (4 lines):
1903 commands: up, down, mute
1904 commands: level <level> (<level> is 0-15)
1905 Peter Tarjan (ptarjan@citromail.hu)
1908 if ( !p_client_buffer || client_buffer_size <= 0 )
1914 snprintf(volume, 127, "%s/volume",IBM_ACPI_DIR);
1915 unsigned int vol=-1;
1918 fp = fopen(volume, "r");
1924 if (fgets(line, 255, fp) == NULL) break;
1925 if (sscanf(line, "level: %d", &vol)) continue;
1926 if (sscanf(line, "mute: %s", mute)) break;
1931 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", volume, strerror(errno));
1936 if (strcmp(mute, "on")==0)
1938 snprintf( p_client_buffer, client_buffer_size, "%s", "mute" );
1943 snprintf( p_client_buffer, client_buffer_size, "%d", vol );
1949 /*static FILE *fp=NULL;*/
1951 void get_ibm_acpi_brightness(char * p_client_buffer, size_t client_buffer_size)
1953 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
1954 /proc/acpi/ibm/brightness looks like this (3 lines):
1957 commands: level <level> (<level> is 0-7)
1958 Peter Tarjan (ptarjan@citromail.hu)
1961 if ( !p_client_buffer || client_buffer_size <= 0 )
1965 unsigned int brightness=0;
1967 snprintf(filename, 127, "%s/brightness",IBM_ACPI_DIR);
1969 fp = fopen(filename, "r");
1975 if (fgets(line, 255, fp) == NULL) break;
1976 if (sscanf(line, "level: %d", &brightness)) break;
1981 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", filename, strerror(errno));
1986 snprintf( p_client_buffer, client_buffer_size, "%d", brightness );
1991 void update_entropy (void)
1994 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
1995 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
1998 info.entropy.entropy_avail=0;
1999 info.entropy.poolsize=0;
2001 if ((fp1 = open_file (entropy_avail, &rep))==NULL)
2004 if ((fp2 = open_file (entropy_poolsize, &rep))==NULL)
2010 fscanf (fp1, "%u", &info.entropy.entropy_avail);
2011 fscanf (fp2, "%u", &info.entropy.poolsize);
2016 info.mask |= (1 << INFO_ENTROPY);