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 /* need the procraw service from the libdexter dxt-sysinfo plugin */
37 #include <dxt-sysinfo/procraw-public.h>
38 #define PROCRAW_SERVICE_UUID "ce975a10-0e52-458a-a4b9-253734760436"
39 /* timed sampler that delivers the procraw data */
40 static DexterTimedSampler *procraw_sampler = NULL;
41 /* procraw structure used as /proc surrogate */
42 static DxtSysinfoProcrawData procraw_data;
43 /* data selector mask for the service */
47 static int show_nice_processes;
49 /* this flags tells the linux routines to use the /proc system
50 * where possible, even if other api's are available, e.g. sysinfo()
51 * or getloadavg(). the reason for this is to allow for /proc-based
52 * distributed monitoring. using a flag in this manner creates less
55 static int prefer_proc = 0;
66 struct sysinfo s_info;
68 info.uptime = (double) s_info.uptime;
76 if (!(fp = open_file("/proc/uptime", &rep)))
80 fscanf(fp, "%lf", &info.uptime);
83 info.mask |= (1 << INFO_UPTIME);
86 /* these things are also in sysinfo except Buffers:, that's why I'm reading
96 info.mem = info.memmax = info.swap = info.swapmax = info.bufmem =
97 info.buffers = info.cached = 0;
99 if (!(meminfo_fp = open_file("/proc/meminfo", &rep)))
102 while (!feof(meminfo_fp)) {
103 if (fgets(buf, 255, meminfo_fp) == NULL)
106 if (strncmp(buf, "MemTotal:", 9) == 0) {
107 sscanf(buf, "%*s %Lu", &info.memmax);
108 } else if (strncmp(buf, "MemFree:", 8) == 0) {
109 sscanf(buf, "%*s %Lu", &info.mem);
110 } else if (strncmp(buf, "SwapTotal:", 10) == 0) {
111 sscanf(buf, "%*s %Lu", &info.swapmax);
112 } else if (strncmp(buf, "SwapFree:", 9) == 0) {
113 sscanf(buf, "%*s %Lu", &info.swap);
114 } else if (strncmp(buf, "Buffers:", 8) == 0) {
115 sscanf(buf, "%*s %Lu", &info.buffers);
116 } else if (strncmp(buf, "Cached:", 7) == 0) {
117 sscanf(buf, "%*s %Lu", &info.cached);
121 info.mem = info.memmax - info.mem;
122 info.swap = info.swapmax - info.swap;
124 info.bufmem = info.cached + info.buffers;
126 info.mask |= (1 << INFO_MEM) | (1 << INFO_BUFFERS);
131 static FILE *net_wireless_fp;
133 inline void update_net_stats()
137 // FIXME: arbitrary size chosen to keep code simple.
139 unsigned int curtmp1, curtmp2;
146 delta = current_update_time - last_update_time;
150 /* open file and ignore first two lines */
151 if (!(net_dev_fp = open_file("/proc/net/dev", &rep)))
154 fgets(buf, 255, net_dev_fp); /* garbage */
155 fgets(buf, 255, net_dev_fp); /* garbage (field names) */
157 /* read each interface */
158 for (i2 = 0; i2 < 16; i2++) {
161 long long r, t, last_recv, last_trans;
163 if (fgets(buf, 255, net_dev_fp) == NULL) {
167 while (isspace((int) *p))
172 while (*p && *p != ':')
179 ns = get_net_stat(s);
181 memset(&(ns->addr.sa_data), 0, 14);
182 last_recv = ns->recv;
183 last_trans = ns->trans;
186 /* bytes packets errs drop fifo frame compressed multicast|bytes ... */
187 "%Ld %*d %*d %*d %*d %*d %*d %*d %Ld",
190 /* if recv or trans is less than last time, an overflow happened */
192 if (r < ns->last_read_recv)
194 ((long long) 4294967295U -
195 ns->last_read_recv) + r;
197 ns->recv += (r - ns->last_read_recv);
198 ns->last_read_recv = r;
200 if (t < ns->last_read_trans)
202 ((long long) 4294967295U -
203 ns->last_read_trans) + t;
205 ns->trans += (t - ns->last_read_trans);
206 ns->last_read_trans = t;
208 /*** ip addr patch ***/
209 i = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
211 conf.ifc_buf = malloc(sizeof(struct ifreq) * 16);
213 conf.ifc_len = sizeof(struct ifreq) * 16;
215 ioctl((long) i, SIOCGIFCONF, &conf);
217 for (k = 0; k < conf.ifc_len / sizeof(struct ifreq); k++) {
219 ns = get_net_stat(((struct ifreq *) conf.
220 ifc_buf)[k].ifr_ifrn.ifrn_name);
222 ((struct ifreq *) conf.ifc_buf)[k].ifr_ifru.
231 /*** end ip addr patch ***/
234 /* calculate speeds */
235 ns->net_rec[0] = (ns->recv - last_recv) / delta;
236 ns->net_trans[0] = (ns->trans - last_trans) / delta;
240 for (i = 0; (unsigned) i < info.net_avg_samples; i++) {
241 curtmp1 += ns->net_rec[i];
242 curtmp2 += ns->net_trans[i];
244 ns->recv_speed = curtmp1 / (double) info.net_avg_samples;
245 ns->trans_speed = curtmp2 / (double) info.net_avg_samples;
246 if (info.net_avg_samples > 1) {
247 for (i = info.net_avg_samples; i > 1; i--) {
248 ns->net_rec[i - 1] = ns->net_rec[i - 2];
249 ns->net_trans[i - 1] =
250 ns->net_trans[i - 2];
258 info.mask |= (1 << INFO_NET);
261 inline void update_wifi_stats()
263 /** wireless stats patch by Bobby Beckmann **/
267 /*open file and ignore first two lines sorry, this code sucks ass right now, i'll clean it up later */
268 if (net_wireless_fp == NULL)
269 net_wireless_fp = open_file("/proc/net/wireless", &rep);
271 fseek(net_wireless_fp, 0, SEEK_SET);
272 if (net_wireless_fp == NULL)
275 fgets(buf, 255, net_wireless_fp); /* garbage */
276 fgets(buf, 255, net_wireless_fp); /* garbage (field names) */
278 /* read each interface */
279 for (i = 0; i < 16; i++) {
284 if (fgets(buf, 255, net_wireless_fp) == NULL)
287 while (isspace((int) *p))
292 while (*p && *p != ':')
299 ns = get_net_stat(s);
301 sscanf(p, "%*d %d. %d. %d", &l, &m, &n);
303 ns->linkstatus = (int) (log(MIN(MAX(l,1),92)) / log(92) * 100);
307 /*** end wireless patch ***/
312 void update_total_processes()
317 struct sysinfo s_info;
319 info.procs = s_info.procs;
327 if (!(fp = open_file("/proc/loadavg", &rep)))
331 fscanf(fp, "%*f %*f %*f %*d/%hd", &info.procs );
334 info.mask |= (1 << INFO_PROCS);
337 #define CPU_SAMPLE_COUNT 15
339 unsigned long long cpu_user;
340 unsigned long long cpu_system;
341 unsigned long long cpu_nice;
342 unsigned long long cpu_idle;
343 unsigned long long cpu_iowait;
344 unsigned long long cpu_irq;
345 unsigned long long cpu_softirq;
346 unsigned long long cpu_steal;
347 unsigned long long cpu_total;
348 unsigned long long cpu_active_total;
349 unsigned long long cpu_last_total;
350 unsigned long long cpu_last_active_total;
351 double cpu_val[CPU_SAMPLE_COUNT];
353 static short cpu_setup = 0;
356 determine if this kernel gives us "extended" statistics information in /proc/stat.
357 Kernels around 2.5 and earlier only reported user, system, nice and idle values in proc stat.
358 Kernels around 2.6 and greater report these PLUS iowait, irq, softirq, and steal
360 void determine_longstat(char * buf) {
361 unsigned long long iowait=0;
362 KFLAG_SETOFF(KFLAG_IS_LONGSTAT);
363 /* scanf will either return -1 or 1 because there is only 1 assignment */
364 if (sscanf(buf, "%*s %*d %*d %*d %*d %llu",&iowait)>0) KFLAG_SETON(KFLAG_IS_LONGSTAT);
372 if (info.cpu_usage) {
377 if (!(stat_fp = open_file("/proc/stat", &rep)))
382 while (!feof(stat_fp)) {
383 if (fgets(buf, 255, stat_fp) == NULL)
386 if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
387 if (info.cpu_count == 0) {
388 determine_longstat(buf);
393 info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
398 #define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
399 #define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
401 inline static void update_stat()
405 static struct cpu_info *cpu = NULL;
410 char * stat_template=NULL;
411 unsigned int malloc_cpu_size=0;
414 /* add check for !info.cpu_usage since that mem is freed on a SIGUSR1 */
415 if (!cpu_setup || !info.cpu_usage) {
420 if (!stat_template) {
421 stat_template = KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT ;
425 malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info);
426 cpu = malloc(malloc_cpu_size);
427 memset(cpu, 0, malloc_cpu_size);
430 if (!(stat_fp = open_file("/proc/stat", &rep)))
434 while (!feof(stat_fp)) {
435 if (fgets(buf, 255, stat_fp) == NULL)
438 if (strncmp(buf, "procs_running ", 14) == 0) {
439 sscanf(buf, "%*s %hu", &info.run_procs);
440 info.mask |= (1 << INFO_RUN_PROCS);
441 } else if (strncmp(buf, "cpu", 3) == 0) {
442 index = isdigit(buf[3]) ? ((int)buf[3]) - 0x2F : 0;
443 sscanf(buf, stat_template
444 , &(cpu[index].cpu_user)
445 , &(cpu[index].cpu_nice)
446 , &(cpu[index].cpu_system)
447 , &(cpu[index].cpu_idle)
448 , &(cpu[index].cpu_iowait)
449 , &(cpu[index].cpu_irq)
450 , &(cpu[index].cpu_softirq)
451 , &(cpu[index].cpu_steal)
454 cpu[index].cpu_total = cpu[index].cpu_user
455 + cpu[index].cpu_nice
456 + cpu[index].cpu_system
457 + cpu[index].cpu_idle
458 + cpu[index].cpu_iowait
460 + cpu[index].cpu_softirq
461 + cpu[index].cpu_steal
464 cpu[index].cpu_active_total = cpu[index].cpu_total - (cpu[index].cpu_idle + cpu[index].cpu_iowait);
465 info.mask |= (1 << INFO_CPU);
467 double delta = current_update_time - last_update_time;
468 if (delta <= 0.001) break;
470 cpu[index].cpu_val[0] = (cpu[index].cpu_active_total - cpu[index].cpu_last_active_total) /
471 (float )(cpu[index].cpu_total - cpu[index].cpu_last_total);
473 for (i=0; i < info.cpu_avg_samples; i++ ) {
474 curtmp += cpu[index].cpu_val[i];
476 /* TESTING -- I've removed this, because I don't think it is right. You shouldn't divide
477 by the cpu count here ... removing for testing */
479 info.cpu_usage[index] = curtmp / info.cpu_avg_samples / info.cpu_count;
481 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
483 /* TESTING -- this line replaces the prev. "suspect" if/else */
484 info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
486 cpu[index].cpu_last_total = cpu[index].cpu_total;
487 cpu[index].cpu_last_active_total = cpu[index].cpu_active_total;
488 for (i = info.cpu_avg_samples - 1; i > 0; i--) {
489 cpu[index].cpu_val[i] = cpu[index].cpu_val[i - 1];
497 void update_running_processes()
502 void update_cpu_usage()
507 void update_load_average()
509 #ifdef HAVE_GETLOADAVG
514 info.loadavg[0] = (float) v[0];
515 info.loadavg[1] = (float) v[1];
516 info.loadavg[2] = (float) v[2];
524 if (!(fp = open_file("/proc/loadavg", &rep)))
526 info.loadavg[0] = info.loadavg[1] = info.loadavg[2] = 0.0;
529 fscanf(fp, "%f %f %f", &info.loadavg[0], &info.loadavg[1], &info.loadavg[2]);
532 info.mask |= (1 << INFO_LOADAVG);
535 #define PROC_I8K "/proc/i8k"
536 #define I8K_DELIM " "
537 static char *i8k_procbuf = NULL;
542 i8k_procbuf = (char*)malloc(128*sizeof(char));
544 if ((fp = fopen(PROC_I8K,"r")) == NULL) {
545 CRIT_ERR("/proc/i8k doesn't exist! use insmod to make sure the kernel driver is loaded...");
548 memset(&i8k_procbuf[0],0,128);
549 if (fread(&i8k_procbuf[0],sizeof(char),128,fp) == 0) {
550 ERR("something wrong with /proc/i8k...");
555 i8k.version = strtok(&i8k_procbuf[0],I8K_DELIM);
556 i8k.bios = strtok(NULL,I8K_DELIM);
557 i8k.serial = strtok(NULL,I8K_DELIM);
558 i8k.cpu_temp = strtok(NULL,I8K_DELIM);
559 i8k.left_fan_status = strtok(NULL,I8K_DELIM);
560 i8k.right_fan_status = strtok(NULL,I8K_DELIM);
561 i8k.left_fan_rpm = strtok(NULL,I8K_DELIM);
562 i8k.right_fan_rpm = strtok(NULL,I8K_DELIM);
563 i8k.ac_status = strtok(NULL,I8K_DELIM);
564 i8k.buttons_status = strtok(NULL,I8K_DELIM);
568 /***********************************************************/
569 /***********************************************************/
570 /***********************************************************/
572 static int no_dots(const struct dirent *d)
574 if (d->d_name[0] == '.')
580 get_first_file_in_a_directory(const char *dir, char *s, int *rep)
582 struct dirent **namelist;
585 n = scandir(dir, &namelist, no_dots, alphasort);
588 ERR("scandir for %s: %s", dir, strerror(errno));
597 strncpy(s, namelist[0]->d_name, 255);
600 for (i = 0; i < n; i++)
608 #define I2C_DIR "/sys/bus/i2c/devices/"
611 open_i2c_sensor(const char *dev, const char *type, int n, int *div,
619 /* if i2c device is NULL or *, get first */
620 if (dev == NULL || strcmp(dev, "*") == 0) {
622 if (!get_first_file_in_a_directory(I2C_DIR, buf, &rep))
627 /* change vol to in */
628 if (strcmp(type, "vol") == 0)
631 if (strcmp(type, "tempf") == 0) {
632 snprintf(path, 255, I2C_DIR "%s/%s%d_input", dev, "temp", n);
634 snprintf(path, 255, I2C_DIR "%s/%s%d_input", dev, type, n);
636 strncpy(devtype, path, 255);
639 fd = open(path, O_RDONLY);
641 CRIT_ERR("can't open '%s': %s\nplease fix i2c or remove it from Conky", path, strerror(errno));
644 if (strcmp(type, "in") == 0 || strcmp(type, "temp") == 0
645 || strcmp(type, "tempf") == 0)
649 /* fan does not use *_div as a read divisor */
650 if (strcmp("fan", type) == 0)
653 /* test if *_div file exist, open it and use it as divisor */
654 if (strcmp(type, "tempf") == 0) {
655 snprintf(path, 255, I2C_DIR "%s/%s%d_div", "one", "two",
658 snprintf(path, 255, I2C_DIR "%s/%s%d_div", dev, type, n);
661 divfd = open(path, O_RDONLY);
666 divn = read(divfd, divbuf, 63);
667 /* should read until n == 0 but I doubt that kernel will give these
668 * in multiple pieces. :) */
678 double get_i2c_info(int *fd, int div, char *devtype, char *type)
685 lseek(*fd, 0, SEEK_SET);
691 n = read(*fd, buf, 63);
692 /* should read until n == 0 but I doubt that kernel will give these
693 * in multiple pieces. :) */
700 *fd = open(devtype, O_RDONLY);
702 ERR("can't open '%s': %s", devtype, strerror(errno));
704 /* My dirty hack for computing CPU value
705 * Filedil, from forums.gentoo.org
707 /* if (strstr(devtype, "temp1_input") != NULL)
708 return -15.096+1.4893*(val / 1000.0); */
711 /* divide voltage and temperature by 1000 */
712 /* or if any other divisor is given, use that */
713 if (strcmp(type, "tempf") == 0) {
715 return ((val / div + 40) * 9.0 / 5) - 40;
717 return ((val / 1000.0 + 40) * 9.0 / 5) - 40;
719 return ((val + 40) * 9.0 / 5) - 40;
730 /* Prior to kernel version 2.6.12, the CPU fan speed was available
731 * in ADT746X_FAN_OLD, whereas later kernel versions provide this
732 * information in ADT746X_FAN.
734 #define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
735 #define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
737 void get_adt746x_fan( char * p_client_buffer, size_t client_buffer_size )
740 char adt746x_fan_state[64];
743 if ( !p_client_buffer || client_buffer_size <= 0 )
746 if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
747 && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL)
750 sprintf(adt746x_fan_state, "adt746x not found");
754 fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
755 adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
759 snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_fan_state );
763 /* Prior to kernel version 2.6.12, the CPU temperature was found
764 * in ADT746X_CPU_OLD, whereas later kernel versions provide this
765 * information in ADT746X_CPU.
767 #define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
768 #define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
770 void get_adt746x_cpu( char * p_client_buffer, size_t client_buffer_size )
773 char adt746x_cpu_state[64];
776 if ( !p_client_buffer || client_buffer_size <= 0 )
779 if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
780 && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL)
782 sprintf(adt746x_cpu_state, "adt746x not found");
786 fscanf(fp, "%2s", adt746x_cpu_state);
790 snprintf( p_client_buffer, client_buffer_size, "%s", adt746x_cpu_state );
794 /* Thanks to "Walt Nelson" <wnelsonjr@comcast.net> */
796 /***********************************************************************/
798 * This file is part of x86info.
799 * (C) 2001 Dave Jones.
801 * Licensed under the terms of the GNU GPL License version 2.
803 * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
804 * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz>
807 #if defined(__i386) || defined(__x86_64)
808 __inline__ unsigned long long int rdtsc()
810 unsigned long long int x;
811 __asm__ volatile (".byte 0x0f, 0x31":"=A" (x));
816 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
817 void get_freq_dynamic( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor )
819 #if defined(__i386) || defined(__x86_64)
821 struct timeval tvstart, tvstop;
822 unsigned long long cycles[2]; /* gotta be 64 bit */
823 unsigned int microseconds; /* total time taken */
825 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
828 memset(&tz, 0, sizeof(tz));
830 /* get this function in cached memory */
831 gettimeofday(&tvstart, &tz);
833 gettimeofday(&tvstart, &tz);
835 /* we don't trust that this is any specific length of time */
838 gettimeofday(&tvstop, &tz);
839 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
840 (tvstop.tv_usec - tvstart.tv_usec);
842 snprintf( p_client_buffer, client_buffer_size, p_format, (float)((cycles[1] - cycles[0]) / microseconds) / divisor );
845 /* FIXME: hardwired: get freq for first cpu!
846 this whole function needs to be rethought and redone for
847 multi-cpu/multi-core/multi-threaded environments and
848 arbitrary combinations thereof
850 get_freq( p_client_buffer, client_buffer_size, p_format, divisor, 1 );
856 #define CPUFREQ_PREFIX "/sys/devices/system/cpu"
857 #define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
859 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
860 char get_freq( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
868 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
873 char current_freq_file[128];
874 snprintf(current_freq_file, 127, "%s/cpu%d/%s",CPUFREQ_PREFIX, cpu-1, CPUFREQ_POSTFIX);
875 f = fopen(current_freq_file, "r");
878 /* if there's a cpufreq /sys node, read the current frequency from this node;
879 * divide by 1000 to get Mhz. */
880 if (fgets(s, sizeof(s), f)) {
881 s[strlen(s)-1] = '\0';
882 freq = strtod(s, NULL);
885 snprintf( p_client_buffer, client_buffer_size, p_format, (freq/1000)/divisor );
890 f = open_file("/proc/cpuinfo", &rep); //open the CPU information file
892 perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
896 while (fgets(s, sizeof(s), f) != NULL){ //read the file
898 #if defined(__i386) || defined(__x86_64)
899 if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) { //and search for the cpu mhz
902 if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) { // different on alpha
904 if (strncmp(s, "clock", 5) == 0 && cpu == 0) { // this is different on ppc for some reason
905 #endif // defined(__alpha)
906 #endif // defined(__i386) || defined(__x86_64)
908 strcpy(frequency, strchr(s, ':') + 2); //copy just the number
910 frequency[strlen(frequency) - 6] = '\0';// strip " est.\n"
911 freq = strtod(frequency, NULL)/1000000; // kernel reports in Hz
913 frequency[strlen(frequency) - 1] = '\0'; // strip \n
914 freq = strtod(frequency, NULL);
918 if (strncmp(s, "processor", 9) == 0) {
926 snprintf( p_client_buffer, client_buffer_size, p_format, (float)freq/divisor );
930 #define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
932 /* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
933 char get_voltage( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
935 /* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks
947 /* Peter Tarjan (ptarjan@citromail.hu) */
952 char current_freq_file[128];
956 /* build the voltage file name */
958 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
959 CPUFREQ_PREFIX, cpu, CPUFREQ_POSTFIX);
961 if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
964 /* read the current cpu frequency from the /sys node */
965 f = fopen(current_freq_file, "r");
967 if (fgets(s, sizeof(s), f)) {
968 s[strlen(s)-1] = '\0';
969 freq = strtod(s, NULL);
973 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
974 perror("get_voltage()");
981 snprintf(current_freq_file, 127, "%s/cpu%d/%s",
982 CPUFREQ_PREFIX, cpu, CPUFREQ_VOLTAGE);
984 /* use the current cpu frequency to find the corresponding voltage */
985 f = fopen(current_freq_file, "r");
990 if (fgets(line, 255, f) == NULL) break;
991 sscanf(line, "%d %d", &freq_comp, &voltage);
992 if(freq_comp == freq) break;
996 fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
997 perror("get_voltage()");
1003 snprintf( p_client_buffer, client_buffer_size, p_format, (float)voltage/divisor );
1008 #define ACPI_FAN_DIR "/proc/acpi/fan/"
1010 void get_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1017 if ( !p_client_buffer || client_buffer_size <= 0 )
1020 /* yeah, slow... :/ */
1021 if (!get_first_file_in_a_directory(ACPI_FAN_DIR, buf, &rep))
1023 snprintf( p_client_buffer, client_buffer_size, "no fans?" );
1027 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_FAN_DIR, buf );
1029 fp = open_file(buf2, &rep);
1031 snprintf( p_client_buffer, client_buffer_size, "can't open fan's state file" );
1034 memset(buf,0,sizeof(buf));
1035 fscanf(fp, "%*s %99s", buf);
1038 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1043 #define ACPI_AC_ADAPTER_DIR "/proc/acpi/ac_adapter/"
1045 void get_acpi_ac_adapter( char * p_client_buffer, size_t client_buffer_size )
1052 if ( !p_client_buffer || client_buffer_size <= 0 )
1055 /* yeah, slow... :/ */
1056 if (!get_first_file_in_a_directory(ACPI_AC_ADAPTER_DIR, buf, &rep))
1058 snprintf( p_client_buffer, client_buffer_size, "no ac_adapters?" );
1062 snprintf(buf2, sizeof(buf2), "%s%s/state", ACPI_AC_ADAPTER_DIR, buf );
1065 fp = open_file(buf2, &rep);
1067 snprintf( p_client_buffer, client_buffer_size, "No ac adapter found.... where is it?" );
1070 memset(buf,0,sizeof(buf));
1071 fscanf(fp, "%*s %99s", buf );
1074 snprintf( p_client_buffer, client_buffer_size, "%s", buf );
1080 /proc/acpi/thermal_zone/THRM/cooling_mode
1081 cooling mode: active
1082 /proc/acpi/thermal_zone/THRM/polling_frequency
1084 /proc/acpi/thermal_zone/THRM/state
1086 /proc/acpi/thermal_zone/THRM/temperature
1088 /proc/acpi/thermal_zone/THRM/trip_points
1090 passive: 73 C: tc1=4 tc2=3 tsp=40 devices=0xcdf6e6c0
1093 #define ACPI_THERMAL_DIR "/proc/acpi/thermal_zone/"
1094 #define ACPI_THERMAL_FORMAT "/proc/acpi/thermal_zone/%s/temperature"
1096 int open_acpi_temperature(const char *name)
1102 if (name == NULL || strcmp(name, "*") == 0) {
1104 if (!get_first_file_in_a_directory
1105 (ACPI_THERMAL_DIR, buf, &rep))
1110 snprintf(path, 255, ACPI_THERMAL_FORMAT, name);
1112 fd = open(path, O_RDONLY);
1114 ERR("can't open '%s': %s", path, strerror(errno));
1119 static double last_acpi_temp;
1120 static double last_acpi_temp_time;
1122 double get_acpi_temperature(int fd)
1127 /* don't update acpi temperature too often */
1128 if (current_update_time - last_acpi_temp_time < 11.32) {
1129 return last_acpi_temp;
1131 last_acpi_temp_time = current_update_time;
1133 /* seek to beginning */
1134 lseek(fd, 0, SEEK_SET);
1140 n = read(fd, buf, 255);
1142 ERR("can't read fd %d: %s", fd, strerror(errno));
1145 sscanf(buf, "temperature: %lf", &last_acpi_temp);
1149 return last_acpi_temp;
1153 hipo@lepakko hipo $ cat /proc/acpi/battery/BAT1/info
1155 design capacity: 4400 mAh
1156 last full capacity: 4064 mAh
1157 battery technology: rechargeable
1158 design voltage: 14800 mV
1159 design capacity warning: 300 mAh
1160 design capacity low: 200 mAh
1161 capacity granularity 1: 32 mAh
1162 capacity granularity 2: 32 mAh
1164 serial number: 16922
1170 hipo@lepakko conky $ cat /proc/acpi/battery/BAT1/state
1173 charging state: unknown
1175 remaining capacity: 4064 mAh
1176 present voltage: 16608 mV
1180 2213<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1181 2213<@jupet kellari ö> 1.16 1.2 0x03 0x01 0xff 0x10 -1% -1 ?
1182 2213<@jupet kellari ö> (-1 ollee ei akkua kiinni, koska akku on pöydällä)
1183 2214<@jupet kellari ö> jupet@lagi-unstable:~$ cat /proc/apm
1184 2214<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 98% -1 ?
1186 2238<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 100% -1 ? ilman verkkovirtaa
1187 2239<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x00 0x01 99% -1 ? verkkovirralla
1189 2240<@jupet kellari ö> 1.16 1.2 0x03 0x01 0x03 0x09 100% -1 ? verkkovirralla ja monitori päällä
1190 2241<@jupet kellari ö> 1.16 1.2 0x03 0x00 0x00 0x01 99% -1 ? monitori päällä mutta ilman verkkovirtaa
1193 #define ACPI_BATTERY_BASE_PATH "/proc/acpi/battery"
1194 #define APM_PATH "/proc/apm"
1196 static FILE *acpi_bat_fp;
1197 static FILE *apm_bat_fp;
1199 static int acpi_last_full;
1201 static char last_battery_str[64]; /* e.g. "charging 75%" */
1202 static char last_battery_time_str[64]; /* e.g. "3h 15m" */
1204 static double last_battery_time;
1206 void get_battery_stuff(char *buf, unsigned int n, const char *bat, int item)
1208 static int rep = 0, rep2 = 0;
1209 char acpi_path[128];
1210 snprintf(acpi_path, 127, ACPI_BATTERY_BASE_PATH "/%s/state", bat);
1212 /* don't update battery too often */
1213 if (current_update_time - last_battery_time < 29.5)
1214 goto set_return_value;
1216 last_battery_time = current_update_time;
1218 memset (last_battery_str, 0, sizeof (last_battery_str));
1219 memset (last_battery_time_str, 0, sizeof (last_battery_time_str));
1221 /* first try ACPI */
1223 if (acpi_bat_fp == NULL && apm_bat_fp == NULL)
1224 acpi_bat_fp = open_file(acpi_path, &rep);
1226 if (acpi_bat_fp != NULL) {
1227 int present_rate = -1;
1228 int remaining_capacity = -1;
1229 char charging_state[64];
1232 /* read last full capacity if it's zero */
1233 if (acpi_last_full == 0) {
1238 ACPI_BATTERY_BASE_PATH "/%s/info", bat);
1239 fp = open_file(path, &rep);
1243 if (fgets(b, 256, fp) == NULL)
1245 if (sscanf(b, "last full capacity: %d", &acpi_last_full) != 0) {
1254 fseek(acpi_bat_fp, 0, SEEK_SET);
1256 strcpy(charging_state, "unknown");
1258 while (!feof(acpi_bat_fp)) {
1260 if (fgets(buf, 256, acpi_bat_fp) == NULL)
1263 /* let's just hope units are ok */
1264 if (strncmp (buf, "present:", 8) == 0)
1265 sscanf(buf, "present: %4s", present);
1266 else if (strncmp (buf, "charging state:", 15) == 0)
1267 sscanf(buf, "charging state: %63s", charging_state);
1268 else if (strncmp (buf, "present rate:", 13) == 0)
1269 sscanf(buf, "present rate: %d", &present_rate);
1270 else if (strncmp(buf, "remaining capacity:", 19) == 0)
1271 sscanf(buf, "remaining capacity: %d", &remaining_capacity);
1274 /* Hellf[i]re notes that remaining capacity can exceed acpi_last_full */
1275 if (remaining_capacity > acpi_last_full)
1276 acpi_last_full = remaining_capacity; /* normalize to 100% */
1279 if (strcmp(present, "no") == 0) {
1280 strncpy(last_battery_str, "not present", 64);
1283 else if (strcmp(charging_state, "charging") == 0) {
1284 if (acpi_last_full != 0 && present_rate > 0) {
1285 /* e.g. charging 75% */
1286 snprintf(last_battery_str, sizeof(last_battery_str)-1, "charging %i%%",
1287 (int) ((remaining_capacity * 100) / acpi_last_full));
1289 format_seconds(last_battery_time_str, sizeof(last_battery_time_str)-1,
1290 (long) (((acpi_last_full - remaining_capacity) * 3600) /
1292 } else if (acpi_last_full != 0 && present_rate <= 0) {
1293 snprintf(last_battery_str, sizeof(last_battery_str)-1, "charging %d%%",
1294 (int) ((remaining_capacity * 100) / acpi_last_full));
1296 strncpy(last_battery_str, "charging", sizeof(last_battery_str)-1);
1300 else if (strncmp(charging_state, "discharging", 64) == 0) {
1301 if (present_rate > 0) {
1302 /* e.g. discharging 35% */
1303 snprintf(last_battery_str, sizeof(last_battery_str)-1, "discharging %i%%",
1304 (int) ((remaining_capacity * 100) / acpi_last_full));
1306 format_seconds(last_battery_time_str, sizeof(last_battery_time_str)-1,
1307 (long) ((remaining_capacity * 3600) / present_rate));
1308 } else if (present_rate == 0) { /* Thanks to Nexox for this one */
1309 snprintf(last_battery_str, sizeof(last_battery_str)-1, "full");
1311 snprintf(last_battery_str, sizeof(last_battery_str)-1,
1313 (int) ((remaining_capacity * 100) / acpi_last_full));
1317 /* thanks to Lukas Zapletal <lzap@seznam.cz> */
1318 else if (strncmp(charging_state, "charged", 64) == 0) {
1319 strcpy(last_battery_str, "charged");
1321 /* unknown, probably full / AC */
1323 if (acpi_last_full != 0
1324 && remaining_capacity != acpi_last_full)
1325 snprintf(last_battery_str, 64, "unknown %d%%",
1326 (int) ((remaining_capacity * 100) / acpi_last_full));
1328 strncpy(last_battery_str, "AC", 64);
1332 if (apm_bat_fp == NULL)
1333 apm_bat_fp = open_file(APM_PATH, &rep2);
1335 if (apm_bat_fp != NULL) {
1336 int ac, status, flag, life;
1339 "%*s %*s %*x %x %x %x %d%%",
1340 &ac, &status, &flag, &life);
1343 /* could check now that there is ac */
1344 snprintf(last_battery_str, 64, "AC");
1345 } else if (ac && life != 100) { /* could check that status==3 here? */
1346 snprintf(last_battery_str, 64,
1347 "charging %d%%", life);
1349 snprintf(last_battery_str, 64, "%d%%",
1353 /* it seemed to buffer it so file must be closed (or could use syscalls
1354 * directly but I don't feel like coding it now) */
1362 case BATTERY_STATUS:
1364 snprintf(buf, n, "%s", last_battery_str);
1369 snprintf(buf, n, "%s", last_battery_time_str);
1378 /* On Apple powerbook and ibook:
1379 $ cat /proc/pmu/battery_0
1386 $ cat /proc/pmu/info
1387 PMU driver version : 2
1388 PMU firmware version : 0c
1393 /* defines as in <linux/pmu.h> */
1394 #define PMU_BATT_PRESENT 0x00000001
1395 #define PMU_BATT_CHARGING 0x00000002
1397 static FILE* pmu_battery_fp;
1398 static FILE* pmu_info_fp;
1399 static char pb_battery_info[3][32];
1400 static double pb_battery_info_update;
1402 #define PMU_PATH "/proc/pmu"
1403 void get_powerbook_batt_info(char *buf, size_t n, int i)
1406 const char* batt_path = PMU_PATH "/battery_0";
1407 const char* info_path = PMU_PATH "/info";
1408 int flags, charge, max_charge, ac = -1;
1411 /* don't update battery too often */
1412 if (current_update_time - pb_battery_info_update < 29.5) {
1413 snprintf(buf, n, "%s", pb_battery_info[i]);
1416 pb_battery_info_update = current_update_time;
1418 if (pmu_battery_fp == NULL)
1419 pmu_battery_fp = open_file(batt_path, &rep);
1421 if (pmu_battery_fp != NULL) {
1422 rewind(pmu_battery_fp);
1423 while (!feof(pmu_battery_fp)) {
1425 if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL)
1429 sscanf(buf, "flags : %8x", &flags);
1430 else if (buf[0] == 'c' && buf[1] == 'h')
1431 sscanf(buf, "charge : %d", &charge);
1432 else if (buf[0] == 'm')
1433 sscanf(buf, "max_charge : %d", &max_charge);
1434 else if (buf[0] == 't')
1435 sscanf(buf, "time rem. : %ld", &time);
1438 if (pmu_info_fp == NULL)
1439 pmu_info_fp = open_file(info_path, &rep);
1441 if (pmu_info_fp != NULL) {
1442 rewind(pmu_info_fp);
1443 while (!feof(pmu_info_fp)) {
1445 if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL)
1448 sscanf(buf, "AC Power : %d", &ac);
1451 /* update status string */
1452 if ((ac && !(flags & PMU_BATT_PRESENT)))
1453 strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
1454 else if (ac && (flags & PMU_BATT_PRESENT)
1455 && !(flags & PMU_BATT_CHARGING))
1456 strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
1457 else if ((flags & PMU_BATT_PRESENT)
1458 && (flags & PMU_BATT_CHARGING))
1459 strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
1461 strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
1463 /* update percentage string */
1465 pb_battery_info[PB_BATT_PERCENT][0] = 0;
1467 snprintf(pb_battery_info[PB_BATT_PERCENT],
1468 sizeof(pb_battery_info[PB_BATT_PERCENT]),
1469 "%d%%", (charge * 100)/max_charge);
1471 /* update time string */
1472 if (time == 0) /* fully charged or battery not present */
1473 pb_battery_info[PB_BATT_TIME][0] = 0;
1474 else if (time < 60*60) /* don't show secs */
1475 format_seconds_short(pb_battery_info[PB_BATT_TIME],
1476 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1478 format_seconds(pb_battery_info[PB_BATT_TIME],
1479 sizeof(pb_battery_info[PB_BATT_TIME]), time);
1481 snprintf(buf, n, "%s", pb_battery_info[i]);
1486 show_nice_processes = 1;
1487 process_find_top(info.cpu, info.memu);
1488 info.first_process = get_first_process();
1493 * The following ifdefs were adapted from gkrellm
1495 #include <linux/major.h>
1497 #if ! defined (MD_MAJOR)
1501 #if !defined(LVM_BLK_MAJOR)
1502 #define LVM_BLK_MAJOR 58
1505 #if !defined(NBD_MAJOR)
1506 #define NBD_MAJOR 43
1509 void update_diskio()
1511 static unsigned int last = UINT_MAX;
1517 unsigned int current = 0;
1518 unsigned int reads, writes = 0;
1521 if (!(fp =open_file("/proc/diskstats", &rep)))
1524 /* read reads and writes from all disks (minor = 0), including
1525 * cd-roms and floppies, and summ them up
1529 fgets(buf, 512, fp);
1530 col_count = sscanf(buf, "%u %u %*s %*u %*u %u %*u %*u %*u %u",
1531 &major, &minor, &reads, &writes);
1532 /* ignore subdevices (they have only 3 matching entries in their line)
1533 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
1535 * XXX ignore devices which are part of a SW RAID (MD_MAJOR)
1537 if (col_count > 3 &&
1538 major != LVM_BLK_MAJOR && major != NBD_MAJOR &&
1539 major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
1540 current += reads + writes;
1544 /* since the values in /proc/diststats are absolute, we have
1545 * to substract our last reading. The numbers stand for
1546 * "sectors read", and we therefore have to divide by two to
1548 int tot = ((double)(current-last)/2);
1549 if (last > current) {
1550 /* we hit this either if it's the very first time we
1551 * run this, or when /proc/diskstats overflows; while
1552 * 0 is not correct, it's at least not way off */
1562 /* Here come the IBM ACPI-specific things. For reference, see
1563 http://ibm-acpi.sourceforge.net/README
1564 If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
1580 The content of these files is described in detail in the aforementioned
1581 README - some of them also in the following functions accessing them.
1582 Peter Tarjan (ptarjan@citromail.hu)
1585 #define IBM_ACPI_DIR "/proc/acpi/ibm"
1587 void get_ibm_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
1589 /* get fan speed on IBM/Lenovo laptops running the ibm acpi.
1590 /proc/acpi/ibm/fan looks like this (3 lines):
1593 commands: enable, disable
1594 Peter Tarjan (ptarjan@citromail.hu)
1597 if ( !p_client_buffer || client_buffer_size <= 0 )
1601 unsigned int speed=0;
1603 snprintf(fan, 127, "%s/fan",IBM_ACPI_DIR);
1605 fp = fopen(fan, "r");
1611 if (fgets(line, 255, fp) == NULL) break;
1612 if (sscanf(line, "speed: %d", &speed)) break;
1617 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", fan, strerror(errno));
1621 snprintf( p_client_buffer, client_buffer_size, "%d", speed );
1626 static double last_ibm_acpi_temp_time;
1627 void get_ibm_acpi_temps()
1629 /* get the measured temperatures from the temperature sensors
1630 on IBM/Lenovo laptops running the ibm acpi.
1631 There are 8 values in /proc/acpi/ibm/thermal, and according to
1632 http://ibm-acpi.sourceforge.net/README
1633 these mean the following (at least on an IBM R51...)
1634 0: CPU (also on the T series laptops)
1635 1: Mini PCI Module (?)
1637 3: GPU (also on the T series laptops)
1642 I'm not too sure about those with the question mark, but the values I'm
1643 reading from *my* thermal file (on a T42p) look realistic for the
1644 hdd and the battery.
1645 #5 and #7 are always -128.
1646 /proc/acpi/ibm/thermal looks like this (1 line):
1647 temperatures: 41 43 31 46 33 -128 29 -128
1648 Peter Tarjan (ptarjan@citromail.hu)
1651 /* don't update too often */
1652 if (current_update_time - last_ibm_acpi_temp_time < 10.00)
1656 last_ibm_acpi_temp_time = current_update_time;
1658 /* if ( !p_client_buffer || client_buffer_size <= 0 )
1664 snprintf(thermal, 127, "%s/thermal",IBM_ACPI_DIR);
1665 fp = fopen(thermal, "r");
1672 if (fgets(line, 255, fp) == NULL) break;
1673 if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
1674 &ibm_acpi.temps[0], &ibm_acpi.temps[1],
1675 &ibm_acpi.temps[2], &ibm_acpi.temps[3],
1676 &ibm_acpi.temps[4], &ibm_acpi.temps[5],
1677 &ibm_acpi.temps[6], &ibm_acpi.temps[7])) break;
1682 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", thermal, strerror(errno));
1690 void get_ibm_acpi_volume( char * p_client_buffer, size_t client_buffer_size )
1693 /* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
1694 "Volume" here is none of the mixer volumes, but a "master of masters"
1695 volume adjusted by the IBM volume keys.
1696 /proc/acpi/ibm/fan looks like this (4 lines):
1699 commands: up, down, mute
1700 commands: level <level> (<level> is 0-15)
1701 Peter Tarjan (ptarjan@citromail.hu)
1704 if ( !p_client_buffer || client_buffer_size <= 0 )
1710 snprintf(volume, 127, "%s/volume",IBM_ACPI_DIR);
1711 unsigned int vol=-1;
1714 fp = fopen(volume, "r");
1720 if (fgets(line, 255, fp) == NULL) break;
1721 if (sscanf(line, "level: %d", &vol)) continue;
1722 if (sscanf(line, "mute: %s", mute)) break;
1727 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", volume, strerror(errno));
1732 if (strcmp(mute, "on")==0)
1734 snprintf( p_client_buffer, client_buffer_size, "%s", "mute" );
1739 snprintf( p_client_buffer, client_buffer_size, "%d", vol );
1745 /*static FILE *fp=NULL;*/
1747 void get_ibm_acpi_brightness(char * p_client_buffer, size_t client_buffer_size)
1749 /* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
1750 /proc/acpi/ibm/brightness looks like this (3 lines):
1753 commands: level <level> (<level> is 0-7)
1754 Peter Tarjan (ptarjan@citromail.hu)
1757 if ( !p_client_buffer || client_buffer_size <= 0 )
1761 unsigned int brightness=0;
1763 snprintf(filename, 127, "%s/brightness",IBM_ACPI_DIR);
1765 fp = fopen(filename, "r");
1771 if (fgets(line, 255, fp) == NULL) break;
1772 if (sscanf(line, "level: %d", &brightness)) break;
1777 CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", filename, strerror(errno));
1782 snprintf( p_client_buffer, client_buffer_size, "%d", brightness );
1787 void update_entropy (void)
1790 const char *entropy_avail = "/proc/sys/kernel/random/entropy_avail";
1791 const char *entropy_poolsize = "/proc/sys/kernel/random/poolsize";
1794 info.entropy.entropy_avail=0;
1795 info.entropy.poolsize=0;
1797 if ((fp1 = open_file (entropy_avail, &rep))==NULL)
1800 if ((fp2 = open_file (entropy_poolsize, &rep))==NULL)
1806 fscanf (fp1, "%u", &info.entropy.entropy_avail);
1807 fscanf (fp2, "%u", &info.entropy.poolsize);
1812 info.mask |= (1 << INFO_ENTROPY);
1815 #ifdef HAVE_LIBDEXTER
1816 FILE *open_file(const char *file, int *reported)
1818 /* this version of open_file() is the hook that ties the client/server code
1819 * into conky. if conky wants to open a /proc file that the server is feeding
1820 * us, we do not return an ordinary file stream pointer to the local /proc
1821 * filesystem. instead, we return a string stream pointer to the proc surrogate,
1822 * so conky parses remote data as if it were local.
1826 if ((strcmp (file,"/proc/cpuinfo")==0) && (procraw_mask & PROCRAW_CPUINFO))
1828 if (!procraw_sampler)
1830 fp = fmemopen (procraw_data.cpuinfo, procraw_data.cpuinfo_sz, "r");
1832 else if ((strcmp (file,"/proc/loadavg")==0) && (procraw_mask & PROCRAW_LOADAVG))
1834 if (!procraw_sampler)
1836 fp = fmemopen (procraw_data.loadavg, procraw_data.loadavg_sz, "r");
1838 else if ((strcmp (file,"/proc/meminfo")==0) && (procraw_mask & PROCRAW_MEMINFO))
1840 if (!procraw_sampler)
1842 fp = fmemopen (procraw_data.meminfo, procraw_data.meminfo_sz, "r");
1844 else if ((strcmp (file,"/proc/stat")==0) && (procraw_mask & PROCRAW_STAT))
1846 if (!procraw_sampler)
1848 fp = fmemopen (procraw_data.stat, procraw_data.stat_sz, "r");
1850 else if ((strcmp (file,"/proc/uptime")==0) && (procraw_mask & PROCRAW_UPTIME))
1852 if (!procraw_sampler)
1854 fp = fmemopen (procraw_data.uptime, procraw_data.uptime_sz, "r");
1856 else if ((strcmp (file,"/proc/net/dev")==0) && (procraw_mask & PROCRAW_NET_DEV))
1858 if (!procraw_sampler)
1860 fp = fmemopen (procraw_data.net_dev, procraw_data.net_dev_sz, "r");
1862 else if ((strcmp (file,"/proc/diskstats")==0) && (procraw_mask & PROCRAW_DISKSTATS))
1864 if (!procraw_sampler)
1866 fp = fmemopen (procraw_data.diskstats, procraw_data.diskstats_sz, "r");
1870 fp = fopen(file, "r");
1875 if (!reported || *reported == 0)
1877 ERR("can't open %s: %s", file, strerror(errno));
1886 void sampler_data_callback (gpointer sampler, gpointer sampler_data)
1888 /* callback runs in a thread */
1897 DxtSysinfoProcrawData *data = (DxtSysinfoProcrawData *)sampler_data;
1899 /* use GNU string streams and stdio locking to exchange data with main thread. */
1901 /* update /proc/cpuinfo surrogate */
1902 for (;data->cpuinfo;)
1904 if (!(out = open_memstream (&procraw_data.cpuinfo, &procraw_data.cpuinfo_sz)))
1908 if (procraw_data.cpuinfo)
1910 free (procraw_data.cpuinfo); procraw_data.cpuinfo=NULL;
1912 for (p=data->cpuinfo, i=0; i<data->cpuinfo_sz; i++, p++)
1914 /* we have the FILE lock so use faster putc_unlocked() */
1915 if (fputc_unlocked (*p, out) == EOF)
1923 /* update /proc/loadavg surrogate */
1924 for (;data->loadavg;)
1926 if (!(out = open_memstream (&procraw_data.loadavg, &procraw_data.loadavg_sz)))
1930 if (procraw_data.loadavg)
1932 free (procraw_data.loadavg); procraw_data.loadavg=NULL;
1934 for (p=data->loadavg, i=0; i<data->loadavg_sz; i++, p++)
1936 /* we have the FILE lock so use faster putc_unlocked() */
1937 if (fputc_unlocked (*p, out) == EOF)
1945 /* update /proc/meminfo surrogate */
1946 for (;data->meminfo;)
1948 if (!(out = open_memstream (&procraw_data.meminfo, &procraw_data.meminfo_sz)))
1952 if (procraw_data.meminfo)
1954 free (procraw_data.meminfo); procraw_data.meminfo=NULL;
1956 for (p=data->meminfo, i=0; i<data->meminfo_sz; i++, p++)
1958 /* we have the FILE lock so use faster putc_unlocked() */
1959 if (fputc_unlocked (*p, out) == EOF)
1967 /* update /proc/stat surrogate */
1970 if (!(out = open_memstream (&procraw_data.stat, &procraw_data.stat_sz)))
1974 if (procraw_data.stat)
1976 free (procraw_data.stat); procraw_data.stat=NULL;
1978 for (p=data->stat, i=0; i<data->stat_sz; i++, p++)
1980 /* we have the FILE lock so use faster putc_unlocked() */
1981 if (fputc_unlocked (*p, out) == EOF)
1989 /* update /proc/uptime surrogate */
1990 for (;data->uptime;)
1992 if (!(out = open_memstream (&procraw_data.uptime, &procraw_data.uptime_sz)))
1996 if (procraw_data.uptime)
1998 free (procraw_data.uptime); procraw_data.uptime=NULL;
2000 for (p=data->uptime, i=0; i<data->uptime_sz; i++, p++)
2002 /* we have the FILE lock so use faster putc_unlocked() */
2003 if (fputc_unlocked (*p, out) == EOF)
2011 /* update /proc/net/dev surrogate */
2012 for (;data->net_dev;)
2014 if (!(out = open_memstream (&procraw_data.net_dev, &procraw_data.net_dev_sz)))
2018 if (procraw_data.net_dev)
2020 free (procraw_data.net_dev); procraw_data.net_dev=NULL;
2022 for (p=data->net_dev, i=0; i<data->net_dev_sz; i++, p++)
2024 /* we have the FILE lock so use faster putc_unlocked() */
2025 if (fputc_unlocked (*p, out) == EOF)
2033 /* update /proc/diskstats surrogate */
2034 for (;data->diskstats;)
2036 if (!(out = open_memstream (&procraw_data.diskstats, &procraw_data.diskstats_sz)))
2040 if (procraw_data.diskstats)
2042 free (procraw_data.diskstats); procraw_data.diskstats=NULL;
2044 for (p=data->diskstats, i=0; i<data->diskstats_sz; i++, p++)
2046 /* we have the FILE lock so use faster putc_unlocked() */
2047 if (fputc_unlocked (*p, out) == EOF)
2055 /* record data packet arrival time */
2056 g_mutex_lock (packet_mutex);
2057 clock_gettime (CLOCK_REALTIME, &packet_arrival_time);
2058 g_mutex_unlock (packet_mutex);
2060 fprintf(stderr, "Conky: data packet arrived\n");
2063 } /* if (sampler_data) ... */
2066 /* return 0 on success, -1 on failure */
2067 int dexter_client_init (void)
2069 /* init libdexter for linux-specific client-side activity */
2071 DexterServiceBroker *broker;
2072 DexterPluginServiceGroup *service_group;
2073 DexterPluginService *procraw_service;
2074 DexterSamplerDataCallback *callbacks;
2075 GError *error = NULL;
2077 /* create a service broker so we can query the server for its services */
2078 if (!(broker = dexter_service_broker_new (info.dexter.channel)))
2080 ERR ("unable to create service broker");
2084 /* fetch the services from the server */
2085 service_group = dexter_service_broker_get_services (broker, DEXTER_SERVICE_SAMPLER, &error);
2088 ERR("%s", error->message);
2089 g_clear_error (&error);
2090 dexter_service_broker_free (broker);
2094 /* dont need service broker any more */
2095 dexter_service_broker_free (broker);
2098 /* find the procraw service */
2099 procraw_service=NULL;
2100 if (!dexterplugin_service_group_find_uuid (&procraw_service, service_group, PROCRAW_SERVICE_UUID))
2102 ERR ("server doesn't offer the procraw service: (%s)", PROCRAW_SERVICE_UUID);
2103 dexterplugin_service_group_free (service_group);
2107 /* create null-terminated callback list with one callback on it */
2108 callbacks = g_new0 (DexterSamplerDataCallback, 2);
2109 callbacks[0] = sampler_data_callback;
2111 /* create the procraw timed sampler, timed to match conky's update_interval */
2112 procraw_sampler = dexter_timedsampler_new (procraw_service, update_interval*G_USEC_PER_SEC,
2113 callbacks, info.dexter.channel, &error);
2116 ERR("%s", error->message);
2117 g_clear_error (&error);
2118 dexterplugin_service_group_free (service_group);
2122 /* free callbacks as libdexter makes internal copy */
2126 /* initialize the timed sampler */
2128 if (need_mask & (1 << INFO_FREQ))
2129 procraw_mask |= PROCRAW_CPUINFO;
2130 if (need_mask & (1 << INFO_LOADAVG))
2131 procraw_mask |= PROCRAW_LOADAVG;
2132 if ((need_mask & (1 << INFO_MEM)) || (need_mask & (1 << INFO_BUFFERS)))
2133 procraw_mask |= PROCRAW_MEMINFO;
2134 if ((need_mask & (1 << INFO_CPU)) || (need_mask & (1 << INFO_PROCS)) ||
2135 (need_mask & (1 << INFO_RUN_PROCS)) || (need_mask & (1 << INFO_FREQ )))
2136 procraw_mask |= PROCRAW_STAT;
2137 if (need_mask & (1 << INFO_UPTIME))
2138 procraw_mask |= PROCRAW_UPTIME;
2139 if (need_mask & (1 << INFO_NET))
2140 procraw_mask |= PROCRAW_NET_DEV;
2141 if (need_mask & (1 << INFO_DISKIO))
2142 procraw_mask |= PROCRAW_DISKSTATS;
2144 dexter_timedsampler_initialize (procraw_sampler, &procraw_mask, NULL, &error);
2147 ERR("%s", error->message);
2148 g_clear_error (&error);
2149 dexter_timedsampler_free (procraw_sampler, NULL);
2150 dexterplugin_service_group_free (service_group);
2154 /* start the timed sampler and begin receiving updates from server */
2155 dexter_timedsampler_start (procraw_sampler, &error);
2158 ERR("%s", error->message);
2159 g_clear_error (&error);
2160 dexter_timedsampler_free (procraw_sampler, NULL);
2161 dexterplugin_service_group_free (service_group);
2165 dexterplugin_service_group_free (service_group);
2167 /* so far, so good. tell the linux routines to read /proc,
2168 * even if other api's are available. */
2174 /* return 0 on success, -1 on failure */
2175 int dexter_client_exit (void)
2177 /* de-init libdexter for linux-specific client-side activity */
2179 if (procraw_sampler)
2181 dexter_timedsampler_stop (procraw_sampler, NULL);
2182 dexter_timedsampler_free (procraw_sampler, NULL);
2183 procraw_sampler=NULL;
2186 /* free left-over sampler data. ok to do this without thread sync because
2187 * this function runs in the same thread that conky issues open_file(). */
2188 if (procraw_data.cpuinfo)
2190 free (procraw_data.cpuinfo); procraw_data.cpuinfo=NULL;
2192 if (procraw_data.loadavg)
2194 free (procraw_data.loadavg); procraw_data.loadavg=NULL;
2196 if (procraw_data.meminfo)
2198 free (procraw_data.meminfo); procraw_data.meminfo=NULL;
2200 if (procraw_data.stat)
2202 free (procraw_data.stat); procraw_data.stat=NULL;
2204 if (procraw_data.uptime)
2206 free (procraw_data.uptime); procraw_data.uptime=NULL;
2208 if (procraw_data.net_dev)
2210 free (procraw_data.net_dev); procraw_data.net_dev=NULL;
2212 if (procraw_data.diskstats)
2214 free (procraw_data.diskstats); procraw_data.diskstats=NULL;
2219 info.mem = info.memmax = info.swap = info.swapmax = info.bufmem = info.buffers = info.cached = 0;
2223 memset(info.cpu_usage, 0, info.cpu_count * sizeof (float));