2003-08-13 05:53:07 +04:00
/*
Unix SMB / CIFS implementation .
Samba utility functions
Copyright ( C ) Andrew Tridgell 1992 - 1998
Copyright ( C ) Jeremy Allison 2001 - 2002
Copyright ( C ) Simo Sorce 2001
2004-07-28 17:08:08 +04:00
Copyright ( C ) Jim McDonough ( jmcd @ us . ibm . com ) 2003.
2003-08-13 05:53:07 +04:00
Copyright ( C ) James J Myers 2003
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2003-08-13 05:53:07 +04:00
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2003-08-13 05:53:07 +04:00
*/
# include "includes.h"
2004-11-02 01:48:25 +03:00
# include "system/network.h"
2005-02-10 08:09:35 +03:00
# include "system/filesys.h"
2006-05-13 23:14:12 +04:00
# include "system/locale.h"
2010-03-22 10:27:58 +03:00
# include "system/shmem.h"
2008-10-17 14:26:46 +04:00
# undef malloc
# undef strcasecmp
2008-10-19 14:38:16 +04:00
# undef strncasecmp
2008-10-17 14:26:46 +04:00
# undef strdup
# undef realloc
2003-08-13 05:53:07 +04:00
2010-01-30 16:25:51 +03:00
# if defined(UID_WRAPPER)
# if !defined(UID_WRAPPER_REPLACE) && !defined(UID_WRAPPER_NOT_REPLACE)
# define UID_WRAPPER_REPLACE
# include "../uid_wrapper/uid_wrapper.h"
# endif
# else
# define uwrap_enabled() 0
# endif
2006-02-28 16:12:39 +03:00
/**
* @ file
* @ brief Misc utility functions
*/
/**
2003-08-13 05:53:07 +04:00
Find a suitable temporary directory . The result should be copied immediately
as it may be overwritten by a subsequent call .
2006-02-28 16:12:39 +03:00
* */
2006-03-05 20:15:19 +03:00
_PUBLIC_ const char * tmpdir ( void )
2003-08-13 05:53:07 +04:00
{
char * p ;
if ( ( p = getenv ( " TMPDIR " ) ) )
return p ;
return " /tmp " ;
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
Check if a file exists - call vfs_file_exist for samba files .
2006-02-28 16:12:39 +03:00
* */
2007-08-27 21:21:16 +04:00
_PUBLIC_ bool file_exist ( const char * fname )
2003-08-13 05:53:07 +04:00
{
2004-11-01 23:21:54 +03:00
struct stat st ;
2003-08-13 05:53:07 +04:00
2005-02-10 09:36:30 +03:00
if ( stat ( fname , & st ) ! = 0 ) {
2007-08-27 21:21:16 +04:00
return false ;
2005-02-10 09:36:30 +03:00
}
return ( ( S_ISREG ( st . st_mode ) ) | | ( S_ISFIFO ( st . st_mode ) ) ) ;
2003-08-13 05:53:07 +04:00
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
Check a files mod time .
2006-02-28 16:12:39 +03:00
* */
2003-08-13 05:53:07 +04:00
2006-03-05 20:15:19 +03:00
_PUBLIC_ time_t file_modtime ( const char * fname )
2003-08-13 05:53:07 +04:00
{
2004-11-01 23:21:54 +03:00
struct stat st ;
2003-08-13 05:53:07 +04:00
2004-11-01 23:21:54 +03:00
if ( stat ( fname , & st ) ! = 0 )
2003-08-13 05:53:07 +04:00
return ( 0 ) ;
return ( st . st_mtime ) ;
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
Check if a directory exists .
2006-02-28 16:12:39 +03:00
* */
2003-08-13 05:53:07 +04:00
2007-08-27 21:21:16 +04:00
_PUBLIC_ bool directory_exist ( const char * dname )
2003-08-13 05:53:07 +04:00
{
2005-02-10 09:36:30 +03:00
struct stat st ;
2007-08-27 21:21:16 +04:00
bool ret ;
2003-08-13 05:53:07 +04:00
2005-02-10 09:36:30 +03:00
if ( stat ( dname , & st ) ! = 0 ) {
2007-08-27 21:21:16 +04:00
return false ;
2005-02-10 09:36:30 +03:00
}
2003-08-13 05:53:07 +04:00
2005-02-10 09:36:30 +03:00
ret = S_ISDIR ( st . st_mode ) ;
2003-08-13 05:53:07 +04:00
if ( ! ret )
errno = ENOTDIR ;
return ret ;
}
2006-03-06 03:24:51 +03:00
/**
* Try to create the specified directory if it didn ' t exist .
*
2007-08-27 21:21:16 +04:00
* @ retval true if the directory already existed and has the right permissions
2006-03-06 03:24:51 +03:00
* or was successfully created .
*/
2007-08-27 21:21:16 +04:00
_PUBLIC_ bool directory_create_or_exist ( const char * dname , uid_t uid ,
2006-01-31 03:48:57 +03:00
mode_t dir_perms )
{
mode_t old_umask ;
struct stat st ;
old_umask = umask ( 0 ) ;
if ( lstat ( dname , & st ) = = - 1 ) {
if ( errno = = ENOENT ) {
/* Create directory */
if ( mkdir ( dname , dir_perms ) = = - 1 ) {
DEBUG ( 0 , ( " error creating directory "
" %s: %s \n " , dname ,
strerror ( errno ) ) ) ;
umask ( old_umask ) ;
2007-08-27 21:21:16 +04:00
return false ;
2006-01-31 03:48:57 +03:00
}
} else {
DEBUG ( 0 , ( " lstat failed on directory %s: %s \n " ,
dname , strerror ( errno ) ) ) ;
umask ( old_umask ) ;
2007-08-27 21:21:16 +04:00
return false ;
2006-01-31 03:48:57 +03:00
}
} else {
/* Check ownership and permission on existing directory */
if ( ! S_ISDIR ( st . st_mode ) ) {
DEBUG ( 0 , ( " directory %s isn't a directory \n " ,
dname ) ) ;
umask ( old_umask ) ;
2007-08-27 21:21:16 +04:00
return false ;
2006-01-31 03:48:57 +03:00
}
2009-08-05 05:21:06 +04:00
if ( st . st_uid ! = uid & & ! uwrap_enabled ( ) ) {
DEBUG ( 0 , ( " invalid ownership on directory "
" %s \n " , dname ) ) ;
umask ( old_umask ) ;
return false ;
}
if ( ( st . st_mode & 0777 ) ! = dir_perms ) {
2006-01-31 03:48:57 +03:00
DEBUG ( 0 , ( " invalid permissions on directory "
" %s \n " , dname ) ) ;
umask ( old_umask ) ;
2007-08-27 21:21:16 +04:00
return false ;
2006-01-31 03:48:57 +03:00
}
}
2007-08-27 21:21:16 +04:00
return true ;
2006-01-31 03:48:57 +03:00
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
Sleep for a specified number of milliseconds .
2006-02-28 16:12:39 +03:00
* */
2003-08-13 05:53:07 +04:00
2006-04-24 13:36:09 +04:00
_PUBLIC_ void msleep ( unsigned int t )
2003-08-13 05:53:07 +04:00
{
struct timeval tval ;
tval . tv_sec = t / 1000 ;
tval . tv_usec = 1000 * ( t % 1000 ) ;
/* this should be the real select - do NOT replace
with sys_select ( ) */
select ( 0 , NULL , NULL , NULL , & tval ) ;
}
2006-02-28 16:12:39 +03:00
/**
2009-02-13 12:56:34 +03:00
Get my own name , return in talloc ' ed storage .
2006-02-28 16:12:39 +03:00
* */
2003-08-13 05:53:07 +04:00
2009-02-13 12:56:34 +03:00
_PUBLIC_ char * get_myname ( TALLOC_CTX * ctx )
2003-08-13 05:53:07 +04:00
{
char * p ;
2009-02-13 12:56:34 +03:00
char hostname [ HOST_NAME_MAX ] ;
2003-08-13 05:53:07 +04:00
/* get my host name */
2009-02-13 12:56:34 +03:00
if ( gethostname ( hostname , sizeof ( hostname ) ) = = - 1 ) {
2003-08-13 05:53:07 +04:00
DEBUG ( 0 , ( " gethostname failed \n " ) ) ;
return NULL ;
2009-02-13 12:56:34 +03:00
}
2003-08-13 05:53:07 +04:00
/* Ensure null termination. */
2009-02-13 12:56:34 +03:00
hostname [ sizeof ( hostname ) - 1 ] = ' \0 ' ;
2003-08-13 05:53:07 +04:00
/* split off any parts after an initial . */
2009-02-13 12:56:34 +03:00
p = strchr_m ( hostname , ' . ' ) ;
if ( p ) {
2003-08-13 05:53:07 +04:00
* p = 0 ;
2009-02-13 12:56:34 +03:00
}
return talloc_strdup ( ctx , hostname ) ;
2003-08-13 05:53:07 +04:00
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
Check if a process exists . Does this work on all unixes ?
2006-02-28 16:12:39 +03:00
* */
2003-08-13 05:53:07 +04:00
2008-10-17 14:26:46 +04:00
_PUBLIC_ bool process_exists_by_pid ( pid_t pid )
2003-08-13 05:53:07 +04:00
{
/* Doing kill with a non-positive pid causes messages to be
* sent to places we don ' t want . */
SMB_ASSERT ( pid > 0 ) ;
return ( kill ( pid , 0 ) = = 0 | | errno ! = ESRCH ) ;
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
Simple routine to do POSIX file locking . Cruft in NFS and 64 - > 32 bit mapping
is dealt with in posix . c
2006-02-28 16:12:39 +03:00
* */
2003-08-13 05:53:07 +04:00
2007-08-27 21:21:16 +04:00
_PUBLIC_ bool fcntl_lock ( int fd , int op , off_t offset , off_t count , int type )
2003-08-13 05:53:07 +04:00
{
2004-11-01 23:21:54 +03:00
struct flock lock ;
2003-08-13 05:53:07 +04:00
int ret ;
DEBUG ( 8 , ( " fcntl_lock %d %d %.0f %.0f %d \n " , fd , op , ( double ) offset , ( double ) count , type ) ) ;
lock . l_type = type ;
lock . l_whence = SEEK_SET ;
lock . l_start = offset ;
lock . l_len = count ;
lock . l_pid = 0 ;
2004-11-01 23:21:54 +03:00
ret = fcntl ( fd , op , & lock ) ;
2003-08-13 05:53:07 +04:00
if ( ret = = - 1 & & errno ! = 0 )
DEBUG ( 3 , ( " fcntl_lock: fcntl lock gave errno %d (%s) \n " , errno , strerror ( errno ) ) ) ;
/* a lock query */
2004-11-01 23:21:54 +03:00
if ( op = = F_GETLK ) {
2003-08-13 05:53:07 +04:00
if ( ( ret ! = - 1 ) & &
( lock . l_type ! = F_UNLCK ) & &
( lock . l_pid ! = 0 ) & &
( lock . l_pid ! = getpid ( ) ) ) {
DEBUG ( 3 , ( " fcntl_lock: fd %d is locked by pid %d \n " , fd , ( int ) lock . l_pid ) ) ;
2007-08-27 21:21:16 +04:00
return true ;
2003-08-13 05:53:07 +04:00
}
/* it must be not locked or locked by me */
2007-08-27 21:21:16 +04:00
return false ;
2003-08-13 05:53:07 +04:00
}
/* a lock set or unset */
if ( ret = = - 1 ) {
DEBUG ( 3 , ( " fcntl_lock: lock failed at offset %.0f count %.0f op %d type %d (%s) \n " ,
( double ) offset , ( double ) count , op , type , strerror ( errno ) ) ) ;
2007-08-27 21:21:16 +04:00
return false ;
2003-08-13 05:53:07 +04:00
}
/* everything went OK */
DEBUG ( 8 , ( " fcntl_lock: Lock call successful \n " ) ) ;
2007-08-27 21:21:16 +04:00
return true ;
2003-08-13 05:53:07 +04:00
}
2008-10-17 14:26:46 +04:00
void print_asc ( int level , const uint8_t * buf , int len )
2003-08-13 05:53:07 +04:00
{
int i ;
for ( i = 0 ; i < len ; i + + )
DEBUGADD ( level , ( " %c " , isprint ( buf [ i ] ) ? buf [ i ] : ' . ' ) ) ;
}
2006-03-06 03:24:51 +03:00
/**
* Write dump of binary data to the log file .
*
* The data is only written if the log level is at least level .
*/
2007-11-02 13:33:53 +03:00
static void _dump_data ( int level , const uint8_t * buf , int len ,
bool omit_zero_bytes )
2003-08-13 05:53:07 +04:00
{
int i = 0 ;
2009-07-25 20:56:06 +04:00
static const uint8_t empty [ 16 ] = { 0 , } ;
2007-11-02 13:33:53 +03:00
bool skipped = false ;
2003-08-13 05:53:07 +04:00
if ( len < = 0 ) return ;
if ( ! DEBUGLVL ( level ) ) return ;
2007-11-02 13:33:53 +03:00
2003-08-13 05:53:07 +04:00
for ( i = 0 ; i < len ; ) {
2007-11-02 13:33:53 +03:00
if ( i % 16 = = 0 ) {
if ( ( omit_zero_bytes = = true ) & &
( i > 0 ) & &
( len > i + 16 ) & &
( memcmp ( & buf [ i ] , & empty , 16 ) = = 0 ) )
{
i + = 16 ;
continue ;
}
if ( i < len ) {
DEBUGADD ( level , ( " [%04X] " , i ) ) ;
}
}
2003-08-13 05:53:07 +04:00
DEBUGADD ( level , ( " %02X " , ( int ) buf [ i ] ) ) ;
i + + ;
2007-11-02 13:33:53 +03:00
if ( i % 8 = = 0 ) DEBUGADD ( level , ( " " ) ) ;
if ( i % 16 = = 0 ) {
2003-08-13 05:53:07 +04:00
print_asc ( level , & buf [ i - 16 ] , 8 ) ; DEBUGADD ( level , ( " " ) ) ;
print_asc ( level , & buf [ i - 8 ] , 8 ) ; DEBUGADD ( level , ( " \n " ) ) ;
2007-11-02 13:33:53 +03:00
if ( ( omit_zero_bytes = = true ) & &
( len > i + 16 ) & &
( memcmp ( & buf [ i ] , & empty , 16 ) = = 0 ) ) {
if ( ! skipped ) {
DEBUGADD ( level , ( " skipping zero buffer bytes \n " ) ) ;
skipped = true ;
}
}
2003-08-13 05:53:07 +04:00
}
}
2007-11-02 13:33:53 +03:00
2003-08-13 05:53:07 +04:00
if ( i % 16 ) {
int n ;
n = 16 - ( i % 16 ) ;
DEBUGADD ( level , ( " " ) ) ;
if ( n > 8 ) DEBUGADD ( level , ( " " ) ) ;
while ( n - - ) DEBUGADD ( level , ( " " ) ) ;
n = MIN ( 8 , i % 16 ) ;
print_asc ( level , & buf [ i - ( i % 16 ) ] , n ) ; DEBUGADD ( level , ( " " ) ) ;
n = ( i % 16 ) - n ;
2007-11-02 13:33:53 +03:00
if ( n > 0 ) print_asc ( level , & buf [ i - n ] , n ) ;
DEBUGADD ( level , ( " \n " ) ) ;
}
2003-08-13 05:53:07 +04:00
}
2007-11-02 13:33:53 +03:00
/**
* Write dump of binary data to the log file .
*
* The data is only written if the log level is at least level .
*/
_PUBLIC_ void dump_data ( int level , const uint8_t * buf , int len )
{
2007-11-02 14:50:24 +03:00
_dump_data ( level , buf , len , false ) ;
2007-11-02 13:33:53 +03:00
}
/**
* Write dump of binary data to the log file .
*
* The data is only written if the log level is at least level .
2010-02-21 08:58:07 +03:00
* 16 zero bytes in a row are omitted
2007-11-02 13:33:53 +03:00
*/
_PUBLIC_ void dump_data_skip_zeros ( int level , const uint8_t * buf , int len )
{
2007-11-02 14:50:24 +03:00
_dump_data ( level , buf , len , true ) ;
2007-11-02 13:33:53 +03:00
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
malloc that aborts with smb_panic on fail or zero size .
2006-02-28 16:12:39 +03:00
* */
2003-08-13 05:53:07 +04:00
2006-03-05 20:15:19 +03:00
_PUBLIC_ void * smb_xmalloc ( size_t size )
2003-08-13 05:53:07 +04:00
{
void * p ;
if ( size = = 0 )
smb_panic ( " smb_xmalloc: called with zero size. \n " ) ;
if ( ( p = malloc ( size ) ) = = NULL )
smb_panic ( " smb_xmalloc: malloc fail. \n " ) ;
return p ;
}
/**
Memdup with smb_panic on fail .
* */
2006-03-05 20:15:19 +03:00
_PUBLIC_ void * smb_xmemdup ( const void * p , size_t size )
2003-08-13 05:53:07 +04:00
{
void * p2 ;
p2 = smb_xmalloc ( size ) ;
memcpy ( p2 , p , size ) ;
return p2 ;
}
/**
strdup that aborts on malloc fail .
* */
2008-10-17 14:26:46 +04:00
char * smb_xstrdup ( const char * s )
2003-08-13 05:53:07 +04:00
{
2008-10-17 14:26:46 +04:00
# if defined(PARANOID_MALLOC_CHECKER)
# ifdef strdup
# undef strdup
# endif
# endif
# ifndef HAVE_STRDUP
# define strdup rep_strdup
# endif
2003-08-13 05:53:07 +04:00
char * s1 = strdup ( s ) ;
2008-10-17 14:26:46 +04:00
# if defined(PARANOID_MALLOC_CHECKER)
# ifdef strdup
# undef strdup
# endif
# define strdup(s) __ERROR_DONT_USE_STRDUP_DIRECTLY
# endif
if ( ! s1 ) {
smb_panic ( " smb_xstrdup: malloc failed " ) ;
}
return s1 ;
}
/**
strndup that aborts on malloc fail .
* */
char * smb_xstrndup ( const char * s , size_t n )
{
# if defined(PARANOID_MALLOC_CHECKER)
# ifdef strndup
# undef strndup
# endif
# endif
# if (defined(BROKEN_STRNDUP) || !defined(HAVE_STRNDUP))
# undef HAVE_STRNDUP
# define strndup rep_strndup
# endif
char * s1 = strndup ( s , n ) ;
# if defined(PARANOID_MALLOC_CHECKER)
# ifdef strndup
# undef strndup
# endif
# define strndup(s,n) __ERROR_DONT_USE_STRNDUP_DIRECTLY
# endif
if ( ! s1 ) {
smb_panic ( " smb_xstrndup: malloc failed " ) ;
}
2003-08-13 05:53:07 +04:00
return s1 ;
}
2008-10-17 14:26:46 +04:00
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
Like strdup but for memory .
2006-02-28 16:12:39 +03:00
* */
2003-08-13 05:53:07 +04:00
2006-03-05 20:15:19 +03:00
_PUBLIC_ void * memdup ( const void * p , size_t size )
2003-08-13 05:53:07 +04:00
{
void * p2 ;
if ( size = = 0 )
return NULL ;
p2 = malloc ( size ) ;
if ( ! p2 )
return NULL ;
memcpy ( p2 , p , size ) ;
return p2 ;
}
2006-03-06 03:24:51 +03:00
/**
* Write a password to the log file .
*
* @ note Only actually does something if DEBUG_PASSWORD was defined during
* compile - time .
*/
2006-03-05 20:15:19 +03:00
_PUBLIC_ void dump_data_pw ( const char * msg , const uint8_t * data , size_t len )
2003-11-26 04:16:41 +03:00
{
# ifdef DEBUG_PASSWORD
DEBUG ( 11 , ( " %s " , msg ) ) ;
if ( data ! = NULL & & len > 0 )
{
dump_data ( 11 , data , len ) ;
}
# endif
}
2003-12-13 05:20:40 +03:00
2006-02-28 16:12:39 +03:00
/**
* see if a range of memory is all zero . A NULL pointer is considered
* to be all zero
*/
2007-08-27 21:21:16 +04:00
_PUBLIC_ bool all_zero ( const uint8_t * ptr , size_t size )
2003-12-13 05:20:40 +03:00
{
int i ;
2007-08-27 21:21:16 +04:00
if ( ! ptr ) return true ;
2003-12-13 05:20:40 +03:00
for ( i = 0 ; i < size ; i + + ) {
2007-08-27 21:21:16 +04:00
if ( ptr [ i ] ) return false ;
2003-12-13 05:20:40 +03:00
}
2007-08-27 21:21:16 +04:00
return true ;
2003-12-13 05:20:40 +03:00
}
2004-12-03 09:24:38 +03:00
2006-02-28 16:12:39 +03:00
/**
2004-12-03 09:24:38 +03:00
realloc an array , checking for integer overflow in the array size
*/
2008-10-18 16:12:56 +04:00
_PUBLIC_ void * realloc_array ( void * ptr , size_t el_size , unsigned count , bool free_on_fail )
2004-12-03 09:24:38 +03:00
{
# define MAX_MALLOC_SIZE 0x7fffffff
if ( count = = 0 | |
count > = MAX_MALLOC_SIZE / el_size ) {
2008-10-18 16:12:56 +04:00
if ( free_on_fail )
SAFE_FREE ( ptr ) ;
2004-12-03 09:24:38 +03:00
return NULL ;
}
if ( ! ptr ) {
return malloc ( el_size * count ) ;
}
return realloc ( ptr , el_size * count ) ;
}
2008-10-11 21:44:10 +04:00
/****************************************************************************
Type - safe malloc .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void * malloc_array ( size_t el_size , unsigned int count )
{
2008-10-18 16:12:56 +04:00
return realloc_array ( NULL , el_size , count , false ) ;
2008-10-11 21:44:10 +04:00
}
2008-10-19 14:38:16 +04:00
/**
Trim the specified elements off the front and back of a string .
* */
_PUBLIC_ bool trim_string ( char * s , const char * front , const char * back )
{
bool ret = false ;
size_t front_len ;
size_t back_len ;
size_t len ;
/* Ignore null or empty strings. */
if ( ! s | | ( s [ 0 ] = = ' \0 ' ) )
return false ;
front_len = front ? strlen ( front ) : 0 ;
back_len = back ? strlen ( back ) : 0 ;
len = strlen ( s ) ;
if ( front_len ) {
while ( len & & strncmp ( s , front , front_len ) = = 0 ) {
/* Must use memmove here as src & dest can
* easily overlap . Found by valgrind . JRA . */
memmove ( s , s + front_len , ( len - front_len ) + 1 ) ;
len - = front_len ;
ret = true ;
}
}
if ( back_len ) {
while ( ( len > = back_len ) & & strncmp ( s + len - back_len , back , back_len ) = = 0 ) {
s [ len - back_len ] = ' \0 ' ;
len - = back_len ;
ret = true ;
}
}
return ret ;
}
/**
Find the number of ' c ' chars in a string
* */
_PUBLIC_ _PURE_ size_t count_chars ( const char * s , char c )
{
size_t count = 0 ;
while ( * s ) {
if ( * s = = c ) count + + ;
s + + ;
}
return count ;
}
/**
Routine to get hex characters and turn them into a 16 byte array .
the array can be variable length , and any non - hex - numeric
characters are skipped . " 0xnn " or " 0Xnn " is specially catered
for .
valid examples : " 0A5D15 " ; " 0x15, 0x49, 0xa2 " ; " 59 \t a9 \t e3 \n "
* */
_PUBLIC_ size_t strhex_to_str ( char * p , size_t p_len , const char * strhex , size_t strhex_len )
{
2009-09-26 00:40:55 +04:00
size_t i = 0 ;
2008-10-19 14:38:16 +04:00
size_t num_chars = 0 ;
uint8_t lonybble , hinybble ;
const char * hexchars = " 0123456789ABCDEF " ;
char * p1 = NULL , * p2 = NULL ;
2009-09-26 00:40:55 +04:00
/* skip leading 0x prefix */
if ( strncasecmp ( strhex , " 0x " , 2 ) = = 0 ) {
i + = 2 ; /* skip two chars */
}
2008-10-19 14:38:16 +04:00
2009-09-26 00:40:55 +04:00
for ( ; i < strhex_len & & strhex [ i ] ! = 0 ; i + + ) {
2008-10-19 14:38:16 +04:00
if ( ! ( p1 = strchr ( hexchars , toupper ( ( unsigned char ) strhex [ i ] ) ) ) )
break ;
i + + ; /* next hex digit */
if ( ! ( p2 = strchr ( hexchars , toupper ( ( unsigned char ) strhex [ i ] ) ) ) )
break ;
/* get the two nybbles */
hinybble = PTR_DIFF ( p1 , hexchars ) ;
lonybble = PTR_DIFF ( p2 , hexchars ) ;
if ( num_chars > = p_len ) {
break ;
}
p [ num_chars ] = ( hinybble < < 4 ) | lonybble ;
num_chars + + ;
p1 = NULL ;
p2 = NULL ;
}
return num_chars ;
}
/**
* Parse a hex string and return a data blob .
*/
_PUBLIC_ _PURE_ DATA_BLOB strhex_to_data_blob ( TALLOC_CTX * mem_ctx , const char * strhex )
{
DATA_BLOB ret_blob = data_blob_talloc ( mem_ctx , NULL , strlen ( strhex ) / 2 + 1 ) ;
ret_blob . length = strhex_to_str ( ( char * ) ret_blob . data , ret_blob . length ,
strhex ,
strlen ( strhex ) ) ;
return ret_blob ;
}
/**
* Routine to print a buffer as HEX digits , into an allocated string .
*/
_PUBLIC_ void hex_encode ( const unsigned char * buff_in , size_t len , char * * out_hex_buffer )
{
int i ;
char * hex_buffer ;
* out_hex_buffer = malloc_array_p ( char , ( len * 2 ) + 1 ) ;
hex_buffer = * out_hex_buffer ;
for ( i = 0 ; i < len ; i + + )
slprintf ( & hex_buffer [ i * 2 ] , 3 , " %02X " , buff_in [ i ] ) ;
}
/**
* talloc version of hex_encode ( )
*/
_PUBLIC_ char * hex_encode_talloc ( TALLOC_CTX * mem_ctx , const unsigned char * buff_in , size_t len )
{
int i ;
char * hex_buffer ;
hex_buffer = talloc_array ( mem_ctx , char , ( len * 2 ) + 1 ) ;
2008-11-13 23:26:03 +03:00
if ( ! hex_buffer ) {
return NULL ;
}
2008-10-19 14:38:16 +04:00
for ( i = 0 ; i < len ; i + + )
slprintf ( & hex_buffer [ i * 2 ] , 3 , " %02X " , buff_in [ i ] ) ;
2008-11-13 23:26:03 +03:00
talloc_set_name_const ( hex_buffer , hex_buffer ) ;
2008-10-19 14:38:16 +04:00
return hex_buffer ;
}
/**
varient of strcmp ( ) that handles NULL ptrs
* */
_PUBLIC_ int strcmp_safe ( const char * s1 , const char * s2 )
{
if ( s1 = = s2 ) {
return 0 ;
}
if ( s1 = = NULL | | s2 = = NULL ) {
return s1 ? - 1 : 1 ;
}
return strcmp ( s1 , s2 ) ;
}
/**
return the number of bytes occupied by a buffer in ASCII format
the result includes the null termination
limited by ' n ' bytes
* */
_PUBLIC_ size_t ascii_len_n ( const char * src , size_t n )
{
size_t len ;
len = strnlen ( src , n ) ;
if ( len + 1 < = n ) {
len + = 1 ;
}
return len ;
}
/**
Set a boolean variable from the text value stored in the passed string .
Returns true in success , false if the passed string does not correctly
represent a boolean .
* */
_PUBLIC_ bool set_boolean ( const char * boolean_string , bool * boolean )
{
if ( strwicmp ( boolean_string , " yes " ) = = 0 | |
strwicmp ( boolean_string , " true " ) = = 0 | |
strwicmp ( boolean_string , " on " ) = = 0 | |
strwicmp ( boolean_string , " 1 " ) = = 0 ) {
* boolean = true ;
return true ;
} else if ( strwicmp ( boolean_string , " no " ) = = 0 | |
strwicmp ( boolean_string , " false " ) = = 0 | |
strwicmp ( boolean_string , " off " ) = = 0 | |
strwicmp ( boolean_string , " 0 " ) = = 0 ) {
* boolean = false ;
return true ;
}
return false ;
}
/**
return the number of bytes occupied by a buffer in CH_UTF16 format
the result includes the null termination
* */
_PUBLIC_ size_t utf16_len ( const void * buf )
{
size_t len ;
for ( len = 0 ; SVAL ( buf , len ) ; len + = 2 ) ;
return len + 2 ;
}
/**
return the number of bytes occupied by a buffer in CH_UTF16 format
the result includes the null termination
limited by ' n ' bytes
* */
_PUBLIC_ size_t utf16_len_n ( const void * src , size_t n )
{
size_t len ;
for ( len = 0 ; ( len + 2 < n ) & & SVAL ( src , len ) ; len + = 2 ) ;
if ( len + 2 < = n ) {
len + = 2 ;
}
return len ;
}
2009-03-01 18:19:38 +03:00
/**
* @ file
* @ brief String utilities .
* */
static bool next_token_internal_talloc ( TALLOC_CTX * ctx ,
const char * * ptr ,
char * * pp_buff ,
const char * sep ,
bool ltrim )
{
2009-09-26 00:40:04 +04:00
const char * s ;
const char * saved_s ;
2009-03-01 18:19:38 +03:00
char * pbuf ;
bool quoted ;
size_t len = 1 ;
* pp_buff = NULL ;
if ( ! ptr ) {
return ( false ) ;
}
2009-09-26 00:40:04 +04:00
s = * ptr ;
2009-03-01 18:19:38 +03:00
/* default to simple separators */
if ( ! sep ) {
sep = " \t \n \r " ;
}
/* find the first non sep char, if left-trimming is requested */
if ( ltrim ) {
while ( * s & & strchr_m ( sep , * s ) ) {
s + + ;
}
}
/* nothing left? */
if ( ! * s ) {
return false ;
}
/* When restarting we need to go from here. */
saved_s = s ;
/* Work out the length needed. */
for ( quoted = false ; * s & &
( quoted | | ! strchr_m ( sep , * s ) ) ; s + + ) {
if ( * s = = ' \" ' ) {
quoted = ! quoted ;
} else {
len + + ;
}
}
/* We started with len = 1 so we have space for the nul. */
* pp_buff = talloc_array ( ctx , char , len ) ;
if ( ! * pp_buff ) {
return false ;
}
/* copy over the token */
pbuf = * pp_buff ;
s = saved_s ;
for ( quoted = false ; * s & &
( quoted | | ! strchr_m ( sep , * s ) ) ; s + + ) {
if ( * s = = ' \" ' ) {
quoted = ! quoted ;
} else {
* pbuf + + = * s ;
}
}
* ptr = ( * s ) ? s + 1 : s ;
* pbuf = 0 ;
return true ;
}
bool next_token_talloc ( TALLOC_CTX * ctx ,
const char * * ptr ,
char * * pp_buff ,
const char * sep )
{
return next_token_internal_talloc ( ctx , ptr , pp_buff , sep , true ) ;
}
/*
* Get the next token from a string , return false if none found . Handles
* double - quotes . This version does not trim leading separator characters
* before looking for a token .
*/
bool next_token_no_ltrim_talloc ( TALLOC_CTX * ctx ,
const char * * ptr ,
char * * pp_buff ,
const char * sep )
{
return next_token_internal_talloc ( ctx , ptr , pp_buff , sep , false ) ;
}
2010-03-22 10:27:58 +03:00
/* Map a shared memory buffer of at least nelem counters. */
void * allocate_anonymous_shared ( size_t bufsz )
{
void * buf ;
size_t pagesz = getpagesize ( ) ;
if ( bufsz % pagesz ) {
bufsz = ( bufsz + pagesz ) % pagesz ; /* round up to pagesz */
}
# ifdef MAP_ANON
/* BSD */
buf = mmap ( NULL , bufsz , PROT_READ | PROT_WRITE , MAP_ANON | MAP_SHARED ,
- 1 /* fd */ , 0 /* offset */ ) ;
# else
buf = mmap ( NULL , bufsz , PROT_READ | PROT_WRITE , MAP_FILE | MAP_SHARED ,
open ( " /dev/zero " , O_RDWR ) , 0 /* offset */ ) ;
# endif
if ( buf = = MAP_FAILED ) {
return NULL ;
}
return buf ;
}
2008-10-19 14:38:16 +04:00
2010-07-20 09:31:49 +04:00
# ifdef DEVELOPER
/* used when you want a debugger started at a particular point in the
code . Mostly useful in code that runs as a child process , where
normal gdb attach is harder to organise .
*/
void samba_start_debugger ( void )
{
char * cmd = NULL ;
asprintf ( & cmd , " xterm -e \" gdb --pid %u \" & " , getpid ( ) ) ;
system ( cmd ) ;
free ( cmd ) ;
sleep ( 2 ) ;
}
# endif