Add vim modelines.
[monky] / src / hddtemp.c
1 /* Conky, a system monitor, based on torsmo
2  *
3  * Any original torsmo code is licensed under the BSD license
4  *
5  * All code written since the fork of torsmo is licensed under the GPL
6  *
7  * Please see COPYING for details
8  *
9  * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
10  * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
11  *      (see AUTHORS)
12  * All rights reserved.
13  *
14  * This program is free software: you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation, either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  * You should have received a copy of the GNU General Public License
24  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
25  *
26  * vim: ts=4 sw=4 noet ai cindent syntax=c
27  *
28  */
29
30 #include "conky.h"
31 #include "logging.h"
32 #include <errno.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <netdb.h>
36 #include <sys/select.h>
37 #include <sys/socket.h>
38 #include <netinet/in.h>
39
40 #define BUFLEN 512
41 #define PORT 7634
42
43 char buf[BUFLEN];
44
45 int scan_hddtemp(const char *arg, char **dev, char **addr, int *port)
46 {
47         char buf1[32], buf2[64];
48         int n, ret;
49
50         if (!arg)
51                 return 1;
52
53         if ((ret = sscanf(arg, "%31s %63s %d", buf1, buf2, &n)) < 1)
54                 return 1;
55
56         if (strncmp(buf1, "/dev/", 5)) {
57                 strncpy(buf1 + 5, buf1, 32 - 5);
58                 strncpy(buf1, "/dev/", 5);
59         }
60         *dev = strndup(buf1, text_buffer_size);
61
62         if (ret >= 2) {
63                 *addr = strndup(buf2, text_buffer_size);
64         } else {
65                 *addr = strndup("127.0.0.1", text_buffer_size);
66         }
67
68         if (ret == 3) {
69                 *port = n;
70         } else {
71                 *port = PORT;
72         }
73
74         return 0;
75 }
76
77 /* this is an iterator:
78  * set line to NULL in consecutive calls to get the next field
79  * returns "<dev><unit><val>" or NULL on error
80  */
81 static char *read_hdd_val(const char *line)
82 {
83         static char line_s[512] = "\0";
84         static char *p = 0;
85         char *dev, *val, unit;
86         char *ret = NULL;
87
88         if (line) {
89                 if (!snprintf(line_s, 512, "%s", line)) return ret;
90                 p = line_s;
91         }
92         if (!(*line_s) || !p)
93                 return ret;
94         /* read the device */
95         dev = ++p;
96         if (!(p = strchr(p, line_s[0])))
97                 return ret;
98         *(p++) = '\0';
99         /* jump over the devname */
100         if (!(p = strchr(p, line_s[0])))
101                 return ret;
102         /* read the value */
103         val = ++p;
104         if (!(p = strchr(p, line_s[0])))
105                 return ret;
106         *(p++) = '\0';
107         unit = *(p++);
108         /* preset p for next call */
109         p = strchr(p + 1, line_s[0]);
110
111         if (dev && *dev && val && *val) {
112                 asprintf(&ret, "%s%c%s", dev, unit, val);
113         }
114         return ret;
115 }
116
117 /* returns <unit><val> or NULL on error or N/A */
118 char *get_hddtemp_info(char *dev, char *hostaddr, int port)
119 {
120         int sockfd = 0;
121         struct hostent he, *he_res = 0;
122         int he_errno;
123         char hostbuff[2048];
124         struct sockaddr_in addr;
125         struct timeval tv;
126         fd_set rfds;
127         int len, i;
128         char *p, *r = NULL;
129
130         if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
131                 perror("socket");
132                 goto GET_OUT;
133         }
134
135 #ifdef HAVE_GETHOSTBYNAME_R
136         if (gethostbyname_r(hostaddr, &he, hostbuff,
137                             sizeof(hostbuff), &he_res, &he_errno)) {
138                 ERR("hddtemp gethostbyname_r: %s", hstrerror(h_errno));
139 #else /* HAVE_GETHOSTBYNAME_R */
140         if (!(he_res = gethostbyname(hostaddr))) {
141                 perror("gethostbyname()");
142 #endif /* HAVE_GETHOSTBYNAME_R */
143                 goto GET_OUT;
144         }
145
146         addr.sin_family = AF_INET;
147         addr.sin_port = htons(port);
148         addr.sin_addr = *((struct in_addr *) he_res->h_addr);
149         memset(&(addr.sin_zero), 0, 8);
150
151         if (connect(sockfd, (struct sockaddr *) &addr,
152                                 sizeof(struct sockaddr)) == -1) {
153                 perror("connect");
154                 goto GET_OUT;
155         }
156
157         FD_ZERO(&rfds);
158         FD_SET(sockfd, &rfds);
159
160         /* We're going to wait up to a half second to see whether there's any
161          * data available. Polling with timeout set to 0 doesn't seem to work
162          * with hddtemp.
163          */
164         tv.tv_sec = 0;
165         tv.tv_usec = 500000;
166
167         i = select(sockfd + 1, &rfds, NULL, NULL, &tv);
168         if (i == -1) { /* select() failed */
169                 if (errno == EINTR) {
170                         /* silently ignore interrupted system call */
171                         goto GET_OUT;
172                 } else {
173                         perror("select");
174                 }
175         } else if (i == 0) { /* select() timeouted */
176                 ERR("hddtemp had nothing for us");
177                 goto GET_OUT;
178         }
179
180         p = buf;
181         len = 0;
182         do {
183                 i = recv(sockfd, p, BUFLEN - (p - buf), 0);
184                 if (i < 0) {
185                         perror("recv");
186                         break;
187                 }
188                 len += i;
189                 p += i;
190         } while (i > 0 && p < buf + BUFLEN - 1);
191
192         if (len < 2) {
193                 ERR("hddtemp returned nada");
194                 goto GET_OUT;
195         }
196
197         buf[len] = 0;
198
199         if ((p = read_hdd_val(buf)) == NULL)
200                 goto GET_OUT;
201         do {
202                 if (!strncmp(dev, p, strlen(dev)))
203                         asprintf(&r, "%s", p + strlen(dev));
204                 free(p);
205         } while(!r && (p = read_hdd_val(NULL)) != NULL);
206
207 GET_OUT:
208         close(sockfd);
209         return r;
210 }