Merge remote-tracking branch 'github/pr/1749'
[collectd.git] / src / daemon / common.c
1 /**
2  * collectd - src/common.c
3  * Copyright (C) 2005-2014  Florian octo Forster
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  *   Florian octo Forster <octo at collectd.org>
25  *   Niki W. Waibel <niki.waibel@gmx.net>
26  *   Sebastian Harl <sh at tokkee.org>
27  *   Michał Mirosław <mirq-linux at rere.qmqm.pl>
28 **/
29
30 #if HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include "collectd.h"
35
36 #include "common.h"
37 #include "plugin.h"
38 #include "utils_cache.h"
39
40 #ifdef HAVE_MATH_H
41 # include <math.h>
42 #endif
43
44 /* for getaddrinfo */
45 #include <sys/types.h>
46 #include <netdb.h>
47
48 #include <poll.h>
49
50 #if HAVE_NETINET_IN_H
51 # include <netinet/in.h>
52 #endif
53
54 #if HAVE_NETINET_TCP_H
55 # include <netinet/tcp.h>
56 #endif
57
58 /* for ntohl and htonl */
59 #if HAVE_ARPA_INET_H
60 # include <arpa/inet.h>
61 #endif
62
63 #ifdef HAVE_SYS_CAPABILITY_H
64 # include <sys/capability.h>
65 #endif
66
67 #ifdef HAVE_LIBKSTAT
68 extern kstat_ctl_t *kc;
69 #endif
70
71 /* AIX doesn't have MSG_DONTWAIT */
72 #ifndef MSG_DONTWAIT
73 #  define MSG_DONTWAIT MSG_NONBLOCK
74 #endif
75
76 #if !HAVE_GETPWNAM_R
77 static pthread_mutex_t getpwnam_r_lock = PTHREAD_MUTEX_INITIALIZER;
78 #endif
79
80 #if !HAVE_STRERROR_R
81 static pthread_mutex_t strerror_r_lock = PTHREAD_MUTEX_INITIALIZER;
82 #endif
83
84 char *sstrncpy (char *dest, const char *src, size_t n)
85 {
86         strncpy (dest, src, n);
87         dest[n - 1] = '\0';
88
89         return (dest);
90 } /* char *sstrncpy */
91
92 int ssnprintf (char *dest, size_t n, const char *format, ...)
93 {
94         int ret = 0;
95         va_list ap;
96
97         va_start (ap, format);
98         ret = vsnprintf (dest, n, format, ap);
99         dest[n - 1] = '\0';
100         va_end (ap);
101
102         return (ret);
103 } /* int ssnprintf */
104
105 char *ssnprintf_alloc (char const *format, ...) /* {{{ */
106 {
107         char static_buffer[1024] = "";
108         char *alloc_buffer;
109         size_t alloc_buffer_size;
110         int status;
111         va_list ap;
112
113         /* Try printing into the static buffer. In many cases it will be
114          * sufficiently large and we can simply return a strdup() of this
115          * buffer. */
116         va_start (ap, format);
117         status = vsnprintf (static_buffer, sizeof (static_buffer), format, ap);
118         va_end (ap);
119         if (status < 0)
120                 return (NULL);
121
122         /* "status" does not include the null byte. */
123         alloc_buffer_size = (size_t) (status + 1);
124         if (alloc_buffer_size <= sizeof (static_buffer))
125                 return (strdup (static_buffer));
126
127         /* Allocate a buffer large enough to hold the string. */
128         alloc_buffer = calloc (1, alloc_buffer_size);
129         if (alloc_buffer == NULL)
130                 return (NULL);
131
132         /* Print again into this new buffer. */
133         va_start (ap, format);
134         status = vsnprintf (alloc_buffer, alloc_buffer_size, format, ap);
135         va_end (ap);
136         if (status < 0)
137         {
138                 sfree (alloc_buffer);
139                 return (NULL);
140         }
141
142         return (alloc_buffer);
143 } /* }}} char *ssnprintf_alloc */
144
145 char *sstrdup (const char *s)
146 {
147         char *r;
148         size_t sz;
149
150         if (s == NULL)
151                 return (NULL);
152
153         /* Do not use `strdup' here, because it's not specified in POSIX. It's
154          * ``only'' an XSI extension. */
155         sz = strlen (s) + 1;
156         r = malloc (sz);
157         if (r == NULL)
158         {
159                 ERROR ("sstrdup: Out of memory.");
160                 exit (3);
161         }
162         memcpy (r, s, sizeof (char) * sz);
163
164         return (r);
165 } /* char *sstrdup */
166
167 /* Even though Posix requires "strerror_r" to return an "int",
168  * some systems (e.g. the GNU libc) return a "char *" _and_
169  * ignore the second argument ... -tokkee */
170 char *sstrerror (int errnum, char *buf, size_t buflen)
171 {
172         buf[0] = '\0';
173
174 #if !HAVE_STRERROR_R
175         {
176                 char *temp;
177
178                 pthread_mutex_lock (&strerror_r_lock);
179
180                 temp = strerror (errnum);
181                 sstrncpy (buf, temp, buflen);
182
183                 pthread_mutex_unlock (&strerror_r_lock);
184         }
185 /* #endif !HAVE_STRERROR_R */
186
187 #elif STRERROR_R_CHAR_P
188         {
189                 char *temp;
190                 temp = strerror_r (errnum, buf, buflen);
191                 if (buf[0] == '\0')
192                 {
193                         if ((temp != NULL) && (temp != buf) && (temp[0] != '\0'))
194                                 sstrncpy (buf, temp, buflen);
195                         else
196                                 sstrncpy (buf, "strerror_r did not return "
197                                                 "an error message", buflen);
198                 }
199         }
200 /* #endif STRERROR_R_CHAR_P */
201
202 #else
203         if (strerror_r (errnum, buf, buflen) != 0)
204         {
205                 ssnprintf (buf, buflen, "Error #%i; "
206                                 "Additionally, strerror_r failed.",
207                                 errnum);
208         }
209 #endif /* STRERROR_R_CHAR_P */
210
211         return (buf);
212 } /* char *sstrerror */
213
214 void *smalloc (size_t size)
215 {
216         void *r;
217
218         if ((r = malloc (size)) == NULL)
219         {
220                 ERROR ("Not enough memory.");
221                 exit (3);
222         }
223
224         return (r);
225 } /* void *smalloc */
226
227 #if 0
228 void sfree (void **ptr)
229 {
230         if (ptr == NULL)
231                 return;
232
233         if (*ptr != NULL)
234                 free (*ptr);
235
236         *ptr = NULL;
237 }
238 #endif
239
240 ssize_t sread (int fd, void *buf, size_t count)
241 {
242         char    *ptr;
243         size_t   nleft;
244         ssize_t  status;
245
246         ptr   = (char *) buf;
247         nleft = count;
248
249         while (nleft > 0)
250         {
251                 status = read (fd, (void *) ptr, nleft);
252
253                 if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR)))
254                         continue;
255
256                 if (status < 0)
257                         return (status);
258
259                 if (status == 0)
260                 {
261                         DEBUG ("Received EOF from fd %i. "
262                                         "Closing fd and returning error.",
263                                         fd);
264                         close (fd);
265                         return (-1);
266                 }
267
268                 assert ((0 > status) || (nleft >= (size_t)status));
269
270                 nleft = nleft - ((size_t) status);
271                 ptr   = ptr   + ((size_t) status);
272         }
273
274         return (0);
275 }
276
277
278 ssize_t swrite (int fd, const void *buf, size_t count)
279 {
280         const char *ptr;
281         size_t      nleft;
282         ssize_t     status;
283         struct      pollfd pfd;
284
285         ptr   = (const char *) buf;
286         nleft = count;
287         
288         if (fd < 0)
289                 return (-1);
290
291         /* checking for closed peer connection */
292         pfd.fd = fd;
293         pfd.events = POLLIN | POLLHUP;
294         pfd.revents = 0;
295         if (poll(&pfd, 1, 0) > 0) {
296                 char buffer[32];
297                 if (recv(fd, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0) {
298                         // if recv returns zero (even though poll() said there is data to be read),
299                         // that means the connection has been closed
300                         return -1;
301                 }
302         }
303
304         while (nleft > 0)
305         {
306                 status = write (fd, (const void *) ptr, nleft);
307
308                 if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR)))
309                         continue;
310
311                 if (status < 0)
312                         return (status);
313
314                 nleft = nleft - ((size_t) status);
315                 ptr   = ptr   + ((size_t) status);
316         }
317
318         return (0);
319 }
320
321 int strsplit (char *string, char **fields, size_t size)
322 {
323         size_t i;
324         char *ptr;
325         char *saveptr;
326
327         i = 0;
328         ptr = string;
329         saveptr = NULL;
330         while ((fields[i] = strtok_r (ptr, " \t\r\n", &saveptr)) != NULL)
331         {
332                 ptr = NULL;
333                 i++;
334
335                 if (i >= size)
336                         break;
337         }
338
339         return ((int) i);
340 }
341
342 int strjoin(char *buffer, size_t buffer_size, char **fields, size_t fields_num,
343             const char *sep) {
344   size_t avail = 0;
345   char *ptr = buffer;
346   size_t sep_len = 0;
347
348   size_t buffer_req = 0;
349
350   if (((fields_num != 0) && (fields == NULL)) ||
351       ((buffer_size != 0) && (buffer == NULL)))
352     return (-EINVAL);
353
354   if (buffer != NULL)
355     buffer[0] = 0;
356
357   if (buffer_size != 0)
358     avail = buffer_size - 1;
359
360   if (sep != NULL)
361     sep_len = strlen(sep);
362
363   for (size_t i = 0; i < fields_num; i++) {
364     size_t field_len = strlen(fields[i]);
365
366     if (i != 0)
367       buffer_req += sep_len;
368     buffer_req += field_len;
369
370     if ((i != 0) && (sep_len > 0)) {
371       if (sep_len >= avail) {
372         /* prevent subsequent iterations from writing to the
373          * buffer. */
374         avail = 0;
375         continue;
376       }
377
378       memcpy(ptr, sep, sep_len);
379
380       ptr += sep_len;
381       avail -= sep_len;
382     }
383
384     if (field_len > avail)
385       field_len = avail;
386
387     memcpy(ptr, fields[i], field_len);
388     ptr += field_len;
389
390     avail -= field_len;
391     if (ptr != NULL)
392       *ptr = 0;
393   }
394
395   return (int)buffer_req;
396 }
397
398 int escape_string (char *buffer, size_t buffer_size)
399 {
400   char *temp;
401   size_t j;
402
403   /* Check if we need to escape at all first */
404   temp = strpbrk (buffer, " \t\"\\");
405   if (temp == NULL)
406     return (0);
407
408   if (buffer_size < 3)
409     return (EINVAL);
410
411   temp = calloc (1, buffer_size);
412   if (temp == NULL)
413     return (ENOMEM);
414
415   temp[0] = '"';
416   j = 1;
417
418   for (size_t i = 0; i < buffer_size; i++)
419   {
420     if (buffer[i] == 0)
421     {
422       break;
423     }
424     else if ((buffer[i] == '"') || (buffer[i] == '\\'))
425     {
426       if (j > (buffer_size - 4))
427         break;
428       temp[j] = '\\';
429       temp[j + 1] = buffer[i];
430       j += 2;
431     }
432     else
433     {
434       if (j > (buffer_size - 3))
435         break;
436       temp[j] = buffer[i];
437       j++;
438     }
439   }
440
441   assert ((j + 1) < buffer_size);
442   temp[j] = '"';
443   temp[j + 1] = 0;
444
445   sstrncpy (buffer, temp, buffer_size);
446   sfree (temp);
447   return (0);
448 } /* int escape_string */
449
450 int strunescape (char *buf, size_t buf_len)
451 {
452         for (size_t i = 0; (i < buf_len) && (buf[i] != '\0'); ++i)
453         {
454                 if (buf[i] != '\\')
455                         continue;
456
457                 if (((i + 1) >= buf_len) || (buf[i + 1] == 0)) {
458                         ERROR ("string unescape: backslash found at end of string.");
459                         /* Ensure null-byte at the end of the buffer. */
460                         buf[i] = 0;
461                         return (-1);
462                 }
463
464                 switch (buf[i + 1]) {
465                         case 't':
466                                 buf[i] = '\t';
467                                 break;
468                         case 'n':
469                                 buf[i] = '\n';
470                                 break;
471                         case 'r':
472                                 buf[i] = '\r';
473                                 break;
474                         default:
475                                 buf[i] = buf[i + 1];
476                                 break;
477                 }
478
479                 /* Move everything after the position one position to the left.
480                  * Add a null-byte as last character in the buffer. */
481                 memmove (buf + i + 1, buf + i + 2, buf_len - i - 2);
482                 buf[buf_len - 1] = 0;
483         }
484         return (0);
485 } /* int strunescape */
486
487 size_t strstripnewline (char *buffer)
488 {
489         size_t buffer_len = strlen (buffer);
490
491         while (buffer_len > 0)
492         {
493                 if ((buffer[buffer_len - 1] != '\n')
494                                 && (buffer[buffer_len - 1] != '\r'))
495                         break;
496                 buffer_len--;
497                 buffer[buffer_len] = 0;
498         }
499
500         return (buffer_len);
501 } /* size_t strstripnewline */
502
503 int escape_slashes (char *buffer, size_t buffer_size)
504 {
505         size_t buffer_len;
506
507         buffer_len = strlen (buffer);
508
509         if (buffer_len <= 1)
510         {
511                 if (strcmp ("/", buffer) == 0)
512                 {
513                         if (buffer_size < 5)
514                                 return (-1);
515                         sstrncpy (buffer, "root", buffer_size);
516                 }
517                 return (0);
518         }
519
520         /* Move one to the left */
521         if (buffer[0] == '/')
522         {
523                 memmove (buffer, buffer + 1, buffer_len);
524                 buffer_len--;
525         }
526
527         for (size_t i = 0; i < buffer_len; i++)
528         {
529                 if (buffer[i] == '/')
530                         buffer[i] = '_';
531         }
532
533         return (0);
534 } /* int escape_slashes */
535
536 void replace_special (char *buffer, size_t buffer_size)
537 {
538         for (size_t i = 0; i < buffer_size; i++)
539         {
540                 if (buffer[i] == 0)
541                         return;
542                 if ((!isalnum ((int) buffer[i])) && (buffer[i] != '-'))
543                         buffer[i] = '_';
544         }
545 } /* void replace_special */
546
547 int timeval_cmp (struct timeval tv0, struct timeval tv1, struct timeval *delta)
548 {
549         struct timeval *larger;
550         struct timeval *smaller;
551
552         int status;
553
554         NORMALIZE_TIMEVAL (tv0);
555         NORMALIZE_TIMEVAL (tv1);
556
557         if ((tv0.tv_sec == tv1.tv_sec) && (tv0.tv_usec == tv1.tv_usec))
558         {
559                 if (delta != NULL) {
560                         delta->tv_sec  = 0;
561                         delta->tv_usec = 0;
562                 }
563                 return (0);
564         }
565
566         if ((tv0.tv_sec < tv1.tv_sec)
567                         || ((tv0.tv_sec == tv1.tv_sec) && (tv0.tv_usec < tv1.tv_usec)))
568         {
569                 larger  = &tv1;
570                 smaller = &tv0;
571                 status  = -1;
572         }
573         else
574         {
575                 larger  = &tv0;
576                 smaller = &tv1;
577                 status  = 1;
578         }
579
580         if (delta != NULL) {
581                 delta->tv_sec = larger->tv_sec - smaller->tv_sec;
582
583                 if (smaller->tv_usec <= larger->tv_usec)
584                         delta->tv_usec = larger->tv_usec - smaller->tv_usec;
585                 else
586                 {
587                         --delta->tv_sec;
588                         delta->tv_usec = 1000000 + larger->tv_usec - smaller->tv_usec;
589                 }
590         }
591
592         assert ((delta == NULL)
593                         || ((0 <= delta->tv_usec) && (delta->tv_usec < 1000000)));
594
595         return (status);
596 } /* int timeval_cmp */
597
598 int check_create_dir (const char *file_orig)
599 {
600         struct stat statbuf;
601
602         char  file_copy[512];
603         char  dir[512];
604         int   dir_len = 512;
605         char *fields[16];
606         int   fields_num;
607         char *ptr;
608         char *saveptr;
609         int   last_is_file = 1;
610         int   path_is_absolute = 0;
611         size_t len;
612
613         /*
614          * Sanity checks first
615          */
616         if (file_orig == NULL)
617                 return (-1);
618
619         if ((len = strlen (file_orig)) < 1)
620                 return (-1);
621         else if (len >= sizeof (file_copy))
622                 return (-1);
623
624         /*
625          * If `file_orig' ends in a slash the last component is a directory,
626          * otherwise it's a file. Act accordingly..
627          */
628         if (file_orig[len - 1] == '/')
629                 last_is_file = 0;
630         if (file_orig[0] == '/')
631                 path_is_absolute = 1;
632
633         /*
634          * Create a copy for `strtok_r' to destroy
635          */
636         sstrncpy (file_copy, file_orig, sizeof (file_copy));
637
638         /*
639          * Break into components. This will eat up several slashes in a row and
640          * remove leading and trailing slashes..
641          */
642         ptr = file_copy;
643         saveptr = NULL;
644         fields_num = 0;
645         while ((fields[fields_num] = strtok_r (ptr, "/", &saveptr)) != NULL)
646         {
647                 ptr = NULL;
648                 fields_num++;
649
650                 if (fields_num >= 16)
651                         break;
652         }
653
654         /*
655          * For each component, do..
656          */
657         for (int i = 0; i < (fields_num - last_is_file); i++)
658         {
659                 /*
660                  * Do not create directories that start with a dot. This
661                  * prevents `../../' attacks and other likely malicious
662                  * behavior.
663                  */
664                 if (fields[i][0] == '.')
665                 {
666                         ERROR ("Cowardly refusing to create a directory that "
667                                         "begins with a `.' (dot): `%s'", file_orig);
668                         return (-2);
669                 }
670
671                 /*
672                  * Join the components together again
673                  */
674                 dir[0] = '/';
675                 if (strjoin (dir + path_is_absolute, (size_t) (dir_len - path_is_absolute),
676                                         fields, (size_t) (i + 1), "/") < 0)
677                 {
678                         ERROR ("strjoin failed: `%s', component #%i", file_orig, i);
679                         return (-1);
680                 }
681
682                 while (42) {
683                         if ((stat (dir, &statbuf) == -1)
684                                         && (lstat (dir, &statbuf) == -1))
685                         {
686                                 if (errno == ENOENT)
687                                 {
688                                         if (mkdir (dir, S_IRWXU | S_IRWXG | S_IRWXO) == 0)
689                                                 break;
690
691                                         /* this might happen, if a different thread created
692                                          * the directory in the meantime
693                                          * => call stat() again to check for S_ISDIR() */
694                                         if (EEXIST == errno)
695                                                 continue;
696
697                                         char errbuf[1024];
698                                         ERROR ("check_create_dir: mkdir (%s): %s", dir,
699                                                         sstrerror (errno,
700                                                                 errbuf, sizeof (errbuf)));
701                                         return (-1);
702                                 }
703                                 else
704                                 {
705                                         char errbuf[1024];
706                                         ERROR ("check_create_dir: stat (%s): %s", dir,
707                                                         sstrerror (errno, errbuf,
708                                                                 sizeof (errbuf)));
709                                         return (-1);
710                                 }
711                         }
712                         else if (!S_ISDIR (statbuf.st_mode))
713                         {
714                                 ERROR ("check_create_dir: `%s' exists but is not "
715                                                 "a directory!", dir);
716                                 return (-1);
717                         }
718                         break;
719                 }
720         }
721
722         return (0);
723 } /* check_create_dir */
724
725 #ifdef HAVE_LIBKSTAT
726 int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name)
727 {
728         char ident[128];
729
730         *ksp_ptr = NULL;
731
732         if (kc == NULL)
733                 return (-1);
734
735         ssnprintf (ident, sizeof (ident), "%s,%i,%s", module, instance, name);
736
737         *ksp_ptr = kstat_lookup (kc, module, instance, name);
738         if (*ksp_ptr == NULL)
739         {
740                 ERROR ("get_kstat: Cound not find kstat %s", ident);
741                 return (-1);
742         }
743
744         if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED)
745         {
746                 ERROR ("get_kstat: kstat %s has wrong type", ident);
747                 *ksp_ptr = NULL;
748                 return (-1);
749         }
750
751 #ifdef assert
752         assert (*ksp_ptr != NULL);
753         assert ((*ksp_ptr)->ks_type == KSTAT_TYPE_NAMED);
754 #endif
755
756         if (kstat_read (kc, *ksp_ptr, NULL) == -1)
757         {
758                 ERROR ("get_kstat: kstat %s could not be read", ident);
759                 return (-1);
760         }
761
762         if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED)
763         {
764                 ERROR ("get_kstat: kstat %s has wrong type", ident);
765                 return (-1);
766         }
767
768         return (0);
769 }
770
771 long long get_kstat_value (kstat_t *ksp, char *name)
772 {
773         kstat_named_t *kn;
774         long long retval = -1LL;
775
776         if (ksp == NULL)
777         {
778                 ERROR ("get_kstat_value (\"%s\"): ksp is NULL.", name);
779                 return (-1LL);
780         }
781         else if (ksp->ks_type != KSTAT_TYPE_NAMED)
782         {
783                 ERROR ("get_kstat_value (\"%s\"): ksp->ks_type (%#x) "
784                                 "is not KSTAT_TYPE_NAMED (%#x).",
785                                 name,
786                                 (unsigned int) ksp->ks_type,
787                                 (unsigned int) KSTAT_TYPE_NAMED);
788                 return (-1LL);
789         }
790
791         if ((kn = (kstat_named_t *) kstat_data_lookup (ksp, name)) == NULL)
792                 return (-1LL);
793
794         if (kn->data_type == KSTAT_DATA_INT32)
795                 retval = (long long) kn->value.i32;
796         else if (kn->data_type == KSTAT_DATA_UINT32)
797                 retval = (long long) kn->value.ui32;
798         else if (kn->data_type == KSTAT_DATA_INT64)
799                 retval = (long long) kn->value.i64; /* According to ANSI C99 `long long' must hold at least 64 bits */
800         else if (kn->data_type == KSTAT_DATA_UINT64)
801                 retval = (long long) kn->value.ui64; /* XXX: Might overflow! */
802         else
803                 WARNING ("get_kstat_value: Not a numeric value: %s", name);
804
805         return (retval);
806 }
807 #endif /* HAVE_LIBKSTAT */
808
809 #ifndef HAVE_HTONLL
810 unsigned long long ntohll (unsigned long long n)
811 {
812 #if BYTE_ORDER == BIG_ENDIAN
813         return (n);
814 #else
815         return (((unsigned long long) ntohl (n)) << 32) + ntohl (n >> 32);
816 #endif
817 } /* unsigned long long ntohll */
818
819 unsigned long long htonll (unsigned long long n)
820 {
821 #if BYTE_ORDER == BIG_ENDIAN
822         return (n);
823 #else
824         return (((unsigned long long) htonl (n)) << 32) + htonl (n >> 32);
825 #endif
826 } /* unsigned long long htonll */
827 #endif /* HAVE_HTONLL */
828
829 #if FP_LAYOUT_NEED_NOTHING
830 /* Well, we need nothing.. */
831 /* #endif FP_LAYOUT_NEED_NOTHING */
832
833 #elif FP_LAYOUT_NEED_ENDIANFLIP || FP_LAYOUT_NEED_INTSWAP
834 # if FP_LAYOUT_NEED_ENDIANFLIP
835 #  define FP_CONVERT(A) ((((uint64_t)(A) & 0xff00000000000000LL) >> 56) | \
836                          (((uint64_t)(A) & 0x00ff000000000000LL) >> 40) | \
837                          (((uint64_t)(A) & 0x0000ff0000000000LL) >> 24) | \
838                          (((uint64_t)(A) & 0x000000ff00000000LL) >> 8)  | \
839                          (((uint64_t)(A) & 0x00000000ff000000LL) << 8)  | \
840                          (((uint64_t)(A) & 0x0000000000ff0000LL) << 24) | \
841                          (((uint64_t)(A) & 0x000000000000ff00LL) << 40) | \
842                          (((uint64_t)(A) & 0x00000000000000ffLL) << 56))
843 # else
844 #  define FP_CONVERT(A) ((((uint64_t)(A) & 0xffffffff00000000LL) >> 32) | \
845                          (((uint64_t)(A) & 0x00000000ffffffffLL) << 32))
846 # endif
847
848 double ntohd (double d)
849 {
850         union
851         {
852                 uint8_t  byte[8];
853                 uint64_t integer;
854                 double   floating;
855         } ret;
856
857         ret.floating = d;
858
859         /* NAN in x86 byte order */
860         if ((ret.byte[0] == 0x00) && (ret.byte[1] == 0x00)
861                         && (ret.byte[2] == 0x00) && (ret.byte[3] == 0x00)
862                         && (ret.byte[4] == 0x00) && (ret.byte[5] == 0x00)
863                         && (ret.byte[6] == 0xf8) && (ret.byte[7] == 0x7f))
864         {
865                 return (NAN);
866         }
867         else
868         {
869                 uint64_t tmp;
870
871                 tmp = ret.integer;
872                 ret.integer = FP_CONVERT (tmp);
873                 return (ret.floating);
874         }
875 } /* double ntohd */
876
877 double htond (double d)
878 {
879         union
880         {
881                 uint8_t  byte[8];
882                 uint64_t integer;
883                 double   floating;
884         } ret;
885
886         if (isnan (d))
887         {
888                 ret.byte[0] = ret.byte[1] = ret.byte[2] = ret.byte[3] = 0x00;
889                 ret.byte[4] = ret.byte[5] = 0x00;
890                 ret.byte[6] = 0xf8;
891                 ret.byte[7] = 0x7f;
892                 return (ret.floating);
893         }
894         else
895         {
896                 uint64_t tmp;
897
898                 ret.floating = d;
899                 tmp = FP_CONVERT (ret.integer);
900                 ret.integer = tmp;
901                 return (ret.floating);
902         }
903 } /* double htond */
904 #endif /* FP_LAYOUT_NEED_ENDIANFLIP || FP_LAYOUT_NEED_INTSWAP */
905
906 int format_name (char *ret, int ret_len,
907                 const char *hostname,
908                 const char *plugin, const char *plugin_instance,
909                 const char *type, const char *type_instance)
910 {
911   char *buffer;
912   size_t buffer_size;
913
914   buffer = ret;
915   buffer_size = (size_t) ret_len;
916
917 #define APPEND(str) do {                                               \
918   size_t l = strlen (str);                                             \
919   if (l >= buffer_size)                                                \
920     return (ENOBUFS);                                                  \
921   memcpy (buffer, (str), l);                                           \
922   buffer += l; buffer_size -= l;                                       \
923 } while (0)
924
925   assert (plugin != NULL);
926   assert (type != NULL);
927
928   APPEND (hostname);
929   APPEND ("/");
930   APPEND (plugin);
931   if ((plugin_instance != NULL) && (plugin_instance[0] != 0))
932   {
933     APPEND ("-");
934     APPEND (plugin_instance);
935   }
936   APPEND ("/");
937   APPEND (type);
938   if ((type_instance != NULL) && (type_instance[0] != 0))
939   {
940     APPEND ("-");
941     APPEND (type_instance);
942   }
943   assert (buffer_size > 0);
944   buffer[0] = 0;
945
946 #undef APPEND
947   return (0);
948 } /* int format_name */
949
950 int format_values (char *ret, size_t ret_len, /* {{{ */
951                 const data_set_t *ds, const value_list_t *vl,
952                 _Bool store_rates)
953 {
954         size_t offset = 0;
955         int status;
956         gauge_t *rates = NULL;
957
958         assert (0 == strcmp (ds->type, vl->type));
959
960         memset (ret, 0, ret_len);
961
962 #define BUFFER_ADD(...) do { \
963         status = ssnprintf (ret + offset, ret_len - offset, \
964                         __VA_ARGS__); \
965         if (status < 1) \
966         { \
967                 sfree (rates); \
968                 return (-1); \
969         } \
970         else if (((size_t) status) >= (ret_len - offset)) \
971         { \
972                 sfree (rates); \
973                 return (-1); \
974         } \
975         else \
976                 offset += ((size_t) status); \
977 } while (0)
978
979         BUFFER_ADD ("%.3f", CDTIME_T_TO_DOUBLE (vl->time));
980
981         for (size_t i = 0; i < ds->ds_num; i++)
982         {
983                 if (ds->ds[i].type == DS_TYPE_GAUGE)
984                         BUFFER_ADD (":"GAUGE_FORMAT, vl->values[i].gauge);
985                 else if (store_rates)
986                 {
987                         if (rates == NULL)
988                                 rates = uc_get_rate (ds, vl);
989                         if (rates == NULL)
990                         {
991                                 WARNING ("format_values: uc_get_rate failed.");
992                                 return (-1);
993                         }
994                         BUFFER_ADD (":"GAUGE_FORMAT, rates[i]);
995                 }
996                 else if (ds->ds[i].type == DS_TYPE_COUNTER)
997                         BUFFER_ADD (":%llu", vl->values[i].counter);
998                 else if (ds->ds[i].type == DS_TYPE_DERIVE)
999                         BUFFER_ADD (":%"PRIi64, vl->values[i].derive);
1000                 else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
1001                         BUFFER_ADD (":%"PRIu64, vl->values[i].absolute);
1002                 else
1003                 {
1004                         ERROR ("format_values: Unknown data source type: %i",
1005                                         ds->ds[i].type);
1006                         sfree (rates);
1007                         return (-1);
1008                 }
1009         } /* for ds->ds_num */
1010
1011 #undef BUFFER_ADD
1012
1013         sfree (rates);
1014         return (0);
1015 } /* }}} int format_values */
1016
1017 int parse_identifier (char *str, char **ret_host,
1018                 char **ret_plugin, char **ret_plugin_instance,
1019                 char **ret_type, char **ret_type_instance,
1020                 char *default_host)
1021 {
1022         char *hostname = NULL;
1023         char *plugin = NULL;
1024         char *plugin_instance = NULL;
1025         char *type = NULL;
1026         char *type_instance = NULL;
1027
1028         hostname = str;
1029         if (hostname == NULL)
1030                 return (-1);
1031
1032         plugin = strchr (hostname, '/');
1033         if (plugin == NULL)
1034                 return (-1);
1035         *plugin = '\0'; plugin++;
1036
1037         type = strchr (plugin, '/');
1038         if (type == NULL)
1039         {
1040                 if (default_host == NULL)
1041                         return (-1);
1042                 /* else: no host specified; use default */
1043                 type = plugin;
1044                 plugin = hostname;
1045                 hostname = default_host;
1046         }
1047         else
1048         {
1049                 *type = '\0';
1050                 type++;
1051         }
1052
1053         plugin_instance = strchr (plugin, '-');
1054         if (plugin_instance != NULL)
1055         {
1056                 *plugin_instance = '\0';
1057                 plugin_instance++;
1058         }
1059
1060         type_instance = strchr (type, '-');
1061         if (type_instance != NULL)
1062         {
1063                 *type_instance = '\0';
1064                 type_instance++;
1065         }
1066
1067         *ret_host = hostname;
1068         *ret_plugin = plugin;
1069         *ret_plugin_instance = plugin_instance;
1070         *ret_type = type;
1071         *ret_type_instance = type_instance;
1072         return (0);
1073 } /* int parse_identifier */
1074
1075 int parse_identifier_vl (const char *str, value_list_t *vl) /* {{{ */
1076 {
1077         char str_copy[6 * DATA_MAX_NAME_LEN];
1078         char *host = NULL;
1079         char *plugin = NULL;
1080         char *plugin_instance = NULL;
1081         char *type = NULL;
1082         char *type_instance = NULL;
1083         int status;
1084
1085         if ((str == NULL) || (vl == NULL))
1086                 return (EINVAL);
1087
1088         sstrncpy (str_copy, str, sizeof (str_copy));
1089
1090         status = parse_identifier (str_copy, &host,
1091                         &plugin, &plugin_instance,
1092                         &type, &type_instance,
1093                         /* default_host = */ NULL);
1094         if (status != 0)
1095                 return (status);
1096
1097         sstrncpy (vl->host, host, sizeof (vl->host));
1098         sstrncpy (vl->plugin, plugin, sizeof (vl->plugin));
1099         sstrncpy (vl->plugin_instance,
1100                         (plugin_instance != NULL) ? plugin_instance : "",
1101                         sizeof (vl->plugin_instance));
1102         sstrncpy (vl->type, type, sizeof (vl->type));
1103         sstrncpy (vl->type_instance,
1104                         (type_instance != NULL) ? type_instance : "",
1105                         sizeof (vl->type_instance));
1106
1107         return (0);
1108 } /* }}} int parse_identifier_vl */
1109
1110 int parse_value (const char *value_orig, value_t *ret_value, int ds_type)
1111 {
1112   char *value;
1113   char *endptr = NULL;
1114   size_t value_len;
1115
1116   if (value_orig == NULL)
1117     return (EINVAL);
1118
1119   value = strdup (value_orig);
1120   if (value == NULL)
1121     return (ENOMEM);
1122   value_len = strlen (value);
1123
1124   while ((value_len > 0) && isspace ((int) value[value_len - 1]))
1125   {
1126     value[value_len - 1] = 0;
1127     value_len--;
1128   }
1129
1130   switch (ds_type)
1131   {
1132     case DS_TYPE_COUNTER:
1133       ret_value->counter = (counter_t) strtoull (value, &endptr, 0);
1134       break;
1135
1136     case DS_TYPE_GAUGE:
1137       ret_value->gauge = (gauge_t) strtod (value, &endptr);
1138       break;
1139
1140     case DS_TYPE_DERIVE:
1141       ret_value->derive = (derive_t) strtoll (value, &endptr, 0);
1142       break;
1143
1144     case DS_TYPE_ABSOLUTE:
1145       ret_value->absolute = (absolute_t) strtoull (value, &endptr, 0);
1146       break;
1147
1148     default:
1149       sfree (value);
1150       ERROR ("parse_value: Invalid data source type: %i.", ds_type);
1151       return -1;
1152   }
1153
1154   if (value == endptr) {
1155     ERROR ("parse_value: Failed to parse string as %s: \"%s\".",
1156         DS_TYPE_TO_STRING (ds_type), value);
1157     sfree (value);
1158     return -1;
1159   }
1160   else if ((NULL != endptr) && ('\0' != *endptr))
1161     INFO ("parse_value: Ignoring trailing garbage \"%s\" after %s value. "
1162         "Input string was \"%s\".",
1163         endptr, DS_TYPE_TO_STRING (ds_type), value_orig);
1164
1165   sfree (value);
1166   return 0;
1167 } /* int parse_value */
1168
1169 int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds)
1170 {
1171         size_t i;
1172         char *dummy;
1173         char *ptr;
1174         char *saveptr;
1175
1176         if ((buffer == NULL) || (vl == NULL) || (ds == NULL))
1177                 return EINVAL;
1178
1179         i = 0;
1180         dummy = buffer;
1181         saveptr = NULL;
1182         vl->time = 0;
1183         while ((ptr = strtok_r (dummy, ":", &saveptr)) != NULL)
1184         {
1185                 dummy = NULL;
1186
1187                 if (i >= vl->values_len)
1188                 {
1189                         /* Make sure i is invalid. */
1190                         i = 0;
1191                         break;
1192                 }
1193
1194                 if (vl->time == 0)
1195                 {
1196                         if (strcmp ("N", ptr) == 0)
1197                                 vl->time = cdtime ();
1198                         else
1199                         {
1200                                 char *endptr = NULL;
1201                                 double tmp;
1202
1203                                 errno = 0;
1204                                 tmp = strtod (ptr, &endptr);
1205                                 if ((errno != 0)                    /* Overflow */
1206                                                 || (endptr == ptr)  /* Invalid string */
1207                                                 || (endptr == NULL) /* This should not happen */
1208                                                 || (*endptr != 0))  /* Trailing chars */
1209                                         return (-1);
1210
1211                                 vl->time = DOUBLE_TO_CDTIME_T (tmp);
1212                         }
1213
1214                         continue;
1215                 }
1216
1217                 if ((strcmp ("U", ptr) == 0) && (ds->ds[i].type == DS_TYPE_GAUGE))
1218                         vl->values[i].gauge = NAN;
1219                 else if (0 != parse_value (ptr, &vl->values[i], ds->ds[i].type))
1220                         return -1;
1221
1222                 i++;
1223         } /* while (strtok_r) */
1224
1225         if ((ptr != NULL) || (i == 0))
1226                 return (-1);
1227         return (0);
1228 } /* int parse_values */
1229
1230 int parse_value_file (char const *path, value_t *ret_value, int ds_type)
1231 {
1232         FILE *fh;
1233         char buffer[256];
1234
1235         fh = fopen (path, "r");
1236         if (fh == NULL)
1237                 return (-1);
1238
1239         if (fgets (buffer, sizeof (buffer), fh) == NULL)
1240         {
1241                 fclose (fh);
1242                 return (-1);
1243         }
1244
1245         fclose (fh);
1246
1247         strstripnewline (buffer);
1248
1249         return parse_value (buffer, ret_value, ds_type);
1250 } /* int parse_value_file */
1251
1252 #if !HAVE_GETPWNAM_R
1253 int getpwnam_r (const char *name, struct passwd *pwbuf, char *buf,
1254                 size_t buflen, struct passwd **pwbufp)
1255 {
1256         int status = 0;
1257         struct passwd *pw;
1258
1259         memset (pwbuf, '\0', sizeof (struct passwd));
1260
1261         pthread_mutex_lock (&getpwnam_r_lock);
1262
1263         do
1264         {
1265                 pw = getpwnam (name);
1266                 if (pw == NULL)
1267                 {
1268                         status = (errno != 0) ? errno : ENOENT;
1269                         break;
1270                 }
1271
1272 #define GETPWNAM_COPY_MEMBER(member) \
1273                 if (pw->member != NULL) \
1274                 { \
1275                         int len = strlen (pw->member); \
1276                         if (len >= buflen) \
1277                         { \
1278                                 status = ENOMEM; \
1279                                 break; \
1280                         } \
1281                         sstrncpy (buf, pw->member, buflen); \
1282                         pwbuf->member = buf; \
1283                         buf    += (len + 1); \
1284                         buflen -= (len + 1); \
1285                 }
1286                 GETPWNAM_COPY_MEMBER(pw_name);
1287                 GETPWNAM_COPY_MEMBER(pw_passwd);
1288                 GETPWNAM_COPY_MEMBER(pw_gecos);
1289                 GETPWNAM_COPY_MEMBER(pw_dir);
1290                 GETPWNAM_COPY_MEMBER(pw_shell);
1291
1292                 pwbuf->pw_uid = pw->pw_uid;
1293                 pwbuf->pw_gid = pw->pw_gid;
1294
1295                 if (pwbufp != NULL)
1296                         *pwbufp = pwbuf;
1297         } while (0);
1298
1299         pthread_mutex_unlock (&getpwnam_r_lock);
1300
1301         return (status);
1302 } /* int getpwnam_r */
1303 #endif /* !HAVE_GETPWNAM_R */
1304
1305 int notification_init (notification_t *n, int severity, const char *message,
1306                 const char *host,
1307                 const char *plugin, const char *plugin_instance,
1308                 const char *type, const char *type_instance)
1309 {
1310         memset (n, '\0', sizeof (notification_t));
1311
1312         n->severity = severity;
1313
1314         if (message != NULL)
1315                 sstrncpy (n->message, message, sizeof (n->message));
1316         if (host != NULL)
1317                 sstrncpy (n->host, host, sizeof (n->host));
1318         if (plugin != NULL)
1319                 sstrncpy (n->plugin, plugin, sizeof (n->plugin));
1320         if (plugin_instance != NULL)
1321                 sstrncpy (n->plugin_instance, plugin_instance,
1322                                 sizeof (n->plugin_instance));
1323         if (type != NULL)
1324                 sstrncpy (n->type, type, sizeof (n->type));
1325         if (type_instance != NULL)
1326                 sstrncpy (n->type_instance, type_instance,
1327                                 sizeof (n->type_instance));
1328
1329         return (0);
1330 } /* int notification_init */
1331
1332 int walk_directory (const char *dir, dirwalk_callback_f callback,
1333                 void *user_data, int include_hidden)
1334 {
1335         struct dirent *ent;
1336         DIR *dh;
1337         int success;
1338         int failure;
1339
1340         success = 0;
1341         failure = 0;
1342
1343         if ((dh = opendir (dir)) == NULL)
1344         {
1345                 char errbuf[1024];
1346                 ERROR ("walk_directory: Cannot open '%s': %s", dir,
1347                                 sstrerror (errno, errbuf, sizeof (errbuf)));
1348                 return -1;
1349         }
1350
1351         while ((ent = readdir (dh)) != NULL)
1352         {
1353                 int status;
1354
1355                 if (include_hidden)
1356                 {
1357                         if ((strcmp (".", ent->d_name) == 0)
1358                                         || (strcmp ("..", ent->d_name) == 0))
1359                                 continue;
1360                 }
1361                 else /* if (!include_hidden) */
1362                 {
1363                         if (ent->d_name[0]=='.')
1364                                 continue;
1365                 }
1366
1367                 status = (*callback) (dir, ent->d_name, user_data);
1368                 if (status != 0)
1369                         failure++;
1370                 else
1371                         success++;
1372         }
1373
1374         closedir (dh);
1375
1376         if ((success == 0) && (failure > 0))
1377                 return (-1);
1378         return (0);
1379 }
1380
1381 ssize_t read_file_contents (const char *filename, char *buf, size_t bufsize)
1382 {
1383         FILE *fh;
1384         ssize_t ret;
1385
1386         fh = fopen (filename, "r");
1387         if (fh == NULL)
1388                 return (-1);
1389
1390         ret = (ssize_t) fread (buf, 1, bufsize, fh);
1391         if ((ret == 0) && (ferror (fh) != 0))
1392         {
1393                 ERROR ("read_file_contents: Reading file \"%s\" failed.",
1394                                 filename);
1395                 ret = -1;
1396         }
1397
1398         fclose(fh);
1399         return (ret);
1400 }
1401
1402 counter_t counter_diff (counter_t old_value, counter_t new_value)
1403 {
1404         counter_t diff;
1405
1406         if (old_value > new_value)
1407         {
1408                 if (old_value <= 4294967295U)
1409                         diff = (4294967295U - old_value) + new_value + 1;
1410                 else
1411                         diff = (18446744073709551615ULL - old_value) + new_value + 1;
1412         }
1413         else
1414         {
1415                 diff = new_value - old_value;
1416         }
1417
1418         return (diff);
1419 } /* counter_t counter_diff */
1420
1421 int rate_to_value (value_t *ret_value, gauge_t rate, /* {{{ */
1422                 rate_to_value_state_t *state,
1423                 int ds_type, cdtime_t t)
1424 {
1425         gauge_t delta_gauge;
1426         cdtime_t delta_t;
1427
1428         if (ds_type == DS_TYPE_GAUGE)
1429         {
1430                 state->last_value.gauge = rate;
1431                 state->last_time = t;
1432
1433                 *ret_value = state->last_value;
1434                 return (0);
1435         }
1436
1437         /* Counter and absolute can't handle negative rates. Reset "last time"
1438          * to zero, so that the next valid rate will re-initialize the
1439          * structure. */
1440         if ((rate < 0.0)
1441                         && ((ds_type == DS_TYPE_COUNTER)
1442                                 || (ds_type == DS_TYPE_ABSOLUTE)))
1443         {
1444                 memset (state, 0, sizeof (*state));
1445                 return (EINVAL);
1446         }
1447
1448         /* Another invalid state: The time is not increasing. */
1449         if (t <= state->last_time)
1450         {
1451                 memset (state, 0, sizeof (*state));
1452                 return (EINVAL);
1453         }
1454
1455         delta_t = t - state->last_time;
1456         delta_gauge = (rate * CDTIME_T_TO_DOUBLE (delta_t)) + state->residual;
1457
1458         /* Previous value is invalid. */
1459         if (state->last_time == 0) /* {{{ */
1460         {
1461                 if (ds_type == DS_TYPE_DERIVE)
1462                 {
1463                         state->last_value.derive = (derive_t) rate;
1464                         state->residual = rate - ((gauge_t) state->last_value.derive);
1465                 }
1466                 else if (ds_type == DS_TYPE_COUNTER)
1467                 {
1468                         state->last_value.counter = (counter_t) rate;
1469                         state->residual = rate - ((gauge_t) state->last_value.counter);
1470                 }
1471                 else if (ds_type == DS_TYPE_ABSOLUTE)
1472                 {
1473                         state->last_value.absolute = (absolute_t) rate;
1474                         state->residual = rate - ((gauge_t) state->last_value.absolute);
1475                 }
1476                 else
1477                 {
1478                         assert (23 == 42);
1479                 }
1480
1481                 state->last_time = t;
1482                 return (EAGAIN);
1483         } /* }}} */
1484
1485         if (ds_type == DS_TYPE_DERIVE)
1486         {
1487                 derive_t delta_derive = (derive_t) delta_gauge;
1488
1489                 state->last_value.derive += delta_derive;
1490                 state->residual = delta_gauge - ((gauge_t) delta_derive);
1491         }
1492         else if (ds_type == DS_TYPE_COUNTER)
1493         {
1494                 counter_t delta_counter = (counter_t) delta_gauge;
1495
1496                 state->last_value.counter += delta_counter;
1497                 state->residual = delta_gauge - ((gauge_t) delta_counter);
1498         }
1499         else if (ds_type == DS_TYPE_ABSOLUTE)
1500         {
1501                 absolute_t delta_absolute = (absolute_t) delta_gauge;
1502
1503                 state->last_value.absolute = delta_absolute;
1504                 state->residual = delta_gauge - ((gauge_t) delta_absolute);
1505         }
1506         else
1507         {
1508                 assert (23 == 42);
1509         }
1510
1511         state->last_time = t;
1512         *ret_value = state->last_value;
1513         return (0);
1514 } /* }}} value_t rate_to_value */
1515
1516 int value_to_rate (gauge_t *ret_rate, /* {{{ */
1517                 value_t value, int ds_type, cdtime_t t, value_to_rate_state_t *state)
1518 {
1519         gauge_t interval;
1520
1521         /* Another invalid state: The time is not increasing. */
1522         if (t <= state->last_time)
1523         {
1524                 memset (state, 0, sizeof (*state));
1525                 return (EINVAL);
1526         }
1527
1528         interval = CDTIME_T_TO_DOUBLE(t - state->last_time);
1529
1530         /* Previous value is invalid. */
1531         if (state->last_time == 0)
1532         {
1533                 state->last_value = value;
1534                 state->last_time = t;
1535                 return (EAGAIN);
1536         }
1537
1538         switch (ds_type) {
1539         case DS_TYPE_DERIVE: {
1540                 derive_t diff = value.derive - state->last_value.derive;
1541                 *ret_rate = ((gauge_t) diff) / ((gauge_t) interval);
1542                 break;
1543         }
1544         case DS_TYPE_GAUGE: {
1545                 *ret_rate = value.gauge;
1546                 break;
1547         }
1548         case DS_TYPE_COUNTER: {
1549                 counter_t diff = counter_diff (state->last_value.counter, value.counter);
1550                 *ret_rate = ((gauge_t) diff) / ((gauge_t) interval);
1551                 break;
1552         }
1553         case DS_TYPE_ABSOLUTE: {
1554                 absolute_t diff = value.absolute;
1555                 *ret_rate = ((gauge_t) diff) / ((gauge_t) interval);
1556                 break;
1557         }
1558         default:
1559                 return EINVAL;
1560         }
1561
1562         state->last_value = value;
1563         state->last_time = t;
1564         return (0);
1565 } /* }}} value_t rate_to_value */
1566
1567 int service_name_to_port_number (const char *service_name)
1568 {
1569         struct addrinfo *ai_list;
1570         int status;
1571         int service_number;
1572
1573         if (service_name == NULL)
1574                 return (-1);
1575
1576         struct addrinfo ai_hints = {
1577                 .ai_family = AF_UNSPEC
1578         };
1579
1580         status = getaddrinfo (/* node = */ NULL, service_name,
1581                         &ai_hints, &ai_list);
1582         if (status != 0)
1583         {
1584                 ERROR ("service_name_to_port_number: getaddrinfo failed: %s",
1585                                 gai_strerror (status));
1586                 return (-1);
1587         }
1588
1589         service_number = -1;
1590         for (struct addrinfo *ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
1591         {
1592                 if (ai_ptr->ai_family == AF_INET)
1593                 {
1594                         struct sockaddr_in *sa;
1595
1596                         sa = (void *) ai_ptr->ai_addr;
1597                         service_number = (int) ntohs (sa->sin_port);
1598                 }
1599                 else if (ai_ptr->ai_family == AF_INET6)
1600                 {
1601                         struct sockaddr_in6 *sa;
1602
1603                         sa = (void *) ai_ptr->ai_addr;
1604                         service_number = (int) ntohs (sa->sin6_port);
1605                 }
1606
1607                 if ((service_number > 0) && (service_number <= 65535))
1608                         break;
1609         }
1610
1611         freeaddrinfo (ai_list);
1612
1613         if ((service_number > 0) && (service_number <= 65535))
1614                 return (service_number);
1615         return (-1);
1616 } /* int service_name_to_port_number */
1617
1618 void set_sock_opts (int sockfd) /* {{{ */
1619 {
1620         int status;
1621         int socktype;
1622
1623         socklen_t socklen = sizeof (socklen_t);
1624         int so_keepalive = 1;
1625
1626         status = getsockopt (sockfd, SOL_SOCKET, SO_TYPE, &socktype, &socklen);
1627         if (status != 0)
1628         {
1629                 WARNING ("set_sock_opts: failed to determine socket type");
1630                 return;
1631         }
1632
1633         if (socktype == SOCK_STREAM)
1634         {
1635                 status = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
1636                                 &so_keepalive, sizeof (so_keepalive));
1637                 if (status != 0)
1638                         WARNING ("set_sock_opts: failed to set socket keepalive flag");
1639
1640 #ifdef TCP_KEEPIDLE
1641                 int tcp_keepidle = ((CDTIME_T_TO_MS(plugin_get_interval()) - 1) / 100 + 1);
1642                 status = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
1643                                 &tcp_keepidle, sizeof (tcp_keepidle));
1644                 if (status != 0)
1645                         WARNING ("set_sock_opts: failed to set socket tcp keepalive time");
1646 #endif
1647
1648 #ifdef TCP_KEEPINTVL
1649                 int tcp_keepintvl = ((CDTIME_T_TO_MS(plugin_get_interval()) - 1) / 1000 + 1);
1650                 status = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
1651                                 &tcp_keepintvl, sizeof (tcp_keepintvl));
1652                 if (status != 0)
1653                         WARNING ("set_sock_opts: failed to set socket tcp keepalive interval");
1654 #endif
1655         }
1656 } /* }}} void set_sock_opts */
1657
1658 int strtoderive (const char *string, derive_t *ret_value) /* {{{ */
1659 {
1660         derive_t tmp;
1661         char *endptr;
1662
1663         if ((string == NULL) || (ret_value == NULL))
1664                 return (EINVAL);
1665
1666         errno = 0;
1667         endptr = NULL;
1668         tmp = (derive_t) strtoll (string, &endptr, /* base = */ 0);
1669         if ((endptr == string) || (errno != 0))
1670                 return (-1);
1671
1672         *ret_value = tmp;
1673         return (0);
1674 } /* }}} int strtoderive */
1675
1676 int strtogauge (const char *string, gauge_t *ret_value) /* {{{ */
1677 {
1678         gauge_t tmp;
1679         char *endptr = NULL;
1680
1681         if ((string == NULL) || (ret_value == NULL))
1682                 return (EINVAL);
1683
1684         errno = 0;
1685         endptr = NULL;
1686         tmp = (gauge_t) strtod (string, &endptr);
1687         if (errno != 0)
1688                 return (errno);
1689         else if ((endptr == NULL) || (*endptr != 0))
1690                 return (EINVAL);
1691
1692         *ret_value = tmp;
1693         return (0);
1694 } /* }}} int strtogauge */
1695
1696 int strarray_add (char ***ret_array, size_t *ret_array_len, char const *str) /* {{{ */
1697 {
1698         char **array;
1699         size_t array_len = *ret_array_len;
1700
1701         if (str == NULL)
1702                 return (EINVAL);
1703
1704         array = realloc (*ret_array,
1705             (array_len + 1) * sizeof (*array));
1706         if (array == NULL)
1707                 return (ENOMEM);
1708         *ret_array = array;
1709
1710         array[array_len] = strdup (str);
1711         if (array[array_len] == NULL)
1712                 return (ENOMEM);
1713
1714         array_len++;
1715         *ret_array_len = array_len;
1716         return (0);
1717 } /* }}} int strarray_add */
1718
1719 void strarray_free (char **array, size_t array_len) /* {{{ */
1720 {
1721         for (size_t i = 0; i < array_len; i++)
1722                 sfree (array[i]);
1723         sfree (array);
1724 } /* }}} void strarray_free */
1725
1726 #ifdef HAVE_SYS_CAPABILITY_H
1727 int check_capability (int capability) /* {{{ */
1728 {
1729 #ifdef _LINUX_CAPABILITY_VERSION_3
1730         cap_user_header_t cap_header = calloc(1, sizeof (*cap_header));
1731         if (cap_header == NULL)
1732         {
1733                 ERROR("check_capability: calloc failed");
1734                 return (-1);
1735         }
1736
1737         cap_user_data_t cap_data = calloc(1, sizeof (*cap_data));
1738         if (cap_data == NULL)
1739         {
1740                 ERROR("check_capability: calloc failed");
1741                 sfree(cap_header);
1742                 return (-1);
1743         }
1744
1745         cap_header->pid = getpid();
1746         cap_header->version = _LINUX_CAPABILITY_VERSION;
1747         if (capget(cap_header, cap_data) < 0)
1748         {
1749                 ERROR("check_capability: capget failed");
1750                 sfree(cap_header);
1751                 sfree(cap_data);
1752                 return (-1);
1753         }
1754
1755         if ((cap_data->effective & (1 << capability)) == 0)
1756         {
1757                 sfree(cap_header);
1758                 sfree(cap_data);
1759                 return (-1);
1760         }
1761         else
1762         {
1763                 sfree(cap_header);
1764                 sfree(cap_data);
1765                 return (0);
1766         }
1767 #else
1768         WARNING ("check_capability: unsupported capability implementation. "
1769             "Some plugin(s) may require elevated privileges to work properly.");
1770         return (0);
1771 #endif /* _LINUX_CAPABILITY_VERSION_3 */
1772 } /* }}} int check_capability */
1773 #endif /* HAVE_SYS_CAPABILITY_H */