@ -7,19 +7,24 @@
*
* Portions Copyright ( c ) 1996 - 2003 , PostgreSQL Global Development Group
*
* $ Id : thread . c , v 1.6 2003 / 09 / 05 17 : 43 : 40 momjian Exp $
* $ Id : thread . c , v 1.7 2003 / 09 / 13 14 : 49 : 51 momjian Exp $
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
# include "postgres.h"
# include <pthread.h>
# include <sys/types.h>
# include <pwd.h>
/*
* Threading sometimes requires specially - named versions of functions
* that return data in static buffers , like strerror_r ( ) instead of
* strerror ( ) . Other operating systems use pthread_setspecific ( )
* and pthread_getspecific ( ) internally to allow standard library
* functions to return static data to threaded applications .
* functions to return static data to threaded applications . And some
* operating systems have neither , meaning we have to do our own locking .
*
* Additional confusion exists because many operating systems that
* use pthread_setspecific / pthread_getspecific ( ) also have * _r versions
@ -36,11 +41,15 @@
* doesn ' t have strerror_r ( ) , so we can ' t fall back to only using * _r
* functions for threaded programs .
*
* The current setup is to assume either all standard functions are
* thread - safe ( NEED_REENTRANT_FUNC_NAMES = no ) , or the operating system
* requires reentrant function names ( NEED_REENTRANT_FUNC_NAMES = yes ) .
* The current setup is to try threading in this order :
*
* use non - * _r function names if they are all thread - safe
* ( NEED_REENTRANT_FUNCS = no )
* use * _r functions if they exist ( configure test )
* do our own locking and copying of non - threadsafe functions
*
* Compile and run src / tools / test_thread_funcs . c to see if your operating
* system requires reentrant function names .
* system has thread - safe non - * _r function s.
*/
@ -51,14 +60,27 @@
char *
pqStrerror ( int errnum , char * strerrbuf , size_t buflen )
{
# if defined(USE_THREADS) && defined(NEED_REENTRANT_FUNC_NAMES )
# if defined(FRONTEND) && defined( USE_THREADS) && defined(NEED_REENTRANT_FUNCS) && defined(HAVE_STRERROR_R )
/* reentrant strerror_r is available */
/* some early standards had strerror_r returning char * */
strerror_r ( errnum , strerrbuf , buflen ) ;
return ( strerrbuf ) ;
return strerrbuf ;
# else
# if defined(FRONTEND) && defined(USE_THREADS) && defined(NEED_REENTRANT_FUNCS) && !defined(HAVE_STRERROR_R)
static pthread_mutex_t strerror_lock = PTHREAD_MUTEX_INITIALIZER ;
pthread_mutex_lock ( & strerror_lock ) ;
# endif
/* no strerror_r() available, just use strerror */
return strerror ( errnum ) ;
StrNCpy ( strerrbuf , strerror ( errnum ) , buflen ) ;
# if defined(FRONTEND) && defined(USE_THREADS) && defined(NEED_REENTRANT_FUNCS) && !defined(HAVE_STRERROR_R)
pthread_mutex_unlock ( & strerror_lock ) ;
# endif
return strerrbuf ;
# endif
}
@ -71,7 +93,7 @@ int
pqGetpwuid ( uid_t uid , struct passwd * resultbuf , char * buffer ,
size_t buflen , struct passwd * * result )
{
# if defined(USE_THREADS) && defined(NEED_REENTRANT_FUNC_NAMES )
# if defined(FRONTEND) && defined( USE_THREADS) && defined(NEED_REENTRANT_FUNCS) && defined(HAVE_GETPWUID_R )
/*
* Early POSIX draft of getpwuid_r ( ) returns ' struct passwd * ' .
* getpwuid_r ( uid , resultbuf , buffer , buflen )
@ -79,9 +101,52 @@ pqGetpwuid(uid_t uid, struct passwd *resultbuf, char *buffer,
*/
/* POSIX version */
getpwuid_r ( uid , resultbuf , buffer , buflen , result ) ;
# else
# if defined(FRONTEND) && defined(USE_THREADS) && defined(NEED_REENTRANT_FUNCS) && !defined(HAVE_GETPWUID_R)
static pthread_mutex_t getpwuid_lock = PTHREAD_MUTEX_INITIALIZER ;
pthread_mutex_lock ( & getpwuid_lock ) ;
# endif
/* no getpwuid_r() available, just use getpwuid() */
* result = getpwuid ( uid ) ;
# if defined(FRONTEND) && defined(USE_THREADS) && defined(NEED_REENTRANT_FUNCS) && !defined(HAVE_GETPWUID_R)
/* Use 'buffer' memory for storage of strings used by struct passwd */
if ( * result & &
strlen ( ( * result ) - > pw_name ) + 1 +
strlen ( ( * result ) - > pw_passwd ) + 1 +
strlen ( ( * result ) - > pw_gecos ) + 1 +
/* skip class if it exists */
strlen ( ( * result ) - > pw_dir ) + 1 +
strlen ( ( * result ) - > pw_shell ) + 1 < = buflen )
{
memcpy ( resultbuf , * result , sizeof ( struct passwd ) ) ;
strcpy ( buffer , ( * result ) - > pw_name ) ;
resultbuf - > pw_name = buffer ;
buffer + = strlen ( resultbuf - > pw_name ) + 1 ;
strcpy ( buffer , ( * result ) - > pw_passwd ) ;
resultbuf - > pw_passwd = buffer ;
buffer + = strlen ( resultbuf - > pw_passwd ) + 1 ;
strcpy ( buffer , ( * result ) - > pw_gecos ) ;
resultbuf - > pw_gecos = buffer ;
buffer + = strlen ( resultbuf - > pw_gecos ) + 1 ;
strcpy ( buffer , ( * result ) - > pw_dir ) ;
resultbuf - > pw_dir = buffer ;
buffer + = strlen ( resultbuf - > pw_dir ) + 1 ;
strcpy ( buffer , ( * result ) - > pw_shell ) ;
resultbuf - > pw_shell = buffer ;
buffer + = strlen ( resultbuf - > pw_shell ) + 1 ;
* result = resultbuf ;
}
else
* result = NULL ;
pthread_mutex_unlock ( & getpwuid_lock ) ;
# endif
# endif
return ( * result = = NULL ) ? - 1 : 0 ;
}
@ -93,27 +158,101 @@ pqGetpwuid(uid_t uid, struct passwd *resultbuf, char *buffer,
*/
int
pqGethostbyname ( const char * name ,
struct hostent * resbuf ,
char * buf , size_t buflen ,
struct hostent * result buf ,
char * buffer , size_t buflen ,
struct hostent * * result ,
int * herrno )
{
# if defined(USE_THREADS) && defined(NEED_REENTRANT_FUNC_NAMES )
# if defined(FRONTEND) && defined( USE_THREADS) && defined(NEED_REENTRANT_FUNCS) && defined(HAVE_GETHOSTBYNAME_R )
/*
* broken ( well early POSIX draft ) gethostbyname_r ( ) which returns
* ' struct hostent * '
*/
* result = gethostbyname_r ( name , resbuf , buf , buflen , herrno ) ;
* result = gethostbyname_r ( name , resbuf , buffer , buflen , herrno ) ;
return ( * result = = NULL ) ? - 1 : 0 ;
# else
# if defined(FRONTEND) && defined(USE_THREADS) && defined(NEED_REENTRANT_FUNCS) && !defined(HAVE_GETHOSTBYNAME_R)
static pthread_mutex_t gethostbyname_lock = PTHREAD_MUTEX_INITIALIZER ;
pthread_mutex_lock ( & gethostbyname_lock ) ;
# endif
/* no gethostbyname_r(), just use gethostbyname() */
* result = gethostbyname ( name ) ;
# if defined(FRONTEND) && defined(USE_THREADS) && defined(NEED_REENTRANT_FUNCS) && !defined(HAVE_GETHOSTBYNAME_R)
/*
* Use ' buffer ' memory for storage of structures used by struct hostent .
* The layout is :
*
* addr pointers
* alias pointers
* addr structures
* alias structures
* name
*/
if ( * result )
{
int i , pointers = 2 /* for nulls */ , len = 0 ;
char * * pbuffer ;
for ( i = 0 ; ( * result ) - > h_addr_list [ i ] ; i + + , pointers + + )
len + = ( * result ) - > h_length ;
for ( i = 0 ; ( * result ) - > h_aliases [ i ] ; i + + , pointers + + )
len + = ( * result ) - > h_length ;
if ( MAXALIGN ( len ) + pointers * sizeof ( char * ) + strlen ( ( * result ) - > h_name ) + 1 < = buflen )
{
memcpy ( resultbuf , * result , sizeof ( struct hostent ) ) ;
pbuffer = ( char * * ) buffer ;
resultbuf - > h_addr_list = pbuffer ;
buffer + = pointers * sizeof ( char * ) ;
for ( i = 0 ; ( * result ) - > h_addr_list [ i ] ; i + + , pbuffer + + )
{
memcpy ( buffer , ( * result ) - > h_addr_list [ i ] , ( * result ) - > h_length ) ;
resultbuf - > h_addr_list [ i ] = buffer ;
buffer + = ( * result ) - > h_length ;
}
resultbuf - > h_addr_list [ i ] = NULL ;
pbuffer + + ;
resultbuf - > h_aliases = pbuffer ;
for ( i = 0 ; ( * result ) - > h_aliases [ i ] ; i + + , pbuffer + + )
{
memcpy ( buffer , ( * result ) - > h_aliases [ i ] , ( * result ) - > h_length ) ;
resultbuf - > h_aliases [ i ] = buffer ;
buffer + = ( * result ) - > h_length ;
}
resultbuf - > h_aliases [ i ] = NULL ;
pbuffer + + ;
/* Place at end for cleaner alignment */
strcpy ( buffer , ( * result ) - > h_name ) ;
resultbuf - > h_name = buffer ;
buffer + = strlen ( resultbuf - > h_name ) + 1 ;
* result = resultbuf ;
}
else
* result = NULL ;
}
# endif
if ( * result ! = NULL )
* herrno = h_errno ;
# if defined(FRONTEND) && defined(USE_THREADS) && defined(NEED_REENTRANT_FUNCS) && !defined(HAVE_GETHOSTBYNAME_R)
pthread_mutex_unlock ( & gethostbyname_lock ) ;
# endif
if ( * result ! = NULL )
return 0 ;
else
{
* herrno = h_errno ;
return - 1 ;
}
# endif
}