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 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1205 /* don't update battery too often */
1206 if (current_update_time - last_battery_time < 29.5) {
1207 snprintf(buf, n, "%s", last_battery_str);
1210 last_battery_time = current_update_time;
1212 /* first try ACPI */
1214 if (acpi_bat_fp == NULL && apm_bat_fp == NULL)
1215 acpi_bat_fp = open_file(acpi_path, &rep);
1217 if (acpi_bat_fp != NULL) {
1218 int present_rate = -1;
1219 int remaining_capacity = -1;
1220 char charging_state[64];
1223 /* read last full capacity if it's zero */
1224 if (acpi_last_full == 0) {
1229 ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1230 fp = open_file(path, &rep);
1234 if (fgets(b, 256, fp) == NULL)
1236 if (sscanf(b, "last full capacity: %d", &acpi_last_full) != 0) {
1245 fseek(acpi_bat_fp, 0, SEEK_SET);
1247 strcpy(charging_state, "unknown");
1249 while (!feof(acpi_bat_fp)) {
1251 if (fgets(buf, 256, acpi_bat_fp) == NULL)
1254 /* let's just hope units are ok */
1255 if (strncmp (buf, "present:", 8) == 0)
1256 sscanf(buf, "present: %4s", present);
1257 else if (strncmp (buf, "charging state:", 15) == 0)
1258 sscanf(buf, "charging state: %63s", charging_state);
1259 else if (strncmp (buf, "present rate:", 13) == 0)
1260 sscanf(buf, "present rate: %d", &present_rate);
1261 else if (strncmp(buf, "remaining capacity:", 19) == 0)
1262 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1266 if (strcmp(present, "no") == 0) {
1267 strncpy(last_battery_str, "not present", 64);
1270 else if (strcmp(charging_state, "charging") == 0) {
1271 if (acpi_last_full != 0 && present_rate > 0) {
1272 snprintf(last_battery_str, 63, "charging %i%% ", (int) (remaining_capacity / acpi_last_full) * 100);
1273 format_seconds(last_battery_str + 14,
1276 remaining_capacity) * 60 *
1278 } else if (acpi_last_full != 0
1279 && present_rate <= 0) {
1280 snprintf(last_battery_str, 64, "charging %d%%",
1281 remaining_capacity * 100 /
1284 strncpy(last_battery_str, "charging", 63);
1288 else if (strncmp(charging_state, "discharging", 64) == 0) {
1289 if (present_rate > 0) {
1290 snprintf(last_battery_str, 63, "discharging %i%% ", (int)(remaining_capacity / acpi_last_full) * 100);
1291 format_seconds(last_battery_str + 17, 63 - 17,
1292 (remaining_capacity * 60 *
1293 60) / present_rate);
1294 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1295 snprintf(last_battery_str, 64, "full");
1297 snprintf(last_battery_str, 64,
1299 remaining_capacity * 100 /
1304 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1305 else if (strncmp(charging_state, "charged", 64) == 0) {
1306 strcpy(last_battery_str, "charged");
1308 /* unknown, probably full / AC */
1310 if (acpi_last_full != 0
1311 && remaining_capacity != acpi_last_full)
1312 snprintf(last_battery_str, 64, "unknown %d%%",
1313 remaining_capacity * 100 /
1316 strncpy(last_battery_str, "AC", 64);
1320 if (apm_bat_fp == NULL)
1321 apm_bat_fp = open_file(APM_PATH, &rep2);
1323 if (apm_bat_fp != NULL) {
1324 int ac, status, flag, life;
1327 "%*s %*s %*x %x %x %x %d%%",
1328 &ac, &status, &flag, &life);
1331 /* could check now that there is ac */
1332 snprintf(last_battery_str, 64, "AC");
1333 } else if (ac && life != 100) { /* could check that status==3 here? */
1334 snprintf(last_battery_str, 64,
1335 "charging %d%%", life);
1337 snprintf(last_battery_str, 64, "%d%%",
1341 /* it seemed to buffer it so file must be closed (or could use syscalls
1342 * directly but I don't feel like coding it now) */
1348 snprintf(buf, n, "%s", last_battery_str);
1351 /* On Apple powerbook and ibook:
1352 $ cat /proc/pmu/battery_0
1359 $ cat /proc/pmu/info
1360 PMU driver version : 2
1361 PMU firmware version : 0c
1366 /* defines as in <linux/pmu.h> */
1367 #define PMU_BATT_PRESENT 0x00000001
1368 #define PMU_BATT_CHARGING 0x00000002
1370 static FILE* pmu_battery_fp;
1371 static FILE* pmu_info_fp;
1372 static char pb_battery_info[3][32];
1373 static double pb_battery_info_update;
1375 #define PMU_PATH "/proc/pmu"
1376 void get_powerbook_batt_info(char *buf, size_t n, int i)
1379 const char* batt_path = PMU_PATH "/battery_0";
1380 const char* info_path = PMU_PATH "/info";
1381 int flags, charge, max_charge, ac = -1;
1384 /* don't update battery too often */
1385 if (current_update_time - pb_battery_info_update < 29.5) {
1386 snprintf(buf, n, "%s", pb_battery_info[i]);
1389 pb_battery_info_update = current_update_time;
1391 if (pmu_battery_fp == NULL)
1392 pmu_battery_fp = open_file(batt_path, &rep);
1394 if (pmu_battery_fp != NULL) {
1395 rewind(pmu_battery_fp);
1396 while (!feof(pmu_battery_fp)) {
1398 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL)
1402 sscanf(buf, "flags : %8x", &flags);
1403 else if (buf[0] == 'c' && buf[1] == 'h')
1404 sscanf(buf, "charge : %d", &charge);
1405 else if (buf[0] == 'm')
1406 sscanf(buf, "max_charge : %d", &max_charge);
1407 else if (buf[0] == 't')
1408 sscanf(buf, "time rem. : %ld", &time);
1411 if (pmu_info_fp == NULL)
1412 pmu_info_fp = open_file(info_path, &rep);
1414 if (pmu_info_fp != NULL) {
1415 rewind(pmu_info_fp);
1416 while (!feof(pmu_info_fp)) {
1418 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL)
1421 sscanf(buf, "AC Power : %d", &ac);
1424 /* update status string */
1425 if ((ac && !(flags & PMU_BATT_PRESENT)))
1426 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
1427 else if (ac && (flags & PMU_BATT_PRESENT)
1428 && !(flags & PMU_BATT_CHARGING))
1429 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
1430 else if ((flags & PMU_BATT_PRESENT)
1431 && (flags & PMU_BATT_CHARGING))
1432 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
1434 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
1436 /* update percentage string */
1438 pb_battery_info[PB_BATT_PERCENT][0] = 0;
1440 snprintf(pb_battery_info[PB_BATT_PERCENT],
1441 sizeof(pb_battery_info[PB_BATT_PERCENT]),
1442 "%d%%", (charge * 100)/max_charge);
1444 /* update time string */
1445 if (time == 0) /* fully charged or battery not present */
1446 pb_battery_info[PB_BATT_TIME][0] = 0;
1447 else if (time < 60*60) /* don't show secs */
1448 format_seconds_short(pb_battery_info[PB_BATT_TIME],
1449 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1451 format_seconds(pb_battery_info[PB_BATT_TIME],
1452 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1454 snprintf(buf, n, "%s", pb_battery_info[i]);
1459 show_nice_processes = 1;
1460 process_find_top(info.cpu, info.memu);
1461 info.first_process = get_first_process();
1466 * The following ifdefs were adapted from gkrellm
1468 #include <linux/major.h>
1470 #if ! defined (MD_MAJOR)
1474 #if !defined(LVM_BLK_MAJOR)
1475 #define LVM_BLK_MAJOR 58
1478 #if !defined(NBD_MAJOR)
1479 #define NBD_MAJOR 43
1482 void update_diskio()
1484 static unsigned int last = UINT_MAX;
1489 unsigned int current = 0;
1490 unsigned int reads, writes = 0;
1494 fp = fopen("/proc/diskstats", "r");
1496 fseek(fp, 0, SEEK_SET);
1499 /* read reads and writes from all disks (minor = 0), including
1500 * cd-roms and floppies, and summ them up
1504 fgets(buf, 512, fp);
1505 col_count = sscanf(buf, "%u %u %*s %*u %*u %u %*u %*u %*u %u",
1506 &major, &minor, &reads, &writes);
1507 /* ignore subdevices (they have only 3 matching entries in their line)
1508 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
1510 * XXX ignore devices which are part of a SW RAID (MD_MAJOR)
1512 if (col_count > 3 &&
1513 major != LVM_BLK_MAJOR && major != NBD_MAJOR &&
1514 major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
1515 current += reads + writes;
1519 /* since the values in /proc/diststats are absolute, we have
1520 * to substract our last reading. The numbers stand for
1521 * "sectors read", and we therefore have to divide by two to
1523 int tot = ((double)(current-last)/2);
1524 if (last > current) {
1525 /* we hit this either if it's the very first time we
1526 * run this, or when /proc/diskstats overflows; while
1527 * 0 is not correct, it's at least not way off */
1535 /* Here come the IBM ACPI-specific things. For reference, see
1536 http://ibm-acpi.sourceforge.net/README
1537 If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
1553 The content of these files is described in detail in the aforementioned
1554 README - some of them also in the following functions accessing them.
1555 Peter Tarjan (ptarjan@citromail.hu)
1558 #define IBM_ACPI_DIR "/proc/acpi/ibm"
1560 void get_ibm_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1562 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
1563 /proc/acpi/ibm/fan looks like this (3 lines):
1566 commands: enable, disable
1567 Peter Tarjan (ptarjan@citromail.hu)
1570 if ( !p_client_buffer || client_buffer_size <= 0 )
1574 unsigned int speed=0;
1576 snprintf(fan, 127, "%s/fan",IBM_ACPI_DIR);
1578 fp = fopen(fan, "r");
1584 if (fgets(line, 255, fp) == NULL) break;
1585 if (sscanf(line, "speed: %d", &speed)) break;
1590 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", fan, strerror(errno));
1594 snprintf( p_client_buffer, client_buffer_size, "%d", speed );
1599 static double last_ibm_acpi_temp_time;
1600 void get_ibm_acpi_temps()
1602 /* get the measured temperatures from the temperature sensors
1603 on IBM/Lenovo laptops running the ibm acpi.
1604 There are 8 values in /proc/acpi/ibm/thermal, and according to
1605 http://ibm-acpi.sourceforge.net/README
1606 these mean the following (at least on an IBM R51...)
1607 0: CPU (also on the T series laptops)
1608 1: Mini PCI Module (?)
1610 3: GPU (also on the T series laptops)
1615 I'm not too sure about those with the question mark, but the values I'm
1616 reading from *my* thermal file (on a T42p) look realistic for the
1617 hdd and the battery.
1618 #5 and #7 are always -128.
1619 /proc/acpi/ibm/thermal looks like this (1 line):
1620 temperatures: 41 43 31 46 33 -128 29 -128
1621 Peter Tarjan (ptarjan@citromail.hu)
1624 /* don't update too often */
1625 if (current_update_time - last_ibm_acpi_temp_time < 10.00)
1629 last_ibm_acpi_temp_time = current_update_time;
1631 /* if ( !p_client_buffer || client_buffer_size <= 0 )
1637 snprintf(thermal, 127, "%s/thermal",IBM_ACPI_DIR);
1638 fp = fopen(thermal, "r");
1645 if (fgets(line, 255, fp) == NULL) break;
1646 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
1647 &ibm_acpi.temps[0], &ibm_acpi.temps[1],
1648 &ibm_acpi.temps[2], &ibm_acpi.temps[3],
1649 &ibm_acpi.temps[4], &ibm_acpi.temps[5],
1650 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) break;
1655 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", thermal, strerror(errno));
1663 void get_ibm_acpi_volume( char * p_client_buffer, size_t client_buffer_size )
1666 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
1667 "Volume" here is none of the mixer volumes, but a "master of masters"
1668 volume adjusted by the IBM volume keys.
1669 /proc/acpi/ibm/fan looks like this (4 lines):
1672 commands: up, down, mute
1673 commands: level <level> (<level> is 0-15)
1674 Peter Tarjan (ptarjan@citromail.hu)
1677 if ( !p_client_buffer || client_buffer_size <= 0 )
1683 snprintf(volume, 127, "%s/volume",IBM_ACPI_DIR);
1684 unsigned int vol=-1;
1687 fp = fopen(volume, "r");
1693 if (fgets(line, 255, fp) == NULL) break;
1694 if (sscanf(line, "level: %d", &vol)) continue;
1695 if (sscanf(line, "mute: %s", mute)) break;
1700 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", volume, strerror(errno));
1705 if (strcmp(mute, "on")==0)
1707 snprintf( p_client_buffer, client_buffer_size, "%s", "mute" );
1712 snprintf( p_client_buffer, client_buffer_size, "%d", vol );
1718 /*static FILE *fp=NULL;*/
1720 void get_ibm_acpi_brightness(char * p_client_buffer, size_t client_buffer_size)
1722 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
1723 /proc/acpi/ibm/brightness looks like this (3 lines):
1726 commands: level <level> (<level> is 0-7)
1727 Peter Tarjan (ptarjan@citromail.hu)
1730 if ( !p_client_buffer || client_buffer_size <= 0 )
1734 unsigned int brightness=0;
1736 snprintf(filename, 127, "%s/brightness",IBM_ACPI_DIR);
1738 fp = fopen(filename, "r");
1744 if (fgets(line, 255, fp) == NULL) break;
1745 if (sscanf(line, "level: %d", &brightness)) break;
1750 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", filename, strerror(errno));
1755 snprintf( p_client_buffer, client_buffer_size, "%d", brightness );