2 * Contains linux specific code
16 #include <sys/types.h>
17 #include <sys/sysinfo.h>
19 #ifndef HAVE_CLOCK_GETTIME
24 // #include <assert.h>
28 #include <sys/ioctl.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <linux/sockios.h>
35 #define SHORTSTAT_TEMPL "%*s %llu %llu %llu"
36 #define LONGSTAT_TEMPL "%*s %llu %llu %llu "
38 static int show_nice_processes;
40 /* this flags tells the linux routines to use the /proc system
41 * where possible, even if other api's are available, e.g. sysinfo()
42 * or getloadavg(). the reason for this is to allow for /proc-based
43 * distributed monitoring. using a flag in this manner creates less
46 static int prefer_proc = 0;
57 struct sysinfo s_info;
59 info.uptime = (double) s_info.uptime;
67 if (!(fp = open_file("/proc/uptime", &rep)))
72 fscanf(fp, "%lf", &info.uptime);
75 info.mask |= (1 << INFO_UPTIME);
78 int check_mount(char *s)
81 FILE *mtab = fopen("/etc/mtab", "r");
83 char buf1[256], buf2[128];
84 while (fgets(buf1, 256, mtab)) {
85 sscanf(buf1, "%*s %128s", buf2);
86 if (!strcmp(s, buf2)) {
93 ERR("Could not open mtab");
98 /* these things are also in sysinfo except Buffers:, that's why I'm reading
101 void update_meminfo()
105 /* unsigned int a; */
108 info.mem = info.memmax = info.swap = info.swapmax = info.bufmem =
109 info.buffers = info.cached = 0;
111 if (!(meminfo_fp = open_file("/proc/meminfo", &rep)))
114 while (!feof(meminfo_fp)) {
115 if (fgets(buf, 255, meminfo_fp) == NULL)
118 if (strncmp(buf, "MemTotal:", 9) == 0) {
119 sscanf(buf, "%*s %Lu", &info.memmax);
120 } else if (strncmp(buf, "MemFree:", 8) == 0) {
121 sscanf(buf, "%*s %Lu", &info.mem);
122 } else if (strncmp(buf, "SwapTotal:", 10) == 0) {
123 sscanf(buf, "%*s %Lu", &info.swapmax);
124 } else if (strncmp(buf, "SwapFree:", 9) == 0) {
125 sscanf(buf, "%*s %Lu", &info.swap);
126 } else if (strncmp(buf, "Buffers:", 8) == 0) {
127 sscanf(buf, "%*s %Lu", &info.buffers);
128 } else if (strncmp(buf, "Cached:", 7) == 0) {
129 sscanf(buf, "%*s %Lu", &info.cached);
133 info.mem = info.memmax - info.mem;
134 info.swap = info.swapmax - info.swap;
136 info.bufmem = info.cached + info.buffers;
138 info.mask |= (1 << INFO_MEM) | (1 << INFO_BUFFERS);
143 static FILE *net_wireless_fp;
145 inline void update_net_stats()
149 // FIXME: arbitrary size chosen to keep code simple.
151 unsigned int curtmp1, curtmp2;
158 delta = current_update_time - last_update_time;
162 /* open file and ignore first two lines */
163 if (!(net_dev_fp = open_file("/proc/net/dev", &rep)))
169 fgets(buf, 255, net_dev_fp); /* garbage */
170 fgets(buf, 255, net_dev_fp); /* garbage (field names) */
172 /* read each interface */
173 for (i2 = 0; i2 < 16; i2++) {
176 long long r, t, last_recv, last_trans;
178 if (fgets(buf, 255, net_dev_fp) == NULL) {
182 while (isspace((int) *p))
187 while (*p && *p != ':')
194 ns = get_net_stat(s);
196 memset(&(ns->addr.sa_data), 0, 14);
197 last_recv = ns->recv;
198 last_trans = ns->trans;
201 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
202 "%Ld %*d %*d %*d %*d %*d %*d %*d %Ld",
205 /* if recv or trans is less than last time, an overflow happened */
207 if (r < ns->last_read_recv)
210 ns->recv += (r - ns->last_read_recv);
211 ns->last_read_recv = r;
213 if (t < ns->last_read_trans)
216 ns->trans += (t - ns->last_read_trans);
217 ns->last_read_trans = t;
219 /*** ip addr patch ***/
220 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
222 conf.ifc_buf = malloc(sizeof(struct ifreq) * 16);
224 conf.ifc_len = sizeof(struct ifreq) * 16;
226 ioctl((long) i, SIOCGIFCONF, &conf);
228 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
230 ns = get_net_stat(((struct ifreq *) conf.
231 ifc_buf)[k].ifr_ifrn.ifrn_name);
233 ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.
242 /*** end ip addr patch ***/
245 /* calculate speeds */
246 ns->net_rec[0] = (ns->recv - last_recv) / delta;
247 ns->net_trans[0] = (ns->trans - last_trans) / delta;
251 for (i = 0; (unsigned) i < info.net_avg_samples; i++) {
252 curtmp1 += ns->net_rec[i];
253 curtmp2 += ns->net_trans[i];
255 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
256 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
257 if (info.net_avg_samples > 1) {
258 for (i = info.net_avg_samples; i > 1; i--) {
259 ns->net_rec[i - 1] = ns->net_rec[i - 2];
260 ns->net_trans[i - 1] =
261 ns->net_trans[i - 2];
269 info.mask |= (1 << INFO_NET);
272 inline void update_wifi_stats()
274 /** wireless stats patch by Bobby Beckmann **/
278 /*open file and ignore first two lines sorry, this code sucks ass right now, i'll clean it up later */
279 if (net_wireless_fp == NULL)
280 net_wireless_fp = open_file("/proc/net/wireless", &rep);
282 fseek(net_wireless_fp, 0, SEEK_SET);
283 if (net_wireless_fp == NULL)
286 fgets(buf, 255, net_wireless_fp); /* garbage */
287 fgets(buf, 255, net_wireless_fp); /* garbage (field names) */
289 /* read each interface */
290 for (i = 0; i < 16; i++) {
295 if (fgets(buf, 255, net_wireless_fp) == NULL)
298 while (isspace((int) *p))
303 while (*p && *p != ':')
310 ns = get_net_stat(s);
312 sscanf(p, "%*d %d. %d. %d", &l, &m, &n);
314 ns->linkstatus = (int) (log(MIN(MAX(l,1),92)) / log(92) * 100);
318 /*** end wireless patch ***/
323 void update_total_processes()
328 struct sysinfo s_info;
330 info.procs = s_info.procs;
338 if (!(fp = open_file("/proc/loadavg", &rep)))
343 fscanf(fp, "%*f %*f %*f %*d/%hd", &info.procs );
346 info.mask |= (1 << INFO_PROCS);
349 #define CPU_SAMPLE_COUNT 15
351 unsigned long long cpu_user;
352 unsigned long long cpu_system;
353 unsigned long long cpu_nice;
354 unsigned long long cpu_idle;
355 unsigned long long cpu_iowait;
356 unsigned long long cpu_irq;
357 unsigned long long cpu_softirq;
358 unsigned long long cpu_steal;
359 unsigned long long cpu_total;
360 unsigned long long cpu_active_total;
361 unsigned long long cpu_last_total;
362 unsigned long long cpu_last_active_total;
363 double cpu_val[CPU_SAMPLE_COUNT];
365 static short cpu_setup = 0;
368 determine if this kernel gives us "extended" statistics information in /proc/stat.
369 Kernels around 2.5 and earlier only reported user, system, nice and idle values in proc stat.
370 Kernels around 2.6 and greater report these PLUS iowait, irq, softirq, and steal
372 void determine_longstat(char * buf) {
373 unsigned long long iowait=0;
374 KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
375 /* scanf will either return -1 or 1 because there is only 1 assignment */
376 if (sscanf(buf, "%*s %*d %*d %*d %*d %llu",&iowait)>0) KFLAG_SETON(KFLAG_IS_LONGSTAT);
384 if (info.cpu_usage) {
389 if (!(stat_fp = open_file("/proc/stat", &rep)))
394 while (!feof(stat_fp)) {
395 if (fgets(buf, 255, stat_fp) == NULL)
398 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
399 if (info.cpu_count == 0) {
400 determine_longstat(buf);
405 info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
410 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
411 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
413 inline static void update_stat()
417 static struct cpu_info *cpu = NULL;
422 char * stat_template=NULL;
423 unsigned int malloc_cpu_size=0;
426 /* add check for !info.cpu_usage since that mem is freed on a SIGUSR1 */
427 if (!cpu_setup || !info.cpu_usage) {
432 if (!stat_template) {
433 stat_template = KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT ;
437 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
438 cpu = malloc(malloc_cpu_size);
439 memset(cpu, 0, malloc_cpu_size);
442 if (!(stat_fp = open_file("/proc/stat", &rep)))
447 memset(info.cpu_usage, 0, info.cpu_count * sizeof (float));
453 while (!feof(stat_fp)) {
454 if (fgets(buf, 255, stat_fp) == NULL)
457 if (strncmp(buf, "procs_running ", 14) == 0) {
458 sscanf(buf, "%*s %hu", &info.run_procs);
459 info.mask |= (1 << INFO_RUN_PROCS);
460 } else if (strncmp(buf, "cpu", 3) == 0) {
461 index = isdigit(buf[3]) ? ((int)buf[3]) - 0x2F : 0;
462 sscanf(buf, stat_template
463 , &(cpu[index].cpu_user)
464 , &(cpu[index].cpu_nice)
465 , &(cpu[index].cpu_system)
466 , &(cpu[index].cpu_idle)
467 , &(cpu[index].cpu_iowait)
468 , &(cpu[index].cpu_irq)
469 , &(cpu[index].cpu_softirq)
470 , &(cpu[index].cpu_steal)
473 cpu[index].cpu_total = cpu[index].cpu_user
474 + cpu[index].cpu_nice
475 + cpu[index].cpu_system
476 + cpu[index].cpu_idle
477 + cpu[index].cpu_iowait
479 + cpu[index].cpu_softirq
480 + cpu[index].cpu_steal
483 cpu[index].cpu_active_total = cpu[index].cpu_total - (cpu[index].cpu_idle + cpu[index].cpu_iowait);
484 info.mask |= (1 << INFO_CPU);
486 double delta = current_update_time - last_update_time;
487 if (delta <= 0.001) break;
489 cpu[index].cpu_val[0] = (cpu[index].cpu_active_total - cpu[index].cpu_last_active_total) /
490 (float )(cpu[index].cpu_total - cpu[index].cpu_last_total);
492 for (i=0; i < info.cpu_avg_samples; i++ ) {
493 curtmp += cpu[index].cpu_val[i];
495 /* TESTING -- I've removed this, because I don't think it is right. You shouldn't divide
496 by the cpu count here ... removing for testing */
498 info.cpu_usage[index] = curtmp / info.cpu_avg_samples / info.cpu_count;
500 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
502 /* TESTING -- this line replaces the prev. "suspect" if/else */
503 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
505 cpu[index].cpu_last_total = cpu[index].cpu_total;
506 cpu[index].cpu_last_active_total = cpu[index].cpu_active_total;
507 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
508 cpu[index].cpu_val[i] = cpu[index].cpu_val[i - 1];
516 void update_running_processes()
521 void update_cpu_usage()
526 void update_load_average()
528 #ifdef HAVE_GETLOADAVG
533 info.loadavg[0] = (float) v[0];
534 info.loadavg[1] = (float) v[1];
535 info.loadavg[2] = (float) v[2];
543 if (!(fp = open_file("/proc/loadavg", &rep)))
545 info.loadavg[0] = info.loadavg[1] = info.loadavg[2] = 0.0;
548 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1], &info.loadavg[2]);
551 info.mask |= (1 << INFO_LOADAVG);
554 #define PROC_I8K "/proc/i8k"
555 #define I8K_DELIM " "
556 static char *i8k_procbuf = NULL;
561 i8k_procbuf = (char*)malloc(128*sizeof(char));
563 if ((fp = fopen(PROC_I8K,"r")) == NULL) {
564 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel driver is loaded...");
567 memset(&i8k_procbuf[0],0,128);
568 if (fread(&i8k_procbuf[0],sizeof(char),128,fp) == 0) {
569 ERR("something wrong with /proc/i8k...");
574 i8k.version = strtok(&i8k_procbuf[0],I8K_DELIM);
575 i8k.bios = strtok(NULL,I8K_DELIM);
576 i8k.serial = strtok(NULL,I8K_DELIM);
577 i8k.cpu_temp = strtok(NULL,I8K_DELIM);
578 i8k.left_fan_status = strtok(NULL,I8K_DELIM);
579 i8k.right_fan_status = strtok(NULL,I8K_DELIM);
580 i8k.left_fan_rpm = strtok(NULL,I8K_DELIM);
581 i8k.right_fan_rpm = strtok(NULL,I8K_DELIM);
582 i8k.ac_status = strtok(NULL,I8K_DELIM);
583 i8k.buttons_status = strtok(NULL,I8K_DELIM);
587 /***********************************************************/
588 /***********************************************************/
589 /***********************************************************/
591 static int no_dots(const struct dirent *d)
593 if (d->d_name[0] == '.')
599 get_first_file_in_a_directory(const char *dir, char *s, int *rep)
601 struct dirent **namelist;
604 n = scandir(dir, &namelist, no_dots, alphasort);
607 ERR("scandir for %s: %s", dir, strerror(errno));
616 strncpy(s, namelist[0]->d_name, 255);
619 for (i = 0; i < n; i++)
627 #define I2C_DIR "/sys/bus/i2c/devices/"
630 open_i2c_sensor(const char *dev, const char *type, int n, int *div,
638 /* if i2c device is NULL or *, get first */
639 if (dev == NULL || strcmp(dev, "*") == 0) {
641 if (!get_first_file_in_a_directory(I2C_DIR, buf, &rep))
646 /* change vol to in */
647 if (strcmp(type, "vol") == 0)
650 if (strcmp(type, "tempf") == 0) {
651 snprintf(path, 255, I2C_DIR "%s/%s%d_input", dev, "temp", n);
653 snprintf(path, 255, I2C_DIR "%s/%s%d_input", dev, type, n);
655 strncpy(devtype, path, 255);
658 fd = open(path, O_RDONLY);
660 CRIT_ERR("can't open '%s': %s\nplease fix i2c or remove it from Conky", path, strerror(errno));
663 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
664 || strcmp(type, "tempf") == 0)
668 /* fan does not use *_div as a read divisor */
669 if (strcmp("fan", type) == 0)
672 /* test if *_div file exist, open it and use it as divisor */
673 if (strcmp(type, "tempf") == 0) {
674 snprintf(path, 255, I2C_DIR "%s/%s%d_div", "one", "two",
677 snprintf(path, 255, I2C_DIR "%s/%s%d_div", dev, type, n);
680 divfd = open(path, O_RDONLY);
685 divn = read(divfd, divbuf, 63);
686 /* should read until n == 0 but I doubt that kernel will give these
687 * in multiple pieces. :) */
697 double get_i2c_info(int *fd, int div, char *devtype, char *type)
704 lseek(*fd, 0, SEEK_SET);
710 n = read(*fd, buf, 63);
711 /* should read until n == 0 but I doubt that kernel will give these
712 * in multiple pieces. :) */
719 *fd = open(devtype, O_RDONLY);
721 ERR("can't open '%s': %s", devtype, strerror(errno));
723 /* My dirty hack for computing CPU value
724 * Filedil, from forums.gentoo.org
726 /* if (strstr(devtype, "temp1_input") != NULL)
727 return -15.096+1.4893*(val / 1000.0); */
730 /* divide voltage and temperature by 1000 */
731 /* or if any other divisor is given, use that */
732 if (strcmp(type, "tempf") == 0) {
734 return ((val / div + 40) * 9.0 / 5) - 40;
736 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
738 return ((val + 40) * 9.0 / 5) - 40;
749 /* Prior to kernel version 2.6.12, the CPU fan speed was available
750 * in ADT746X_FAN_OLD, whereas later kernel versions provide this
751 * information in ADT746X_FAN.
753 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
754 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
756 void get_adt746x_fan( char * p_client_buffer, size_t client_buffer_size )
759 char adt746x_fan_state[64];
762 if ( !p_client_buffer || client_buffer_size <= 0 )
765 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
766 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL)
769 sprintf(adt746x_fan_state, "adt746x not found");
773 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
774 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
778 snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_fan_state );
782 /* Prior to kernel version 2.6.12, the CPU temperature was found
783 * in ADT746X_CPU_OLD, whereas later kernel versions provide this
784 * information in ADT746X_CPU.
786 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
787 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
789 void get_adt746x_cpu( char * p_client_buffer, size_t client_buffer_size )
792 char adt746x_cpu_state[64];
795 if ( !p_client_buffer || client_buffer_size <= 0 )
798 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
799 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL)
801 sprintf(adt746x_cpu_state, "adt746x not found");
805 fscanf(fp, "%2s", adt746x_cpu_state);
809 snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state );
813 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
815 /***********************************************************************/
817 * This file is part of x86info.
818 * (C) 2001 Dave Jones.
820 * Licensed under the terms of the GNU GPL License version 2.
822 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
823 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz>
826 #if defined(__i386) || defined(__x86_64)
827 __inline__ unsigned long long int rdtsc()
829 unsigned long long int x;
830 __asm__ volatile (".byte 0x0f, 0x31":"=A" (x));
835 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
836 void get_freq_dynamic( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor )
838 #if defined(__i386) || defined(__x86_64)
840 struct timeval tvstart, tvstop;
841 unsigned long long cycles[2]; /* gotta be 64 bit */
842 unsigned int microseconds; /* total time taken */
844 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
847 memset(&tz, 0, sizeof(tz));
849 /* get this function in cached memory */
850 gettimeofday(&tvstart, &tz);
852 gettimeofday(&tvstart, &tz);
854 /* we don't trust that this is any specific length of time */
857 gettimeofday(&tvstop, &tz);
858 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
859 (tvstop.tv_usec - tvstart.tv_usec);
861 snprintf( p_client_buffer, client_buffer_size, p_format, (float)((cycles[1] - cycles[0]) / microseconds) / divisor );
864 /* FIXME: hardwired: get freq for first cpu!
865 this whole function needs to be rethought and redone for
866 multi-cpu/multi-core/multi-threaded environments and
867 arbitrary combinations thereof
869 get_freq( p_client_buffer, client_buffer_size, p_format, divisor, 1 );
875 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
876 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
878 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
879 char get_freq( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
887 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
892 char current_freq_file[128];
893 snprintf(current_freq_file, 127, "%s/cpu%d/%s",CPUFREQ_PREFIX, cpu-1, CPUFREQ_POSTFIX);
894 f = fopen(current_freq_file, "r");
897 /* if there's a cpufreq /sys node, read the current frequency from this node;
898 * divide by 1000 to get Mhz. */
899 if (fgets(s, sizeof(s), f)) {
900 s[strlen(s)-1] = '\0';
901 freq = strtod(s, NULL);
904 snprintf( p_client_buffer, client_buffer_size, p_format, (freq/1000)/divisor );
909 f = open_file("/proc/cpuinfo", &rep); //open the CPU information file
911 perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
915 while (fgets(s, sizeof(s), f) != NULL){ //read the file
917 #if defined(__i386) || defined(__x86_64)
918 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) { //and search for the cpu mhz
921 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) { // different on alpha
923 if (strncmp(s, "clock", 5) == 0 && cpu == 0) { // this is different on ppc for some reason
924 #endif // defined(__alpha)
925 #endif // defined(__i386) || defined(__x86_64)
927 strcpy(frequency, strchr(s, ':') + 2); //copy just the number
929 frequency[strlen(frequency) - 6] = '\0';// strip " est.\n"
930 freq = strtod(frequency, NULL)/1000000; // kernel reports in Hz
932 frequency[strlen(frequency) - 1] = '\0'; // strip \n
933 freq = strtod(frequency, NULL);
937 if (strncmp(s, "processor", 9) == 0) {
945 snprintf( p_client_buffer, client_buffer_size, p_format, (float)freq/divisor );
949 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
951 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
952 char get_voltage( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
954 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks
966 /* Peter Tarjan (ptarjan@citromail.hu) */
971 char current_freq_file[128];
975 /* build the voltage file name */
977 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
978 CPUFREQ_PREFIX, cpu, CPUFREQ_POSTFIX);
980 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
983 /* read the current cpu frequency from the /sys node */
984 f = fopen(current_freq_file, "r");
986 if (fgets(s, sizeof(s), f)) {
987 s[strlen(s)-1] = '\0';
988 freq = strtod(s, NULL);
992 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
993 perror("get_voltage()");
1000 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
1001 CPUFREQ_PREFIX, cpu, CPUFREQ_VOLTAGE);
1003 /* use the current cpu frequency to find the corresponding voltage */
1004 f = fopen(current_freq_file, "r");
1009 if (fgets(line, 255, f) == NULL) break;
1010 sscanf(line, "%d %d", &freq_comp, &voltage);
1011 if(freq_comp == freq) break;
1015 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1016 perror("get_voltage()");
1022 snprintf( p_client_buffer, client_buffer_size, p_format, (float)voltage/divisor );
1027 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1029 void get_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1036 if ( !p_client_buffer || client_buffer_size <= 0 )
1039 /* yeah, slow... :/ */
1040 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep))
1042 snprintf( p_client_buffer, client_buffer_size, "no fans?" );
1046 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf );
1048 fp = open_file(buf2, &rep);
1050 snprintf( p_client_buffer, client_buffer_size, "can't open fan's state file" );
1053 memset(buf,0,sizeof(buf));
1054 fscanf(fp, "%*s %99s", buf);
1057 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1062 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1064 void get_acpi_ac_adapter( char * p_client_buffer, size_t client_buffer_size )
1071 if ( !p_client_buffer || client_buffer_size <= 0 )
1074 /* yeah, slow... :/ */
1075 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep))
1077 snprintf( p_client_buffer, client_buffer_size, "no ac_adapters?" );
1081 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf );
1084 fp = open_file(buf2, &rep);
1086 snprintf( p_client_buffer, client_buffer_size, "No ac adapter found.... where is it?" );
1089 memset(buf,0,sizeof(buf));
1090 fscanf(fp, "%*s %99s", buf );
1093 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1099 /proc/acpi/thermal_zone/THRM/cooling_mode
1100 cooling mode: active
1101 /proc/acpi/thermal_zone/THRM/polling_frequency
1103 /proc/acpi/thermal_zone/THRM/state
1105 /proc/acpi/thermal_zone/THRM/temperature
1107 /proc/acpi/thermal_zone/THRM/trip_points
1109 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1112 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1113 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1115 int open_acpi_temperature(const char *name)
1121 if (name == NULL || strcmp(name, "*") == 0) {
1123 if (!get_first_file_in_a_directory
1124 (ACPI_THERMAL_DIR, buf, &rep))
1129 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1131 fd = open(path, O_RDONLY);
1133 ERR("can't open '%s': %s", path, strerror(errno));
1138 static double last_acpi_temp;
1139 static double last_acpi_temp_time;
1141 double get_acpi_temperature(int fd)
1146 /* don't update acpi temperature too often */
1147 if (current_update_time - last_acpi_temp_time < 11.32) {
1148 return last_acpi_temp;
1150 last_acpi_temp_time = current_update_time;
1152 /* seek to beginning */
1153 lseek(fd, 0, SEEK_SET);
1159 n = read(fd, buf, 255);
1161 ERR("can't read fd %d: %s", fd, strerror(errno));
1164 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1168 return last_acpi_temp;
1172 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1174 design capacity: 4400 mAh
1175 last full capacity: 4064 mAh
1176 battery technology: rechargeable
1177 design voltage: 14800 mV
1178 design capacity warning: 300 mAh
1179 design capacity low: 200 mAh
1180 capacity granularity 1: 32 mAh
1181 capacity granularity 2: 32 mAh
1183 serial number: 16922
1189 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1192 charging state: unknown
1194 remaining capacity: 4064 mAh
1195 present voltage: 16608 mV
1199 2213<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1200 2213<@jupet kellari ö> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1201 2213<@jupet kellari ö> (-1 ollee ei akkua kiinni, koska akku on pöydällä)
1202 2214<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1203 2214<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1205 2238<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1206 2239<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1208 2240<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori päällä
1209 2241<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori päällä mutta ilman verkkovirtaa
1212 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1213 #define APM_PATH "/proc/apm"
1214 #define MAX_BATTERY_COUNT 4
1216 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT];
1217 static FILE *apm_bat_fp[MAX_BATTERY_COUNT];
1219 static int batteries_initialized = 0;
1220 static char batteries[MAX_BATTERY_COUNT][32];
1222 static int acpi_last_full[MAX_BATTERY_COUNT];
1223 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1225 static char last_battery_str[MAX_BATTERY_COUNT][64]; /* e.g. "charging 75%" */
1226 static char last_battery_time_str[MAX_BATTERY_COUNT][64]; /* e.g. "3h 15m" */
1228 static double last_battery_time[MAX_BATTERY_COUNT];
1230 static int last_battery_perct[MAX_BATTERY_COUNT];
1231 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1234 void init_batteries(void)
1237 if(batteries_initialized)
1239 for(idx = 0; idx < MAX_BATTERY_COUNT; idx++)
1240 batteries[idx][0] = '\0';
1241 batteries_initialized = 1;
1244 int get_battery_idx(const char *bat)
1247 for(idx = 0; idx < MAX_BATTERY_COUNT; idx++)
1248 if(!strlen(batteries[idx]) || !strcmp(batteries[idx], bat))
1251 /* if not found, enter a new entry */
1252 if(!strlen(batteries[idx]))
1253 snprintf(batteries[idx], 31, "%s", bat);
1258 void get_battery_stuff(char *buf, unsigned int n, const char *bat, int item)
1260 static int idx, rep = 0, rep2 = 0;
1261 char acpi_path[128];
1262 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1266 idx = get_battery_idx(bat);
1268 /* don't update battery too often */
1269 if (current_update_time - last_battery_time[idx] < 29.5)
1270 goto set_return_value;
1272 last_battery_time[idx] = current_update_time;
1274 memset (last_battery_str[idx], 0, sizeof (last_battery_str[idx]));
1275 memset (last_battery_time_str[idx], 0, sizeof (last_battery_time_str[idx]));
1277 /* first try ACPI */
1279 if (acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1280 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1282 if (acpi_bat_fp[idx] != NULL) {
1283 int present_rate = -1;
1284 int remaining_capacity = -1;
1285 char charging_state[64];
1288 /* read last full capacity if it's zero */
1289 if (acpi_last_full[idx] == 0) {
1294 ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1295 fp = open_file(path, &rep);
1299 if (fgets(b, 256, fp) == NULL)
1301 if (sscanf(b, "last full capacity: %d", &acpi_last_full[idx]) != 0) {
1310 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1312 strcpy(charging_state, "unknown");
1314 while (!feof(acpi_bat_fp[idx])) {
1316 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL)
1319 /* let's just hope units are ok */
1320 if (strncmp (buf, "present:", 8) == 0)
1321 sscanf(buf, "present: %4s", present);
1322 else if (strncmp (buf, "charging state:", 15) == 0)
1323 sscanf(buf, "charging state: %63s", charging_state);
1324 else if (strncmp (buf, "present rate:", 13) == 0)
1325 sscanf(buf, "present rate: %d", &present_rate);
1326 else if (strncmp(buf, "remaining capacity:", 19) == 0)
1327 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1330 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1331 if (remaining_capacity > acpi_last_full[idx])
1332 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1335 if (strcmp(present, "no") == 0) {
1336 strncpy(last_battery_str[idx], "not present", 64);
1339 else if (strcmp(charging_state, "charging") == 0) {
1340 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1341 /* e.g. charging 75% */
1342 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %i%%",
1343 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1345 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1346 (long) (((acpi_last_full[idx] - remaining_capacity) * 3600) /
1348 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1349 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %d%%",
1350 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1352 strncpy(last_battery_str[idx], "charging", sizeof(last_battery_str[idx])-1);
1356 else if (strncmp(charging_state, "discharging", 64) == 0) {
1357 if (present_rate > 0) {
1358 /* e.g. discharging 35% */
1359 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "discharging %i%%",
1360 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1362 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1363 (long) ((remaining_capacity * 3600) / present_rate));
1364 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1365 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "full");
1367 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1369 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1373 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1374 else if (strncmp(charging_state, "charged", 64) == 0) {
1375 /* Below happens with the second battery on my X40,
1376 * when the second one is empty and the first one
1378 if (remaining_capacity == 0)
1379 strcpy(last_battery_str[idx], "empty");
1381 strcpy(last_battery_str[idx], "charged");
1383 /* unknown, probably full / AC */
1385 if (acpi_last_full[idx] != 0
1386 && remaining_capacity != acpi_last_full[idx])
1387 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1388 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1390 strncpy(last_battery_str[idx], "AC", 64);
1394 if (apm_bat_fp[idx] == NULL)
1395 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1397 if (apm_bat_fp[idx] != NULL) {
1398 int ac, status, flag, life;
1400 fscanf(apm_bat_fp[idx],
1401 "%*s %*s %*x %x %x %x %d%%",
1402 &ac, &status, &flag, &life);
1405 /* could check now that there is ac */
1406 snprintf(last_battery_str[idx], 64, "AC");
1407 } else if (ac && life != 100) { /* could check that status==3 here? */
1408 snprintf(last_battery_str[idx], 64,
1409 "charging %d%%", life);
1411 snprintf(last_battery_str[idx], 64, "%d%%",
1415 /* it seemed to buffer it so file must be closed (or could use syscalls
1416 * directly but I don't feel like coding it now) */
1417 fclose(apm_bat_fp[idx]);
1418 apm_bat_fp[idx] = NULL;
1424 case BATTERY_STATUS:
1426 snprintf(buf, n, "%s", last_battery_str[idx]);
1431 snprintf(buf, n, "%s", last_battery_time_str[idx]);
1440 int get_battery_perct(const char *bat)
1444 char acpi_path[128];
1445 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1449 idx = get_battery_idx(bat);
1451 /* don't update battery too often */
1452 if (current_update_time - last_battery_perct_time[idx] < 30) {
1453 return last_battery_perct[idx];
1455 last_battery_perct_time[idx] = current_update_time;
1457 /* Only check for ACPI */
1459 if (acpi_bat_fp == NULL && apm_bat_fp == NULL)
1460 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1462 int remaining_capacity = -1;
1463 if (acpi_bat_fp[idx] != NULL) {
1464 /* read last full capacity if it's zero */
1465 if (acpi_design_capacity[idx] == 0) {
1470 ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1471 fp = open_file(path, &rep);
1475 if (fgets(b, 256, fp) == NULL)
1477 if (sscanf(b, "design capacity: %d", &acpi_design_capacity[idx]) != 0) {
1485 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1487 while (!feof(acpi_bat_fp[idx])) {
1489 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL)
1493 sscanf(buf, "remaining capacity: %d",
1494 &remaining_capacity);
1497 if(remaining_capacity < 0)
1499 /* compute the battery percentage */
1500 last_battery_perct[idx] =
1501 (int) (((float)remaining_capacity/acpi_design_capacity[idx]) * 100);
1502 return last_battery_perct[idx];
1505 int get_battery_perct_bar(const char *bar)
1508 get_battery_perct(bar);
1509 idx = get_battery_idx(bar);
1510 return (int) (last_battery_perct[idx] * 2.56 - 1);
1515 /* On Apple powerbook and ibook:
1516 $ cat /proc/pmu/battery_0
1523 $ cat /proc/pmu/info
1524 PMU driver version : 2
1525 PMU firmware version : 0c
1530 /* defines as in <linux/pmu.h> */
1531 #define PMU_BATT_PRESENT 0x00000001
1532 #define PMU_BATT_CHARGING 0x00000002
1534 static FILE* pmu_battery_fp;
1535 static FILE* pmu_info_fp;
1536 static char pb_battery_info[3][32];
1537 static double pb_battery_info_update;
1539 #define PMU_PATH "/proc/pmu"
1540 void get_powerbook_batt_info(char *buf, size_t n, int i)
1543 const char* batt_path = PMU_PATH "/battery_0";
1544 const char* info_path = PMU_PATH "/info";
1545 int flags, charge, max_charge, ac = -1;
1548 /* don't update battery too often */
1549 if (current_update_time - pb_battery_info_update < 29.5) {
1550 snprintf(buf, n, "%s", pb_battery_info[i]);
1553 pb_battery_info_update = current_update_time;
1555 if (pmu_battery_fp == NULL)
1556 pmu_battery_fp = open_file(batt_path, &rep);
1558 if (pmu_battery_fp != NULL) {
1559 rewind(pmu_battery_fp);
1560 while (!feof(pmu_battery_fp)) {
1562 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL)
1566 sscanf(buf, "flags : %8x", &flags);
1567 else if (buf[0] == 'c' && buf[1] == 'h')
1568 sscanf(buf, "charge : %d", &charge);
1569 else if (buf[0] == 'm')
1570 sscanf(buf, "max_charge : %d", &max_charge);
1571 else if (buf[0] == 't')
1572 sscanf(buf, "time rem. : %ld", &time);
1575 if (pmu_info_fp == NULL)
1576 pmu_info_fp = open_file(info_path, &rep);
1578 if (pmu_info_fp != NULL) {
1579 rewind(pmu_info_fp);
1580 while (!feof(pmu_info_fp)) {
1582 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL)
1585 sscanf(buf, "AC Power : %d", &ac);
1588 /* update status string */
1589 if ((ac && !(flags & PMU_BATT_PRESENT)))
1590 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
1591 else if (ac && (flags & PMU_BATT_PRESENT)
1592 && !(flags & PMU_BATT_CHARGING))
1593 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
1594 else if ((flags & PMU_BATT_PRESENT)
1595 && (flags & PMU_BATT_CHARGING))
1596 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
1598 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
1600 /* update percentage string */
1602 pb_battery_info[PB_BATT_PERCENT][0] = 0;
1604 snprintf(pb_battery_info[PB_BATT_PERCENT],
1605 sizeof(pb_battery_info[PB_BATT_PERCENT]),
1606 "%d%%", (charge * 100)/max_charge);
1608 /* update time string */
1609 if (time == 0) /* fully charged or battery not present */
1610 pb_battery_info[PB_BATT_TIME][0] = 0;
1611 else if (time < 60*60) /* don't show secs */
1612 format_seconds_short(pb_battery_info[PB_BATT_TIME],
1613 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1615 format_seconds(pb_battery_info[PB_BATT_TIME],
1616 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1618 snprintf(buf, n, "%s", pb_battery_info[i]);
1623 show_nice_processes = 1;
1624 process_find_top(info.cpu, info.memu);
1625 info.first_process = get_first_process();
1630 * The following ifdefs were adapted from gkrellm
1632 #include <linux/major.h>
1634 #if ! defined (MD_MAJOR)
1638 #if !defined(LVM_BLK_MAJOR)
1639 #define LVM_BLK_MAJOR 58
1642 #if !defined(NBD_MAJOR)
1643 #define NBD_MAJOR 43
1646 void update_diskio()
1648 static unsigned int last = UINT_MAX;
1649 static unsigned int last_read = UINT_MAX;
1650 static unsigned int last_write = UINT_MAX;
1656 unsigned int current = 0;
1657 unsigned int current_read = 0;
1658 unsigned int current_write = 0;
1659 unsigned int reads, writes = 0;
1662 if (!(fp =open_file("/proc/diskstats", &rep))) {
1667 /* read reads and writes from all disks (minor = 0), including
1668 * cd-roms and floppies, and summ them up
1671 fgets(buf, 512, fp);
1672 col_count = sscanf(buf, "%u %u %*s %*u %*u %u %*u %*u %*u %u",
1673 &major, &minor, &reads, &writes);
1674 /* ignore subdevices (they have only 3 matching entries in their line)
1675 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
1677 * XXX ignore devices which are part of a SW RAID (MD_MAJOR)
1679 if (col_count > 3 &&
1680 major != LVM_BLK_MAJOR && major != NBD_MAJOR &&
1681 major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
1682 current += reads + writes;
1683 current_read += reads;
1684 current_write += writes;
1688 /* since the values in /proc/diststats are absolute, we have
1689 * to substract our last reading. The numbers stand for
1690 * "sectors read", and we therefore have to divide by two to
1692 int tot = ((double)(current-last)/2);
1693 int tot_read = ((double)(current_read-last_read)/2);
1694 int tot_write = ((double)(current_write-last_write)/2);
1696 if (last_read > current_read)
1698 if (last_write > current_write)
1701 if (last > current) {
1702 /* we hit this either if it's the very first time we
1703 * run this, or when /proc/diskstats overflows; while
1704 * 0 is not correct, it's at least not way off */
1708 last_read = current_read;
1709 last_write = current_write;
1712 diskio_read_value = tot_read;
1713 diskio_write_value = tot_write;
1718 /* Here come the IBM ACPI-specific things. For reference, see
1719 http://ibm-acpi.sourceforge.net/README
1720 If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
1736 The content of these files is described in detail in the aforementioned
1737 README - some of them also in the following functions accessing them.
1738 Peter Tarjan (ptarjan@citromail.hu)
1741 #define IBM_ACPI_DIR "/proc/acpi/ibm"
1743 void get_ibm_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1745 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
1746 /proc/acpi/ibm/fan looks like this (3 lines):
1749 commands: enable, disable
1750 Peter Tarjan (ptarjan@citromail.hu)
1753 if ( !p_client_buffer || client_buffer_size <= 0 )
1757 unsigned int speed=0;
1759 snprintf(fan, 127, "%s/fan",IBM_ACPI_DIR);
1761 fp = fopen(fan, "r");
1767 if (fgets(line, 255, fp) == NULL) break;
1768 if (sscanf(line, "speed: %d", &speed)) break;
1773 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", fan, strerror(errno));
1777 snprintf( p_client_buffer, client_buffer_size, "%d", speed );
1782 static double last_ibm_acpi_temp_time;
1783 void get_ibm_acpi_temps()
1785 /* get the measured temperatures from the temperature sensors
1786 on IBM/Lenovo laptops running the ibm acpi.
1787 There are 8 values in /proc/acpi/ibm/thermal, and according to
1788 http://ibm-acpi.sourceforge.net/README
1789 these mean the following (at least on an IBM R51...)
1790 0: CPU (also on the T series laptops)
1791 1: Mini PCI Module (?)
1793 3: GPU (also on the T series laptops)
1798 I'm not too sure about those with the question mark, but the values I'm
1799 reading from *my* thermal file (on a T42p) look realistic for the
1800 hdd and the battery.
1801 #5 and #7 are always -128.
1802 /proc/acpi/ibm/thermal looks like this (1 line):
1803 temperatures: 41 43 31 46 33 -128 29 -128
1804 Peter Tarjan (ptarjan@citromail.hu)
1807 /* don't update too often */
1808 if (current_update_time - last_ibm_acpi_temp_time < 10.00)
1812 last_ibm_acpi_temp_time = current_update_time;
1814 /* if ( !p_client_buffer || client_buffer_size <= 0 )
1820 snprintf(thermal, 127, "%s/thermal",IBM_ACPI_DIR);
1821 fp = fopen(thermal, "r");
1828 if (fgets(line, 255, fp) == NULL) break;
1829 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
1830 &ibm_acpi.temps[0], &ibm_acpi.temps[1],
1831 &ibm_acpi.temps[2], &ibm_acpi.temps[3],
1832 &ibm_acpi.temps[4], &ibm_acpi.temps[5],
1833 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) break;
1838 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", thermal, strerror(errno));
1846 void get_ibm_acpi_volume( char * p_client_buffer, size_t client_buffer_size )
1849 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
1850 "Volume" here is none of the mixer volumes, but a "master of masters"
1851 volume adjusted by the IBM volume keys.
1852 /proc/acpi/ibm/fan looks like this (4 lines):
1855 commands: up, down, mute
1856 commands: level <level> (<level> is 0-15)
1857 Peter Tarjan (ptarjan@citromail.hu)
1860 if ( !p_client_buffer || client_buffer_size <= 0 )
1866 snprintf(volume, 127, "%s/volume",IBM_ACPI_DIR);
1867 unsigned int vol=-1;
1870 fp = fopen(volume, "r");
1876 if (fgets(line, 255, fp) == NULL) break;
1877 if (sscanf(line, "level: %d", &vol)) continue;
1878 if (sscanf(line, "mute: %s", mute)) break;
1883 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", volume, strerror(errno));
1888 if (strcmp(mute, "on")==0)
1890 snprintf( p_client_buffer, client_buffer_size, "%s", "mute" );
1895 snprintf( p_client_buffer, client_buffer_size, "%d", vol );
1901 /*static FILE *fp=NULL;*/
1903 void get_ibm_acpi_brightness(char * p_client_buffer, size_t client_buffer_size)
1905 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
1906 /proc/acpi/ibm/brightness looks like this (3 lines):
1909 commands: level <level> (<level> is 0-7)
1910 Peter Tarjan (ptarjan@citromail.hu)
1913 if ( !p_client_buffer || client_buffer_size <= 0 )
1917 unsigned int brightness=0;
1919 snprintf(filename, 127, "%s/brightness",IBM_ACPI_DIR);
1921 fp = fopen(filename, "r");
1927 if (fgets(line, 255, fp) == NULL) break;
1928 if (sscanf(line, "level: %d", &brightness)) break;
1933 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", filename, strerror(errno));
1938 snprintf( p_client_buffer, client_buffer_size, "%d", brightness );
1943 void update_entropy (void)
1946 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
1947 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
1950 info.entropy.entropy_avail=0;
1951 info.entropy.poolsize=0;
1953 if ((fp1 = open_file (entropy_avail, &rep))==NULL)
1956 if ((fp2 = open_file (entropy_poolsize, &rep))==NULL)
1962 fscanf (fp1, "%u", &info.entropy.entropy_avail);
1963 fscanf (fp2, "%u", &info.entropy.poolsize);
1968 info.mask |= (1 << INFO_ENTROPY);