/src/strongswan/src/libstrongswan/utils/utils/strerror.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2012-2014 Tobias Brunner |
3 | | * |
4 | | * Copyright (C) secunet Security Networks AG |
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. |
15 | | */ |
16 | | |
17 | | #include <stdlib.h> |
18 | | #include <string.h> |
19 | | |
20 | | #include <library.h> |
21 | | #include <threading/thread_value.h> |
22 | | #include <threading/spinlock.h> |
23 | | |
24 | | #include "strerror.h" |
25 | | |
26 | | /** |
27 | | * The size of the thread-specific error buffer |
28 | | */ |
29 | 0 | #define STRERROR_BUF_LEN 256 |
30 | | |
31 | | /** |
32 | | * Thread specific strerror buffer, as char* |
33 | | */ |
34 | | static thread_value_t *strerror_buf; |
35 | | |
36 | | #ifndef HAVE_STRERROR_R |
37 | | /** |
38 | | * Lock to access strerror() safely |
39 | | */ |
40 | | static spinlock_t *strerror_lock; |
41 | | #endif /* HAVE_STRERROR_R */ |
42 | | |
43 | | /** |
44 | | * Retrieve the error buffer assigned to the current thread (or create it) |
45 | | */ |
46 | | static inline char *get_strerror_buf() |
47 | 0 | { |
48 | 0 | char *buf; |
49 | 0 | bool old = FALSE; |
50 | |
|
51 | 0 | if (!strerror_buf) |
52 | 0 | { |
53 | 0 | return NULL; |
54 | 0 | } |
55 | | |
56 | 0 | buf = strerror_buf->get(strerror_buf); |
57 | 0 | if (!buf) |
58 | 0 | { |
59 | 0 | if (lib->leak_detective) |
60 | 0 | { |
61 | 0 | old = lib->leak_detective->set_state(lib->leak_detective, FALSE); |
62 | 0 | } |
63 | 0 | buf = malloc(STRERROR_BUF_LEN); |
64 | 0 | strerror_buf->set(strerror_buf, buf); |
65 | 0 | if (lib->leak_detective) |
66 | 0 | { |
67 | 0 | lib->leak_detective->set_state(lib->leak_detective, old); |
68 | 0 | } |
69 | 0 | } |
70 | 0 | return buf; |
71 | 0 | } |
72 | | |
73 | | /** |
74 | | * Use real strerror() below |
75 | | */ |
76 | | #undef strerror |
77 | | |
78 | | /* |
79 | | * Described in header. |
80 | | */ |
81 | | const char *strerror_safe(int errnum) |
82 | 0 | { |
83 | 0 | char *buf, *msg; |
84 | |
|
85 | 0 | buf = get_strerror_buf(); |
86 | 0 | if (!buf) |
87 | 0 | { |
88 | | /* library not initialized? fallback */ |
89 | 0 | return strerror(errnum); |
90 | 0 | } |
91 | 0 | #ifdef HAVE_STRERROR_R |
92 | | # ifdef STRERROR_R_CHAR_P |
93 | | /* char* version which may or may not return the original buffer */ |
94 | | msg = strerror_r(errnum, buf, STRERROR_BUF_LEN); |
95 | | # else |
96 | | /* int version returns 0 on success */ |
97 | 0 | msg = strerror_r(errnum, buf, STRERROR_BUF_LEN) ? "Unknown error" : buf; |
98 | 0 | # endif |
99 | | #else /* HAVE_STRERROR_R */ |
100 | | /* use a lock to ensure calling strerror(3) is thread-safe */ |
101 | | strerror_lock->lock(strerror_lock); |
102 | | msg = strncpy(buf, strerror(errnum), STRERROR_BUF_LEN); |
103 | | strerror_lock->unlock(strerror_lock); |
104 | | buf[STRERROR_BUF_LEN - 1] = '\0'; |
105 | | #endif /* HAVE_STRERROR_R */ |
106 | 0 | return msg; |
107 | 0 | } |
108 | | |
109 | | /** |
110 | | * free() with disabled leak detective |
111 | | */ |
112 | | static void free_no_ld(void *buf) |
113 | 0 | { |
114 | 0 | bool old = FALSE; |
115 | |
|
116 | 0 | if (lib->leak_detective) |
117 | 0 | { |
118 | 0 | old = lib->leak_detective->set_state(lib->leak_detective, FALSE); |
119 | 0 | } |
120 | 0 | free(buf); |
121 | 0 | if (lib->leak_detective) |
122 | 0 | { |
123 | 0 | lib->leak_detective->set_state(lib->leak_detective, old); |
124 | 0 | } |
125 | 0 | } |
126 | | |
127 | | /** |
128 | | * See header |
129 | | */ |
130 | | void strerror_init() |
131 | 3.92k | { |
132 | 3.92k | strerror_buf = thread_value_create(free_no_ld); |
133 | | #ifndef HAVE_STRERROR_R |
134 | | strerror_lock = spinlock_create(); |
135 | | #endif |
136 | 3.92k | } |
137 | | |
138 | | /** |
139 | | * See header |
140 | | */ |
141 | | void strerror_deinit() |
142 | 3.92k | { |
143 | 3.92k | strerror_buf->destroy(strerror_buf); |
144 | 3.92k | strerror_buf = NULL; |
145 | | #ifndef HAVE_STRERROR_R |
146 | | strerror_lock->destroy(strerror_lock); |
147 | | #endif |
148 | 3.92k | } |