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 void 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
887 while (fgets(s, sizeof(s), f) != NULL){ //read the file
889 #if defined(__i386) || defined(__x86_64)
890 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) { //and search for the cpu mhz
893 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) { // different on alpha
895 if (strncmp(s, "clock", 5) == 0 && cpu == 0) { // this is different on ppc for some reason
896 #endif // defined(__alpha)
897 #endif // defined(__i386) || defined(__x86_64)
899 strcpy(frequency, strchr(s, ':') + 2); //copy just the number
901 frequency[strlen(frequency) - 6] = '\0';// strip " est.\n"
902 freq = strtod(frequency, NULL)/1000000; // kernel reports in Hz
904 frequency[strlen(frequency) - 1] = '\0'; // strip \n
905 freq = strtod(frequency, NULL);
909 if (strncmp(s, "processor", 9) == 0) {
917 snprintf( p_client_buffer, client_buffer_size, p_format, (float)freq/divisor );
921 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
923 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
924 void get_voltage( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
926 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks
938 /* Peter Tarjan (ptarjan@citromail.hu) */
943 char current_freq_file[128];
947 /* build the voltage file name */
949 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
950 CPUFREQ_PREFIX, cpu, CPUFREQ_POSTFIX);
952 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
955 /* read the current cpu frequency from the /sys node */
956 f = fopen(current_freq_file, "r");
958 if (fgets(s, sizeof(s), f)) {
959 s[strlen(s)-1] = '\0';
960 freq = strtod(s, NULL);
966 ERR("voltage: No %s.", current_freq_file);
971 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
972 CPUFREQ_PREFIX, cpu, CPUFREQ_VOLTAGE);
974 /* use the current cpu frequency to find the corresponding voltage */
975 f = fopen(current_freq_file, "r");
982 if (fgets(line, 255, f) == NULL) break;
983 sscanf(line, "%d %d", &freq_comp, &voltage);
984 if(freq_comp == freq) break;
990 ERR("voltage: No %s.", current_freq_file);
995 snprintf( p_client_buffer, client_buffer_size, p_format, (float)voltage/divisor );
1000 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1002 void get_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1009 if ( !p_client_buffer || client_buffer_size <= 0 )
1012 /* yeah, slow... :/ */
1013 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep))
1015 snprintf( p_client_buffer, client_buffer_size, "no fans?" );
1019 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf );
1021 fp = open_file(buf2, &rep);
1023 snprintf( p_client_buffer, client_buffer_size, "can't open fan's state file" );
1026 memset(buf,0,sizeof(buf));
1027 fscanf(fp, "%*s %99s", buf);
1030 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1035 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1037 void get_acpi_ac_adapter( char * p_client_buffer, size_t client_buffer_size )
1044 if ( !p_client_buffer || client_buffer_size <= 0 )
1047 /* yeah, slow... :/ */
1048 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep))
1050 snprintf( p_client_buffer, client_buffer_size, "no ac_adapters?" );
1054 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf );
1057 fp = open_file(buf2, &rep);
1059 snprintf( p_client_buffer, client_buffer_size, "No ac adapter found.... where is it?" );
1062 memset(buf,0,sizeof(buf));
1063 fscanf(fp, "%*s %99s", buf );
1066 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1072 /proc/acpi/thermal_zone/THRM/cooling_mode
1073 cooling mode: active
1074 /proc/acpi/thermal_zone/THRM/polling_frequency
1076 /proc/acpi/thermal_zone/THRM/state
1078 /proc/acpi/thermal_zone/THRM/temperature
1080 /proc/acpi/thermal_zone/THRM/trip_points
1082 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1085 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1086 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1088 int open_acpi_temperature(const char *name)
1094 if (name == NULL || strcmp(name, "*") == 0) {
1096 if (!get_first_file_in_a_directory
1097 (ACPI_THERMAL_DIR, buf, &rep))
1102 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1104 fd = open(path, O_RDONLY);
1106 ERR("can't open '%s': %s", path, strerror(errno));
1111 static double last_acpi_temp;
1112 static double last_acpi_temp_time;
1114 double get_acpi_temperature(int fd)
1119 /* don't update acpi temperature too often */
1120 if (current_update_time - last_acpi_temp_time < 11.32) {
1121 return last_acpi_temp;
1123 last_acpi_temp_time = current_update_time;
1125 /* seek to beginning */
1126 lseek(fd, 0, SEEK_SET);
1132 n = read(fd, buf, 255);
1134 ERR("can't read fd %d: %s", fd, strerror(errno));
1137 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1141 return last_acpi_temp;
1145 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1147 design capacity: 4400 mAh
1148 last full capacity: 4064 mAh
1149 battery technology: rechargeable
1150 design voltage: 14800 mV
1151 design capacity warning: 300 mAh
1152 design capacity low: 200 mAh
1153 capacity granularity 1: 32 mAh
1154 capacity granularity 2: 32 mAh
1156 serial number: 16922
1162 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1165 charging state: unknown
1167 remaining capacity: 4064 mAh
1168 present voltage: 16608 mV
1172 2213<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1173 2213<@jupet kellari ö> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1174 2213<@jupet kellari ö> (-1 ollee ei akkua kiinni, koska akku on pöydällä)
1175 2214<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1176 2214<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1178 2238<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1179 2239<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1181 2240<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori päällä
1182 2241<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori päällä mutta ilman verkkovirtaa
1185 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1186 #define APM_PATH "/proc/apm"
1188 static FILE *acpi_bat_fp;
1189 static FILE *apm_bat_fp;
1191 static int acpi_last_full;
1193 static char last_battery_str[64];
1195 static double last_battery_time;
1197 void get_battery_stuff(char *buf, unsigned int n, const char *bat)
1199 static int rep, rep2;
1200 char acpi_path[128];
1201 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1203 /* don't update battery too often */
1204 if (current_update_time - last_battery_time < 29.5) {
1205 snprintf(buf, n, "%s", last_battery_str);
1208 last_battery_time = current_update_time;
1210 /* first try ACPI */
1212 if (acpi_bat_fp == NULL && apm_bat_fp == NULL)
1213 acpi_bat_fp = open_file(acpi_path, &rep);
1215 if (acpi_bat_fp != NULL) {
1216 int present_rate = -1;
1217 int remaining_capacity = -1;
1218 char charging_state[64];
1220 /* read last full capacity if it's zero */
1221 if (acpi_last_full == 0) {
1226 ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1227 fp = open_file(path, &rep);
1231 if (fgets(b, 256, fp) == NULL)
1233 if (sscanf(b, "last full capacity: %d", &acpi_last_full) != 0) {
1242 fseek(acpi_bat_fp, 0, SEEK_SET);
1244 strcpy(charging_state, "unknown");
1246 while (!feof(acpi_bat_fp)) {
1248 if (fgets(buf, 256, acpi_bat_fp) == NULL)
1251 /* let's just hope units are ok */
1253 sscanf(buf, "charging state: %63s",
1255 else if (buf[0] == 'p')
1256 sscanf(buf, "present rate: %d",
1258 else if (buf[0] == 'r')
1259 sscanf(buf, "remaining capacity: %d",
1260 &remaining_capacity);
1264 if (strcmp(charging_state, "charging") == 0) {
1265 if (acpi_last_full != 0 && present_rate > 0) {
1266 strcpy(last_battery_str, "charging ");
1267 format_seconds(last_battery_str + 9,
1270 remaining_capacity) * 60 *
1272 } else if (acpi_last_full != 0
1273 && present_rate <= 0) {
1274 sprintf(last_battery_str, "charging %d%%",
1275 remaining_capacity * 100 /
1278 strcpy(last_battery_str, "charging");
1282 else if (strcmp(charging_state, "discharging") == 0) {
1283 if (present_rate > 0)
1284 format_seconds(last_battery_str, 63,
1285 (remaining_capacity * 60 *
1286 60) / present_rate);
1288 sprintf(last_battery_str,
1290 remaining_capacity * 100 /
1294 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1295 else if (strcmp(charging_state, "charged") == 0) {
1296 strcpy(last_battery_str, "charged");
1298 /* unknown, probably full / AC */
1300 if (acpi_last_full != 0
1301 && remaining_capacity != acpi_last_full)
1302 sprintf(last_battery_str, "unknown %d%%",
1303 remaining_capacity * 100 /
1306 strcpy(last_battery_str, "AC");
1310 if (apm_bat_fp == NULL)
1311 apm_bat_fp = open_file(APM_PATH, &rep2);
1313 if (apm_bat_fp != NULL) {
1314 int ac, status, flag, life;
1317 "%*s %*s %*x %x %x %x %d%%",
1318 &ac, &status, &flag, &life);
1321 /* could check now that there is ac */
1322 snprintf(last_battery_str, 64, "AC");
1323 } else if (ac && life != 100) { /* could check that status==3 here? */
1324 snprintf(last_battery_str, 64,
1325 "charging %d%%", life);
1327 snprintf(last_battery_str, 64, "%d%%",
1331 /* it seemed to buffer it so file must be closed (or could use syscalls
1332 * directly but I don't feel like coding it now) */
1338 snprintf(buf, n, "%s", last_battery_str);
1341 /* On Apple powerbook and ibook:
1342 $ cat /proc/pmu/battery_0
1349 $ cat /proc/pmu/info
1350 PMU driver version : 2
1351 PMU firmware version : 0c
1356 /* defines as in <linux/pmu.h> */
1357 #define PMU_BATT_PRESENT 0x00000001
1358 #define PMU_BATT_CHARGING 0x00000002
1360 static FILE* pmu_battery_fp;
1361 static FILE* pmu_info_fp;
1362 static char pb_battery_info[3][32];
1363 static double pb_battery_info_update;
1365 #define PMU_PATH "/proc/pmu"
1366 void get_powerbook_batt_info(char *buf, size_t n, int i)
1369 const char* batt_path = PMU_PATH "/battery_0";
1370 const char* info_path = PMU_PATH "/info";
1371 int flags, charge, max_charge, ac = -1;
1374 /* don't update battery too often */
1375 if (current_update_time - pb_battery_info_update < 29.5) {
1376 snprintf(buf, n, "%s", pb_battery_info[i]);
1379 pb_battery_info_update = current_update_time;
1381 if (pmu_battery_fp == NULL)
1382 pmu_battery_fp = open_file(batt_path, &rep);
1384 if (pmu_battery_fp != NULL) {
1385 rewind(pmu_battery_fp);
1386 while (!feof(pmu_battery_fp)) {
1388 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL)
1392 sscanf(buf, "flags : %8x", &flags);
1393 else if (buf[0] == 'c' && buf[1] == 'h')
1394 sscanf(buf, "charge : %d", &charge);
1395 else if (buf[0] == 'm')
1396 sscanf(buf, "max_charge : %d", &max_charge);
1397 else if (buf[0] == 't')
1398 sscanf(buf, "time rem. : %ld", &time);
1401 if (pmu_info_fp == NULL)
1402 pmu_info_fp = open_file(info_path, &rep);
1404 if (pmu_info_fp != NULL) {
1405 rewind(pmu_info_fp);
1406 while (!feof(pmu_info_fp)) {
1408 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL)
1411 sscanf(buf, "AC Power : %d", &ac);
1414 /* update status string */
1415 if ((ac && !(flags & PMU_BATT_PRESENT)))
1416 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
1417 else if (ac && (flags & PMU_BATT_PRESENT)
1418 && !(flags & PMU_BATT_CHARGING))
1419 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
1420 else if ((flags & PMU_BATT_PRESENT)
1421 && (flags & PMU_BATT_CHARGING))
1422 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
1424 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
1426 /* update percentage string */
1428 pb_battery_info[PB_BATT_PERCENT][0] = 0;
1430 snprintf(pb_battery_info[PB_BATT_PERCENT],
1431 sizeof(pb_battery_info[PB_BATT_PERCENT]),
1432 "%d%%", (charge * 100)/max_charge);
1434 /* update time string */
1435 if (time == 0) /* fully charged or battery not present */
1436 pb_battery_info[PB_BATT_TIME][0] = 0;
1437 else if (time < 60*60) /* don't show secs */
1438 format_seconds_short(pb_battery_info[PB_BATT_TIME],
1439 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1441 format_seconds(pb_battery_info[PB_BATT_TIME],
1442 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1444 snprintf(buf, n, "%s", pb_battery_info[i]);
1449 show_nice_processes = 1;
1450 process_find_top(info.cpu, info.memu);
1451 info.first_process = get_first_process();
1456 * The following ifdefs were adapted from gkrellm
1458 #include <linux/major.h>
1460 #if ! defined (MD_MAJOR)
1464 #if !defined(LVM_BLK_MAJOR)
1465 #define LVM_BLK_MAJOR 58
1468 #if !defined(NBD_MAJOR)
1469 #define NBD_MAJOR 43
1472 void update_diskio()
1474 static unsigned int last = UINT_MAX;
1479 unsigned int current = 0;
1480 unsigned int reads, writes = 0;
1484 fp = fopen("/proc/diskstats", "r");
1486 fseek(fp, 0, SEEK_SET);
1489 /* read reads and writes from all disks (minor = 0), including
1490 * cd-roms and floppies, and summ them up
1494 fgets(buf, 512, fp);
1495 col_count = sscanf(buf, "%u %u %*s %*u %*u %u %*u %*u %*u %u",
1496 &major, &minor, &reads, &writes);
1497 /* ignore subdevices (they have only 3 matching entries in their line)
1498 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
1500 * XXX ignore devices which are part of a SW RAID (MD_MAJOR)
1502 if (col_count > 3 &&
1503 major != LVM_BLK_MAJOR && major != NBD_MAJOR &&
1504 major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
1505 current += reads + writes;
1509 /* since the values in /proc/diststats are absolute, we have
1510 * to substract our last reading. The numbers stand for
1511 * "sectors read", and we therefore have to divide by two to
1513 int tot = ((double)(current-last)/2);
1514 if (last > current) {
1515 /* we hit this either if it's the very first time we
1516 * run this, or when /proc/diskstats overflows; while
1517 * 0 is not correct, it's at least not way off */
1525 /* Here come the IBM ACPI-specific things. For reference, see
1526 http://ibm-acpi.sourceforge.net/README
1527 If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
1543 The content of these files is described in detail in the aforementioned
1544 README - some of them also in the following functions accessing them.
1545 Peter Tarjan (ptarjan@citromail.hu)
1548 #define IBM_ACPI_DIR "/proc/acpi/ibm"
1550 void get_ibm_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1552 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
1553 /proc/acpi/ibm/fan looks like this (3 lines):
1556 commands: enable, disable
1557 Peter Tarjan (ptarjan@citromail.hu)
1560 if ( !p_client_buffer || client_buffer_size <= 0 )
1564 unsigned int speed=0;
1566 snprintf(fan, 127, "%s/fan",IBM_ACPI_DIR);
1568 fp = fopen(fan, "r");
1574 if (fgets(line, 255, fp) == NULL) break;
1575 if (sscanf(line, "speed: %d", &speed)) break;
1580 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", fan, strerror(errno));
1584 snprintf( p_client_buffer, client_buffer_size, "%d", speed );
1589 static double last_ibm_acpi_temp_time;
1590 void get_ibm_acpi_temps()
1592 /* get the measured temperatures from the temperature sensors
1593 on IBM/Lenovo laptops running the ibm acpi.
1594 There are 8 values in /proc/acpi/ibm/thermal, and according to
1595 http://ibm-acpi.sourceforge.net/README
1596 these mean the following (at least on an IBM R51...)
1597 0: CPU (also on the T series laptops)
1598 1: Mini PCI Module (?)
1600 3: GPU (also on the T series laptops)
1605 I'm not too sure about those with the question mark, but the values I'm
1606 reading from *my* thermal file (on a T42p) look realistic for the
1607 hdd and the battery.
1608 #5 and #7 are always -128.
1609 /proc/acpi/ibm/thermal looks like this (1 line):
1610 temperatures: 41 43 31 46 33 -128 29 -128
1611 Peter Tarjan (ptarjan@citromail.hu)
1614 /* don't update too often */
1615 if (current_update_time - last_ibm_acpi_temp_time < 10.00)
1619 last_ibm_acpi_temp_time = current_update_time;
1621 /* if ( !p_client_buffer || client_buffer_size <= 0 )
1627 snprintf(thermal, 127, "%s/thermal",IBM_ACPI_DIR);
1628 fp = fopen(thermal, "r");
1635 if (fgets(line, 255, fp) == NULL) break;
1636 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
1637 &ibm_acpi.temps[0], &ibm_acpi.temps[1],
1638 &ibm_acpi.temps[2], &ibm_acpi.temps[3],
1639 &ibm_acpi.temps[4], &ibm_acpi.temps[5],
1640 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) break;
1645 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", thermal, strerror(errno));
1653 void get_ibm_acpi_volume( char * p_client_buffer, size_t client_buffer_size )
1656 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
1657 "Volume" here is none of the mixer volumes, but a "master of masters"
1658 volume adjusted by the IBM volume keys.
1659 /proc/acpi/ibm/fan looks like this (4 lines):
1662 commands: up, down, mute
1663 commands: level <level> (<level> is 0-15)
1664 Peter Tarjan (ptarjan@citromail.hu)
1667 if ( !p_client_buffer || client_buffer_size <= 0 )
1673 snprintf(volume, 127, "%s/volume",IBM_ACPI_DIR);
1674 unsigned int vol=-1;
1677 fp = fopen(volume, "r");
1683 if (fgets(line, 255, fp) == NULL) break;
1684 if (sscanf(line, "level: %d", &vol)) continue;
1685 if (sscanf(line, "mute: %s", mute)) break;
1690 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", volume, strerror(errno));
1695 if (strcmp(mute, "on")==0)
1697 snprintf( p_client_buffer, client_buffer_size, "%s", "mute" );
1702 snprintf( p_client_buffer, client_buffer_size, "%d", vol );
1708 /*static FILE *fp=NULL;*/
1710 void get_ibm_acpi_brightness(char * p_client_buffer, size_t client_buffer_size)
1712 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
1713 /proc/acpi/ibm/brightness looks like this (3 lines):
1716 commands: level <level> (<level> is 0-7)
1717 Peter Tarjan (ptarjan@citromail.hu)
1720 if ( !p_client_buffer || client_buffer_size <= 0 )
1724 unsigned int brightness=0;
1726 snprintf(filename, 127, "%s/brightness",IBM_ACPI_DIR);
1728 fp = fopen(filename, "r");
1734 if (fgets(line, 255, fp) == NULL) break;
1735 if (sscanf(line, "level: %d", &brightness)) break;
1740 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", filename, strerror(errno));
1745 snprintf( p_client_buffer, client_buffer_size, "%d", brightness );