]>
git.ipfire.org Git - people/ms/strongswan.git/blob - src/libstrongswan/utils/utils.c
2 * Copyright (C) 2008-2014 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
17 #define _GNU_SOURCE /* for memrchr */
19 /* for GetTickCount64, Windows 7 */
20 # define _WIN32_WINNT 0x0601
39 #include <utils/debug.h>
40 #include <utils/chunk.h>
41 #include <collections/enumerator.h>
42 #include <threading/spinlock.h>
43 #include <threading/mutex.h>
44 #include <threading/condvar.h>
46 ENUM(status_names
, SUCCESS
, NEED_MORE
,
62 * Described in header.
64 void memxor(u_int8_t dst
[], u_int8_t src
[], size_t n
)
68 /* byte wise XOR until dst aligned */
69 for (i
= 0; (uintptr_t)&dst
[i
] % sizeof(long) && i
< n
; i
++)
73 /* try to use words if src shares an aligment with dst */
74 switch (((uintptr_t)&src
[i
] % sizeof(long)))
77 for (m
= n
- sizeof(long); i
<= m
; i
+= sizeof(long))
79 *(long*)&dst
[i
] ^= *(long*)&src
[i
];
83 for (m
= n
- sizeof(int); i
<= m
; i
+= sizeof(int))
85 *(int*)&dst
[i
] ^= *(int*)&src
[i
];
89 for (m
= n
- sizeof(short); i
<= m
; i
+= sizeof(short))
91 *(short*)&dst
[i
] ^= *(short*)&src
[i
];
97 /* byte wise XOR of the rest */
105 * Described in header.
107 void memwipe_noinline(void *ptr
, size_t n
)
109 memwipe_inline(ptr
, n
);
113 * Described in header.
115 void *memstr(const void *haystack
, const char *needle
, size_t n
)
117 const u_char
*pos
= haystack
;
120 if (!haystack
|| !needle
|| (l
= strlen(needle
)) == 0)
124 for (; n
>= l
; ++pos
, --n
)
126 if (memeq(pos
, needle
, l
))
135 * Described in header.
137 void *utils_memrchr(const void *s
, int c
, size_t n
)
146 for (pos
= s
+ n
- 1; pos
>= (u_char
*)s
; pos
--)
148 if (*pos
== (u_char
)c
)
157 * Described in header.
159 char* translate(char *str
, const char *from
, const char *to
)
162 if (strlen(from
) != strlen(to
))
169 if ((match
= strchr(from
, *pos
)) != NULL
)
171 *pos
= to
[match
- from
];
179 * Described in header.
181 char* strreplace(const char *str
, const char *search
, const char *replace
)
183 size_t len
, slen
, rlen
, count
= 0;
184 char *res
, *pos
, *found
, *dst
;
186 if (!str
|| !*str
|| !search
|| !*search
|| !replace
)
190 slen
= strlen(search
);
191 rlen
= strlen(replace
);
194 for (pos
= (char*)str
; (pos
= strstr(pos
, search
)); pos
+= slen
)
203 len
= (found
- str
) + strlen(found
) + count
* (rlen
- slen
);
209 found
= strstr(str
, search
);
214 dst
= res
= malloc(len
+ 1);
219 memcpy(dst
, pos
, len
);
221 memcpy(dst
, replace
, rlen
);
225 while ((found
= strstr(pos
, search
)));
233 * Flag to indicate signaled wait_sigint()
235 static bool sigint_signaled
= FALSE
;
238 * Condvar to wait in wait_sigint()
240 static condvar_t
*sigint_cond
;
243 * Mutex to check signaling()
245 static mutex_t
*sigint_mutex
;
248 * Control handler to catch ^C
250 static BOOL
handler(DWORD dwCtrlType
)
255 case CTRL_BREAK_EVENT
:
256 case CTRL_CLOSE_EVENT
:
257 sigint_mutex
->lock(sigint_mutex
);
258 sigint_signaled
= TRUE
;
259 sigint_cond
->signal(sigint_cond
);
260 sigint_mutex
->unlock(sigint_mutex
);
272 SetConsoleCtrlHandler(handler
, TRUE
);
274 sigint_mutex
= mutex_create(MUTEX_TYPE_DEFAULT
);
275 sigint_cond
= condvar_create(CONDVAR_TYPE_DEFAULT
);
277 sigint_mutex
->lock(sigint_mutex
);
278 while (!sigint_signaled
)
280 sigint_cond
->wait(sigint_cond
, sigint_mutex
);
282 sigint_mutex
->unlock(sigint_mutex
);
284 sigint_mutex
->destroy(sigint_mutex
);
285 sigint_cond
->destroy(sigint_cond
);
299 sigaddset(&set
, SIGINT
);
300 sigaddset(&set
, SIGTERM
);
302 sigprocmask(SIG_BLOCK
, &set
, NULL
);
309 * Described in header.
311 char* path_dirname(const char *path
)
315 pos
= path
? strrchr(path
, DIRECTORY_SEPARATOR
[0]) : NULL
;
318 { /* if path ends with slashes we have to look beyond them */
319 while (pos
> path
&& *pos
== DIRECTORY_SEPARATOR
[0])
320 { /* skip trailing slashes */
323 pos
= memrchr(path
, DIRECTORY_SEPARATOR
[0], pos
- path
+ 1);
328 if (path
&& strlen(path
))
330 if ((isalpha(path
[0]) && path
[1] == ':'))
331 { /* if just a drive letter given, return that as dirname */
332 return chunk_clone(chunk_from_chars(path
[0], ':', 0)).ptr
;
338 while (pos
> path
&& *pos
== DIRECTORY_SEPARATOR
[0])
339 { /* skip superfluous slashes */
342 return strndup(path
, pos
- path
+ 1);
346 * Described in header.
348 char* path_basename(const char *path
)
350 char *pos
, *trail
= NULL
;
356 pos
= strrchr(path
, DIRECTORY_SEPARATOR
[0]);
358 { /* if path ends with slashes we have to look beyond them */
359 while (pos
> path
&& *pos
== DIRECTORY_SEPARATOR
[0])
360 { /* skip trailing slashes */
363 if (pos
== path
&& *pos
== DIRECTORY_SEPARATOR
[0])
364 { /* contains only slashes */
365 return strdup(DIRECTORY_SEPARATOR
);
368 pos
= memrchr(path
, DIRECTORY_SEPARATOR
[0], trail
- path
);
370 pos
= pos
? pos
+ 1 : (char*)path
;
371 return trail
? strndup(pos
, trail
- pos
) : strdup(pos
);
375 * Described in header.
377 bool path_absolute(const char *path
)
384 if (strpfx(path
, "\\\\"))
388 if (strlen(path
) && isalpha(path
[0]) && path
[1] == ':')
393 if (path
[0] == DIRECTORY_SEPARATOR
[0])
402 * Described in header.
404 bool mkdir_p(const char *path
, mode_t mode
)
407 char *pos
, full
[PATH_MAX
];
409 if (!path
|| *path
== '\0')
413 len
= snprintf(full
, sizeof(full
)-1, "%s", path
);
414 if (len
< 0 || len
>= sizeof(full
)-1)
416 DBG1(DBG_LIB
, "path string %s too long", path
);
419 /* ensure that the path ends with a '/' */
420 if (full
[len
-1] != '/')
425 /* skip '/' at the beginning */
430 while ((pos
= strchr(pos
, '/')))
433 if (access(full
, F_OK
) < 0)
436 if (_mkdir(full
) < 0)
438 if (mkdir(full
, mode
) < 0)
441 DBG1(DBG_LIB
, "failed to create directory %s", full
);
451 ENUM(tty_color_names
, TTY_RESET
, TTY_BG_DEF
,
477 * Get the escape string for a given TTY color, empty string on non-tty FILE
479 char* tty_escape_get(int fd
, tty_escape_t escape
)
512 return enum_to_name(tty_color_names
, escape
);
513 /* warn if a escape code is missing */
518 #ifndef HAVE_CLOSEFROM
520 * Described in header.
522 void closefrom(int lowfd
)
524 char fd_dir
[PATH_MAX
];
527 /* try to close only open file descriptors on Linux... */
528 len
= snprintf(fd_dir
, sizeof(fd_dir
), "/proc/%u/fd", getpid());
529 if (len
> 0 && len
< sizeof(fd_dir
) && access(fd_dir
, F_OK
) == 0)
531 enumerator_t
*enumerator
= enumerator_create_directory(fd_dir
);
535 while (enumerator
->enumerate(enumerator
, &rel
, NULL
, NULL
))
543 enumerator
->destroy(enumerator
);
548 /* ...fall back to closing all fds otherwise */
550 maxfd
= _getmaxstdio();
552 maxfd
= (int)sysconf(_SC_OPEN_MAX
);
558 for (fd
= lowfd
; fd
< maxfd
; fd
++)
563 #endif /* HAVE_CLOSEFROM */
566 * Return monotonic time
568 time_t time_monotonic(timeval_t
*tv
)
574 ms
= GetTickCount64();
579 tv
->tv_usec
= (ms
- (s
* 1000)) * 1000;
583 #if defined(HAVE_CLOCK_GETTIME) && \
584 (defined(HAVE_CONDATTR_CLOCK_MONOTONIC) || \
585 defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC))
586 /* as we use time_monotonic() for condvar operations, we use the
587 * monotonic time source only if it is also supported by pthread. */
590 if (clock_gettime(CLOCK_MONOTONIC
, &ts
) == 0)
594 tv
->tv_sec
= ts
.tv_sec
;
595 tv
->tv_usec
= ts
.tv_nsec
/ 1000;
599 #endif /* HAVE_CLOCK_GETTIME && (...) */
600 /* Fallback to non-monotonic timestamps:
601 * On MAC OS X, creating monotonic timestamps is rather difficult. We
602 * could use mach_absolute_time() and catch sleep/wakeup notifications.
603 * We stick to the simpler (non-monotonic) gettimeofday() for now.
604 * But keep in mind: we need the same time source here as in condvar! */
609 if (gettimeofday(tv
, NULL
) != 0)
610 { /* should actually never fail if passed pointers are valid */
644 status_t
return_failed()
652 status_t
return_success()
664 #if !defined(HAVE_GCC_ATOMIC_OPERATIONS) && !defined(HAVE_GCC_SYNC_OPERATIONS)
667 * Spinlock for ref_get/put
669 static spinlock_t
*ref_lock
;
674 refcount_t
ref_get(refcount_t
*ref
)
678 ref_lock
->lock(ref_lock
);
680 ref_lock
->unlock(ref_lock
);
688 bool ref_put(refcount_t
*ref
)
692 ref_lock
->lock(ref_lock
);
693 more_refs
= --(*ref
) > 0;
694 ref_lock
->unlock(ref_lock
);
701 refcount_t
ref_cur(refcount_t
*ref
)
705 ref_lock
->lock(ref_lock
);
707 ref_lock
->unlock(ref_lock
);
713 * Spinlock for all compare and swap operations.
715 static spinlock_t
*cas_lock
;
718 * Compare and swap if equal to old value
720 #define _cas_impl(name, type) \
721 bool cas_##name(type *ptr, type oldval, type newval) \
724 cas_lock->lock(cas_lock); \
725 if ((swapped = (*ptr == oldval))) { *ptr = newval; } \
726 cas_lock->unlock(cas_lock); \
730 _cas_impl(bool, bool)
731 _cas_impl(ptr
, void*)
733 #endif /* !HAVE_GCC_ATOMIC_OPERATIONS && !HAVE_GCC_SYNC_OPERATIONS */
736 #ifdef HAVE_FMEMOPEN_FALLBACK
738 static int fmemread(chunk_t
*cookie
, char *buf
, int size
)
742 len
= min(size
, cookie
->len
);
743 memcpy(buf
, cookie
->ptr
, len
);
744 *cookie
= chunk_skip(*cookie
, len
);
749 static int fmemwrite(chunk_t
*cookie
, const char *buf
, int size
)
753 len
= min(size
, cookie
->len
);
754 memcpy(cookie
->ptr
, buf
, len
);
755 *cookie
= chunk_skip(*cookie
, len
);
760 static int fmemclose(void *cookie
)
766 FILE *fmemopen(void *buf
, size_t size
, const char *mode
)
775 return funopen(cookie
, (void*)fmemread
, (void*)fmemwrite
, NULL
, fmemclose
);
778 #endif /* FMEMOPEN fallback*/
789 #if !defined(HAVE_GCC_ATOMIC_OPERATIONS) && !defined(HAVE_GCC_SYNC_OPERATIONS)
790 ref_lock
= spinlock_create();
791 cas_lock
= spinlock_create();
806 #if !defined(HAVE_GCC_ATOMIC_OPERATIONS) && !defined(HAVE_GCC_SYNC_OPERATIONS)
807 ref_lock
->destroy(ref_lock
);
808 cas_lock
->destroy(cas_lock
);
815 * Described in header.
817 int time_printf_hook(printf_hook_data_t
*data
, printf_hook_spec_t
*spec
,
818 const void *const *args
)
820 static const char* months
[] = {
821 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
822 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
824 time_t *time
= *((time_t**)(args
[0]));
825 bool utc
= *((int*)(args
[1]));
826 struct tm t
, *ret
= NULL
;
828 if (*time
!= UNDEFINED_TIME
)
832 ret
= gmtime_r(time
, &t
);
836 ret
= localtime_r(time
, &t
);
841 return print_in_hook(data
, "--- -- --:--:--%s----",
842 utc
? " UTC " : " ");
844 return print_in_hook(data
, "%s %02d %02d:%02d:%02d%s%04d",
845 months
[t
.tm_mon
], t
.tm_mday
, t
.tm_hour
, t
.tm_min
,
846 t
.tm_sec
, utc
? " UTC " : " ", t
.tm_year
+ 1900);
850 * Described in header.
852 int time_delta_printf_hook(printf_hook_data_t
*data
, printf_hook_spec_t
*spec
,
853 const void *const *args
)
855 char* unit
= "second";
856 time_t *arg1
= *((time_t**)(args
[0]));
857 time_t *arg2
= *((time_t**)(args
[1]));
858 u_int64_t delta
= llabs(*arg1
- *arg2
);
860 if (delta
> 2 * 60 * 60 * 24)
862 delta
/= 60 * 60 * 24;
865 else if (delta
> 2 * 60 * 60)
870 else if (delta
> 2 * 60)
875 return print_in_hook(data
, "%" PRIu64
" %s%s", delta
, unit
,
876 (delta
== 1) ? "" : "s");
880 * Number of bytes per line to dump raw data
882 #define BYTES_PER_LINE 16
884 static char hexdig_upper
[] = "0123456789ABCDEF";
887 * Described in header.
889 int mem_printf_hook(printf_hook_data_t
*data
,
890 printf_hook_spec_t
*spec
, const void *const *args
)
892 char *bytes
= *((void**)(args
[0]));
893 u_int len
= *((int*)(args
[1]));
895 char buffer
[BYTES_PER_LINE
* 3];
896 char ascii_buffer
[BYTES_PER_LINE
+ 1];
897 char *buffer_pos
= buffer
;
898 char *bytes_pos
= bytes
;
899 char *bytes_roof
= bytes
+ len
;
904 written
+= print_in_hook(data
, "=> %u bytes @ %p", len
, bytes
);
906 while (bytes_pos
< bytes_roof
)
908 *buffer_pos
++ = hexdig_upper
[(*bytes_pos
>> 4) & 0xF];
909 *buffer_pos
++ = hexdig_upper
[ *bytes_pos
& 0xF];
912 (*bytes_pos
> 31 && *bytes_pos
< 127) ? *bytes_pos
: '.';
914 if (++bytes_pos
== bytes_roof
|| i
== BYTES_PER_LINE
)
916 int padding
= 3 * (BYTES_PER_LINE
- i
);
922 *buffer_pos
++ = '\0';
923 ascii_buffer
[i
] = '\0';
925 written
+= print_in_hook(data
, "\n%4d: %s %s",
926 line_start
, buffer
, ascii_buffer
);
929 line_start
+= BYTES_PER_LINE
;