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 int interface_up(const char *dev)
174 if((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
175 CRIT_ERR("could not create sockfd");
178 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
179 if(ioctl(fd, SIOCGIFFLAGS, &ifr)) {
180 /* if device does not exist, treat like not up */
182 perror("SIOCGIFFLAGS");
185 return (ifr.ifr_flags & IFF_UP);
191 inline void update_net_stats()
196 // FIXME: arbitrary size chosen to keep code simple.
198 unsigned int curtmp1, curtmp2;
205 // wireless info variables
206 int skfd, has_bitrate = 0;
207 struct wireless_info *winfo;
212 delta = current_update_time - last_update_time;
213 if (delta <= 0.0001) {
217 /* open file and ignore first two lines */
218 if (!(net_dev_fp = open_file("/proc/net/dev", &rep))) {
223 fgets(buf, 255, net_dev_fp); /* garbage */
224 fgets(buf, 255, net_dev_fp); /* garbage (field names) */
226 /* read each interface */
227 for (i2 = 0; i2 < 16; i2++) {
231 long long r, t, last_recv, last_trans;
233 if (fgets(buf, 255, net_dev_fp) == NULL) {
237 while (isspace((int) *p)) {
243 while (*p && *p != ':') {
252 ns = get_net_stat(s);
254 memset(&(ns->addr.sa_data), 0, 14);
256 if(NULL == ns->addrs)
257 ns->addrs = (char*) malloc(17 * 16);
258 if(NULL != ns->addrs)
259 memset(ns->addrs, 0, 17 * 16); /* Up to 17 chars per ip, max 16 interfaces. Nasty memory usage... */
261 last_recv = ns->recv;
262 last_trans = ns->trans;
264 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
265 sscanf(p, "%Ld %*d %*d %*d %*d %*d %*d %*d %Ld",
268 /* if recv or trans is less than last time, an overflow happened */
269 if (r < ns->last_read_recv) {
272 ns->recv += (r - ns->last_read_recv);
274 ns->last_read_recv = r;
276 if (t < ns->last_read_trans) {
279 ns->trans += (t - ns->last_read_trans);
281 ns->last_read_trans = t;
283 /*** ip addr patch ***/
284 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
286 conf.ifc_buf = malloc(sizeof(struct ifreq) * 16);
288 conf.ifc_len = sizeof(struct ifreq) * 16;
290 ioctl((long) i, SIOCGIFCONF, &conf);
292 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
296 ((struct ifreq *) conf.ifc_buf)[k].ifr_ifrn.ifrn_name);
297 ns->addr = ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.ifru_addr;
298 if(NULL != ns->addrs)
300 sprintf(temp_addr, "%u.%u.%u.%u, ",
301 ns->addr.sa_data[2] & 255,
302 ns->addr.sa_data[3] & 255,
303 ns->addr.sa_data[4] & 255,
304 ns->addr.sa_data[5] & 255);
305 if(NULL == strstr(ns->addrs, temp_addr))
306 strncpy(ns->addrs + strlen(ns->addrs), temp_addr, 17);
314 /*** end ip addr patch ***/
316 /* calculate speeds */
317 ns->net_rec[0] = (ns->recv - last_recv) / delta;
318 ns->net_trans[0] = (ns->trans - last_trans) / delta;
322 for (i = 0; (unsigned) i < info.net_avg_samples; i++) {
323 curtmp1 += ns->net_rec[i];
324 curtmp2 += ns->net_trans[i];
332 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
333 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
334 if (info.net_avg_samples > 1) {
335 for (i = info.net_avg_samples; i > 1; i--) {
336 ns->net_rec[i - 1] = ns->net_rec[i - 2];
337 ns->net_trans[i - 1] = ns->net_trans[i - 2];
342 /* update wireless info */
343 winfo = malloc(sizeof(struct wireless_info));
344 memset(winfo, 0, sizeof(struct wireless_info));
346 skfd = iw_sockets_open();
347 if (iw_get_basic_config(skfd, s, &(winfo->b)) > -1) {
349 // set present winfo variables
350 if (iw_get_stats(skfd, s, &(winfo->stats),
351 &winfo->range, winfo->has_range) >= 0) {
352 winfo->has_stats = 1;
354 if (iw_get_range_info(skfd, s, &(winfo->range)) >= 0) {
355 winfo->has_range = 1;
357 if (iw_get_ext(skfd, s, SIOCGIWAP, &wrq) >= 0) {
358 winfo->has_ap_addr = 1;
359 memcpy(&(winfo->ap_addr), &(wrq.u.ap_addr), sizeof(sockaddr));
363 if (iw_get_ext(skfd, s, SIOCGIWRATE, &wrq) >= 0) {
364 memcpy(&(winfo->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
365 iw_print_bitrate(ns->bitrate, 16, winfo->bitrate.value);
370 if (winfo->has_range && winfo->has_stats
371 && ((winfo->stats.qual.level != 0)
372 || (winfo->stats.qual.updated & IW_QUAL_DBM))) {
373 if (!(winfo->stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
374 ns->link_qual = winfo->stats.qual.qual;
375 ns->link_qual_max = winfo->range.max_qual.qual;
380 if (winfo->has_ap_addr) {
381 iw_sawap_ntop(&winfo->ap_addr, ns->ap);
385 if (winfo->b.has_essid) {
386 if (winfo->b.essid_on) {
387 snprintf(ns->essid, 32, "%s", winfo->b.essid);
389 snprintf(ns->essid, 32, "off/any");
393 snprintf(ns->mode, 16, "%s", iw_operation_mode[winfo->b.mode]);
395 iw_sockets_close(skfd);
402 info.mask |= (1 << INFO_NET);
407 void update_total_processes()
411 struct sysinfo s_info;
414 info.procs = s_info.procs;
421 if (!(fp = open_file("/proc/loadavg", &rep))) {
425 fscanf(fp, "%*f %*f %*f %*d/%hd", &info.procs);
428 info.mask |= (1 << INFO_PROCS);
431 #define CPU_SAMPLE_COUNT 15
433 unsigned long long cpu_user;
434 unsigned long long cpu_system;
435 unsigned long long cpu_nice;
436 unsigned long long cpu_idle;
437 unsigned long long cpu_iowait;
438 unsigned long long cpu_irq;
439 unsigned long long cpu_softirq;
440 unsigned long long cpu_steal;
441 unsigned long long cpu_total;
442 unsigned long long cpu_active_total;
443 unsigned long long cpu_last_total;
444 unsigned long long cpu_last_active_total;
445 double cpu_val[CPU_SAMPLE_COUNT];
447 static short cpu_setup = 0;
449 /* Determine if this kernel gives us "extended" statistics information in
451 * Kernels around 2.5 and earlier only reported user, system, nice, and
452 * idle values in proc stat.
453 * Kernels around 2.6 and greater report these PLUS iowait, irq, softirq,
455 void determine_longstat(char *buf)
457 unsigned long long iowait = 0;
459 KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
460 /* scanf will either return -1 or 1 because there is only 1 assignment */
461 if (sscanf(buf, "%*s %*d %*d %*d %*d %llu", &iowait) > 0) {
462 KFLAG_SETON(KFLAG_IS_LONGSTAT);
471 if (info.cpu_usage) {
476 if (!(stat_fp = open_file("/proc/stat", &rep))) {
482 while (!feof(stat_fp)) {
483 if (fgets(buf, 255, stat_fp) == NULL) {
487 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
488 if (info.cpu_count == 0) {
489 determine_longstat(buf);
494 info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
499 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
500 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
502 inline static void update_stat()
506 static struct cpu_info *cpu = NULL;
511 char *stat_template = NULL;
512 unsigned int malloc_cpu_size = 0;
514 /* add check for !info.cpu_usage since that mem is freed on a SIGUSR1 */
515 if (!cpu_setup || !info.cpu_usage) {
520 if (!stat_template) {
522 KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT;
526 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
527 cpu = malloc(malloc_cpu_size);
528 memset(cpu, 0, malloc_cpu_size);
531 if (!(stat_fp = open_file("/proc/stat", &rep))) {
533 if (info.cpu_usage) {
534 memset(info.cpu_usage, 0, info.cpu_count * sizeof(float));
540 while (!feof(stat_fp)) {
541 if (fgets(buf, 255, stat_fp) == NULL) {
545 if (strncmp(buf, "procs_running ", 14) == 0) {
546 sscanf(buf, "%*s %hu", &info.run_procs);
547 info.mask |= (1 << INFO_RUN_PROCS);
548 } else if (strncmp(buf, "cpu", 3) == 0) {
549 index = isdigit(buf[3]) ? ((int) buf[3]) - 0x2F : 0;
550 sscanf(buf, stat_template, &(cpu[index].cpu_user),
551 &(cpu[index].cpu_nice), &(cpu[index].cpu_system),
552 &(cpu[index].cpu_idle), &(cpu[index].cpu_iowait),
553 &(cpu[index].cpu_irq), &(cpu[index].cpu_softirq),
554 &(cpu[index].cpu_steal));
556 cpu[index].cpu_total = cpu[index].cpu_user + cpu[index].cpu_nice +
557 cpu[index].cpu_system + cpu[index].cpu_idle +
558 cpu[index].cpu_iowait + cpu[index].cpu_irq +
559 cpu[index].cpu_softirq + cpu[index].cpu_steal;
561 cpu[index].cpu_active_total = cpu[index].cpu_total -
562 (cpu[index].cpu_idle + cpu[index].cpu_iowait);
563 info.mask |= (1 << INFO_CPU);
565 double delta = current_update_time - last_update_time;
567 if (delta <= 0.001) {
571 cpu[index].cpu_val[0] = (cpu[index].cpu_active_total -
572 cpu[index].cpu_last_active_total) /
573 (float) (cpu[index].cpu_total - cpu[index].cpu_last_total);
575 for (i = 0; i < info.cpu_avg_samples; i++) {
576 curtmp += cpu[index].cpu_val[i];
578 /* TESTING -- I've removed this, because I don't think it is right.
579 * You shouldn't divide by the cpu count here ...
580 * removing for testing */
582 info.cpu_usage[index] = curtmp / info.cpu_avg_samples /
585 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
587 /* TESTING -- this line replaces the prev. "suspect" if/else */
588 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
590 cpu[index].cpu_last_total = cpu[index].cpu_total;
591 cpu[index].cpu_last_active_total = cpu[index].cpu_active_total;
592 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
593 cpu[index].cpu_val[i] = cpu[index].cpu_val[i - 1];
600 void update_running_processes()
605 void update_cpu_usage()
610 void update_load_average()
612 #ifdef HAVE_GETLOADAVG
617 info.loadavg[0] = (float) v[0];
618 info.loadavg[1] = (float) v[1];
619 info.loadavg[2] = (float) v[2];
626 if (!(fp = open_file("/proc/loadavg", &rep))) {
627 info.loadavg[0] = info.loadavg[1] = info.loadavg[2] = 0.0;
630 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1],
634 info.mask |= (1 << INFO_LOADAVG);
637 #define PROC_I8K "/proc/i8k"
638 #define I8K_DELIM " "
639 static char *i8k_procbuf = NULL;
645 i8k_procbuf = (char *) malloc(128 * sizeof(char));
647 if ((fp = fopen(PROC_I8K, "r")) == NULL) {
648 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel "
649 "driver is loaded...");
652 memset(&i8k_procbuf[0], 0, 128);
653 if (fread(&i8k_procbuf[0], sizeof(char), 128, fp) == 0) {
654 ERR("something wrong with /proc/i8k...");
659 i8k.version = strtok(&i8k_procbuf[0], I8K_DELIM);
660 i8k.bios = strtok(NULL, I8K_DELIM);
661 i8k.serial = strtok(NULL, I8K_DELIM);
662 i8k.cpu_temp = strtok(NULL, I8K_DELIM);
663 i8k.left_fan_status = strtok(NULL, I8K_DELIM);
664 i8k.right_fan_status = strtok(NULL, I8K_DELIM);
665 i8k.left_fan_rpm = strtok(NULL, I8K_DELIM);
666 i8k.right_fan_rpm = strtok(NULL, I8K_DELIM);
667 i8k.ac_status = strtok(NULL, I8K_DELIM);
668 i8k.buttons_status = strtok(NULL, I8K_DELIM);
671 /***********************************************************/
672 /***********************************************************/
673 /***********************************************************/
675 static int no_dots(const struct dirent *d)
677 if (d->d_name[0] == '.') {
683 static int get_first_file_in_a_directory(const char *dir, char *s, int *rep)
685 struct dirent **namelist;
688 n = scandir(dir, &namelist, no_dots, alphasort);
691 ERR("scandir for %s: %s", dir, strerror(errno));
702 strncpy(s, namelist[0]->d_name, 255);
705 for (i = 0; i < n; i++) {
714 int open_sysfs_sensor(const char *dir, const char *dev, const char *type, int n,
715 int *div, char *devtype)
722 memset(buf, 0, sizeof(buf));
724 /* if device is NULL or *, get first */
725 if (dev == NULL || strcmp(dev, "*") == 0) {
728 if (!get_first_file_in_a_directory(dir, buf, &rep)) {
734 if (strcmp(dir, "/sys/class/hwmon/") == 0) {
736 /* buf holds result from get_first_file_in_a_directory() above,
737 * e.g. "hwmon0" -- append "/device" */
738 strcat(buf, "/device");
740 /* dev holds device number N as a string,
741 * e.g. "0", -- convert to "hwmon0/device" */
742 sprintf(buf, "hwmon%s/device", dev);
747 /* change vol to in */
748 if (strcmp(type, "vol") == 0) {
752 if (strcmp(type, "tempf") == 0) {
753 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, "temp", n);
755 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, type, n);
757 strncpy(devtype, path, 255);
760 fd = open(path, O_RDONLY);
762 CRIT_ERR("can't open '%s': %s\nplease check your device or remove this "
763 "var from Conky", path, strerror(errno));
766 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
767 || strcmp(type, "tempf") == 0) {
772 /* fan does not use *_div as a read divisor */
773 if (strcmp("fan", type) == 0) {
777 /* test if *_div file exist, open it and use it as divisor */
778 if (strcmp(type, "tempf") == 0) {
779 snprintf(path, 255, "%s%s/%s%d_div", dir, "one", "two", n);
781 snprintf(path, 255, "%s%s/%s%d_div", dir, dev, type, n);
784 divfd = open(path, O_RDONLY);
790 divn = read(divfd, divbuf, 63);
791 /* should read until n == 0 but I doubt that kernel will give these
792 * in multiple pieces. :) */
802 double get_sysfs_info(int *fd, int div, char *devtype, char *type)
810 lseek(*fd, 0, SEEK_SET);
816 n = read(*fd, buf, 63);
817 /* should read until n == 0 but I doubt that kernel will give these
818 * in multiple pieces. :) */
820 printf("get_sysfs_info(): read from %s failed\n", devtype);
829 *fd = open(devtype, O_RDONLY);
831 ERR("can't open '%s': %s", devtype, strerror(errno));
834 /* My dirty hack for computing CPU value
835 * Filedil, from forums.gentoo.org */
836 /* if (strstr(devtype, "temp1_input") != NULL) {
837 return -15.096 + 1.4893 * (val / 1000.0);
840 /* divide voltage and temperature by 1000 */
841 /* or if any other divisor is given, use that */
842 if (strcmp(type, "tempf") == 0) {
844 return ((val / div + 40) * 9.0 / 5) - 40;
846 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
848 return ((val + 40) * 9.0 / 5) - 40;
861 /* Prior to kernel version 2.6.12, the CPU fan speed was available in
862 * ADT746X_FAN_OLD, whereas later kernel versions provide this information in
864 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
865 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
867 void get_adt746x_fan(char *p_client_buffer, size_t client_buffer_size)
870 char adt746x_fan_state[64];
873 if (!p_client_buffer || client_buffer_size <= 0) {
877 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
878 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL) {
879 sprintf(adt746x_fan_state, "adt746x not found");
881 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
882 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
886 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_fan_state);
889 /* Prior to kernel version 2.6.12, the CPU temperature was found in
890 * ADT746X_CPU_OLD, whereas later kernel versions provide this information in
892 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
893 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
895 void get_adt746x_cpu(char *p_client_buffer, size_t client_buffer_size)
898 char adt746x_cpu_state[64];
901 if (!p_client_buffer || client_buffer_size <= 0) {
905 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
906 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL) {
907 sprintf(adt746x_cpu_state, "adt746x not found");
909 fscanf(fp, "%2s", adt746x_cpu_state);
913 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state);
916 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
918 /***********************************************************************/
919 /* This file is part of x86info.
920 * (C) 2001 Dave Jones.
922 * Licensed under the terms of the GNU GPL License version 2.
924 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
925 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz> */
927 #if defined(__i386) || defined(__x86_64)
928 __inline__ unsigned long long int rdtsc()
930 unsigned long long int x;
932 __asm__ volatile(".byte 0x0f, 0x31":"=A" (x));
937 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
938 void get_freq_dynamic(char *p_client_buffer, size_t client_buffer_size,
939 char *p_format, int divisor)
941 #if defined(__i386) || defined(__x86_64)
943 struct timeval tvstart, tvstop;
944 unsigned long long cycles[2]; /* gotta be 64 bit */
945 unsigned int microseconds; /* total time taken */
947 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
952 memset(&tz, 0, sizeof(tz));
954 /* get this function in cached memory */
955 gettimeofday(&tvstart, &tz);
957 gettimeofday(&tvstart, &tz);
959 /* we don't trust that this is any specific length of time */
962 gettimeofday(&tvstop, &tz);
963 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
964 (tvstop.tv_usec - tvstart.tv_usec);
966 snprintf(p_client_buffer, client_buffer_size, p_format,
967 (float) ((cycles[1] - cycles[0]) / microseconds) / divisor);
970 /* FIXME: hardwired: get freq for first cpu!
971 * this whole function needs to be rethought and redone for
972 * multi-cpu/multi-core/multi-threaded environments and
973 * arbitrary combinations thereof */
974 get_freq(p_client_buffer, client_buffer_size, p_format, divisor, 1);
979 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
980 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
982 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
983 char get_freq(char *p_client_buffer, size_t client_buffer_size, char *p_format,
984 int divisor, unsigned int cpu)
992 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
998 char current_freq_file[128];
1000 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu - 1,
1002 f = fopen(current_freq_file, "r");
1004 /* if there's a cpufreq /sys node, read the current frequency from
1005 * this node and divide by 1000 to get Mhz. */
1006 if (fgets(s, sizeof(s), f)) {
1007 s[strlen(s) - 1] = '\0';
1008 freq = strtod(s, NULL);
1011 snprintf(p_client_buffer, client_buffer_size, p_format,
1012 (freq / 1000) / divisor);
1017 // open the CPU information file
1018 f = open_file("/proc/cpuinfo", &rep);
1020 perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
1025 while (fgets(s, sizeof(s), f) != NULL) {
1027 #if defined(__i386) || defined(__x86_64)
1028 // and search for the cpu mhz
1029 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) {
1031 #if defined(__alpha)
1032 // different on alpha
1033 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) {
1035 // this is different on ppc for some reason
1036 if (strncmp(s, "clock", 5) == 0 && cpu == 0) {
1037 #endif // defined(__alpha)
1038 #endif // defined(__i386) || defined(__x86_64)
1040 // copy just the number
1041 strcpy(frequency, strchr(s, ':') + 2);
1042 #if defined(__alpha)
1044 frequency[strlen(frequency) - 6] = '\0';
1045 // kernel reports in Hz
1046 freq = strtod(frequency, NULL) / 1000000;
1049 frequency[strlen(frequency) - 1] = '\0';
1050 freq = strtod(frequency, NULL);
1054 if (strncmp(s, "processor", 9) == 0) {
1061 snprintf(p_client_buffer, client_buffer_size, p_format,
1062 (float) freq / divisor);
1066 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
1068 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks something
1078 * Peter Tarjan (ptarjan@citromail.hu) */
1080 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
1081 char get_voltage(char *p_client_buffer, size_t client_buffer_size,
1082 char *p_format, int divisor, unsigned int cpu)
1088 char current_freq_file[128];
1091 /* build the voltage file name */
1093 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1096 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1101 /* read the current cpu frequency from the /sys node */
1102 f = fopen(current_freq_file, "r");
1104 if (fgets(s, sizeof(s), f)) {
1105 s[strlen(s) - 1] = '\0';
1106 freq = strtod(s, NULL);
1110 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1111 perror("get_voltage()");
1118 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1121 /* use the current cpu frequency to find the corresponding voltage */
1122 f = fopen(current_freq_file, "r");
1128 if (fgets(line, 255, f) == NULL) {
1131 sscanf(line, "%d %d", &freq_comp, &voltage);
1132 if (freq_comp == freq) {
1138 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1139 perror("get_voltage()");
1145 snprintf(p_client_buffer, client_buffer_size, p_format,
1146 (float) voltage / divisor);
1150 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1152 void get_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
1159 if (!p_client_buffer || client_buffer_size <= 0) {
1163 /* yeah, slow... :/ */
1164 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep)) {
1165 snprintf(p_client_buffer, client_buffer_size, "no fans?");
1169 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf);
1171 fp = open_file(buf2, &rep);
1173 snprintf(p_client_buffer, client_buffer_size,
1174 "can't open fan's state file");
1177 memset(buf, 0, sizeof(buf));
1178 fscanf(fp, "%*s %99s", buf);
1181 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1184 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1186 void get_acpi_ac_adapter(char *p_client_buffer, size_t client_buffer_size)
1193 if (!p_client_buffer || client_buffer_size <= 0) {
1197 /* yeah, slow... :/ */
1198 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep)) {
1199 snprintf(p_client_buffer, client_buffer_size, "no ac_adapters?");
1203 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf);
1205 fp = open_file(buf2, &rep);
1207 snprintf(p_client_buffer, client_buffer_size,
1208 "No ac adapter found.... where is it?");
1211 memset(buf, 0, sizeof(buf));
1212 fscanf(fp, "%*s %99s", buf);
1215 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1219 /proc/acpi/thermal_zone/THRM/cooling_mode
1220 cooling mode: active
1221 /proc/acpi/thermal_zone/THRM/polling_frequency
1223 /proc/acpi/thermal_zone/THRM/state
1225 /proc/acpi/thermal_zone/THRM/temperature
1227 /proc/acpi/thermal_zone/THRM/trip_points
1229 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1232 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1233 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1235 int open_acpi_temperature(const char *name)
1241 if (name == NULL || strcmp(name, "*") == 0) {
1244 if (!get_first_file_in_a_directory(ACPI_THERMAL_DIR, buf, &rep)) {
1250 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1252 fd = open(path, O_RDONLY);
1254 ERR("can't open '%s': %s", path, strerror(errno));
1260 static double last_acpi_temp;
1261 static double last_acpi_temp_time;
1263 double get_acpi_temperature(int fd)
1269 /* don't update acpi temperature too often */
1270 if (current_update_time - last_acpi_temp_time < 11.32) {
1271 return last_acpi_temp;
1273 last_acpi_temp_time = current_update_time;
1275 /* seek to beginning */
1276 lseek(fd, 0, SEEK_SET);
1283 n = read(fd, buf, 255);
1285 ERR("can't read fd %d: %s", fd, strerror(errno));
1288 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1292 return last_acpi_temp;
1296 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1298 design capacity: 4400 mAh
1299 last full capacity: 4064 mAh
1300 battery technology: rechargeable
1301 design voltage: 14800 mV
1302 design capacity warning: 300 mAh
1303 design capacity low: 200 mAh
1304 capacity granularity 1: 32 mAh
1305 capacity granularity 2: 32 mAh
1307 serial number: 16922
1313 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1316 charging state: unknown
1318 remaining capacity: 4064 mAh
1319 present voltage: 16608 mV
1323 2213<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1324 2213<@jupet�kellari��> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1325 2213<@jupet�kellari��> (-1 ollee ei akkua kiinni, koska akku on p�yd�ll�)
1326 2214<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1327 2214<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1329 2238<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1330 2239<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1332 2240<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori p��ll�
1333 2241<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori p��ll� mutta ilman verkkovirtaa
1336 /* Kapil Hari Paranjape <kapil@imsc.res.in>
1337 Linux 2.6.24 onwards battery info is in
1338 /sys/class/power_supply/BAT0/
1339 On my system I get the following.
1340 /sys/class/power_supply/BAT0/uevent:
1341 PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A03:00/device:01/PNP0C09:00/PNP0C0A:00
1343 PHYSDEVDRIVER=battery
1344 POWER_SUPPLY_NAME=BAT0
1345 POWER_SUPPLY_TYPE=Battery
1346 POWER_SUPPLY_STATUS=Discharging
1347 POWER_SUPPLY_PRESENT=1
1348 POWER_SUPPLY_TECHNOLOGY=Li-ion
1349 POWER_SUPPLY_VOLTAGE_MIN_DESIGN=10800000
1350 POWER_SUPPLY_VOLTAGE_NOW=10780000
1351 POWER_SUPPLY_CURRENT_NOW=13970000
1352 POWER_SUPPLY_ENERGY_FULL_DESIGN=47510000
1353 POWER_SUPPLY_ENERGY_FULL=27370000
1354 POWER_SUPPLY_ENERGY_NOW=11810000
1355 POWER_SUPPLY_MODEL_NAME=IBM-92P1060
1356 POWER_SUPPLY_MANUFACTURER=Panasonic
1357 On some systems POWER_SUPPLY_ENERGY_* is replaced by POWER_SUPPLY_CHARGE_*
1360 #define SYSFS_BATTERY_BASE_PATH "/sys/class/power_supply"
1361 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1362 #define APM_PATH "/proc/apm"
1363 #define MAX_BATTERY_COUNT 4
1365 static FILE *sysfs_bat_fp[MAX_BATTERY_COUNT];
1366 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT];
1367 static FILE *apm_bat_fp[MAX_BATTERY_COUNT];
1369 static int batteries_initialized = 0;
1370 static char batteries[MAX_BATTERY_COUNT][32];
1372 static int acpi_last_full[MAX_BATTERY_COUNT];
1373 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1375 /* e.g. "charging 75%" */
1376 static char last_battery_str[MAX_BATTERY_COUNT][64];
1378 static char last_battery_time_str[MAX_BATTERY_COUNT][64];
1380 static double last_battery_time[MAX_BATTERY_COUNT];
1382 static int last_battery_perct[MAX_BATTERY_COUNT];
1383 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1385 void init_batteries(void)
1389 if (batteries_initialized) {
1392 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1393 batteries[idx][0] = '\0';
1395 batteries_initialized = 1;
1398 int get_battery_idx(const char *bat)
1402 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1403 if (!strlen(batteries[idx]) || !strcmp(batteries[idx], bat)) {
1408 /* if not found, enter a new entry */
1409 if (!strlen(batteries[idx])) {
1410 snprintf(batteries[idx], 31, "%s", bat);
1416 void get_battery_stuff(char *buf, unsigned int n, const char *bat, int item)
1418 static int idx, rep = 0, rep2 = 0;
1419 char acpi_path[128];
1421 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1422 char sysfs_path[128];
1423 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1427 idx = get_battery_idx(bat);
1429 /* don't update battery too often */
1430 if (current_update_time - last_battery_time[idx] < 29.5) {
1431 goto set_return_value;
1434 last_battery_time[idx] = current_update_time;
1436 memset(last_battery_str[idx], 0, sizeof(last_battery_str[idx]));
1437 memset(last_battery_time_str[idx], 0, sizeof(last_battery_time_str[idx]));
1439 /* first try SYSFS if that fails try ACPI */
1441 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1442 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1444 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1445 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1447 if (sysfs_bat_fp[idx] != NULL) {
1449 int present_rate = -1;
1450 int remaining_capacity = -1;
1451 char charging_state[64];
1454 strcpy(charging_state, "Unknown");
1456 while (!feof(sysfs_bat_fp[idx])) {
1458 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1461 /* let's just hope units are ok */
1462 if (strncmp (buf, "POWER_SUPPLY_PRESENT=1", 22) == 0)
1463 strcpy(present, "Yes");
1464 else if (strncmp (buf, "POWER_SUPPLY_PRESENT=0", 22) == 0)
1465 strcpy(present, "No");
1466 else if (strncmp (buf, "POWER_SUPPLY_STATUS=", 20) == 0)
1467 sscanf(buf, "POWER_SUPPLY_STATUS=%63s", charging_state);
1468 /* present_rate is not the same as the
1469 current flowing now but it is the same value
1470 which was used in the past. so we continue
1472 else if (strncmp(buf, "POWER_SUPPLY_CURRENT_NOW=", 25) == 0)
1473 sscanf(buf, "POWER_SUPPLY_CURRENT_NOW=%d", &present_rate);
1474 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0)
1475 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1476 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=", 25) == 0)
1477 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_last_full[idx]);
1478 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0)
1479 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1480 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=", 25) == 0)
1481 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_last_full[idx]);
1484 fclose(sysfs_bat_fp[idx]);
1485 sysfs_bat_fp[idx] = NULL;
1487 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1488 if (remaining_capacity > acpi_last_full[idx])
1489 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1492 if (strcmp(present, "No") == 0) {
1493 strncpy(last_battery_str[idx], "not present", 64);
1496 else if (strcmp(charging_state, "Charging") == 0) {
1497 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1498 /* e.g. charging 75% */
1499 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Charging %i%%",
1500 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1502 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1503 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1504 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1505 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Charging %d%%",
1506 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1508 strncpy(last_battery_str[idx], "Charging", sizeof(last_battery_str[idx])-1);
1512 else if (strncmp(charging_state, "Discharging", 64) == 0) {
1513 if (present_rate > 0) {
1514 /* e.g. discharging 35% */
1515 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Discharging %i%%",
1516 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1518 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1519 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1520 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1521 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Full");
1523 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1525 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1529 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1530 else if (strncmp(charging_state, "Charged", 64) == 0) {
1531 /* Below happens with the second battery on my X40,
1532 * when the second one is empty and the first one
1534 if (remaining_capacity == 0)
1535 strcpy(last_battery_str[idx], "Empty");
1537 strcpy(last_battery_str[idx], "Charged");
1539 /* unknown, probably full / AC */
1541 if (acpi_last_full[idx] != 0
1542 && remaining_capacity != acpi_last_full[idx])
1543 snprintf(last_battery_str[idx], 64, "Unknown %d%%",
1544 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1546 strncpy(last_battery_str[idx], "AC", 64);
1548 } else if (acpi_bat_fp[idx] != NULL) {
1550 int present_rate = -1;
1551 int remaining_capacity = -1;
1552 char charging_state[64];
1555 /* read last full capacity if it's zero */
1556 if (acpi_last_full[idx] == 0) {
1561 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1562 fp = open_file(path, &rep);
1567 if (fgets(b, 256, fp) == NULL) {
1570 if (sscanf(b, "last full capacity: %d",
1571 &acpi_last_full[idx]) != 0) {
1580 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1582 strcpy(charging_state, "unknown");
1584 while (!feof(acpi_bat_fp[idx])) {
1587 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1591 /* let's just hope units are ok */
1592 if (strncmp(buf, "present:", 8) == 0) {
1593 sscanf(buf, "present: %4s", present);
1594 } else if (strncmp(buf, "charging state:", 15) == 0) {
1595 sscanf(buf, "charging state: %63s", charging_state);
1596 } else if (strncmp(buf, "present rate:", 13) == 0) {
1597 sscanf(buf, "present rate: %d", &present_rate);
1598 } else if (strncmp(buf, "remaining capacity:", 19) == 0) {
1599 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1602 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1603 if (remaining_capacity > acpi_last_full[idx]) {
1604 /* normalize to 100% */
1605 acpi_last_full[idx] = remaining_capacity;
1609 if (strcmp(present, "no") == 0) {
1610 strncpy(last_battery_str[idx], "not present", 64);
1612 } else if (strcmp(charging_state, "charging") == 0) {
1613 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1614 /* e.g. charging 75% */
1615 snprintf(last_battery_str[idx],
1616 sizeof(last_battery_str[idx]) - 1, "charging %i%%",
1617 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1619 format_seconds(last_battery_time_str[idx],
1620 sizeof(last_battery_time_str[idx]) - 1,
1621 (long) (((acpi_last_full[idx] - remaining_capacity) *
1622 3600) / present_rate));
1623 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1624 snprintf(last_battery_str[idx],
1625 sizeof(last_battery_str[idx]) - 1, "charging %d%%",
1626 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1628 strncpy(last_battery_str[idx], "charging",
1629 sizeof(last_battery_str[idx]) - 1);
1632 } else if (strncmp(charging_state, "discharging", 64) == 0) {
1633 if (present_rate > 0) {
1634 /* e.g. discharging 35% */
1635 snprintf(last_battery_str[idx],
1636 sizeof(last_battery_str[idx]) - 1, "discharging %i%%",
1637 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1639 format_seconds(last_battery_time_str[idx],
1640 sizeof(last_battery_time_str[idx]) - 1,
1641 (long) ((remaining_capacity * 3600) / present_rate));
1642 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1643 snprintf(last_battery_str[idx],
1644 sizeof(last_battery_str[idx]) - 1, "full");
1646 snprintf(last_battery_str[idx],
1647 sizeof(last_battery_str[idx]) - 1, "discharging %d%%",
1648 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1651 } else if (strncmp(charging_state, "charged", 64) == 0) {
1652 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1653 /* Below happens with the second battery on my X40,
1654 * when the second one is empty and the first one being charged. */
1655 if (remaining_capacity == 0) {
1656 strcpy(last_battery_str[idx], "empty");
1658 strcpy(last_battery_str[idx], "charged");
1660 /* unknown, probably full / AC */
1662 if (acpi_last_full[idx] != 0
1663 && remaining_capacity != acpi_last_full[idx]) {
1664 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1665 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1667 strncpy(last_battery_str[idx], "AC", 64);
1672 if (apm_bat_fp[idx] == NULL) {
1673 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1676 if (apm_bat_fp[idx] != NULL) {
1677 int ac, status, flag, life;
1679 fscanf(apm_bat_fp[idx], "%*s %*s %*x %x %x %x %d%%",
1680 &ac, &status, &flag, &life);
1683 /* could check now that there is ac */
1684 snprintf(last_battery_str[idx], 64, "AC");
1686 /* could check that status == 3 here? */
1687 } else if (ac && life != 100) {
1688 snprintf(last_battery_str[idx], 64, "charging %d%%", life);
1690 snprintf(last_battery_str[idx], 64, "%d%%", life);
1693 /* it seemed to buffer it so file must be closed (or could use
1694 * syscalls directly but I don't feel like coding it now) */
1695 fclose(apm_bat_fp[idx]);
1696 apm_bat_fp[idx] = NULL;
1702 case BATTERY_STATUS:
1703 snprintf(buf, n, "%s", last_battery_str[idx]);
1706 snprintf(buf, n, "%s", last_battery_time_str[idx]);
1713 int get_battery_perct(const char *bat)
1717 char acpi_path[128];
1719 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1720 char sysfs_path[128];
1721 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1725 idx = get_battery_idx(bat);
1727 /* don't update battery too often */
1728 if (current_update_time - last_battery_perct_time[idx] < 30) {
1729 return last_battery_perct[idx];
1731 last_battery_perct_time[idx] = current_update_time;
1733 /* Only check for SYSFS or ACPI */
1735 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1736 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1738 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1739 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1741 int remaining_capacity = -1;
1743 if (sysfs_bat_fp[idx] != NULL) {
1745 while (!feof(sysfs_bat_fp[idx])) {
1747 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1750 if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0)
1751 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1752 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=",25) != 0)
1753 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_last_full[idx]);
1754 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0)
1755 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1756 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=",25) != 0)
1757 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_last_full[idx]);
1760 fclose(sysfs_bat_fp[idx]);
1761 sysfs_bat_fp[idx] = NULL;
1763 } else if (acpi_bat_fp[idx] != NULL) {
1765 /* read last full capacity if it's zero */
1766 if (acpi_design_capacity[idx] == 0) {
1771 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1772 fp = open_file(path, &rep);
1777 if (fgets(b, 256, fp) == NULL) {
1780 if (sscanf(b, "last full capacity: %d",
1781 &acpi_design_capacity[idx]) != 0) {
1789 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1791 while (!feof(acpi_bat_fp[idx])) {
1794 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1798 if (buf[0] == 'r') {
1799 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1803 if (remaining_capacity < 0) {
1806 /* compute the battery percentage */
1807 last_battery_perct[idx] =
1808 (int) (((float) remaining_capacity / acpi_design_capacity[idx]) * 100);
1809 return last_battery_perct[idx];
1812 int get_battery_perct_bar(const char *bar)
1816 get_battery_perct(bar);
1817 idx = get_battery_idx(bar);
1818 return (int) (last_battery_perct[idx] * 2.56 - 1);
1821 /* On Apple powerbook and ibook:
1822 $ cat /proc/pmu/battery_0
1829 $ cat /proc/pmu/info
1830 PMU driver version : 2
1831 PMU firmware version : 0c
1836 /* defines as in <linux/pmu.h> */
1837 #define PMU_BATT_PRESENT 0x00000001
1838 #define PMU_BATT_CHARGING 0x00000002
1840 static FILE *pmu_battery_fp;
1841 static FILE *pmu_info_fp;
1842 static char pb_battery_info[3][32];
1843 static double pb_battery_info_update;
1845 #define PMU_PATH "/proc/pmu"
1846 void get_powerbook_batt_info(char *buf, size_t n, int i)
1849 const char *batt_path = PMU_PATH "/battery_0";
1850 const char *info_path = PMU_PATH "/info";
1851 int flags, charge, max_charge, ac = -1;
1854 /* don't update battery too often */
1855 if (current_update_time - pb_battery_info_update < 29.5) {
1856 snprintf(buf, n, "%s", pb_battery_info[i]);
1859 pb_battery_info_update = current_update_time;
1861 if (pmu_battery_fp == NULL) {
1862 pmu_battery_fp = open_file(batt_path, &rep);
1865 if (pmu_battery_fp != NULL) {
1866 rewind(pmu_battery_fp);
1867 while (!feof(pmu_battery_fp)) {
1870 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL) {
1874 if (buf[0] == 'f') {
1875 sscanf(buf, "flags : %8x", &flags);
1876 } else if (buf[0] == 'c' && buf[1] == 'h') {
1877 sscanf(buf, "charge : %d", &charge);
1878 } else if (buf[0] == 'm') {
1879 sscanf(buf, "max_charge : %d", &max_charge);
1880 } else if (buf[0] == 't') {
1881 sscanf(buf, "time rem. : %ld", &time);
1885 if (pmu_info_fp == NULL) {
1886 pmu_info_fp = open_file(info_path, &rep);
1889 if (pmu_info_fp != NULL) {
1890 rewind(pmu_info_fp);
1891 while (!feof(pmu_info_fp)) {
1894 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL) {
1897 if (buf[0] == 'A') {
1898 sscanf(buf, "AC Power : %d", &ac);
1902 /* update status string */
1903 if ((ac && !(flags & PMU_BATT_PRESENT))) {
1904 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
1905 } else if (ac && (flags & PMU_BATT_PRESENT)
1906 && !(flags & PMU_BATT_CHARGING)) {
1907 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
1908 } else if ((flags & PMU_BATT_PRESENT) && (flags & PMU_BATT_CHARGING)) {
1909 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
1911 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
1914 /* update percentage string */
1916 pb_battery_info[PB_BATT_PERCENT][0] = 0;
1918 snprintf(pb_battery_info[PB_BATT_PERCENT],
1919 sizeof(pb_battery_info[PB_BATT_PERCENT]), "%d%%",
1920 (charge * 100) / max_charge);
1923 /* update time string */
1924 if (time == 0) { /* fully charged or battery not present */
1925 pb_battery_info[PB_BATT_TIME][0] = 0;
1926 } else if (time < 60 * 60) { /* don't show secs */
1927 format_seconds_short(pb_battery_info[PB_BATT_TIME],
1928 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1930 format_seconds(pb_battery_info[PB_BATT_TIME],
1931 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1934 snprintf(buf, n, "%s", pb_battery_info[i]);
1939 show_nice_processes = 1;
1940 process_find_top(info.cpu, info.memu);
1941 info.first_process = get_first_process();
1944 /* The following ifdefs were adapted from gkrellm */
1945 #include <linux/major.h>
1947 #if !defined(MD_MAJOR)
1951 #if !defined(LVM_BLK_MAJOR)
1952 #define LVM_BLK_MAJOR 58
1955 #if !defined(NBD_MAJOR)
1956 #define NBD_MAJOR 43
1959 void update_diskio()
1961 static unsigned int last = UINT_MAX;
1962 static unsigned int last_read = UINT_MAX;
1963 static unsigned int last_write = UINT_MAX;
1967 char buf[512], devbuf[64];
1968 int major, minor, i;
1969 unsigned int current = 0;
1970 unsigned int current_read = 0;
1971 unsigned int current_write = 0;
1972 unsigned int reads, writes = 0;
1975 if (!(fp = open_file("/proc/diskstats", &rep))) {
1980 /* read reads and writes from all disks (minor = 0), including cd-roms
1981 * and floppies, and sum them up */
1983 fgets(buf, 512, fp);
1984 col_count = sscanf(buf, "%u %u %s %*u %*u %u %*u %*u %*u %u", &major,
1985 &minor, devbuf, &reads, &writes);
1986 /* ignore subdevices (they have only 3 matching entries in their line)
1987 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
1989 * XXX: ignore devices which are part of a SW RAID (MD_MAJOR) */
1990 if (col_count == 5 && major != LVM_BLK_MAJOR && major != NBD_MAJOR
1991 && major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
1992 current += reads + writes;
1993 current_read += reads;
1994 current_write += writes;
1996 col_count = sscanf(buf, "%u %u %s %*u %u %*u %u",
1997 &major, &minor, devbuf, &reads, &writes);
1998 if (col_count != 5) {
2002 for (i = 0; i < MAX_DISKIO_STATS; i++) {
2003 if (diskio_stats[i].dev &&
2004 strcmp(devbuf, diskio_stats[i].dev) == 0) {
2005 diskio_stats[i].current =
2006 (reads + writes - diskio_stats[i].last) / 2;
2007 diskio_stats[i].current_read =
2008 (reads - diskio_stats[i].last_read) / 2;
2009 diskio_stats[i].current_write =
2010 (writes - diskio_stats[i].last_write) / 2;
2011 if (reads + writes < diskio_stats[i].last) {
2012 diskio_stats[i].current = 0;
2014 if (reads < diskio_stats[i].last_read) {
2015 diskio_stats[i].current_read = 0;
2016 diskio_stats[i].current = diskio_stats[i].current_write;
2018 if (writes < diskio_stats[i].last_write) {
2019 diskio_stats[i].current_write = 0;
2020 diskio_stats[i].current = diskio_stats[i].current_read;
2022 diskio_stats[i].last = reads + writes;
2023 diskio_stats[i].last_read = reads;
2024 diskio_stats[i].last_write = writes;
2029 /* since the values in /proc/diststats are absolute, we have to substract
2030 * our last reading. The numbers stand for "sectors read", and we therefore
2031 * have to divide by two to get KB */
2032 int tot = ((double) (current - last) / 2);
2033 int tot_read = ((double) (current_read - last_read) / 2);
2034 int tot_write = ((double) (current_write - last_write) / 2);
2036 if (last_read > current_read) {
2039 if (last_write > current_write) {
2043 if (last > current) {
2044 /* we hit this either if it's the very first time we run this, or
2045 * when /proc/diskstats overflows; while 0 is not correct, it's at
2046 * least not way off */
2050 last_read = current_read;
2051 last_write = current_write;
2054 diskio_read_value = tot_read;
2055 diskio_write_value = tot_write;
2060 /* Here come the IBM ACPI-specific things. For reference, see
2061 * http://ibm-acpi.sourceforge.net/README
2062 * If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
2078 * The content of these files is described in detail in the aforementioned
2079 * README - some of them also in the following functions accessing them.
2080 * Peter Tarjan (ptarjan@citromail.hu) */
2082 #define IBM_ACPI_DIR "/proc/acpi/ibm"
2084 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
2085 * /proc/acpi/ibm/fan looks like this (3 lines):
2088 commands: enable, disable
2089 * Peter Tarjan (ptarjan@citromail.hu) */
2091 void get_ibm_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
2093 if (!p_client_buffer || client_buffer_size <= 0) {
2098 unsigned int speed = 0;
2101 snprintf(fan, 127, "%s/fan", IBM_ACPI_DIR);
2103 fp = fopen(fan, "r");
2108 if (fgets(line, 255, fp) == NULL) {
2111 if (sscanf(line, "speed: %d", &speed)) {
2116 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2117 "ibm* from your Conky config file.", fan, strerror(errno));
2121 snprintf(p_client_buffer, client_buffer_size, "%d", speed);
2124 /* get the measured temperatures from the temperature sensors
2125 * on IBM/Lenovo laptops running the ibm acpi.
2126 * There are 8 values in /proc/acpi/ibm/thermal, and according to
2127 * http://ibm-acpi.sourceforge.net/README
2128 * these mean the following (at least on an IBM R51...)
2129 * 0: CPU (also on the T series laptops)
2130 * 1: Mini PCI Module (?)
2132 * 3: GPU (also on the T series laptops)
2137 * I'm not too sure about those with the question mark, but the values I'm
2138 * reading from *my* thermal file (on a T42p) look realistic for the
2139 * hdd and the battery.
2140 * #5 and #7 are always -128.
2141 * /proc/acpi/ibm/thermal looks like this (1 line):
2142 temperatures: 41 43 31 46 33 -128 29 -128
2143 * Peter Tarjan (ptarjan@citromail.hu) */
2145 static double last_ibm_acpi_temp_time;
2146 void get_ibm_acpi_temps()
2149 /* don't update too often */
2150 if (current_update_time - last_ibm_acpi_temp_time < 10.00) {
2153 last_ibm_acpi_temp_time = current_update_time;
2155 /* if (!p_client_buffer || client_buffer_size <= 0) {
2163 snprintf(thermal, 127, "%s/thermal", IBM_ACPI_DIR);
2164 fp = fopen(thermal, "r");
2170 if (fgets(line, 255, fp) == NULL) {
2173 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
2174 &ibm_acpi.temps[0], &ibm_acpi.temps[1], &ibm_acpi.temps[2],
2175 &ibm_acpi.temps[3], &ibm_acpi.temps[4], &ibm_acpi.temps[5],
2176 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) {
2181 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2182 "ibm* from your Conky config file.", thermal, strerror(errno));
2188 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
2189 * "Volume" here is none of the mixer volumes, but a "master of masters"
2190 * volume adjusted by the IBM volume keys.
2191 * /proc/acpi/ibm/fan looks like this (4 lines):
2194 commands: up, down, mute
2195 commands: level <level> (<level> is 0-15)
2196 * Peter Tarjan (ptarjan@citromail.hu) */
2198 void get_ibm_acpi_volume(char *p_client_buffer, size_t client_buffer_size)
2200 if (!p_client_buffer || client_buffer_size <= 0) {
2208 snprintf(volume, 127, "%s/volume", IBM_ACPI_DIR);
2209 unsigned int vol = -1;
2212 fp = fopen(volume, "r");
2216 unsigned int read_vol = -1;
2218 if (fgets(line, 255, fp) == NULL) {
2221 if (sscanf(line, "level: %d", &read_vol)) {
2225 if (sscanf(line, "mute: %s", mute)) {
2230 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2231 "ibm* from your Conky config file.", volume, strerror(errno));
2236 if (strcmp(mute, "on") == 0) {
2237 snprintf(p_client_buffer, client_buffer_size, "%s", "mute");
2240 snprintf(p_client_buffer, client_buffer_size, "%d", vol);
2245 /* static FILE *fp = NULL; */
2247 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
2248 * /proc/acpi/ibm/brightness looks like this (3 lines):
2251 commands: level <level> (<level> is 0-7)
2252 * Peter Tarjan (ptarjan@citromail.hu) */
2254 void get_ibm_acpi_brightness(char *p_client_buffer, size_t client_buffer_size)
2256 if (!p_client_buffer || client_buffer_size <= 0) {
2261 unsigned int brightness = 0;
2264 snprintf(filename, 127, "%s/brightness", IBM_ACPI_DIR);
2266 fp = fopen(filename, "r");
2271 if (fgets(line, 255, fp) == NULL) {
2274 if (sscanf(line, "level: %d", &brightness)) {
2279 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2280 "ibm* from your Conky config file.", filename, strerror(errno));
2285 snprintf(p_client_buffer, client_buffer_size, "%d", brightness);
2288 void update_entropy(void)
2291 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
2292 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
2295 info.entropy.entropy_avail = 0;
2296 info.entropy.poolsize = 0;
2298 if ((fp1 = open_file(entropy_avail, &rep)) == NULL) {
2302 if ((fp2 = open_file(entropy_poolsize, &rep)) == NULL) {
2307 fscanf(fp1, "%u", &info.entropy.entropy_avail);
2308 fscanf(fp2, "%u", &info.entropy.poolsize);
2313 info.mask |= (1 << INFO_ENTROPY);