Update copyright stuff, fix conky.conf weirdness.
[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  */
27
28 #include "conky.h"
29 #include "logging.h"
30 #include <errno.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <netdb.h>
34 #include <sys/select.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37
38 #define BUFLEN 512
39 #define PORT 7634
40
41 char buf[BUFLEN];
42
43 int scan_hddtemp(const char *arg, char **dev, char **addr, int *port)
44 {
45         char buf1[32], buf2[64];
46         int n, ret;
47
48         if (!arg)
49                 return 1;
50
51         if ((ret = sscanf(arg, "%31s %63s %d", buf1, buf2, &n)) < 1)
52                 return 1;
53
54         if (strncmp(buf1, "/dev/", 5)) {
55                 strncpy(buf1 + 5, buf1, 32 - 5);
56                 strncpy(buf1, "/dev/", 5);
57         }
58         *dev = strndup(buf1, text_buffer_size);
59
60         if (ret >= 2) {
61                 *addr = strndup(buf2, text_buffer_size);
62         } else {
63                 *addr = strndup("127.0.0.1", text_buffer_size);
64         }
65
66         if (ret == 3) {
67                 *port = n;
68         } else {
69                 *port = PORT;
70         }
71
72         return 0;
73 }
74
75 /* this is an iterator:
76  * set line to NULL in consecutive calls to get the next field
77  * returns "<dev><unit><val>" or NULL on error
78  */
79 static char *read_hdd_val(const char *line)
80 {
81         static char line_s[512] = "\0";
82         static char *p = 0;
83         char *dev, *val, unit;
84         char *ret = NULL;
85
86         if (line) {
87                 snprintf(line_s, 512, "%s", line);
88                 p = line_s;
89         }
90         if (!(*line_s))
91                 return ret;
92         /* read the device */
93         dev = ++p;
94         if (!(p = strchr(p, line_s[0])))
95                 return ret;
96         *(p++) = '\0';
97         /* jump over the devname */
98         if (!(p = strchr(p, line_s[0])))
99                 return ret;
100         /* read the value */
101         val = ++p;
102         if (!(p = strchr(p, line_s[0])))
103                 return ret;
104         *(p++) = '\0';
105         unit = *(p++);
106         /* preset p for next call */
107         p = strchr(p + 1, line_s[0]);
108
109         if (dev && *dev && val && *val) {
110                 asprintf(&ret, "%s%c%s", dev, unit, val);
111         }
112         return ret;
113 }
114
115 /* returns <unit><val> or NULL on error or N/A */
116 char *get_hddtemp_info(char *dev, char *hostaddr, int port)
117 {
118         int sockfd = 0;
119         struct hostent he, *he_res = 0;
120         int he_errno;
121         char hostbuff[2048];
122         struct sockaddr_in addr;
123         struct timeval tv;
124         fd_set rfds;
125         int len, i;
126         char *p, *r = NULL;
127
128         if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
129                 perror("socket");
130                 goto GET_OUT;
131         }
132
133 #ifdef HAVE_GETHOSTBYNAME_R
134         if (gethostbyname_r(hostaddr, &he, hostbuff,
135                             sizeof(hostbuff), &he_res, &he_errno)) {
136                 ERR("hddtemp gethostbyname_r: %s", hstrerror(h_errno));
137 #else /* HAVE_GETHOSTBYNAME_R */
138         if (!(he_res = gethostbyname(hostaddr))) {
139                 perror("gethostbyname()");
140 #endif /* HAVE_GETHOSTBYNAME_R */
141                 goto GET_OUT;
142         }
143
144         addr.sin_family = AF_INET;
145         addr.sin_port = htons(port);
146         addr.sin_addr = *((struct in_addr *) he_res->h_addr);
147         memset(&(addr.sin_zero), 0, 8);
148
149         if (connect(sockfd, (struct sockaddr *) &addr,
150                                 sizeof(struct sockaddr)) == -1) {
151                 perror("connect");
152                 goto GET_OUT;
153         }
154
155         FD_ZERO(&rfds);
156         FD_SET(sockfd, &rfds);
157
158         /* We're going to wait up to a half second to see whether there's any
159          * data available. Polling with timeout set to 0 doesn't seem to work
160          * with hddtemp.
161          */
162         tv.tv_sec = 0;
163         tv.tv_usec = 500000;
164
165         i = select(sockfd + 1, &rfds, NULL, NULL, &tv);
166         if (i == -1) { /* select() failed */
167                 if (errno == EINTR) {
168                         /* silently ignore interrupted system call */
169                         goto GET_OUT;
170                 } else {
171                         perror("select");
172                 }
173         } else if (i == 0) { /* select() timeouted */
174                 ERR("hddtemp had nothing for us");
175                 goto GET_OUT;
176         }
177
178         p = buf;
179         len = 0;
180         do {
181                 i = recv(sockfd, p, BUFLEN - (p - buf), 0);
182                 if (i < 0) {
183                         perror("recv");
184                         break;
185                 }
186                 len += i;
187                 p += i;
188         } while (i > 0 && p < buf + BUFLEN - 1);
189
190         if (len < 2) {
191                 ERR("hddtemp returned nada");
192                 goto GET_OUT;
193         }
194
195         buf[len] = 0;
196
197         if ((p = read_hdd_val(buf)) == NULL)
198                 goto GET_OUT;
199         do {
200                 if (!strncmp(dev, p, strlen(dev)))
201                         asprintf(&r, "%s", p + strlen(dev));
202                 free(p);
203         } while(!r && (p = read_hdd_val(NULL)) != NULL);
204
205 GET_OUT:
206         close(sockfd);
207         return r;
208 }