src/rrd_daemon.c: Use `sread' and `swrite' instead of read(2) and write(2).
authorFlorian Forster <octo@verplant.org>
Thu, 3 Jul 2008 09:39:13 +0000 (11:39 +0200)
committerFlorian Forster <octo@verplant.org>
Thu, 3 Jul 2008 09:39:13 +0000 (11:39 +0200)
The ``secure'' sread assures that the received string ends with a newline,
strips it off the buffer and assures that the returned buffer is null
terminated. swrite returns success only if all bytes could be written.

src/rrd_daemon.c

index 7a51f5d..ac974ed 100644 (file)
@@ -223,6 +223,84 @@ static int remove_pidfile (void) /* {{{ */
   return (errno);
 } /* }}} int remove_pidfile */
 
+static ssize_t sread (int fd, void *buffer_void, size_t buffer_size) /* {{{ */
+{
+  char    *buffer;
+  size_t   buffer_used;
+  size_t   buffer_free;
+  ssize_t  status;
+
+  buffer       = (char *) buffer_void;
+  buffer_used  = 0;
+  buffer_free  = buffer_size;
+
+  while (buffer_free > 0)
+  {
+    status = read (fd, buffer + buffer_used, buffer_free);
+    if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+      continue;
+
+    if (status < 0)
+      return (-1);
+
+    if (status == 0)
+      return (0);
+
+    assert ((0 > status) || (buffer_free >= (size_t) status));
+
+    buffer_free = buffer_free - status;
+    buffer_used = buffer_used + status;
+
+    if (buffer[buffer_used - 1] == '\n')
+      break;
+  }
+
+  assert (buffer_used > 0);
+
+  if (buffer[buffer_used - 1] != '\n')
+  {
+    errno = ENOBUFS;
+    return (-1);
+  }
+
+  buffer[buffer_used - 1] = 0;
+
+  /* Fix network line endings. */
+  if ((buffer_used > 1) && (buffer[buffer_used - 2] == '\r'))
+  {
+    buffer_used--;
+    buffer[buffer_used - 1] = 0;
+  }
+
+  return (buffer_used);
+} /* }}} ssize_t sread */
+
+static ssize_t swrite (int fd, const void *buf, size_t count) /* {{{ */
+{
+  const char *ptr;
+  size_t      nleft;
+  ssize_t     status;
+
+  ptr   = (const char *) buf;
+  nleft = count;
+
+  while (nleft > 0)
+  {
+    status = write (fd, (const void *) ptr, nleft);
+
+    if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+      continue;
+
+    if (status < 0)
+      return (status);
+
+    nleft = nleft - status;
+    ptr   = ptr   + status;
+  }
+
+  return (0);
+} /* }}} ssize_t swrite */
+
 /*
  * enqueue_cache_item:
  * `cache_lock' must be acquired before calling this function!
@@ -687,11 +765,11 @@ static int handle_request_help (int fd, /* {{{ */
 
   for (i = 0; i < help_text_len; i++)
   {
-    status = write (fd, help_text[i], strlen (help_text[i]));
+    status = swrite (fd, help_text[i], strlen (help_text[i]));
     if (status < 0)
     {
       status = errno;
-      RRDD_LOG (LOG_ERR, "handle_request_help: write(2) returned an error.");
+      RRDD_LOG (LOG_ERR, "handle_request_help: swrite returned an error.");
       return (status);
     }
   }
@@ -726,11 +804,11 @@ static int handle_request_stats (int fd, /* {{{ */
 
 #define RRDD_STATS_SEND \
   outbuf[sizeof (outbuf) - 1] = 0; \
-  status = write (fd, outbuf, strlen (outbuf)); \
+  status = swrite (fd, outbuf, strlen (outbuf)); \
   if (status < 0) \
   { \
     status = errno; \
-    RRDD_LOG (LOG_INFO, "handle_request_stats: write(2) returned an error."); \
+    RRDD_LOG (LOG_INFO, "handle_request_stats: swrite returned an error."); \
     return (status); \
   }
 
@@ -786,11 +864,11 @@ static int handle_request_flush (int fd, /* {{{ */
   }
   result[sizeof (result) - 1] = 0;
 
-  status = write (fd, result, strlen (result));
+  status = swrite (fd, result, strlen (result));
   if (status < 0)
   {
     status = errno;
-    RRDD_LOG (LOG_INFO, "handle_request_flush: write(2) returned an error.");
+    RRDD_LOG (LOG_INFO, "handle_request_flush: swrite returned an error.");
     return (status);
   }
 
@@ -895,14 +973,15 @@ static int handle_request_update (int fd, /* {{{ */
 
   pthread_mutex_unlock (&cache_lock);
 
-  snprintf (answer, sizeof (answer), "0 Enqueued %i value(s)\n", values_num);
+  snprintf (answer, sizeof (answer), "0 Enqueued %i value%s\n", values_num,
+      (values_num == 1) ? "" : "s");
   answer[sizeof (answer) - 1] = 0;
 
-  status = write (fd, answer, strlen (answer));
+  status = swrite (fd, answer, strlen (answer));
   if (status < 0)
   {
     status = errno;
-    RRDD_LOG (LOG_INFO, "handle_request_update: write(2) returned an error.");
+    RRDD_LOG (LOG_INFO, "handle_request_update: swrite returned an error.");
     return (status);
   }
 
@@ -917,31 +996,19 @@ static int handle_request (int fd) /* {{{ */
   char *command;
   int status;
 
-  status = read (fd, buffer, sizeof (buffer));
+  status = (int) sread (fd, buffer, sizeof (buffer));
   if (status == 0)
   {
     return (1);
   }
   else if (status < 0)
   {
-    RRDD_LOG (LOG_ERR, "handle_request: read(2) failed.");
-    return (-1);
-  }
-  buffer_size = status;
-  assert (((size_t) buffer_size) <= sizeof (buffer));
-
-  if (buffer[buffer_size - 1] != '\n')
-  {
-    RRDD_LOG (LOG_INFO, "handle_request: malformed request.");
+    RRDD_LOG (LOG_ERR, "handle_request: sread failed.");
     return (-1);
   }
-
-  /* Accept Windows style line endings, too */
-  if ((buffer_size > 2) && (buffer[buffer_size - 2] == '\r'))
-  {
-    buffer_size--;
-    buffer[buffer_size - 1] = '\n';
-  }
+  buffer_size = (size_t) status;
+  assert (buffer_size <= sizeof (buffer));
+  assert (buffer[buffer_size - 1] == 0);
 
   /* Place the normal field separator at the end to simplify
    * `buffer_get_field's work. */
@@ -979,10 +1046,10 @@ static int handle_request (int fd) /* {{{ */
     snprintf (result, sizeof (result), "-1 Unknown command: %s\n", command);
     result[sizeof (result) - 1] = 0;
 
-    status = write (fd, result, strlen (result));
+    status = swrite (fd, result, strlen (result));
     if (status < 0)
     {
-      RRDD_LOG (LOG_ERR, "handle_request: write(2) failed.");
+      RRDD_LOG (LOG_ERR, "handle_request: swrite failed.");
       return (-1);
     }
   }