diff options
Diffstat (limited to 'unix/tclUnixCompat.c')
-rw-r--r-- | unix/tclUnixCompat.c | 922 |
1 files changed, 608 insertions, 314 deletions
diff --git a/unix/tclUnixCompat.c b/unix/tclUnixCompat.c index 4ca7da9..0fc51b7 100644 --- a/unix/tclUnixCompat.c +++ b/unix/tclUnixCompat.c @@ -3,25 +3,37 @@ * * Written by: Zoran Vasiljevic (vasiljevic@users.sourceforge.net). * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" -#include "tclPort.h" #include <pwd.h> #include <grp.h> #include <errno.h> #include <string.h> /* + * See also: SC_BLOCKING_STYLE in unix/tcl.m4 + */ + +#ifdef USE_FIONBIO +# ifdef HAVE_SYS_FILIO_H +# include <sys/filio.h> /* For FIONBIO. */ +# endif +# ifdef HAVE_SYS_IOCTL_H +# include <sys/ioctl.h> +# endif +#endif /* USE_FIONBIO */ + +/* * Used to pad structures at size'd boundaries * - * This macro assumes that the pointer 'buffer' was created from an - * aligned pointer by adding the 'length'. If this 'length' was not a - * multiple of the 'size' the result is unaligned and PadBuffer - * corrects both the pointer, _and_ the 'length'. The latter means - * that future increments of 'buffer' by 'length' stay aligned. + * This macro assumes that the pointer 'buffer' was created from an aligned + * pointer by adding the 'length'. If this 'length' was not a multiple of the + * 'size' the result is unaligned and PadBuffer corrects both the pointer, + * _and_ the 'length'. The latter means that future increments of 'buffer' by + * 'length' stay aligned. */ #define PadBuffer(buffer, length, size) \ @@ -31,324 +43,131 @@ } /* - * Per-thread private storage used to store values - * returned from MT-unsafe library calls. + * Per-thread private storage used to store values returned from MT-unsafe + * library calls. */ #ifdef TCL_THREADS typedef struct ThreadSpecificData { - struct passwd pwd; +#if defined(HAVE_GETPWNAM_R_5) || defined(HAVE_GETPWUID_R_5) +#define NEED_PW_CLEANER 1 + char *pbuf; + int pbuflen; +#else char pbuf[2048]; +#endif struct group grp; +#if defined(HAVE_GETGRNAM_R_5) || defined(HAVE_GETGRGID_R_5) +#define NEED_GR_CLEANER 1 + char *gbuf; + int gbuflen; +#else char gbuf[2048]; +#endif #if !defined(HAVE_MTSAFE_GETHOSTBYNAME) || !defined(HAVE_MTSAFE_GETHOSTBYADDR) struct hostent hent; char hbuf[2048]; #endif - } ThreadSpecificData; - static Tcl_ThreadDataKey dataKey; #if ((!defined(HAVE_GETHOSTBYNAME_R) || !defined(HAVE_GETHOSTBYADDR_R)) && \ - (!defined(HAVE_MTSAFE_GETHOSTBYNAME) || !defined(HAVE_MTSAFE_GETHOSTBYADDR))) || \ + (!defined(HAVE_MTSAFE_GETHOSTBYNAME) || \ + !defined(HAVE_MTSAFE_GETHOSTBYADDR))) || \ !defined(HAVE_GETPWNAM_R) || !defined(HAVE_GETPWUID_R) || \ !defined(HAVE_GETGRNAM_R) || !defined(HAVE_GETGRGID_R) - /* - * Mutex to lock access to MT-unsafe calls. This is just to protect - * our own usage. It does not protect us from others calling the - * same functions without (or using some different) lock. + * Mutex to lock access to MT-unsafe calls. This is just to protect our own + * usage. It does not protect us from others calling the same functions + * without (or using some different) lock. */ static Tcl_Mutex compatLock; - -/* - *--------------------------------------------------------------------------- - * - * CopyArray -- - * - * Copies array of NULL-terminated or fixed-length strings - * to the private buffer, honouring the size of the buffer. - * - * Results: - * Number of bytes copied on success or -1 on error (errno = ERANGE) - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ - -static int -CopyArray(char **src, int elsize, char *buf, int buflen) -{ - int i, j, len = 0; - char *p, **new; - - if (src == NULL) { - return 0; - } - for (i = 0; src[i] != NULL; i++) { - /* Empty loop to count howmany */ - } - if ((sizeof(char *)*(i + 1)) > buflen) { - return -1; - } - len = (sizeof(char *)*(i + 1)); /* Leave place for the array */ - new = (char **)buf; - p = buf + (sizeof(char *)*(i + 1)); - for (j = 0; j < i; j++) { - if (elsize < 0) { - len += strlen(src[j]) + 1; - } else { - len += elsize; - } - if (len > buflen) { - return -1; - } - if (elsize < 0) { - strcpy(p, src[j]); - } else { - memcpy(p, src[j], elsize); - } - new[j] = p; - p = buf + len; - } - new[j] = NULL; - - return len; -} - - -/* - *--------------------------------------------------------------------------- - * - * CopyString -- - * - * Copies a NULL-terminated string to the private buffer, - * honouring the size of the buffer - * - * Results: - * 0 success or -1 on error (errno = ERANGE) - * - * Side effects: - * None - * - *--------------------------------------------------------------------------- - */ - - -static int -CopyString(CONST char *src, char *buf, int buflen) -{ - int len = 0; - - if (src != NULL) { - len += strlen(src) + 1; - if (len > buflen) { - return -1; - } - strcpy(buf, src); - } - - return len; -} -#endif /* ((!defined(HAVE_GETHOSTBYNAME_R) || !defined(HAVE_GETHOSTBYADDR_R)) && \ - (!defined(HAVE_MTSAFE_GETHOSTBYNAME) || !defined(HAVE_MTSAFE_GETHOSTBYADDR))) || \ - !defined(HAVE_GETPWNAM_R) || !defined(HAVE_GETPWUID_R) || \ - !defined(HAVE_GETGRNAM_R) || !defined(HAVE_GETGRGID_R) */ - -#if (!defined(HAVE_GETHOSTBYNAME_R) || !defined(HAVE_GETHOSTBYADDR_R)) && \ - (!defined(HAVE_MTSAFE_GETHOSTBYNAME) || !defined(HAVE_MTSAFE_GETHOSTBYADDR)) - -/* - *--------------------------------------------------------------------------- - * - * CopyHostnent -- - * - * Copies string fields of the hostnent structure to the - * private buffer, honouring the size of the buffer. - * - * Results: - * Number of bytes copied on success or -1 on error (errno = ERANGE) - * - * Side effects: - * None - * - *--------------------------------------------------------------------------- - */ - -static int -CopyHostent(struct hostent *tgtPtr, char *buf, int buflen) -{ - char *p = buf; - int copied, len = 0; - - copied = CopyString(tgtPtr->h_name, p, buflen - len); - if (copied == -1) { - range: - errno = ERANGE; - return -1; - } - tgtPtr->h_name = (copied > 0) ? p : NULL; - len += copied; - p = buf + len; - - PadBuffer(p, len, sizeof(char *)); - copied = CopyArray(tgtPtr->h_aliases, -1, p, buflen - len); - if (copied == -1) { - goto range; - } - tgtPtr->h_aliases = (copied > 0) ? (char **)p : NULL; - len += copied; - p += len; - - PadBuffer(p, len, sizeof(char *)); - copied = CopyArray(tgtPtr->h_addr_list, tgtPtr->h_length, p, buflen - len); - if (copied == -1) { - goto range; - } - tgtPtr->h_addr_list = (copied > 0) ? (char **)p : NULL; - return 0; -} -#endif /* (!defined(HAVE_GETHOSTBYNAME_R) || !defined(HAVE_GETHOSTBYADDR_R)) && \ - (!defined(HAVE_MTSAFE_GETHOSTBYNAME) || !defined(HAVE_MTSAFE_GETHOSTBYADDR)) */ - -#if !defined(HAVE_GETPWNAM_R) || !defined(HAVE_GETPWUID_R) - /* - *--------------------------------------------------------------------------- - * - * CopyPwd -- - * - * Copies string fields of the passwd structure to the - * private buffer, honouring the size of the buffer. - * - * Results: - * 0 on success or -1 on error (errno = ERANGE) - * - * Side effects: - * We are not copying the gecos field as it may not be supported - * on all platforms. - * - *--------------------------------------------------------------------------- + * Helper function declarations. Note that these are only used if needed and + * only defined if used (via the NEED_* macros). */ -static int -CopyPwd(struct passwd *tgtPtr, char *buf, int buflen) -{ - char *p = buf; - int copied, len = 0; - - copied = CopyString(tgtPtr->pw_name, p, buflen - len); - if (copied == -1) { - range: - errno = ERANGE; - return -1; - } - tgtPtr->pw_name = (copied > 0) ? p : NULL; - len += copied; - p = buf + len; +#undef NEED_COPYARRAY +#undef NEED_COPYGRP +#undef NEED_COPYHOSTENT +#undef NEED_COPYPWD +#undef NEED_COPYSTRING - copied = CopyString(tgtPtr->pw_passwd, p, buflen - len); - if (copied == -1) { - goto range; - } - tgtPtr->pw_passwd = (copied > 0) ? p : NULL; - len += copied; - p = buf + len; +#if !defined(HAVE_GETGRNAM_R_5) && !defined(HAVE_GETGRNAM_R_4) +#define NEED_COPYGRP 1 +static int CopyGrp(struct group *tgtPtr, char *buf, int buflen); +#endif - copied = CopyString(tgtPtr->pw_dir, p, buflen - len); - if (copied == -1) { - goto range; - } - tgtPtr->pw_dir = (copied > 0) ? p : NULL; - len += copied; - p = buf + len; +#if !defined(HAVE_GETPWNAM_R_5) && !defined(HAVE_GETPWNAM_R_4) +#define NEED_COPYPWD 1 +static int CopyPwd(struct passwd *tgtPtr, char *buf, int buflen); +#endif - copied = CopyString(tgtPtr->pw_shell, p, buflen - len); - if (copied == -1) { - goto range; - } - tgtPtr->pw_shell = (copied > 0) ? p : NULL; +static int CopyArray(char **src, int elsize, char *buf, + int buflen); +static int CopyHostent(struct hostent *tgtPtr, char *buf, + int buflen); +static int CopyString(const char *src, char *buf, int buflen); - return 0; -} -#endif /* !defined(HAVE_GETPWNAM_R) || !defined(HAVE_GETPWUID_R) */ +#endif -#if !defined(HAVE_GETGRNAM_R) || !defined(HAVE_GETGRGID_R) +#ifdef NEED_PW_CLEANER +static void FreePwBuf(ClientData ignored); +#endif +#ifdef NEED_GR_CLEANER +static void FreeGrBuf(ClientData ignored); +#endif +#endif /* TCL_THREADS */ /* *--------------------------------------------------------------------------- * - * CopyGrp -- + * TclUnixSetBlockingMode -- * - * Copies string fields of the group structure to the - * private buffer, honouring the size of the buffer. + * Set the blocking mode of a file descriptor. * * Results: - * 0 on success or -1 on error (errno = ERANGE) * - * Side effects: - * None. + * 0 on success, -1 (with errno set) on error. * *--------------------------------------------------------------------------- */ -static int -CopyGrp(struct group *tgtPtr, char *buf, int buflen) +int +TclUnixSetBlockingMode( + int fd, /* File descriptor */ + int mode) /* Either TCL_MODE_BLOCKING or + * TCL_MODE_NONBLOCKING. */ { - register char *p = buf; - register int copied, len = 0; - - /* Copy username */ - copied = CopyString(tgtPtr->gr_name, p, buflen - len); - if (copied == -1) { - range: - errno = ERANGE; - return -1; - } - tgtPtr->gr_name = (copied > 0) ? p : NULL; - len += copied; - p = buf + len; - - /* Copy password */ - copied = CopyString(tgtPtr->gr_passwd, p, buflen - len); - if (copied == -1) { - goto range; - } - tgtPtr->gr_passwd = (copied > 0) ? p : NULL; - len += copied; - p = buf + len; +#ifndef USE_FIONBIO + int flags = fcntl(fd, F_GETFL); - /* Copy group members */ - PadBuffer(p, len, sizeof(char *)); - copied = CopyArray((char **)tgtPtr->gr_mem, -1, p, buflen - len); - if (copied == -1) { - goto range; + if (mode == TCL_MODE_BLOCKING) { + flags &= ~O_NONBLOCK; + } else { + flags |= O_NONBLOCK; } - tgtPtr->gr_mem = (copied > 0) ? (char **)p : NULL; + return fcntl(fd, F_SETFL, flags); +#else /* USE_FIONBIO */ + int state = (mode == TCL_MODE_NONBLOCKING); - return 0; + return ioctl(fd, FIONBIO, &state); +#endif /* !USE_FIONBIO */ } -#endif /* !defined(HAVE_GETGRNAM_R) || !defined(HAVE_GETGRGID_R) */ - -#endif /* TCL_THREADS */ - /* *--------------------------------------------------------------------------- * * TclpGetPwNam -- * - * Thread-safe wrappers for getpwnam(). - * See "man getpwnam" for more details. + * Thread-safe wrappers for getpwnam(). See "man getpwnam" for more + * details. * * Results: * Pointer to struct passwd on success or NULL on error. @@ -360,7 +179,8 @@ CopyGrp(struct group *tgtPtr, char *buf, int buflen) */ struct passwd * -TclpGetPwNam(const char *name) +TclpGetPwNam( + const char *name) { #if !defined(TCL_THREADS) return getpwnam(name); @@ -369,14 +189,41 @@ TclpGetPwNam(const char *name) #if defined(HAVE_GETPWNAM_R_5) struct passwd *pwPtr = NULL; - return (getpwnam_r(name, &tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf), - &pwPtr) == 0 && pwPtr != NULL) ? &tsdPtr->pwd : NULL; + + /* + * How to allocate a buffer of the right initial size. If you want the + * gory detail, see http://www.opengroup.org/austin/docs/austin_328.txt + * and weep. + */ + + if (tsdPtr->pbuf == NULL) { + tsdPtr->pbuflen = (int) sysconf(_SC_GETPW_R_SIZE_MAX); + if (tsdPtr->pbuflen < 1) { + tsdPtr->pbuflen = 1024; + } + tsdPtr->pbuf = ckalloc(tsdPtr->pbuflen); + Tcl_CreateThreadExitHandler(FreePwBuf, NULL); + } + while (1) { + int e = getpwnam_r(name, &tsdPtr->pwd, tsdPtr->pbuf, tsdPtr->pbuflen, + &pwPtr); + + if (e == 0) { + break; + } else if (e != ERANGE) { + return NULL; + } + tsdPtr->pbuflen *= 2; + tsdPtr->pbuf = ckrealloc(tsdPtr->pbuf, tsdPtr->pbuflen); + } + return (pwPtr != NULL ? &tsdPtr->pwd : NULL); #elif defined(HAVE_GETPWNAM_R_4) return getpwnam_r(name, &tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf)); #else struct passwd *pwPtr; + Tcl_MutexLock(&compatLock); pwPtr = getpwnam(name); if (pwPtr != NULL) { @@ -389,18 +236,18 @@ TclpGetPwNam(const char *name) Tcl_MutexUnlock(&compatLock); return pwPtr; #endif - return NULL; /* Not reached */ + + return NULL; /* Not reached. */ #endif /* TCL_THREADS */ } - /* *--------------------------------------------------------------------------- * * TclpGetPwUid -- * - * Thread-safe wrappers for getpwuid(). - * See "man getpwuid" for more details. + * Thread-safe wrappers for getpwuid(). See "man getpwuid" for more + * details. * * Results: * Pointer to struct passwd on success or NULL on error. @@ -412,7 +259,8 @@ TclpGetPwNam(const char *name) */ struct passwd * -TclpGetPwUid(uid_t uid) +TclpGetPwUid( + uid_t uid) { #if !defined(TCL_THREADS) return getpwuid(uid); @@ -421,14 +269,41 @@ TclpGetPwUid(uid_t uid) #if defined(HAVE_GETPWUID_R_5) struct passwd *pwPtr = NULL; - return (getpwuid_r(uid, &tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf), - &pwPtr) == 0 && pwPtr != NULL) ? &tsdPtr->pwd : NULL; + + /* + * How to allocate a buffer of the right initial size. If you want the + * gory detail, see http://www.opengroup.org/austin/docs/austin_328.txt + * and weep. + */ + + if (tsdPtr->pbuf == NULL) { + tsdPtr->pbuflen = (int) sysconf(_SC_GETPW_R_SIZE_MAX); + if (tsdPtr->pbuflen < 1) { + tsdPtr->pbuflen = 1024; + } + tsdPtr->pbuf = ckalloc(tsdPtr->pbuflen); + Tcl_CreateThreadExitHandler(FreePwBuf, NULL); + } + while (1) { + int e = getpwuid_r(uid, &tsdPtr->pwd, tsdPtr->pbuf, tsdPtr->pbuflen, + &pwPtr); + + if (e == 0) { + break; + } else if (e != ERANGE) { + return NULL; + } + tsdPtr->pbuflen *= 2; + tsdPtr->pbuf = ckrealloc(tsdPtr->pbuf, tsdPtr->pbuflen); + } + return (pwPtr != NULL ? &tsdPtr->pwd : NULL); #elif defined(HAVE_GETPWUID_R_4) return getpwuid_r(uid, &tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf)); #else struct passwd *pwPtr; + Tcl_MutexLock(&compatLock); pwPtr = getpwuid(uid); if (pwPtr != NULL) { @@ -441,18 +316,41 @@ TclpGetPwUid(uid_t uid) Tcl_MutexUnlock(&compatLock); return pwPtr; #endif - return NULL; /* Not reached */ + + return NULL; /* Not reached. */ #endif /* TCL_THREADS */ } + +/* + *--------------------------------------------------------------------------- + * + * FreePwBuf -- + * + * Helper that is used to dispose of space allocated and referenced from + * the ThreadSpecificData for user entries. (Darn that baroque POSIX + * reentrant interface.) + * + *--------------------------------------------------------------------------- + */ + +#ifdef NEED_PW_CLEANER +static void +FreePwBuf( + ClientData ignored) +{ + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + ckfree(tsdPtr->pbuf); +} +#endif /* NEED_PW_CLEANER */ /* *--------------------------------------------------------------------------- * * TclpGetGrNam -- * - * Thread-safe wrappers for getgrnam(). - * See "man getgrnam" for more details. + * Thread-safe wrappers for getgrnam(). See "man getgrnam" for more + * details. * * Results: * Pointer to struct group on success or NULL on error. @@ -464,23 +362,51 @@ TclpGetPwUid(uid_t uid) */ struct group * -TclpGetGrNam(const char *name) +TclpGetGrNam( + const char *name) { #if !defined(TCL_THREADS) return getgrnam(name); #else ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); -#if defined(HAVE_GETGRNAM_R_5) +#ifdef HAVE_GETGRNAM_R_5 struct group *grPtr = NULL; - return (getgrnam_r(name, &tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf), - &grPtr) == 0 && grPtr != NULL) ? &tsdPtr->grp : NULL; + + /* + * How to allocate a buffer of the right initial size. If you want the + * gory detail, see http://www.opengroup.org/austin/docs/austin_328.txt + * and weep. + */ + + if (tsdPtr->gbuf == NULL) { + tsdPtr->gbuflen = (int) sysconf(_SC_GETGR_R_SIZE_MAX); + if (tsdPtr->gbuflen < 1) { + tsdPtr->gbuflen = 1024; + } + tsdPtr->gbuf = ckalloc(tsdPtr->gbuflen); + Tcl_CreateThreadExitHandler(FreeGrBuf, NULL); + } + while (1) { + int e = getgrnam_r(name, &tsdPtr->grp, tsdPtr->gbuf, tsdPtr->gbuflen, + &grPtr); + + if (e == 0) { + break; + } else if (e != ERANGE) { + return NULL; + } + tsdPtr->gbuflen *= 2; + tsdPtr->gbuf = ckrealloc(tsdPtr->gbuf, tsdPtr->gbuflen); + } + return (grPtr != NULL ? &tsdPtr->grp : NULL); #elif defined(HAVE_GETGRNAM_R_4) return getgrnam_r(name, &tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf)); #else struct group *grPtr; + Tcl_MutexLock(&compatLock); grPtr = getgrnam(name); if (grPtr != NULL) { @@ -493,18 +419,18 @@ TclpGetGrNam(const char *name) Tcl_MutexUnlock(&compatLock); return grPtr; #endif - return NULL; /* Not reached */ + + return NULL; /* Not reached. */ #endif /* TCL_THREADS */ } - /* *--------------------------------------------------------------------------- * * TclpGetGrGid -- * - * Thread-safe wrappers for getgrgid(). - * See "man getgrgid" for more details. + * Thread-safe wrappers for getgrgid(). See "man getgrgid" for more + * details. * * Results: * Pointer to struct group on success or NULL on error. @@ -516,7 +442,8 @@ TclpGetGrNam(const char *name) */ struct group * -TclpGetGrGid(gid_t gid) +TclpGetGrGid( + gid_t gid) { #if !defined(TCL_THREADS) return getgrgid(gid); @@ -525,14 +452,41 @@ TclpGetGrGid(gid_t gid) #if defined(HAVE_GETGRGID_R_5) struct group *grPtr = NULL; - return (getgrgid_r(gid, &tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf), - &grPtr) == 0 && grPtr != NULL) ? &tsdPtr->grp : NULL; + + /* + * How to allocate a buffer of the right initial size. If you want the + * gory detail, see http://www.opengroup.org/austin/docs/austin_328.txt + * and weep. + */ + + if (tsdPtr->gbuf == NULL) { + tsdPtr->gbuflen = (int) sysconf(_SC_GETGR_R_SIZE_MAX); + if (tsdPtr->gbuflen < 1) { + tsdPtr->gbuflen = 1024; + } + tsdPtr->gbuf = ckalloc(tsdPtr->gbuflen); + Tcl_CreateThreadExitHandler(FreeGrBuf, NULL); + } + while (1) { + int e = getgrgid_r(gid, &tsdPtr->grp, tsdPtr->gbuf, tsdPtr->gbuflen, + &grPtr); + + if (e == 0) { + break; + } else if (e != ERANGE) { + return NULL; + } + tsdPtr->gbuflen *= 2; + tsdPtr->gbuf = ckrealloc(tsdPtr->gbuf, tsdPtr->gbuflen); + } + return (grPtr != NULL ? &tsdPtr->grp : NULL); #elif defined(HAVE_GETGRGID_R_4) return getgrgid_r(gid, &tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf)); #else struct group *grPtr; + Tcl_MutexLock(&compatLock); grPtr = getgrgid(gid); if (grPtr != NULL) { @@ -545,18 +499,41 @@ TclpGetGrGid(gid_t gid) Tcl_MutexUnlock(&compatLock); return grPtr; #endif - return NULL; /* Not reached */ + + return NULL; /* Not reached. */ #endif /* TCL_THREADS */ } + +/* + *--------------------------------------------------------------------------- + * + * FreeGrBuf -- + * + * Helper that is used to dispose of space allocated and referenced from + * the ThreadSpecificData for group entries. (Darn that baroque POSIX + * reentrant interface.) + * + *--------------------------------------------------------------------------- + */ + +#ifdef NEED_GR_CLEANER +static void +FreeGrBuf( + ClientData ignored) +{ + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + ckfree(tsdPtr->gbuf); +} +#endif /* NEED_GR_CLEANER */ /* *--------------------------------------------------------------------------- * * TclpGetHostByName -- * - * Thread-safe wrappers for gethostbyname(). - * See "man gethostbyname" for more details. + * Thread-safe wrappers for gethostbyname(). See "man gethostbyname" for + * more details. * * Results: * Pointer to struct hostent on success or NULL on error. @@ -568,7 +545,8 @@ TclpGetGrGid(gid_t gid) */ struct hostent * -TclpGetHostByName(const char *name) +TclpGetHostByName( + const char *name) { #if !defined(TCL_THREADS) || defined(HAVE_MTSAFE_GETHOSTBYNAME) return gethostbyname(name); @@ -577,48 +555,53 @@ TclpGetHostByName(const char *name) #if defined(HAVE_GETHOSTBYNAME_R_5) int h_errno; + return gethostbyname_r(name, &tsdPtr->hent, tsdPtr->hbuf, sizeof(tsdPtr->hbuf), &h_errno); #elif defined(HAVE_GETHOSTBYNAME_R_6) - struct hostent *hePtr; - int result, h_errno; + struct hostent *hePtr = NULL; + int h_errno, result; result = gethostbyname_r(name, &tsdPtr->hent, tsdPtr->hbuf, - sizeof(tsdPtr->hbuf), &hePtr, &h_errno); + sizeof(tsdPtr->hbuf), &hePtr, &h_errno); return (result == 0) ? hePtr : NULL; #elif defined(HAVE_GETHOSTBYNAME_R_3) struct hostent_data data; - return (gethostbyname_r(name, &tsdPtr->hent, &data) == 0) ? - &tsdPtr->hent : NULL; + + return (gethostbyname_r(name, &tsdPtr->hent, &data) == 0) + ? &tsdPtr->hent : NULL; + #else +#define NEED_COPYHOSTENT 1 struct hostent *hePtr; + Tcl_MutexLock(&compatLock); hePtr = gethostbyname(name); if (hePtr != NULL) { tsdPtr->hent = *hePtr; hePtr = &tsdPtr->hent; if (CopyHostent(&tsdPtr->hent, tsdPtr->hbuf, - sizeof(tsdPtr->hbuf)) == -1) { + sizeof(tsdPtr->hbuf)) == -1) { hePtr = NULL; } } Tcl_MutexUnlock(&compatLock); return hePtr; #endif - return NULL; /* Not reached */ + + return NULL; /* Not reached. */ #endif /* TCL_THREADS */ } - /* *--------------------------------------------------------------------------- * * TclpGetHostByAddr -- * - * Thread-safe wrappers for gethostbyaddr(). - * See "man gethostbyaddr" for more details. + * Thread-safe wrappers for gethostbyaddr(). See "man gethostbyaddr" for + * more details. * * Results: * Pointer to struct hostent on success or NULL on error. @@ -630,7 +613,10 @@ TclpGetHostByName(const char *name) */ struct hostent * -TclpGetHostByAddr(const char *addr, int length, int type) +TclpGetHostByAddr( + const char *addr, + int length, + int type) { #if !defined(TCL_THREADS) || defined(HAVE_MTSAFE_GETHOSTBYADDR) return gethostbyaddr(addr, length, type); @@ -639,34 +625,342 @@ TclpGetHostByAddr(const char *addr, int length, int type) #if defined(HAVE_GETHOSTBYADDR_R_7) int h_errno; + return gethostbyaddr_r(addr, length, type, &tsdPtr->hent, tsdPtr->hbuf, - sizeof(tsdPtr->hbuf), &h_errno); + sizeof(tsdPtr->hbuf), &h_errno); #elif defined(HAVE_GETHOSTBYADDR_R_8) struct hostent *hePtr; int h_errno; + return (gethostbyaddr_r(addr, length, type, &tsdPtr->hent, tsdPtr->hbuf, - sizeof(tsdPtr->hbuf), &hePtr, &h_errno) == 0) ? - &tsdPtr->hent : NULL; + sizeof(tsdPtr->hbuf), &hePtr, &h_errno) == 0) + ? &tsdPtr->hent : NULL; #else +#define NEED_COPYHOSTENT 1 struct hostent *hePtr; + Tcl_MutexLock(&compatLock); hePtr = gethostbyaddr(addr, length, type); if (hePtr != NULL) { tsdPtr->hent = *hePtr; hePtr = &tsdPtr->hent; if (CopyHostent(&tsdPtr->hent, tsdPtr->hbuf, - sizeof(tsdPtr->hbuf)) == -1) { + sizeof(tsdPtr->hbuf)) == -1) { hePtr = NULL; } } Tcl_MutexUnlock(&compatLock); return hePtr; #endif - return NULL; /* Not reached */ + + return NULL; /* Not reached. */ #endif /* TCL_THREADS */ } + +/* + *--------------------------------------------------------------------------- + * + * CopyGrp -- + * + * Copies string fields of the group structure to the private buffer, + * honouring the size of the buffer. + * + * Results: + * 0 on success or -1 on error (errno = ERANGE). + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +#ifdef NEED_COPYGRP +#define NEED_COPYARRAY 1 +#define NEED_COPYSTRING 1 + +static int +CopyGrp( + struct group *tgtPtr, + char *buf, + int buflen) +{ + register char *p = buf; + register int copied, len = 0; + + /* + * Copy username. + */ + + copied = CopyString(tgtPtr->gr_name, p, buflen - len); + if (copied == -1) { + goto range; + } + tgtPtr->gr_name = (copied > 0) ? p : NULL; + len += copied; + p = buf + len; + + /* + * Copy password. + */ + + copied = CopyString(tgtPtr->gr_passwd, p, buflen - len); + if (copied == -1) { + goto range; + } + tgtPtr->gr_passwd = (copied > 0) ? p : NULL; + len += copied; + p = buf + len; + + /* + * Copy group members. + */ + + PadBuffer(p, len, sizeof(char *)); + copied = CopyArray((char **)tgtPtr->gr_mem, -1, p, buflen - len); + if (copied == -1) { + goto range; + } + tgtPtr->gr_mem = (copied > 0) ? (char **)p : NULL; + + return 0; + + range: + errno = ERANGE; + return -1; +} +#endif /* NEED_COPYGRP */ + +/* + *--------------------------------------------------------------------------- + * + * CopyHostent -- + * + * Copies string fields of the hostnent structure to the private buffer, + * honouring the size of the buffer. + * + * Results: + * Number of bytes copied on success or -1 on error (errno = ERANGE) + * + * Side effects: + * None + * + *--------------------------------------------------------------------------- + */ + +#ifdef NEED_COPYHOSTENT +#define NEED_COPYSTRING 1 +#define NEED_COPYARRAY 1 + +static int +CopyHostent( + struct hostent *tgtPtr, + char *buf, + int buflen) +{ + char *p = buf; + int copied, len = 0; + + copied = CopyString(tgtPtr->h_name, p, buflen - len); + if (copied == -1) { + goto range; + } + tgtPtr->h_name = (copied > 0) ? p : NULL; + len += copied; + p = buf + len; + + PadBuffer(p, len, sizeof(char *)); + copied = CopyArray(tgtPtr->h_aliases, -1, p, buflen - len); + if (copied == -1) { + goto range; + } + tgtPtr->h_aliases = (copied > 0) ? (char **)p : NULL; + len += copied; + p += len; + + PadBuffer(p, len, sizeof(char *)); + copied = CopyArray(tgtPtr->h_addr_list, tgtPtr->h_length, p, buflen-len); + if (copied == -1) { + goto range; + } + tgtPtr->h_addr_list = (copied > 0) ? (char **)p : NULL; + + return 0; + + range: + errno = ERANGE; + return -1; +} +#endif /* NEED_COPYHOSTENT */ + +/* + *--------------------------------------------------------------------------- + * + * CopyPwd -- + * + * Copies string fields of the passwd structure to the private buffer, + * honouring the size of the buffer. + * + * Results: + * 0 on success or -1 on error (errno = ERANGE). + * + * Side effects: + * We are not copying the gecos field as it may not be supported on all + * platforms. + * + *--------------------------------------------------------------------------- + */ + +#ifdef NEED_COPYPWD +#define NEED_COPYSTRING 1 + +static int +CopyPwd( + struct passwd *tgtPtr, + char *buf, + int buflen) +{ + char *p = buf; + int copied, len = 0; + + copied = CopyString(tgtPtr->pw_name, p, buflen - len); + if (copied == -1) { + range: + errno = ERANGE; + return -1; + } + tgtPtr->pw_name = (copied > 0) ? p : NULL; + len += copied; + p = buf + len; + + copied = CopyString(tgtPtr->pw_passwd, p, buflen - len); + if (copied == -1) { + goto range; + } + tgtPtr->pw_passwd = (copied > 0) ? p : NULL; + len += copied; + p = buf + len; + + copied = CopyString(tgtPtr->pw_dir, p, buflen - len); + if (copied == -1) { + goto range; + } + tgtPtr->pw_dir = (copied > 0) ? p : NULL; + len += copied; + p = buf + len; + + copied = CopyString(tgtPtr->pw_shell, p, buflen - len); + if (copied == -1) { + goto range; + } + tgtPtr->pw_shell = (copied > 0) ? p : NULL; + + return 0; +} +#endif /* NEED_COPYPWD */ + +/* + *--------------------------------------------------------------------------- + * + * CopyArray -- + * + * Copies array of NULL-terminated or fixed-length strings to the private + * buffer, honouring the size of the buffer. + * + * Results: + * Number of bytes copied on success or -1 on error (errno = ERANGE) + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +#ifdef NEED_COPYARRAY +static int +CopyArray( + char **src, /* Array of elements to copy. */ + int elsize, /* Size of each element, or -1 to indicate + * that they are C strings of dynamic + * length. */ + char *buf, /* Buffer to copy into. */ + int buflen) /* Size of buffer. */ +{ + int i, j, len = 0; + char *p, **new; + + if (src == NULL) { + return 0; + } + + for (i = 0; src[i] != NULL; i++) { + /* + * Empty loop to count how many. + */ + } + len = sizeof(char *) * (i + 1); /* Leave place for the array. */ + if (len > buflen) { + return -1; + } + + new = (char **) buf; + p = buf + len; + + for (j = 0; j < i; j++) { + int sz = (elsize<0 ? (int) strlen(src[j]) + 1 : elsize); + + len += sz; + if (len > buflen) { + return -1; + } + memcpy(p, src[j], sz); + new[j] = p; + p = buf + len; + } + new[j] = NULL; + + return len; +} +#endif /* NEED_COPYARRAY */ + +/* + *--------------------------------------------------------------------------- + * + * CopyString -- + * + * Copies a NULL-terminated string to the private buffer, honouring the + * size of the buffer + * + * Results: + * 0 success or -1 on error (errno = ERANGE) + * + * Side effects: + * None + * + *--------------------------------------------------------------------------- + */ + +#ifdef NEED_COPYSTRING +static int +CopyString( + const char *src, /* String to copy. */ + char *buf, /* Buffer to copy into. */ + int buflen) /* Size of buffer. */ +{ + int len = 0; + + if (src != NULL) { + len = strlen(src) + 1; + if (len > buflen) { + return -1; + } + memcpy(buf, src, len); + } + return len; +} +#endif /* NEED_COPYSTRING */ + /* *------------------------------------------------------------------------ * @@ -710,7 +1004,7 @@ TclWinCPUID( #endif return status; } - + /* * Local Variables: * mode: c |