2 * Copyright (C) 2008-2012 Tobias Brunner
3 * Copyright (C) 2005-2008 Martin Willi
4 * Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
30 #include "collections/enumerator.h"
31 #include "utils/debug.h"
32 #include "utils/chunk.h"
34 ENUM(status_names
, SUCCESS
, NEED_MORE
,
50 * Described in header.
52 void memxor(u_int8_t dst
[], u_int8_t src
[], size_t n
)
56 /* byte wise XOR until dst aligned */
57 for (i
= 0; (uintptr_t)&dst
[i
] % sizeof(long) && i
< n
; i
++)
61 /* try to use words if src shares an aligment with dst */
62 switch (((uintptr_t)&src
[i
] % sizeof(long)))
65 for (m
= n
- sizeof(long); i
<= m
; i
+= sizeof(long))
67 *(long*)&dst
[i
] ^= *(long*)&src
[i
];
71 for (m
= n
- sizeof(int); i
<= m
; i
+= sizeof(int))
73 *(int*)&dst
[i
] ^= *(int*)&src
[i
];
77 for (m
= n
- sizeof(short); i
<= m
; i
+= sizeof(short))
79 *(short*)&dst
[i
] ^= *(short*)&src
[i
];
85 /* byte wise XOR of the rest */
93 * Described in header.
95 void memwipe_noinline(void *ptr
, size_t n
)
97 memwipe_inline(ptr
, n
);
101 * Described in header.
103 void *memstr(const void *haystack
, const char *needle
, size_t n
)
105 unsigned const char *pos
= haystack
;
108 if (!haystack
|| !needle
|| (l
= strlen(needle
)) == 0)
112 for (; n
>= l
; ++pos
, --n
)
114 if (memeq(pos
, needle
, l
))
123 * Described in header.
125 char* translate(char *str
, const char *from
, const char *to
)
128 if (strlen(from
) != strlen(to
))
135 if ((match
= strchr(from
, *pos
)) != NULL
)
137 *pos
= to
[match
- from
];
145 * Described in header.
147 bool mkdir_p(const char *path
, mode_t mode
)
150 char *pos
, full
[PATH_MAX
];
152 if (!path
|| *path
== '\0')
156 len
= snprintf(full
, sizeof(full
)-1, "%s", path
);
157 if (len
< 0 || len
>= sizeof(full
)-1)
159 DBG1(DBG_LIB
, "path string %s too long", path
);
162 /* ensure that the path ends with a '/' */
163 if (full
[len
-1] != '/')
168 /* skip '/' at the beginning */
173 while ((pos
= strchr(pos
, '/')))
176 if (access(full
, F_OK
) < 0)
178 if (mkdir(full
, mode
) < 0)
180 DBG1(DBG_LIB
, "failed to create directory %s", full
);
190 ENUM(tty_color_names
, TTY_RESET
, TTY_BG_DEF
,
216 * Get the escape string for a given TTY color, empty string on non-tty FILE
218 char* tty_escape_get(int fd
, tty_escape_t escape
)
248 return enum_to_name(tty_color_names
, escape
);
249 /* warn if a excape code is missing */
255 * The size of the thread-specific error buffer
257 #define STRERROR_BUF_LEN 256
260 * Key to store thread-specific error buffer
262 static pthread_key_t strerror_buf_key
;
265 * Only initialize the key above once
267 static pthread_once_t strerror_buf_key_once
= PTHREAD_ONCE_INIT
;
270 * Create the key used for the thread-specific error buffer
272 static void create_strerror_buf_key()
274 pthread_key_create(&strerror_buf_key
, free
);
278 * Retrieve the error buffer assigned to the current thread (or create it)
280 static inline char *get_strerror_buf()
284 pthread_once(&strerror_buf_key_once
, create_strerror_buf_key
);
285 buf
= pthread_getspecific(strerror_buf_key
);
288 buf
= malloc(STRERROR_BUF_LEN
);
289 pthread_setspecific(strerror_buf_key
, buf
);
294 #ifdef HAVE_STRERROR_R
296 * Described in header.
298 const char *safe_strerror(int errnum
)
300 char *buf
= get_strerror_buf(), *msg
;
302 #ifdef STRERROR_R_CHAR_P
303 /* char* version which may or may not return the original buffer */
304 msg
= strerror_r(errnum
, buf
, STRERROR_BUF_LEN
);
306 /* int version returns 0 on success */
307 msg
= strerror_r(errnum
, buf
, STRERROR_BUF_LEN
) ?
"Unknown error" : buf
;
311 #else /* HAVE_STRERROR_R */
312 /* we actually wan't to call strerror(3) below */
315 * Described in header.
317 const char *safe_strerror(int errnum
)
319 static pthread_mutex_t mutex
= PTHREAD_MUTEX_INITIALIZER
;
320 char *buf
= get_strerror_buf();
322 /* use a mutex to ensure calling strerror(3) is thread-safe */
323 pthread_mutex_lock(&mutex
);
324 strncpy(buf
, strerror(errnum
), STRERROR_BUF_LEN
);
325 pthread_mutex_unlock(&mutex
);
326 buf
[STRERROR_BUF_LEN
- 1] = '\0';
329 #endif /* HAVE_STRERROR_R */
332 #ifndef HAVE_CLOSEFROM
334 * Described in header.
336 void closefrom(int lowfd
)
338 char fd_dir
[PATH_MAX
];
341 /* try to close only open file descriptors on Linux... */
342 len
= snprintf(fd_dir
, sizeof(fd_dir
), "/proc/%u/fd", getpid());
343 if (len
> 0 && len
< sizeof(fd_dir
) && access(fd_dir
, F_OK
) == 0)
345 enumerator_t
*enumerator
= enumerator_create_directory(fd_dir
);
349 while (enumerator
->enumerate(enumerator
, &rel
, NULL
, NULL
))
357 enumerator
->destroy(enumerator
);
362 /* ...fall back to closing all fds otherwise */
363 maxfd
= (int)sysconf(_SC_OPEN_MAX
);
368 for (fd
= lowfd
; fd
< maxfd
; fd
++)
373 #endif /* HAVE_CLOSEFROM */
376 * Return monotonic time
378 time_t time_monotonic(timeval_t
*tv
)
380 #if defined(HAVE_CLOCK_GETTIME) && \
381 (defined(HAVE_CONDATTR_CLOCK_MONOTONIC) || \
382 defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC))
383 /* as we use time_monotonic() for condvar operations, we use the
384 * monotonic time source only if it is also supported by pthread. */
387 if (clock_gettime(CLOCK_MONOTONIC
, &ts
) == 0)
391 tv
->tv_sec
= ts
.tv_sec
;
392 tv
->tv_usec
= ts
.tv_nsec
/ 1000;
396 #endif /* HAVE_CLOCK_GETTIME && (...) */
397 /* Fallback to non-monotonic timestamps:
398 * On MAC OS X, creating monotonic timestamps is rather difficult. We
399 * could use mach_absolute_time() and catch sleep/wakeup notifications.
400 * We stick to the simpler (non-monotonic) gettimeofday() for now.
401 * But keep in mind: we need the same time source here as in condvar! */
406 if (gettimeofday(tv
, NULL
) != 0)
407 { /* should actually never fail if passed pointers are valid */
440 status_t
return_failed()
448 status_t
return_success()
460 #ifndef HAVE_GCC_ATOMIC_OPERATIONS
463 * We use a single mutex for all refcount variables.
465 static pthread_mutex_t ref_mutex
= PTHREAD_MUTEX_INITIALIZER
;
470 refcount_t
ref_get(refcount_t
*ref
)
474 pthread_mutex_lock(&ref_mutex
);
476 pthread_mutex_unlock(&ref_mutex
);
484 bool ref_put(refcount_t
*ref
)
488 pthread_mutex_lock(&ref_mutex
);
489 more_refs
= --(*ref
) > 0;
490 pthread_mutex_unlock(&ref_mutex
);
495 * Single mutex for all compare and swap operations.
497 static pthread_mutex_t cas_mutex
= PTHREAD_MUTEX_INITIALIZER
;
500 * Compare and swap if equal to old value
502 #define _cas_impl(name, type) \
503 bool cas_##name(type *ptr, type oldval, type newval) \
506 pthread_mutex_lock(&cas_mutex); \
507 if ((swapped = (*ptr == oldval))) { *ptr = newval; } \
508 pthread_mutex_unlock(&cas_mutex); \
512 _cas_impl(bool, bool)
513 _cas_impl(ptr
, void*)
515 #endif /* HAVE_GCC_ATOMIC_OPERATIONS */
518 #ifdef HAVE_FMEMOPEN_FALLBACK
520 static int fmemread(chunk_t
*cookie
, char *buf
, int size
)
524 len
= min(size
, cookie
->len
);
525 memcpy(buf
, cookie
->ptr
, len
);
526 *cookie
= chunk_skip(*cookie
, len
);
531 static int fmemwrite(chunk_t
*cookie
, const char *buf
, int size
)
535 len
= min(size
, cookie
->len
);
536 memcpy(cookie
->ptr
, buf
, len
);
537 *cookie
= chunk_skip(*cookie
, len
);
542 static int fmemclose(void *cookie
)
548 FILE *fmemopen(void *buf
, size_t size
, const char *mode
)
557 return funopen(cookie
, (void*)fmemread
, (void*)fmemwrite
, NULL
, fmemclose
);
560 #endif /* FMEMOPEN fallback*/
563 * Described in header.
565 int time_printf_hook(printf_hook_data_t
*data
, printf_hook_spec_t
*spec
,
566 const void *const *args
)
568 static const char* months
[] = {
569 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
570 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
572 time_t *time
= *((time_t**)(args
[0]));
573 bool utc
= *((int*)(args
[1]));
576 if (*time
== UNDEFINED_TIME
)
578 return print_in_hook(data
, "--- -- --:--:--%s----",
579 utc ?
" UTC " : " ");
587 localtime_r(time
, &t
);
589 return print_in_hook(data
, "%s %02d %02d:%02d:%02d%s%04d",
590 months
[t
.tm_mon
], t
.tm_mday
, t
.tm_hour
, t
.tm_min
,
591 t
.tm_sec
, utc ?
" UTC " : " ", t
.tm_year
+ 1900);
595 * Described in header.
597 int time_delta_printf_hook(printf_hook_data_t
*data
, printf_hook_spec_t
*spec
,
598 const void *const *args
)
600 char* unit
= "second";
601 time_t *arg1
= *((time_t**)(args
[0]));
602 time_t *arg2
= *((time_t**)(args
[1]));
603 u_int64_t delta
= llabs(*arg1
- *arg2
);
605 if (delta
> 2 * 60 * 60 * 24)
607 delta
/= 60 * 60 * 24;
610 else if (delta
> 2 * 60 * 60)
615 else if (delta
> 2 * 60)
620 return print_in_hook(data
, "%" PRIu64
" %s%s", delta
, unit
,
621 (delta
== 1) ?
"" : "s");
625 * Number of bytes per line to dump raw data
627 #define BYTES_PER_LINE 16
629 static char hexdig_upper
[] = "0123456789ABCDEF";
632 * Described in header.
634 int mem_printf_hook(printf_hook_data_t
*data
,
635 printf_hook_spec_t
*spec
, const void *const *args
)
637 char *bytes
= *((void**)(args
[0]));
638 u_int len
= *((int*)(args
[1]));
640 char buffer
[BYTES_PER_LINE
* 3];
641 char ascii_buffer
[BYTES_PER_LINE
+ 1];
642 char *buffer_pos
= buffer
;
643 char *bytes_pos
= bytes
;
644 char *bytes_roof
= bytes
+ len
;
649 written
+= print_in_hook(data
, "=> %u bytes @ %p", len
, bytes
);
651 while (bytes_pos
< bytes_roof
)
653 *buffer_pos
++ = hexdig_upper
[(*bytes_pos
>> 4) & 0xF];
654 *buffer_pos
++ = hexdig_upper
[ *bytes_pos
& 0xF];
657 (*bytes_pos
> 31 && *bytes_pos
< 127) ?
*bytes_pos
: '.';
659 if (++bytes_pos
== bytes_roof
|| i
== BYTES_PER_LINE
)
661 int padding
= 3 * (BYTES_PER_LINE
- i
);
667 *buffer_pos
++ = '\0';
668 ascii_buffer
[i
] = '\0';
670 written
+= print_in_hook(data
, "\n%4d: %s %s",
671 line_start
, buffer
, ascii_buffer
);
674 line_start
+= BYTES_PER_LINE
;