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 if (curtmp1 == 0) curtmp1 = 1;
256 if (curtmp2 == 0) curtmp2 = 1;
257 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
258 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
259 if (info.net_avg_samples > 1) {
260 for (i = info.net_avg_samples; i > 1; i--) {
261 ns->net_rec[i - 1] = ns->net_rec[i - 2];
262 ns->net_trans[i - 1] =
263 ns->net_trans[i - 2];
271 info.mask |= (1 << INFO_NET);
274 inline void update_wifi_stats()
276 /** wireless stats patch by Bobby Beckmann **/
280 /*open file and ignore first two lines sorry, this code sucks ass right now, i'll clean it up later */
281 if (net_wireless_fp == NULL)
282 net_wireless_fp = open_file("/proc/net/wireless", &rep);
284 fseek(net_wireless_fp, 0, SEEK_SET);
285 if (net_wireless_fp == NULL)
288 fgets(buf, 255, net_wireless_fp); /* garbage */
289 fgets(buf, 255, net_wireless_fp); /* garbage (field names) */
291 /* read each interface */
292 for (i = 0; i < 16; i++) {
297 if (fgets(buf, 255, net_wireless_fp) == NULL)
300 while (isspace((int) *p))
305 while (*p && *p != ':')
312 ns = get_net_stat(s);
314 sscanf(p, "%*d %d. %d. %d", &l, &m, &n);
316 ns->linkstatus = (int) (log(MIN(MAX(l,1),92)) / log(92) * 100);
320 /*** end wireless patch ***/
325 void update_total_processes()
330 struct sysinfo s_info;
332 info.procs = s_info.procs;
340 if (!(fp = open_file("/proc/loadavg", &rep)))
345 fscanf(fp, "%*f %*f %*f %*d/%hd", &info.procs );
348 info.mask |= (1 << INFO_PROCS);
351 #define CPU_SAMPLE_COUNT 15
353 unsigned long long cpu_user;
354 unsigned long long cpu_system;
355 unsigned long long cpu_nice;
356 unsigned long long cpu_idle;
357 unsigned long long cpu_iowait;
358 unsigned long long cpu_irq;
359 unsigned long long cpu_softirq;
360 unsigned long long cpu_steal;
361 unsigned long long cpu_total;
362 unsigned long long cpu_active_total;
363 unsigned long long cpu_last_total;
364 unsigned long long cpu_last_active_total;
365 double cpu_val[CPU_SAMPLE_COUNT];
367 static short cpu_setup = 0;
370 determine if this kernel gives us "extended" statistics information in /proc/stat.
371 Kernels around 2.5 and earlier only reported user, system, nice and idle values in proc stat.
372 Kernels around 2.6 and greater report these PLUS iowait, irq, softirq, and steal
374 void determine_longstat(char * buf) {
375 unsigned long long iowait=0;
376 KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
377 /* scanf will either return -1 or 1 because there is only 1 assignment */
378 if (sscanf(buf, "%*s %*d %*d %*d %*d %llu",&iowait)>0) KFLAG_SETON(KFLAG_IS_LONGSTAT);
386 if (info.cpu_usage) {
391 if (!(stat_fp = open_file("/proc/stat", &rep)))
396 while (!feof(stat_fp)) {
397 if (fgets(buf, 255, stat_fp) == NULL)
400 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
401 if (info.cpu_count == 0) {
402 determine_longstat(buf);
407 info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
412 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
413 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
415 inline static void update_stat()
419 static struct cpu_info *cpu = NULL;
424 char * stat_template=NULL;
425 unsigned int malloc_cpu_size=0;
428 /* add check for !info.cpu_usage since that mem is freed on a SIGUSR1 */
429 if (!cpu_setup || !info.cpu_usage) {
434 if (!stat_template) {
435 stat_template = KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT ;
439 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
440 cpu = malloc(malloc_cpu_size);
441 memset(cpu, 0, malloc_cpu_size);
444 if (!(stat_fp = open_file("/proc/stat", &rep)))
449 memset(info.cpu_usage, 0, info.cpu_count * sizeof (float));
455 while (!feof(stat_fp)) {
456 if (fgets(buf, 255, stat_fp) == NULL)
459 if (strncmp(buf, "procs_running ", 14) == 0) {
460 sscanf(buf, "%*s %hu", &info.run_procs);
461 info.mask |= (1 << INFO_RUN_PROCS);
462 } else if (strncmp(buf, "cpu", 3) == 0) {
463 index = isdigit(buf[3]) ? ((int)buf[3]) - 0x2F : 0;
464 sscanf(buf, stat_template
465 , &(cpu[index].cpu_user)
466 , &(cpu[index].cpu_nice)
467 , &(cpu[index].cpu_system)
468 , &(cpu[index].cpu_idle)
469 , &(cpu[index].cpu_iowait)
470 , &(cpu[index].cpu_irq)
471 , &(cpu[index].cpu_softirq)
472 , &(cpu[index].cpu_steal)
475 cpu[index].cpu_total = cpu[index].cpu_user
476 + cpu[index].cpu_nice
477 + cpu[index].cpu_system
478 + cpu[index].cpu_idle
479 + cpu[index].cpu_iowait
481 + cpu[index].cpu_softirq
482 + cpu[index].cpu_steal
485 cpu[index].cpu_active_total = cpu[index].cpu_total - (cpu[index].cpu_idle + cpu[index].cpu_iowait);
486 info.mask |= (1 << INFO_CPU);
488 double delta = current_update_time - last_update_time;
489 if (delta <= 0.001) break;
491 cpu[index].cpu_val[0] = (cpu[index].cpu_active_total - cpu[index].cpu_last_active_total) /
492 (float )(cpu[index].cpu_total - cpu[index].cpu_last_total);
494 for (i=0; i < info.cpu_avg_samples; i++ ) {
495 curtmp += cpu[index].cpu_val[i];
497 /* TESTING -- I've removed this, because I don't think it is right. You shouldn't divide
498 by the cpu count here ... removing for testing */
500 info.cpu_usage[index] = curtmp / info.cpu_avg_samples / info.cpu_count;
502 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
504 /* TESTING -- this line replaces the prev. "suspect" if/else */
505 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
507 cpu[index].cpu_last_total = cpu[index].cpu_total;
508 cpu[index].cpu_last_active_total = cpu[index].cpu_active_total;
509 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
510 cpu[index].cpu_val[i] = cpu[index].cpu_val[i - 1];
518 void update_running_processes()
523 void update_cpu_usage()
528 void update_load_average()
530 #ifdef HAVE_GETLOADAVG
535 info.loadavg[0] = (float) v[0];
536 info.loadavg[1] = (float) v[1];
537 info.loadavg[2] = (float) v[2];
545 if (!(fp = open_file("/proc/loadavg", &rep)))
547 info.loadavg[0] = info.loadavg[1] = info.loadavg[2] = 0.0;
550 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1], &info.loadavg[2]);
553 info.mask |= (1 << INFO_LOADAVG);
556 #define PROC_I8K "/proc/i8k"
557 #define I8K_DELIM " "
558 static char *i8k_procbuf = NULL;
563 i8k_procbuf = (char*)malloc(128*sizeof(char));
565 if ((fp = fopen(PROC_I8K,"r")) == NULL) {
566 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel driver is loaded...");
569 memset(&i8k_procbuf[0],0,128);
570 if (fread(&i8k_procbuf[0],sizeof(char),128,fp) == 0) {
571 ERR("something wrong with /proc/i8k...");
576 i8k.version = strtok(&i8k_procbuf[0],I8K_DELIM);
577 i8k.bios = strtok(NULL,I8K_DELIM);
578 i8k.serial = strtok(NULL,I8K_DELIM);
579 i8k.cpu_temp = strtok(NULL,I8K_DELIM);
580 i8k.left_fan_status = strtok(NULL,I8K_DELIM);
581 i8k.right_fan_status = strtok(NULL,I8K_DELIM);
582 i8k.left_fan_rpm = strtok(NULL,I8K_DELIM);
583 i8k.right_fan_rpm = strtok(NULL,I8K_DELIM);
584 i8k.ac_status = strtok(NULL,I8K_DELIM);
585 i8k.buttons_status = strtok(NULL,I8K_DELIM);
589 /***********************************************************/
590 /***********************************************************/
591 /***********************************************************/
593 static int no_dots(const struct dirent *d)
595 if (d->d_name[0] == '.')
601 get_first_file_in_a_directory(const char *dir, char *s, int *rep)
603 struct dirent **namelist;
606 n = scandir(dir, &namelist, no_dots, alphasort);
609 ERR("scandir for %s: %s", dir, strerror(errno));
618 strncpy(s, namelist[0]->d_name, 255);
621 for (i = 0; i < n; i++)
629 int open_i2c_sensor(const char *dev, const char *type, int n, int *div, char *devtype)
632 if (post_21_kernel) {
633 strncpy(i2c_dir, "/sys/bus/platform/devices/", 64);
635 strncpy(i2c_dir, "/sys/bus/i2c/devices/", 64);
642 /* if i2c device is NULL or *, get first */
643 if (dev == NULL || strcmp(dev, "*") == 0) {
645 if (!get_first_file_in_a_directory(i2c_dir, buf, &rep))
650 /* change vol to in */
651 if (strcmp(type, "vol") == 0)
654 if (strcmp(type, "tempf") == 0) {
655 snprintf(path, 255, "%s%s/%s%d_input", i2c_dir, dev, "temp", n);
657 snprintf(path, 255, "%s%s/%s%d_input", i2c_dir, dev, type, n);
659 strncpy(devtype, path, 255);
662 fd = open(path, O_RDONLY);
664 CRIT_ERR("can't open '%s': %s\nplease fix i2c or remove it from Conky", path, strerror(errno));
667 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
668 || strcmp(type, "tempf") == 0)
672 /* fan does not use *_div as a read divisor */
673 if (strcmp("fan", type) == 0)
676 /* test if *_div file exist, open it and use it as divisor */
677 if (strcmp(type, "tempf") == 0) {
678 snprintf(path, 255, "%s%s/%s%d_div", i2c_dir, "one", "two",
681 snprintf(path, 255, "%s%s/%s%d_div", i2c_dir, dev, type, n);
684 divfd = open(path, O_RDONLY);
689 divn = read(divfd, divbuf, 63);
690 /* should read until n == 0 but I doubt that kernel will give these
691 * in multiple pieces. :) */
701 double get_i2c_info(int *fd, int div, char *devtype, char *type)
708 lseek(*fd, 0, SEEK_SET);
714 n = read(*fd, buf, 63);
715 /* should read until n == 0 but I doubt that kernel will give these
716 * in multiple pieces. :) */
723 *fd = open(devtype, O_RDONLY);
725 ERR("can't open '%s': %s", devtype, strerror(errno));
727 /* My dirty hack for computing CPU value
728 * Filedil, from forums.gentoo.org
730 /* if (strstr(devtype, "temp1_input") != NULL)
731 return -15.096+1.4893*(val / 1000.0); */
734 /* divide voltage and temperature by 1000 */
735 /* or if any other divisor is given, use that */
736 if (strcmp(type, "tempf") == 0) {
738 return ((val / div + 40) * 9.0 / 5) - 40;
740 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
742 return ((val + 40) * 9.0 / 5) - 40;
753 /* Prior to kernel version 2.6.12, the CPU fan speed was available
754 * in ADT746X_FAN_OLD, whereas later kernel versions provide this
755 * information in ADT746X_FAN.
757 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
758 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
760 void get_adt746x_fan( char * p_client_buffer, size_t client_buffer_size )
763 char adt746x_fan_state[64];
766 if ( !p_client_buffer || client_buffer_size <= 0 )
769 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
770 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL)
773 sprintf(adt746x_fan_state, "adt746x not found");
777 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
778 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
782 snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_fan_state );
786 /* Prior to kernel version 2.6.12, the CPU temperature was found
787 * in ADT746X_CPU_OLD, whereas later kernel versions provide this
788 * information in ADT746X_CPU.
790 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
791 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
793 void get_adt746x_cpu( char * p_client_buffer, size_t client_buffer_size )
796 char adt746x_cpu_state[64];
799 if ( !p_client_buffer || client_buffer_size <= 0 )
802 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
803 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL)
805 sprintf(adt746x_cpu_state, "adt746x not found");
809 fscanf(fp, "%2s", adt746x_cpu_state);
813 snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state );
817 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
819 /***********************************************************************/
821 * This file is part of x86info.
822 * (C) 2001 Dave Jones.
824 * Licensed under the terms of the GNU GPL License version 2.
826 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
827 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz>
830 #if defined(__i386) || defined(__x86_64)
831 __inline__ unsigned long long int rdtsc()
833 unsigned long long int x;
834 __asm__ volatile (".byte 0x0f, 0x31":"=A" (x));
839 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
840 void get_freq_dynamic( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor )
842 #if defined(__i386) || defined(__x86_64)
844 struct timeval tvstart, tvstop;
845 unsigned long long cycles[2]; /* gotta be 64 bit */
846 unsigned int microseconds; /* total time taken */
848 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
851 memset(&tz, 0, sizeof(tz));
853 /* get this function in cached memory */
854 gettimeofday(&tvstart, &tz);
856 gettimeofday(&tvstart, &tz);
858 /* we don't trust that this is any specific length of time */
861 gettimeofday(&tvstop, &tz);
862 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
863 (tvstop.tv_usec - tvstart.tv_usec);
865 snprintf( p_client_buffer, client_buffer_size, p_format, (float)((cycles[1] - cycles[0]) / microseconds) / divisor );
868 /* FIXME: hardwired: get freq for first cpu!
869 this whole function needs to be rethought and redone for
870 multi-cpu/multi-core/multi-threaded environments and
871 arbitrary combinations thereof
873 get_freq( p_client_buffer, client_buffer_size, p_format, divisor, 1 );
879 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
880 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
882 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
883 char get_freq( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
891 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
896 char current_freq_file[128];
897 snprintf(current_freq_file, 127, "%s/cpu%d/%s",CPUFREQ_PREFIX, cpu-1, CPUFREQ_POSTFIX);
898 f = fopen(current_freq_file, "r");
901 /* if there's a cpufreq /sys node, read the current frequency from this node;
902 * divide by 1000 to get Mhz. */
903 if (fgets(s, sizeof(s), f)) {
904 s[strlen(s)-1] = '\0';
905 freq = strtod(s, NULL);
908 snprintf( p_client_buffer, client_buffer_size, p_format, (freq/1000)/divisor );
913 f = open_file("/proc/cpuinfo", &rep); //open the CPU information file
915 perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
919 while (fgets(s, sizeof(s), f) != NULL){ //read the file
921 #if defined(__i386) || defined(__x86_64)
922 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) { //and search for the cpu mhz
925 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) { // different on alpha
927 if (strncmp(s, "clock", 5) == 0 && cpu == 0) { // this is different on ppc for some reason
928 #endif // defined(__alpha)
929 #endif // defined(__i386) || defined(__x86_64)
931 strcpy(frequency, strchr(s, ':') + 2); //copy just the number
933 frequency[strlen(frequency) - 6] = '\0';// strip " est.\n"
934 freq = strtod(frequency, NULL)/1000000; // kernel reports in Hz
936 frequency[strlen(frequency) - 1] = '\0'; // strip \n
937 freq = strtod(frequency, NULL);
941 if (strncmp(s, "processor", 9) == 0) {
949 snprintf( p_client_buffer, client_buffer_size, p_format, (float)freq/divisor );
953 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
955 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
956 char get_voltage( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
958 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks
970 /* Peter Tarjan (ptarjan@citromail.hu) */
975 char current_freq_file[128];
979 /* build the voltage file name */
981 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
982 CPUFREQ_PREFIX, cpu, CPUFREQ_POSTFIX);
984 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
987 /* read the current cpu frequency from the /sys node */
988 f = fopen(current_freq_file, "r");
990 if (fgets(s, sizeof(s), f)) {
991 s[strlen(s)-1] = '\0';
992 freq = strtod(s, NULL);
996 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
997 perror("get_voltage()");
1004 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
1005 CPUFREQ_PREFIX, cpu, CPUFREQ_VOLTAGE);
1007 /* use the current cpu frequency to find the corresponding voltage */
1008 f = fopen(current_freq_file, "r");
1013 if (fgets(line, 255, f) == NULL) break;
1014 sscanf(line, "%d %d", &freq_comp, &voltage);
1015 if(freq_comp == freq) break;
1019 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1020 perror("get_voltage()");
1026 snprintf( p_client_buffer, client_buffer_size, p_format, (float)voltage/divisor );
1031 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1033 void get_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1040 if ( !p_client_buffer || client_buffer_size <= 0 )
1043 /* yeah, slow... :/ */
1044 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep))
1046 snprintf( p_client_buffer, client_buffer_size, "no fans?" );
1050 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf );
1052 fp = open_file(buf2, &rep);
1054 snprintf( p_client_buffer, client_buffer_size, "can't open fan's state file" );
1057 memset(buf,0,sizeof(buf));
1058 fscanf(fp, "%*s %99s", buf);
1061 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1066 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1068 void get_acpi_ac_adapter( char * p_client_buffer, size_t client_buffer_size )
1075 if ( !p_client_buffer || client_buffer_size <= 0 )
1078 /* yeah, slow... :/ */
1079 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep))
1081 snprintf( p_client_buffer, client_buffer_size, "no ac_adapters?" );
1085 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf );
1088 fp = open_file(buf2, &rep);
1090 snprintf( p_client_buffer, client_buffer_size, "No ac adapter found.... where is it?" );
1093 memset(buf,0,sizeof(buf));
1094 fscanf(fp, "%*s %99s", buf );
1097 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1103 /proc/acpi/thermal_zone/THRM/cooling_mode
1104 cooling mode: active
1105 /proc/acpi/thermal_zone/THRM/polling_frequency
1107 /proc/acpi/thermal_zone/THRM/state
1109 /proc/acpi/thermal_zone/THRM/temperature
1111 /proc/acpi/thermal_zone/THRM/trip_points
1113 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1116 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1117 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1119 int open_acpi_temperature(const char *name)
1125 if (name == NULL || strcmp(name, "*") == 0) {
1127 if (!get_first_file_in_a_directory
1128 (ACPI_THERMAL_DIR, buf, &rep))
1133 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1135 fd = open(path, O_RDONLY);
1137 ERR("can't open '%s': %s", path, strerror(errno));
1142 static double last_acpi_temp;
1143 static double last_acpi_temp_time;
1145 double get_acpi_temperature(int fd)
1150 /* don't update acpi temperature too often */
1151 if (current_update_time - last_acpi_temp_time < 11.32) {
1152 return last_acpi_temp;
1154 last_acpi_temp_time = current_update_time;
1156 /* seek to beginning */
1157 lseek(fd, 0, SEEK_SET);
1163 n = read(fd, buf, 255);
1165 ERR("can't read fd %d: %s", fd, strerror(errno));
1168 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1172 return last_acpi_temp;
1176 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1178 design capacity: 4400 mAh
1179 last full capacity: 4064 mAh
1180 battery technology: rechargeable
1181 design voltage: 14800 mV
1182 design capacity warning: 300 mAh
1183 design capacity low: 200 mAh
1184 capacity granularity 1: 32 mAh
1185 capacity granularity 2: 32 mAh
1187 serial number: 16922
1193 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1196 charging state: unknown
1198 remaining capacity: 4064 mAh
1199 present voltage: 16608 mV
1203 2213<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1204 2213<@jupet kellari ö> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1205 2213<@jupet kellari ö> (-1 ollee ei akkua kiinni, koska akku on pöydällä)
1206 2214<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1207 2214<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1209 2238<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1210 2239<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1212 2240<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori päällä
1213 2241<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori päällä mutta ilman verkkovirtaa
1216 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1217 #define APM_PATH "/proc/apm"
1218 #define MAX_BATTERY_COUNT 4
1220 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT];
1221 static FILE *apm_bat_fp[MAX_BATTERY_COUNT];
1223 static int batteries_initialized = 0;
1224 static char batteries[MAX_BATTERY_COUNT][32];
1226 static int acpi_last_full[MAX_BATTERY_COUNT];
1227 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1229 static char last_battery_str[MAX_BATTERY_COUNT][64]; /* e.g. "charging 75%" */
1230 static char last_battery_time_str[MAX_BATTERY_COUNT][64]; /* e.g. "3h 15m" */
1232 static double last_battery_time[MAX_BATTERY_COUNT];
1234 static int last_battery_perct[MAX_BATTERY_COUNT];
1235 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1238 void init_batteries(void)
1241 if(batteries_initialized)
1243 for(idx = 0; idx < MAX_BATTERY_COUNT; idx++)
1244 batteries[idx][0] = '\0';
1245 batteries_initialized = 1;
1248 int get_battery_idx(const char *bat)
1251 for(idx = 0; idx < MAX_BATTERY_COUNT; idx++)
1252 if(!strlen(batteries[idx]) || !strcmp(batteries[idx], bat))
1255 /* if not found, enter a new entry */
1256 if(!strlen(batteries[idx]))
1257 snprintf(batteries[idx], 31, "%s", bat);
1262 void get_battery_stuff(char *buf, unsigned int n, const char *bat, int item)
1264 static int idx, rep = 0, rep2 = 0;
1265 char acpi_path[128];
1266 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1270 idx = get_battery_idx(bat);
1272 /* don't update battery too often */
1273 if (current_update_time - last_battery_time[idx] < 29.5)
1274 goto set_return_value;
1276 last_battery_time[idx] = current_update_time;
1278 memset (last_battery_str[idx], 0, sizeof (last_battery_str[idx]));
1279 memset (last_battery_time_str[idx], 0, sizeof (last_battery_time_str[idx]));
1281 /* first try ACPI */
1283 if (acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1284 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1286 if (acpi_bat_fp[idx] != NULL) {
1287 int present_rate = -1;
1288 int remaining_capacity = -1;
1289 char charging_state[64];
1292 /* read last full capacity if it's zero */
1293 if (acpi_last_full[idx] == 0) {
1298 ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1299 fp = open_file(path, &rep);
1303 if (fgets(b, 256, fp) == NULL)
1305 if (sscanf(b, "last full capacity: %d", &acpi_last_full[idx]) != 0) {
1314 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1316 strcpy(charging_state, "unknown");
1318 while (!feof(acpi_bat_fp[idx])) {
1320 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL)
1323 /* let's just hope units are ok */
1324 if (strncmp (buf, "present:", 8) == 0)
1325 sscanf(buf, "present: %4s", present);
1326 else if (strncmp (buf, "charging state:", 15) == 0)
1327 sscanf(buf, "charging state: %63s", charging_state);
1328 else if (strncmp (buf, "present rate:", 13) == 0)
1329 sscanf(buf, "present rate: %d", &present_rate);
1330 else if (strncmp(buf, "remaining capacity:", 19) == 0)
1331 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1334 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1335 if (remaining_capacity > acpi_last_full[idx])
1336 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1339 if (strcmp(present, "no") == 0) {
1340 strncpy(last_battery_str[idx], "not present", 64);
1343 else if (strcmp(charging_state, "charging") == 0) {
1344 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1345 /* e.g. charging 75% */
1346 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %i%%",
1347 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1349 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1350 (long) (((acpi_last_full[idx] - remaining_capacity) * 3600) /
1352 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1353 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %d%%",
1354 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1356 strncpy(last_battery_str[idx], "charging", sizeof(last_battery_str[idx])-1);
1360 else if (strncmp(charging_state, "discharging", 64) == 0) {
1361 if (present_rate > 0) {
1362 /* e.g. discharging 35% */
1363 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "discharging %i%%",
1364 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1366 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1367 (long) ((remaining_capacity * 3600) / present_rate));
1368 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1369 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "full");
1371 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1373 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1377 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1378 else if (strncmp(charging_state, "charged", 64) == 0) {
1379 /* Below happens with the second battery on my X40,
1380 * when the second one is empty and the first one
1382 if (remaining_capacity == 0)
1383 strcpy(last_battery_str[idx], "empty");
1385 strcpy(last_battery_str[idx], "charged");
1387 /* unknown, probably full / AC */
1389 if (acpi_last_full[idx] != 0
1390 && remaining_capacity != acpi_last_full[idx])
1391 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1392 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1394 strncpy(last_battery_str[idx], "AC", 64);
1398 if (apm_bat_fp[idx] == NULL)
1399 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1401 if (apm_bat_fp[idx] != NULL) {
1402 int ac, status, flag, life;
1404 fscanf(apm_bat_fp[idx],
1405 "%*s %*s %*x %x %x %x %d%%",
1406 &ac, &status, &flag, &life);
1409 /* could check now that there is ac */
1410 snprintf(last_battery_str[idx], 64, "AC");
1411 } else if (ac && life != 100) { /* could check that status==3 here? */
1412 snprintf(last_battery_str[idx], 64,
1413 "charging %d%%", life);
1415 snprintf(last_battery_str[idx], 64, "%d%%",
1419 /* it seemed to buffer it so file must be closed (or could use syscalls
1420 * directly but I don't feel like coding it now) */
1421 fclose(apm_bat_fp[idx]);
1422 apm_bat_fp[idx] = NULL;
1428 case BATTERY_STATUS:
1430 snprintf(buf, n, "%s", last_battery_str[idx]);
1435 snprintf(buf, n, "%s", last_battery_time_str[idx]);
1444 int get_battery_perct(const char *bat)
1448 char acpi_path[128];
1449 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1453 idx = get_battery_idx(bat);
1455 /* don't update battery too often */
1456 if (current_update_time - last_battery_perct_time[idx] < 30) {
1457 return last_battery_perct[idx];
1459 last_battery_perct_time[idx] = current_update_time;
1461 /* Only check for ACPI */
1463 if (acpi_bat_fp == NULL && apm_bat_fp == NULL)
1464 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1466 int remaining_capacity = -1;
1467 if (acpi_bat_fp[idx] != NULL) {
1468 /* read last full capacity if it's zero */
1469 if (acpi_design_capacity[idx] == 0) {
1474 ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1475 fp = open_file(path, &rep);
1479 if (fgets(b, 256, fp) == NULL)
1481 if (sscanf(b, "design capacity: %d", &acpi_design_capacity[idx]) != 0) {
1489 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1491 while (!feof(acpi_bat_fp[idx])) {
1493 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL)
1497 sscanf(buf, "remaining capacity: %d",
1498 &remaining_capacity);
1501 if(remaining_capacity < 0)
1503 /* compute the battery percentage */
1504 last_battery_perct[idx] =
1505 (int) (((float)remaining_capacity/acpi_design_capacity[idx]) * 100);
1506 return last_battery_perct[idx];
1509 int get_battery_perct_bar(const char *bar)
1512 get_battery_perct(bar);
1513 idx = get_battery_idx(bar);
1514 return (int) (last_battery_perct[idx] * 2.56 - 1);
1519 /* On Apple powerbook and ibook:
1520 $ cat /proc/pmu/battery_0
1527 $ cat /proc/pmu/info
1528 PMU driver version : 2
1529 PMU firmware version : 0c
1534 /* defines as in <linux/pmu.h> */
1535 #define PMU_BATT_PRESENT 0x00000001
1536 #define PMU_BATT_CHARGING 0x00000002
1538 static FILE* pmu_battery_fp;
1539 static FILE* pmu_info_fp;
1540 static char pb_battery_info[3][32];
1541 static double pb_battery_info_update;
1543 #define PMU_PATH "/proc/pmu"
1544 void get_powerbook_batt_info(char *buf, size_t n, int i)
1547 const char* batt_path = PMU_PATH "/battery_0";
1548 const char* info_path = PMU_PATH "/info";
1549 int flags, charge, max_charge, ac = -1;
1552 /* don't update battery too often */
1553 if (current_update_time - pb_battery_info_update < 29.5) {
1554 snprintf(buf, n, "%s", pb_battery_info[i]);
1557 pb_battery_info_update = current_update_time;
1559 if (pmu_battery_fp == NULL)
1560 pmu_battery_fp = open_file(batt_path, &rep);
1562 if (pmu_battery_fp != NULL) {
1563 rewind(pmu_battery_fp);
1564 while (!feof(pmu_battery_fp)) {
1566 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL)
1570 sscanf(buf, "flags : %8x", &flags);
1571 else if (buf[0] == 'c' && buf[1] == 'h')
1572 sscanf(buf, "charge : %d", &charge);
1573 else if (buf[0] == 'm')
1574 sscanf(buf, "max_charge : %d", &max_charge);
1575 else if (buf[0] == 't')
1576 sscanf(buf, "time rem. : %ld", &time);
1579 if (pmu_info_fp == NULL)
1580 pmu_info_fp = open_file(info_path, &rep);
1582 if (pmu_info_fp != NULL) {
1583 rewind(pmu_info_fp);
1584 while (!feof(pmu_info_fp)) {
1586 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL)
1589 sscanf(buf, "AC Power : %d", &ac);
1592 /* update status string */
1593 if ((ac && !(flags & PMU_BATT_PRESENT)))
1594 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
1595 else if (ac && (flags & PMU_BATT_PRESENT)
1596 && !(flags & PMU_BATT_CHARGING))
1597 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
1598 else if ((flags & PMU_BATT_PRESENT)
1599 && (flags & PMU_BATT_CHARGING))
1600 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
1602 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
1604 /* update percentage string */
1606 pb_battery_info[PB_BATT_PERCENT][0] = 0;
1608 snprintf(pb_battery_info[PB_BATT_PERCENT],
1609 sizeof(pb_battery_info[PB_BATT_PERCENT]),
1610 "%d%%", (charge * 100)/max_charge);
1612 /* update time string */
1613 if (time == 0) /* fully charged or battery not present */
1614 pb_battery_info[PB_BATT_TIME][0] = 0;
1615 else if (time < 60*60) /* don't show secs */
1616 format_seconds_short(pb_battery_info[PB_BATT_TIME],
1617 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1619 format_seconds(pb_battery_info[PB_BATT_TIME],
1620 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1622 snprintf(buf, n, "%s", pb_battery_info[i]);
1627 show_nice_processes = 1;
1628 process_find_top(info.cpu, info.memu);
1629 info.first_process = get_first_process();
1634 * The following ifdefs were adapted from gkrellm
1636 #include <linux/major.h>
1638 #if ! defined (MD_MAJOR)
1642 #if !defined(LVM_BLK_MAJOR)
1643 #define LVM_BLK_MAJOR 58
1646 #if !defined(NBD_MAJOR)
1647 #define NBD_MAJOR 43
1650 void update_diskio()
1652 static unsigned int last = UINT_MAX;
1653 static unsigned int last_read = UINT_MAX;
1654 static unsigned int last_write = UINT_MAX;
1660 unsigned int current = 0;
1661 unsigned int current_read = 0;
1662 unsigned int current_write = 0;
1663 unsigned int reads, writes = 0;
1666 if (!(fp =open_file("/proc/diskstats", &rep))) {
1671 /* read reads and writes from all disks (minor = 0), including
1672 * cd-roms and floppies, and summ them up
1675 fgets(buf, 512, fp);
1676 col_count = sscanf(buf, "%u %u %*s %*u %*u %u %*u %*u %*u %u",
1677 &major, &minor, &reads, &writes);
1678 /* ignore subdevices (they have only 3 matching entries in their line)
1679 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
1681 * XXX ignore devices which are part of a SW RAID (MD_MAJOR)
1683 if (col_count > 3 &&
1684 major != LVM_BLK_MAJOR && major != NBD_MAJOR &&
1685 major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
1686 current += reads + writes;
1687 current_read += reads;
1688 current_write += writes;
1692 /* since the values in /proc/diststats are absolute, we have
1693 * to substract our last reading. The numbers stand for
1694 * "sectors read", and we therefore have to divide by two to
1696 int tot = ((double)(current-last)/2);
1697 int tot_read = ((double)(current_read-last_read)/2);
1698 int tot_write = ((double)(current_write-last_write)/2);
1700 if (last_read > current_read)
1702 if (last_write > current_write)
1705 if (last > current) {
1706 /* we hit this either if it's the very first time we
1707 * run this, or when /proc/diskstats overflows; while
1708 * 0 is not correct, it's at least not way off */
1712 last_read = current_read;
1713 last_write = current_write;
1716 diskio_read_value = tot_read;
1717 diskio_write_value = tot_write;
1722 /* Here come the IBM ACPI-specific things. For reference, see
1723 http://ibm-acpi.sourceforge.net/README
1724 If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
1740 The content of these files is described in detail in the aforementioned
1741 README - some of them also in the following functions accessing them.
1742 Peter Tarjan (ptarjan@citromail.hu)
1745 #define IBM_ACPI_DIR "/proc/acpi/ibm"
1747 void get_ibm_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1749 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
1750 /proc/acpi/ibm/fan looks like this (3 lines):
1753 commands: enable, disable
1754 Peter Tarjan (ptarjan@citromail.hu)
1757 if ( !p_client_buffer || client_buffer_size <= 0 )
1761 unsigned int speed=0;
1763 snprintf(fan, 127, "%s/fan",IBM_ACPI_DIR);
1765 fp = fopen(fan, "r");
1771 if (fgets(line, 255, fp) == NULL) break;
1772 if (sscanf(line, "speed: %d", &speed)) break;
1777 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", fan, strerror(errno));
1781 snprintf( p_client_buffer, client_buffer_size, "%d", speed );
1786 static double last_ibm_acpi_temp_time;
1787 void get_ibm_acpi_temps()
1789 /* get the measured temperatures from the temperature sensors
1790 on IBM/Lenovo laptops running the ibm acpi.
1791 There are 8 values in /proc/acpi/ibm/thermal, and according to
1792 http://ibm-acpi.sourceforge.net/README
1793 these mean the following (at least on an IBM R51...)
1794 0: CPU (also on the T series laptops)
1795 1: Mini PCI Module (?)
1797 3: GPU (also on the T series laptops)
1802 I'm not too sure about those with the question mark, but the values I'm
1803 reading from *my* thermal file (on a T42p) look realistic for the
1804 hdd and the battery.
1805 #5 and #7 are always -128.
1806 /proc/acpi/ibm/thermal looks like this (1 line):
1807 temperatures: 41 43 31 46 33 -128 29 -128
1808 Peter Tarjan (ptarjan@citromail.hu)
1811 /* don't update too often */
1812 if (current_update_time - last_ibm_acpi_temp_time < 10.00)
1816 last_ibm_acpi_temp_time = current_update_time;
1818 /* if ( !p_client_buffer || client_buffer_size <= 0 )
1824 snprintf(thermal, 127, "%s/thermal",IBM_ACPI_DIR);
1825 fp = fopen(thermal, "r");
1832 if (fgets(line, 255, fp) == NULL) break;
1833 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
1834 &ibm_acpi.temps[0], &ibm_acpi.temps[1],
1835 &ibm_acpi.temps[2], &ibm_acpi.temps[3],
1836 &ibm_acpi.temps[4], &ibm_acpi.temps[5],
1837 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) break;
1842 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", thermal, strerror(errno));
1850 void get_ibm_acpi_volume( char * p_client_buffer, size_t client_buffer_size )
1853 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
1854 "Volume" here is none of the mixer volumes, but a "master of masters"
1855 volume adjusted by the IBM volume keys.
1856 /proc/acpi/ibm/fan looks like this (4 lines):
1859 commands: up, down, mute
1860 commands: level <level> (<level> is 0-15)
1861 Peter Tarjan (ptarjan@citromail.hu)
1864 if ( !p_client_buffer || client_buffer_size <= 0 )
1870 snprintf(volume, 127, "%s/volume",IBM_ACPI_DIR);
1871 unsigned int vol=-1;
1874 fp = fopen(volume, "r");
1880 if (fgets(line, 255, fp) == NULL) break;
1881 if (sscanf(line, "level: %d", &vol)) continue;
1882 if (sscanf(line, "mute: %s", mute)) break;
1887 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", volume, strerror(errno));
1892 if (strcmp(mute, "on")==0)
1894 snprintf( p_client_buffer, client_buffer_size, "%s", "mute" );
1899 snprintf( p_client_buffer, client_buffer_size, "%d", vol );
1905 /*static FILE *fp=NULL;*/
1907 void get_ibm_acpi_brightness(char * p_client_buffer, size_t client_buffer_size)
1909 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
1910 /proc/acpi/ibm/brightness looks like this (3 lines):
1913 commands: level <level> (<level> is 0-7)
1914 Peter Tarjan (ptarjan@citromail.hu)
1917 if ( !p_client_buffer || client_buffer_size <= 0 )
1921 unsigned int brightness=0;
1923 snprintf(filename, 127, "%s/brightness",IBM_ACPI_DIR);
1925 fp = fopen(filename, "r");
1931 if (fgets(line, 255, fp) == NULL) break;
1932 if (sscanf(line, "level: %d", &brightness)) break;
1937 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", filename, strerror(errno));
1942 snprintf( p_client_buffer, client_buffer_size, "%d", brightness );
1947 void update_entropy (void)
1950 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
1951 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
1954 info.entropy.entropy_avail=0;
1955 info.entropy.poolsize=0;
1957 if ((fp1 = open_file (entropy_avail, &rep))==NULL)
1960 if ((fp2 = open_file (entropy_poolsize, &rep))==NULL)
1966 fscanf (fp1, "%u", &info.entropy.entropy_avail);
1967 fscanf (fp2, "%u", &info.entropy.poolsize);
1972 info.mask |= (1 << INFO_ENTROPY);