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>
32 #define SHORTSTAT_TEMPL "%*s %llu %llu %llu"
33 #define LONGSTAT_TEMPL "%*s %llu %llu %llu "
36 static struct sysinfo s_info;
38 static int show_nice_processes;
44 static void update_sysinfo()
48 info.uptime = (double) s_info.uptime;
50 /* there was some problem with these */
52 // info.loadavg[0] = s_info.loads[0] / 100000.0f;
53 info.loadavg[1] = s_info.loads[1] / 100000.0f;
54 info.loadavg[2] = s_info.loads[2] / 100000.0f;
55 gkrelltop_process_find_top_three info.mask |= 1 << INFO_LOADAVG;
58 info.procs = s_info.procs;
60 /* these aren't nice, no cache and should check kernel version for mem_unit */
62 info.memmax = s_info.totalram;
63 info.mem = s_info.totalram - s_info.freeram;
64 info.swapmax = s_info.totalswap;
65 info.swap = s_info.totalswap - s_info.swap;
66 info.mask |= 1 << INFO_MEM;
69 info.mask |= (1 << INFO_UPTIME) | (1 << INFO_PROCS);
74 /* prefers sysinfo() for uptime, I don't really know which one is better
76 #ifdef USE_PROC_UPTIME
78 FILE *fp = open_file("/proc/uptime", &rep);
81 fscanf(fp, "%lf", &info.uptime);
84 info.mask |= (1 << INFO_UPTIME);
90 /* these things are also in sysinfo except Buffers:, that's why I'm reading
93 static FILE *meminfo_fp;
101 info.mem = info.memmax = info.swap = info.swapmax = info.bufmem =
102 info.buffers = info.cached = 0;
104 if (meminfo_fp == NULL)
105 meminfo_fp = open_file("/proc/meminfo", &rep);
107 fseek(meminfo_fp, 0, SEEK_SET);
108 if (meminfo_fp == NULL)
111 while (!feof(meminfo_fp)) {
112 if (fgets(buf, 255, meminfo_fp) == NULL)
115 if (strncmp(buf, "MemTotal:", 9) == 0) {
116 sscanf(buf, "%*s %lu", &info.memmax);
117 } else if (strncmp(buf, "MemFree:", 8) == 0) {
118 sscanf(buf, "%*s %lu", &info.mem);
119 } else if (strncmp(buf, "SwapTotal:", 10) == 0) {
120 sscanf(buf, "%*s %lu", &info.swapmax);
121 } else if (strncmp(buf, "SwapFree:", 9) == 0) {
122 sscanf(buf, "%*s %lu", &info.swap);
123 } else if (strncmp(buf, "Buffers:", 8) == 0) {
124 sscanf(buf, "%*s %lu", &info.buffers);
125 } else if (strncmp(buf, "Cached:", 7) == 0) {
126 sscanf(buf, "%*s %lu", &info.cached);
130 info.mem = info.memmax - info.mem;
131 info.swap = info.swapmax - info.swap;
133 info.bufmem = info.cached + info.buffers;
135 info.mask |= (1 << INFO_MEM) | (1 << INFO_BUFFERS);
138 static FILE *net_dev_fp;
139 static FILE *net_wireless_fp;
141 inline void update_net_stats()
144 // FIXME: arbitrary size chosen to keep code simple.
146 unsigned int curtmp1, curtmp2;
155 delta = current_update_time - last_update_time;
159 /* open file and ignore first two lines */
160 if (net_dev_fp == NULL) {
161 net_dev_fp = open_file("/proc/net/dev", &rep);
164 fseek(net_dev_fp, 0, SEEK_SET);
168 fgets(buf, 255, net_dev_fp); /* garbage */
169 fgets(buf, 255, net_dev_fp); /* garbage (field names) */
171 /* read each interface */
172 for (i2 = 0; i2 < 16; i2++) {
175 long long r, t, last_recv, last_trans;
177 if (fgets(buf, 255, net_dev_fp) == NULL) {
181 while (isspace((int) *p))
186 while (*p && *p != ':')
193 ns = get_net_stat(s);
195 memset(&(ns->addr.sa_data), 0, 14);
196 last_recv = ns->recv;
197 last_trans = ns->trans;
200 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
201 "%Ld %*d %*d %*d %*d %*d %*d %*d %Ld",
204 /* if recv or trans is less than last time, an overflow happened */
206 if (r < ns->last_read_recv)
208 ((long long) 4294967295U -
209 ns->last_read_recv) + r;
211 ns->recv += (r - ns->last_read_recv);
212 ns->last_read_recv = r;
214 if (t < ns->last_read_trans)
216 ((long long) 4294967295U -
217 ns->last_read_trans) + t;
219 ns->trans += (t - ns->last_read_trans);
220 ns->last_read_trans = t;
222 /*** ip addr patch ***/
223 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
225 conf.ifc_buf = malloc(sizeof(struct ifreq) * 16);
227 conf.ifc_len = sizeof(struct ifreq) * 16;
229 ioctl((long) i, SIOCGIFCONF, &conf);
231 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
233 ns = get_net_stat(((struct ifreq *) conf.
234 ifc_buf)[k].ifr_ifrn.ifrn_name);
236 ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.
245 /*** end ip addr patch ***/
248 /* calculate speeds */
249 ns->net_rec[0] = (ns->recv - last_recv) / delta;
250 ns->net_trans[0] = (ns->trans - last_trans) / delta;
254 for (i = 0; (unsigned) i < info.net_avg_samples; i++) {
255 curtmp1 += ns->net_rec[i];
256 curtmp2 += ns->net_trans[i];
258 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
259 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
260 if (info.net_avg_samples > 1) {
261 for (i = info.net_avg_samples; i > 1; i--) {
262 ns->net_rec[i - 1] = ns->net_rec[i - 2];
263 ns->net_trans[i - 1] =
264 ns->net_trans[i - 2];
272 /* fclose(net_dev_fp); net_dev_fp = NULL; */
275 inline void update_wifi_stats()
277 /** wireless stats patch by Bobby Beckmann **/
281 /*open file and ignore first two lines sorry, this code sucks ass right now, i'll clean it up later */
282 if (net_wireless_fp == NULL)
283 net_wireless_fp = open_file("/proc/net/wireless", &rep);
285 fseek(net_wireless_fp, 0, SEEK_SET);
286 if (net_wireless_fp == NULL)
289 fgets(buf, 255, net_wireless_fp); /* garbage */
290 fgets(buf, 255, net_wireless_fp); /* garbage (field names) */
292 /* read each interface */
293 for (i = 0; i < 16; i++) {
298 if (fgets(buf, 255, net_wireless_fp) == NULL)
301 while (isspace((int) *p))
306 while (*p && *p != ':')
313 ns = get_net_stat(s);
315 sscanf(p, "%*d %d. %d. %d", &l, &m, &n);
317 ns->linkstatus = (int) (log(MIN(MAX(l,1),92)) / log(92) * 100);
321 /*** end wireless patch ***/
326 void update_total_processes()
331 #define CPU_SAMPLE_COUNT 15
333 unsigned long long cpu_user;
334 unsigned long long cpu_system;
335 unsigned long long cpu_nice;
336 unsigned long long cpu_idle;
337 unsigned long long cpu_iowait;
338 unsigned long long cpu_irq;
339 unsigned long long cpu_softirq;
340 unsigned long long cpu_steal;
341 unsigned long long cpu_total;
342 unsigned long long cpu_active_total;
343 unsigned long long cpu_last_total;
344 unsigned long long cpu_last_active_total;
345 double cpu_val[CPU_SAMPLE_COUNT];
347 static short cpu_setup = 0;
351 static FILE *stat_fp;
354 determine if this kernel gives us "extended" statistics information in /proc/stat.
355 Kernels around 2.5 and earlier only reported user, system, nice and idle values in proc stat.
356 Kernels around 2.6 and greater report these PLUS iowait, irq, softirq, and steal
358 void determine_longstat(char * buf) {
359 unsigned long long iowait=0;
360 KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
361 /* scanf will either return -1 or 1 because there is only 1 assignment */
362 if (sscanf(buf, "%*s %*d %*d %*d %*d %llu",&iowait)>0) KFLAG_SETON(KFLAG_IS_LONGSTAT);
369 stat_fp = open_file("/proc/stat", &rep);
371 fseek(stat_fp, 0, SEEK_SET);
377 while (!feof(stat_fp)) {
378 if (fgets(buf, 255, stat_fp) == NULL)
381 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
382 if (info.cpu_count == 0) {
383 determine_longstat(buf);
388 info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
392 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
393 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
395 inline static void update_stat()
397 static struct cpu_info *cpu = NULL;
402 char * stat_template=NULL;
403 unsigned int malloc_cpu_size=0;
411 if (stat_template == NULL) {
412 stat_template = KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT ;
416 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
417 cpu = malloc(malloc_cpu_size);
418 memset(cpu, 0, malloc_cpu_size);
421 if (stat_fp == NULL) {
422 stat_fp = open_file("/proc/stat", &rep);
424 fseek(stat_fp, 0, SEEK_SET);
426 if (stat_fp == NULL) {
430 while (!feof(stat_fp)) {
431 if (fgets(buf, 255, stat_fp) == NULL)
434 if (strncmp(buf, "procs_running ", 14) == 0) {
435 sscanf(buf, "%*s %hu", &info.run_procs);
436 info.mask |= (1 << INFO_RUN_PROCS);
437 } else if (strncmp(buf, "cpu", 3) == 0) {
438 index = isdigit(buf[3]) ? ((int)buf[3]) - 0x2F : 0;
439 sscanf(buf, stat_template
440 , &(cpu[index].cpu_user)
441 , &(cpu[index].cpu_nice)
442 , &(cpu[index].cpu_system)
443 , &(cpu[index].cpu_idle)
444 , &(cpu[index].cpu_iowait)
445 , &(cpu[index].cpu_irq)
446 , &(cpu[index].cpu_softirq)
447 , &(cpu[index].cpu_steal)
450 cpu[index].cpu_total = cpu[index].cpu_user
451 + cpu[index].cpu_nice
452 + cpu[index].cpu_system
453 + cpu[index].cpu_idle
454 + cpu[index].cpu_iowait
456 + cpu[index].cpu_softirq
457 + cpu[index].cpu_steal
460 cpu[index].cpu_active_total = cpu[index].cpu_total - (cpu[index].cpu_idle + cpu[index].cpu_iowait);
461 info.mask |= (1 << INFO_CPU);
463 double delta = current_update_time - last_update_time;
464 if (delta <= 0.001) return;
466 cpu[index].cpu_val[0] = (cpu[index].cpu_active_total - cpu[index].cpu_last_active_total) /
467 (float )(cpu[index].cpu_total - cpu[index].cpu_last_total);
469 for (i=0; i < info.cpu_avg_samples; i++ ) {
470 curtmp += cpu[index].cpu_val[i];
472 /* TESTING -- I've removed this, because I don't think it is right. You shouldn't divide
473 by the cpu count here ... removing for testing */
475 info.cpu_usage[index] = curtmp / info.cpu_avg_samples / info.cpu_count;
477 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
479 /* TESTING -- this line replaces the prev. "suspect" if/else */
480 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
482 cpu[index].cpu_last_total = cpu[index].cpu_total;
483 cpu[index].cpu_last_active_total = cpu[index].cpu_active_total;
484 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
485 cpu[index].cpu_val[i] = cpu[index].cpu_val[i - 1];
492 void update_running_processes()
497 void update_cpu_usage()
502 void update_load_average()
504 #ifdef HAVE_GETLOADAVG
507 info.loadavg[0] = (float) v[0];
508 info.loadavg[1] = (float) v[1];
509 info.loadavg[2] = (float) v[2];
514 fp = open_file("/proc/loadavg", &rep);
516 v[0] = v[1] = v[2] = 0.0;
520 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1],
527 #define PROC_I8K "/proc/i8k"
528 #define I8K_DELIM " "
529 static char *i8k_procbuf = NULL;
534 i8k_procbuf = (char*)malloc(128*sizeof(char));
536 if ((fp = fopen(PROC_I8K,"r")) == NULL) {
537 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel driver is loaded...");
540 memset(&i8k_procbuf[0],0,128);
541 if (fread(&i8k_procbuf[0],sizeof(char),128,fp) == 0) {
542 ERR("something wrong with /proc/i8k...");
547 i8k.version = strtok(&i8k_procbuf[0],I8K_DELIM);
548 i8k.bios = strtok(NULL,I8K_DELIM);
549 i8k.serial = strtok(NULL,I8K_DELIM);
550 i8k.cpu_temp = strtok(NULL,I8K_DELIM);
551 i8k.left_fan_status = strtok(NULL,I8K_DELIM);
552 i8k.right_fan_status = strtok(NULL,I8K_DELIM);
553 i8k.left_fan_rpm = strtok(NULL,I8K_DELIM);
554 i8k.right_fan_rpm = strtok(NULL,I8K_DELIM);
555 i8k.ac_status = strtok(NULL,I8K_DELIM);
556 i8k.buttons_status = strtok(NULL,I8K_DELIM);
560 /***********************************************************/
561 /***********************************************************/
562 /***********************************************************/
564 static int no_dots(const struct dirent *d)
566 if (d->d_name[0] == '.')
572 get_first_file_in_a_directory(const char *dir, char *s, int *rep)
574 struct dirent **namelist;
577 n = scandir(dir, &namelist, no_dots, alphasort);
580 ERR("scandir for %s: %s", dir, strerror(errno));
589 strncpy(s, namelist[0]->d_name, 255);
592 for (i = 0; i < n; i++)
600 #define I2C_DIR "/sys/bus/i2c/devices/"
603 open_i2c_sensor(const char *dev, const char *type, int n, int *div,
611 /* if i2c device is NULL or *, get first */
612 if (dev == NULL || strcmp(dev, "*") == 0) {
614 if (!get_first_file_in_a_directory(I2C_DIR, buf, &rep))
619 /* change vol to in */
620 if (strcmp(type, "vol") == 0)
623 if (strcmp(type, "tempf") == 0) {
624 snprintf(path, 255, I2C_DIR "%s/%s%d_input", dev, "temp", n);
626 snprintf(path, 255, I2C_DIR "%s/%s%d_input", dev, type, n);
628 strncpy(devtype, path, 255);
631 fd = open(path, O_RDONLY);
633 CRIT_ERR("can't open '%s': %s\nplease fix i2c or remove it from Conky", path, strerror(errno));
636 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
637 || strcmp(type, "tempf") == 0)
641 /* fan does not use *_div as a read divisor */
642 if (strcmp("fan", type) == 0)
645 /* test if *_div file exist, open it and use it as divisor */
646 if (strcmp(type, "tempf") == 0) {
647 snprintf(path, 255, I2C_DIR "%s/%s%d_div", "one", "two",
650 snprintf(path, 255, I2C_DIR "%s/%s%d_div", dev, type, n);
653 divfd = open(path, O_RDONLY);
658 divn = read(divfd, divbuf, 63);
659 /* should read until n == 0 but I doubt that kernel will give these
660 * in multiple pieces. :) */
670 double get_i2c_info(int *fd, int div, char *devtype, char *type)
677 lseek(*fd, 0, SEEK_SET);
683 n = read(*fd, buf, 63);
684 /* should read until n == 0 but I doubt that kernel will give these
685 * in multiple pieces. :) */
692 *fd = open(devtype, O_RDONLY);
694 ERR("can't open '%s': %s", devtype, strerror(errno));
696 /* My dirty hack for computing CPU value
697 * Filedil, from forums.gentoo.org
699 /* if (strstr(devtype, "temp1_input") != NULL)
700 return -15.096+1.4893*(val / 1000.0); */
703 /* divide voltage and temperature by 1000 */
704 /* or if any other divisor is given, use that */
705 if (strcmp(type, "tempf") == 0) {
707 return ((val / div + 40) * 9.0 / 5) - 40;
709 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
711 return ((val + 40) * 9.0 / 5) - 40;
722 #define ADT746X_FAN "/sys/devices/temperatures/cpu_fan_speed"
724 void get_adt746x_fan( char * p_client_buffer, size_t client_buffer_size )
727 char adt746x_fan_state[64];
730 if ( !p_client_buffer || client_buffer_size <= 0 )
733 fp = open_file(ADT746X_FAN, &rep);
736 sprintf(adt746x_fan_state, "adt746x not found");
740 fscanf(fp, "%s", adt746x_fan_state);
744 snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_fan_state );
748 #define ADT746X_CPU "/sys/devices/temperatures/cpu_temperature"
750 void get_adt746x_cpu( char * p_client_buffer, size_t client_buffer_size )
753 char adt746x_cpu_state[64];
756 if ( !p_client_buffer || client_buffer_size <= 0 )
759 fp = open_file(ADT746X_CPU, &rep);
762 sprintf(adt746x_cpu_state, "adt746x not found");
766 fscanf(fp, "%2s", adt746x_cpu_state);
770 snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state );
774 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
776 /***********************************************************************/
778 * This file is part of x86info.
779 * (C) 2001 Dave Jones.
781 * Licensed under the terms of the GNU GPL License version 2.
783 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
784 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz>
787 #if defined(__i386) || defined(__x86_64)
788 __inline__ unsigned long long int rdtsc()
790 unsigned long long int x;
791 __asm__ volatile (".byte 0x0f, 0x31":"=A" (x));
796 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
797 void get_freq_dynamic( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor )
799 #if defined(__i386) || defined(__x86_64)
801 struct timeval tvstart, tvstop;
802 unsigned long long cycles[2]; /* gotta be 64 bit */
803 unsigned int microseconds; /* total time taken */
805 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
808 memset(&tz, 0, sizeof(tz));
810 /* get this function in cached memory */
811 gettimeofday(&tvstart, &tz);
813 gettimeofday(&tvstart, &tz);
815 /* we don't trust that this is any specific length of time */
818 gettimeofday(&tvstop, &tz);
819 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
820 (tvstop.tv_usec - tvstart.tv_usec);
822 snprintf( p_client_buffer, client_buffer_size, p_format, (float)((cycles[1] - cycles[0]) / microseconds) / divisor );
825 get_freq( p_client_buffer, client_buffer_size, p_format, divisor );
830 #define CPUFREQ_CURRENT "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq"
832 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
833 void get_freq( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor )
840 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
843 f = fopen(CPUFREQ_CURRENT, "r");
845 /* if there's a cpufreq /sys node, read the current frequency from this node;
846 * divide by 1000 to get Mhz. */
847 if (fgets(s, sizeof(s), f)) {
848 s[strlen(s)-1] = '\0';
849 freq = strtod(s, NULL);
852 snprintf( p_client_buffer, client_buffer_size, p_format, (freq/1000)/divisor );
856 f = fopen("/proc/cpuinfo", "r"); //open the CPU information file
860 while (fgets(s, sizeof(s), f) != NULL){ //read the file
861 #if defined(__i386) || defined(__x86_64)
862 if (strncmp(s, "cpu MHz", 7) == 0) { //and search for the cpu mhz
864 if (strncmp(s, "clock", 5) == 0) { // this is different on ppc for some reason
866 strcpy(frequency, strchr(s, ':') + 2); //copy just the number
867 frequency[strlen(frequency) - 1] = '\0'; // strip \n
868 freq = strtod(frequency, NULL);
874 snprintf( p_client_buffer, client_buffer_size, p_format, (float)freq/divisor );
879 #define ACPI_FAN_DIR "/proc/acpi/fan/"
881 void get_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
888 if ( !p_client_buffer || client_buffer_size <= 0 )
891 /* yeah, slow... :/ */
892 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep))
894 snprintf( p_client_buffer, client_buffer_size, "no fans?" );
898 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf );
900 fp = open_file(buf2, &rep);
902 snprintf( p_client_buffer, client_buffer_size, "can't open fan's state file" );
905 memset(buf,0,sizeof(buf));
906 fscanf(fp, "%*s %99s", buf);
909 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
914 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
916 void get_acpi_ac_adapter( char * p_client_buffer, size_t client_buffer_size )
923 if ( !p_client_buffer || client_buffer_size <= 0 )
926 /* yeah, slow... :/ */
927 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep))
929 snprintf( p_client_buffer, client_buffer_size, "no ac_adapters?" );
933 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf );
936 fp = open_file(buf2, &rep);
938 snprintf( p_client_buffer, client_buffer_size, "No ac adapter found.... where is it?" );
941 memset(buf,0,sizeof(buf));
942 fscanf(fp, "%*s %99s", buf );
945 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
951 /proc/acpi/thermal_zone/THRM/cooling_mode
953 /proc/acpi/thermal_zone/THRM/polling_frequency
955 /proc/acpi/thermal_zone/THRM/state
957 /proc/acpi/thermal_zone/THRM/temperature
959 /proc/acpi/thermal_zone/THRM/trip_points
961 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
964 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
965 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
967 int open_acpi_temperature(const char *name)
973 if (name == NULL || strcmp(name, "*") == 0) {
975 if (!get_first_file_in_a_directory
976 (ACPI_THERMAL_DIR, buf, &rep))
981 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
983 fd = open(path, O_RDONLY);
985 ERR("can't open '%s': %s", path, strerror(errno));
990 static double last_acpi_temp;
991 static double last_acpi_temp_time;
993 double get_acpi_temperature(int fd)
998 /* don't update acpi temperature too often */
999 if (current_update_time - last_acpi_temp_time < 11.32) {
1000 return last_acpi_temp;
1002 last_acpi_temp_time = current_update_time;
1004 /* seek to beginning */
1005 lseek(fd, 0, SEEK_SET);
1011 n = read(fd, buf, 255);
1013 ERR("can't read fd %d: %s", fd, strerror(errno));
1016 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1020 return last_acpi_temp;
1024 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1026 design capacity: 4400 mAh
1027 last full capacity: 4064 mAh
1028 battery technology: rechargeable
1029 design voltage: 14800 mV
1030 design capacity warning: 300 mAh
1031 design capacity low: 200 mAh
1032 capacity granularity 1: 32 mAh
1033 capacity granularity 2: 32 mAh
1035 serial number: 16922
1041 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1044 charging state: unknown
1046 remaining capacity: 4064 mAh
1047 present voltage: 16608 mV
1051 2213<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1052 2213<@jupet kellari ö> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1053 2213<@jupet kellari ö> (-1 ollee ei akkua kiinni, koska akku on pöydällä)
1054 2214<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1055 2214<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1057 2238<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1058 2239<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1060 2240<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori päällä
1061 2241<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori päällä mutta ilman verkkovirtaa
1064 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1065 #define APM_PATH "/proc/apm"
1067 static FILE *acpi_bat_fp;
1068 static FILE *apm_bat_fp;
1070 static int acpi_last_full;
1072 static char last_battery_str[64];
1074 static double last_battery_time;
1076 void get_battery_stuff(char *buf, unsigned int n, const char *bat)
1078 static int rep, rep2;
1079 char acpi_path[128];
1080 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1082 /* don't update battery too often */
1083 if (current_update_time - last_battery_time < 29.5) {
1084 snprintf(buf, n, "%s", last_battery_str);
1087 last_battery_time = current_update_time;
1089 /* first try ACPI */
1091 if (acpi_bat_fp == NULL && apm_bat_fp == NULL)
1092 acpi_bat_fp = open_file(acpi_path, &rep);
1094 if (acpi_bat_fp != NULL) {
1095 int present_rate = -1;
1096 int remaining_capacity = -1;
1097 char charging_state[64];
1099 /* read last full capacity if it's zero */
1100 if (acpi_last_full == 0) {
1105 ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1106 fp = open_file(path, &rep);
1110 if (fgets(b, 256, fp) == NULL)
1114 (b, "last full capacity: %d",
1115 &acpi_last_full) != 0)
1123 fseek(acpi_bat_fp, 0, SEEK_SET);
1125 strcpy(charging_state, "unknown");
1127 while (!feof(acpi_bat_fp)) {
1129 if (fgets(buf, 256, acpi_bat_fp) == NULL)
1132 /* let's just hope units are ok */
1134 sscanf(buf, "charging state: %63s",
1136 else if (buf[0] == 'p')
1137 sscanf(buf, "present rate: %d",
1139 else if (buf[0] == 'r')
1140 sscanf(buf, "remaining capacity: %d",
1141 &remaining_capacity);
1145 if (strcmp(charging_state, "charging") == 0) {
1146 if (acpi_last_full != 0 && present_rate > 0) {
1147 strcpy(last_battery_str, "charging ");
1148 format_seconds(last_battery_str + 9,
1151 remaining_capacity) * 60 *
1153 } else if (acpi_last_full != 0
1154 && present_rate <= 0) {
1155 sprintf(last_battery_str, "charging %d%%",
1156 remaining_capacity * 100 /
1159 strcpy(last_battery_str, "charging");
1163 else if (strcmp(charging_state, "discharging") == 0) {
1164 if (present_rate > 0)
1165 format_seconds(last_battery_str, 63,
1166 (remaining_capacity * 60 *
1167 60) / present_rate);
1169 sprintf(last_battery_str,
1171 remaining_capacity * 100 /
1175 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1176 else if (strcmp(charging_state, "charged") == 0) {
1177 if (acpi_last_full != 0
1178 && remaining_capacity != acpi_last_full)
1179 sprintf(last_battery_str, "charged %d%%",
1180 remaining_capacity * 100 /
1183 strcpy(last_battery_str, "charged");
1185 /* unknown, probably full / AC */
1187 if (acpi_last_full != 0
1188 && remaining_capacity != acpi_last_full)
1189 sprintf(last_battery_str, "unknown %d%%",
1190 remaining_capacity * 100 /
1193 strcpy(last_battery_str, "AC");
1197 if (apm_bat_fp == NULL)
1198 apm_bat_fp = open_file(APM_PATH, &rep2);
1200 if (apm_bat_fp != NULL) {
1201 int ac, status, flag, life;
1204 "%*s %*s %*x %x %x %x %d%%",
1205 &ac, &status, &flag, &life);
1208 /* could check now that there is ac */
1209 snprintf(last_battery_str, 64, "AC");
1210 } else if (ac && life != 100) { /* could check that status==3 here? */
1211 snprintf(last_battery_str, 64,
1212 "charging %d%%", life);
1214 snprintf(last_battery_str, 64, "%d%%",
1218 /* it seemed to buffer it so file must be closed (or could use syscalls
1219 * directly but I don't feel like coding it now) */
1225 snprintf(buf, n, "%s", last_battery_str);
1230 show_nice_processes = 1;
1231 process_find_top(info.cpu, info.memu);
1232 info.first_process = get_first_process();
1237 * The following ifdefs were adapted from gkrellm
1239 #include <linux/major.h>
1241 #if ! defined (MD_MAJOR)
1245 #if !defined(LVM_BLK_MAJOR)
1246 #define LVM_BLK_MAJOR 58
1249 #if !defined(NBD_MAJOR)
1250 #define NBD_MAJOR 43
1253 void update_diskio()
1255 static unsigned int last = UINT_MAX;
1260 unsigned int current = 0;
1261 unsigned int reads, writes = 0;
1265 fp = fopen("/proc/diskstats", "r");
1267 fseek(fp, 0, SEEK_SET);
1270 /* read reads and writes from all disks (minor = 0), including
1271 * cd-roms and floppies, and summ them up
1275 fgets(buf, 512, fp);
1276 col_count = sscanf(buf, "%u %u %*s %*u %*u %u %*u %*u %*u %u",
1277 &major, &minor, &reads, &writes);
1278 /* ignore subdevices (they have only 3 matching entries in their line)
1279 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
1281 * XXX ignore devices which are part of a SW RAID (MD_MAJOR)
1283 if (col_count > 3 &&
1284 major != LVM_BLK_MAJOR && major != NBD_MAJOR &&
1285 major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
1286 current += reads + writes;
1290 /* since the values in /proc/diststats are absolute, we have
1291 * to substract our last reading. The numbers stand for
1292 * "sectors read", and we therefore have to divide by two to
1294 int tot = ((double)(current-last)/2);
1295 if (last > current) {
1296 /* we hit this either if it's the very first time we
1297 * run this, or when /proc/diskstats overflows; while
1298 * 0 is not correct, it's at least not way off */