Delay checking for want_apcupsd.
[monky] / src / hddtemp.c
index 66c9f15..a622f6b 100644 (file)
@@ -1,8 +1,33 @@
+/* Conky, a system monitor, based on torsmo
+ *
+ * Any original torsmo code is licensed under the BSD license
+ *
+ * All code written since the fork of torsmo is licensed under the GPL
+ *
+ * Please see COPYING for details
+ *
+ * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
+ * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
+ *     (see AUTHORS)
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
 #include "conky.h"
+#include "logging.h"
 #include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <netdb.h>
@@ -19,133 +44,165 @@ int scan_hddtemp(const char *arg, char **dev, char **addr, int *port)
 {
        char buf1[32], buf2[64];
        int n, ret;
-       
-       ret = sscanf(arg, "%31s %63s %d", buf1, buf2, &n);
-       
-       if (ret < 1)
-               return -1;
-
-       *dev = strdup(buf1);
-       if (ret >= 2)
-               *addr = strdup(buf2);
-       else
-               *addr = strdup("127.0.0.1");
-
-       if (ret == 3) 
+
+       if (!arg)
+               return 1;
+
+       if ((ret = sscanf(arg, "%31s %63s %d", buf1, buf2, &n)) < 1)
+               return 1;
+
+       if (strncmp(buf1, "/dev/", 5)) {
+               strncpy(buf1 + 5, buf1, 32 - 5);
+               strncpy(buf1, "/dev/", 5);
+       }
+       *dev = strndup(buf1, text_buffer_size);
+
+       if (ret >= 2) {
+               *addr = strndup(buf2, text_buffer_size);
+       } else {
+               *addr = strndup("127.0.0.1", text_buffer_size);
+       }
+
+       if (ret == 3) {
                *port = n;
-       else
+       } else {
                *port = PORT;
+       }
 
        return 0;
 }
 
-char *get_hddtemp_info(char *dev, char *hostaddr, int port, char *unit)
+/* this is an iterator:
+ * set line to NULL in consecutive calls to get the next field
+ * returns "<dev><unit><val>" or NULL on error
+ */
+static char *read_hdd_val(const char *line)
+{
+       static char line_s[512] = "\0";
+       static char *p = 0;
+       char *dev, *val, unit;
+       char *ret = NULL;
+
+       if (line) {
+               snprintf(line_s, 512, "%s", line);
+               p = line_s;
+       }
+       if (!(*line_s))
+               return ret;
+       /* read the device */
+       dev = ++p;
+       if (!(p = strchr(p, line_s[0])))
+               return ret;
+       *(p++) = '\0';
+       /* jump over the devname */
+       if (!(p = strchr(p, line_s[0])))
+               return ret;
+       /* read the value */
+       val = ++p;
+       if (!(p = strchr(p, line_s[0])))
+               return ret;
+       *(p++) = '\0';
+       unit = *(p++);
+       /* preset p for next call */
+       p = strchr(p + 1, line_s[0]);
+
+       if (dev && *dev && val && *val) {
+               asprintf(&ret, "%s%c%s", dev, unit, val);
+       }
+       return ret;
+}
+
+/* returns <unit><val> or NULL on error or N/A */
+char *get_hddtemp_info(char *dev, char *hostaddr, int port)
 {
        int sockfd = 0;
-       struct hostent *he;
+       struct hostent he, *he_res = 0;
+       int he_errno;
+       char hostbuff[2048];
        struct sockaddr_in addr;
        struct timeval tv;
        fd_set rfds;
-       int len, i, devlen = strlen(dev);
-       char sep;
-       char *p, *out, *r = NULL;
-       
+       int len, i;
+       char *p, *r = NULL;
+
        if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
                perror("socket");
-               return NULL;
+               goto GET_OUT;
        }
 
-       he = gethostbyname(hostaddr);
-       if (!he) {
-               perror("gethostbyname");
-               goto out;
+#ifdef HAVE_GETHOSTBYNAME_R
+       if (gethostbyname_r(hostaddr, &he, hostbuff,
+                           sizeof(hostbuff), &he_res, &he_errno)) {
+               ERR("hddtemp gethostbyname_r: %s", hstrerror(h_errno));
+#else /* HAVE_GETHOSTBYNAME_R */
+       if (!(he_res = gethostbyname(hostaddr))) {
+               perror("gethostbyname()");
+#endif /* HAVE_GETHOSTBYNAME_R */
+               goto GET_OUT;
        }
 
        addr.sin_family = AF_INET;
        addr.sin_port = htons(port);
-       addr.sin_addr = *((struct in_addr *)he->h_addr);
+       addr.sin_addr = *((struct in_addr *) he_res->h_addr);
        memset(&(addr.sin_zero), 0, 8);
 
-       if (connect(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
+       if (connect(sockfd, (struct sockaddr *) &addr,
+                               sizeof(struct sockaddr)) == -1) {
                perror("connect");
-               goto out;
+               goto GET_OUT;
        }
 
        FD_ZERO(&rfds);
        FD_SET(sockfd, &rfds);
 
-       /* We're going to wait up to a quarter a second to see whether
-        * there's any data available. Polling with timeout set to 0
-        * doesn't seem to work with hddtemp. */
+       /* We're going to wait up to a half second to see whether there's any
+        * data available. Polling with timeout set to 0 doesn't seem to work
+        * with hddtemp.
+        */
        tv.tv_sec = 0;
-       tv.tv_usec = 250000;
-       
-       i = select(sockfd+1, &rfds, NULL, NULL, &tv);
-       if (i == -1)
-       {
-               if (errno == EINTR)     /* silently ignore interrupted system call */
-                   goto out;
-               else
-                   perror("select");
+       tv.tv_usec = 500000;
+
+       i = select(sockfd + 1, &rfds, NULL, NULL, &tv);
+       if (i == -1) { /* select() failed */
+               if (errno == EINTR) {
+                       /* silently ignore interrupted system call */
+                       goto GET_OUT;
+               } else {
+                       perror("select");
+               }
+       } else if (i == 0) { /* select() timeouted */
+               ERR("hddtemp had nothing for us");
+               goto GET_OUT;
        }
 
-       /* No data available */
-       if (i <= 0)
-               goto out;
-       
        p = buf;
        len = 0;
        do {
-               i = recv(sockfd, p, BUFLEN - (p-buf), 0);
+               i = recv(sockfd, p, BUFLEN - (p - buf), 0);
                if (i < 0) {
                        perror("recv");
-                       goto out;
+                       break;
                }
                len += i;
                p += i;
        } while (i > 0 && p < buf + BUFLEN - 1);
-       
+
        if (len < 2) {
-               goto out;
+               ERR("hddtemp returned nada");
+               goto GET_OUT;
        }
-       
+
        buf[len] = 0;
-               
-       /* The first character read is the separator. */
-       sep = buf[0];
-       p = buf+1;
-       
-       while (*p) {
-               if (!strncmp(p, dev, devlen)) {
-                       p += devlen + 1; 
-                       p = strchr(p, sep);
-                       if (!p) 
-                               goto out;
-                       p++;
-                       out = p;        
-                       p = strchr(p, sep);
-                       if (!p) 
-                               goto out;
-                       *p = '\0';
-                       p++;
-                       *unit = *p;     
-                       if (!strncmp(out, "NA", 2)) {
-                               strcpy(buf, "N/A");
-                               r = buf;
-                       } else {                                        
-                               r = out;
-                       }
-                       goto out;
-               } else {
-                       for (i = 0; i < 5; i++) {
-                               p = strchr(p, sep);
-                               if (!p)
-                                       goto out;
-                               p++;
-                       }
-               }
-       }
-out:   close(sockfd);
+
+       if ((p = read_hdd_val(buf)) == NULL)
+               goto GET_OUT;
+       do {
+               if (!strncmp(dev, p, strlen(dev)))
+                       asprintf(&r, "%s", p + strlen(dev));
+               free(p);
+       } while(!r && (p = read_hdd_val(NULL)) != NULL);
+
+GET_OUT:
+       close(sockfd);
        return r;
 }
-