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>
58 #include <linux/route.h>
65 #define SHORTSTAT_TEMPL "%*s %llu %llu %llu"
66 #define LONGSTAT_TEMPL "%*s %llu %llu %llu "
68 static int show_nice_processes;
70 /* This flag tells the linux routines to use the /proc system where possible,
71 * even if other api's are available, e.g. sysinfo() or getloadavg().
72 * the reason for this is to allow for /proc-based distributed monitoring.
73 * using a flag in this manner creates less confusing code. */
74 static int prefer_proc = 0;
84 struct sysinfo s_info;
87 info.uptime = (double) s_info.uptime;
94 if (!(fp = open_file("/proc/uptime", &rep))) {
98 fscanf(fp, "%lf", &info.uptime);
101 info.mask |= (1 << INFO_UPTIME);
104 int check_mount(char *s)
107 FILE *mtab = fopen("/etc/mtab", "r");
110 char buf1[256], buf2[128];
112 while (fgets(buf1, 256, mtab)) {
113 sscanf(buf1, "%*s %128s", buf2);
114 if (!strcmp(s, buf2)) {
121 ERR("Could not open mtab");
126 /* these things are also in sysinfo except Buffers:
127 * (that's why I'm reading them from proc) */
129 void update_meminfo()
134 /* unsigned int a; */
137 info.mem = info.memmax = info.swap = info.swapmax = info.bufmem =
138 info.buffers = info.cached = 0;
140 if (!(meminfo_fp = open_file("/proc/meminfo", &rep))) {
144 while (!feof(meminfo_fp)) {
145 if (fgets(buf, 255, meminfo_fp) == NULL) {
149 if (strncmp(buf, "MemTotal:", 9) == 0) {
150 sscanf(buf, "%*s %Lu", &info.memmax);
151 } else if (strncmp(buf, "MemFree:", 8) == 0) {
152 sscanf(buf, "%*s %Lu", &info.mem);
153 } else if (strncmp(buf, "SwapTotal:", 10) == 0) {
154 sscanf(buf, "%*s %Lu", &info.swapmax);
155 } else if (strncmp(buf, "SwapFree:", 9) == 0) {
156 sscanf(buf, "%*s %Lu", &info.swap);
157 } else if (strncmp(buf, "Buffers:", 8) == 0) {
158 sscanf(buf, "%*s %Lu", &info.buffers);
159 } else if (strncmp(buf, "Cached:", 7) == 0) {
160 sscanf(buf, "%*s %Lu", &info.cached);
164 info.mem = info.memmax - info.mem;
165 info.swap = info.swapmax - info.swap;
167 info.bufmem = info.cached + info.buffers;
169 info.mask |= (1 << INFO_MEM) | (1 << INFO_BUFFERS);
174 int get_laptop_mode()
179 if ((fp = fopen("/proc/sys/vm/laptop_mode", "r")) != NULL)
180 fscanf(fp, "%d\n", &val);
185 * # cat /sys/block/sda/queue/scheduler
186 * noop [anticipatory] cfq
188 char *get_ioscheduler(char *disk)
196 snprintf(buf, 127, "/sys/block/%s/queue/scheduler", disk);
197 if ((fp = fopen(buf, "r")) == NULL) {
198 return strdup("n/a");
201 fscanf(fp, "%127s", buf);
203 buf[strlen(buf) - 1] = '\0';
205 return strdup(buf + 1);
209 return strdup("n/a");
212 int interface_up(const char *dev)
217 if((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
218 CRIT_ERR("could not create sockfd");
221 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
222 if(ioctl(fd, SIOCGIFFLAGS, &ifr)) {
223 /* if device does not exist, treat like not up */
225 perror("SIOCGIFFLAGS");
228 return (ifr.ifr_flags & IFF_UP);
234 #define COND_FREE(x) if(x) free(x); x = 0
235 #define SAVE_SET_STRING(x, y) \
236 if (x && strcmp((char *)x, (char *)y)) { \
238 x = strdup("multiple"); \
243 void update_gateway_info()
248 unsigned long dest, gate, mask;
250 short ref, use, metric, mtu, win, irtt;
252 struct gateway_info *gw_info = &info.gw_info;
254 COND_FREE(gw_info->iface);
255 COND_FREE(gw_info->ip);
258 if ((fp = fopen("/proc/net/route", "r")) == NULL) {
262 if (fscanf(fp, "%*[^\n]\n") == EOF) {
267 // Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
268 if(fscanf(fp, "%63s %lx %lx %x %hd %hd %hd %lx %hd %hd %hd\n",
269 iface, &dest, &gate, &flags, &ref, &use,
270 &metric, &mask, &mtu, &win, &irtt) != 11) {
274 if (flags & RTF_GATEWAY && dest == 0 && mask == 0) {
276 SAVE_SET_STRING(gw_info->iface, iface)
278 SAVE_SET_STRING(gw_info->ip, inet_ntoa(ina))
286 info.gw_info.iface = info.gw_info.ip = strdup("failed");
290 inline void update_net_stats()
295 // FIXME: arbitrary size chosen to keep code simple.
297 unsigned int curtmp1, curtmp2;
304 // wireless info variables
305 int skfd, has_bitrate = 0;
306 struct wireless_info *winfo;
311 delta = current_update_time - last_update_time;
312 if (delta <= 0.0001) {
316 /* open file and ignore first two lines */
317 if (!(net_dev_fp = open_file("/proc/net/dev", &rep))) {
322 fgets(buf, 255, net_dev_fp); /* garbage */
323 fgets(buf, 255, net_dev_fp); /* garbage (field names) */
325 /* read each interface */
326 for (i2 = 0; i2 < 16; i2++) {
330 long long r, t, last_recv, last_trans;
332 if (fgets(buf, 255, net_dev_fp) == NULL) {
336 while (isspace((int) *p)) {
342 while (*p && *p != ':') {
351 ns = get_net_stat(s);
353 memset(&(ns->addr.sa_data), 0, 14);
355 if(NULL == ns->addrs)
356 ns->addrs = (char*) malloc(17 * 16);
357 if(NULL != ns->addrs)
358 memset(ns->addrs, 0, 17 * 16); /* Up to 17 chars per ip, max 16 interfaces. Nasty memory usage... */
360 last_recv = ns->recv;
361 last_trans = ns->trans;
363 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
364 sscanf(p, "%Ld %*d %*d %*d %*d %*d %*d %*d %Ld",
367 /* if recv or trans is less than last time, an overflow happened */
368 if (r < ns->last_read_recv) {
371 ns->recv += (r - ns->last_read_recv);
373 ns->last_read_recv = r;
375 if (t < ns->last_read_trans) {
378 ns->trans += (t - ns->last_read_trans);
380 ns->last_read_trans = t;
382 /*** ip addr patch ***/
383 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
385 conf.ifc_buf = malloc(sizeof(struct ifreq) * 16);
387 conf.ifc_len = sizeof(struct ifreq) * 16;
389 ioctl((long) i, SIOCGIFCONF, &conf);
391 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
395 ((struct ifreq *) conf.ifc_buf)[k].ifr_ifrn.ifrn_name);
396 ns->addr = ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.ifru_addr;
397 if(NULL != ns->addrs)
399 sprintf(temp_addr, "%u.%u.%u.%u, ",
400 ns->addr.sa_data[2] & 255,
401 ns->addr.sa_data[3] & 255,
402 ns->addr.sa_data[4] & 255,
403 ns->addr.sa_data[5] & 255);
404 if(NULL == strstr(ns->addrs, temp_addr))
405 strncpy(ns->addrs + strlen(ns->addrs), temp_addr, 17);
413 /*** end ip addr patch ***/
415 /* calculate speeds */
416 ns->net_rec[0] = (ns->recv - last_recv) / delta;
417 ns->net_trans[0] = (ns->trans - last_trans) / delta;
421 for (i = 0; (unsigned) i < info.net_avg_samples; i++) {
422 curtmp1 += ns->net_rec[i];
423 curtmp2 += ns->net_trans[i];
431 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
432 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
433 if (info.net_avg_samples > 1) {
434 for (i = info.net_avg_samples; i > 1; i--) {
435 ns->net_rec[i - 1] = ns->net_rec[i - 2];
436 ns->net_trans[i - 1] = ns->net_trans[i - 2];
441 /* update wireless info */
442 winfo = malloc(sizeof(struct wireless_info));
443 memset(winfo, 0, sizeof(struct wireless_info));
445 skfd = iw_sockets_open();
446 if (iw_get_basic_config(skfd, s, &(winfo->b)) > -1) {
448 // set present winfo variables
449 if (iw_get_stats(skfd, s, &(winfo->stats),
450 &winfo->range, winfo->has_range) >= 0) {
451 winfo->has_stats = 1;
453 if (iw_get_range_info(skfd, s, &(winfo->range)) >= 0) {
454 winfo->has_range = 1;
456 if (iw_get_ext(skfd, s, SIOCGIWAP, &wrq) >= 0) {
457 winfo->has_ap_addr = 1;
458 memcpy(&(winfo->ap_addr), &(wrq.u.ap_addr), sizeof(sockaddr));
462 if (iw_get_ext(skfd, s, SIOCGIWRATE, &wrq) >= 0) {
463 memcpy(&(winfo->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
464 iw_print_bitrate(ns->bitrate, 16, winfo->bitrate.value);
469 if (winfo->has_range && winfo->has_stats
470 && ((winfo->stats.qual.level != 0)
471 || (winfo->stats.qual.updated & IW_QUAL_DBM))) {
472 if (!(winfo->stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
473 ns->link_qual = winfo->stats.qual.qual;
474 ns->link_qual_max = winfo->range.max_qual.qual;
479 if (winfo->has_ap_addr) {
480 iw_sawap_ntop(&winfo->ap_addr, ns->ap);
484 if (winfo->b.has_essid) {
485 if (winfo->b.essid_on) {
486 snprintf(ns->essid, 32, "%s", winfo->b.essid);
488 snprintf(ns->essid, 32, "off/any");
492 snprintf(ns->mode, 16, "%s", iw_operation_mode[winfo->b.mode]);
494 iw_sockets_close(skfd);
501 info.mask |= (1 << INFO_NET);
506 void update_total_processes()
510 struct sysinfo s_info;
513 info.procs = s_info.procs;
520 if (!(fp = open_file("/proc/loadavg", &rep))) {
524 fscanf(fp, "%*f %*f %*f %*d/%hd", &info.procs);
527 info.mask |= (1 << INFO_PROCS);
530 #define CPU_SAMPLE_COUNT 15
532 unsigned long long cpu_user;
533 unsigned long long cpu_system;
534 unsigned long long cpu_nice;
535 unsigned long long cpu_idle;
536 unsigned long long cpu_iowait;
537 unsigned long long cpu_irq;
538 unsigned long long cpu_softirq;
539 unsigned long long cpu_steal;
540 unsigned long long cpu_total;
541 unsigned long long cpu_active_total;
542 unsigned long long cpu_last_total;
543 unsigned long long cpu_last_active_total;
544 double cpu_val[CPU_SAMPLE_COUNT];
546 static short cpu_setup = 0;
548 /* Determine if this kernel gives us "extended" statistics information in
550 * Kernels around 2.5 and earlier only reported user, system, nice, and
551 * idle values in proc stat.
552 * Kernels around 2.6 and greater report these PLUS iowait, irq, softirq,
554 void determine_longstat(char *buf)
556 unsigned long long iowait = 0;
558 KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
559 /* scanf will either return -1 or 1 because there is only 1 assignment */
560 if (sscanf(buf, "%*s %*d %*d %*d %*d %llu", &iowait) > 0) {
561 KFLAG_SETON(KFLAG_IS_LONGSTAT);
570 if (info.cpu_usage) {
575 if (!(stat_fp = open_file("/proc/stat", &rep))) {
581 while (!feof(stat_fp)) {
582 if (fgets(buf, 255, stat_fp) == NULL) {
586 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
587 if (info.cpu_count == 0) {
588 determine_longstat(buf);
593 info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
598 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
599 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
601 inline static void update_stat()
605 static struct cpu_info *cpu = NULL;
610 char *stat_template = NULL;
611 unsigned int malloc_cpu_size = 0;
613 /* add check for !info.cpu_usage since that mem is freed on a SIGUSR1 */
614 if (!cpu_setup || !info.cpu_usage) {
619 if (!stat_template) {
621 KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT;
625 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
626 cpu = malloc(malloc_cpu_size);
627 memset(cpu, 0, malloc_cpu_size);
630 if (!(stat_fp = open_file("/proc/stat", &rep))) {
632 if (info.cpu_usage) {
633 memset(info.cpu_usage, 0, info.cpu_count * sizeof(float));
639 while (!feof(stat_fp)) {
640 if (fgets(buf, 255, stat_fp) == NULL) {
644 if (strncmp(buf, "procs_running ", 14) == 0) {
645 sscanf(buf, "%*s %hu", &info.run_procs);
646 info.mask |= (1 << INFO_RUN_PROCS);
647 } else if (strncmp(buf, "cpu", 3) == 0) {
648 index = isdigit(buf[3]) ? ((int) buf[3]) - 0x2F : 0;
649 sscanf(buf, stat_template, &(cpu[index].cpu_user),
650 &(cpu[index].cpu_nice), &(cpu[index].cpu_system),
651 &(cpu[index].cpu_idle), &(cpu[index].cpu_iowait),
652 &(cpu[index].cpu_irq), &(cpu[index].cpu_softirq),
653 &(cpu[index].cpu_steal));
655 cpu[index].cpu_total = cpu[index].cpu_user + cpu[index].cpu_nice +
656 cpu[index].cpu_system + cpu[index].cpu_idle +
657 cpu[index].cpu_iowait + cpu[index].cpu_irq +
658 cpu[index].cpu_softirq + cpu[index].cpu_steal;
660 cpu[index].cpu_active_total = cpu[index].cpu_total -
661 (cpu[index].cpu_idle + cpu[index].cpu_iowait);
662 info.mask |= (1 << INFO_CPU);
664 double delta = current_update_time - last_update_time;
666 if (delta <= 0.001) {
670 cpu[index].cpu_val[0] = (cpu[index].cpu_active_total -
671 cpu[index].cpu_last_active_total) /
672 (float) (cpu[index].cpu_total - cpu[index].cpu_last_total);
674 for (i = 0; i < info.cpu_avg_samples; i++) {
675 curtmp += cpu[index].cpu_val[i];
677 /* TESTING -- I've removed this, because I don't think it is right.
678 * You shouldn't divide by the cpu count here ...
679 * removing for testing */
681 info.cpu_usage[index] = curtmp / info.cpu_avg_samples /
684 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
686 /* TESTING -- this line replaces the prev. "suspect" if/else */
687 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
689 cpu[index].cpu_last_total = cpu[index].cpu_total;
690 cpu[index].cpu_last_active_total = cpu[index].cpu_active_total;
691 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
692 cpu[index].cpu_val[i] = cpu[index].cpu_val[i - 1];
699 void update_running_processes()
704 void update_cpu_usage()
709 void update_load_average()
711 #ifdef HAVE_GETLOADAVG
716 info.loadavg[0] = (float) v[0];
717 info.loadavg[1] = (float) v[1];
718 info.loadavg[2] = (float) v[2];
725 if (!(fp = open_file("/proc/loadavg", &rep))) {
726 info.loadavg[0] = info.loadavg[1] = info.loadavg[2] = 0.0;
729 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1],
733 info.mask |= (1 << INFO_LOADAVG);
736 #define PROC_I8K "/proc/i8k"
737 #define I8K_DELIM " "
738 static char *i8k_procbuf = NULL;
744 i8k_procbuf = (char *) malloc(128 * sizeof(char));
746 if ((fp = fopen(PROC_I8K, "r")) == NULL) {
747 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel "
748 "driver is loaded...");
751 memset(&i8k_procbuf[0], 0, 128);
752 if (fread(&i8k_procbuf[0], sizeof(char), 128, fp) == 0) {
753 ERR("something wrong with /proc/i8k...");
758 i8k.version = strtok(&i8k_procbuf[0], I8K_DELIM);
759 i8k.bios = strtok(NULL, I8K_DELIM);
760 i8k.serial = strtok(NULL, I8K_DELIM);
761 i8k.cpu_temp = strtok(NULL, I8K_DELIM);
762 i8k.left_fan_status = strtok(NULL, I8K_DELIM);
763 i8k.right_fan_status = strtok(NULL, I8K_DELIM);
764 i8k.left_fan_rpm = strtok(NULL, I8K_DELIM);
765 i8k.right_fan_rpm = strtok(NULL, I8K_DELIM);
766 i8k.ac_status = strtok(NULL, I8K_DELIM);
767 i8k.buttons_status = strtok(NULL, I8K_DELIM);
770 /***********************************************************/
771 /***********************************************************/
772 /***********************************************************/
774 static int no_dots(const struct dirent *d)
776 if (d->d_name[0] == '.') {
782 static int get_first_file_in_a_directory(const char *dir, char *s, int *rep)
784 struct dirent **namelist;
787 n = scandir(dir, &namelist, no_dots, alphasort);
790 ERR("scandir for %s: %s", dir, strerror(errno));
801 strncpy(s, namelist[0]->d_name, 255);
804 for (i = 0; i < n; i++) {
813 int open_sysfs_sensor(const char *dir, const char *dev, const char *type, int n,
814 int *div, char *devtype)
821 memset(buf, 0, sizeof(buf));
823 /* if device is NULL or *, get first */
824 if (dev == NULL || strcmp(dev, "*") == 0) {
827 if (!get_first_file_in_a_directory(dir, buf, &rep)) {
833 if (strcmp(dir, "/sys/class/hwmon/") == 0) {
835 /* buf holds result from get_first_file_in_a_directory() above,
836 * e.g. "hwmon0" -- append "/device" */
837 strcat(buf, "/device");
839 /* dev holds device number N as a string,
840 * e.g. "0", -- convert to "hwmon0/device" */
841 sprintf(buf, "hwmon%s/device", dev);
846 /* change vol to in */
847 if (strcmp(type, "vol") == 0) {
851 if (strcmp(type, "tempf") == 0) {
852 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, "temp", n);
854 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, type, n);
856 strncpy(devtype, path, 255);
859 fd = open(path, O_RDONLY);
861 CRIT_ERR("can't open '%s': %s\nplease check your device or remove this "
862 "var from Conky", path, strerror(errno));
865 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
866 || strcmp(type, "tempf") == 0) {
871 /* fan does not use *_div as a read divisor */
872 if (strcmp("fan", type) == 0) {
876 /* test if *_div file exist, open it and use it as divisor */
877 if (strcmp(type, "tempf") == 0) {
878 snprintf(path, 255, "%s%s/%s%d_div", dir, "one", "two", n);
880 snprintf(path, 255, "%s%s/%s%d_div", dir, dev, type, n);
883 divfd = open(path, O_RDONLY);
889 divn = read(divfd, divbuf, 63);
890 /* should read until n == 0 but I doubt that kernel will give these
891 * in multiple pieces. :) */
893 ERR("open_sysfs_sensor(): can't read from sysfs");
905 double get_sysfs_info(int *fd, int div, char *devtype, char *type)
913 lseek(*fd, 0, SEEK_SET);
919 n = read(*fd, buf, 63);
920 /* should read until n == 0 but I doubt that kernel will give these
921 * in multiple pieces. :) */
923 ERR("get_sysfs_info(): read from %s failed\n", devtype);
932 *fd = open(devtype, O_RDONLY);
934 ERR("can't open '%s': %s", devtype, strerror(errno));
937 /* My dirty hack for computing CPU value
938 * Filedil, from forums.gentoo.org */
939 /* if (strstr(devtype, "temp1_input") != NULL) {
940 return -15.096 + 1.4893 * (val / 1000.0);
943 /* divide voltage and temperature by 1000 */
944 /* or if any other divisor is given, use that */
945 if (strcmp(type, "tempf") == 0) {
947 return ((val / div + 40) * 9.0 / 5) - 40;
949 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
951 return ((val + 40) * 9.0 / 5) - 40;
964 /* Prior to kernel version 2.6.12, the CPU fan speed was available in
965 * ADT746X_FAN_OLD, whereas later kernel versions provide this information in
967 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
968 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
970 void get_adt746x_fan(char *p_client_buffer, size_t client_buffer_size)
973 char adt746x_fan_state[64];
976 if (!p_client_buffer || client_buffer_size <= 0) {
980 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
981 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL) {
982 sprintf(adt746x_fan_state, "adt746x not found");
984 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
985 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
989 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_fan_state);
992 /* Prior to kernel version 2.6.12, the CPU temperature was found in
993 * ADT746X_CPU_OLD, whereas later kernel versions provide this information in
995 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
996 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
998 void get_adt746x_cpu(char *p_client_buffer, size_t client_buffer_size)
1001 char adt746x_cpu_state[64];
1004 if (!p_client_buffer || client_buffer_size <= 0) {
1008 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
1009 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL) {
1010 sprintf(adt746x_cpu_state, "adt746x not found");
1012 fscanf(fp, "%2s", adt746x_cpu_state);
1016 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state);
1019 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
1021 /***********************************************************************/
1022 /* This file is part of x86info.
1023 * (C) 2001 Dave Jones.
1025 * Licensed under the terms of the GNU GPL License version 2.
1027 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
1028 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz> */
1030 #if defined(__i386) || defined(__x86_64)
1031 __inline__ unsigned long long int rdtsc()
1033 unsigned long long int x;
1035 __asm__ volatile(".byte 0x0f, 0x31":"=A" (x));
1040 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1041 void get_freq_dynamic(char *p_client_buffer, size_t client_buffer_size,
1042 char *p_format, int divisor)
1044 #if defined(__i386) || defined(__x86_64)
1046 struct timeval tvstart, tvstop;
1047 unsigned long long cycles[2]; /* gotta be 64 bit */
1048 unsigned int microseconds; /* total time taken */
1050 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1055 memset(&tz, 0, sizeof(tz));
1057 /* get this function in cached memory */
1058 gettimeofday(&tvstart, &tz);
1059 cycles[0] = rdtsc();
1060 gettimeofday(&tvstart, &tz);
1062 /* we don't trust that this is any specific length of time */
1064 cycles[1] = rdtsc();
1065 gettimeofday(&tvstop, &tz);
1066 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
1067 (tvstop.tv_usec - tvstart.tv_usec);
1069 snprintf(p_client_buffer, client_buffer_size, p_format,
1070 (float) ((cycles[1] - cycles[0]) / microseconds) / divisor);
1073 /* FIXME: hardwired: get freq for first cpu!
1074 * this whole function needs to be rethought and redone for
1075 * multi-cpu/multi-core/multi-threaded environments and
1076 * arbitrary combinations thereof */
1077 get_freq(p_client_buffer, client_buffer_size, p_format, divisor, 1);
1082 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
1083 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
1085 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1086 char get_freq(char *p_client_buffer, size_t client_buffer_size, char *p_format,
1087 int divisor, unsigned int cpu)
1095 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1101 char current_freq_file[128];
1103 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu - 1,
1105 f = fopen(current_freq_file, "r");
1107 /* if there's a cpufreq /sys node, read the current frequency from
1108 * this node and divide by 1000 to get Mhz. */
1109 if (fgets(s, sizeof(s), f)) {
1110 s[strlen(s) - 1] = '\0';
1111 freq = strtod(s, NULL);
1114 snprintf(p_client_buffer, client_buffer_size, p_format,
1115 (freq / 1000) / divisor);
1120 // open the CPU information file
1121 f = open_file("/proc/cpuinfo", &rep);
1123 perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
1128 while (fgets(s, sizeof(s), f) != NULL) {
1130 #if defined(__i386) || defined(__x86_64)
1131 // and search for the cpu mhz
1132 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) {
1134 #if defined(__alpha)
1135 // different on alpha
1136 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) {
1138 // this is different on ppc for some reason
1139 if (strncmp(s, "clock", 5) == 0 && cpu == 0) {
1140 #endif // defined(__alpha)
1141 #endif // defined(__i386) || defined(__x86_64)
1143 // copy just the number
1144 strcpy(frequency, strchr(s, ':') + 2);
1145 #if defined(__alpha)
1147 frequency[strlen(frequency) - 6] = '\0';
1148 // kernel reports in Hz
1149 freq = strtod(frequency, NULL) / 1000000;
1152 frequency[strlen(frequency) - 1] = '\0';
1153 freq = strtod(frequency, NULL);
1157 if (strncmp(s, "processor", 9) == 0) {
1164 snprintf(p_client_buffer, client_buffer_size, p_format,
1165 (float) freq / divisor);
1169 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
1171 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks something
1181 * Peter Tarjan (ptarjan@citromail.hu) */
1183 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
1184 char get_voltage(char *p_client_buffer, size_t client_buffer_size,
1185 char *p_format, int divisor, unsigned int cpu)
1191 char current_freq_file[128];
1194 /* build the voltage file name */
1196 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1199 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1204 /* read the current cpu frequency from the /sys node */
1205 f = fopen(current_freq_file, "r");
1207 if (fgets(s, sizeof(s), f)) {
1208 s[strlen(s) - 1] = '\0';
1209 freq = strtod(s, NULL);
1213 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1214 perror("get_voltage()");
1221 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1224 /* use the current cpu frequency to find the corresponding voltage */
1225 f = fopen(current_freq_file, "r");
1231 if (fgets(line, 255, f) == NULL) {
1234 sscanf(line, "%d %d", &freq_comp, &voltage);
1235 if (freq_comp == freq) {
1241 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1242 perror("get_voltage()");
1248 snprintf(p_client_buffer, client_buffer_size, p_format,
1249 (float) voltage / divisor);
1253 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1255 void get_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
1262 if (!p_client_buffer || client_buffer_size <= 0) {
1266 /* yeah, slow... :/ */
1267 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep)) {
1268 snprintf(p_client_buffer, client_buffer_size, "no fans?");
1272 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf);
1274 fp = open_file(buf2, &rep);
1276 snprintf(p_client_buffer, client_buffer_size,
1277 "can't open fan's state file");
1280 memset(buf, 0, sizeof(buf));
1281 fscanf(fp, "%*s %99s", buf);
1284 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1287 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1289 void get_acpi_ac_adapter(char *p_client_buffer, size_t client_buffer_size)
1296 if (!p_client_buffer || client_buffer_size <= 0) {
1300 /* yeah, slow... :/ */
1301 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep)) {
1302 snprintf(p_client_buffer, client_buffer_size, "no ac_adapters?");
1306 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf);
1308 fp = open_file(buf2, &rep);
1310 snprintf(p_client_buffer, client_buffer_size,
1311 "No ac adapter found.... where is it?");
1314 memset(buf, 0, sizeof(buf));
1315 fscanf(fp, "%*s %99s", buf);
1318 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1322 /proc/acpi/thermal_zone/THRM/cooling_mode
1323 cooling mode: active
1324 /proc/acpi/thermal_zone/THRM/polling_frequency
1326 /proc/acpi/thermal_zone/THRM/state
1328 /proc/acpi/thermal_zone/THRM/temperature
1330 /proc/acpi/thermal_zone/THRM/trip_points
1332 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1335 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1336 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1338 int open_acpi_temperature(const char *name)
1344 if (name == NULL || strcmp(name, "*") == 0) {
1347 if (!get_first_file_in_a_directory(ACPI_THERMAL_DIR, buf, &rep)) {
1353 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1355 fd = open(path, O_RDONLY);
1357 ERR("can't open '%s': %s", path, strerror(errno));
1363 static double last_acpi_temp;
1364 static double last_acpi_temp_time;
1366 double get_acpi_temperature(int fd)
1372 /* don't update acpi temperature too often */
1373 if (current_update_time - last_acpi_temp_time < 11.32) {
1374 return last_acpi_temp;
1376 last_acpi_temp_time = current_update_time;
1378 /* seek to beginning */
1379 lseek(fd, 0, SEEK_SET);
1386 n = read(fd, buf, 255);
1388 ERR("can't read fd %d: %s", fd, strerror(errno));
1391 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1395 return last_acpi_temp;
1399 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1401 design capacity: 4400 mAh
1402 last full capacity: 4064 mAh
1403 battery technology: rechargeable
1404 design voltage: 14800 mV
1405 design capacity warning: 300 mAh
1406 design capacity low: 200 mAh
1407 capacity granularity 1: 32 mAh
1408 capacity granularity 2: 32 mAh
1410 serial number: 16922
1416 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1419 charging state: unknown
1421 remaining capacity: 4064 mAh
1422 present voltage: 16608 mV
1426 2213<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1427 2213<@jupet�kellari��> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1428 2213<@jupet�kellari��> (-1 ollee ei akkua kiinni, koska akku on p�yd�ll�)
1429 2214<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1430 2214<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1432 2238<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1433 2239<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1435 2240<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori p��ll�
1436 2241<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori p��ll� mutta ilman verkkovirtaa
1439 /* Kapil Hari Paranjape <kapil@imsc.res.in>
1440 Linux 2.6.24 onwards battery info is in
1441 /sys/class/power_supply/BAT0/
1442 On my system I get the following.
1443 /sys/class/power_supply/BAT0/uevent:
1444 PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A03:00/device:01/PNP0C09:00/PNP0C0A:00
1446 PHYSDEVDRIVER=battery
1447 POWER_SUPPLY_NAME=BAT0
1448 POWER_SUPPLY_TYPE=Battery
1449 POWER_SUPPLY_STATUS=Discharging
1450 POWER_SUPPLY_PRESENT=1
1451 POWER_SUPPLY_TECHNOLOGY=Li-ion
1452 POWER_SUPPLY_VOLTAGE_MIN_DESIGN=10800000
1453 POWER_SUPPLY_VOLTAGE_NOW=10780000
1454 POWER_SUPPLY_CURRENT_NOW=13970000
1455 POWER_SUPPLY_ENERGY_FULL_DESIGN=47510000
1456 POWER_SUPPLY_ENERGY_FULL=27370000
1457 POWER_SUPPLY_ENERGY_NOW=11810000
1458 POWER_SUPPLY_MODEL_NAME=IBM-92P1060
1459 POWER_SUPPLY_MANUFACTURER=Panasonic
1460 On some systems POWER_SUPPLY_ENERGY_* is replaced by POWER_SUPPLY_CHARGE_*
1463 #define SYSFS_BATTERY_BASE_PATH "/sys/class/power_supply"
1464 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1465 #define APM_PATH "/proc/apm"
1466 #define MAX_BATTERY_COUNT 4
1468 static FILE *sysfs_bat_fp[MAX_BATTERY_COUNT];
1469 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT];
1470 static FILE *apm_bat_fp[MAX_BATTERY_COUNT];
1472 static int batteries_initialized = 0;
1473 static char batteries[MAX_BATTERY_COUNT][32];
1475 static int acpi_last_full[MAX_BATTERY_COUNT];
1476 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1478 /* e.g. "charging 75%" */
1479 static char last_battery_str[MAX_BATTERY_COUNT][64];
1481 static char last_battery_time_str[MAX_BATTERY_COUNT][64];
1483 static double last_battery_time[MAX_BATTERY_COUNT];
1485 static int last_battery_perct[MAX_BATTERY_COUNT];
1486 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1488 void init_batteries(void)
1492 if (batteries_initialized) {
1495 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1496 batteries[idx][0] = '\0';
1498 batteries_initialized = 1;
1501 int get_battery_idx(const char *bat)
1505 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1506 if (!strlen(batteries[idx]) || !strcmp(batteries[idx], bat)) {
1511 /* if not found, enter a new entry */
1512 if (!strlen(batteries[idx])) {
1513 snprintf(batteries[idx], 31, "%s", bat);
1519 void get_battery_stuff(char *buf, unsigned int n, const char *bat, int item)
1521 static int idx, rep = 0, rep2 = 0;
1522 char acpi_path[128];
1524 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1525 char sysfs_path[128];
1526 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1530 idx = get_battery_idx(bat);
1532 /* don't update battery too often */
1533 if (current_update_time - last_battery_time[idx] < 29.5) {
1534 goto set_return_value;
1537 last_battery_time[idx] = current_update_time;
1539 memset(last_battery_str[idx], 0, sizeof(last_battery_str[idx]));
1540 memset(last_battery_time_str[idx], 0, sizeof(last_battery_time_str[idx]));
1542 /* first try SYSFS if that fails try ACPI */
1544 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1545 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1547 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1548 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1550 if (sysfs_bat_fp[idx] != NULL) {
1552 int present_rate = -1;
1553 int remaining_capacity = -1;
1554 char charging_state[64];
1557 strcpy(charging_state, "Unknown");
1559 while (!feof(sysfs_bat_fp[idx])) {
1561 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1564 /* let's just hope units are ok */
1565 if (strncmp (buf, "POWER_SUPPLY_PRESENT=1", 22) == 0)
1566 strcpy(present, "Yes");
1567 else if (strncmp (buf, "POWER_SUPPLY_PRESENT=0", 22) == 0)
1568 strcpy(present, "No");
1569 else if (strncmp (buf, "POWER_SUPPLY_STATUS=", 20) == 0)
1570 sscanf(buf, "POWER_SUPPLY_STATUS=%63s", charging_state);
1571 /* present_rate is not the same as the
1572 current flowing now but it is the same value
1573 which was used in the past. so we continue
1575 else if (strncmp(buf, "POWER_SUPPLY_CURRENT_NOW=", 25) == 0)
1576 sscanf(buf, "POWER_SUPPLY_CURRENT_NOW=%d", &present_rate);
1577 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0)
1578 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1579 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=", 25) == 0)
1580 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_last_full[idx]);
1581 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0)
1582 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1583 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=", 25) == 0)
1584 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_last_full[idx]);
1587 fclose(sysfs_bat_fp[idx]);
1588 sysfs_bat_fp[idx] = NULL;
1590 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1591 if (remaining_capacity > acpi_last_full[idx])
1592 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1595 if (strcmp(present, "No") == 0) {
1596 strncpy(last_battery_str[idx], "not present", 64);
1599 else if (strcmp(charging_state, "Charging") == 0) {
1600 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1601 /* e.g. charging 75% */
1602 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Charging %i%%",
1603 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1605 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1606 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1607 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1608 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Charging %d%%",
1609 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1611 strncpy(last_battery_str[idx], "Charging", sizeof(last_battery_str[idx])-1);
1615 else if (strncmp(charging_state, "Discharging", 64) == 0) {
1616 if (present_rate > 0) {
1617 /* e.g. discharging 35% */
1618 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Discharging %i%%",
1619 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1621 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1622 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1623 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1624 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Full");
1626 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1628 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1632 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1633 else if (strncmp(charging_state, "Charged", 64) == 0) {
1634 /* Below happens with the second battery on my X40,
1635 * when the second one is empty and the first one
1637 if (remaining_capacity == 0)
1638 strcpy(last_battery_str[idx], "Empty");
1640 strcpy(last_battery_str[idx], "Charged");
1642 /* unknown, probably full / AC */
1644 if (acpi_last_full[idx] != 0
1645 && remaining_capacity != acpi_last_full[idx])
1646 snprintf(last_battery_str[idx], 64, "Unknown %d%%",
1647 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1649 strncpy(last_battery_str[idx], "AC", 64);
1651 } else if (acpi_bat_fp[idx] != NULL) {
1653 int present_rate = -1;
1654 int remaining_capacity = -1;
1655 char charging_state[64];
1658 /* read last full capacity if it's zero */
1659 if (acpi_last_full[idx] == 0) {
1664 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1665 fp = open_file(path, &rep);
1670 if (fgets(b, 256, fp) == NULL) {
1673 if (sscanf(b, "last full capacity: %d",
1674 &acpi_last_full[idx]) != 0) {
1683 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1685 strcpy(charging_state, "unknown");
1687 while (!feof(acpi_bat_fp[idx])) {
1690 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1694 /* let's just hope units are ok */
1695 if (strncmp(buf, "present:", 8) == 0) {
1696 sscanf(buf, "present: %4s", present);
1697 } else if (strncmp(buf, "charging state:", 15) == 0) {
1698 sscanf(buf, "charging state: %63s", charging_state);
1699 } else if (strncmp(buf, "present rate:", 13) == 0) {
1700 sscanf(buf, "present rate: %d", &present_rate);
1701 } else if (strncmp(buf, "remaining capacity:", 19) == 0) {
1702 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1705 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1706 if (remaining_capacity > acpi_last_full[idx]) {
1707 /* normalize to 100% */
1708 acpi_last_full[idx] = remaining_capacity;
1712 if (strcmp(present, "no") == 0) {
1713 strncpy(last_battery_str[idx], "not present", 64);
1715 } else if (strcmp(charging_state, "charging") == 0) {
1716 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1717 /* e.g. charging 75% */
1718 snprintf(last_battery_str[idx],
1719 sizeof(last_battery_str[idx]) - 1, "charging %i%%",
1720 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1722 format_seconds(last_battery_time_str[idx],
1723 sizeof(last_battery_time_str[idx]) - 1,
1724 (long) (((acpi_last_full[idx] - remaining_capacity) *
1725 3600) / present_rate));
1726 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1727 snprintf(last_battery_str[idx],
1728 sizeof(last_battery_str[idx]) - 1, "charging %d%%",
1729 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1731 strncpy(last_battery_str[idx], "charging",
1732 sizeof(last_battery_str[idx]) - 1);
1735 } else if (strncmp(charging_state, "discharging", 64) == 0) {
1736 if (present_rate > 0) {
1737 /* e.g. discharging 35% */
1738 snprintf(last_battery_str[idx],
1739 sizeof(last_battery_str[idx]) - 1, "discharging %i%%",
1740 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1742 format_seconds(last_battery_time_str[idx],
1743 sizeof(last_battery_time_str[idx]) - 1,
1744 (long) ((remaining_capacity * 3600) / present_rate));
1745 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1746 snprintf(last_battery_str[idx],
1747 sizeof(last_battery_str[idx]) - 1, "full");
1749 snprintf(last_battery_str[idx],
1750 sizeof(last_battery_str[idx]) - 1, "discharging %d%%",
1751 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1754 } else if (strncmp(charging_state, "charged", 64) == 0) {
1755 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1756 /* Below happens with the second battery on my X40,
1757 * when the second one is empty and the first one being charged. */
1758 if (remaining_capacity == 0) {
1759 strcpy(last_battery_str[idx], "empty");
1761 strcpy(last_battery_str[idx], "charged");
1763 /* unknown, probably full / AC */
1765 if (acpi_last_full[idx] != 0
1766 && remaining_capacity != acpi_last_full[idx]) {
1767 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1768 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1770 strncpy(last_battery_str[idx], "AC", 64);
1775 if (apm_bat_fp[idx] == NULL) {
1776 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1779 if (apm_bat_fp[idx] != NULL) {
1780 int ac, status, flag, life;
1782 fscanf(apm_bat_fp[idx], "%*s %*s %*x %x %x %x %d%%",
1783 &ac, &status, &flag, &life);
1786 /* could check now that there is ac */
1787 snprintf(last_battery_str[idx], 64, "AC");
1789 /* could check that status == 3 here? */
1790 } else if (ac && life != 100) {
1791 snprintf(last_battery_str[idx], 64, "charging %d%%", life);
1793 snprintf(last_battery_str[idx], 64, "%d%%", life);
1796 /* it seemed to buffer it so file must be closed (or could use
1797 * syscalls directly but I don't feel like coding it now) */
1798 fclose(apm_bat_fp[idx]);
1799 apm_bat_fp[idx] = NULL;
1805 case BATTERY_STATUS:
1806 snprintf(buf, n, "%s", last_battery_str[idx]);
1809 snprintf(buf, n, "%s", last_battery_time_str[idx]);
1816 int get_battery_perct(const char *bat)
1820 char acpi_path[128];
1822 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1823 char sysfs_path[128];
1824 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1828 idx = get_battery_idx(bat);
1830 /* don't update battery too often */
1831 if (current_update_time - last_battery_perct_time[idx] < 30) {
1832 return last_battery_perct[idx];
1834 last_battery_perct_time[idx] = current_update_time;
1836 /* Only check for SYSFS or ACPI */
1838 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1839 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1841 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1842 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1844 int remaining_capacity = -1;
1846 if (sysfs_bat_fp[idx] != NULL) {
1848 while (!feof(sysfs_bat_fp[idx])) {
1850 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1853 if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0)
1854 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1855 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=",25) != 0)
1856 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_last_full[idx]);
1857 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0)
1858 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1859 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=",25) != 0)
1860 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_last_full[idx]);
1863 fclose(sysfs_bat_fp[idx]);
1864 sysfs_bat_fp[idx] = NULL;
1866 } else if (acpi_bat_fp[idx] != NULL) {
1868 /* read last full capacity if it's zero */
1869 if (acpi_design_capacity[idx] == 0) {
1874 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1875 fp = open_file(path, &rep);
1880 if (fgets(b, 256, fp) == NULL) {
1883 if (sscanf(b, "last full capacity: %d",
1884 &acpi_design_capacity[idx]) != 0) {
1892 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1894 while (!feof(acpi_bat_fp[idx])) {
1897 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1901 if (buf[0] == 'r') {
1902 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1906 if (remaining_capacity < 0) {
1909 /* compute the battery percentage */
1910 last_battery_perct[idx] =
1911 (int) (((float) remaining_capacity / acpi_design_capacity[idx]) * 100);
1912 return last_battery_perct[idx];
1915 int get_battery_perct_bar(const char *bar)
1919 get_battery_perct(bar);
1920 idx = get_battery_idx(bar);
1921 return (int) (last_battery_perct[idx] * 2.56 - 1);
1924 /* On Apple powerbook and ibook:
1925 $ cat /proc/pmu/battery_0
1932 $ cat /proc/pmu/info
1933 PMU driver version : 2
1934 PMU firmware version : 0c
1939 /* defines as in <linux/pmu.h> */
1940 #define PMU_BATT_PRESENT 0x00000001
1941 #define PMU_BATT_CHARGING 0x00000002
1943 static FILE *pmu_battery_fp;
1944 static FILE *pmu_info_fp;
1945 static char pb_battery_info[3][32];
1946 static double pb_battery_info_update;
1948 #define PMU_PATH "/proc/pmu"
1949 void get_powerbook_batt_info(char *buf, size_t n, int i)
1952 const char *batt_path = PMU_PATH "/battery_0";
1953 const char *info_path = PMU_PATH "/info";
1954 int flags, charge, max_charge, ac = -1;
1957 /* don't update battery too often */
1958 if (current_update_time - pb_battery_info_update < 29.5) {
1959 snprintf(buf, n, "%s", pb_battery_info[i]);
1962 pb_battery_info_update = current_update_time;
1964 if (pmu_battery_fp == NULL) {
1965 pmu_battery_fp = open_file(batt_path, &rep);
1968 if (pmu_battery_fp != NULL) {
1969 rewind(pmu_battery_fp);
1970 while (!feof(pmu_battery_fp)) {
1973 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL) {
1977 if (buf[0] == 'f') {
1978 sscanf(buf, "flags : %8x", &flags);
1979 } else if (buf[0] == 'c' && buf[1] == 'h') {
1980 sscanf(buf, "charge : %d", &charge);
1981 } else if (buf[0] == 'm') {
1982 sscanf(buf, "max_charge : %d", &max_charge);
1983 } else if (buf[0] == 't') {
1984 sscanf(buf, "time rem. : %ld", &time);
1988 if (pmu_info_fp == NULL) {
1989 pmu_info_fp = open_file(info_path, &rep);
1992 if (pmu_info_fp != NULL) {
1993 rewind(pmu_info_fp);
1994 while (!feof(pmu_info_fp)) {
1997 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL) {
2000 if (buf[0] == 'A') {
2001 sscanf(buf, "AC Power : %d", &ac);
2005 /* update status string */
2006 if ((ac && !(flags & PMU_BATT_PRESENT))) {
2007 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
2008 } else if (ac && (flags & PMU_BATT_PRESENT)
2009 && !(flags & PMU_BATT_CHARGING)) {
2010 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
2011 } else if ((flags & PMU_BATT_PRESENT) && (flags & PMU_BATT_CHARGING)) {
2012 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
2014 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
2017 /* update percentage string */
2019 pb_battery_info[PB_BATT_PERCENT][0] = 0;
2021 snprintf(pb_battery_info[PB_BATT_PERCENT],
2022 sizeof(pb_battery_info[PB_BATT_PERCENT]), "%d%%",
2023 (charge * 100) / max_charge);
2026 /* update time string */
2027 if (time == 0) { /* fully charged or battery not present */
2028 pb_battery_info[PB_BATT_TIME][0] = 0;
2029 } else if (time < 60 * 60) { /* don't show secs */
2030 format_seconds_short(pb_battery_info[PB_BATT_TIME],
2031 sizeof(pb_battery_info[PB_BATT_TIME]), time);
2033 format_seconds(pb_battery_info[PB_BATT_TIME],
2034 sizeof(pb_battery_info[PB_BATT_TIME]), time);
2037 snprintf(buf, n, "%s", pb_battery_info[i]);
2042 show_nice_processes = 1;
2043 process_find_top(info.cpu, info.memu);
2044 info.first_process = get_first_process();
2047 /* The following ifdefs were adapted from gkrellm */
2048 #include <linux/major.h>
2050 #if !defined(MD_MAJOR)
2054 #if !defined(LVM_BLK_MAJOR)
2055 #define LVM_BLK_MAJOR 58
2058 #if !defined(NBD_MAJOR)
2059 #define NBD_MAJOR 43
2062 void update_diskio()
2064 static unsigned int last = UINT_MAX;
2065 static unsigned int last_read = UINT_MAX;
2066 static unsigned int last_write = UINT_MAX;
2070 char buf[512], devbuf[64];
2071 int major, minor, i;
2072 unsigned int current = 0;
2073 unsigned int current_read = 0;
2074 unsigned int current_write = 0;
2075 unsigned int reads, writes = 0;
2078 if (!(fp = open_file("/proc/diskstats", &rep))) {
2083 /* read reads and writes from all disks (minor = 0), including cd-roms
2084 * and floppies, and sum them up */
2086 fgets(buf, 512, fp);
2087 col_count = sscanf(buf, "%u %u %s %*u %*u %u %*u %*u %*u %u", &major,
2088 &minor, devbuf, &reads, &writes);
2089 /* ignore subdevices (they have only 3 matching entries in their line)
2090 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
2092 * XXX: ignore devices which are part of a SW RAID (MD_MAJOR) */
2093 if (col_count == 5 && major != LVM_BLK_MAJOR && major != NBD_MAJOR
2094 && major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
2095 current += reads + writes;
2096 current_read += reads;
2097 current_write += writes;
2099 col_count = sscanf(buf, "%u %u %s %*u %u %*u %u",
2100 &major, &minor, devbuf, &reads, &writes);
2101 if (col_count != 5) {
2105 for (i = 0; i < MAX_DISKIO_STATS; i++) {
2106 if (diskio_stats[i].dev &&
2107 strcmp(devbuf, diskio_stats[i].dev) == 0) {
2108 diskio_stats[i].current =
2109 (reads + writes - diskio_stats[i].last) / 2;
2110 diskio_stats[i].current_read =
2111 (reads - diskio_stats[i].last_read) / 2;
2112 diskio_stats[i].current_write =
2113 (writes - diskio_stats[i].last_write) / 2;
2114 if (reads + writes < diskio_stats[i].last) {
2115 diskio_stats[i].current = 0;
2117 if (reads < diskio_stats[i].last_read) {
2118 diskio_stats[i].current_read = 0;
2119 diskio_stats[i].current = diskio_stats[i].current_write;
2121 if (writes < diskio_stats[i].last_write) {
2122 diskio_stats[i].current_write = 0;
2123 diskio_stats[i].current = diskio_stats[i].current_read;
2125 diskio_stats[i].last = reads + writes;
2126 diskio_stats[i].last_read = reads;
2127 diskio_stats[i].last_write = writes;
2132 /* since the values in /proc/diststats are absolute, we have to substract
2133 * our last reading. The numbers stand for "sectors read", and we therefore
2134 * have to divide by two to get KB */
2135 int tot = ((double) (current - last) / 2);
2136 int tot_read = ((double) (current_read - last_read) / 2);
2137 int tot_write = ((double) (current_write - last_write) / 2);
2139 if (last_read > current_read) {
2142 if (last_write > current_write) {
2146 if (last > current) {
2147 /* we hit this either if it's the very first time we run this, or
2148 * when /proc/diskstats overflows; while 0 is not correct, it's at
2149 * least not way off */
2153 last_read = current_read;
2154 last_write = current_write;
2157 diskio_read_value = tot_read;
2158 diskio_write_value = tot_write;
2163 /* Here come the IBM ACPI-specific things. For reference, see
2164 * http://ibm-acpi.sourceforge.net/README
2165 * If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
2181 * The content of these files is described in detail in the aforementioned
2182 * README - some of them also in the following functions accessing them.
2183 * Peter Tarjan (ptarjan@citromail.hu) */
2185 #define IBM_ACPI_DIR "/proc/acpi/ibm"
2187 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
2188 * /proc/acpi/ibm/fan looks like this (3 lines):
2191 commands: enable, disable
2192 * Peter Tarjan (ptarjan@citromail.hu) */
2194 void get_ibm_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
2196 if (!p_client_buffer || client_buffer_size <= 0) {
2201 unsigned int speed = 0;
2204 snprintf(fan, 127, "%s/fan", IBM_ACPI_DIR);
2206 fp = fopen(fan, "r");
2211 if (fgets(line, 255, fp) == NULL) {
2214 if (sscanf(line, "speed: %d", &speed)) {
2219 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2220 "ibm* from your Conky config file.", fan, strerror(errno));
2224 snprintf(p_client_buffer, client_buffer_size, "%d", speed);
2227 /* get the measured temperatures from the temperature sensors
2228 * on IBM/Lenovo laptops running the ibm acpi.
2229 * There are 8 values in /proc/acpi/ibm/thermal, and according to
2230 * http://ibm-acpi.sourceforge.net/README
2231 * these mean the following (at least on an IBM R51...)
2232 * 0: CPU (also on the T series laptops)
2233 * 1: Mini PCI Module (?)
2235 * 3: GPU (also on the T series laptops)
2240 * I'm not too sure about those with the question mark, but the values I'm
2241 * reading from *my* thermal file (on a T42p) look realistic for the
2242 * hdd and the battery.
2243 * #5 and #7 are always -128.
2244 * /proc/acpi/ibm/thermal looks like this (1 line):
2245 temperatures: 41 43 31 46 33 -128 29 -128
2246 * Peter Tarjan (ptarjan@citromail.hu) */
2248 static double last_ibm_acpi_temp_time;
2249 void get_ibm_acpi_temps()
2252 /* don't update too often */
2253 if (current_update_time - last_ibm_acpi_temp_time < 10.00) {
2256 last_ibm_acpi_temp_time = current_update_time;
2258 /* if (!p_client_buffer || client_buffer_size <= 0) {
2266 snprintf(thermal, 127, "%s/thermal", IBM_ACPI_DIR);
2267 fp = fopen(thermal, "r");
2273 if (fgets(line, 255, fp) == NULL) {
2276 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
2277 &ibm_acpi.temps[0], &ibm_acpi.temps[1], &ibm_acpi.temps[2],
2278 &ibm_acpi.temps[3], &ibm_acpi.temps[4], &ibm_acpi.temps[5],
2279 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) {
2284 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2285 "ibm* from your Conky config file.", thermal, strerror(errno));
2291 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
2292 * "Volume" here is none of the mixer volumes, but a "master of masters"
2293 * volume adjusted by the IBM volume keys.
2294 * /proc/acpi/ibm/fan looks like this (4 lines):
2297 commands: up, down, mute
2298 commands: level <level> (<level> is 0-15)
2299 * Peter Tarjan (ptarjan@citromail.hu) */
2301 void get_ibm_acpi_volume(char *p_client_buffer, size_t client_buffer_size)
2303 if (!p_client_buffer || client_buffer_size <= 0) {
2311 snprintf(volume, 127, "%s/volume", IBM_ACPI_DIR);
2312 unsigned int vol = -1;
2315 fp = fopen(volume, "r");
2319 unsigned int read_vol = -1;
2321 if (fgets(line, 255, fp) == NULL) {
2324 if (sscanf(line, "level: %d", &read_vol)) {
2328 if (sscanf(line, "mute: %s", mute)) {
2333 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2334 "ibm* from your Conky config file.", volume, strerror(errno));
2339 if (strcmp(mute, "on") == 0) {
2340 snprintf(p_client_buffer, client_buffer_size, "%s", "mute");
2343 snprintf(p_client_buffer, client_buffer_size, "%d", vol);
2348 /* static FILE *fp = NULL; */
2350 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
2351 * /proc/acpi/ibm/brightness looks like this (3 lines):
2354 commands: level <level> (<level> is 0-7)
2355 * Peter Tarjan (ptarjan@citromail.hu) */
2357 void get_ibm_acpi_brightness(char *p_client_buffer, size_t client_buffer_size)
2359 if (!p_client_buffer || client_buffer_size <= 0) {
2364 unsigned int brightness = 0;
2367 snprintf(filename, 127, "%s/brightness", IBM_ACPI_DIR);
2369 fp = fopen(filename, "r");
2374 if (fgets(line, 255, fp) == NULL) {
2377 if (sscanf(line, "level: %d", &brightness)) {
2382 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2383 "ibm* from your Conky config file.", filename, strerror(errno));
2388 snprintf(p_client_buffer, client_buffer_size, "%d", brightness);
2391 void update_entropy(void)
2394 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
2395 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
2398 info.entropy.entropy_avail = 0;
2399 info.entropy.poolsize = 0;
2401 if ((fp1 = open_file(entropy_avail, &rep)) == NULL) {
2405 if ((fp2 = open_file(entropy_poolsize, &rep)) == NULL) {
2410 fscanf(fp1, "%u", &info.entropy.entropy_avail);
2411 fscanf(fp2, "%u", &info.entropy.poolsize);
2416 info.mask |= (1 << INFO_ENTROPY);