void get_cpu_count()
{
+ if (info.cpu_usage) {
+ return;
+ }
char buf[256];
if (stat_fp == NULL)
stat_fp = open_file("/proc/stat", &rep);
}
}
info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
-
}
#define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
}
/* TESTING -- I've removed this, because I don't think it is right. You shouldn't divide
by the cpu count here ... removing for testing */
- if (index == 0) {
+ /* if (index == 0) {
info.cpu_usage[index] = curtmp / info.cpu_avg_samples / info.cpu_count;
} else {
info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
- }
+ } */
/* TESTING -- this line replaces the prev. "suspect" if/else */
info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
}
}
-#define ADT746X_FAN "/sys/devices/temperatures/cpu_fan_speed"
+/* Prior to kernel version 2.6.12, the CPU fan speed was available
+ * in ADT746X_FAN_OLD, whereas later kernel versions provide this
+ * information in ADT746X_FAN.
+ */
+#define ADT746X_FAN "/sys/devices/temperatures/sensor1_fan_speed"
+#define ADT746X_FAN_OLD "/sys/devices/temperatures/cpu_fan_speed"
void get_adt746x_fan( char * p_client_buffer, size_t client_buffer_size )
{
if ( !p_client_buffer || client_buffer_size <= 0 )
return;
- fp = open_file(ADT746X_FAN, &rep);
- if (!fp)
+ if ((fp = open_file(ADT746X_FAN, &rep)) == NULL
+ && (fp = open_file(ADT746X_FAN_OLD, &rep)) == NULL)
+
{
sprintf(adt746x_fan_state, "adt746x not found");
}
else
{
- fscanf(fp, "%s", adt746x_fan_state);
+ fgets(adt746x_fan_state, sizeof(adt746x_fan_state), fp);
+ adt746x_fan_state[strlen(adt746x_fan_state) - 1] = 0;
fclose(fp);
}
return;
}
-#define ADT746X_CPU "/sys/devices/temperatures/cpu_temperature"
+/* Prior to kernel version 2.6.12, the CPU temperature was found
+ * in ADT746X_CPU_OLD, whereas later kernel versions provide this
+ * information in ADT746X_CPU.
+ */
+#define ADT746X_CPU "/sys/devices/temperatures/sensor1_temperature"
+#define ADT746X_CPU_OLD "/sys/devices/temperatures/cpu_temperature"
void get_adt746x_cpu( char * p_client_buffer, size_t client_buffer_size )
{
if ( !p_client_buffer || client_buffer_size <= 0 )
return;
- fp = open_file(ADT746X_CPU, &rep);
- if (!fp)
+ if ((fp = open_file(ADT746X_CPU, &rep)) == NULL
+ && (fp = open_file(ADT746X_CPU_OLD, &rep)) == NULL)
{
sprintf(adt746x_cpu_state, "adt746x not found");
}
snprintf( p_client_buffer, client_buffer_size, p_format, (float)((cycles[1] - cycles[0]) / microseconds) / divisor );
return;
#else
- get_freq( p_client_buffer, client_buffer_size, p_format, divisor );
+/* FIXME: hardwired: get freq for first cpu!
+ this whole function needs to be rethought and redone for
+ multi-cpu/multi-core/multi-threaded environments and
+ arbitrary combinations thereof
+*/
+ get_freq( p_client_buffer, client_buffer_size, p_format, divisor, 1 );
return;
#endif
}
-#define CPUFREQ_CURRENT "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq"
+
+#define CPUFREQ_PREFIX "/sys/devices/system/cpu"
+#define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
/* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
-void get_freq( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor )
+char get_freq( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
{
FILE *f;
char frequency[32];
char s[256];
double freq = 0;
+ char current_freq_file[128];
+
+ cpu--;
+ snprintf(current_freq_file, 127, "%s/cpu%d/%s",
+ CPUFREQ_PREFIX, cpu, CPUFREQ_POSTFIX);
if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
- return;
-
- f = fopen(CPUFREQ_CURRENT, "r");
+ return 0;
+
+ f = fopen(current_freq_file, "r");
if (f) {
/* if there's a cpufreq /sys node, read the current frequency from this node;
* divide by 1000 to get Mhz. */
}
fclose(f);
snprintf( p_client_buffer, client_buffer_size, p_format, (freq/1000)/divisor );
- return;
+ return 1;
}
+ cpu++;
f = fopen("/proc/cpuinfo", "r"); //open the CPU information file
- if (!f)
- return;
+ if (!f) {
+ perror("Conky: Failed to access '/proc/cpuinfo' at get_freq()");
+ return 0;
+ }
while (fgets(s, sizeof(s), f) != NULL){ //read the file
+
#if defined(__i386) || defined(__x86_64)
- if (strncmp(s, "cpu MHz", 7) == 0) { //and search for the cpu mhz
+ if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) { //and search for the cpu mhz
#else
- if (strncmp(s, "clock", 5) == 0) { // this is different on ppc for some reason
-#endif
+#if defined(__alpha)
+ if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) { // different on alpha
+#else
+ if (strncmp(s, "clock", 5) == 0 && cpu == 0) { // this is different on ppc for some reason
+#endif // defined(__alpha)
+#endif // defined(__i386) || defined(__x86_64)
+
strcpy(frequency, strchr(s, ':') + 2); //copy just the number
+#if defined(__alpha)
+ frequency[strlen(frequency) - 6] = '\0';// strip " est.\n"
+ freq = strtod(frequency, NULL)/1000000; // kernel reports in Hz
+#else
frequency[strlen(frequency) - 1] = '\0'; // strip \n
freq = strtod(frequency, NULL);
+#endif
break;
}
+ if (strncmp(s, "processor", 9) == 0) {
+ cpu--;
+ continue;
+ }
+
}
fclose(f);
snprintf( p_client_buffer, client_buffer_size, p_format, (float)freq/divisor );
- return;
+ return 1;
}
+#define CPUFREQ_VOLTAGE "cpufreq/scaling_voltages"
+
+/* return cpu voltage in mV (use divisor=1) or V (use divisor=1000) */
+char get_voltage( char * p_client_buffer, size_t client_buffer_size, char * p_format, int divisor, unsigned int cpu )
+{
+/* /sys/devices/system/cpu/cpu0/cpufreq/scaling_voltages looks
+ something like this:
+# frequency voltage
+1800000 1340
+1600000 1292
+1400000 1100
+1200000 988
+1000000 1116
+800000 1004
+600000 988
+*/
+
+/* Peter Tarjan (ptarjan@citromail.hu) */
+ FILE *f;
+ char s[256];
+ int freq = 0;
+ int voltage = 0;
+ char current_freq_file[128];
+ int freq_comp = 0;
+
+
+/* build the voltage file name */
+ cpu--;
+ snprintf(current_freq_file, 127, "%s/cpu%d/%s",
+ CPUFREQ_PREFIX, cpu, CPUFREQ_POSTFIX);
+
+ if ( !p_client_buffer || client_buffer_size <= 0 || !p_format || divisor <= 0 )
+ return 0;
+
+ /* read the current cpu frequency from the /sys node */
+ f = fopen(current_freq_file, "r");
+ if (f) {
+ if (fgets(s, sizeof(s), f)) {
+ s[strlen(s)-1] = '\0';
+ freq = strtod(s, NULL);
+ }
+ fclose(f);
+ } else {
+ fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
+ perror("get_voltage()");
+ if (f) {
+ fclose(f);
+ }
+ return 0;
+ }
+
+ snprintf(current_freq_file, 127, "%s/cpu%d/%s",
+ CPUFREQ_PREFIX, cpu, CPUFREQ_VOLTAGE);
+
+/* use the current cpu frequency to find the corresponding voltage */
+ f = fopen(current_freq_file, "r");
+
+ if (f) {
+ while (!feof(f)) {
+ char line[256];
+ if (fgets(line, 255, f) == NULL) break;
+ sscanf(line, "%d %d", &freq_comp, &voltage);
+ if(freq_comp == freq) break;
+ }
+ fclose(f);
+ } else {
+ fprintf(stderr, "Conky: Failed to access '%s' at ", current_freq_file);
+ perror("get_voltage()");
+ if (f) {
+ fclose(f);
+ }
+ return 0;
+ }
+ snprintf( p_client_buffer, client_buffer_size, p_format, (float)voltage/divisor );
+ return 1;
+
+}
#define ACPI_FAN_DIR "/proc/acpi/fan/"
int present_rate = -1;
int remaining_capacity = -1;
char charging_state[64];
+ char present[4];
/* read last full capacity if it's zero */
if (acpi_last_full == 0) {
char b[256];
if (fgets(b, 256, fp) == NULL)
break;
-
- if (sscanf
- (b, "last full capacity: %d",
- &acpi_last_full) != 0)
+ if (sscanf(b, "last full capacity: %d", &acpi_last_full) != 0) {
break;
+ }
}
fclose(fp);
break;
/* let's just hope units are ok */
- if (buf[0] == 'c')
+ if (buf[0] == 'p') {
+ sscanf(buf, "present: %4s", present);
+ } else if (buf[0] == 'c')
sscanf(buf, "charging state: %63s",
charging_state);
else if (buf[0] == 'p')
sscanf(buf, "remaining capacity: %d",
&remaining_capacity);
}
-
+
+ /* not present */
+ if (strcmp(present, "no") == 0) {
+ strncpy(last_battery_str, "not present", 64);
+ }
/* charging */
- if (strcmp(charging_state, "charging") == 0) {
+ else if (strcmp(charging_state, "charging") == 0) {
if (acpi_last_full != 0 && present_rate > 0) {
- strcpy(last_battery_str, "charging ");
- format_seconds(last_battery_str + 9,
- 63 - 9,
+ snprintf(last_battery_str, 63, "charging %i%% ", (int) (remaining_capacity / acpi_last_full) * 100);
+ format_seconds(last_battery_str + 14,
+ 63 - 14,
(acpi_last_full -
remaining_capacity) * 60 *
60 / present_rate);
} else if (acpi_last_full != 0
&& present_rate <= 0) {
- sprintf(last_battery_str, "charging %d%%",
+ snprintf(last_battery_str, 64, "charging %d%%",
remaining_capacity * 100 /
acpi_last_full);
} else {
- strcpy(last_battery_str, "charging");
+ strncpy(last_battery_str, "charging", 63);
}
}
/* discharging */
- else if (strcmp(charging_state, "discharging") == 0) {
- if (present_rate > 0)
- format_seconds(last_battery_str, 63,
+ else if (strncmp(charging_state, "discharging", 64) == 0) {
+ if (present_rate > 0) {
+ snprintf(last_battery_str, 63, "discharging %i%% ", (int)(remaining_capacity / acpi_last_full) * 100);
+ format_seconds(last_battery_str + 17, 63 - 17,
(remaining_capacity * 60 *
60) / present_rate);
- else
- sprintf(last_battery_str,
+ } else if (present_rate == 0) { /* Thanks to Nexox for this one */
+ snprintf(last_battery_str, 64, "full");
+ } else {
+ snprintf(last_battery_str, 64,
"discharging %d%%",
remaining_capacity * 100 /
acpi_last_full);
+ }
}
/* charged */
/* thanks to Lukas Zapletal <lzap@seznam.cz> */
- else if (strcmp(charging_state, "charged") == 0) {
- if (acpi_last_full != 0
- && remaining_capacity != acpi_last_full)
- sprintf(last_battery_str, "charged %d%%",
- remaining_capacity * 100 /
- acpi_last_full);
- else
+ else if (strncmp(charging_state, "charged", 64) == 0) {
strcpy(last_battery_str, "charged");
- }
+ }
/* unknown, probably full / AC */
else {
if (acpi_last_full != 0
&& remaining_capacity != acpi_last_full)
- sprintf(last_battery_str, "unknown %d%%",
+ snprintf(last_battery_str, 64, "unknown %d%%",
remaining_capacity * 100 /
acpi_last_full);
else
- strcpy(last_battery_str, "AC");
+ strncpy(last_battery_str, "AC", 64);
}
} else {
/* APM */
snprintf(buf, n, "%s", last_battery_str);
}
+/* On Apple powerbook and ibook:
+$ cat /proc/pmu/battery_0
+flags : 00000013
+charge : 3623
+max_charge : 3720
+current : 388
+voltage : 16787
+time rem. : 900
+$ cat /proc/pmu/info
+PMU driver version : 2
+PMU firmware version : 0c
+AC Power : 1
+Battery count : 1
+*/
+
+/* defines as in <linux/pmu.h> */
+#define PMU_BATT_PRESENT 0x00000001
+#define PMU_BATT_CHARGING 0x00000002
+
+static FILE* pmu_battery_fp;
+static FILE* pmu_info_fp;
+static char pb_battery_info[3][32];
+static double pb_battery_info_update;
+
+#define PMU_PATH "/proc/pmu"
+void get_powerbook_batt_info(char *buf, size_t n, int i)
+{
+ static int rep;
+ const char* batt_path = PMU_PATH "/battery_0";
+ const char* info_path = PMU_PATH "/info";
+ int flags, charge, max_charge, ac = -1;
+ long time = -1;
+
+ /* don't update battery too often */
+ if (current_update_time - pb_battery_info_update < 29.5) {
+ snprintf(buf, n, "%s", pb_battery_info[i]);
+ return;
+ }
+ pb_battery_info_update = current_update_time;
+
+ if (pmu_battery_fp == NULL)
+ pmu_battery_fp = open_file(batt_path, &rep);
+
+ if (pmu_battery_fp != NULL) {
+ rewind(pmu_battery_fp);
+ while (!feof(pmu_battery_fp)) {
+ char buf[32];
+ if (fgets(buf, sizeof(buf), pmu_battery_fp) == NULL)
+ break;
+
+ if (buf[0] == 'f')
+ sscanf(buf, "flags : %8x", &flags);
+ else if (buf[0] == 'c' && buf[1] == 'h')
+ sscanf(buf, "charge : %d", &charge);
+ else if (buf[0] == 'm')
+ sscanf(buf, "max_charge : %d", &max_charge);
+ else if (buf[0] == 't')
+ sscanf(buf, "time rem. : %ld", &time);
+ }
+ }
+ if (pmu_info_fp == NULL)
+ pmu_info_fp = open_file(info_path, &rep);
+
+ if (pmu_info_fp != NULL) {
+ rewind(pmu_info_fp);
+ while (!feof(pmu_info_fp)) {
+ char buf[32];
+ if (fgets(buf, sizeof(buf), pmu_info_fp) == NULL)
+ break;
+ if (buf[0] == 'A')
+ sscanf(buf, "AC Power : %d", &ac);
+ }
+ }
+ /* update status string */
+ if ((ac && !(flags & PMU_BATT_PRESENT)))
+ strcpy(pb_battery_info[PB_BATT_STATUS], "AC");
+ else if (ac && (flags & PMU_BATT_PRESENT)
+ && !(flags & PMU_BATT_CHARGING))
+ strcpy(pb_battery_info[PB_BATT_STATUS], "charged");
+ else if ((flags & PMU_BATT_PRESENT)
+ && (flags & PMU_BATT_CHARGING))
+ strcpy(pb_battery_info[PB_BATT_STATUS], "charging");
+ else
+ strcpy(pb_battery_info[PB_BATT_STATUS], "discharging");
+
+ /* update percentage string */
+ if (time == 0)
+ pb_battery_info[PB_BATT_PERCENT][0] = 0;
+ else
+ snprintf(pb_battery_info[PB_BATT_PERCENT],
+ sizeof(pb_battery_info[PB_BATT_PERCENT]),
+ "%d%%", (charge * 100)/max_charge);
+
+ /* update time string */
+ if (time == 0) /* fully charged or battery not present */
+ pb_battery_info[PB_BATT_TIME][0] = 0;
+ else if (time < 60*60) /* don't show secs */
+ format_seconds_short(pb_battery_info[PB_BATT_TIME],
+ sizeof(pb_battery_info[PB_BATT_TIME]), time);
+ else
+ format_seconds(pb_battery_info[PB_BATT_TIME],
+ sizeof(pb_battery_info[PB_BATT_TIME]), time);
+
+ snprintf(buf, n, "%s", pb_battery_info[i]);
+}
+
void update_top()
{
show_nice_processes = 1;
diskio_value = tot;
}
+/* Here come the IBM ACPI-specific things. For reference, see
+ http://ibm-acpi.sourceforge.net/README
+If IBM ACPI is installed, /proc/acpi/ibm contains the following files:
+bay
+beep
+bluetooth
+brightness
+cmos
+dock
+driver
+ecdump
+fan
+hotkey
+led
+light
+thermal
+video
+volume
+The content of these files is described in detail in the aforementioned
+README - some of them also in the following functions accessing them.
+Peter Tarjan (ptarjan@citromail.hu)
+*/
+
+#define IBM_ACPI_DIR "/proc/acpi/ibm"
+
+void get_ibm_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
+{
+/* get fan speed on IBM/Lenovo laptops running the ibm acpi.
+ /proc/acpi/ibm/fan looks like this (3 lines):
+status: disabled
+speed: 2944
+commands: enable, disable
+Peter Tarjan (ptarjan@citromail.hu)
+*/
+
+ if ( !p_client_buffer || client_buffer_size <= 0 )
+ return;
+
+ FILE *fp;
+ unsigned int speed=0;
+ char fan[128];
+ snprintf(fan, 127, "%s/fan",IBM_ACPI_DIR);
+
+ fp = fopen(fan, "r");
+ if (fp != NULL)
+ {
+ while (!feof(fp))
+ {
+ char line[256];
+ if (fgets(line, 255, fp) == NULL) break;
+ if (sscanf(line, "speed: %d", &speed)) break;
+ }
+ }
+ else
+ {
+ CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", fan, strerror(errno));
+ }
+
+ fclose(fp);
+ snprintf( p_client_buffer, client_buffer_size, "%d", speed );
+ return;
+
+}
+
+static double last_ibm_acpi_temp_time;
+void get_ibm_acpi_temps()
+{
+/* get the measured temperatures from the temperature sensors
+ on IBM/Lenovo laptops running the ibm acpi.
+ There are 8 values in /proc/acpi/ibm/thermal, and according to
+ http://ibm-acpi.sourceforge.net/README
+ these mean the following (at least on an IBM R51...)
+0: CPU (also on the T series laptops)
+1: Mini PCI Module (?)
+2: HDD (?)
+3: GPU (also on the T series laptops)
+4: Battery (?)
+5: N/A
+6: Battery (?)
+7: N/A
+ I'm not too sure about those with the question mark, but the values I'm
+ reading from *my* thermal file (on a T42p) look realistic for the
+ hdd and the battery.
+ #5 and #7 are always -128.
+ /proc/acpi/ibm/thermal looks like this (1 line):
+temperatures: 41 43 31 46 33 -128 29 -128
+Peter Tarjan (ptarjan@citromail.hu)
+*/
+
+/* don't update too often */
+ if (current_update_time - last_ibm_acpi_temp_time < 10.00)
+ {
+ return;
+ }
+ last_ibm_acpi_temp_time = current_update_time;
+
+/* if ( !p_client_buffer || client_buffer_size <= 0 )
+ return; */
+
+ FILE *fp;
+
+ char thermal[128];
+ snprintf(thermal, 127, "%s/thermal",IBM_ACPI_DIR);
+ fp = fopen(thermal, "r");
+
+ if (fp != NULL)
+ {
+ while (!feof(fp))
+ {
+ char line[256];
+ if (fgets(line, 255, fp) == NULL) break;
+ if (sscanf(line, "temperatures: %d %d %d %d %d %d %d %d",
+ &ibm_acpi.temps[0], &ibm_acpi.temps[1],
+ &ibm_acpi.temps[2], &ibm_acpi.temps[3],
+ &ibm_acpi.temps[4], &ibm_acpi.temps[5],
+ &ibm_acpi.temps[6], &ibm_acpi.temps[7])) break;
+ }
+ }
+ else
+ {
+ CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", thermal, strerror(errno));
+ }
+
+ fclose(fp);
+
+}
+
+
+void get_ibm_acpi_volume( char * p_client_buffer, size_t client_buffer_size )
+{
+
+/* get volume (0-14) on IBM/Lenovo laptops running the ibm acpi.
+ "Volume" here is none of the mixer volumes, but a "master of masters"
+ volume adjusted by the IBM volume keys.
+ /proc/acpi/ibm/fan looks like this (4 lines):
+level: 4
+mute: off
+commands: up, down, mute
+commands: level <level> (<level> is 0-15)
+Peter Tarjan (ptarjan@citromail.hu)
+*/
+
+ if ( !p_client_buffer || client_buffer_size <= 0 )
+ return;
+
+ FILE *fp;
+
+ char volume[128];
+ snprintf(volume, 127, "%s/volume",IBM_ACPI_DIR);
+ unsigned int vol=-1;
+ char mute[3]="";
+
+ fp = fopen(volume, "r");
+ if (fp != NULL)
+ {
+ while (!feof(fp))
+ {
+ char line[256];
+ if (fgets(line, 255, fp) == NULL) break;
+ if (sscanf(line, "level: %d", &vol)) continue;
+ if (sscanf(line, "mute: %s", mute)) break;
+ }
+ }
+ else
+ {
+ CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", volume, strerror(errno));
+ }
+
+ fclose(fp);
+
+ if (strcmp(mute, "on")==0)
+ {
+ snprintf( p_client_buffer, client_buffer_size, "%s", "mute" );
+ return;
+ }
+ else
+ {
+ snprintf( p_client_buffer, client_buffer_size, "%d", vol );
+ return;
+ }
+
+}
+
+/*static FILE *fp=NULL;*/
+
+void get_ibm_acpi_brightness(char * p_client_buffer, size_t client_buffer_size)
+{
+/* get LCD brightness on IBM/Lenovo laptops running the ibm acpi.
+ /proc/acpi/ibm/brightness looks like this (3 lines):
+level: 7
+commands: up, down
+commands: level <level> (<level> is 0-7)
+Peter Tarjan (ptarjan@citromail.hu)
+*/
+
+ if ( !p_client_buffer || client_buffer_size <= 0 )
+ return;
+
+ FILE *fp;
+ unsigned int brightness=0;
+ char filename[128];
+ snprintf(filename, 127, "%s/brightness",IBM_ACPI_DIR);
+
+ fp = fopen(filename, "r");
+ if (fp != NULL)
+ {
+ while (!feof(fp))
+ {
+ char line[256];
+ if (fgets(line, 255, fp) == NULL) break;
+ if (sscanf(line, "level: %d", &brightness)) break;
+ }
+ }
+ else
+ {
+ CRIT_ERR("can't open '%s': %s\nYou are not using the IBM ACPI. Remove ibm* from your Conky config file.", filename, strerror(errno));
+ }
+
+ fclose(fp);
+
+ snprintf( p_client_buffer, client_buffer_size, "%d", brightness );
+ return;
+
+}