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 extern int operating_mode;
37 #ifdef HAVE_LIBKSTAT
38 extern kstat_ctl_t *kc;
39 #endif
41 void sstrncpy (char *d, const char *s, int len)
42 {
43 strncpy (d, s, len);
44 d[len - 1] = '\0';
45 }
47 char *sstrdup (const char *s)
48 {
49 char *r;
51 if (s == NULL)
52 return (NULL);
54 if((r = strdup (s)) == NULL)
55 {
56 DBG ("Not enough memory.");
57 exit(3);
58 }
60 return (r);
61 }
63 void *smalloc (size_t size)
64 {
65 void *r;
67 if ((r = malloc (size)) == NULL)
68 {
69 DBG("Not enough memory.");
70 exit(3);
71 }
73 return r;
74 }
76 #if 0
77 void sfree (void **ptr)
78 {
79 if (ptr == NULL)
80 return;
82 if (*ptr != NULL)
83 free (*ptr);
85 *ptr = NULL;
86 }
87 #endif
89 ssize_t sread (int fd, void *buf, size_t count)
90 {
91 char *ptr;
92 size_t nleft;
93 ssize_t status;
95 ptr = (char *) buf;
96 nleft = count;
98 while (nleft > 0)
99 {
100 status = read (fd, (void *) ptr, nleft);
102 if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR)))
103 continue;
105 if (status < 0)
106 return (status);
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 }
117 assert (nleft >= status);
119 nleft = nleft - status;
120 ptr = ptr + status;
121 }
123 return (0);
124 }
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;
133 ptr = (const char *) buf;
134 nleft = count;
136 while (nleft > 0)
137 {
138 status = write (fd, (const void *) ptr, nleft);
140 if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR)))
141 continue;
143 if (status < 0)
144 return (status);
146 nleft = nleft - status;
147 ptr = ptr + status;
148 }
150 return (0);
151 }
153 int strsplit (char *string, char **fields, size_t size)
154 {
155 size_t i;
156 char *ptr;
158 i = 0;
159 ptr = string;
160 while ((fields[i] = strtok (ptr, " \t")) != NULL)
161 {
162 ptr = NULL;
163 i++;
165 if (i >= size)
166 break;
167 }
169 return (i);
170 }
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;
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));
210 }
212 int strsubstitute (char *str, char c_from, char c_to)
213 {
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);
231 }
233 int escape_slashes (char *buf, int buf_len)
234 {
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);
259 }
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);
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);
282 }
284 int check_create_dir (const char *file_orig)
285 {
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 int last_is_file = 1;
295 int len;
296 int i;
298 /*
299 * Sanity checks first
300 */
301 if (file_orig == NULL)
302 return (-1);
304 if ((len = strlen (file_orig)) < 1)
305 return (-1);
306 else if (len >= 512)
307 return (-1);
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;
316 /*
317 * Create a copy for `strtok' to destroy
318 */
319 strncpy (file_copy, file_orig, 512);
320 file_copy[511] = '\0';
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++;
333 if (fields_num >= 16)
334 break;
335 }
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 }
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 }
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 }
385 return (0);
386 }
388 #ifdef HAVE_LIBKSTAT
389 int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name)
390 {
391 char ident[128];
393 if (kc == NULL)
394 return (-1);
396 snprintf (ident, 128, "%s,%i,%s", module, instance, name);
397 ident[127] = '\0';
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 }
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 }
415 #ifdef assert
416 assert (*ksp_ptr != NULL);
417 assert ((*ksp_ptr)->ks_type == KSTAT_TYPE_NAMED);
418 #endif
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 }
426 if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED)
427 {
428 syslog (LOG_WARNING, "kstat %s has wrong type", ident);
429 return (-1);
430 }
432 return (0);
433 }
435 long long get_kstat_value (kstat_t *ksp, char *name)
436 {
437 kstat_named_t *kn;
438 long long retval = -1LL;
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
456 if ((kn = (kstat_named_t *) kstat_data_lookup (ksp, name)) == NULL)
457 return (retval);
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);
470 return (retval);
471 }
472 #endif /* HAVE_LIBKSTAT */
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 }
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 }