2 * Contains linux specific code
16 #include <sys/types.h>
17 #include <sys/sysinfo.h>
21 // #include <assert.h>
25 #include <sys/ioctl.h>
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <linux/sockios.h>
32 #define SHORTSTAT_TEMPL "%*s %llu %llu %llu"
33 #define LONGSTAT_TEMPL "%*s %llu %llu %llu "
36 static struct sysinfo s_info;
38 static int show_nice_processes;
44 static void update_sysinfo()
48 info.uptime = (double) s_info.uptime;
50 /* there was some problem with these */
52 // info.loadavg[0] = s_info.loads[0] / 100000.0f;
53 info.loadavg[1] = s_info.loads[1] / 100000.0f;
54 info.loadavg[2] = s_info.loads[2] / 100000.0f;
55 gkrelltop_process_find_top_three info.mask |= 1 << INFO_LOADAVG;
58 info.procs = s_info.procs;
60 /* these aren't nice, no cache and should check kernel version for mem_unit */
62 info.memmax = s_info.totalram;
63 info.mem = s_info.totalram - s_info.freeram;
64 info.swapmax = s_info.totalswap;
65 info.swap = s_info.totalswap - s_info.swap;
66 info.mask |= 1 << INFO_MEM;
69 info.mask |= (1 << INFO_UPTIME) | (1 << INFO_PROCS);
74 /* prefers sysinfo() for uptime, I don't really know which one is better
76 #ifdef USE_PROC_UPTIME
78 FILE *fp = open_file("/proc/uptime", &rep);
81 fscanf(fp, "%lf", &info.uptime);
84 info.mask |= (1 << INFO_UPTIME);
90 /* these things are also in sysinfo except Buffers:, that's why I'm reading
93 static FILE *meminfo_fp;
101 info.mem = info.memmax = info.swap = info.swapmax = info.bufmem =
102 info.buffers = info.cached = 0;
104 if (meminfo_fp == NULL)
105 meminfo_fp = open_file("/proc/meminfo", &rep);
107 fseek(meminfo_fp, 0, SEEK_SET);
108 if (meminfo_fp == NULL)
111 while (!feof(meminfo_fp)) {
112 if (fgets(buf, 255, meminfo_fp) == NULL)
115 if (strncmp(buf, "MemTotal:", 9) == 0) {
116 sscanf(buf, "%*s %lu", &info.memmax);
117 } else if (strncmp(buf, "MemFree:", 8) == 0) {
118 sscanf(buf, "%*s %lu", &info.mem);
119 } else if (strncmp(buf, "SwapTotal:", 10) == 0) {
120 sscanf(buf, "%*s %lu", &info.swapmax);
121 } else if (strncmp(buf, "SwapFree:", 9) == 0) {
122 sscanf(buf, "%*s %lu", &info.swap);
123 } else if (strncmp(buf, "Buffers:", 8) == 0) {
124 sscanf(buf, "%*s %lu", &info.buffers);
125 } else if (strncmp(buf, "Cached:", 7) == 0) {
126 sscanf(buf, "%*s %lu", &info.cached);
130 info.mem = info.memmax - info.mem;
131 info.swap = info.swapmax - info.swap;
133 info.bufmem = info.cached + info.buffers;
135 info.mask |= (1 << INFO_MEM) | (1 << INFO_BUFFERS);
138 static FILE *net_dev_fp;
139 static FILE *net_wireless_fp;
141 inline void update_net_stats()
144 // FIXME: arbitrary size chosen to keep code simple.
146 unsigned int curtmp1, curtmp2;
155 delta = current_update_time - last_update_time;
159 /* open file and ignore first two lines */
160 if (net_dev_fp == NULL) {
161 net_dev_fp = open_file("/proc/net/dev", &rep);
164 fseek(net_dev_fp, 0, SEEK_SET);
168 fgets(buf, 255, net_dev_fp); /* garbage */
169 fgets(buf, 255, net_dev_fp); /* garbage (field names) */
171 /* read each interface */
172 for (i2 = 0; i2 < 16; i2++) {
175 long long r, t, last_recv, last_trans;
177 if (fgets(buf, 255, net_dev_fp) == NULL) {
181 while (isspace((int) *p))
186 while (*p && *p != ':')
193 ns = get_net_stat(s);
195 memset(&(ns->addr.sa_data), 0, 14);
196 last_recv = ns->recv;
197 last_trans = ns->trans;
200 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
201 "%Ld %*d %*d %*d %*d %*d %*d %*d %Ld",
204 /* if recv or trans is less than last time, an overflow happened */
206 if (r < ns->last_read_recv)
208 ((long long) 4294967295U -
209 ns->last_read_recv) + r;
211 ns->recv += (r - ns->last_read_recv);
212 ns->last_read_recv = r;
214 if (t < ns->last_read_trans)
216 ((long long) 4294967295U -
217 ns->last_read_trans) + t;
219 ns->trans += (t - ns->last_read_trans);
220 ns->last_read_trans = t;
222 /*** ip addr patch ***/
223 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
225 conf.ifc_buf = malloc(sizeof(struct ifreq) * 16);
227 conf.ifc_len = sizeof(struct ifreq) * 16;
229 ioctl((long) i, SIOCGIFCONF, &conf);
231 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
233 ns = get_net_stat(((struct ifreq *) conf.
234 ifc_buf)[k].ifr_ifrn.ifrn_name);
236 ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.
245 /*** end ip addr patch ***/
248 /* calculate speeds */
249 ns->net_rec[0] = (ns->recv - last_recv) / delta;
250 ns->net_trans[0] = (ns->trans - last_trans) / delta;
254 for (i = 0; (unsigned) i < info.net_avg_samples; i++) {
255 curtmp1 += ns->net_rec[i];
256 curtmp2 += ns->net_trans[i];
258 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
259 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
260 if (info.net_avg_samples > 1) {
261 for (i = info.net_avg_samples; i > 1; i--) {
262 ns->net_rec[i - 1] = ns->net_rec[i - 2];
263 ns->net_trans[i - 1] =
264 ns->net_trans[i - 2];
272 /* fclose(net_dev_fp); net_dev_fp = NULL; */
275 inline void update_wifi_stats()
277 /** wireless stats patch by Bobby Beckmann **/
281 /*open file and ignore first two lines sorry, this code sucks ass right now, i'll clean it up later */
282 if (net_wireless_fp == NULL)
283 net_wireless_fp = open_file("/proc/net/wireless", &rep);
285 fseek(net_wireless_fp, 0, SEEK_SET);
286 if (net_wireless_fp == NULL)
289 fgets(buf, 255, net_wireless_fp); /* garbage */
290 fgets(buf, 255, net_wireless_fp); /* garbage (field names) */
292 /* read each interface */
293 for (i = 0; i < 16; i++) {
298 if (fgets(buf, 255, net_wireless_fp) == NULL)
301 while (isspace((int) *p))
306 while (*p && *p != ':')
313 ns = get_net_stat(s);
315 sscanf(p, "%*d %d. %d. %d", &l, &m, &n);
317 ns->linkstatus = (int) (log(MIN(MAX(l,1),92)) / log(92) * 100);
321 /*** end wireless patch ***/
326 void update_total_processes()
331 #define CPU_SAMPLE_COUNT 15
333 unsigned long long cpu_user;
334 unsigned long long cpu_system;
335 unsigned long long cpu_nice;
336 unsigned long long cpu_idle;
337 unsigned long long cpu_iowait;
338 unsigned long long cpu_irq;
339 unsigned long long cpu_softirq;
340 unsigned long long cpu_steal;
341 unsigned long long cpu_total;
342 unsigned long long cpu_active_total;
343 unsigned long long cpu_last_total;
344 unsigned long long cpu_last_active_total;
345 double cpu_val[CPU_SAMPLE_COUNT];
347 static short cpu_setup = 0;
351 static FILE *stat_fp;
354 determine if this kernel gives us "extended" statistics information in /proc/stat.
355 Kernels around 2.5 and earlier only reported user, system, nice and idle values in proc stat.
356 Kernels around 2.6 and greater report these PLUS iowait, irq, softirq, and steal
358 void determine_longstat(char * buf) {
359 unsigned long long iowait=0;
360 KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
361 /* scanf will either return -1 or 1 because there is only 1 assignment */
362 if (sscanf(buf, "%*s %*d %*d %*d %*d %llu",&iowait)>0) KFLAG_SETON(KFLAG_IS_LONGSTAT);
367 if (info.cpu_usage) {
372 stat_fp = open_file("/proc/stat", &rep);
374 fseek(stat_fp, 0, SEEK_SET);
380 while (!feof(stat_fp)) {
381 if (fgets(buf, 255, stat_fp) == NULL)
384 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
385 if (info.cpu_count == 0) {
386 determine_longstat(buf);
391 info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
394 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
395 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
397 inline static void update_stat()
399 static struct cpu_info *cpu = NULL;
404 char * stat_template=NULL;
405 unsigned int malloc_cpu_size=0;
413 if (stat_template == NULL) {
414 stat_template = KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT ;
418 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
419 cpu = malloc(malloc_cpu_size);
420 memset(cpu, 0, malloc_cpu_size);
423 if (stat_fp == NULL) {
424 stat_fp = open_file("/proc/stat", &rep);
426 fseek(stat_fp, 0, SEEK_SET);
428 if (stat_fp == NULL) {
432 while (!feof(stat_fp)) {
433 if (fgets(buf, 255, stat_fp) == NULL)
436 if (strncmp(buf, "procs_running ", 14) == 0) {
437 sscanf(buf, "%*s %hu", &info.run_procs);
438 info.mask |= (1 << INFO_RUN_PROCS);
439 } else if (strncmp(buf, "cpu", 3) == 0) {
440 index = isdigit(buf[3]) ? ((int)buf[3]) - 0x2F : 0;
441 sscanf(buf, stat_template
442 , &(cpu[index].cpu_user)
443 , &(cpu[index].cpu_nice)
444 , &(cpu[index].cpu_system)
445 , &(cpu[index].cpu_idle)
446 , &(cpu[index].cpu_iowait)
447 , &(cpu[index].cpu_irq)
448 , &(cpu[index].cpu_softirq)
449 , &(cpu[index].cpu_steal)
452 cpu[index].cpu_total = cpu[index].cpu_user
453 + cpu[index].cpu_nice
454 + cpu[index].cpu_system
455 + cpu[index].cpu_idle
456 + cpu[index].cpu_iowait
458 + cpu[index].cpu_softirq
459 + cpu[index].cpu_steal
462 cpu[index].cpu_active_total = cpu[index].cpu_total - (cpu[index].cpu_idle + cpu[index].cpu_iowait);
463 info.mask |= (1 << INFO_CPU);
465 double delta = current_update_time - last_update_time;
466 if (delta <= 0.001) return;
468 cpu[index].cpu_val[0] = (cpu[index].cpu_active_total - cpu[index].cpu_last_active_total) /
469 (float )(cpu[index].cpu_total - cpu[index].cpu_last_total);
471 for (i=0; i < info.cpu_avg_samples; i++ ) {
472 curtmp += cpu[index].cpu_val[i];
474 /* TESTING -- I've removed this, because I don't think it is right. You shouldn't divide
475 by the cpu count here ... removing for testing */
477 info.cpu_usage[index] = curtmp / info.cpu_avg_samples / info.cpu_count;
479 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
481 /* TESTING -- this line replaces the prev. "suspect" if/else */
482 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
484 cpu[index].cpu_last_total = cpu[index].cpu_total;
485 cpu[index].cpu_last_active_total = cpu[index].cpu_active_total;
486 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
487 cpu[index].cpu_val[i] = cpu[index].cpu_val[i - 1];
494 void update_running_processes()
499 void update_cpu_usage()
504 void update_load_average()
506 #ifdef HAVE_GETLOADAVG
509 info.loadavg[0] = (float) v[0];
510 info.loadavg[1] = (float) v[1];
511 info.loadavg[2] = (float) v[2];
516 fp = open_file("/proc/loadavg", &rep);
518 v[0] = v[1] = v[2] = 0.0;
522 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1],
529 #define PROC_I8K "/proc/i8k"
530 #define I8K_DELIM " "
531 static char *i8k_procbuf = NULL;
536 i8k_procbuf = (char*)malloc(128*sizeof(char));
538 if ((fp = fopen(PROC_I8K,"r")) == NULL) {
539 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel driver is loaded...");
542 memset(&i8k_procbuf[0],0,128);
543 if (fread(&i8k_procbuf[0],sizeof(char),128,fp) == 0) {
544 ERR("something wrong with /proc/i8k...");
549 i8k.version = strtok(&i8k_procbuf[0],I8K_DELIM);
550 i8k.bios = strtok(NULL,I8K_DELIM);
551 i8k.serial = strtok(NULL,I8K_DELIM);
552 i8k.cpu_temp = strtok(NULL,I8K_DELIM);
553 i8k.left_fan_status = strtok(NULL,I8K_DELIM);
554 i8k.right_fan_status = strtok(NULL,I8K_DELIM);
555 i8k.left_fan_rpm = strtok(NULL,I8K_DELIM);
556 i8k.right_fan_rpm = strtok(NULL,I8K_DELIM);
557 i8k.ac_status = strtok(NULL,I8K_DELIM);
558 i8k.buttons_status = strtok(NULL,I8K_DELIM);
562 /***********************************************************/
563 /***********************************************************/
564 /***********************************************************/
566 static int no_dots(const struct dirent *d)
568 if (d->d_name[0] == '.')
574 get_first_file_in_a_directory(const char *dir, char *s, int *rep)
576 struct dirent **namelist;
579 n = scandir(dir, &namelist, no_dots, alphasort);
582 ERR("scandir for %s: %s", dir, strerror(errno));
591 strncpy(s, namelist[0]->d_name, 255);
594 for (i = 0; i < n; i++)
602 #define I2C_DIR "/sys/bus/i2c/devices/"
605 open_i2c_sensor(const char *dev, const char *type, int n, int *div,
613 /* if i2c device is NULL or *, get first */
614 if (dev == NULL || strcmp(dev, "*") == 0) {
616 if (!get_first_file_in_a_directory(I2C_DIR, buf, &rep))
621 /* change vol to in */
622 if (strcmp(type, "vol") == 0)
625 if (strcmp(type, "tempf") == 0) {
626 snprintf(path, 255, I2C_DIR "%s/%s%d_input", dev, "temp", n);
628 snprintf(path, 255, I2C_DIR "%s/%s%d_input", dev, type, n);
630 strncpy(devtype, path, 255);
633 fd = open(path, O_RDONLY);
635 CRIT_ERR("can't open '%s': %s\nplease fix i2c or remove it from Conky", path, strerror(errno));
638 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
639 || strcmp(type, "tempf") == 0)
643 /* fan does not use *_div as a read divisor */
644 if (strcmp("fan", type) == 0)
647 /* test if *_div file exist, open it and use it as divisor */
648 if (strcmp(type, "tempf") == 0) {
649 snprintf(path, 255, I2C_DIR "%s/%s%d_div", "one", "two",
652 snprintf(path, 255, I2C_DIR "%s/%s%d_div", dev, type, n);
655 divfd = open(path, O_RDONLY);
660 divn = read(divfd, divbuf, 63);
661 /* should read until n == 0 but I doubt that kernel will give these
662 * in multiple pieces. :) */
672 double get_i2c_info(int *fd, int div, char *devtype, char *type)
679 lseek(*fd, 0, SEEK_SET);
685 n = read(*fd, buf, 63);
686 /* should read until n == 0 but I doubt that kernel will give these
687 * in multiple pieces. :) */
694 *fd = open(devtype, O_RDONLY);
696 ERR("can't open '%s': %s", devtype, strerror(errno));
698 /* My dirty hack for computing CPU value
699 * Filedil, from forums.gentoo.org
701 /* if (strstr(devtype, "temp1_input") != NULL)
702 return -15.096+1.4893*(val / 1000.0); */
705 /* divide voltage and temperature by 1000 */
706 /* or if any other divisor is given, use that */
707 if (strcmp(type, "tempf") == 0) {
709 return ((val / div + 40) * 9.0 / 5) - 40;
711 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
713 return ((val + 40) * 9.0 / 5) - 40;
724 /* Prior to kernel version 2.6.12, the CPU fan speed was available
725 * in ADT746X_FAN_OLD, whereas later kernel versions provide this
726 * information in ADT746X_FAN.
728 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
729 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
731 void get_adt746x_fan( char * p_client_buffer, size_t client_buffer_size )
734 char adt746x_fan_state[64];
737 if ( !p_client_buffer || client_buffer_size <= 0 )
740 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
741 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL)
744 sprintf(adt746x_fan_state, "adt746x not found");
748 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
749 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
753 snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_fan_state );
757 /* Prior to kernel version 2.6.12, the CPU temperature was found
758 * in ADT746X_CPU_OLD, whereas later kernel versions provide this
759 * information in ADT746X_CPU.
761 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
762 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
764 void get_adt746x_cpu( char * p_client_buffer, size_t client_buffer_size )
767 char adt746x_cpu_state[64];
770 if ( !p_client_buffer || client_buffer_size <= 0 )
773 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
774 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL)
776 sprintf(adt746x_cpu_state, "adt746x not found");
780 fscanf(fp, "%2s", adt746x_cpu_state);
784 snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state );
788 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
790 /***********************************************************************/
792 * This file is part of x86info.
793 * (C) 2001 Dave Jones.
795 * Licensed under the terms of the GNU GPL License version 2.
797 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
798 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz>
801 #if defined(__i386) || defined(__x86_64)
802 __inline__ unsigned long long int rdtsc()
804 unsigned long long int x;
805 __asm__ volatile (".byte 0x0f, 0x31":"=A" (x));
810 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
811 void get_freq_dynamic( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor )
813 #if defined(__i386) || defined(__x86_64)
815 struct timeval tvstart, tvstop;
816 unsigned long long cycles[2]; /* gotta be 64 bit */
817 unsigned int microseconds; /* total time taken */
819 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
822 memset(&tz, 0, sizeof(tz));
824 /* get this function in cached memory */
825 gettimeofday(&tvstart, &tz);
827 gettimeofday(&tvstart, &tz);
829 /* we don't trust that this is any specific length of time */
832 gettimeofday(&tvstop, &tz);
833 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
834 (tvstop.tv_usec - tvstart.tv_usec);
836 snprintf( p_client_buffer, client_buffer_size, p_format, (float)((cycles[1] - cycles[0]) / microseconds) / divisor );
839 /* FIXME: hardwired: get freq for first cpu!
840 this whole function needs to be rethought and redone for
841 multi-cpu/multi-core/multi-threaded environments and
842 arbitrary combinations thereof
844 get_freq( p_client_buffer, client_buffer_size, p_format, divisor, 1 );
850 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
851 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
853 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
854 char get_freq( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
860 char current_freq_file[128];
863 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
864 CPUFREQ_PREFIX, cpu, CPUFREQ_POSTFIX);
866 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
869 f = fopen(current_freq_file, "r");
871 /* if there's a cpufreq /sys node, read the current frequency from this node;
872 * divide by 1000 to get Mhz. */
873 if (fgets(s, sizeof(s), f)) {
874 s[strlen(s)-1] = '\0';
875 freq = strtod(s, NULL);
878 snprintf( p_client_buffer, client_buffer_size, p_format, (freq/1000)/divisor );
883 f = fopen("/proc/cpuinfo", "r"); //open the CPU information file
885 perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
889 while (fgets(s, sizeof(s), f) != NULL){ //read the file
891 #if defined(__i386) || defined(__x86_64)
892 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) { //and search for the cpu mhz
895 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) { // different on alpha
897 if (strncmp(s, "clock", 5) == 0 && cpu == 0) { // this is different on ppc for some reason
898 #endif // defined(__alpha)
899 #endif // defined(__i386) || defined(__x86_64)
901 strcpy(frequency, strchr(s, ':') + 2); //copy just the number
903 frequency[strlen(frequency) - 6] = '\0';// strip " est.\n"
904 freq = strtod(frequency, NULL)/1000000; // kernel reports in Hz
906 frequency[strlen(frequency) - 1] = '\0'; // strip \n
907 freq = strtod(frequency, NULL);
911 if (strncmp(s, "processor", 9) == 0) {
919 snprintf( p_client_buffer, client_buffer_size, p_format, (float)freq/divisor );
923 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
925 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
926 char get_voltage( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
928 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks
940 /* Peter Tarjan (ptarjan@citromail.hu) */
945 char current_freq_file[128];
949 /* build the voltage file name */
951 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
952 CPUFREQ_PREFIX, cpu, CPUFREQ_POSTFIX);
954 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
957 /* read the current cpu frequency from the /sys node */
958 f = fopen(current_freq_file, "r");
960 if (fgets(s, sizeof(s), f)) {
961 s[strlen(s)-1] = '\0';
962 freq = strtod(s, NULL);
966 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
967 perror("get_voltage()");
974 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
975 CPUFREQ_PREFIX, cpu, CPUFREQ_VOLTAGE);
977 /* use the current cpu frequency to find the corresponding voltage */
978 f = fopen(current_freq_file, "r");
983 if (fgets(line, 255, f) == NULL) break;
984 sscanf(line, "%d %d", &freq_comp, &voltage);
985 if(freq_comp == freq) break;
989 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
990 perror("get_voltage()");
996 snprintf( p_client_buffer, client_buffer_size, p_format, (float)voltage/divisor );
1001 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1003 void get_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1010 if ( !p_client_buffer || client_buffer_size <= 0 )
1013 /* yeah, slow... :/ */
1014 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep))
1016 snprintf( p_client_buffer, client_buffer_size, "no fans?" );
1020 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf );
1022 fp = open_file(buf2, &rep);
1024 snprintf( p_client_buffer, client_buffer_size, "can't open fan's state file" );
1027 memset(buf,0,sizeof(buf));
1028 fscanf(fp, "%*s %99s", buf);
1031 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1036 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1038 void get_acpi_ac_adapter( char * p_client_buffer, size_t client_buffer_size )
1045 if ( !p_client_buffer || client_buffer_size <= 0 )
1048 /* yeah, slow... :/ */
1049 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep))
1051 snprintf( p_client_buffer, client_buffer_size, "no ac_adapters?" );
1055 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf );
1058 fp = open_file(buf2, &rep);
1060 snprintf( p_client_buffer, client_buffer_size, "No ac adapter found.... where is it?" );
1063 memset(buf,0,sizeof(buf));
1064 fscanf(fp, "%*s %99s", buf );
1067 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1073 /proc/acpi/thermal_zone/THRM/cooling_mode
1074 cooling mode: active
1075 /proc/acpi/thermal_zone/THRM/polling_frequency
1077 /proc/acpi/thermal_zone/THRM/state
1079 /proc/acpi/thermal_zone/THRM/temperature
1081 /proc/acpi/thermal_zone/THRM/trip_points
1083 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1086 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1087 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1089 int open_acpi_temperature(const char *name)
1095 if (name == NULL || strcmp(name, "*") == 0) {
1097 if (!get_first_file_in_a_directory
1098 (ACPI_THERMAL_DIR, buf, &rep))
1103 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1105 fd = open(path, O_RDONLY);
1107 ERR("can't open '%s': %s", path, strerror(errno));
1112 static double last_acpi_temp;
1113 static double last_acpi_temp_time;
1115 double get_acpi_temperature(int fd)
1120 /* don't update acpi temperature too often */
1121 if (current_update_time - last_acpi_temp_time < 11.32) {
1122 return last_acpi_temp;
1124 last_acpi_temp_time = current_update_time;
1126 /* seek to beginning */
1127 lseek(fd, 0, SEEK_SET);
1133 n = read(fd, buf, 255);
1135 ERR("can't read fd %d: %s", fd, strerror(errno));
1138 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1142 return last_acpi_temp;
1146 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1148 design capacity: 4400 mAh
1149 last full capacity: 4064 mAh
1150 battery technology: rechargeable
1151 design voltage: 14800 mV
1152 design capacity warning: 300 mAh
1153 design capacity low: 200 mAh
1154 capacity granularity 1: 32 mAh
1155 capacity granularity 2: 32 mAh
1157 serial number: 16922
1163 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1166 charging state: unknown
1168 remaining capacity: 4064 mAh
1169 present voltage: 16608 mV
1173 2213<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1174 2213<@jupet kellari ö> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1175 2213<@jupet kellari ö> (-1 ollee ei akkua kiinni, koska akku on pöydällä)
1176 2214<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1177 2214<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1179 2238<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1180 2239<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1182 2240<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori päällä
1183 2241<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori päällä mutta ilman verkkovirtaa
1186 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1187 #define APM_PATH "/proc/apm"
1189 static FILE *acpi_bat_fp;
1190 static FILE *apm_bat_fp;
1192 static int acpi_last_full;
1194 static char last_battery_str[64];
1196 static double last_battery_time;
1198 void get_battery_stuff(char *buf, unsigned int n, const char *bat)
1200 static int rep, rep2;
1201 char acpi_path[128];
1202 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1204 /* don't update battery too often */
1205 if (current_update_time - last_battery_time < 29.5) {
1206 snprintf(buf, n, "%s", last_battery_str);
1209 last_battery_time = current_update_time;
1211 /* first try ACPI */
1213 if (acpi_bat_fp == NULL && apm_bat_fp == NULL)
1214 acpi_bat_fp = open_file(acpi_path, &rep);
1216 if (acpi_bat_fp != NULL) {
1217 int present_rate = -1;
1218 int remaining_capacity = -1;
1219 char charging_state[64];
1222 /* read last full capacity if it's zero */
1223 if (acpi_last_full == 0) {
1228 ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1229 fp = open_file(path, &rep);
1233 if (fgets(b, 256, fp) == NULL)
1235 if (sscanf(b, "last full capacity: %d", &acpi_last_full) != 0) {
1244 fseek(acpi_bat_fp, 0, SEEK_SET);
1246 strcpy(charging_state, "unknown");
1248 while (!feof(acpi_bat_fp)) {
1250 if (fgets(buf, 256, acpi_bat_fp) == NULL)
1253 /* let's just hope units are ok */
1254 if (buf[0] == 'p') {
1255 sscanf(buf, "present: %4s", present);
1256 } else if (buf[0] == 'c')
1257 sscanf(buf, "charging state: %63s",
1259 else if (buf[0] == 'p')
1260 sscanf(buf, "present rate: %d",
1262 else if (buf[0] == 'r')
1263 sscanf(buf, "remaining capacity: %d",
1264 &remaining_capacity);
1268 if (strcmp(present, "no") == 0) {
1269 strncpy(last_battery_str, "not present", 64);
1272 else if (strcmp(charging_state, "charging") == 0) {
1273 if (acpi_last_full != 0 && present_rate > 0) {
1274 snprintf(last_battery_str, 63, "charging %i%% ", (int) (remaining_capacity / acpi_last_full) * 100);
1275 format_seconds(last_battery_str + 14,
1278 remaining_capacity) * 60 *
1280 } else if (acpi_last_full != 0
1281 && present_rate <= 0) {
1282 snprintf(last_battery_str, 64, "charging %d%%",
1283 remaining_capacity * 100 /
1286 strncpy(last_battery_str, "charging", 63);
1290 else if (strncmp(charging_state, "discharging", 64) == 0) {
1291 if (present_rate > 0) {
1292 snprintf(last_battery_str, 63, "discharging %i%% ", (int)(remaining_capacity / acpi_last_full) * 100);
1293 format_seconds(last_battery_str + 17, 63 - 17,
1294 (remaining_capacity * 60 *
1295 60) / present_rate);
1296 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1297 snprintf(last_battery_str, 64, "full");
1299 snprintf(last_battery_str, 64,
1301 remaining_capacity * 100 /
1306 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1307 else if (strncmp(charging_state, "charged", 64) == 0) {
1308 strcpy(last_battery_str, "charged");
1310 /* unknown, probably full / AC */
1312 if (acpi_last_full != 0
1313 && remaining_capacity != acpi_last_full)
1314 snprintf(last_battery_str, 64, "unknown %d%%",
1315 remaining_capacity * 100 /
1318 strncpy(last_battery_str, "AC", 64);
1322 if (apm_bat_fp == NULL)
1323 apm_bat_fp = open_file(APM_PATH, &rep2);
1325 if (apm_bat_fp != NULL) {
1326 int ac, status, flag, life;
1329 "%*s %*s %*x %x %x %x %d%%",
1330 &ac, &status, &flag, &life);
1333 /* could check now that there is ac */
1334 snprintf(last_battery_str, 64, "AC");
1335 } else if (ac && life != 100) { /* could check that status==3 here? */
1336 snprintf(last_battery_str, 64,
1337 "charging %d%%", life);
1339 snprintf(last_battery_str, 64, "%d%%",
1343 /* it seemed to buffer it so file must be closed (or could use syscalls
1344 * directly but I don't feel like coding it now) */
1350 snprintf(buf, n, "%s", last_battery_str);
1353 /* On Apple powerbook and ibook:
1354 $ cat /proc/pmu/battery_0
1361 $ cat /proc/pmu/info
1362 PMU driver version : 2
1363 PMU firmware version : 0c
1368 /* defines as in <linux/pmu.h> */
1369 #define PMU_BATT_PRESENT 0x00000001
1370 #define PMU_BATT_CHARGING 0x00000002
1372 static FILE* pmu_battery_fp;
1373 static FILE* pmu_info_fp;
1374 static char pb_battery_info[3][32];
1375 static double pb_battery_info_update;
1377 #define PMU_PATH "/proc/pmu"
1378 void get_powerbook_batt_info(char *buf, size_t n, int i)
1381 const char* batt_path = PMU_PATH "/battery_0";
1382 const char* info_path = PMU_PATH "/info";
1383 int flags, charge, max_charge, ac = -1;
1386 /* don't update battery too often */
1387 if (current_update_time - pb_battery_info_update < 29.5) {
1388 snprintf(buf, n, "%s", pb_battery_info[i]);
1391 pb_battery_info_update = current_update_time;
1393 if (pmu_battery_fp == NULL)
1394 pmu_battery_fp = open_file(batt_path, &rep);
1396 if (pmu_battery_fp != NULL) {
1397 rewind(pmu_battery_fp);
1398 while (!feof(pmu_battery_fp)) {
1400 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL)
1404 sscanf(buf, "flags : %8x", &flags);
1405 else if (buf[0] == 'c' && buf[1] == 'h')
1406 sscanf(buf, "charge : %d", &charge);
1407 else if (buf[0] == 'm')
1408 sscanf(buf, "max_charge : %d", &max_charge);
1409 else if (buf[0] == 't')
1410 sscanf(buf, "time rem. : %ld", &time);
1413 if (pmu_info_fp == NULL)
1414 pmu_info_fp = open_file(info_path, &rep);
1416 if (pmu_info_fp != NULL) {
1417 rewind(pmu_info_fp);
1418 while (!feof(pmu_info_fp)) {
1420 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL)
1423 sscanf(buf, "AC Power : %d", &ac);
1426 /* update status string */
1427 if ((ac && !(flags & PMU_BATT_PRESENT)))
1428 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
1429 else if (ac && (flags & PMU_BATT_PRESENT)
1430 && !(flags & PMU_BATT_CHARGING))
1431 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
1432 else if ((flags & PMU_BATT_PRESENT)
1433 && (flags & PMU_BATT_CHARGING))
1434 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
1436 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
1438 /* update percentage string */
1440 pb_battery_info[PB_BATT_PERCENT][0] = 0;
1442 snprintf(pb_battery_info[PB_BATT_PERCENT],
1443 sizeof(pb_battery_info[PB_BATT_PERCENT]),
1444 "%d%%", (charge * 100)/max_charge);
1446 /* update time string */
1447 if (time == 0) /* fully charged or battery not present */
1448 pb_battery_info[PB_BATT_TIME][0] = 0;
1449 else if (time < 60*60) /* don't show secs */
1450 format_seconds_short(pb_battery_info[PB_BATT_TIME],
1451 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1453 format_seconds(pb_battery_info[PB_BATT_TIME],
1454 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1456 snprintf(buf, n, "%s", pb_battery_info[i]);
1461 show_nice_processes = 1;
1462 process_find_top(info.cpu, info.memu);
1463 info.first_process = get_first_process();
1468 * The following ifdefs were adapted from gkrellm
1470 #include <linux/major.h>
1472 #if ! defined (MD_MAJOR)
1476 #if !defined(LVM_BLK_MAJOR)
1477 #define LVM_BLK_MAJOR 58
1480 #if !defined(NBD_MAJOR)
1481 #define NBD_MAJOR 43
1484 void update_diskio()
1486 static unsigned int last = UINT_MAX;
1491 unsigned int current = 0;
1492 unsigned int reads, writes = 0;
1496 fp = fopen("/proc/diskstats", "r");
1498 fseek(fp, 0, SEEK_SET);
1501 /* read reads and writes from all disks (minor = 0), including
1502 * cd-roms and floppies, and summ them up
1506 fgets(buf, 512, fp);
1507 col_count = sscanf(buf, "%u %u %*s %*u %*u %u %*u %*u %*u %u",
1508 &major, &minor, &reads, &writes);
1509 /* ignore subdevices (they have only 3 matching entries in their line)
1510 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
1512 * XXX ignore devices which are part of a SW RAID (MD_MAJOR)
1514 if (col_count > 3 &&
1515 major != LVM_BLK_MAJOR && major != NBD_MAJOR &&
1516 major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
1517 current += reads + writes;
1521 /* since the values in /proc/diststats are absolute, we have
1522 * to substract our last reading. The numbers stand for
1523 * "sectors read", and we therefore have to divide by two to
1525 int tot = ((double)(current-last)/2);
1526 if (last > current) {
1527 /* we hit this either if it's the very first time we
1528 * run this, or when /proc/diskstats overflows; while
1529 * 0 is not correct, it's at least not way off */
1537 /* Here come the IBM ACPI-specific things. For reference, see
1538 http://ibm-acpi.sourceforge.net/README
1539 If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
1555 The content of these files is described in detail in the aforementioned
1556 README - some of them also in the following functions accessing them.
1557 Peter Tarjan (ptarjan@citromail.hu)
1560 #define IBM_ACPI_DIR "/proc/acpi/ibm"
1562 void get_ibm_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1564 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
1565 /proc/acpi/ibm/fan looks like this (3 lines):
1568 commands: enable, disable
1569 Peter Tarjan (ptarjan@citromail.hu)
1572 if ( !p_client_buffer || client_buffer_size <= 0 )
1576 unsigned int speed=0;
1578 snprintf(fan, 127, "%s/fan",IBM_ACPI_DIR);
1580 fp = fopen(fan, "r");
1586 if (fgets(line, 255, fp) == NULL) break;
1587 if (sscanf(line, "speed: %d", &speed)) break;
1592 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", fan, strerror(errno));
1596 snprintf( p_client_buffer, client_buffer_size, "%d", speed );
1601 static double last_ibm_acpi_temp_time;
1602 void get_ibm_acpi_temps()
1604 /* get the measured temperatures from the temperature sensors
1605 on IBM/Lenovo laptops running the ibm acpi.
1606 There are 8 values in /proc/acpi/ibm/thermal, and according to
1607 http://ibm-acpi.sourceforge.net/README
1608 these mean the following (at least on an IBM R51...)
1609 0: CPU (also on the T series laptops)
1610 1: Mini PCI Module (?)
1612 3: GPU (also on the T series laptops)
1617 I'm not too sure about those with the question mark, but the values I'm
1618 reading from *my* thermal file (on a T42p) look realistic for the
1619 hdd and the battery.
1620 #5 and #7 are always -128.
1621 /proc/acpi/ibm/thermal looks like this (1 line):
1622 temperatures: 41 43 31 46 33 -128 29 -128
1623 Peter Tarjan (ptarjan@citromail.hu)
1626 /* don't update too often */
1627 if (current_update_time - last_ibm_acpi_temp_time < 10.00)
1631 last_ibm_acpi_temp_time = current_update_time;
1633 /* if ( !p_client_buffer || client_buffer_size <= 0 )
1639 snprintf(thermal, 127, "%s/thermal",IBM_ACPI_DIR);
1640 fp = fopen(thermal, "r");
1647 if (fgets(line, 255, fp) == NULL) break;
1648 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
1649 &ibm_acpi.temps[0], &ibm_acpi.temps[1],
1650 &ibm_acpi.temps[2], &ibm_acpi.temps[3],
1651 &ibm_acpi.temps[4], &ibm_acpi.temps[5],
1652 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) break;
1657 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", thermal, strerror(errno));
1665 void get_ibm_acpi_volume( char * p_client_buffer, size_t client_buffer_size )
1668 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
1669 "Volume" here is none of the mixer volumes, but a "master of masters"
1670 volume adjusted by the IBM volume keys.
1671 /proc/acpi/ibm/fan looks like this (4 lines):
1674 commands: up, down, mute
1675 commands: level <level> (<level> is 0-15)
1676 Peter Tarjan (ptarjan@citromail.hu)
1679 if ( !p_client_buffer || client_buffer_size <= 0 )
1685 snprintf(volume, 127, "%s/volume",IBM_ACPI_DIR);
1686 unsigned int vol=-1;
1689 fp = fopen(volume, "r");
1695 if (fgets(line, 255, fp) == NULL) break;
1696 if (sscanf(line, "level: %d", &vol)) continue;
1697 if (sscanf(line, "mute: %s", mute)) break;
1702 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", volume, strerror(errno));
1707 if (strcmp(mute, "on")==0)
1709 snprintf( p_client_buffer, client_buffer_size, "%s", "mute" );
1714 snprintf( p_client_buffer, client_buffer_size, "%d", vol );
1720 /*static FILE *fp=NULL;*/
1722 void get_ibm_acpi_brightness(char * p_client_buffer, size_t client_buffer_size)
1724 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
1725 /proc/acpi/ibm/brightness looks like this (3 lines):
1728 commands: level <level> (<level> is 0-7)
1729 Peter Tarjan (ptarjan@citromail.hu)
1732 if ( !p_client_buffer || client_buffer_size <= 0 )
1736 unsigned int brightness=0;
1738 snprintf(filename, 127, "%s/brightness",IBM_ACPI_DIR);
1740 fp = fopen(filename, "r");
1746 if (fgets(line, 255, fp) == NULL) break;
1747 if (sscanf(line, "level: %d", &brightness)) break;
1752 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", filename, strerror(errno));
1757 snprintf( p_client_buffer, client_buffer_size, "%d", brightness );