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