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