Code

922bd15e4406077b162b40c5052e07b3ebddd5eb
[collectd.git] / src / common.c
1 /**
2  * collectd - src/common.c
3  * Copyright (C) 2005-2007  Florian octo Forster
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; only version 2 of the License is applicable.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  * Authors:
19  *   Florian octo Forster <octo at verplant.org>
20  *   Niki W. Waibel <niki.waibel@gmx.net>
21 **/
23 #include "common.h"
24 #include "utils_debug.h"
26 #ifdef HAVE_MATH_H
27 #  include <math.h>
28 #endif
30 /* for ntohl and htonl */
31 #if HAVE_ARPA_INET_H
32 # include <arpa/inet.h>
33 #endif
35 #ifdef HAVE_LIBKSTAT
36 extern kstat_ctl_t *kc;
37 #endif
39 void sstrncpy (char *d, const char *s, int len)
40 {
41         strncpy (d, s, len);
42         d[len - 1] = '\0';
43 }
45 char *sstrdup (const char *s)
46 {
47         char *r;
49         if (s == NULL)
50                 return (NULL);
52         if((r = strdup (s)) == NULL)
53         {
54                 DBG ("Not enough memory.");
55                 exit(3);
56         }
58         return (r);
59 }
61 void *smalloc (size_t size)
62 {
63         void *r;
65         if ((r = malloc (size)) == NULL)
66         {
67                 DBG("Not enough memory.");
68                 exit(3);
69         }
71         return r;
72 }
74 #if 0
75 void sfree (void **ptr)
76 {
77         if (ptr == NULL)
78                 return;
80         if (*ptr != NULL)
81                 free (*ptr);
83         *ptr = NULL;
84 }
85 #endif
87 ssize_t sread (int fd, void *buf, size_t count)
88 {
89         char    *ptr;
90         size_t   nleft;
91         ssize_t  status;
93         ptr   = (char *) buf;
94         nleft = count;
96         while (nleft > 0)
97         {
98                 status = read (fd, (void *) ptr, nleft);
100                 if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR)))
101                         continue;
103                 if (status < 0)
104                         return (status);
106                 if (status == 0)
107                 {
108                         DBG ("Received EOF from fd %i. "
109                                         "Closing fd and returning error.",
110                                         fd);
111                         close (fd);
112                         return (-1);
113                 }
115                 assert (nleft >= status);
117                 nleft = nleft - status;
118                 ptr   = ptr   + status;
119         }
121         return (0);
125 ssize_t swrite (int fd, const void *buf, size_t count)
127         const char *ptr;
128         size_t      nleft;
129         ssize_t     status;
131         ptr   = (const char *) buf;
132         nleft = count;
134         while (nleft > 0)
135         {
136                 status = write (fd, (const void *) ptr, nleft);
138                 if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR)))
139                         continue;
141                 if (status < 0)
142                         return (status);
144                 nleft = nleft - status;
145                 ptr   = ptr   + status;
146         }
148         return (0);
151 int strsplit (char *string, char **fields, size_t size)
153         size_t i;
154         char *ptr;
155         char *saveptr;
157         i = 0;
158         ptr = string;
159         saveptr = NULL;
160         while ((fields[i] = strtok_r (ptr, " \t", &saveptr)) != NULL)
161         {
162                 ptr = NULL;
163                 i++;
165                 if (i >= size)
166                         break;
167         }
169         return (i);
172 int strjoin (char *dst, size_t dst_len,
173                 char **fields, size_t fields_num,
174                 const char *sep)
176         int field_len;
177         int sep_len;
178         int i;
180         memset (dst, '\0', dst_len);
182         if (fields_num <= 0)
183                 return (-1);
185         sep_len = 0;
186         if (sep != NULL)
187                 sep_len = strlen (sep);
189         for (i = 0; i < fields_num; i++)
190         {
191                 if ((i > 0) && (sep_len > 0))
192                 {
193                         if (dst_len <= sep_len)
194                                 return (-1);
196                         strncat (dst, sep, dst_len);
197                         dst_len -= sep_len;
198                 }
200                 field_len = strlen (fields[i]);
202                 if (dst_len <= field_len)
203                         return (-1);
205                 strncat (dst, fields[i], dst_len);
206                 dst_len -= field_len;
207         }
209         return (strlen (dst));
212 int strsubstitute (char *str, char c_from, char c_to)
214         int ret;
216         if (str == NULL)
217                 return (-1);
219         ret = 0;
220         while (*str != '\0')
221         {
222                 if (*str == c_from)
223                 {
224                         *str = c_to;
225                         ret++;
226                 }
227                 str++;
228         }
230         return (ret);
233 int escape_slashes (char *buf, int buf_len)
235         int i;
237         if (strcmp (buf, "/") == 0)
238         {
239                 if (buf_len < 5)
240                         return (-1);
242                 strncpy (buf, "root", buf_len);
243                 return (0);
244         }
246         /* Move one to the left */
247         memmove (buf, buf + 1, buf_len - 1);
249         for (i = 0; i < buf_len - 1; i++)
250         {
251                 if (buf[i] == '\0')
252                         break;
253                 else if (buf[i] == '/')
254                         buf[i] = '_';
255         }
256         buf[i] = '\0';
258         return (0);
261 int timeval_sub_timespec (struct timeval *tv0, struct timeval *tv1, struct timespec *ret)
263         if ((tv0 == NULL) || (tv1 == NULL) || (ret == NULL))
264                 return (-2);
266         if ((tv0->tv_sec < tv1->tv_sec)
267                         || ((tv0->tv_sec == tv1->tv_sec) && (tv0->tv_usec < tv1->tv_usec)))
268                 return (-1);
270         ret->tv_sec  = tv0->tv_sec - tv1->tv_sec;
271         ret->tv_nsec = 1000 * ((long) (tv0->tv_usec - tv1->tv_usec));
273         if (ret->tv_nsec < 0)
274         {
275                 assert (ret->tv_sec > 0);
277                 ret->tv_nsec += 1000000000;
278                 ret->tv_sec  -= 1;
279         }
281         return (0);
284 int check_create_dir (const char *file_orig)
286         struct stat statbuf;
288         char  file_copy[512];
289         char  dir[512];
290         int   dir_len = 512;
291         char *fields[16];
292         int   fields_num;
293         char *ptr;
294         char *saveptr;
295         int   last_is_file = 1;
296         int   path_is_absolute = 0;
297         int   len;
298         int   i;
300         /*
301          * Sanity checks first
302          */
303         if (file_orig == NULL)
304                 return (-1);
306         if ((len = strlen (file_orig)) < 1)
307                 return (-1);
308         else if (len >= 512)
309                 return (-1);
311         /*
312          * If `file_orig' ends in a slash the last component is a directory,
313          * otherwise it's a file. Act accordingly..
314          */
315         if (file_orig[len - 1] == '/')
316                 last_is_file = 0;
317         if (file_orig[0] == '/')
318                 path_is_absolute = 1;
320         /*
321          * Create a copy for `strtok_r' to destroy
322          */
323         strncpy (file_copy, file_orig, 512);
324         file_copy[511] = '\0';
326         /*
327          * Break into components. This will eat up several slashes in a row and
328          * remove leading and trailing slashes..
329          */
330         ptr = file_copy;
331         saveptr = NULL;
332         fields_num = 0;
333         while ((fields[fields_num] = strtok_r (ptr, "/", &saveptr)) != NULL)
334         {
335                 ptr = NULL;
336                 fields_num++;
338                 if (fields_num >= 16)
339                         break;
340         }
342         /*
343          * For each component, do..
344          */
345         for (i = 0; i < (fields_num - last_is_file); i++)
346         {
347                 /*
348                  * Do not create directories that start with a dot. This
349                  * prevents `../../' attacks and other likely malicious
350                  * behavior.
351                  */
352                 if (fields[i][0] == '.')
353                 {
354                         syslog (LOG_ERR, "Cowardly refusing to create a directory that begins with a `.' (dot): `%s'", file_orig);
355                         return (-2);
356                 }
358                 /*
359                  * Join the components together again
360                  */
361                 dir[0] = '/';
362                 if (strjoin (dir + path_is_absolute, dir_len - path_is_absolute,
363                                         fields, i + 1, "/") < 0)
364                 {
365                         syslog (LOG_ERR, "strjoin failed: `%s', component #%i", file_orig, i);
366                         return (-1);
367                 }
369                 if (stat (dir, &statbuf) == -1)
370                 {
371                         if (errno == ENOENT)
372                         {
373                                 if (mkdir (dir, 0755) == -1)
374                                 {
375                                         syslog (LOG_ERR, "mkdir (%s): %s", dir, strerror (errno));
376                                         return (-1);
377                                 }
378                         }
379                         else
380                         {
381                                 syslog (LOG_ERR, "stat (%s): %s", dir, strerror (errno));
382                                 return (-1);
383                         }
384                 }
385                 else if (!S_ISDIR (statbuf.st_mode))
386                 {
387                         syslog (LOG_ERR, "stat (%s): Not a directory!", dir);
388                         return (-1);
389                 }
390         }
392         return (0);
395 #ifdef HAVE_LIBKSTAT
396 int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name)
398         char ident[128];
399         
400         if (kc == NULL)
401                 return (-1);
403         snprintf (ident, 128, "%s,%i,%s", module, instance, name);
404         ident[127] = '\0';
406         if (*ksp_ptr == NULL)
407         {
408                 if ((*ksp_ptr = kstat_lookup (kc, module, instance, name)) == NULL)
409                 {
410                         syslog (LOG_ERR, "Cound not find kstat %s", ident);
411                         return (-1);
412                 }
414                 if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED)
415                 {
416                         syslog (LOG_WARNING, "kstat %s has wrong type", ident);
417                         *ksp_ptr = NULL;
418                         return (-1);
419                 }
420         }
422 #ifdef assert
423         assert (*ksp_ptr != NULL);
424         assert ((*ksp_ptr)->ks_type == KSTAT_TYPE_NAMED);
425 #endif
427         if (kstat_read (kc, *ksp_ptr, NULL) == -1)
428         {
429                 syslog (LOG_WARNING, "kstat %s could not be read", ident);
430                 return (-1);
431         }
433         if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED)
434         {
435                 syslog (LOG_WARNING, "kstat %s has wrong type", ident);
436                 return (-1);
437         }
439         return (0);
442 long long get_kstat_value (kstat_t *ksp, char *name)
444         kstat_named_t *kn;
445         long long retval = -1LL;
447 #ifdef assert
448         assert (ksp != NULL);
449         assert (ksp->ks_type == KSTAT_TYPE_NAMED);
450 #else
451         if (ksp == NULL)
452         {
453                 fprintf (stderr, "ERROR: %s:%i: ksp == NULL\n", __FILE__, __LINE__);
454                 return (-1LL);
455         }
456         else if (ksp->ks_type != KSTAT_TYPE_NAMED)
457         {
458                 fprintf (stderr, "ERROR: %s:%i: ksp->ks_type != KSTAT_TYPE_NAMED\n", __FILE__, __LINE__);
459                 return (-1LL);
460         }
461 #endif
463         if ((kn = (kstat_named_t *) kstat_data_lookup (ksp, name)) == NULL)
464                 return (retval);
466         if (kn->data_type == KSTAT_DATA_INT32)
467                 retval = (long long) kn->value.i32;
468         else if (kn->data_type == KSTAT_DATA_UINT32)
469                 retval = (long long) kn->value.ui32;
470         else if (kn->data_type == KSTAT_DATA_INT64)
471                 retval = (long long) kn->value.i64; /* According to ANSI C99 `long long' must hold at least 64 bits */
472         else if (kn->data_type == KSTAT_DATA_UINT64)
473                 retval = (long long) kn->value.ui64; /* XXX: Might overflow! */
474         else
475                 syslog (LOG_WARNING, "get_kstat_value: Not a numeric value: %s", name);
476                  
477         return (retval);
479 #endif /* HAVE_LIBKSTAT */
481 unsigned long long ntohll (unsigned long long n)
483 #if __BYTE_ORDER == __BIG_ENDIAN
484         return (n);
485 #else
486         return (((unsigned long long) ntohl (n)) << 32) + ntohl (n >> 32);
487 #endif
490 unsigned long long htonll (unsigned long long n)
492 #if __BYTE_ORDER == __BIG_ENDIAN
493         return (n);
494 #else
495         return (((unsigned long long) htonl (n)) << 32) + htonl (n >> 32);
496 #endif