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>
39 #define SHORTSTAT_TEMPL "%*s %llu %llu %llu"
40 #define LONGSTAT_TEMPL "%*s %llu %llu %llu "
42 static int show_nice_processes;
44 /* this flags tells the linux routines to use the /proc system
45 * where possible, even if other api's are available, e.g. sysinfo()
46 * or getloadavg(). the reason for this is to allow for /proc-based
47 * distributed monitoring. using a flag in this manner creates less
50 static int prefer_proc = 0;
61 struct sysinfo s_info;
63 info.uptime = (double) s_info.uptime;
71 if (!(fp = open_file("/proc/uptime", &rep)))
76 fscanf(fp, "%lf", &info.uptime);
79 info.mask |= (1 << INFO_UPTIME);
82 int check_mount(char *s)
85 FILE *mtab = fopen("/etc/mtab", "r");
87 char buf1[256], buf2[128];
88 while (fgets(buf1, 256, mtab)) {
89 sscanf(buf1, "%*s %128s", buf2);
90 if (!strcmp(s, buf2)) {
97 ERR("Could not open mtab");
102 /* these things are also in sysinfo except Buffers:, that's why I'm reading
105 void update_meminfo()
109 /* unsigned int a; */
112 info.mem = info.memmax = info.swap = info.swapmax = info.bufmem =
113 info.buffers = info.cached = 0;
115 if (!(meminfo_fp = open_file("/proc/meminfo", &rep)))
118 while (!feof(meminfo_fp)) {
119 if (fgets(buf, 255, meminfo_fp) == NULL)
122 if (strncmp(buf, "MemTotal:", 9) == 0) {
123 sscanf(buf, "%*s %Lu", &info.memmax);
124 } else if (strncmp(buf, "MemFree:", 8) == 0) {
125 sscanf(buf, "%*s %Lu", &info.mem);
126 } else if (strncmp(buf, "SwapTotal:", 10) == 0) {
127 sscanf(buf, "%*s %Lu", &info.swapmax);
128 } else if (strncmp(buf, "SwapFree:", 9) == 0) {
129 sscanf(buf, "%*s %Lu", &info.swap);
130 } else if (strncmp(buf, "Buffers:", 8) == 0) {
131 sscanf(buf, "%*s %Lu", &info.buffers);
132 } else if (strncmp(buf, "Cached:", 7) == 0) {
133 sscanf(buf, "%*s %Lu", &info.cached);
137 info.mem = info.memmax - info.mem;
138 info.swap = info.swapmax - info.swap;
140 info.bufmem = info.cached + info.buffers;
142 info.mask |= (1 << INFO_MEM) | (1 << INFO_BUFFERS);
147 static FILE *net_wireless_fp;
149 inline void update_net_stats()
153 // FIXME: arbitrary size chosen to keep code simple.
155 unsigned int curtmp1, curtmp2;
162 // wireless info variables
163 int skfd, has_bitrate = 0;
164 struct wireless_info *winfo;
169 delta = current_update_time - last_update_time;
173 /* open file and ignore first two lines */
174 if (!(net_dev_fp = open_file("/proc/net/dev", &rep)))
180 fgets(buf, 255, net_dev_fp); /* garbage */
181 fgets(buf, 255, net_dev_fp); /* garbage (field names) */
183 /* read each interface */
184 for (i2 = 0; i2 < 16; i2++) {
187 long long r, t, last_recv, last_trans;
189 if (fgets(buf, 255, net_dev_fp) == NULL) {
193 while (isspace((int) *p))
198 while (*p && *p != ':')
205 ns = get_net_stat(s);
207 memset(&(ns->addr.sa_data), 0, 14);
208 last_recv = ns->recv;
209 last_trans = ns->trans;
212 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
213 "%Ld %*d %*d %*d %*d %*d %*d %*d %Ld",
216 /* if recv or trans is less than last time, an overflow happened */
218 if (r < ns->last_read_recv)
221 ns->recv += (r - ns->last_read_recv);
222 ns->last_read_recv = r;
224 if (t < ns->last_read_trans)
227 ns->trans += (t - ns->last_read_trans);
228 ns->last_read_trans = t;
230 /*** ip addr patch ***/
231 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
233 conf.ifc_buf = malloc(sizeof(struct ifreq) * 16);
235 conf.ifc_len = sizeof(struct ifreq) * 16;
237 ioctl((long) i, SIOCGIFCONF, &conf);
239 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
241 ns = get_net_stat(((struct ifreq *) conf.
242 ifc_buf)[k].ifr_ifrn.ifrn_name);
244 ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.
253 /*** end ip addr patch ***/
256 /* calculate speeds */
257 ns->net_rec[0] = (ns->recv - last_recv) / delta;
258 ns->net_trans[0] = (ns->trans - last_trans) / delta;
262 for (i = 0; (unsigned) i < info.net_avg_samples; i++) {
263 curtmp1 += ns->net_rec[i];
264 curtmp2 += ns->net_trans[i];
266 if (curtmp1 == 0) curtmp1 = 1;
267 if (curtmp2 == 0) curtmp2 = 1;
268 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
269 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
270 if (info.net_avg_samples > 1) {
271 for (i = info.net_avg_samples; i > 1; i--) {
272 ns->net_rec[i - 1] = ns->net_rec[i - 2];
273 ns->net_trans[i - 1] =
274 ns->net_trans[i - 2];
279 /* update wireless info */
280 winfo = malloc(sizeof(struct wireless_info));
281 memset(winfo, 0, sizeof(struct wireless_info));
283 skfd = iw_sockets_open();
284 if(iw_get_basic_config(skfd, s, &(winfo->b)) > -1) {
286 // set present winfo variables
287 if(iw_get_stats(skfd, s, &(winfo->stats), &winfo->range, winfo->has_range) >= 0)
288 winfo->has_stats = 1;
289 if(iw_get_range_info(skfd, s, &(winfo->range)) >= 0)
290 winfo->has_range = 1;
291 if(iw_get_ext(skfd, s, SIOCGIWAP, &wrq) >= 0) {
292 winfo->has_ap_addr = 1;
293 memcpy(&(winfo->ap_addr), &(wrq.u.ap_addr), sizeof (sockaddr));
297 if(iw_get_ext(skfd, s, SIOCGIWRATE, &wrq) >= 0) {
298 memcpy(&(winfo->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
299 iw_print_bitrate(ns->bitrate, 16, winfo->bitrate.value);
304 if(winfo->has_range && winfo->has_stats && ((winfo->stats.qual.level != 0) || (winfo->stats.qual.updated & IW_QUAL_DBM))) {
305 if(!(winfo->stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
306 ns->link_qual = winfo->stats.qual.qual;
307 ns->link_qual_max = winfo->range.max_qual.qual;
312 if(winfo->has_ap_addr) {
313 iw_sawap_ntop(&winfo->ap_addr, ns->ap);
317 if(winfo->b.has_essid) {
318 if(winfo->b.essid_on)
319 snprintf(ns->essid, 32, "%s", winfo->b.essid);
321 snprintf(ns->essid, 32, "off/any");
324 snprintf(ns->mode, 16, "%s", iw_operation_mode[winfo->b.mode]);
326 iw_sockets_close(skfd);
333 info.mask |= (1 << INFO_NET);
336 inline void update_wifi_stats()
338 /** wireless stats patch by Bobby Beckmann **/
342 /*open file and ignore first two lines sorry, this code sucks ass right now, i'll clean it up later */
343 if (net_wireless_fp == NULL)
344 net_wireless_fp = open_file("/proc/net/wireless", &rep);
346 fseek(net_wireless_fp, 0, SEEK_SET);
347 if (net_wireless_fp == NULL)
350 fgets(buf, 255, net_wireless_fp); /* garbage */
351 fgets(buf, 255, net_wireless_fp); /* garbage (field names) */
353 /* read each interface */
354 for (i = 0; i < 16; i++) {
359 if (fgets(buf, 255, net_wireless_fp) == NULL)
362 while (isspace((int) *p))
367 while (*p && *p != ':')
374 ns = get_net_stat(s);
376 sscanf(p, "%*d %d. %d. %d", &l, &m, &n);
378 ns->linkstatus = (int) (log(MIN(MAX(l,1),92)) / log(92) * 100);
381 /*** end wireless patch ***/
386 void update_total_processes()
391 struct sysinfo s_info;
393 info.procs = s_info.procs;
401 if (!(fp = open_file("/proc/loadavg", &rep)))
406 fscanf(fp, "%*f %*f %*f %*d/%hd", &info.procs );
409 info.mask |= (1 << INFO_PROCS);
412 #define CPU_SAMPLE_COUNT 15
414 unsigned long long cpu_user;
415 unsigned long long cpu_system;
416 unsigned long long cpu_nice;
417 unsigned long long cpu_idle;
418 unsigned long long cpu_iowait;
419 unsigned long long cpu_irq;
420 unsigned long long cpu_softirq;
421 unsigned long long cpu_steal;
422 unsigned long long cpu_total;
423 unsigned long long cpu_active_total;
424 unsigned long long cpu_last_total;
425 unsigned long long cpu_last_active_total;
426 double cpu_val[CPU_SAMPLE_COUNT];
428 static short cpu_setup = 0;
431 determine if this kernel gives us "extended" statistics information in /proc/stat.
432 Kernels around 2.5 and earlier only reported user, system, nice and idle values in proc stat.
433 Kernels around 2.6 and greater report these PLUS iowait, irq, softirq, and steal
435 void determine_longstat(char * buf) {
436 unsigned long long iowait=0;
437 KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
438 /* scanf will either return -1 or 1 because there is only 1 assignment */
439 if (sscanf(buf, "%*s %*d %*d %*d %*d %llu",&iowait)>0) KFLAG_SETON(KFLAG_IS_LONGSTAT);
447 if (info.cpu_usage) {
452 if (!(stat_fp = open_file("/proc/stat", &rep)))
457 while (!feof(stat_fp)) {
458 if (fgets(buf, 255, stat_fp) == NULL)
461 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
462 if (info.cpu_count == 0) {
463 determine_longstat(buf);
468 info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
473 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
474 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
476 inline static void update_stat()
480 static struct cpu_info *cpu = NULL;
485 char * stat_template=NULL;
486 unsigned int malloc_cpu_size=0;
489 /* add check for !info.cpu_usage since that mem is freed on a SIGUSR1 */
490 if (!cpu_setup || !info.cpu_usage) {
495 if (!stat_template) {
496 stat_template = KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT ;
500 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
501 cpu = malloc(malloc_cpu_size);
502 memset(cpu, 0, malloc_cpu_size);
505 if (!(stat_fp = open_file("/proc/stat", &rep)))
510 memset(info.cpu_usage, 0, info.cpu_count * sizeof (float));
516 while (!feof(stat_fp)) {
517 if (fgets(buf, 255, stat_fp) == NULL)
520 if (strncmp(buf, "procs_running ", 14) == 0) {
521 sscanf(buf, "%*s %hu", &info.run_procs);
522 info.mask |= (1 << INFO_RUN_PROCS);
523 } else if (strncmp(buf, "cpu", 3) == 0) {
524 index = isdigit(buf[3]) ? ((int)buf[3]) - 0x2F : 0;
525 sscanf(buf, stat_template
526 , &(cpu[index].cpu_user)
527 , &(cpu[index].cpu_nice)
528 , &(cpu[index].cpu_system)
529 , &(cpu[index].cpu_idle)
530 , &(cpu[index].cpu_iowait)
531 , &(cpu[index].cpu_irq)
532 , &(cpu[index].cpu_softirq)
533 , &(cpu[index].cpu_steal)
536 cpu[index].cpu_total = cpu[index].cpu_user
537 + cpu[index].cpu_nice
538 + cpu[index].cpu_system
539 + cpu[index].cpu_idle
540 + cpu[index].cpu_iowait
542 + cpu[index].cpu_softirq
543 + cpu[index].cpu_steal
546 cpu[index].cpu_active_total = cpu[index].cpu_total - (cpu[index].cpu_idle + cpu[index].cpu_iowait);
547 info.mask |= (1 << INFO_CPU);
549 double delta = current_update_time - last_update_time;
550 if (delta <= 0.001) break;
552 cpu[index].cpu_val[0] = (cpu[index].cpu_active_total - cpu[index].cpu_last_active_total) /
553 (float )(cpu[index].cpu_total - cpu[index].cpu_last_total);
555 for (i=0; i < info.cpu_avg_samples; i++ ) {
556 curtmp += cpu[index].cpu_val[i];
558 /* TESTING -- I've removed this, because I don't think it is right. You shouldn't divide
559 by the cpu count here ... removing for testing */
561 info.cpu_usage[index] = curtmp / info.cpu_avg_samples / info.cpu_count;
563 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
565 /* TESTING -- this line replaces the prev. "suspect" if/else */
566 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
568 cpu[index].cpu_last_total = cpu[index].cpu_total;
569 cpu[index].cpu_last_active_total = cpu[index].cpu_active_total;
570 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
571 cpu[index].cpu_val[i] = cpu[index].cpu_val[i - 1];
579 void update_running_processes()
584 void update_cpu_usage()
589 void update_load_average()
591 #ifdef HAVE_GETLOADAVG
596 info.loadavg[0] = (float) v[0];
597 info.loadavg[1] = (float) v[1];
598 info.loadavg[2] = (float) v[2];
606 if (!(fp = open_file("/proc/loadavg", &rep)))
608 info.loadavg[0] = info.loadavg[1] = info.loadavg[2] = 0.0;
611 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1], &info.loadavg[2]);
614 info.mask |= (1 << INFO_LOADAVG);
617 #define PROC_I8K "/proc/i8k"
618 #define I8K_DELIM " "
619 static char *i8k_procbuf = NULL;
624 i8k_procbuf = (char*)malloc(128*sizeof(char));
626 if ((fp = fopen(PROC_I8K,"r")) == NULL) {
627 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel driver is loaded...");
630 memset(&i8k_procbuf[0],0,128);
631 if (fread(&i8k_procbuf[0],sizeof(char),128,fp) == 0) {
632 ERR("something wrong with /proc/i8k...");
637 i8k.version = strtok(&i8k_procbuf[0],I8K_DELIM);
638 i8k.bios = strtok(NULL,I8K_DELIM);
639 i8k.serial = strtok(NULL,I8K_DELIM);
640 i8k.cpu_temp = strtok(NULL,I8K_DELIM);
641 i8k.left_fan_status = strtok(NULL,I8K_DELIM);
642 i8k.right_fan_status = strtok(NULL,I8K_DELIM);
643 i8k.left_fan_rpm = strtok(NULL,I8K_DELIM);
644 i8k.right_fan_rpm = strtok(NULL,I8K_DELIM);
645 i8k.ac_status = strtok(NULL,I8K_DELIM);
646 i8k.buttons_status = strtok(NULL,I8K_DELIM);
650 /***********************************************************/
651 /***********************************************************/
652 /***********************************************************/
654 static int no_dots(const struct dirent *d)
656 if (d->d_name[0] == '.')
662 get_first_file_in_a_directory(const char *dir, char *s, int *rep)
664 struct dirent **namelist;
667 n = scandir(dir, &namelist, no_dots, alphasort);
670 ERR("scandir for %s: %s", dir, strerror(errno));
679 strncpy(s, namelist[0]->d_name, 255);
682 for (i = 0; i < n; i++)
690 int open_i2c_sensor(const char *dev, const char *type, int n, int *div, char *devtype)
693 if (post_21_kernel) {
694 strncpy(i2c_dir, "/sys/bus/platform/devices/", 64);
696 strncpy(i2c_dir, "/sys/bus/i2c/devices/", 64);
703 /* if i2c device is NULL or *, get first */
704 if (dev == NULL || strcmp(dev, "*") == 0) {
706 if (!get_first_file_in_a_directory(i2c_dir, buf, &rep))
711 /* change vol to in */
712 if (strcmp(type, "vol") == 0)
715 if (strcmp(type, "tempf") == 0) {
716 snprintf(path, 255, "%s%s/%s%d_input", i2c_dir, dev, "temp", n);
718 snprintf(path, 255, "%s%s/%s%d_input", i2c_dir, dev, type, n);
720 strncpy(devtype, path, 255);
723 fd = open(path, O_RDONLY);
725 CRIT_ERR("can't open '%s': %s\nplease fix i2c or remove it from Conky", path, strerror(errno));
728 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
729 || strcmp(type, "tempf") == 0)
733 /* fan does not use *_div as a read divisor */
734 if (strcmp("fan", type) == 0)
737 /* test if *_div file exist, open it and use it as divisor */
738 if (strcmp(type, "tempf") == 0) {
739 snprintf(path, 255, "%s%s/%s%d_div", i2c_dir, "one", "two",
742 snprintf(path, 255, "%s%s/%s%d_div", i2c_dir, dev, type, n);
745 divfd = open(path, O_RDONLY);
750 divn = read(divfd, divbuf, 63);
751 /* should read until n == 0 but I doubt that kernel will give these
752 * in multiple pieces. :) */
762 double get_i2c_info(int *fd, int div, char *devtype, char *type)
769 lseek(*fd, 0, SEEK_SET);
775 n = read(*fd, buf, 63);
776 /* should read until n == 0 but I doubt that kernel will give these
777 * in multiple pieces. :) */
784 *fd = open(devtype, O_RDONLY);
786 ERR("can't open '%s': %s", devtype, strerror(errno));
788 /* My dirty hack for computing CPU value
789 * Filedil, from forums.gentoo.org
791 /* if (strstr(devtype, "temp1_input") != NULL)
792 return -15.096+1.4893*(val / 1000.0); */
795 /* divide voltage and temperature by 1000 */
796 /* or if any other divisor is given, use that */
797 if (strcmp(type, "tempf") == 0) {
799 return ((val / div + 40) * 9.0 / 5) - 40;
801 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
803 return ((val + 40) * 9.0 / 5) - 40;
814 /* Prior to kernel version 2.6.12, the CPU fan speed was available
815 * in ADT746X_FAN_OLD, whereas later kernel versions provide this
816 * information in ADT746X_FAN.
818 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
819 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
821 void get_adt746x_fan( char * p_client_buffer, size_t client_buffer_size )
824 char adt746x_fan_state[64];
827 if ( !p_client_buffer || client_buffer_size <= 0 )
830 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
831 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL)
834 sprintf(adt746x_fan_state, "adt746x not found");
838 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
839 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
843 snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_fan_state );
847 /* Prior to kernel version 2.6.12, the CPU temperature was found
848 * in ADT746X_CPU_OLD, whereas later kernel versions provide this
849 * information in ADT746X_CPU.
851 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
852 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
854 void get_adt746x_cpu( char * p_client_buffer, size_t client_buffer_size )
857 char adt746x_cpu_state[64];
860 if ( !p_client_buffer || client_buffer_size <= 0 )
863 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
864 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL)
866 sprintf(adt746x_cpu_state, "adt746x not found");
870 fscanf(fp, "%2s", adt746x_cpu_state);
874 snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state );
878 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
880 /***********************************************************************/
882 * This file is part of x86info.
883 * (C) 2001 Dave Jones.
885 * Licensed under the terms of the GNU GPL License version 2.
887 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
888 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz>
891 #if defined(__i386) || defined(__x86_64)
892 __inline__ unsigned long long int rdtsc()
894 unsigned long long int x;
895 __asm__ volatile (".byte 0x0f, 0x31":"=A" (x));
900 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
901 void get_freq_dynamic( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor )
903 #if defined(__i386) || defined(__x86_64)
905 struct timeval tvstart, tvstop;
906 unsigned long long cycles[2]; /* gotta be 64 bit */
907 unsigned int microseconds; /* total time taken */
909 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
912 memset(&tz, 0, sizeof(tz));
914 /* get this function in cached memory */
915 gettimeofday(&tvstart, &tz);
917 gettimeofday(&tvstart, &tz);
919 /* we don't trust that this is any specific length of time */
922 gettimeofday(&tvstop, &tz);
923 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
924 (tvstop.tv_usec - tvstart.tv_usec);
926 snprintf( p_client_buffer, client_buffer_size, p_format, (float)((cycles[1] - cycles[0]) / microseconds) / divisor );
929 /* FIXME: hardwired: get freq for first cpu!
930 this whole function needs to be rethought and redone for
931 multi-cpu/multi-core/multi-threaded environments and
932 arbitrary combinations thereof
934 get_freq( p_client_buffer, client_buffer_size, p_format, divisor, 1 );
940 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
941 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
943 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
944 char get_freq( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
952 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
957 char current_freq_file[128];
958 snprintf(current_freq_file, 127, "%s/cpu%d/%s",CPUFREQ_PREFIX, cpu-1, CPUFREQ_POSTFIX);
959 f = fopen(current_freq_file, "r");
962 /* if there's a cpufreq /sys node, read the current frequency from this node;
963 * divide by 1000 to get Mhz. */
964 if (fgets(s, sizeof(s), f)) {
965 s[strlen(s)-1] = '\0';
966 freq = strtod(s, NULL);
969 snprintf( p_client_buffer, client_buffer_size, p_format, (freq/1000)/divisor );
974 f = open_file("/proc/cpuinfo", &rep); //open the CPU information file
976 perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
980 while (fgets(s, sizeof(s), f) != NULL){ //read the file
982 #if defined(__i386) || defined(__x86_64)
983 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) { //and search for the cpu mhz
986 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) { // different on alpha
988 if (strncmp(s, "clock", 5) == 0 && cpu == 0) { // this is different on ppc for some reason
989 #endif // defined(__alpha)
990 #endif // defined(__i386) || defined(__x86_64)
992 strcpy(frequency, strchr(s, ':') + 2); //copy just the number
994 frequency[strlen(frequency) - 6] = '\0';// strip " est.\n"
995 freq = strtod(frequency, NULL)/1000000; // kernel reports in Hz
997 frequency[strlen(frequency) - 1] = '\0'; // strip \n
998 freq = strtod(frequency, NULL);
1002 if (strncmp(s, "processor", 9) == 0) {
1010 snprintf( p_client_buffer, client_buffer_size, p_format, (float)freq/divisor );
1014 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
1016 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
1017 char get_voltage( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
1019 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks
1020 something like this:
1031 /* Peter Tarjan (ptarjan@citromail.hu) */
1036 char current_freq_file[128];
1040 /* build the voltage file name */
1042 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
1043 CPUFREQ_PREFIX, cpu, CPUFREQ_POSTFIX);
1045 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
1048 /* read the current cpu frequency from the /sys node */
1049 f = fopen(current_freq_file, "r");
1051 if (fgets(s, sizeof(s), f)) {
1052 s[strlen(s)-1] = '\0';
1053 freq = strtod(s, NULL);
1057 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1058 perror("get_voltage()");
1065 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
1066 CPUFREQ_PREFIX, cpu, CPUFREQ_VOLTAGE);
1068 /* use the current cpu frequency to find the corresponding voltage */
1069 f = fopen(current_freq_file, "r");
1074 if (fgets(line, 255, f) == NULL) break;
1075 sscanf(line, "%d %d", &freq_comp, &voltage);
1076 if(freq_comp == freq) break;
1080 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1081 perror("get_voltage()");
1087 snprintf( p_client_buffer, client_buffer_size, p_format, (float)voltage/divisor );
1092 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1094 void get_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1101 if ( !p_client_buffer || client_buffer_size <= 0 )
1104 /* yeah, slow... :/ */
1105 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep))
1107 snprintf( p_client_buffer, client_buffer_size, "no fans?" );
1111 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf );
1113 fp = open_file(buf2, &rep);
1115 snprintf( p_client_buffer, client_buffer_size, "can't open fan's state file" );
1118 memset(buf,0,sizeof(buf));
1119 fscanf(fp, "%*s %99s", buf);
1122 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1127 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1129 void get_acpi_ac_adapter( char * p_client_buffer, size_t client_buffer_size )
1136 if ( !p_client_buffer || client_buffer_size <= 0 )
1139 /* yeah, slow... :/ */
1140 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep))
1142 snprintf( p_client_buffer, client_buffer_size, "no ac_adapters?" );
1146 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf );
1149 fp = open_file(buf2, &rep);
1151 snprintf( p_client_buffer, client_buffer_size, "No ac adapter found.... where is it?" );
1154 memset(buf,0,sizeof(buf));
1155 fscanf(fp, "%*s %99s", buf );
1158 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1164 /proc/acpi/thermal_zone/THRM/cooling_mode
1165 cooling mode: active
1166 /proc/acpi/thermal_zone/THRM/polling_frequency
1168 /proc/acpi/thermal_zone/THRM/state
1170 /proc/acpi/thermal_zone/THRM/temperature
1172 /proc/acpi/thermal_zone/THRM/trip_points
1174 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1177 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1178 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1180 int open_acpi_temperature(const char *name)
1186 if (name == NULL || strcmp(name, "*") == 0) {
1188 if (!get_first_file_in_a_directory
1189 (ACPI_THERMAL_DIR, buf, &rep))
1194 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1196 fd = open(path, O_RDONLY);
1198 ERR("can't open '%s': %s", path, strerror(errno));
1203 static double last_acpi_temp;
1204 static double last_acpi_temp_time;
1206 double get_acpi_temperature(int fd)
1211 /* don't update acpi temperature too often */
1212 if (current_update_time - last_acpi_temp_time < 11.32) {
1213 return last_acpi_temp;
1215 last_acpi_temp_time = current_update_time;
1217 /* seek to beginning */
1218 lseek(fd, 0, SEEK_SET);
1224 n = read(fd, buf, 255);
1226 ERR("can't read fd %d: %s", fd, strerror(errno));
1229 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1233 return last_acpi_temp;
1237 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1239 design capacity: 4400 mAh
1240 last full capacity: 4064 mAh
1241 battery technology: rechargeable
1242 design voltage: 14800 mV
1243 design capacity warning: 300 mAh
1244 design capacity low: 200 mAh
1245 capacity granularity 1: 32 mAh
1246 capacity granularity 2: 32 mAh
1248 serial number: 16922
1254 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1257 charging state: unknown
1259 remaining capacity: 4064 mAh
1260 present voltage: 16608 mV
1264 2213<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1265 2213<@jupet kellari ö> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1266 2213<@jupet kellari ö> (-1 ollee ei akkua kiinni, koska akku on pöydällä)
1267 2214<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1268 2214<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1270 2238<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1271 2239<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1273 2240<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori päällä
1274 2241<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori päällä mutta ilman verkkovirtaa
1277 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1278 #define APM_PATH "/proc/apm"
1279 #define MAX_BATTERY_COUNT 4
1281 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT];
1282 static FILE *apm_bat_fp[MAX_BATTERY_COUNT];
1284 static int batteries_initialized = 0;
1285 static char batteries[MAX_BATTERY_COUNT][32];
1287 static int acpi_last_full[MAX_BATTERY_COUNT];
1288 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1290 static char last_battery_str[MAX_BATTERY_COUNT][64]; /* e.g. "charging 75%" */
1291 static char last_battery_time_str[MAX_BATTERY_COUNT][64]; /* e.g. "3h 15m" */
1293 static double last_battery_time[MAX_BATTERY_COUNT];
1295 static int last_battery_perct[MAX_BATTERY_COUNT];
1296 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1299 void init_batteries(void)
1302 if(batteries_initialized)
1304 for(idx = 0; idx < MAX_BATTERY_COUNT; idx++)
1305 batteries[idx][0] = '\0';
1306 batteries_initialized = 1;
1309 int get_battery_idx(const char *bat)
1312 for(idx = 0; idx < MAX_BATTERY_COUNT; idx++)
1313 if(!strlen(batteries[idx]) || !strcmp(batteries[idx], bat))
1316 /* if not found, enter a new entry */
1317 if(!strlen(batteries[idx]))
1318 snprintf(batteries[idx], 31, "%s", bat);
1323 void get_battery_stuff(char *buf, unsigned int n, const char *bat, int item)
1325 static int idx, rep = 0, rep2 = 0;
1326 char acpi_path[128];
1327 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1331 idx = get_battery_idx(bat);
1333 /* don't update battery too often */
1334 if (current_update_time - last_battery_time[idx] < 29.5)
1335 goto set_return_value;
1337 last_battery_time[idx] = current_update_time;
1339 memset (last_battery_str[idx], 0, sizeof (last_battery_str[idx]));
1340 memset (last_battery_time_str[idx], 0, sizeof (last_battery_time_str[idx]));
1342 /* first try ACPI */
1344 if (acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1345 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1347 if (acpi_bat_fp[idx] != NULL) {
1348 int present_rate = -1;
1349 int remaining_capacity = -1;
1350 char charging_state[64];
1353 /* read last full capacity if it's zero */
1354 if (acpi_last_full[idx] == 0) {
1359 ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1360 fp = open_file(path, &rep);
1364 if (fgets(b, 256, fp) == NULL)
1366 if (sscanf(b, "last full capacity: %d", &acpi_last_full[idx]) != 0) {
1375 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1377 strcpy(charging_state, "unknown");
1379 while (!feof(acpi_bat_fp[idx])) {
1381 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL)
1384 /* let's just hope units are ok */
1385 if (strncmp (buf, "present:", 8) == 0)
1386 sscanf(buf, "present: %4s", present);
1387 else if (strncmp (buf, "charging state:", 15) == 0)
1388 sscanf(buf, "charging state: %63s", charging_state);
1389 else if (strncmp (buf, "present rate:", 13) == 0)
1390 sscanf(buf, "present rate: %d", &present_rate);
1391 else if (strncmp(buf, "remaining capacity:", 19) == 0)
1392 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1395 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1396 if (remaining_capacity > acpi_last_full[idx])
1397 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1400 if (strcmp(present, "no") == 0) {
1401 strncpy(last_battery_str[idx], "not present", 64);
1404 else if (strcmp(charging_state, "charging") == 0) {
1405 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1406 /* e.g. charging 75% */
1407 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %i%%",
1408 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1410 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1411 (long) (((acpi_last_full[idx] - remaining_capacity) * 3600) /
1413 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1414 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %d%%",
1415 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1417 strncpy(last_battery_str[idx], "charging", sizeof(last_battery_str[idx])-1);
1421 else if (strncmp(charging_state, "discharging", 64) == 0) {
1422 if (present_rate > 0) {
1423 /* e.g. discharging 35% */
1424 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "discharging %i%%",
1425 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1427 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1428 (long) ((remaining_capacity * 3600) / present_rate));
1429 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1430 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "full");
1432 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1434 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1438 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1439 else if (strncmp(charging_state, "charged", 64) == 0) {
1440 /* Below happens with the second battery on my X40,
1441 * when the second one is empty and the first one
1443 if (remaining_capacity == 0)
1444 strcpy(last_battery_str[idx], "empty");
1446 strcpy(last_battery_str[idx], "charged");
1448 /* unknown, probably full / AC */
1450 if (acpi_last_full[idx] != 0
1451 && remaining_capacity != acpi_last_full[idx])
1452 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1453 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1455 strncpy(last_battery_str[idx], "AC", 64);
1459 if (apm_bat_fp[idx] == NULL)
1460 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1462 if (apm_bat_fp[idx] != NULL) {
1463 int ac, status, flag, life;
1465 fscanf(apm_bat_fp[idx],
1466 "%*s %*s %*x %x %x %x %d%%",
1467 &ac, &status, &flag, &life);
1470 /* could check now that there is ac */
1471 snprintf(last_battery_str[idx], 64, "AC");
1472 } else if (ac && life != 100) { /* could check that status==3 here? */
1473 snprintf(last_battery_str[idx], 64,
1474 "charging %d%%", life);
1476 snprintf(last_battery_str[idx], 64, "%d%%",
1480 /* it seemed to buffer it so file must be closed (or could use syscalls
1481 * directly but I don't feel like coding it now) */
1482 fclose(apm_bat_fp[idx]);
1483 apm_bat_fp[idx] = NULL;
1489 case BATTERY_STATUS:
1491 snprintf(buf, n, "%s", last_battery_str[idx]);
1496 snprintf(buf, n, "%s", last_battery_time_str[idx]);
1505 int get_battery_perct(const char *bat)
1509 char acpi_path[128];
1510 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1514 idx = get_battery_idx(bat);
1516 /* don't update battery too often */
1517 if (current_update_time - last_battery_perct_time[idx] < 30) {
1518 return last_battery_perct[idx];
1520 last_battery_perct_time[idx] = current_update_time;
1522 /* Only check for ACPI */
1524 if (acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1525 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1527 int remaining_capacity = -1;
1528 if (acpi_bat_fp[idx] != NULL) {
1529 /* read last full capacity if it's zero */
1530 if (acpi_design_capacity[idx] == 0) {
1535 ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1536 fp = open_file(path, &rep);
1540 if (fgets(b, 256, fp) == NULL)
1542 if (sscanf(b, "last full capacity: %d", &acpi_design_capacity[idx]) != 0) {
1550 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1552 while (!feof(acpi_bat_fp[idx])) {
1554 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL)
1558 sscanf(buf, "remaining capacity: %d",
1559 &remaining_capacity);
1562 if(remaining_capacity < 0)
1564 /* compute the battery percentage */
1565 last_battery_perct[idx] =
1566 (int) (((float)remaining_capacity/acpi_design_capacity[idx]) * 100);
1567 return last_battery_perct[idx];
1570 int get_battery_perct_bar(const char *bar)
1573 get_battery_perct(bar);
1574 idx = get_battery_idx(bar);
1575 return (int) (last_battery_perct[idx] * 2.56 - 1);
1580 /* On Apple powerbook and ibook:
1581 $ cat /proc/pmu/battery_0
1588 $ cat /proc/pmu/info
1589 PMU driver version : 2
1590 PMU firmware version : 0c
1595 /* defines as in <linux/pmu.h> */
1596 #define PMU_BATT_PRESENT 0x00000001
1597 #define PMU_BATT_CHARGING 0x00000002
1599 static FILE* pmu_battery_fp;
1600 static FILE* pmu_info_fp;
1601 static char pb_battery_info[3][32];
1602 static double pb_battery_info_update;
1604 #define PMU_PATH "/proc/pmu"
1605 void get_powerbook_batt_info(char *buf, size_t n, int i)
1608 const char* batt_path = PMU_PATH "/battery_0";
1609 const char* info_path = PMU_PATH "/info";
1610 int flags, charge, max_charge, ac = -1;
1613 /* don't update battery too often */
1614 if (current_update_time - pb_battery_info_update < 29.5) {
1615 snprintf(buf, n, "%s", pb_battery_info[i]);
1618 pb_battery_info_update = current_update_time;
1620 if (pmu_battery_fp == NULL)
1621 pmu_battery_fp = open_file(batt_path, &rep);
1623 if (pmu_battery_fp != NULL) {
1624 rewind(pmu_battery_fp);
1625 while (!feof(pmu_battery_fp)) {
1627 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL)
1631 sscanf(buf, "flags : %8x", &flags);
1632 else if (buf[0] == 'c' && buf[1] == 'h')
1633 sscanf(buf, "charge : %d", &charge);
1634 else if (buf[0] == 'm')
1635 sscanf(buf, "max_charge : %d", &max_charge);
1636 else if (buf[0] == 't')
1637 sscanf(buf, "time rem. : %ld", &time);
1640 if (pmu_info_fp == NULL)
1641 pmu_info_fp = open_file(info_path, &rep);
1643 if (pmu_info_fp != NULL) {
1644 rewind(pmu_info_fp);
1645 while (!feof(pmu_info_fp)) {
1647 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL)
1650 sscanf(buf, "AC Power : %d", &ac);
1653 /* update status string */
1654 if ((ac && !(flags & PMU_BATT_PRESENT)))
1655 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
1656 else if (ac && (flags & PMU_BATT_PRESENT)
1657 && !(flags & PMU_BATT_CHARGING))
1658 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
1659 else if ((flags & PMU_BATT_PRESENT)
1660 && (flags & PMU_BATT_CHARGING))
1661 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
1663 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
1665 /* update percentage string */
1667 pb_battery_info[PB_BATT_PERCENT][0] = 0;
1669 snprintf(pb_battery_info[PB_BATT_PERCENT],
1670 sizeof(pb_battery_info[PB_BATT_PERCENT]),
1671 "%d%%", (charge * 100)/max_charge);
1673 /* update time string */
1674 if (time == 0) /* fully charged or battery not present */
1675 pb_battery_info[PB_BATT_TIME][0] = 0;
1676 else if (time < 60*60) /* don't show secs */
1677 format_seconds_short(pb_battery_info[PB_BATT_TIME],
1678 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1680 format_seconds(pb_battery_info[PB_BATT_TIME],
1681 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1683 snprintf(buf, n, "%s", pb_battery_info[i]);
1688 show_nice_processes = 1;
1689 process_find_top(info.cpu, info.memu);
1690 info.first_process = get_first_process();
1695 * The following ifdefs were adapted from gkrellm
1697 #include <linux/major.h>
1699 #if ! defined (MD_MAJOR)
1703 #if !defined(LVM_BLK_MAJOR)
1704 #define LVM_BLK_MAJOR 58
1707 #if !defined(NBD_MAJOR)
1708 #define NBD_MAJOR 43
1711 void update_diskio()
1713 static unsigned int last = UINT_MAX;
1714 static unsigned int last_read = UINT_MAX;
1715 static unsigned int last_write = UINT_MAX;
1721 unsigned int current = 0;
1722 unsigned int current_read = 0;
1723 unsigned int current_write = 0;
1724 unsigned int reads, writes = 0;
1727 if (!(fp =open_file("/proc/diskstats", &rep))) {
1732 /* read reads and writes from all disks (minor = 0), including
1733 * cd-roms and floppies, and summ them up
1736 fgets(buf, 512, fp);
1737 col_count = sscanf(buf, "%u %u %*s %*u %*u %u %*u %*u %*u %u",
1738 &major, &minor, &reads, &writes);
1739 /* ignore subdevices (they have only 3 matching entries in their line)
1740 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
1742 * XXX ignore devices which are part of a SW RAID (MD_MAJOR)
1744 if (col_count > 3 &&
1745 major != LVM_BLK_MAJOR && major != NBD_MAJOR &&
1746 major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
1747 current += reads + writes;
1748 current_read += reads;
1749 current_write += writes;
1753 /* since the values in /proc/diststats are absolute, we have
1754 * to substract our last reading. The numbers stand for
1755 * "sectors read", and we therefore have to divide by two to
1757 int tot = ((double)(current-last)/2);
1758 int tot_read = ((double)(current_read-last_read)/2);
1759 int tot_write = ((double)(current_write-last_write)/2);
1761 if (last_read > current_read)
1763 if (last_write > current_write)
1766 if (last > current) {
1767 /* we hit this either if it's the very first time we
1768 * run this, or when /proc/diskstats overflows; while
1769 * 0 is not correct, it's at least not way off */
1773 last_read = current_read;
1774 last_write = current_write;
1777 diskio_read_value = tot_read;
1778 diskio_write_value = tot_write;
1783 /* Here come the IBM ACPI-specific things. For reference, see
1784 http://ibm-acpi.sourceforge.net/README
1785 If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
1801 The content of these files is described in detail in the aforementioned
1802 README - some of them also in the following functions accessing them.
1803 Peter Tarjan (ptarjan@citromail.hu)
1806 #define IBM_ACPI_DIR "/proc/acpi/ibm"
1808 void get_ibm_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1810 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
1811 /proc/acpi/ibm/fan looks like this (3 lines):
1814 commands: enable, disable
1815 Peter Tarjan (ptarjan@citromail.hu)
1818 if ( !p_client_buffer || client_buffer_size <= 0 )
1822 unsigned int speed=0;
1824 snprintf(fan, 127, "%s/fan",IBM_ACPI_DIR);
1826 fp = fopen(fan, "r");
1832 if (fgets(line, 255, fp) == NULL) break;
1833 if (sscanf(line, "speed: %d", &speed)) break;
1838 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", fan, strerror(errno));
1842 snprintf( p_client_buffer, client_buffer_size, "%d", speed );
1847 static double last_ibm_acpi_temp_time;
1848 void get_ibm_acpi_temps()
1850 /* get the measured temperatures from the temperature sensors
1851 on IBM/Lenovo laptops running the ibm acpi.
1852 There are 8 values in /proc/acpi/ibm/thermal, and according to
1853 http://ibm-acpi.sourceforge.net/README
1854 these mean the following (at least on an IBM R51...)
1855 0: CPU (also on the T series laptops)
1856 1: Mini PCI Module (?)
1858 3: GPU (also on the T series laptops)
1863 I'm not too sure about those with the question mark, but the values I'm
1864 reading from *my* thermal file (on a T42p) look realistic for the
1865 hdd and the battery.
1866 #5 and #7 are always -128.
1867 /proc/acpi/ibm/thermal looks like this (1 line):
1868 temperatures: 41 43 31 46 33 -128 29 -128
1869 Peter Tarjan (ptarjan@citromail.hu)
1872 /* don't update too often */
1873 if (current_update_time - last_ibm_acpi_temp_time < 10.00)
1877 last_ibm_acpi_temp_time = current_update_time;
1879 /* if ( !p_client_buffer || client_buffer_size <= 0 )
1885 snprintf(thermal, 127, "%s/thermal",IBM_ACPI_DIR);
1886 fp = fopen(thermal, "r");
1893 if (fgets(line, 255, fp) == NULL) break;
1894 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
1895 &ibm_acpi.temps[0], &ibm_acpi.temps[1],
1896 &ibm_acpi.temps[2], &ibm_acpi.temps[3],
1897 &ibm_acpi.temps[4], &ibm_acpi.temps[5],
1898 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) break;
1903 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", thermal, strerror(errno));
1911 void get_ibm_acpi_volume( char * p_client_buffer, size_t client_buffer_size )
1914 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
1915 "Volume" here is none of the mixer volumes, but a "master of masters"
1916 volume adjusted by the IBM volume keys.
1917 /proc/acpi/ibm/fan looks like this (4 lines):
1920 commands: up, down, mute
1921 commands: level <level> (<level> is 0-15)
1922 Peter Tarjan (ptarjan@citromail.hu)
1925 if ( !p_client_buffer || client_buffer_size <= 0 )
1931 snprintf(volume, 127, "%s/volume",IBM_ACPI_DIR);
1932 unsigned int vol=-1;
1935 fp = fopen(volume, "r");
1941 if (fgets(line, 255, fp) == NULL) break;
1942 if (sscanf(line, "level: %d", &vol)) continue;
1943 if (sscanf(line, "mute: %s", mute)) break;
1948 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", volume, strerror(errno));
1953 if (strcmp(mute, "on")==0)
1955 snprintf( p_client_buffer, client_buffer_size, "%s", "mute" );
1960 snprintf( p_client_buffer, client_buffer_size, "%d", vol );
1966 /*static FILE *fp=NULL;*/
1968 void get_ibm_acpi_brightness(char * p_client_buffer, size_t client_buffer_size)
1970 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
1971 /proc/acpi/ibm/brightness looks like this (3 lines):
1974 commands: level <level> (<level> is 0-7)
1975 Peter Tarjan (ptarjan@citromail.hu)
1978 if ( !p_client_buffer || client_buffer_size <= 0 )
1982 unsigned int brightness=0;
1984 snprintf(filename, 127, "%s/brightness",IBM_ACPI_DIR);
1986 fp = fopen(filename, "r");
1992 if (fgets(line, 255, fp) == NULL) break;
1993 if (sscanf(line, "level: %d", &brightness)) break;
1998 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", filename, strerror(errno));
2003 snprintf( p_client_buffer, client_buffer_size, "%d", brightness );
2008 void update_entropy (void)
2011 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
2012 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
2015 info.entropy.entropy_avail=0;
2016 info.entropy.poolsize=0;
2018 if ((fp1 = open_file (entropy_avail, &rep))==NULL)
2021 if ((fp2 = open_file (entropy_poolsize, &rep))==NULL)
2027 fscanf (fp1, "%u", &info.entropy.entropy_avail);
2028 fscanf (fp2, "%u", &info.entropy.poolsize);
2033 info.mask |= (1 << INFO_ENTROPY);