utils: Move thread-safe strerror replacement to a separate file
[strongswan.git] / src / libstrongswan / utils / utils / strerror.c
1 /*
2 * Copyright (C) 2012-2014 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
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; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include <stdlib.h>
17 #include <string.h>
18 #include <pthread.h>
19
20 #include "strerror.h"
21
22 /**
23 * The size of the thread-specific error buffer
24 */
25 #define STRERROR_BUF_LEN 256
26
27 /**
28 * Key to store thread-specific error buffer
29 */
30 static pthread_key_t strerror_buf_key;
31
32 /**
33 * Only initialize the key above once
34 */
35 static pthread_once_t strerror_buf_key_once = PTHREAD_ONCE_INIT;
36
37 /**
38 * Create the key used for the thread-specific error buffer
39 */
40 static void create_strerror_buf_key()
41 {
42 pthread_key_create(&strerror_buf_key, free);
43 }
44
45 /**
46 * Retrieve the error buffer assigned to the current thread (or create it)
47 */
48 static inline char *get_strerror_buf()
49 {
50 char *buf;
51
52 pthread_once(&strerror_buf_key_once, create_strerror_buf_key);
53 buf = pthread_getspecific(strerror_buf_key);
54 if (!buf)
55 {
56 buf = malloc(STRERROR_BUF_LEN);
57 pthread_setspecific(strerror_buf_key, buf);
58 }
59 return buf;
60 }
61
62 #ifdef HAVE_STRERROR_R
63 /*
64 * Described in header.
65 */
66 const char *strerror_safe(int errnum)
67 {
68 char *buf = get_strerror_buf(), *msg;
69
70 #ifdef STRERROR_R_CHAR_P
71 /* char* version which may or may not return the original buffer */
72 msg = strerror_r(errnum, buf, STRERROR_BUF_LEN);
73 #else
74 /* int version returns 0 on success */
75 msg = strerror_r(errnum, buf, STRERROR_BUF_LEN) ? "Unknown error" : buf;
76 #endif
77 return msg;
78 }
79 #else /* HAVE_STRERROR_R */
80 /* we actually wan't to call strerror(3) below */
81 #undef strerror
82 /*
83 * Described in header.
84 */
85 const char *strerror_safe(int errnum)
86 {
87 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
88 char *buf = get_strerror_buf();
89
90 /* use a mutex to ensure calling strerror(3) is thread-safe */
91 pthread_mutex_lock(&mutex);
92 strncpy(buf, strerror(errnum), STRERROR_BUF_LEN);
93 pthread_mutex_unlock(&mutex);
94 buf[STRERROR_BUF_LEN - 1] = '\0';
95 return buf;
96 }
97 #endif /* HAVE_STRERROR_R */