Code

src/plugin.c: Remove slashed from host, {plugin,type}{,-instance} here.
[collectd.git] / src / common.c
1 /**
2  * collectd - src/common.c
3  * Copyright (C) 2005-2007  Florian octo Forster
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; only version 2 of the License is applicable.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  * Authors:
19  *   Florian octo Forster <octo at verplant.org>
20  *   Niki W. Waibel <niki.waibel@gmx.net>
21 **/
23 #if HAVE_CONFIG_H
24 # include "config.h"
25 #endif
27 #include "common.h"
28 #include "plugin.h"
30 #ifdef HAVE_MATH_H
31 #  include <math.h>
32 #endif
34 /* for ntohl and htonl */
35 #if HAVE_ARPA_INET_H
36 # include <arpa/inet.h>
37 #endif
39 #ifdef HAVE_LIBKSTAT
40 extern kstat_ctl_t *kc;
41 #endif
43 void sstrncpy (char *d, const char *s, int len)
44 {
45         strncpy (d, s, len);
46         d[len - 1] = '\0';
47 }
49 char *sstrdup (const char *s)
50 {
51         char *r;
53         if (s == NULL)
54                 return (NULL);
56         if((r = strdup (s)) == NULL)
57         {
58                 DEBUG ("Not enough memory.");
59                 exit(3);
60         }
62         return (r);
63 }
65 /* Don't use the return value of `strerror_r', because the GNU-people got
66  * inventive there.. -octo */
67 char *sstrerror (int errnum, char *buf, size_t buflen)
68 {
69         buf[0] = '\0';
70         strerror_r (errnum, buf, buflen);
71         return (buf);
72 } /* char *sstrerror */
74 void *smalloc (size_t size)
75 {
76         void *r;
78         if ((r = malloc (size)) == NULL)
79         {
80                 DEBUG("Not enough memory.");
81                 exit(3);
82         }
84         return r;
85 }
87 #if 0
88 void sfree (void **ptr)
89 {
90         if (ptr == NULL)
91                 return;
93         if (*ptr != NULL)
94                 free (*ptr);
96         *ptr = NULL;
97 }
98 #endif
100 ssize_t sread (int fd, void *buf, size_t count)
102         char    *ptr;
103         size_t   nleft;
104         ssize_t  status;
106         ptr   = (char *) buf;
107         nleft = count;
109         while (nleft > 0)
110         {
111                 status = read (fd, (void *) ptr, nleft);
113                 if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR)))
114                         continue;
116                 if (status < 0)
117                         return (status);
119                 if (status == 0)
120                 {
121                         DEBUG ("Received EOF from fd %i. "
122                                         "Closing fd and returning error.",
123                                         fd);
124                         close (fd);
125                         return (-1);
126                 }
128                 assert (nleft >= status);
130                 nleft = nleft - status;
131                 ptr   = ptr   + status;
132         }
134         return (0);
138 ssize_t swrite (int fd, const void *buf, size_t count)
140         const char *ptr;
141         size_t      nleft;
142         ssize_t     status;
144         ptr   = (const char *) buf;
145         nleft = count;
147         while (nleft > 0)
148         {
149                 status = write (fd, (const void *) ptr, nleft);
151                 if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR)))
152                         continue;
154                 if (status < 0)
155                         return (status);
157                 nleft = nleft - status;
158                 ptr   = ptr   + status;
159         }
161         return (0);
164 int strsplit (char *string, char **fields, size_t size)
166         size_t i;
167         char *ptr;
168         char *saveptr;
170         i = 0;
171         ptr = string;
172         saveptr = NULL;
173         while ((fields[i] = strtok_r (ptr, " \t", &saveptr)) != NULL)
174         {
175                 ptr = NULL;
176                 i++;
178                 if (i >= size)
179                         break;
180         }
182         return (i);
185 int strjoin (char *dst, size_t dst_len,
186                 char **fields, size_t fields_num,
187                 const char *sep)
189         int field_len;
190         int sep_len;
191         int i;
193         memset (dst, '\0', dst_len);
195         if (fields_num <= 0)
196                 return (-1);
198         sep_len = 0;
199         if (sep != NULL)
200                 sep_len = strlen (sep);
202         for (i = 0; i < fields_num; i++)
203         {
204                 if ((i > 0) && (sep_len > 0))
205                 {
206                         if (dst_len <= sep_len)
207                                 return (-1);
209                         strncat (dst, sep, dst_len);
210                         dst_len -= sep_len;
211                 }
213                 field_len = strlen (fields[i]);
215                 if (dst_len <= field_len)
216                         return (-1);
218                 strncat (dst, fields[i], dst_len);
219                 dst_len -= field_len;
220         }
222         return (strlen (dst));
225 int strsubstitute (char *str, char c_from, char c_to)
227         int ret;
229         if (str == NULL)
230                 return (-1);
232         ret = 0;
233         while (*str != '\0')
234         {
235                 if (*str == c_from)
236                 {
237                         *str = c_to;
238                         ret++;
239                 }
240                 str++;
241         }
243         return (ret);
244 } /* int strsubstitute */
246 int escape_slashes (char *buf, int buf_len)
248         int i;
250         if (strcmp (buf, "/") == 0)
251         {
252                 if (buf_len < 5)
253                         return (-1);
255                 strncpy (buf, "root", buf_len);
256                 return (0);
257         }
259         if (buf_len <= 1)
260                 return (0);
262         /* Move one to the left */
263         if (buf[0] == '/')
264                 memmove (buf, buf + 1, buf_len - 1);
266         for (i = 0; i < buf_len - 1; i++)
267         {
268                 if (buf[i] == '\0')
269                         break;
270                 else if (buf[i] == '/')
271                         buf[i] = '_';
272         }
273         buf[i] = '\0';
275         return (0);
276 } /* int escape_slashes */
278 int timeval_sub_timespec (struct timeval *tv0, struct timeval *tv1, struct timespec *ret)
280         if ((tv0 == NULL) || (tv1 == NULL) || (ret == NULL))
281                 return (-2);
283         if ((tv0->tv_sec < tv1->tv_sec)
284                         || ((tv0->tv_sec == tv1->tv_sec) && (tv0->tv_usec < tv1->tv_usec)))
285                 return (-1);
287         ret->tv_sec  = tv0->tv_sec - tv1->tv_sec;
288         ret->tv_nsec = 1000 * ((long) (tv0->tv_usec - tv1->tv_usec));
290         if (ret->tv_nsec < 0)
291         {
292                 assert (ret->tv_sec > 0);
294                 ret->tv_nsec += 1000000000;
295                 ret->tv_sec  -= 1;
296         }
298         return (0);
301 int check_create_dir (const char *file_orig)
303         struct stat statbuf;
305         char  file_copy[512];
306         char  dir[512];
307         int   dir_len = 512;
308         char *fields[16];
309         int   fields_num;
310         char *ptr;
311         char *saveptr;
312         int   last_is_file = 1;
313         int   path_is_absolute = 0;
314         int   len;
315         int   i;
317         /*
318          * Sanity checks first
319          */
320         if (file_orig == NULL)
321                 return (-1);
323         if ((len = strlen (file_orig)) < 1)
324                 return (-1);
325         else if (len >= 512)
326                 return (-1);
328         /*
329          * If `file_orig' ends in a slash the last component is a directory,
330          * otherwise it's a file. Act accordingly..
331          */
332         if (file_orig[len - 1] == '/')
333                 last_is_file = 0;
334         if (file_orig[0] == '/')
335                 path_is_absolute = 1;
337         /*
338          * Create a copy for `strtok_r' to destroy
339          */
340         strncpy (file_copy, file_orig, 512);
341         file_copy[511] = '\0';
343         /*
344          * Break into components. This will eat up several slashes in a row and
345          * remove leading and trailing slashes..
346          */
347         ptr = file_copy;
348         saveptr = NULL;
349         fields_num = 0;
350         while ((fields[fields_num] = strtok_r (ptr, "/", &saveptr)) != NULL)
351         {
352                 ptr = NULL;
353                 fields_num++;
355                 if (fields_num >= 16)
356                         break;
357         }
359         /*
360          * For each component, do..
361          */
362         for (i = 0; i < (fields_num - last_is_file); i++)
363         {
364                 /*
365                  * Do not create directories that start with a dot. This
366                  * prevents `../../' attacks and other likely malicious
367                  * behavior.
368                  */
369                 if (fields[i][0] == '.')
370                 {
371                         ERROR ("Cowardly refusing to create a directory that begins with a `.' (dot): `%s'", file_orig);
372                         return (-2);
373                 }
375                 /*
376                  * Join the components together again
377                  */
378                 dir[0] = '/';
379                 if (strjoin (dir + path_is_absolute, dir_len - path_is_absolute,
380                                         fields, i + 1, "/") < 0)
381                 {
382                         ERROR ("strjoin failed: `%s', component #%i", file_orig, i);
383                         return (-1);
384                 }
386                 if (stat (dir, &statbuf) == -1)
387                 {
388                         if (errno == ENOENT)
389                         {
390                                 if (mkdir (dir, 0755) == -1)
391                                 {
392                                         char errbuf[1024];
393                                         ERROR ("mkdir (%s): %s", dir,
394                                                         sstrerror (errno,
395                                                                 errbuf, sizeof (errbuf)));
396                                         return (-1);
397                                 }
398                         }
399                         else
400                         {
401                                 char errbuf[1024];
402                                 ERROR ("stat (%s): %s", dir,
403                                                 sstrerror (errno, errbuf,
404                                                         sizeof (errbuf)));
405                                 return (-1);
406                         }
407                 }
408                 else if (!S_ISDIR (statbuf.st_mode))
409                 {
410                         ERROR ("stat (%s): Not a directory!", dir);
411                         return (-1);
412                 }
413         }
415         return (0);
418 #ifdef HAVE_LIBKSTAT
419 int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name)
421         char ident[128];
422         
423         if (kc == NULL)
424                 return (-1);
426         snprintf (ident, 128, "%s,%i,%s", module, instance, name);
427         ident[127] = '\0';
429         if (*ksp_ptr == NULL)
430         {
431                 if ((*ksp_ptr = kstat_lookup (kc, module, instance, name)) == NULL)
432                 {
433                         ERROR ("Cound not find kstat %s", ident);
434                         return (-1);
435                 }
437                 if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED)
438                 {
439                         WARNING ("kstat %s has wrong type", ident);
440                         *ksp_ptr = NULL;
441                         return (-1);
442                 }
443         }
445 #ifdef assert
446         assert (*ksp_ptr != NULL);
447         assert ((*ksp_ptr)->ks_type == KSTAT_TYPE_NAMED);
448 #endif
450         if (kstat_read (kc, *ksp_ptr, NULL) == -1)
451         {
452                 WARNING ("kstat %s could not be read", ident);
453                 return (-1);
454         }
456         if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED)
457         {
458                 WARNING ("kstat %s has wrong type", ident);
459                 return (-1);
460         }
462         return (0);
465 long long get_kstat_value (kstat_t *ksp, char *name)
467         kstat_named_t *kn;
468         long long retval = -1LL;
470 #ifdef assert
471         assert (ksp != NULL);
472         assert (ksp->ks_type == KSTAT_TYPE_NAMED);
473 #else
474         if (ksp == NULL)
475         {
476                 fprintf (stderr, "ERROR: %s:%i: ksp == NULL\n", __FILE__, __LINE__);
477                 return (-1LL);
478         }
479         else if (ksp->ks_type != KSTAT_TYPE_NAMED)
480         {
481                 fprintf (stderr, "ERROR: %s:%i: ksp->ks_type != KSTAT_TYPE_NAMED\n", __FILE__, __LINE__);
482                 return (-1LL);
483         }
484 #endif
486         if ((kn = (kstat_named_t *) kstat_data_lookup (ksp, name)) == NULL)
487                 return (retval);
489         if (kn->data_type == KSTAT_DATA_INT32)
490                 retval = (long long) kn->value.i32;
491         else if (kn->data_type == KSTAT_DATA_UINT32)
492                 retval = (long long) kn->value.ui32;
493         else if (kn->data_type == KSTAT_DATA_INT64)
494                 retval = (long long) kn->value.i64; /* According to ANSI C99 `long long' must hold at least 64 bits */
495         else if (kn->data_type == KSTAT_DATA_UINT64)
496                 retval = (long long) kn->value.ui64; /* XXX: Might overflow! */
497         else
498                 WARNING ("get_kstat_value: Not a numeric value: %s", name);
499                  
500         return (retval);
502 #endif /* HAVE_LIBKSTAT */
504 unsigned long long ntohll (unsigned long long n)
506 #if __BYTE_ORDER == __BIG_ENDIAN
507         return (n);
508 #else
509         return (((unsigned long long) ntohl (n)) << 32) + ntohl (n >> 32);
510 #endif
511 } /* unsigned long long ntohll */
513 unsigned long long htonll (unsigned long long n)
515 #if __BYTE_ORDER == __BIG_ENDIAN
516         return (n);
517 #else
518         return (((unsigned long long) htonl (n)) << 32) + htonl (n >> 32);
519 #endif
520 } /* unsigned long long htonll */
522 int format_name (char *ret, int ret_len,
523                 const char *hostname,
524                 const char *plugin, const char *plugin_instance,
525                 const char *type, const char *type_instance)
527         int  status;
529         assert (plugin != NULL);
530         assert (type != NULL);
532         if ((plugin_instance == NULL) || (strlen (plugin_instance) == 0))
533         {
534                 if ((type_instance == NULL) || (strlen (type_instance) == 0))
535                         status = snprintf (ret, ret_len, "%s/%s/%s",
536                                         hostname, plugin, type);
537                 else
538                         status = snprintf (ret, ret_len, "%s/%s/%s-%s",
539                                         hostname, plugin, type,
540                                         type_instance);
541         }
542         else
543         {
544                 if ((type_instance == NULL) || (strlen (type_instance) == 0))
545                         status = snprintf (ret, ret_len, "%s/%s-%s/%s",
546                                         hostname, plugin, plugin_instance,
547                                         type);
548                 else
549                         status = snprintf (ret, ret_len, "%s/%s-%s/%s-%s",
550                                         hostname, plugin, plugin_instance,
551                                         type, type_instance);
552         }
554         if ((status < 1) || (status >= ret_len))
555                 return (-1);
556         return (0);
557 } /* int format_name */