2013-02-20 07:22:03 +04:00
/*-*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*-*/
2013-02-16 21:32:05 +04:00
/***
This file is part of systemd .
Copyright 2013 Steven Hiscocks , Zbigniew Jędrzejewski - Szmek
systemd is free software ; you can redistribute it and / or modify it
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
( 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
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public License
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
2013-02-08 23:41:21 +04:00
# include <Python.h>
# include <structmember.h>
# include <datetime.h>
2013-02-22 16:33:06 +04:00
# include <stdio.h>
# include <systemd/sd-journal.h>
# include "pyutil.h"
# include "macro.h"
# include "util.h"
2013-02-08 23:41:21 +04:00
typedef struct {
PyObject_HEAD
sd_journal * j ;
2013-03-01 04:32:31 +04:00
} Reader ;
static PyTypeObject ReaderType ;
2013-02-08 23:41:21 +04:00
2013-02-17 20:26:10 +04:00
static int set_error ( int r , const char * path , const char * invalid_message ) {
if ( r > = 0 )
return r ;
if ( r = = - EINVAL & & invalid_message )
PyErr_SetString ( PyExc_ValueError , invalid_message ) ;
else if ( r = = - ENOMEM )
PyErr_SetString ( PyExc_MemoryError , " Not enough memory " ) ;
else {
errno = - r ;
PyErr_SetFromErrnoWithFilename ( PyExc_OSError , path ) ;
}
2013-03-07 20:28:44 +04:00
return - 1 ;
2013-02-17 20:26:10 +04:00
}
2013-02-23 04:11:36 +04:00
# if PY_MAJOR_VERSION >= 3
static PyTypeObject MonotonicType ;
PyDoc_STRVAR ( MonotonicType__doc__ ,
" A tuple of (timestamp, bootid) for holding monotonic timestamps " ) ;
static PyStructSequence_Field MonotonicType_fields [ ] = {
{ ( char * ) " timestamp " , ( char * ) " Time " } ,
{ ( char * ) " bootid " , ( char * ) " Unique identifier of the boot " } ,
{ NULL , NULL }
} ;
static PyStructSequence_Desc Monotonic_desc = {
( char * ) " journal.Monotonic " ,
MonotonicType__doc__ ,
MonotonicType_fields ,
2 ,
} ;
# endif
2013-03-01 04:32:31 +04:00
static void Reader_dealloc ( Reader * self )
2013-02-08 23:41:21 +04:00
{
sd_journal_close ( self - > j ) ;
Py_TYPE ( self ) - > tp_free ( ( PyObject * ) self ) ;
}
2013-03-01 04:32:31 +04:00
PyDoc_STRVAR ( Reader__doc__ ,
2013-03-07 20:28:44 +04:00
" Reader([flags | path]) -> ... \n \n "
2013-03-01 04:32:31 +04:00
" Reader allows filtering and retrieval of Journal entries. \n "
2013-03-07 20:28:44 +04:00
" Note: this is a low-level interface, and probably not what you \n "
" want, use systemd.journal.Reader instead. \n \n "
2013-02-20 07:22:03 +04:00
" Argument `flags` sets open flags of the journal, which can be one \n "
" of, or ORed combination of constants: LOCAL_ONLY (default) opens \n "
" journal on local machine only; RUNTIME_ONLY opens only \n "
" volatile journal files; and SYSTEM_ONLY opens only \n "
2013-03-07 20:28:44 +04:00
" journal files of system services and the kernel. \n \n "
2013-02-20 07:22:03 +04:00
" Argument `path` is the directory of journal files. Note that \n "
2013-03-07 20:28:44 +04:00
" `flags` and `path` are exclusive. \n " ) ;
2013-03-01 04:32:31 +04:00
static int Reader_init ( Reader * self , PyObject * args , PyObject * keywds )
2013-02-08 23:41:21 +04:00
{
2013-03-07 20:28:44 +04:00
int flags = 0 , r ;
2013-02-20 06:58:54 +04:00
char * path = NULL ;
2013-02-08 23:41:21 +04:00
2013-02-20 06:58:54 +04:00
static const char * const kwlist [ ] = { " flags " , " path " , NULL } ;
if ( ! PyArg_ParseTupleAndKeywords ( args , keywds , " |iz " , ( char * * ) kwlist ,
& flags , & path ) )
2013-03-07 20:28:44 +04:00
return - 1 ;
if ( ! flags )
flags = SD_JOURNAL_LOCAL_ONLY ;
else
if ( path ) {
PyErr_SetString ( PyExc_ValueError , " cannot use both flags and path " ) ;
return - 1 ;
}
2013-02-08 23:41:21 +04:00
2013-02-16 21:29:57 +04:00
Py_BEGIN_ALLOW_THREADS
2013-02-20 07:11:02 +04:00
if ( path )
2013-02-08 23:41:21 +04:00
r = sd_journal_open_directory ( & self - > j , path , 0 ) ;
2013-02-20 07:11:02 +04:00
else
2013-02-08 23:41:21 +04:00
r = sd_journal_open ( & self - > j , flags ) ;
2013-02-16 21:29:57 +04:00
Py_END_ALLOW_THREADS
2013-02-08 23:41:21 +04:00
2013-02-17 20:26:10 +04:00
return set_error ( r , path , " Invalid flags or path " ) ;
2013-02-08 23:41:21 +04:00
}
2013-03-07 09:35:28 +04:00
PyDoc_STRVAR ( Reader_fileno__doc__ ,
" fileno() -> int \n \n "
" Get a file descriptor to poll for changes in the journal. \n "
" This method invokes sd_journal_get_fd(). \n "
" See man:sd_journal_get_fd(3). " ) ;
static PyObject * Reader_fileno ( Reader * self , PyObject * args )
{
int r ;
r = sd_journal_get_fd ( self - > j ) ;
set_error ( r , NULL , NULL ) ;
if ( r < 0 )
return NULL ;
return long_FromLong ( r ) ;
}
PyDoc_STRVAR ( Reader_reliable_fd__doc__ ,
" reliable_fd() -> bool \n \n "
" Returns True iff the journal can be polled reliably. \n "
" This method invokes sd_journal_reliable_fd(). \n "
" See man:sd_journal_reliable_fd(3). " ) ;
static PyObject * Reader_reliable_fd ( Reader * self , PyObject * args )
{
int r ;
r = sd_journal_reliable_fd ( self - > j ) ;
set_error ( r , NULL , NULL ) ;
if ( r < 0 )
return NULL ;
return PyBool_FromLong ( r ) ;
}
PyDoc_STRVAR ( Reader_close__doc__ ,
2013-03-08 00:27:30 +04:00
" close() -> None \n \n "
2013-03-07 09:35:28 +04:00
" Free resources allocated by this Reader object. \n "
" This method invokes sd_journal_close(). \n "
" See man:sd_journal_close(3). " ) ;
static PyObject * Reader_close ( Reader * self , PyObject * args )
{
2013-03-18 09:12:25 +04:00
assert ( self ) ;
assert ( ! args ) ;
sd_journal_close ( self - > j ) ;
self - > j = NULL ;
Py_RETURN_NONE ;
}
PyDoc_STRVAR ( Reader___enter____doc__ ,
" __enter__() -> self \n \n "
" Part of the context manager protocol. \n "
" Returns self. \n " ) ;
static PyObject * Reader___enter__ ( PyObject * self , PyObject * args )
{
assert ( self ) ;
assert ( ! args ) ;
Py_INCREF ( self ) ;
return self ;
}
PyDoc_STRVAR ( Reader___exit____doc__ ,
" __exit__(type, value, traceback) -> None \n \n "
" Part of the context manager protocol. \n "
" Closes the journal. \n " ) ;
static PyObject * Reader___exit__ ( Reader * self , PyObject * args )
{
assert ( self ) ;
2013-03-07 09:35:28 +04:00
sd_journal_close ( self - > j ) ;
2013-03-08 00:32:33 +04:00
self - > j = NULL ;
2013-03-07 09:35:28 +04:00
Py_RETURN_NONE ;
}
2013-03-01 04:32:31 +04:00
PyDoc_STRVAR ( Reader_get_next__doc__ ,
2013-02-20 07:22:03 +04:00
" get_next([skip]) -> dict \n \n "
" Return dictionary of the next log entry. Optional skip value will \n "
2013-02-20 08:03:32 +04:00
" return the `skip` \\ -th log entry. " ) ;
2013-03-01 04:32:31 +04:00
static PyObject * Reader_get_next ( Reader * self , PyObject * args )
2013-02-08 23:41:21 +04:00
{
2013-02-20 07:11:02 +04:00
PyObject * dict ;
const void * msg ;
size_t msg_len ;
2013-02-22 16:33:06 +04:00
int64_t skip = 1LL ;
int r ;
2013-02-20 07:11:02 +04:00
2013-02-20 07:22:03 +04:00
if ( ! PyArg_ParseTuple ( args , " |L " , & skip ) )
2013-02-08 23:41:21 +04:00
return NULL ;
2013-02-16 21:29:57 +04:00
if ( skip = = 0LL ) {
2013-02-20 07:11:02 +04:00
PyErr_SetString ( PyExc_ValueError , " skip must be nonzero " ) ;
2013-02-16 21:29:57 +04:00
return NULL ;
}
Py_BEGIN_ALLOW_THREADS
2013-02-20 07:11:02 +04:00
if ( skip = = 1LL )
2013-02-08 23:41:21 +04:00
r = sd_journal_next ( self - > j ) ;
2013-02-20 07:11:02 +04:00
else if ( skip = = - 1LL )
2013-02-08 23:41:21 +04:00
r = sd_journal_previous ( self - > j ) ;
2013-02-20 07:11:02 +04:00
else if ( skip > 1LL )
2013-02-08 23:41:21 +04:00
r = sd_journal_next_skip ( self - > j , skip ) ;
2013-02-20 07:11:02 +04:00
else if ( skip < - 1LL )
2013-02-08 23:41:21 +04:00
r = sd_journal_previous_skip ( self - > j , - skip ) ;
2013-02-22 16:33:06 +04:00
else
assert_not_reached ( " should not be here " ) ;
2013-02-16 21:29:57 +04:00
Py_END_ALLOW_THREADS
2013-02-08 23:41:21 +04:00
2013-02-17 20:26:10 +04:00
set_error ( r , NULL , NULL ) ;
if ( r < 0 )
2013-02-08 23:41:21 +04:00
return NULL ;
2013-02-17 20:26:10 +04:00
else if ( r = = 0 ) /* EOF */
2013-02-08 23:41:21 +04:00
return PyDict_New ( ) ;
dict = PyDict_New ( ) ;
2013-02-22 16:33:06 +04:00
if ( ! dict )
return NULL ;
2013-02-08 23:41:21 +04:00
SD_JOURNAL_FOREACH_DATA ( self - > j , msg , msg_len ) {
2013-02-22 16:33:06 +04:00
PyObject _cleanup_Py_DECREF_ * key = NULL , * value = NULL ;
const char * delim_ptr ;
2013-02-08 23:41:21 +04:00
delim_ptr = memchr ( msg , ' = ' , msg_len ) ;
2013-02-22 16:33:06 +04:00
if ( ! delim_ptr ) {
PyErr_SetString ( PyExc_OSError ,
" journal gave us a field without '=' " ) ;
goto error ;
}
2013-02-17 06:54:09 +04:00
key = unicode_FromStringAndSize ( msg , delim_ptr - ( const char * ) msg ) ;
2013-02-22 16:33:06 +04:00
if ( ! key )
goto error ;
value = PyBytes_FromStringAndSize (
delim_ptr + 1 ,
( const char * ) msg + msg_len - ( delim_ptr + 1 ) ) ;
if ( ! value )
goto error ;
2013-02-08 23:41:21 +04:00
if ( PyDict_Contains ( dict , key ) ) {
2013-02-22 16:33:06 +04:00
PyObject * cur_value = PyDict_GetItem ( dict , key ) ;
2013-02-15 20:59:50 +04:00
if ( PyList_CheckExact ( cur_value ) ) {
2013-02-22 16:33:06 +04:00
r = PyList_Append ( cur_value , value ) ;
if ( r < 0 )
goto error ;
} else {
PyObject _cleanup_Py_DECREF_ * tmp_list = PyList_New ( 0 ) ;
if ( ! tmp_list )
goto error ;
r = PyList_Append ( tmp_list , cur_value ) ;
if ( r < 0 )
goto error ;
r = PyList_Append ( tmp_list , value ) ;
if ( r < 0 )
goto error ;
2013-03-01 21:29:57 +04:00
r = PyDict_SetItem ( dict , key , tmp_list ) ;
2013-02-22 16:33:06 +04:00
if ( r < 0 )
goto error ;
2013-02-08 23:41:21 +04:00
}
2013-02-22 16:33:06 +04:00
} else {
r = PyDict_SetItem ( dict , key , value ) ;
if ( r < 0 )
goto error ;
2013-02-08 23:41:21 +04:00
}
}
2013-02-20 07:11:02 +04:00
{
2013-02-22 16:33:06 +04:00
PyObject _cleanup_Py_DECREF_ * key = NULL , * value = NULL ;
2013-02-20 07:11:02 +04:00
uint64_t realtime ;
2013-02-22 16:33:06 +04:00
r = sd_journal_get_realtime_usec ( self - > j , & realtime ) ;
if ( set_error ( r , NULL , NULL ) )
goto error ;
key = unicode_FromString ( " __REALTIME_TIMESTAMP " ) ;
if ( ! key )
goto error ;
assert_cc ( sizeof ( unsigned long long ) = = sizeof ( realtime ) ) ;
value = PyLong_FromUnsignedLongLong ( realtime ) ;
if ( ! value )
goto error ;
if ( PyDict_SetItem ( dict , key , value ) )
goto error ;
2013-02-08 23:41:21 +04:00
}
2013-02-20 07:11:02 +04:00
{
2013-02-23 04:11:36 +04:00
PyObject _cleanup_Py_DECREF_
* key = NULL , * timestamp = NULL , * bytes = NULL , * value = NULL ;
sd_id128_t id ;
2013-02-20 07:11:02 +04:00
uint64_t monotonic ;
2013-02-22 16:33:06 +04:00
2013-02-23 04:11:36 +04:00
r = sd_journal_get_monotonic_usec ( self - > j , & monotonic , & id ) ;
2013-02-22 16:33:06 +04:00
if ( set_error ( r , NULL , NULL ) )
goto error ;
2013-02-23 04:11:36 +04:00
assert_cc ( sizeof ( unsigned long long ) = = sizeof ( monotonic ) ) ;
2013-02-22 16:33:06 +04:00
key = unicode_FromString ( " __MONOTONIC_TIMESTAMP " ) ;
2013-02-23 04:11:36 +04:00
timestamp = PyLong_FromUnsignedLongLong ( monotonic ) ;
bytes = PyBytes_FromStringAndSize ( ( const char * ) & id . bytes , sizeof ( id . bytes ) ) ;
# if PY_MAJOR_VERSION >= 3
value = PyStructSequence_New ( & MonotonicType ) ;
# else
value = PyTuple_New ( 2 ) ;
# endif
if ( ! key | | ! timestamp | | ! bytes | | ! value )
2013-02-22 16:33:06 +04:00
goto error ;
2013-02-23 04:11:36 +04:00
Py_INCREF ( timestamp ) ;
Py_INCREF ( bytes ) ;
# if PY_MAJOR_VERSION >= 3
PyStructSequence_SET_ITEM ( value , 0 , timestamp ) ;
PyStructSequence_SET_ITEM ( value , 1 , bytes ) ;
# else
PyTuple_SET_ITEM ( value , 0 , timestamp ) ;
PyTuple_SET_ITEM ( value , 1 , bytes ) ;
# endif
2013-02-22 16:33:06 +04:00
if ( PyDict_SetItem ( dict , key , value ) )
goto error ;
2013-02-08 23:41:21 +04:00
}
2013-02-20 07:11:02 +04:00
{
2013-02-22 16:33:06 +04:00
PyObject _cleanup_Py_DECREF_ * key = NULL , * value = NULL ;
char _cleanup_free_ * cursor = NULL ;
r = sd_journal_get_cursor ( self - > j , & cursor ) ;
if ( set_error ( r , NULL , NULL ) )
goto error ;
key = unicode_FromString ( " __CURSOR " ) ;
if ( ! key )
goto error ;
value = PyBytes_FromString ( cursor ) ;
if ( ! value )
goto error ;
if ( PyDict_SetItem ( dict , key , value ) )
goto error ;
2013-02-08 23:41:21 +04:00
}
return dict ;
2013-02-22 16:33:06 +04:00
error :
Py_DECREF ( dict ) ;
return NULL ;
2013-02-08 23:41:21 +04:00
}
2013-03-01 04:32:31 +04:00
PyDoc_STRVAR ( Reader_get_previous__doc__ ,
2013-02-20 07:22:03 +04:00
" get_previous([skip]) -> dict \n \n "
" Return dictionary of the previous log entry. Optional skip value \n "
2013-02-20 08:03:32 +04:00
" will return the -`skip` \\ -th log entry. Equivalent to get_next(-skip). " ) ;
2013-03-01 04:32:31 +04:00
static PyObject * Reader_get_previous ( Reader * self , PyObject * args )
2013-02-08 23:41:21 +04:00
{
2013-02-20 07:22:03 +04:00
int64_t skip = 1LL ;
if ( ! PyArg_ParseTuple ( args , " |L " , & skip ) )
2013-02-08 23:41:21 +04:00
return NULL ;
2013-02-20 06:58:54 +04:00
return PyObject_CallMethod ( ( PyObject * ) self , ( char * ) " get_next " ,
( char * ) " L " , - skip ) ;
2013-02-08 23:41:21 +04:00
}
2013-03-01 04:32:31 +04:00
PyDoc_STRVAR ( Reader_add_match__doc__ ,
2013-02-20 07:22:03 +04:00
" add_match(match) -> None \n \n "
" Add a match to filter journal log entries. All matches of different \n "
2013-02-20 08:03:32 +04:00
" fields are combined with logical AND, and matches of the same field \n "
" are automatically combined with logical OR. \n "
2013-02-20 07:22:03 +04:00
" Match is a string of the form \" FIELD=value \" . " ) ;
2013-03-01 04:32:31 +04:00
static PyObject * Reader_add_match ( Reader * self , PyObject * args , PyObject * keywds )
2013-02-08 23:41:21 +04:00
{
2013-02-16 22:53:52 +04:00
char * match ;
2013-02-20 07:11:02 +04:00
int match_len , r ;
if ( ! PyArg_ParseTuple ( args , " s# " , & match , & match_len ) )
2013-02-16 22:53:52 +04:00
return NULL ;
r = sd_journal_add_match ( self - > j , match , match_len ) ;
2013-02-17 20:26:10 +04:00
set_error ( r , NULL , " Invalid match " ) ;
if ( r < 0 )
return NULL ;
2013-02-08 23:41:21 +04:00
Py_RETURN_NONE ;
}
2013-03-01 04:32:31 +04:00
PyDoc_STRVAR ( Reader_add_disjunction__doc__ ,
2013-02-20 07:22:03 +04:00
" add_disjunction() -> None \n \n "
2013-02-20 08:03:32 +04:00
" Inserts a logical OR between matches added before and afterwards. " ) ;
2013-03-01 04:32:31 +04:00
static PyObject * Reader_add_disjunction ( Reader * self , PyObject * args )
2013-02-08 23:41:21 +04:00
{
int r ;
r = sd_journal_add_disjunction ( self - > j ) ;
2013-02-17 20:26:10 +04:00
set_error ( r , NULL , NULL ) ;
if ( r < 0 )
2013-02-08 23:41:21 +04:00
return NULL ;
Py_RETURN_NONE ;
}
2013-03-01 04:32:31 +04:00
PyDoc_STRVAR ( Reader_flush_matches__doc__ ,
2013-02-20 07:22:03 +04:00
" flush_matches() -> None \n \n "
2013-02-20 08:03:32 +04:00
" Clear all current match filters. " ) ;
2013-03-01 04:32:31 +04:00
static PyObject * Reader_flush_matches ( Reader * self , PyObject * args )
2013-02-08 23:41:21 +04:00
{
sd_journal_flush_matches ( self - > j ) ;
Py_RETURN_NONE ;
}
2013-03-07 09:26:24 +04:00
PyDoc_STRVAR ( Reader_seek_head__doc__ ,
" seek_head() -> None \n \n "
" Jump to the beginning of the journal. \n "
" This method invokes sd_journal_seek_head(). \n "
" See man:sd_journal_seek_head(3). " ) ;
static PyObject * Reader_seek_head ( Reader * self , PyObject * args )
2013-02-08 23:41:21 +04:00
{
2013-03-07 09:26:24 +04:00
int r ;
Py_BEGIN_ALLOW_THREADS
r = sd_journal_seek_head ( self - > j ) ;
Py_END_ALLOW_THREADS
if ( set_error ( r , NULL , NULL ) )
2013-02-08 23:41:21 +04:00
return NULL ;
2013-03-07 09:26:24 +04:00
Py_RETURN_NONE ;
}
2013-02-08 23:41:21 +04:00
2013-03-07 09:26:24 +04:00
PyDoc_STRVAR ( Reader_seek_tail__doc__ ,
" seek_tail() -> None \n \n "
2013-03-08 00:27:30 +04:00
" Jump to the end of the journal. \n "
2013-03-07 09:26:24 +04:00
" This method invokes sd_journal_seek_tail(). \n "
" See man:sd_journal_seek_tail(3). " ) ;
static PyObject * Reader_seek_tail ( Reader * self , PyObject * args )
{
int r ;
Py_BEGIN_ALLOW_THREADS
r = sd_journal_seek_tail ( self - > j ) ;
Py_END_ALLOW_THREADS
if ( set_error ( r , NULL , NULL ) )
2013-02-16 17:40:44 +04:00
return NULL ;
2013-02-08 23:41:21 +04:00
Py_RETURN_NONE ;
}
2013-03-01 04:32:31 +04:00
PyDoc_STRVAR ( Reader_seek_realtime__doc__ ,
2013-02-20 07:22:03 +04:00
" seek_realtime(realtime) -> None \n \n "
" Seek to nearest matching journal entry to `realtime`. Argument \n "
" `realtime` can must be an integer unix timestamp. " ) ;
2013-03-01 04:32:31 +04:00
static PyObject * Reader_seek_realtime ( Reader * self , PyObject * args )
2013-02-08 23:41:21 +04:00
{
2013-02-16 23:10:49 +04:00
double timedouble ;
2013-02-20 07:11:02 +04:00
uint64_t timestamp ;
int r ;
if ( ! PyArg_ParseTuple ( args , " d " , & timedouble ) )
2013-02-08 23:41:21 +04:00
return NULL ;
2013-02-16 23:10:49 +04:00
timestamp = ( uint64_t ) ( timedouble * 1.0E6 ) ;
2013-02-08 23:41:21 +04:00
if ( ( int64_t ) timestamp < 0LL ) {
2013-02-20 07:11:02 +04:00
PyErr_SetString ( PyExc_ValueError , " Time must be a positive integer " ) ;
2013-02-08 23:41:21 +04:00
return NULL ;
}
Py_BEGIN_ALLOW_THREADS
r = sd_journal_seek_realtime_usec ( self - > j , timestamp ) ;
Py_END_ALLOW_THREADS
2013-02-17 20:26:10 +04:00
if ( set_error ( r , NULL , NULL ) )
2013-02-08 23:41:21 +04:00
return NULL ;
Py_RETURN_NONE ;
}
2013-03-01 04:32:31 +04:00
PyDoc_STRVAR ( Reader_seek_monotonic__doc__ ,
2013-02-20 07:22:03 +04:00
" seek_monotonic(monotonic[, bootid]) -> None \n \n "
" Seek to nearest matching journal entry to `monotonic`. Argument \n "
" `monotonic` is an timestamp from boot in seconds. \n "
" Argument `bootid` is a string representing which boot the \n "
" monotonic time is reference to. Defaults to current bootid. " ) ;
2013-03-01 04:32:31 +04:00
static PyObject * Reader_seek_monotonic ( Reader * self , PyObject * args )
2013-02-08 23:41:21 +04:00
{
2013-02-16 21:31:18 +04:00
double timedouble ;
2013-02-20 07:22:03 +04:00
char * bootid = NULL ;
2013-02-20 07:11:02 +04:00
uint64_t timestamp ;
2013-02-23 04:11:36 +04:00
sd_id128_t id ;
2013-02-20 07:11:02 +04:00
int r ;
2013-02-20 07:22:03 +04:00
if ( ! PyArg_ParseTuple ( args , " d|z " , & timedouble , & bootid ) )
2013-02-08 23:41:21 +04:00
return NULL ;
2013-02-16 21:31:18 +04:00
timestamp = ( uint64_t ) ( timedouble * 1.0E6 ) ;
2013-02-08 23:41:21 +04:00
if ( ( int64_t ) timestamp < 0LL ) {
2013-02-16 21:31:18 +04:00
PyErr_SetString ( PyExc_ValueError , " Time must be positive number " ) ;
2013-02-08 23:41:21 +04:00
return NULL ;
}
if ( bootid ) {
2013-02-23 04:11:36 +04:00
r = sd_id128_from_string ( bootid , & id ) ;
2013-02-17 20:26:10 +04:00
if ( set_error ( r , NULL , " Invalid bootid " ) )
2013-02-08 23:41:21 +04:00
return NULL ;
2013-02-17 20:26:10 +04:00
} else {
Py_BEGIN_ALLOW_THREADS
2013-02-23 04:11:36 +04:00
r = sd_id128_get_boot ( & id ) ;
2013-02-17 20:26:10 +04:00
Py_END_ALLOW_THREADS
if ( set_error ( r , NULL , NULL ) )
2013-02-08 23:41:21 +04:00
return NULL ;
}
Py_BEGIN_ALLOW_THREADS
2013-02-23 04:11:36 +04:00
r = sd_journal_seek_monotonic_usec ( self - > j , id , timestamp ) ;
2013-02-08 23:41:21 +04:00
Py_END_ALLOW_THREADS
2013-02-17 20:26:10 +04:00
if ( set_error ( r , NULL , NULL ) )
2013-02-08 23:41:21 +04:00
return NULL ;
Py_RETURN_NONE ;
}
2013-02-17 20:26:10 +04:00
2013-03-01 04:32:31 +04:00
PyDoc_STRVAR ( Reader_wait__doc__ ,
2013-02-20 08:03:32 +04:00
" wait([timeout]) -> state change (integer) \n \n "
" Wait for a change in the journal. Argument `timeout` specifies \n "
" the maximum number of seconds to wait before returning \n "
" regardless of wheter the journal has changed. If `timeout` is not given \n "
" or is 0, then block forever. \n "
2013-02-20 07:22:03 +04:00
" Will return constants: NOP if no change; APPEND if new \n "
" entries have been added to the end of the journal; and \n "
" INVALIDATE if journal files have been added or removed. " ) ;
2013-03-01 04:32:31 +04:00
static PyObject * Reader_wait ( Reader * self , PyObject * args , PyObject * keywds )
2013-02-08 23:41:21 +04:00
{
2013-02-20 06:58:54 +04:00
int r ;
int64_t timeout = 0LL ;
if ( ! PyArg_ParseTuple ( args , " |L " , & timeout ) )
2013-02-08 23:41:21 +04:00
return NULL ;
2013-02-16 21:29:57 +04:00
Py_BEGIN_ALLOW_THREADS
2013-03-06 08:23:09 +04:00
r = sd_journal_wait ( self - > j ,
timeout = = 0 ? ( uint64_t ) - 1 : timeout * 1E6 ) ;
2013-02-16 21:29:57 +04:00
Py_END_ALLOW_THREADS
2013-03-06 08:23:09 +04:00
if ( set_error ( r , NULL , NULL ) < 0 )
2013-02-16 21:29:57 +04:00
return NULL ;
2013-02-17 20:26:10 +04:00
2013-02-17 06:54:09 +04:00
return long_FromLong ( r ) ;
2013-02-08 23:41:21 +04:00
}
2013-03-01 04:32:31 +04:00
PyDoc_STRVAR ( Reader_seek_cursor__doc__ ,
2013-02-20 07:22:03 +04:00
" seek_cursor(cursor) -> None \n \n "
2013-02-20 08:03:32 +04:00
" Seek to journal entry by given unique reference `cursor`. " ) ;
2013-03-01 04:32:31 +04:00
static PyObject * Reader_seek_cursor ( Reader * self , PyObject * args )
2013-02-08 23:41:21 +04:00
{
const char * cursor ;
2013-02-20 07:11:02 +04:00
int r ;
2013-02-20 07:22:03 +04:00
if ( ! PyArg_ParseTuple ( args , " s " , & cursor ) )
2013-02-08 23:41:21 +04:00
return NULL ;
Py_BEGIN_ALLOW_THREADS
r = sd_journal_seek_cursor ( self - > j , cursor ) ;
Py_END_ALLOW_THREADS
2013-02-17 20:26:10 +04:00
if ( set_error ( r , NULL , " Invalid cursor " ) )
2013-02-08 23:41:21 +04:00
return NULL ;
Py_RETURN_NONE ;
}
2013-03-01 04:32:31 +04:00
static PyObject * Reader_iter ( PyObject * self )
2013-02-08 23:41:21 +04:00
{
Py_INCREF ( self ) ;
return self ;
}
2013-03-01 04:32:31 +04:00
static PyObject * Reader_iternext ( PyObject * self )
2013-02-08 23:41:21 +04:00
{
2013-02-16 17:40:44 +04:00
PyObject * dict ;
2013-02-08 23:41:21 +04:00
Py_ssize_t dict_size ;
2013-02-20 06:58:54 +04:00
dict = PyObject_CallMethod ( self , ( char * ) " get_next " , ( char * ) " " ) ;
2013-02-17 18:27:59 +04:00
if ( PyErr_Occurred ( ) )
return NULL ;
2013-02-08 23:41:21 +04:00
dict_size = PyDict_Size ( dict ) ;
if ( ( int64_t ) dict_size > 0LL ) {
return dict ;
2013-02-22 16:33:06 +04:00
} else {
2013-02-08 23:41:21 +04:00
Py_DECREF ( dict ) ;
PyErr_SetNone ( PyExc_StopIteration ) ;
return NULL ;
}
}
2013-03-01 04:32:31 +04:00
PyDoc_STRVAR ( Reader_query_unique__doc__ ,
2013-02-20 07:22:03 +04:00
" query_unique(field) -> a set of values \n \n "
2013-02-20 08:03:32 +04:00
" Return a set of unique values appearing in journal for the \n "
" given `field`. Note this does not respect any journal matches. " ) ;
2013-03-01 04:32:31 +04:00
static PyObject * Reader_query_unique ( Reader * self , PyObject * args )
2013-02-08 23:41:21 +04:00
{
char * query ;
2013-02-20 07:11:02 +04:00
int r ;
const void * uniq ;
size_t uniq_len ;
PyObject * value_set , * key , * value ;
2013-02-20 07:22:03 +04:00
if ( ! PyArg_ParseTuple ( args , " s " , & query ) )
2013-02-08 23:41:21 +04:00
return NULL ;
Py_BEGIN_ALLOW_THREADS
r = sd_journal_query_unique ( self - > j , query ) ;
Py_END_ALLOW_THREADS
2013-02-17 20:26:10 +04:00
if ( set_error ( r , NULL , " Invalid field name " ) )
2013-02-08 23:41:21 +04:00
return NULL ;
value_set = PySet_New ( 0 ) ;
2013-02-17 06:54:09 +04:00
key = unicode_FromString ( query ) ;
2013-02-08 23:41:21 +04:00
SD_JOURNAL_FOREACH_UNIQUE ( self - > j , uniq , uniq_len ) {
2013-02-20 07:11:02 +04:00
const char * delim_ptr ;
2013-02-08 23:41:21 +04:00
delim_ptr = memchr ( uniq , ' = ' , uniq_len ) ;
2013-02-22 16:33:06 +04:00
value = PyBytes_FromStringAndSize (
delim_ptr + 1 ,
( const char * ) uniq + uniq_len - ( delim_ptr + 1 ) ) ;
2013-02-08 23:41:21 +04:00
PySet_Add ( value_set , value ) ;
Py_DECREF ( value ) ;
}
Py_DECREF ( key ) ;
return value_set ;
}
2013-02-20 08:03:32 +04:00
PyDoc_STRVAR ( data_threshold__doc__ ,
2013-02-22 16:33:06 +04:00
" Threshold for field size truncation in bytes. \n \n "
2013-02-20 08:03:32 +04:00
" Fields longer than this will be truncated to the threshold size. \n "
" Defaults to 64Kb. " ) ;
2013-03-01 04:32:31 +04:00
static PyObject * Reader_get_data_threshold ( Reader * self , void * closure )
2013-02-08 23:41:21 +04:00
{
size_t cvalue ;
int r ;
r = sd_journal_get_data_threshold ( self - > j , & cvalue ) ;
2013-02-17 20:26:10 +04:00
if ( set_error ( r , NULL , NULL ) )
2013-02-08 23:41:21 +04:00
return NULL ;
2013-02-17 06:54:09 +04:00
return long_FromSize_t ( cvalue ) ;
2013-02-08 23:41:21 +04:00
}
2013-03-01 04:32:31 +04:00
static int Reader_set_data_threshold ( Reader * self , PyObject * value , void * closure )
2013-02-08 23:41:21 +04:00
{
2013-02-20 07:11:02 +04:00
int r ;
2013-02-08 23:41:21 +04:00
if ( value = = NULL ) {
2013-02-22 16:33:06 +04:00
PyErr_SetString ( PyExc_AttributeError , " Cannot delete data threshold " ) ;
2013-02-08 23:41:21 +04:00
return - 1 ;
}
2013-02-17 06:54:09 +04:00
if ( ! long_Check ( value ) ) {
2013-02-20 07:11:02 +04:00
PyErr_SetString ( PyExc_TypeError , " Data threshold must be an int " ) ;
2013-02-08 23:41:21 +04:00
return - 1 ;
}
2013-02-17 06:54:09 +04:00
r = sd_journal_set_data_threshold ( self - > j , ( size_t ) long_AsLong ( value ) ) ;
2013-02-17 20:26:10 +04:00
return set_error ( r , NULL , NULL ) ;
2013-02-08 23:41:21 +04:00
}
2013-03-01 04:32:31 +04:00
static PyGetSetDef Reader_getseters [ ] = {
2013-02-20 06:58:54 +04:00
{ ( char * ) " data_threshold " ,
2013-03-01 04:32:31 +04:00
( getter ) Reader_get_data_threshold ,
( setter ) Reader_set_data_threshold ,
2013-02-20 08:03:32 +04:00
( char * ) data_threshold__doc__ ,
2013-02-20 06:58:54 +04:00
NULL } ,
2013-02-08 23:41:21 +04:00
{ NULL }
} ;
2013-03-01 04:32:31 +04:00
static PyMethodDef Reader_methods [ ] = {
2013-03-07 09:35:28 +04:00
{ " fileno " , ( PyCFunction ) Reader_fileno , METH_NOARGS , Reader_fileno__doc__ } ,
{ " reliable_fd " , ( PyCFunction ) Reader_reliable_fd , METH_NOARGS , Reader_reliable_fd__doc__ } ,
{ " close " , ( PyCFunction ) Reader_close , METH_NOARGS , Reader_close__doc__ } ,
2013-03-18 09:12:25 +04:00
{ " __enter__ " , ( PyCFunction ) Reader___enter__ , METH_NOARGS , Reader___enter____doc__ } ,
{ " __exit__ " , ( PyCFunction ) Reader___exit__ , METH_VARARGS , Reader___exit____doc__ } ,
{ " close " , ( PyCFunction ) Reader_close , METH_NOARGS , Reader_close__doc__ } ,
2013-03-01 04:32:31 +04:00
{ " get_next " , ( PyCFunction ) Reader_get_next , METH_VARARGS , Reader_get_next__doc__ } ,
{ " get_previous " , ( PyCFunction ) Reader_get_previous , METH_VARARGS , Reader_get_previous__doc__ } ,
{ " add_match " , ( PyCFunction ) Reader_add_match , METH_VARARGS | METH_KEYWORDS , Reader_add_match__doc__ } ,
{ " add_disjunction " , ( PyCFunction ) Reader_add_disjunction , METH_NOARGS , Reader_add_disjunction__doc__ } ,
{ " flush_matches " , ( PyCFunction ) Reader_flush_matches , METH_NOARGS , Reader_flush_matches__doc__ } ,
2013-03-07 09:26:24 +04:00
{ " seek_head " , ( PyCFunction ) Reader_seek_head , METH_NOARGS , Reader_seek_head__doc__ } ,
{ " seek_tail " , ( PyCFunction ) Reader_seek_tail , METH_NOARGS , Reader_seek_tail__doc__ } ,
2013-03-01 04:32:31 +04:00
{ " seek_realtime " , ( PyCFunction ) Reader_seek_realtime , METH_VARARGS , Reader_seek_realtime__doc__ } ,
{ " seek_monotonic " , ( PyCFunction ) Reader_seek_monotonic , METH_VARARGS , Reader_seek_monotonic__doc__ } ,
{ " wait " , ( PyCFunction ) Reader_wait , METH_VARARGS , Reader_wait__doc__ } ,
{ " seek_cursor " , ( PyCFunction ) Reader_seek_cursor , METH_VARARGS , Reader_seek_cursor__doc__ } ,
{ " query_unique " , ( PyCFunction ) Reader_query_unique , METH_VARARGS , Reader_query_unique__doc__ } ,
2013-02-08 23:41:21 +04:00
{ NULL } /* Sentinel */
} ;
2013-03-01 04:32:31 +04:00
static PyTypeObject ReaderType = {
2013-02-08 23:41:21 +04:00
PyVarObject_HEAD_INIT ( NULL , 0 )
2013-03-01 04:32:31 +04:00
" _reader._Reader " , /*tp_name*/
sizeof ( Reader ) , /*tp_basicsize*/
2013-02-22 16:33:06 +04:00
0 , /*tp_itemsize*/
2013-03-01 04:32:31 +04:00
( destructor ) Reader_dealloc , /*tp_dealloc*/
2013-02-22 16:33:06 +04:00
0 , /*tp_print*/
0 , /*tp_getattr*/
0 , /*tp_setattr*/
0 , /*tp_compare*/
0 , /*tp_repr*/
0 , /*tp_as_number*/
0 , /*tp_as_sequence*/
0 , /*tp_as_mapping*/
0 , /*tp_hash */
0 , /*tp_call*/
0 , /*tp_str*/
0 , /*tp_getattro*/
0 , /*tp_setattro*/
0 , /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE , /*tp_flags*/
2013-03-01 04:32:31 +04:00
Reader__doc__ , /* tp_doc */
2013-02-22 16:33:06 +04:00
0 , /* tp_traverse */
0 , /* tp_clear */
0 , /* tp_richcompare */
0 , /* tp_weaklistoffset */
2013-03-01 04:32:31 +04:00
Reader_iter , /* tp_iter */
Reader_iternext , /* tp_iternext */
Reader_methods , /* tp_methods */
2013-02-22 16:33:06 +04:00
0 , /* tp_members */
2013-03-01 04:32:31 +04:00
Reader_getseters , /* tp_getset */
2013-02-22 16:33:06 +04:00
0 , /* tp_base */
0 , /* tp_dict */
0 , /* tp_descr_get */
0 , /* tp_descr_set */
0 , /* tp_dictoffset */
2013-03-01 04:32:31 +04:00
( initproc ) Reader_init , /* tp_init */
2013-02-22 16:33:06 +04:00
0 , /* tp_alloc */
PyType_GenericNew , /* tp_new */
2013-02-08 23:41:21 +04:00
} ;
2013-02-20 08:03:32 +04:00
# define SUMMARY \
" Module that reads the systemd journal similar to journalctl. "
2013-02-08 23:41:21 +04:00
# if PY_MAJOR_VERSION >= 3
static PyModuleDef _reader_module = {
PyModuleDef_HEAD_INIT ,
" _reader " ,
2013-02-20 08:03:32 +04:00
SUMMARY ,
2013-02-08 23:41:21 +04:00
- 1 ,
NULL , NULL , NULL , NULL , NULL
} ;
# endif
2013-02-23 04:11:36 +04:00
# if PY_MAJOR_VERSION >= 3
static bool initialized = false ;
# endif
2013-02-20 06:58:54 +04:00
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmissing-prototypes"
2013-02-08 23:41:21 +04:00
PyMODINIT_FUNC
# if PY_MAJOR_VERSION >= 3
PyInit__reader ( void )
# else
2013-02-20 06:58:54 +04:00
init_reader ( void )
2013-02-08 23:41:21 +04:00
# endif
{
PyObject * m ;
PyDateTime_IMPORT ;
2013-03-01 04:32:31 +04:00
if ( PyType_Ready ( & ReaderType ) < 0 )
2013-02-08 23:41:21 +04:00
# if PY_MAJOR_VERSION >= 3
return NULL ;
# else
return ;
# endif
# if PY_MAJOR_VERSION >= 3
m = PyModule_Create ( & _reader_module ) ;
if ( m = = NULL )
return NULL ;
2013-02-23 04:11:36 +04:00
if ( ! initialized ) {
PyStructSequence_InitType ( & MonotonicType , & Monotonic_desc ) ;
initialized = true ;
}
2013-02-08 23:41:21 +04:00
# else
2013-02-20 08:03:32 +04:00
m = Py_InitModule3 ( " _reader " , NULL , SUMMARY ) ;
2013-02-08 23:41:21 +04:00
if ( m = = NULL )
return ;
# endif
2013-03-01 04:32:31 +04:00
Py_INCREF ( & ReaderType ) ;
2013-02-23 04:11:36 +04:00
# if PY_MAJOR_VERSION >= 3
Py_INCREF ( & MonotonicType ) ;
# endif
2013-03-01 04:32:31 +04:00
if ( PyModule_AddObject ( m , " _Reader " , ( PyObject * ) & ReaderType ) | |
2013-02-23 04:11:36 +04:00
# if PY_MAJOR_VERSION >= 3
PyModule_AddObject ( m , " Monotonic " , ( PyObject * ) & MonotonicType ) | |
# endif
2013-02-22 16:33:06 +04:00
PyModule_AddIntConstant ( m , " NOP " , SD_JOURNAL_NOP ) | |
PyModule_AddIntConstant ( m , " APPEND " , SD_JOURNAL_APPEND ) | |
PyModule_AddIntConstant ( m , " INVALIDATE " , SD_JOURNAL_INVALIDATE ) | |
PyModule_AddIntConstant ( m , " LOCAL_ONLY " , SD_JOURNAL_LOCAL_ONLY ) | |
PyModule_AddIntConstant ( m , " RUNTIME_ONLY " , SD_JOURNAL_RUNTIME_ONLY ) | |
PyModule_AddIntConstant ( m , " SYSTEM_ONLY " , SD_JOURNAL_SYSTEM_ONLY ) ) {
# if PY_MAJOR_VERSION >= 3
Py_DECREF ( m ) ;
return NULL ;
# endif
}
2013-02-08 23:41:21 +04:00
# if PY_MAJOR_VERSION >= 3
return m ;
# endif
}
2013-02-20 06:58:54 +04:00
# pragma GCC diagnostic pop