]> git.sur5r.net Git - i3/i3status/blob - src/print_cpu_temperature.c
c687474b7671b87d54d2c87983d008c3a0e799a3
[i3/i3status] / src / print_cpu_temperature.c
1 // vim:ts=8:expandtab
2 #include <stdlib.h>
3 #include <limits.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <yajl/yajl_gen.h>
7 #include <yajl/yajl_version.h>
8
9 #include "i3status.h"
10
11 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
12 #include <err.h>
13 #include <sys/types.h>
14 #include <sys/sysctl.h>
15 #define TZ_ZEROC 2732
16 #define TZ_KELVTOC(x) (((x) - TZ_ZEROC) / 10), abs(((x) - TZ_ZEROC) % 10)
17 #define TZ_AVG(x) ((x) - TZ_ZEROC) / 10
18 #endif
19
20 #if defined(__DragonFly__)
21 #include <sys/sysctl.h>
22 #include <sys/types.h>
23 #include <sys/sensors.h>
24 #define MUKTOC(v) ((v - 273150000) / 1000000.0)
25 #endif
26
27 #if defined(__OpenBSD__)
28 #include <sys/param.h>
29 #include <sys/types.h>
30 #include <sys/sysctl.h>
31 #include <sys/sensors.h>
32 #include <errno.h>
33 #include <err.h>
34
35 #define MUKTOC(v) ((v - 273150000) / 1000000.0)
36 #endif
37
38 #if defined(__NetBSD__)
39 #include <fcntl.h>
40 #include <prop/proplib.h>
41 #include <sys/envsys.h>
42
43 #define MUKTOC(v) ((v - 273150000) / 1000000.0)
44 #endif
45
46
47 /*
48  * Reads the CPU temperature from /sys/class/thermal/thermal_zone%d/temp (or
49  * the user provided path) and returns the temperature in degree celcius.
50  *
51  */
52 void print_cpu_temperature_info(yajl_gen json_gen, char *buffer, int zone, const char *path, const char *format, int max_threshold) {
53         char *outwalk = buffer;
54 #ifdef THERMAL_ZONE
55         const char *walk;
56         bool colorful_output = false;
57         char *thermal_zone;
58
59         if (path == NULL)
60                 asprintf(&thermal_zone, THERMAL_ZONE, zone);
61         else
62                 asprintf(&thermal_zone, path, zone);
63
64         INSTANCE(thermal_zone);
65
66         for (walk = format; *walk != '\0'; walk++) {
67                 if (*walk != '%') {
68                         *(outwalk++) = *walk;
69                         continue;
70                 }
71
72                 if (BEGINS_WITH(walk+1, "degrees")) {
73 #if defined(LINUX)
74                         static char buf[16];
75                         long int temp;
76                         if (!slurp(thermal_zone, buf, sizeof(buf)))
77                                 goto error;
78                         temp = strtol(buf, NULL, 10);
79                         if (temp == LONG_MIN || temp == LONG_MAX || temp <= 0)
80                                 *(outwalk++) = '?';
81                         else {
82                                 if ((temp/1000) >= max_threshold) {
83                                         START_COLOR("color_bad");
84                                         colorful_output = true;
85                                 }
86                                 outwalk += sprintf(outwalk, "%ld", (temp/1000));
87                                 if (colorful_output) {
88                                         END_COLOR;
89                                         colorful_output = false;
90                                 }
91                         }
92 #elif defined(__DragonFly__)
93                         struct sensor th_sensor;
94                         size_t th_sensorlen;
95
96                         th_sensorlen = sizeof(th_sensor);
97
98                         if (sysctlbyname(thermal_zone, &th_sensor, &th_sensorlen, NULL, 0) == -1) {
99                                 perror("sysctlbyname");
100                                 goto error;
101                         }
102                         if (MUKTOC(th_sensor.value) >= max_threshold) {
103                                 START_COLOR("color_bad");
104                                 colorful_output = true;
105                         }
106                         outwalk += sprintf(outwalk, "%.2f", MUKTOC(th_sensor.value));
107                         if (colorful_output) {
108                                 END_COLOR;
109                                 colorful_output = false;
110                         }
111
112 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
113                         int sysctl_rslt;
114                         size_t sysctl_size = sizeof(sysctl_rslt);
115                         if (sysctlbyname(thermal_zone, &sysctl_rslt, &sysctl_size, NULL, 0))
116                                 goto error;
117
118                         if (TZ_AVG(sysctl_rslt) >= max_threshold) {
119                                 START_COLOR("color_bad");
120                                 colorful_output = true;
121                         }
122                         outwalk += sprintf(outwalk, "%d.%d", TZ_KELVTOC(sysctl_rslt));
123                         if (colorful_output) {
124                                 END_COLOR;
125                                 colorful_output = false;
126                         }
127
128 #elif defined(__OpenBSD__)
129         struct sensordev sensordev;
130         struct sensor sensor;
131         size_t sdlen, slen;
132         int dev, numt, mib[5] = { CTL_HW, HW_SENSORS, 0, 0, 0 };
133
134         sdlen = sizeof(sensordev);
135         slen = sizeof(sensor);
136
137         for (dev = 0; ; dev++) {
138                 mib[2] = dev;
139                 if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) {
140                         if (errno == ENXIO)
141                                 continue;
142                         if (errno == ENOENT)
143                                 break;
144                         goto error;
145                 }
146                 /* 'path' is the node within the full path (defaults to acpitz0). */
147                 if (BEGINS_WITH(sensordev.xname, thermal_zone)) {
148                         mib[3] = SENSOR_TEMP;
149                         /* Limit to temo0, but should retrieve from a full path... */
150                         for (numt = 0; numt < 1 /*sensordev.maxnumt[SENSOR_TEMP]*/; numt++) {
151                                 mib[4] = numt;
152                                 if (sysctl(mib, 5, &sensor, &slen, NULL, 0) == -1) {
153                                         if (errno != ENOENT) {
154                                                 warn("sysctl");
155                                                 continue;
156                                         }
157                                 }
158                                 if ((int)MUKTOC(sensor.value) >= max_threshold) {
159                                         START_COLOR("color_bad");
160                                         colorful_output = true;
161                                 }
162
163                                 outwalk += sprintf(outwalk, "%.2f", MUKTOC(sensor.value));
164
165                                 if (colorful_output) {
166                                         END_COLOR;
167                                         colorful_output = false;
168                                 }
169                         }
170                 }
171         }
172 #elif defined(__NetBSD__)
173         int fd, rval;
174         bool err = false;
175         prop_dictionary_t dict;
176         prop_array_t array;
177         prop_object_iterator_t iter;
178         prop_object_iterator_t iter2;
179         prop_object_t obj, obj2, obj3;
180
181         fd = open("/dev/sysmon", O_RDONLY);
182         if (fd == -1)
183                 goto error;
184
185         rval = prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &dict);
186         if (rval == -1) {
187             err = true;
188             goto error_netbsd1;
189         }
190
191         /* No drivers registered? */
192         if (prop_dictionary_count(dict) == 0) {
193             err = true;
194             goto error_netbsd2;
195         }
196
197         iter = prop_dictionary_iterator(dict);
198         if (iter == NULL) {
199             err = true;
200             goto error_netbsd2;
201         }
202
203         /* iterate over the dictionary returned by the kernel */
204         while ((obj = prop_object_iterator_next(iter)) != NULL) {
205                 /* skip this dict if it's not what we're looking for */
206                 if ((strlen(prop_dictionary_keysym_cstring_nocopy(obj)) != strlen(thermal_zone)) ||
207                     (strncmp(thermal_zone,
208                              prop_dictionary_keysym_cstring_nocopy(obj),
209                              strlen(thermal_zone)) != 0))
210                         continue;
211
212                 array = prop_dictionary_get_keysym(dict, obj);
213                 if (prop_object_type(array) != PROP_TYPE_ARRAY) {
214                     err = true;
215                     goto error_netbsd3;
216                 }
217
218                 iter2 = prop_array_iterator(array);
219                 if (!iter2) {
220                     err = true;
221                     goto error_netbsd3;
222                 }
223
224                 /* iterate over array of dicts specific to target sensor */
225                 while ((obj2 = prop_object_iterator_next(iter2)) != NULL) {
226                         obj3 = prop_dictionary_get(obj2, "cur-value");
227
228                         float temp = MUKTOC(prop_number_integer_value(obj3));
229                         if ((int)temp >= max_threshold) {
230                                 START_COLOR("color_bad");
231                                 colorful_output = true;
232                         }
233
234                         outwalk += sprintf(outwalk, "%.2f", temp);
235
236                         if (colorful_output) {
237                                 END_COLOR;
238                                 colorful_output = false;
239                         }
240
241                         break;
242                 }
243                 prop_object_iterator_release(iter2);
244         }
245 error_netbsd3:
246         prop_object_iterator_release(iter);
247 error_netbsd2:
248         prop_object_release(dict);
249 error_netbsd1:
250         close(fd);
251         if (err) goto error;
252
253 #endif
254
255
256                         walk += strlen("degrees");
257                 }
258         }
259
260         free(thermal_zone);
261
262         OUTPUT_FULL_TEXT(buffer);
263         return;
264 error:
265 #endif
266         free(thermal_zone);
267
268         OUTPUT_FULL_TEXT("cant read temp");
269         (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);
270 }