10 #include <sys/sysinfo.h>
14 // #include <assert.h>
16 #include <proc/procps.h>
17 #include <proc/readproc.h>
20 #include <sys/ioctl.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <linux/sockios.h>
28 static struct sysinfo s_info;
30 #define TEXT_BUFFER_SIZE (1024*4)
32 static int show_nice_processes;
38 static void update_sysinfo()
42 info.uptime = (double) s_info.uptime;
44 /* there was some problem with these */
46 // info.loadavg[0] = s_info.loads[0] / 100000.0f;
47 info.loadavg[1] = s_info.loads[1] / 100000.0f;
48 info.loadavg[2] = s_info.loads[2] / 100000.0f;
49 gkrelltop_process_find_top_three info.mask |= 1 << INFO_LOADAVG;
52 info.procs = s_info.procs;
54 /* these aren't nice, no cache and should check kernel version for mem_unit */
56 info.memmax = s_info.totalram;
57 info.mem = s_info.totalram - s_info.freeram;
58 info.swapmax = s_info.totalswap;
59 info.swap = s_info.totalswap - s_info.swap;
60 info.mask |= 1 << INFO_MEM;
63 info.mask |= (1 << INFO_UPTIME) | (1 << INFO_PROCS);
68 /* prefers sysinfo() for uptime, I don't really know which one is better
70 #ifdef USE_PROC_UPTIME
72 FILE *fp = open_file("/proc/uptime", &rep);
75 fscanf(fp, "%lf", &info.uptime);
78 info.mask |= (1 << INFO_UPTIME);
84 /* these things are also in sysinfo except Buffers:, that's why I'm reading
87 static FILE *meminfo_fp;
95 info.mem = info.memmax = info.swap = info.swapmax = info.bufmem =
96 info.buffers = info.cached = 0;
98 if (meminfo_fp == NULL)
99 meminfo_fp = open_file("/proc/meminfo", &rep);
101 fseek(meminfo_fp, 0, SEEK_SET);
102 if (meminfo_fp == NULL)
105 while (!feof(meminfo_fp)) {
106 if (fgets(buf, 255, meminfo_fp) == NULL)
109 if (strncmp(buf, "MemTotal:", 9) == 0) {
110 sscanf(buf, "%*s %u", &info.memmax);
111 } else if (strncmp(buf, "MemFree:", 8) == 0) {
112 sscanf(buf, "%*s %u", &info.mem);
113 } else if (strncmp(buf, "SwapTotal:", 10) == 0) {
114 sscanf(buf, "%*s %u", &info.swapmax);
115 } else if (strncmp(buf, "SwapFree:", 9) == 0) {
116 sscanf(buf, "%*s %u", &info.swap);
117 } else if (strncmp(buf, "Buffers:", 8) == 0) {
118 sscanf(buf, "%*s %u", &info.buffers);
119 } else if (strncmp(buf, "Cached:", 7) == 0) {
120 sscanf(buf, "%*s %u", &info.cached);
124 info.mem = info.memmax - info.mem;
125 info.swap = info.swapmax - info.swap;
127 info.bufmem = info.cached + info.buffers;
129 info.mask |= (1 << INFO_MEM) | (1 << INFO_BUFFERS);
132 static FILE *net_dev_fp;
133 static FILE *net_wireless_fp;
135 inline void update_net_stats()
138 // FIXME: arbitrary size chosen to keep code simple.
140 unsigned int curtmp1, curtmp2;
149 delta = current_update_time - last_update_time;
153 /* open file and ignore first two lines */
154 if (net_dev_fp == NULL)
155 net_dev_fp = open_file("/proc/net/dev", &rep);
157 fseek(net_dev_fp, 0, SEEK_SET);
161 fgets(buf, 255, net_dev_fp); /* garbage */
162 fgets(buf, 255, net_dev_fp); /* garbage (field names) */
164 /* read each interface */
165 for (i2 = 0; i2 < 16; i2++) {
168 long long r, t, last_recv, last_trans;
170 if (fgets(buf, 255, net_dev_fp) == NULL)
173 while (isspace((int) *p))
178 while (*p && *p != ':')
185 ns = get_net_stat(s);
187 last_recv = ns->recv;
188 last_trans = ns->trans;
191 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
192 "%Ld %*d %*d %*d %*d %*d %*d %*d %Ld",
195 /* if recv or trans is less than last time, an overflow happened */
197 if (r < ns->last_read_recv)
199 ((long long) 4294967295U -
200 ns->last_read_recv) + r;
202 ns->recv += (r - ns->last_read_recv);
203 ns->last_read_recv = r;
205 if (t < ns->last_read_trans)
207 ((long long) 4294967295U -
208 ns->last_read_trans) + t;
210 ns->trans += (t - ns->last_read_trans);
211 ns->last_read_trans = t;
213 /*** ip addr patch ***/
215 s = (char*)socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
217 conf.ifc_buf = malloc(sizeof(struct ifreq) * 16);
219 conf.ifc_len = sizeof(struct ifreq) * 16;
221 ioctl((long)s, SIOCGIFCONF, &conf);
223 for (k=0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
225 ns = get_net_stat(((struct ifreq*)conf.ifc_buf)[k].ifr_ifrn.ifrn_name);
226 ns->addr = ((struct ifreq*)conf.ifc_buf)[k].ifr_ifru.ifru_addr;
234 /*** end ip addr patch ***/
237 /* calculate speeds */
238 ns->net_rec[0] = (ns->recv - last_recv) / delta;
239 ns->net_trans[0] = (ns->trans - last_trans) / delta;
243 for (i = 0; (unsigned) i < info.net_avg_samples; i++) {
244 curtmp1 += ns->net_rec[i];
245 curtmp2 += ns->net_trans[i];
247 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
248 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
249 if (info.net_avg_samples > 1) {
250 for (i = info.net_avg_samples; i > 1; i--) {
251 ns->net_rec[i - 1] = ns->net_rec[i - 2];
252 ns->net_trans[i - 1] =
253 ns->net_trans[i - 2];
261 /* fclose(net_dev_fp); net_dev_fp = NULL; */
264 inline void update_wifi_stats() {
265 /** wireless stats patch by Bobby Beckmann **/
269 /*open file and ignore first two lines sorry, this code sucks ass right now, i'll clean it up later*/
270 if (net_wireless_fp == NULL)
271 net_wireless_fp = open_file("/proc/net/wireless", &rep);
273 fseek(net_wireless_fp, 0, SEEK_SET);
274 if (!net_wireless_fp) return;
276 fgets(buf, 255, net_wireless_fp); /* garbage */
277 fgets(buf, 255, net_wireless_fp); /* garbage (field names) */
279 /* read each interface */
280 for (i=0; i<16; i++) {
285 if (fgets(buf, 255, net_wireless_fp) == NULL) break;
287 while (isspace((int) *p)) p++;
291 while (*p && *p != ':') p++;
292 if (*p == '\0') continue;
296 ns = get_net_stat(s);
302 ns->linkstatus = (int)(log(l) / log(92) * 100);
305 /*** end wireless patch ***/
310 void update_total_processes()
315 static unsigned int cpu_user, cpu_system, cpu_nice;
316 static double last_cpu_sum;
317 static int clock_ticks;
319 static FILE *stat_fp;
321 inline static void update_stat()
323 // FIXME: arbitrary size?
324 static double cpu_val[15];
331 stat_fp = open_file("/proc/stat", &rep);
333 fseek(stat_fp, 0, SEEK_SET);
339 while (!feof(stat_fp)) {
340 if (fgets(buf, 255, stat_fp) == NULL)
343 if (strncmp(buf, "procs_running ", 14) == 0) {
344 sscanf(buf, "%*s %d", &info.run_procs);
345 info.mask |= (1 << INFO_RUN_PROCS);
346 } else if (strncmp(buf, "cpu ", 4) == 0) {
347 sscanf(buf, "%*s %u %u %u", &cpu_user, &cpu_nice,
349 info.mask |= (1 << INFO_CPU);
350 } else if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
357 delta = current_update_time - last_update_time;
361 if (clock_ticks == 0)
362 clock_ticks = sysconf(_SC_CLK_TCK);
365 (cpu_user + cpu_nice + cpu_system -
366 last_cpu_sum) / delta / (double) clock_ticks /
368 for (i = 0; i < info.cpu_avg_samples; i++)
369 curtmp += cpu_val[i];
370 info.cpu_usage = curtmp / info.cpu_avg_samples;
371 last_cpu_sum = cpu_user + cpu_nice + cpu_system;
372 for (i = info.cpu_avg_samples; i > 1; i--)
373 cpu_val[i - 1] = cpu_val[i - 2];
378 // this is for getting proc shit
390 void update_running_processes()
395 void update_cpu_usage()
400 void update_load_average()
402 #ifdef HAVE_GETLOADAVG
405 info.loadavg[0] = (float) v[0];
406 info.loadavg[1] = (float) v[1];
407 info.loadavg[2] = (float) v[2];
412 fp = open_file("/proc/loadavg", &rep);
414 v[0] = v[1] = v[2] = 0.0;
418 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1],
426 static int no_dots(const struct dirent *d)
428 if (d->d_name[0] == '.')
434 get_first_file_in_a_directory(const char *dir, char *s, int *rep)
436 struct dirent **namelist;
439 n = scandir(dir, &namelist, no_dots, alphasort);
442 ERR("scandir for %s: %s", dir, strerror(errno));
451 strncpy(s, namelist[0]->d_name, 255);
454 for (i = 0; i < n; i++)
462 #define I2C_DIR "/sys/bus/i2c/devices/"
465 open_i2c_sensor(const char *dev, const char *type, int n, int *div,
473 /* if i2c device is NULL or *, get first */
474 if (dev == NULL || strcmp(dev, "*") == 0) {
476 if (!get_first_file_in_a_directory(I2C_DIR, buf, &rep))
481 /* change vol to in */
482 if (strcmp(type, "vol") == 0)
485 if (strcmp(type, "tempf") == 0) {
486 snprintf(path, 255, I2C_DIR "%s/%s%d_input", dev, "temp", n);
489 snprintf(path, 255, I2C_DIR "%s/%s%d_input", dev, type, n);
491 strcpy(devtype, path);
494 fd = open(path, O_RDONLY);
496 ERR("can't open '%s': %s", path, strerror(errno));
498 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0 || strcmp(type, "tempf") == 0)
502 /* fan does not use *_div as a read divisor */
503 if (strcmp("fan", type) == 0)
506 /* test if *_div file exist, open it and use it as divisor */
507 if (strcmp(type, "tempf") == 0) {
508 snprintf(path, 255, I2C_DIR "%s/%s%d_div", "one", "two", n);
511 snprintf(path, 255, I2C_DIR "%s/%s%d_div", dev, type, n);
514 divfd = open(path, O_RDONLY);
519 divn = read(divfd, divbuf, 63);
520 /* should read until n == 0 but I doubt that kernel will give these
521 * in multiple pieces. :) */
531 double get_i2c_info(int *fd, int div, char *devtype, char *type)
538 lseek(*fd, 0, SEEK_SET);
544 n = read(*fd, buf, 63);
545 /* should read until n == 0 but I doubt that kernel will give these
546 * in multiple pieces. :) */
553 *fd = open(devtype, O_RDONLY);
555 ERR("can't open '%s': %s", devtype, strerror(errno));
557 /* My dirty hack for computing CPU value
558 * Filedil, from forums.gentoo.org
560 /* if (strstr(devtype, "temp1_input") != NULL)
561 return -15.096+1.4893*(val / 1000.0); */
564 /* divide voltage and temperature by 1000 */
565 /* or if any other divisor is given, use that */
566 if (strcmp(type, "tempf") == 0) {
568 return ((val / div + 40)*9.0/5)-40;
570 return ((val / 1000.0 + 40)*9.0/5)-40;
572 return ((val + 40)*9.0/5)-40;
584 #define ADT746X_FAN "/sys/devices/temperatures/cpu_fan_speed"
586 static char *adt746x_fan_state;
588 char *get_adt746x_fan()
593 if (adt746x_fan_state == NULL) {
594 adt746x_fan_state = (char *) malloc(100);
595 assert(adt746x_fan_state != NULL);
598 fp = open_file(ADT746X_FAN, &rep);
600 strcpy(adt746x_fan_state,
601 "No fan found! Hey, you don't have one?");
602 return adt746x_fan_state;
604 fscanf(fp, "%s", adt746x_fan_state);
607 return adt746x_fan_state;
610 #define ADT746X_CPU "/sys/devices/temperatures/cpu_temperature"
612 static char *adt746x_cpu_state;
614 char *get_adt746x_cpu()
619 if (adt746x_cpu_state == NULL) {
620 adt746x_cpu_state = (char *) malloc(100);
621 assert(adt746x_cpu_state != NULL);
624 fp = open_file(ADT746X_CPU, &rep);
625 fscanf(fp, "%2s", adt746x_cpu_state);
628 return adt746x_cpu_state;
631 static char *frequency;
637 if (frequency == NULL) {
638 frequency = (char *) malloc(100);
639 assert(frequency != NULL);
641 //char frequency[10];
642 f = fopen("/proc/cpuinfo", "r"); //open the CPU information file
645 while (fgets(s, 1000, f) != NULL) //read the file
646 if (strncmp(s, "cpu M", 5) == 0) { //and search for the cpu mhz
647 //printf("%s", strchr(s, ':')+2);
648 strcpy(frequency, strchr(s, ':') + 2); //copy just the number
649 frequency[strlen(frequency) - 1] = '\0'; // strip \n
656 #define ACPI_FAN_DIR "/proc/acpi/fan/"
658 static char *acpi_fan_state;
667 if (acpi_fan_state == NULL) {
668 acpi_fan_state = (char *) malloc(100);
669 assert(acpi_fan_state != NULL);
672 /* yeah, slow... :/ */
673 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep))
676 snprintf(buf2, 256, "%s%s/state", ACPI_FAN_DIR, buf);
678 fp = open_file(buf2, &rep);
680 strcpy(acpi_fan_state, "can't open fan's state file");
681 return acpi_fan_state;
683 fscanf(fp, "%*s %99s", acpi_fan_state);
685 return acpi_fan_state;
688 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
690 static char *acpi_ac_adapter_state;
692 char *get_acpi_ac_adapter()
699 if (acpi_ac_adapter_state == NULL) {
700 acpi_ac_adapter_state = (char *) malloc(100);
701 assert(acpi_ac_adapter_state != NULL);
704 /* yeah, slow... :/ */
705 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep))
706 return "no ac_adapters?";
708 snprintf(buf2, 256, "%s%s/state", ACPI_AC_ADAPTER_DIR, buf);
710 fp = open_file(buf2, &rep);
712 strcpy(acpi_ac_adapter_state,
713 "No ac adapter found.... where is it?");
714 return acpi_ac_adapter_state;
716 fscanf(fp, "%*s %99s", acpi_ac_adapter_state);
719 return acpi_ac_adapter_state;
723 /proc/acpi/thermal_zone/THRM/cooling_mode
725 /proc/acpi/thermal_zone/THRM/polling_frequency
727 /proc/acpi/thermal_zone/THRM/state
729 /proc/acpi/thermal_zone/THRM/temperature
731 /proc/acpi/thermal_zone/THRM/trip_points
733 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
736 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
737 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
739 int open_acpi_temperature(const char *name)
745 if (name == NULL || strcmp(name, "*") == 0) {
747 if (!get_first_file_in_a_directory
748 (ACPI_THERMAL_DIR, buf, &rep))
753 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
755 fd = open(path, O_RDONLY);
757 ERR("can't open '%s': %s", path, strerror(errno));
762 static double last_acpi_temp;
763 static double last_acpi_temp_time;
765 double get_acpi_temperature(int fd)
770 /* don't update acpi temperature too often */
771 if (current_update_time - last_acpi_temp_time < 11.32) {
772 return last_acpi_temp;
774 last_acpi_temp_time = current_update_time;
776 /* seek to beginning */
777 lseek(fd, 0, SEEK_SET);
783 n = read(fd, buf, 255);
785 ERR("can't read fd %d: %s", fd, strerror(errno));
788 sscanf(buf, "temperature: %lf", &last_acpi_temp);
792 return last_acpi_temp;
796 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
798 design capacity: 4400 mAh
799 last full capacity: 4064 mAh
800 battery technology: rechargeable
801 design voltage: 14800 mV
802 design capacity warning: 300 mAh
803 design capacity low: 200 mAh
804 capacity granularity 1: 32 mAh
805 capacity granularity 2: 32 mAh
813 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
816 charging state: unknown
818 remaining capacity: 4064 mAh
819 present voltage: 16608 mV
823 2213<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
824 2213<@jupet kellari ö> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
825 2213<@jupet kellari ö> (-1 ollee ei akkua kiinni, koska akku on pöydällä)
826 2214<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
827 2214<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
829 2238<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
830 2239<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
832 2240<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori päällä
833 2241<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori päällä mutta ilman verkkovirtaa
836 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
837 #define APM_PATH "/proc/apm"
839 static FILE *acpi_bat_fp;
840 static FILE *apm_bat_fp;
842 static int acpi_last_full;
844 static char last_battery_str[64];
846 static double last_battery_time;
848 void get_battery_stuff(char *buf, unsigned int n, const char *bat)
850 static int rep, rep2;
852 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
854 /* don't update battery too often */
855 if (current_update_time - last_battery_time < 29.5) {
856 snprintf(buf, n, "%s", last_battery_str);
859 last_battery_time = current_update_time;
863 if (acpi_bat_fp == NULL && apm_bat_fp == NULL)
864 acpi_bat_fp = open_file(acpi_path, &rep);
866 if (acpi_bat_fp != NULL) {
867 int present_rate = -1;
868 int remaining_capacity = -1;
869 char charging_state[64];
871 /* read last full capacity if it's zero */
872 if (acpi_last_full == 0) {
877 ACPI_BATTERY_BASE_PATH "/%s/info", bat);
878 fp = open_file(path, &rep);
882 if (fgets(b, 256, fp) == NULL)
886 (b, "last full capacity: %d",
887 &acpi_last_full) != 0)
895 fseek(acpi_bat_fp, 0, SEEK_SET);
897 strcpy(charging_state, "unknown");
899 while (!feof(acpi_bat_fp)) {
901 if (fgets(buf, 256, acpi_bat_fp) == NULL)
904 /* let's just hope units are ok */
906 sscanf(buf, "charging state: %63s",
908 else if (buf[0] == 'p')
909 sscanf(buf, "present rate: %d",
911 else if (buf[0] == 'r')
912 sscanf(buf, "remaining capacity: %d",
913 &remaining_capacity);
917 if (strcmp(charging_state, "charging") == 0) {
918 if (acpi_last_full != 0 && present_rate > 0) {
919 strcpy(last_battery_str, "charging ");
920 format_seconds(last_battery_str + 9,
923 remaining_capacity) * 60 *
925 } else if (acpi_last_full != 0
926 && present_rate <= 0) {
927 sprintf(last_battery_str, "charging %d%%",
928 remaining_capacity * 100 /
931 strcpy(last_battery_str, "charging");
935 else if (strcmp(charging_state, "discharging") == 0) {
936 if (present_rate > 0)
937 format_seconds(last_battery_str, 63,
938 (remaining_capacity * 60 *
941 sprintf(last_battery_str,
943 remaining_capacity * 100 /
947 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
948 else if (strcmp(charging_state, "charged") == 0) {
949 if (acpi_last_full != 0 && remaining_capacity != acpi_last_full)
950 sprintf(last_battery_str, "charged %d%%",
951 remaining_capacity * 100 / acpi_last_full);
953 strcpy(last_battery_str, "charged");
955 /* unknown, probably full / AC */
957 if (acpi_last_full != 0
958 && remaining_capacity != acpi_last_full)
959 sprintf(last_battery_str, "unknown %d%%",
960 remaining_capacity * 100 /
963 strcpy(last_battery_str, "AC");
967 if (apm_bat_fp == NULL)
968 apm_bat_fp = open_file(APM_PATH, &rep2);
970 if (apm_bat_fp != NULL) {
971 int ac, status, flag, life;
974 "%*s %*s %*x %x %x %x %d%%",
975 &ac, &status, &flag, &life);
978 /* could check now that there is ac */
979 snprintf(last_battery_str, 64, "AC");
980 } else if (ac && life != 100) { /* could check that status==3 here? */
981 snprintf(last_battery_str, 64,
982 "charging %d%%", life);
984 snprintf(last_battery_str, 64, "%d%%",
988 /* it seemed to buffer it so file must be closed (or could use syscalls
989 * directly but I don't feel like coding it now) */
995 snprintf(buf, n, "%s", last_battery_str);
1000 show_nice_processes = 1;
1001 process_find_top(info.tops);