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;
76 void prepare_update(void)
80 void update_uptime(void)
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(void)
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 %llu", &info.memmax);
151 } else if (strncmp(buf, "MemFree:", 8) == 0) {
152 sscanf(buf, "%*s %llu", &info.mem);
153 } else if (strncmp(buf, "SwapTotal:", 10) == 0) {
154 sscanf(buf, "%*s %llu", &info.swapmax);
155 } else if (strncmp(buf, "SwapFree:", 9) == 0) {
156 sscanf(buf, "%*s %llu", &info.swap);
157 } else if (strncmp(buf, "Buffers:", 8) == 0) {
158 sscanf(buf, "%*s %llu", &info.buffers);
159 } else if (strncmp(buf, "Cached:", 7) == 0) {
160 sscanf(buf, "%*s %llu", &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(void)
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)
195 return strdup("n/a");
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(void)
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(void)
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, "%lld %*d %*d %*d %*d %*d %*d %*d %lld",
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(void)
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/%hu", &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);
568 void get_cpu_count(void)
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(void)
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(void)
707 void update_cpu_usage(void)
712 void update_load_average(void)
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;
742 void update_i8k(void)
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(void)
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] = { NULL, NULL, NULL, NULL };
1472 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1473 static FILE *apm_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
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);
1552 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1553 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1556 if (sysfs_bat_fp[idx] != NULL) {
1558 int present_rate = -1;
1559 int remaining_capacity = -1;
1560 char charging_state[64];
1563 strcpy(charging_state, "Unknown");
1565 while (!feof(sysfs_bat_fp[idx])) {
1567 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1570 /* let's just hope units are ok */
1571 if (strncmp (buf, "POWER_SUPPLY_PRESENT=1", 22) == 0)
1572 strcpy(present, "Yes");
1573 else if (strncmp (buf, "POWER_SUPPLY_PRESENT=0", 22) == 0)
1574 strcpy(present, "No");
1575 else if (strncmp (buf, "POWER_SUPPLY_STATUS=", 20) == 0)
1576 sscanf(buf, "POWER_SUPPLY_STATUS=%63s", charging_state);
1577 /* present_rate is not the same as the
1578 current flowing now but it is the same value
1579 which was used in the past. so we continue
1581 else if (strncmp(buf, "POWER_SUPPLY_CURRENT_NOW=", 25) == 0)
1582 sscanf(buf, "POWER_SUPPLY_CURRENT_NOW=%d", &present_rate);
1583 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0)
1584 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1585 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=", 25) == 0)
1586 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_last_full[idx]);
1587 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0)
1588 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1589 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=", 25) == 0)
1590 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_last_full[idx]);
1593 fclose(sysfs_bat_fp[idx]);
1594 sysfs_bat_fp[idx] = NULL;
1596 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1597 if (remaining_capacity > acpi_last_full[idx])
1598 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1601 if (strcmp(present, "No") == 0) {
1602 strncpy(last_battery_str[idx], "not present", 64);
1605 else if (strcmp(charging_state, "Charging") == 0) {
1606 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1607 /* e.g. charging 75% */
1608 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Charging %i%%",
1609 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1611 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1612 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1613 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1614 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Charging %d%%",
1615 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1617 strncpy(last_battery_str[idx], "Charging", sizeof(last_battery_str[idx])-1);
1621 else if (strncmp(charging_state, "Discharging", 64) == 0) {
1622 if (present_rate > 0) {
1623 /* e.g. discharging 35% */
1624 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Discharging %i%%",
1625 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1627 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1628 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1629 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1630 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Full");
1632 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1634 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1638 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1639 else if (strncmp(charging_state, "Charged", 64) == 0) {
1640 /* Below happens with the second battery on my X40,
1641 * when the second one is empty and the first one
1643 if (remaining_capacity == 0)
1644 strcpy(last_battery_str[idx], "Empty");
1646 strcpy(last_battery_str[idx], "Charged");
1648 /* unknown, probably full / AC */
1650 if (acpi_last_full[idx] != 0
1651 && remaining_capacity != acpi_last_full[idx])
1652 snprintf(last_battery_str[idx], 64, "Unknown %d%%",
1653 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1655 strncpy(last_battery_str[idx], "AC", 64);
1657 } else if (acpi_bat_fp[idx] != NULL) {
1659 int present_rate = -1;
1660 int remaining_capacity = -1;
1661 char charging_state[64];
1664 /* read last full capacity if it's zero */
1665 if (acpi_last_full[idx] == 0) {
1670 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1671 fp = open_file(path, &rep);
1676 if (fgets(b, 256, fp) == NULL) {
1679 if (sscanf(b, "last full capacity: %d",
1680 &acpi_last_full[idx]) != 0) {
1689 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1691 strcpy(charging_state, "unknown");
1693 while (!feof(acpi_bat_fp[idx])) {
1696 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1700 /* let's just hope units are ok */
1701 if (strncmp(buf, "present:", 8) == 0) {
1702 sscanf(buf, "present: %4s", present);
1703 } else if (strncmp(buf, "charging state:", 15) == 0) {
1704 sscanf(buf, "charging state: %63s", charging_state);
1705 } else if (strncmp(buf, "present rate:", 13) == 0) {
1706 sscanf(buf, "present rate: %d", &present_rate);
1707 } else if (strncmp(buf, "remaining capacity:", 19) == 0) {
1708 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1711 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1712 if (remaining_capacity > acpi_last_full[idx]) {
1713 /* normalize to 100% */
1714 acpi_last_full[idx] = remaining_capacity;
1718 if (strcmp(present, "no") == 0) {
1719 strncpy(last_battery_str[idx], "not present", 64);
1721 } else if (strcmp(charging_state, "charging") == 0) {
1722 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1723 /* e.g. charging 75% */
1724 snprintf(last_battery_str[idx],
1725 sizeof(last_battery_str[idx]) - 1, "charging %i%%",
1726 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1728 format_seconds(last_battery_time_str[idx],
1729 sizeof(last_battery_time_str[idx]) - 1,
1730 (long) (((acpi_last_full[idx] - remaining_capacity) *
1731 3600) / present_rate));
1732 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1733 snprintf(last_battery_str[idx],
1734 sizeof(last_battery_str[idx]) - 1, "charging %d%%",
1735 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1737 strncpy(last_battery_str[idx], "charging",
1738 sizeof(last_battery_str[idx]) - 1);
1741 } else if (strncmp(charging_state, "discharging", 64) == 0) {
1742 if (present_rate > 0) {
1743 /* e.g. discharging 35% */
1744 snprintf(last_battery_str[idx],
1745 sizeof(last_battery_str[idx]) - 1, "discharging %i%%",
1746 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1748 format_seconds(last_battery_time_str[idx],
1749 sizeof(last_battery_time_str[idx]) - 1,
1750 (long) ((remaining_capacity * 3600) / present_rate));
1751 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1752 snprintf(last_battery_str[idx],
1753 sizeof(last_battery_str[idx]) - 1, "full");
1755 snprintf(last_battery_str[idx],
1756 sizeof(last_battery_str[idx]) - 1, "discharging %d%%",
1757 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1760 } else if (strncmp(charging_state, "charged", 64) == 0) {
1761 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1762 /* Below happens with the second battery on my X40,
1763 * when the second one is empty and the first one being charged. */
1764 if (remaining_capacity == 0) {
1765 strcpy(last_battery_str[idx], "empty");
1767 strcpy(last_battery_str[idx], "charged");
1769 /* unknown, probably full / AC */
1771 if (acpi_last_full[idx] != 0
1772 && remaining_capacity != acpi_last_full[idx]) {
1773 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1774 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1776 strncpy(last_battery_str[idx], "AC", 64);
1781 if (apm_bat_fp[idx] == NULL) {
1782 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1785 if (apm_bat_fp[idx] != NULL) {
1786 unsigned int ac, status, flag;
1789 fscanf(apm_bat_fp[idx], "%*s %*s %*x %x %x %x %d%%",
1790 &ac, &status, &flag, &life);
1793 /* could check now that there is ac */
1794 snprintf(last_battery_str[idx], 64, "AC");
1796 /* could check that status == 3 here? */
1797 } else if (ac && life != 100) {
1798 snprintf(last_battery_str[idx], 64, "charging %d%%", life);
1800 snprintf(last_battery_str[idx], 64, "%d%%", life);
1803 /* it seemed to buffer it so file must be closed (or could use
1804 * syscalls directly but I don't feel like coding it now) */
1805 fclose(apm_bat_fp[idx]);
1806 apm_bat_fp[idx] = NULL;
1812 case BATTERY_STATUS:
1813 snprintf(buf, n, "%s", last_battery_str[idx]);
1816 snprintf(buf, n, "%s", last_battery_time_str[idx]);
1823 int get_battery_perct(const char *bat)
1827 char acpi_path[128];
1829 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1830 char sysfs_path[128];
1831 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1835 idx = get_battery_idx(bat);
1837 /* don't update battery too often */
1838 if (current_update_time - last_battery_perct_time[idx] < 30) {
1839 return last_battery_perct[idx];
1841 last_battery_perct_time[idx] = current_update_time;
1843 /* Only check for SYSFS or ACPI */
1845 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1846 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1850 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1851 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1854 int remaining_capacity = -1;
1856 if (sysfs_bat_fp[idx] != NULL) {
1858 while (!feof(sysfs_bat_fp[idx])) {
1860 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1863 if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0) {
1864 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1865 } else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=",25) == 0) {
1866 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_design_capacity[idx]);
1867 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0) {
1868 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1869 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=",25) == 0) {
1870 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_design_capacity[idx]);
1874 fclose(sysfs_bat_fp[idx]);
1875 sysfs_bat_fp[idx] = NULL;
1877 } else if (acpi_bat_fp[idx] != NULL) {
1879 /* read last full capacity if it's zero */
1880 if (acpi_design_capacity[idx] == 0) {
1885 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1886 fp = open_file(path, &rep);
1891 if (fgets(b, 256, fp) == NULL) {
1894 if (sscanf(b, "last full capacity: %d",
1895 &acpi_design_capacity[idx]) != 0) {
1903 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1905 while (!feof(acpi_bat_fp[idx])) {
1908 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1912 if (buf[0] == 'r') {
1913 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1917 if (remaining_capacity < 0) {
1920 /* compute the battery percentage */
1921 last_battery_perct[idx] =
1922 (int) (((float) remaining_capacity / acpi_design_capacity[idx]) * 100);
1923 return last_battery_perct[idx];
1926 int get_battery_perct_bar(const char *bar)
1930 get_battery_perct(bar);
1931 idx = get_battery_idx(bar);
1932 return (int) (last_battery_perct[idx] * 2.56 - 1);
1935 /* On Apple powerbook and ibook:
1936 $ cat /proc/pmu/battery_0
1943 $ cat /proc/pmu/info
1944 PMU driver version : 2
1945 PMU firmware version : 0c
1950 /* defines as in <linux/pmu.h> */
1951 #define PMU_BATT_PRESENT 0x00000001
1952 #define PMU_BATT_CHARGING 0x00000002
1954 static FILE *pmu_battery_fp;
1955 static FILE *pmu_info_fp;
1956 static char pb_battery_info[3][32];
1957 static double pb_battery_info_update;
1959 #define PMU_PATH "/proc/pmu"
1960 void get_powerbook_batt_info(char *buf, size_t n, int i)
1963 const char *batt_path = PMU_PATH "/battery_0";
1964 const char *info_path = PMU_PATH "/info";
1966 int charge, max_charge, ac = -1;
1969 /* don't update battery too often */
1970 if (current_update_time - pb_battery_info_update < 29.5) {
1971 snprintf(buf, n, "%s", pb_battery_info[i]);
1974 pb_battery_info_update = current_update_time;
1976 if (pmu_battery_fp == NULL) {
1977 pmu_battery_fp = open_file(batt_path, &rep);
1980 if (pmu_battery_fp != NULL) {
1981 rewind(pmu_battery_fp);
1982 while (!feof(pmu_battery_fp)) {
1985 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL) {
1989 if (buf[0] == 'f') {
1990 sscanf(buf, "flags : %8x", &flags);
1991 } else if (buf[0] == 'c' && buf[1] == 'h') {
1992 sscanf(buf, "charge : %d", &charge);
1993 } else if (buf[0] == 'm') {
1994 sscanf(buf, "max_charge : %d", &max_charge);
1995 } else if (buf[0] == 't') {
1996 sscanf(buf, "time rem. : %ld", &time);
2000 if (pmu_info_fp == NULL) {
2001 pmu_info_fp = open_file(info_path, &rep);
2004 if (pmu_info_fp != NULL) {
2005 rewind(pmu_info_fp);
2006 while (!feof(pmu_info_fp)) {
2009 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL) {
2012 if (buf[0] == 'A') {
2013 sscanf(buf, "AC Power : %d", &ac);
2017 /* update status string */
2018 if ((ac && !(flags & PMU_BATT_PRESENT))) {
2019 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
2020 } else if (ac && (flags & PMU_BATT_PRESENT)
2021 && !(flags & PMU_BATT_CHARGING)) {
2022 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
2023 } else if ((flags & PMU_BATT_PRESENT) && (flags & PMU_BATT_CHARGING)) {
2024 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
2026 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
2029 /* update percentage string */
2031 pb_battery_info[PB_BATT_PERCENT][0] = 0;
2033 snprintf(pb_battery_info[PB_BATT_PERCENT],
2034 sizeof(pb_battery_info[PB_BATT_PERCENT]), "%d%%",
2035 (charge * 100) / max_charge);
2038 /* update time string */
2039 if (time == 0) { /* fully charged or battery not present */
2040 pb_battery_info[PB_BATT_TIME][0] = 0;
2041 } else if (time < 60 * 60) { /* don't show secs */
2042 format_seconds_short(pb_battery_info[PB_BATT_TIME],
2043 sizeof(pb_battery_info[PB_BATT_TIME]), time);
2045 format_seconds(pb_battery_info[PB_BATT_TIME],
2046 sizeof(pb_battery_info[PB_BATT_TIME]), time);
2049 snprintf(buf, n, "%s", pb_battery_info[i]);
2052 void update_top(void)
2054 show_nice_processes = 1;
2055 process_find_top(info.cpu, info.memu);
2056 info.first_process = get_first_process();
2059 /* The following ifdefs were adapted from gkrellm */
2060 #include <linux/major.h>
2062 #if !defined(MD_MAJOR)
2066 #if !defined(LVM_BLK_MAJOR)
2067 #define LVM_BLK_MAJOR 58
2070 #if !defined(NBD_MAJOR)
2071 #define NBD_MAJOR 43
2074 void update_diskio(void)
2076 static unsigned int last = UINT_MAX;
2077 static unsigned int last_read = UINT_MAX;
2078 static unsigned int last_write = UINT_MAX;
2082 char buf[512], devbuf[64];
2084 unsigned int major, minor;
2085 unsigned int current = 0;
2086 unsigned int current_read = 0;
2087 unsigned int current_write = 0;
2088 unsigned int reads, writes = 0;
2091 if (!(fp = open_file("/proc/diskstats", &rep))) {
2096 /* read reads and writes from all disks (minor = 0), including cd-roms
2097 * and floppies, and sum them up */
2099 fgets(buf, 512, fp);
2100 col_count = sscanf(buf, "%u %u %s %*u %*u %u %*u %*u %*u %u", &major,
2101 &minor, devbuf, &reads, &writes);
2102 /* ignore subdevices (they have only 3 matching entries in their line)
2103 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
2105 * XXX: ignore devices which are part of a SW RAID (MD_MAJOR) */
2106 if (col_count == 5 && major != LVM_BLK_MAJOR && major != NBD_MAJOR
2107 && major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
2108 current += reads + writes;
2109 current_read += reads;
2110 current_write += writes;
2112 col_count = sscanf(buf, "%u %u %s %*u %u %*u %u",
2113 &major, &minor, devbuf, &reads, &writes);
2114 if (col_count != 5) {
2118 for (i = 0; i < MAX_DISKIO_STATS; i++) {
2119 if (diskio_stats[i].dev &&
2120 strcmp(devbuf, diskio_stats[i].dev) == 0) {
2121 diskio_stats[i].current =
2122 (reads + writes - diskio_stats[i].last) / 2;
2123 diskio_stats[i].current_read =
2124 (reads - diskio_stats[i].last_read) / 2;
2125 diskio_stats[i].current_write =
2126 (writes - diskio_stats[i].last_write) / 2;
2127 if (reads + writes < diskio_stats[i].last) {
2128 diskio_stats[i].current = 0;
2130 if (reads < diskio_stats[i].last_read) {
2131 diskio_stats[i].current_read = 0;
2132 diskio_stats[i].current = diskio_stats[i].current_write;
2134 if (writes < diskio_stats[i].last_write) {
2135 diskio_stats[i].current_write = 0;
2136 diskio_stats[i].current = diskio_stats[i].current_read;
2138 diskio_stats[i].last = reads + writes;
2139 diskio_stats[i].last_read = reads;
2140 diskio_stats[i].last_write = writes;
2145 /* since the values in /proc/diststats are absolute, we have to substract
2146 * our last reading. The numbers stand for "sectors read", and we therefore
2147 * have to divide by two to get KB */
2148 int tot = ((double) (current - last) / 2);
2149 int tot_read = ((double) (current_read - last_read) / 2);
2150 int tot_write = ((double) (current_write - last_write) / 2);
2152 if (last_read > current_read) {
2155 if (last_write > current_write) {
2159 if (last > current) {
2160 /* we hit this either if it's the very first time we run this, or
2161 * when /proc/diskstats overflows; while 0 is not correct, it's at
2162 * least not way off */
2166 last_read = current_read;
2167 last_write = current_write;
2170 diskio_read_value = tot_read;
2171 diskio_write_value = tot_write;
2176 /* Here come the IBM ACPI-specific things. For reference, see
2177 * http://ibm-acpi.sourceforge.net/README
2178 * If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
2194 * The content of these files is described in detail in the aforementioned
2195 * README - some of them also in the following functions accessing them.
2196 * Peter Tarjan (ptarjan@citromail.hu) */
2198 #define IBM_ACPI_DIR "/proc/acpi/ibm"
2200 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
2201 * /proc/acpi/ibm/fan looks like this (3 lines):
2204 commands: enable, disable
2205 * Peter Tarjan (ptarjan@citromail.hu) */
2207 void get_ibm_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
2209 if (!p_client_buffer || client_buffer_size <= 0) {
2214 unsigned int speed = 0;
2217 snprintf(fan, 127, "%s/fan", IBM_ACPI_DIR);
2219 fp = fopen(fan, "r");
2224 if (fgets(line, 255, fp) == NULL) {
2227 if (sscanf(line, "speed: %u", &speed)) {
2232 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2233 "ibm* from your Conky config file.", fan, strerror(errno));
2237 snprintf(p_client_buffer, client_buffer_size, "%d", speed);
2240 /* get the measured temperatures from the temperature sensors
2241 * on IBM/Lenovo laptops running the ibm acpi.
2242 * There are 8 values in /proc/acpi/ibm/thermal, and according to
2243 * http://ibm-acpi.sourceforge.net/README
2244 * these mean the following (at least on an IBM R51...)
2245 * 0: CPU (also on the T series laptops)
2246 * 1: Mini PCI Module (?)
2248 * 3: GPU (also on the T series laptops)
2253 * I'm not too sure about those with the question mark, but the values I'm
2254 * reading from *my* thermal file (on a T42p) look realistic for the
2255 * hdd and the battery.
2256 * #5 and #7 are always -128.
2257 * /proc/acpi/ibm/thermal looks like this (1 line):
2258 temperatures: 41 43 31 46 33 -128 29 -128
2259 * Peter Tarjan (ptarjan@citromail.hu) */
2261 static double last_ibm_acpi_temp_time;
2262 void get_ibm_acpi_temps(void)
2265 /* don't update too often */
2266 if (current_update_time - last_ibm_acpi_temp_time < 10.00) {
2269 last_ibm_acpi_temp_time = current_update_time;
2271 /* if (!p_client_buffer || client_buffer_size <= 0) {
2279 snprintf(thermal, 127, "%s/thermal", IBM_ACPI_DIR);
2280 fp = fopen(thermal, "r");
2286 if (fgets(line, 255, fp) == NULL) {
2289 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
2290 &ibm_acpi.temps[0], &ibm_acpi.temps[1], &ibm_acpi.temps[2],
2291 &ibm_acpi.temps[3], &ibm_acpi.temps[4], &ibm_acpi.temps[5],
2292 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) {
2297 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2298 "ibm* from your Conky config file.", thermal, strerror(errno));
2304 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
2305 * "Volume" here is none of the mixer volumes, but a "master of masters"
2306 * volume adjusted by the IBM volume keys.
2307 * /proc/acpi/ibm/fan looks like this (4 lines):
2310 commands: up, down, mute
2311 commands: level <level> (<level> is 0-15)
2312 * Peter Tarjan (ptarjan@citromail.hu) */
2314 void get_ibm_acpi_volume(char *p_client_buffer, size_t client_buffer_size)
2316 if (!p_client_buffer || client_buffer_size <= 0) {
2324 snprintf(volume, 127, "%s/volume", IBM_ACPI_DIR);
2325 unsigned int vol = -1;
2328 fp = fopen(volume, "r");
2332 unsigned int read_vol = -1;
2334 if (fgets(line, 255, fp) == NULL) {
2337 if (sscanf(line, "level: %u", &read_vol)) {
2341 if (sscanf(line, "mute: %s", mute)) {
2346 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2347 "ibm* from your Conky config file.", volume, strerror(errno));
2352 if (strcmp(mute, "on") == 0) {
2353 snprintf(p_client_buffer, client_buffer_size, "%s", "mute");
2356 snprintf(p_client_buffer, client_buffer_size, "%d", vol);
2361 /* static FILE *fp = NULL; */
2363 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
2364 * /proc/acpi/ibm/brightness looks like this (3 lines):
2367 commands: level <level> (<level> is 0-7)
2368 * Peter Tarjan (ptarjan@citromail.hu) */
2370 void get_ibm_acpi_brightness(char *p_client_buffer, size_t client_buffer_size)
2372 if (!p_client_buffer || client_buffer_size <= 0) {
2377 unsigned int brightness = 0;
2380 snprintf(filename, 127, "%s/brightness", IBM_ACPI_DIR);
2382 fp = fopen(filename, "r");
2387 if (fgets(line, 255, fp) == NULL) {
2390 if (sscanf(line, "level: %u", &brightness)) {
2395 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2396 "ibm* from your Conky config file.", filename, strerror(errno));
2401 snprintf(p_client_buffer, client_buffer_size, "%d", brightness);
2404 void update_entropy(void)
2407 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
2408 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
2411 info.entropy.entropy_avail = 0;
2412 info.entropy.poolsize = 0;
2414 if ((fp1 = open_file(entropy_avail, &rep)) == NULL) {
2418 if ((fp2 = open_file(entropy_poolsize, &rep)) == NULL) {
2423 fscanf(fp1, "%u", &info.entropy.entropy_avail);
2424 fscanf(fp2, "%u", &info.entropy.poolsize);
2429 info.mask |= (1 << INFO_ENTROPY);
2432 char *get_disk_protect_queue(char *disk)
2438 snprintf(path, 127, "/sys/block/%s/queue/protect", disk);
2439 if ((fp = fopen(path, "r")) == NULL)
2441 if (fscanf(fp, "%d\n", &state) != 1) {
2446 return state ? "frozen" : "free ";