summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--unix/tclUnixCompat.c584
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 */
+}