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 void get_hwmon_value( char * p_client_buffer, size_t client_buffer_size, char * fname, enum hwmon_sensor_type type )
786 if ( !p_client_buffer || client_buffer_size <= 0 || !fname )
789 if ((fp = open_file(fname, &rep)) == NULL) {
790 snprintf( p_client_buffer, client_buffer_size, "hwmon: file '%s' not found", fname );
792 fscanf(fp, "%d", &sensor_value);
796 sensor_value /= 1000; /* temperatures are given in milli-degree (at least for my abit uguru) */
798 case HWMON_fan: /* already in RPM on my abit uguru */
799 case HWMON_other: /* do nothing */
803 snprintf( p_client_buffer, client_buffer_size, "%d", sensor_value );
807 /* Prior to kernel version 2.6.12, the CPU fan speed was available
808 * in ADT746X_FAN_OLD, whereas later kernel versions provide this
809 * information in ADT746X_FAN.
811 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
812 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
814 void get_adt746x_fan( char * p_client_buffer, size_t client_buffer_size )
817 char adt746x_fan_state[64];
820 if ( !p_client_buffer || client_buffer_size <= 0 )
823 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
824 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL)
827 sprintf(adt746x_fan_state, "adt746x not found");
831 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
832 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
836 snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_fan_state );
840 /* Prior to kernel version 2.6.12, the CPU temperature was found
841 * in ADT746X_CPU_OLD, whereas later kernel versions provide this
842 * information in ADT746X_CPU.
844 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
845 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
847 void get_adt746x_cpu( char * p_client_buffer, size_t client_buffer_size )
850 char adt746x_cpu_state[64];
853 if ( !p_client_buffer || client_buffer_size <= 0 )
856 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
857 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL)
859 sprintf(adt746x_cpu_state, "adt746x not found");
863 fscanf(fp, "%2s", adt746x_cpu_state);
867 snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state );
871 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
873 /***********************************************************************/
875 * This file is part of x86info.
876 * (C) 2001 Dave Jones.
878 * Licensed under the terms of the GNU GPL License version 2.
880 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
881 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz>
884 #if defined(__i386) || defined(__x86_64)
885 __inline__ unsigned long long int rdtsc()
887 unsigned long long int x;
888 __asm__ volatile (".byte 0x0f, 0x31":"=A" (x));
893 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
894 void get_freq_dynamic( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor )
896 #if defined(__i386) || defined(__x86_64)
898 struct timeval tvstart, tvstop;
899 unsigned long long cycles[2]; /* gotta be 64 bit */
900 unsigned int microseconds; /* total time taken */
902 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
905 memset(&tz, 0, sizeof(tz));
907 /* get this function in cached memory */
908 gettimeofday(&tvstart, &tz);
910 gettimeofday(&tvstart, &tz);
912 /* we don't trust that this is any specific length of time */
915 gettimeofday(&tvstop, &tz);
916 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
917 (tvstop.tv_usec - tvstart.tv_usec);
919 snprintf( p_client_buffer, client_buffer_size, p_format, (float)((cycles[1] - cycles[0]) / microseconds) / divisor );
922 /* FIXME: hardwired: get freq for first cpu!
923 this whole function needs to be rethought and redone for
924 multi-cpu/multi-core/multi-threaded environments and
925 arbitrary combinations thereof
927 get_freq( p_client_buffer, client_buffer_size, p_format, divisor, 1 );
933 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
934 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
936 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
937 char get_freq( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
945 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
950 char current_freq_file[128];
951 snprintf(current_freq_file, 127, "%s/cpu%d/%s",CPUFREQ_PREFIX, cpu-1, CPUFREQ_POSTFIX);
952 f = fopen(current_freq_file, "r");
955 /* if there's a cpufreq /sys node, read the current frequency from this node;
956 * divide by 1000 to get Mhz. */
957 if (fgets(s, sizeof(s), f)) {
958 s[strlen(s)-1] = '\0';
959 freq = strtod(s, NULL);
962 snprintf( p_client_buffer, client_buffer_size, p_format, (freq/1000)/divisor );
967 f = open_file("/proc/cpuinfo", &rep); //open the CPU information file
969 perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
973 while (fgets(s, sizeof(s), f) != NULL){ //read the file
975 #if defined(__i386) || defined(__x86_64)
976 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) { //and search for the cpu mhz
979 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) { // different on alpha
981 if (strncmp(s, "clock", 5) == 0 && cpu == 0) { // this is different on ppc for some reason
982 #endif // defined(__alpha)
983 #endif // defined(__i386) || defined(__x86_64)
985 strcpy(frequency, strchr(s, ':') + 2); //copy just the number
987 frequency[strlen(frequency) - 6] = '\0';// strip " est.\n"
988 freq = strtod(frequency, NULL)/1000000; // kernel reports in Hz
990 frequency[strlen(frequency) - 1] = '\0'; // strip \n
991 freq = strtod(frequency, NULL);
995 if (strncmp(s, "processor", 9) == 0) {
1003 snprintf( p_client_buffer, client_buffer_size, p_format, (float)freq/divisor );
1007 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
1009 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
1010 char get_voltage( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
1012 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks
1013 something like this:
1024 /* Peter Tarjan (ptarjan@citromail.hu) */
1029 char current_freq_file[128];
1033 /* build the voltage file name */
1035 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
1036 CPUFREQ_PREFIX, cpu, CPUFREQ_POSTFIX);
1038 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
1041 /* read the current cpu frequency from the /sys node */
1042 f = fopen(current_freq_file, "r");
1044 if (fgets(s, sizeof(s), f)) {
1045 s[strlen(s)-1] = '\0';
1046 freq = strtod(s, NULL);
1050 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1051 perror("get_voltage()");
1058 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
1059 CPUFREQ_PREFIX, cpu, CPUFREQ_VOLTAGE);
1061 /* use the current cpu frequency to find the corresponding voltage */
1062 f = fopen(current_freq_file, "r");
1067 if (fgets(line, 255, f) == NULL) break;
1068 sscanf(line, "%d %d", &freq_comp, &voltage);
1069 if(freq_comp == freq) break;
1073 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1074 perror("get_voltage()");
1080 snprintf( p_client_buffer, client_buffer_size, p_format, (float)voltage/divisor );
1085 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1087 void get_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1094 if ( !p_client_buffer || client_buffer_size <= 0 )
1097 /* yeah, slow... :/ */
1098 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep))
1100 snprintf( p_client_buffer, client_buffer_size, "no fans?" );
1104 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf );
1106 fp = open_file(buf2, &rep);
1108 snprintf( p_client_buffer, client_buffer_size, "can't open fan's state file" );
1111 memset(buf,0,sizeof(buf));
1112 fscanf(fp, "%*s %99s", buf);
1115 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1120 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1122 void get_acpi_ac_adapter( char * p_client_buffer, size_t client_buffer_size )
1129 if ( !p_client_buffer || client_buffer_size <= 0 )
1132 /* yeah, slow... :/ */
1133 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep))
1135 snprintf( p_client_buffer, client_buffer_size, "no ac_adapters?" );
1139 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf );
1142 fp = open_file(buf2, &rep);
1144 snprintf( p_client_buffer, client_buffer_size, "No ac adapter found.... where is it?" );
1147 memset(buf,0,sizeof(buf));
1148 fscanf(fp, "%*s %99s", buf );
1151 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1157 /proc/acpi/thermal_zone/THRM/cooling_mode
1158 cooling mode: active
1159 /proc/acpi/thermal_zone/THRM/polling_frequency
1161 /proc/acpi/thermal_zone/THRM/state
1163 /proc/acpi/thermal_zone/THRM/temperature
1165 /proc/acpi/thermal_zone/THRM/trip_points
1167 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1170 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1171 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1173 int open_acpi_temperature(const char *name)
1179 if (name == NULL || strcmp(name, "*") == 0) {
1181 if (!get_first_file_in_a_directory
1182 (ACPI_THERMAL_DIR, buf, &rep))
1187 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1189 fd = open(path, O_RDONLY);
1191 ERR("can't open '%s': %s", path, strerror(errno));
1196 static double last_acpi_temp;
1197 static double last_acpi_temp_time;
1199 double get_acpi_temperature(int fd)
1204 /* don't update acpi temperature too often */
1205 if (current_update_time - last_acpi_temp_time < 11.32) {
1206 return last_acpi_temp;
1208 last_acpi_temp_time = current_update_time;
1210 /* seek to beginning */
1211 lseek(fd, 0, SEEK_SET);
1217 n = read(fd, buf, 255);
1219 ERR("can't read fd %d: %s", fd, strerror(errno));
1222 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1226 return last_acpi_temp;
1230 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1232 design capacity: 4400 mAh
1233 last full capacity: 4064 mAh
1234 battery technology: rechargeable
1235 design voltage: 14800 mV
1236 design capacity warning: 300 mAh
1237 design capacity low: 200 mAh
1238 capacity granularity 1: 32 mAh
1239 capacity granularity 2: 32 mAh
1241 serial number: 16922
1247 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1250 charging state: unknown
1252 remaining capacity: 4064 mAh
1253 present voltage: 16608 mV
1257 2213<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1258 2213<@jupet kellari ö> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1259 2213<@jupet kellari ö> (-1 ollee ei akkua kiinni, koska akku on pöydällä)
1260 2214<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1261 2214<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1263 2238<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1264 2239<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1266 2240<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori päällä
1267 2241<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori päällä mutta ilman verkkovirtaa
1270 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1271 #define APM_PATH "/proc/apm"
1272 #define MAX_BATTERY_COUNT 4
1274 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT];
1275 static FILE *apm_bat_fp[MAX_BATTERY_COUNT];
1277 static int batteries_initialized = 0;
1278 static char batteries[MAX_BATTERY_COUNT][32];
1280 static int acpi_last_full[MAX_BATTERY_COUNT];
1281 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1283 static char last_battery_str[MAX_BATTERY_COUNT][64]; /* e.g. "charging 75%" */
1284 static char last_battery_time_str[MAX_BATTERY_COUNT][64]; /* e.g. "3h 15m" */
1286 static double last_battery_time[MAX_BATTERY_COUNT];
1288 static int last_battery_perct[MAX_BATTERY_COUNT];
1289 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1292 void init_batteries(void)
1295 if(batteries_initialized)
1297 for(idx = 0; idx < MAX_BATTERY_COUNT; idx++)
1298 batteries[idx][0] = '\0';
1299 batteries_initialized = 1;
1302 int get_battery_idx(const char *bat)
1305 for(idx = 0; idx < MAX_BATTERY_COUNT; idx++)
1306 if(!strlen(batteries[idx]) || !strcmp(batteries[idx], bat))
1309 /* if not found, enter a new entry */
1310 if(!strlen(batteries[idx]))
1311 snprintf(batteries[idx], 31, "%s", bat);
1316 void get_battery_stuff(char *buf, unsigned int n, const char *bat, int item)
1318 static int idx, rep = 0, rep2 = 0;
1319 char acpi_path[128];
1320 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1324 idx = get_battery_idx(bat);
1326 /* don't update battery too often */
1327 if (current_update_time - last_battery_time[idx] < 29.5)
1328 goto set_return_value;
1330 last_battery_time[idx] = current_update_time;
1332 memset (last_battery_str[idx], 0, sizeof (last_battery_str[idx]));
1333 memset (last_battery_time_str[idx], 0, sizeof (last_battery_time_str[idx]));
1335 /* first try ACPI */
1337 if (acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1338 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1340 if (acpi_bat_fp[idx] != NULL) {
1341 int present_rate = -1;
1342 int remaining_capacity = -1;
1343 char charging_state[64];
1346 /* read last full capacity if it's zero */
1347 if (acpi_last_full[idx] == 0) {
1352 ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1353 fp = open_file(path, &rep);
1357 if (fgets(b, 256, fp) == NULL)
1359 if (sscanf(b, "last full capacity: %d", &acpi_last_full[idx]) != 0) {
1368 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1370 strcpy(charging_state, "unknown");
1372 while (!feof(acpi_bat_fp[idx])) {
1374 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL)
1377 /* let's just hope units are ok */
1378 if (strncmp (buf, "present:", 8) == 0)
1379 sscanf(buf, "present: %4s", present);
1380 else if (strncmp (buf, "charging state:", 15) == 0)
1381 sscanf(buf, "charging state: %63s", charging_state);
1382 else if (strncmp (buf, "present rate:", 13) == 0)
1383 sscanf(buf, "present rate: %d", &present_rate);
1384 else if (strncmp(buf, "remaining capacity:", 19) == 0)
1385 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1388 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1389 if (remaining_capacity > acpi_last_full[idx])
1390 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1393 if (strcmp(present, "no") == 0) {
1394 strncpy(last_battery_str[idx], "not present", 64);
1397 else if (strcmp(charging_state, "charging") == 0) {
1398 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1399 /* e.g. charging 75% */
1400 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %i%%",
1401 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1403 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1404 (long) (((acpi_last_full[idx] - remaining_capacity) * 3600) /
1406 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1407 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %d%%",
1408 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1410 strncpy(last_battery_str[idx], "charging", sizeof(last_battery_str[idx])-1);
1414 else if (strncmp(charging_state, "discharging", 64) == 0) {
1415 if (present_rate > 0) {
1416 /* e.g. discharging 35% */
1417 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "discharging %i%%",
1418 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1420 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1421 (long) ((remaining_capacity * 3600) / present_rate));
1422 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1423 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "full");
1425 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1427 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1431 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1432 else if (strncmp(charging_state, "charged", 64) == 0) {
1433 /* Below happens with the second battery on my X40,
1434 * when the second one is empty and the first one
1436 if (remaining_capacity == 0)
1437 strcpy(last_battery_str[idx], "empty");
1439 strcpy(last_battery_str[idx], "charged");
1441 /* unknown, probably full / AC */
1443 if (acpi_last_full[idx] != 0
1444 && remaining_capacity != acpi_last_full[idx])
1445 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1446 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1448 strncpy(last_battery_str[idx], "AC", 64);
1452 if (apm_bat_fp[idx] == NULL)
1453 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1455 if (apm_bat_fp[idx] != NULL) {
1456 int ac, status, flag, life;
1458 fscanf(apm_bat_fp[idx],
1459 "%*s %*s %*x %x %x %x %d%%",
1460 &ac, &status, &flag, &life);
1463 /* could check now that there is ac */
1464 snprintf(last_battery_str[idx], 64, "AC");
1465 } else if (ac && life != 100) { /* could check that status==3 here? */
1466 snprintf(last_battery_str[idx], 64,
1467 "charging %d%%", life);
1469 snprintf(last_battery_str[idx], 64, "%d%%",
1473 /* it seemed to buffer it so file must be closed (or could use syscalls
1474 * directly but I don't feel like coding it now) */
1475 fclose(apm_bat_fp[idx]);
1476 apm_bat_fp[idx] = NULL;
1482 case BATTERY_STATUS:
1484 snprintf(buf, n, "%s", last_battery_str[idx]);
1489 snprintf(buf, n, "%s", last_battery_time_str[idx]);
1498 int get_battery_perct(const char *bat)
1502 char acpi_path[128];
1503 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1507 idx = get_battery_idx(bat);
1509 /* don't update battery too often */
1510 if (current_update_time - last_battery_perct_time[idx] < 30) {
1511 return last_battery_perct[idx];
1513 last_battery_perct_time[idx] = current_update_time;
1515 /* Only check for ACPI */
1517 if (acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1518 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1520 int remaining_capacity = -1;
1521 if (acpi_bat_fp[idx] != NULL) {
1522 /* read last full capacity if it's zero */
1523 if (acpi_design_capacity[idx] == 0) {
1528 ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1529 fp = open_file(path, &rep);
1533 if (fgets(b, 256, fp) == NULL)
1535 if (sscanf(b, "last full capacity: %d", &acpi_design_capacity[idx]) != 0) {
1543 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1545 while (!feof(acpi_bat_fp[idx])) {
1547 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL)
1551 sscanf(buf, "remaining capacity: %d",
1552 &remaining_capacity);
1555 if(remaining_capacity < 0)
1557 /* compute the battery percentage */
1558 last_battery_perct[idx] =
1559 (int) (((float)remaining_capacity/acpi_design_capacity[idx]) * 100);
1560 return last_battery_perct[idx];
1563 int get_battery_perct_bar(const char *bar)
1566 get_battery_perct(bar);
1567 idx = get_battery_idx(bar);
1568 return (int) (last_battery_perct[idx] * 2.56 - 1);
1573 /* On Apple powerbook and ibook:
1574 $ cat /proc/pmu/battery_0
1581 $ cat /proc/pmu/info
1582 PMU driver version : 2
1583 PMU firmware version : 0c
1588 /* defines as in <linux/pmu.h> */
1589 #define PMU_BATT_PRESENT 0x00000001
1590 #define PMU_BATT_CHARGING 0x00000002
1592 static FILE* pmu_battery_fp;
1593 static FILE* pmu_info_fp;
1594 static char pb_battery_info[3][32];
1595 static double pb_battery_info_update;
1597 #define PMU_PATH "/proc/pmu"
1598 void get_powerbook_batt_info(char *buf, size_t n, int i)
1601 const char* batt_path = PMU_PATH "/battery_0";
1602 const char* info_path = PMU_PATH "/info";
1603 int flags, charge, max_charge, ac = -1;
1606 /* don't update battery too often */
1607 if (current_update_time - pb_battery_info_update < 29.5) {
1608 snprintf(buf, n, "%s", pb_battery_info[i]);
1611 pb_battery_info_update = current_update_time;
1613 if (pmu_battery_fp == NULL)
1614 pmu_battery_fp = open_file(batt_path, &rep);
1616 if (pmu_battery_fp != NULL) {
1617 rewind(pmu_battery_fp);
1618 while (!feof(pmu_battery_fp)) {
1620 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL)
1624 sscanf(buf, "flags : %8x", &flags);
1625 else if (buf[0] == 'c' && buf[1] == 'h')
1626 sscanf(buf, "charge : %d", &charge);
1627 else if (buf[0] == 'm')
1628 sscanf(buf, "max_charge : %d", &max_charge);
1629 else if (buf[0] == 't')
1630 sscanf(buf, "time rem. : %ld", &time);
1633 if (pmu_info_fp == NULL)
1634 pmu_info_fp = open_file(info_path, &rep);
1636 if (pmu_info_fp != NULL) {
1637 rewind(pmu_info_fp);
1638 while (!feof(pmu_info_fp)) {
1640 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL)
1643 sscanf(buf, "AC Power : %d", &ac);
1646 /* update status string */
1647 if ((ac && !(flags & PMU_BATT_PRESENT)))
1648 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
1649 else if (ac && (flags & PMU_BATT_PRESENT)
1650 && !(flags & PMU_BATT_CHARGING))
1651 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
1652 else if ((flags & PMU_BATT_PRESENT)
1653 && (flags & PMU_BATT_CHARGING))
1654 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
1656 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
1658 /* update percentage string */
1660 pb_battery_info[PB_BATT_PERCENT][0] = 0;
1662 snprintf(pb_battery_info[PB_BATT_PERCENT],
1663 sizeof(pb_battery_info[PB_BATT_PERCENT]),
1664 "%d%%", (charge * 100)/max_charge);
1666 /* update time string */
1667 if (time == 0) /* fully charged or battery not present */
1668 pb_battery_info[PB_BATT_TIME][0] = 0;
1669 else if (time < 60*60) /* don't show secs */
1670 format_seconds_short(pb_battery_info[PB_BATT_TIME],
1671 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1673 format_seconds(pb_battery_info[PB_BATT_TIME],
1674 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1676 snprintf(buf, n, "%s", pb_battery_info[i]);
1681 show_nice_processes = 1;
1682 process_find_top(info.cpu, info.memu);
1683 info.first_process = get_first_process();
1688 * The following ifdefs were adapted from gkrellm
1690 #include <linux/major.h>
1692 #if ! defined (MD_MAJOR)
1696 #if !defined(LVM_BLK_MAJOR)
1697 #define LVM_BLK_MAJOR 58
1700 #if !defined(NBD_MAJOR)
1701 #define NBD_MAJOR 43
1704 void update_diskio()
1706 static unsigned int last = UINT_MAX;
1707 static unsigned int last_read = UINT_MAX;
1708 static unsigned int last_write = UINT_MAX;
1714 unsigned int current = 0;
1715 unsigned int current_read = 0;
1716 unsigned int current_write = 0;
1717 unsigned int reads, writes = 0;
1720 if (!(fp =open_file("/proc/diskstats", &rep))) {
1725 /* read reads and writes from all disks (minor = 0), including
1726 * cd-roms and floppies, and summ them up
1729 fgets(buf, 512, fp);
1730 col_count = sscanf(buf, "%u %u %*s %*u %*u %u %*u %*u %*u %u",
1731 &major, &minor, &reads, &writes);
1732 /* ignore subdevices (they have only 3 matching entries in their line)
1733 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
1735 * XXX ignore devices which are part of a SW RAID (MD_MAJOR)
1737 if (col_count > 3 &&
1738 major != LVM_BLK_MAJOR && major != NBD_MAJOR &&
1739 major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
1740 current += reads + writes;
1741 current_read += reads;
1742 current_write += writes;
1746 /* since the values in /proc/diststats are absolute, we have
1747 * to substract our last reading. The numbers stand for
1748 * "sectors read", and we therefore have to divide by two to
1750 int tot = ((double)(current-last)/2);
1751 int tot_read = ((double)(current_read-last_read)/2);
1752 int tot_write = ((double)(current_write-last_write)/2);
1754 if (last_read > current_read)
1756 if (last_write > current_write)
1759 if (last > current) {
1760 /* we hit this either if it's the very first time we
1761 * run this, or when /proc/diskstats overflows; while
1762 * 0 is not correct, it's at least not way off */
1766 last_read = current_read;
1767 last_write = current_write;
1770 diskio_read_value = tot_read;
1771 diskio_write_value = tot_write;
1776 /* Here come the IBM ACPI-specific things. For reference, see
1777 http://ibm-acpi.sourceforge.net/README
1778 If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
1794 The content of these files is described in detail in the aforementioned
1795 README - some of them also in the following functions accessing them.
1796 Peter Tarjan (ptarjan@citromail.hu)
1799 #define IBM_ACPI_DIR "/proc/acpi/ibm"
1801 void get_ibm_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1803 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
1804 /proc/acpi/ibm/fan looks like this (3 lines):
1807 commands: enable, disable
1808 Peter Tarjan (ptarjan@citromail.hu)
1811 if ( !p_client_buffer || client_buffer_size <= 0 )
1815 unsigned int speed=0;
1817 snprintf(fan, 127, "%s/fan",IBM_ACPI_DIR);
1819 fp = fopen(fan, "r");
1825 if (fgets(line, 255, fp) == NULL) break;
1826 if (sscanf(line, "speed: %d", &speed)) break;
1831 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", fan, strerror(errno));
1835 snprintf( p_client_buffer, client_buffer_size, "%d", speed );
1840 static double last_ibm_acpi_temp_time;
1841 void get_ibm_acpi_temps()
1843 /* get the measured temperatures from the temperature sensors
1844 on IBM/Lenovo laptops running the ibm acpi.
1845 There are 8 values in /proc/acpi/ibm/thermal, and according to
1846 http://ibm-acpi.sourceforge.net/README
1847 these mean the following (at least on an IBM R51...)
1848 0: CPU (also on the T series laptops)
1849 1: Mini PCI Module (?)
1851 3: GPU (also on the T series laptops)
1856 I'm not too sure about those with the question mark, but the values I'm
1857 reading from *my* thermal file (on a T42p) look realistic for the
1858 hdd and the battery.
1859 #5 and #7 are always -128.
1860 /proc/acpi/ibm/thermal looks like this (1 line):
1861 temperatures: 41 43 31 46 33 -128 29 -128
1862 Peter Tarjan (ptarjan@citromail.hu)
1865 /* don't update too often */
1866 if (current_update_time - last_ibm_acpi_temp_time < 10.00)
1870 last_ibm_acpi_temp_time = current_update_time;
1872 /* if ( !p_client_buffer || client_buffer_size <= 0 )
1878 snprintf(thermal, 127, "%s/thermal",IBM_ACPI_DIR);
1879 fp = fopen(thermal, "r");
1886 if (fgets(line, 255, fp) == NULL) break;
1887 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
1888 &ibm_acpi.temps[0], &ibm_acpi.temps[1],
1889 &ibm_acpi.temps[2], &ibm_acpi.temps[3],
1890 &ibm_acpi.temps[4], &ibm_acpi.temps[5],
1891 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) break;
1896 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", thermal, strerror(errno));
1904 void get_ibm_acpi_volume( char * p_client_buffer, size_t client_buffer_size )
1907 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
1908 "Volume" here is none of the mixer volumes, but a "master of masters"
1909 volume adjusted by the IBM volume keys.
1910 /proc/acpi/ibm/fan looks like this (4 lines):
1913 commands: up, down, mute
1914 commands: level <level> (<level> is 0-15)
1915 Peter Tarjan (ptarjan@citromail.hu)
1918 if ( !p_client_buffer || client_buffer_size <= 0 )
1924 snprintf(volume, 127, "%s/volume",IBM_ACPI_DIR);
1925 unsigned int vol=-1;
1928 fp = fopen(volume, "r");
1934 if (fgets(line, 255, fp) == NULL) break;
1935 if (sscanf(line, "level: %d", &vol)) continue;
1936 if (sscanf(line, "mute: %s", mute)) break;
1941 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", volume, strerror(errno));
1946 if (strcmp(mute, "on")==0)
1948 snprintf( p_client_buffer, client_buffer_size, "%s", "mute" );
1953 snprintf( p_client_buffer, client_buffer_size, "%d", vol );
1959 /*static FILE *fp=NULL;*/
1961 void get_ibm_acpi_brightness(char * p_client_buffer, size_t client_buffer_size)
1963 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
1964 /proc/acpi/ibm/brightness looks like this (3 lines):
1967 commands: level <level> (<level> is 0-7)
1968 Peter Tarjan (ptarjan@citromail.hu)
1971 if ( !p_client_buffer || client_buffer_size <= 0 )
1975 unsigned int brightness=0;
1977 snprintf(filename, 127, "%s/brightness",IBM_ACPI_DIR);
1979 fp = fopen(filename, "r");
1985 if (fgets(line, 255, fp) == NULL) break;
1986 if (sscanf(line, "level: %d", &brightness)) break;
1991 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", filename, strerror(errno));
1996 snprintf( p_client_buffer, client_buffer_size, "%d", brightness );
2001 void update_entropy (void)
2004 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
2005 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
2008 info.entropy.entropy_avail=0;
2009 info.entropy.poolsize=0;
2011 if ((fp1 = open_file (entropy_avail, &rep))==NULL)
2014 if ((fp2 = open_file (entropy_poolsize, &rep))==NULL)
2020 fscanf (fp1, "%u", &info.entropy.entropy_avail);
2021 fscanf (fp2, "%u", &info.entropy.poolsize);
2026 info.mask |= (1 << INFO_ENTROPY);