return (i);
}
+int strjoin (char *dst, size_t dst_len,
+ char **fields, size_t fields_num,
+ const char *sep)
+{
+ int field_len;
+ int sep_len;
+ int i;
+
+ memset (dst, '\0', dst_len);
+
+ if (fields_num <= 0)
+ return (-1);
+
+ sep_len = 0;
+ if (sep != NULL)
+ sep_len = strlen (sep);
+
+ for (i = 0; i < fields_num; i++)
+ {
+ if ((i > 0) && (sep_len > 0))
+ {
+ if (dst_len <= sep_len)
+ return (-1);
+
+ strncat (dst, sep, dst_len);
+ dst_len -= sep_len;
+ }
+
+ field_len = strlen (fields[i]);
+
+ if (dst_len <= field_len)
+ return (-1);
+
+ strncat (dst, fields[i], dst_len);
+ dst_len -= field_len;
+ }
+
+ return (strlen (dst));
+}
+
+int escape_slashes (char *buf, int buf_len)
+{
+ int i;
+
+ 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);
+
+ for (i = 0; i < buf_len - 1; i++)
+ {
+ if (buf[i] == '\0')
+ break;
+ else if (buf[i] == '/')
+ buf[i] = '_';
+ }
+ buf[i] = '\0';
+
+ return (0);
+}
+
#ifdef HAVE_LIBRRD
-int check_create_dir (char *dir)
+int check_create_dir (const char *file_orig)
{
struct stat statbuf;
- if (stat (dir, &statbuf) == -1)
+ char file_copy[512];
+ char dir[512];
+ int dir_len = 512;
+ char *fields[16];
+ int fields_num;
+ char *ptr;
+ int last_is_file = 1;
+ 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;
+
+ /*
+ * Create a copy for `strtok' 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;
+ fields_num = 0;
+ while ((fields[fields_num] = strtok (ptr, "/")) != NULL)
{
- if (errno == ENOENT)
+ ptr = NULL;
+ fields_num++;
+
+ if (fields_num >= 16)
+ break;
+ }
+
+ /*
+ * For each component, do..
+ */
+ for (i = 0; i < (fields_num - last_is_file); i++)
+ {
+ /*
+ * Join the components together again
+ */
+ if (strjoin (dir, dir_len, fields, i + 1, "/") < 0)
+ return (-1);
+
+ /*
+ * 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'", dir);
+ return (-2);
+ }
+
+ if (stat (dir, &statbuf) == -1)
{
- if (mkdir (dir, 0755) == -1)
+ if (errno == ENOENT)
+ {
+ if (mkdir (dir, 0755) == -1)
+ {
+ syslog (LOG_ERR, "mkdir (%s): %s", dir, strerror (errno));
+ return (-1);
+ }
+ }
+ else
{
- syslog (LOG_ERR, "mkdir (%s): %s", dir, strerror (errno));
+ 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", dir, strerror (errno));
+ syslog (LOG_ERR, "stat (%s): Not a directory!", dir);
return (-1);
}
}
- else if (!S_ISDIR (statbuf.st_mode))
- {
- syslog (LOG_ERR, "stat %s: Not a directory!", dir);
- return (-1);
- }
return (0);
}
char *sstrdup(const char *s);
void *smalloc(size_t size);
+/*
+ * NAME
+ * strsplit
+ *
+ * DESCRIPTION
+ * Splits a string into parts and stores pointers to the parts in `fields'.
+ * The characters split at are ` ' (space) and "\t" (tab).
+ *
+ * PARAMETERS
+ * `string' String to split. This string will be modified. `fields' will
+ * contain pointers to parts of this string, so free'ing it
+ * will destroy `fields' as well.
+ * `fields' Array of strings where pointers to the parts will be stored.
+ * `size' Number of elements in the array. No more than `size'
+ * pointers will be stored in `fields'.
+ *
+ * RETURN VALUE
+ * Returns the number of parts stored in `fields'.
+ */
int strsplit (char *string, char **fields, size_t size);
+/*
+ * NAME
+ * strjoin
+ *
+ * DESCRIPTION
+ * Joins together several parts of a string using `sep' as a seperator. This
+ * is equipollent to the perl buildin `join'.
+ *
+ * PARAMETERS
+ * `dst' Buffer where the result is stored.
+ * `dst_len' Length of the destination buffer. No more than this many
+ * bytes will be written to the memory pointed to by `dst',
+ * including the trailing null-byte.
+ * `fields' Array of strings to be joined.
+ * `fields_num' Number of elements in the `fields' array.
+ * `sep' String to be inserted between any two elements of `fields'.
+ * This string is neither prepended nor appended to the result.
+ * Instead of passing "" (empty string) one can pass NULL.
+ *
+ * RETURN VALUE
+ * Returns the number of characters in `dst', NOT including the trailing
+ * null-byte. If an error occured (empty array or `dst' too small) a value
+ * smaller than zero will be returned.
+ */
+int strjoin (char *dst, size_t dst_len, char **fields, size_t fields_num, const char *sep);
+
+/*
+ * NAME
+ * escape_slashes
+ *
+ * DESCRIPTION
+ * Removes slashes from the string `buf' and substitutes them with something
+ * appropriate. This function should be used whenever a path is to be used as
+ * (part of) an instance.
+ *
+ * PARAMETERS
+ * `buf' String to be escaped.
+ * `buf_len' Length of the buffer. No more then this many bytes will be
+ * written to `buf', including the trailing null-byte.
+ *
+ * RETURN VALUE
+ * Returns zero upon success and a value smaller than zero upon failure.
+ */
+int escape_slashes (char *buf, int buf_len);
+
int rrd_update_file (char *host, char *file, char *values, char **ds_def,
int ds_num);