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 ;
* 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 ;
if ( bytes = = buffersize ) {
buffersize + = 1024 ;
char * new = realloc ( * buffer , buffersize + 1 ) ;
if ( new )
* buffer = new ;
else
goto fail ;
} else {
( * buffer ) [ bytes ] = 0 ;
char * end ;
if ( ( end = strstr ( ( * buffer ) + bytes - 2 , " \n \n " ) ) ) {
* end = 0 ;
break ; /* success, we have the full message now */
}
/* TODO call select here if we encountered EAGAIN/EWOULDBLOCK */
}
}
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
*/
int write_buffer ( int fd , char * buffer , int length ) {
int written = 0 ;
while ( 1 ) {
int result = write ( fd , buffer + written , length - written ) ;
if ( result > 0 )
written + = result ;
if ( result < 0 & & errno ! = EWOULDBLOCK & & errno ! = EAGAIN )
break ; /* too bad */
if ( written = = length )
return 1 ; /* done */
}
return 0 ;
}
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
}
old = buffer ;
dm_asprintf ( & buffer , " %s \n " , buffer ) ;
dm_free ( old ) ;
return buffer ;
fail :
dm_free ( buffer ) ;
return NULL ;
}