diff options
-rw-r--r-- | unix/tclUnixCompat.c | 584 |
1 files changed, 584 insertions, 0 deletions
diff --git a/unix/tclUnixCompat.c b/unix/tclUnixCompat.c new file mode 100644 index 0000000..691264f --- /dev/null +++ b/unix/tclUnixCompat.c @@ -0,0 +1,584 @@ +/* + * 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.2 2006/09/06 13:25:29 vasiljevic Exp $ + * + */ + +#include "tclInt.h" +#include "tclPort.h" +#include <pwd.h> +#include <grp.h> +#include <errno.h> +#include <string.h> + +/* + * 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. + */ + +Tcl_Mutex compatLock; + +#if !defined(HAVE_GETHOSTBYNAME_R) || !defined(HAVE_GETHOSTBYADDR_R) || \ + !defined(HAVE_GETPWNAM_R) || !defined(HAVE_GETGRNAM_R) + + +/* + *--------------------------------------------------------------------------- + * + * CopyArray -- + * + * Copies array of strings (or fixed values) 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 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_GETPWNAM_R) || !defined(HAVE_GETGRNAM_R) */ + + +/* + *--------------------------------------------------------------------------- + * + * 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 + * + *--------------------------------------------------------------------------- + */ + +#if !defined(HAVE_GETHOSTBYNAME_R) || !defined(HAVE_GETHOSTBYADDR_R) +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; + + 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; + + 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) */ + + +/* + *--------------------------------------------------------------------------- + * + * 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. + * + *--------------------------------------------------------------------------- + */ + +#if !defined(HAVE_GETPWNAM_R) || !defined(HAVE_GETPWUID_R) +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 /* HAVE_GETPWNAM_R || HAVE_GETPWUID_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. + * + *--------------------------------------------------------------------------- + */ + +#if !defined(HAVE_GETGRNAM_R) || !defined(HAVE_GETGRGID_R) +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 */ + 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 /* HAVE_GETGRNAM_R || HAVE_GETGRGID_R*/ + + +/* + *--------------------------------------------------------------------------- + * + * TclpGetPwNam -- + * + * Thread-safe wrappers for getpwnam(). + * See "man getpwnam" for more details. + * + * Results: + * 0 on success or -1 on error. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +int +TclpGetPwNam(const char *name, struct passwd *pwbuf, char *buf, size_t buflen, + struct passwd **pwbufp) +{ + int result = 0; + +#if defined(HAVE_GETPWNAM_R_5) + result = getpwnam_r(name, pwbuf, buf, buflen, pwbufp); +#elif defined(HAVE_GETPWNAM_R_4) + *pwbufp = getpwnam_r(name, pwbuf, buf, buflen); + if (*pwbufp == NULL) { + result = -1; + } +#else + struct passwd *pwPtr = NULL; + Tcl_MutexLock(&compatLock); + pwPtr = getpwnam(name); + if (pwPtr == NULL) { + result = -1; + } else { + *pwbuf = *pwPtr; + *pwbufp = pwbuf; + result = CopyPwd(pwbuf, buf, buflen); + } + Tcl_MutexUnlock(&compatLock); +#endif + return result; +} + + +/* + *--------------------------------------------------------------------------- + * + * TclpGetPwUid -- + * + * Thread-safe wrappers for getpwuid(). + * See "man getpwuid" for more details. + * + * Results: + * 0 on success or -1 on error. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +int +TclpGetPwUid(uid_t uid, struct passwd *pwbuf, char *buf, size_t buflen, + struct passwd **pwbufp) +{ + int result = 0; + +#if defined(HAVE_GETPWUID_R_5) + result = getpwuid_r(uid, pwbuf, buf, buflen, pwbufp); +#elif defined(HAVE_GETPWUID_R_4) + *pwbufp = getpwuid_r(uid, pwbuf, buf, buflen); + if (*pwbufp == NULL) { + result = -1; + } +#else + struct passwd *pwPtr = NULL; + Tcl_MutexLock(&compatLock); + pwPtr = getpwuid(uid); + if (pwPtr == NULL) { + result = -1; + } else { + *pwbuf = *pwPtr; + *pwbufp = pwbuf; + result = CopyPwd(pwbuf, buf, buflen); + } + Tcl_MutexUnlock(&compatLock); +#endif + return result; +} + + +/* + *--------------------------------------------------------------------------- + * + * TclpGetGrNam -- + * + * Thread-safe wrappers for getgrnam(). + * See "man getgrnam" for more details. + * + * Results: + * 0 on success or -1 on error. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +int +TclpGetGrNam(const char *name, struct group *gbuf, char *buf, size_t buflen, + struct group **gbufp) +{ + int result = 0; + +#if defined(HAVE_GETGRNAM_R_5) + result = getgrnam_r(name, gbuf, buf, buflen, gbufp); +#elif defined(HAVE_GETGRNAM_R_4) + *gbufp = getgrgid_r(name, gbuf, buf, buflen); + if (*gbufp == NULL) { + result = -1; + } +#else + struct group *grPtr = NULL; + Tcl_MutexLock(&compatLock); + grPtr = getgrnam(name); + if (grPtr == NULL) { + result = -1; + } else { + *gbuf = *grPtr; + *gbufp = gbuf; + result = CopyGrp(gbuf, buf, buflen); + } + Tcl_MutexUnlock(&compatLock); +#endif + return result; +} + + +/* + *--------------------------------------------------------------------------- + * + * TclpGetGrGid -- + * + * Thread-safe wrappers for getgrgid(). + * See "man getgrgid" for more details. + * + * Results: + * 0 on success or -1 on error. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +int +TclpGetGrGid(gid_t gid, struct group *gbuf, char *buf, size_t buflen, + struct group **gbufp) +{ + int result = 0; + +#if defined(HAVE_GETGRGID_R_5) + result = getgrgid_r(gid, gbuf, buf, buflen, gbufp); +#elif defined(HAVE_GETGRGID_R_4) + *gbufp = getgrgid_r(gid, gbuf, buf, buflen); + if (*gbufp == NULL) { + result = -1; + } +#else + struct group *grPtr = NULL; + Tcl_MutexLock(&compatLock); + grPtr = getgrgid(gid); + if (grPtr == NULL) { + result = -1; + } else { + *gbuf = *grPtr; + *gbufp = gbuf; + result = CopyGrp(gbuf, buf, buflen); + } + Tcl_MutexUnlock(&compatLock); +#endif + return result; +} + + +/* + *--------------------------------------------------------------------------- + * + * 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, struct hostent *hbuf, char *buf, + size_t buflen, int *h_errnop) +{ +#if defined(HAVE_GETHOSTBYNAME_R_5) + return gethostbyname_r(name, hbuf, buf, buflen, h_errnop); +#elif defined(HAVE_GETHOSTBYNAME_R_6) + struct hostent *hePtr; + return (gethostbyname_r(name, hbuf, buf, buflen, &hePtr, + h_errnop) == 0) ? hbuf : NULL; +#elif defined(HAVE_GETHOSTBYNAME_R_3) + struct hostent_data data; + if (-1 == gethostbyname_r(host, hbuf, &data)) { + *h_errnop = h_errno; + return NULL; + } else { + return &hbuf; + } +#else + struct hostent *hePtr = NULL; + Tcl_MutexLock(&compatLock); + hePtr = gethostbyname(name); + if (hePtr != NULL) { + *hbuf = *hePtr; + if (-1 == CopyHostent(hbuf, buf, buflen)) { + hePtr = NULL; + } else { + hePtr = hbuf; + } + } + Tcl_MutexUnlock(&compatLock); + return hePtr; +#endif + return NULL; /* Not reached */ +} + + +/* + *--------------------------------------------------------------------------- + * + * 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, struct hostent *hbuf, + char *buf, size_t buflen, int *h_errnop) +{ +#if defined(HAVE_GETHOSTBYADDR_R_7) + return gethostbyaddr_r(addr, length, type, hbuf, buf, buflen, h_errnop); +#elif defined(HAVE_GETHOSTBYADDR_R_8) + struct hostent *hePtr; + return (gethostbyaddr_r(addr, length, type, hbuf, buf, buflen, + &hePtr, h_errnop) == 0) ? hbuf : NULL; +#else + struct hostent *hePtr = NULL; + Tcl_MutexLock(&compatLock); + hePtr = gethostbyaddr(addr, length, type); + if (hePtr != NULL) { + *hbuf = *hePtr; + if (-1 == CopyHostent(hbuf, buf, buflen)) { + hePtr = NULL; + } else { + hePtr = hbuf; + } + } + Tcl_MutexUnlock(&compatLock); + return hePtr; +#endif + return NULL; /* Not reached */ +} |