]> git.ipfire.org Git - people/ms/strongswan.git/blame - src/libstrongswan/utils/utils.c
library: Change init/deinit order to allow utils to depend on threading
[people/ms/strongswan.git] / src / libstrongswan / utils / utils.c
CommitLineData
552cc11b 1/*
766141bc 2 * Copyright (C) 2008-2014 Tobias Brunner
552cc11b
MW
3 * Copyright (C) 2005-2008 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
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>.
10 *
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
14 * for more details.
552cc11b
MW
15 */
16
766141bc 17#define _GNU_SOURCE /* for memrchr */
6c20579a 18#include <sys/stat.h>
552cc11b 19#include <string.h>
552cc11b 20#include <stdio.h>
6c20579a 21#include <unistd.h>
876961cf 22#include <inttypes.h>
74b14b40 23#include <stdint.h>
d24a74c5 24#include <limits.h>
6c20579a 25#include <dirent.h>
f464d750 26#include <time.h>
552cc11b 27
f1c9653e
MW
28#include <library.h>
29#include <utils/debug.h>
30#include <utils/chunk.h>
31#include <collections/enumerator.h>
32#include <threading/spinlock.h>
552cc11b 33
a8809bb0 34ENUM(status_names, SUCCESS, NEED_MORE,
552cc11b
MW
35 "SUCCESS",
36 "FAILED",
37 "OUT_OF_RES",
38 "ALREADY_DONE",
39 "NOT_SUPPORTED",
40 "INVALID_ARG",
41 "NOT_FOUND",
42 "PARSE_ERROR",
43 "VERIFY_ERROR",
44 "INVALID_STATE",
45 "DESTROY_ME",
46 "NEED_MORE",
47);
48
552cc11b
MW
49/**
50 * Described in header.
51 */
01e43e31 52void memxor(u_int8_t dst[], u_int8_t src[], size_t n)
552cc11b 53{
01e43e31 54 int m, i;
7daf5226 55
01e43e31 56 /* byte wise XOR until dst aligned */
09846603 57 for (i = 0; (uintptr_t)&dst[i] % sizeof(long) && i < n; i++)
4fd233a7 58 {
01e43e31 59 dst[i] ^= src[i];
4fd233a7 60 }
01e43e31 61 /* try to use words if src shares an aligment with dst */
74b14b40 62 switch (((uintptr_t)&src[i] % sizeof(long)))
552cc11b 63 {
01e43e31
MW
64 case 0:
65 for (m = n - sizeof(long); i <= m; i += sizeof(long))
66 {
67 *(long*)&dst[i] ^= *(long*)&src[i];
68 }
69 break;
70 case sizeof(int):
71 for (m = n - sizeof(int); i <= m; i += sizeof(int))
72 {
73 *(int*)&dst[i] ^= *(int*)&src[i];
74 }
75 break;
76 case sizeof(short):
77 for (m = n - sizeof(short); i <= m; i += sizeof(short))
78 {
79 *(short*)&dst[i] ^= *(short*)&src[i];
80 }
81 break;
82 default:
83 break;
84 }
85 /* byte wise XOR of the rest */
86 for (; i < n; i++)
87 {
88 dst[i] ^= src[i];
552cc11b
MW
89 }
90}
91
ed678b52
MW
92/**
93 * Described in header.
94 */
95void memwipe_noinline(void *ptr, size_t n)
96{
97 memwipe_inline(ptr, n);
98}
99
81736d7d
TB
100/**
101 * Described in header.
102 */
103void *memstr(const void *haystack, const char *needle, size_t n)
104{
2ed241ae 105 const u_char *pos = haystack;
7b91011d
TB
106 size_t l;
107
108 if (!haystack || !needle || (l = strlen(needle)) == 0)
109 {
110 return NULL;
111 }
81736d7d
TB
112 for (; n >= l; ++pos, --n)
113 {
114 if (memeq(pos, needle, l))
115 {
116 return (void*)pos;
117 }
118 }
119 return NULL;
120}
121
2ed241ae
TB
122/**
123 * Described in header.
124 */
125void *utils_memrchr(const void *s, int c, size_t n)
126{
127 const u_char *pos;
128
129 if (!s || !n)
130 {
131 return NULL;
132 }
133
134 for (pos = s + n - 1; pos >= (u_char*)s; pos--)
135 {
136 if (*pos == (u_char)c)
137 {
138 return (void*)pos;
139 }
140 }
141 return NULL;
142}
143
d543d9ca
TB
144/**
145 * Described in header.
146 */
147char* translate(char *str, const char *from, const char *to)
148{
149 char *pos = str;
150 if (strlen(from) != strlen(to))
151 {
152 return str;
153 }
154 while (pos && *pos)
155 {
156 char *match;
157 if ((match = strchr(from, *pos)) != NULL)
158 {
159 *pos = to[match - from];
160 }
161 pos++;
162 }
163 return str;
ccb6758e
TB
164}
165
166/**
167 * Described in header.
168 */
169char* strreplace(const char *str, const char *search, const char *replace)
170{
171 size_t len, slen, rlen, count = 0;
172 char *res, *pos, *found, *dst;
173
174 if (!str || !*str || !search || !*search || !replace)
175 {
176 return (char*)str;
177 }
178 slen = strlen(search);
179 rlen = strlen(replace);
180 if (slen != rlen)
181 {
182 for (pos = (char*)str; (pos = strstr(pos, search)); pos += slen)
183 {
184 found = pos;
185 count++;
186 }
187 if (!count)
188 {
189 return (char*)str;
190 }
191 len = (found - str) + strlen(found) + count * (rlen - slen);
192 }
193 else
194 {
195 len = strlen(str);
196 }
197 found = strstr(str, search);
198 if (!found)
199 {
200 return (char*)str;
201 }
202 dst = res = malloc(len + 1);
203 pos = (char*)str;
204 do
205 {
206 len = found - pos;
207 memcpy(dst, pos, len);
208 dst += len;
209 memcpy(dst, replace, rlen);
210 dst += rlen;
211 pos = found + slen;
212 }
213 while ((found = strstr(pos, search)));
214 strcpy(dst, pos);
215 return res;
d543d9ca
TB
216}
217
766141bc
TB
218/**
219 * Described in header.
220 */
221char* path_dirname(const char *path)
222{
223 char *pos;
224
225 pos = path ? strrchr(path, '/') : NULL;
226
227 if (pos && !pos[1])
228 { /* if path ends with slashes we have to look beyond them */
229 while (pos > path && *pos == '/')
230 { /* skip trailing slashes */
231 pos--;
232 }
233 pos = memrchr(path, '/', pos - path + 1);
234 }
235 if (!pos)
236 {
237 return strdup(".");
238 }
239 while (pos > path && *pos == '/')
240 { /* skip superfluous slashes */
241 pos--;
242 }
243 return strndup(path, pos - path + 1);
244}
245
246/**
247 * Described in header.
248 */
249char* path_basename(const char *path)
250{
251 char *pos, *trail = NULL;
252
253 if (!path || !*path)
254 {
255 return strdup(".");
256 }
257 pos = strrchr(path, '/');
258 if (pos && !pos[1])
259 { /* if path ends with slashes we have to look beyond them */
260 while (pos > path && *pos == '/')
261 { /* skip trailing slashes */
262 pos--;
263 }
264 if (pos == path && *pos == '/')
265 { /* contains only slashes */
266 return strdup("/");
267 }
268 trail = pos + 1;
269 pos = memrchr(path, '/', trail - path);
270 }
271 pos = pos ? pos + 1 : (char*)path;
272 return trail ? strndup(pos, trail - pos) : strdup(pos);
273}
274
6c20579a
TB
275/**
276 * Described in header.
277 */
278bool mkdir_p(const char *path, mode_t mode)
279{
fc1afcc8 280 int len;
6c20579a
TB
281 char *pos, full[PATH_MAX];
282 pos = full;
283 if (!path || *path == '\0')
284 {
285 return TRUE;
286 }
287 len = snprintf(full, sizeof(full)-1, "%s", path);
288 if (len < 0 || len >= sizeof(full)-1)
289 {
8b0e0910 290 DBG1(DBG_LIB, "path string %s too long", path);
6c20579a
TB
291 return FALSE;
292 }
293 /* ensure that the path ends with a '/' */
294 if (full[len-1] != '/')
295 {
296 full[len++] = '/';
297 full[len] = '\0';
298 }
299 /* skip '/' at the beginning */
300 while (*pos == '/')
301 {
302 pos++;
303 }
304 while ((pos = strchr(pos, '/')))
305 {
306 *pos = '\0';
307 if (access(full, F_OK) < 0)
308 {
a3f7dfc1
MW
309#ifdef WIN32
310 if (_mkdir(full) < 0)
311#else
6c20579a 312 if (mkdir(full, mode) < 0)
a3f7dfc1 313#endif
6c20579a 314 {
8b0e0910 315 DBG1(DBG_LIB, "failed to create directory %s", full);
6c20579a
TB
316 return FALSE;
317 }
318 }
319 *pos = '/';
320 pos++;
321 }
322 return TRUE;
323}
324
4d174272
MW
325ENUM(tty_color_names, TTY_RESET, TTY_BG_DEF,
326 "\e[0m",
327 "\e[1m",
328 "\e[4m",
329 "\e[5m",
330 "\e[30m",
331 "\e[31m",
332 "\e[32m",
333 "\e[33m",
334 "\e[34m",
335 "\e[35m",
336 "\e[36m",
337 "\e[37m",
338 "\e[39m",
339 "\e[40m",
340 "\e[41m",
341 "\e[42m",
342 "\e[43m",
343 "\e[44m",
344 "\e[45m",
345 "\e[46m",
346 "\e[47m",
347 "\e[49m",
348);
349
350/**
351 * Get the escape string for a given TTY color, empty string on non-tty FILE
352 */
353char* tty_escape_get(int fd, tty_escape_t escape)
354{
355 if (!isatty(fd))
356 {
357 return "";
358 }
359 switch (escape)
360 {
361 case TTY_RESET:
362 case TTY_BOLD:
363 case TTY_UNDERLINE:
364 case TTY_BLINKING:
1f2b8c8c
MW
365#ifdef WIN32
366 return "";
367#endif
4d174272
MW
368 case TTY_FG_BLACK:
369 case TTY_FG_RED:
370 case TTY_FG_GREEN:
371 case TTY_FG_YELLOW:
372 case TTY_FG_BLUE:
373 case TTY_FG_MAGENTA:
374 case TTY_FG_CYAN:
375 case TTY_FG_WHITE:
376 case TTY_FG_DEF:
377 case TTY_BG_BLACK:
378 case TTY_BG_RED:
379 case TTY_BG_GREEN:
380 case TTY_BG_YELLOW:
381 case TTY_BG_BLUE:
382 case TTY_BG_MAGENTA:
383 case TTY_BG_CYAN:
384 case TTY_BG_WHITE:
385 case TTY_BG_DEF:
386 return enum_to_name(tty_color_names, escape);
1f2b8c8c 387 /* warn if a escape code is missing */
4d174272
MW
388 }
389 return "";
390}
2a595276 391
9a8fdc15
TB
392#ifndef HAVE_CLOSEFROM
393/**
394 * Described in header.
395 */
396void closefrom(int lowfd)
397{
5051bd23
TB
398 char fd_dir[PATH_MAX];
399 int maxfd, fd, len;
400
401 /* try to close only open file descriptors on Linux... */
402 len = snprintf(fd_dir, sizeof(fd_dir), "/proc/%u/fd", getpid());
4a4cf41b 403 if (len > 0 && len < sizeof(fd_dir) && access(fd_dir, F_OK) == 0)
5051bd23
TB
404 {
405 enumerator_t *enumerator = enumerator_create_directory(fd_dir);
406 if (enumerator)
407 {
68fcf917 408 char *rel;
5051bd23
TB
409 while (enumerator->enumerate(enumerator, &rel, NULL, NULL))
410 {
411 fd = atoi(rel);
412 if (fd >= lowfd)
413 {
414 close(fd);
415 }
416 }
417 enumerator->destroy(enumerator);
418 return;
419 }
420 }
421
422 /* ...fall back to closing all fds otherwise */
d3c30b35
MW
423#ifdef WIN32
424 maxfd = _getmaxstdio();
425#else
9a8fdc15 426 maxfd = (int)sysconf(_SC_OPEN_MAX);
d3c30b35 427#endif
9a8fdc15
TB
428 if (maxfd < 0)
429 {
430 maxfd = 256;
431 }
432 for (fd = lowfd; fd < maxfd; fd++)
433 {
434 close(fd);
435 }
436}
437#endif /* HAVE_CLOSEFROM */
438
3f310c0d
MW
439/**
440 * Return monotonic time
441 */
442time_t time_monotonic(timeval_t *tv)
443{
b2944d71
TB
444#if defined(HAVE_CLOCK_GETTIME) && \
445 (defined(HAVE_CONDATTR_CLOCK_MONOTONIC) || \
446 defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC))
3d5818ec
MW
447 /* as we use time_monotonic() for condvar operations, we use the
448 * monotonic time source only if it is also supported by pthread. */
3f310c0d 449 timespec_t ts;
7daf5226 450
3f310c0d
MW
451 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
452 {
453 if (tv)
454 {
455 tv->tv_sec = ts.tv_sec;
456 tv->tv_usec = ts.tv_nsec / 1000;
457 }
458 return ts.tv_sec;
459 }
b2944d71 460#endif /* HAVE_CLOCK_GETTIME && (...) */
3f310c0d
MW
461 /* Fallback to non-monotonic timestamps:
462 * On MAC OS X, creating monotonic timestamps is rather difficult. We
463 * could use mach_absolute_time() and catch sleep/wakeup notifications.
3d5818ec
MW
464 * We stick to the simpler (non-monotonic) gettimeofday() for now.
465 * But keep in mind: we need the same time source here as in condvar! */
3f310c0d
MW
466 if (!tv)
467 {
468 return time(NULL);
469 }
470 if (gettimeofday(tv, NULL) != 0)
471 { /* should actually never fail if passed pointers are valid */
472 return -1;
473 }
474 return tv->tv_sec;
475}
476
081ae2eb
MW
477/**
478 * return null
479 */
480void *return_null()
481{
482 return NULL;
483}
484
da17b016
MW
485/**
486 * returns TRUE
487 */
488bool return_true()
489{
490 return TRUE;
491}
492
493/**
494 * returns FALSE
495 */
496bool return_false()
497{
498 return FALSE;
499}
500
502edf42
MW
501/**
502 * returns FAILED
503 */
504status_t return_failed()
505{
506 return FAILED;
507}
508
4755ab50
MW
509/**
510 * returns SUCCESS
511 */
512status_t return_success()
513{
514 return SUCCESS;
515}
516
233b853d
MW
517/**
518 * nop operation
519 */
520void nop()
521{
522}
523
0f603d42 524#if !defined(HAVE_GCC_ATOMIC_OPERATIONS) && !defined(HAVE_GCC_SYNC_OPERATIONS)
efd0fe21 525
552cc11b 526/**
f1c9653e 527 * Spinlock for ref_get/put
552cc11b 528 */
f1c9653e 529static spinlock_t *ref_lock;
552cc11b
MW
530
531/**
efd0fe21 532 * Increase refcount
552cc11b 533 */
3160b92a 534refcount_t ref_get(refcount_t *ref)
552cc11b 535{
3160b92a
MW
536 refcount_t current;
537
f1c9653e 538 ref_lock->lock(ref_lock);
3160b92a 539 current = ++(*ref);
f1c9653e
MW
540 ref_lock->unlock(ref_lock);
541
3160b92a 542 return current;
552cc11b
MW
543}
544
545/**
efd0fe21 546 * Decrease refcount
552cc11b
MW
547 */
548bool ref_put(refcount_t *ref)
549{
550 bool more_refs;
7daf5226 551
f1c9653e 552 ref_lock->lock(ref_lock);
21f411b8 553 more_refs = --(*ref) > 0;
f1c9653e 554 ref_lock->unlock(ref_lock);
552cc11b
MW
555 return !more_refs;
556}
5317dd68 557
efedd0d2
TB
558/**
559 * Current refcount
560 */
561refcount_t ref_cur(refcount_t *ref)
562{
563 refcount_t current;
564
f1c9653e 565 ref_lock->lock(ref_lock);
efedd0d2 566 current = *ref;
f1c9653e
MW
567 ref_lock->unlock(ref_lock);
568
efedd0d2
TB
569 return current;
570}
571
5317dd68 572/**
f1c9653e 573 * Spinlock for all compare and swap operations.
5317dd68 574 */
f1c9653e 575static spinlock_t *cas_lock;
5317dd68
TB
576
577/**
578 * Compare and swap if equal to old value
579 */
580#define _cas_impl(name, type) \
581bool cas_##name(type *ptr, type oldval, type newval) \
582{ \
583 bool swapped; \
f1c9653e 584 cas_lock->lock(cas_lock); \
5317dd68 585 if ((swapped = (*ptr == oldval))) { *ptr = newval; } \
f1c9653e 586 cas_lock->unlock(cas_lock); \
5317dd68
TB
587 return swapped; \
588}
589
590_cas_impl(bool, bool)
591_cas_impl(ptr, void*)
592
0f603d42 593#endif /* !HAVE_GCC_ATOMIC_OPERATIONS && !HAVE_GCC_SYNC_OPERATIONS */
552cc11b 594
2077d996 595
9df621d2 596#ifdef HAVE_FMEMOPEN_FALLBACK
2077d996
MW
597
598static int fmemread(chunk_t *cookie, char *buf, int size)
599{
600 int len;
601
602 len = min(size, cookie->len);
603 memcpy(buf, cookie->ptr, len);
604 *cookie = chunk_skip(*cookie, len);
605
606 return len;
607}
608
609static int fmemwrite(chunk_t *cookie, const char *buf, int size)
610{
611 int len;
612
613 len = min(size, cookie->len);
614 memcpy(cookie->ptr, buf, len);
615 *cookie = chunk_skip(*cookie, len);
616
617 return len;
618}
619
620static int fmemclose(void *cookie)
621{
622 free(cookie);
623 return 0;
624}
625
626FILE *fmemopen(void *buf, size_t size, const char *mode)
627{
628 chunk_t *cookie;
629
630 INIT(cookie,
631 .ptr = buf,
632 .len = size,
633 );
634
635 return funopen(cookie, (void*)fmemread, (void*)fmemwrite, NULL, fmemclose);
636}
637
638#endif /* FMEMOPEN fallback*/
639
f1c9653e
MW
640/**
641 * See header
642 */
643void utils_init()
644{
645#ifdef WIN32
646 windows_init();
647#endif
648
649#if !defined(HAVE_GCC_ATOMIC_OPERATIONS) && !defined(HAVE_GCC_SYNC_OPERATIONS)
650 ref_lock = spinlock_create();
651 cas_lock = spinlock_create();
652#endif
653
654 strerror_init();
655}
656
657/**
658 * See header
659 */
660void utils_deinit()
661{
662#ifdef WIN32
663 windows_deinit();
664#endif
665
666#if !defined(HAVE_GCC_ATOMIC_OPERATIONS) && !defined(HAVE_GCC_SYNC_OPERATIONS)
667 ref_lock->destroy(ref_lock);
668 cas_lock->destroy(cas_lock);
669#endif
670
671 strerror_deinit();
672}
673
552cc11b 674/**
d25ce370 675 * Described in header.
552cc11b 676 */
1b40b74d 677int time_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
d25ce370 678 const void *const *args)
552cc11b
MW
679{
680 static const char* months[] = {
681 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
682 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
683 };
684 time_t *time = *((time_t**)(args[0]));
13f2d3a2 685 bool utc = *((int*)(args[1]));
8f129319 686 struct tm t, *ret = NULL;
7daf5226 687
8f129319 688 if (*time != UNDEFINED_TIME)
552cc11b 689 {
8f129319
MW
690 if (utc)
691 {
692 ret = gmtime_r(time, &t);
693 }
694 else
695 {
696 ret = localtime_r(time, &t);
697 }
552cc11b 698 }
8f129319 699 if (ret == NULL)
552cc11b 700 {
8f129319
MW
701 return print_in_hook(data, "--- -- --:--:--%s----",
702 utc ? " UTC " : " ");
552cc11b 703 }
1b40b74d 704 return print_in_hook(data, "%s %02d %02d:%02d:%02d%s%04d",
d25ce370
TB
705 months[t.tm_mon], t.tm_mday, t.tm_hour, t.tm_min,
706 t.tm_sec, utc ? " UTC " : " ", t.tm_year + 1900);
552cc11b
MW
707}
708
709/**
d25ce370 710 * Described in header.
552cc11b 711 */
1b40b74d 712int time_delta_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
d25ce370 713 const void *const *args)
552cc11b
MW
714{
715 char* unit = "second";
d25ce370
TB
716 time_t *arg1 = *((time_t**)(args[0]));
717 time_t *arg2 = *((time_t**)(args[1]));
876961cf 718 u_int64_t delta = llabs(*arg1 - *arg2);
7daf5226 719
552cc11b
MW
720 if (delta > 2 * 60 * 60 * 24)
721 {
722 delta /= 60 * 60 * 24;
723 unit = "day";
724 }
725 else if (delta > 2 * 60 * 60)
726 {
727 delta /= 60 * 60;
728 unit = "hour";
729 }
730 else if (delta > 2 * 60)
731 {
732 delta /= 60;
733 unit = "minute";
734 }
1b40b74d 735 return print_in_hook(data, "%" PRIu64 " %s%s", delta, unit,
876961cf 736 (delta == 1) ? "" : "s");
552cc11b
MW
737}
738
739/**
740 * Number of bytes per line to dump raw data
741 */
742#define BYTES_PER_LINE 16
743
744static char hexdig_upper[] = "0123456789ABCDEF";
745
746/**
d25ce370 747 * Described in header.
552cc11b 748 */
1b40b74d 749int mem_printf_hook(printf_hook_data_t *data,
d25ce370 750 printf_hook_spec_t *spec, const void *const *args)
552cc11b
MW
751{
752 char *bytes = *((void**)(args[0]));
817ab8a8 753 u_int len = *((int*)(args[1]));
7daf5226 754
552cc11b
MW
755 char buffer[BYTES_PER_LINE * 3];
756 char ascii_buffer[BYTES_PER_LINE + 1];
757 char *buffer_pos = buffer;
758 char *bytes_pos = bytes;
759 char *bytes_roof = bytes + len;
760 int line_start = 0;
761 int i = 0;
762 int written = 0;
7daf5226 763
1b40b74d 764 written += print_in_hook(data, "=> %u bytes @ %p", len, bytes);
7daf5226 765
552cc11b
MW
766 while (bytes_pos < bytes_roof)
767 {
768 *buffer_pos++ = hexdig_upper[(*bytes_pos >> 4) & 0xF];
769 *buffer_pos++ = hexdig_upper[ *bytes_pos & 0xF];
770
771 ascii_buffer[i++] =
772 (*bytes_pos > 31 && *bytes_pos < 127) ? *bytes_pos : '.';
773
7daf5226 774 if (++bytes_pos == bytes_roof || i == BYTES_PER_LINE)
552cc11b
MW
775 {
776 int padding = 3 * (BYTES_PER_LINE - i);
7daf5226 777
552cc11b
MW
778 while (padding--)
779 {
780 *buffer_pos++ = ' ';
781 }
782 *buffer_pos++ = '\0';
783 ascii_buffer[i] = '\0';
7daf5226 784
1b40b74d 785 written += print_in_hook(data, "\n%4d: %s %s",
323f9f99 786 line_start, buffer, ascii_buffer);
7daf5226 787
552cc11b
MW
788 buffer_pos = buffer;
789 line_start += BYTES_PER_LINE;
790 i = 0;
791 }
792 else
793 {
794 *buffer_pos++ = ' ';
795 }
796 }
797 return written;
798}