fixed hddtemp problems as well as some other misc things
[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-2008 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  * $Id$ */
27
28 #include "conky.h"
29 #include <errno.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.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, char** temp)
46 {
47         char buf1[32], buf2[64];
48         int n, ret;
49
50         ret = sscanf(arg, "%31s %63s %d", buf1, buf2, &n);
51
52         if (ret < 1) {
53                 return -1;
54         }
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         *temp = malloc(text_buffer_size);
75         memset(*temp, 0, text_buffer_size);
76
77         return 0;
78 }
79
80 char *get_hddtemp_info(char *dev, char *hostaddr, int port, char *unit)
81 {
82         int sockfd = 0;
83         struct hostent he, *he_res = 0;
84         int he_errno;
85         char hostbuff[2048];
86         struct sockaddr_in addr;
87         struct timeval tv;
88         fd_set rfds;
89         int len, i, devlen = strlen(dev);
90         char sep;
91         char *p, *out, *r = NULL;
92
93         if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
94                 perror("socket");
95                 return NULL;
96         }
97
98         do {
99 #ifdef HAVE_GETHOSTBYNAME_R
100                 if (gethostbyname_r(hostaddr, &he, hostbuff, sizeof(hostbuff), &he_res, &he_errno)) {   // get the host info
101                         ERR("hddtemp gethostbyname_r: %s", hstrerror(h_errno));
102                         break;
103                 }
104 #else /* HAVE_GETHOSTBYNAME_R */
105                 he_res = gethostbyname(hostaddr);
106                 if (!he_res) {
107                         perror("gethostbyname");
108                         break;
109                 }
110 #endif /* HAVE_GETHOSTBYNAME_R */
111
112                 addr.sin_family = AF_INET;
113                 addr.sin_port = htons(port);
114                 addr.sin_addr = *((struct in_addr *) he_res->h_addr);
115                 memset(&(addr.sin_zero), 0, 8);
116
117                 if (connect(sockfd, (struct sockaddr *) &addr,
118                                         sizeof(struct sockaddr)) == -1) {
119                         perror("connect");
120                         break;
121                 }
122
123                 FD_ZERO(&rfds);
124                 FD_SET(sockfd, &rfds);
125
126                 /* We're going to wait up to a quarter a second to see whether there's
127                  * any data available. Polling with timeout set to 0 doesn't seem to work
128                  * with hddtemp. */
129                 tv.tv_sec = 0;
130                 tv.tv_usec = 250000;
131
132                 i = select(sockfd + 1, &rfds, NULL, NULL, &tv);
133                 if (i == -1) {
134                         if (errno == EINTR) {   /* silently ignore interrupted system call */
135                                 break;
136                         } else {
137                                 perror("select");
138                         }
139                 }
140
141                 /* No data available */
142                 if (i <= 0) {
143                         break;
144                 }
145
146                 p = buf;
147                 len = 0;
148                 do {
149                         i = recv(sockfd, p, BUFLEN - (p - buf), 0);
150                         if (i < 0) {
151                                 perror("recv");
152                                 break;
153                         }
154                         len += i;
155                         p += i;
156                 } while (i > 0 && p < buf + BUFLEN - 1);
157
158                 if (len < 2) {
159                         break;
160                 }
161
162                 buf[len] = 0;
163
164                 /* The first character read is the separator. */
165                 sep = buf[0];
166                 p = buf + 1;
167
168                 while (*p) {
169                         if (!strncmp(p, dev, devlen)) {
170                                 p += devlen + 1;
171                                 p = strchr(p, sep);
172                                 if (!p) {
173                                         break;
174                                 }
175                                 p++;
176                                 out = p;
177                                 p = strchr(p, sep);
178                                 if (!p) {
179                                         break;
180                                 }
181                                 *p = '\0';
182                                 p++;
183                                 *unit = *p;
184                                 if (!strncmp(out, "NA", 2)) {
185                                         strncpy(buf, "N/A", BUFLEN);
186                                         r = buf;
187                                 } else {
188                                         r = out;
189                                 }
190                                 break;
191                         } else {
192                                 for (i = 0; i < 5; i++) {
193                                         p = strchr(p, sep);
194                                         if (!p) {
195                                                 break;
196                                         }
197                                         p++;
198                                 }
199                                 if (!p && i < 5) {
200                                         break;
201                                 }
202                         }
203                 }
204         } while (0);
205         close(sockfd);
206         return r;
207 }