errno in MIPS is macro for "*__errno)()". Use of errno inside WRAP(__errno)() cause infinite loop. This may happen in other wrapper functions which access errno. Change all error to *REAL(__error)() Change-Id: I1c09d84a58855bd7896fcd4e70f740b8a0f0b386
371 lines
14 KiB
C
371 lines
14 KiB
C
/*
|
|
* Copyright 2012, The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <portability.h>
|
|
#include <pthread.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <errno_portable.h>
|
|
|
|
#define PORTABLE_TAG "errno_portable"
|
|
#include <log_portable.h>
|
|
|
|
#if ENAMETOOLONG==ENAMETOOLONG_PORTABLE
|
|
#error Bad build environment
|
|
#endif
|
|
|
|
__hidden int errno_ntop(int native_errno)
|
|
{
|
|
switch (native_errno) {
|
|
case ENAMETOOLONG: return ENAMETOOLONG_PORTABLE;
|
|
case ENOLCK: return ENOLCK_PORTABLE;
|
|
case ENOSYS: return ENOSYS_PORTABLE;
|
|
case ENOTEMPTY: return ENOTEMPTY_PORTABLE;
|
|
case ELOOP: return ELOOP_PORTABLE;
|
|
case EWOULDBLOCK: return EWOULDBLOCK_PORTABLE;
|
|
case ENOMSG: return ENOMSG_PORTABLE;
|
|
case EIDRM: return EIDRM_PORTABLE;
|
|
case ECHRNG: return ECHRNG_PORTABLE;
|
|
case EL2NSYNC: return EL2NSYNC_PORTABLE;
|
|
case EL3HLT: return EL3HLT_PORTABLE;
|
|
case EL3RST: return EL3RST_PORTABLE;
|
|
case ELNRNG: return ELNRNG_PORTABLE;
|
|
case EUNATCH: return EUNATCH_PORTABLE;
|
|
case ENOCSI: return ENOCSI_PORTABLE;
|
|
case EL2HLT: return EL2HLT_PORTABLE;
|
|
case EBADE: return EBADE_PORTABLE;
|
|
case EBADR: return EBADR_PORTABLE;
|
|
case EXFULL: return EXFULL_PORTABLE;
|
|
case ENOANO: return ENOANO_PORTABLE;
|
|
case EBADRQC: return EBADRQC_PORTABLE;
|
|
case EBADSLT: return EBADSLT_PORTABLE;
|
|
case EDEADLOCK: return EDEADLOCK_PORTABLE;
|
|
case EBFONT: return EBFONT_PORTABLE;
|
|
case ENOSTR: return ENOSTR_PORTABLE;
|
|
case ENODATA: return ENODATA_PORTABLE;
|
|
case ETIME: return ETIME_PORTABLE;
|
|
case ENOSR: return ENOSR_PORTABLE;
|
|
case ENONET: return ENONET_PORTABLE;
|
|
case ENOPKG: return ENOPKG_PORTABLE;
|
|
case EREMOTE: return EREMOTE_PORTABLE;
|
|
case ENOLINK: return ENOLINK_PORTABLE;
|
|
case EADV: return EADV_PORTABLE;
|
|
case ESRMNT: return ESRMNT_PORTABLE;
|
|
case ECOMM: return ECOMM_PORTABLE;
|
|
case EPROTO: return EPROTO_PORTABLE;
|
|
case EMULTIHOP: return EMULTIHOP_PORTABLE;
|
|
case EDOTDOT: return EDOTDOT_PORTABLE;
|
|
case EBADMSG: return EBADMSG_PORTABLE;
|
|
case EOVERFLOW: return EOVERFLOW_PORTABLE;
|
|
case ENOTUNIQ: return ENOTUNIQ_PORTABLE;
|
|
case EBADFD: return EBADFD_PORTABLE;
|
|
case EREMCHG: return EREMCHG_PORTABLE;
|
|
case ELIBACC: return ELIBACC_PORTABLE;
|
|
case ELIBBAD: return ELIBBAD_PORTABLE;
|
|
case ELIBSCN: return ELIBSCN_PORTABLE;
|
|
case ELIBMAX: return ELIBMAX_PORTABLE;
|
|
case ELIBEXEC: return ELIBEXEC_PORTABLE;
|
|
case EILSEQ: return EILSEQ_PORTABLE;
|
|
case ERESTART: return ERESTART_PORTABLE;
|
|
case ESTRPIPE: return ESTRPIPE_PORTABLE;
|
|
case EUSERS: return EUSERS_PORTABLE;
|
|
case ENOTSOCK: return ENOTSOCK_PORTABLE;
|
|
case EDESTADDRREQ: return EDESTADDRREQ_PORTABLE;
|
|
case EMSGSIZE: return EMSGSIZE_PORTABLE;
|
|
case EPROTOTYPE: return EPROTOTYPE_PORTABLE;
|
|
case ENOPROTOOPT: return ENOPROTOOPT_PORTABLE;
|
|
case EPROTONOSUPPORT: return EPROTONOSUPPORT_PORTABLE;
|
|
case ESOCKTNOSUPPORT: return ESOCKTNOSUPPORT_PORTABLE;
|
|
case EOPNOTSUPP: return EOPNOTSUPP_PORTABLE;
|
|
case EPFNOSUPPORT: return EPFNOSUPPORT_PORTABLE;
|
|
case EAFNOSUPPORT: return EAFNOSUPPORT_PORTABLE;
|
|
case EADDRINUSE: return EADDRINUSE_PORTABLE;
|
|
case EADDRNOTAVAIL: return EADDRNOTAVAIL_PORTABLE;
|
|
case ENETDOWN: return ENETDOWN_PORTABLE;
|
|
case ENETUNREACH: return ENETUNREACH_PORTABLE;
|
|
case ENETRESET: return ENETRESET_PORTABLE;
|
|
case ECONNABORTED: return ECONNABORTED_PORTABLE;
|
|
case ECONNRESET: return ECONNRESET_PORTABLE;
|
|
case ENOBUFS: return ENOBUFS_PORTABLE;
|
|
case EISCONN: return EISCONN_PORTABLE;
|
|
case ENOTCONN: return ENOTCONN_PORTABLE;
|
|
case ESHUTDOWN: return ESHUTDOWN_PORTABLE;
|
|
case ETOOMANYREFS: return ETOOMANYREFS_PORTABLE;
|
|
case ETIMEDOUT: return ETIMEDOUT_PORTABLE;
|
|
case ECONNREFUSED: return ECONNREFUSED_PORTABLE;
|
|
case EHOSTDOWN: return EHOSTDOWN_PORTABLE;
|
|
case EHOSTUNREACH: return EHOSTUNREACH_PORTABLE;
|
|
case EALREADY: return EALREADY_PORTABLE;
|
|
case EINPROGRESS: return EINPROGRESS_PORTABLE;
|
|
case ESTALE: return ESTALE_PORTABLE;
|
|
case EUCLEAN: return EUCLEAN_PORTABLE;
|
|
case ENOTNAM: return ENOTNAM_PORTABLE;
|
|
case ENAVAIL: return ENAVAIL_PORTABLE;
|
|
case EISNAM: return EISNAM_PORTABLE;
|
|
case EREMOTEIO: return EREMOTEIO_PORTABLE;
|
|
case EDQUOT: return EDQUOT_PORTABLE;
|
|
case ENOMEDIUM: return ENOMEDIUM_PORTABLE;
|
|
case EMEDIUMTYPE: return EMEDIUMTYPE_PORTABLE;
|
|
case ECANCELED: return ECANCELED_PORTABLE;
|
|
case ENOKEY: return ENOKEY_PORTABLE;
|
|
case EKEYEXPIRED: return EKEYEXPIRED_PORTABLE;
|
|
case EKEYREVOKED: return EKEYREVOKED_PORTABLE;
|
|
case EKEYREJECTED: return EKEYREJECTED_PORTABLE;
|
|
case EOWNERDEAD: return EOWNERDEAD_PORTABLE;
|
|
case ENOTRECOVERABLE: return ENOTRECOVERABLE_PORTABLE;
|
|
}
|
|
return native_errno;
|
|
}
|
|
|
|
__hidden int errno_pton(int portable_errno)
|
|
{
|
|
switch (portable_errno) {
|
|
case ENAMETOOLONG_PORTABLE: return ENAMETOOLONG;
|
|
case ENOLCK_PORTABLE: return ENOLCK;
|
|
case ENOSYS_PORTABLE: return ENOSYS;
|
|
case ENOTEMPTY_PORTABLE: return ENOTEMPTY;
|
|
case ELOOP_PORTABLE: return ELOOP;
|
|
case EWOULDBLOCK_PORTABLE: return EWOULDBLOCK;
|
|
case ENOMSG_PORTABLE: return ENOMSG;
|
|
case EIDRM_PORTABLE: return EIDRM;
|
|
case ECHRNG_PORTABLE: return ECHRNG;
|
|
case EL2NSYNC_PORTABLE: return EL2NSYNC;
|
|
case EL3HLT_PORTABLE: return EL3HLT;
|
|
case EL3RST_PORTABLE: return EL3RST;
|
|
case ELNRNG_PORTABLE: return ELNRNG;
|
|
case EUNATCH_PORTABLE: return EUNATCH;
|
|
case ENOCSI_PORTABLE: return ENOCSI;
|
|
case EL2HLT_PORTABLE: return EL2HLT;
|
|
case EBADE_PORTABLE: return EBADE;
|
|
case EBADR_PORTABLE: return EBADR;
|
|
case EXFULL_PORTABLE: return EXFULL;
|
|
case ENOANO_PORTABLE: return ENOANO;
|
|
case EBADRQC_PORTABLE: return EBADRQC;
|
|
case EBADSLT_PORTABLE: return EBADSLT;
|
|
case EDEADLOCK_PORTABLE: return EDEADLOCK;
|
|
case EBFONT_PORTABLE: return EBFONT;
|
|
case ENOSTR_PORTABLE: return ENOSTR;
|
|
case ENODATA_PORTABLE: return ENODATA;
|
|
case ETIME_PORTABLE: return ETIME;
|
|
case ENOSR_PORTABLE: return ENOSR;
|
|
case ENONET_PORTABLE: return ENONET;
|
|
case ENOPKG_PORTABLE: return ENOPKG;
|
|
case EREMOTE_PORTABLE: return EREMOTE;
|
|
case ENOLINK_PORTABLE: return ENOLINK;
|
|
case EADV_PORTABLE: return EADV;
|
|
case ESRMNT_PORTABLE: return ESRMNT;
|
|
case ECOMM_PORTABLE: return ECOMM;
|
|
case EPROTO_PORTABLE: return EPROTO;
|
|
case EMULTIHOP_PORTABLE: return EMULTIHOP;
|
|
case EDOTDOT_PORTABLE: return EDOTDOT;
|
|
case EBADMSG_PORTABLE: return EBADMSG;
|
|
case EOVERFLOW_PORTABLE: return EOVERFLOW;
|
|
case ENOTUNIQ_PORTABLE: return ENOTUNIQ;
|
|
case EBADFD_PORTABLE: return EBADFD;
|
|
case EREMCHG_PORTABLE: return EREMCHG;
|
|
case ELIBACC_PORTABLE: return ELIBACC;
|
|
case ELIBBAD_PORTABLE: return ELIBBAD;
|
|
case ELIBSCN_PORTABLE: return ELIBSCN;
|
|
case ELIBMAX_PORTABLE: return ELIBMAX;
|
|
case ELIBEXEC_PORTABLE: return ELIBEXEC;
|
|
case EILSEQ_PORTABLE: return EILSEQ;
|
|
case ERESTART_PORTABLE: return ERESTART;
|
|
case ESTRPIPE_PORTABLE: return ESTRPIPE;
|
|
case EUSERS_PORTABLE: return EUSERS;
|
|
case ENOTSOCK_PORTABLE: return ENOTSOCK;
|
|
case EDESTADDRREQ_PORTABLE: return EDESTADDRREQ;
|
|
case EMSGSIZE_PORTABLE: return EMSGSIZE;
|
|
case EPROTOTYPE_PORTABLE: return EPROTOTYPE;
|
|
case ENOPROTOOPT_PORTABLE: return ENOPROTOOPT;
|
|
case EPROTONOSUPPORT_PORTABLE: return EPROTONOSUPPORT;
|
|
case ESOCKTNOSUPPORT_PORTABLE: return ESOCKTNOSUPPORT;
|
|
case EOPNOTSUPP_PORTABLE: return EOPNOTSUPP;
|
|
case EPFNOSUPPORT_PORTABLE: return EPFNOSUPPORT;
|
|
case EAFNOSUPPORT_PORTABLE: return EAFNOSUPPORT;
|
|
case EADDRINUSE_PORTABLE: return EADDRINUSE;
|
|
case EADDRNOTAVAIL_PORTABLE: return EADDRNOTAVAIL;
|
|
case ENETDOWN_PORTABLE: return ENETDOWN;
|
|
case ENETUNREACH_PORTABLE: return ENETUNREACH;
|
|
case ENETRESET_PORTABLE: return ENETRESET;
|
|
case ECONNABORTED_PORTABLE: return ECONNABORTED;
|
|
case ECONNRESET_PORTABLE: return ECONNRESET;
|
|
case ENOBUFS_PORTABLE: return ENOBUFS;
|
|
case EISCONN_PORTABLE: return EISCONN;
|
|
case ENOTCONN_PORTABLE: return ENOTCONN;
|
|
case ESHUTDOWN_PORTABLE: return ESHUTDOWN;
|
|
case ETOOMANYREFS_PORTABLE: return ETOOMANYREFS;
|
|
case ETIMEDOUT_PORTABLE: return ETIMEDOUT;
|
|
case ECONNREFUSED_PORTABLE: return ECONNREFUSED;
|
|
case EHOSTDOWN_PORTABLE: return EHOSTDOWN;
|
|
case EHOSTUNREACH_PORTABLE: return EHOSTUNREACH;
|
|
case EALREADY_PORTABLE: return EALREADY;
|
|
case EINPROGRESS_PORTABLE: return EINPROGRESS;
|
|
case ESTALE_PORTABLE: return ESTALE;
|
|
case EUCLEAN_PORTABLE: return EUCLEAN;
|
|
case ENOTNAM_PORTABLE: return ENOTNAM;
|
|
case ENAVAIL_PORTABLE: return ENAVAIL;
|
|
case EISNAM_PORTABLE: return EISNAM;
|
|
case EREMOTEIO_PORTABLE: return EREMOTEIO;
|
|
case EDQUOT_PORTABLE: return EDQUOT;
|
|
case ENOMEDIUM_PORTABLE: return ENOMEDIUM;
|
|
case EMEDIUMTYPE_PORTABLE: return EMEDIUMTYPE;
|
|
case ECANCELED_PORTABLE: return ECANCELED;
|
|
case ENOKEY_PORTABLE: return ENOKEY;
|
|
case EKEYEXPIRED_PORTABLE: return EKEYEXPIRED;
|
|
case EKEYREVOKED_PORTABLE: return EKEYREVOKED;
|
|
case EKEYREJECTED_PORTABLE: return EKEYREJECTED;
|
|
case EOWNERDEAD_PORTABLE: return EOWNERDEAD;
|
|
case ENOTRECOVERABLE_PORTABLE: return ENOTRECOVERABLE;
|
|
}
|
|
return portable_errno;
|
|
}
|
|
|
|
/* Key for the thread-specific portable errno */
|
|
static pthread_key_t errno_key;
|
|
|
|
/* Once-only initialisation of the key */
|
|
static pthread_once_t errno_key_once = PTHREAD_ONCE_INIT;
|
|
|
|
/* Free the thread-specific portable errno */
|
|
static void errno_key_destroy(void *buf)
|
|
{
|
|
if (buf)
|
|
free(buf);
|
|
}
|
|
|
|
/* Allocate the key */
|
|
static void errno_key_create(void)
|
|
{
|
|
pthread_key_create(&errno_key, errno_key_destroy);
|
|
}
|
|
|
|
struct errno_state {
|
|
int pshadow; /* copy of last portable errno */
|
|
int perrno; /* portable errno that may be modified by app */
|
|
};
|
|
|
|
/* Return the thread-specific portable errno */
|
|
static struct errno_state *errno_key_data(void)
|
|
{
|
|
struct errno_state *data;
|
|
static struct errno_state errno_state;
|
|
|
|
pthread_once(&errno_key_once, errno_key_create);
|
|
data = (struct errno_state *)pthread_getspecific(errno_key);
|
|
if (data == NULL) {
|
|
data = malloc(sizeof(struct errno_state));
|
|
pthread_setspecific(errno_key, data);
|
|
}
|
|
if (data == NULL)
|
|
data = &errno_state;
|
|
return data;
|
|
}
|
|
|
|
/*
|
|
* Attempt to return a thread specific location containnig the portable errno.
|
|
* This can be assigned to without affecting the native errno. If the key
|
|
* allocation fails fall back to using the native errno location.
|
|
*/
|
|
volatile int* WRAP(__errno)()
|
|
{
|
|
struct errno_state *p;
|
|
int save_errno;
|
|
|
|
/* pthread_* calls may modify errno so use a copy */
|
|
save_errno = *REAL(__errno)();
|
|
|
|
p = errno_key_data();
|
|
|
|
ALOGV(" ");
|
|
ALOGV("%s(): { save_errno = errno:%d, (p:%p)->{pshadow:%d, perrno:%d}", __func__,
|
|
save_errno, p, p->pshadow, p->perrno);
|
|
|
|
if (save_errno == 0 && p->pshadow != p->perrno) {
|
|
/*
|
|
* portable errno has changed but native hasn't
|
|
* - copy portable error back to native
|
|
*/
|
|
p->pshadow = p->perrno;
|
|
save_errno = errno_pton(p->perrno);
|
|
}
|
|
else if (save_errno != 0 && p->pshadow == p->perrno) {
|
|
/*
|
|
* Native errno has changed but portable hasn't
|
|
* - copy native error to portable.
|
|
*/
|
|
p->pshadow = p->perrno = errno_ntop(save_errno);
|
|
save_errno = 0;
|
|
}
|
|
else if (save_errno != 0 && p->pshadow != p->perrno) {
|
|
/*
|
|
* Both native and portable errno values have changed
|
|
* so give priority to native errno
|
|
* - copy native error to portable
|
|
*/
|
|
p->pshadow = p->perrno = errno_ntop(save_errno);
|
|
save_errno = 0;
|
|
}
|
|
|
|
ALOGV("%s: new save_errno:%d p:%p->{pshadow:%d, perrno:%d}", __func__,
|
|
save_errno, p, p->pshadow, p->perrno);
|
|
|
|
*REAL(__errno)() = save_errno;
|
|
|
|
ALOGV("%s: return (&p->perrno):%p; }", __func__, &p->perrno);
|
|
|
|
/* return pointer to the modifiable portable errno value */
|
|
return &p->perrno;
|
|
}
|
|
|
|
|
|
/* set portable errno */
|
|
void WRAP(__set_errno)(int portable_errno)
|
|
{
|
|
struct errno_state *p;
|
|
int save_errno;
|
|
|
|
/* pthread_* calls may modify errno so use a copy */
|
|
save_errno = *REAL(__errno)();
|
|
|
|
p = errno_key_data();
|
|
|
|
ALOGV("%s(): { save_errno = errno:%d, p:%p->{pshadow:%d, perrno:%d}", __func__,
|
|
save_errno, p, p->pshadow, p->perrno);
|
|
|
|
p->pshadow = p->perrno = portable_errno;
|
|
|
|
save_errno = errno_pton(portable_errno);
|
|
|
|
ALOGV("%s: new save_errno:%d, p:%p->{pshadow:%d, perrno:%d}", __func__,
|
|
save_errno, p, p->pshadow, p->perrno);
|
|
|
|
*REAL(__errno)() = save_errno;
|
|
|
|
ALOGV("%s: return; }", __func__);
|
|
}
|
|
|
|
extern char* REAL(strerror)(int);
|
|
char *WRAP(strerror)(int errnum)
|
|
{
|
|
return REAL(strerror)(errno_pton(errnum));
|
|
}
|
|
|
|
/* BSD style strerror_r */
|
|
int WRAP(strerror_r)(int errnum, char *buf, size_t buflen)
|
|
{
|
|
return REAL(strerror_r)(errno_pton(errnum), buf, buflen);
|
|
}
|