/**
* collectd - src/common.c
- * Copyright (C) 2005 Florian octo Forster
+ * Copyright (C) 2005-2007 Florian octo Forster
*
- * This program is free software; you can redistribute it and/
- * or modify it under the terms of the GNU General Public Li-
- * cence as published by the Free Software Foundation; either
- * version 2 of the Licence, or any later version.
+ * 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; only version 2 of the License is applicable.
*
- * This program is distributed in the hope that it will be use-
- * ful, but WITHOUT ANY WARRANTY; without even the implied war-
- * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public Licence for more details.
+ * 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
- * Licence along with this program; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
- * USA.
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors:
* Florian octo Forster <octo at verplant.org>
#include "common.h"
#include "utils_debug.h"
+#ifdef HAVE_MATH_H
+# include <math.h>
+#endif
+
+/* for ntohl and htonl */
+#if HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
#ifdef HAVE_LIBKSTAT
extern kstat_ctl_t *kc;
#endif
-#ifdef HAVE_LIBRRD
-static char *rra_def[] =
-{
- "RRA:AVERAGE:0.2:6:1500",
- "RRA:AVERAGE:0.1:180:1680",
- "RRA:AVERAGE:0.1:2160:1520",
- "RRA:MIN:0.2:6:1500",
- "RRA:MIN:0.1:180:1680",
- "RRA:MIN:0.1:2160:1520",
- "RRA:MAX:0.2:6:1500",
- "RRA:MAX:0.1:180:1680",
- "RRA:MAX:0.1:2160:1520",
- NULL
-};
-static int rra_num = 9;
-#endif /* HAVE_LIBRRD */
-
-void
-sstrncpy(char *d, const char *s, int len)
+void sstrncpy (char *d, const char *s, int len)
{
- strncpy(d, s, len);
- d[len - 1] = 0;
+ strncpy (d, s, len);
+ d[len - 1] = '\0';
}
-char *
-sstrdup(const char *s)
+char *sstrdup (const char *s)
{
- char *r = strdup(s);
- if(r == NULL) {
- DBG("Not enough memory.");
+ char *r;
+
+ if (s == NULL)
+ return (NULL);
+
+ if((r = strdup (s)) == NULL)
+ {
+ DBG ("Not enough memory.");
exit(3);
}
- return r;
+
+ return (r);
}
-void *
-smalloc(size_t size)
+void *smalloc (size_t size)
{
- void *r = malloc(size);
- if(r == NULL) {
+ void *r;
+
+ if ((r = malloc (size)) == NULL)
+ {
DBG("Not enough memory.");
exit(3);
}
+
return r;
}
+#if 0
+void sfree (void **ptr)
+{
+ if (ptr == NULL)
+ return;
+
+ if (*ptr != NULL)
+ free (*ptr);
+
+ *ptr = NULL;
+}
+#endif
+
+ssize_t sread (int fd, void *buf, size_t count)
+{
+ char *ptr;
+ size_t nleft;
+ ssize_t status;
+
+ ptr = (char *) buf;
+ nleft = count;
+
+ while (nleft > 0)
+ {
+ status = read (fd, (void *) ptr, nleft);
+
+ if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+ continue;
+
+ if (status < 0)
+ return (status);
+
+ if (status == 0)
+ {
+ DBG ("Received EOF from fd %i. "
+ "Closing fd and returning error.",
+ fd);
+ close (fd);
+ return (-1);
+ }
+
+ assert (nleft >= status);
+
+ nleft = nleft - status;
+ ptr = ptr + status;
+ }
+
+ return (0);
+}
+
+
+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);
+}
+
int strsplit (char *string, char **fields, size_t size)
{
size_t i;
char *ptr;
+ char *saveptr;
i = 0;
ptr = string;
- while ((fields[i] = strtok (ptr, " \t")) != NULL)
+ saveptr = NULL;
+ while ((fields[i] = strtok_r (ptr, " \t", &saveptr)) != NULL)
{
ptr = NULL;
i++;
return (i);
}
-#ifdef HAVE_LIBRRD
-int check_create_dir (char *dir)
+int strjoin (char *dst, size_t dst_len,
+ char **fields, size_t fields_num,
+ const char *sep)
{
- struct stat statbuf;
+ int field_len;
+ int sep_len;
+ int i;
+
+ memset (dst, '\0', dst_len);
+
+ if (fields_num <= 0)
+ return (-1);
- if (stat (dir, &statbuf) == -1)
+ sep_len = 0;
+ if (sep != NULL)
+ sep_len = strlen (sep);
+
+ for (i = 0; i < fields_num; i++)
{
- if (errno == ENOENT)
+ if ((i > 0) && (sep_len > 0))
{
- if (mkdir (dir, 0755) == -1)
- {
- syslog (LOG_ERR, "mkdir (%s): %s", dir, strerror (errno));
+ if (dst_len <= sep_len)
return (-1);
- }
+
+ strncat (dst, sep, dst_len);
+ dst_len -= sep_len;
}
- else
- {
- syslog (LOG_ERR, "stat (%s): %s", dir, strerror (errno));
+
+ field_len = strlen (fields[i]);
+
+ if (dst_len <= field_len)
return (-1);
- }
+
+ strncat (dst, fields[i], dst_len);
+ dst_len -= field_len;
}
- else if (!S_ISDIR (statbuf.st_mode))
- {
- syslog (LOG_ERR, "stat %s: Not a directory!", dir);
+
+ return (strlen (dst));
+}
+
+int strsubstitute (char *str, char c_from, char c_to)
+{
+ int ret;
+
+ if (str == NULL)
return (-1);
+
+ ret = 0;
+ while (*str != '\0')
+ {
+ if (*str == c_from)
+ {
+ *str = c_to;
+ ret++;
+ }
+ str++;
}
- return (0);
+ return (ret);
}
-int rrd_create_file (char *filename, char **ds_def, int ds_num)
+int escape_slashes (char *buf, int buf_len)
{
- char **argv;
- int argc;
- int i, j;
- int status = 0;
+ int i;
- argc = ds_num + rra_num + 4;
+ if (strcmp (buf, "/") == 0)
+ {
+ if (buf_len < 5)
+ return (-1);
+
+ strncpy (buf, "root", buf_len);
+ return (0);
+ }
+
+ /* Move one to the left */
+ memmove (buf, buf + 1, buf_len - 1);
- if ((argv = (char **) malloc (sizeof (char *) * (argc + 1))) == NULL)
+ for (i = 0; i < buf_len - 1; i++)
{
- syslog (LOG_ERR, "rrd_create failed: %s", strerror (errno));
- return (-1);
+ if (buf[i] == '\0')
+ break;
+ else if (buf[i] == '/')
+ buf[i] = '_';
}
+ buf[i] = '\0';
- argv[0] = "create";
- argv[1] = filename;
- argv[2] = "-s";
- argv[3] = "10";
-
- j = 4;
- for (i = 0; i < ds_num; i++)
- argv[j++] = ds_def[i];
- for (i = 0; i < rra_num; i++)
- argv[j++] = rra_def[i];
- argv[j] = NULL;
-
- optind = 0; /* bug in librrd? */
- rrd_clear_error ();
- if (rrd_create (argc, argv) == -1)
+ return (0);
+}
+
+int timeval_sub_timespec (struct timeval *tv0, struct timeval *tv1, struct timespec *ret)
+{
+ if ((tv0 == NULL) || (tv1 == NULL) || (ret == NULL))
+ return (-2);
+
+ if ((tv0->tv_sec < tv1->tv_sec)
+ || ((tv0->tv_sec == tv1->tv_sec) && (tv0->tv_usec < tv1->tv_usec)))
+ return (-1);
+
+ ret->tv_sec = tv0->tv_sec - tv1->tv_sec;
+ ret->tv_nsec = 1000 * ((long) (tv0->tv_usec - tv1->tv_usec));
+
+ if (ret->tv_nsec < 0)
{
- syslog (LOG_ERR, "rrd_create failed: %s: %s", filename, rrd_get_error ());
- status = -1;
+ assert (ret->tv_sec > 0);
+
+ ret->tv_nsec += 1000000000;
+ ret->tv_sec -= 1;
}
- free (argv);
-
- return (status);
+ return (0);
}
-#endif /* HAVE_LIBRRD */
-int rrd_update_file (char *host, char *file, char *values,
- char **ds_def, int ds_num)
+int check_create_dir (const char *file_orig)
{
-#ifdef HAVE_LIBRRD
struct stat statbuf;
- char full_file[1024];
- char *argv[4] = { "update", full_file, values, NULL };
- /* host == NULL => local mode */
- if (host != NULL)
+ char file_copy[512];
+ char dir[512];
+ int dir_len = 512;
+ char *fields[16];
+ int fields_num;
+ char *ptr;
+ char *saveptr;
+ int last_is_file = 1;
+ int path_is_absolute = 0;
+ int len;
+ int i;
+
+ /*
+ * Sanity checks first
+ */
+ if (file_orig == NULL)
+ return (-1);
+
+ if ((len = strlen (file_orig)) < 1)
+ return (-1);
+ else if (len >= 512)
+ return (-1);
+
+ /*
+ * If `file_orig' ends in a slash the last component is a directory,
+ * otherwise it's a file. Act accordingly..
+ */
+ if (file_orig[len - 1] == '/')
+ last_is_file = 0;
+ if (file_orig[0] == '/')
+ path_is_absolute = 1;
+
+ /*
+ * Create a copy for `strtok_r' to destroy
+ */
+ strncpy (file_copy, file_orig, 512);
+ file_copy[511] = '\0';
+
+ /*
+ * Break into components. This will eat up several slashes in a row and
+ * remove leading and trailing slashes..
+ */
+ ptr = file_copy;
+ saveptr = NULL;
+ fields_num = 0;
+ while ((fields[fields_num] = strtok_r (ptr, "/", &saveptr)) != NULL)
{
- if (check_create_dir (host))
- return (-1);
+ ptr = NULL;
+ fields_num++;
- if (snprintf (full_file, 1024, "%s/%s", host, file) >= 1024)
- return (-1);
+ if (fields_num >= 16)
+ break;
}
- else
+
+ /*
+ * For each component, do..
+ */
+ for (i = 0; i < (fields_num - last_is_file); i++)
{
- if (snprintf (full_file, 1024, "%s", file) >= 1024)
+ /*
+ * Do not create directories that start with a dot. This
+ * prevents `../../' attacks and other likely malicious
+ * behavior.
+ */
+ if (fields[i][0] == '.')
+ {
+ syslog (LOG_ERR, "Cowardly refusing to create a directory that begins with a `.' (dot): `%s'", file_orig);
+ return (-2);
+ }
+
+ /*
+ * Join the components together again
+ */
+ dir[0] = '/';
+ if (strjoin (dir + path_is_absolute, dir_len - path_is_absolute,
+ fields, i + 1, "/") < 0)
+ {
+ syslog (LOG_ERR, "strjoin failed: `%s', component #%i", file_orig, i);
return (-1);
- }
+ }
- if (stat (full_file, &statbuf) == -1)
- {
- if (errno == ENOENT)
+ if (stat (dir, &statbuf) == -1)
{
- if (rrd_create_file (full_file, ds_def, ds_num))
+ if (errno == ENOENT)
+ {
+ if (mkdir (dir, 0755) == -1)
+ {
+ syslog (LOG_ERR, "mkdir (%s): %s", dir, strerror (errno));
+ return (-1);
+ }
+ }
+ else
+ {
+ syslog (LOG_ERR, "stat (%s): %s", dir, strerror (errno));
return (-1);
+ }
}
- else
+ else if (!S_ISDIR (statbuf.st_mode))
{
- syslog (LOG_ERR, "stat %s: %s", full_file, strerror (errno));
+ syslog (LOG_ERR, "stat (%s): Not a directory!", dir);
return (-1);
}
}
- else if (!S_ISREG (statbuf.st_mode))
- {
- syslog (LOG_ERR, "stat %s: Not a regular file!", full_file);
- return (-1);
- }
-
- optind = 0; /* bug in librrd? */
- rrd_clear_error ();
- if (rrd_update (3, argv) == -1)
- {
- syslog (LOG_WARNING, "rrd_update failed: %s: %s", full_file, rrd_get_error ());
- return (-1);
- }
-#endif /* HAVE_LIBRRD */
return (0);
}
return (retval);
}
#endif /* HAVE_LIBKSTAT */
+
+unsigned long long ntohll (unsigned long long n)
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ return (n);
+#else
+ return (((unsigned long long) ntohl (n)) << 32) + ntohl (n >> 32);
+#endif
+}
+
+unsigned long long htonll (unsigned long long n)
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ return (n);
+#else
+ return (((unsigned long long) htonl (n)) << 32) + htonl (n >> 32);
+#endif
+}