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++) {
393 struct net_stat *ns2;
395 if (!(((struct ifreq *) conf.ifc_buf) + k))
399 ((struct ifreq *) conf.ifc_buf)[k].ifr_ifrn.ifrn_name);
400 ns2->addr = ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.ifru_addr;
401 if(NULL != ns2->addrs) {
402 sprintf(temp_addr, "%u.%u.%u.%u, ",
403 ns2->addr.sa_data[2] & 255,
404 ns2->addr.sa_data[3] & 255,
405 ns2->addr.sa_data[4] & 255,
406 ns2->addr.sa_data[5] & 255);
407 if(NULL == strstr(ns2->addrs, temp_addr))
408 strncpy(ns2->addrs + strlen(ns2->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)
574 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 const 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) {
652 idx = isdigit(buf[3]) ? ((int) buf[3]) - 0x2F : 0;
653 sscanf(buf, stat_template, &(cpu[idx].cpu_user),
654 &(cpu[idx].cpu_nice), &(cpu[idx].cpu_system),
655 &(cpu[idx].cpu_idle), &(cpu[idx].cpu_iowait),
656 &(cpu[idx].cpu_irq), &(cpu[idx].cpu_softirq),
657 &(cpu[idx].cpu_steal));
659 cpu[idx].cpu_total = cpu[idx].cpu_user + cpu[idx].cpu_nice +
660 cpu[idx].cpu_system + cpu[idx].cpu_idle +
661 cpu[idx].cpu_iowait + cpu[idx].cpu_irq +
662 cpu[idx].cpu_softirq + cpu[idx].cpu_steal;
664 cpu[idx].cpu_active_total = cpu[idx].cpu_total -
665 (cpu[idx].cpu_idle + cpu[idx].cpu_iowait);
666 info.mask |= (1 << INFO_CPU);
668 delta = current_update_time - last_update_time;
670 if (delta <= 0.001) {
674 cpu[idx].cpu_val[0] = (cpu[idx].cpu_active_total -
675 cpu[idx].cpu_last_active_total) /
676 (float) (cpu[idx].cpu_total - cpu[idx].cpu_last_total);
678 for (i = 0; i < info.cpu_avg_samples; i++) {
679 curtmp += cpu[idx].cpu_val[i];
681 /* TESTING -- I've removed this, because I don't think it is right.
682 * You shouldn't divide by the cpu count here ...
683 * removing for testing */
685 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples /
688 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples;
690 /* TESTING -- this line replaces the prev. "suspect" if/else */
691 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples;
693 cpu[idx].cpu_last_total = cpu[idx].cpu_total;
694 cpu[idx].cpu_last_active_total = cpu[idx].cpu_active_total;
695 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
696 cpu[idx].cpu_val[i] = cpu[idx].cpu_val[i - 1];
703 void update_running_processes(void)
708 void update_cpu_usage(void)
713 void update_load_average(void)
715 #ifdef HAVE_GETLOADAVG
720 info.loadavg[0] = (float) v[0];
721 info.loadavg[1] = (float) v[1];
722 info.loadavg[2] = (float) v[2];
729 if (!(fp = open_file("/proc/loadavg", &rep))) {
730 info.loadavg[0] = info.loadavg[1] = info.loadavg[2] = 0.0;
733 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1],
737 info.mask |= (1 << INFO_LOADAVG);
740 #define PROC_I8K "/proc/i8k"
741 #define I8K_DELIM " "
742 static char *i8k_procbuf = NULL;
743 void update_i8k(void)
748 i8k_procbuf = (char *) malloc(128 * sizeof(char));
750 if ((fp = fopen(PROC_I8K, "r")) == NULL) {
751 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel "
752 "driver is loaded...");
755 memset(&i8k_procbuf[0], 0, 128);
756 if (fread(&i8k_procbuf[0], sizeof(char), 128, fp) == 0) {
757 ERR("something wrong with /proc/i8k...");
762 i8k.version = strtok(&i8k_procbuf[0], I8K_DELIM);
763 i8k.bios = strtok(NULL, I8K_DELIM);
764 i8k.serial = strtok(NULL, I8K_DELIM);
765 i8k.cpu_temp = strtok(NULL, I8K_DELIM);
766 i8k.left_fan_status = strtok(NULL, I8K_DELIM);
767 i8k.right_fan_status = strtok(NULL, I8K_DELIM);
768 i8k.left_fan_rpm = strtok(NULL, I8K_DELIM);
769 i8k.right_fan_rpm = strtok(NULL, I8K_DELIM);
770 i8k.ac_status = strtok(NULL, I8K_DELIM);
771 i8k.buttons_status = strtok(NULL, I8K_DELIM);
774 /***********************************************************/
775 /***********************************************************/
776 /***********************************************************/
778 static int no_dots(const struct dirent *d)
780 if (d->d_name[0] == '.') {
786 static int get_first_file_in_a_directory(const char *dir, char *s, int *rep)
788 struct dirent **namelist;
791 n = scandir(dir, &namelist, no_dots, alphasort);
794 ERR("scandir for %s: %s", dir, strerror(errno));
805 strncpy(s, namelist[0]->d_name, 255);
808 for (i = 0; i < n; i++) {
817 int open_sysfs_sensor(const char *dir, const char *dev, const char *type, int n,
818 int *divisor, char *devtype)
825 memset(buf, 0, sizeof(buf));
827 /* if device is NULL or *, get first */
828 if (dev == NULL || strcmp(dev, "*") == 0) {
831 if (!get_first_file_in_a_directory(dir, buf, &rep)) {
837 if (strcmp(dir, "/sys/class/hwmon/") == 0) {
839 /* buf holds result from get_first_file_in_a_directory() above,
840 * e.g. "hwmon0" -- append "/device" */
841 strcat(buf, "/device");
843 /* dev holds device number N as a string,
844 * e.g. "0", -- convert to "hwmon0/device" */
845 sprintf(buf, "hwmon%s/device", dev);
850 /* change vol to in */
851 if (strcmp(type, "vol") == 0) {
855 if (strcmp(type, "tempf") == 0) {
856 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, "temp", n);
858 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, type, n);
860 strncpy(devtype, path, 255);
863 fd = open(path, O_RDONLY);
865 CRIT_ERR("can't open '%s': %s\nplease check your device or remove this "
866 "var from Conky", path, strerror(errno));
869 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
870 || strcmp(type, "tempf") == 0) {
875 /* fan does not use *_div as a read divisor */
876 if (strcmp("fan", type) == 0) {
880 /* test if *_div file exist, open it and use it as divisor */
881 if (strcmp(type, "tempf") == 0) {
882 snprintf(path, 255, "%s%s/%s%d_div", dir, "one", "two", n);
884 snprintf(path, 255, "%s%s/%s%d_div", dir, dev, type, n);
887 divfd = open(path, O_RDONLY);
893 divn = read(divfd, divbuf, 63);
894 /* should read until n == 0 but I doubt that kernel will give these
895 * in multiple pieces. :) */
897 ERR("open_sysfs_sensor(): can't read from sysfs");
900 *divisor = atoi(divbuf);
909 double get_sysfs_info(int *fd, int divisor, char *devtype, char *type)
917 lseek(*fd, 0, SEEK_SET);
923 n = read(*fd, buf, 63);
924 /* should read until n == 0 but I doubt that kernel will give these
925 * in multiple pieces. :) */
927 ERR("get_sysfs_info(): read from %s failed\n", devtype);
936 *fd = open(devtype, O_RDONLY);
938 ERR("can't open '%s': %s", devtype, strerror(errno));
941 /* My dirty hack for computing CPU value
942 * Filedil, from forums.gentoo.org */
943 /* if (strstr(devtype, "temp1_input") != NULL) {
944 return -15.096 + 1.4893 * (val / 1000.0);
947 /* divide voltage and temperature by 1000 */
948 /* or if any other divisor is given, use that */
949 if (strcmp(type, "tempf") == 0) {
951 return ((val / divisor + 40) * 9.0 / 5) - 40;
952 } else if (divisor) {
953 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
955 return ((val + 40) * 9.0 / 5) - 40;
959 return val / divisor;
960 } else if (divisor) {
968 /* Prior to kernel version 2.6.12, the CPU fan speed was available in
969 * ADT746X_FAN_OLD, whereas later kernel versions provide this information in
971 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
972 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
974 void get_adt746x_fan(char *p_client_buffer, size_t client_buffer_size)
977 char adt746x_fan_state[64];
980 if (!p_client_buffer || client_buffer_size <= 0) {
984 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
985 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL) {
986 sprintf(adt746x_fan_state, "adt746x not found");
988 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
989 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
993 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_fan_state);
996 /* Prior to kernel version 2.6.12, the CPU temperature was found in
997 * ADT746X_CPU_OLD, whereas later kernel versions provide this information in
999 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
1000 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
1002 void get_adt746x_cpu(char *p_client_buffer, size_t client_buffer_size)
1005 char adt746x_cpu_state[64];
1008 if (!p_client_buffer || client_buffer_size <= 0) {
1012 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
1013 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL) {
1014 sprintf(adt746x_cpu_state, "adt746x not found");
1016 fscanf(fp, "%2s", adt746x_cpu_state);
1020 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state);
1023 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
1025 /***********************************************************************/
1026 /* This file is part of x86info.
1027 * (C) 2001 Dave Jones.
1029 * Licensed under the terms of the GNU GPL License version 2.
1031 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
1032 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz> */
1034 #if defined(__i386) || defined(__x86_64)
1035 __inline__ unsigned long long int rdtsc(void)
1037 unsigned long long int x;
1039 __asm__ volatile(".byte 0x0f, 0x31":"=A" (x));
1044 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1045 void get_freq_dynamic(char *p_client_buffer, size_t client_buffer_size,
1046 const char *p_format, int divisor)
1048 #if defined(__i386) || defined(__x86_64)
1050 struct timeval tvstart, tvstop;
1051 unsigned long long cycles[2]; /* gotta be 64 bit */
1052 unsigned int microseconds; /* total time taken */
1054 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1059 memset(&tz, 0, sizeof(tz));
1061 /* get this function in cached memory */
1062 gettimeofday(&tvstart, &tz);
1063 cycles[0] = rdtsc();
1064 gettimeofday(&tvstart, &tz);
1066 /* we don't trust that this is any specific length of time */
1068 cycles[1] = rdtsc();
1069 gettimeofday(&tvstop, &tz);
1070 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
1071 (tvstop.tv_usec - tvstart.tv_usec);
1073 snprintf(p_client_buffer, client_buffer_size, p_format,
1074 (float) ((cycles[1] - cycles[0]) / microseconds) / divisor);
1077 /* FIXME: hardwired: get freq for first cpu!
1078 * this whole function needs to be rethought and redone for
1079 * multi-cpu/multi-core/multi-threaded environments and
1080 * arbitrary combinations thereof */
1081 get_freq(p_client_buffer, client_buffer_size, p_format, divisor, 1);
1086 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
1087 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
1089 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1090 char get_freq(char *p_client_buffer, size_t client_buffer_size,
1091 const char *p_format, int divisor, unsigned int cpu)
1099 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1105 char current_freq_file[128];
1107 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu - 1,
1109 f = fopen(current_freq_file, "r");
1111 /* if there's a cpufreq /sys node, read the current frequency from
1112 * this node and divide by 1000 to get Mhz. */
1113 if (fgets(s, sizeof(s), f)) {
1114 s[strlen(s) - 1] = '\0';
1115 freq = strtod(s, NULL);
1118 snprintf(p_client_buffer, client_buffer_size, p_format,
1119 (freq / 1000) / divisor);
1124 // open the CPU information file
1125 f = open_file("/proc/cpuinfo", &rep);
1127 perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
1132 while (fgets(s, sizeof(s), f) != NULL) {
1134 #if defined(__i386) || defined(__x86_64)
1135 // and search for the cpu mhz
1136 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) {
1138 #if defined(__alpha)
1139 // different on alpha
1140 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) {
1142 // this is different on ppc for some reason
1143 if (strncmp(s, "clock", 5) == 0 && cpu == 0) {
1144 #endif // defined(__alpha)
1145 #endif // defined(__i386) || defined(__x86_64)
1147 // copy just the number
1148 strcpy(frequency, strchr(s, ':') + 2);
1149 #if defined(__alpha)
1151 frequency[strlen(frequency) - 6] = '\0';
1152 // kernel reports in Hz
1153 freq = strtod(frequency, NULL) / 1000000;
1156 frequency[strlen(frequency) - 1] = '\0';
1157 freq = strtod(frequency, NULL);
1161 if (strncmp(s, "processor", 9) == 0) {
1168 snprintf(p_client_buffer, client_buffer_size, p_format,
1169 (float) freq / divisor);
1173 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
1175 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks something
1185 * Peter Tarjan (ptarjan@citromail.hu) */
1187 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
1188 char get_voltage(char *p_client_buffer, size_t client_buffer_size,
1189 const char *p_format, int divisor, unsigned int cpu)
1195 char current_freq_file[128];
1198 /* build the voltage file name */
1200 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1203 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1208 /* read the current cpu frequency from the /sys node */
1209 f = fopen(current_freq_file, "r");
1211 if (fgets(s, sizeof(s), f)) {
1212 s[strlen(s) - 1] = '\0';
1213 freq = strtod(s, NULL);
1217 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1218 perror("get_voltage()");
1225 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1228 /* use the current cpu frequency to find the corresponding voltage */
1229 f = fopen(current_freq_file, "r");
1235 if (fgets(line, 255, f) == NULL) {
1238 sscanf(line, "%d %d", &freq_comp, &voltage);
1239 if (freq_comp == freq) {
1245 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1246 perror("get_voltage()");
1252 snprintf(p_client_buffer, client_buffer_size, p_format,
1253 (float) voltage / divisor);
1257 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1259 void get_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
1266 if (!p_client_buffer || client_buffer_size <= 0) {
1270 /* yeah, slow... :/ */
1271 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep)) {
1272 snprintf(p_client_buffer, client_buffer_size, "no fans?");
1276 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf);
1278 fp = open_file(buf2, &rep);
1280 snprintf(p_client_buffer, client_buffer_size,
1281 "can't open fan's state file");
1284 memset(buf, 0, sizeof(buf));
1285 fscanf(fp, "%*s %99s", buf);
1288 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1291 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1293 void get_acpi_ac_adapter(char *p_client_buffer, size_t client_buffer_size)
1300 if (!p_client_buffer || client_buffer_size <= 0) {
1304 /* yeah, slow... :/ */
1305 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep)) {
1306 snprintf(p_client_buffer, client_buffer_size, "no ac_adapters?");
1310 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf);
1312 fp = open_file(buf2, &rep);
1314 snprintf(p_client_buffer, client_buffer_size,
1315 "No ac adapter found.... where is it?");
1318 memset(buf, 0, sizeof(buf));
1319 fscanf(fp, "%*s %99s", buf);
1322 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1326 /proc/acpi/thermal_zone/THRM/cooling_mode
1327 cooling mode: active
1328 /proc/acpi/thermal_zone/THRM/polling_frequency
1330 /proc/acpi/thermal_zone/THRM/state
1332 /proc/acpi/thermal_zone/THRM/temperature
1334 /proc/acpi/thermal_zone/THRM/trip_points
1336 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1339 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1340 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1342 int open_acpi_temperature(const char *name)
1348 if (name == NULL || strcmp(name, "*") == 0) {
1351 if (!get_first_file_in_a_directory(ACPI_THERMAL_DIR, buf, &rep)) {
1357 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1359 fd = open(path, O_RDONLY);
1361 ERR("can't open '%s': %s", path, strerror(errno));
1367 static double last_acpi_temp;
1368 static double last_acpi_temp_time;
1370 double get_acpi_temperature(int fd)
1376 /* don't update acpi temperature too often */
1377 if (current_update_time - last_acpi_temp_time < 11.32) {
1378 return last_acpi_temp;
1380 last_acpi_temp_time = current_update_time;
1382 /* seek to beginning */
1383 lseek(fd, 0, SEEK_SET);
1390 n = read(fd, buf, 255);
1392 ERR("can't read fd %d: %s", fd, strerror(errno));
1395 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1399 return last_acpi_temp;
1403 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1405 design capacity: 4400 mAh
1406 last full capacity: 4064 mAh
1407 battery technology: rechargeable
1408 design voltage: 14800 mV
1409 design capacity warning: 300 mAh
1410 design capacity low: 200 mAh
1411 capacity granularity 1: 32 mAh
1412 capacity granularity 2: 32 mAh
1414 serial number: 16922
1420 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1423 charging state: unknown
1425 remaining capacity: 4064 mAh
1426 present voltage: 16608 mV
1430 2213<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1431 2213<@jupet�kellari��> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1432 2213<@jupet�kellari��> (-1 ollee ei akkua kiinni, koska akku on p�yd�ll�)
1433 2214<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1434 2214<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1436 2238<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1437 2239<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1439 2240<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori p��ll�
1440 2241<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori p��ll� mutta ilman verkkovirtaa
1443 /* Kapil Hari Paranjape <kapil@imsc.res.in>
1444 Linux 2.6.24 onwards battery info is in
1445 /sys/class/power_supply/BAT0/
1446 On my system I get the following.
1447 /sys/class/power_supply/BAT0/uevent:
1448 PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A03:00/device:01/PNP0C09:00/PNP0C0A:00
1450 PHYSDEVDRIVER=battery
1451 POWER_SUPPLY_NAME=BAT0
1452 POWER_SUPPLY_TYPE=Battery
1453 POWER_SUPPLY_STATUS=Discharging
1454 POWER_SUPPLY_PRESENT=1
1455 POWER_SUPPLY_TECHNOLOGY=Li-ion
1456 POWER_SUPPLY_VOLTAGE_MIN_DESIGN=10800000
1457 POWER_SUPPLY_VOLTAGE_NOW=10780000
1458 POWER_SUPPLY_CURRENT_NOW=13970000
1459 POWER_SUPPLY_ENERGY_FULL_DESIGN=47510000
1460 POWER_SUPPLY_ENERGY_FULL=27370000
1461 POWER_SUPPLY_ENERGY_NOW=11810000
1462 POWER_SUPPLY_MODEL_NAME=IBM-92P1060
1463 POWER_SUPPLY_MANUFACTURER=Panasonic
1464 On some systems POWER_SUPPLY_ENERGY_* is replaced by POWER_SUPPLY_CHARGE_*
1467 #define SYSFS_BATTERY_BASE_PATH "/sys/class/power_supply"
1468 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1469 #define APM_PATH "/proc/apm"
1470 #define MAX_BATTERY_COUNT 4
1472 static FILE *sysfs_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1473 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1474 static FILE *apm_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1476 static int batteries_initialized = 0;
1477 static char batteries[MAX_BATTERY_COUNT][32];
1479 static int acpi_last_full[MAX_BATTERY_COUNT];
1480 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1482 /* e.g. "charging 75%" */
1483 static char last_battery_str[MAX_BATTERY_COUNT][64];
1485 static char last_battery_time_str[MAX_BATTERY_COUNT][64];
1487 static double last_battery_time[MAX_BATTERY_COUNT];
1489 static int last_battery_perct[MAX_BATTERY_COUNT];
1490 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1492 void init_batteries(void)
1496 if (batteries_initialized) {
1499 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1500 batteries[idx][0] = '\0';
1502 batteries_initialized = 1;
1505 int get_battery_idx(const char *bat)
1509 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1510 if (!strlen(batteries[idx]) || !strcmp(batteries[idx], bat)) {
1515 /* if not found, enter a new entry */
1516 if (!strlen(batteries[idx])) {
1517 snprintf(batteries[idx], 31, "%s", bat);
1523 void get_battery_stuff(char *buffer, unsigned int n, const char *bat, int item)
1525 static int idx, rep = 0, rep2 = 0;
1526 char acpi_path[128];
1527 char sysfs_path[128];
1529 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1530 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1534 idx = get_battery_idx(bat);
1536 /* don't update battery too often */
1537 if (current_update_time - last_battery_time[idx] < 29.5) {
1538 goto set_return_value;
1541 last_battery_time[idx] = current_update_time;
1543 memset(last_battery_str[idx], 0, sizeof(last_battery_str[idx]));
1544 memset(last_battery_time_str[idx], 0, sizeof(last_battery_time_str[idx]));
1546 /* first try SYSFS if that fails try ACPI */
1548 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1549 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1553 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1554 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1557 if (sysfs_bat_fp[idx] != NULL) {
1559 int present_rate = -1;
1560 int remaining_capacity = -1;
1561 char charging_state[64];
1564 strcpy(charging_state, "Unknown");
1566 while (!feof(sysfs_bat_fp[idx])) {
1568 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1571 /* let's just hope units are ok */
1572 if (strncmp (buf, "POWER_SUPPLY_PRESENT=1", 22) == 0)
1573 strcpy(present, "Yes");
1574 else if (strncmp (buf, "POWER_SUPPLY_PRESENT=0", 22) == 0)
1575 strcpy(present, "No");
1576 else if (strncmp (buf, "POWER_SUPPLY_STATUS=", 20) == 0)
1577 sscanf(buf, "POWER_SUPPLY_STATUS=%63s", charging_state);
1578 /* present_rate is not the same as the
1579 current flowing now but it is the same value
1580 which was used in the past. so we continue
1582 else if (strncmp(buf, "POWER_SUPPLY_CURRENT_NOW=", 25) == 0)
1583 sscanf(buf, "POWER_SUPPLY_CURRENT_NOW=%d", &present_rate);
1584 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0)
1585 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1586 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=", 25) == 0)
1587 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_last_full[idx]);
1588 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0)
1589 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1590 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=", 25) == 0)
1591 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_last_full[idx]);
1594 fclose(sysfs_bat_fp[idx]);
1595 sysfs_bat_fp[idx] = NULL;
1597 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1598 if (remaining_capacity > acpi_last_full[idx])
1599 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1602 if (strcmp(present, "No") == 0) {
1603 strncpy(last_battery_str[idx], "not present", 64);
1606 else if (strcmp(charging_state, "Charging") == 0) {
1607 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1608 /* e.g. charging 75% */
1609 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Charging %i%%",
1610 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1612 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1613 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1614 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1615 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Charging %d%%",
1616 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1618 strncpy(last_battery_str[idx], "Charging", sizeof(last_battery_str[idx])-1);
1622 else if (strncmp(charging_state, "Discharging", 64) == 0) {
1623 if (present_rate > 0) {
1624 /* e.g. discharging 35% */
1625 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Discharging %i%%",
1626 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1628 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1629 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1630 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1631 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "Full");
1633 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1635 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1639 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1640 else if (strncmp(charging_state, "Charged", 64) == 0) {
1641 /* Below happens with the second battery on my X40,
1642 * when the second one is empty and the first one
1644 if (remaining_capacity == 0)
1645 strcpy(last_battery_str[idx], "Empty");
1647 strcpy(last_battery_str[idx], "Charged");
1649 /* unknown, probably full / AC */
1651 if (acpi_last_full[idx] != 0
1652 && remaining_capacity != acpi_last_full[idx])
1653 snprintf(last_battery_str[idx], 64, "Unknown %d%%",
1654 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1656 strncpy(last_battery_str[idx], "AC", 64);
1658 } else if (acpi_bat_fp[idx] != NULL) {
1660 int present_rate = -1;
1661 int remaining_capacity = -1;
1662 char charging_state[64];
1665 /* read last full capacity if it's zero */
1666 if (acpi_last_full[idx] == 0) {
1667 static int rep3 = 0;
1671 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1672 fp = open_file(path, &rep3);
1677 if (fgets(b, 256, fp) == NULL) {
1680 if (sscanf(b, "last full capacity: %d",
1681 &acpi_last_full[idx]) != 0) {
1690 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1692 strcpy(charging_state, "unknown");
1694 while (!feof(acpi_bat_fp[idx])) {
1697 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1701 /* let's just hope units are ok */
1702 if (strncmp(buf, "present:", 8) == 0) {
1703 sscanf(buf, "present: %4s", present);
1704 } else if (strncmp(buf, "charging state:", 15) == 0) {
1705 sscanf(buf, "charging state: %63s", charging_state);
1706 } else if (strncmp(buf, "present rate:", 13) == 0) {
1707 sscanf(buf, "present rate: %d", &present_rate);
1708 } else if (strncmp(buf, "remaining capacity:", 19) == 0) {
1709 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1712 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1713 if (remaining_capacity > acpi_last_full[idx]) {
1714 /* normalize to 100% */
1715 acpi_last_full[idx] = remaining_capacity;
1719 if (strcmp(present, "no") == 0) {
1720 strncpy(last_battery_str[idx], "not present", 64);
1722 } else if (strcmp(charging_state, "charging") == 0) {
1723 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1724 /* e.g. charging 75% */
1725 snprintf(last_battery_str[idx],
1726 sizeof(last_battery_str[idx]) - 1, "charging %i%%",
1727 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1729 format_seconds(last_battery_time_str[idx],
1730 sizeof(last_battery_time_str[idx]) - 1,
1731 (long) (((acpi_last_full[idx] - remaining_capacity) *
1732 3600) / present_rate));
1733 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1734 snprintf(last_battery_str[idx],
1735 sizeof(last_battery_str[idx]) - 1, "charging %d%%",
1736 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1738 strncpy(last_battery_str[idx], "charging",
1739 sizeof(last_battery_str[idx]) - 1);
1742 } else if (strncmp(charging_state, "discharging", 64) == 0) {
1743 if (present_rate > 0) {
1744 /* e.g. discharging 35% */
1745 snprintf(last_battery_str[idx],
1746 sizeof(last_battery_str[idx]) - 1, "discharging %i%%",
1747 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1749 format_seconds(last_battery_time_str[idx],
1750 sizeof(last_battery_time_str[idx]) - 1,
1751 (long) ((remaining_capacity * 3600) / present_rate));
1752 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1753 snprintf(last_battery_str[idx],
1754 sizeof(last_battery_str[idx]) - 1, "full");
1756 snprintf(last_battery_str[idx],
1757 sizeof(last_battery_str[idx]) - 1, "discharging %d%%",
1758 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1761 } else if (strncmp(charging_state, "charged", 64) == 0) {
1762 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1763 /* Below happens with the second battery on my X40,
1764 * when the second one is empty and the first one being charged. */
1765 if (remaining_capacity == 0) {
1766 strcpy(last_battery_str[idx], "empty");
1768 strcpy(last_battery_str[idx], "charged");
1770 /* unknown, probably full / AC */
1772 if (acpi_last_full[idx] != 0
1773 && remaining_capacity != acpi_last_full[idx]) {
1774 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1775 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1777 strncpy(last_battery_str[idx], "AC", 64);
1782 if (apm_bat_fp[idx] == NULL) {
1783 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1786 if (apm_bat_fp[idx] != NULL) {
1787 unsigned int ac, status, flag;
1790 fscanf(apm_bat_fp[idx], "%*s %*s %*x %x %x %x %d%%",
1791 &ac, &status, &flag, &life);
1794 /* could check now that there is ac */
1795 snprintf(last_battery_str[idx], 64, "AC");
1797 /* could check that status == 3 here? */
1798 } else if (ac && life != 100) {
1799 snprintf(last_battery_str[idx], 64, "charging %d%%", life);
1801 snprintf(last_battery_str[idx], 64, "%d%%", life);
1804 /* it seemed to buffer it so file must be closed (or could use
1805 * syscalls directly but I don't feel like coding it now) */
1806 fclose(apm_bat_fp[idx]);
1807 apm_bat_fp[idx] = NULL;
1813 case BATTERY_STATUS:
1814 snprintf(buffer, n, "%s", last_battery_str[idx]);
1817 snprintf(buffer, n, "%s", last_battery_time_str[idx]);
1824 int get_battery_perct(const char *bat)
1828 char acpi_path[128];
1829 char sysfs_path[128];
1830 int remaining_capacity = -1;
1832 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1833 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1837 idx = get_battery_idx(bat);
1839 /* don't update battery too often */
1840 if (current_update_time - last_battery_perct_time[idx] < 30) {
1841 return last_battery_perct[idx];
1843 last_battery_perct_time[idx] = current_update_time;
1845 /* Only check for SYSFS or ACPI */
1847 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1848 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1852 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1853 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
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, &rep2);
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 *buffer, 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(buffer, 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", &timeval);
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 (timeval == 0) { /* fully charged or battery not present */
2040 pb_battery_info[PB_BATT_TIME][0] = 0;
2041 } else if (timeval < 60 * 60) { /* don't show secs */
2042 format_seconds_short(pb_battery_info[PB_BATT_TIME],
2043 sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2045 format_seconds(pb_battery_info[PB_BATT_TIME],
2046 sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2049 snprintf(buffer, 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;
2090 int tot, tot_read, tot_write;
2092 if (!(fp = open_file("/proc/diskstats", &rep))) {
2097 /* read reads and writes from all disks (minor = 0), including cd-roms
2098 * and floppies, and sum them up */
2100 fgets(buf, 512, fp);
2101 col_count = sscanf(buf, "%u %u %s %*u %*u %u %*u %*u %*u %u", &major,
2102 &minor, devbuf, &reads, &writes);
2103 /* ignore subdevices (they have only 3 matching entries in their line)
2104 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
2106 * XXX: ignore devices which are part of a SW RAID (MD_MAJOR) */
2107 if (col_count == 5 && major != LVM_BLK_MAJOR && major != NBD_MAJOR
2108 && major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
2109 current += reads + writes;
2110 current_read += reads;
2111 current_write += writes;
2113 col_count = sscanf(buf, "%u %u %s %*u %u %*u %u",
2114 &major, &minor, devbuf, &reads, &writes);
2115 if (col_count != 5) {
2119 for (i = 0; i < MAX_DISKIO_STATS; i++) {
2120 if (diskio_stats[i].dev &&
2121 strcmp(devbuf, diskio_stats[i].dev) == 0) {
2122 diskio_stats[i].current =
2123 (reads + writes - diskio_stats[i].last) / 2;
2124 diskio_stats[i].current_read =
2125 (reads - diskio_stats[i].last_read) / 2;
2126 diskio_stats[i].current_write =
2127 (writes - diskio_stats[i].last_write) / 2;
2128 if (reads + writes < diskio_stats[i].last) {
2129 diskio_stats[i].current = 0;
2131 if (reads < diskio_stats[i].last_read) {
2132 diskio_stats[i].current_read = 0;
2133 diskio_stats[i].current = diskio_stats[i].current_write;
2135 if (writes < diskio_stats[i].last_write) {
2136 diskio_stats[i].current_write = 0;
2137 diskio_stats[i].current = diskio_stats[i].current_read;
2139 diskio_stats[i].last = reads + writes;
2140 diskio_stats[i].last_read = reads;
2141 diskio_stats[i].last_write = writes;
2146 /* since the values in /proc/diststats are absolute, we have to substract
2147 * our last reading. The numbers stand for "sectors read", and we therefore
2148 * have to divide by two to get KB */
2149 tot = ((double) (current - last) / 2);
2150 tot_read = ((double) (current_read - last_read) / 2);
2151 tot_write = ((double) (current_write - last_write) / 2);
2153 if (last_read > current_read) {
2156 if (last_write > current_write) {
2160 if (last > current) {
2161 /* we hit this either if it's the very first time we run this, or
2162 * when /proc/diskstats overflows; while 0 is not correct, it's at
2163 * least not way off */
2167 last_read = current_read;
2168 last_write = current_write;
2171 diskio_read_value = tot_read;
2172 diskio_write_value = tot_write;
2177 /* Here come the IBM ACPI-specific things. For reference, see
2178 * http://ibm-acpi.sourceforge.net/README
2179 * If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
2195 * The content of these files is described in detail in the aforementioned
2196 * README - some of them also in the following functions accessing them.
2197 * Peter Tarjan (ptarjan@citromail.hu) */
2199 #define IBM_ACPI_DIR "/proc/acpi/ibm"
2201 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
2202 * /proc/acpi/ibm/fan looks like this (3 lines):
2205 commands: enable, disable
2206 * Peter Tarjan (ptarjan@citromail.hu) */
2208 void get_ibm_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
2211 unsigned int speed = 0;
2214 if (!p_client_buffer || client_buffer_size <= 0) {
2218 snprintf(fan, 127, "%s/fan", IBM_ACPI_DIR);
2220 fp = fopen(fan, "r");
2225 if (fgets(line, 255, fp) == NULL) {
2228 if (sscanf(line, "speed: %u", &speed)) {
2233 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2234 "ibm* from your Conky config file.", fan, strerror(errno));
2238 snprintf(p_client_buffer, client_buffer_size, "%d", speed);
2241 /* get the measured temperatures from the temperature sensors
2242 * on IBM/Lenovo laptops running the ibm acpi.
2243 * There are 8 values in /proc/acpi/ibm/thermal, and according to
2244 * http://ibm-acpi.sourceforge.net/README
2245 * these mean the following (at least on an IBM R51...)
2246 * 0: CPU (also on the T series laptops)
2247 * 1: Mini PCI Module (?)
2249 * 3: GPU (also on the T series laptops)
2254 * I'm not too sure about those with the question mark, but the values I'm
2255 * reading from *my* thermal file (on a T42p) look realistic for the
2256 * hdd and the battery.
2257 * #5 and #7 are always -128.
2258 * /proc/acpi/ibm/thermal looks like this (1 line):
2259 temperatures: 41 43 31 46 33 -128 29 -128
2260 * Peter Tarjan (ptarjan@citromail.hu) */
2262 static double last_ibm_acpi_temp_time;
2263 void get_ibm_acpi_temps(void)
2269 /* don't update too often */
2270 if (current_update_time - last_ibm_acpi_temp_time < 10.00) {
2273 last_ibm_acpi_temp_time = current_update_time;
2275 /* 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)
2318 unsigned int vol = -1;
2321 if (!p_client_buffer || client_buffer_size <= 0) {
2325 snprintf(volume, 127, "%s/volume", IBM_ACPI_DIR);
2327 fp = fopen(volume, "r");
2331 unsigned int read_vol = -1;
2333 if (fgets(line, 255, fp) == NULL) {
2336 if (sscanf(line, "level: %u", &read_vol)) {
2340 if (sscanf(line, "mute: %s", mute)) {
2345 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2346 "ibm* from your Conky config file.", volume, strerror(errno));
2351 if (strcmp(mute, "on") == 0) {
2352 snprintf(p_client_buffer, client_buffer_size, "%s", "mute");
2355 snprintf(p_client_buffer, client_buffer_size, "%d", vol);
2360 /* static FILE *fp = NULL; */
2362 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
2363 * /proc/acpi/ibm/brightness looks like this (3 lines):
2366 commands: level <level> (<level> is 0-7)
2367 * Peter Tarjan (ptarjan@citromail.hu) */
2369 void get_ibm_acpi_brightness(char *p_client_buffer, size_t client_buffer_size)
2372 unsigned int brightness = 0;
2375 if (!p_client_buffer || client_buffer_size <= 0) {
2379 snprintf(filename, 127, "%s/brightness", IBM_ACPI_DIR);
2381 fp = fopen(filename, "r");
2386 if (fgets(line, 255, fp) == NULL) {
2389 if (sscanf(line, "level: %u", &brightness)) {
2394 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2395 "ibm* from your Conky config file.", filename, strerror(errno));
2400 snprintf(p_client_buffer, client_buffer_size, "%d", brightness);
2403 void update_entropy(void)
2406 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
2407 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
2410 info.entropy.entropy_avail = 0;
2411 info.entropy.poolsize = 0;
2413 if ((fp1 = open_file(entropy_avail, &rep)) == NULL) {
2417 if ((fp2 = open_file(entropy_poolsize, &rep)) == NULL) {
2422 fscanf(fp1, "%u", &info.entropy.entropy_avail);
2423 fscanf(fp2, "%u", &info.entropy.poolsize);
2428 info.mask |= (1 << INFO_ENTROPY);
2431 const char *get_disk_protect_queue(const char *disk)
2437 snprintf(path, 127, "/sys/block/%s/queue/protect", disk);
2438 if ((fp = fopen(path, "r")) == NULL)
2440 if (fscanf(fp, "%d\n", &state) != 1) {
2445 return state ? "frozen" : "free ";