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;
408 /* add check for !info.cpu_usage since that mem is freed on a SIGUSR1 */
409 if (!cpu_setup || !info.cpu_usage) {
414 if (stat_template == NULL) {
415 stat_template = KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT ;
419 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
420 cpu = malloc(malloc_cpu_size);
421 memset(cpu, 0, malloc_cpu_size);
424 if (stat_fp == NULL) {
425 stat_fp = open_file("/proc/stat", &rep);
427 fseek(stat_fp, 0, SEEK_SET);
429 if (stat_fp == NULL) {
433 while (!feof(stat_fp)) {
434 if (fgets(buf, 255, stat_fp) == NULL)
437 if (strncmp(buf, "procs_running ", 14) == 0) {
438 sscanf(buf, "%*s %hu", &info.run_procs);
439 info.mask |= (1 << INFO_RUN_PROCS);
440 } else if (strncmp(buf, "cpu", 3) == 0) {
441 index = isdigit(buf[3]) ? ((int)buf[3]) - 0x2F : 0;
442 sscanf(buf, stat_template
443 , &(cpu[index].cpu_user)
444 , &(cpu[index].cpu_nice)
445 , &(cpu[index].cpu_system)
446 , &(cpu[index].cpu_idle)
447 , &(cpu[index].cpu_iowait)
448 , &(cpu[index].cpu_irq)
449 , &(cpu[index].cpu_softirq)
450 , &(cpu[index].cpu_steal)
453 cpu[index].cpu_total = cpu[index].cpu_user
454 + cpu[index].cpu_nice
455 + cpu[index].cpu_system
456 + cpu[index].cpu_idle
457 + cpu[index].cpu_iowait
459 + cpu[index].cpu_softirq
460 + cpu[index].cpu_steal
463 cpu[index].cpu_active_total = cpu[index].cpu_total - (cpu[index].cpu_idle + cpu[index].cpu_iowait);
464 info.mask |= (1 << INFO_CPU);
466 double delta = current_update_time - last_update_time;
467 if (delta <= 0.001) return;
469 cpu[index].cpu_val[0] = (cpu[index].cpu_active_total - cpu[index].cpu_last_active_total) /
470 (float )(cpu[index].cpu_total - cpu[index].cpu_last_total);
472 for (i=0; i < info.cpu_avg_samples; i++ ) {
473 curtmp += cpu[index].cpu_val[i];
475 /* TESTING -- I've removed this, because I don't think it is right. You shouldn't divide
476 by the cpu count here ... removing for testing */
478 info.cpu_usage[index] = curtmp / info.cpu_avg_samples / info.cpu_count;
480 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
482 /* TESTING -- this line replaces the prev. "suspect" if/else */
483 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
485 cpu[index].cpu_last_total = cpu[index].cpu_total;
486 cpu[index].cpu_last_active_total = cpu[index].cpu_active_total;
487 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
488 cpu[index].cpu_val[i] = cpu[index].cpu_val[i - 1];
495 void update_running_processes()
500 void update_cpu_usage()
505 void update_load_average()
507 #ifdef HAVE_GETLOADAVG
510 info.loadavg[0] = (float) v[0];
511 info.loadavg[1] = (float) v[1];
512 info.loadavg[2] = (float) v[2];
517 fp = open_file("/proc/loadavg", &rep);
519 v[0] = v[1] = v[2] = 0.0;
523 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1],
530 #define PROC_I8K "/proc/i8k"
531 #define I8K_DELIM " "
532 static char *i8k_procbuf = NULL;
537 i8k_procbuf = (char*)malloc(128*sizeof(char));
539 if ((fp = fopen(PROC_I8K,"r")) == NULL) {
540 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel driver is loaded...");
543 memset(&i8k_procbuf[0],0,128);
544 if (fread(&i8k_procbuf[0],sizeof(char),128,fp) == 0) {
545 ERR("something wrong with /proc/i8k...");
550 i8k.version = strtok(&i8k_procbuf[0],I8K_DELIM);
551 i8k.bios = strtok(NULL,I8K_DELIM);
552 i8k.serial = strtok(NULL,I8K_DELIM);
553 i8k.cpu_temp = strtok(NULL,I8K_DELIM);
554 i8k.left_fan_status = strtok(NULL,I8K_DELIM);
555 i8k.right_fan_status = strtok(NULL,I8K_DELIM);
556 i8k.left_fan_rpm = strtok(NULL,I8K_DELIM);
557 i8k.right_fan_rpm = strtok(NULL,I8K_DELIM);
558 i8k.ac_status = strtok(NULL,I8K_DELIM);
559 i8k.buttons_status = strtok(NULL,I8K_DELIM);
563 /***********************************************************/
564 /***********************************************************/
565 /***********************************************************/
567 static int no_dots(const struct dirent *d)
569 if (d->d_name[0] == '.')
575 get_first_file_in_a_directory(const char *dir, char *s, int *rep)
577 struct dirent **namelist;
580 n = scandir(dir, &namelist, no_dots, alphasort);
583 ERR("scandir for %s: %s", dir, strerror(errno));
592 strncpy(s, namelist[0]->d_name, 255);
595 for (i = 0; i < n; i++)
603 #define I2C_DIR "/sys/bus/i2c/devices/"
606 open_i2c_sensor(const char *dev, const char *type, int n, int *div,
614 /* if i2c device is NULL or *, get first */
615 if (dev == NULL || strcmp(dev, "*") == 0) {
617 if (!get_first_file_in_a_directory(I2C_DIR, buf, &rep))
622 /* change vol to in */
623 if (strcmp(type, "vol") == 0)
626 if (strcmp(type, "tempf") == 0) {
627 snprintf(path, 255, I2C_DIR "%s/%s%d_input", dev, "temp", n);
629 snprintf(path, 255, I2C_DIR "%s/%s%d_input", dev, type, n);
631 strncpy(devtype, path, 255);
634 fd = open(path, O_RDONLY);
636 CRIT_ERR("can't open '%s': %s\nplease fix i2c or remove it from Conky", path, strerror(errno));
639 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
640 || strcmp(type, "tempf") == 0)
644 /* fan does not use *_div as a read divisor */
645 if (strcmp("fan", type) == 0)
648 /* test if *_div file exist, open it and use it as divisor */
649 if (strcmp(type, "tempf") == 0) {
650 snprintf(path, 255, I2C_DIR "%s/%s%d_div", "one", "two",
653 snprintf(path, 255, I2C_DIR "%s/%s%d_div", dev, type, n);
656 divfd = open(path, O_RDONLY);
661 divn = read(divfd, divbuf, 63);
662 /* should read until n == 0 but I doubt that kernel will give these
663 * in multiple pieces. :) */
673 double get_i2c_info(int *fd, int div, char *devtype, char *type)
680 lseek(*fd, 0, SEEK_SET);
686 n = read(*fd, buf, 63);
687 /* should read until n == 0 but I doubt that kernel will give these
688 * in multiple pieces. :) */
695 *fd = open(devtype, O_RDONLY);
697 ERR("can't open '%s': %s", devtype, strerror(errno));
699 /* My dirty hack for computing CPU value
700 * Filedil, from forums.gentoo.org
702 /* if (strstr(devtype, "temp1_input") != NULL)
703 return -15.096+1.4893*(val / 1000.0); */
706 /* divide voltage and temperature by 1000 */
707 /* or if any other divisor is given, use that */
708 if (strcmp(type, "tempf") == 0) {
710 return ((val / div + 40) * 9.0 / 5) - 40;
712 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
714 return ((val + 40) * 9.0 / 5) - 40;
725 /* Prior to kernel version 2.6.12, the CPU fan speed was available
726 * in ADT746X_FAN_OLD, whereas later kernel versions provide this
727 * information in ADT746X_FAN.
729 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
730 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
732 void get_adt746x_fan( char * p_client_buffer, size_t client_buffer_size )
735 char adt746x_fan_state[64];
738 if ( !p_client_buffer || client_buffer_size <= 0 )
741 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
742 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL)
745 sprintf(adt746x_fan_state, "adt746x not found");
749 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
750 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
754 snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_fan_state );
758 /* Prior to kernel version 2.6.12, the CPU temperature was found
759 * in ADT746X_CPU_OLD, whereas later kernel versions provide this
760 * information in ADT746X_CPU.
762 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
763 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
765 void get_adt746x_cpu( char * p_client_buffer, size_t client_buffer_size )
768 char adt746x_cpu_state[64];
771 if ( !p_client_buffer || client_buffer_size <= 0 )
774 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
775 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL)
777 sprintf(adt746x_cpu_state, "adt746x not found");
781 fscanf(fp, "%2s", adt746x_cpu_state);
785 snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state );
789 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
791 /***********************************************************************/
793 * This file is part of x86info.
794 * (C) 2001 Dave Jones.
796 * Licensed under the terms of the GNU GPL License version 2.
798 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
799 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz>
802 #if defined(__i386) || defined(__x86_64)
803 __inline__ unsigned long long int rdtsc()
805 unsigned long long int x;
806 __asm__ volatile (".byte 0x0f, 0x31":"=A" (x));
811 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
812 void get_freq_dynamic( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor )
814 #if defined(__i386) || defined(__x86_64)
816 struct timeval tvstart, tvstop;
817 unsigned long long cycles[2]; /* gotta be 64 bit */
818 unsigned int microseconds; /* total time taken */
820 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
823 memset(&tz, 0, sizeof(tz));
825 /* get this function in cached memory */
826 gettimeofday(&tvstart, &tz);
828 gettimeofday(&tvstart, &tz);
830 /* we don't trust that this is any specific length of time */
833 gettimeofday(&tvstop, &tz);
834 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
835 (tvstop.tv_usec - tvstart.tv_usec);
837 snprintf( p_client_buffer, client_buffer_size, p_format, (float)((cycles[1] - cycles[0]) / microseconds) / divisor );
840 /* FIXME: hardwired: get freq for first cpu!
841 this whole function needs to be rethought and redone for
842 multi-cpu/multi-core/multi-threaded environments and
843 arbitrary combinations thereof
845 get_freq( p_client_buffer, client_buffer_size, p_format, divisor, 1 );
851 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
852 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
854 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
855 char get_freq( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
861 char current_freq_file[128];
864 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
865 CPUFREQ_PREFIX, cpu, CPUFREQ_POSTFIX);
867 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
870 f = fopen(current_freq_file, "r");
872 /* if there's a cpufreq /sys node, read the current frequency from this node;
873 * divide by 1000 to get Mhz. */
874 if (fgets(s, sizeof(s), f)) {
875 s[strlen(s)-1] = '\0';
876 freq = strtod(s, NULL);
879 snprintf( p_client_buffer, client_buffer_size, p_format, (freq/1000)/divisor );
884 f = fopen("/proc/cpuinfo", "r"); //open the CPU information file
886 perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
890 while (fgets(s, sizeof(s), f) != NULL){ //read the file
892 #if defined(__i386) || defined(__x86_64)
893 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) { //and search for the cpu mhz
896 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) { // different on alpha
898 if (strncmp(s, "clock", 5) == 0 && cpu == 0) { // this is different on ppc for some reason
899 #endif // defined(__alpha)
900 #endif // defined(__i386) || defined(__x86_64)
902 strcpy(frequency, strchr(s, ':') + 2); //copy just the number
904 frequency[strlen(frequency) - 6] = '\0';// strip " est.\n"
905 freq = strtod(frequency, NULL)/1000000; // kernel reports in Hz
907 frequency[strlen(frequency) - 1] = '\0'; // strip \n
908 freq = strtod(frequency, NULL);
912 if (strncmp(s, "processor", 9) == 0) {
920 snprintf( p_client_buffer, client_buffer_size, p_format, (float)freq/divisor );
924 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
926 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
927 char get_voltage( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
929 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks
941 /* Peter Tarjan (ptarjan@citromail.hu) */
946 char current_freq_file[128];
950 /* build the voltage file name */
952 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
953 CPUFREQ_PREFIX, cpu, CPUFREQ_POSTFIX);
955 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
958 /* read the current cpu frequency from the /sys node */
959 f = fopen(current_freq_file, "r");
961 if (fgets(s, sizeof(s), f)) {
962 s[strlen(s)-1] = '\0';
963 freq = strtod(s, NULL);
967 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
968 perror("get_voltage()");
975 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
976 CPUFREQ_PREFIX, cpu, CPUFREQ_VOLTAGE);
978 /* use the current cpu frequency to find the corresponding voltage */
979 f = fopen(current_freq_file, "r");
984 if (fgets(line, 255, f) == NULL) break;
985 sscanf(line, "%d %d", &freq_comp, &voltage);
986 if(freq_comp == freq) break;
990 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
991 perror("get_voltage()");
997 snprintf( p_client_buffer, client_buffer_size, p_format, (float)voltage/divisor );
1002 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1004 void get_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1011 if ( !p_client_buffer || client_buffer_size <= 0 )
1014 /* yeah, slow... :/ */
1015 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep))
1017 snprintf( p_client_buffer, client_buffer_size, "no fans?" );
1021 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf );
1023 fp = open_file(buf2, &rep);
1025 snprintf( p_client_buffer, client_buffer_size, "can't open fan's state file" );
1028 memset(buf,0,sizeof(buf));
1029 fscanf(fp, "%*s %99s", buf);
1032 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1037 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1039 void get_acpi_ac_adapter( char * p_client_buffer, size_t client_buffer_size )
1046 if ( !p_client_buffer || client_buffer_size <= 0 )
1049 /* yeah, slow... :/ */
1050 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep))
1052 snprintf( p_client_buffer, client_buffer_size, "no ac_adapters?" );
1056 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf );
1059 fp = open_file(buf2, &rep);
1061 snprintf( p_client_buffer, client_buffer_size, "No ac adapter found.... where is it?" );
1064 memset(buf,0,sizeof(buf));
1065 fscanf(fp, "%*s %99s", buf );
1068 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1074 /proc/acpi/thermal_zone/THRM/cooling_mode
1075 cooling mode: active
1076 /proc/acpi/thermal_zone/THRM/polling_frequency
1078 /proc/acpi/thermal_zone/THRM/state
1080 /proc/acpi/thermal_zone/THRM/temperature
1082 /proc/acpi/thermal_zone/THRM/trip_points
1084 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1087 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1088 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1090 int open_acpi_temperature(const char *name)
1096 if (name == NULL || strcmp(name, "*") == 0) {
1098 if (!get_first_file_in_a_directory
1099 (ACPI_THERMAL_DIR, buf, &rep))
1104 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1106 fd = open(path, O_RDONLY);
1108 ERR("can't open '%s': %s", path, strerror(errno));
1113 static double last_acpi_temp;
1114 static double last_acpi_temp_time;
1116 double get_acpi_temperature(int fd)
1121 /* don't update acpi temperature too often */
1122 if (current_update_time - last_acpi_temp_time < 11.32) {
1123 return last_acpi_temp;
1125 last_acpi_temp_time = current_update_time;
1127 /* seek to beginning */
1128 lseek(fd, 0, SEEK_SET);
1134 n = read(fd, buf, 255);
1136 ERR("can't read fd %d: %s", fd, strerror(errno));
1139 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1143 return last_acpi_temp;
1147 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1149 design capacity: 4400 mAh
1150 last full capacity: 4064 mAh
1151 battery technology: rechargeable
1152 design voltage: 14800 mV
1153 design capacity warning: 300 mAh
1154 design capacity low: 200 mAh
1155 capacity granularity 1: 32 mAh
1156 capacity granularity 2: 32 mAh
1158 serial number: 16922
1164 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1167 charging state: unknown
1169 remaining capacity: 4064 mAh
1170 present voltage: 16608 mV
1174 2213<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1175 2213<@jupet kellari ö> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1176 2213<@jupet kellari ö> (-1 ollee ei akkua kiinni, koska akku on pöydällä)
1177 2214<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1178 2214<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1180 2238<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1181 2239<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1183 2240<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori päällä
1184 2241<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori päällä mutta ilman verkkovirtaa
1187 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1188 #define APM_PATH "/proc/apm"
1190 static FILE *acpi_bat_fp;
1191 static FILE *apm_bat_fp;
1193 static int acpi_last_full;
1195 static char last_battery_str[64];
1197 static double last_battery_time;
1199 void get_battery_stuff(char *buf, unsigned int n, const char *bat)
1201 static int rep, rep2;
1202 char acpi_path[128];
1203 char tmp_battery[64], tmp_time_left[64];
1204 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1206 /* don't update battery too often */
1207 if (current_update_time - last_battery_time < 29.5) {
1208 snprintf(buf, n, "%s", last_battery_str);
1211 last_battery_time = current_update_time;
1213 /* first try ACPI */
1215 if (acpi_bat_fp == NULL && apm_bat_fp == NULL)
1216 acpi_bat_fp = open_file(acpi_path, &rep);
1218 if (acpi_bat_fp != NULL) {
1219 int present_rate = -1;
1220 int remaining_capacity = -1;
1221 char charging_state[64];
1224 /* read last full capacity if it's zero */
1225 if (acpi_last_full == 0) {
1230 ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1231 fp = open_file(path, &rep);
1235 if (fgets(b, 256, fp) == NULL)
1237 if (sscanf(b, "last full capacity: %d", &acpi_last_full) != 0) {
1246 fseek(acpi_bat_fp, 0, SEEK_SET);
1248 strcpy(charging_state, "unknown");
1250 while (!feof(acpi_bat_fp)) {
1252 if (fgets(buf, 256, acpi_bat_fp) == NULL)
1255 /* let's just hope units are ok */
1256 if (strncmp (buf, "present:", 8) == 0)
1257 sscanf(buf, "present: %4s", present);
1258 else if (strncmp (buf, "charging state:", 15) == 0)
1259 sscanf(buf, "charging state: %63s", charging_state);
1260 else if (strncmp (buf, "present rate:", 13) == 0)
1261 sscanf(buf, "present rate: %d", &present_rate);
1262 else if (strncmp(buf, "remaining capacity:", 19) == 0)
1263 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1266 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1267 if (remaining_capacity > acpi_last_full)
1268 acpi_last_full = remaining_capacity; /* normalize to 100% */
1271 if (strcmp(present, "no") == 0) {
1272 strncpy(last_battery_str, "not present", 64);
1275 else if (strcmp(charging_state, "charging") == 0) {
1276 if (acpi_last_full != 0 && present_rate > 0) {
1277 /* e.g. charging 75% */
1278 snprintf(tmp_battery, sizeof(tmp_battery)-1, "charging %i%%",
1279 (int) ((remaining_capacity * 100) / acpi_last_full));
1281 format_seconds(tmp_time_left, sizeof(tmp_time_left)-1,
1282 (long) (((acpi_last_full - remaining_capacity) * 3600) /
1284 /* e.g. charging 75% (2h 37m) */
1285 snprintf (last_battery_str, sizeof(last_battery_str)-1,
1286 "%s (%s)", tmp_battery, tmp_time_left);
1288 } else if (acpi_last_full != 0 && present_rate <= 0) {
1289 snprintf(last_battery_str, sizeof(last_battery_str)-1, "charging %d%%",
1290 (int) ((remaining_capacity * 100) / acpi_last_full));
1292 strncpy(last_battery_str, "charging", sizeof(last_battery_str)-1);
1296 else if (strncmp(charging_state, "discharging", 64) == 0) {
1297 if (present_rate > 0) {
1298 /* e.g. discharging 35% */
1299 snprintf(tmp_battery, sizeof(tmp_battery)-1, "discharging %i%%",
1300 (int) ((remaining_capacity * 100) / acpi_last_full));
1302 format_seconds(tmp_time_left, sizeof(tmp_time_left)-1,
1303 (long) ((remaining_capacity * 3600) / present_rate));
1304 /* e.g. discharging 35% (1h 12m) */
1305 snprintf (last_battery_str, sizeof(last_battery_str)-1,
1306 "%s (%s)", tmp_battery, tmp_time_left);
1307 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1308 snprintf(last_battery_str, sizeof(last_battery_str)-1, "full");
1310 snprintf(last_battery_str, sizeof(last_battery_str)-1,
1312 (int) ((remaining_capacity * 100) / acpi_last_full));
1316 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1317 else if (strncmp(charging_state, "charged", 64) == 0) {
1318 strcpy(last_battery_str, "charged");
1320 /* unknown, probably full / AC */
1322 if (acpi_last_full != 0
1323 && remaining_capacity != acpi_last_full)
1324 snprintf(last_battery_str, 64, "unknown %d%%",
1325 (int) ((remaining_capacity * 100) / acpi_last_full));
1327 strncpy(last_battery_str, "AC", 64);
1331 if (apm_bat_fp == NULL)
1332 apm_bat_fp = open_file(APM_PATH, &rep2);
1334 if (apm_bat_fp != NULL) {
1335 int ac, status, flag, life;
1338 "%*s %*s %*x %x %x %x %d%%",
1339 &ac, &status, &flag, &life);
1342 /* could check now that there is ac */
1343 snprintf(last_battery_str, 64, "AC");
1344 } else if (ac && life != 100) { /* could check that status==3 here? */
1345 snprintf(last_battery_str, 64,
1346 "charging %d%%", life);
1348 snprintf(last_battery_str, 64, "%d%%",
1352 /* it seemed to buffer it so file must be closed (or could use syscalls
1353 * directly but I don't feel like coding it now) */
1359 snprintf(buf, n, "%s", last_battery_str);
1362 /* On Apple powerbook and ibook:
1363 $ cat /proc/pmu/battery_0
1370 $ cat /proc/pmu/info
1371 PMU driver version : 2
1372 PMU firmware version : 0c
1377 /* defines as in <linux/pmu.h> */
1378 #define PMU_BATT_PRESENT 0x00000001
1379 #define PMU_BATT_CHARGING 0x00000002
1381 static FILE* pmu_battery_fp;
1382 static FILE* pmu_info_fp;
1383 static char pb_battery_info[3][32];
1384 static double pb_battery_info_update;
1386 #define PMU_PATH "/proc/pmu"
1387 void get_powerbook_batt_info(char *buf, size_t n, int i)
1390 const char* batt_path = PMU_PATH "/battery_0";
1391 const char* info_path = PMU_PATH "/info";
1392 int flags, charge, max_charge, ac = -1;
1395 /* don't update battery too often */
1396 if (current_update_time - pb_battery_info_update < 29.5) {
1397 snprintf(buf, n, "%s", pb_battery_info[i]);
1400 pb_battery_info_update = current_update_time;
1402 if (pmu_battery_fp == NULL)
1403 pmu_battery_fp = open_file(batt_path, &rep);
1405 if (pmu_battery_fp != NULL) {
1406 rewind(pmu_battery_fp);
1407 while (!feof(pmu_battery_fp)) {
1409 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL)
1413 sscanf(buf, "flags : %8x", &flags);
1414 else if (buf[0] == 'c' && buf[1] == 'h')
1415 sscanf(buf, "charge : %d", &charge);
1416 else if (buf[0] == 'm')
1417 sscanf(buf, "max_charge : %d", &max_charge);
1418 else if (buf[0] == 't')
1419 sscanf(buf, "time rem. : %ld", &time);
1422 if (pmu_info_fp == NULL)
1423 pmu_info_fp = open_file(info_path, &rep);
1425 if (pmu_info_fp != NULL) {
1426 rewind(pmu_info_fp);
1427 while (!feof(pmu_info_fp)) {
1429 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL)
1432 sscanf(buf, "AC Power : %d", &ac);
1435 /* update status string */
1436 if ((ac && !(flags & PMU_BATT_PRESENT)))
1437 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
1438 else if (ac && (flags & PMU_BATT_PRESENT)
1439 && !(flags & PMU_BATT_CHARGING))
1440 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
1441 else if ((flags & PMU_BATT_PRESENT)
1442 && (flags & PMU_BATT_CHARGING))
1443 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
1445 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
1447 /* update percentage string */
1449 pb_battery_info[PB_BATT_PERCENT][0] = 0;
1451 snprintf(pb_battery_info[PB_BATT_PERCENT],
1452 sizeof(pb_battery_info[PB_BATT_PERCENT]),
1453 "%d%%", (charge * 100)/max_charge);
1455 /* update time string */
1456 if (time == 0) /* fully charged or battery not present */
1457 pb_battery_info[PB_BATT_TIME][0] = 0;
1458 else if (time < 60*60) /* don't show secs */
1459 format_seconds_short(pb_battery_info[PB_BATT_TIME],
1460 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1462 format_seconds(pb_battery_info[PB_BATT_TIME],
1463 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1465 snprintf(buf, n, "%s", pb_battery_info[i]);
1470 show_nice_processes = 1;
1471 process_find_top(info.cpu, info.memu);
1472 info.first_process = get_first_process();
1477 * The following ifdefs were adapted from gkrellm
1479 #include <linux/major.h>
1481 #if ! defined (MD_MAJOR)
1485 #if !defined(LVM_BLK_MAJOR)
1486 #define LVM_BLK_MAJOR 58
1489 #if !defined(NBD_MAJOR)
1490 #define NBD_MAJOR 43
1493 void update_diskio()
1495 static unsigned int last = UINT_MAX;
1500 unsigned int current = 0;
1501 unsigned int reads, writes = 0;
1505 fp = fopen("/proc/diskstats", "r");
1507 fseek(fp, 0, SEEK_SET);
1510 /* read reads and writes from all disks (minor = 0), including
1511 * cd-roms and floppies, and summ them up
1515 fgets(buf, 512, fp);
1516 col_count = sscanf(buf, "%u %u %*s %*u %*u %u %*u %*u %*u %u",
1517 &major, &minor, &reads, &writes);
1518 /* ignore subdevices (they have only 3 matching entries in their line)
1519 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
1521 * XXX ignore devices which are part of a SW RAID (MD_MAJOR)
1523 if (col_count > 3 &&
1524 major != LVM_BLK_MAJOR && major != NBD_MAJOR &&
1525 major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
1526 current += reads + writes;
1530 /* since the values in /proc/diststats are absolute, we have
1531 * to substract our last reading. The numbers stand for
1532 * "sectors read", and we therefore have to divide by two to
1534 int tot = ((double)(current-last)/2);
1535 if (last > current) {
1536 /* we hit this either if it's the very first time we
1537 * run this, or when /proc/diskstats overflows; while
1538 * 0 is not correct, it's at least not way off */
1546 /* Here come the IBM ACPI-specific things. For reference, see
1547 http://ibm-acpi.sourceforge.net/README
1548 If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
1564 The content of these files is described in detail in the aforementioned
1565 README - some of them also in the following functions accessing them.
1566 Peter Tarjan (ptarjan@citromail.hu)
1569 #define IBM_ACPI_DIR "/proc/acpi/ibm"
1571 void get_ibm_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1573 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
1574 /proc/acpi/ibm/fan looks like this (3 lines):
1577 commands: enable, disable
1578 Peter Tarjan (ptarjan@citromail.hu)
1581 if ( !p_client_buffer || client_buffer_size <= 0 )
1585 unsigned int speed=0;
1587 snprintf(fan, 127, "%s/fan",IBM_ACPI_DIR);
1589 fp = fopen(fan, "r");
1595 if (fgets(line, 255, fp) == NULL) break;
1596 if (sscanf(line, "speed: %d", &speed)) break;
1601 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", fan, strerror(errno));
1605 snprintf( p_client_buffer, client_buffer_size, "%d", speed );
1610 static double last_ibm_acpi_temp_time;
1611 void get_ibm_acpi_temps()
1613 /* get the measured temperatures from the temperature sensors
1614 on IBM/Lenovo laptops running the ibm acpi.
1615 There are 8 values in /proc/acpi/ibm/thermal, and according to
1616 http://ibm-acpi.sourceforge.net/README
1617 these mean the following (at least on an IBM R51...)
1618 0: CPU (also on the T series laptops)
1619 1: Mini PCI Module (?)
1621 3: GPU (also on the T series laptops)
1626 I'm not too sure about those with the question mark, but the values I'm
1627 reading from *my* thermal file (on a T42p) look realistic for the
1628 hdd and the battery.
1629 #5 and #7 are always -128.
1630 /proc/acpi/ibm/thermal looks like this (1 line):
1631 temperatures: 41 43 31 46 33 -128 29 -128
1632 Peter Tarjan (ptarjan@citromail.hu)
1635 /* don't update too often */
1636 if (current_update_time - last_ibm_acpi_temp_time < 10.00)
1640 last_ibm_acpi_temp_time = current_update_time;
1642 /* if ( !p_client_buffer || client_buffer_size <= 0 )
1648 snprintf(thermal, 127, "%s/thermal",IBM_ACPI_DIR);
1649 fp = fopen(thermal, "r");
1656 if (fgets(line, 255, fp) == NULL) break;
1657 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
1658 &ibm_acpi.temps[0], &ibm_acpi.temps[1],
1659 &ibm_acpi.temps[2], &ibm_acpi.temps[3],
1660 &ibm_acpi.temps[4], &ibm_acpi.temps[5],
1661 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) break;
1666 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", thermal, strerror(errno));
1674 void get_ibm_acpi_volume( char * p_client_buffer, size_t client_buffer_size )
1677 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
1678 "Volume" here is none of the mixer volumes, but a "master of masters"
1679 volume adjusted by the IBM volume keys.
1680 /proc/acpi/ibm/fan looks like this (4 lines):
1683 commands: up, down, mute
1684 commands: level <level> (<level> is 0-15)
1685 Peter Tarjan (ptarjan@citromail.hu)
1688 if ( !p_client_buffer || client_buffer_size <= 0 )
1694 snprintf(volume, 127, "%s/volume",IBM_ACPI_DIR);
1695 unsigned int vol=-1;
1698 fp = fopen(volume, "r");
1704 if (fgets(line, 255, fp) == NULL) break;
1705 if (sscanf(line, "level: %d", &vol)) continue;
1706 if (sscanf(line, "mute: %s", mute)) break;
1711 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", volume, strerror(errno));
1716 if (strcmp(mute, "on")==0)
1718 snprintf( p_client_buffer, client_buffer_size, "%s", "mute" );
1723 snprintf( p_client_buffer, client_buffer_size, "%d", vol );
1729 /*static FILE *fp=NULL;*/
1731 void get_ibm_acpi_brightness(char * p_client_buffer, size_t client_buffer_size)
1733 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
1734 /proc/acpi/ibm/brightness looks like this (3 lines):
1737 commands: level <level> (<level> is 0-7)
1738 Peter Tarjan (ptarjan@citromail.hu)
1741 if ( !p_client_buffer || client_buffer_size <= 0 )
1745 unsigned int brightness=0;
1747 snprintf(filename, 127, "%s/brightness",IBM_ACPI_DIR);
1749 fp = fopen(filename, "r");
1755 if (fgets(line, 255, fp) == NULL) break;
1756 if (sscanf(line, "level: %d", &brightness)) break;
1761 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", filename, strerror(errno));
1766 snprintf( p_client_buffer, client_buffer_size, "%d", brightness );
1771 void update_entropy (void)
1774 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
1775 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
1778 info.entropy.entropy_avail=0;
1779 info.entropy.poolsize=0;
1781 if ((fp1 = open_file (entropy_avail, &rep))==NULL)
1784 if ((fp2 = open_file (entropy_poolsize, &rep))==NULL)
1790 fscanf (fp1, "%u", &info.entropy.entropy_avail);
1791 fscanf (fp2, "%u", &info.entropy.poolsize);