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));
1617 snprintf(last_battery_time_str[idx],
1618 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1620 strncpy(last_battery_str[idx], "Charging", sizeof(last_battery_str[idx])-1);
1621 snprintf(last_battery_time_str[idx],
1622 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1626 else if (strncmp(charging_state, "Discharging", 64) == 0) {
1627 if (present_rate > 0) {
1628 /* e.g. discharging 35% */
1629 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "discharging %i%%",
1630 (int) (((float) remaining_capacity / acpi_last_full[idx]) * 100 ));
1632 format_seconds(last_battery_time_str[idx], sizeof(last_battery_time_str[idx])-1,
1633 (long) (((float)(acpi_last_full[idx] - remaining_capacity) / present_rate) * 3600));
1634 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1635 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1, "full");
1636 snprintf(last_battery_time_str[idx],
1637 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1639 snprintf(last_battery_str[idx], sizeof(last_battery_str[idx])-1,
1641 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1642 snprintf(last_battery_time_str[idx],
1643 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1647 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1648 else if (strncmp(charging_state, "Charged", 64) == 0) {
1649 /* Below happens with the second battery on my X40,
1650 * when the second one is empty and the first one
1652 if (remaining_capacity == 0)
1653 strcpy(last_battery_str[idx], "empty");
1655 strcpy(last_battery_str[idx], "charged");
1657 /* unknown, probably full / AC */
1659 if (acpi_last_full[idx] != 0
1660 && remaining_capacity != acpi_last_full[idx])
1661 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1662 (int) (((float)remaining_capacity / acpi_last_full[idx]) * 100));
1664 strncpy(last_battery_str[idx], "AC", 64);
1666 } else if (acpi_bat_fp[idx] != NULL) {
1668 int present_rate = -1;
1669 int remaining_capacity = -1;
1670 char charging_state[64];
1673 /* read last full capacity if it's zero */
1674 if (acpi_last_full[idx] == 0) {
1675 static int rep3 = 0;
1679 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1680 fp = open_file(path, &rep3);
1685 if (fgets(b, 256, fp) == NULL) {
1688 if (sscanf(b, "last full capacity: %d",
1689 &acpi_last_full[idx]) != 0) {
1698 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1700 strcpy(charging_state, "unknown");
1702 while (!feof(acpi_bat_fp[idx])) {
1705 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1709 /* let's just hope units are ok */
1710 if (strncmp(buf, "present:", 8) == 0) {
1711 sscanf(buf, "present: %4s", present);
1712 } else if (strncmp(buf, "charging state:", 15) == 0) {
1713 sscanf(buf, "charging state: %63s", charging_state);
1714 } else if (strncmp(buf, "present rate:", 13) == 0) {
1715 sscanf(buf, "present rate: %d", &present_rate);
1716 } else if (strncmp(buf, "remaining capacity:", 19) == 0) {
1717 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1720 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1721 if (remaining_capacity > acpi_last_full[idx]) {
1722 /* normalize to 100% */
1723 acpi_last_full[idx] = remaining_capacity;
1727 if (strcmp(present, "no") == 0) {
1728 strncpy(last_battery_str[idx], "not present", 64);
1730 } else if (strcmp(charging_state, "charging") == 0) {
1731 if (acpi_last_full[idx] != 0 && present_rate > 0) {
1732 /* e.g. charging 75% */
1733 snprintf(last_battery_str[idx],
1734 sizeof(last_battery_str[idx]) - 1, "charging %i%%",
1735 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1737 format_seconds(last_battery_time_str[idx],
1738 sizeof(last_battery_time_str[idx]) - 1,
1739 (long) (((acpi_last_full[idx] - remaining_capacity) *
1740 3600) / present_rate));
1741 } else if (acpi_last_full[idx] != 0 && present_rate <= 0) {
1742 snprintf(last_battery_str[idx],
1743 sizeof(last_battery_str[idx]) - 1, "charging %d%%",
1744 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1745 snprintf(last_battery_time_str[idx],
1746 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1748 strncpy(last_battery_str[idx], "charging",
1749 sizeof(last_battery_str[idx]) - 1);
1750 snprintf(last_battery_time_str[idx],
1751 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1754 } else if (strncmp(charging_state, "discharging", 64) == 0) {
1755 if (present_rate > 0) {
1756 /* e.g. discharging 35% */
1757 snprintf(last_battery_str[idx],
1758 sizeof(last_battery_str[idx]) - 1, "discharging %i%%",
1759 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1761 format_seconds(last_battery_time_str[idx],
1762 sizeof(last_battery_time_str[idx]) - 1,
1763 (long) ((remaining_capacity * 3600) / present_rate));
1764 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1765 snprintf(last_battery_str[idx],
1766 sizeof(last_battery_str[idx]) - 1, "full");
1767 snprintf(last_battery_time_str[idx],
1768 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1770 snprintf(last_battery_str[idx],
1771 sizeof(last_battery_str[idx]) - 1, "discharging %d%%",
1772 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1773 snprintf(last_battery_time_str[idx],
1774 sizeof(last_battery_time_str[idx]) - 1, "unknown");
1777 } else if (strncmp(charging_state, "charged", 64) == 0) {
1778 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1779 /* Below happens with the second battery on my X40,
1780 * when the second one is empty and the first one being charged. */
1781 if (remaining_capacity == 0) {
1782 strcpy(last_battery_str[idx], "empty");
1784 strcpy(last_battery_str[idx], "charged");
1786 /* unknown, probably full / AC */
1788 if (acpi_last_full[idx] != 0
1789 && remaining_capacity != acpi_last_full[idx]) {
1790 snprintf(last_battery_str[idx], 64, "unknown %d%%",
1791 (int) ((remaining_capacity * 100) / acpi_last_full[idx]));
1793 strncpy(last_battery_str[idx], "AC", 64);
1798 if (apm_bat_fp[idx] == NULL) {
1799 apm_bat_fp[idx] = open_file(APM_PATH, &rep2);
1802 if (apm_bat_fp[idx] != NULL) {
1803 unsigned int ac, status, flag;
1806 fscanf(apm_bat_fp[idx], "%*s %*s %*x %x %x %x %d%%",
1807 &ac, &status, &flag, &life);
1810 /* could check now that there is ac */
1811 snprintf(last_battery_str[idx], 64, "AC");
1813 /* could check that status == 3 here? */
1814 } else if (ac && life != 100) {
1815 snprintf(last_battery_str[idx], 64, "charging %d%%", life);
1817 snprintf(last_battery_str[idx], 64, "%d%%", life);
1820 /* it seemed to buffer it so file must be closed (or could use
1821 * syscalls directly but I don't feel like coding it now) */
1822 fclose(apm_bat_fp[idx]);
1823 apm_bat_fp[idx] = NULL;
1829 case BATTERY_STATUS:
1830 snprintf(buffer, n, "%s", last_battery_str[idx]);
1833 snprintf(buffer, n, "%s", last_battery_time_str[idx]);
1840 int get_battery_perct(const char *bat)
1844 char acpi_path[128];
1845 char sysfs_path[128];
1846 int remaining_capacity = -1;
1848 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1849 snprintf(sysfs_path, 127, SYSFS_BATTERY_BASE_PATH "/%s/uevent", bat);
1853 idx = get_battery_idx(bat);
1855 /* don't update battery too often */
1856 if (current_update_time - last_battery_perct_time[idx] < 30) {
1857 return last_battery_perct[idx];
1859 last_battery_perct_time[idx] = current_update_time;
1861 /* Only check for SYSFS or ACPI */
1863 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1864 sysfs_bat_fp[idx] = open_file(sysfs_path, &rep);
1868 if (sysfs_bat_fp[idx] == NULL && acpi_bat_fp[idx] == NULL && apm_bat_fp[idx] == NULL) {
1869 acpi_bat_fp[idx] = open_file(acpi_path, &rep);
1872 if (sysfs_bat_fp[idx] != NULL) {
1874 while (!feof(sysfs_bat_fp[idx])) {
1876 if (fgets(buf, 256, sysfs_bat_fp[idx]) == NULL)
1879 if (strncmp(buf, "POWER_SUPPLY_CHARGE_NOW=", 24) == 0) {
1880 sscanf(buf, "POWER_SUPPLY_CHARGE_NOW=%d", &remaining_capacity);
1881 } else if (strncmp(buf, "POWER_SUPPLY_CHARGE_FULL=",25) == 0) {
1882 sscanf(buf, "POWER_SUPPLY_CHARGE_FULL=%d", &acpi_design_capacity[idx]);
1883 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_NOW=", 24) == 0) {
1884 sscanf(buf, "POWER_SUPPLY_ENERGY_NOW=%d", &remaining_capacity);
1885 } else if (strncmp(buf, "POWER_SUPPLY_ENERGY_FULL=",25) == 0) {
1886 sscanf(buf, "POWER_SUPPLY_ENERGY_FULL=%d", &acpi_design_capacity[idx]);
1890 fclose(sysfs_bat_fp[idx]);
1891 sysfs_bat_fp[idx] = NULL;
1893 } else if (acpi_bat_fp[idx] != NULL) {
1895 /* read last full capacity if it's zero */
1896 if (acpi_design_capacity[idx] == 0) {
1901 snprintf(path, 127, ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1902 fp = open_file(path, &rep2);
1907 if (fgets(b, 256, fp) == NULL) {
1910 if (sscanf(b, "last full capacity: %d",
1911 &acpi_design_capacity[idx]) != 0) {
1919 fseek(acpi_bat_fp[idx], 0, SEEK_SET);
1921 while (!feof(acpi_bat_fp[idx])) {
1924 if (fgets(buf, 256, acpi_bat_fp[idx]) == NULL) {
1928 if (buf[0] == 'r') {
1929 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1933 if (remaining_capacity < 0) {
1936 /* compute the battery percentage */
1937 last_battery_perct[idx] =
1938 (int) (((float) remaining_capacity / acpi_design_capacity[idx]) * 100);
1939 return last_battery_perct[idx];
1942 int get_battery_perct_bar(const char *bar)
1946 get_battery_perct(bar);
1947 idx = get_battery_idx(bar);
1948 return (int) (last_battery_perct[idx] * 2.56 - 1);
1951 /* On Apple powerbook and ibook:
1952 $ cat /proc/pmu/battery_0
1959 $ cat /proc/pmu/info
1960 PMU driver version : 2
1961 PMU firmware version : 0c
1966 /* defines as in <linux/pmu.h> */
1967 #define PMU_BATT_PRESENT 0x00000001
1968 #define PMU_BATT_CHARGING 0x00000002
1970 static FILE *pmu_battery_fp;
1971 static FILE *pmu_info_fp;
1972 static char pb_battery_info[3][32];
1973 static double pb_battery_info_update;
1975 #define PMU_PATH "/proc/pmu"
1976 void get_powerbook_batt_info(char *buffer, size_t n, int i)
1979 const char *batt_path = PMU_PATH "/battery_0";
1980 const char *info_path = PMU_PATH "/info";
1982 int charge, max_charge, ac = -1;
1985 /* don't update battery too often */
1986 if (current_update_time - pb_battery_info_update < 29.5) {
1987 snprintf(buffer, n, "%s", pb_battery_info[i]);
1990 pb_battery_info_update = current_update_time;
1992 if (pmu_battery_fp == NULL) {
1993 pmu_battery_fp = open_file(batt_path, &rep);
1996 if (pmu_battery_fp != NULL) {
1997 rewind(pmu_battery_fp);
1998 while (!feof(pmu_battery_fp)) {
2001 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL) {
2005 if (buf[0] == 'f') {
2006 sscanf(buf, "flags : %8x", &flags);
2007 } else if (buf[0] == 'c' && buf[1] == 'h') {
2008 sscanf(buf, "charge : %d", &charge);
2009 } else if (buf[0] == 'm') {
2010 sscanf(buf, "max_charge : %d", &max_charge);
2011 } else if (buf[0] == 't') {
2012 sscanf(buf, "time rem. : %ld", &timeval);
2016 if (pmu_info_fp == NULL) {
2017 pmu_info_fp = open_file(info_path, &rep);
2020 if (pmu_info_fp != NULL) {
2021 rewind(pmu_info_fp);
2022 while (!feof(pmu_info_fp)) {
2025 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL) {
2028 if (buf[0] == 'A') {
2029 sscanf(buf, "AC Power : %d", &ac);
2033 /* update status string */
2034 if ((ac && !(flags & PMU_BATT_PRESENT))) {
2035 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
2036 } else if (ac && (flags & PMU_BATT_PRESENT)
2037 && !(flags & PMU_BATT_CHARGING)) {
2038 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
2039 } else if ((flags & PMU_BATT_PRESENT) && (flags & PMU_BATT_CHARGING)) {
2040 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
2042 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
2045 /* update percentage string */
2047 pb_battery_info[PB_BATT_PERCENT][0] = 0;
2049 snprintf(pb_battery_info[PB_BATT_PERCENT],
2050 sizeof(pb_battery_info[PB_BATT_PERCENT]), "%d%%",
2051 (charge * 100) / max_charge);
2054 /* update time string */
2055 if (timeval == 0) { /* fully charged or battery not present */
2056 pb_battery_info[PB_BATT_TIME][0] = 0;
2057 } else if (timeval < 60 * 60) { /* don't show secs */
2058 format_seconds_short(pb_battery_info[PB_BATT_TIME],
2059 sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2061 format_seconds(pb_battery_info[PB_BATT_TIME],
2062 sizeof(pb_battery_info[PB_BATT_TIME]), timeval);
2065 snprintf(buffer, n, "%s", pb_battery_info[i]);
2068 void update_top(void)
2070 show_nice_processes = 1;
2071 process_find_top(info.cpu, info.memu);
2072 info.first_process = get_first_process();
2075 /* The following ifdefs were adapted from gkrellm */
2076 #include <linux/major.h>
2078 #if !defined(MD_MAJOR)
2082 #if !defined(LVM_BLK_MAJOR)
2083 #define LVM_BLK_MAJOR 58
2086 #if !defined(NBD_MAJOR)
2087 #define NBD_MAJOR 43
2090 void update_diskio(void)
2092 static unsigned int last = UINT_MAX;
2093 static unsigned int last_read = UINT_MAX;
2094 static unsigned int last_write = UINT_MAX;
2098 char buf[512], devbuf[64];
2100 unsigned int major, minor;
2101 unsigned int current = 0;
2102 unsigned int current_read = 0;
2103 unsigned int current_write = 0;
2104 unsigned int reads, writes = 0;
2106 int tot, tot_read, tot_write;
2108 if (!(fp = open_file("/proc/diskstats", &rep))) {
2113 /* read reads and writes from all disks (minor = 0), including cd-roms
2114 * and floppies, and sum them up */
2116 fgets(buf, 512, fp);
2117 col_count = sscanf(buf, "%u %u %s %*u %*u %u %*u %*u %*u %u", &major,
2118 &minor, devbuf, &reads, &writes);
2119 /* ignore subdevices (they have only 3 matching entries in their line)
2120 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
2122 * XXX: ignore devices which are part of a SW RAID (MD_MAJOR) */
2123 if (col_count == 5 && major != LVM_BLK_MAJOR && major != NBD_MAJOR
2124 && major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
2125 current += reads + writes;
2126 current_read += reads;
2127 current_write += writes;
2129 col_count = sscanf(buf, "%u %u %s %*u %u %*u %u",
2130 &major, &minor, devbuf, &reads, &writes);
2131 if (col_count != 5) {
2135 for (i = 0; i < MAX_DISKIO_STATS; i++) {
2136 if (diskio_stats[i].dev &&
2137 strncmp(devbuf, diskio_stats[i].dev, text_buffer_size) == 0) {
2138 diskio_stats[i].current =
2139 (reads + writes - diskio_stats[i].last) / 2;
2140 diskio_stats[i].current_read =
2141 (reads - diskio_stats[i].last_read) / 2;
2142 diskio_stats[i].current_write =
2143 (writes - diskio_stats[i].last_write) / 2;
2144 if (reads + writes < diskio_stats[i].last) {
2145 diskio_stats[i].current = 0;
2147 if (reads < diskio_stats[i].last_read) {
2148 diskio_stats[i].current_read = 0;
2149 diskio_stats[i].current = diskio_stats[i].current_write;
2151 if (writes < diskio_stats[i].last_write) {
2152 diskio_stats[i].current_write = 0;
2153 diskio_stats[i].current = diskio_stats[i].current_read;
2155 diskio_stats[i].last = reads + writes;
2156 diskio_stats[i].last_read = reads;
2157 diskio_stats[i].last_write = writes;
2162 /* since the values in /proc/diststats are absolute, we have to substract
2163 * our last reading. The numbers stand for "sectors read", and we therefore
2164 * have to divide by two to get KB */
2165 tot = ((double) (current - last) / 2);
2166 tot_read = ((double) (current_read - last_read) / 2);
2167 tot_write = ((double) (current_write - last_write) / 2);
2169 if (last_read > current_read) {
2172 if (last_write > current_write) {
2176 if (last > current) {
2177 /* we hit this either if it's the very first time we run this, or
2178 * when /proc/diskstats overflows; while 0 is not correct, it's at
2179 * least not way off */
2183 last_read = current_read;
2184 last_write = current_write;
2187 diskio_read_value = tot_read;
2188 diskio_write_value = tot_write;
2193 /* Here come the IBM ACPI-specific things. For reference, see
2194 * http://ibm-acpi.sourceforge.net/README
2195 * If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
2211 * The content of these files is described in detail in the aforementioned
2212 * README - some of them also in the following functions accessing them.
2213 * Peter Tarjan (ptarjan@citromail.hu) */
2215 #define IBM_ACPI_DIR "/proc/acpi/ibm"
2217 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
2218 * /proc/acpi/ibm/fan looks like this (3 lines):
2221 commands: enable, disable
2222 * Peter Tarjan (ptarjan@citromail.hu) */
2224 void get_ibm_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
2227 unsigned int speed = 0;
2230 if (!p_client_buffer || client_buffer_size <= 0) {
2234 snprintf(fan, 127, "%s/fan", IBM_ACPI_DIR);
2236 fp = fopen(fan, "r");
2241 if (fgets(line, 255, fp) == NULL) {
2244 if (sscanf(line, "speed: %u", &speed)) {
2249 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2250 "ibm* from your Conky config file.", fan, strerror(errno));
2254 snprintf(p_client_buffer, client_buffer_size, "%d", speed);
2257 /* get the measured temperatures from the temperature sensors
2258 * on IBM/Lenovo laptops running the ibm acpi.
2259 * There are 8 values in /proc/acpi/ibm/thermal, and according to
2260 * http://ibm-acpi.sourceforge.net/README
2261 * these mean the following (at least on an IBM R51...)
2262 * 0: CPU (also on the T series laptops)
2263 * 1: Mini PCI Module (?)
2265 * 3: GPU (also on the T series laptops)
2270 * I'm not too sure about those with the question mark, but the values I'm
2271 * reading from *my* thermal file (on a T42p) look realistic for the
2272 * hdd and the battery.
2273 * #5 and #7 are always -128.
2274 * /proc/acpi/ibm/thermal looks like this (1 line):
2275 temperatures: 41 43 31 46 33 -128 29 -128
2276 * Peter Tarjan (ptarjan@citromail.hu) */
2278 static double last_ibm_acpi_temp_time;
2279 void get_ibm_acpi_temps(void)
2285 /* don't update too often */
2286 if (current_update_time - last_ibm_acpi_temp_time < 10.00) {
2289 last_ibm_acpi_temp_time = current_update_time;
2291 /* if (!p_client_buffer || client_buffer_size <= 0) {
2295 snprintf(thermal, 127, "%s/thermal", IBM_ACPI_DIR);
2296 fp = fopen(thermal, "r");
2302 if (fgets(line, 255, fp) == NULL) {
2305 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
2306 &ibm_acpi.temps[0], &ibm_acpi.temps[1], &ibm_acpi.temps[2],
2307 &ibm_acpi.temps[3], &ibm_acpi.temps[4], &ibm_acpi.temps[5],
2308 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) {
2313 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2314 "ibm* from your Conky config file.", thermal, strerror(errno));
2320 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
2321 * "Volume" here is none of the mixer volumes, but a "master of masters"
2322 * volume adjusted by the IBM volume keys.
2323 * /proc/acpi/ibm/fan looks like this (4 lines):
2326 commands: up, down, mute
2327 commands: level <level> (<level> is 0-15)
2328 * Peter Tarjan (ptarjan@citromail.hu) */
2330 void get_ibm_acpi_volume(char *p_client_buffer, size_t client_buffer_size)
2334 unsigned int vol = -1;
2337 if (!p_client_buffer || client_buffer_size <= 0) {
2341 snprintf(volume, 127, "%s/volume", IBM_ACPI_DIR);
2343 fp = fopen(volume, "r");
2347 unsigned int read_vol = -1;
2349 if (fgets(line, 255, fp) == NULL) {
2352 if (sscanf(line, "level: %u", &read_vol)) {
2356 if (sscanf(line, "mute: %s", mute)) {
2361 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2362 "ibm* from your Conky config file.", volume, strerror(errno));
2367 if (strcmp(mute, "on") == 0) {
2368 snprintf(p_client_buffer, client_buffer_size, "%s", "mute");
2371 snprintf(p_client_buffer, client_buffer_size, "%d", vol);
2376 /* static FILE *fp = NULL; */
2378 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
2379 * /proc/acpi/ibm/brightness looks like this (3 lines):
2382 commands: level <level> (<level> is 0-7)
2383 * Peter Tarjan (ptarjan@citromail.hu) */
2385 void get_ibm_acpi_brightness(char *p_client_buffer, size_t client_buffer_size)
2388 unsigned int brightness = 0;
2391 if (!p_client_buffer || client_buffer_size <= 0) {
2395 snprintf(filename, 127, "%s/brightness", IBM_ACPI_DIR);
2397 fp = fopen(filename, "r");
2402 if (fgets(line, 255, fp) == NULL) {
2405 if (sscanf(line, "level: %u", &brightness)) {
2410 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove "
2411 "ibm* from your Conky config file.", filename, strerror(errno));
2416 snprintf(p_client_buffer, client_buffer_size, "%d", brightness);
2419 void update_entropy(void)
2422 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
2423 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
2426 info.entropy.entropy_avail = 0;
2427 info.entropy.poolsize = 0;
2429 if ((fp1 = open_file(entropy_avail, &rep)) == NULL) {
2433 if ((fp2 = open_file(entropy_poolsize, &rep)) == NULL) {
2438 fscanf(fp1, "%u", &info.entropy.entropy_avail);
2439 fscanf(fp2, "%u", &info.entropy.poolsize);
2444 info.mask |= (1 << INFO_ENTROPY);
2447 const char *get_disk_protect_queue(const char *disk)
2453 snprintf(path, 127, "/sys/block/%s/queue/protect", disk);
2454 if ((fp = fopen(path, "r")) == NULL)
2456 if (fscanf(fp, "%d\n", &state) != 1) {
2461 return state ? "frozen" : "free ";