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);
186 * # cat /sys/block/sda/queue/scheduler
187 * noop [anticipatory] cfq
189 char *get_ioscheduler(char *disk)
197 snprintf(buf, 127, "/sys/block/%s/queue/scheduler", disk);
198 if ((fp = fopen(buf, "r")) == NULL) {
199 return strdup("n/a");
202 fscanf(fp, "%127s", buf);
204 buf[strlen(buf) - 1] = '\0';
206 return strdup(buf + 1);
210 return strdup("n/a");
213 int interface_up(const char *dev)
218 if((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
219 CRIT_ERR("could not create sockfd");
222 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
223 if(ioctl(fd, SIOCGIFFLAGS, &ifr)) {
224 /* if device does not exist, treat like not up */
226 perror("SIOCGIFFLAGS");
229 return (ifr.ifr_flags & IFF_UP);
235 #define COND_FREE(x) if(x) free(x); x = 0
236 #define SAVE_SET_STRING(x, y) \
237 if (x && strcmp((char *)x, (char *)y)) { \
239 x = strdup("multiple"); \
244 void update_gateway_info()
249 unsigned long dest, gate, mask;
251 short ref, use, metric, mtu, win, irtt;
253 struct gateway_info *gw_info = &info.gw_info;
255 COND_FREE(gw_info->iface);
256 COND_FREE(gw_info->ip);
259 if ((fp = fopen("/proc/net/route", "r")) == NULL) {
263 if (fscanf(fp, "%*[^\n]\n") == EOF) {
268 // Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
269 if(fscanf(fp, "%63s %lx %lx %x %hd %hd %hd %lx %hd %hd %hd\n",
270 iface, &dest, &gate, &flags, &ref, &use,
271 &metric, &mask, &mtu, &win, &irtt) != 11) {
275 if (flags & RTF_GATEWAY && dest == 0 && mask == 0) {
277 SAVE_SET_STRING(gw_info->iface, iface)
279 SAVE_SET_STRING(gw_info->ip, inet_ntoa(ina))
287 info.gw_info.iface = info.gw_info.ip = strdup("failed");
291 inline void update_net_stats()
296 // FIXME: arbitrary size chosen to keep code simple.
298 unsigned int curtmp1, curtmp2;
305 // wireless info variables
306 int skfd, has_bitrate = 0;
307 struct wireless_info *winfo;
312 delta = current_update_time - last_update_time;
313 if (delta <= 0.0001) {
317 /* open file and ignore first two lines */
318 if (!(net_dev_fp = open_file("/proc/net/dev", &rep))) {
323 fgets(buf, 255, net_dev_fp); /* garbage */
324 fgets(buf, 255, net_dev_fp); /* garbage (field names) */
326 /* read each interface */
327 for (i2 = 0; i2 < 16; i2++) {
331 long long r, t, last_recv, last_trans;
333 if (fgets(buf, 255, net_dev_fp) == NULL) {
337 while (isspace((int) *p)) {
343 while (*p && *p != ':') {
352 ns = get_net_stat(s);
354 memset(&(ns->addr.sa_data), 0, 14);
356 if(NULL == ns->addrs)
357 ns->addrs = (char*) malloc(17 * 16);
358 if(NULL != ns->addrs)
359 memset(ns->addrs, 0, 17 * 16); /* Up to 17 chars per ip, max 16 interfaces. Nasty memory usage... */
361 last_recv = ns->recv;
362 last_trans = ns->trans;
364 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
365 sscanf(p, "%Ld %*d %*d %*d %*d %*d %*d %*d %Ld",
368 /* if recv or trans is less than last time, an overflow happened */
369 if (r < ns->last_read_recv) {
372 ns->recv += (r - ns->last_read_recv);
374 ns->last_read_recv = r;
376 if (t < ns->last_read_trans) {
379 ns->trans += (t - ns->last_read_trans);
381 ns->last_read_trans = t;
383 /*** ip addr patch ***/
384 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
386 conf.ifc_buf = malloc(sizeof(struct ifreq) * 16);
387 conf.ifc_len = sizeof(struct ifreq) * 16;
388 memset(conf.ifc_buf, 0, conf.ifc_len);
390 ioctl((long) i, SIOCGIFCONF, &conf);
392 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
395 if (!(((struct ifreq *) conf.ifc_buf) + k))
399 ((struct ifreq *) conf.ifc_buf)[k].ifr_ifrn.ifrn_name);
400 ns->addr = ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.ifru_addr;
401 if(NULL != ns->addrs) {
402 sprintf(temp_addr, "%u.%u.%u.%u, ",
403 ns->addr.sa_data[2] & 255,
404 ns->addr.sa_data[3] & 255,
405 ns->addr.sa_data[4] & 255,
406 ns->addr.sa_data[5] & 255);
407 if(NULL == strstr(ns->addrs, temp_addr))
408 strncpy(ns->addrs + strlen(ns->addrs), temp_addr, 17);
416 /*** end ip addr patch ***/
418 /* calculate speeds */
419 ns->net_rec[0] = (ns->recv - last_recv) / delta;
420 ns->net_trans[0] = (ns->trans - last_trans) / delta;
424 for (i = 0; (unsigned) i < info.net_avg_samples; i++) {
425 curtmp1 += ns->net_rec[i];
426 curtmp2 += ns->net_trans[i];
434 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
435 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
436 if (info.net_avg_samples > 1) {
437 for (i = info.net_avg_samples; i > 1; i--) {
438 ns->net_rec[i - 1] = ns->net_rec[i - 2];
439 ns->net_trans[i - 1] = ns->net_trans[i - 2];
444 /* update wireless info */
445 winfo = malloc(sizeof(struct wireless_info));
446 memset(winfo, 0, sizeof(struct wireless_info));
448 skfd = iw_sockets_open();
449 if (iw_get_basic_config(skfd, s, &(winfo->b)) > -1) {
451 // set present winfo variables
452 if (iw_get_stats(skfd, s, &(winfo->stats),
453 &winfo->range, winfo->has_range) >= 0) {
454 winfo->has_stats = 1;
456 if (iw_get_range_info(skfd, s, &(winfo->range)) >= 0) {
457 winfo->has_range = 1;
459 if (iw_get_ext(skfd, s, SIOCGIWAP, &wrq) >= 0) {
460 winfo->has_ap_addr = 1;
461 memcpy(&(winfo->ap_addr), &(wrq.u.ap_addr), sizeof(sockaddr));
465 if (iw_get_ext(skfd, s, SIOCGIWRATE, &wrq) >= 0) {
466 memcpy(&(winfo->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
467 iw_print_bitrate(ns->bitrate, 16, winfo->bitrate.value);
472 if (winfo->has_range && winfo->has_stats
473 && ((winfo->stats.qual.level != 0)
474 || (winfo->stats.qual.updated & IW_QUAL_DBM))) {
475 if (!(winfo->stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
476 ns->link_qual = winfo->stats.qual.qual;
477 ns->link_qual_max = winfo->range.max_qual.qual;
482 if (winfo->has_ap_addr) {
483 iw_sawap_ntop(&winfo->ap_addr, ns->ap);
487 if (winfo->b.has_essid) {
488 if (winfo->b.essid_on) {
489 snprintf(ns->essid, 32, "%s", winfo->b.essid);
491 snprintf(ns->essid, 32, "off/any");
495 snprintf(ns->mode, 16, "%s", iw_operation_mode[winfo->b.mode]);
497 iw_sockets_close(skfd);
504 info.mask |= (1 << INFO_NET);
509 void update_total_processes()
513 struct sysinfo s_info;
516 info.procs = s_info.procs;
523 if (!(fp = open_file("/proc/loadavg", &rep))) {
527 fscanf(fp, "%*f %*f %*f %*d/%hd", &info.procs);
530 info.mask |= (1 << INFO_PROCS);
533 #define CPU_SAMPLE_COUNT 15
535 unsigned long long cpu_user;
536 unsigned long long cpu_system;
537 unsigned long long cpu_nice;
538 unsigned long long cpu_idle;
539 unsigned long long cpu_iowait;
540 unsigned long long cpu_irq;
541 unsigned long long cpu_softirq;
542 unsigned long long cpu_steal;
543 unsigned long long cpu_total;
544 unsigned long long cpu_active_total;
545 unsigned long long cpu_last_total;
546 unsigned long long cpu_last_active_total;
547 double cpu_val[CPU_SAMPLE_COUNT];
549 static short cpu_setup = 0;
551 /* Determine if this kernel gives us "extended" statistics information in
553 * Kernels around 2.5 and earlier only reported user, system, nice, and
554 * idle values in proc stat.
555 * Kernels around 2.6 and greater report these PLUS iowait, irq, softirq,
557 void determine_longstat(char *buf)
559 unsigned long long iowait = 0;
561 KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
562 /* scanf will either return -1 or 1 because there is only 1 assignment */
563 if (sscanf(buf, "%*s %*d %*d %*d %*d %llu", &iowait) > 0) {
564 KFLAG_SETON(KFLAG_IS_LONGSTAT);
573 if (info.cpu_usage) {
578 if (!(stat_fp = open_file("/proc/stat", &rep))) {
584 while (!feof(stat_fp)) {
585 if (fgets(buf, 255, stat_fp) == NULL) {
589 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
590 if (info.cpu_count == 0) {
591 determine_longstat(buf);
596 info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
601 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
602 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
604 inline static void update_stat()
608 static struct cpu_info *cpu = NULL;
613 char *stat_template = NULL;
614 unsigned int malloc_cpu_size = 0;
616 /* add check for !info.cpu_usage since that mem is freed on a SIGUSR1 */
617 if (!cpu_setup || !info.cpu_usage) {
622 if (!stat_template) {
624 KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT;
628 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
629 cpu = malloc(malloc_cpu_size);
630 memset(cpu, 0, malloc_cpu_size);
633 if (!(stat_fp = open_file("/proc/stat", &rep))) {
635 if (info.cpu_usage) {
636 memset(info.cpu_usage, 0, info.cpu_count * sizeof(float));
642 while (!feof(stat_fp)) {
643 if (fgets(buf, 255, stat_fp) == NULL) {
647 if (strncmp(buf, "procs_running ", 14) == 0) {
648 sscanf(buf, "%*s %hu", &info.run_procs);
649 info.mask |= (1 << INFO_RUN_PROCS);
650 } else if (strncmp(buf, "cpu", 3) == 0) {
651 index = isdigit(buf[3]) ? ((int) buf[3]) - 0x2F : 0;
652 sscanf(buf, stat_template, &(cpu[index].cpu_user),
653 &(cpu[index].cpu_nice), &(cpu[index].cpu_system),
654 &(cpu[index].cpu_idle), &(cpu[index].cpu_iowait),
655 &(cpu[index].cpu_irq), &(cpu[index].cpu_softirq),
656 &(cpu[index].cpu_steal));
658 cpu[index].cpu_total = cpu[index].cpu_user + cpu[index].cpu_nice +
659 cpu[index].cpu_system + cpu[index].cpu_idle +
660 cpu[index].cpu_iowait + cpu[index].cpu_irq +
661 cpu[index].cpu_softirq + cpu[index].cpu_steal;
663 cpu[index].cpu_active_total = cpu[index].cpu_total -
664 (cpu[index].cpu_idle + cpu[index].cpu_iowait);
665 info.mask |= (1 << INFO_CPU);
667 double delta = current_update_time - last_update_time;
669 if (delta <= 0.001) {
673 cpu[index].cpu_val[0] = (cpu[index].cpu_active_total -
674 cpu[index].cpu_last_active_total) /
675 (float) (cpu[index].cpu_total - cpu[index].cpu_last_total);
677 for (i = 0; i < info.cpu_avg_samples; i++) {
678 curtmp += cpu[index].cpu_val[i];
680 /* TESTING -- I've removed this, because I don't think it is right.
681 * You shouldn't divide by the cpu count here ...
682 * removing for testing */
684 info.cpu_usage[index] = curtmp / info.cpu_avg_samples /
687 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
689 /* TESTING -- this line replaces the prev. "suspect" if/else */
690 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
692 cpu[index].cpu_last_total = cpu[index].cpu_total;
693 cpu[index].cpu_last_active_total = cpu[index].cpu_active_total;
694 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
695 cpu[index].cpu_val[i] = cpu[index].cpu_val[i - 1];
702 void update_running_processes()
707 void update_cpu_usage()
712 void update_load_average()
714 #ifdef HAVE_GETLOADAVG
719 info.loadavg[0] = (float) v[0];
720 info.loadavg[1] = (float) v[1];
721 info.loadavg[2] = (float) v[2];
728 if (!(fp = open_file("/proc/loadavg", &rep))) {
729 info.loadavg[0] = info.loadavg[1] = info.loadavg[2] = 0.0;
732 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1],
736 info.mask |= (1 << INFO_LOADAVG);
739 #define PROC_I8K "/proc/i8k"
740 #define I8K_DELIM " "
741 static char *i8k_procbuf = NULL;
747 i8k_procbuf = (char *) malloc(128 * sizeof(char));
749 if ((fp = fopen(PROC_I8K, "r")) == NULL) {
750 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel "
751 "driver is loaded...");
754 memset(&i8k_procbuf[0], 0, 128);
755 if (fread(&i8k_procbuf[0], sizeof(char), 128, fp) == 0) {
756 ERR("something wrong with /proc/i8k...");
761 i8k.version = strtok(&i8k_procbuf[0], I8K_DELIM);
762 i8k.bios = strtok(NULL, I8K_DELIM);
763 i8k.serial = strtok(NULL, I8K_DELIM);
764 i8k.cpu_temp = strtok(NULL, I8K_DELIM);
765 i8k.left_fan_status = strtok(NULL, I8K_DELIM);
766 i8k.right_fan_status = strtok(NULL, I8K_DELIM);
767 i8k.left_fan_rpm = strtok(NULL, I8K_DELIM);
768 i8k.right_fan_rpm = strtok(NULL, I8K_DELIM);
769 i8k.ac_status = strtok(NULL, I8K_DELIM);
770 i8k.buttons_status = strtok(NULL, I8K_DELIM);
773 /***********************************************************/
774 /***********************************************************/
775 /***********************************************************/
777 static int no_dots(const struct dirent *d)
779 if (d->d_name[0] == '.') {
785 static int get_first_file_in_a_directory(const char *dir, char *s, int *rep)
787 struct dirent **namelist;
790 n = scandir(dir, &namelist, no_dots, alphasort);
793 ERR("scandir for %s: %s", dir, strerror(errno));
804 strncpy(s, namelist[0]->d_name, 255);
807 for (i = 0; i < n; i++) {
816 int open_sysfs_sensor(const char *dir, const char *dev, const char *type, int n,
817 int *div, char *devtype)
824 memset(buf, 0, sizeof(buf));
826 /* if device is NULL or *, get first */
827 if (dev == NULL || strcmp(dev, "*") == 0) {
830 if (!get_first_file_in_a_directory(dir, buf, &rep)) {
836 if (strcmp(dir, "/sys/class/hwmon/") == 0) {
838 /* buf holds result from get_first_file_in_a_directory() above,
839 * e.g. "hwmon0" -- append "/device" */
840 strcat(buf, "/device");
842 /* dev holds device number N as a string,
843 * e.g. "0", -- convert to "hwmon0/device" */
844 sprintf(buf, "hwmon%s/device", dev);
849 /* change vol to in */
850 if (strcmp(type, "vol") == 0) {
854 if (strcmp(type, "tempf") == 0) {
855 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, "temp", n);
857 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, type, n);
859 strncpy(devtype, path, 255);
862 fd = open(path, O_RDONLY);
864 CRIT_ERR("can't open '%s': %s\nplease check your device or remove this "
865 "var from Conky", path, strerror(errno));
868 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
869 || strcmp(type, "tempf") == 0) {
874 /* fan does not use *_div as a read divisor */
875 if (strcmp("fan", type) == 0) {
879 /* test if *_div file exist, open it and use it as divisor */
880 if (strcmp(type, "tempf") == 0) {
881 snprintf(path, 255, "%s%s/%s%d_div", dir, "one", "two", n);
883 snprintf(path, 255, "%s%s/%s%d_div", dir, dev, type, n);
886 divfd = open(path, O_RDONLY);
892 divn = read(divfd, divbuf, 63);
893 /* should read until n == 0 but I doubt that kernel will give these
894 * in multiple pieces. :) */
896 ERR("open_sysfs_sensor(): can't read from sysfs");
908 double get_sysfs_info(int *fd, int div, char *devtype, char *type)
916 lseek(*fd, 0, SEEK_SET);
922 n = read(*fd, buf, 63);
923 /* should read until n == 0 but I doubt that kernel will give these
924 * in multiple pieces. :) */
926 ERR("get_sysfs_info(): read from %s failed\n", devtype);
935 *fd = open(devtype, O_RDONLY);
937 ERR("can't open '%s': %s", devtype, strerror(errno));
940 /* My dirty hack for computing CPU value
941 * Filedil, from forums.gentoo.org */
942 /* if (strstr(devtype, "temp1_input") != NULL) {
943 return -15.096 + 1.4893 * (val / 1000.0);
946 /* divide voltage and temperature by 1000 */
947 /* or if any other divisor is given, use that */
948 if (strcmp(type, "tempf") == 0) {
950 return ((val / div + 40) * 9.0 / 5) - 40;
952 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
954 return ((val + 40) * 9.0 / 5) - 40;
967 /* Prior to kernel version 2.6.12, the CPU fan speed was available in
968 * ADT746X_FAN_OLD, whereas later kernel versions provide this information in
970 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
971 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
973 void get_adt746x_fan(char *p_client_buffer, size_t client_buffer_size)
976 char adt746x_fan_state[64];
979 if (!p_client_buffer || client_buffer_size <= 0) {
983 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
984 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL) {
985 sprintf(adt746x_fan_state, "adt746x not found");
987 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
988 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
992 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_fan_state);
995 /* Prior to kernel version 2.6.12, the CPU temperature was found in
996 * ADT746X_CPU_OLD, whereas later kernel versions provide this information in
998 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
999 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
1001 void get_adt746x_cpu(char *p_client_buffer, size_t client_buffer_size)
1004 char adt746x_cpu_state[64];
1007 if (!p_client_buffer || client_buffer_size <= 0) {
1011 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
1012 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL) {
1013 sprintf(adt746x_cpu_state, "adt746x not found");
1015 fscanf(fp, "%2s", adt746x_cpu_state);
1019 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state);
1022 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
1024 /***********************************************************************/
1025 /* This file is part of x86info.
1026 * (C) 2001 Dave Jones.
1028 * Licensed under the terms of the GNU GPL License version 2.
1030 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
1031 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz> */
1033 #if defined(__i386) || defined(__x86_64)
1034 __inline__ unsigned long long int rdtsc()
1036 unsigned long long int x;
1038 __asm__ volatile(".byte 0x0f, 0x31":"=A" (x));
1043 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1044 void get_freq_dynamic(char *p_client_buffer, size_t client_buffer_size,
1045 char *p_format, int divisor)
1047 #if defined(__i386) || defined(__x86_64)
1049 struct timeval tvstart, tvstop;
1050 unsigned long long cycles[2]; /* gotta be 64 bit */
1051 unsigned int microseconds; /* total time taken */
1053 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1058 memset(&tz, 0, sizeof(tz));
1060 /* get this function in cached memory */
1061 gettimeofday(&tvstart, &tz);
1062 cycles[0] = rdtsc();
1063 gettimeofday(&tvstart, &tz);
1065 /* we don't trust that this is any specific length of time */
1067 cycles[1] = rdtsc();
1068 gettimeofday(&tvstop, &tz);
1069 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
1070 (tvstop.tv_usec - tvstart.tv_usec);
1072 snprintf(p_client_buffer, client_buffer_size, p_format,
1073 (float) ((cycles[1] - cycles[0]) / microseconds) / divisor);
1076 /* FIXME: hardwired: get freq for first cpu!
1077 * this whole function needs to be rethought and redone for
1078 * multi-cpu/multi-core/multi-threaded environments and
1079 * arbitrary combinations thereof */
1080 get_freq(p_client_buffer, client_buffer_size, p_format, divisor, 1);
1085 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
1086 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
1088 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1089 char get_freq(char *p_client_buffer, size_t client_buffer_size, char *p_format,
1090 int divisor, unsigned int cpu)
1098 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1104 char current_freq_file[128];
1106 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu - 1,
1108 f = fopen(current_freq_file, "r");
1110 /* if there's a cpufreq /sys node, read the current frequency from
1111 * this node and divide by 1000 to get Mhz. */
1112 if (fgets(s, sizeof(s), f)) {
1113 s[strlen(s) - 1] = '\0';
1114 freq = strtod(s, NULL);
1117 snprintf(p_client_buffer, client_buffer_size, p_format,
1118 (freq / 1000) / divisor);
1123 // open the CPU information file
1124 f = open_file("/proc/cpuinfo", &rep);
1126 perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
1131 while (fgets(s, sizeof(s), f) != NULL) {
1133 #if defined(__i386) || defined(__x86_64)
1134 // and search for the cpu mhz
1135 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) {
1137 #if defined(__alpha)
1138 // different on alpha
1139 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) {
1141 // this is different on ppc for some reason
1142 if (strncmp(s, "clock", 5) == 0 && cpu == 0) {
1143 #endif // defined(__alpha)
1144 #endif // defined(__i386) || defined(__x86_64)
1146 // copy just the number
1147 strcpy(frequency, strchr(s, ':') + 2);
1148 #if defined(__alpha)
1150 frequency[strlen(frequency) - 6] = '\0';
1151 // kernel reports in Hz
1152 freq = strtod(frequency, NULL) / 1000000;
1155 frequency[strlen(frequency) - 1] = '\0';
1156 freq = strtod(frequency, NULL);
1160 if (strncmp(s, "processor", 9) == 0) {
1167 snprintf(p_client_buffer, client_buffer_size, p_format,
1168 (float) freq / divisor);
1172 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
1174 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks something
1184 * Peter Tarjan (ptarjan@citromail.hu) */
1186 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
1187 char get_voltage(char *p_client_buffer, size_t client_buffer_size,
1188 char *p_format, int divisor, unsigned int cpu)
1194 char current_freq_file[128];
1197 /* build the voltage file name */
1199 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1202 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1207 /* read the current cpu frequency from the /sys node */
1208 f = fopen(current_freq_file, "r");
1210 if (fgets(s, sizeof(s), f)) {
1211 s[strlen(s) - 1] = '\0';
1212 freq = strtod(s, NULL);
1216 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1217 perror("get_voltage()");
1224 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1227 /* use the current cpu frequency to find the corresponding voltage */
1228 f = fopen(current_freq_file, "r");
1234 if (fgets(line, 255, f) == NULL) {
1237 sscanf(line, "%d %d", &freq_comp, &voltage);
1238 if (freq_comp == freq) {
1244 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1245 perror("get_voltage()");
1251 snprintf(p_client_buffer, client_buffer_size, p_format,
1252 (float) voltage / divisor);
1256 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1258 void get_acpi_fan(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_FAN_DIR, buf, &rep)) {
1271 snprintf(p_client_buffer, client_buffer_size, "no fans?");
1275 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf);
1277 fp = open_file(buf2, &rep);
1279 snprintf(p_client_buffer, client_buffer_size,
1280 "can't open fan's state file");
1283 memset(buf, 0, sizeof(buf));
1284 fscanf(fp, "%*s %99s", buf);
1287 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1290 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1292 void get_acpi_ac_adapter(char *p_client_buffer, size_t client_buffer_size)
1299 if (!p_client_buffer || client_buffer_size <= 0) {
1303 /* yeah, slow... :/ */
1304 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep)) {
1305 snprintf(p_client_buffer, client_buffer_size, "no ac_adapters?");
1309 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf);
1311 fp = open_file(buf2, &rep);
1313 snprintf(p_client_buffer, client_buffer_size,
1314 "No ac adapter found.... where is it?");
1317 memset(buf, 0, sizeof(buf));
1318 fscanf(fp, "%*s %99s", buf);
1321 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1325 /proc/acpi/thermal_zone/THRM/cooling_mode
1326 cooling mode: active
1327 /proc/acpi/thermal_zone/THRM/polling_frequency
1329 /proc/acpi/thermal_zone/THRM/state
1331 /proc/acpi/thermal_zone/THRM/temperature
1333 /proc/acpi/thermal_zone/THRM/trip_points
1335 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1338 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1339 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1341 int open_acpi_temperature(const char *name)
1347 if (name == NULL || strcmp(name, "*") == 0) {
1350 if (!get_first_file_in_a_directory(ACPI_THERMAL_DIR, buf, &rep)) {
1356 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1358 fd = open(path, O_RDONLY);
1360 ERR("can't open '%s': %s", path, strerror(errno));
1366 static double last_acpi_temp;
1367 static double last_acpi_temp_time;
1369 double get_acpi_temperature(int fd)
1375 /* don't update acpi temperature too often */
1376 if (current_update_time - last_acpi_temp_time < 11.32) {
1377 return last_acpi_temp;
1379 last_acpi_temp_time = current_update_time;
1381 /* seek to beginning */
1382 lseek(fd, 0, SEEK_SET);
1389 n = read(fd, buf, 255);
1391 ERR("can't read fd %d: %s", fd, strerror(errno));
1394 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1398 return last_acpi_temp;
1402 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1404 design capacity: 4400 mAh
1405 last full capacity: 4064 mAh
1406 battery technology: rechargeable
1407 design voltage: 14800 mV
1408 design capacity warning: 300 mAh
1409 design capacity low: 200 mAh
1410 capacity granularity 1: 32 mAh
1411 capacity granularity 2: 32 mAh
1413 serial number: 16922
1419 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1422 charging state: unknown
1424 remaining capacity: 4064 mAh
1425 present voltage: 16608 mV
1429 2213<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1430 2213<@jupet�kellari��> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1431 2213<@jupet�kellari��> (-1 ollee ei akkua kiinni, koska akku on p�yd�ll�)
1432 2214<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1433 2214<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1435 2238<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1436 2239<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1438 2240<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori p��ll�
1439 2241<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori p��ll� mutta ilman verkkovirtaa
1442 /* Kapil Hari Paranjape <kapil@imsc.res.in>
1443 Linux 2.6.24 onwards battery info is in
1444 /sys/class/power_supply/BAT0/
1445 On my system I get the following.
1446 /sys/class/power_supply/BAT0/uevent:
1447 PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A03:00/device:01/PNP0C09:00/PNP0C0A:00
1449 PHYSDEVDRIVER=battery
1450 POWER_SUPPLY_NAME=BAT0
1451 POWER_SUPPLY_TYPE=Battery
1452 POWER_SUPPLY_STATUS=Discharging
1453 POWER_SUPPLY_PRESENT=1
1454 POWER_SUPPLY_TECHNOLOGY=Li-ion
1455 POWER_SUPPLY_VOLTAGE_MIN_DESIGN=10800000
1456 POWER_SUPPLY_VOLTAGE_NOW=10780000
1457 POWER_SUPPLY_CURRENT_NOW=13970000
1458 POWER_SUPPLY_ENERGY_FULL_DESIGN=47510000
1459 POWER_SUPPLY_ENERGY_FULL=27370000
1460 POWER_SUPPLY_ENERGY_NOW=11810000
1461 POWER_SUPPLY_MODEL_NAME=IBM-92P1060
1462 POWER_SUPPLY_MANUFACTURER=Panasonic
1463 On some systems POWER_SUPPLY_ENERGY_* is replaced by POWER_SUPPLY_CHARGE_*
1466 #define SYSFS_BATTERY_BASE_PATH "/sys/class/power_supply"
1467 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1468 #define APM_PATH "/proc/apm"
1469 #define MAX_BATTERY_COUNT 4
1471 static FILE *sysfs_bat_fp[MAX_BATTERY_COUNT];
1472 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT];
1473 static FILE *apm_bat_fp[MAX_BATTERY_COUNT];
1475 static int batteries_initialized = 0;
1476 static char batteries[MAX_BATTERY_COUNT][32];
1478 static int acpi_last_full[MAX_BATTERY_COUNT];
1479 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1481 /* e.g. "charging 75%" */
1482 static char last_battery_str[MAX_BATTERY_COUNT][64];
1484 static char last_battery_time_str[MAX_BATTERY_COUNT][64];
1486 static double last_battery_time[MAX_BATTERY_COUNT];
1488 static int last_battery_perct[MAX_BATTERY_COUNT];
1489 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1491 void init_batteries(void)
1495 if (batteries_initialized) {
1498 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1499 batteries[idx][0] = '\0';
1501 batteries_initialized = 1;
1504 int get_battery_idx(const char *bat)
1508 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1509 if (!strlen(batteries[idx]) || !strcmp(batteries[idx], bat)) {
1514 /* if not found, enter a new entry */
1515 if (!strlen(batteries[idx])) {
1516 snprintf(batteries[idx], 31, "%s", bat);
1522 void get_battery_stuff(char *buf, unsigned int n, const char *bat, int item)
1524 static int idx, rep = 0, rep2 = 0;
1525 char acpi_path[128];
1527 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1528 char sysfs_path[128];
1529 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1533 idx = get_battery_idx(bat);
1535 /* don't update battery too often */
1536 if (current_update_time - last_battery_time[idx] < 29.5) {
1537 goto set_return_value;
1540 last_battery_time[idx] = current_update_time;
1542 memset(last_battery_str[idx], 0, sizeof(last_battery_str[idx]));
1543 memset(last_battery_time_str[idx], 0, sizeof(last_battery_time_str[idx]));
1545 /* first try SYSFS if that fails try ACPI */
1547 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1548 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1550 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1551 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1553 if (sysfs_bat_fp[idx] != NULL) {
1555 int present_rate = -1;
1556 int remaining_capacity = -1;
1557 char charging_state[64];
1560 strcpy(charging_state, "Unknown");
1562 while (!feof(sysfs_bat_fp[idx])) {
1564 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1567 /* let's just hope units are ok */
1568 if (strncmp (buf, "POWER_SUPPLY_PRESENT=1", 22) == 0)
1569 strcpy(present, "Yes");
1570 else if (strncmp (buf, "POWER_SUPPLY_PRESENT=0", 22) == 0)
1571 strcpy(present, "No");
1572 else if (strncmp (buf, "POWER_SUPPLY_STATUS=", 20) == 0)
1573 sscanf(buf, "POWER_SUPPLY_STATUS=%63s", charging_state);
1574 /* present_rate is not the same as the
1575 current flowing now but it is the same value
1576 which was used in the past. so we continue
1578 else if (strncmp(buf, "POWER_SUPPLY_CURRENT_NOW=", 25) == 0)
1579 sscanf(buf, "POWER_SUPPLY_CURRENT_NOW=%d", &present_rate);
1580 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0)
1581 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1582 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=", 25) == 0)
1583 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_last_full[idx]);
1584 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0)
1585 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1586 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=", 25) == 0)
1587 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_last_full[idx]);
1590 fclose(sysfs_bat_fp[idx]);
1591 sysfs_bat_fp[idx] = NULL;
1593 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1594 if (remaining_capacity > acpi_last_full[idx])
1595 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1598 if (strcmp(present, "No") == 0) {
1599 strncpy(last_battery_str[idx], "not present", 64);
1602 else if (strcmp(charging_state, "Charging") == 0) {
1603 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1604 /* e.g. charging 75% */
1605 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Charging %i%%",
1606 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1608 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1609 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1610 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1611 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Charging %d%%",
1612 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1614 strncpy(last_battery_str[idx], "Charging", sizeof(last_battery_str[idx])-1);
1618 else if (strncmp(charging_state, "Discharging", 64) == 0) {
1619 if (present_rate > 0) {
1620 /* e.g. discharging 35% */
1621 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Discharging %i%%",
1622 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1624 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1625 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1626 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1627 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Full");
1629 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1631 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1635 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1636 else if (strncmp(charging_state, "Charged", 64) == 0) {
1637 /* Below happens with the second battery on my X40,
1638 * when the second one is empty and the first one
1640 if (remaining_capacity == 0)
1641 strcpy(last_battery_str[idx], "Empty");
1643 strcpy(last_battery_str[idx], "Charged");
1645 /* unknown, probably full / AC */
1647 if (acpi_last_full[idx] != 0
1648 && remaining_capacity != acpi_last_full[idx])
1649 snprintf(last_battery_str[idx], 64, "Unknown %d%%",
1650 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1652 strncpy(last_battery_str[idx], "AC", 64);
1654 } else if (acpi_bat_fp[idx] != NULL) {
1656 int present_rate = -1;
1657 int remaining_capacity = -1;
1658 char charging_state[64];
1661 /* read last full capacity if it's zero */
1662 if (acpi_last_full[idx] == 0) {
1667 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1668 fp = open_file(path, &rep);
1673 if (fgets(b, 256, fp) == NULL) {
1676 if (sscanf(b, "last full capacity: %d",
1677 &acpi_last_full[idx]) != 0) {
1686 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1688 strcpy(charging_state, "unknown");
1690 while (!feof(acpi_bat_fp[idx])) {
1693 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1697 /* let's just hope units are ok */
1698 if (strncmp(buf, "present:", 8) == 0) {
1699 sscanf(buf, "present: %4s", present);
1700 } else if (strncmp(buf, "charging state:", 15) == 0) {
1701 sscanf(buf, "charging state: %63s", charging_state);
1702 } else if (strncmp(buf, "present rate:", 13) == 0) {
1703 sscanf(buf, "present rate: %d", &present_rate);
1704 } else if (strncmp(buf, "remaining capacity:", 19) == 0) {
1705 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1708 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1709 if (remaining_capacity > acpi_last_full[idx]) {
1710 /* normalize to 100% */
1711 acpi_last_full[idx] = remaining_capacity;
1715 if (strcmp(present, "no") == 0) {
1716 strncpy(last_battery_str[idx], "not present", 64);
1718 } else if (strcmp(charging_state, "charging") == 0) {
1719 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1720 /* e.g. charging 75% */
1721 snprintf(last_battery_str[idx],
1722 sizeof(last_battery_str[idx]) - 1, "charging %i%%",
1723 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1725 format_seconds(last_battery_time_str[idx],
1726 sizeof(last_battery_time_str[idx]) - 1,
1727 (long) (((acpi_last_full[idx] - remaining_capacity) *
1728 3600) / present_rate));
1729 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1730 snprintf(last_battery_str[idx],
1731 sizeof(last_battery_str[idx]) - 1, "charging %d%%",
1732 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1734 strncpy(last_battery_str[idx], "charging",
1735 sizeof(last_battery_str[idx]) - 1);
1738 } else if (strncmp(charging_state, "discharging", 64) == 0) {
1739 if (present_rate > 0) {
1740 /* e.g. discharging 35% */
1741 snprintf(last_battery_str[idx],
1742 sizeof(last_battery_str[idx]) - 1, "discharging %i%%",
1743 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1745 format_seconds(last_battery_time_str[idx],
1746 sizeof(last_battery_time_str[idx]) - 1,
1747 (long) ((remaining_capacity * 3600) / present_rate));
1748 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1749 snprintf(last_battery_str[idx],
1750 sizeof(last_battery_str[idx]) - 1, "full");
1752 snprintf(last_battery_str[idx],
1753 sizeof(last_battery_str[idx]) - 1, "discharging %d%%",
1754 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1757 } else if (strncmp(charging_state, "charged", 64) == 0) {
1758 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1759 /* Below happens with the second battery on my X40,
1760 * when the second one is empty and the first one being charged. */
1761 if (remaining_capacity == 0) {
1762 strcpy(last_battery_str[idx], "empty");
1764 strcpy(last_battery_str[idx], "charged");
1766 /* unknown, probably full / AC */
1768 if (acpi_last_full[idx] != 0
1769 && remaining_capacity != acpi_last_full[idx]) {
1770 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1771 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1773 strncpy(last_battery_str[idx], "AC", 64);
1778 if (apm_bat_fp[idx] == NULL) {
1779 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1782 if (apm_bat_fp[idx] != NULL) {
1783 int ac, status, flag, life;
1785 fscanf(apm_bat_fp[idx], "%*s %*s %*x %x %x %x %d%%",
1786 &ac, &status, &flag, &life);
1789 /* could check now that there is ac */
1790 snprintf(last_battery_str[idx], 64, "AC");
1792 /* could check that status == 3 here? */
1793 } else if (ac && life != 100) {
1794 snprintf(last_battery_str[idx], 64, "charging %d%%", life);
1796 snprintf(last_battery_str[idx], 64, "%d%%", life);
1799 /* it seemed to buffer it so file must be closed (or could use
1800 * syscalls directly but I don't feel like coding it now) */
1801 fclose(apm_bat_fp[idx]);
1802 apm_bat_fp[idx] = NULL;
1808 case BATTERY_STATUS:
1809 snprintf(buf, n, "%s", last_battery_str[idx]);
1812 snprintf(buf, n, "%s", last_battery_time_str[idx]);
1819 int get_battery_perct(const char *bat)
1823 char acpi_path[128];
1825 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1826 char sysfs_path[128];
1827 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1831 idx = get_battery_idx(bat);
1833 /* don't update battery too often */
1834 if (current_update_time - last_battery_perct_time[idx] < 30) {
1835 return last_battery_perct[idx];
1837 last_battery_perct_time[idx] = current_update_time;
1839 /* Only check for SYSFS or ACPI */
1841 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1842 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1844 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL)
1845 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1847 int remaining_capacity = -1;
1849 if (sysfs_bat_fp[idx] != NULL) {
1851 while (!feof(sysfs_bat_fp[idx])) {
1853 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1856 if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0) {
1857 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1858 } else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=",25) == 0) {
1859 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_design_capacity[idx]);
1860 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0) {
1861 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1862 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=",25) == 0) {
1863 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_design_capacity[idx]);
1867 fclose(sysfs_bat_fp[idx]);
1868 sysfs_bat_fp[idx] = NULL;
1870 } else if (acpi_bat_fp[idx] != NULL) {
1872 /* read last full capacity if it's zero */
1873 if (acpi_design_capacity[idx] == 0) {
1878 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1879 fp = open_file(path, &rep);
1884 if (fgets(b, 256, fp) == NULL) {
1887 if (sscanf(b, "last full capacity: %d",
1888 &acpi_design_capacity[idx]) != 0) {
1896 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1898 while (!feof(acpi_bat_fp[idx])) {
1901 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1905 if (buf[0] == 'r') {
1906 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1910 if (remaining_capacity < 0) {
1913 /* compute the battery percentage */
1914 last_battery_perct[idx] =
1915 (int) (((float) remaining_capacity / acpi_design_capacity[idx]) * 100);
1916 return last_battery_perct[idx];
1919 int get_battery_perct_bar(const char *bar)
1923 get_battery_perct(bar);
1924 idx = get_battery_idx(bar);
1925 return (int) (last_battery_perct[idx] * 2.56 - 1);
1928 /* On Apple powerbook and ibook:
1929 $ cat /proc/pmu/battery_0
1936 $ cat /proc/pmu/info
1937 PMU driver version : 2
1938 PMU firmware version : 0c
1943 /* defines as in <linux/pmu.h> */
1944 #define PMU_BATT_PRESENT 0x00000001
1945 #define PMU_BATT_CHARGING 0x00000002
1947 static FILE *pmu_battery_fp;
1948 static FILE *pmu_info_fp;
1949 static char pb_battery_info[3][32];
1950 static double pb_battery_info_update;
1952 #define PMU_PATH "/proc/pmu"
1953 void get_powerbook_batt_info(char *buf, size_t n, int i)
1956 const char *batt_path = PMU_PATH "/battery_0";
1957 const char *info_path = PMU_PATH "/info";
1958 int flags, charge, max_charge, ac = -1;
1961 /* don't update battery too often */
1962 if (current_update_time - pb_battery_info_update < 29.5) {
1963 snprintf(buf, n, "%s", pb_battery_info[i]);
1966 pb_battery_info_update = current_update_time;
1968 if (pmu_battery_fp == NULL) {
1969 pmu_battery_fp = open_file(batt_path, &rep);
1972 if (pmu_battery_fp != NULL) {
1973 rewind(pmu_battery_fp);
1974 while (!feof(pmu_battery_fp)) {
1977 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL) {
1981 if (buf[0] == 'f') {
1982 sscanf(buf, "flags : %8x", &flags);
1983 } else if (buf[0] == 'c' && buf[1] == 'h') {
1984 sscanf(buf, "charge : %d", &charge);
1985 } else if (buf[0] == 'm') {
1986 sscanf(buf, "max_charge : %d", &max_charge);
1987 } else if (buf[0] == 't') {
1988 sscanf(buf, "time rem. : %ld", &time);
1992 if (pmu_info_fp == NULL) {
1993 pmu_info_fp = open_file(info_path, &rep);
1996 if (pmu_info_fp != NULL) {
1997 rewind(pmu_info_fp);
1998 while (!feof(pmu_info_fp)) {
2001 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL) {
2004 if (buf[0] == 'A') {
2005 sscanf(buf, "AC Power : %d", &ac);
2009 /* update status string */
2010 if ((ac && !(flags & PMU_BATT_PRESENT))) {
2011 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
2012 } else if (ac && (flags & PMU_BATT_PRESENT)
2013 && !(flags & PMU_BATT_CHARGING)) {
2014 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
2015 } else if ((flags & PMU_BATT_PRESENT) && (flags & PMU_BATT_CHARGING)) {
2016 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
2018 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
2021 /* update percentage string */
2023 pb_battery_info[PB_BATT_PERCENT][0] = 0;
2025 snprintf(pb_battery_info[PB_BATT_PERCENT],
2026 sizeof(pb_battery_info[PB_BATT_PERCENT]), "%d%%",
2027 (charge * 100) / max_charge);
2030 /* update time string */
2031 if (time == 0) { /* fully charged or battery not present */
2032 pb_battery_info[PB_BATT_TIME][0] = 0;
2033 } else if (time < 60 * 60) { /* don't show secs */
2034 format_seconds_short(pb_battery_info[PB_BATT_TIME],
2035 sizeof(pb_battery_info[PB_BATT_TIME]), time);
2037 format_seconds(pb_battery_info[PB_BATT_TIME],
2038 sizeof(pb_battery_info[PB_BATT_TIME]), time);
2041 snprintf(buf, n, "%s", pb_battery_info[i]);
2046 show_nice_processes = 1;
2047 process_find_top(info.cpu, info.memu);
2048 info.first_process = get_first_process();
2051 /* The following ifdefs were adapted from gkrellm */
2052 #include <linux/major.h>
2054 #if !defined(MD_MAJOR)
2058 #if !defined(LVM_BLK_MAJOR)
2059 #define LVM_BLK_MAJOR 58
2062 #if !defined(NBD_MAJOR)
2063 #define NBD_MAJOR 43
2066 void update_diskio()
2068 static unsigned int last = UINT_MAX;
2069 static unsigned int last_read = UINT_MAX;
2070 static unsigned int last_write = UINT_MAX;
2074 char buf[512], devbuf[64];
2075 int major, minor, i;
2076 unsigned int current = 0;
2077 unsigned int current_read = 0;
2078 unsigned int current_write = 0;
2079 unsigned int reads, writes = 0;
2082 if (!(fp = open_file("/proc/diskstats", &rep))) {
2087 /* read reads and writes from all disks (minor = 0), including cd-roms
2088 * and floppies, and sum them up */
2090 fgets(buf, 512, fp);
2091 col_count = sscanf(buf, "%u %u %s %*u %*u %u %*u %*u %*u %u", &major,
2092 &minor, devbuf, &reads, &writes);
2093 /* ignore subdevices (they have only 3 matching entries in their line)
2094 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
2096 * XXX: ignore devices which are part of a SW RAID (MD_MAJOR) */
2097 if (col_count == 5 && major != LVM_BLK_MAJOR && major != NBD_MAJOR
2098 && major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
2099 current += reads + writes;
2100 current_read += reads;
2101 current_write += writes;
2103 col_count = sscanf(buf, "%u %u %s %*u %u %*u %u",
2104 &major, &minor, devbuf, &reads, &writes);
2105 if (col_count != 5) {
2109 for (i = 0; i < MAX_DISKIO_STATS; i++) {
2110 if (diskio_stats[i].dev &&
2111 strcmp(devbuf, diskio_stats[i].dev) == 0) {
2112 diskio_stats[i].current =
2113 (reads + writes - diskio_stats[i].last) / 2;
2114 diskio_stats[i].current_read =
2115 (reads - diskio_stats[i].last_read) / 2;
2116 diskio_stats[i].current_write =
2117 (writes - diskio_stats[i].last_write) / 2;
2118 if (reads + writes < diskio_stats[i].last) {
2119 diskio_stats[i].current = 0;
2121 if (reads < diskio_stats[i].last_read) {
2122 diskio_stats[i].current_read = 0;
2123 diskio_stats[i].current = diskio_stats[i].current_write;
2125 if (writes < diskio_stats[i].last_write) {
2126 diskio_stats[i].current_write = 0;
2127 diskio_stats[i].current = diskio_stats[i].current_read;
2129 diskio_stats[i].last = reads + writes;
2130 diskio_stats[i].last_read = reads;
2131 diskio_stats[i].last_write = writes;
2136 /* since the values in /proc/diststats are absolute, we have to substract
2137 * our last reading. The numbers stand for "sectors read", and we therefore
2138 * have to divide by two to get KB */
2139 int tot = ((double) (current - last) / 2);
2140 int tot_read = ((double) (current_read - last_read) / 2);
2141 int tot_write = ((double) (current_write - last_write) / 2);
2143 if (last_read > current_read) {
2146 if (last_write > current_write) {
2150 if (last > current) {
2151 /* we hit this either if it's the very first time we run this, or
2152 * when /proc/diskstats overflows; while 0 is not correct, it's at
2153 * least not way off */
2157 last_read = current_read;
2158 last_write = current_write;
2161 diskio_read_value = tot_read;
2162 diskio_write_value = tot_write;
2167 /* Here come the IBM ACPI-specific things. For reference, see
2168 * http://ibm-acpi.sourceforge.net/README
2169 * If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
2185 * The content of these files is described in detail in the aforementioned
2186 * README - some of them also in the following functions accessing them.
2187 * Peter Tarjan (ptarjan@citromail.hu) */
2189 #define IBM_ACPI_DIR "/proc/acpi/ibm"
2191 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
2192 * /proc/acpi/ibm/fan looks like this (3 lines):
2195 commands: enable, disable
2196 * Peter Tarjan (ptarjan@citromail.hu) */
2198 void get_ibm_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
2200 if (!p_client_buffer || client_buffer_size <= 0) {
2205 unsigned int speed = 0;
2208 snprintf(fan, 127, "%s/fan", IBM_ACPI_DIR);
2210 fp = fopen(fan, "r");
2215 if (fgets(line, 255, fp) == NULL) {
2218 if (sscanf(line, "speed: %d", &speed)) {
2223 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2224 "ibm* from your Conky config file.", fan, strerror(errno));
2228 snprintf(p_client_buffer, client_buffer_size, "%d", speed);
2231 /* get the measured temperatures from the temperature sensors
2232 * on IBM/Lenovo laptops running the ibm acpi.
2233 * There are 8 values in /proc/acpi/ibm/thermal, and according to
2234 * http://ibm-acpi.sourceforge.net/README
2235 * these mean the following (at least on an IBM R51...)
2236 * 0: CPU (also on the T series laptops)
2237 * 1: Mini PCI Module (?)
2239 * 3: GPU (also on the T series laptops)
2244 * I'm not too sure about those with the question mark, but the values I'm
2245 * reading from *my* thermal file (on a T42p) look realistic for the
2246 * hdd and the battery.
2247 * #5 and #7 are always -128.
2248 * /proc/acpi/ibm/thermal looks like this (1 line):
2249 temperatures: 41 43 31 46 33 -128 29 -128
2250 * Peter Tarjan (ptarjan@citromail.hu) */
2252 static double last_ibm_acpi_temp_time;
2253 void get_ibm_acpi_temps()
2256 /* don't update too often */
2257 if (current_update_time - last_ibm_acpi_temp_time < 10.00) {
2260 last_ibm_acpi_temp_time = current_update_time;
2262 /* if (!p_client_buffer || client_buffer_size <= 0) {
2270 snprintf(thermal, 127, "%s/thermal", IBM_ACPI_DIR);
2271 fp = fopen(thermal, "r");
2277 if (fgets(line, 255, fp) == NULL) {
2280 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
2281 &ibm_acpi.temps[0], &ibm_acpi.temps[1], &ibm_acpi.temps[2],
2282 &ibm_acpi.temps[3], &ibm_acpi.temps[4], &ibm_acpi.temps[5],
2283 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) {
2288 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2289 "ibm* from your Conky config file.", thermal, strerror(errno));
2295 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
2296 * "Volume" here is none of the mixer volumes, but a "master of masters"
2297 * volume adjusted by the IBM volume keys.
2298 * /proc/acpi/ibm/fan looks like this (4 lines):
2301 commands: up, down, mute
2302 commands: level <level> (<level> is 0-15)
2303 * Peter Tarjan (ptarjan@citromail.hu) */
2305 void get_ibm_acpi_volume(char *p_client_buffer, size_t client_buffer_size)
2307 if (!p_client_buffer || client_buffer_size <= 0) {
2315 snprintf(volume, 127, "%s/volume", IBM_ACPI_DIR);
2316 unsigned int vol = -1;
2319 fp = fopen(volume, "r");
2323 unsigned int read_vol = -1;
2325 if (fgets(line, 255, fp) == NULL) {
2328 if (sscanf(line, "level: %d", &read_vol)) {
2332 if (sscanf(line, "mute: %s", mute)) {
2337 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2338 "ibm* from your Conky config file.", volume, strerror(errno));
2343 if (strcmp(mute, "on") == 0) {
2344 snprintf(p_client_buffer, client_buffer_size, "%s", "mute");
2347 snprintf(p_client_buffer, client_buffer_size, "%d", vol);
2352 /* static FILE *fp = NULL; */
2354 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
2355 * /proc/acpi/ibm/brightness looks like this (3 lines):
2358 commands: level <level> (<level> is 0-7)
2359 * Peter Tarjan (ptarjan@citromail.hu) */
2361 void get_ibm_acpi_brightness(char *p_client_buffer, size_t client_buffer_size)
2363 if (!p_client_buffer || client_buffer_size <= 0) {
2368 unsigned int brightness = 0;
2371 snprintf(filename, 127, "%s/brightness", IBM_ACPI_DIR);
2373 fp = fopen(filename, "r");
2378 if (fgets(line, 255, fp) == NULL) {
2381 if (sscanf(line, "level: %d", &brightness)) {
2386 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2387 "ibm* from your Conky config file.", filename, strerror(errno));
2392 snprintf(p_client_buffer, client_buffer_size, "%d", brightness);
2395 void update_entropy(void)
2398 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
2399 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
2402 info.entropy.entropy_avail = 0;
2403 info.entropy.poolsize = 0;
2405 if ((fp1 = open_file(entropy_avail, &rep)) == NULL) {
2409 if ((fp2 = open_file(entropy_poolsize, &rep)) == NULL) {
2414 fscanf(fp1, "%u", &info.entropy.entropy_avail);
2415 fscanf(fp2, "%u", &info.entropy.poolsize);
2420 info.mask |= (1 << INFO_ENTROPY);
2423 char *get_disk_protect_queue(char *disk)
2429 snprintf(path, 127, "/sys/block/%s/queue/protect", disk);
2430 if ((fp = fopen(path, "r")) == NULL)
2432 if (fscanf(fp, "%d\n", &state) != 1) {
2437 return state ? "frozen" : "free ";