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