1 /*
2 * Copyright 2012, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <portability.h>
18 #include <pthread.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <errno_portable.h>
22
23 #define PORTABLE_TAG "errno_portable"
24 #include <log_portable.h>
25
26 #if ENAMETOOLONG==ENAMETOOLONG_PORTABLE
27 #error Bad build environment
28 #endif
29
errno_ntop(int native_errno)30 __hidden int errno_ntop(int native_errno)
31 {
32 switch (native_errno) {
33 case ENAMETOOLONG: return ENAMETOOLONG_PORTABLE;
34 case ENOLCK: return ENOLCK_PORTABLE;
35 case ENOSYS: return ENOSYS_PORTABLE;
36 case ENOTEMPTY: return ENOTEMPTY_PORTABLE;
37 case ELOOP: return ELOOP_PORTABLE;
38 case EWOULDBLOCK: return EWOULDBLOCK_PORTABLE;
39 case ENOMSG: return ENOMSG_PORTABLE;
40 case EIDRM: return EIDRM_PORTABLE;
41 case ECHRNG: return ECHRNG_PORTABLE;
42 case EL2NSYNC: return EL2NSYNC_PORTABLE;
43 case EL3HLT: return EL3HLT_PORTABLE;
44 case EL3RST: return EL3RST_PORTABLE;
45 case ELNRNG: return ELNRNG_PORTABLE;
46 case EUNATCH: return EUNATCH_PORTABLE;
47 case ENOCSI: return ENOCSI_PORTABLE;
48 case EL2HLT: return EL2HLT_PORTABLE;
49 case EBADE: return EBADE_PORTABLE;
50 case EBADR: return EBADR_PORTABLE;
51 case EXFULL: return EXFULL_PORTABLE;
52 case ENOANO: return ENOANO_PORTABLE;
53 case EBADRQC: return EBADRQC_PORTABLE;
54 case EBADSLT: return EBADSLT_PORTABLE;
55 case EDEADLOCK: return EDEADLOCK_PORTABLE;
56 case EBFONT: return EBFONT_PORTABLE;
57 case ENOSTR: return ENOSTR_PORTABLE;
58 case ENODATA: return ENODATA_PORTABLE;
59 case ETIME: return ETIME_PORTABLE;
60 case ENOSR: return ENOSR_PORTABLE;
61 case ENONET: return ENONET_PORTABLE;
62 case ENOPKG: return ENOPKG_PORTABLE;
63 case EREMOTE: return EREMOTE_PORTABLE;
64 case ENOLINK: return ENOLINK_PORTABLE;
65 case EADV: return EADV_PORTABLE;
66 case ESRMNT: return ESRMNT_PORTABLE;
67 case ECOMM: return ECOMM_PORTABLE;
68 case EPROTO: return EPROTO_PORTABLE;
69 case EMULTIHOP: return EMULTIHOP_PORTABLE;
70 case EDOTDOT: return EDOTDOT_PORTABLE;
71 case EBADMSG: return EBADMSG_PORTABLE;
72 case EOVERFLOW: return EOVERFLOW_PORTABLE;
73 case ENOTUNIQ: return ENOTUNIQ_PORTABLE;
74 case EBADFD: return EBADFD_PORTABLE;
75 case EREMCHG: return EREMCHG_PORTABLE;
76 case ELIBACC: return ELIBACC_PORTABLE;
77 case ELIBBAD: return ELIBBAD_PORTABLE;
78 case ELIBSCN: return ELIBSCN_PORTABLE;
79 case ELIBMAX: return ELIBMAX_PORTABLE;
80 case ELIBEXEC: return ELIBEXEC_PORTABLE;
81 case EILSEQ: return EILSEQ_PORTABLE;
82 case ERESTART: return ERESTART_PORTABLE;
83 case ESTRPIPE: return ESTRPIPE_PORTABLE;
84 case EUSERS: return EUSERS_PORTABLE;
85 case ENOTSOCK: return ENOTSOCK_PORTABLE;
86 case EDESTADDRREQ: return EDESTADDRREQ_PORTABLE;
87 case EMSGSIZE: return EMSGSIZE_PORTABLE;
88 case EPROTOTYPE: return EPROTOTYPE_PORTABLE;
89 case ENOPROTOOPT: return ENOPROTOOPT_PORTABLE;
90 case EPROTONOSUPPORT: return EPROTONOSUPPORT_PORTABLE;
91 case ESOCKTNOSUPPORT: return ESOCKTNOSUPPORT_PORTABLE;
92 case EOPNOTSUPP: return EOPNOTSUPP_PORTABLE;
93 case EPFNOSUPPORT: return EPFNOSUPPORT_PORTABLE;
94 case EAFNOSUPPORT: return EAFNOSUPPORT_PORTABLE;
95 case EADDRINUSE: return EADDRINUSE_PORTABLE;
96 case EADDRNOTAVAIL: return EADDRNOTAVAIL_PORTABLE;
97 case ENETDOWN: return ENETDOWN_PORTABLE;
98 case ENETUNREACH: return ENETUNREACH_PORTABLE;
99 case ENETRESET: return ENETRESET_PORTABLE;
100 case ECONNABORTED: return ECONNABORTED_PORTABLE;
101 case ECONNRESET: return ECONNRESET_PORTABLE;
102 case ENOBUFS: return ENOBUFS_PORTABLE;
103 case EISCONN: return EISCONN_PORTABLE;
104 case ENOTCONN: return ENOTCONN_PORTABLE;
105 case ESHUTDOWN: return ESHUTDOWN_PORTABLE;
106 case ETOOMANYREFS: return ETOOMANYREFS_PORTABLE;
107 case ETIMEDOUT: return ETIMEDOUT_PORTABLE;
108 case ECONNREFUSED: return ECONNREFUSED_PORTABLE;
109 case EHOSTDOWN: return EHOSTDOWN_PORTABLE;
110 case EHOSTUNREACH: return EHOSTUNREACH_PORTABLE;
111 case EALREADY: return EALREADY_PORTABLE;
112 case EINPROGRESS: return EINPROGRESS_PORTABLE;
113 case ESTALE: return ESTALE_PORTABLE;
114 case EUCLEAN: return EUCLEAN_PORTABLE;
115 case ENOTNAM: return ENOTNAM_PORTABLE;
116 case ENAVAIL: return ENAVAIL_PORTABLE;
117 case EISNAM: return EISNAM_PORTABLE;
118 case EREMOTEIO: return EREMOTEIO_PORTABLE;
119 case EDQUOT: return EDQUOT_PORTABLE;
120 case ENOMEDIUM: return ENOMEDIUM_PORTABLE;
121 case EMEDIUMTYPE: return EMEDIUMTYPE_PORTABLE;
122 case ECANCELED: return ECANCELED_PORTABLE;
123 case ENOKEY: return ENOKEY_PORTABLE;
124 case EKEYEXPIRED: return EKEYEXPIRED_PORTABLE;
125 case EKEYREVOKED: return EKEYREVOKED_PORTABLE;
126 case EKEYREJECTED: return EKEYREJECTED_PORTABLE;
127 case EOWNERDEAD: return EOWNERDEAD_PORTABLE;
128 case ENOTRECOVERABLE: return ENOTRECOVERABLE_PORTABLE;
129 }
130 return native_errno;
131 }
132
errno_pton(int portable_errno)133 __hidden int errno_pton(int portable_errno)
134 {
135 switch (portable_errno) {
136 case ENAMETOOLONG_PORTABLE: return ENAMETOOLONG;
137 case ENOLCK_PORTABLE: return ENOLCK;
138 case ENOSYS_PORTABLE: return ENOSYS;
139 case ENOTEMPTY_PORTABLE: return ENOTEMPTY;
140 case ELOOP_PORTABLE: return ELOOP;
141 case EWOULDBLOCK_PORTABLE: return EWOULDBLOCK;
142 case ENOMSG_PORTABLE: return ENOMSG;
143 case EIDRM_PORTABLE: return EIDRM;
144 case ECHRNG_PORTABLE: return ECHRNG;
145 case EL2NSYNC_PORTABLE: return EL2NSYNC;
146 case EL3HLT_PORTABLE: return EL3HLT;
147 case EL3RST_PORTABLE: return EL3RST;
148 case ELNRNG_PORTABLE: return ELNRNG;
149 case EUNATCH_PORTABLE: return EUNATCH;
150 case ENOCSI_PORTABLE: return ENOCSI;
151 case EL2HLT_PORTABLE: return EL2HLT;
152 case EBADE_PORTABLE: return EBADE;
153 case EBADR_PORTABLE: return EBADR;
154 case EXFULL_PORTABLE: return EXFULL;
155 case ENOANO_PORTABLE: return ENOANO;
156 case EBADRQC_PORTABLE: return EBADRQC;
157 case EBADSLT_PORTABLE: return EBADSLT;
158 case EDEADLOCK_PORTABLE: return EDEADLOCK;
159 case EBFONT_PORTABLE: return EBFONT;
160 case ENOSTR_PORTABLE: return ENOSTR;
161 case ENODATA_PORTABLE: return ENODATA;
162 case ETIME_PORTABLE: return ETIME;
163 case ENOSR_PORTABLE: return ENOSR;
164 case ENONET_PORTABLE: return ENONET;
165 case ENOPKG_PORTABLE: return ENOPKG;
166 case EREMOTE_PORTABLE: return EREMOTE;
167 case ENOLINK_PORTABLE: return ENOLINK;
168 case EADV_PORTABLE: return EADV;
169 case ESRMNT_PORTABLE: return ESRMNT;
170 case ECOMM_PORTABLE: return ECOMM;
171 case EPROTO_PORTABLE: return EPROTO;
172 case EMULTIHOP_PORTABLE: return EMULTIHOP;
173 case EDOTDOT_PORTABLE: return EDOTDOT;
174 case EBADMSG_PORTABLE: return EBADMSG;
175 case EOVERFLOW_PORTABLE: return EOVERFLOW;
176 case ENOTUNIQ_PORTABLE: return ENOTUNIQ;
177 case EBADFD_PORTABLE: return EBADFD;
178 case EREMCHG_PORTABLE: return EREMCHG;
179 case ELIBACC_PORTABLE: return ELIBACC;
180 case ELIBBAD_PORTABLE: return ELIBBAD;
181 case ELIBSCN_PORTABLE: return ELIBSCN;
182 case ELIBMAX_PORTABLE: return ELIBMAX;
183 case ELIBEXEC_PORTABLE: return ELIBEXEC;
184 case EILSEQ_PORTABLE: return EILSEQ;
185 case ERESTART_PORTABLE: return ERESTART;
186 case ESTRPIPE_PORTABLE: return ESTRPIPE;
187 case EUSERS_PORTABLE: return EUSERS;
188 case ENOTSOCK_PORTABLE: return ENOTSOCK;
189 case EDESTADDRREQ_PORTABLE: return EDESTADDRREQ;
190 case EMSGSIZE_PORTABLE: return EMSGSIZE;
191 case EPROTOTYPE_PORTABLE: return EPROTOTYPE;
192 case ENOPROTOOPT_PORTABLE: return ENOPROTOOPT;
193 case EPROTONOSUPPORT_PORTABLE: return EPROTONOSUPPORT;
194 case ESOCKTNOSUPPORT_PORTABLE: return ESOCKTNOSUPPORT;
195 case EOPNOTSUPP_PORTABLE: return EOPNOTSUPP;
196 case EPFNOSUPPORT_PORTABLE: return EPFNOSUPPORT;
197 case EAFNOSUPPORT_PORTABLE: return EAFNOSUPPORT;
198 case EADDRINUSE_PORTABLE: return EADDRINUSE;
199 case EADDRNOTAVAIL_PORTABLE: return EADDRNOTAVAIL;
200 case ENETDOWN_PORTABLE: return ENETDOWN;
201 case ENETUNREACH_PORTABLE: return ENETUNREACH;
202 case ENETRESET_PORTABLE: return ENETRESET;
203 case ECONNABORTED_PORTABLE: return ECONNABORTED;
204 case ECONNRESET_PORTABLE: return ECONNRESET;
205 case ENOBUFS_PORTABLE: return ENOBUFS;
206 case EISCONN_PORTABLE: return EISCONN;
207 case ENOTCONN_PORTABLE: return ENOTCONN;
208 case ESHUTDOWN_PORTABLE: return ESHUTDOWN;
209 case ETOOMANYREFS_PORTABLE: return ETOOMANYREFS;
210 case ETIMEDOUT_PORTABLE: return ETIMEDOUT;
211 case ECONNREFUSED_PORTABLE: return ECONNREFUSED;
212 case EHOSTDOWN_PORTABLE: return EHOSTDOWN;
213 case EHOSTUNREACH_PORTABLE: return EHOSTUNREACH;
214 case EALREADY_PORTABLE: return EALREADY;
215 case EINPROGRESS_PORTABLE: return EINPROGRESS;
216 case ESTALE_PORTABLE: return ESTALE;
217 case EUCLEAN_PORTABLE: return EUCLEAN;
218 case ENOTNAM_PORTABLE: return ENOTNAM;
219 case ENAVAIL_PORTABLE: return ENAVAIL;
220 case EISNAM_PORTABLE: return EISNAM;
221 case EREMOTEIO_PORTABLE: return EREMOTEIO;
222 case EDQUOT_PORTABLE: return EDQUOT;
223 case ENOMEDIUM_PORTABLE: return ENOMEDIUM;
224 case EMEDIUMTYPE_PORTABLE: return EMEDIUMTYPE;
225 case ECANCELED_PORTABLE: return ECANCELED;
226 case ENOKEY_PORTABLE: return ENOKEY;
227 case EKEYEXPIRED_PORTABLE: return EKEYEXPIRED;
228 case EKEYREVOKED_PORTABLE: return EKEYREVOKED;
229 case EKEYREJECTED_PORTABLE: return EKEYREJECTED;
230 case EOWNERDEAD_PORTABLE: return EOWNERDEAD;
231 case ENOTRECOVERABLE_PORTABLE: return ENOTRECOVERABLE;
232 }
233 return portable_errno;
234 }
235
236 /* Key for the thread-specific portable errno */
237 static pthread_key_t errno_key;
238
239 /* Once-only initialisation of the key */
240 static pthread_once_t errno_key_once = PTHREAD_ONCE_INIT;
241
242 /* Free the thread-specific portable errno */
errno_key_destroy(void * buf)243 static void errno_key_destroy(void *buf)
244 {
245 if (buf)
246 free(buf);
247 }
248
249 /* Allocate the key */
errno_key_create(void)250 static void errno_key_create(void)
251 {
252 pthread_key_create(&errno_key, errno_key_destroy);
253 }
254
255 struct errno_state {
256 int pshadow; /* copy of last portable errno */
257 int perrno; /* portable errno that may be modified by app */
258 };
259
260 /* Return the thread-specific portable errno */
errno_key_data(void)261 static struct errno_state *errno_key_data(void)
262 {
263 struct errno_state *data;
264 static struct errno_state errno_state;
265
266 pthread_once(&errno_key_once, errno_key_create);
267 data = (struct errno_state *)pthread_getspecific(errno_key);
268 if (data == NULL) {
269 data = malloc(sizeof(struct errno_state));
270 pthread_setspecific(errno_key, data);
271 }
272 if (data == NULL)
273 data = &errno_state;
274 return data;
275 }
276
277 /*
278 * Attempt to return a thread specific location containnig the portable errno.
279 * This can be assigned to without affecting the native errno. If the key
280 * allocation fails fall back to using the native errno location.
281 */
WRAP(__errno)282 volatile int* WRAP(__errno)()
283 {
284 struct errno_state *p;
285 int save_errno;
286
287 /* pthread_* calls may modify errno so use a copy */
288 save_errno = *REAL(__errno)();
289
290 p = errno_key_data();
291
292 ALOGV(" ");
293 ALOGV("%s(): { save_errno = errno:%d, (p:%p)->{pshadow:%d, perrno:%d}", __func__,
294 save_errno, p, p->pshadow, p->perrno);
295
296 if (save_errno == 0 && p->pshadow != p->perrno) {
297 /*
298 * portable errno has changed but native hasn't
299 * - copy portable error back to native
300 */
301 p->pshadow = p->perrno;
302 save_errno = errno_pton(p->perrno);
303 }
304 else if (save_errno != 0 && p->pshadow == p->perrno) {
305 /*
306 * Native errno has changed but portable hasn't
307 * - copy native error to portable.
308 */
309 p->pshadow = p->perrno = errno_ntop(save_errno);
310 save_errno = 0;
311 }
312 else if (save_errno != 0 && p->pshadow != p->perrno) {
313 /*
314 * Both native and portable errno values have changed
315 * so give priority to native errno
316 * - copy native error to portable
317 */
318 p->pshadow = p->perrno = errno_ntop(save_errno);
319 save_errno = 0;
320 }
321
322 ALOGV("%s: new save_errno:%d p:%p->{pshadow:%d, perrno:%d}", __func__,
323 save_errno, p, p->pshadow, p->perrno);
324
325 *REAL(__errno)() = save_errno;
326
327 ALOGV("%s: return (&p->perrno):%p; }", __func__, &p->perrno);
328
329 /* return pointer to the modifiable portable errno value */
330 return &p->perrno;
331 }
332
333
334 /* set portable errno */
WRAP(__set_errno)335 void WRAP(__set_errno)(int portable_errno)
336 {
337 struct errno_state *p;
338 int save_errno;
339
340 /* pthread_* calls may modify errno so use a copy */
341 save_errno = *REAL(__errno)();
342
343 p = errno_key_data();
344
345 ALOGV("%s(): { save_errno = errno:%d, p:%p->{pshadow:%d, perrno:%d}", __func__,
346 save_errno, p, p->pshadow, p->perrno);
347
348 p->pshadow = p->perrno = portable_errno;
349
350 save_errno = errno_pton(portable_errno);
351
352 ALOGV("%s: new save_errno:%d, p:%p->{pshadow:%d, perrno:%d}", __func__,
353 save_errno, p, p->pshadow, p->perrno);
354
355 *REAL(__errno)() = save_errno;
356
357 ALOGV("%s: return; }", __func__);
358 }
359
360 extern char* REAL(strerror)(int);
WRAP(strerror)361 char *WRAP(strerror)(int errnum)
362 {
363 return REAL(strerror)(errno_pton(errnum));
364 }
365
366 /* BSD style strerror_r */
WRAP(strerror_r)367 int WRAP(strerror_r)(int errnum, char *buf, size_t buflen)
368 {
369 return REAL(strerror_r)(errno_pton(errnum), buf, buflen);
370 }
371