2 * Contains linux specific code
16 #include <sys/types.h>
17 #include <sys/sysinfo.h>
21 // #include <assert.h>
25 #include <sys/ioctl.h>
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <linux/sockios.h>
33 static struct sysinfo s_info;
35 static int show_nice_processes;
41 static void update_sysinfo()
45 info.uptime = (double) s_info.uptime;
47 /* there was some problem with these */
49 // info.loadavg[0] = s_info.loads[0] / 100000.0f;
50 info.loadavg[1] = s_info.loads[1] / 100000.0f;
51 info.loadavg[2] = s_info.loads[2] / 100000.0f;
52 gkrelltop_process_find_top_three info.mask |= 1 << INFO_LOADAVG;
55 info.procs = s_info.procs;
57 /* these aren't nice, no cache and should check kernel version for mem_unit */
59 info.memmax = s_info.totalram;
60 info.mem = s_info.totalram - s_info.freeram;
61 info.swapmax = s_info.totalswap;
62 info.swap = s_info.totalswap - s_info.swap;
63 info.mask |= 1 << INFO_MEM;
66 info.mask |= (1 << INFO_UPTIME) | (1 << INFO_PROCS);
71 /* prefers sysinfo() for uptime, I don't really know which one is better
73 #ifdef USE_PROC_UPTIME
75 FILE *fp = open_file("/proc/uptime", &rep);
78 fscanf(fp, "%lf", &info.uptime);
81 info.mask |= (1 << INFO_UPTIME);
87 /* these things are also in sysinfo except Buffers:, that's why I'm reading
90 static FILE *meminfo_fp;
98 info.mem = info.memmax = info.swap = info.swapmax = info.bufmem =
99 info.buffers = info.cached = 0;
101 if (meminfo_fp == NULL)
102 meminfo_fp = open_file("/proc/meminfo", &rep);
104 fseek(meminfo_fp, 0, SEEK_SET);
105 if (meminfo_fp == NULL)
108 while (!feof(meminfo_fp)) {
109 if (fgets(buf, 255, meminfo_fp) == NULL)
112 if (strncmp(buf, "MemTotal:", 9) == 0) {
113 sscanf(buf, "%*s %u", &info.memmax);
114 } else if (strncmp(buf, "MemFree:", 8) == 0) {
115 sscanf(buf, "%*s %u", &info.mem);
116 } else if (strncmp(buf, "SwapTotal:", 10) == 0) {
117 sscanf(buf, "%*s %u", &info.swapmax);
118 } else if (strncmp(buf, "SwapFree:", 9) == 0) {
119 sscanf(buf, "%*s %u", &info.swap);
120 } else if (strncmp(buf, "Buffers:", 8) == 0) {
121 sscanf(buf, "%*s %u", &info.buffers);
122 } else if (strncmp(buf, "Cached:", 7) == 0) {
123 sscanf(buf, "%*s %u", &info.cached);
127 info.mem = info.memmax - info.mem;
128 info.swap = info.swapmax - info.swap;
130 info.bufmem = info.cached + info.buffers;
132 info.mask |= (1 << INFO_MEM) | (1 << INFO_BUFFERS);
135 static FILE *net_dev_fp;
136 static FILE *net_wireless_fp;
138 inline void update_net_stats()
141 // FIXME: arbitrary size chosen to keep code simple.
143 unsigned int curtmp1, curtmp2;
152 delta = current_update_time - last_update_time;
156 /* open file and ignore first two lines */
157 if (net_dev_fp == NULL)
158 net_dev_fp = open_file("/proc/net/dev", &rep);
160 fseek(net_dev_fp, 0, SEEK_SET);
164 fgets(buf, 255, net_dev_fp); /* garbage */
165 fgets(buf, 255, net_dev_fp); /* garbage (field names) */
167 /* read each interface */
168 for (i2 = 0; i2 < 16; i2++) {
171 long long r, t, last_recv, last_trans;
173 if (fgets(buf, 255, net_dev_fp) == NULL)
176 while (isspace((int) *p))
181 while (*p && *p != ':')
188 ns = get_net_stat(s);
190 last_recv = ns->recv;
191 last_trans = ns->trans;
194 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
195 "%Ld %*d %*d %*d %*d %*d %*d %*d %Ld",
198 /* if recv or trans is less than last time, an overflow happened */
200 if (r < ns->last_read_recv)
202 ((long long) 4294967295U -
203 ns->last_read_recv) + r;
205 ns->recv += (r - ns->last_read_recv);
206 ns->last_read_recv = r;
208 if (t < ns->last_read_trans)
210 ((long long) 4294967295U -
211 ns->last_read_trans) + t;
213 ns->trans += (t - ns->last_read_trans);
214 ns->last_read_trans = t;
216 /*** ip addr patch ***/
217 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
219 conf.ifc_buf = malloc(sizeof(struct ifreq) * 16);
221 conf.ifc_len = sizeof(struct ifreq) * 16;
223 ioctl((long) i, SIOCGIFCONF, &conf);
225 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
227 ns = get_net_stat(((struct ifreq *) conf.
228 ifc_buf)[k].ifr_ifrn.ifrn_name);
230 ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.
239 /*** end ip addr patch ***/
242 /* calculate speeds */
243 ns->net_rec[0] = (ns->recv - last_recv) / delta;
244 ns->net_trans[0] = (ns->trans - last_trans) / delta;
248 for (i = 0; (unsigned) i < info.net_avg_samples; i++) {
249 curtmp1 += ns->net_rec[i];
250 curtmp2 += ns->net_trans[i];
252 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
253 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
254 if (info.net_avg_samples > 1) {
255 for (i = info.net_avg_samples; i > 1; i--) {
256 ns->net_rec[i - 1] = ns->net_rec[i - 2];
257 ns->net_trans[i - 1] =
258 ns->net_trans[i - 2];
266 /* fclose(net_dev_fp); net_dev_fp = NULL; */
269 inline void update_wifi_stats()
271 /** wireless stats patch by Bobby Beckmann **/
275 /*open file and ignore first two lines sorry, this code sucks ass right now, i'll clean it up later */
276 if (net_wireless_fp == NULL)
277 net_wireless_fp = open_file("/proc/net/wireless", &rep);
279 fseek(net_wireless_fp, 0, SEEK_SET);
280 if (net_wireless_fp == NULL)
283 fgets(buf, 255, net_wireless_fp); /* garbage */
284 fgets(buf, 255, net_wireless_fp); /* garbage (field names) */
286 /* read each interface */
287 for (i = 0; i < 16; i++) {
292 if (fgets(buf, 255, net_wireless_fp) == NULL)
295 while (isspace((int) *p))
300 while (*p && *p != ':')
307 ns = get_net_stat(s);
309 sscanf(p, "%*d %d. %d. %d", &l, &m, &n);
311 ns->linkstatus = (int) (log(l) / log(92) * 100);
314 /*** end wireless patch ***/
319 void update_total_processes()
324 static unsigned int cpu_user, cpu_system, cpu_nice;
325 static double last_cpu_sum;
326 static int clock_ticks;
328 static FILE *stat_fp;
330 inline static void update_stat()
332 // FIXME: arbitrary size?
333 static double cpu_val[15];
340 stat_fp = open_file("/proc/stat", &rep);
342 fseek(stat_fp, 0, SEEK_SET);
348 while (!feof(stat_fp)) {
349 if (fgets(buf, 255, stat_fp) == NULL)
352 if (strncmp(buf, "procs_running ", 14) == 0) {
353 sscanf(buf, "%*s %d", &info.run_procs);
354 info.mask |= (1 << INFO_RUN_PROCS);
355 } else if (strncmp(buf, "cpu ", 4) == 0) {
356 sscanf(buf, "%*s %u %u %u", &cpu_user, &cpu_nice,
358 info.mask |= (1 << INFO_CPU);
359 } else if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
366 delta = current_update_time - last_update_time;
370 if (clock_ticks == 0)
371 clock_ticks = sysconf(_SC_CLK_TCK);
374 (cpu_user + cpu_nice + cpu_system -
375 last_cpu_sum) / delta / (double) clock_ticks /
377 for (i = 0; i < info.cpu_avg_samples; i++)
378 curtmp += cpu_val[i];
379 info.cpu_usage = curtmp / info.cpu_avg_samples;
380 last_cpu_sum = cpu_user + cpu_nice + cpu_system;
381 for (i = info.cpu_avg_samples; i > 1; i--)
382 cpu_val[i - 1] = cpu_val[i - 2];
387 // this is for getting proc shit
399 void update_running_processes()
404 void update_cpu_usage()
409 void update_load_average()
411 #ifdef HAVE_GETLOADAVG
414 info.loadavg[0] = (float) v[0];
415 info.loadavg[1] = (float) v[1];
416 info.loadavg[2] = (float) v[2];
421 fp = open_file("/proc/loadavg", &rep);
423 v[0] = v[1] = v[2] = 0.0;
427 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1],
435 static int no_dots(const struct dirent *d)
437 if (d->d_name[0] == '.')
443 get_first_file_in_a_directory(const char *dir, char *s, int *rep)
445 struct dirent **namelist;
448 n = scandir(dir, &namelist, no_dots, alphasort);
451 ERR("scandir for %s: %s", dir, strerror(errno));
460 strncpy(s, namelist[0]->d_name, 255);
463 for (i = 0; i < n; i++)
471 #define I2C_DIR "/sys/bus/i2c/devices/"
474 open_i2c_sensor(const char *dev, const char *type, int n, int *div,
482 /* if i2c device is NULL or *, get first */
483 if (dev == NULL || strcmp(dev, "*") == 0) {
485 if (!get_first_file_in_a_directory(I2C_DIR, buf, &rep))
490 /* change vol to in */
491 if (strcmp(type, "vol") == 0)
494 if (strcmp(type, "tempf") == 0) {
495 snprintf(path, 255, I2C_DIR "%s/%s%d_input", dev, "temp",
498 snprintf(path, 255, I2C_DIR "%s/%s%d_input", dev, type, n);
500 strcpy(devtype, path);
503 fd = open(path, O_RDONLY);
505 CRIT_ERR("can't open '%s': %s\nplease fix i2c or remove it from Conky", path, strerror(errno));
508 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
509 || strcmp(type, "tempf") == 0)
513 /* fan does not use *_div as a read divisor */
514 if (strcmp("fan", type) == 0)
517 /* test if *_div file exist, open it and use it as divisor */
518 if (strcmp(type, "tempf") == 0) {
519 snprintf(path, 255, I2C_DIR "%s/%s%d_div", "one", "two",
522 snprintf(path, 255, I2C_DIR "%s/%s%d_div", dev, type, n);
525 divfd = open(path, O_RDONLY);
530 divn = read(divfd, divbuf, 63);
531 /* should read until n == 0 but I doubt that kernel will give these
532 * in multiple pieces. :) */
542 double get_i2c_info(int *fd, int div, char *devtype, char *type)
549 lseek(*fd, 0, SEEK_SET);
555 n = read(*fd, buf, 63);
556 /* should read until n == 0 but I doubt that kernel will give these
557 * in multiple pieces. :) */
564 *fd = open(devtype, O_RDONLY);
566 ERR("can't open '%s': %s", devtype, strerror(errno));
568 /* My dirty hack for computing CPU value
569 * Filedil, from forums.gentoo.org
571 /* if (strstr(devtype, "temp1_input") != NULL)
572 return -15.096+1.4893*(val / 1000.0); */
575 /* divide voltage and temperature by 1000 */
576 /* or if any other divisor is given, use that */
577 if (strcmp(type, "tempf") == 0) {
579 return ((val / div + 40) * 9.0 / 5) - 40;
581 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
583 return ((val + 40) * 9.0 / 5) - 40;
594 #define ADT746X_FAN "/sys/devices/temperatures/cpu_fan_speed"
596 static char *adt746x_fan_state;
598 char *get_adt746x_fan()
603 if (adt746x_fan_state == NULL) {
604 adt746x_fan_state = (char *) malloc(100);
605 assert(adt746x_fan_state != NULL);
608 fp = open_file(ADT746X_FAN, &rep);
610 strcpy(adt746x_fan_state,
611 "No fan found! Hey, you don't have one?");
612 return adt746x_fan_state;
614 fscanf(fp, "%s", adt746x_fan_state);
617 return adt746x_fan_state;
620 #define ADT746X_CPU "/sys/devices/temperatures/cpu_temperature"
622 static char *adt746x_cpu_state;
624 char *get_adt746x_cpu()
629 if (adt746x_cpu_state == NULL) {
630 adt746x_cpu_state = (char *) malloc(100);
631 assert(adt746x_cpu_state != NULL);
634 fp = open_file(ADT746X_CPU, &rep);
635 fscanf(fp, "%2s", adt746x_cpu_state);
638 return adt746x_cpu_state;
641 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
643 /***********************************************************************/
645 * This file is part of x86info.
646 * (C) 2001 Dave Jones.
648 * Licensed under the terms of the GNU GPL License version 2.
650 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
651 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz>
654 #if defined(__i386) || defined(__x86_64)
655 __inline__ unsigned long long int rdtsc()
657 unsigned long long int x;
658 __asm__ volatile (".byte 0x0f, 0x31":"=A" (x));
661 static char *buffer = NULL;
663 static char *frequency;
668 #if defined(__i386) || defined(__x86_64)
672 struct timeval tvstart, tvstop;
673 unsigned long long cycles[2]; /* gotta be 64 bit */
674 unsigned int microseconds; /* total time taken */
676 memset(&tz, 0, sizeof(tz));
678 /* get this function in cached memory */
679 gettimeofday(&tvstart, &tz);
681 gettimeofday(&tvstart, &tz);
683 /* we don't trust that this is any specific length of time */
686 gettimeofday(&tvstop, &tz);
687 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
688 (tvstop.tv_usec - tvstart.tv_usec);
690 sprintf(buffer, "%lld", (cycles[1] - cycles[0]) / microseconds);
696 if (frequency == NULL) {
697 frequency = (char *) malloc(100);
698 assert(frequency != NULL);
700 //char frequency[10];
701 f = fopen("/proc/cpuinfo", "r"); //open the CPU information file
704 while (fgets(s, 1000, f) != NULL){ //read the file
705 if (strncmp(s, "clock", 5) == 0) { //and search for the cpu mhz
706 //printf("%s", strchr(s, ':')+2);
707 strcpy(frequency, strchr(s, ':') + 2); //copy just the number
708 frequency[strlen(frequency) - 1] = '\0'; // strip \n
713 //printf("%s\n", frequency);
719 #define ACPI_FAN_DIR "/proc/acpi/fan/"
721 static char *acpi_fan_state;
730 if (acpi_fan_state == NULL) {
731 acpi_fan_state = (char *) malloc(100);
732 assert(acpi_fan_state != NULL);
735 /* yeah, slow... :/ */
736 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep))
739 snprintf(buf2, 256, "%s%s/state", ACPI_FAN_DIR, buf);
741 fp = open_file(buf2, &rep);
743 strcpy(acpi_fan_state, "can't open fan's state file");
744 return acpi_fan_state;
746 fscanf(fp, "%*s %99s", acpi_fan_state);
748 return acpi_fan_state;
751 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
753 static char *acpi_ac_adapter_state;
755 char *get_acpi_ac_adapter()
762 if (acpi_ac_adapter_state == NULL) {
763 acpi_ac_adapter_state = (char *) malloc(100);
764 assert(acpi_ac_adapter_state != NULL);
767 /* yeah, slow... :/ */
768 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep))
769 return "no ac_adapters?";
771 snprintf(buf2, 256, "%s%s/state", ACPI_AC_ADAPTER_DIR, buf);
773 fp = open_file(buf2, &rep);
775 strcpy(acpi_ac_adapter_state,
776 "No ac adapter found.... where is it?");
777 return acpi_ac_adapter_state;
779 fscanf(fp, "%*s %99s", acpi_ac_adapter_state);
782 return acpi_ac_adapter_state;
786 /proc/acpi/thermal_zone/THRM/cooling_mode
788 /proc/acpi/thermal_zone/THRM/polling_frequency
790 /proc/acpi/thermal_zone/THRM/state
792 /proc/acpi/thermal_zone/THRM/temperature
794 /proc/acpi/thermal_zone/THRM/trip_points
796 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
799 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
800 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
802 int open_acpi_temperature(const char *name)
808 if (name == NULL || strcmp(name, "*") == 0) {
810 if (!get_first_file_in_a_directory
811 (ACPI_THERMAL_DIR, buf, &rep))
816 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
818 fd = open(path, O_RDONLY);
820 ERR("can't open '%s': %s", path, strerror(errno));
825 static double last_acpi_temp;
826 static double last_acpi_temp_time;
828 double get_acpi_temperature(int fd)
833 /* don't update acpi temperature too often */
834 if (current_update_time - last_acpi_temp_time < 11.32) {
835 return last_acpi_temp;
837 last_acpi_temp_time = current_update_time;
839 /* seek to beginning */
840 lseek(fd, 0, SEEK_SET);
846 n = read(fd, buf, 255);
848 ERR("can't read fd %d: %s", fd, strerror(errno));
851 sscanf(buf, "temperature: %lf", &last_acpi_temp);
855 return last_acpi_temp;
859 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
861 design capacity: 4400 mAh
862 last full capacity: 4064 mAh
863 battery technology: rechargeable
864 design voltage: 14800 mV
865 design capacity warning: 300 mAh
866 design capacity low: 200 mAh
867 capacity granularity 1: 32 mAh
868 capacity granularity 2: 32 mAh
876 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
879 charging state: unknown
881 remaining capacity: 4064 mAh
882 present voltage: 16608 mV
886 2213<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
887 2213<@jupet kellari ö> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
888 2213<@jupet kellari ö> (-1 ollee ei akkua kiinni, koska akku on pöydällä)
889 2214<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
890 2214<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
892 2238<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
893 2239<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
895 2240<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori päällä
896 2241<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori päällä mutta ilman verkkovirtaa
899 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
900 #define APM_PATH "/proc/apm"
902 static FILE *acpi_bat_fp;
903 static FILE *apm_bat_fp;
905 static int acpi_last_full;
907 static char last_battery_str[64];
909 static double last_battery_time;
911 void get_battery_stuff(char *buf, unsigned int n, const char *bat)
913 static int rep, rep2;
915 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
917 /* don't update battery too often */
918 if (current_update_time - last_battery_time < 29.5) {
919 snprintf(buf, n, "%s", last_battery_str);
922 last_battery_time = current_update_time;
926 if (acpi_bat_fp == NULL && apm_bat_fp == NULL)
927 acpi_bat_fp = open_file(acpi_path, &rep);
929 if (acpi_bat_fp != NULL) {
930 int present_rate = -1;
931 int remaining_capacity = -1;
932 char charging_state[64];
934 /* read last full capacity if it's zero */
935 if (acpi_last_full == 0) {
940 ACPI_BATTERY_BASE_PATH "/%s/info", bat);
941 fp = open_file(path, &rep);
945 if (fgets(b, 256, fp) == NULL)
949 (b, "last full capacity: %d",
950 &acpi_last_full) != 0)
958 fseek(acpi_bat_fp, 0, SEEK_SET);
960 strcpy(charging_state, "unknown");
962 while (!feof(acpi_bat_fp)) {
964 if (fgets(buf, 256, acpi_bat_fp) == NULL)
967 /* let's just hope units are ok */
969 sscanf(buf, "charging state: %63s",
971 else if (buf[0] == 'p')
972 sscanf(buf, "present rate: %d",
974 else if (buf[0] == 'r')
975 sscanf(buf, "remaining capacity: %d",
976 &remaining_capacity);
980 if (strcmp(charging_state, "charging") == 0) {
981 if (acpi_last_full != 0 && present_rate > 0) {
982 strcpy(last_battery_str, "charging ");
983 format_seconds(last_battery_str + 9,
986 remaining_capacity) * 60 *
988 } else if (acpi_last_full != 0
989 && present_rate <= 0) {
990 sprintf(last_battery_str, "charging %d%%",
991 remaining_capacity * 100 /
994 strcpy(last_battery_str, "charging");
998 else if (strcmp(charging_state, "discharging") == 0) {
999 if (present_rate > 0)
1000 format_seconds(last_battery_str, 63,
1001 (remaining_capacity * 60 *
1002 60) / present_rate);
1004 sprintf(last_battery_str,
1006 remaining_capacity * 100 /
1010 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1011 else if (strcmp(charging_state, "charged") == 0) {
1012 if (acpi_last_full != 0
1013 && remaining_capacity != acpi_last_full)
1014 sprintf(last_battery_str, "charged %d%%",
1015 remaining_capacity * 100 /
1018 strcpy(last_battery_str, "charged");
1020 /* unknown, probably full / AC */
1022 if (acpi_last_full != 0
1023 && remaining_capacity != acpi_last_full)
1024 sprintf(last_battery_str, "unknown %d%%",
1025 remaining_capacity * 100 /
1028 strcpy(last_battery_str, "AC");
1032 if (apm_bat_fp == NULL)
1033 apm_bat_fp = open_file(APM_PATH, &rep2);
1035 if (apm_bat_fp != NULL) {
1036 int ac, status, flag, life;
1039 "%*s %*s %*x %x %x %x %d%%",
1040 &ac, &status, &flag, &life);
1043 /* could check now that there is ac */
1044 snprintf(last_battery_str, 64, "AC");
1045 } else if (ac && life != 100) { /* could check that status==3 here? */
1046 snprintf(last_battery_str, 64,
1047 "charging %d%%", life);
1049 snprintf(last_battery_str, 64, "%d%%",
1053 /* it seemed to buffer it so file must be closed (or could use syscalls
1054 * directly but I don't feel like coding it now) */
1060 snprintf(buf, n, "%s", last_battery_str);
1065 show_nice_processes = 1;
1066 process_find_top(info.cpu, info.memu);