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: }