summaryrefslogtreecommitdiff
path: root/src/print_cpu_temperature.c
blob: e25cea5b6b1772e5ba0bd7741fc3fdb30691c37f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// vim:ts=8:expandtab
#include <stdlib.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <yajl/yajl_gen.h>
#include <yajl/yajl_version.h>

#include "i3status.h"

#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
#include <err.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#define TZ_ZEROC 2732
#define TZ_KELVTOC(x) (((x) - TZ_ZEROC) / 10), abs(((x) - TZ_ZEROC) % 10)
#endif

#if defined(__OpenBSD__)
#include <sys/param.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/sensors.h>
#include <errno.h>
#include <err.h>

#define MUKTOC(v) ((v - 273150000) / 1000000.0)
#endif

static char *thermal_zone;

/*
 * Reads the CPU temperature from /sys/class/thermal/thermal_zone0/temp and
 * returns the temperature in degree celcius.
 *
 */
void print_cpu_temperature_info(yajl_gen json_gen, char *buffer, int zone, const char *path, const char *format, int max_threshold) {
#ifdef THERMAL_ZONE
        const char *walk;
        char *outwalk = buffer;
        bool colorful_output = false;

        if (path == NULL)
                asprintf(&thermal_zone, THERMAL_ZONE, zone);
        else
                asprintf(&thermal_zone, path, zone);
        path = thermal_zone;

        INSTANCE(path);

        for (walk = format; *walk != '\0'; walk++) {
                if (*walk != '%') {
                        *(outwalk++) = *walk;
                        continue;
                }

                if (BEGINS_WITH(walk+1, "degrees")) {
#if defined(LINUX)
		        static char buf[16];
                        long int temp;
                        if (!slurp(path, buf, sizeof(buf)))
                                goto error;
                        temp = strtol(buf, NULL, 10);
                        if (temp == LONG_MIN || temp == LONG_MAX || temp <= 0)
                                *(outwalk++) = '?';
                        else {
                                if ((temp/1000) >= max_threshold) {
                                        START_COLOR("color_bad");
                                        colorful_output = true;
                                }
                                outwalk += sprintf(outwalk, "%ld", (temp/1000));
                                if (colorful_output) {
                                        END_COLOR;
                                        colorful_output = false;
                                }
                        }
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
                        int sysctl_rslt;
                        size_t sysctl_size = sizeof(sysctl_rslt);
                        if (sysctlbyname(path, &sysctl_rslt, &sysctl_size, NULL, 0))
                                goto error;

                        outwalk += sprintf(outwalk, "%d.%d", TZ_KELVTOC(sysctl_rslt));
#elif defined(__OpenBSD__)
	struct sensordev sensordev;
	struct sensor sensor;
	size_t sdlen, slen;
	int dev, numt, mib[5] = { CTL_HW, HW_SENSORS, 0, 0, 0 };

	sdlen = sizeof(sensordev);
	slen = sizeof(sensor);

	for (dev = 0; ; dev++) {
		mib[2] = dev;
		if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) {
			if (errno == ENXIO)
				continue;
			if (errno == ENOENT)
				break;
			goto error;
		}
		/* 'path' is the node within the full path (defaults to acpitz0). */
		if (strncmp(sensordev.xname, path, strlen(path)) == 0) {
			mib[3] = SENSOR_TEMP;
			/* Limit to temo0, but should retrieve from a full path... */
			for (numt = 0; numt < 1 /*sensordev.maxnumt[SENSOR_TEMP]*/; numt++) {
				mib[4] = numt;
				if (sysctl(mib, 5, &sensor, &slen, NULL, 0) == -1) {
					if (errno != ENOENT) {
						warn("sysctl");
						continue;
					}
				}
				if ((int)MUKTOC(sensor.value) >= max_threshold) {
					START_COLOR("color_bad");
					colorful_output = true;
				}

				outwalk += sprintf(outwalk, "%.2f", MUKTOC(sensor.value));

				if (colorful_output) {
					END_COLOR;
                                        colorful_output = false;
                                }
			}
		}
	}
#endif
                        walk += strlen("degrees");
                }
        }
        OUTPUT_FULL_TEXT(buffer);
        return;
error:
#endif
        OUTPUT_FULL_TEXT("cant read temp");
        (void)fputs("i3status: Cannot read temperature. Verify that you have a thermal zone in /sys/class/thermal or disable the cpu_temperature module in your i3status config.\n", stderr);
}