unixsock plugin: Moved the `parse_identifier' code to `common.c'
[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 **/
22
23 #if HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include "common.h"
28 #include "plugin.h"
29
30 #ifdef HAVE_MATH_H
31 #  include <math.h>
32 #endif
33
34 /* for ntohl and htonl */
35 #if HAVE_ARPA_INET_H
36 # include <arpa/inet.h>
37 #endif
38
39 #ifdef HAVE_LIBKSTAT
40 extern kstat_ctl_t *kc;
41 #endif
42
43 void sstrncpy (char *d, const char *s, int len)
44 {
45         strncpy (d, s, len);
46         d[len - 1] = '\0';
47 }
48
49 char *sstrdup (const char *s)
50 {
51         char *r;
52
53         if (s == NULL)
54                 return (NULL);
55
56         if((r = strdup (s)) == NULL)
57         {
58                 DEBUG ("Not enough memory.");
59                 exit(3);
60         }
61
62         return (r);
63 }
64
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 */
73
74 void *smalloc (size_t size)
75 {
76         void *r;
77
78         if ((r = malloc (size)) == NULL)
79         {
80                 DEBUG("Not enough memory.");
81                 exit(3);
82         }
83
84         return r;
85 }
86
87 #if 0
88 void sfree (void **ptr)
89 {
90         if (ptr == NULL)
91                 return;
92
93         if (*ptr != NULL)
94                 free (*ptr);
95
96         *ptr = NULL;
97 }
98 #endif
99
100 ssize_t sread (int fd, void *buf, size_t count)
101 {
102         char    *ptr;
103         size_t   nleft;
104         ssize_t  status;
105
106         ptr   = (char *) buf;
107         nleft = count;
108
109         while (nleft > 0)
110         {
111                 status = read (fd, (void *) ptr, nleft);
112
113                 if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR)))
114                         continue;
115
116                 if (status < 0)
117                         return (status);
118
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                 }
127
128                 assert (nleft >= status);
129
130                 nleft = nleft - status;
131                 ptr   = ptr   + status;
132         }
133
134         return (0);
135 }
136
137
138 ssize_t swrite (int fd, const void *buf, size_t count)
139 {
140         const char *ptr;
141         size_t      nleft;
142         ssize_t     status;
143
144         ptr   = (const char *) buf;
145         nleft = count;
146
147         while (nleft > 0)
148         {
149                 status = write (fd, (const void *) ptr, nleft);
150
151                 if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR)))
152                         continue;
153
154                 if (status < 0)
155                         return (status);
156
157                 nleft = nleft - status;
158                 ptr   = ptr   + status;
159         }
160
161         return (0);
162 }
163
164 int strsplit (char *string, char **fields, size_t size)
165 {
166         size_t i;
167         char *ptr;
168         char *saveptr;
169
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++;
177
178                 if (i >= size)
179                         break;
180         }
181
182         return (i);
183 }
184
185 int strjoin (char *dst, size_t dst_len,
186                 char **fields, size_t fields_num,
187                 const char *sep)
188 {
189         int field_len;
190         int sep_len;
191         int i;
192
193         memset (dst, '\0', dst_len);
194
195         if (fields_num <= 0)
196                 return (-1);
197
198         sep_len = 0;
199         if (sep != NULL)
200                 sep_len = strlen (sep);
201
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);
208
209                         strncat (dst, sep, dst_len);
210                         dst_len -= sep_len;
211                 }
212
213                 field_len = strlen (fields[i]);
214
215                 if (dst_len <= field_len)
216                         return (-1);
217
218                 strncat (dst, fields[i], dst_len);
219                 dst_len -= field_len;
220         }
221
222         return (strlen (dst));
223 }
224
225 int strsubstitute (char *str, char c_from, char c_to)
226 {
227         int ret;
228
229         if (str == NULL)
230                 return (-1);
231
232         ret = 0;
233         while (*str != '\0')
234         {
235                 if (*str == c_from)
236                 {
237                         *str = c_to;
238                         ret++;
239                 }
240                 str++;
241         }
242
243         return (ret);
244 } /* int strsubstitute */
245
246 int escape_slashes (char *buf, int buf_len)
247 {
248         int i;
249
250         if (strcmp (buf, "/") == 0)
251         {
252                 if (buf_len < 5)
253                         return (-1);
254
255                 strncpy (buf, "root", buf_len);
256                 return (0);
257         }
258
259         if (buf_len <= 1)
260                 return (0);
261
262         /* Move one to the left */
263         if (buf[0] == '/')
264                 memmove (buf, buf + 1, buf_len - 1);
265
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';
274
275         return (0);
276 } /* int escape_slashes */
277
278 int timeval_sub_timespec (struct timeval *tv0, struct timeval *tv1, struct timespec *ret)
279 {
280         if ((tv0 == NULL) || (tv1 == NULL) || (ret == NULL))
281                 return (-2);
282
283         if ((tv0->tv_sec < tv1->tv_sec)
284                         || ((tv0->tv_sec == tv1->tv_sec) && (tv0->tv_usec < tv1->tv_usec)))
285                 return (-1);
286
287         ret->tv_sec  = tv0->tv_sec - tv1->tv_sec;
288         ret->tv_nsec = 1000 * ((long) (tv0->tv_usec - tv1->tv_usec));
289
290         if (ret->tv_nsec < 0)
291         {
292                 assert (ret->tv_sec > 0);
293
294                 ret->tv_nsec += 1000000000;
295                 ret->tv_sec  -= 1;
296         }
297
298         return (0);
299 }
300
301 int check_create_dir (const char *file_orig)
302 {
303         struct stat statbuf;
304
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;
316
317         /*
318          * Sanity checks first
319          */
320         if (file_orig == NULL)
321                 return (-1);
322
323         if ((len = strlen (file_orig)) < 1)
324                 return (-1);
325         else if (len >= 512)
326                 return (-1);
327
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;
336
337         /*
338          * Create a copy for `strtok_r' to destroy
339          */
340         strncpy (file_copy, file_orig, 512);
341         file_copy[511] = '\0';
342
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++;
354
355                 if (fields_num >= 16)
356                         break;
357         }
358
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                 }
374
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                 }
385
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         }
414
415         return (0);
416 }
417
418 #ifdef HAVE_LIBKSTAT
419 int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name)
420 {
421         char ident[128];
422         
423         if (kc == NULL)
424                 return (-1);
425
426         snprintf (ident, 128, "%s,%i,%s", module, instance, name);
427         ident[127] = '\0';
428
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                 }
436
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         }
444
445 #ifdef assert
446         assert (*ksp_ptr != NULL);
447         assert ((*ksp_ptr)->ks_type == KSTAT_TYPE_NAMED);
448 #endif
449
450         if (kstat_read (kc, *ksp_ptr, NULL) == -1)
451         {
452                 WARNING ("kstat %s could not be read", ident);
453                 return (-1);
454         }
455
456         if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED)
457         {
458                 WARNING ("kstat %s has wrong type", ident);
459                 return (-1);
460         }
461
462         return (0);
463 }
464
465 long long get_kstat_value (kstat_t *ksp, char *name)
466 {
467         kstat_named_t *kn;
468         long long retval = -1LL;
469
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
485
486         if ((kn = (kstat_named_t *) kstat_data_lookup (ksp, name)) == NULL)
487                 return (retval);
488
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);
501 }
502 #endif /* HAVE_LIBKSTAT */
503
504 unsigned long long ntohll (unsigned long long n)
505 {
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 */
512
513 unsigned long long htonll (unsigned long long n)
514 {
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 */
521
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)
526 {
527         int  status;
528
529         assert (plugin != NULL);
530         assert (type != NULL);
531
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         }
553
554         if ((status < 1) || (status >= ret_len))
555                 return (-1);
556         return (0);
557 } /* int format_name */
558
559 int parse_identifier (char *str, char **ret_host,
560                 char **ret_plugin, char **ret_plugin_instance,
561                 char **ret_type, char **ret_type_instance)
562 {
563         char *hostname = NULL;
564         char *plugin = NULL;
565         char *plugin_instance = NULL;
566         char *type = NULL;
567         char *type_instance = NULL;
568
569         hostname = str;
570         if (hostname == NULL)
571                 return (-1);
572
573         plugin = strchr (hostname, '/');
574         if (plugin == NULL)
575                 return (-1);
576         *plugin = '\0'; plugin++;
577
578         type = strchr (plugin, '/');
579         if (type == NULL)
580                 return (-1);
581         *type = '\0'; type++;
582
583         plugin_instance = strchr (plugin, '-');
584         if (plugin_instance != NULL)
585         {
586                 *plugin_instance = '\0';
587                 plugin_instance++;
588         }
589
590         type_instance = strchr (type, '-');
591         if (type_instance != NULL)
592         {
593                 *type_instance = '\0';
594                 type_instance++;
595         }
596
597         *ret_host = hostname;
598         *ret_plugin = plugin;
599         *ret_plugin_instance = plugin_instance;
600         *ret_type = type;
601         *ret_type_instance = type_instance;
602         return (0);
603 } /* int parse_identifier */
604
605 int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds)
606 {
607         int i;
608         char *dummy;
609         char *ptr;
610         char *saveptr;
611
612         i = -1;
613         dummy = buffer;
614         saveptr = NULL;
615         while ((ptr = strtok_r (dummy, ":", &saveptr)) != NULL)
616         {
617                 dummy = NULL;
618
619                 if (i >= vl->values_len)
620                         break;
621
622                 if (i == -1)
623                 {
624                         if (strcmp ("N", ptr) == 0)
625                                 vl->time = time (NULL);
626                         else
627                                 vl->time = (time_t) atoi (ptr);
628                 }
629                 else
630                 {
631                         if (strcmp ("U", ptr) == 0)
632                                 vl->values[i].gauge = NAN;
633                         else if (ds->ds[i].type == DS_TYPE_COUNTER)
634                                 vl->values[i].counter = atoll (ptr);
635                         else if (ds->ds[i].type == DS_TYPE_GAUGE)
636                                 vl->values[i].gauge = atof (ptr);
637                 }
638
639                 i++;
640         } /* while (strtok_r) */
641
642         if ((ptr != NULL) || (i != vl->values_len))
643                 return (-1);
644         return (0);
645 } /* int parse_values */