ede2ea5c26aea81720b23c16555216d942aa99d2
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 "plugin.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 DEBUG ("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 DEBUG("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 DEBUG ("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);
122 }
125 ssize_t swrite (int fd, const void *buf, size_t count)
126 {
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);
149 }
151 int strsplit (char *string, char **fields, size_t size)
152 {
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);
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 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 ERROR ("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 ERROR ("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 ERROR ("mkdir (%s): %s", dir, strerror (errno));
376 return (-1);
377 }
378 }
379 else
380 {
381 ERROR ("stat (%s): %s", dir, strerror (errno));
382 return (-1);
383 }
384 }
385 else if (!S_ISDIR (statbuf.st_mode))
386 {
387 ERROR ("stat (%s): Not a directory!", dir);
388 return (-1);
389 }
390 }
392 return (0);
393 }
395 #ifdef HAVE_LIBKSTAT
396 int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name)
397 {
398 char ident[128];
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 ERROR ("Cound not find kstat %s", ident);
411 return (-1);
412 }
414 if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED)
415 {
416 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 WARNING ("kstat %s could not be read", ident);
430 return (-1);
431 }
433 if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED)
434 {
435 WARNING ("kstat %s has wrong type", ident);
436 return (-1);
437 }
439 return (0);
440 }
442 long long get_kstat_value (kstat_t *ksp, char *name)
443 {
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 WARNING ("get_kstat_value: Not a numeric value: %s", name);
477 return (retval);
478 }
479 #endif /* HAVE_LIBKSTAT */
481 unsigned long long ntohll (unsigned long long n)
482 {
483 #if __BYTE_ORDER == __BIG_ENDIAN
484 return (n);
485 #else
486 return (((unsigned long long) ntohl (n)) << 32) + ntohl (n >> 32);
487 #endif
488 }
490 unsigned long long htonll (unsigned long long n)
491 {
492 #if __BYTE_ORDER == __BIG_ENDIAN
493 return (n);
494 #else
495 return (((unsigned long long) htonl (n)) << 32) + htonl (n >> 32);
496 #endif
497 }