2011-06-14 06:34:18 +04:00
# include <errno.h>
# include <stdio.h>
# include <malloc.h>
# include <string.h>
2011-08-31 16:18:40 +04:00
# include <unistd.h>
2011-07-18 18:42:44 +04:00
# include <assert.h>
2011-06-27 17:15:49 +04:00
# include "daemon-shared.h"
2011-06-14 06:34:18 +04:00
/*
* Read a single message from a ( socket ) filedescriptor . Messages are delimited
* by blank lines . This call will block until all of a message is received . The
* memory will be allocated from heap . Upon error , all memory is freed and the
* buffer pointer is set to NULL .
2011-06-27 17:15:49 +04:00
*
* See also write_buffer about blocking ( read_buffer has identical behaviour ) .
2011-06-14 06:34:18 +04:00
*/
int read_buffer ( int fd , char * * buffer ) {
int bytes = 0 ;
int buffersize = 32 ;
2011-09-17 18:49:18 +04:00
char * new ;
2011-06-14 06:34:18 +04:00
* buffer = malloc ( buffersize + 1 ) ;
while ( 1 ) {
int result = read ( fd , ( * buffer ) + bytes , buffersize - bytes ) ;
if ( result > 0 )
bytes + = result ;
if ( result = = 0 )
goto fail ; /* we should never encounter EOF here */
if ( result < 0 & & errno ! = EAGAIN & & errno ! = EWOULDBLOCK )
goto fail ;
2012-01-16 09:09:16 +04:00
if ( ( ! strncmp ( ( * buffer ) + bytes - 4 , " \n ## \n " , 4 ) ) ) {
* ( * buffer + bytes - 4 ) = 0 ;
break ; /* success, we have the full message now */
}
2011-06-14 06:34:18 +04:00
if ( bytes = = buffersize ) {
buffersize + = 1024 ;
2011-09-17 18:49:18 +04:00
if ( ! ( new = realloc ( * buffer , buffersize + 1 ) ) )
2011-06-14 06:34:18 +04:00
goto fail ;
2011-09-17 18:49:18 +04:00
* buffer = new ;
2011-06-14 06:34:18 +04:00
}
2012-01-16 09:09:16 +04:00
/* TODO call select here if we encountered EAGAIN/EWOULDBLOCK */
2011-06-14 06:34:18 +04:00
}
return 1 ;
fail :
free ( * buffer ) ;
* buffer = NULL ;
return 0 ;
}
/*
* Write a buffer to a filedescriptor . Keep trying . Blocks ( even on
* SOCK_NONBLOCK ) until all of the write went through .
*
* TODO use select on EWOULDBLOCK / EAGAIN to avoid useless spinning
*/
2012-01-15 15:17:16 +04:00
int write_buffer ( int fd , const char * buffer , int length ) {
int done = 0 ;
2011-06-14 06:34:18 +04:00
int written = 0 ;
2012-01-15 15:17:16 +04:00
write :
2011-06-14 06:34:18 +04:00
while ( 1 ) {
int result = write ( fd , buffer + written , length - written ) ;
if ( result > 0 )
written + = result ;
if ( result < 0 & & errno ! = EWOULDBLOCK & & errno ! = EAGAIN )
2012-01-15 15:17:16 +04:00
return 0 ; /* too bad */
if ( written = = length ) {
if ( done )
return 1 ;
else
break ; /* done */
}
2011-06-14 06:34:18 +04:00
}
2012-01-15 15:17:16 +04:00
const char * terminate = " \n ## \n " ;
buffer = terminate ;
length = 4 ;
written = 0 ;
done = 1 ;
goto write ;
2011-06-14 06:34:18 +04:00
}
2011-06-27 17:15:49 +04:00
2011-06-30 02:20:14 +04:00
char * format_buffer ( const char * what , const char * id , va_list ap )
2011-06-27 17:15:49 +04:00
{
char * buffer , * old ;
char * next ;
2011-07-18 18:42:44 +04:00
int keylen ;
2011-06-27 17:15:49 +04:00
2011-06-30 02:20:14 +04:00
dm_asprintf ( & buffer , " %s = \" %s \" \n " , what , id ) ;
2011-06-27 17:15:49 +04:00
if ( ! buffer ) goto fail ;
2011-08-31 16:18:40 +04:00
while ( ( next = va_arg ( ap , char * ) ) ) {
2011-06-27 17:15:49 +04:00
old = buffer ;
2011-07-18 18:42:44 +04:00
assert ( strchr ( next , ' = ' ) ) ;
keylen = strchr ( next , ' = ' ) - next ;
if ( strstr ( next , " %d " ) ) {
int value = va_arg ( ap , int ) ;
dm_asprintf ( & buffer , " %s%.*s= %d \n " , buffer , keylen , next , value ) ;
dm_free ( old ) ;
} else if ( strstr ( next , " %s " ) ) {
char * value = va_arg ( ap , char * ) ;
dm_asprintf ( & buffer , " %s%.*s= \" %s \" \n " , buffer , keylen , next , value ) ;
dm_free ( old ) ;
} else if ( strstr ( next , " %b " ) ) {
char * block = va_arg ( ap , char * ) ;
if ( ! block )
continue ;
dm_asprintf ( & buffer , " %s%.*s%s " , buffer , keylen , next , block ) ;
2011-06-27 17:15:49 +04:00
dm_free ( old ) ;
} else {
dm_asprintf ( & buffer , " %s%s " , buffer , next ) ;
dm_free ( old ) ;
}
2011-07-18 18:42:44 +04:00
if ( ! buffer ) goto fail ;
2011-06-27 17:15:49 +04:00
}
return buffer ;
fail :
dm_free ( buffer ) ;
return NULL ;
}