X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fpython-systemd%2F_reader.c;h=a678f69318055c94b14179aa3f13a7771d5b1a21;hp=14f8a4034762b8b981cab1b1cb425a00e40fc48c;hb=fd587c876d480863d56bbbdc5e9fcf7e735d98f3;hpb=6a58bf4135faa98f1600672179a2bf364d455f7e diff --git a/src/python-systemd/_reader.c b/src/python-systemd/_reader.c index 14f8a4034..a678f6931 100644 --- a/src/python-systemd/_reader.c +++ b/src/python-systemd/_reader.c @@ -30,6 +30,8 @@ #include "pyutil.h" #include "macro.h" #include "util.h" +#include "strv.h" +#include "build.h" typedef struct { PyObject_HEAD @@ -37,20 +39,6 @@ typedef struct { } Reader; static PyTypeObject ReaderType; -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); - } - return -1; -} - PyDoc_STRVAR(module__doc__, "Class to reads the systemd journal similar to journalctl."); @@ -76,6 +64,57 @@ static PyStructSequence_Desc Monotonic_desc = { }; #endif +static int strv_converter(PyObject* obj, void *_result) { + char ***result = _result; + Py_ssize_t i, len; + + assert(result); + + if (!obj) + goto cleanup; + + if (!PySequence_Check(obj)) + return 0; + + len = PySequence_Length(obj); + *result = new0(char*, len + 1); + + for (i = 0; i < len; i++) { + PyObject *item; +#if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1 + int r; + PyObject *bytes; +#endif + char *s, *s2; + + item = PySequence_ITEM(obj, i); +#if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1 + r = PyUnicode_FSConverter(item, &bytes); + if (r == 0) + goto cleanup; + + s = PyBytes_AsString(bytes); +#else + s = PyString_AsString(item); +#endif + if (!s) + goto cleanup; + + s2 = strdup(s); + if (!s2) + log_oom(); + + (*result)[i] = s2; + } + + return 1; + +cleanup: + strv_free(*result); + *result = NULL; + + return 0; +} static void Reader_dealloc(Reader* self) { @@ -84,40 +123,45 @@ static void Reader_dealloc(Reader* self) } PyDoc_STRVAR(Reader__doc__, - "_Reader([flags | path]) -> ...\n\n" + "_Reader([flags | path | files]) -> ...\n\n" "_Reader allows filtering and retrieval of Journal entries.\n" "Note: this is a low-level interface, and probably not what you\n" "want, use systemd.journal.Reader instead.\n\n" "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" - "journal files of system services and the kernel.\n\n" - "Argument `path` is the directory of journal files. Note that\n" - "`flags` and `path` are exclusive.\n\n" + "volatile journal files; and SYSTEM opens journal files of\n" + "system services and the kernel, and CURRENT_USER opens files\n" + "of the current user.\n\n" + "Argument `path` is the directory of journal files.\n" + "Argument `files` is a list of files. Note that\n" + "`flags`, `path`, and `files` are exclusive.\n\n" "_Reader implements the context manager protocol: the journal\n" "will be closed when exiting the block."); static int Reader_init(Reader *self, PyObject *args, PyObject *keywds) { int flags = 0, r; char *path = NULL; + char **files = NULL; + + static const char* const kwlist[] = {"flags", "path", "files", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "|izO&", (char**) kwlist, + &flags, &path, strv_converter, &files)) + return -1; - static const char* const kwlist[] = {"flags", "path", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "|iz", (char**) kwlist, - &flags, &path)) + if (!!flags + !!path + !!files > 1) { + PyErr_SetString(PyExc_ValueError, "cannot use more than one of flags, path, and files"); return -1; + } if (!flags) flags = SD_JOURNAL_LOCAL_ONLY; - else - if (path) { - PyErr_SetString(PyExc_ValueError, "cannot use both flags and path"); - return -1; - } Py_BEGIN_ALLOW_THREADS if (path) r = sd_journal_open_directory(&self->j, path, 0); + else if (files) + r = sd_journal_open_files(&self->j, (const char**) files, 0); else r = sd_journal_open(&self->j, flags); Py_END_ALLOW_THREADS @@ -176,7 +220,7 @@ PyDoc_STRVAR(Reader_get_timeout__doc__, "Returns a timeout value for usage in poll(), the time since the\n" "epoch of clock_gettime(2) in microseconds, or None if no timeout\n" "is necessary.\n\n" - "The return value must be converted to a relative timeout in \n" + "The return value must be converted to a relative timeout in\n" "milliseconds if it is to be used as an argument for poll().\n" "See man:sd_journal_get_timeout(3) for further discussion."); static PyObject* Reader_get_timeout(Reader *self, PyObject *args) @@ -212,19 +256,7 @@ static PyObject* Reader_get_timeout_ms(Reader *self, PyObject *args) if (r < 0) return NULL; - if (t == (uint64_t) -1) - return PyLong_FromLong(-1); - else { - struct timespec ts; - uint64_t n; - int msec; - - clock_gettime(CLOCK_MONOTONIC, &ts); - n = (uint64_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000; - msec = t > n ? (int) ((t - n + 999) / 1000) : 0; - - return PyLong_FromLong(msec); - } + return absolute_timeout(t); } @@ -286,11 +318,7 @@ PyDoc_STRVAR(Reader___exit____doc__, "Closes the journal.\n"); static PyObject* Reader___exit__(Reader *self, PyObject *args) { - assert(self); - - sd_journal_close(self->j); - self->j = NULL; - Py_RETURN_NONE; + return Reader_close(self, args); } @@ -429,7 +457,7 @@ static PyObject* Reader_get_all(Reader *self, PyObject *args) return NULL; SD_JOURNAL_FOREACH_DATA(self->j, msg, msg_len) { - PyObject _cleanup_Py_DECREF_ *key = NULL, *value = NULL; + _cleanup_Py_DECREF_ PyObject *key = NULL, *value = NULL; r = extract(msg, msg_len, &key, &value); if (r < 0) @@ -443,7 +471,7 @@ static PyObject* Reader_get_all(Reader *self, PyObject *args) if (r < 0) goto error; } else { - PyObject _cleanup_Py_DECREF_ *tmp_list = PyList_New(0); + _cleanup_Py_DECREF_ PyObject *tmp_list = PyList_New(0); if (!tmp_list) goto error; @@ -567,7 +595,10 @@ static PyObject* Reader_add_match(Reader *self, PyObject *args, PyObject *keywds PyDoc_STRVAR(Reader_add_disjunction__doc__, "add_disjunction() -> None\n\n" - "Inserts a logical OR between matches added before and afterwards."); + "Inserts a logical OR between matches added since previous\n" + "add_disjunction() or add_conjunction() and the next\n" + "add_disjunction() or add_conjunction().\n\n" + "See man:sd_journal_add_disjunction(3) for explanation."); static PyObject* Reader_add_disjunction(Reader *self, PyObject *args) { int r; @@ -579,6 +610,23 @@ static PyObject* Reader_add_disjunction(Reader *self, PyObject *args) } +PyDoc_STRVAR(Reader_add_conjunction__doc__, + "add_conjunction() -> None\n\n" + "Inserts a logical AND between matches added since previous\n" + "add_disjunction() or add_conjunction() and the next\n" + "add_disjunction() or add_conjunction().\n\n" + "See man:sd_journal_add_disjunction(3) for explanation."); +static PyObject* Reader_add_conjunction(Reader *self, PyObject *args) +{ + int r; + r = sd_journal_add_conjunction(self->j); + set_error(r, NULL, NULL); + if (r < 0) + return NULL; + Py_RETURN_NONE; +} + + PyDoc_STRVAR(Reader_flush_matches__doc__, "flush_matches() -> None\n\n" "Clear all current match filters."); @@ -760,7 +808,7 @@ PyDoc_STRVAR(Reader_get_cursor__doc__, "Wraps sd_journal_get_cursor(). See man:sd_journal_get_cursor(3)."); static PyObject* Reader_get_cursor(Reader *self, PyObject *args) { - char _cleanup_free_ *cursor = NULL; + _cleanup_free_ char *cursor = NULL; int r; assert(self); @@ -846,7 +894,7 @@ PyDoc_STRVAR(Reader_get_catalog__doc__, static PyObject* Reader_get_catalog(Reader *self, PyObject *args) { int r; - char _cleanup_free_ *msg = NULL; + _cleanup_free_ char *msg = NULL; assert(self); assert(!args); @@ -860,9 +908,9 @@ static PyObject* Reader_get_catalog(Reader *self, PyObject *args) r = sd_journal_get_data(self->j, "MESSAGE_ID", &mid, &mid_len); if (r == 0) { - const int l = sizeof("MESSAGE_ID"); + const size_t l = sizeof("MESSAGE_ID"); assert(mid_len > l); - PyErr_Format(PyExc_KeyError, "%.*s", (int) mid_len - l, + PyErr_Format(PyExc_KeyError, "%.*s", (int) (mid_len - l), (const char*) mid + l); } else if (r == -ENOENT) PyErr_SetString(PyExc_IndexError, "no MESSAGE_ID field"); @@ -885,7 +933,7 @@ static PyObject* get_catalog(PyObject *self, PyObject *args) int r; char *id_ = NULL; sd_id128_t id; - char _cleanup_free_ *msg = NULL; + _cleanup_free_ char *msg = NULL; assert(!self); assert(args); @@ -980,6 +1028,7 @@ static PyMethodDef Reader_methods[] = { {"_get_monotonic", (PyCFunction) Reader_get_monotonic, METH_NOARGS, Reader_get_monotonic__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__}, + {"add_conjunction", (PyCFunction) Reader_add_conjunction, METH_NOARGS, Reader_add_conjunction__doc__}, {"flush_matches", (PyCFunction) Reader_flush_matches, METH_NOARGS, Reader_flush_matches__doc__}, {"seek_head", (PyCFunction) Reader_seek_head, METH_NOARGS, Reader_seek_head__doc__}, {"seek_tail", (PyCFunction) Reader_seek_tail, METH_NOARGS, Reader_seek_tail__doc__}, @@ -997,48 +1046,20 @@ static PyMethodDef Reader_methods[] = { static PyTypeObject ReaderType = { PyVarObject_HEAD_INIT(NULL, 0) - "_reader._Reader", /*tp_name*/ - sizeof(Reader), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)Reader_dealloc, /*tp_dealloc*/ - 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*/ - Reader__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Reader_methods, /* tp_methods */ - 0, /* tp_members */ - Reader_getsetters, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc) Reader_init, /* tp_init */ - 0, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ + .tp_name = "_reader._Reader", + .tp_basicsize = sizeof(Reader), + .tp_dealloc = (destructor) Reader_dealloc, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_doc = Reader__doc__, + .tp_methods = Reader_methods, + .tp_getset = Reader_getsetters, + .tp_init = (initproc) Reader_init, + .tp_new = PyType_GenericNew, }; static PyMethodDef methods[] = { { "_get_catalog", get_catalog, METH_VARARGS, get_catalog__doc__}, - { NULL, NULL, 0, NULL } /* Sentinel */ + {} /* Sentinel */ }; #if PY_MAJOR_VERSION >= 3 @@ -1048,7 +1069,6 @@ static PyModuleDef module = { module__doc__, -1, methods, - NULL, NULL, NULL, NULL }; #endif @@ -1105,7 +1125,10 @@ init_reader(void) 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)) { + 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_AddStringConstant(m, "__version__", PACKAGE_VERSION)) { #if PY_MAJOR_VERSION >= 3 Py_DECREF(m); return NULL;