Connect top.c to the build only on Linux.
[monky] / src / linux.c
1 /* linux.c
2  * Contains linux specific code
3  *
4  *  $Id$
5  */
6
7
8 #include "conky.h"
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <dirent.h>
13 #include <ctype.h>
14 #include <errno.h>
15 #include <limits.h>
16 #include <sys/types.h>
17 #include <sys/sysinfo.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 // #include <assert.h>
22 #include <time.h>
23 #include "top.h"
24
25 #include <sys/ioctl.h>
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <linux/sockios.h>
29 #include <net/if.h>
30 #include <math.h>
31
32 static struct sysinfo s_info;
33
34 static int show_nice_processes;
35
36 void prepare_update()
37 {
38 }
39
40 static void update_sysinfo()
41 {
42         sysinfo(&s_info);
43
44         info.uptime = (double) s_info.uptime;
45
46         /* there was some problem with these */
47 #if 0
48 //      info.loadavg[0] = s_info.loads[0] / 100000.0f;
49         info.loadavg[1] = s_info.loads[1] / 100000.0f;
50         info.loadavg[2] = s_info.loads[2] / 100000.0f;
51         gkrelltop_process_find_top_three info.mask |= 1 << INFO_LOADAVG;
52 #endif
53
54         info.procs = s_info.procs;
55
56         /* these aren't nice, no cache and should check kernel version for mem_unit */
57 #if 0
58         info.memmax = s_info.totalram;
59         info.mem = s_info.totalram - s_info.freeram;
60         info.swapmax = s_info.totalswap;
61         info.swap = s_info.totalswap - s_info.swap;
62         info.mask |= 1 << INFO_MEM;
63 #endif
64
65         info.mask |= (1 << INFO_UPTIME) | (1 << INFO_PROCS);
66 }
67
68 void update_uptime()
69 {
70         /* prefers sysinfo() for uptime, I don't really know which one is better
71          * (=faster?) */
72 #ifdef USE_PROC_UPTIME
73         static int rep;
74         FILE *fp = open_file("/proc/uptime", &rep);
75         if (!fp)
76                 return 0;
77         fscanf(fp, "%lf", &info.uptime);
78         fclose(fp);
79
80         info.mask |= (1 << INFO_UPTIME);
81 #else
82         update_sysinfo();
83 #endif
84 }
85
86 /* these things are also in sysinfo except Buffers:, that's why I'm reading
87 * them from proc */
88
89 static FILE *meminfo_fp;
90
91 void update_meminfo()
92 {
93         static int rep;
94         /*  unsigned int a; */
95         char buf[256];
96
97         info.mem = info.memmax = info.swap = info.swapmax = info.bufmem =
98             info.buffers = info.cached = 0;
99
100         if (meminfo_fp == NULL)
101                 meminfo_fp = open_file("/proc/meminfo", &rep);
102         else
103                 fseek(meminfo_fp, 0, SEEK_SET);
104         if (meminfo_fp == NULL)
105                 return;
106
107         while (!feof(meminfo_fp)) {
108                 if (fgets(buf, 255, meminfo_fp) == NULL)
109                         break;
110
111                 if (strncmp(buf, "MemTotal:", 9) == 0) {
112                         sscanf(buf, "%*s %u", &info.memmax);
113                 } else if (strncmp(buf, "MemFree:", 8) == 0) {
114                         sscanf(buf, "%*s %u", &info.mem);
115                 } else if (strncmp(buf, "SwapTotal:", 10) == 0) {
116                         sscanf(buf, "%*s %u", &info.swapmax);
117                 } else if (strncmp(buf, "SwapFree:", 9) == 0) {
118                         sscanf(buf, "%*s %u", &info.swap);
119                 } else if (strncmp(buf, "Buffers:", 8) == 0) {
120                         sscanf(buf, "%*s %u", &info.buffers);
121                 } else if (strncmp(buf, "Cached:", 7) == 0) {
122                         sscanf(buf, "%*s %u", &info.cached);
123                 }
124         }
125
126         info.mem = info.memmax - info.mem;
127         info.swap = info.swapmax - info.swap;
128
129         info.bufmem = info.cached + info.buffers;
130
131         info.mask |= (1 << INFO_MEM) | (1 << INFO_BUFFERS);
132 }
133
134 static FILE *net_dev_fp;
135 static FILE *net_wireless_fp;
136
137 inline void update_net_stats()
138 {
139         static int rep;
140         // FIXME: arbitrary size chosen to keep code simple.
141         int i, i2;
142         unsigned int curtmp1, curtmp2;
143         unsigned int k;
144         struct ifconf conf;
145
146
147         char buf[256];
148         double delta;
149
150         /* get delta */
151         delta = current_update_time - last_update_time;
152         if (delta <= 0.0001)
153                 return;
154
155         /* open file and ignore first two lines */
156         if (net_dev_fp == NULL)
157                 net_dev_fp = open_file("/proc/net/dev", &rep);
158         else
159                 fseek(net_dev_fp, 0, SEEK_SET);
160         if (!net_dev_fp)
161                 return;
162
163         fgets(buf, 255, net_dev_fp);    /* garbage */
164         fgets(buf, 255, net_dev_fp);    /* garbage (field names) */
165
166         /* read each interface */
167         for (i2 = 0; i2 < 16; i2++) {
168                 struct net_stat *ns;
169                 char *s, *p;
170                 long long r, t, last_recv, last_trans;
171
172                 if (fgets(buf, 255, net_dev_fp) == NULL)
173                         break;
174                 p = buf;
175                 while (isspace((int) *p))
176                         p++;
177
178                 s = p;
179
180                 while (*p && *p != ':')
181                         p++;
182                 if (*p == '\0')
183                         continue;
184                 *p = '\0';
185                 p++;
186
187                 ns = get_net_stat(s);
188                 ns->up = 1;
189                 last_recv = ns->recv;
190                 last_trans = ns->trans;
191
192                 sscanf(p,
193                        /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
194                        "%Ld  %*d     %*d  %*d  %*d  %*d   %*d        %*d       %Ld",
195                        &r, &t);
196
197                 /* if recv or trans is less than last time, an overflow happened */
198
199                 if (r < ns->last_read_recv)
200                         ns->recv +=
201                             ((long long) 4294967295U -
202                              ns->last_read_recv) + r;
203                 else
204                         ns->recv += (r - ns->last_read_recv);
205                 ns->last_read_recv = r;
206
207                 if (t < ns->last_read_trans)
208                         ns->trans +=
209                             ((long long) 4294967295U -
210                              ns->last_read_trans) + t;
211                 else
212                         ns->trans += (t - ns->last_read_trans);
213                 ns->last_read_trans = t;
214
215                 /*** ip addr patch ***/
216                 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
217
218                 conf.ifc_buf = malloc(sizeof(struct ifreq) * 16);
219
220                 conf.ifc_len = sizeof(struct ifreq) * 16;
221
222                 ioctl((long) i, SIOCGIFCONF, &conf);
223
224                 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
225                         struct net_stat *ns;
226                         ns = get_net_stat(((struct ifreq *) conf.
227                                            ifc_buf)[k].ifr_ifrn.ifrn_name);
228                         ns->addr =
229                             ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.
230                             ifru_addr;
231                 }
232
233                 close((long) i);
234
235                 free(conf.ifc_buf);
236
237
238                 /*** end ip addr patch ***/
239
240
241                 /* calculate speeds */
242                 ns->net_rec[0] = (ns->recv - last_recv) / delta;
243                 ns->net_trans[0] = (ns->trans - last_trans) / delta;
244                 curtmp1 = 0;
245                 curtmp2 = 0;
246                 // get an average
247                 for (i = 0; (unsigned) i < info.net_avg_samples; i++) {
248                         curtmp1 += ns->net_rec[i];
249                         curtmp2 += ns->net_trans[i];
250                 }
251                 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
252                 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
253                 if (info.net_avg_samples > 1) {
254                         for (i = info.net_avg_samples; i > 1; i--) {
255                                 ns->net_rec[i - 1] = ns->net_rec[i - 2];
256                                 ns->net_trans[i - 1] =
257                                     ns->net_trans[i - 2];
258                         }
259                 }
260
261
262
263         }
264
265         /* fclose(net_dev_fp); net_dev_fp = NULL; */
266 }
267
268 inline void update_wifi_stats()
269 {
270         /** wireless stats patch by Bobby Beckmann **/
271         static int rep;
272         int i;
273         char buf[256];
274         /*open file and ignore first two lines       sorry, this code sucks ass right now, i'll clean it up later */
275         if (net_wireless_fp == NULL)
276                 net_wireless_fp = open_file("/proc/net/wireless", &rep);
277         else
278                 fseek(net_wireless_fp, 0, SEEK_SET);
279         if (net_wireless_fp == NULL)
280                 return;
281
282         fgets(buf, 255, net_wireless_fp);       /* garbage */
283         fgets(buf, 255, net_wireless_fp);       /* garbage (field names) */
284
285         /* read each interface */
286         for (i = 0; i < 16; i++) {
287                 struct net_stat *ns;
288                 char *s, *p;
289                 int l, m, n;
290
291                 if (fgets(buf, 255, net_wireless_fp) == NULL)
292                         break;
293                 p = buf;
294                 while (isspace((int) *p))
295                         p++;
296
297                 s = p;
298
299                 while (*p && *p != ':')
300                         p++;
301                 if (*p == '\0')
302                         continue;
303                 *p = '\0';
304                 p++;
305
306                 ns = get_net_stat(s);
307
308                 sscanf(p, "%*d   %d.  %d.  %d", &l, &m, &n);
309
310                 ns->linkstatus = (int) (log(l) / log(92) * 100);
311         }
312
313         /*** end wireless patch ***/
314 }
315
316 int result;
317
318 void update_total_processes()
319 {
320         update_sysinfo();
321 }
322
323 #define CPU_SAMPLE_COUNT 15
324 struct cpu_info {
325         unsigned int cpu_user;
326         unsigned int cpu_system;
327         unsigned int cpu_nice;
328         double last_cpu_sum;
329         int clock_ticks;
330         double cpu_val[CPU_SAMPLE_COUNT];
331 };
332 static short cpu_setup = 0;
333 static int rep;
334
335
336 static FILE *stat_fp;
337
338 void get_cpu_count()
339 {
340         char buf[256];
341         if (stat_fp == NULL)
342                 stat_fp = open_file("/proc/stat", &rep);
343         else
344                 fseek(stat_fp, 0, SEEK_SET);
345         if (stat_fp == NULL)
346                 return;
347
348         info.cpu_count = 0;
349
350         while (!feof(stat_fp)) {
351                 if (fgets(buf, 255, stat_fp) == NULL)
352                         break;
353
354                 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
355                         info.cpu_count++;
356                 }
357         }
358         info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
359 }
360
361
362 inline static void update_stat()
363 {
364         static struct cpu_info *cpu = NULL;
365         char buf[256];
366         unsigned int i;
367         unsigned int index;
368         double curtmp;
369         if (!cpu_setup) {
370                 get_cpu_count();
371                 cpu_setup = 1;
372         }
373         if (cpu == NULL) {
374                 cpu = malloc((info.cpu_count + 1) * sizeof(struct cpu_info));
375                 for (index = 0; index < info.cpu_count + 1; ++index) {
376                         cpu[index].clock_ticks = 0;
377                         cpu[index].last_cpu_sum = 0;
378                         for (i = 0; i < CPU_SAMPLE_COUNT; ++i) {
379                                 cpu[index].cpu_val[i] = 0;
380                         }
381                 }
382         }
383         if (stat_fp == NULL) {
384                 stat_fp = open_file("/proc/stat", &rep);
385         } else {
386                 fseek(stat_fp, 0, SEEK_SET);
387         }
388         if (stat_fp == NULL) {
389                 return;
390         }
391         index = 0;
392         while (!feof(stat_fp)) {
393                 if (fgets(buf, 255, stat_fp) == NULL)
394                         break;
395
396                 if (strncmp(buf, "procs_running ", 14) == 0) {
397                         sscanf(buf, "%*s %d", &info.run_procs);
398                         info.mask |= (1 << INFO_RUN_PROCS);
399                 } else if (strncmp(buf, "cpu ", 4) == 0) {
400                         sscanf(buf, "%*s %u %u %u", &(cpu[index].cpu_user), &(cpu[index].cpu_nice), &(cpu[index].cpu_system));
401                         index++;
402                         info.mask |= (1 << INFO_CPU);
403                 } else if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3]) && index <= info.cpu_count) {
404                         sscanf(buf, "%*s %u %u %u", &(cpu[index].cpu_user), &(cpu[index].cpu_nice), &(cpu[index].cpu_system));
405                         index++;
406                         info.mask |= (1 << INFO_CPU);
407                 }
408         }
409         for (index = 0; index < info.cpu_count + 1; index++) {
410                 double delta;
411                 delta = current_update_time - last_update_time;
412                 if (delta <= 0.001) {
413                         return;
414                 }
415
416                 if (cpu[index].clock_ticks == 0) {
417                         cpu[index].clock_ticks = sysconf(_SC_CLK_TCK);
418                 }
419                 curtmp = 0;
420                 cpu[index].cpu_val[0] =
421                                 (cpu[index].cpu_user + cpu[index].cpu_nice + cpu[index].cpu_system -
422                                 cpu[index].last_cpu_sum) / delta / (double) cpu[index].clock_ticks;
423                 for (i = 0; i < info.cpu_avg_samples; i++) {
424                         curtmp += cpu[index].cpu_val[i];
425                 }
426                 if (index == 0) {
427                         info.cpu_usage[index] = curtmp / info.cpu_avg_samples / info.cpu_count;
428                 } else {
429                         info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
430                 }
431                 cpu[index].last_cpu_sum = cpu[index].cpu_user + cpu[index].cpu_nice + cpu[index].cpu_system;
432                 for (i = info.cpu_avg_samples; i > 1; i--)
433                         cpu[index].cpu_val[i - 1] = cpu[index].cpu_val[i - 2];
434
435         }
436
437 // test code
438 // this is for getting proc shit
439 // pee pee
440 // poo
441         //
442
443
444
445
446
447
448 }
449
450 void update_running_processes()
451 {
452         update_stat();
453 }
454
455 void update_cpu_usage()
456 {
457         update_stat();
458 }
459
460 void update_load_average()
461 {
462 #ifdef HAVE_GETLOADAVG
463         double v[3];
464         getloadavg(v, 3);
465         info.loadavg[0] = (float) v[0];
466         info.loadavg[1] = (float) v[1];
467         info.loadavg[2] = (float) v[2];
468 #else
469         static int rep;
470         FILE *fp;
471
472         fp = open_file("/proc/loadavg", &rep);
473         if (!fp) {
474                 v[0] = v[1] = v[2] = 0.0;
475                 return;
476         }
477
478         fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1],
479                &info.loadavg[2]);
480
481         fclose(fp);
482 #endif
483 }
484
485 #define PROC_I8K "/proc/i8k"
486 #define I8K_DELIM " "
487 static char *i8k_procbuf = NULL;
488 void update_i8k()
489 {
490         FILE *fp;
491         if (!i8k_procbuf) {
492                 i8k_procbuf = (char*)malloc(128*sizeof(char));
493         }
494         if ((fp = fopen(PROC_I8K,"r")) == NULL) {
495                 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel driver is loaded...");
496         }
497
498         memset(&i8k_procbuf[0],0,128);
499         if (fread(&i8k_procbuf[0],sizeof(char),128,fp) == 0) {
500                 ERR("something wrong with /proc/i8k...");
501         }
502
503         fclose(fp);
504
505   i8k.version = strtok(&i8k_procbuf[0],I8K_DELIM);
506         i8k.bios = strtok(NULL,I8K_DELIM);
507         i8k.serial = strtok(NULL,I8K_DELIM);
508         i8k.cpu_temp = strtok(NULL,I8K_DELIM);
509         i8k.left_fan_status = strtok(NULL,I8K_DELIM);   
510         i8k.right_fan_status = strtok(NULL,I8K_DELIM);  
511         i8k.left_fan_rpm = strtok(NULL,I8K_DELIM);
512         i8k.right_fan_rpm = strtok(NULL,I8K_DELIM);
513         i8k.ac_status = strtok(NULL,I8K_DELIM);
514         i8k.buttons_status = strtok(NULL,I8K_DELIM);
515 }
516
517
518 /***********************************************************/
519 /***********************************************************/
520 /***********************************************************/
521
522 static int no_dots(const struct dirent *d)
523 {
524         if (d->d_name[0] == '.')
525                 return 0;
526         return 1;
527 }
528
529 static int
530 get_first_file_in_a_directory(const char *dir, char *s, int *rep)
531 {
532         struct dirent **namelist;
533         int i, n;
534
535         n = scandir(dir, &namelist, no_dots, alphasort);
536         if (n < 0) {
537                 if (!rep || !*rep) {
538                         ERR("scandir for %s: %s", dir, strerror(errno));
539                         if (rep)
540                                 *rep = 1;
541                 }
542                 return 0;
543         } else {
544                 if (n == 0)
545                         return 0;
546
547                 strncpy(s, namelist[0]->d_name, 255);
548                 s[255] = '\0';
549
550                 for (i = 0; i < n; i++)
551                         free(namelist[i]);
552                 free(namelist);
553
554                 return 1;
555         }
556 }
557
558 #define I2C_DIR "/sys/bus/i2c/devices/"
559
560 int
561 open_i2c_sensor(const char *dev, const char *type, int n, int *div,
562                 char *devtype)
563 {
564         char path[256];
565         char buf[64];
566         int fd;
567         int divfd;
568
569         /* if i2c device is NULL or *, get first */
570         if (dev == NULL || strcmp(dev, "*") == 0) {
571                 static int rep;
572                 if (!get_first_file_in_a_directory(I2C_DIR, buf, &rep))
573                         return -1;
574                 dev = buf;
575         }
576
577         /* change vol to in */
578         if (strcmp(type, "vol") == 0)
579                 type = "in";
580
581         if (strcmp(type, "tempf") == 0) {
582                 snprintf(path, 255, I2C_DIR "%s/%s%d_input", dev, "temp",
583                          n);
584         } else {
585                 snprintf(path, 255, I2C_DIR "%s/%s%d_input", dev, type, n);
586         }
587         strcpy(devtype, path);
588
589         /* open file */
590         fd = open(path, O_RDONLY);
591         if (fd < 0) {
592                 CRIT_ERR("can't open '%s': %s\nplease fix i2c or remove it from Conky", path, strerror(errno));
593         }
594
595         if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
596             || strcmp(type, "tempf") == 0)
597                 *div = 1;
598         else
599                 *div = 0;
600         /* fan does not use *_div as a read divisor */
601         if (strcmp("fan", type) == 0)
602                 return fd;
603
604         /* test if *_div file exist, open it and use it as divisor */
605         if (strcmp(type, "tempf") == 0) {
606                 snprintf(path, 255, I2C_DIR "%s/%s%d_div", "one", "two",
607                          n);
608         } else {
609                 snprintf(path, 255, I2C_DIR "%s/%s%d_div", dev, type, n);
610         }
611
612         divfd = open(path, O_RDONLY);
613         if (divfd > 0) {
614                 /* read integer */
615                 char divbuf[64];
616                 unsigned int divn;
617                 divn = read(divfd, divbuf, 63);
618                 /* should read until n == 0 but I doubt that kernel will give these
619                  * in multiple pieces. :) */
620                 divbuf[divn] = '\0';
621                 *div = atoi(divbuf);
622         }
623
624         close(divfd);
625
626         return fd;
627 }
628
629 double get_i2c_info(int *fd, int div, char *devtype, char *type)
630 {
631         int val = 0;
632
633         if (*fd <= 0)
634                 return 0;
635
636         lseek(*fd, 0, SEEK_SET);
637
638         /* read integer */
639         {
640                 char buf[64];
641                 unsigned int n;
642                 n = read(*fd, buf, 63);
643                 /* should read until n == 0 but I doubt that kernel will give these
644                  * in multiple pieces. :) */
645                 buf[n] = '\0';
646                 val = atoi(buf);
647         }
648
649         close(*fd);
650         /* open file */
651         *fd = open(devtype, O_RDONLY);
652         if (*fd < 0)
653                 ERR("can't open '%s': %s", devtype, strerror(errno));
654
655         /* My dirty hack for computing CPU value 
656          * Filedil, from forums.gentoo.org
657          */
658 /*      if (strstr(devtype, "temp1_input") != NULL)
659         return -15.096+1.4893*(val / 1000.0); */
660
661
662         /* divide voltage and temperature by 1000 */
663         /* or if any other divisor is given, use that */
664         if (strcmp(type, "tempf") == 0) {
665                 if (div > 1)
666                         return ((val / div + 40) * 9.0 / 5) - 40;
667                 else if (div)
668                         return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
669                 else
670                         return ((val + 40) * 9.0 / 5) - 40;
671         } else {
672                 if (div > 1)
673                         return val / div;
674                 else if (div)
675                         return val / 1000.0;
676                 else
677                         return val;
678         }
679 }
680
681 #define ADT746X_FAN "/sys/devices/temperatures/cpu_fan_speed"
682
683 static char *adt746x_fan_state;
684
685 char *get_adt746x_fan()
686 {
687         static int rep;
688         FILE *fp;
689
690         if (adt746x_fan_state == NULL) {
691                 adt746x_fan_state = (char *) malloc(100);
692                 assert(adt746x_fan_state != NULL);
693         }
694
695         fp = open_file(ADT746X_FAN, &rep);
696         if (!fp) {
697                 strcpy(adt746x_fan_state,
698                        "No fan found! Hey, you don't have one?");
699                 return adt746x_fan_state;
700         }
701         fscanf(fp, "%s", adt746x_fan_state);
702         fclose(fp);
703
704         return adt746x_fan_state;
705 }
706
707 #define ADT746X_CPU "/sys/devices/temperatures/cpu_temperature"
708
709 static char *adt746x_cpu_state;
710
711 char *get_adt746x_cpu()
712 {
713         static int rep;
714         FILE *fp;
715
716         if (adt746x_cpu_state == NULL) {
717                 adt746x_cpu_state = (char *) malloc(100);
718                 assert(adt746x_cpu_state != NULL);
719         }
720
721         fp = open_file(ADT746X_CPU, &rep);
722         fscanf(fp, "%2s", adt746x_cpu_state);
723         fclose(fp);
724
725         return adt746x_cpu_state;
726 }
727
728 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
729
730 /***********************************************************************/
731 /*
732  *  This file is part of x86info.
733  *  (C) 2001 Dave Jones.
734  *
735  *  Licensed under the terms of the GNU GPL License version 2.
736  *
737  * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
738  * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz>
739  *
740  */
741 #if  defined(__i386) || defined(__x86_64)
742 __inline__ unsigned long long int rdtsc()
743 {
744         unsigned long long int x;
745         __asm__ volatile (".byte 0x0f, 0x31":"=A" (x));
746         return x;
747 }
748 static char *buffer = NULL;
749 #endif
750
751 float get_freq_dynamic()
752 {
753 #if  defined(__i386) || defined(__x86_64)
754         if (buffer == NULL)
755                 buffer = malloc(64);
756         struct timezone tz;
757         struct timeval tvstart, tvstop;
758         unsigned long long cycles[2];   /* gotta be 64 bit */
759         unsigned int microseconds;      /* total time taken */
760
761         memset(&tz, 0, sizeof(tz));
762
763         /* get this function in cached memory */
764         gettimeofday(&tvstart, &tz);
765         cycles[0] = rdtsc();
766         gettimeofday(&tvstart, &tz);
767
768         /* we don't trust that this is any specific length of time */
769         usleep(100);
770         cycles[1] = rdtsc();
771         gettimeofday(&tvstop, &tz);
772         microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
773             (tvstop.tv_usec - tvstart.tv_usec);
774
775         return (cycles[1] - cycles[0]) / microseconds;
776 #else
777         return get_freq();
778 #endif
779 }
780
781 #define CPUFREQ_CURRENT "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq"
782
783 static char *frequency;
784         
785 float get_freq()
786 {
787         FILE *f;
788         char s[1000];
789         if (frequency == NULL) {
790                 frequency = (char *) malloc(100);
791                 assert(frequency != NULL);
792         }
793         f = fopen(CPUFREQ_CURRENT, "r");
794         if (f) {
795                 /* if there's a cpufreq /sys node, read the current
796                  * frequency there from this node; divice by 1000 to
797                  * get MHz
798                  */
799                 double freq = 0;
800                 if (fgets(s, 1000,f)) {
801                         s[strlen(s)-1] = '\0';
802                         freq = strtod(s, NULL);
803                 }
804                 fclose(f);
805                 return (freq/1000);
806         }
807         
808         f = fopen("/proc/cpuinfo", "r");        //open the CPU information file
809         if (!f)
810             return 0;
811         while (fgets(s, 1000, f) != NULL){      //read the file
812 #if defined(__i386) || defined(__x86_64)
813                 if (strncmp(s, "cpu MHz", 5) == 0) {    //and search for the cpu mhz
814 #else
815                 if (strncmp(s, "clock", 5) == 0) {      // this is different on ppc for some reason
816 #endif
817                 strcpy(frequency, strchr(s, ':') + 2);  //copy just the number
818                 frequency[strlen(frequency) - 1] = '\0';        // strip \n
819                 break;
820                 }
821         }
822                 fclose(f);
823                 return strtod(frequency, (char **)NULL);
824 }
825
826
827 #define ACPI_FAN_DIR "/proc/acpi/fan/"
828
829 static char *acpi_fan_state;
830
831 char *get_acpi_fan()
832 {
833         static int rep;
834         char buf[256];
835         char buf2[256];
836         FILE *fp;
837
838         if (acpi_fan_state == NULL) {
839                 acpi_fan_state = (char *) malloc(100);
840                 assert(acpi_fan_state != NULL);
841         }
842
843         /* yeah, slow... :/ */
844         if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep))
845                 return "no fans?";
846
847         snprintf(buf2, 256, "%s%s/state", ACPI_FAN_DIR, buf);
848
849         fp = open_file(buf2, &rep);
850         if (!fp) {
851                 strcpy(acpi_fan_state, "can't open fan's state file");
852                 return acpi_fan_state;
853         }
854         fscanf(fp, "%*s %99s", acpi_fan_state);
855
856         return acpi_fan_state;
857 }
858
859 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
860
861 static char *acpi_ac_adapter_state;
862
863 char *get_acpi_ac_adapter()
864 {
865         static int rep;
866         char buf[256];
867         char buf2[256];
868         FILE *fp;
869
870         if (acpi_ac_adapter_state == NULL) {
871                 acpi_ac_adapter_state = (char *) malloc(100);
872                 assert(acpi_ac_adapter_state != NULL);
873         }
874
875         /* yeah, slow... :/ */
876         if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep))
877                 return "no ac_adapters?";
878
879         snprintf(buf2, 256, "%s%s/state", ACPI_AC_ADAPTER_DIR, buf);
880
881         fp = open_file(buf2, &rep);
882         if (!fp) {
883                 strcpy(acpi_ac_adapter_state,
884                        "No ac adapter found.... where is it?");
885                 return acpi_ac_adapter_state;
886         }
887         fscanf(fp, "%*s %99s", acpi_ac_adapter_state);
888         fclose(fp);
889
890         return acpi_ac_adapter_state;
891 }
892
893 /*
894 /proc/acpi/thermal_zone/THRM/cooling_mode
895 cooling mode:            active
896 /proc/acpi/thermal_zone/THRM/polling_frequency
897 <polling disabled>
898 /proc/acpi/thermal_zone/THRM/state
899 state:                   ok
900 /proc/acpi/thermal_zone/THRM/temperature
901 temperature:             45 C
902 /proc/acpi/thermal_zone/THRM/trip_points
903 critical (S5):           73 C
904 passive:                 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
905 */
906
907 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
908 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
909
910 int open_acpi_temperature(const char *name)
911 {
912         char path[256];
913         char buf[64];
914         int fd;
915
916         if (name == NULL || strcmp(name, "*") == 0) {
917                 static int rep;
918                 if (!get_first_file_in_a_directory
919                     (ACPI_THERMAL_DIR, buf, &rep))
920                         return -1;
921                 name = buf;
922         }
923
924         snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
925
926         fd = open(path, O_RDONLY);
927         if (fd < 0)
928                 ERR("can't open '%s': %s", path, strerror(errno));
929
930         return fd;
931 }
932
933 static double last_acpi_temp;
934 static double last_acpi_temp_time;
935
936 double get_acpi_temperature(int fd)
937 {
938         if (fd <= 0)
939                 return 0;
940
941         /* don't update acpi temperature too often */
942         if (current_update_time - last_acpi_temp_time < 11.32) {
943                 return last_acpi_temp;
944         }
945         last_acpi_temp_time = current_update_time;
946
947         /* seek to beginning */
948         lseek(fd, 0, SEEK_SET);
949
950         /* read */
951         {
952                 char buf[256];
953                 int n;
954                 n = read(fd, buf, 255);
955                 if (n < 0)
956                         ERR("can't read fd %d: %s", fd, strerror(errno));
957                 else {
958                         buf[n] = '\0';
959                         sscanf(buf, "temperature: %lf", &last_acpi_temp);
960                 }
961         }
962
963         return last_acpi_temp;
964 }
965
966 /*
967 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info 
968 present:                 yes
969 design capacity:         4400 mAh
970 last full capacity:      4064 mAh
971 battery technology:      rechargeable
972 design voltage:          14800 mV
973 design capacity warning: 300 mAh
974 design capacity low:     200 mAh
975 capacity granularity 1:  32 mAh
976 capacity granularity 2:  32 mAh
977 model number:            02KT
978 serial number:           16922
979 battery type:            LION
980 OEM info:                SANYO
981 */
982
983 /*
984 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
985 present:                 yes
986 capacity state:          ok
987 charging state:          unknown
988 present rate:            0 mA
989 remaining capacity:      4064 mAh
990 present voltage:         16608 mV
991 */
992
993 /*
994 2213<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm 
995 2213<@jupet kellari ö> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
996 2213<@jupet kellari ö> (-1 ollee ei akkua kiinni, koska akku on pöydällä)
997 2214<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm 
998 2214<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
999
1000 2238<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1001 2239<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1002
1003 2240<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori päällä
1004 2241<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori päällä mutta ilman verkkovirtaa
1005 */
1006
1007 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1008 #define APM_PATH "/proc/apm"
1009
1010 static FILE *acpi_bat_fp;
1011 static FILE *apm_bat_fp;
1012
1013 static int acpi_last_full;
1014
1015 static char last_battery_str[64];
1016
1017 static double last_battery_time;
1018
1019 void get_battery_stuff(char *buf, unsigned int n, const char *bat)
1020 {
1021         static int rep, rep2;
1022         char acpi_path[128];
1023         snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1024
1025         /* don't update battery too often */
1026         if (current_update_time - last_battery_time < 29.5) {
1027                 snprintf(buf, n, "%s", last_battery_str);
1028                 return;
1029         }
1030         last_battery_time = current_update_time;
1031
1032         /* first try ACPI */
1033
1034         if (acpi_bat_fp == NULL && apm_bat_fp == NULL)
1035                 acpi_bat_fp = open_file(acpi_path, &rep);
1036
1037         if (acpi_bat_fp != NULL) {
1038                 int present_rate = -1;
1039                 int remaining_capacity = -1;
1040                 char charging_state[64];
1041
1042                 /* read last full capacity if it's zero */
1043                 if (acpi_last_full == 0) {
1044                         static int rep;
1045                         char path[128];
1046                         FILE *fp;
1047                         snprintf(path, 127,
1048                                  ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1049                         fp = open_file(path, &rep);
1050                         if (fp != NULL) {
1051                                 while (!feof(fp)) {
1052                                         char b[256];
1053                                         if (fgets(b, 256, fp) == NULL)
1054                                                 break;
1055
1056                                         if (sscanf
1057                                             (b, "last full capacity: %d",
1058                                              &acpi_last_full) != 0)
1059                                                 break;
1060                                 }
1061
1062                                 fclose(fp);
1063                         }
1064                 }
1065
1066                 fseek(acpi_bat_fp, 0, SEEK_SET);
1067
1068                 strcpy(charging_state, "unknown");
1069
1070                 while (!feof(acpi_bat_fp)) {
1071                         char buf[256];
1072                         if (fgets(buf, 256, acpi_bat_fp) == NULL)
1073                                 break;
1074
1075                         /* let's just hope units are ok */
1076                         if (buf[0] == 'c')
1077                                 sscanf(buf, "charging state: %63s",
1078                                        charging_state);
1079                         else if (buf[0] == 'p')
1080                                 sscanf(buf, "present rate: %d",
1081                                        &present_rate);
1082                         else if (buf[0] == 'r')
1083                                 sscanf(buf, "remaining capacity: %d",
1084                                        &remaining_capacity);
1085                 }
1086
1087                 /* charging */
1088                 if (strcmp(charging_state, "charging") == 0) {
1089                         if (acpi_last_full != 0 && present_rate > 0) {
1090                                 strcpy(last_battery_str, "charging ");
1091                                 format_seconds(last_battery_str + 9,
1092                                                63 - 9,
1093                                                (acpi_last_full -
1094                                                 remaining_capacity) * 60 *
1095                                                60 / present_rate);
1096                         } else if (acpi_last_full != 0
1097                                    && present_rate <= 0) {
1098                                 sprintf(last_battery_str, "charging %d%%",
1099                                         remaining_capacity * 100 /
1100                                         acpi_last_full);
1101                         } else {
1102                                 strcpy(last_battery_str, "charging");
1103                         }
1104                 }
1105                 /* discharging */
1106                 else if (strcmp(charging_state, "discharging") == 0) {
1107                         if (present_rate > 0)
1108                                 format_seconds(last_battery_str, 63,
1109                                                (remaining_capacity * 60 *
1110                                                 60) / present_rate);
1111                         else
1112                                 sprintf(last_battery_str,
1113                                         "discharging %d%%",
1114                                         remaining_capacity * 100 /
1115                                         acpi_last_full);
1116                 }
1117                 /* charged */
1118                 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1119                 else if (strcmp(charging_state, "charged") == 0) {
1120                         if (acpi_last_full != 0
1121                             && remaining_capacity != acpi_last_full)
1122                                 sprintf(last_battery_str, "charged %d%%",
1123                                         remaining_capacity * 100 /
1124                                         acpi_last_full);
1125                         else
1126                                 strcpy(last_battery_str, "charged");
1127                 }
1128                 /* unknown, probably full / AC */
1129                 else {
1130                         if (acpi_last_full != 0
1131                             && remaining_capacity != acpi_last_full)
1132                                 sprintf(last_battery_str, "unknown %d%%",
1133                                         remaining_capacity * 100 /
1134                                         acpi_last_full);
1135                         else
1136                                 strcpy(last_battery_str, "AC");
1137                 }
1138         } else {
1139                 /* APM */
1140                 if (apm_bat_fp == NULL)
1141                         apm_bat_fp = open_file(APM_PATH, &rep2);
1142
1143                 if (apm_bat_fp != NULL) {
1144                         int ac, status, flag, life;
1145
1146                         fscanf(apm_bat_fp,
1147                                "%*s %*s %*x %x   %x       %x     %d%%",
1148                                &ac, &status, &flag, &life);
1149
1150                         if (life == -1) {
1151                                 /* could check now that there is ac */
1152                                 snprintf(last_battery_str, 64, "AC");
1153                         } else if (ac && life != 100) { /* could check that status==3 here? */
1154                                 snprintf(last_battery_str, 64,
1155                                          "charging %d%%", life);
1156                         } else {
1157                                 snprintf(last_battery_str, 64, "%d%%",
1158                                          life);
1159                         }
1160
1161                         /* it seemed to buffer it so file must be closed (or could use syscalls
1162                          * directly but I don't feel like coding it now) */
1163                         fclose(apm_bat_fp);
1164                         apm_bat_fp = NULL;
1165                 }
1166         }
1167
1168         snprintf(buf, n, "%s", last_battery_str);
1169 }
1170
1171 void update_top()
1172 {
1173         show_nice_processes = 1;
1174         process_find_top(info.cpu, info.memu);
1175 }
1176
1177
1178 /*
1179  *  The following ifdefs were adapted from gkrellm
1180  */
1181 #include <linux/major.h>
1182
1183 #if ! defined (MD_MAJOR)
1184 #define MD_MAJOR 9
1185 #endif
1186
1187 #if !defined(LVM_BLK_MAJOR)
1188 #define LVM_BLK_MAJOR 58
1189 #endif
1190
1191 #if !defined(NBD_MAJOR)
1192 #define NBD_MAJOR 43
1193 #endif
1194
1195 void update_diskio()
1196 {
1197         static unsigned int last = UINT_MAX;
1198         static FILE* fp;
1199
1200         char buf[512];
1201         int major, minor;
1202         unsigned int current = 0;
1203         unsigned int reads, writes = 0;
1204         int col_count = 0;
1205
1206         if (!fp) {
1207                 fp = fopen("/proc/diskstats", "r");
1208         } else {
1209                 fseek(fp, 0, SEEK_SET);
1210         }
1211
1212         /* read reads and writes from all disks (minor = 0), including
1213          * cd-roms and floppies, and summ them up
1214          */
1215         current = 0;
1216         while (!feof(fp)) {
1217                 fgets(buf, 512, fp);
1218                 col_count = sscanf(buf, "%u %u %*s %*u %*u %u %*u %*u %*u %u",
1219                                    &major, &minor, &reads, &writes);
1220                 /* ignore subdevices (they have only 3 matching entries in their line)
1221                  * and virtual devices (LVM, network block devices, RAM disks, Loopback)
1222                  *
1223                  * XXX ignore devices which are part of a SW RAID (MD_MAJOR)
1224                  */
1225                 if (col_count > 3 &&
1226                     major != LVM_BLK_MAJOR && major != NBD_MAJOR &&
1227                     major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
1228                         current += reads + writes;
1229                 }
1230         }
1231
1232         /* since the values in /proc/diststats are absolute, we have
1233          * to substract our last reading. The numbers stand for
1234          * "sectors read", and we therefore have to divide by two to
1235          * get KB */
1236         int tot = ((double)(current-last)/2);
1237         if (last > current) {
1238                 /* we hit this either if it's the very first time we
1239                  * run this, or when /proc/diskstats overflows; while
1240                  * 0 is not correct, it's at least not way off */
1241                 tot = 0;
1242         }
1243         last = current;
1244
1245         diskio_value = tot;
1246 }