Code

Changed mysql plugin to create one RRD file for each command
[collectd.git] / src / common.c
1 /**
2  * collectd - src/common.c
3  * Copyright (C) 2005  Florian octo Forster
4  *
5  * This program is free software; you can redistribute it and/
6  * or modify it under the terms of the GNU General Public Li-
7  * cence as published by the Free Software Foundation; either
8  * version 2 of the Licence, or any later version.
9  *
10  * This program is distributed in the hope that it will be use-
11  * ful, but WITHOUT ANY WARRANTY; without even the implied war-
12  * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13  * See the GNU General Public Licence for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * Licence along with this program; if not, write to the Free
17  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
18  * USA.
19  *
20  * Authors:
21  *   Florian octo Forster <octo at verplant.org>
22  *   Niki W. Waibel <niki.waibel@gmx.net>
23 **/
25 #include "common.h"
26 #include "utils_debug.h"
28 #ifdef HAVE_LIBKSTAT
29 extern kstat_ctl_t *kc;
30 #endif
32 #ifdef HAVE_LIBRRD
33 static char *rra_def[] =
34 {
35                 "RRA:AVERAGE:0.2:6:1500",
36                 "RRA:AVERAGE:0.1:180:1680",
37                 "RRA:AVERAGE:0.1:2160:1520",
38                 "RRA:MIN:0.2:6:1500",
39                 "RRA:MIN:0.1:180:1680",
40                 "RRA:MIN:0.1:2160:1520",
41                 "RRA:MAX:0.2:6:1500",
42                 "RRA:MAX:0.1:180:1680",
43                 "RRA:MAX:0.1:2160:1520",
44                 NULL
45 };
46 static int rra_num = 9;
47 #endif /* HAVE_LIBRRD */
49 void
50 sstrncpy(char *d, const char *s, int len)
51 {
52         strncpy(d, s, len);
53         d[len - 1] = 0;
54 }
56 char *
57 sstrdup(const char *s)
58 {
59         char *r = strdup(s);
60         if(r == NULL) {
61                 DBG("Not enough memory.");
62                 exit(3);
63         }
64         return r;
65 }
67 void *
68 smalloc(size_t size)
69 {
70         void *r = malloc(size);
71         if(r == NULL) {
72                 DBG("Not enough memory.");
73                 exit(3);
74         }
75         return r;
76 }
78 int strsplit (char *string, char **fields, size_t size)
79 {
80         size_t i;
81         char *ptr;
83         i = 0;
84         ptr = string;
85         while ((fields[i] = strtok (ptr, " \t")) != NULL)
86         {
87                 ptr = NULL;
88                 i++;
90                 if (i >= size)
91                         break;
92         }
94         return (i);
95 }
97 int strjoin (char *dst, size_t dst_len,
98                 char **fields, size_t fields_num,
99                 const char *sep)
101         int field_len;
102         int sep_len;
103         int i;
105         memset (dst, '\0', dst_len);
107         if (fields_num <= 0)
108                 return (-1);
110         sep_len = 0;
111         if (sep != NULL)
112                 sep_len = strlen (sep);
114         for (i = 0; i < fields_num; i++)
115         {
116                 if ((i > 0) && (sep_len > 0))
117                 {
118                         if (dst_len <= sep_len)
119                                 return (-1);
121                         strncat (dst, sep, dst_len);
122                         dst_len -= sep_len;
123                 }
125                 field_len = strlen (fields[i]);
127                 if (dst_len <= field_len)
128                         return (-1);
130                 strncat (dst, fields[i], dst_len);
131                 dst_len -= field_len;
132         }
134         return (strlen (dst));
137 int escape_slashes (char *buf, int buf_len)
139         int i;
141         if (strcmp (buf, "/") == 0)
142         {
143                 if (buf_len < 5)
144                         return (-1);
146                 strncpy (buf, "root", buf_len);
147                 return (0);
148         }
150         /* Move one to the left */
151         memmove (buf, buf + 1, buf_len - 1);
153         for (i = 0; i < buf_len - 1; i++)
154         {
155                 if (buf[i] == '\0')
156                         break;
157                 else if (buf[i] == '/')
158                         buf[i] = '_';
159         }
160         buf[i] = '\0';
162         return (0);
165 #ifdef HAVE_LIBRRD
166 int check_create_dir (const char *file_orig)
168         struct stat statbuf;
170         char  file_copy[512];
171         char  dir[512];
172         int   dir_len = 512;
173         char *fields[16];
174         int   fields_num;
175         char *ptr;
176         int   last_is_file = 1;
177         int   len;
178         int   i;
180         /*
181          * Sanity checks first
182          */
183         if (file_orig == NULL)
184                 return (-1);
186         if ((len = strlen (file_orig)) < 1)
187                 return (-1);
188         else if (len >= 512)
189                 return (-1);
191         /*
192          * If `file_orig' ends in a slash the last component is a directory,
193          * otherwise it's a file. Act accordingly..
194          */
195         if (file_orig[len - 1] == '/')
196                 last_is_file = 0;
198         /*
199          * Create a copy for `strtok' to destroy
200          */
201         strncpy (file_copy, file_orig, 512);
202         file_copy[511] = '\0';
204         /*
205          * Break into components. This will eat up several slashes in a row and
206          * remove leading and trailing slashes..
207          */
208         ptr = file_copy;
209         fields_num = 0;
210         while ((fields[fields_num] = strtok (ptr, "/")) != NULL)
211         {
212                 ptr = NULL;
213                 fields_num++;
215                 if (fields_num >= 16)
216                         break;
217         }
219         /*
220          * For each component, do..
221          */
222         for (i = 0; i < (fields_num - last_is_file); i++)
223         {
224                 /*
225                  * Join the components together again
226                  */
227                 if (strjoin (dir, dir_len, fields, i + 1, "/") < 0)
228                         return (-1);
230                 /*
231                  * Do not create directories that start with a dot. This
232                  * prevents `../../' attacks and other likely malicious
233                  * behavior.
234                  */
235                 if (fields[i][0] == '.')
236                 {
237                         syslog (LOG_ERR, "Cowardly refusing to create a directory that begins with a `.' (dot): `%s'", dir);
238                         return (-2);
239                 }
241                 if (stat (dir, &statbuf) == -1)
242                 {
243                         if (errno == ENOENT)
244                         {
245                                 if (mkdir (dir, 0755) == -1)
246                                 {
247                                         syslog (LOG_ERR, "mkdir (%s): %s", dir, strerror (errno));
248                                         return (-1);
249                                 }
250                         }
251                         else
252                         {
253                                 syslog (LOG_ERR, "stat (%s): %s", dir, strerror (errno));
254                                 return (-1);
255                         }
256                 }
257                 else if (!S_ISDIR (statbuf.st_mode))
258                 {
259                         syslog (LOG_ERR, "stat (%s): Not a directory!", dir);
260                         return (-1);
261                 }
262         }
264         return (0);
267 int rrd_create_file (char *filename, char **ds_def, int ds_num)
269         char **argv;
270         int argc;
271         int i, j;
272         int status = 0;
274         argc = ds_num + rra_num + 4;
276         if ((argv = (char **) malloc (sizeof (char *) * (argc + 1))) == NULL)
277         {
278                 syslog (LOG_ERR, "rrd_create failed: %s", strerror (errno));
279                 return (-1);
280         }
282         argv[0] = "create";
283         argv[1] = filename;
284         argv[2] = "-s";
285         argv[3] = "10";
287         j = 4;
288         for (i = 0; i < ds_num; i++)
289                 argv[j++] = ds_def[i];
290         for (i = 0; i < rra_num; i++)
291                 argv[j++] = rra_def[i];
292         argv[j] = NULL;
294         optind = 0; /* bug in librrd? */
295         rrd_clear_error ();
296         if (rrd_create (argc, argv) == -1)
297         {
298                 syslog (LOG_ERR, "rrd_create failed: %s: %s", filename, rrd_get_error ());
299                 status = -1;
300         }
302         free (argv);
303         
304         return (status);
306 #endif /* HAVE_LIBRRD */
308 int rrd_update_file (char *host, char *file, char *values,
309                 char **ds_def, int ds_num)
311 #ifdef HAVE_LIBRRD
312         struct stat statbuf;
313         char full_file[1024];
314         char *argv[4] = { "update", full_file, values, NULL };
316         /* host == NULL => local mode */
317         if (host != NULL)
318         {
319                 if (check_create_dir (host))
320                         return (-1);
322                 if (snprintf (full_file, 1024, "%s/%s", host, file) >= 1024)
323                         return (-1);
324         }
325         else
326         {
327                 if (snprintf (full_file, 1024, "%s", file) >= 1024)
328                         return (-1);
329         }
331         if (stat (full_file, &statbuf) == -1)
332         {
333                 if (errno == ENOENT)
334                 {
335                         if (rrd_create_file (full_file, ds_def, ds_num))
336                                 return (-1);
337                 }
338                 else
339                 {
340                         syslog (LOG_ERR, "stat %s: %s", full_file, strerror (errno));
341                         return (-1);
342                 }
343         }
344         else if (!S_ISREG (statbuf.st_mode))
345         {
346                 syslog (LOG_ERR, "stat %s: Not a regular file!", full_file);
347                 return (-1);
348         }
350         optind = 0; /* bug in librrd? */
351         rrd_clear_error ();
352         if (rrd_update (3, argv) == -1)
353         {
354                 syslog (LOG_WARNING, "rrd_update failed: %s: %s", full_file, rrd_get_error ());
355                 return (-1);
356         }
357 #endif /* HAVE_LIBRRD */
359         return (0);
362 #ifdef HAVE_LIBKSTAT
363 int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name)
365         char ident[128];
366         
367         if (kc == NULL)
368                 return (-1);
370         snprintf (ident, 128, "%s,%i,%s", module, instance, name);
371         ident[127] = '\0';
373         if (*ksp_ptr == NULL)
374         {
375                 if ((*ksp_ptr = kstat_lookup (kc, module, instance, name)) == NULL)
376                 {
377                         syslog (LOG_ERR, "Cound not find kstat %s", ident);
378                         return (-1);
379                 }
381                 if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED)
382                 {
383                         syslog (LOG_WARNING, "kstat %s has wrong type", ident);
384                         *ksp_ptr = NULL;
385                         return (-1);
386                 }
387         }
389 #ifdef assert
390         assert (*ksp_ptr != NULL);
391         assert ((*ksp_ptr)->ks_type == KSTAT_TYPE_NAMED);
392 #endif
394         if (kstat_read (kc, *ksp_ptr, NULL) == -1)
395         {
396                 syslog (LOG_WARNING, "kstat %s could not be read", ident);
397                 return (-1);
398         }
400         if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED)
401         {
402                 syslog (LOG_WARNING, "kstat %s has wrong type", ident);
403                 return (-1);
404         }
406         return (0);
409 long long get_kstat_value (kstat_t *ksp, char *name)
411         kstat_named_t *kn;
412         long long retval = -1LL;
414 #ifdef assert
415         assert (ksp != NULL);
416         assert (ksp->ks_type == KSTAT_TYPE_NAMED);
417 #else
418         if (ksp == NULL)
419         {
420                 fprintf (stderr, "ERROR: %s:%i: ksp == NULL\n", __FILE__, __LINE__);
421                 return (-1LL);
422         }
423         else if (ksp->ks_type != KSTAT_TYPE_NAMED)
424         {
425                 fprintf (stderr, "ERROR: %s:%i: ksp->ks_type != KSTAT_TYPE_NAMED\n", __FILE__, __LINE__);
426                 return (-1LL);
427         }
428 #endif
430         if ((kn = (kstat_named_t *) kstat_data_lookup (ksp, name)) == NULL)
431                 return (retval);
433         if (kn->data_type == KSTAT_DATA_INT32)
434                 retval = (long long) kn->value.i32;
435         else if (kn->data_type == KSTAT_DATA_UINT32)
436                 retval = (long long) kn->value.ui32;
437         else if (kn->data_type == KSTAT_DATA_INT64)
438                 retval = (long long) kn->value.i64; /* According to ANSI C99 `long long' must hold at least 64 bits */
439         else if (kn->data_type == KSTAT_DATA_UINT64)
440                 retval = (long long) kn->value.ui64; /* XXX: Might overflow! */
441         else
442                 syslog (LOG_WARNING, "get_kstat_value: Not a numeric value: %s", name);
443                  
444         return (retval);
446 #endif /* HAVE_LIBKSTAT */