tclUnixCompat.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:16k
- /*
- * tclUnixCompat.c
- *
- * 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.
- *
- * RCS: @(#) $Id: tclUnixCompat.c,v 1.1.2.12 2007/12/14 12:45:48 vasiljevic Exp $
- *
- */
- #include "tclInt.h"
- #include "tclPort.h"
- #include <pwd.h>
- #include <grp.h>
- #include <errno.h>
- #include <string.h>
- /*
- * 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.
- */
- #define PadBuffer(buffer, length, size)
- if (((length) % (size))) {
- (buffer) += ((size) - ((length) % (size)));
- (length) += ((size) - ((length) % (size)));
- }
- /*
- * Per-thread private storage used to store values
- * returned from MT-unsafe library calls.
- */
- #ifdef TCL_THREADS
- typedef struct ThreadSpecificData {
- struct passwd pwd;
- char pbuf[2048];
- struct group grp;
- char gbuf[2048];
- #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_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.
- */
- 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(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.
- *
- *---------------------------------------------------------------------------
- */
- 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 /* !defined(HAVE_GETPWNAM_R) || !defined(HAVE_GETPWUID_R) */
- #if !defined(HAVE_GETGRNAM_R) || !defined(HAVE_GETGRGID_R)
- /*
- *---------------------------------------------------------------------------
- *
- * 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.
- *
- *---------------------------------------------------------------------------
- */
- 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) {
- 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;
- /* 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;
- }
- #endif /* !defined(HAVE_GETGRNAM_R) || !defined(HAVE_GETGRGID_R) */
- #endif /* TCL_THREADS */
- /*
- *---------------------------------------------------------------------------
- *
- * TclpGetPwNam --
- *
- * Thread-safe wrappers for getpwnam().
- * See "man getpwnam" for more details.
- *
- * Results:
- * Pointer to struct passwd on success or NULL on error.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
- struct passwd *
- TclpGetPwNam(const char *name)
- {
- #if !defined(TCL_THREADS)
- return getpwnam(name);
- #else
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- #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;
- #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) {
- tsdPtr->pwd = *pwPtr;
- pwPtr = &tsdPtr->pwd;
- if (CopyPwd(&tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf)) == -1) {
- pwPtr = NULL;
- }
- }
- Tcl_MutexUnlock(&compatLock);
- return pwPtr;
- #endif
- return NULL; /* Not reached */
- #endif /* TCL_THREADS */
- }
- /*
- *---------------------------------------------------------------------------
- *
- * TclpGetPwUid --
- *
- * Thread-safe wrappers for getpwuid().
- * See "man getpwuid" for more details.
- *
- * Results:
- * Pointer to struct passwd on success or NULL on error.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
- struct passwd *
- TclpGetPwUid(uid_t uid)
- {
- #if !defined(TCL_THREADS)
- return getpwuid(uid);
- #else
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- #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;
- #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) {
- tsdPtr->pwd = *pwPtr;
- pwPtr = &tsdPtr->pwd;
- if (CopyPwd(&tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf)) == -1) {
- pwPtr = NULL;
- }
- }
- Tcl_MutexUnlock(&compatLock);
- return pwPtr;
- #endif
- return NULL; /* Not reached */
- #endif /* TCL_THREADS */
- }
- /*
- *---------------------------------------------------------------------------
- *
- * TclpGetGrNam --
- *
- * Thread-safe wrappers for getgrnam().
- * See "man getgrnam" for more details.
- *
- * Results:
- * Pointer to struct group on success or NULL on error.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
- struct group *
- TclpGetGrNam(const char *name)
- {
- #if !defined(TCL_THREADS)
- return getgrnam(name);
- #else
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- #if defined(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;
- #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) {
- tsdPtr->grp = *grPtr;
- grPtr = &tsdPtr->grp;
- if (CopyGrp(&tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf)) == -1) {
- grPtr = NULL;
- }
- }
- Tcl_MutexUnlock(&compatLock);
- return grPtr;
- #endif
- return NULL; /* Not reached */
- #endif /* TCL_THREADS */
- }
- /*
- *---------------------------------------------------------------------------
- *
- * TclpGetGrGid --
- *
- * Thread-safe wrappers for getgrgid().
- * See "man getgrgid" for more details.
- *
- * Results:
- * Pointer to struct group on success or NULL on error.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
- struct group *
- TclpGetGrGid(gid_t gid)
- {
- #if !defined(TCL_THREADS)
- return getgrgid(gid);
- #else
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- #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;
- #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) {
- tsdPtr->grp = *grPtr;
- grPtr = &tsdPtr->grp;
- if (CopyGrp(&tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf)) == -1) {
- grPtr = NULL;
- }
- }
- Tcl_MutexUnlock(&compatLock);
- return grPtr;
- #endif
- return NULL; /* Not reached */
- #endif /* TCL_THREADS */
- }
- /*
- *---------------------------------------------------------------------------
- *
- * TclpGetHostByName --
- *
- * Thread-safe wrappers for gethostbyname().
- * See "man gethostbyname" for more details.
- *
- * Results:
- * Pointer to struct hostent on success or NULL on error.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
- struct hostent *
- TclpGetHostByName(const char *name)
- {
- #if !defined(TCL_THREADS) || defined(HAVE_MTSAFE_GETHOSTBYNAME)
- return gethostbyname(name);
- #else
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- #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;
- result = gethostbyname_r(name, &tsdPtr->hent, tsdPtr->hbuf,
- 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;
- #else
- 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) {
- hePtr = NULL;
- }
- }
- Tcl_MutexUnlock(&compatLock);
- return hePtr;
- #endif
- return NULL; /* Not reached */
- #endif /* TCL_THREADS */
- }
- /*
- *---------------------------------------------------------------------------
- *
- * TclpGetHostByAddr --
- *
- * Thread-safe wrappers for gethostbyaddr().
- * See "man gethostbyaddr" for more details.
- *
- * Results:
- * Pointer to struct hostent on success or NULL on error.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
- struct hostent *
- TclpGetHostByAddr(const char *addr, int length, int type)
- {
- #if !defined(TCL_THREADS) || defined(HAVE_MTSAFE_GETHOSTBYADDR)
- return gethostbyaddr(addr, length, type);
- #else
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- #if defined(HAVE_GETHOSTBYADDR_R_7)
- int h_errno;
- return gethostbyaddr_r(addr, length, type, &tsdPtr->hent, tsdPtr->hbuf,
- 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;
- #else
- 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) {
- hePtr = NULL;
- }
- }
- Tcl_MutexUnlock(&compatLock);
- return hePtr;
- #endif
- return NULL; /* Not reached */
- #endif /* TCL_THREADS */
- }