sl@0: /* sl@0: * tclUnixCompat.c sl@0: * sl@0: * Written by: Zoran Vasiljevic (vasiljevic@users.sourceforge.net). sl@0: * sl@0: * See the file "license.terms" for information on usage and redistribution sl@0: * of this file, and for a DISCLAIMER OF ALL WARRANTIES. sl@0: * sl@0: * RCS: @(#) $Id: tclUnixCompat.c,v 1.1.2.10 2006/09/12 22:05:03 andreas_kupries Exp $ sl@0: * sl@0: */ sl@0: sl@0: #include "tclInt.h" sl@0: #include "tclPort.h" sl@0: #include <pwd.h> sl@0: #include <grp.h> sl@0: #include <errno.h> sl@0: #include <string.h> sl@0: sl@0: /* sl@0: * Used to pad structures at size'd boundaries sl@0: * sl@0: * This macro assumes that the pointer 'buffer' was created from an sl@0: * aligned pointer by adding the 'length'. If this 'length' was not a sl@0: * multiple of the 'size' the result is unaligned and PadBuffer sl@0: * corrects both the pointer, _and_ the 'length'. The latter means sl@0: * that future increments of 'buffer' by 'length' stay aligned. sl@0: */ sl@0: sl@0: #define PadBuffer(buffer, length, size) \ sl@0: if (((length) % (size))) { \ sl@0: (buffer) += ((size) - ((length) % (size))); \ sl@0: (length) += ((size) - ((length) % (size))); \ sl@0: } sl@0: sl@0: /* sl@0: * Per-thread private storage used to store values sl@0: * returned from MT-unsafe library calls. sl@0: */ sl@0: sl@0: #ifdef TCL_THREADS sl@0: sl@0: typedef struct ThreadSpecificData { sl@0: sl@0: struct passwd pwd; sl@0: char pbuf[2048]; sl@0: sl@0: struct group grp; sl@0: char gbuf[2048]; sl@0: sl@0: #if !defined(HAVE_MTSAFE_GETHOSTBYNAME) || !defined(HAVE_MTSAFE_GETHOSTBYADDR) sl@0: struct hostent hent; sl@0: char hbuf[2048]; sl@0: #endif sl@0: sl@0: } ThreadSpecificData; sl@0: sl@0: static Tcl_ThreadDataKey dataKey; sl@0: sl@0: #if ((!defined(HAVE_GETHOSTBYNAME_R) || !defined(HAVE_GETHOSTBYADDR_R)) && \ sl@0: (!defined(HAVE_MTSAFE_GETHOSTBYNAME) || !defined(HAVE_MTSAFE_GETHOSTBYADDR))) || \ sl@0: !defined(HAVE_GETPWNAM_R) || !defined(HAVE_GETPWUID_R) || \ sl@0: !defined(HAVE_GETGRNAM_R) || !defined(HAVE_GETGRGID_R) sl@0: sl@0: /* sl@0: * Mutex to lock access to MT-unsafe calls. This is just to protect sl@0: * our own usage. It does not protect us from others calling the sl@0: * same functions without (or using some different) lock. sl@0: */ sl@0: sl@0: static Tcl_Mutex compatLock; sl@0: sl@0: /* sl@0: *--------------------------------------------------------------------------- sl@0: * sl@0: * CopyArray -- sl@0: * sl@0: * Copies array of NULL-terminated or fixed-length strings sl@0: * to the private buffer, honouring the size of the buffer. sl@0: * sl@0: * Results: sl@0: * Number of bytes copied on success or -1 on error (errno = ERANGE) sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *--------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: static int sl@0: CopyArray(char **src, int elsize, char *buf, int buflen) sl@0: { sl@0: int i, j, len = 0; sl@0: char *p, **new; sl@0: sl@0: if (src == NULL) { sl@0: return 0; sl@0: } sl@0: for (i = 0; src[i] != NULL; i++) { sl@0: /* Empty loop to count howmany */ sl@0: } sl@0: if ((sizeof(char *)*(i + 1)) > buflen) { sl@0: return -1; sl@0: } sl@0: len = (sizeof(char *)*(i + 1)); /* Leave place for the array */ sl@0: new = (char **)buf; sl@0: p = buf + (sizeof(char *)*(i + 1)); sl@0: for (j = 0; j < i; j++) { sl@0: if (elsize < 0) { sl@0: len += strlen(src[j]) + 1; sl@0: } else { sl@0: len += elsize; sl@0: } sl@0: if (len > buflen) { sl@0: return -1; sl@0: } sl@0: if (elsize < 0) { sl@0: strcpy(p, src[j]); sl@0: } else { sl@0: memcpy(p, src[j], elsize); sl@0: } sl@0: new[j] = p; sl@0: p = buf + len; sl@0: } sl@0: new[j] = NULL; sl@0: sl@0: return len; sl@0: } sl@0: sl@0: sl@0: /* sl@0: *--------------------------------------------------------------------------- sl@0: * sl@0: * CopyString -- sl@0: * sl@0: * Copies a NULL-terminated string to the private buffer, sl@0: * honouring the size of the buffer sl@0: * sl@0: * Results: sl@0: * 0 success or -1 on error (errno = ERANGE) sl@0: * sl@0: * Side effects: sl@0: * None sl@0: * sl@0: *--------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: sl@0: static int sl@0: CopyString(char *src, char *buf, int buflen) sl@0: { sl@0: int len = 0; sl@0: sl@0: if (src != NULL) { sl@0: len += strlen(src) + 1; sl@0: if (len > buflen) { sl@0: return -1; sl@0: } sl@0: strcpy(buf, src); sl@0: } sl@0: sl@0: return len; sl@0: } sl@0: #endif /* ((!defined(HAVE_GETHOSTBYNAME_R) || !defined(HAVE_GETHOSTBYADDR_R)) && \ sl@0: (!defined(HAVE_MTSAFE_GETHOSTBYNAME) || !defined(HAVE_MTSAFE_GETHOSTBYADDR))) || \ sl@0: !defined(HAVE_GETPWNAM_R) || !defined(HAVE_GETPWUID_R) || \ sl@0: !defined(HAVE_GETGRNAM_R) || !defined(HAVE_GETGRGID_R) */ sl@0: sl@0: #if (!defined(HAVE_GETHOSTBYNAME_R) || !defined(HAVE_GETHOSTBYADDR_R)) && \ sl@0: (!defined(HAVE_MTSAFE_GETHOSTBYNAME) || !defined(HAVE_MTSAFE_GETHOSTBYADDR)) sl@0: sl@0: /* sl@0: *--------------------------------------------------------------------------- sl@0: * sl@0: * CopyHostnent -- sl@0: * sl@0: * Copies string fields of the hostnent structure to the sl@0: * private buffer, honouring the size of the buffer. sl@0: * sl@0: * Results: sl@0: * Number of bytes copied on success or -1 on error (errno = ERANGE) sl@0: * sl@0: * Side effects: sl@0: * None sl@0: * sl@0: *--------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: static int sl@0: CopyHostent(struct hostent *tgtPtr, char *buf, int buflen) sl@0: { sl@0: char *p = buf; sl@0: int copied, len = 0; sl@0: sl@0: copied = CopyString(tgtPtr->h_name, p, buflen - len); sl@0: if (copied == -1) { sl@0: range: sl@0: errno = ERANGE; sl@0: return -1; sl@0: } sl@0: tgtPtr->h_name = (copied > 0) ? p : NULL; sl@0: len += copied; sl@0: p = buf + len; sl@0: sl@0: PadBuffer(p, len, sizeof(char *)); sl@0: copied = CopyArray(tgtPtr->h_aliases, -1, p, buflen - len); sl@0: if (copied == -1) { sl@0: goto range; sl@0: } sl@0: tgtPtr->h_aliases = (copied > 0) ? (char **)p : NULL; sl@0: len += copied; sl@0: p += len; sl@0: sl@0: PadBuffer(p, len, sizeof(char *)); sl@0: copied = CopyArray(tgtPtr->h_addr_list, tgtPtr->h_length, p, buflen - len); sl@0: if (copied == -1) { sl@0: goto range; sl@0: } sl@0: tgtPtr->h_addr_list = (copied > 0) ? (char **)p : NULL; sl@0: sl@0: return 0; sl@0: } sl@0: #endif /* (!defined(HAVE_GETHOSTBYNAME_R) || !defined(HAVE_GETHOSTBYADDR_R)) && \ sl@0: (!defined(HAVE_MTSAFE_GETHOSTBYNAME) || !defined(HAVE_MTSAFE_GETHOSTBYADDR)) */ sl@0: sl@0: #if !defined(HAVE_GETPWNAM_R) || !defined(HAVE_GETPWUID_R) sl@0: sl@0: /* sl@0: *--------------------------------------------------------------------------- sl@0: * sl@0: * CopyPwd -- sl@0: * sl@0: * Copies string fields of the passwd structure to the sl@0: * private buffer, honouring the size of the buffer. sl@0: * sl@0: * Results: sl@0: * 0 on success or -1 on error (errno = ERANGE) sl@0: * sl@0: * Side effects: sl@0: * We are not copying the gecos field as it may not be supported sl@0: * on all platforms. sl@0: * sl@0: *--------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: static int sl@0: CopyPwd(struct passwd *tgtPtr, char *buf, int buflen) sl@0: { sl@0: char *p = buf; sl@0: int copied, len = 0; sl@0: sl@0: copied = CopyString(tgtPtr->pw_name, p, buflen - len); sl@0: if (copied == -1) { sl@0: range: sl@0: errno = ERANGE; sl@0: return -1; sl@0: } sl@0: tgtPtr->pw_name = (copied > 0) ? p : NULL; sl@0: len += copied; sl@0: p = buf + len; sl@0: sl@0: copied = CopyString(tgtPtr->pw_passwd, p, buflen - len); sl@0: if (copied == -1) { sl@0: goto range; sl@0: } sl@0: tgtPtr->pw_passwd = (copied > 0) ? p : NULL; sl@0: len += copied; sl@0: p = buf + len; sl@0: sl@0: copied = CopyString(tgtPtr->pw_dir, p, buflen - len); sl@0: if (copied == -1) { sl@0: goto range; sl@0: } sl@0: tgtPtr->pw_dir = (copied > 0) ? p : NULL; sl@0: len += copied; sl@0: p = buf + len; sl@0: sl@0: copied = CopyString(tgtPtr->pw_shell, p, buflen - len); sl@0: if (copied == -1) { sl@0: goto range; sl@0: } sl@0: tgtPtr->pw_shell = (copied > 0) ? p : NULL; sl@0: sl@0: return 0; sl@0: } sl@0: #endif /* !defined(HAVE_GETPWNAM_R) || !defined(HAVE_GETPWUID_R) */ sl@0: sl@0: #if !defined(HAVE_GETGRNAM_R) || !defined(HAVE_GETGRGID_R) sl@0: sl@0: /* sl@0: *--------------------------------------------------------------------------- sl@0: * sl@0: * CopyGrp -- sl@0: * sl@0: * Copies string fields of the group structure to the sl@0: * private buffer, honouring the size of the buffer. sl@0: * sl@0: * Results: sl@0: * 0 on success or -1 on error (errno = ERANGE) sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *--------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: static int sl@0: CopyGrp(struct group *tgtPtr, char *buf, int buflen) sl@0: { sl@0: register char *p = buf; sl@0: register int copied, len = 0; sl@0: sl@0: /* Copy username */ sl@0: copied = CopyString(tgtPtr->gr_name, p, buflen - len); sl@0: if (copied == -1) { sl@0: range: sl@0: errno = ERANGE; sl@0: return -1; sl@0: } sl@0: tgtPtr->gr_name = (copied > 0) ? p : NULL; sl@0: len += copied; sl@0: p = buf + len; sl@0: sl@0: /* Copy password */ sl@0: copied = CopyString(tgtPtr->gr_passwd, p, buflen - len); sl@0: if (copied == -1) { sl@0: goto range; sl@0: } sl@0: tgtPtr->gr_passwd = (copied > 0) ? p : NULL; sl@0: len += copied; sl@0: p = buf + len; sl@0: sl@0: /* Copy group members */ sl@0: PadBuffer(p, len, sizeof(char *)); sl@0: copied = CopyArray((char **)tgtPtr->gr_mem, -1, p, buflen - len); sl@0: if (copied == -1) { sl@0: goto range; sl@0: } sl@0: tgtPtr->gr_mem = (copied > 0) ? (char **)p : NULL; sl@0: sl@0: return 0; sl@0: } sl@0: #endif /* !defined(HAVE_GETGRNAM_R) || !defined(HAVE_GETGRGID_R) */ sl@0: sl@0: #endif /* TCL_THREADS */ sl@0: sl@0: sl@0: /* sl@0: *--------------------------------------------------------------------------- sl@0: * sl@0: * TclpGetPwNam -- sl@0: * sl@0: * Thread-safe wrappers for getpwnam(). sl@0: * See "man getpwnam" for more details. sl@0: * sl@0: * Results: sl@0: * Pointer to struct passwd on success or NULL on error. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *--------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: struct passwd * sl@0: TclpGetPwNam(const char *name) sl@0: { sl@0: #if !defined(TCL_THREADS) sl@0: return getpwnam(name); sl@0: #else sl@0: ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); sl@0: sl@0: #if defined(HAVE_GETPWNAM_R_5) sl@0: struct passwd *pwPtr = NULL; sl@0: return (getpwnam_r(name, &tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf), sl@0: &pwPtr) == 0 && pwPtr != NULL) ? &tsdPtr->pwd : NULL; sl@0: sl@0: #elif defined(HAVE_GETPWNAM_R_4) sl@0: return getpwnam_r(name, &tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf)); sl@0: sl@0: #else sl@0: struct passwd *pwPtr; sl@0: Tcl_MutexLock(&compatLock); sl@0: pwPtr = getpwnam(name); sl@0: if (pwPtr != NULL) { sl@0: tsdPtr->pwd = *pwPtr; sl@0: pwPtr = &tsdPtr->pwd; sl@0: if (CopyPwd(&tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf)) == -1) { sl@0: pwPtr = NULL; sl@0: } sl@0: } sl@0: Tcl_MutexUnlock(&compatLock); sl@0: return pwPtr; sl@0: #endif sl@0: return NULL; /* Not reached */ sl@0: #endif /* TCL_THREADS */ sl@0: } sl@0: sl@0: sl@0: /* sl@0: *--------------------------------------------------------------------------- sl@0: * sl@0: * TclpGetPwUid -- sl@0: * sl@0: * Thread-safe wrappers for getpwuid(). sl@0: * See "man getpwuid" for more details. sl@0: * sl@0: * Results: sl@0: * Pointer to struct passwd on success or NULL on error. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *--------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: struct passwd * sl@0: TclpGetPwUid(uid_t uid) sl@0: { sl@0: #if !defined(TCL_THREADS) sl@0: return getpwuid(uid); sl@0: #else sl@0: ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); sl@0: sl@0: #if defined(HAVE_GETPWUID_R_5) sl@0: struct passwd *pwPtr = NULL; sl@0: return (getpwuid_r(uid, &tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf), sl@0: &pwPtr) == 0 && pwPtr != NULL) ? &tsdPtr->pwd : NULL; sl@0: sl@0: #elif defined(HAVE_GETPWUID_R_4) sl@0: return getpwuid_r(uid, &tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf)); sl@0: sl@0: #else sl@0: struct passwd *pwPtr; sl@0: Tcl_MutexLock(&compatLock); sl@0: pwPtr = getpwuid(uid); sl@0: if (pwPtr != NULL) { sl@0: tsdPtr->pwd = *pwPtr; sl@0: pwPtr = &tsdPtr->pwd; sl@0: if (CopyPwd(&tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf)) == -1) { sl@0: pwPtr = NULL; sl@0: } sl@0: } sl@0: Tcl_MutexUnlock(&compatLock); sl@0: return pwPtr; sl@0: #endif sl@0: return NULL; /* Not reached */ sl@0: #endif /* TCL_THREADS */ sl@0: } sl@0: sl@0: sl@0: /* sl@0: *--------------------------------------------------------------------------- sl@0: * sl@0: * TclpGetGrNam -- sl@0: * sl@0: * Thread-safe wrappers for getgrnam(). sl@0: * See "man getgrnam" for more details. sl@0: * sl@0: * Results: sl@0: * Pointer to struct group on success or NULL on error. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *--------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: struct group * sl@0: TclpGetGrNam(const char *name) sl@0: { sl@0: #if !defined(TCL_THREADS) sl@0: return getgrnam(name); sl@0: #else sl@0: ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); sl@0: sl@0: #if defined(HAVE_GETGRNAM_R_5) sl@0: struct group *grPtr = NULL; sl@0: return (getgrnam_r(name, &tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf), sl@0: &grPtr) == 0 && grPtr != NULL) ? &tsdPtr->grp : NULL; sl@0: sl@0: #elif defined(HAVE_GETGRNAM_R_4) sl@0: return getgrnam_r(name, &tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf)); sl@0: sl@0: #else sl@0: struct group *grPtr; sl@0: Tcl_MutexLock(&compatLock); sl@0: grPtr = getgrnam(name); sl@0: if (grPtr != NULL) { sl@0: tsdPtr->grp = *grPtr; sl@0: grPtr = &tsdPtr->grp; sl@0: if (CopyGrp(&tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf)) == -1) { sl@0: grPtr = NULL; sl@0: } sl@0: } sl@0: Tcl_MutexUnlock(&compatLock); sl@0: return grPtr; sl@0: #endif sl@0: return NULL; /* Not reached */ sl@0: #endif /* TCL_THREADS */ sl@0: } sl@0: sl@0: sl@0: /* sl@0: *--------------------------------------------------------------------------- sl@0: * sl@0: * TclpGetGrGid -- sl@0: * sl@0: * Thread-safe wrappers for getgrgid(). sl@0: * See "man getgrgid" for more details. sl@0: * sl@0: * Results: sl@0: * Pointer to struct group on success or NULL on error. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *--------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: struct group * sl@0: TclpGetGrGid(gid_t gid) sl@0: { sl@0: #if !defined(TCL_THREADS) sl@0: return getgrgid(gid); sl@0: #else sl@0: ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); sl@0: sl@0: #if defined(HAVE_GETGRGID_R_5) sl@0: struct group *grPtr = NULL; sl@0: return (getgrgid_r(gid, &tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf), sl@0: &grPtr) == 0 && grPtr != NULL) ? &tsdPtr->grp : NULL; sl@0: sl@0: #elif defined(HAVE_GETGRGID_R_4) sl@0: return getgrgid_r(gid, &tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf)); sl@0: sl@0: #else sl@0: struct group *grPtr; sl@0: Tcl_MutexLock(&compatLock); sl@0: grPtr = getgrgid(gid); sl@0: if (grPtr != NULL) { sl@0: tsdPtr->grp = *grPtr; sl@0: grPtr = &tsdPtr->grp; sl@0: if (CopyGrp(&tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf)) == -1) { sl@0: grPtr = NULL; sl@0: } sl@0: } sl@0: Tcl_MutexUnlock(&compatLock); sl@0: return grPtr; sl@0: #endif sl@0: return NULL; /* Not reached */ sl@0: #endif /* TCL_THREADS */ sl@0: } sl@0: sl@0: sl@0: /* sl@0: *--------------------------------------------------------------------------- sl@0: * sl@0: * TclpGetHostByName -- sl@0: * sl@0: * Thread-safe wrappers for gethostbyname(). sl@0: * See "man gethostbyname" for more details. sl@0: * sl@0: * Results: sl@0: * Pointer to struct hostent on success or NULL on error. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *--------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: struct hostent * sl@0: TclpGetHostByName(const char *name) sl@0: { sl@0: #if !defined(TCL_THREADS) || defined(HAVE_MTSAFE_GETHOSTBYNAME) sl@0: return gethostbyname(name); sl@0: #else sl@0: ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); sl@0: sl@0: #if defined(HAVE_GETHOSTBYNAME_R_5) sl@0: int h_errno; sl@0: return gethostbyname_r(name, &tsdPtr->hent, tsdPtr->hbuf, sl@0: sizeof(tsdPtr->hbuf), &h_errno); sl@0: sl@0: #elif defined(HAVE_GETHOSTBYNAME_R_6) sl@0: struct hostent *hePtr; sl@0: int h_errno; sl@0: return (gethostbyname_r(name, &tsdPtr->hent, tsdPtr->hbuf, sl@0: sizeof(tsdPtr->hbuf), &hePtr, &h_errno) == 0) ? sl@0: &tsdPtr->hent : NULL; sl@0: sl@0: #elif defined(HAVE_GETHOSTBYNAME_R_3) sl@0: struct hostent_data data; sl@0: return (gethostbyname_r(name, &tsdPtr->hent, &data) == 0) ? sl@0: &tsdPtr->hent : NULL; sl@0: #else sl@0: struct hostent *hePtr; sl@0: Tcl_MutexLock(&compatLock); sl@0: hePtr = gethostbyname(name); sl@0: if (hePtr != NULL) { sl@0: tsdPtr->hent = *hePtr; sl@0: hePtr = &tsdPtr->hent; sl@0: if (CopyHostent(&tsdPtr->hent, tsdPtr->hbuf, sl@0: sizeof(tsdPtr->hbuf)) == -1) { sl@0: hePtr = NULL; sl@0: } sl@0: } sl@0: Tcl_MutexUnlock(&compatLock); sl@0: return hePtr; sl@0: #endif sl@0: return NULL; /* Not reached */ sl@0: #endif /* TCL_THREADS */ sl@0: } sl@0: sl@0: sl@0: /* sl@0: *--------------------------------------------------------------------------- sl@0: * sl@0: * TclpGetHostByAddr -- sl@0: * sl@0: * Thread-safe wrappers for gethostbyaddr(). sl@0: * See "man gethostbyaddr" for more details. sl@0: * sl@0: * Results: sl@0: * Pointer to struct hostent on success or NULL on error. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *--------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: struct hostent * sl@0: TclpGetHostByAddr(const char *addr, int length, int type) sl@0: { sl@0: #if !defined(TCL_THREADS) || defined(HAVE_MTSAFE_GETHOSTBYADDR) sl@0: return gethostbyaddr(addr, length, type); sl@0: #else sl@0: ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); sl@0: sl@0: #if defined(HAVE_GETHOSTBYADDR_R_7) sl@0: int h_errno; sl@0: return gethostbyaddr_r(addr, length, type, &tsdPtr->hent, tsdPtr->hbuf, sl@0: sizeof(tsdPtr->hbuf), &h_errno); sl@0: sl@0: #elif defined(HAVE_GETHOSTBYADDR_R_8) sl@0: struct hostent *hePtr; sl@0: int h_errno; sl@0: return (gethostbyaddr_r(addr, length, type, &tsdPtr->hent, tsdPtr->hbuf, sl@0: sizeof(tsdPtr->hbuf), &hePtr, &h_errno) == 0) ? sl@0: &tsdPtr->hent : NULL; sl@0: #else sl@0: struct hostent *hePtr; sl@0: Tcl_MutexLock(&compatLock); sl@0: hePtr = gethostbyaddr(addr, length, type); sl@0: if (hePtr != NULL) { sl@0: tsdPtr->hent = *hePtr; sl@0: hePtr = &tsdPtr->hent; sl@0: if (CopyHostent(&tsdPtr->hent, tsdPtr->hbuf, sl@0: sizeof(tsdPtr->hbuf)) == -1) { sl@0: hePtr = NULL; sl@0: } sl@0: } sl@0: Tcl_MutexUnlock(&compatLock); sl@0: return hePtr; sl@0: #endif sl@0: return NULL; /* Not reached */ sl@0: #endif /* TCL_THREADS */ sl@0: }