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-2008 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 strndup("n/a", text_buffer_size);
197 snprintf(buf, 127, "/sys/block/%s/queue/scheduler", disk);
198 if ((fp = fopen(buf, "r")) == NULL) {
199 return strndup("n/a", text_buffer_size);
202 fscanf(fp, "%127s", buf);
204 buf[strlen(buf) - 1] = '\0';
206 return strndup(buf + 1, text_buffer_size);
210 return strndup("n/a", text_buffer_size);
213 int interface_up(const char *dev)
215 int fd, dnl, ifnl, nl;
218 struct sockaddr addr;
222 if((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
223 CRIT_ERR("could not create sockfd");
227 /* allocate memory for interface request */
228 if((conf.ifc_buf = calloc(16, sizeof(struct ifreq))) == NULL) {
229 CRIT_ERR("could not allocate memory for interface query");
232 conf.ifc_len = sizeof(struct ifreq) * 16;
234 /* send a conf query ioctl to device to enumerate all interfaces */
235 if(ioctl(fd, SIOCGIFCONF, &conf)) {
236 /* if device does not exist, treat like not up - fail fast */
238 perror("SIOCGIFFLAGS");
240 /* for all enumerated interface devices ... */
241 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
242 /* end of buffer - break out */
243 if (!(((struct ifreq *) conf.ifc_buf) + k))
245 /* get interface device name */
246 ifdev = ((struct ifreq *) conf.ifc_buf)[k].ifr_ifrn.ifrn_name;
247 ifnl = strlen(ifdev);
248 nl = dnl > ifnl ? ifnl : dnl;
249 /* if it does not match our specified device - move on */
250 if (strncmp(dev, ifdev, nl) != 0) {
253 /* get associated address on device */
254 addr = ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.ifru_addr;
255 /* if ip is 0.0.0.0 it is not up */
256 if(((addr.sa_data[2] & 255) == 0 && (addr.sa_data[3] & 255) == 0 &&
257 (addr.sa_data[4] & 255) == 0 && (addr.sa_data[5] & 255) == 0) ||
258 /* oh yeah also include IANA link local RFC3330
259 * http://www.faqs.org/rfcs/rfc3330.html
260 * http://www.iana.org/assignments/ipv4-address-space Notes [6]
261 * exclude 169.254.*.* how about 223.255 and 240.0??? */
262 ((addr.sa_data[2] & 255) == 169 && (addr.sa_data[3] & 255) == 254)) {
265 /* otherwise we are good */
276 #define COND_FREE(x) if(x) free(x); x = 0
277 #define SAVE_SET_STRING(x, y) \
278 if (x && strcmp((char *)x, (char *)y)) { \
280 x = strndup("multiple", text_buffer_size); \
282 x = strndup(y, text_buffer_size); \
285 void update_gateway_info(void)
290 unsigned long dest, gate, mask;
292 short ref, use, metric, mtu, win, irtt;
294 struct gateway_info *gw_info = &info.gw_info;
296 COND_FREE(gw_info->iface);
297 COND_FREE(gw_info->ip);
300 if ((fp = fopen("/proc/net/route", "r")) == NULL) {
302 info.gw_info.iface = info.gw_info.ip = strndup("failed", text_buffer_size);
305 if (fscanf(fp, "%*[^\n]\n") == EOF) {
308 info.gw_info.iface = info.gw_info.ip = strndup("failed", text_buffer_size);
312 // Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
313 if(fscanf(fp, "%63s %lx %lx %x %hd %hd %hd %lx %hd %hd %hd\n",
314 iface, &dest, &gate, &flags, &ref, &use,
315 &metric, &mask, &mtu, &win, &irtt) != 11) {
318 info.gw_info.iface = info.gw_info.ip = strndup("failed", text_buffer_size);
321 if (flags & RTF_GATEWAY && dest == 0 && mask == 0) {
323 SAVE_SET_STRING(gw_info->iface, iface)
325 SAVE_SET_STRING(gw_info->ip, inet_ntoa(ina))
332 inline void update_net_stats(void)
337 // FIXME: arbitrary size chosen to keep code simple.
339 unsigned int curtmp1, curtmp2;
346 // wireless info variables
347 int skfd, has_bitrate = 0;
348 struct wireless_info *winfo;
353 delta = current_update_time - last_update_time;
354 if (delta <= 0.0001) {
358 /* open file and ignore first two lines */
359 if (!(net_dev_fp = open_file("/proc/net/dev", &rep))) {
364 fgets(buf, 255, net_dev_fp); /* garbage */
365 fgets(buf, 255, net_dev_fp); /* garbage (field names) */
367 /* read each interface */
368 for (i2 = 0; i2 < 16; i2++) {
372 long long r, t, last_recv, last_trans;
374 if (fgets(buf, 255, net_dev_fp) == NULL) {
378 while (isspace((int) *p)) {
384 while (*p && *p != ':') {
393 ns = get_net_stat(s);
395 memset(&(ns->addr.sa_data), 0, 14);
397 if(NULL == ns->addrs)
398 ns->addrs = (char*) malloc(17 * 16);
399 if(NULL != ns->addrs)
400 memset(ns->addrs, 0, 17 * 16); /* Up to 17 chars per ip, max 16 interfaces. Nasty memory usage... */
402 last_recv = ns->recv;
403 last_trans = ns->trans;
405 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
406 sscanf(p, "%lld %*d %*d %*d %*d %*d %*d %*d %lld",
409 /* if recv or trans is less than last time, an overflow happened */
410 if (r < ns->last_read_recv) {
413 ns->recv += (r - ns->last_read_recv);
415 ns->last_read_recv = r;
417 if (t < ns->last_read_trans) {
420 ns->trans += (t - ns->last_read_trans);
422 ns->last_read_trans = t;
424 /*** ip addr patch ***/
425 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
427 conf.ifc_buf = malloc(sizeof(struct ifreq) * 16);
428 conf.ifc_len = sizeof(struct ifreq) * 16;
429 memset(conf.ifc_buf, 0, conf.ifc_len);
431 ioctl((long) i, SIOCGIFCONF, &conf);
433 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
434 struct net_stat *ns2;
436 if (!(((struct ifreq *) conf.ifc_buf) + k))
440 ((struct ifreq *) conf.ifc_buf)[k].ifr_ifrn.ifrn_name);
441 ns2->addr = ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.ifru_addr;
442 if(NULL != ns2->addrs) {
443 sprintf(temp_addr, "%u.%u.%u.%u, ",
444 ns2->addr.sa_data[2] & 255,
445 ns2->addr.sa_data[3] & 255,
446 ns2->addr.sa_data[4] & 255,
447 ns2->addr.sa_data[5] & 255);
448 if(NULL == strstr(ns2->addrs, temp_addr))
449 strncpy(ns2->addrs + strlen(ns2->addrs), temp_addr, 17);
457 /*** end ip addr patch ***/
459 /* calculate speeds */
460 ns->net_rec[0] = (ns->recv - last_recv) / delta;
461 ns->net_trans[0] = (ns->trans - last_trans) / delta;
465 for (i = 0; (unsigned) i < info.net_avg_samples; i++) {
466 curtmp1 += ns->net_rec[i];
467 curtmp2 += ns->net_trans[i];
475 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
476 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
477 if (info.net_avg_samples > 1) {
478 for (i = info.net_avg_samples; i > 1; i--) {
479 ns->net_rec[i - 1] = ns->net_rec[i - 2];
480 ns->net_trans[i - 1] = ns->net_trans[i - 2];
485 /* update wireless info */
486 winfo = malloc(sizeof(struct wireless_info));
487 memset(winfo, 0, sizeof(struct wireless_info));
489 skfd = iw_sockets_open();
490 if (iw_get_basic_config(skfd, s, &(winfo->b)) > -1) {
492 // set present winfo variables
493 if (iw_get_stats(skfd, s, &(winfo->stats),
494 &winfo->range, winfo->has_range) >= 0) {
495 winfo->has_stats = 1;
497 if (iw_get_range_info(skfd, s, &(winfo->range)) >= 0) {
498 winfo->has_range = 1;
500 if (iw_get_ext(skfd, s, SIOCGIWAP, &wrq) >= 0) {
501 winfo->has_ap_addr = 1;
502 memcpy(&(winfo->ap_addr), &(wrq.u.ap_addr), sizeof(sockaddr));
506 if (iw_get_ext(skfd, s, SIOCGIWRATE, &wrq) >= 0) {
507 memcpy(&(winfo->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
508 iw_print_bitrate(ns->bitrate, 16, winfo->bitrate.value);
513 if (winfo->has_range && winfo->has_stats
514 && ((winfo->stats.qual.level != 0)
515 || (winfo->stats.qual.updated & IW_QUAL_DBM))) {
516 if (!(winfo->stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
517 ns->link_qual = winfo->stats.qual.qual;
518 ns->link_qual_max = winfo->range.max_qual.qual;
523 if (winfo->has_ap_addr) {
524 iw_sawap_ntop(&winfo->ap_addr, ns->ap);
528 if (winfo->b.has_essid) {
529 if (winfo->b.essid_on) {
530 snprintf(ns->essid, 32, "%s", winfo->b.essid);
532 snprintf(ns->essid, 32, "off/any");
536 snprintf(ns->mode, 16, "%s", iw_operation_mode[winfo->b.mode]);
538 iw_sockets_close(skfd);
545 info.mask |= (1 << INFO_NET);
550 void update_total_processes(void)
554 struct sysinfo s_info;
557 info.procs = s_info.procs;
564 if (!(fp = open_file("/proc/loadavg", &rep))) {
568 fscanf(fp, "%*f %*f %*f %*d/%hu", &info.procs);
571 info.mask |= (1 << INFO_PROCS);
574 #define CPU_SAMPLE_COUNT 15
576 unsigned long long cpu_user;
577 unsigned long long cpu_system;
578 unsigned long long cpu_nice;
579 unsigned long long cpu_idle;
580 unsigned long long cpu_iowait;
581 unsigned long long cpu_irq;
582 unsigned long long cpu_softirq;
583 unsigned long long cpu_steal;
584 unsigned long long cpu_total;
585 unsigned long long cpu_active_total;
586 unsigned long long cpu_last_total;
587 unsigned long long cpu_last_active_total;
588 double cpu_val[CPU_SAMPLE_COUNT];
590 static short cpu_setup = 0;
592 /* Determine if this kernel gives us "extended" statistics information in
594 * Kernels around 2.5 and earlier only reported user, system, nice, and
595 * idle values in proc stat.
596 * Kernels around 2.6 and greater report these PLUS iowait, irq, softirq,
598 void determine_longstat(char *buf)
600 unsigned long long iowait = 0;
602 KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
603 /* scanf will either return -1 or 1 because there is only 1 assignment */
604 if (sscanf(buf, "%*s %*d %*d %*d %*d %llu", &iowait) > 0) {
605 KFLAG_SETON(KFLAG_IS_LONGSTAT);
609 void get_cpu_count(void)
615 if (info.cpu_usage) {
619 if (!(stat_fp = open_file("/proc/stat", &rep))) {
625 while (!feof(stat_fp)) {
626 if (fgets(buf, 255, stat_fp) == NULL) {
630 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
631 if (info.cpu_count == 0) {
632 determine_longstat(buf);
637 info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
642 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
643 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
645 inline static void update_stat(void)
649 static struct cpu_info *cpu = NULL;
654 const char *stat_template = NULL;
655 unsigned int malloc_cpu_size = 0;
657 /* add check for !info.cpu_usage since that mem is freed on a SIGUSR1 */
658 if (!cpu_setup || !info.cpu_usage) {
663 if (!stat_template) {
665 KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT;
669 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
670 cpu = malloc(malloc_cpu_size);
671 memset(cpu, 0, malloc_cpu_size);
674 if (!(stat_fp = open_file("/proc/stat", &rep))) {
676 if (info.cpu_usage) {
677 memset(info.cpu_usage, 0, info.cpu_count * sizeof(float));
683 while (!feof(stat_fp)) {
684 if (fgets(buf, 255, stat_fp) == NULL) {
688 if (strncmp(buf, "procs_running ", 14) == 0) {
689 sscanf(buf, "%*s %hu", &info.run_procs);
690 info.mask |= (1 << INFO_RUN_PROCS);
691 } else if (strncmp(buf, "cpu", 3) == 0) {
693 idx = isdigit(buf[3]) ? ((int) buf[3]) - 0x2F : 0;
694 sscanf(buf, stat_template, &(cpu[idx].cpu_user),
695 &(cpu[idx].cpu_nice), &(cpu[idx].cpu_system),
696 &(cpu[idx].cpu_idle), &(cpu[idx].cpu_iowait),
697 &(cpu[idx].cpu_irq), &(cpu[idx].cpu_softirq),
698 &(cpu[idx].cpu_steal));
700 cpu[idx].cpu_total = cpu[idx].cpu_user + cpu[idx].cpu_nice +
701 cpu[idx].cpu_system + cpu[idx].cpu_idle +
702 cpu[idx].cpu_iowait + cpu[idx].cpu_irq +
703 cpu[idx].cpu_softirq + cpu[idx].cpu_steal;
705 cpu[idx].cpu_active_total = cpu[idx].cpu_total -
706 (cpu[idx].cpu_idle + cpu[idx].cpu_iowait);
707 info.mask |= (1 << INFO_CPU);
709 delta = current_update_time - last_update_time;
711 if (delta <= 0.001) {
715 cpu[idx].cpu_val[0] = (cpu[idx].cpu_active_total -
716 cpu[idx].cpu_last_active_total) /
717 (float) (cpu[idx].cpu_total - cpu[idx].cpu_last_total);
719 for (i = 0; i < info.cpu_avg_samples; i++) {
720 curtmp += cpu[idx].cpu_val[i];
722 /* TESTING -- I've removed this, because I don't think it is right.
723 * You shouldn't divide by the cpu count here ...
724 * removing for testing */
726 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples /
729 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples;
731 /* TESTING -- this line replaces the prev. "suspect" if/else */
732 info.cpu_usage[idx] = curtmp / info.cpu_avg_samples;
734 cpu[idx].cpu_last_total = cpu[idx].cpu_total;
735 cpu[idx].cpu_last_active_total = cpu[idx].cpu_active_total;
736 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
737 cpu[idx].cpu_val[i] = cpu[idx].cpu_val[i - 1];
744 void update_running_processes(void)
749 void update_cpu_usage(void)
754 void update_load_average(void)
756 #ifdef HAVE_GETLOADAVG
761 info.loadavg[0] = (float) v[0];
762 info.loadavg[1] = (float) v[1];
763 info.loadavg[2] = (float) v[2];
770 if (!(fp = open_file("/proc/loadavg", &rep))) {
771 info.loadavg[0] = info.loadavg[1] = info.loadavg[2] = 0.0;
774 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1],
778 info.mask |= (1 << INFO_LOADAVG);
781 #define PROC_I8K "/proc/i8k"
782 #define I8K_DELIM " "
783 static char *i8k_procbuf = NULL;
784 void update_i8k(void)
789 i8k_procbuf = (char *) malloc(128 * sizeof(char));
791 if ((fp = fopen(PROC_I8K, "r")) == NULL) {
792 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel "
793 "driver is loaded...");
796 memset(&i8k_procbuf[0], 0, 128);
797 if (fread(&i8k_procbuf[0], sizeof(char), 128, fp) == 0) {
798 ERR("something wrong with /proc/i8k...");
803 i8k.version = strtok(&i8k_procbuf[0], I8K_DELIM);
804 i8k.bios = strtok(NULL, I8K_DELIM);
805 i8k.serial = strtok(NULL, I8K_DELIM);
806 i8k.cpu_temp = strtok(NULL, I8K_DELIM);
807 i8k.left_fan_status = strtok(NULL, I8K_DELIM);
808 i8k.right_fan_status = strtok(NULL, I8K_DELIM);
809 i8k.left_fan_rpm = strtok(NULL, I8K_DELIM);
810 i8k.right_fan_rpm = strtok(NULL, I8K_DELIM);
811 i8k.ac_status = strtok(NULL, I8K_DELIM);
812 i8k.buttons_status = strtok(NULL, I8K_DELIM);
815 /***********************************************************/
816 /***********************************************************/
817 /***********************************************************/
819 static int no_dots(const struct dirent *d)
821 if (d->d_name[0] == '.') {
827 static int get_first_file_in_a_directory(const char *dir, char *s, int *rep)
829 struct dirent **namelist;
832 n = scandir(dir, &namelist, no_dots, alphasort);
835 ERR("scandir for %s: %s", dir, strerror(errno));
846 strncpy(s, namelist[0]->d_name, 255);
849 for (i = 0; i < n; i++) {
858 int open_sysfs_sensor(const char *dir, const char *dev, const char *type, int n,
859 int *divisor, char *devtype)
866 memset(buf, 0, sizeof(buf));
868 /* if device is NULL or *, get first */
869 if (dev == NULL || strcmp(dev, "*") == 0) {
872 if (!get_first_file_in_a_directory(dir, buf, &rep)) {
878 if (strcmp(dir, "/sys/class/hwmon/") == 0) {
880 /* buf holds result from get_first_file_in_a_directory() above,
881 * e.g. "hwmon0" -- append "/device" */
882 strcat(buf, "/device");
884 /* dev holds device number N as a string,
885 * e.g. "0", -- convert to "hwmon0/device" */
886 sprintf(buf, "hwmon%s/device", dev);
891 /* change vol to in */
892 if (strcmp(type, "vol") == 0) {
896 if (strcmp(type, "tempf") == 0) {
897 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, "temp", n);
899 snprintf(path, 255, "%s%s/%s%d_input", dir, dev, type, n);
901 strncpy(devtype, path, 255);
904 fd = open(path, O_RDONLY);
906 CRIT_ERR("can't open '%s': %s\nplease check your device or remove this "
907 "var from Conky", path, strerror(errno));
910 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
911 || strcmp(type, "tempf") == 0) {
916 /* fan does not use *_div as a read divisor */
917 if (strcmp("fan", type) == 0) {
921 /* test if *_div file exist, open it and use it as divisor */
922 if (strcmp(type, "tempf") == 0) {
923 snprintf(path, 255, "%s%s/%s%d_div", dir, "one", "two", n);
925 snprintf(path, 255, "%s%s/%s%d_div", dir, dev, type, n);
928 divfd = open(path, O_RDONLY);
934 divn = read(divfd, divbuf, 63);
935 /* should read until n == 0 but I doubt that kernel will give these
936 * in multiple pieces. :) */
938 ERR("open_sysfs_sensor(): can't read from sysfs");
941 *divisor = atoi(divbuf);
950 double get_sysfs_info(int *fd, int divisor, char *devtype, char *type)
958 lseek(*fd, 0, SEEK_SET);
964 n = read(*fd, buf, 63);
965 /* should read until n == 0 but I doubt that kernel will give these
966 * in multiple pieces. :) */
968 ERR("get_sysfs_info(): read from %s failed\n", devtype);
977 *fd = open(devtype, O_RDONLY);
979 ERR("can't open '%s': %s", devtype, strerror(errno));
982 /* My dirty hack for computing CPU value
983 * Filedil, from forums.gentoo.org */
984 /* if (strstr(devtype, "temp1_input") != NULL) {
985 return -15.096 + 1.4893 * (val / 1000.0);
988 /* divide voltage and temperature by 1000 */
989 /* or if any other divisor is given, use that */
990 if (strcmp(type, "tempf") == 0) {
992 return ((val / divisor + 40) * 9.0 / 5) - 40;
993 } else if (divisor) {
994 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
996 return ((val + 40) * 9.0 / 5) - 40;
1000 return val / divisor;
1001 } else if (divisor) {
1002 return val / 1000.0;
1009 /* Prior to kernel version 2.6.12, the CPU fan speed was available in
1010 * ADT746X_FAN_OLD, whereas later kernel versions provide this information in
1012 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
1013 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
1015 void get_adt746x_fan(char *p_client_buffer, size_t client_buffer_size)
1018 char adt746x_fan_state[64];
1021 if (!p_client_buffer || client_buffer_size <= 0) {
1025 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
1026 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL) {
1027 sprintf(adt746x_fan_state, "adt746x not found");
1029 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
1030 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
1034 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_fan_state);
1037 /* Prior to kernel version 2.6.12, the CPU temperature was found in
1038 * ADT746X_CPU_OLD, whereas later kernel versions provide this information in
1040 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
1041 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
1043 void get_adt746x_cpu(char *p_client_buffer, size_t client_buffer_size)
1046 char adt746x_cpu_state[64];
1049 if (!p_client_buffer || client_buffer_size <= 0) {
1053 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
1054 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL) {
1055 sprintf(adt746x_cpu_state, "adt746x not found");
1057 fscanf(fp, "%2s", adt746x_cpu_state);
1061 snprintf(p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state);
1064 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
1066 /***********************************************************************/
1067 /* This file is part of x86info.
1068 * (C) 2001 Dave Jones.
1070 * Licensed under the terms of the GNU GPL License version 2.
1072 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
1073 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz> */
1075 #if defined(__i386) || defined(__x86_64)
1076 __inline__ unsigned long long int rdtsc(void)
1078 unsigned long long int x;
1080 __asm__ volatile(".byte 0x0f, 0x31":"=A" (x));
1085 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1086 void get_freq_dynamic(char *p_client_buffer, size_t client_buffer_size,
1087 const char *p_format, int divisor)
1089 #if defined(__i386) || defined(__x86_64)
1091 struct timeval tvstart, tvstop;
1092 unsigned long long cycles[2]; /* gotta be 64 bit */
1093 unsigned int microseconds; /* total time taken */
1095 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1100 memset(&tz, 0, sizeof(tz));
1102 /* get this function in cached memory */
1103 gettimeofday(&tvstart, &tz);
1104 cycles[0] = rdtsc();
1105 gettimeofday(&tvstart, &tz);
1107 /* we don't trust that this is any specific length of time */
1109 cycles[1] = rdtsc();
1110 gettimeofday(&tvstop, &tz);
1111 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
1112 (tvstop.tv_usec - tvstart.tv_usec);
1114 snprintf(p_client_buffer, client_buffer_size, p_format,
1115 (float) ((cycles[1] - cycles[0]) / microseconds) / divisor);
1118 /* FIXME: hardwired: get freq for first cpu!
1119 * this whole function needs to be rethought and redone for
1120 * multi-cpu/multi-core/multi-threaded environments and
1121 * arbitrary combinations thereof */
1122 get_freq(p_client_buffer, client_buffer_size, p_format, divisor, 1);
1127 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
1128 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
1130 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
1131 char get_freq(char *p_client_buffer, size_t client_buffer_size,
1132 const char *p_format, int divisor, unsigned int cpu)
1140 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1146 char current_freq_file[128];
1148 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu - 1,
1150 f = fopen(current_freq_file, "r");
1152 /* if there's a cpufreq /sys node, read the current frequency from
1153 * this node and divide by 1000 to get Mhz. */
1154 if (fgets(s, sizeof(s), f)) {
1155 s[strlen(s) - 1] = '\0';
1156 freq = strtod(s, NULL);
1159 snprintf(p_client_buffer, client_buffer_size, p_format,
1160 (freq / 1000) / divisor);
1165 // open the CPU information file
1166 f = open_file("/proc/cpuinfo", &rep);
1168 perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
1173 while (fgets(s, sizeof(s), f) != NULL) {
1175 #if defined(__i386) || defined(__x86_64)
1176 // and search for the cpu mhz
1177 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) {
1179 #if defined(__alpha)
1180 // different on alpha
1181 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) {
1183 // this is different on ppc for some reason
1184 if (strncmp(s, "clock", 5) == 0 && cpu == 0) {
1185 #endif // defined(__alpha)
1186 #endif // defined(__i386) || defined(__x86_64)
1188 // copy just the number
1189 strcpy(frequency, strchr(s, ':') + 2);
1190 #if defined(__alpha)
1192 frequency[strlen(frequency) - 6] = '\0';
1193 // kernel reports in Hz
1194 freq = strtod(frequency, NULL) / 1000000;
1197 frequency[strlen(frequency) - 1] = '\0';
1198 freq = strtod(frequency, NULL);
1202 if (strncmp(s, "processor", 9) == 0) {
1209 snprintf(p_client_buffer, client_buffer_size, p_format,
1210 (float) freq / divisor);
1214 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
1216 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks something
1226 * Peter Tarjan (ptarjan@citromail.hu) */
1228 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
1229 char get_voltage(char *p_client_buffer, size_t client_buffer_size,
1230 const char *p_format, int divisor, unsigned int cpu)
1236 char current_freq_file[128];
1239 /* build the voltage file name */
1241 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1244 if (!p_client_buffer || client_buffer_size <= 0 || !p_format
1249 /* read the current cpu frequency from the /sys node */
1250 f = fopen(current_freq_file, "r");
1252 if (fgets(s, sizeof(s), f)) {
1253 s[strlen(s) - 1] = '\0';
1254 freq = strtod(s, NULL);
1258 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1259 perror("get_voltage()");
1266 snprintf(current_freq_file, 127, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu,
1269 /* use the current cpu frequency to find the corresponding voltage */
1270 f = fopen(current_freq_file, "r");
1276 if (fgets(line, 255, f) == NULL) {
1279 sscanf(line, "%d %d", &freq_comp, &voltage);
1280 if (freq_comp == freq) {
1286 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
1287 perror("get_voltage()");
1293 snprintf(p_client_buffer, client_buffer_size, p_format,
1294 (float) voltage / divisor);
1298 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1300 void get_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
1307 if (!p_client_buffer || client_buffer_size <= 0) {
1311 /* yeah, slow... :/ */
1312 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep)) {
1313 snprintf(p_client_buffer, client_buffer_size, "no fans?");
1317 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf);
1319 fp = open_file(buf2, &rep);
1321 snprintf(p_client_buffer, client_buffer_size,
1322 "can't open fan's state file");
1325 memset(buf, 0, sizeof(buf));
1326 fscanf(fp, "%*s %99s", buf);
1329 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1332 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1334 void get_acpi_ac_adapter(char *p_client_buffer, size_t client_buffer_size)
1341 if (!p_client_buffer || client_buffer_size <= 0) {
1345 /* yeah, slow... :/ */
1346 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep)) {
1347 snprintf(p_client_buffer, client_buffer_size, "no ac_adapters?");
1351 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf);
1353 fp = open_file(buf2, &rep);
1355 snprintf(p_client_buffer, client_buffer_size,
1356 "No ac adapter found.... where is it?");
1359 memset(buf, 0, sizeof(buf));
1360 fscanf(fp, "%*s %99s", buf);
1363 snprintf(p_client_buffer, client_buffer_size, "%s", buf);
1367 /proc/acpi/thermal_zone/THRM/cooling_mode
1368 cooling mode: active
1369 /proc/acpi/thermal_zone/THRM/polling_frequency
1371 /proc/acpi/thermal_zone/THRM/state
1373 /proc/acpi/thermal_zone/THRM/temperature
1375 /proc/acpi/thermal_zone/THRM/trip_points
1377 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1380 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1381 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1383 int open_acpi_temperature(const char *name)
1389 if (name == NULL || strcmp(name, "*") == 0) {
1392 if (!get_first_file_in_a_directory(ACPI_THERMAL_DIR, buf, &rep)) {
1398 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1400 fd = open(path, O_RDONLY);
1402 ERR("can't open '%s': %s", path, strerror(errno));
1408 static double last_acpi_temp;
1409 static double last_acpi_temp_time;
1411 double get_acpi_temperature(int fd)
1417 /* don't update acpi temperature too often */
1418 if (current_update_time - last_acpi_temp_time < 11.32) {
1419 return last_acpi_temp;
1421 last_acpi_temp_time = current_update_time;
1423 /* seek to beginning */
1424 lseek(fd, 0, SEEK_SET);
1431 n = read(fd, buf, 255);
1433 ERR("can't read fd %d: %s", fd, strerror(errno));
1436 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1440 return last_acpi_temp;
1444 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1446 design capacity: 4400 mAh
1447 last full capacity: 4064 mAh
1448 battery technology: rechargeable
1449 design voltage: 14800 mV
1450 design capacity warning: 300 mAh
1451 design capacity low: 200 mAh
1452 capacity granularity 1: 32 mAh
1453 capacity granularity 2: 32 mAh
1455 serial number: 16922
1461 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1464 charging state: unknown
1466 remaining capacity: 4064 mAh
1467 present voltage: 16608 mV
1471 2213<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1472 2213<@jupet�kellari��> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1473 2213<@jupet�kellari��> (-1 ollee ei akkua kiinni, koska akku on p�yd�ll�)
1474 2214<@jupet�kellari��> jupet@lagi-unstable:~$ cat /proc/apm
1475 2214<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1477 2238<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1478 2239<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1480 2240<@jupet�kellari��> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori p��ll�
1481 2241<@jupet�kellari��> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori p��ll� mutta ilman verkkovirtaa
1484 /* Kapil Hari Paranjape <kapil@imsc.res.in>
1485 Linux 2.6.24 onwards battery info is in
1486 /sys/class/power_supply/BAT0/
1487 On my system I get the following.
1488 /sys/class/power_supply/BAT0/uevent:
1489 PHYSDEVPATH=/devices/LNXSYSTM:00/device:00/PNP0A03:00/device:01/PNP0C09:00/PNP0C0A:00
1491 PHYSDEVDRIVER=battery
1492 POWER_SUPPLY_NAME=BAT0
1493 POWER_SUPPLY_TYPE=Battery
1494 POWER_SUPPLY_STATUS=Discharging
1495 POWER_SUPPLY_PRESENT=1
1496 POWER_SUPPLY_TECHNOLOGY=Li-ion
1497 POWER_SUPPLY_VOLTAGE_MIN_DESIGN=10800000
1498 POWER_SUPPLY_VOLTAGE_NOW=10780000
1499 POWER_SUPPLY_CURRENT_NOW=13970000
1500 POWER_SUPPLY_ENERGY_FULL_DESIGN=47510000
1501 POWER_SUPPLY_ENERGY_FULL=27370000
1502 POWER_SUPPLY_ENERGY_NOW=11810000
1503 POWER_SUPPLY_MODEL_NAME=IBM-92P1060
1504 POWER_SUPPLY_MANUFACTURER=Panasonic
1505 On some systems POWER_SUPPLY_ENERGY_* is replaced by POWER_SUPPLY_CHARGE_*
1508 #define SYSFS_BATTERY_BASE_PATH "/sys/class/power_supply"
1509 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1510 #define APM_PATH "/proc/apm"
1511 #define MAX_BATTERY_COUNT 4
1513 static FILE *sysfs_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1514 static FILE *acpi_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1515 static FILE *apm_bat_fp[MAX_BATTERY_COUNT] = { NULL, NULL, NULL, NULL };
1517 static int batteries_initialized = 0;
1518 static char batteries[MAX_BATTERY_COUNT][32];
1520 static int acpi_last_full[MAX_BATTERY_COUNT];
1521 static int acpi_design_capacity[MAX_BATTERY_COUNT];
1523 /* e.g. "charging 75%" */
1524 static char last_battery_str[MAX_BATTERY_COUNT][64];
1526 static char last_battery_time_str[MAX_BATTERY_COUNT][64];
1528 static double last_battery_time[MAX_BATTERY_COUNT];
1530 static int last_battery_perct[MAX_BATTERY_COUNT];
1531 static double last_battery_perct_time[MAX_BATTERY_COUNT];
1533 void init_batteries(void)
1537 if (batteries_initialized) {
1540 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1541 batteries[idx][0] = '\0';
1543 batteries_initialized = 1;
1546 int get_battery_idx(const char *bat)
1550 for (idx = 0; idx < MAX_BATTERY_COUNT; idx++) {
1551 if (!strlen(batteries[idx]) || !strcmp(batteries[idx], bat)) {
1556 /* if not found, enter a new entry */
1557 if (!strlen(batteries[idx])) {
1558 snprintf(batteries[idx], 31, "%s", bat);
1564 void set_return_value(char *buffer, unsigned int n, int item, int idx);
1566 void get_battery_stuff(char *buffer, unsigned int n, const char *bat, int item)
1568 static int idx, rep = 0, rep2 = 0;
1569 char acpi_path[128];
1570 char sysfs_path[128];
1572 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1573 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1577 idx = get_battery_idx(bat);
1579 /* don't update battery too often */
1580 if (current_update_time - last_battery_time[idx] < 29.5) {
1581 set_return_value(buffer, n, item, idx);
1585 last_battery_time[idx] = current_update_time;
1587 memset(last_battery_str[idx], 0, sizeof(last_battery_str[idx]));
1588 memset(last_battery_time_str[idx], 0, sizeof(last_battery_time_str[idx]));
1590 /* first try SYSFS if that fails try ACPI */
1592 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1593 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1597 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1598 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1601 if (sysfs_bat_fp[idx] != NULL) {
1603 int present_rate = -1;
1604 int remaining_capacity = -1;
1605 char charging_state[64];
1608 strcpy(charging_state, "unknown");
1610 while (!feof(sysfs_bat_fp[idx])) {
1612 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1615 /* let's just hope units are ok */
1616 if (strncmp (buf, "POWER_SUPPLY_PRESENT=1", 22) == 0)
1617 strcpy(present, "yes");
1618 else if (strncmp (buf, "POWER_SUPPLY_PRESENT=0", 22) == 0)
1619 strcpy(present, "no");
1620 else if (strncmp (buf, "POWER_SUPPLY_STATUS=", 20) == 0)
1621 sscanf(buf, "POWER_SUPPLY_STATUS=%63s", charging_state);
1622 /* present_rate is not the same as the
1623 current flowing now but it is the same value
1624 which was used in the past. so we continue
1626 else if (strncmp(buf, "POWER_SUPPLY_CURRENT_NOW=", 25) == 0)
1627 sscanf(buf, "POWER_SUPPLY_CURRENT_NOW=%d", &present_rate);
1628 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0)
1629 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1630 else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=", 25) == 0)
1631 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_last_full[idx]);
1632 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0)
1633 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1634 else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=", 25) == 0)
1635 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_last_full[idx]);
1638 fclose(sysfs_bat_fp[idx]);
1639 sysfs_bat_fp[idx] = NULL;
1641 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1642 if (remaining_capacity > acpi_last_full[idx])
1643 acpi_last_full[idx] = remaining_capacity; /* normalize to 100% */
1646 if (strcmp(present, "No") == 0) {
1647 strncpy(last_battery_str[idx], "not present", 64);
1650 else if (strcmp(charging_state, "Charging") == 0) {
1651 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1652 /* e.g. charging 75% */
1653 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %i%%",
1654 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1656 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1657 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1658 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1659 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "charging %d%%",
1660 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1661 snprintf(last_battery_time_str[idx],
1662 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1664 strncpy(last_battery_str[idx], "charging", sizeof(last_battery_str[idx])-1);
1665 snprintf(last_battery_time_str[idx],
1666 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1670 else if (strncmp(charging_state, "Discharging", 64) == 0) {
1671 if (present_rate > 0) {
1672 /* e.g. discharging 35% */
1673 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "discharging %i%%",
1674 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1676 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1677 (long) (((float) remaining_capacity / present_rate) * 3600));
1678 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1679 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "full");
1680 snprintf(last_battery_time_str[idx],
1681 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1683 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1685 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1686 snprintf(last_battery_time_str[idx],
1687 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1691 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1692 else if (strncmp(charging_state, "Charged", 64) == 0) {
1693 /* Below happens with the second battery on my X40,
1694 * when the second one is empty and the first one
1696 if (remaining_capacity == 0)
1697 strcpy(last_battery_str[idx], "empty");
1699 strcpy(last_battery_str[idx], "charged");
1701 /* unknown, probably full / AC */
1703 if (acpi_last_full[idx] != 0
1704 && remaining_capacity != acpi_last_full[idx])
1705 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1706 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1708 strncpy(last_battery_str[idx], "AC", 64);
1710 } else if (acpi_bat_fp[idx] != NULL) {
1712 int present_rate = -1;
1713 int remaining_capacity = -1;
1714 char charging_state[64];
1717 /* read last full capacity if it's zero */
1718 if (acpi_last_full[idx] == 0) {
1719 static int rep3 = 0;
1723 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1724 fp = open_file(path, &rep3);
1729 if (fgets(b, 256, fp) == NULL) {
1732 if (sscanf(b, "last full capacity: %d",
1733 &acpi_last_full[idx]) != 0) {
1742 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1744 strcpy(charging_state, "unknown");
1746 while (!feof(acpi_bat_fp[idx])) {
1749 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1753 /* let's just hope units are ok */
1754 if (strncmp(buf, "present:", 8) == 0) {
1755 sscanf(buf, "present: %4s", present);
1756 } else if (strncmp(buf, "charging state:", 15) == 0) {
1757 sscanf(buf, "charging state: %63s", charging_state);
1758 } else if (strncmp(buf, "present rate:", 13) == 0) {
1759 sscanf(buf, "present rate: %d", &present_rate);
1760 } else if (strncmp(buf, "remaining capacity:", 19) == 0) {
1761 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1764 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1765 if (remaining_capacity > acpi_last_full[idx]) {
1766 /* normalize to 100% */
1767 acpi_last_full[idx] = remaining_capacity;
1771 if (strcmp(present, "no") == 0) {
1772 strncpy(last_battery_str[idx], "not present", 64);
1774 } else if (strcmp(charging_state, "charging") == 0) {
1775 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1776 /* e.g. charging 75% */
1777 snprintf(last_battery_str[idx],
1778 sizeof(last_battery_str[idx]) - 1, "charging %i%%",
1779 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1781 format_seconds(last_battery_time_str[idx],
1782 sizeof(last_battery_time_str[idx]) - 1,
1783 (long) (((acpi_last_full[idx] - remaining_capacity) *
1784 3600) / present_rate));
1785 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1786 snprintf(last_battery_str[idx],
1787 sizeof(last_battery_str[idx]) - 1, "charging %d%%",
1788 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1789 snprintf(last_battery_time_str[idx],
1790 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1792 strncpy(last_battery_str[idx], "charging",
1793 sizeof(last_battery_str[idx]) - 1);
1794 snprintf(last_battery_time_str[idx],
1795 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1798 } else if (strncmp(charging_state, "discharging", 64) == 0) {
1799 if (present_rate > 0) {
1800 /* e.g. discharging 35% */
1801 snprintf(last_battery_str[idx],
1802 sizeof(last_battery_str[idx]) - 1, "discharging %i%%",
1803 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1805 format_seconds(last_battery_time_str[idx],
1806 sizeof(last_battery_time_str[idx]) - 1,
1807 (long) ((remaining_capacity * 3600) / present_rate));
1808 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1809 snprintf(last_battery_str[idx],
1810 sizeof(last_battery_str[idx]) - 1, "full");
1811 snprintf(last_battery_time_str[idx],
1812 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1814 snprintf(last_battery_str[idx],
1815 sizeof(last_battery_str[idx]) - 1, "discharging %d%%",
1816 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1817 snprintf(last_battery_time_str[idx],
1818 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1821 } else if (strncmp(charging_state, "charged", 64) == 0) {
1822 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1823 /* Below happens with the second battery on my X40,
1824 * when the second one is empty and the first one being charged. */
1825 if (remaining_capacity == 0) {
1826 strcpy(last_battery_str[idx], "empty");
1828 strcpy(last_battery_str[idx], "charged");
1830 /* unknown, probably full / AC */
1832 if (acpi_last_full[idx] != 0
1833 && remaining_capacity != acpi_last_full[idx]) {
1834 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1835 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1837 strncpy(last_battery_str[idx], "AC", 64);
1842 if (apm_bat_fp[idx] == NULL) {
1843 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1846 if (apm_bat_fp[idx] != NULL) {
1847 unsigned int ac, status, flag;
1850 fscanf(apm_bat_fp[idx], "%*s %*s %*x %x %x %x %d%%",
1851 &ac, &status, &flag, &life);
1854 /* could check now that there is ac */
1855 snprintf(last_battery_str[idx], 64, "AC");
1857 /* could check that status == 3 here? */
1858 } else if (ac && life != 100) {
1859 snprintf(last_battery_str[idx], 64, "charging %d%%", life);
1861 snprintf(last_battery_str[idx], 64, "%d%%", life);
1864 /* it seemed to buffer it so file must be closed (or could use
1865 * syscalls directly but I don't feel like coding it now) */
1866 fclose(apm_bat_fp[idx]);
1867 apm_bat_fp[idx] = NULL;
1870 set_return_value(buffer, n, item, idx);
1873 void set_return_value(char *buffer, unsigned int n, int item, int idx)
1876 case BATTERY_STATUS:
1877 snprintf(buffer, n, "%s", last_battery_str[idx]);
1880 snprintf(buffer, n, "%s", last_battery_time_str[idx]);
1887 int get_battery_perct(const char *bat)
1891 char acpi_path[128];
1892 char sysfs_path[128];
1893 int remaining_capacity = -1;
1895 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1896 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1900 idx = get_battery_idx(bat);
1902 /* don't update battery too often */
1903 if (current_update_time - last_battery_perct_time[idx] < 30) {
1904 return last_battery_perct[idx];
1906 last_battery_perct_time[idx] = current_update_time;
1908 /* Only check for SYSFS or ACPI */
1910 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1911 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1915 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1916 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1919 if (sysfs_bat_fp[idx] != NULL) {
1921 while (!feof(sysfs_bat_fp[idx])) {
1923 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1926 if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0) {
1927 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1928 } else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=",25) == 0) {
1929 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_design_capacity[idx]);
1930 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0) {
1931 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1932 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=",25) == 0) {
1933 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_design_capacity[idx]);
1937 fclose(sysfs_bat_fp[idx]);
1938 sysfs_bat_fp[idx] = NULL;
1940 } else if (acpi_bat_fp[idx] != NULL) {
1942 /* read last full capacity if it's zero */
1943 if (acpi_design_capacity[idx] == 0) {
1948 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1949 fp = open_file(path, &rep2);
1954 if (fgets(b, 256, fp) == NULL) {
1957 if (sscanf(b, "last full capacity: %d",
1958 &acpi_design_capacity[idx]) != 0) {
1966 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1968 while (!feof(acpi_bat_fp[idx])) {
1971 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1975 if (buf[0] == 'r') {
1976 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1980 if (remaining_capacity < 0) {
1983 /* compute the battery percentage */
1984 last_battery_perct[idx] =
1985 (int) (((float) remaining_capacity / acpi_design_capacity[idx]) * 100);
1986 return last_battery_perct[idx];
1989 int get_battery_perct_bar(const char *bar)
1993 get_battery_perct(bar);
1994 idx = get_battery_idx(bar);
1995 return (int) (last_battery_perct[idx] * 2.56 - 1);
1998 /* On Apple powerbook and ibook:
1999 $ cat /proc/pmu/battery_0
2006 $ cat /proc/pmu/info
2007 PMU driver version : 2
2008 PMU firmware version : 0c
2013 /* defines as in <linux/pmu.h> */
2014 #define PMU_BATT_PRESENT 0x00000001
2015 #define PMU_BATT_CHARGING 0x00000002
2017 static FILE *pmu_battery_fp;
2018 static FILE *pmu_info_fp;
2019 static char pb_battery_info[3][32];
2020 static double pb_battery_info_update;
2022 #define PMU_PATH "/proc/pmu"
2023 void get_powerbook_batt_info(char *buffer, size_t n, int i)
2026 const char *batt_path = PMU_PATH "/battery_0";
2027 const char *info_path = PMU_PATH "/info";
2029 int charge, max_charge, ac = -1;
2032 /* don't update battery too often */
2033 if (current_update_time - pb_battery_info_update < 29.5) {
2034 snprintf(buffer, n, "%s", pb_battery_info[i]);
2037 pb_battery_info_update = current_update_time;
2039 if (pmu_battery_fp == NULL) {
2040 pmu_battery_fp = open_file(batt_path, &rep);
2043 if (pmu_battery_fp != NULL) {
2044 rewind(pmu_battery_fp);
2045 while (!feof(pmu_battery_fp)) {
2048 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL) {
2052 if (buf[0] == 'f') {
2053 sscanf(buf, "flags : %8x", &flags);
2054 } else if (buf[0] == 'c' && buf[1] == 'h') {
2055 sscanf(buf, "charge : %d", &charge);
2056 } else if (buf[0] == 'm') {
2057 sscanf(buf, "max_charge : %d", &max_charge);
2058 } else if (buf[0] == 't') {
2059 sscanf(buf, "time rem. : %ld", &timeval);
2063 if (pmu_info_fp == NULL) {
2064 pmu_info_fp = open_file(info_path, &rep);
2067 if (pmu_info_fp != NULL) {
2068 rewind(pmu_info_fp);
2069 while (!feof(pmu_info_fp)) {
2072 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL) {
2075 if (buf[0] == 'A') {
2076 sscanf(buf, "AC Power : %d", &ac);
2080 /* update status string */
2081 if ((ac && !(flags & PMU_BATT_PRESENT))) {
2082 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
2083 } else if (ac && (flags & PMU_BATT_PRESENT)
2084 && !(flags & PMU_BATT_CHARGING)) {
2085 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
2086 } else if ((flags & PMU_BATT_PRESENT) && (flags & PMU_BATT_CHARGING)) {
2087 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
2089 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
2092 /* update percentage string */
2094 pb_battery_info[PB_BATT_PERCENT][0] = 0;
2096 snprintf(pb_battery_info[PB_BATT_PERCENT],
2097 sizeof(pb_battery_info[PB_BATT_PERCENT]), "%d%%",
2098 (charge * 100) / max_charge);
2101 /* update time string */
2102 if (timeval == 0) { /* fully charged or battery not present */
2103 pb_battery_info[PB_BATT_TIME][0] = 0;
2104 } else if (timeval < 60 * 60) { /* don't show secs */
2105 format_seconds_short(pb_battery_info[PB_BATT_TIME],
2106 sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2108 format_seconds(pb_battery_info[PB_BATT_TIME],
2109 sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2112 snprintf(buffer, n, "%s", pb_battery_info[i]);
2115 void update_top(void)
2117 show_nice_processes = 1;
2118 process_find_top(info.cpu, info.memu);
2119 info.first_process = get_first_process();
2122 /* Here come the IBM ACPI-specific things. For reference, see
2123 * http://ibm-acpi.sourceforge.net/README
2124 * If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
2140 * The content of these files is described in detail in the aforementioned
2141 * README - some of them also in the following functions accessing them.
2142 * Peter Tarjan (ptarjan@citromail.hu) */
2144 #define IBM_ACPI_DIR "/proc/acpi/ibm"
2146 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
2147 * /proc/acpi/ibm/fan looks like this (3 lines):
2150 commands: enable, disable
2151 * Peter Tarjan (ptarjan@citromail.hu) */
2153 void get_ibm_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
2156 unsigned int speed = 0;
2159 if (!p_client_buffer || client_buffer_size <= 0) {
2163 snprintf(fan, 127, "%s/fan", IBM_ACPI_DIR);
2165 fp = fopen(fan, "r");
2170 if (fgets(line, 255, fp) == NULL) {
2173 if (sscanf(line, "speed: %u", &speed)) {
2178 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2179 "ibm* from your Conky config file.", fan, strerror(errno));
2183 snprintf(p_client_buffer, client_buffer_size, "%d", speed);
2186 /* get the measured temperatures from the temperature sensors
2187 * on IBM/Lenovo laptops running the ibm acpi.
2188 * There are 8 values in /proc/acpi/ibm/thermal, and according to
2189 * http://ibm-acpi.sourceforge.net/README
2190 * these mean the following (at least on an IBM R51...)
2191 * 0: CPU (also on the T series laptops)
2192 * 1: Mini PCI Module (?)
2194 * 3: GPU (also on the T series laptops)
2199 * I'm not too sure about those with the question mark, but the values I'm
2200 * reading from *my* thermal file (on a T42p) look realistic for the
2201 * hdd and the battery.
2202 * #5 and #7 are always -128.
2203 * /proc/acpi/ibm/thermal looks like this (1 line):
2204 temperatures: 41 43 31 46 33 -128 29 -128
2205 * Peter Tarjan (ptarjan@citromail.hu) */
2207 static double last_ibm_acpi_temp_time;
2208 void get_ibm_acpi_temps(void)
2214 /* don't update too often */
2215 if (current_update_time - last_ibm_acpi_temp_time < 10.00) {
2218 last_ibm_acpi_temp_time = current_update_time;
2220 /* if (!p_client_buffer || client_buffer_size <= 0) {
2224 snprintf(thermal, 127, "%s/thermal", IBM_ACPI_DIR);
2225 fp = fopen(thermal, "r");
2231 if (fgets(line, 255, fp) == NULL) {
2234 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
2235 &ibm_acpi.temps[0], &ibm_acpi.temps[1], &ibm_acpi.temps[2],
2236 &ibm_acpi.temps[3], &ibm_acpi.temps[4], &ibm_acpi.temps[5],
2237 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) {
2242 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2243 "ibm* from your Conky config file.", thermal, strerror(errno));
2249 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
2250 * "Volume" here is none of the mixer volumes, but a "master of masters"
2251 * volume adjusted by the IBM volume keys.
2252 * /proc/acpi/ibm/fan looks like this (4 lines):
2255 commands: up, down, mute
2256 commands: level <level> (<level> is 0-15)
2257 * Peter Tarjan (ptarjan@citromail.hu) */
2259 void get_ibm_acpi_volume(char *p_client_buffer, size_t client_buffer_size)
2263 unsigned int vol = -1;
2266 if (!p_client_buffer || client_buffer_size <= 0) {
2270 snprintf(volume, 127, "%s/volume", IBM_ACPI_DIR);
2272 fp = fopen(volume, "r");
2276 unsigned int read_vol = -1;
2278 if (fgets(line, 255, fp) == NULL) {
2281 if (sscanf(line, "level: %u", &read_vol)) {
2285 if (sscanf(line, "mute: %s", mute)) {
2290 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2291 "ibm* from your Conky config file.", volume, strerror(errno));
2296 if (strcmp(mute, "on") == 0) {
2297 snprintf(p_client_buffer, client_buffer_size, "%s", "mute");
2300 snprintf(p_client_buffer, client_buffer_size, "%d", vol);
2305 /* static FILE *fp = NULL; */
2307 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
2308 * /proc/acpi/ibm/brightness looks like this (3 lines):
2311 commands: level <level> (<level> is 0-7)
2312 * Peter Tarjan (ptarjan@citromail.hu) */
2314 void get_ibm_acpi_brightness(char *p_client_buffer, size_t client_buffer_size)
2317 unsigned int brightness = 0;
2320 if (!p_client_buffer || client_buffer_size <= 0) {
2324 snprintf(filename, 127, "%s/brightness", IBM_ACPI_DIR);
2326 fp = fopen(filename, "r");
2331 if (fgets(line, 255, fp) == NULL) {
2334 if (sscanf(line, "level: %u", &brightness)) {
2339 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2340 "ibm* from your Conky config file.", filename, strerror(errno));
2345 snprintf(p_client_buffer, client_buffer_size, "%d", brightness);
2348 void update_entropy(void)
2351 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
2352 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
2355 info.entropy.entropy_avail = 0;
2356 info.entropy.poolsize = 0;
2358 if ((fp1 = open_file(entropy_avail, &rep)) == NULL) {
2362 if ((fp2 = open_file(entropy_poolsize, &rep)) == NULL) {
2367 fscanf(fp1, "%u", &info.entropy.entropy_avail);
2368 fscanf(fp2, "%u", &info.entropy.poolsize);
2373 info.mask |= (1 << INFO_ENTROPY);
2376 const char *get_disk_protect_queue(const char *disk)
2382 snprintf(path, 127, "/sys/block/%s/queue/protect", disk);
2383 if ((fp = fopen(path, "r")) == NULL)
2385 if (fscanf(fp, "%d\n", &state) != 1) {
2390 return state ? "frozen" : "free ";