1 /* Conky, a system monitor, based on torsmo
3 * Any original torsmo code is licensed under the BSD license
5 * All code written since the fork of torsmo is licensed under the GPL
7 * Please see COPYING for details
9 * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
10 * Copyright (c) 2007 Toni Spets
11 * Copyright (c) 2005-2007 Brenden Matthews, Philip Kovacs, et. al.
13 * All rights reserved.
15 * This program is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation, either version 3 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program. If not, see <http://www.gnu.org/licenses/>.
37 #include <sys/types.h>
38 #include <sys/sysinfo.h>
40 #ifndef HAVE_CLOCK_GETTIME
45 // #include <assert.h>
49 #include <sys/ioctl.h>
50 #include <sys/socket.h>
51 #include <netinet/in.h>
52 #include <linux/sockios.h>
60 #define SHORTSTAT_TEMPL "%*s %llu %llu %llu"
61 #define LONGSTAT_TEMPL "%*s %llu %llu %llu "
63 static int show_nice_processes;
65 /* This flag tells the linux routines to use the /proc system where possible,
66 * even if other api's are available, e.g. sysinfo() or getloadavg().
67 * the reason for this is to allow for /proc-based distributed monitoring.
68 * using a flag in this manner creates less confusing code. */
69 static int prefer_proc = 0;
79 struct sysinfo s_info;
82 info.uptime = (double) s_info.uptime;
89 if (!(fp = open_file("/proc/uptime", &rep))) {
93 fscanf(fp, "%lf", &info.uptime);
96 info.mask |= (1 << INFO_UPTIME);
99 int check_mount(char *s)
102 FILE *mtab = fopen("/etc/mtab", "r");
105 char buf1[256], buf2[128];
107 while (fgets(buf1, 256, mtab)) {
108 sscanf(buf1, "%*s %128s", buf2);
109 if (!strcmp(s, buf2)) {
116 ERR("Could not open mtab");
121 /* these things are also in sysinfo except Buffers:
122 * (that's why I'm reading them from proc) */
124 void update_meminfo()
129 /* unsigned int a; */
132 info.mem = info.memmax = info.swap = info.swapmax = info.bufmem =
133 info.buffers = info.cached = 0;
135 if (!(meminfo_fp = open_file("/proc/meminfo", &rep))) {
139 while (!feof(meminfo_fp)) {
140 if (fgets(buf, 255, meminfo_fp) == NULL) {
144 if (strncmp(buf, "MemTotal:", 9) == 0) {
145 sscanf(buf, "%*s %Lu", &info.memmax);
146 } else if (strncmp(buf, "MemFree:", 8) == 0) {
147 sscanf(buf, "%*s %Lu", &info.mem);
148 } else if (strncmp(buf, "SwapTotal:", 10) == 0) {
149 sscanf(buf, "%*s %Lu", &info.swapmax);
150 } else if (strncmp(buf, "SwapFree:", 9) == 0) {
151 sscanf(buf, "%*s %Lu", &info.swap);
152 } else if (strncmp(buf, "Buffers:", 8) == 0) {
153 sscanf(buf, "%*s %Lu", &info.buffers);
154 } else if (strncmp(buf, "Cached:", 7) == 0) {
155 sscanf(buf, "%*s %Lu", &info.cached);
159 info.mem = info.memmax - info.mem;
160 info.swap = info.swapmax - info.swap;
162 info.bufmem = info.cached + info.buffers;
164 info.mask |= (1 << INFO_MEM) | (1 << INFO_BUFFERS);
169 inline void update_net_stats()
174 // FIXME: arbitrary size chosen to keep code simple.
176 unsigned int curtmp1, curtmp2;
183 // wireless info variables
184 int skfd, has_bitrate = 0;
185 struct wireless_info *winfo;
190 delta = current_update_time - last_update_time;
191 if (delta <= 0.0001) {
195 /* open file and ignore first two lines */
196 if (!(net_dev_fp = open_file("/proc/net/dev", &rep))) {
201 fgets(buf, 255, net_dev_fp); /* garbage */
202 fgets(buf, 255, net_dev_fp); /* garbage (field names) */
204 /* read each interface */
205 for (i2 = 0; i2 < 16; i2++) {
208 long long r, t, last_recv, last_trans;
210 if (fgets(buf, 255, net_dev_fp) == NULL) {
214 while (isspace((int) *p)) {
220 while (*p && *p != ':') {
229 ns = get_net_stat(s);
231 memset(&(ns->addr.sa_data), 0, 14);
232 last_recv = ns->recv;
233 last_trans = ns->trans;
235 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
236 sscanf(p, "%Ld %*d %*d %*d %*d %*d %*d %*d %Ld",
239 /* if recv or trans is less than last time, an overflow happened */
240 if (r < ns->last_read_recv) {
243 ns->recv += (r - ns->last_read_recv);
245 ns->last_read_recv = r;
247 if (t < ns->last_read_trans) {
250 ns->trans += (t - ns->last_read_trans);
252 ns->last_read_trans = t;
254 /*** ip addr patch ***/
255 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
257 conf.ifc_buf = malloc(sizeof(struct ifreq) * 16);
259 conf.ifc_len = sizeof(struct ifreq) * 16;
261 ioctl((long) i, SIOCGIFCONF, &conf);
263 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
267 ((struct ifreq *) conf.ifc_buf)[k].ifr_ifrn.ifrn_name);
268 ns->addr = ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.ifru_addr;
275 /*** end ip addr patch ***/
277 /* calculate speeds */
278 ns->net_rec[0] = (ns->recv - last_recv) / delta;
279 ns->net_trans[0] = (ns->trans - last_trans) / delta;
283 for (i = 0; (unsigned) i < info.net_avg_samples; i++) {
284 curtmp1 += ns->net_rec[i];
285 curtmp2 += ns->net_trans[i];
293 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
294 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
295 if (info.net_avg_samples > 1) {
296 for (i = info.net_avg_samples; i > 1; i--) {
297 ns->net_rec[i - 1] = ns->net_rec[i - 2];
298 ns->net_trans[i - 1] = ns->net_trans[i - 2];
303 /* update wireless info */
304 winfo = malloc(sizeof(struct wireless_info));
305 memset(winfo, 0, sizeof(struct wireless_info));
307 skfd = iw_sockets_open();
308 if (iw_get_basic_config(skfd, s, &(winfo->b)) > -1) {
310 // set present winfo variables
311 if (iw_get_stats(skfd, s, &(winfo->stats),
312 &winfo->range, winfo->has_range) >= 0) {
313 winfo->has_stats = 1;
315 if (iw_get_range_info(skfd, s, &(winfo->range)) >= 0) {
316 winfo->has_range = 1;
318 if (iw_get_ext(skfd, s, SIOCGIWAP, &wrq) >= 0) {
319 winfo->has_ap_addr = 1;
320 memcpy(&(winfo->ap_addr), &(wrq.u.ap_addr), sizeof(sockaddr));
324 if (iw_get_ext(skfd, s, SIOCGIWRATE, &wrq) >= 0) {
325 memcpy(&(winfo->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
326 iw_print_bitrate(ns->bitrate, 16, winfo->bitrate.value);
331 if (winfo->has_range && winfo->has_stats
332 && ((winfo->stats.qual.level != 0)
333 || (winfo->stats.qual.updated & IW_QUAL_DBM))) {
334 if (!(winfo->stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
335 ns->link_qual = winfo->stats.qual.qual;
336 ns->link_qual_max = winfo->range.max_qual.qual;
341 if (winfo->has_ap_addr) {
342 iw_sawap_ntop(&winfo->ap_addr, ns->ap);
346 if (winfo->b.has_essid) {
347 if (winfo->b.essid_on) {
348 snprintf(ns->essid, 32, "%s", winfo->b.essid);
350 snprintf(ns->essid, 32, "off/any");
354 snprintf(ns->mode, 16, "%s", iw_operation_mode[winfo->b.mode]);
356 iw_sockets_close(skfd);
363 info.mask |= (1 << INFO_NET);
368 void update_total_processes()
372 struct sysinfo s_info;
375 info.procs = s_info.procs;
382 if (!(fp = open_file("/proc/loadavg", &rep))) {
386 fscanf(fp, "%*f %*f %*f %*d/%hd", &info.procs);
389 info.mask |= (1 << INFO_PROCS);
392 #define CPU_SAMPLE_COUNT 15
394 unsigned long long cpu_user;
395 unsigned long long cpu_system;
396 unsigned long long cpu_nice;
397 unsigned long long cpu_idle;
398 unsigned long long cpu_iowait;
399 unsigned long long cpu_irq;
400 unsigned long long cpu_softirq;
401 unsigned long long cpu_steal;
402 unsigned long long cpu_total;
403 unsigned long long cpu_active_total;
404 unsigned long long cpu_last_total;
405 unsigned long long cpu_last_active_total;
406 double cpu_val[CPU_SAMPLE_COUNT];
408 static short cpu_setup = 0;
410 /* Determine if this kernel gives us "extended" statistics information in
412 * Kernels around 2.5 and earlier only reported user, system, nice, and
413 * idle values in proc stat.
414 * Kernels around 2.6 and greater report these PLUS iowait, irq, softirq,
416 void determine_longstat(char *buf)
418 unsigned long long iowait = 0;
420 KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
421 /* scanf will either return -1 or 1 because there is only 1 assignment */
422 if (sscanf(buf, "%*s %*d %*d %*d %*d %llu", &iowait) > 0) {
423 KFLAG_SETON(KFLAG_IS_LONGSTAT);
432 if (info.cpu_usage) {
437 if (!(stat_fp = open_file("/proc/stat", &rep))) {
443 while (!feof(stat_fp)) {
444 if (fgets(buf, 255, stat_fp) == NULL) {
448 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
449 if (info.cpu_count == 0) {
450 determine_longstat(buf);
455 info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
460 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
461 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
463 inline static void update_stat()
467 static struct cpu_info *cpu = NULL;
472 char *stat_template = NULL;
473 unsigned int malloc_cpu_size = 0;
475 /* add check for !info.cpu_usage since that mem is freed on a SIGUSR1 */
476 if (!cpu_setup || !info.cpu_usage) {
481 if (!stat_template) {
483 KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT;
487 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
488 cpu = malloc(malloc_cpu_size);
489 memset(cpu, 0, malloc_cpu_size);
492 if (!(stat_fp = open_file("/proc/stat", &rep))) {
494 if (info.cpu_usage) {
495 memset(info.cpu_usage, 0, info.cpu_count * sizeof(float));
501 while (!feof(stat_fp)) {
502 if (fgets(buf, 255, stat_fp) == NULL) {
506 if (strncmp(buf, "procs_running ", 14) == 0) {
507 sscanf(buf, "%*s %hu", &info.run_procs);
508 info.mask |= (1 << INFO_RUN_PROCS);
509 } else if (strncmp(buf, "cpu", 3) == 0) {
510 index = isdigit(buf[3]) ? ((int) buf[3]) - 0x2F : 0;
511 sscanf(buf, stat_template, &(cpu[index].cpu_user),
512 &(cpu[index].cpu_nice), &(cpu[index].cpu_system),
513 &(cpu[index].cpu_idle), &(cpu[index].cpu_iowait),
514 &(cpu[index].cpu_irq), &(cpu[index].cpu_softirq),
515 &(cpu[index].cpu_steal));
517 cpu[index].cpu_total = cpu[index].cpu_user + cpu[index].cpu_nice +
518 cpu[index].cpu_system + cpu[index].cpu_idle +
519 cpu[index].cpu_iowait + cpu[index].cpu_irq +
520 cpu[index].cpu_softirq + cpu[index].cpu_steal;
522 cpu[index].cpu_active_total = cpu[index].cpu_total -
523 (cpu[index].cpu_idle + cpu[index].cpu_iowait);
524 info.mask |= (1 << INFO_CPU);
526 double delta = current_update_time - last_update_time;
528 if (delta <= 0.001) {
532 cpu[index].cpu_val[0] = (cpu[index].cpu_active_total -
533 cpu[index].cpu_last_active_total) /
534 (float) (cpu[index].cpu_total - cpu[index].cpu_last_total);
536 for (i = 0; i < info.cpu_avg_samples; i++) {
537 curtmp += cpu[index].cpu_val[i];
539 /* TESTING -- I've removed this, because I don't think it is right.
540 * You shouldn't divide by the cpu count here ...
541 * removing for testing */
543 info.cpu_usage[index] = curtmp / info.cpu_avg_samples /
546 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
548 /* TESTING -- this line replaces the prev. "suspect" if/else */
549 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
551 cpu[index].cpu_last_total = cpu[index].cpu_total;
552 cpu[index].cpu_last_active_total = cpu[index].cpu_active_total;
553 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
554 cpu[index].cpu_val[i] = cpu[index].cpu_val[i - 1];
561 void update_running_processes()
566 void update_cpu_usage()
571 void update_load_average()
573 #ifdef HAVE_GETLOADAVG
578 info.loadavg[0] = (float) v[0];
579 info.loadavg[1] = (float) v[1];
580 info.loadavg[2] = (float) v[2];
587 if (!(fp = open_file("/proc/loadavg", &rep))) {
588 info.loadavg[0] = info.loadavg[1] = info.loadavg[2] = 0.0;
591 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1],
595 info.mask |= (1 << INFO_LOADAVG);
598 #define PROC_I8K "/proc/i8k"
599 #define I8K_DELIM " "
600 static char *i8k_procbuf = NULL;
606 i8k_procbuf = (char *) malloc(128 * sizeof(char));
608 if ((fp = fopen(PROC_I8K, "r")) == NULL) {
609 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel "
610 "driver is loaded...");
613 memset(&i8k_procbuf[0], 0, 128);
614 if (fread(&i8k_procbuf[0], sizeof(char), 128, fp) == 0) {
615 ERR("something wrong with /proc/i8k...");
620 i8k.version = strtok(&i8k_procbuf[0], I8K_DELIM);
621 i8k.bios = strtok(NULL, I8K_DELIM);
622 i8k.serial = strtok(NULL, I8K_DELIM);
623 i8k.cpu_temp = strtok(NULL, I8K_DELIM);
624 i8k.left_fan_status = strtok(NULL, I8K_DELIM);
625 i8k.right_fan_status = strtok(NULL, I8K_DELIM);
626 i8k.left_fan_rpm = strtok(NULL, I8K_DELIM);
627 i8k.right_fan_rpm = strtok(NULL, I8K_DELIM);
628 i8k.ac_status = strtok(NULL, I8K_DELIM);
629 i8k.buttons_status = strtok(NULL, I8K_DELIM);
632 /***********************************************************/
633 /***********************************************************/
634 /***********************************************************/
636 static int no_dots(const struct dirent *d)
638 if (d->d_name[0] == '.') {
644 static int get_first_file_in_a_directory(const char *dir, char *s, int *rep)
646 struct dirent **namelist;
649 n = scandir(dir, &namelist, no_dots, alphasort);
652 ERR("scandir for %s: %s", dir, strerror(errno));
663 strncpy(s, namelist[0]->d_name, 255);
666 for (i = 0; i < n; i++) {
675 int open_sysfs_sensor(const char *dir, const char *dev, const char *type, int n,
676 int *div, char *devtype)
683 memset(buf, 0, sizeof(buf));
685 /* if device is NULL or *, get first */
686 if (dev == NULL || strcmp(dev, "*") == 0) {
689 if (!get_first_file_in_a_directory(dir, buf, &rep)) {
695 if (strcmp(dir, "/sys/class/hwmon/") == 0) {
697 /* buf holds result from get_first_file_in_a_directory() above,
698 * e.g. "hwmon0" -- append "/device" */
699 strcat(buf, "/device");
701 /* dev holds device number N as a string,
702 * e.g. "0", -- convert to "hwmon0/device" */
703 sprintf(buf, "hwmon%s/device", dev);
708 /* change vol to in */
709 if (strcmp(type, "vol") == 0) {
713 if (strcmp(type, "tempf") == 0) {
714 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, "temp", n);
716 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, type, n);
718 strncpy(devtype, path, 255);
721 fd = open(path, O_RDONLY);
723 CRIT_ERR("can't open '%s': %s\nplease check your device or remove this "
724 "var from Conky", path, strerror(errno));
727 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
728 || strcmp(type, "tempf") == 0) {
733 /* fan does not use *_div as a read divisor */
734 if (strcmp("fan", type) == 0) {
738 /* test if *_div file exist, open it and use it as divisor */
739 if (strcmp(type, "tempf") == 0) {
740 snprintf(path, 255, "%s%s/%s%d_div", dir, "one", "two", n);
742 snprintf(path, 255, "%s%s/%s%d_div", dir, dev, type, n);
745 divfd = open(path, O_RDONLY);
751 divn = read(divfd, divbuf, 63);
752 /* should read until n == 0 but I doubt that kernel will give these
753 * in multiple pieces. :) */
763 double get_sysfs_info(int *fd, int div, char *devtype, char *type)
771 lseek(*fd, 0, SEEK_SET);
778 n = read(*fd, buf, 63);
779 /* should read until n == 0 but I doubt that kernel will give these
780 * in multiple pieces. :) */
787 *fd = open(devtype, O_RDONLY);
789 ERR("can't open '%s': %s", devtype, strerror(errno));
792 /* My dirty hack for computing CPU value
793 * Filedil, from forums.gentoo.org */
794 /* if (strstr(devtype, "temp1_input") != NULL) {
795 return -15.096 + 1.4893 * (val / 1000.0);
798 /* divide voltage and temperature by 1000 */
799 /* or if any other divisor is given, use that */
800 if (strcmp(type, "tempf") == 0) {
802 return ((val / div + 40) * 9.0 / 5) - 40;
804 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
806 return ((val + 40) * 9.0 / 5) - 40;
819 /* Prior to kernel version 2.6.12, the CPU fan speed was available in
820 * ADT746X_FAN_OLD, whereas later kernel versions provide this information in
822 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
823 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
825 void get_adt746x_fan(char *p_client_buffer, size_t client_buffer_size)
828 char adt746x_fan_state[64];
831 if (!p_client_buffer || client_buffer_size <= 0) {
835 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
836 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL) {
837 sprintf(adt746x_fan_state, "adt746x not found");
839 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
840 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
844 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_fan_state);
847 /* Prior to kernel version 2.6.12, the CPU temperature was found in
848 * ADT746X_CPU_OLD, whereas later kernel versions provide this information in
850 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
851 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
853 void get_adt746x_cpu(char *p_client_buffer, size_t client_buffer_size)
856 char adt746x_cpu_state[64];
859 if (!p_client_buffer || client_buffer_size <= 0) {
863 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
864 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL) {
865 sprintf(adt746x_cpu_state, "adt746x not found");
867 fscanf(fp, "%2s", adt746x_cpu_state);
871 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state);
874 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
876 /***********************************************************************/
877 /* This file is part of x86info.
878 * (C) 2001 Dave Jones.
880 * Licensed under the terms of the GNU GPL License version 2.
882 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
883 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz> */
885 #if defined(__i386) || defined(__x86_64)
886 __inline__ unsigned long long int rdtsc()
888 unsigned long long int x;
890 __asm__ volatile(".byte 0x0f, 0x31":"=A" (x));
895 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
896 void get_freq_dynamic(char *p_client_buffer, size_t client_buffer_size,
897 char *p_format, int divisor)
899 #if defined(__i386) || defined(__x86_64)
901 struct timeval tvstart, tvstop;
902 unsigned long long cycles[2]; /* gotta be 64 bit */
903 unsigned int microseconds; /* total time taken */
905 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
910 memset(&tz, 0, sizeof(tz));
912 /* get this function in cached memory */
913 gettimeofday(&tvstart, &tz);
915 gettimeofday(&tvstart, &tz);
917 /* we don't trust that this is any specific length of time */
920 gettimeofday(&tvstop, &tz);
921 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
922 (tvstop.tv_usec - tvstart.tv_usec);
924 snprintf(p_client_buffer, client_buffer_size, p_format,
925 (float) ((cycles[1] - cycles[0]) / microseconds) / divisor);
928 /* FIXME: hardwired: get freq for first cpu!
929 * this whole function needs to be rethought and redone for
930 * multi-cpu/multi-core/multi-threaded environments and
931 * arbitrary combinations thereof */
932 get_freq(p_client_buffer, client_buffer_size, p_format, divisor, 1);
937 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
938 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
940 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
941 char get_freq(char *p_client_buffer, size_t client_buffer_size, char *p_format,
942 int divisor, unsigned int cpu)
950 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
956 char current_freq_file[128];
958 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu - 1,
960 f = fopen(current_freq_file, "r");
962 /* if there's a cpufreq /sys node, read the current frequency from
963 * this node and divide by 1000 to get Mhz. */
964 if (fgets(s, sizeof(s), f)) {
965 s[strlen(s) - 1] = '\0';
966 freq = strtod(s, NULL);
969 snprintf(p_client_buffer, client_buffer_size, p_format,
970 (freq / 1000) / divisor);
975 // open the CPU information file
976 f = open_file("/proc/cpuinfo", &rep);
978 perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
983 while (fgets(s, sizeof(s), f) != NULL) {
985 #if defined(__i386) || defined(__x86_64)
986 // and search for the cpu mhz
987 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) {
990 // different on alpha
991 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) {
993 // this is different on ppc for some reason
994 if (strncmp(s, "clock", 5) == 0 && cpu == 0) {
995 #endif // defined(__alpha)
996 #endif // defined(__i386) || defined(__x86_64)
998 // copy just the number
999 strcpy(frequency, strchr(s, ':') + 2);
1000 #if defined(__alpha)
1002 frequency[strlen(frequency) - 6] = '\0';
1003 // kernel reports in Hz
1004 freq = strtod(frequency, NULL) / 1000000;
1007 frequency[strlen(frequency) - 1] = '\0';
1008 freq = strtod(frequency, NULL);
1012 if (strncmp(s, "processor", 9) == 0) {
1019 snprintf(p_client_buffer, client_buffer_size, p_format,
1020 (float) freq / divisor);
1024 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
1026 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks something
1036 * Peter Tarjan (ptarjan@citromail.hu) */
1038 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
1039 char get_voltage(char *p_client_buffer, size_t client_buffer_size,
1040 char *p_format, int divisor, unsigned int cpu)
1046 char current_freq_file[128];
1049 /* build the voltage file name */
1051 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1054 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1059 /* read the current cpu frequency from the /sys node */
1060 f = fopen(current_freq_file, "r");
1062 if (fgets(s, sizeof(s), f)) {
1063 s[strlen(s) - 1] = '\0';
1064 freq = strtod(s, NULL);
1068 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1069 perror("get_voltage()");
1076 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1079 /* use the current cpu frequency to find the corresponding voltage */
1080 f = fopen(current_freq_file, "r");
1086 if (fgets(line, 255, f) == NULL) {
1089 sscanf(line, "%d %d", &freq_comp, &voltage);
1090 if (freq_comp == freq) {
1096 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1097 perror("get_voltage()");
1103 snprintf(p_client_buffer, client_buffer_size, p_format,
1104 (float) voltage / divisor);
1108 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1110 void get_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
1117 if (!p_client_buffer || client_buffer_size <= 0) {
1121 /* yeah, slow... :/ */
1122 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep)) {
1123 snprintf(p_client_buffer, client_buffer_size, "no fans?");
1127 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf);
1129 fp = open_file(buf2, &rep);
1131 snprintf(p_client_buffer, client_buffer_size,
1132 "can't open fan's state file");
1135 memset(buf, 0, sizeof(buf));
1136 fscanf(fp, "%*s %99s", buf);
1139 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1142 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1144 void get_acpi_ac_adapter(char *p_client_buffer, size_t client_buffer_size)
1151 if (!p_client_buffer || client_buffer_size <= 0) {
1155 /* yeah, slow... :/ */
1156 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep)) {
1157 snprintf(p_client_buffer, client_buffer_size, "no ac_adapters?");
1161 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf);
1163 fp = open_file(buf2, &rep);
1165 snprintf(p_client_buffer, client_buffer_size,
1166 "No ac adapter found.... where is it?");
1169 memset(buf, 0, sizeof(buf));
1170 fscanf(fp, "%*s %99s", buf);
1173 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1177 /proc/acpi/thermal_zone/THRM/cooling_mode
1178 cooling mode: active
1179 /proc/acpi/thermal_zone/THRM/polling_frequency
1181 /proc/acpi/thermal_zone/THRM/state
1183 /proc/acpi/thermal_zone/THRM/temperature
1185 /proc/acpi/thermal_zone/THRM/trip_points
1187 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1190 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1191 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1193 int open_acpi_temperature(const char *name)
1199 if (name == NULL || strcmp(name, "*") == 0) {
1202 if (!get_first_file_in_a_directory(ACPI_THERMAL_DIR, buf, &rep)) {
1208 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1210 fd = open(path, O_RDONLY);
1212 ERR("can't open '%s': %s", path, strerror(errno));
1218 static double last_acpi_temp;
1219 static double last_acpi_temp_time;
1221 double get_acpi_temperature(int fd)
1227 /* don't update acpi temperature too often */
1228 if (current_update_time - last_acpi_temp_time < 11.32) {
1229 return last_acpi_temp;
1231 last_acpi_temp_time = current_update_time;
1233 /* seek to beginning */
1234 lseek(fd, 0, SEEK_SET);
1241 n = read(fd, buf, 255);
1243 ERR("can't read fd %d: %s", fd, strerror(errno));
1246 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1250 return last_acpi_temp;
1254 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1256 design capacity: 4400 mAh
1257 last full capacity: 4064 mAh
1258 battery technology: rechargeable
1259 design voltage: 14800 mV
1260 design capacity warning: 300 mAh
1261 design capacity low: 200 mAh
1262 capacity granularity 1: 32 mAh
1263 capacity granularity 2: 32 mAh
1265 serial number: 16922
1271 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1274 charging state: unknown
1276 remaining capacity: 4064 mAh
1277 present voltage: 16608 mV
1281 2213<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1282 2213<@jupet�kellari��> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1283 2213<@jupet�kellari��> (-1 ollee ei akkua kiinni, koska akku on p�yd�ll�)
1284 2214<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1285 2214<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1287 2238<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1288 2239<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1290 2240<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori p��ll�
1291 2241<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori p��ll� mutta ilman verkkovirtaa
1294 /* Kapil Hari Paranjape <kapil@imsc.res.in>
1295 Linux 2.6.24 onwards battery info is in
1296 /sys/class/power_supply/BAT0/
1297 On my system I get the following.
1298 /sys/class/power_supply/BAT0/uevent:
1299 PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A03:00/device:01/PNP0C09:00/PNP0C0A:00
1301 PHYSDEVDRIVER=battery
1302 POWER_SUPPLY_NAME=BAT0
1303 POWER_SUPPLY_TYPE=Battery
1304 POWER_SUPPLY_STATUS=Discharging
1305 POWER_SUPPLY_PRESENT=1
1306 POWER_SUPPLY_TECHNOLOGY=Li-ion
1307 POWER_SUPPLY_VOLTAGE_MIN_DESIGN=10800000
1308 POWER_SUPPLY_VOLTAGE_NOW=10780000
1309 POWER_SUPPLY_CURRENT_NOW=13970000
1310 POWER_SUPPLY_ENERGY_FULL_DESIGN=47510000
1311 POWER_SUPPLY_ENERGY_FULL=27370000
1312 POWER_SUPPLY_ENERGY_NOW=11810000
1313 POWER_SUPPLY_MODEL_NAME=IBM-92P1060
1314 POWER_SUPPLY_MANUFACTURER=Panasonic
1315 On some systems POWER_SUPPLY_ENERGY_* is replaced by POWER_SUPPLY_CHARGE_*
1318 #define SYSFS_BATTERY_BASE_PATH "/sys/class/power_supply"
1319 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1320 #define APM_PATH "/proc/apm"
1321 #define MAX_BATTERY_COUNT 4
1323 static FILE *sysfs_bat_fp[MAX_BATTERY_COUNT];
1324 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT];
1325 static FILE *apm_bat_fp[MAX_BATTERY_COUNT];
1327 static int batteries_initialized = 0;
1328 static char batteries[MAX_BATTERY_COUNT][32];
1330 static int acpi_last_full[MAX_BATTERY_COUNT];
1331 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1333 /* e.g. "charging 75%" */
1334 static char last_battery_str[MAX_BATTERY_COUNT][64];
1336 static char last_battery_time_str[MAX_BATTERY_COUNT][64];
1338 static double last_battery_time[MAX_BATTERY_COUNT];
1340 static int last_battery_perct[MAX_BATTERY_COUNT];
1341 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1343 void init_batteries(void)
1347 if (batteries_initialized) {
1350 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1351 batteries[idx][0] = '\0';
1353 batteries_initialized = 1;
1356 int get_battery_idx(const char *bat)
1360 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1361 if (!strlen(batteries[idx]) || !strcmp(batteries[idx], bat)) {
1366 /* if not found, enter a new entry */
1367 if (!strlen(batteries[idx])) {
1368 snprintf(batteries[idx], 31, "%s", bat);
1374 void get_battery_stuff(char *buf, unsigned int n, const char *bat, int item)
1376 static int idx, rep = 0, rep2 = 0;
1377 char acpi_path[128];
1379 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1380 char sysfs_path[128];
1381 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1385 idx = get_battery_idx(bat);
1387 /* don't update battery too often */
1388 if (current_update_time - last_battery_time[idx] < 29.5) {
1389 goto set_return_value;
1392 last_battery_time[idx] = current_update_time;
1394 memset(last_battery_str[idx], 0, sizeof(last_battery_str[idx]));
1395 memset(last_battery_time_str[idx], 0, sizeof(last_battery_time_str[idx]));
1397 /* first try SYSFS if that fails try ACPI */
1399 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1400 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1402 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1403 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1405 if (sysfs_bat_fp[idx] != NULL) {
1407 int present_rate = -1;
1408 int remaining_capacity = -1;
1409 char charging_state[64];
1412 strcpy(charging_state, "Unknown");
1414 while (!feof(sysfs_bat_fp[idx])) {
1416 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1419 /* let's just hope units are ok */
1420 if (strncmp (buf, "POWER_SUPPLY_PRESENT=1", 22) == 0)
1421 strcpy(present, "Yes");
1422 else if (strncmp (buf, "POWER_SUPPLY_PRESENT=0", 22) == 0)
1423 strcpy(present, "No");
1424 else if (strncmp (buf, "POWER_SUPPLY_STATUS=", 20) == 0)
1425 sscanf(buf, "POWER_SUPPLY_STATUS=%63s", charging_state);
1426 /* present_rate is not the same as the
1427 current flowing now but it is the same value
1428 which was used in the past. so we continue
1430 else if (strncmp(buf, "POWER_SUPPLY_CURRENT_NOW=", 25) == 0)
1431 sscanf(buf, "POWER_SUPPLY_CURRENT_NOW=%d", &present_rate);
1432 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0)
1433 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1434 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=", 25) == 0)
1435 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_last_full[idx]);
1436 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0)
1437 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1438 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=", 25) == 0)
1439 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_last_full[idx]);
1442 fclose(sysfs_bat_fp[idx]);
1443 sysfs_bat_fp[idx] = NULL;
1445 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1446 if (remaining_capacity > acpi_last_full[idx])
1447 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1450 if (strcmp(present, "No") == 0) {
1451 strncpy(last_battery_str[idx], "not present", 64);
1454 else if (strcmp(charging_state, "Charging") == 0) {
1455 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1456 /* e.g. charging 75% */
1457 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Charging %i%%",
1458 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1460 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1461 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1462 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1463 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Charging %d%%",
1464 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1466 strncpy(last_battery_str[idx], "Charging", sizeof(last_battery_str[idx])-1);
1470 else if (strncmp(charging_state, "Discharging", 64) == 0) {
1471 if (present_rate > 0) {
1472 /* e.g. discharging 35% */
1473 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Discharging %i%%",
1474 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1476 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1477 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1478 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1479 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Full");
1481 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1483 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1487 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1488 else if (strncmp(charging_state, "Charged", 64) == 0) {
1489 /* Below happens with the second battery on my X40,
1490 * when the second one is empty and the first one
1492 if (remaining_capacity == 0)
1493 strcpy(last_battery_str[idx], "Empty");
1495 strcpy(last_battery_str[idx], "Charged");
1497 /* unknown, probably full / AC */
1499 if (acpi_last_full[idx] != 0
1500 && remaining_capacity != acpi_last_full[idx])
1501 snprintf(last_battery_str[idx], 64, "Unknown %d%%",
1502 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1504 strncpy(last_battery_str[idx], "AC", 64);
1506 } else if (acpi_bat_fp[idx] != NULL) {
1508 int present_rate = -1;
1509 int remaining_capacity = -1;
1510 char charging_state[64];
1513 /* read last full capacity if it's zero */
1514 if (acpi_last_full[idx] == 0) {
1519 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1520 fp = open_file(path, &rep);
1525 if (fgets(b, 256, fp) == NULL) {
1528 if (sscanf(b, "last full capacity: %d",
1529 &acpi_last_full[idx]) != 0) {
1538 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1540 strcpy(charging_state, "unknown");
1542 while (!feof(acpi_bat_fp[idx])) {
1545 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1549 /* let's just hope units are ok */
1550 if (strncmp(buf, "present:", 8) == 0) {
1551 sscanf(buf, "present: %4s", present);
1552 } else if (strncmp(buf, "charging state:", 15) == 0) {
1553 sscanf(buf, "charging state: %63s", charging_state);
1554 } else if (strncmp(buf, "present rate:", 13) == 0) {
1555 sscanf(buf, "present rate: %d", &present_rate);
1556 } else if (strncmp(buf, "remaining capacity:", 19) == 0) {
1557 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1560 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1561 if (remaining_capacity > acpi_last_full[idx]) {
1562 /* normalize to 100% */
1563 acpi_last_full[idx] = remaining_capacity;
1567 if (strcmp(present, "no") == 0) {
1568 strncpy(last_battery_str[idx], "not present", 64);
1570 } else if (strcmp(charging_state, "charging") == 0) {
1571 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1572 /* e.g. charging 75% */
1573 snprintf(last_battery_str[idx],
1574 sizeof(last_battery_str[idx]) - 1, "charging %i%%",
1575 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1577 format_seconds(last_battery_time_str[idx],
1578 sizeof(last_battery_time_str[idx]) - 1,
1579 (long) (((acpi_last_full[idx] - remaining_capacity) *
1580 3600) / present_rate));
1581 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1582 snprintf(last_battery_str[idx],
1583 sizeof(last_battery_str[idx]) - 1, "charging %d%%",
1584 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1586 strncpy(last_battery_str[idx], "charging",
1587 sizeof(last_battery_str[idx]) - 1);
1590 } else if (strncmp(charging_state, "discharging", 64) == 0) {
1591 if (present_rate > 0) {
1592 /* e.g. discharging 35% */
1593 snprintf(last_battery_str[idx],
1594 sizeof(last_battery_str[idx]) - 1, "discharging %i%%",
1595 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1597 format_seconds(last_battery_time_str[idx],
1598 sizeof(last_battery_time_str[idx]) - 1,
1599 (long) ((remaining_capacity * 3600) / present_rate));
1600 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1601 snprintf(last_battery_str[idx],
1602 sizeof(last_battery_str[idx]) - 1, "full");
1604 snprintf(last_battery_str[idx],
1605 sizeof(last_battery_str[idx]) - 1, "discharging %d%%",
1606 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1609 } else if (strncmp(charging_state, "charged", 64) == 0) {
1610 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1611 /* Below happens with the second battery on my X40,
1612 * when the second one is empty and the first one being charged. */
1613 if (remaining_capacity == 0) {
1614 strcpy(last_battery_str[idx], "empty");
1616 strcpy(last_battery_str[idx], "charged");
1618 /* unknown, probably full / AC */
1620 if (acpi_last_full[idx] != 0
1621 && remaining_capacity != acpi_last_full[idx]) {
1622 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1623 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1625 strncpy(last_battery_str[idx], "AC", 64);
1630 if (apm_bat_fp[idx] == NULL) {
1631 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1634 if (apm_bat_fp[idx] != NULL) {
1635 int ac, status, flag, life;
1637 fscanf(apm_bat_fp[idx], "%*s %*s %*x %x %x %x %d%%",
1638 &ac, &status, &flag, &life);
1641 /* could check now that there is ac */
1642 snprintf(last_battery_str[idx], 64, "AC");
1644 /* could check that status == 3 here? */
1645 } else if (ac && life != 100) {
1646 snprintf(last_battery_str[idx], 64, "charging %d%%", life);
1648 snprintf(last_battery_str[idx], 64, "%d%%", life);
1651 /* it seemed to buffer it so file must be closed (or could use
1652 * syscalls directly but I don't feel like coding it now) */
1653 fclose(apm_bat_fp[idx]);
1654 apm_bat_fp[idx] = NULL;
1660 case BATTERY_STATUS:
1661 snprintf(buf, n, "%s", last_battery_str[idx]);
1664 snprintf(buf, n, "%s", last_battery_time_str[idx]);
1671 int get_battery_perct(const char *bat)
1675 char acpi_path[128];
1677 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1678 char sysfs_path[128];
1679 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1683 idx = get_battery_idx(bat);
1685 /* don't update battery too often */
1686 if (current_update_time - last_battery_perct_time[idx] < 30) {
1687 return last_battery_perct[idx];
1689 last_battery_perct_time[idx] = current_update_time;
1691 /* Only check for SYSFS or ACPI */
1693 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1694 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1696 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1697 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1699 int remaining_capacity = -1;
1701 if (sysfs_bat_fp[idx] != NULL) {
1703 while (!feof(sysfs_bat_fp[idx])) {
1705 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1708 if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0)
1709 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1710 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=",25) != 0)
1711 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_last_full[idx]);
1712 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0)
1713 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1714 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=",25) != 0)
1715 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_last_full[idx]);
1718 fclose(sysfs_bat_fp[idx]);
1719 sysfs_bat_fp[idx] = NULL;
1721 } else if (acpi_bat_fp[idx] != NULL) {
1723 /* read last full capacity if it's zero */
1724 if (acpi_design_capacity[idx] == 0) {
1729 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1730 fp = open_file(path, &rep);
1735 if (fgets(b, 256, fp) == NULL) {
1738 if (sscanf(b, "last full capacity: %d",
1739 &acpi_design_capacity[idx]) != 0) {
1747 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1749 while (!feof(acpi_bat_fp[idx])) {
1752 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1756 if (buf[0] == 'r') {
1757 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1761 if (remaining_capacity < 0) {
1764 /* compute the battery percentage */
1765 last_battery_perct[idx] =
1766 (int) (((float) remaining_capacity / acpi_design_capacity[idx]) * 100);
1767 return last_battery_perct[idx];
1770 int get_battery_perct_bar(const char *bar)
1774 get_battery_perct(bar);
1775 idx = get_battery_idx(bar);
1776 return (int) (last_battery_perct[idx] * 2.56 - 1);
1779 /* On Apple powerbook and ibook:
1780 $ cat /proc/pmu/battery_0
1787 $ cat /proc/pmu/info
1788 PMU driver version : 2
1789 PMU firmware version : 0c
1794 /* defines as in <linux/pmu.h> */
1795 #define PMU_BATT_PRESENT 0x00000001
1796 #define PMU_BATT_CHARGING 0x00000002
1798 static FILE *pmu_battery_fp;
1799 static FILE *pmu_info_fp;
1800 static char pb_battery_info[3][32];
1801 static double pb_battery_info_update;
1803 #define PMU_PATH "/proc/pmu"
1804 void get_powerbook_batt_info(char *buf, size_t n, int i)
1807 const char *batt_path = PMU_PATH "/battery_0";
1808 const char *info_path = PMU_PATH "/info";
1809 int flags, charge, max_charge, ac = -1;
1812 /* don't update battery too often */
1813 if (current_update_time - pb_battery_info_update < 29.5) {
1814 snprintf(buf, n, "%s", pb_battery_info[i]);
1817 pb_battery_info_update = current_update_time;
1819 if (pmu_battery_fp == NULL) {
1820 pmu_battery_fp = open_file(batt_path, &rep);
1823 if (pmu_battery_fp != NULL) {
1824 rewind(pmu_battery_fp);
1825 while (!feof(pmu_battery_fp)) {
1828 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL) {
1832 if (buf[0] == 'f') {
1833 sscanf(buf, "flags : %8x", &flags);
1834 } else if (buf[0] == 'c' && buf[1] == 'h') {
1835 sscanf(buf, "charge : %d", &charge);
1836 } else if (buf[0] == 'm') {
1837 sscanf(buf, "max_charge : %d", &max_charge);
1838 } else if (buf[0] == 't') {
1839 sscanf(buf, "time rem. : %ld", &time);
1843 if (pmu_info_fp == NULL) {
1844 pmu_info_fp = open_file(info_path, &rep);
1847 if (pmu_info_fp != NULL) {
1848 rewind(pmu_info_fp);
1849 while (!feof(pmu_info_fp)) {
1852 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL) {
1855 if (buf[0] == 'A') {
1856 sscanf(buf, "AC Power : %d", &ac);
1860 /* update status string */
1861 if ((ac && !(flags & PMU_BATT_PRESENT))) {
1862 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
1863 } else if (ac && (flags & PMU_BATT_PRESENT)
1864 && !(flags & PMU_BATT_CHARGING)) {
1865 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
1866 } else if ((flags & PMU_BATT_PRESENT) && (flags & PMU_BATT_CHARGING)) {
1867 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
1869 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
1872 /* update percentage string */
1874 pb_battery_info[PB_BATT_PERCENT][0] = 0;
1876 snprintf(pb_battery_info[PB_BATT_PERCENT],
1877 sizeof(pb_battery_info[PB_BATT_PERCENT]), "%d%%",
1878 (charge * 100) / max_charge);
1881 /* update time string */
1882 if (time == 0) { /* fully charged or battery not present */
1883 pb_battery_info[PB_BATT_TIME][0] = 0;
1884 } else if (time < 60 * 60) { /* don't show secs */
1885 format_seconds_short(pb_battery_info[PB_BATT_TIME],
1886 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1888 format_seconds(pb_battery_info[PB_BATT_TIME],
1889 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1892 snprintf(buf, n, "%s", pb_battery_info[i]);
1897 show_nice_processes = 1;
1898 process_find_top(info.cpu, info.memu);
1899 info.first_process = get_first_process();
1902 /* The following ifdefs were adapted from gkrellm */
1903 #include <linux/major.h>
1905 #if !defined(MD_MAJOR)
1909 #if !defined(LVM_BLK_MAJOR)
1910 #define LVM_BLK_MAJOR 58
1913 #if !defined(NBD_MAJOR)
1914 #define NBD_MAJOR 43
1917 void update_diskio()
1919 static unsigned int last = UINT_MAX;
1920 static unsigned int last_read = UINT_MAX;
1921 static unsigned int last_write = UINT_MAX;
1925 char buf[512], devbuf[64];
1926 int major, minor, i;
1927 unsigned int current = 0;
1928 unsigned int current_read = 0;
1929 unsigned int current_write = 0;
1930 unsigned int reads, writes = 0;
1933 if (!(fp = open_file("/proc/diskstats", &rep))) {
1938 /* read reads and writes from all disks (minor = 0), including cd-roms
1939 * and floppies, and sum them up */
1941 fgets(buf, 512, fp);
1942 col_count = sscanf(buf, "%u %u %s %*u %*u %u %*u %*u %*u %u", &major,
1943 &minor, devbuf, &reads, &writes);
1944 /* ignore subdevices (they have only 3 matching entries in their line)
1945 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
1947 * XXX: ignore devices which are part of a SW RAID (MD_MAJOR) */
1948 if (col_count == 5 && major != LVM_BLK_MAJOR && major != NBD_MAJOR
1949 && major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
1950 current += reads + writes;
1951 current_read += reads;
1952 current_write += writes;
1954 col_count = sscanf(buf, "%u %u %s %*u %u %*u %u",
1955 &major, &minor, devbuf, &reads, &writes);
1956 if (col_count != 5) {
1960 for (i = 0; i < MAX_DISKIO_STATS; i++) {
1961 if (diskio_stats[i].dev &&
1962 strcmp(devbuf, diskio_stats[i].dev) == 0) {
1963 diskio_stats[i].current =
1964 (reads + writes - diskio_stats[i].last) / 2;
1965 diskio_stats[i].current_read =
1966 (reads - diskio_stats[i].last_read) / 2;
1967 diskio_stats[i].current_write =
1968 (writes - diskio_stats[i].last_write) / 2;
1969 if (reads + writes < diskio_stats[i].last) {
1970 diskio_stats[i].current = 0;
1972 if (reads < diskio_stats[i].last_read) {
1973 diskio_stats[i].current_read = 0;
1974 diskio_stats[i].current = diskio_stats[i].current_write;
1976 if (writes < diskio_stats[i].last_write) {
1977 diskio_stats[i].current_write = 0;
1978 diskio_stats[i].current = diskio_stats[i].current_read;
1980 diskio_stats[i].last = reads + writes;
1981 diskio_stats[i].last_read = reads;
1982 diskio_stats[i].last_write = writes;
1987 /* since the values in /proc/diststats are absolute, we have to substract
1988 * our last reading. The numbers stand for "sectors read", and we therefore
1989 * have to divide by two to get KB */
1990 int tot = ((double) (current - last) / 2);
1991 int tot_read = ((double) (current_read - last_read) / 2);
1992 int tot_write = ((double) (current_write - last_write) / 2);
1994 if (last_read > current_read) {
1997 if (last_write > current_write) {
2001 if (last > current) {
2002 /* we hit this either if it's the very first time we run this, or
2003 * when /proc/diskstats overflows; while 0 is not correct, it's at
2004 * least not way off */
2008 last_read = current_read;
2009 last_write = current_write;
2012 diskio_read_value = tot_read;
2013 diskio_write_value = tot_write;
2018 /* Here come the IBM ACPI-specific things. For reference, see
2019 * http://ibm-acpi.sourceforge.net/README
2020 * If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
2036 * The content of these files is described in detail in the aforementioned
2037 * README - some of them also in the following functions accessing them.
2038 * Peter Tarjan (ptarjan@citromail.hu) */
2040 #define IBM_ACPI_DIR "/proc/acpi/ibm"
2042 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
2043 * /proc/acpi/ibm/fan looks like this (3 lines):
2046 commands: enable, disable
2047 * Peter Tarjan (ptarjan@citromail.hu) */
2049 void get_ibm_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
2051 if (!p_client_buffer || client_buffer_size <= 0) {
2056 unsigned int speed = 0;
2059 snprintf(fan, 127, "%s/fan", IBM_ACPI_DIR);
2061 fp = fopen(fan, "r");
2066 if (fgets(line, 255, fp) == NULL) {
2069 if (sscanf(line, "speed: %d", &speed)) {
2074 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2075 "ibm* from your Conky config file.", fan, strerror(errno));
2079 snprintf(p_client_buffer, client_buffer_size, "%d", speed);
2082 /* get the measured temperatures from the temperature sensors
2083 * on IBM/Lenovo laptops running the ibm acpi.
2084 * There are 8 values in /proc/acpi/ibm/thermal, and according to
2085 * http://ibm-acpi.sourceforge.net/README
2086 * these mean the following (at least on an IBM R51...)
2087 * 0: CPU (also on the T series laptops)
2088 * 1: Mini PCI Module (?)
2090 * 3: GPU (also on the T series laptops)
2095 * I'm not too sure about those with the question mark, but the values I'm
2096 * reading from *my* thermal file (on a T42p) look realistic for the
2097 * hdd and the battery.
2098 * #5 and #7 are always -128.
2099 * /proc/acpi/ibm/thermal looks like this (1 line):
2100 temperatures: 41 43 31 46 33 -128 29 -128
2101 * Peter Tarjan (ptarjan@citromail.hu) */
2103 static double last_ibm_acpi_temp_time;
2104 void get_ibm_acpi_temps()
2107 /* don't update too often */
2108 if (current_update_time - last_ibm_acpi_temp_time < 10.00) {
2111 last_ibm_acpi_temp_time = current_update_time;
2113 /* if (!p_client_buffer || client_buffer_size <= 0) {
2121 snprintf(thermal, 127, "%s/thermal", IBM_ACPI_DIR);
2122 fp = fopen(thermal, "r");
2128 if (fgets(line, 255, fp) == NULL) {
2131 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
2132 &ibm_acpi.temps[0], &ibm_acpi.temps[1], &ibm_acpi.temps[2],
2133 &ibm_acpi.temps[3], &ibm_acpi.temps[4], &ibm_acpi.temps[5],
2134 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) {
2139 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2140 "ibm* from your Conky config file.", thermal, strerror(errno));
2146 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
2147 * "Volume" here is none of the mixer volumes, but a "master of masters"
2148 * volume adjusted by the IBM volume keys.
2149 * /proc/acpi/ibm/fan looks like this (4 lines):
2152 commands: up, down, mute
2153 commands: level <level> (<level> is 0-15)
2154 * Peter Tarjan (ptarjan@citromail.hu) */
2156 void get_ibm_acpi_volume(char *p_client_buffer, size_t client_buffer_size)
2158 if (!p_client_buffer || client_buffer_size <= 0) {
2166 snprintf(volume, 127, "%s/volume", IBM_ACPI_DIR);
2167 unsigned int vol = -1;
2170 fp = fopen(volume, "r");
2174 unsigned int read_vol = -1;
2176 if (fgets(line, 255, fp) == NULL) {
2179 if (sscanf(line, "level: %d", &read_vol)) {
2183 if (sscanf(line, "mute: %s", mute)) {
2188 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2189 "ibm* from your Conky config file.", volume, strerror(errno));
2194 if (strcmp(mute, "on") == 0) {
2195 snprintf(p_client_buffer, client_buffer_size, "%s", "mute");
2198 snprintf(p_client_buffer, client_buffer_size, "%d", vol);
2203 /* static FILE *fp = NULL; */
2205 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
2206 * /proc/acpi/ibm/brightness looks like this (3 lines):
2209 commands: level <level> (<level> is 0-7)
2210 * Peter Tarjan (ptarjan@citromail.hu) */
2212 void get_ibm_acpi_brightness(char *p_client_buffer, size_t client_buffer_size)
2214 if (!p_client_buffer || client_buffer_size <= 0) {
2219 unsigned int brightness = 0;
2222 snprintf(filename, 127, "%s/brightness", IBM_ACPI_DIR);
2224 fp = fopen(filename, "r");
2229 if (fgets(line, 255, fp) == NULL) {
2232 if (sscanf(line, "level: %d", &brightness)) {
2237 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2238 "ibm* from your Conky config file.", filename, strerror(errno));
2243 snprintf(p_client_buffer, client_buffer_size, "%d", brightness);
2246 void update_entropy(void)
2249 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
2250 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
2253 info.entropy.entropy_avail = 0;
2254 info.entropy.poolsize = 0;
2256 if ((fp1 = open_file(entropy_avail, &rep)) == NULL) {
2260 if ((fp2 = open_file(entropy_poolsize, &rep)) == NULL) {
2265 fscanf(fp1, "%u", &info.entropy.entropy_avail);
2266 fscanf(fp2, "%u", &info.entropy.poolsize);
2271 info.mask |= (1 << INFO_ENTROPY);