2005-09-20 23:26:39 +10:00
/**
\ file env_universal_common . c
The utility library for universal variables . Used both by the
client library and by the daemon .
*/
2006-01-31 02:58:00 +10:00
# include "config.h"
2006-02-28 23:17:16 +10:00
2005-09-20 23:26:39 +10:00
# include <stdlib.h>
# include <stdio.h>
# include <wchar.h>
2006-08-10 08:34:52 +10:00
# include <string.h>
2005-09-20 23:26:39 +10:00
# include <unistd.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <sys/un.h>
# include <pwd.h>
# include <errno.h>
# include <sys/stat.h>
# include <dirent.h>
# include <wctype.h>
2006-10-18 07:11:29 +10:00
# include <iconv.h>
2005-09-20 23:26:39 +10:00
# include <errno.h>
# include <locale.h>
# include <dirent.h>
# include <signal.h>
# include <sys/stat.h>
2012-02-18 00:22:30 +05:30
# include <map>
2005-09-20 23:26:39 +10:00
2006-08-10 08:26:05 +10:00
# ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
# endif
2006-02-28 23:17:16 +10:00
# include "fallback.h"
2005-09-20 23:26:39 +10:00
# include "util.h"
2006-02-28 23:17:16 +10:00
2005-09-20 23:26:39 +10:00
# include "common.h"
# include "wutil.h"
# include "env_universal_common.h"
/**
Non - wide version of the set command
*/
# define SET_MBS "SET"
2005-09-23 06:16:52 +10:00
/**
Non - wide version of the set_export command
*/
# define SET_EXPORT_MBS "SET_EXPORT"
2005-09-20 23:26:39 +10:00
/**
Non - wide version of the erase command
*/
# define ERASE_MBS "ERASE"
2005-09-23 06:16:52 +10:00
/**
Non - wide version of the barrier command
*/
2005-09-20 23:26:39 +10:00
# define BARRIER_MBS "BARRIER"
2005-09-23 06:16:52 +10:00
/**
Non - wide version of the barrier_reply command
*/
2005-09-20 23:26:39 +10:00
# define BARRIER_REPLY_MBS "BARRIER_REPLY"
/**
Error message
*/
# define PARSE_ERR L"Unable to parse universal variable message: '%ls'"
2006-10-07 04:45:39 +10:00
/**
ERROR string for internal buffered reader
*/
# define ENV_UNIVERSAL_ERROR 0x100
/**
EAGAIN string for internal buffered reader
*/
# define ENV_UNIVERSAL_AGAIN 0x101
/**
EOF string for internal buffered reader
*/
# define ENV_UNIVERSAL_EOF 0x102
2005-09-23 06:16:52 +10:00
/**
A variable entry . Stores the value of a variable and whether it
should be exported . Obviously , it needs to be allocated large
enough to fit the value string .
*/
2005-10-25 01:26:25 +10:00
typedef struct var_uni_entry
2005-09-23 06:16:52 +10:00
{
2011-12-26 19:18:46 -08:00
int exportv ; /**< Whether the variable should be exported */
2012-02-18 00:22:30 +05:30
wcstring val ; /**< The value of the variable */
var_uni_entry ( ) : exportv ( 0 ) { }
2005-09-23 06:16:52 +10:00
}
2005-10-25 01:26:25 +10:00
var_uni_entry_t ;
2005-09-23 06:16:52 +10:00
2005-09-21 09:42:00 +10:00
static void parse_message ( wchar_t * msg ,
2008-01-14 02:47:47 +10:00
connection_t * src ) ;
2005-09-20 23:26:39 +10:00
/**
The table of all universal variables
*/
2012-02-18 00:22:30 +05:30
std : : map < wcstring , var_uni_entry_t * > env_universal_var ;
2005-09-20 23:26:39 +10:00
2005-10-25 01:26:25 +10:00
/**
Callback function , should be called on all events
*/
2011-12-26 19:18:46 -08:00
void ( * callback ) ( int type ,
const wchar_t * key ,
2005-09-21 09:42:00 +10:00
const wchar_t * val ) ;
2005-09-20 23:26:39 +10:00
2007-05-16 05:46:10 +10:00
/**
List of names for the UTF - 8 character set .
*/
2012-01-14 22:00:00 -08:00
static const char * iconv_utf8_names [ ] =
2007-05-16 05:46:10 +10:00
{
" utf-8 " , " UTF-8 " ,
" utf8 " , " UTF8 " ,
0
}
;
/**
List of wide character names , undefined byte length .
*/
2012-01-14 22:00:00 -08:00
static const char * iconv_wide_names_unknown [ ] =
2007-05-16 05:46:10 +10:00
{
2011-12-26 19:18:46 -08:00
" wchar_t " , " WCHAR_T " ,
" wchar " , " WCHAR " ,
2007-05-16 05:46:10 +10:00
0
}
;
/**
List of wide character names , 4 bytes long .
*/
2012-01-14 22:00:00 -08:00
static const char * iconv_wide_names_4 [ ] =
2007-05-16 05:46:10 +10:00
{
2011-12-26 19:18:46 -08:00
" wchar_t " , " WCHAR_T " ,
" wchar " , " WCHAR " ,
" ucs-4 " , " UCS-4 " ,
" ucs4 " , " UCS4 " ,
" utf-32 " , " UTF-32 " ,
" utf32 " , " UTF32 " ,
2007-05-16 05:46:10 +10:00
0
}
;
/**
List of wide character names , 2 bytes long .
*/
2012-01-14 22:00:00 -08:00
static const char * iconv_wide_names_2 [ ] =
2007-05-16 05:46:10 +10:00
{
2011-12-26 19:18:46 -08:00
" wchar_t " , " WCHAR_T " ,
" wchar " , " WCHAR " ,
" ucs-2 " , " UCS-2 " ,
" ucs2 " , " UCS2 " ,
" utf-16 " , " UTF-16 " ,
" utf16 " , " UTF16 " ,
2007-05-16 05:46:10 +10:00
0
}
;
2008-01-14 02:47:47 +10:00
/**
Convert utf - 8 string to wide string
*/
static wchar_t * utf2wcs ( const char * in )
2006-10-18 07:11:29 +10:00
{
iconv_t cd = ( iconv_t ) - 1 ;
int i , j ;
wchar_t * out ;
2007-05-10 16:14:28 +10:00
/*
Try to convert to wchar_t . If that is not a valid character set ,
try various names for ucs - 4. We can ' t be sure that ucs - 4 is
really the character set used by wchar_t , but it is the best
assumption we can make .
*/
2012-01-14 22:00:00 -08:00
const char * * to_name = 0 ;
2007-05-10 16:14:28 +10:00
switch ( sizeof ( wchar_t ) )
{
2011-12-26 19:18:46 -08:00
2007-05-10 16:14:28 +10:00
case 2 :
2007-05-16 05:46:10 +10:00
to_name = iconv_wide_names_2 ;
2007-05-10 16:14:28 +10:00
break ;
case 4 :
2007-05-16 05:46:10 +10:00
to_name = iconv_wide_names_4 ;
2007-05-10 16:14:28 +10:00
break ;
2011-12-26 19:18:46 -08:00
2007-05-10 16:14:28 +10:00
default :
2007-05-16 05:46:10 +10:00
to_name = iconv_wide_names_unknown ;
2007-05-10 16:14:28 +10:00
break ;
}
2011-12-26 19:18:46 -08:00
2007-05-10 16:14:28 +10:00
/*
2011-12-26 19:18:46 -08:00
The line protocol fish uses is always utf - 8.
2007-05-10 16:14:28 +10:00
*/
2012-01-14 22:00:00 -08:00
const char * * from_name = iconv_utf8_names ;
2006-10-18 07:11:29 +10:00
size_t in_len = strlen ( in ) ;
2007-09-09 05:19:40 +10:00
size_t out_len = sizeof ( wchar_t ) * ( in_len + 2 ) ;
2006-10-18 07:11:29 +10:00
size_t nconv ;
char * nout ;
2011-12-26 19:18:46 -08:00
out = ( wchar_t * ) malloc ( out_len ) ;
2006-10-18 07:11:29 +10:00
nout = ( char * ) out ;
if ( ! out )
return 0 ;
2011-12-26 19:18:46 -08:00
2006-10-18 07:11:29 +10:00
for ( i = 0 ; to_name [ i ] ; i + + )
{
for ( j = 0 ; from_name [ j ] ; j + + )
{
cd = iconv_open ( to_name [ i ] , from_name [ j ] ) ;
if ( cd ! = ( iconv_t ) - 1 )
{
goto start_conversion ;
2011-12-26 19:18:46 -08:00
2006-10-18 07:11:29 +10:00
}
}
}
start_conversion :
if ( cd = = ( iconv_t ) - 1 )
{
/* Something went wrong. */
2011-12-26 19:18:46 -08:00
debug ( 0 , L " Could not perform utf-8 conversion " ) ;
2006-10-18 07:11:29 +10:00
if ( errno ! = EINVAL )
wperror ( L " iconv_open " ) ;
2011-12-26 19:18:46 -08:00
2006-10-18 07:11:29 +10:00
/* Terminate the output string. */
free ( out ) ;
2011-12-26 19:18:46 -08:00
return 0 ;
2006-10-18 07:11:29 +10:00
}
2011-12-26 19:18:46 -08:00
2009-12-02 03:06:54 +11:00
nconv = iconv ( cd , ( char * * ) & in , & in_len , & nout , & out_len ) ;
2011-12-26 19:18:46 -08:00
2006-10-18 07:11:29 +10:00
if ( nconv = = ( size_t ) - 1 )
{
debug ( 0 , L " Error while converting from utf string " ) ;
return 0 ;
}
2011-12-26 19:18:46 -08:00
2006-10-18 07:11:29 +10:00
* ( ( wchar_t * ) nout ) = L ' \0 ' ;
2007-09-09 05:19:40 +10:00
/*
Check for silly iconv behaviour inserting an bytemark in the output
string .
*/
if ( * out = = L ' \ xfeff ' | | * out = = L ' \ xffef ' | | * out = = L ' \ xefbbbf ' )
{
wchar_t * out_old = out ;
out = wcsdup ( out + 1 ) ;
if ( ! out )
{
debug ( 0 , L " FNORD!!!! " ) ;
free ( out_old ) ;
return 0 ;
}
free ( out_old ) ;
}
2011-12-26 19:18:46 -08:00
2006-10-18 07:11:29 +10:00
if ( iconv_close ( cd ) ! = 0 )
wperror ( L " iconv_close " ) ;
2011-12-26 19:18:46 -08:00
return out ;
2006-10-18 07:11:29 +10:00
}
2008-01-14 02:47:47 +10:00
/**
Convert wide string to utf - 8
*/
static char * wcs2utf ( const wchar_t * in )
2006-10-18 07:11:29 +10:00
{
iconv_t cd = ( iconv_t ) - 1 ;
int i , j ;
2011-12-26 19:18:46 -08:00
2006-10-18 07:11:29 +10:00
char * char_in = ( char * ) in ;
char * out ;
2007-05-16 05:46:10 +10:00
/*
Try to convert to wchar_t . If that is not a valid character set ,
try various names for ucs - 4. We can ' t be sure that ucs - 4 is
really the character set used by wchar_t , but it is the best
assumption we can make .
*/
2012-01-14 22:00:00 -08:00
const char * * from_name = 0 ;
2006-10-18 07:11:29 +10:00
2007-05-16 05:46:10 +10:00
switch ( sizeof ( wchar_t ) )
2006-10-18 07:11:29 +10:00
{
2011-12-26 19:18:46 -08:00
2007-05-16 05:46:10 +10:00
case 2 :
from_name = iconv_wide_names_2 ;
break ;
case 4 :
from_name = iconv_wide_names_4 ;
break ;
2011-12-26 19:18:46 -08:00
2007-05-16 05:46:10 +10:00
default :
from_name = iconv_wide_names_unknown ;
break ;
2006-10-18 07:11:29 +10:00
}
2007-05-16 05:46:10 +10:00
2012-01-14 22:00:00 -08:00
const char * * to_name = iconv_utf8_names ;
2006-10-18 07:11:29 +10:00
size_t in_len = wcslen ( in ) ;
size_t out_len = sizeof ( char ) * ( ( MAX_UTF8_BYTES * in_len ) + 1 ) ;
size_t nconv ;
char * nout ;
2011-12-26 19:18:46 -08:00
out = ( char * ) malloc ( out_len ) ;
2006-10-18 07:11:29 +10:00
nout = ( char * ) out ;
in_len * = sizeof ( wchar_t ) ;
if ( ! out )
return 0 ;
2011-12-26 19:18:46 -08:00
2006-10-18 07:11:29 +10:00
for ( i = 0 ; to_name [ i ] ; i + + )
{
for ( j = 0 ; from_name [ j ] ; j + + )
{
cd = iconv_open ( to_name [ i ] , from_name [ j ] ) ;
2011-12-26 19:18:46 -08:00
2006-10-18 07:11:29 +10:00
if ( cd ! = ( iconv_t ) - 1 )
{
goto start_conversion ;
2011-12-26 19:18:46 -08:00
2006-10-18 07:11:29 +10:00
}
}
}
start_conversion :
if ( cd = = ( iconv_t ) - 1 )
{
/* Something went wrong. */
2011-12-26 19:18:46 -08:00
debug ( 0 , L " Could not perform utf-8 conversion " ) ;
2006-10-18 07:11:29 +10:00
if ( errno ! = EINVAL )
wperror ( L " iconv_open " ) ;
2011-12-26 19:18:46 -08:00
2006-10-18 07:11:29 +10:00
/* Terminate the output string. */
free ( out ) ;
2011-12-26 19:18:46 -08:00
return 0 ;
2006-10-18 07:11:29 +10:00
}
2011-12-26 19:18:46 -08:00
2006-10-18 07:11:29 +10:00
nconv = iconv ( cd , & char_in , & in_len , & nout , & out_len ) ;
2011-12-26 19:18:46 -08:00
2006-10-18 07:11:29 +10:00
if ( nconv = = ( size_t ) - 1 )
{
debug ( 0 , L " %d %d " , in_len , out_len ) ;
debug ( 0 , L " Error while converting from to string " ) ;
return 0 ;
}
2011-12-26 19:18:46 -08:00
2006-10-18 07:11:29 +10:00
* nout = ' \0 ' ;
2011-12-26 19:18:46 -08:00
2006-10-18 07:11:29 +10:00
if ( iconv_close ( cd ) ! = 0 )
wperror ( L " iconv_close " ) ;
2011-12-26 19:18:46 -08:00
return out ;
2006-10-18 07:11:29 +10:00
}
2005-09-21 09:42:00 +10:00
void env_universal_common_init ( void ( * cb ) ( int type , const wchar_t * key , const wchar_t * val ) )
2005-09-20 23:26:39 +10:00
{
callback = cb ;
}
void env_universal_common_destroy ( )
{
2012-02-18 00:22:30 +05:30
std : : map < wcstring , var_uni_entry_t * > : : iterator iter ;
for ( iter = env_universal_var . begin ( ) ; iter ! = env_universal_var . end ( ) ; + + iter )
{
var_uni_entry_t * value = iter - > second ;
delete value ;
}
2005-09-20 23:26:39 +10:00
}
2008-01-14 02:47:47 +10:00
/**
Read one byte of date form the specified connection
*/
2006-10-07 04:45:39 +10:00
static int read_byte ( connection_t * src )
{
if ( src - > buffer_consumed > = src - > buffer_used )
{
int res ;
res = read ( src - > fd , src - > buffer , ENV_UNIVERSAL_BUFFER_SIZE ) ;
2011-12-26 19:18:46 -08:00
2006-10-11 08:21:13 +10:00
// debug(4, L"Read chunk '%.*s'", res, src->buffer );
2011-12-26 19:18:46 -08:00
2006-10-07 04:45:39 +10:00
if ( res < 0 )
{
if ( errno = = EAGAIN | |
errno = = EINTR )
{
return ENV_UNIVERSAL_AGAIN ;
}
2011-12-26 19:18:46 -08:00
2006-10-07 04:45:39 +10:00
return ENV_UNIVERSAL_ERROR ;
}
2011-12-26 19:18:46 -08:00
2006-10-07 04:45:39 +10:00
if ( res = = 0 )
{
return ENV_UNIVERSAL_EOF ;
}
2011-12-26 19:18:46 -08:00
2006-10-07 04:45:39 +10:00
src - > buffer_consumed = 0 ;
src - > buffer_used = res ;
}
2011-12-26 19:18:46 -08:00
2006-10-07 04:45:39 +10:00
return src - > buffer [ src - > buffer_consumed + + ] ;
}
2005-09-20 23:26:39 +10:00
void read_message ( connection_t * src )
{
while ( 1 )
{
2011-12-26 19:18:46 -08:00
2006-10-07 04:45:39 +10:00
int ib = read_byte ( src ) ;
char b ;
2011-12-26 19:18:46 -08:00
2006-10-07 04:45:39 +10:00
switch ( ib )
2005-09-20 23:26:39 +10:00
{
2006-10-07 04:45:39 +10:00
case ENV_UNIVERSAL_AGAIN :
{
return ;
}
case ENV_UNIVERSAL_ERROR :
2005-09-20 23:26:39 +10:00
{
debug ( 2 , L " Read error on fd %d, set killme flag " , src - > fd ) ;
2006-10-23 02:03:29 +10:00
if ( debug_level > 2 )
wperror ( L " read " ) ;
2005-09-20 23:26:39 +10:00
src - > killme = 1 ;
2006-10-07 04:45:39 +10:00
return ;
2005-09-20 23:26:39 +10:00
}
2006-10-07 04:45:39 +10:00
case ENV_UNIVERSAL_EOF :
2005-09-20 23:26:39 +10:00
{
2006-10-07 04:45:39 +10:00
src - > killme = 1 ;
debug ( 3 , L " Fd %d has reached eof, set killme flag " , src - > fd ) ;
2012-03-03 23:01:42 -08:00
if ( src - > input . size ( ) > 0 )
2006-10-07 04:45:39 +10:00
{
2006-10-18 07:11:29 +10:00
char c = 0 ;
2012-03-03 23:01:42 -08:00
src - > input . push_back ( c ) ;
2011-12-26 19:18:46 -08:00
debug ( 1 ,
L " Universal variable connection closed while reading command. Partial command recieved: '%s' " ,
2012-03-03 23:01:42 -08:00
& src - > input . at ( 0 ) ) ;
2006-10-07 04:45:39 +10:00
}
return ;
2005-09-20 23:26:39 +10:00
}
}
2011-12-26 19:18:46 -08:00
2006-10-07 04:45:39 +10:00
b = ( char ) ib ;
2011-12-26 19:18:46 -08:00
2006-10-18 07:11:29 +10:00
if ( b = = ' \n ' )
2005-09-20 23:26:39 +10:00
{
2006-10-18 07:11:29 +10:00
wchar_t * msg ;
2011-12-26 19:18:46 -08:00
2006-10-18 07:11:29 +10:00
b = 0 ;
2012-03-03 23:01:42 -08:00
src - > input . push_back ( b ) ;
2011-12-26 19:18:46 -08:00
2012-03-03 23:01:42 -08:00
msg = utf2wcs ( & src - > input . at ( 0 ) ) ;
2011-12-26 19:18:46 -08:00
2006-10-18 07:11:29 +10:00
/*
Before calling parse_message , we must empty reset
everything , since the callback function could
potentially call read_message .
*/
2012-03-03 23:01:42 -08:00
src - > input . clear ( ) ;
2011-12-26 19:18:46 -08:00
2006-10-18 07:11:29 +10:00
if ( msg )
2005-09-20 23:26:39 +10:00
{
2011-12-26 19:18:46 -08:00
parse_message ( msg , src ) ;
2005-09-20 23:26:39 +10:00
}
else
{
2012-03-03 23:01:42 -08:00
debug ( 0 , _ ( L " Could not convert message '%s' to wide character string " ) , & src - > input . at ( 0 ) ) ;
2005-09-20 23:26:39 +10:00
}
2011-12-26 19:18:46 -08:00
2006-10-18 07:11:29 +10:00
free ( msg ) ;
2011-12-26 19:18:46 -08:00
2006-10-18 07:11:29 +10:00
}
else
{
2012-03-03 23:01:42 -08:00
src - > input . push_back ( b ) ;
2005-09-20 23:26:39 +10:00
}
}
}
2005-10-25 01:26:25 +10:00
/**
Remove variable with specified name
*/
2012-02-18 00:22:30 +05:30
void env_universal_common_remove ( const wcstring & name )
2005-09-20 23:26:39 +10:00
{
2012-02-18 00:22:30 +05:30
std : : map < wcstring , var_uni_entry_t * > : : iterator result = env_universal_var . find ( name ) ;
if ( result ! = env_universal_var . end ( ) )
{
var_uni_entry_t * v = result - > second ;
2012-02-18 14:42:02 +05:30
env_universal_var . erase ( result ) ;
2012-02-18 00:22:30 +05:30
delete v ;
}
2005-09-20 23:26:39 +10:00
}
2005-10-25 01:26:25 +10:00
/**
Test if the message msg contains the command cmd
*/
2005-09-20 23:26:39 +10:00
static int match ( const wchar_t * msg , const wchar_t * cmd )
{
size_t len = wcslen ( cmd ) ;
if ( wcsncasecmp ( msg , cmd , len ) ! = 0 )
return 0 ;
2005-09-23 06:16:52 +10:00
2005-09-20 23:26:39 +10:00
if ( msg [ len ] & & msg [ len ] ! = L ' ' & & msg [ len ] ! = L ' \t ' )
return 0 ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
return 1 ;
}
2011-12-26 19:18:46 -08:00
void env_universal_common_set ( const wchar_t * key , const wchar_t * val , int exportv )
2006-11-15 22:34:47 +10:00
{
var_uni_entry_t * entry ;
CHECK ( key , ) ;
CHECK ( val , ) ;
2011-12-26 19:18:46 -08:00
2012-02-18 00:22:30 +05:30
entry = new var_uni_entry_t ;
2011-12-26 19:18:46 -08:00
entry - > exportv = exportv ;
2012-02-18 00:22:30 +05:30
entry - > val = val ;
2012-03-26 01:21:10 -07:00
env_universal_common_remove ( key ) ;
2011-12-26 19:18:46 -08:00
2012-02-18 00:22:30 +05:30
env_universal_var . insert ( std : : pair < wcstring , var_uni_entry_t * > ( key , entry ) ) ;
2006-11-15 22:34:47 +10:00
if ( callback )
{
2012-03-26 01:21:10 -07:00
callback ( exportv ? SET_EXPORT : SET , key , val ) ;
2006-11-15 22:34:47 +10:00
}
}
2005-10-25 01:26:25 +10:00
/**
Parse message msg
*/
2011-12-26 19:18:46 -08:00
static void parse_message ( wchar_t * msg ,
2005-09-21 09:42:00 +10:00
connection_t * src )
2005-09-20 23:26:39 +10:00
{
2006-10-11 08:21:13 +10:00
// debug( 3, L"parse_message( %ls );", msg );
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
if ( msg [ 0 ] = = L ' # ' )
return ;
2011-12-26 19:18:46 -08:00
2005-09-23 06:16:52 +10:00
if ( match ( msg , SET_STR ) | | match ( msg , SET_EXPORT_STR ) )
2005-09-20 23:26:39 +10:00
{
2006-11-15 22:34:47 +10:00
wchar_t * name , * tmp ;
2011-12-26 19:18:46 -08:00
int exportv = match ( msg , SET_EXPORT_STR ) ;
name = msg + ( exportv ? wcslen ( SET_EXPORT_STR ) : wcslen ( SET_STR ) ) ;
2005-09-20 23:26:39 +10:00
while ( wcschr ( L " \t " , * name ) )
name + + ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
tmp = wcschr ( name , L ' : ' ) ;
if ( tmp )
{
2006-11-15 22:34:47 +10:00
wchar_t * key ;
wchar_t * val ;
2011-12-26 19:18:46 -08:00
key = ( wchar_t * ) malloc ( sizeof ( wchar_t ) * ( tmp - name + 1 ) ) ;
2005-09-20 23:26:39 +10:00
memcpy ( key , name , sizeof ( wchar_t ) * ( tmp - name ) ) ;
key [ tmp - name ] = 0 ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
val = tmp + 1 ;
2005-10-07 20:36:51 +10:00
val = unescape ( val , 0 ) ;
2011-12-26 19:18:46 -08:00
env_universal_common_set ( key , val , exportv ) ;
2006-11-15 22:34:47 +10:00
free ( val ) ;
free ( key ) ;
2005-09-20 23:26:39 +10:00
}
else
{
debug ( 1 , PARSE_ERR , msg ) ;
2011-12-26 19:18:46 -08:00
}
2005-09-20 23:26:39 +10:00
}
else if ( match ( msg , ERASE_STR ) )
{
2005-09-23 06:16:52 +10:00
wchar_t * name , * tmp ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
name = msg + wcslen ( ERASE_STR ) ;
while ( wcschr ( L " \t " , * name ) )
name + + ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
tmp = name ;
while ( iswalnum ( * tmp ) | | * tmp = = L ' _ ' )
tmp + + ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
* tmp = 0 ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
if ( ! wcslen ( name ) )
{
debug ( 1 , PARSE_ERR , msg ) ;
}
2006-11-15 22:34:47 +10:00
env_universal_common_remove ( name ) ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
if ( callback )
{
callback ( ERASE , name , 0 ) ;
}
}
else if ( match ( msg , BARRIER_STR ) )
{
message_t * msg = create_message ( BARRIER_REPLY , 0 , 0 ) ;
msg - > count = 1 ;
2011-12-26 21:39:08 -08:00
src - > unsent - > push ( msg ) ;
2005-09-20 23:26:39 +10:00
try_send_all ( src ) ;
}
else if ( match ( msg , BARRIER_REPLY_STR ) )
{
if ( callback )
{
callback ( BARRIER_REPLY , 0 , 0 ) ;
}
}
else
{
debug ( 1 , PARSE_ERR , msg ) ;
2011-12-26 19:18:46 -08:00
}
2005-09-20 23:26:39 +10:00
}
2005-10-25 01:26:25 +10:00
/**
Attempt to send the specified message to the specified file descriptor
\ return 1 on sucess , 0 if the message could not be sent without blocking and - 1 on error
*/
static int try_send ( message_t * msg ,
int fd )
2005-09-20 23:26:39 +10:00
{
2005-09-23 06:16:52 +10:00
debug ( 3 ,
2011-12-26 19:18:46 -08:00
L " before write of %d chars to fd %d " , strlen ( msg - > body ) , fd ) ;
2005-09-23 06:16:52 +10:00
2005-09-20 23:26:39 +10:00
int res = write ( fd , msg - > body , strlen ( msg - > body ) ) ;
2006-10-11 08:21:13 +10:00
if ( res ! = - 1 )
{
debug ( 4 , L " Wrote message '%s' " , msg - > body ) ;
}
else
{
debug ( 4 , L " Failed to write message '%s' " , msg - > body ) ;
}
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
if ( res = = - 1 )
{
switch ( errno )
{
case EAGAIN :
return 0 ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
default :
2006-10-23 02:03:29 +10:00
debug ( 2 ,
2005-09-23 23:10:31 +10:00
L " Error while sending universal variable message to fd %d. Closing connection " ,
2005-09-20 23:26:39 +10:00
fd ) ;
2006-10-23 02:03:29 +10:00
if ( debug_level > 2 )
wperror ( L " write " ) ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
return - 1 ;
2011-12-26 19:18:46 -08:00
}
2005-09-20 23:26:39 +10:00
}
msg - > count - - ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
if ( ! msg - > count )
{
free ( msg ) ;
}
return 1 ;
}
void try_send_all ( connection_t * c )
{
2006-10-11 08:21:13 +10:00
/* debug( 3,
2011-12-26 19:18:46 -08:00
L " Send all updates to connection on fd %d " ,
2006-10-11 08:21:13 +10:00
c - > fd ) ; */
2011-12-26 21:39:08 -08:00
while ( ! c - > unsent - > empty ( ) )
2005-09-20 23:26:39 +10:00
{
2011-12-26 21:39:08 -08:00
switch ( try_send ( c - > unsent - > front ( ) , c - > fd ) )
2005-09-20 23:26:39 +10:00
{
case 1 :
2011-12-26 21:39:08 -08:00
c - > unsent - > pop ( ) ;
2005-09-20 23:26:39 +10:00
break ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
case 0 :
2006-10-11 08:21:13 +10:00
debug ( 4 ,
2011-12-26 19:18:46 -08:00
L " Socket full, send rest later " ) ;
2005-09-20 23:26:39 +10:00
return ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
case - 1 :
c - > killme = 1 ;
return ;
}
}
}
2008-01-14 02:47:47 +10:00
/**
Escape specified string
*/
2012-02-22 12:00:02 -08:00
static wcstring full_escape ( const wchar_t * in )
2006-10-18 07:11:29 +10:00
{
2012-02-22 12:00:02 -08:00
wcstring out ;
2006-10-18 07:11:29 +10:00
for ( ; * in ; in + + )
{
if ( * in < 32 )
{
2012-02-22 12:00:02 -08:00
append_format ( out , L " \\ x%.2x " , * in ) ;
2006-10-18 07:11:29 +10:00
}
else if ( * in < 128 )
{
2012-02-22 12:00:02 -08:00
out . push_back ( * in ) ;
2006-10-18 07:11:29 +10:00
}
else if ( * in < 65536 )
{
2012-02-22 12:00:02 -08:00
append_format ( out , L " \\ u%.4x " , * in ) ;
2006-10-18 07:11:29 +10:00
}
else
{
2012-02-22 12:00:02 -08:00
append_format ( out , L " \\ U%.8x " , * in ) ;
2006-10-18 07:11:29 +10:00
}
}
2012-02-22 12:00:02 -08:00
return out ;
2006-10-18 07:11:29 +10:00
}
2005-09-20 23:26:39 +10:00
message_t * create_message ( int type ,
2011-12-26 19:18:46 -08:00
const wchar_t * key_in ,
2005-09-20 23:26:39 +10:00
const wchar_t * val_in )
{
message_t * msg = 0 ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
char * key = 0 ;
size_t sz ;
2006-10-11 08:21:13 +10:00
// debug( 4, L"Crete message of type %d", type );
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
if ( key_in )
{
2006-10-18 07:11:29 +10:00
if ( wcsvarname ( key_in ) )
{
debug ( 0 , L " Illegal variable name: '%ls' " , key_in ) ;
return 0 ;
}
2011-12-26 19:18:46 -08:00
2006-10-18 07:11:29 +10:00
key = wcs2utf ( key_in ) ;
2005-09-20 23:26:39 +10:00
if ( ! key )
{
debug ( 0 ,
L " Could not convert %ls to narrow character string " ,
key_in ) ;
return 0 ;
}
}
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
switch ( type )
{
case SET :
2005-09-23 06:16:52 +10:00
case SET_EXPORT :
2005-09-20 23:26:39 +10:00
{
if ( ! val_in )
{
val_in = L " " ;
}
2011-12-26 19:18:46 -08:00
2012-02-22 12:00:02 -08:00
wcstring esc = full_escape ( val_in ) ;
char * val = wcs2utf ( esc . c_str ( ) ) ;
2011-12-26 19:18:46 -08:00
2005-09-23 06:16:52 +10:00
sz = strlen ( type = = SET ? SET_MBS : SET_EXPORT_MBS ) + strlen ( key ) + strlen ( val ) + 4 ;
2011-12-26 19:18:46 -08:00
msg = ( message_t * ) malloc ( sizeof ( message_t ) + sz ) ;
2005-09-20 23:26:39 +10:00
if ( ! msg )
2006-07-03 20:39:57 +10:00
DIE_MEM ( ) ;
2011-12-26 19:18:46 -08:00
2005-09-23 06:16:52 +10:00
strcpy ( msg - > body , ( type = = SET ? SET_MBS : SET_EXPORT_MBS ) ) ;
strcat ( msg - > body , " " ) ;
2005-09-20 23:26:39 +10:00
strcat ( msg - > body , key ) ;
strcat ( msg - > body , " : " ) ;
strcat ( msg - > body , val ) ;
strcat ( msg - > body , " \n " ) ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
free ( val ) ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
break ;
}
case ERASE :
{
sz = strlen ( ERASE_MBS ) + strlen ( key ) + 3 ;
2011-12-26 19:18:46 -08:00
msg = ( message_t * ) malloc ( sizeof ( message_t ) + sz ) ;
2005-09-20 23:26:39 +10:00
if ( ! msg )
2006-07-03 20:39:57 +10:00
DIE_MEM ( ) ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
strcpy ( msg - > body , ERASE_MBS " " ) ;
strcat ( msg - > body , key ) ;
strcat ( msg - > body , " \n " ) ;
break ;
}
case BARRIER :
{
2011-12-26 19:18:46 -08:00
msg = ( message_t * ) malloc ( sizeof ( message_t ) +
2005-09-20 23:26:39 +10:00
strlen ( BARRIER_MBS ) + 2 ) ;
if ( ! msg )
2006-07-03 20:39:57 +10:00
DIE_MEM ( ) ;
2005-09-20 23:26:39 +10:00
strcpy ( msg - > body , BARRIER_MBS " \n " ) ;
break ;
}
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
case BARRIER_REPLY :
{
2011-12-26 19:18:46 -08:00
msg = ( message_t * ) malloc ( sizeof ( message_t ) +
2005-09-20 23:26:39 +10:00
strlen ( BARRIER_REPLY_MBS ) + 2 ) ;
if ( ! msg )
2006-07-03 20:39:57 +10:00
DIE_MEM ( ) ;
2005-09-20 23:26:39 +10:00
strcpy ( msg - > body , BARRIER_REPLY_MBS " \n " ) ;
break ;
}
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
default :
{
debug ( 0 , L " create_message: Unknown message type " ) ;
}
}
free ( key ) ;
if ( msg )
msg - > count = 0 ;
2006-10-11 08:21:13 +10:00
// debug( 4, L"Message body is '%s'", msg->body );
2011-12-26 19:18:46 -08:00
return msg ;
2005-09-20 23:26:39 +10:00
}
2005-09-23 06:16:52 +10:00
/**
2012-02-18 00:22:30 +05:30
Put exported or unexported variables in a string list
*/
2012-02-21 10:47:21 -08:00
void env_universal_common_get_names ( wcstring_list_t & lst ,
2011-12-27 18:41:38 -08:00
int show_exported ,
int show_unexported )
{
2012-02-18 00:22:30 +05:30
std : : map < wcstring , var_uni_entry_t * > : : const_iterator iter ;
for ( iter = env_universal_var . begin ( ) ; iter ! = env_universal_var . end ( ) ; + + iter )
{
const wcstring & key = iter - > first ;
const var_uni_entry_t * e = iter - > second ;
if ( ( e - > exportv & & show_exported ) | |
( ! e - > exportv & & show_unexported ) )
{
lst . push_back ( key ) ;
}
2011-12-27 18:41:38 -08:00
2012-02-18 00:22:30 +05:30
}
2011-12-27 18:41:38 -08:00
}
2012-02-24 00:55:46 +05:30
wchar_t * env_universal_common_get ( const wcstring & name )
2005-09-23 06:16:52 +10:00
{
2012-02-18 00:22:30 +05:30
std : : map < wcstring , var_uni_entry_t * > : : const_iterator result = env_universal_var . find ( name ) ;
if ( result ! = env_universal_var . end ( ) )
{
const var_uni_entry_t * e = result - > second ;
if ( e )
return const_cast < wchar_t * > ( e - > val . c_str ( ) ) ;
}
2011-12-26 19:18:46 -08:00
return 0 ;
2005-09-23 06:16:52 +10:00
}
2012-05-09 03:06:10 -07:00
int env_universal_common_get_export ( const wcstring & name )
2005-09-23 06:16:52 +10:00
{
2012-02-18 00:22:30 +05:30
std : : map < wcstring , var_uni_entry_t * > : : const_iterator result = env_universal_var . find ( name ) ;
if ( result ! = env_universal_var . end ( ) )
{
const var_uni_entry_t * e = result - > second ;
2012-05-09 03:06:10 -07:00
if ( e ! = NULL )
2012-02-18 00:22:30 +05:30
return e - > exportv ;
}
2005-09-23 06:16:52 +10:00
return 0 ;
}
2012-02-18 00:22:30 +05:30
void enqueue_all ( connection_t * c )
2005-09-23 06:16:52 +10:00
{
2012-02-18 00:22:30 +05:30
std : : map < wcstring , var_uni_entry_t * > : : const_iterator iter ;
for ( iter = env_universal_var . begin ( ) ; iter ! = env_universal_var . end ( ) ; + + iter )
{
const wcstring & key = iter - > first ;
const var_uni_entry_t * val = iter - > second ;
2011-12-26 19:18:46 -08:00
2012-02-18 00:22:30 +05:30
message_t * msg = create_message ( val - > exportv ? SET_EXPORT : SET , key . c_str ( ) , val - > val . c_str ( ) ) ;
msg - > count = 1 ;
c - > unsent - > push ( msg ) ;
}
2005-09-23 06:16:52 +10:00
try_send_all ( c ) ;
}
2006-10-19 02:44:38 +10:00
void connection_init ( connection_t * c , int fd )
{
memset ( c , 0 , sizeof ( connection_t ) ) ;
c - > fd = fd ;
2011-12-26 21:39:08 -08:00
c - > unsent = new std : : queue < message_t * > ;
2011-12-26 19:18:46 -08:00
c - > buffer_consumed = c - > buffer_used = 0 ;
2006-10-19 02:44:38 +10:00
}
void connection_destroy ( connection_t * c )
{
2011-12-26 21:39:08 -08:00
if ( c - > unsent ) delete c - > unsent ;
2006-11-15 22:34:47 +10:00
/*
A connection need not always be open - we only try to close it
if it is open .
*/
if ( c - > fd > = 0 )
2006-10-19 02:44:38 +10:00
{
2006-11-15 22:34:47 +10:00
if ( close ( c - > fd ) )
{
wperror ( L " close " ) ;
}
2006-10-19 02:44:38 +10:00
}
}