diff options
Diffstat (limited to 'unix/tclUnixCompat.c')
| -rw-r--r-- | unix/tclUnixCompat.c | 1022 | 
1 files changed, 1022 insertions, 0 deletions
| diff --git a/unix/tclUnixCompat.c b/unix/tclUnixCompat.c new file mode 100644 index 0000000..2a68f7f --- /dev/null +++ b/unix/tclUnixCompat.c @@ -0,0 +1,1022 @@ +/* + * 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. + */ + +#include "tclInt.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. + */ + +#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; +#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_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; + +/* + * Helper function declarations. Note that these are only used if needed and + * only defined if used (via the NEED_* macros). + */ + +#undef NEED_COPYARRAY +#undef NEED_COPYGRP +#undef NEED_COPYHOSTENT +#undef NEED_COPYPWD +#undef NEED_COPYSTRING + +#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 + +#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 + +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); + +#endif + +#ifdef NEED_PW_CLEANER +static void		FreePwBuf(ClientData ignored); +#endif +#ifdef NEED_GR_CLEANER +static void		FreeGrBuf(ClientData ignored); +#endif +#endif /* TCL_THREADS */ + +/* + *--------------------------------------------------------------------------- + * + * TclUnixSetBlockingMode -- + * + *	Set the blocking mode of a file descriptor. + * + * Results: + * + *	0 on success, -1 (with errno set) on error. + * + *--------------------------------------------------------------------------- + */ + +int +TclUnixSetBlockingMode( +    int fd,			/* File descriptor */ +    int mode)			/* Either TCL_MODE_BLOCKING or +				 * TCL_MODE_NONBLOCKING. */ +{ +#ifndef USE_FIONBIO +    int flags = fcntl(fd, F_GETFL); + +    if (mode == TCL_MODE_BLOCKING) { +	flags &= ~O_NONBLOCK; +    } else { +	flags |= O_NONBLOCK; +    } +    return fcntl(fd, F_SETFL, flags); +#else /* USE_FIONBIO */ +    int state = (mode == TCL_MODE_NONBLOCKING); + +    return ioctl(fd, FIONBIO, &state); +#endif /* !USE_FIONBIO */ +} + +/* + *--------------------------------------------------------------------------- + * + * 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; + +    /* +     * 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) { +	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; + +    /* +     * 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) { +	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 */ +} + +/* + *--------------------------------------------------------------------------- + * + * 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. + * + * 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; + +    /* +     * 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) { +	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; + +    /* +     * 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) { +	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 */ +} + +/* + *--------------------------------------------------------------------------- + * + * 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. + * + * 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 = NULL; +    int h_errno, result; + +    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 +#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) { +	    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 +#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) { +	    hePtr = NULL; +	} +    } +    Tcl_MutexUnlock(&compatLock); +    return hePtr; +#endif + +    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 */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ + +/* + *------------------------------------------------------------------------ + * + * TclWinCPUID -- + * + *	Get CPU ID information on an Intel box under UNIX (either Linux or Cygwin) + * + * Results: + *	Returns TCL_OK if successful, TCL_ERROR if CPUID is not supported. + * + * Side effects: + *	If successful, stores EAX, EBX, ECX and EDX registers after the CPUID + *	instruction in the four integers designated by 'regsPtr' + * + *---------------------------------------------------------------------- + */ + +int +TclWinCPUID( +    unsigned int index,		/* Which CPUID value to retrieve. */ +    unsigned int *regsPtr)	/* Registers after the CPUID. */ +{ +    int status = TCL_ERROR; + +    /* See: <http://en.wikipedia.org/wiki/CPUID> */ +#if defined(HAVE_CPUID) +#if defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64) +    __asm__ __volatile__("movq %%rbx, %%rsi     \n\t" /* save %rbx */ +                 "cpuid            \n\t" +                 "xchgq %%rsi, %%rbx   \n\t" /* restore the old %rbx */ +                 : "=a"(regsPtr[0]), "=S"(regsPtr[1]), "=c"(regsPtr[2]), "=d"(regsPtr[3]) +                 : "a"(index)); +#else +    __asm__ __volatile__("mov %%ebx, %%esi     \n\t" /* save %ebx */ +                 "cpuid            \n\t" +                 "xchg %%esi, %%ebx   \n\t" /* restore the old %ebx */ +                 : "=a"(regsPtr[0]), "=S"(regsPtr[1]), "=c"(regsPtr[2]), "=d"(regsPtr[3]) +                 : "a"(index)); +#endif +    status = TCL_OK; +#endif +    return status; +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ | 
