2011-12-17 03:56:34 +04:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd .
Copyright 2011 Lennart Poettering
systemd is free software ; you can redistribute it and / or modify it
2012-04-12 02:20:58 +04:00
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation ; either version 2.1 of the License , or
2011-12-17 03:56:34 +04:00
( at your option ) any later version .
systemd 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
2012-04-12 02:20:58 +04:00
Lesser General Public License for more details .
2011-12-17 03:56:34 +04:00
2012-04-12 02:20:58 +04:00
You should have received a copy of the GNU Lesser General Public License
2011-12-17 03:56:34 +04:00
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
# include <sys/socket.h>
# include <sys/un.h>
# include <errno.h>
# include <stddef.h>
2012-01-14 04:53:20 +04:00
# include <unistd.h>
# include <fcntl.h>
2012-09-25 01:42:03 +04:00
# include <printf.h>
2011-12-17 03:56:34 +04:00
2012-04-02 21:24:30 +04:00
# define SD_JOURNAL_SUPPRESS_LOCATION
2011-12-17 03:56:34 +04:00
# include "sd-journal.h"
# include "util.h"
2011-12-23 23:50:48 +04:00
# include "socket-util.h"
2011-12-17 03:56:34 +04:00
2012-01-27 21:57:37 +04:00
# define SNDBUF_SIZE (8*1024*1024)
2012-11-21 00:22:18 +04:00
# define ALLOCA_CODE_FUNC(f, func) \
do { \
size_t _fl ; \
const char * _func = ( func ) ; \
char * * _f = & ( f ) ; \
_fl = strlen ( _func ) + 1 ; \
* _f = alloca ( _fl + 10 ) ; \
memcpy ( * _f , " CODE_FUNC= " , 10 ) ; \
memcpy ( * _f + 10 , _func , _fl ) ; \
} while ( false )
2011-12-17 03:56:34 +04:00
/* We open a single fd, and we'll share it with the current process,
* all its threads , and all its subprocesses . This means we need to
* initialize it atomically , and need to operate on it atomically
* never assuming we are the only user */
static int journal_fd ( void ) {
int fd ;
static int fd_plus_one = 0 ;
retry :
if ( fd_plus_one > 0 )
return fd_plus_one - 1 ;
fd = socket ( AF_UNIX , SOCK_DGRAM | SOCK_CLOEXEC , 0 ) ;
if ( fd < 0 )
return - errno ;
2012-01-27 21:57:37 +04:00
fd_inc_sndbuf ( fd , SNDBUF_SIZE ) ;
2011-12-17 03:56:34 +04:00
if ( ! __sync_bool_compare_and_swap ( & fd_plus_one , 0 , fd + 1 ) ) {
close_nointr_nofail ( fd ) ;
goto retry ;
}
return fd ;
}
2012-01-03 23:54:15 +04:00
_public_ int sd_journal_print ( int priority , const char * format , . . . ) {
2011-12-17 03:56:34 +04:00
int r ;
va_list ap ;
va_start ( ap , format ) ;
2011-12-17 04:32:49 +04:00
r = sd_journal_printv ( priority , format , ap ) ;
2011-12-17 03:56:34 +04:00
va_end ( ap ) ;
return r ;
}
2012-01-03 23:54:15 +04:00
_public_ int sd_journal_printv ( int priority , const char * format , va_list ap ) {
2012-07-31 18:09:01 +04:00
/* FIXME: Instead of limiting things to LINE_MAX we could do a
C99 variable - length array on the stack here in a loop . */
char buffer [ 8 + LINE_MAX ] , p [ 11 ] ; struct iovec iov [ 2 ] ;
2011-12-17 04:32:49 +04:00
2013-12-03 01:42:01 +04:00
assert_return ( priority > = 0 , - EINVAL ) ;
assert_return ( priority < = 7 , - EINVAL ) ;
assert_return ( format , - EINVAL ) ;
2011-12-23 23:50:48 +04:00
2011-12-17 04:32:49 +04:00
snprintf ( p , sizeof ( p ) , " PRIORITY=%i " , priority & LOG_PRIMASK ) ;
char_array_0 ( p ) ;
2011-12-17 03:56:34 +04:00
memcpy ( buffer , " MESSAGE= " , 8 ) ;
vsnprintf ( buffer + 8 , sizeof ( buffer ) - 8 , format , ap ) ;
char_array_0 ( buffer ) ;
zero ( iov ) ;
2011-12-17 04:32:49 +04:00
IOVEC_SET_STRING ( iov [ 0 ] , buffer ) ;
IOVEC_SET_STRING ( iov [ 1 ] , p ) ;
2011-12-17 03:56:34 +04:00
2011-12-17 04:32:49 +04:00
return sd_journal_sendv ( iov , 2 ) ;
2011-12-17 03:56:34 +04:00
}
2013-10-16 05:17:09 +04:00
_printf_ ( 1 , 0 ) static int fill_iovec_sprintf ( const char * format , va_list ap , int extra , struct iovec * * _iov ) {
2013-04-02 18:31:55 +04:00
PROTECT_ERRNO ;
2012-04-12 19:43:33 +04:00
int r , n = 0 , i = 0 , j ;
2011-12-17 03:56:34 +04:00
struct iovec * iov = NULL ;
2012-04-02 21:24:30 +04:00
assert ( _iov ) ;
if ( extra > 0 ) {
n = MAX ( extra * 2 , extra + 4 ) ;
iov = malloc0 ( n * sizeof ( struct iovec ) ) ;
if ( ! iov ) {
r = - ENOMEM ;
goto fail ;
}
i = extra ;
2012-04-12 19:43:33 +04:00
}
2011-12-17 03:56:34 +04:00
while ( format ) {
struct iovec * c ;
char * buffer ;
2012-09-25 01:42:03 +04:00
va_list aq ;
2011-12-17 03:56:34 +04:00
if ( i > = n ) {
n = MAX ( i * 2 , 4 ) ;
c = realloc ( iov , n * sizeof ( struct iovec ) ) ;
if ( ! c ) {
r = - ENOMEM ;
goto fail ;
}
iov = c ;
}
2012-09-25 01:42:03 +04:00
va_copy ( aq , ap ) ;
if ( vasprintf ( & buffer , format , aq ) < 0 ) {
va_end ( aq ) ;
2011-12-17 03:56:34 +04:00
r = - ENOMEM ;
goto fail ;
}
2012-09-25 01:42:03 +04:00
va_end ( aq ) ;
VA_FORMAT_ADVANCE ( format , ap ) ;
2011-12-17 03:56:34 +04:00
IOVEC_SET_STRING ( iov [ i + + ] , buffer ) ;
format = va_arg ( ap , char * ) ;
}
2012-04-02 21:24:30 +04:00
* _iov = iov ;
return i ;
fail :
for ( j = 0 ; j < i ; j + + )
free ( iov [ j ] . iov_base ) ;
free ( iov ) ;
return r ;
}
_public_ int sd_journal_send ( const char * format , . . . ) {
int r , i , j ;
va_list ap ;
struct iovec * iov = NULL ;
va_start ( ap , format ) ;
i = fill_iovec_sprintf ( format , ap , 0 , & iov ) ;
2011-12-17 03:56:34 +04:00
va_end ( ap ) ;
2012-04-02 21:24:30 +04:00
if ( _unlikely_ ( i < 0 ) ) {
r = i ;
goto finish ;
}
2011-12-17 03:56:34 +04:00
r = sd_journal_sendv ( iov , i ) ;
2012-04-02 21:24:30 +04:00
finish :
2011-12-17 03:56:34 +04:00
for ( j = 0 ; j < i ; j + + )
free ( iov [ j ] . iov_base ) ;
free ( iov ) ;
return r ;
}
2012-01-03 23:54:15 +04:00
_public_ int sd_journal_sendv ( const struct iovec * iov , int n ) {
2013-04-02 18:31:55 +04:00
PROTECT_ERRNO ;
2012-01-14 04:53:20 +04:00
int fd , buffer_fd ;
2011-12-17 03:56:34 +04:00
struct iovec * w ;
uint64_t * l ;
2013-04-02 18:31:55 +04:00
int i , j = 0 ;
2013-06-14 07:32:14 +04:00
struct sockaddr_un sa = {
. sun_family = AF_UNIX ,
. sun_path = " /run/systemd/journal/socket " ,
} ;
struct msghdr mh = {
. msg_name = & sa ,
. msg_namelen = offsetof ( struct sockaddr_un , sun_path ) + strlen ( sa . sun_path ) ,
} ;
2012-01-14 04:53:20 +04:00
ssize_t k ;
union {
struct cmsghdr cmsghdr ;
uint8_t buf [ CMSG_SPACE ( sizeof ( int ) ) ] ;
} control ;
struct cmsghdr * cmsg ;
2012-01-18 18:40:58 +04:00
/* We use /dev/shm instead of /tmp here, since we want this to
* be a tmpfs , and one that is available from early boot on
* and where unprivileged users can create files . */
char path [ ] = " /dev/shm/journal.XXXXXX " ;
2012-11-21 00:25:26 +04:00
bool have_syslog_identifier = false ;
2011-12-17 03:56:34 +04:00
2013-12-03 01:42:01 +04:00
assert_return ( iov , - EINVAL ) ;
assert_return ( n > 0 , - EINVAL ) ;
2011-12-17 03:56:34 +04:00
2012-11-21 00:25:26 +04:00
w = alloca ( sizeof ( struct iovec ) * n * 5 + 3 ) ;
2011-12-17 03:56:34 +04:00
l = alloca ( sizeof ( uint64_t ) * n ) ;
for ( i = 0 ; i < n ; i + + ) {
char * c , * nl ;
2013-04-02 18:31:55 +04:00
if ( _unlikely_ ( ! iov [ i ] . iov_base | | iov [ i ] . iov_len < = 1 ) )
return - EINVAL ;
2012-01-03 23:54:15 +04:00
2011-12-17 03:56:34 +04:00
c = memchr ( iov [ i ] . iov_base , ' = ' , iov [ i ] . iov_len ) ;
2013-04-02 18:31:55 +04:00
if ( _unlikely_ ( ! c | | c = = iov [ i ] . iov_base ) )
return - EINVAL ;
2011-12-17 03:56:34 +04:00
2012-11-26 00:34:10 +04:00
have_syslog_identifier = have_syslog_identifier | |
( c = = ( char * ) iov [ i ] . iov_base + 17 & &
2013-08-22 05:20:55 +04:00
startswith ( iov [ i ] . iov_base , " SYSLOG_IDENTIFIER " ) ) ;
2012-11-21 00:25:26 +04:00
2011-12-17 03:56:34 +04:00
nl = memchr ( iov [ i ] . iov_base , ' \n ' , iov [ i ] . iov_len ) ;
if ( nl ) {
2013-04-02 18:31:55 +04:00
if ( _unlikely_ ( nl < c ) )
return - EINVAL ;
2011-12-17 03:56:34 +04:00
/* Already includes a newline? Bummer, then
* let ' s write the variable name , then a
* newline , then the size ( 64 bit LE ) , followed
* by the data and a final newline */
w [ j ] . iov_base = iov [ i ] . iov_base ;
w [ j ] . iov_len = c - ( char * ) iov [ i ] . iov_base ;
j + + ;
IOVEC_SET_STRING ( w [ j + + ] , " \n " ) ;
l [ i ] = htole64 ( iov [ i ] . iov_len - ( c - ( char * ) iov [ i ] . iov_base ) - 1 ) ;
w [ j ] . iov_base = & l [ i ] ;
w [ j ] . iov_len = sizeof ( uint64_t ) ;
j + + ;
w [ j ] . iov_base = c + 1 ;
w [ j ] . iov_len = iov [ i ] . iov_len - ( c - ( char * ) iov [ i ] . iov_base ) - 1 ;
j + + ;
} else
/* Nothing special? Then just add the line and
* append a newline */
w [ j + + ] = iov [ i ] ;
IOVEC_SET_STRING ( w [ j + + ] , " \n " ) ;
}
2012-11-21 00:25:26 +04:00
if ( ! have_syslog_identifier & &
string_is_safe ( program_invocation_short_name ) ) {
/* Implicitly add program_invocation_short_name, if it
* is not set explicitly . We only do this for
* program_invocation_short_name , and nothing else
* since everything else is much nicer to retrieve
* from the outside . */
IOVEC_SET_STRING ( w [ j + + ] , " SYSLOG_IDENTIFIER= " ) ;
IOVEC_SET_STRING ( w [ j + + ] , program_invocation_short_name ) ;
IOVEC_SET_STRING ( w [ j + + ] , " \n " ) ;
}
2011-12-17 03:56:34 +04:00
fd = journal_fd ( ) ;
2013-04-02 18:31:55 +04:00
if ( _unlikely_ ( fd < 0 ) )
return fd ;
2011-12-17 03:56:34 +04:00
mh . msg_iov = w ;
mh . msg_iovlen = j ;
2012-01-14 04:53:20 +04:00
k = sendmsg ( fd , & mh , MSG_NOSIGNAL ) ;
2013-04-02 18:31:55 +04:00
if ( k > = 0 )
return 0 ;
2012-01-14 04:53:20 +04:00
2013-12-03 17:07:32 +04:00
/* Fail silently if the journal is not available */
if ( errno = = ENOENT )
return 0 ;
2013-04-02 18:31:55 +04:00
if ( errno ! = EMSGSIZE & & errno ! = ENOBUFS )
return - errno ;
2012-01-14 04:53:20 +04:00
/* Message doesn't fit... Let's dump the data in a temporary
* file and just pass a file descriptor of it to the other
* side */
buffer_fd = mkostemp ( path , O_CLOEXEC | O_RDWR ) ;
2013-04-02 18:31:55 +04:00
if ( buffer_fd < 0 )
return - errno ;
2012-01-14 04:53:20 +04:00
if ( unlink ( path ) < 0 ) {
close_nointr_nofail ( buffer_fd ) ;
2013-04-02 18:31:55 +04:00
return - errno ;
2012-01-14 04:53:20 +04:00
}
n = writev ( buffer_fd , w , j ) ;
2012-04-02 21:24:30 +04:00
if ( n < 0 ) {
2012-01-14 04:53:20 +04:00
close_nointr_nofail ( buffer_fd ) ;
2013-04-02 18:31:55 +04:00
return - errno ;
2012-01-14 04:53:20 +04:00
}
mh . msg_iov = NULL ;
mh . msg_iovlen = 0 ;
zero ( control ) ;
mh . msg_control = & control ;
mh . msg_controllen = sizeof ( control ) ;
cmsg = CMSG_FIRSTHDR ( & mh ) ;
cmsg - > cmsg_level = SOL_SOCKET ;
cmsg - > cmsg_type = SCM_RIGHTS ;
cmsg - > cmsg_len = CMSG_LEN ( sizeof ( int ) ) ;
memcpy ( CMSG_DATA ( cmsg ) , & buffer_fd , sizeof ( int ) ) ;
mh . msg_controllen = cmsg - > cmsg_len ;
k = sendmsg ( fd , & mh , MSG_NOSIGNAL ) ;
close_nointr_nofail ( buffer_fd ) ;
2013-04-02 18:31:55 +04:00
if ( k < 0 )
return - errno ;
2011-12-17 03:56:34 +04:00
2013-04-02 18:31:55 +04:00
return 0 ;
2011-12-17 03:56:34 +04:00
}
2011-12-23 23:50:48 +04:00
2012-07-31 18:09:01 +04:00
static int fill_iovec_perror_and_send ( const char * message , int skip , struct iovec iov [ ] ) {
2013-04-02 18:31:55 +04:00
PROTECT_ERRNO ;
size_t n , k ;
2012-07-31 18:09:01 +04:00
k = isempty ( message ) ? 0 : strlen ( message ) + 2 ;
n = 8 + k + 256 + 1 ;
for ( ; ; ) {
char buffer [ n ] ;
char * j ;
errno = 0 ;
2013-04-02 18:31:55 +04:00
j = strerror_r ( _saved_errno_ , buffer + 8 + k , n - 8 - k ) ;
2012-07-31 18:09:01 +04:00
if ( errno = = 0 ) {
char error [ 6 + 10 + 1 ] ; /* for a 32bit value */
if ( j ! = buffer + 8 + k )
memmove ( buffer + 8 + k , j , strlen ( j ) + 1 ) ;
memcpy ( buffer , " MESSAGE= " , 8 ) ;
if ( k > 0 ) {
memcpy ( buffer + 8 , message , k - 2 ) ;
memcpy ( buffer + 8 + k - 2 , " : " , 2 ) ;
}
2013-04-02 18:31:55 +04:00
snprintf ( error , sizeof ( error ) , " ERRNO=%u " , _saved_errno_ ) ;
2012-07-31 18:09:01 +04:00
char_array_0 ( error ) ;
IOVEC_SET_STRING ( iov [ skip + 0 ] , " PRIORITY=3 " ) ;
IOVEC_SET_STRING ( iov [ skip + 1 ] , buffer ) ;
IOVEC_SET_STRING ( iov [ skip + 2 ] , error ) ;
2013-04-02 18:31:55 +04:00
return sd_journal_sendv ( iov , skip + 3 ) ;
2012-07-31 18:09:01 +04:00
}
2013-04-02 18:31:55 +04:00
if ( errno ! = ERANGE )
return - errno ;
2012-07-31 18:09:01 +04:00
n * = 2 ;
}
}
_public_ int sd_journal_perror ( const char * message ) {
struct iovec iovec [ 3 ] ;
return fill_iovec_perror_and_send ( message , 0 , iovec ) ;
}
2012-01-06 00:43:49 +04:00
_public_ int sd_journal_stream_fd ( const char * identifier , int priority , int level_prefix ) {
2013-06-14 07:32:14 +04:00
union sockaddr_union sa = {
. un . sun_family = AF_UNIX ,
. un . sun_path = " /run/systemd/journal/stdout " ,
} ;
2011-12-23 23:50:48 +04:00
int fd ;
char * header ;
size_t l ;
ssize_t r ;
2013-12-03 01:42:01 +04:00
assert_return ( priority > = 0 , - EINVAL ) ;
assert_return ( priority < = 7 , - EINVAL ) ;
2011-12-23 23:50:48 +04:00
fd = socket ( AF_UNIX , SOCK_STREAM | SOCK_CLOEXEC , 0 ) ;
if ( fd < 0 )
return - errno ;
r = connect ( fd , & sa . sa , offsetof ( union sockaddr_union , un . sun_path ) + strlen ( sa . un . sun_path ) ) ;
if ( r < 0 ) {
close_nointr_nofail ( fd ) ;
return - errno ;
}
2012-01-06 00:39:31 +04:00
if ( shutdown ( fd , SHUT_RD ) < 0 ) {
close_nointr_nofail ( fd ) ;
return - errno ;
}
2012-01-27 21:57:37 +04:00
fd_inc_sndbuf ( fd , SNDBUF_SIZE ) ;
2012-01-06 00:43:49 +04:00
if ( ! identifier )
identifier = " " ;
2011-12-23 23:50:48 +04:00
2012-01-06 00:43:49 +04:00
l = strlen ( identifier ) ;
2012-06-22 02:19:13 +04:00
header = alloca ( l + 1 + 1 + 2 + 2 + 2 + 2 + 2 ) ;
2011-12-23 23:50:48 +04:00
2012-01-06 00:43:49 +04:00
memcpy ( header , identifier , l ) ;
2011-12-23 23:50:48 +04:00
header [ l + + ] = ' \n ' ;
2012-09-06 02:25:32 +04:00
header [ l + + ] = ' \n ' ; /* unit id */
2011-12-23 23:50:48 +04:00
header [ l + + ] = ' 0 ' + priority ;
header [ l + + ] = ' \n ' ;
2012-01-06 00:43:49 +04:00
header [ l + + ] = ' 0 ' + ! ! level_prefix ;
2011-12-23 23:50:48 +04:00
header [ l + + ] = ' \n ' ;
header [ l + + ] = ' 0 ' ;
header [ l + + ] = ' \n ' ;
2012-01-05 18:34:13 +04:00
header [ l + + ] = ' 0 ' ;
header [ l + + ] = ' \n ' ;
header [ l + + ] = ' 0 ' ;
header [ l + + ] = ' \n ' ;
2011-12-23 23:50:48 +04:00
r = loop_write ( fd , header , l , false ) ;
if ( r < 0 ) {
close_nointr_nofail ( fd ) ;
return ( int ) r ;
}
if ( ( size_t ) r ! = l ) {
close_nointr_nofail ( fd ) ;
return - errno ;
}
return fd ;
}
2012-04-02 21:24:30 +04:00
_public_ int sd_journal_print_with_location ( int priority , const char * file , const char * line , const char * func , const char * format , . . . ) {
int r ;
va_list ap ;
va_start ( ap , format ) ;
r = sd_journal_printv_with_location ( priority , file , line , func , format , ap ) ;
va_end ( ap ) ;
return r ;
}
_public_ int sd_journal_printv_with_location ( int priority , const char * file , const char * line , const char * func , const char * format , va_list ap ) {
char buffer [ 8 + LINE_MAX ] , p [ 11 ] ;
struct iovec iov [ 5 ] ;
char * f ;
2013-12-03 01:42:01 +04:00
assert_return ( priority > = 0 , - EINVAL ) ;
assert_return ( priority < = 7 , - EINVAL ) ;
assert_return ( format , - EINVAL ) ;
2012-04-02 21:24:30 +04:00
snprintf ( p , sizeof ( p ) , " PRIORITY=%i " , priority & LOG_PRIMASK ) ;
char_array_0 ( p ) ;
memcpy ( buffer , " MESSAGE= " , 8 ) ;
vsnprintf ( buffer + 8 , sizeof ( buffer ) - 8 , format , ap ) ;
char_array_0 ( buffer ) ;
/* func is initialized from __func__ which is not a macro, but
* a static const char [ ] , hence cannot easily be prefixed with
* CODE_FUNC = , hence let ' s do it manually here . */
2012-11-21 00:22:18 +04:00
ALLOCA_CODE_FUNC ( f , func ) ;
2012-04-02 21:24:30 +04:00
zero ( iov ) ;
IOVEC_SET_STRING ( iov [ 0 ] , buffer ) ;
IOVEC_SET_STRING ( iov [ 1 ] , p ) ;
IOVEC_SET_STRING ( iov [ 2 ] , file ) ;
IOVEC_SET_STRING ( iov [ 3 ] , line ) ;
IOVEC_SET_STRING ( iov [ 4 ] , f ) ;
return sd_journal_sendv ( iov , ELEMENTSOF ( iov ) ) ;
}
_public_ int sd_journal_send_with_location ( const char * file , const char * line , const char * func , const char * format , . . . ) {
int r , i , j ;
va_list ap ;
struct iovec * iov = NULL ;
char * f ;
va_start ( ap , format ) ;
i = fill_iovec_sprintf ( format , ap , 3 , & iov ) ;
va_end ( ap ) ;
if ( _unlikely_ ( i < 0 ) ) {
r = i ;
goto finish ;
}
2012-11-21 00:22:18 +04:00
ALLOCA_CODE_FUNC ( f , func ) ;
2012-04-02 21:24:30 +04:00
IOVEC_SET_STRING ( iov [ 0 ] , file ) ;
IOVEC_SET_STRING ( iov [ 1 ] , line ) ;
IOVEC_SET_STRING ( iov [ 2 ] , f ) ;
r = sd_journal_sendv ( iov , i ) ;
finish :
for ( j = 3 ; j < i ; j + + )
free ( iov [ j ] . iov_base ) ;
free ( iov ) ;
return r ;
}
2012-07-31 18:09:01 +04:00
_public_ int sd_journal_sendv_with_location (
const char * file , const char * line ,
const char * func ,
const struct iovec * iov , int n ) {
2012-04-02 21:24:30 +04:00
struct iovec * niov ;
char * f ;
2013-12-03 01:42:01 +04:00
assert_return ( iov , - EINVAL ) ;
assert_return ( n > 0 , - EINVAL ) ;
2012-04-02 21:24:30 +04:00
niov = alloca ( sizeof ( struct iovec ) * ( n + 3 ) ) ;
memcpy ( niov , iov , sizeof ( struct iovec ) * n ) ;
2012-11-21 00:22:18 +04:00
ALLOCA_CODE_FUNC ( f , func ) ;
2012-04-02 21:24:30 +04:00
IOVEC_SET_STRING ( niov [ n + + ] , file ) ;
IOVEC_SET_STRING ( niov [ n + + ] , line ) ;
IOVEC_SET_STRING ( niov [ n + + ] , f ) ;
return sd_journal_sendv ( niov , n ) ;
}
2012-07-31 18:09:01 +04:00
_public_ int sd_journal_perror_with_location (
const char * file , const char * line ,
const char * func ,
const char * message ) {
struct iovec iov [ 6 ] ;
char * f ;
2012-11-21 00:22:18 +04:00
ALLOCA_CODE_FUNC ( f , func ) ;
2012-07-31 18:09:01 +04:00
IOVEC_SET_STRING ( iov [ 0 ] , file ) ;
IOVEC_SET_STRING ( iov [ 1 ] , line ) ;
IOVEC_SET_STRING ( iov [ 2 ] , f ) ;
return fill_iovec_perror_and_send ( message , 3 , iov ) ;
}