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>
54 #include <arpa/inet.h>
55 #include <linux/route.h>
62 #define SHORTSTAT_TEMPL "%*s %llu %llu %llu"
63 #define LONGSTAT_TEMPL "%*s %llu %llu %llu "
65 static int show_nice_processes;
67 /* This flag tells the linux routines to use the /proc system where possible,
68 * even if other api's are available, e.g. sysinfo() or getloadavg().
69 * the reason for this is to allow for /proc-based distributed monitoring.
70 * using a flag in this manner creates less confusing code. */
71 static int prefer_proc = 0;
81 struct sysinfo s_info;
84 info.uptime = (double) s_info.uptime;
91 if (!(fp = open_file("/proc/uptime", &rep))) {
95 fscanf(fp, "%lf", &info.uptime);
98 info.mask |= (1 << INFO_UPTIME);
101 int check_mount(char *s)
104 FILE *mtab = fopen("/etc/mtab", "r");
107 char buf1[256], buf2[128];
109 while (fgets(buf1, 256, mtab)) {
110 sscanf(buf1, "%*s %128s", buf2);
111 if (!strcmp(s, buf2)) {
118 ERR("Could not open mtab");
123 /* these things are also in sysinfo except Buffers:
124 * (that's why I'm reading them from proc) */
126 void update_meminfo()
131 /* unsigned int a; */
134 info.mem = info.memmax = info.swap = info.swapmax = info.bufmem =
135 info.buffers = info.cached = 0;
137 if (!(meminfo_fp = open_file("/proc/meminfo", &rep))) {
141 while (!feof(meminfo_fp)) {
142 if (fgets(buf, 255, meminfo_fp) == NULL) {
146 if (strncmp(buf, "MemTotal:", 9) == 0) {
147 sscanf(buf, "%*s %Lu", &info.memmax);
148 } else if (strncmp(buf, "MemFree:", 8) == 0) {
149 sscanf(buf, "%*s %Lu", &info.mem);
150 } else if (strncmp(buf, "SwapTotal:", 10) == 0) {
151 sscanf(buf, "%*s %Lu", &info.swapmax);
152 } else if (strncmp(buf, "SwapFree:", 9) == 0) {
153 sscanf(buf, "%*s %Lu", &info.swap);
154 } else if (strncmp(buf, "Buffers:", 8) == 0) {
155 sscanf(buf, "%*s %Lu", &info.buffers);
156 } else if (strncmp(buf, "Cached:", 7) == 0) {
157 sscanf(buf, "%*s %Lu", &info.cached);
161 info.mem = info.memmax - info.mem;
162 info.swap = info.swapmax - info.swap;
164 info.bufmem = info.cached + info.buffers;
166 info.mask |= (1 << INFO_MEM) | (1 << INFO_BUFFERS);
171 int get_laptop_mode()
176 if ((fp = fopen("/proc/sys/vm/laptop_mode", "r")) != NULL)
177 fscanf(fp, "%d\n", &val);
181 int interface_up(const char *dev)
186 if((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
187 CRIT_ERR("could not create sockfd");
190 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
191 if(ioctl(fd, SIOCGIFFLAGS, &ifr)) {
192 /* if device does not exist, treat like not up */
194 perror("SIOCGIFFLAGS");
197 return (ifr.ifr_flags & IFF_UP);
203 #define COND_FREE(x) if(x) free(x); x = 0
204 #define SAVE_SET_STRING(x, y) \
205 if (x && strcmp((char *)x, (char *)y)) { \
207 x = strdup("multiple"); \
212 void update_gateway_info()
217 unsigned long dest, gate, mask;
219 short ref, use, metric, mtu, win, irtt;
221 struct gateway_info *gw_info = &info.gw_info;
223 COND_FREE(gw_info->iface);
224 COND_FREE(gw_info->ip);
227 if ((fp = fopen("/proc/net/route", "r")) == NULL) {
231 if (fscanf(fp, "%*[^\n]\n") == EOF) {
236 // Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
237 if(fscanf(fp, "%63s %lx %lx %x %hd %hd %hd %lx %hd %hd %hd\n",
238 iface, &dest, &gate, &flags, &ref, &use,
239 &metric, &mask, &mtu, &win, &irtt) != 11) {
243 if (flags & RTF_GATEWAY && dest == 0 && mask == 0) {
245 SAVE_SET_STRING(gw_info->iface, iface)
247 SAVE_SET_STRING(gw_info->ip, inet_ntoa(ina))
255 info.gw_info.iface = info.gw_info.ip = strdup("failed");
259 inline void update_net_stats()
264 // FIXME: arbitrary size chosen to keep code simple.
266 unsigned int curtmp1, curtmp2;
273 // wireless info variables
274 int skfd, has_bitrate = 0;
275 struct wireless_info *winfo;
280 delta = current_update_time - last_update_time;
281 if (delta <= 0.0001) {
285 /* open file and ignore first two lines */
286 if (!(net_dev_fp = open_file("/proc/net/dev", &rep))) {
291 fgets(buf, 255, net_dev_fp); /* garbage */
292 fgets(buf, 255, net_dev_fp); /* garbage (field names) */
294 /* read each interface */
295 for (i2 = 0; i2 < 16; i2++) {
299 long long r, t, last_recv, last_trans;
301 if (fgets(buf, 255, net_dev_fp) == NULL) {
305 while (isspace((int) *p)) {
311 while (*p && *p != ':') {
320 ns = get_net_stat(s);
322 memset(&(ns->addr.sa_data), 0, 14);
324 if(NULL == ns->addrs)
325 ns->addrs = (char*) malloc(17 * 16);
326 if(NULL != ns->addrs)
327 memset(ns->addrs, 0, 17 * 16); /* Up to 17 chars per ip, max 16 interfaces. Nasty memory usage... */
329 last_recv = ns->recv;
330 last_trans = ns->trans;
332 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
333 sscanf(p, "%Ld %*d %*d %*d %*d %*d %*d %*d %Ld",
336 /* if recv or trans is less than last time, an overflow happened */
337 if (r < ns->last_read_recv) {
340 ns->recv += (r - ns->last_read_recv);
342 ns->last_read_recv = r;
344 if (t < ns->last_read_trans) {
347 ns->trans += (t - ns->last_read_trans);
349 ns->last_read_trans = t;
351 /*** ip addr patch ***/
352 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
354 conf.ifc_buf = malloc(sizeof(struct ifreq) * 16);
356 conf.ifc_len = sizeof(struct ifreq) * 16;
358 ioctl((long) i, SIOCGIFCONF, &conf);
360 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
364 ((struct ifreq *) conf.ifc_buf)[k].ifr_ifrn.ifrn_name);
365 ns->addr = ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.ifru_addr;
366 if(NULL != ns->addrs)
368 sprintf(temp_addr, "%u.%u.%u.%u, ",
369 ns->addr.sa_data[2] & 255,
370 ns->addr.sa_data[3] & 255,
371 ns->addr.sa_data[4] & 255,
372 ns->addr.sa_data[5] & 255);
373 if(NULL == strstr(ns->addrs, temp_addr))
374 strncpy(ns->addrs + strlen(ns->addrs), temp_addr, 17);
382 /*** end ip addr patch ***/
384 /* calculate speeds */
385 ns->net_rec[0] = (ns->recv - last_recv) / delta;
386 ns->net_trans[0] = (ns->trans - last_trans) / delta;
390 for (i = 0; (unsigned) i < info.net_avg_samples; i++) {
391 curtmp1 += ns->net_rec[i];
392 curtmp2 += ns->net_trans[i];
400 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
401 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
402 if (info.net_avg_samples > 1) {
403 for (i = info.net_avg_samples; i > 1; i--) {
404 ns->net_rec[i - 1] = ns->net_rec[i - 2];
405 ns->net_trans[i - 1] = ns->net_trans[i - 2];
410 /* update wireless info */
411 winfo = malloc(sizeof(struct wireless_info));
412 memset(winfo, 0, sizeof(struct wireless_info));
414 skfd = iw_sockets_open();
415 if (iw_get_basic_config(skfd, s, &(winfo->b)) > -1) {
417 // set present winfo variables
418 if (iw_get_stats(skfd, s, &(winfo->stats),
419 &winfo->range, winfo->has_range) >= 0) {
420 winfo->has_stats = 1;
422 if (iw_get_range_info(skfd, s, &(winfo->range)) >= 0) {
423 winfo->has_range = 1;
425 if (iw_get_ext(skfd, s, SIOCGIWAP, &wrq) >= 0) {
426 winfo->has_ap_addr = 1;
427 memcpy(&(winfo->ap_addr), &(wrq.u.ap_addr), sizeof(sockaddr));
431 if (iw_get_ext(skfd, s, SIOCGIWRATE, &wrq) >= 0) {
432 memcpy(&(winfo->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
433 iw_print_bitrate(ns->bitrate, 16, winfo->bitrate.value);
438 if (winfo->has_range && winfo->has_stats
439 && ((winfo->stats.qual.level != 0)
440 || (winfo->stats.qual.updated & IW_QUAL_DBM))) {
441 if (!(winfo->stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
442 ns->link_qual = winfo->stats.qual.qual;
443 ns->link_qual_max = winfo->range.max_qual.qual;
448 if (winfo->has_ap_addr) {
449 iw_sawap_ntop(&winfo->ap_addr, ns->ap);
453 if (winfo->b.has_essid) {
454 if (winfo->b.essid_on) {
455 snprintf(ns->essid, 32, "%s", winfo->b.essid);
457 snprintf(ns->essid, 32, "off/any");
461 snprintf(ns->mode, 16, "%s", iw_operation_mode[winfo->b.mode]);
463 iw_sockets_close(skfd);
470 info.mask |= (1 << INFO_NET);
475 void update_total_processes()
479 struct sysinfo s_info;
482 info.procs = s_info.procs;
489 if (!(fp = open_file("/proc/loadavg", &rep))) {
493 fscanf(fp, "%*f %*f %*f %*d/%hd", &info.procs);
496 info.mask |= (1 << INFO_PROCS);
499 #define CPU_SAMPLE_COUNT 15
501 unsigned long long cpu_user;
502 unsigned long long cpu_system;
503 unsigned long long cpu_nice;
504 unsigned long long cpu_idle;
505 unsigned long long cpu_iowait;
506 unsigned long long cpu_irq;
507 unsigned long long cpu_softirq;
508 unsigned long long cpu_steal;
509 unsigned long long cpu_total;
510 unsigned long long cpu_active_total;
511 unsigned long long cpu_last_total;
512 unsigned long long cpu_last_active_total;
513 double cpu_val[CPU_SAMPLE_COUNT];
515 static short cpu_setup = 0;
517 /* Determine if this kernel gives us "extended" statistics information in
519 * Kernels around 2.5 and earlier only reported user, system, nice, and
520 * idle values in proc stat.
521 * Kernels around 2.6 and greater report these PLUS iowait, irq, softirq,
523 void determine_longstat(char *buf)
525 unsigned long long iowait = 0;
527 KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
528 /* scanf will either return -1 or 1 because there is only 1 assignment */
529 if (sscanf(buf, "%*s %*d %*d %*d %*d %llu", &iowait) > 0) {
530 KFLAG_SETON(KFLAG_IS_LONGSTAT);
539 if (info.cpu_usage) {
544 if (!(stat_fp = open_file("/proc/stat", &rep))) {
550 while (!feof(stat_fp)) {
551 if (fgets(buf, 255, stat_fp) == NULL) {
555 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
556 if (info.cpu_count == 0) {
557 determine_longstat(buf);
562 info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
567 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
568 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
570 inline static void update_stat()
574 static struct cpu_info *cpu = NULL;
579 char *stat_template = NULL;
580 unsigned int malloc_cpu_size = 0;
582 /* add check for !info.cpu_usage since that mem is freed on a SIGUSR1 */
583 if (!cpu_setup || !info.cpu_usage) {
588 if (!stat_template) {
590 KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT;
594 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
595 cpu = malloc(malloc_cpu_size);
596 memset(cpu, 0, malloc_cpu_size);
599 if (!(stat_fp = open_file("/proc/stat", &rep))) {
601 if (info.cpu_usage) {
602 memset(info.cpu_usage, 0, info.cpu_count * sizeof(float));
608 while (!feof(stat_fp)) {
609 if (fgets(buf, 255, stat_fp) == NULL) {
613 if (strncmp(buf, "procs_running ", 14) == 0) {
614 sscanf(buf, "%*s %hu", &info.run_procs);
615 info.mask |= (1 << INFO_RUN_PROCS);
616 } else if (strncmp(buf, "cpu", 3) == 0) {
617 index = isdigit(buf[3]) ? ((int) buf[3]) - 0x2F : 0;
618 sscanf(buf, stat_template, &(cpu[index].cpu_user),
619 &(cpu[index].cpu_nice), &(cpu[index].cpu_system),
620 &(cpu[index].cpu_idle), &(cpu[index].cpu_iowait),
621 &(cpu[index].cpu_irq), &(cpu[index].cpu_softirq),
622 &(cpu[index].cpu_steal));
624 cpu[index].cpu_total = cpu[index].cpu_user + cpu[index].cpu_nice +
625 cpu[index].cpu_system + cpu[index].cpu_idle +
626 cpu[index].cpu_iowait + cpu[index].cpu_irq +
627 cpu[index].cpu_softirq + cpu[index].cpu_steal;
629 cpu[index].cpu_active_total = cpu[index].cpu_total -
630 (cpu[index].cpu_idle + cpu[index].cpu_iowait);
631 info.mask |= (1 << INFO_CPU);
633 double delta = current_update_time - last_update_time;
635 if (delta <= 0.001) {
639 cpu[index].cpu_val[0] = (cpu[index].cpu_active_total -
640 cpu[index].cpu_last_active_total) /
641 (float) (cpu[index].cpu_total - cpu[index].cpu_last_total);
643 for (i = 0; i < info.cpu_avg_samples; i++) {
644 curtmp += cpu[index].cpu_val[i];
646 /* TESTING -- I've removed this, because I don't think it is right.
647 * You shouldn't divide by the cpu count here ...
648 * removing for testing */
650 info.cpu_usage[index] = curtmp / info.cpu_avg_samples /
653 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
655 /* TESTING -- this line replaces the prev. "suspect" if/else */
656 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
658 cpu[index].cpu_last_total = cpu[index].cpu_total;
659 cpu[index].cpu_last_active_total = cpu[index].cpu_active_total;
660 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
661 cpu[index].cpu_val[i] = cpu[index].cpu_val[i - 1];
668 void update_running_processes()
673 void update_cpu_usage()
678 void update_load_average()
680 #ifdef HAVE_GETLOADAVG
685 info.loadavg[0] = (float) v[0];
686 info.loadavg[1] = (float) v[1];
687 info.loadavg[2] = (float) v[2];
694 if (!(fp = open_file("/proc/loadavg", &rep))) {
695 info.loadavg[0] = info.loadavg[1] = info.loadavg[2] = 0.0;
698 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1],
702 info.mask |= (1 << INFO_LOADAVG);
705 #define PROC_I8K "/proc/i8k"
706 #define I8K_DELIM " "
707 static char *i8k_procbuf = NULL;
713 i8k_procbuf = (char *) malloc(128 * sizeof(char));
715 if ((fp = fopen(PROC_I8K, "r")) == NULL) {
716 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel "
717 "driver is loaded...");
720 memset(&i8k_procbuf[0], 0, 128);
721 if (fread(&i8k_procbuf[0], sizeof(char), 128, fp) == 0) {
722 ERR("something wrong with /proc/i8k...");
727 i8k.version = strtok(&i8k_procbuf[0], I8K_DELIM);
728 i8k.bios = strtok(NULL, I8K_DELIM);
729 i8k.serial = strtok(NULL, I8K_DELIM);
730 i8k.cpu_temp = strtok(NULL, I8K_DELIM);
731 i8k.left_fan_status = strtok(NULL, I8K_DELIM);
732 i8k.right_fan_status = strtok(NULL, I8K_DELIM);
733 i8k.left_fan_rpm = strtok(NULL, I8K_DELIM);
734 i8k.right_fan_rpm = strtok(NULL, I8K_DELIM);
735 i8k.ac_status = strtok(NULL, I8K_DELIM);
736 i8k.buttons_status = strtok(NULL, I8K_DELIM);
739 /***********************************************************/
740 /***********************************************************/
741 /***********************************************************/
743 static int no_dots(const struct dirent *d)
745 if (d->d_name[0] == '.') {
751 static int get_first_file_in_a_directory(const char *dir, char *s, int *rep)
753 struct dirent **namelist;
756 n = scandir(dir, &namelist, no_dots, alphasort);
759 ERR("scandir for %s: %s", dir, strerror(errno));
770 strncpy(s, namelist[0]->d_name, 255);
773 for (i = 0; i < n; i++) {
782 int open_sysfs_sensor(const char *dir, const char *dev, const char *type, int n,
783 int *div, char *devtype)
790 memset(buf, 0, sizeof(buf));
792 /* if device is NULL or *, get first */
793 if (dev == NULL || strcmp(dev, "*") == 0) {
796 if (!get_first_file_in_a_directory(dir, buf, &rep)) {
802 if (strcmp(dir, "/sys/class/hwmon/") == 0) {
804 /* buf holds result from get_first_file_in_a_directory() above,
805 * e.g. "hwmon0" -- append "/device" */
806 strcat(buf, "/device");
808 /* dev holds device number N as a string,
809 * e.g. "0", -- convert to "hwmon0/device" */
810 sprintf(buf, "hwmon%s/device", dev);
815 /* change vol to in */
816 if (strcmp(type, "vol") == 0) {
820 if (strcmp(type, "tempf") == 0) {
821 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, "temp", n);
823 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, type, n);
825 strncpy(devtype, path, 255);
828 fd = open(path, O_RDONLY);
830 CRIT_ERR("can't open '%s': %s\nplease check your device or remove this "
831 "var from Conky", path, strerror(errno));
834 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
835 || strcmp(type, "tempf") == 0) {
840 /* fan does not use *_div as a read divisor */
841 if (strcmp("fan", type) == 0) {
845 /* test if *_div file exist, open it and use it as divisor */
846 if (strcmp(type, "tempf") == 0) {
847 snprintf(path, 255, "%s%s/%s%d_div", dir, "one", "two", n);
849 snprintf(path, 255, "%s%s/%s%d_div", dir, dev, type, n);
852 divfd = open(path, O_RDONLY);
858 divn = read(divfd, divbuf, 63);
859 /* should read until n == 0 but I doubt that kernel will give these
860 * in multiple pieces. :) */
862 ERR("open_sysfs_sensor(): can't read from sysfs");
874 double get_sysfs_info(int *fd, int div, char *devtype, char *type)
882 lseek(*fd, 0, SEEK_SET);
888 n = read(*fd, buf, 63);
889 /* should read until n == 0 but I doubt that kernel will give these
890 * in multiple pieces. :) */
892 ERR("get_sysfs_info(): read from %s failed\n", devtype);
901 *fd = open(devtype, O_RDONLY);
903 ERR("can't open '%s': %s", devtype, strerror(errno));
906 /* My dirty hack for computing CPU value
907 * Filedil, from forums.gentoo.org */
908 /* if (strstr(devtype, "temp1_input") != NULL) {
909 return -15.096 + 1.4893 * (val / 1000.0);
912 /* divide voltage and temperature by 1000 */
913 /* or if any other divisor is given, use that */
914 if (strcmp(type, "tempf") == 0) {
916 return ((val / div + 40) * 9.0 / 5) - 40;
918 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
920 return ((val + 40) * 9.0 / 5) - 40;
933 /* Prior to kernel version 2.6.12, the CPU fan speed was available in
934 * ADT746X_FAN_OLD, whereas later kernel versions provide this information in
936 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
937 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
939 void get_adt746x_fan(char *p_client_buffer, size_t client_buffer_size)
942 char adt746x_fan_state[64];
945 if (!p_client_buffer || client_buffer_size <= 0) {
949 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
950 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL) {
951 sprintf(adt746x_fan_state, "adt746x not found");
953 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
954 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
958 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_fan_state);
961 /* Prior to kernel version 2.6.12, the CPU temperature was found in
962 * ADT746X_CPU_OLD, whereas later kernel versions provide this information in
964 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
965 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
967 void get_adt746x_cpu(char *p_client_buffer, size_t client_buffer_size)
970 char adt746x_cpu_state[64];
973 if (!p_client_buffer || client_buffer_size <= 0) {
977 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
978 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL) {
979 sprintf(adt746x_cpu_state, "adt746x not found");
981 fscanf(fp, "%2s", adt746x_cpu_state);
985 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state);
988 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
990 /***********************************************************************/
991 /* This file is part of x86info.
992 * (C) 2001 Dave Jones.
994 * Licensed under the terms of the GNU GPL License version 2.
996 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
997 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz> */
999 #if defined(__i386) || defined(__x86_64)
1000 __inline__ unsigned long long int rdtsc()
1002 unsigned long long int x;
1004 __asm__ volatile(".byte 0x0f, 0x31":"=A" (x));
1009 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1010 void get_freq_dynamic(char *p_client_buffer, size_t client_buffer_size,
1011 char *p_format, int divisor)
1013 #if defined(__i386) || defined(__x86_64)
1015 struct timeval tvstart, tvstop;
1016 unsigned long long cycles[2]; /* gotta be 64 bit */
1017 unsigned int microseconds; /* total time taken */
1019 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1024 memset(&tz, 0, sizeof(tz));
1026 /* get this function in cached memory */
1027 gettimeofday(&tvstart, &tz);
1028 cycles[0] = rdtsc();
1029 gettimeofday(&tvstart, &tz);
1031 /* we don't trust that this is any specific length of time */
1033 cycles[1] = rdtsc();
1034 gettimeofday(&tvstop, &tz);
1035 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
1036 (tvstop.tv_usec - tvstart.tv_usec);
1038 snprintf(p_client_buffer, client_buffer_size, p_format,
1039 (float) ((cycles[1] - cycles[0]) / microseconds) / divisor);
1042 /* FIXME: hardwired: get freq for first cpu!
1043 * this whole function needs to be rethought and redone for
1044 * multi-cpu/multi-core/multi-threaded environments and
1045 * arbitrary combinations thereof */
1046 get_freq(p_client_buffer, client_buffer_size, p_format, divisor, 1);
1051 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
1052 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
1054 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1055 char get_freq(char *p_client_buffer, size_t client_buffer_size, char *p_format,
1056 int divisor, unsigned int cpu)
1064 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1070 char current_freq_file[128];
1072 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu - 1,
1074 f = fopen(current_freq_file, "r");
1076 /* if there's a cpufreq /sys node, read the current frequency from
1077 * this node and divide by 1000 to get Mhz. */
1078 if (fgets(s, sizeof(s), f)) {
1079 s[strlen(s) - 1] = '\0';
1080 freq = strtod(s, NULL);
1083 snprintf(p_client_buffer, client_buffer_size, p_format,
1084 (freq / 1000) / divisor);
1089 // open the CPU information file
1090 f = open_file("/proc/cpuinfo", &rep);
1092 perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
1097 while (fgets(s, sizeof(s), f) != NULL) {
1099 #if defined(__i386) || defined(__x86_64)
1100 // and search for the cpu mhz
1101 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) {
1103 #if defined(__alpha)
1104 // different on alpha
1105 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) {
1107 // this is different on ppc for some reason
1108 if (strncmp(s, "clock", 5) == 0 && cpu == 0) {
1109 #endif // defined(__alpha)
1110 #endif // defined(__i386) || defined(__x86_64)
1112 // copy just the number
1113 strcpy(frequency, strchr(s, ':') + 2);
1114 #if defined(__alpha)
1116 frequency[strlen(frequency) - 6] = '\0';
1117 // kernel reports in Hz
1118 freq = strtod(frequency, NULL) / 1000000;
1121 frequency[strlen(frequency) - 1] = '\0';
1122 freq = strtod(frequency, NULL);
1126 if (strncmp(s, "processor", 9) == 0) {
1133 snprintf(p_client_buffer, client_buffer_size, p_format,
1134 (float) freq / divisor);
1138 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
1140 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks something
1150 * Peter Tarjan (ptarjan@citromail.hu) */
1152 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
1153 char get_voltage(char *p_client_buffer, size_t client_buffer_size,
1154 char *p_format, int divisor, unsigned int cpu)
1160 char current_freq_file[128];
1163 /* build the voltage file name */
1165 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1168 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1173 /* read the current cpu frequency from the /sys node */
1174 f = fopen(current_freq_file, "r");
1176 if (fgets(s, sizeof(s), f)) {
1177 s[strlen(s) - 1] = '\0';
1178 freq = strtod(s, NULL);
1182 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1183 perror("get_voltage()");
1190 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1193 /* use the current cpu frequency to find the corresponding voltage */
1194 f = fopen(current_freq_file, "r");
1200 if (fgets(line, 255, f) == NULL) {
1203 sscanf(line, "%d %d", &freq_comp, &voltage);
1204 if (freq_comp == freq) {
1210 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1211 perror("get_voltage()");
1217 snprintf(p_client_buffer, client_buffer_size, p_format,
1218 (float) voltage / divisor);
1222 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1224 void get_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
1231 if (!p_client_buffer || client_buffer_size <= 0) {
1235 /* yeah, slow... :/ */
1236 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep)) {
1237 snprintf(p_client_buffer, client_buffer_size, "no fans?");
1241 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf);
1243 fp = open_file(buf2, &rep);
1245 snprintf(p_client_buffer, client_buffer_size,
1246 "can't open fan's state file");
1249 memset(buf, 0, sizeof(buf));
1250 fscanf(fp, "%*s %99s", buf);
1253 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1256 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1258 void get_acpi_ac_adapter(char *p_client_buffer, size_t client_buffer_size)
1265 if (!p_client_buffer || client_buffer_size <= 0) {
1269 /* yeah, slow... :/ */
1270 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep)) {
1271 snprintf(p_client_buffer, client_buffer_size, "no ac_adapters?");
1275 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf);
1277 fp = open_file(buf2, &rep);
1279 snprintf(p_client_buffer, client_buffer_size,
1280 "No ac adapter found.... where is it?");
1283 memset(buf, 0, sizeof(buf));
1284 fscanf(fp, "%*s %99s", buf);
1287 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1291 /proc/acpi/thermal_zone/THRM/cooling_mode
1292 cooling mode: active
1293 /proc/acpi/thermal_zone/THRM/polling_frequency
1295 /proc/acpi/thermal_zone/THRM/state
1297 /proc/acpi/thermal_zone/THRM/temperature
1299 /proc/acpi/thermal_zone/THRM/trip_points
1301 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1304 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1305 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1307 int open_acpi_temperature(const char *name)
1313 if (name == NULL || strcmp(name, "*") == 0) {
1316 if (!get_first_file_in_a_directory(ACPI_THERMAL_DIR, buf, &rep)) {
1322 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1324 fd = open(path, O_RDONLY);
1326 ERR("can't open '%s': %s", path, strerror(errno));
1332 static double last_acpi_temp;
1333 static double last_acpi_temp_time;
1335 double get_acpi_temperature(int fd)
1341 /* don't update acpi temperature too often */
1342 if (current_update_time - last_acpi_temp_time < 11.32) {
1343 return last_acpi_temp;
1345 last_acpi_temp_time = current_update_time;
1347 /* seek to beginning */
1348 lseek(fd, 0, SEEK_SET);
1355 n = read(fd, buf, 255);
1357 ERR("can't read fd %d: %s", fd, strerror(errno));
1360 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1364 return last_acpi_temp;
1368 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1370 design capacity: 4400 mAh
1371 last full capacity: 4064 mAh
1372 battery technology: rechargeable
1373 design voltage: 14800 mV
1374 design capacity warning: 300 mAh
1375 design capacity low: 200 mAh
1376 capacity granularity 1: 32 mAh
1377 capacity granularity 2: 32 mAh
1379 serial number: 16922
1385 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1388 charging state: unknown
1390 remaining capacity: 4064 mAh
1391 present voltage: 16608 mV
1395 2213<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1396 2213<@jupet�kellari��> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1397 2213<@jupet�kellari��> (-1 ollee ei akkua kiinni, koska akku on p�yd�ll�)
1398 2214<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1399 2214<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1401 2238<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1402 2239<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1404 2240<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori p��ll�
1405 2241<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori p��ll� mutta ilman verkkovirtaa
1408 /* Kapil Hari Paranjape <kapil@imsc.res.in>
1409 Linux 2.6.24 onwards battery info is in
1410 /sys/class/power_supply/BAT0/
1411 On my system I get the following.
1412 /sys/class/power_supply/BAT0/uevent:
1413 PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A03:00/device:01/PNP0C09:00/PNP0C0A:00
1415 PHYSDEVDRIVER=battery
1416 POWER_SUPPLY_NAME=BAT0
1417 POWER_SUPPLY_TYPE=Battery
1418 POWER_SUPPLY_STATUS=Discharging
1419 POWER_SUPPLY_PRESENT=1
1420 POWER_SUPPLY_TECHNOLOGY=Li-ion
1421 POWER_SUPPLY_VOLTAGE_MIN_DESIGN=10800000
1422 POWER_SUPPLY_VOLTAGE_NOW=10780000
1423 POWER_SUPPLY_CURRENT_NOW=13970000
1424 POWER_SUPPLY_ENERGY_FULL_DESIGN=47510000
1425 POWER_SUPPLY_ENERGY_FULL=27370000
1426 POWER_SUPPLY_ENERGY_NOW=11810000
1427 POWER_SUPPLY_MODEL_NAME=IBM-92P1060
1428 POWER_SUPPLY_MANUFACTURER=Panasonic
1429 On some systems POWER_SUPPLY_ENERGY_* is replaced by POWER_SUPPLY_CHARGE_*
1432 #define SYSFS_BATTERY_BASE_PATH "/sys/class/power_supply"
1433 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1434 #define APM_PATH "/proc/apm"
1435 #define MAX_BATTERY_COUNT 4
1437 static FILE *sysfs_bat_fp[MAX_BATTERY_COUNT];
1438 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT];
1439 static FILE *apm_bat_fp[MAX_BATTERY_COUNT];
1441 static int batteries_initialized = 0;
1442 static char batteries[MAX_BATTERY_COUNT][32];
1444 static int acpi_last_full[MAX_BATTERY_COUNT];
1445 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1447 /* e.g. "charging 75%" */
1448 static char last_battery_str[MAX_BATTERY_COUNT][64];
1450 static char last_battery_time_str[MAX_BATTERY_COUNT][64];
1452 static double last_battery_time[MAX_BATTERY_COUNT];
1454 static int last_battery_perct[MAX_BATTERY_COUNT];
1455 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1457 void init_batteries(void)
1461 if (batteries_initialized) {
1464 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1465 batteries[idx][0] = '\0';
1467 batteries_initialized = 1;
1470 int get_battery_idx(const char *bat)
1474 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1475 if (!strlen(batteries[idx]) || !strcmp(batteries[idx], bat)) {
1480 /* if not found, enter a new entry */
1481 if (!strlen(batteries[idx])) {
1482 snprintf(batteries[idx], 31, "%s", bat);
1488 void get_battery_stuff(char *buf, unsigned int n, const char *bat, int item)
1490 static int idx, rep = 0, rep2 = 0;
1491 char acpi_path[128];
1493 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1494 char sysfs_path[128];
1495 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1499 idx = get_battery_idx(bat);
1501 /* don't update battery too often */
1502 if (current_update_time - last_battery_time[idx] < 29.5) {
1503 goto set_return_value;
1506 last_battery_time[idx] = current_update_time;
1508 memset(last_battery_str[idx], 0, sizeof(last_battery_str[idx]));
1509 memset(last_battery_time_str[idx], 0, sizeof(last_battery_time_str[idx]));
1511 /* first try SYSFS if that fails try ACPI */
1513 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1514 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1516 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1517 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1519 if (sysfs_bat_fp[idx] != NULL) {
1521 int present_rate = -1;
1522 int remaining_capacity = -1;
1523 char charging_state[64];
1526 strcpy(charging_state, "Unknown");
1528 while (!feof(sysfs_bat_fp[idx])) {
1530 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1533 /* let's just hope units are ok */
1534 if (strncmp (buf, "POWER_SUPPLY_PRESENT=1", 22) == 0)
1535 strcpy(present, "Yes");
1536 else if (strncmp (buf, "POWER_SUPPLY_PRESENT=0", 22) == 0)
1537 strcpy(present, "No");
1538 else if (strncmp (buf, "POWER_SUPPLY_STATUS=", 20) == 0)
1539 sscanf(buf, "POWER_SUPPLY_STATUS=%63s", charging_state);
1540 /* present_rate is not the same as the
1541 current flowing now but it is the same value
1542 which was used in the past. so we continue
1544 else if (strncmp(buf, "POWER_SUPPLY_CURRENT_NOW=", 25) == 0)
1545 sscanf(buf, "POWER_SUPPLY_CURRENT_NOW=%d", &present_rate);
1546 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0)
1547 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1548 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=", 25) == 0)
1549 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_last_full[idx]);
1550 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0)
1551 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1552 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=", 25) == 0)
1553 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_last_full[idx]);
1556 fclose(sysfs_bat_fp[idx]);
1557 sysfs_bat_fp[idx] = NULL;
1559 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1560 if (remaining_capacity > acpi_last_full[idx])
1561 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1564 if (strcmp(present, "No") == 0) {
1565 strncpy(last_battery_str[idx], "not present", 64);
1568 else if (strcmp(charging_state, "Charging") == 0) {
1569 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1570 /* e.g. charging 75% */
1571 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Charging %i%%",
1572 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1574 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1575 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1576 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1577 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Charging %d%%",
1578 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1580 strncpy(last_battery_str[idx], "Charging", sizeof(last_battery_str[idx])-1);
1584 else if (strncmp(charging_state, "Discharging", 64) == 0) {
1585 if (present_rate > 0) {
1586 /* e.g. discharging 35% */
1587 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Discharging %i%%",
1588 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1590 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1591 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1592 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1593 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Full");
1595 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1597 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1601 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1602 else if (strncmp(charging_state, "Charged", 64) == 0) {
1603 /* Below happens with the second battery on my X40,
1604 * when the second one is empty and the first one
1606 if (remaining_capacity == 0)
1607 strcpy(last_battery_str[idx], "Empty");
1609 strcpy(last_battery_str[idx], "Charged");
1611 /* unknown, probably full / AC */
1613 if (acpi_last_full[idx] != 0
1614 && remaining_capacity != acpi_last_full[idx])
1615 snprintf(last_battery_str[idx], 64, "Unknown %d%%",
1616 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1618 strncpy(last_battery_str[idx], "AC", 64);
1620 } else if (acpi_bat_fp[idx] != NULL) {
1622 int present_rate = -1;
1623 int remaining_capacity = -1;
1624 char charging_state[64];
1627 /* read last full capacity if it's zero */
1628 if (acpi_last_full[idx] == 0) {
1633 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1634 fp = open_file(path, &rep);
1639 if (fgets(b, 256, fp) == NULL) {
1642 if (sscanf(b, "last full capacity: %d",
1643 &acpi_last_full[idx]) != 0) {
1652 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1654 strcpy(charging_state, "unknown");
1656 while (!feof(acpi_bat_fp[idx])) {
1659 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1663 /* let's just hope units are ok */
1664 if (strncmp(buf, "present:", 8) == 0) {
1665 sscanf(buf, "present: %4s", present);
1666 } else if (strncmp(buf, "charging state:", 15) == 0) {
1667 sscanf(buf, "charging state: %63s", charging_state);
1668 } else if (strncmp(buf, "present rate:", 13) == 0) {
1669 sscanf(buf, "present rate: %d", &present_rate);
1670 } else if (strncmp(buf, "remaining capacity:", 19) == 0) {
1671 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1674 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1675 if (remaining_capacity > acpi_last_full[idx]) {
1676 /* normalize to 100% */
1677 acpi_last_full[idx] = remaining_capacity;
1681 if (strcmp(present, "no") == 0) {
1682 strncpy(last_battery_str[idx], "not present", 64);
1684 } else if (strcmp(charging_state, "charging") == 0) {
1685 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1686 /* e.g. charging 75% */
1687 snprintf(last_battery_str[idx],
1688 sizeof(last_battery_str[idx]) - 1, "charging %i%%",
1689 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1691 format_seconds(last_battery_time_str[idx],
1692 sizeof(last_battery_time_str[idx]) - 1,
1693 (long) (((acpi_last_full[idx] - remaining_capacity) *
1694 3600) / present_rate));
1695 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1696 snprintf(last_battery_str[idx],
1697 sizeof(last_battery_str[idx]) - 1, "charging %d%%",
1698 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1700 strncpy(last_battery_str[idx], "charging",
1701 sizeof(last_battery_str[idx]) - 1);
1704 } else if (strncmp(charging_state, "discharging", 64) == 0) {
1705 if (present_rate > 0) {
1706 /* e.g. discharging 35% */
1707 snprintf(last_battery_str[idx],
1708 sizeof(last_battery_str[idx]) - 1, "discharging %i%%",
1709 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1711 format_seconds(last_battery_time_str[idx],
1712 sizeof(last_battery_time_str[idx]) - 1,
1713 (long) ((remaining_capacity * 3600) / present_rate));
1714 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1715 snprintf(last_battery_str[idx],
1716 sizeof(last_battery_str[idx]) - 1, "full");
1718 snprintf(last_battery_str[idx],
1719 sizeof(last_battery_str[idx]) - 1, "discharging %d%%",
1720 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1723 } else if (strncmp(charging_state, "charged", 64) == 0) {
1724 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1725 /* Below happens with the second battery on my X40,
1726 * when the second one is empty and the first one being charged. */
1727 if (remaining_capacity == 0) {
1728 strcpy(last_battery_str[idx], "empty");
1730 strcpy(last_battery_str[idx], "charged");
1732 /* unknown, probably full / AC */
1734 if (acpi_last_full[idx] != 0
1735 && remaining_capacity != acpi_last_full[idx]) {
1736 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1737 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1739 strncpy(last_battery_str[idx], "AC", 64);
1744 if (apm_bat_fp[idx] == NULL) {
1745 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1748 if (apm_bat_fp[idx] != NULL) {
1749 int ac, status, flag, life;
1751 fscanf(apm_bat_fp[idx], "%*s %*s %*x %x %x %x %d%%",
1752 &ac, &status, &flag, &life);
1755 /* could check now that there is ac */
1756 snprintf(last_battery_str[idx], 64, "AC");
1758 /* could check that status == 3 here? */
1759 } else if (ac && life != 100) {
1760 snprintf(last_battery_str[idx], 64, "charging %d%%", life);
1762 snprintf(last_battery_str[idx], 64, "%d%%", life);
1765 /* it seemed to buffer it so file must be closed (or could use
1766 * syscalls directly but I don't feel like coding it now) */
1767 fclose(apm_bat_fp[idx]);
1768 apm_bat_fp[idx] = NULL;
1774 case BATTERY_STATUS:
1775 snprintf(buf, n, "%s", last_battery_str[idx]);
1778 snprintf(buf, n, "%s", last_battery_time_str[idx]);
1785 int get_battery_perct(const char *bat)
1789 char acpi_path[128];
1791 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1792 char sysfs_path[128];
1793 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1797 idx = get_battery_idx(bat);
1799 /* don't update battery too often */
1800 if (current_update_time - last_battery_perct_time[idx] < 30) {
1801 return last_battery_perct[idx];
1803 last_battery_perct_time[idx] = current_update_time;
1805 /* Only check for SYSFS or ACPI */
1807 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1808 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1810 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1811 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1813 int remaining_capacity = -1;
1815 if (sysfs_bat_fp[idx] != NULL) {
1817 while (!feof(sysfs_bat_fp[idx])) {
1819 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1822 if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0)
1823 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1824 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=",25) != 0)
1825 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_last_full[idx]);
1826 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0)
1827 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1828 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=",25) != 0)
1829 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_last_full[idx]);
1832 fclose(sysfs_bat_fp[idx]);
1833 sysfs_bat_fp[idx] = NULL;
1835 } else if (acpi_bat_fp[idx] != NULL) {
1837 /* read last full capacity if it's zero */
1838 if (acpi_design_capacity[idx] == 0) {
1843 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1844 fp = open_file(path, &rep);
1849 if (fgets(b, 256, fp) == NULL) {
1852 if (sscanf(b, "last full capacity: %d",
1853 &acpi_design_capacity[idx]) != 0) {
1861 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1863 while (!feof(acpi_bat_fp[idx])) {
1866 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1870 if (buf[0] == 'r') {
1871 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1875 if (remaining_capacity < 0) {
1878 /* compute the battery percentage */
1879 last_battery_perct[idx] =
1880 (int) (((float) remaining_capacity / acpi_design_capacity[idx]) * 100);
1881 return last_battery_perct[idx];
1884 int get_battery_perct_bar(const char *bar)
1888 get_battery_perct(bar);
1889 idx = get_battery_idx(bar);
1890 return (int) (last_battery_perct[idx] * 2.56 - 1);
1893 /* On Apple powerbook and ibook:
1894 $ cat /proc/pmu/battery_0
1901 $ cat /proc/pmu/info
1902 PMU driver version : 2
1903 PMU firmware version : 0c
1908 /* defines as in <linux/pmu.h> */
1909 #define PMU_BATT_PRESENT 0x00000001
1910 #define PMU_BATT_CHARGING 0x00000002
1912 static FILE *pmu_battery_fp;
1913 static FILE *pmu_info_fp;
1914 static char pb_battery_info[3][32];
1915 static double pb_battery_info_update;
1917 #define PMU_PATH "/proc/pmu"
1918 void get_powerbook_batt_info(char *buf, size_t n, int i)
1921 const char *batt_path = PMU_PATH "/battery_0";
1922 const char *info_path = PMU_PATH "/info";
1923 int flags, charge, max_charge, ac = -1;
1926 /* don't update battery too often */
1927 if (current_update_time - pb_battery_info_update < 29.5) {
1928 snprintf(buf, n, "%s", pb_battery_info[i]);
1931 pb_battery_info_update = current_update_time;
1933 if (pmu_battery_fp == NULL) {
1934 pmu_battery_fp = open_file(batt_path, &rep);
1937 if (pmu_battery_fp != NULL) {
1938 rewind(pmu_battery_fp);
1939 while (!feof(pmu_battery_fp)) {
1942 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL) {
1946 if (buf[0] == 'f') {
1947 sscanf(buf, "flags : %8x", &flags);
1948 } else if (buf[0] == 'c' && buf[1] == 'h') {
1949 sscanf(buf, "charge : %d", &charge);
1950 } else if (buf[0] == 'm') {
1951 sscanf(buf, "max_charge : %d", &max_charge);
1952 } else if (buf[0] == 't') {
1953 sscanf(buf, "time rem. : %ld", &time);
1957 if (pmu_info_fp == NULL) {
1958 pmu_info_fp = open_file(info_path, &rep);
1961 if (pmu_info_fp != NULL) {
1962 rewind(pmu_info_fp);
1963 while (!feof(pmu_info_fp)) {
1966 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL) {
1969 if (buf[0] == 'A') {
1970 sscanf(buf, "AC Power : %d", &ac);
1974 /* update status string */
1975 if ((ac && !(flags & PMU_BATT_PRESENT))) {
1976 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
1977 } else if (ac && (flags & PMU_BATT_PRESENT)
1978 && !(flags & PMU_BATT_CHARGING)) {
1979 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
1980 } else if ((flags & PMU_BATT_PRESENT) && (flags & PMU_BATT_CHARGING)) {
1981 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
1983 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
1986 /* update percentage string */
1988 pb_battery_info[PB_BATT_PERCENT][0] = 0;
1990 snprintf(pb_battery_info[PB_BATT_PERCENT],
1991 sizeof(pb_battery_info[PB_BATT_PERCENT]), "%d%%",
1992 (charge * 100) / max_charge);
1995 /* update time string */
1996 if (time == 0) { /* fully charged or battery not present */
1997 pb_battery_info[PB_BATT_TIME][0] = 0;
1998 } else if (time < 60 * 60) { /* don't show secs */
1999 format_seconds_short(pb_battery_info[PB_BATT_TIME],
2000 sizeof(pb_battery_info[PB_BATT_TIME]), time);
2002 format_seconds(pb_battery_info[PB_BATT_TIME],
2003 sizeof(pb_battery_info[PB_BATT_TIME]), time);
2006 snprintf(buf, n, "%s", pb_battery_info[i]);
2011 show_nice_processes = 1;
2012 process_find_top(info.cpu, info.memu);
2013 info.first_process = get_first_process();
2016 /* The following ifdefs were adapted from gkrellm */
2017 #include <linux/major.h>
2019 #if !defined(MD_MAJOR)
2023 #if !defined(LVM_BLK_MAJOR)
2024 #define LVM_BLK_MAJOR 58
2027 #if !defined(NBD_MAJOR)
2028 #define NBD_MAJOR 43
2031 void update_diskio()
2033 static unsigned int last = UINT_MAX;
2034 static unsigned int last_read = UINT_MAX;
2035 static unsigned int last_write = UINT_MAX;
2039 char buf[512], devbuf[64];
2040 int major, minor, i;
2041 unsigned int current = 0;
2042 unsigned int current_read = 0;
2043 unsigned int current_write = 0;
2044 unsigned int reads, writes = 0;
2047 if (!(fp = open_file("/proc/diskstats", &rep))) {
2052 /* read reads and writes from all disks (minor = 0), including cd-roms
2053 * and floppies, and sum them up */
2055 fgets(buf, 512, fp);
2056 col_count = sscanf(buf, "%u %u %s %*u %*u %u %*u %*u %*u %u", &major,
2057 &minor, devbuf, &reads, &writes);
2058 /* ignore subdevices (they have only 3 matching entries in their line)
2059 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
2061 * XXX: ignore devices which are part of a SW RAID (MD_MAJOR) */
2062 if (col_count == 5 && major != LVM_BLK_MAJOR && major != NBD_MAJOR
2063 && major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
2064 current += reads + writes;
2065 current_read += reads;
2066 current_write += writes;
2068 col_count = sscanf(buf, "%u %u %s %*u %u %*u %u",
2069 &major, &minor, devbuf, &reads, &writes);
2070 if (col_count != 5) {
2074 for (i = 0; i < MAX_DISKIO_STATS; i++) {
2075 if (diskio_stats[i].dev &&
2076 strcmp(devbuf, diskio_stats[i].dev) == 0) {
2077 diskio_stats[i].current =
2078 (reads + writes - diskio_stats[i].last) / 2;
2079 diskio_stats[i].current_read =
2080 (reads - diskio_stats[i].last_read) / 2;
2081 diskio_stats[i].current_write =
2082 (writes - diskio_stats[i].last_write) / 2;
2083 if (reads + writes < diskio_stats[i].last) {
2084 diskio_stats[i].current = 0;
2086 if (reads < diskio_stats[i].last_read) {
2087 diskio_stats[i].current_read = 0;
2088 diskio_stats[i].current = diskio_stats[i].current_write;
2090 if (writes < diskio_stats[i].last_write) {
2091 diskio_stats[i].current_write = 0;
2092 diskio_stats[i].current = diskio_stats[i].current_read;
2094 diskio_stats[i].last = reads + writes;
2095 diskio_stats[i].last_read = reads;
2096 diskio_stats[i].last_write = writes;
2101 /* since the values in /proc/diststats are absolute, we have to substract
2102 * our last reading. The numbers stand for "sectors read", and we therefore
2103 * have to divide by two to get KB */
2104 int tot = ((double) (current - last) / 2);
2105 int tot_read = ((double) (current_read - last_read) / 2);
2106 int tot_write = ((double) (current_write - last_write) / 2);
2108 if (last_read > current_read) {
2111 if (last_write > current_write) {
2115 if (last > current) {
2116 /* we hit this either if it's the very first time we run this, or
2117 * when /proc/diskstats overflows; while 0 is not correct, it's at
2118 * least not way off */
2122 last_read = current_read;
2123 last_write = current_write;
2126 diskio_read_value = tot_read;
2127 diskio_write_value = tot_write;
2132 /* Here come the IBM ACPI-specific things. For reference, see
2133 * http://ibm-acpi.sourceforge.net/README
2134 * If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
2150 * The content of these files is described in detail in the aforementioned
2151 * README - some of them also in the following functions accessing them.
2152 * Peter Tarjan (ptarjan@citromail.hu) */
2154 #define IBM_ACPI_DIR "/proc/acpi/ibm"
2156 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
2157 * /proc/acpi/ibm/fan looks like this (3 lines):
2160 commands: enable, disable
2161 * Peter Tarjan (ptarjan@citromail.hu) */
2163 void get_ibm_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
2165 if (!p_client_buffer || client_buffer_size <= 0) {
2170 unsigned int speed = 0;
2173 snprintf(fan, 127, "%s/fan", IBM_ACPI_DIR);
2175 fp = fopen(fan, "r");
2180 if (fgets(line, 255, fp) == NULL) {
2183 if (sscanf(line, "speed: %d", &speed)) {
2188 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2189 "ibm* from your Conky config file.", fan, strerror(errno));
2193 snprintf(p_client_buffer, client_buffer_size, "%d", speed);
2196 /* get the measured temperatures from the temperature sensors
2197 * on IBM/Lenovo laptops running the ibm acpi.
2198 * There are 8 values in /proc/acpi/ibm/thermal, and according to
2199 * http://ibm-acpi.sourceforge.net/README
2200 * these mean the following (at least on an IBM R51...)
2201 * 0: CPU (also on the T series laptops)
2202 * 1: Mini PCI Module (?)
2204 * 3: GPU (also on the T series laptops)
2209 * I'm not too sure about those with the question mark, but the values I'm
2210 * reading from *my* thermal file (on a T42p) look realistic for the
2211 * hdd and the battery.
2212 * #5 and #7 are always -128.
2213 * /proc/acpi/ibm/thermal looks like this (1 line):
2214 temperatures: 41 43 31 46 33 -128 29 -128
2215 * Peter Tarjan (ptarjan@citromail.hu) */
2217 static double last_ibm_acpi_temp_time;
2218 void get_ibm_acpi_temps()
2221 /* don't update too often */
2222 if (current_update_time - last_ibm_acpi_temp_time < 10.00) {
2225 last_ibm_acpi_temp_time = current_update_time;
2227 /* if (!p_client_buffer || client_buffer_size <= 0) {
2235 snprintf(thermal, 127, "%s/thermal", IBM_ACPI_DIR);
2236 fp = fopen(thermal, "r");
2242 if (fgets(line, 255, fp) == NULL) {
2245 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
2246 &ibm_acpi.temps[0], &ibm_acpi.temps[1], &ibm_acpi.temps[2],
2247 &ibm_acpi.temps[3], &ibm_acpi.temps[4], &ibm_acpi.temps[5],
2248 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) {
2253 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2254 "ibm* from your Conky config file.", thermal, strerror(errno));
2260 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
2261 * "Volume" here is none of the mixer volumes, but a "master of masters"
2262 * volume adjusted by the IBM volume keys.
2263 * /proc/acpi/ibm/fan looks like this (4 lines):
2266 commands: up, down, mute
2267 commands: level <level> (<level> is 0-15)
2268 * Peter Tarjan (ptarjan@citromail.hu) */
2270 void get_ibm_acpi_volume(char *p_client_buffer, size_t client_buffer_size)
2272 if (!p_client_buffer || client_buffer_size <= 0) {
2280 snprintf(volume, 127, "%s/volume", IBM_ACPI_DIR);
2281 unsigned int vol = -1;
2284 fp = fopen(volume, "r");
2288 unsigned int read_vol = -1;
2290 if (fgets(line, 255, fp) == NULL) {
2293 if (sscanf(line, "level: %d", &read_vol)) {
2297 if (sscanf(line, "mute: %s", mute)) {
2302 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2303 "ibm* from your Conky config file.", volume, strerror(errno));
2308 if (strcmp(mute, "on") == 0) {
2309 snprintf(p_client_buffer, client_buffer_size, "%s", "mute");
2312 snprintf(p_client_buffer, client_buffer_size, "%d", vol);
2317 /* static FILE *fp = NULL; */
2319 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
2320 * /proc/acpi/ibm/brightness looks like this (3 lines):
2323 commands: level <level> (<level> is 0-7)
2324 * Peter Tarjan (ptarjan@citromail.hu) */
2326 void get_ibm_acpi_brightness(char *p_client_buffer, size_t client_buffer_size)
2328 if (!p_client_buffer || client_buffer_size <= 0) {
2333 unsigned int brightness = 0;
2336 snprintf(filename, 127, "%s/brightness", IBM_ACPI_DIR);
2338 fp = fopen(filename, "r");
2343 if (fgets(line, 255, fp) == NULL) {
2346 if (sscanf(line, "level: %d", &brightness)) {
2351 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2352 "ibm* from your Conky config file.", filename, strerror(errno));
2357 snprintf(p_client_buffer, client_buffer_size, "%d", brightness);
2360 void update_entropy(void)
2363 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
2364 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
2367 info.entropy.entropy_avail = 0;
2368 info.entropy.poolsize = 0;
2370 if ((fp1 = open_file(entropy_avail, &rep)) == NULL) {
2374 if ((fp2 = open_file(entropy_poolsize, &rep)) == NULL) {
2379 fscanf(fp1, "%u", &info.entropy.entropy_avail);
2380 fscanf(fp2, "%u", &info.entropy.poolsize);
2385 info.mask |= (1 << INFO_ENTROPY);