Merge branch 'collectd-5.6'
[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 {
1021         char *hostname = NULL;
1022         char *plugin = NULL;
1023         char *plugin_instance = NULL;
1024         char *type = NULL;
1025         char *type_instance = NULL;
1026
1027         hostname = str;
1028         if (hostname == NULL)
1029                 return (-1);
1030
1031         plugin = strchr (hostname, '/');
1032         if (plugin == NULL)
1033                 return (-1);
1034         *plugin = '\0'; plugin++;
1035
1036         type = strchr (plugin, '/');
1037         if (type == NULL)
1038                 return (-1);
1039         *type = '\0'; type++;
1040
1041         plugin_instance = strchr (plugin, '-');
1042         if (plugin_instance != NULL)
1043         {
1044                 *plugin_instance = '\0';
1045                 plugin_instance++;
1046         }
1047
1048         type_instance = strchr (type, '-');
1049         if (type_instance != NULL)
1050         {
1051                 *type_instance = '\0';
1052                 type_instance++;
1053         }
1054
1055         *ret_host = hostname;
1056         *ret_plugin = plugin;
1057         *ret_plugin_instance = plugin_instance;
1058         *ret_type = type;
1059         *ret_type_instance = type_instance;
1060         return (0);
1061 } /* int parse_identifier */
1062
1063 int parse_identifier_vl (const char *str, value_list_t *vl) /* {{{ */
1064 {
1065         char str_copy[6 * DATA_MAX_NAME_LEN];
1066         char *host = NULL;
1067         char *plugin = NULL;
1068         char *plugin_instance = NULL;
1069         char *type = NULL;
1070         char *type_instance = NULL;
1071         int status;
1072
1073         if ((str == NULL) || (vl == NULL))
1074                 return (EINVAL);
1075
1076         sstrncpy (str_copy, str, sizeof (str_copy));
1077
1078         status = parse_identifier (str_copy, &host,
1079                         &plugin, &plugin_instance,
1080                         &type, &type_instance);
1081         if (status != 0)
1082                 return (status);
1083
1084         sstrncpy (vl->host, host, sizeof (vl->host));
1085         sstrncpy (vl->plugin, plugin, sizeof (vl->plugin));
1086         sstrncpy (vl->plugin_instance,
1087                         (plugin_instance != NULL) ? plugin_instance : "",
1088                         sizeof (vl->plugin_instance));
1089         sstrncpy (vl->type, type, sizeof (vl->type));
1090         sstrncpy (vl->type_instance,
1091                         (type_instance != NULL) ? type_instance : "",
1092                         sizeof (vl->type_instance));
1093
1094         return (0);
1095 } /* }}} int parse_identifier_vl */
1096
1097 int parse_value (const char *value_orig, value_t *ret_value, int ds_type)
1098 {
1099   char *value;
1100   char *endptr = NULL;
1101   size_t value_len;
1102
1103   if (value_orig == NULL)
1104     return (EINVAL);
1105
1106   value = strdup (value_orig);
1107   if (value == NULL)
1108     return (ENOMEM);
1109   value_len = strlen (value);
1110
1111   while ((value_len > 0) && isspace ((int) value[value_len - 1]))
1112   {
1113     value[value_len - 1] = 0;
1114     value_len--;
1115   }
1116
1117   switch (ds_type)
1118   {
1119     case DS_TYPE_COUNTER:
1120       ret_value->counter = (counter_t) strtoull (value, &endptr, 0);
1121       break;
1122
1123     case DS_TYPE_GAUGE:
1124       ret_value->gauge = (gauge_t) strtod (value, &endptr);
1125       break;
1126
1127     case DS_TYPE_DERIVE:
1128       ret_value->derive = (derive_t) strtoll (value, &endptr, 0);
1129       break;
1130
1131     case DS_TYPE_ABSOLUTE:
1132       ret_value->absolute = (absolute_t) strtoull (value, &endptr, 0);
1133       break;
1134
1135     default:
1136       sfree (value);
1137       ERROR ("parse_value: Invalid data source type: %i.", ds_type);
1138       return -1;
1139   }
1140
1141   if (value == endptr) {
1142     ERROR ("parse_value: Failed to parse string as %s: \"%s\".",
1143         DS_TYPE_TO_STRING (ds_type), value);
1144     sfree (value);
1145     return -1;
1146   }
1147   else if ((NULL != endptr) && ('\0' != *endptr))
1148     INFO ("parse_value: Ignoring trailing garbage \"%s\" after %s value. "
1149         "Input string was \"%s\".",
1150         endptr, DS_TYPE_TO_STRING (ds_type), value_orig);
1151
1152   sfree (value);
1153   return 0;
1154 } /* int parse_value */
1155
1156 int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds)
1157 {
1158         size_t i;
1159         char *dummy;
1160         char *ptr;
1161         char *saveptr;
1162
1163         if ((buffer == NULL) || (vl == NULL) || (ds == NULL))
1164                 return EINVAL;
1165
1166         i = 0;
1167         dummy = buffer;
1168         saveptr = NULL;
1169         vl->time = 0;
1170         while ((ptr = strtok_r (dummy, ":", &saveptr)) != NULL)
1171         {
1172                 dummy = NULL;
1173
1174                 if (i >= vl->values_len)
1175                 {
1176                         /* Make sure i is invalid. */
1177                         i = 0;
1178                         break;
1179                 }
1180
1181                 if (vl->time == 0)
1182                 {
1183                         if (strcmp ("N", ptr) == 0)
1184                                 vl->time = cdtime ();
1185                         else
1186                         {
1187                                 char *endptr = NULL;
1188                                 double tmp;
1189
1190                                 errno = 0;
1191                                 tmp = strtod (ptr, &endptr);
1192                                 if ((errno != 0)                    /* Overflow */
1193                                                 || (endptr == ptr)  /* Invalid string */
1194                                                 || (endptr == NULL) /* This should not happen */
1195                                                 || (*endptr != 0))  /* Trailing chars */
1196                                         return (-1);
1197
1198                                 vl->time = DOUBLE_TO_CDTIME_T (tmp);
1199                         }
1200
1201                         continue;
1202                 }
1203
1204                 if ((strcmp ("U", ptr) == 0) && (ds->ds[i].type == DS_TYPE_GAUGE))
1205                         vl->values[i].gauge = NAN;
1206                 else if (0 != parse_value (ptr, &vl->values[i], ds->ds[i].type))
1207                         return -1;
1208
1209                 i++;
1210         } /* while (strtok_r) */
1211
1212         if ((ptr != NULL) || (i == 0))
1213                 return (-1);
1214         return (0);
1215 } /* int parse_values */
1216
1217 int parse_value_file (char const *path, value_t *ret_value, int ds_type)
1218 {
1219         FILE *fh;
1220         char buffer[256];
1221
1222         fh = fopen (path, "r");
1223         if (fh == NULL)
1224                 return (-1);
1225
1226         if (fgets (buffer, sizeof (buffer), fh) == NULL)
1227         {
1228                 fclose (fh);
1229                 return (-1);
1230         }
1231
1232         fclose (fh);
1233
1234         strstripnewline (buffer);
1235
1236         return parse_value (buffer, ret_value, ds_type);
1237 } /* int parse_value_file */
1238
1239 #if !HAVE_GETPWNAM_R
1240 int getpwnam_r (const char *name, struct passwd *pwbuf, char *buf,
1241                 size_t buflen, struct passwd **pwbufp)
1242 {
1243         int status = 0;
1244         struct passwd *pw;
1245
1246         memset (pwbuf, '\0', sizeof (struct passwd));
1247
1248         pthread_mutex_lock (&getpwnam_r_lock);
1249
1250         do
1251         {
1252                 pw = getpwnam (name);
1253                 if (pw == NULL)
1254                 {
1255                         status = (errno != 0) ? errno : ENOENT;
1256                         break;
1257                 }
1258
1259 #define GETPWNAM_COPY_MEMBER(member) \
1260                 if (pw->member != NULL) \
1261                 { \
1262                         int len = strlen (pw->member); \
1263                         if (len >= buflen) \
1264                         { \
1265                                 status = ENOMEM; \
1266                                 break; \
1267                         } \
1268                         sstrncpy (buf, pw->member, buflen); \
1269                         pwbuf->member = buf; \
1270                         buf    += (len + 1); \
1271                         buflen -= (len + 1); \
1272                 }
1273                 GETPWNAM_COPY_MEMBER(pw_name);
1274                 GETPWNAM_COPY_MEMBER(pw_passwd);
1275                 GETPWNAM_COPY_MEMBER(pw_gecos);
1276                 GETPWNAM_COPY_MEMBER(pw_dir);
1277                 GETPWNAM_COPY_MEMBER(pw_shell);
1278
1279                 pwbuf->pw_uid = pw->pw_uid;
1280                 pwbuf->pw_gid = pw->pw_gid;
1281
1282                 if (pwbufp != NULL)
1283                         *pwbufp = pwbuf;
1284         } while (0);
1285
1286         pthread_mutex_unlock (&getpwnam_r_lock);
1287
1288         return (status);
1289 } /* int getpwnam_r */
1290 #endif /* !HAVE_GETPWNAM_R */
1291
1292 int notification_init (notification_t *n, int severity, const char *message,
1293                 const char *host,
1294                 const char *plugin, const char *plugin_instance,
1295                 const char *type, const char *type_instance)
1296 {
1297         memset (n, '\0', sizeof (notification_t));
1298
1299         n->severity = severity;
1300
1301         if (message != NULL)
1302                 sstrncpy (n->message, message, sizeof (n->message));
1303         if (host != NULL)
1304                 sstrncpy (n->host, host, sizeof (n->host));
1305         if (plugin != NULL)
1306                 sstrncpy (n->plugin, plugin, sizeof (n->plugin));
1307         if (plugin_instance != NULL)
1308                 sstrncpy (n->plugin_instance, plugin_instance,
1309                                 sizeof (n->plugin_instance));
1310         if (type != NULL)
1311                 sstrncpy (n->type, type, sizeof (n->type));
1312         if (type_instance != NULL)
1313                 sstrncpy (n->type_instance, type_instance,
1314                                 sizeof (n->type_instance));
1315
1316         return (0);
1317 } /* int notification_init */
1318
1319 int walk_directory (const char *dir, dirwalk_callback_f callback,
1320                 void *user_data, int include_hidden)
1321 {
1322         struct dirent *ent;
1323         DIR *dh;
1324         int success;
1325         int failure;
1326
1327         success = 0;
1328         failure = 0;
1329
1330         if ((dh = opendir (dir)) == NULL)
1331         {
1332                 char errbuf[1024];
1333                 ERROR ("walk_directory: Cannot open '%s': %s", dir,
1334                                 sstrerror (errno, errbuf, sizeof (errbuf)));
1335                 return -1;
1336         }
1337
1338         while ((ent = readdir (dh)) != NULL)
1339         {
1340                 int status;
1341
1342                 if (include_hidden)
1343                 {
1344                         if ((strcmp (".", ent->d_name) == 0)
1345                                         || (strcmp ("..", ent->d_name) == 0))
1346                                 continue;
1347                 }
1348                 else /* if (!include_hidden) */
1349                 {
1350                         if (ent->d_name[0]=='.')
1351                                 continue;
1352                 }
1353
1354                 status = (*callback) (dir, ent->d_name, user_data);
1355                 if (status != 0)
1356                         failure++;
1357                 else
1358                         success++;
1359         }
1360
1361         closedir (dh);
1362
1363         if ((success == 0) && (failure > 0))
1364                 return (-1);
1365         return (0);
1366 }
1367
1368 ssize_t read_file_contents (const char *filename, char *buf, size_t bufsize)
1369 {
1370         FILE *fh;
1371         ssize_t ret;
1372
1373         fh = fopen (filename, "r");
1374         if (fh == NULL)
1375                 return (-1);
1376
1377         ret = (ssize_t) fread (buf, 1, bufsize, fh);
1378         if ((ret == 0) && (ferror (fh) != 0))
1379         {
1380                 ERROR ("read_file_contents: Reading file \"%s\" failed.",
1381                                 filename);
1382                 ret = -1;
1383         }
1384
1385         fclose(fh);
1386         return (ret);
1387 }
1388
1389 counter_t counter_diff (counter_t old_value, counter_t new_value)
1390 {
1391         counter_t diff;
1392
1393         if (old_value > new_value)
1394         {
1395                 if (old_value <= 4294967295U)
1396                         diff = (4294967295U - old_value) + new_value + 1;
1397                 else
1398                         diff = (18446744073709551615ULL - old_value) + new_value + 1;
1399         }
1400         else
1401         {
1402                 diff = new_value - old_value;
1403         }
1404
1405         return (diff);
1406 } /* counter_t counter_diff */
1407
1408 int rate_to_value (value_t *ret_value, gauge_t rate, /* {{{ */
1409                 rate_to_value_state_t *state,
1410                 int ds_type, cdtime_t t)
1411 {
1412         gauge_t delta_gauge;
1413         cdtime_t delta_t;
1414
1415         if (ds_type == DS_TYPE_GAUGE)
1416         {
1417                 state->last_value.gauge = rate;
1418                 state->last_time = t;
1419
1420                 *ret_value = state->last_value;
1421                 return (0);
1422         }
1423
1424         /* Counter and absolute can't handle negative rates. Reset "last time"
1425          * to zero, so that the next valid rate will re-initialize the
1426          * structure. */
1427         if ((rate < 0.0)
1428                         && ((ds_type == DS_TYPE_COUNTER)
1429                                 || (ds_type == DS_TYPE_ABSOLUTE)))
1430         {
1431                 memset (state, 0, sizeof (*state));
1432                 return (EINVAL);
1433         }
1434
1435         /* Another invalid state: The time is not increasing. */
1436         if (t <= state->last_time)
1437         {
1438                 memset (state, 0, sizeof (*state));
1439                 return (EINVAL);
1440         }
1441
1442         delta_t = t - state->last_time;
1443         delta_gauge = (rate * CDTIME_T_TO_DOUBLE (delta_t)) + state->residual;
1444
1445         /* Previous value is invalid. */
1446         if (state->last_time == 0) /* {{{ */
1447         {
1448                 if (ds_type == DS_TYPE_DERIVE)
1449                 {
1450                         state->last_value.derive = (derive_t) rate;
1451                         state->residual = rate - ((gauge_t) state->last_value.derive);
1452                 }
1453                 else if (ds_type == DS_TYPE_COUNTER)
1454                 {
1455                         state->last_value.counter = (counter_t) rate;
1456                         state->residual = rate - ((gauge_t) state->last_value.counter);
1457                 }
1458                 else if (ds_type == DS_TYPE_ABSOLUTE)
1459                 {
1460                         state->last_value.absolute = (absolute_t) rate;
1461                         state->residual = rate - ((gauge_t) state->last_value.absolute);
1462                 }
1463                 else
1464                 {
1465                         assert (23 == 42);
1466                 }
1467
1468                 state->last_time = t;
1469                 return (EAGAIN);
1470         } /* }}} */
1471
1472         if (ds_type == DS_TYPE_DERIVE)
1473         {
1474                 derive_t delta_derive = (derive_t) delta_gauge;
1475
1476                 state->last_value.derive += delta_derive;
1477                 state->residual = delta_gauge - ((gauge_t) delta_derive);
1478         }
1479         else if (ds_type == DS_TYPE_COUNTER)
1480         {
1481                 counter_t delta_counter = (counter_t) delta_gauge;
1482
1483                 state->last_value.counter += delta_counter;
1484                 state->residual = delta_gauge - ((gauge_t) delta_counter);
1485         }
1486         else if (ds_type == DS_TYPE_ABSOLUTE)
1487         {
1488                 absolute_t delta_absolute = (absolute_t) delta_gauge;
1489
1490                 state->last_value.absolute = delta_absolute;
1491                 state->residual = delta_gauge - ((gauge_t) delta_absolute);
1492         }
1493         else
1494         {
1495                 assert (23 == 42);
1496         }
1497
1498         state->last_time = t;
1499         *ret_value = state->last_value;
1500         return (0);
1501 } /* }}} value_t rate_to_value */
1502
1503 int value_to_rate (gauge_t *ret_rate, /* {{{ */
1504                 value_t value, int ds_type, cdtime_t t, value_to_rate_state_t *state)
1505 {
1506         gauge_t interval;
1507
1508         /* Another invalid state: The time is not increasing. */
1509         if (t <= state->last_time)
1510         {
1511                 memset (state, 0, sizeof (*state));
1512                 return (EINVAL);
1513         }
1514
1515         interval = CDTIME_T_TO_DOUBLE(t - state->last_time);
1516
1517         /* Previous value is invalid. */
1518         if (state->last_time == 0)
1519         {
1520                 state->last_value = value;
1521                 state->last_time = t;
1522                 return (EAGAIN);
1523         }
1524
1525         switch (ds_type) {
1526         case DS_TYPE_DERIVE: {
1527                 derive_t diff = value.derive - state->last_value.derive;
1528                 *ret_rate = ((gauge_t) diff) / ((gauge_t) interval);
1529                 break;
1530         }
1531         case DS_TYPE_GAUGE: {
1532                 *ret_rate = value.gauge;
1533                 break;
1534         }
1535         case DS_TYPE_COUNTER: {
1536                 counter_t diff = counter_diff (state->last_value.counter, value.counter);
1537                 *ret_rate = ((gauge_t) diff) / ((gauge_t) interval);
1538                 break;
1539         }
1540         case DS_TYPE_ABSOLUTE: {
1541                 absolute_t diff = value.absolute;
1542                 *ret_rate = ((gauge_t) diff) / ((gauge_t) interval);
1543                 break;
1544         }
1545         default:
1546                 return EINVAL;
1547         }
1548
1549         state->last_value = value;
1550         state->last_time = t;
1551         return (0);
1552 } /* }}} value_t rate_to_value */
1553
1554 int service_name_to_port_number (const char *service_name)
1555 {
1556         struct addrinfo *ai_list;
1557         int status;
1558         int service_number;
1559
1560         if (service_name == NULL)
1561                 return (-1);
1562
1563         struct addrinfo ai_hints = {
1564                 .ai_family = AF_UNSPEC
1565         };
1566
1567         status = getaddrinfo (/* node = */ NULL, service_name,
1568                         &ai_hints, &ai_list);
1569         if (status != 0)
1570         {
1571                 ERROR ("service_name_to_port_number: getaddrinfo failed: %s",
1572                                 gai_strerror (status));
1573                 return (-1);
1574         }
1575
1576         service_number = -1;
1577         for (struct addrinfo *ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
1578         {
1579                 if (ai_ptr->ai_family == AF_INET)
1580                 {
1581                         struct sockaddr_in *sa;
1582
1583                         sa = (void *) ai_ptr->ai_addr;
1584                         service_number = (int) ntohs (sa->sin_port);
1585                 }
1586                 else if (ai_ptr->ai_family == AF_INET6)
1587                 {
1588                         struct sockaddr_in6 *sa;
1589
1590                         sa = (void *) ai_ptr->ai_addr;
1591                         service_number = (int) ntohs (sa->sin6_port);
1592                 }
1593
1594                 if ((service_number > 0) && (service_number <= 65535))
1595                         break;
1596         }
1597
1598         freeaddrinfo (ai_list);
1599
1600         if ((service_number > 0) && (service_number <= 65535))
1601                 return (service_number);
1602         return (-1);
1603 } /* int service_name_to_port_number */
1604
1605 void set_sock_opts (int sockfd) /* {{{ */
1606 {
1607         int status;
1608         int socktype;
1609
1610         socklen_t socklen = sizeof (socklen_t);
1611         int so_keepalive = 1;
1612
1613         status = getsockopt (sockfd, SOL_SOCKET, SO_TYPE, &socktype, &socklen);
1614         if (status != 0)
1615         {
1616                 WARNING ("set_sock_opts: failed to determine socket type");
1617                 return;
1618         }
1619
1620         if (socktype == SOCK_STREAM)
1621         {
1622                 status = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
1623                                 &so_keepalive, sizeof (so_keepalive));
1624                 if (status != 0)
1625                         WARNING ("set_sock_opts: failed to set socket keepalive flag");
1626
1627 #ifdef TCP_KEEPIDLE
1628                 int tcp_keepidle = ((CDTIME_T_TO_MS(plugin_get_interval()) - 1) / 100 + 1);
1629                 status = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
1630                                 &tcp_keepidle, sizeof (tcp_keepidle));
1631                 if (status != 0)
1632                         WARNING ("set_sock_opts: failed to set socket tcp keepalive time");
1633 #endif
1634
1635 #ifdef TCP_KEEPINTVL
1636                 int tcp_keepintvl = ((CDTIME_T_TO_MS(plugin_get_interval()) - 1) / 1000 + 1);
1637                 status = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
1638                                 &tcp_keepintvl, sizeof (tcp_keepintvl));
1639                 if (status != 0)
1640                         WARNING ("set_sock_opts: failed to set socket tcp keepalive interval");
1641 #endif
1642         }
1643 } /* }}} void set_sock_opts */
1644
1645 int strtoderive (const char *string, derive_t *ret_value) /* {{{ */
1646 {
1647         derive_t tmp;
1648         char *endptr;
1649
1650         if ((string == NULL) || (ret_value == NULL))
1651                 return (EINVAL);
1652
1653         errno = 0;
1654         endptr = NULL;
1655         tmp = (derive_t) strtoll (string, &endptr, /* base = */ 0);
1656         if ((endptr == string) || (errno != 0))
1657                 return (-1);
1658
1659         *ret_value = tmp;
1660         return (0);
1661 } /* }}} int strtoderive */
1662
1663 int strtogauge (const char *string, gauge_t *ret_value) /* {{{ */
1664 {
1665         gauge_t tmp;
1666         char *endptr = NULL;
1667
1668         if ((string == NULL) || (ret_value == NULL))
1669                 return (EINVAL);
1670
1671         errno = 0;
1672         endptr = NULL;
1673         tmp = (gauge_t) strtod (string, &endptr);
1674         if (errno != 0)
1675                 return (errno);
1676         else if ((endptr == NULL) || (*endptr != 0))
1677                 return (EINVAL);
1678
1679         *ret_value = tmp;
1680         return (0);
1681 } /* }}} int strtogauge */
1682
1683 int strarray_add (char ***ret_array, size_t *ret_array_len, char const *str) /* {{{ */
1684 {
1685         char **array;
1686         size_t array_len = *ret_array_len;
1687
1688         if (str == NULL)
1689                 return (EINVAL);
1690
1691         array = realloc (*ret_array,
1692             (array_len + 1) * sizeof (*array));
1693         if (array == NULL)
1694                 return (ENOMEM);
1695         *ret_array = array;
1696
1697         array[array_len] = strdup (str);
1698         if (array[array_len] == NULL)
1699                 return (ENOMEM);
1700
1701         array_len++;
1702         *ret_array_len = array_len;
1703         return (0);
1704 } /* }}} int strarray_add */
1705
1706 void strarray_free (char **array, size_t array_len) /* {{{ */
1707 {
1708         for (size_t i = 0; i < array_len; i++)
1709                 sfree (array[i]);
1710         sfree (array);
1711 } /* }}} void strarray_free */
1712
1713 #ifdef HAVE_SYS_CAPABILITY_H
1714 int check_capability (int capability) /* {{{ */
1715 {
1716 #ifdef _LINUX_CAPABILITY_VERSION_3
1717         cap_user_header_t cap_header = calloc(1, sizeof (*cap_header));
1718         if (cap_header == NULL)
1719         {
1720                 ERROR("check_capability: calloc failed");
1721                 return (-1);
1722         }
1723
1724         cap_user_data_t cap_data = calloc(1, sizeof (*cap_data));
1725         if (cap_data == NULL)
1726         {
1727                 ERROR("check_capability: calloc failed");
1728                 sfree(cap_header);
1729                 return (-1);
1730         }
1731
1732         cap_header->pid = getpid();
1733         cap_header->version = _LINUX_CAPABILITY_VERSION;
1734         if (capget(cap_header, cap_data) < 0)
1735         {
1736                 ERROR("check_capability: capget failed");
1737                 sfree(cap_header);
1738                 sfree(cap_data);
1739                 return (-1);
1740         }
1741
1742         if ((cap_data->effective & (1 << capability)) == 0)
1743         {
1744                 sfree(cap_header);
1745                 sfree(cap_data);
1746                 return (-1);
1747         }
1748         else
1749         {
1750                 sfree(cap_header);
1751                 sfree(cap_data);
1752                 return (0);
1753         }
1754 #else
1755         WARNING ("check_capability: unsupported capability implementation. "
1756             "Some plugin(s) may require elevated privileges to work properly.");
1757         return (0);
1758 #endif /* _LINUX_CAPABILITY_VERSION_3 */
1759 } /* }}} int check_capability */
1760 #endif /* HAVE_SYS_CAPABILITY_H */