From 02b9432e736f3951078f3ad232baa445ca5d30b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 20 Sep 2016 09:03:07 -0400 Subject: reader: add SD_JOURNAL_OS_ROOT and rework flag passing Let's pass any flags through to the journal functions without checking validity. Those functions do their own checking, so there's no need to second-guess. The semantics for _Reader(flags=0) are a bit changed: before, this would be transformed into sd_journal_open(SD_J_LOCAL_ONLY). Now, this results in sd_journal_open(0). Previous behaviour should be achieved by not specifying the flags at all. This change is necessary, because previously it was not possible to pass flags=0 to sd_journal_open(0), i.e. it was not possible to "merge" journals through the Python interface. Similarly, Reader(flags=0) now means to open all journals, and Reader(flags=None) is the same as Reader(flags=LOCAL_ONLY). --- docs/journal.rst | 1 + systemd/_reader.c | 29 ++++++++++++++++------------- systemd/journal.py | 10 +++++++++- systemd/test/test_journal.py | 35 +++++++++++++++++++++++++---------- 4 files changed, 51 insertions(+), 24 deletions(-) diff --git a/docs/journal.rst b/docs/journal.rst index 8e4b5b6..49c07b1 100644 --- a/docs/journal.rst +++ b/docs/journal.rst @@ -89,6 +89,7 @@ Journal access types .. autoattribute:: systemd.journal.RUNTIME_ONLY .. autoattribute:: systemd.journal.SYSTEM .. autoattribute:: systemd.journal.CURRENT_USER +.. autoattribute:: systemd.journal.OS_ROOT Journal event types ~~~~~~~~~~~~~~~~~~~ diff --git a/systemd/_reader.c b/systemd/_reader.c index 020bfbd..0f6fd3f 100644 --- a/systemd/_reader.c +++ b/systemd/_reader.c @@ -34,8 +34,8 @@ #if defined(LIBSYSTEMD_VERSION) || LIBSYSTEMD_JOURNAL_VERSION > 204 # define HAVE_JOURNAL_OPEN_FILES #else -# define SD_JOURNAL_SYSTEM 4 -# define SD_JOURNAL_CURRENT_USER 8 +# define SD_JOURNAL_SYSTEM (1 << 2) +# define SD_JOURNAL_CURRENT_USER (1 << 3) #endif #if LIBSYSTEMD_VERSION >= 229 @@ -46,6 +46,8 @@ #if LIBSYSTEMD_VERSION >= 230 # define HAVE_JOURNAL_OPEN_DIRECTORY_FD +#else +# define SD_JOURNAL_OS_ROOT (1 << 4) #endif typedef struct { @@ -225,7 +227,9 @@ PyDoc_STRVAR(Reader__doc__, "Argument `flags` sets open flags of the journal, which can be one of, or an ORed\n" "combination of constants: LOCAL_ONLY (default) opens journal on local machine only;\n" "RUNTIME_ONLY opens only volatile journal files; and SYSTEM opens journal files of\n" - "system services and the kernel, and CURRENT_USER opens file of the current user.\n" + "system services and the kernel, CURRENT_USER opens files of the current user; and\n" + "OS_ROOT is used to open the journal from directories relative to the specified\n" + "directory path or file descriptor.\n" "\n" "Instead of opening the system journal, argument `path` may specify a directory\n" "which contains the journal. It maybe be either a file system path (a string), or\n" @@ -235,8 +239,9 @@ PyDoc_STRVAR(Reader__doc__, "_Reader implements the context manager protocol: the journal will be closed when\n" "exiting the block."); static int Reader_init(Reader *self, PyObject *args, PyObject *keywds) { - int flags = 0, r; + unsigned flags = SD_JOURNAL_LOCAL_ONLY; PyObject *_path = NULL, *_files = NULL; + int r; static const char* const kwlist[] = {"flags", "path", "files", NULL}; if (!PyArg_ParseTupleAndKeywords(args, keywds, "|iO&O&:__init__", (char**) kwlist, @@ -245,9 +250,9 @@ static int Reader_init(Reader *self, PyObject *args, PyObject *keywds) { null_converter, &_files)) return -1; - if (!!flags + !!_path + !!_files > 1) { + if (!!_path + !!_files > 1) { PyErr_SetString(PyExc_ValueError, - "cannot use more than one of flags, path, and files"); + "path and files cannot be specified simultaneously"); return -1; } @@ -260,7 +265,7 @@ static int Reader_init(Reader *self, PyObject *args, PyObject *keywds) { #ifdef HAVE_JOURNAL_OPEN_DIRECTORY_FD Py_BEGIN_ALLOW_THREADS - r = sd_journal_open_directory_fd(&self->j, (int) fd, 0); + r = sd_journal_open_directory_fd(&self->j, (int) fd, flags); Py_END_ALLOW_THREADS #else r = -ENOSYS; @@ -274,7 +279,7 @@ static int Reader_init(Reader *self, PyObject *args, PyObject *keywds) { return -1; Py_BEGIN_ALLOW_THREADS - r = sd_journal_open_directory(&self->j, path, 0); + r = sd_journal_open_directory(&self->j, path, flags); Py_END_ALLOW_THREADS } } else if (_files) { @@ -289,7 +294,7 @@ static int Reader_init(Reader *self, PyObject *args, PyObject *keywds) { return -1; Py_BEGIN_ALLOW_THREADS - r = sd_journal_open_files(&self->j, (const char**) files, 0); + r = sd_journal_open_files(&self->j, (const char**) files, flags); Py_END_ALLOW_THREADS } else { _cleanup_free_ int *fds = NULL; @@ -299,16 +304,13 @@ static int Reader_init(Reader *self, PyObject *args, PyObject *keywds) { return -1; Py_BEGIN_ALLOW_THREADS - r = sd_journal_open_files_fd(&self->j, fds, n_fds, 0); + r = sd_journal_open_files_fd(&self->j, fds, n_fds, flags); Py_END_ALLOW_THREADS } #else r = -ENOSYS; #endif } else { - if (!flags) - flags = SD_JOURNAL_LOCAL_ONLY; - Py_BEGIN_ALLOW_THREADS r = sd_journal_open(&self->j, flags); Py_END_ALLOW_THREADS @@ -1332,6 +1334,7 @@ init_reader(void) PyModule_AddIntConstant(m, "SYSTEM", SD_JOURNAL_SYSTEM) || PyModule_AddIntConstant(m, "SYSTEM_ONLY", SD_JOURNAL_SYSTEM_ONLY) || PyModule_AddIntConstant(m, "CURRENT_USER", SD_JOURNAL_CURRENT_USER) || + PyModule_AddIntConstant(m, "OS_ROOT", SD_JOURNAL_OS_ROOT) || PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) { #if PY_MAJOR_VERSION >= 3 Py_DECREF(m); diff --git a/systemd/journal.py b/systemd/journal.py index 4440dec..b91337d 100644 --- a/systemd/journal.py +++ b/systemd/journal.py @@ -34,6 +34,7 @@ from ._journal import __version__, sendv, stream_fd from ._reader import (_Reader, NOP, APPEND, INVALIDATE, LOCAL_ONLY, RUNTIME_ONLY, SYSTEM, SYSTEM_ONLY, CURRENT_USER, + OS_ROOT, _get_catalog) from . import id128 as _id128 @@ -131,7 +132,7 @@ class Reader(_Reader): journal. """ - def __init__(self, flags=0, path=None, files=None, converters=None): + def __init__(self, flags=None, path=None, files=None, converters=None): """Create a new Reader. Argument `flags` defines the open flags of the journal, which can be one @@ -155,6 +156,13 @@ class Reader(_Reader): Reader implements the context manager protocol: the journal will be closed when exiting the block. """ + if flags is None: + if path is None and files is None: + # This mimics journalctl behaviour of default to local journal only + flags = LOCAL_ONLY + else: + flags = 0 + super(Reader, self).__init__(flags, path, files) if _sys.version_info >= (3,3): self.converters = _ChainMap() diff --git a/systemd/test/test_journal.py b/systemd/test/test_journal.py index 4b23a70..10a57e9 100644 --- a/systemd/test/test_journal.py +++ b/systemd/test/test_journal.py @@ -43,15 +43,25 @@ def test_reader_init_flags(): j2 = journal.Reader(journal.LOCAL_ONLY) j3 = journal.Reader(journal.RUNTIME_ONLY) j4 = journal.Reader(journal.SYSTEM_ONLY) - j5 = journal.Reader(journal.LOCAL_ONLY| - journal.RUNTIME_ONLY| - journal.SYSTEM_ONLY) + j5 = journal.Reader(journal.LOCAL_ONLY | journal.RUNTIME_ONLY | journal.SYSTEM_ONLY) j6 = journal.Reader(0) -def test_reader_init_path(tmpdir): - j = journal.Reader(path=tmpdir.strpath) +def test_reader_os_root(tmpdir): with pytest.raises(ValueError): - journal.Reader(journal.LOCAL_ONLY, path=tmpdir.strpath) + journal.Reader(journal.OS_ROOT) + j1 = journal.Reader(path=tmpdir.strpath, + flags=journal.OS_ROOT) + j2 = journal.Reader(path=tmpdir.strpath, + flags=journal.OS_ROOT | journal.CURRENT_USER) + j3 = journal.Reader(path=tmpdir.strpath, + flags=journal.OS_ROOT | journal.SYSTEM_ONLY) + +def test_reader_init_path(tmpdir): + j1 = journal.Reader(path=tmpdir.strpath) + journal.Reader(0, path=tmpdir.strpath) + + j2 = journal.Reader(path=tmpdir.strpath) + journal.Reader(path=tmpdir.strpath) def test_reader_init_path_invalid_fd(): with pytest.raises(OSError): @@ -63,10 +73,15 @@ def test_reader_init_path_nondirectory_fd(): def test_reader_init_path_fd(tmpdir): fd = os.open(tmpdir.strpath, os.O_RDONLY) - j = journal.Reader(path=fd) - with pytest.raises(ValueError): - journal.Reader(journal.LOCAL_ONLY, path=fd) - assert list(j) == [] + + j1 = journal.Reader(path=fd) + assert list(j1) == [] + + j2 = journal.Reader(journal.SYSTEM, path=fd) + assert list(j2) == [] + + j3 = journal.Reader(journal.CURRENT_USER, path=fd) + assert list(j3) == [] def test_reader_as_cm(tmpdir): j = journal.Reader(path=tmpdir.strpath) -- cgit v1.2.1