#include "dns_common.h"
#include <dlfcn.h>
#pragma init(_nss_dns_init)
static void _nss_dns_init(void);
extern struct hostent *res_gethostbyname(const char *);
#pragma weak res_gethostbyname
#define RES_SET_NO_HOSTS_FALLBACK "__res_set_no_hosts_fallback"
extern void __res_set_no_hosts_fallback(void);
#pragma weak __res_set_no_hosts_fallback
#define RES_UNSET_NO_HOSTS_FALLBACK "__res_unset_no_hosts_fallback"
extern void __res_unset_no_hosts_fallback(void);
#pragma weak __res_unset_no_hosts_fallback
#define RES_GET_RES "__res_get_res"
extern struct __res_state *__res_get_res(void);
#pragma weak __res_get_res
#define RES_ENABLE_MT "__res_enable_mt"
extern int __res_enable_mt(void);
#pragma weak __res_enable_mt
#define RES_DISABLE_MT "__res_disable_mt"
extern int __res_disable_mt(void);
#pragma weak __res_disable_mt
#define RES_GET_H_ERRNO "__res_get_h_errno"
extern int *__res_get_h_errno();
#pragma weak __res_get_h_errno
#define __H_ERRNO "__h_errno"
extern int *__h_errno(void);
#pragma weak __h_errno
#define RES_OVERRIDE_RETRY "__res_override_retry"
extern int __res_override_retry(int);
#pragma weak __res_override_retry
static void __fallback_set_no_hosts(void);
static int *__fallback_h_errno(void);
static int __fallback_override_retry(int);
static int __is_mt_safe(void);
void (*set_no_hosts_fallback)(void) = __fallback_set_no_hosts;
void (*unset_no_hosts_fallback)(void) = __fallback_set_no_hosts;
struct __res_state *(*set_res_retry)() = 0;
int (*enable_mt)() = 0;
int (*disable_mt)() = 0;
int *(*get_h_errno)(void) = 0;
int (*override_retry)(int) = 0;
#ifndef NSS_DNS_LIBRESOLV
#define NSS_DNS_LIBRESOLV "libresolv.so.2"
#endif
extern int h_errno;
mutex_t one_lane = DEFAULTMUTEX;
void
_nss_dns_init(void)
{
void *reslib, (*f_void_ptr)();
if (res_gethostbyname == 0) {
if ((reslib =
dlopen(NSS_DNS_LIBRESOLV, RTLD_LAZY|RTLD_GLOBAL)) != 0) {
if ((f_void_ptr = (void (*)(void))dlsym(reslib,
RES_SET_NO_HOSTS_FALLBACK)) != 0) {
set_no_hosts_fallback = f_void_ptr;
}
if ((f_void_ptr = (void (*)(void))dlsym(reslib,
RES_SET_NO_HOSTS_FALLBACK)) != 0) {
unset_no_hosts_fallback = f_void_ptr;
}
if ((override_retry = (int (*)(int))dlsym(reslib,
RES_OVERRIDE_RETRY)) == 0) {
set_res_retry =
(struct __res_state *(*)(void))dlsym(reslib,
RES_GET_RES);
override_retry = __fallback_override_retry;
}
if ((get_h_errno = (int *(*)(void))dlsym(reslib,
__H_ERRNO)) != 0) {
enable_mt = __is_mt_safe;
disable_mt = __is_mt_safe;
} else {
if ((get_h_errno =
(int *(*)(void))dlsym(reslib,
RES_GET_H_ERRNO)) == 0) {
get_h_errno = __fallback_h_errno;
}
if ((enable_mt = (int (*)(void))dlsym(reslib,
RES_ENABLE_MT)) != 0 &&
(disable_mt = (int (*)(void))dlsym(reslib,
RES_DISABLE_MT)) == 0) {
enable_mt = 0;
}
}
}
} else {
if ((f_void_ptr = __res_set_no_hosts_fallback) != 0) {
set_no_hosts_fallback = f_void_ptr;
}
if ((f_void_ptr = __res_unset_no_hosts_fallback) != 0) {
unset_no_hosts_fallback = f_void_ptr;
}
if ((override_retry = __res_override_retry) == 0) {
set_res_retry = __res_get_res;
override_retry = __fallback_override_retry;
}
if ((get_h_errno = __h_errno) == 0 &&
(get_h_errno = __res_get_h_errno) == 0) {
get_h_errno = __fallback_h_errno;
}
if (get_h_errno == __h_errno) {
enable_mt = __is_mt_safe;
disable_mt = __is_mt_safe;
} else {
if ((enable_mt = __res_enable_mt) != 0 &&
(disable_mt = __res_disable_mt) == 0) {
enable_mt = 0;
}
}
}
}
static int
__is_mt_safe(void) {
return (0);
}
static int *
__fallback_h_errno(void) {
return (&h_errno);
}
static int
__fallback_override_retry(int retry) {
struct __res_state *res;
int old_retry = 0;
if (set_res_retry != 0) {
res = set_res_retry();
old_retry = res->retry;
res->retry = retry;
}
return (old_retry);
}
static void
__fallback_set_no_hosts(void) {
}
void
switch_resolver_setup(int *mt_disabled, sigset_t *oldmask, int *old_retry) {
*mt_disabled = 1;
if (enable_mt == 0 || (*mt_disabled = (*enable_mt)()) != 0) {
sigset_t newmask;
(void) sigfillset(&newmask);
(void) thr_sigsetmask(SIG_SETMASK, &newmask, oldmask);
(void) mutex_lock(&one_lane);
}
(*set_no_hosts_fallback)();
*old_retry = (*override_retry)(1);
}
void
switch_resolver_reset(int mt_disabled, sigset_t oldmask, int old_retry) {
if (mt_disabled) {
(void) mutex_unlock(&one_lane);
(void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL);
} else {
(void) (*disable_mt)();
}
(*unset_no_hosts_fallback)();
(void) (*override_retry)(old_retry);
}