Initial dockapps git repo
[dockapps.git] / wmfu / linux / sensors.c
blob0db9353ec93b3d1a3315f4061cc09c1aa3ba0b22
1 /*
2 * Copyright (c) 2007 Daniel Borca All rights reserved.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #include <dirent.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/stat.h>
25 #include <sys/wait.h>
26 #include <unistd.h>
28 #include "../list.h"
29 #include "../sensors.h"
32 static int
33 spawn_sync_read (const char *filename, const char *const argv[], int max, char *out)
35 #define READ 0
36 #define WRITE 1
37 pid_t pid;
38 int fd[2];
39 int status;
41 int size;
42 int eof;
44 if (pipe(fd) != 0) {
45 return -1;
48 pid = fork();
49 if (pid == -1) {
50 return -1;
52 if (pid == 0) {
53 close(fd[READ]);
54 close(STDERR_FILENO);
55 dup2(fd[WRITE], STDOUT_FILENO);
57 exit(execvp(filename, (char *const *)argv));
60 close(fd[WRITE]);
62 for (--max, size = 0, eof = 0; !eof;) {
63 char buf[512];
64 int chunk = read(fd[READ], buf, sizeof(buf));
65 if (chunk < 0) {
66 break;
68 eof = (chunk < (int)sizeof(buf));
69 if (size + chunk > max) {
70 chunk = max - size;
72 memcpy(&out[size], buf, chunk);
73 size += chunk;
75 out[size] = '\0';
77 close(fd[READ]);
79 wait(&status);
81 return size;
82 #undef WRITE
83 #undef READ
87 int
88 sensors_nvidia (const char *setting, int *val)
90 const char *argv[] = { "nvidia-settings", "-q" , NULL, NULL };
91 char out[BUFSIZ];
92 int dummy;
94 argv[2] = (char *)setting;
96 if (val == NULL) {
97 val = &dummy;
100 if (spawn_sync_read(argv[0], argv, sizeof(out), out) < 0) {
101 return -1;
104 if (sscanf(out, " Attribute %*s %*s %d", val) != 1) {
105 return -1;
108 return 0;
113 sensors_read_line (const char *filename, int max, char *out)
115 char *p;
116 FILE *f;
117 f = fopen(filename, "rt");
118 if (f == NULL) {
119 return -1;
121 if (fgets(out, max, f) == NULL) {
122 fclose(f);
123 return -1;
125 fclose(f);
126 p = strchr(out, '\n');
127 if (p != NULL) {
128 *p = '\0';
129 return p - out;
131 return strlen(out);
135 static int
136 add_sensor (SENSOR *list, const char *filename, const char *name, SENSOR_TYPE type)
138 SENSOR *s;
139 char *p, buf[256];
141 s = malloc(sizeof(SENSOR));
142 if (s == NULL) {
143 return -1;
145 s->type = type;
146 s->idata = 0;
148 switch (type) {
149 case S_ACPI_THERMAL_ZONE:
150 p = malloc(strlen(filename) + 32);
151 if (p == NULL) {
152 break;
154 strcat(strcpy(p, filename), "/trip_points");
155 s->idata = 100;
156 if (sensors_read_line(p, sizeof(buf), buf) > 0) {
157 sscanf(buf, "%*s %*s %d", &s->idata);
159 s->filename = strcat(strcpy(p, filename), "/temperature");
160 s->name = strdup(name);
161 if (s->name == NULL) {
162 free(p);
163 break;
165 list_append(list, s);
166 return 0;
167 case S_ACPI_AC_ADAPTER:
168 p = malloc(strlen(filename) + 32);
169 if (p == NULL) {
170 break;
172 s->filename = strcat(strcpy(p, filename), "/state");
173 s->name = strdup(name);
174 if (s->name == NULL) {
175 free(p);
176 break;
178 list_append(list, s);
179 return 0;
180 case S_ACPI_BATTERY:
181 p = malloc(strlen(filename) + 32);
182 if (p == NULL) {
183 break;
185 s->filename = strcat(strcpy(p, filename), "/");
186 s->name = strdup(name);
187 if (s->name == NULL) {
188 free(p);
189 break;
191 list_append(list, s);
192 return 0;
193 case S_HWMON_CORETEMP:
194 p = malloc(strlen(filename) + 32);
195 if (p == NULL) {
196 break;
198 strcat(strcpy(p, filename), "/device/name");
199 if (sensors_read_line(p, sizeof(buf), buf) <= 0) {
200 free(p);
201 break;
203 if (strcmp(buf, "coretemp")) {
204 free(p);
205 break;
207 strcat(strcpy(p, filename), "/device/temp1_crit");
208 s->idata = 100;
209 if (sensors_read_line(p, sizeof(buf), buf) > 0) {
210 sscanf(buf, "%d", &s->idata);
212 strcat(strcpy(p, filename), "/device/temp1_label");
213 if (sensors_read_line(p, sizeof(buf), buf) > 0) {
214 s->name = strdup(buf);
215 } else {
216 s->name = strdup(name);
218 s->filename = strcat(strcpy(p, filename), "/device/temp1_input");
219 if (s->name == NULL) {
220 free(s->filename);
221 break;
223 list_append(list, s);
224 return 0;
225 case S_NVIDIA_SETTINGS_GPUCORETEMP:
226 if (sensors_nvidia(name, NULL) != 0) {
227 break;
229 p = strdup(filename);
230 if (p == NULL) {
231 break;
233 s->filename = p;
234 s->name = strdup(name);
235 if (s->name == NULL) {
236 free(p);
237 break;
239 list_append(list, s);
240 return 0;
243 free(s);
244 return -1;
248 static void
249 scan_dirs (const char *dirname, SENSOR *list, SENSOR_TYPE type)
251 DIR *dir;
252 int len = strlen(dirname);
254 dir = opendir(dirname);
255 if (dir != NULL) {
256 struct dirent *ent;
257 while ((ent = readdir(dir))) {
258 if (strcmp(ent->d_name, ".") && strcmp(ent->d_name, "..")) {
259 char *fullname = malloc(len + 1 + strlen(ent->d_name) + 1);
260 if (fullname != NULL) {
261 struct stat buf;
262 int l = len;
263 strcpy(fullname, dirname);
264 if (fullname[l - 1] != '/') {
265 fullname[l++] = '/';
267 strcpy(&fullname[l], ent->d_name);
268 /* don't use d_type */
269 if (stat(fullname, &buf) == 0 && S_ISDIR(buf.st_mode)) {
270 add_sensor(list, fullname, ent->d_name, type);
272 free(fullname);
276 closedir(dir);
281 SENSOR *
282 sensors_init (void)
284 SENSOR *list;
286 list = malloc(sizeof(SENSOR));
287 if (list == NULL) {
288 return NULL;
290 list->type = -1;
292 list_create(list);
294 scan_dirs("/proc/acpi/thermal_zone", list, S_ACPI_THERMAL_ZONE);
295 scan_dirs("/proc/acpi/ac_adapter", list, S_ACPI_AC_ADAPTER);
296 scan_dirs("/proc/acpi/battery", list, S_ACPI_BATTERY);
297 scan_dirs("/sys/class/hwmon", list, S_HWMON_CORETEMP);
298 add_sensor(list, "nvidia-settings", "GPUCoreTemp", S_NVIDIA_SETTINGS_GPUCORETEMP);
300 return list;
304 void
305 sensors_free (SENSOR *list)
307 SENSOR *s, *tmp;
309 list_foreach_s (s, tmp, list) {
310 list_remove(s);
311 free(s->filename);
312 free((char *)s->name);
313 free(s);
316 free(list);