X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fpython-systemd%2F_reader.c;h=42029abd4647234f12fd631f55a7fd05e770c141;hp=7645cb9a848b7dcfc6ab80eb2c2a64cbc531de18;hb=0eff0f3bce1d0826765f6e84ff046b10fe5a1a12;hpb=86e3d32a1d52cd2ccba184e8375da8828914d3ff diff --git a/src/python-systemd/_reader.c b/src/python-systemd/_reader.c index 7645cb9a8..42029abd4 100644 --- a/src/python-systemd/_reader.c +++ b/src/python-systemd/_reader.c @@ -50,8 +50,8 @@ typedef struct { PyObject_HEAD sd_journal *j; -} Journal; -static PyTypeObject JournalType; +} Reader; +static PyTypeObject ReaderType; static int set_error(int r, const char* path, const char* invalid_message) { if (r >= 0) @@ -64,7 +64,7 @@ static int set_error(int r, const char* path, const char* invalid_message) { errno = -r; PyErr_SetFromErrnoWithFilename(PyExc_OSError, path); } - return 1; + return -1; } #if PY_MAJOR_VERSION >= 3 @@ -87,32 +87,41 @@ static PyStructSequence_Desc Monotonic_desc = { }; #endif -static void Journal_dealloc(Journal* self) +static void Reader_dealloc(Reader* self) { sd_journal_close(self->j); Py_TYPE(self)->tp_free((PyObject*)self); } -PyDoc_STRVAR(Journal__doc__, - "Journal([flags][,path]) -> ...\n\n" - "Journal allows filtering and retrieval of Journal entries.\n" +PyDoc_STRVAR(Reader__doc__, + "Reader([flags | path]) -> ...\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" + "journal files of system services and the kernel.\n\n" "Argument `path` is the directory of journal files. Note that\n" - "currently flags are ignored when `path` is present as they are\n" - "not relevant."); -static int Journal_init(Journal *self, PyObject *args, PyObject *keywds) + "`flags` and `path` are exclusive.\n"); +static int Reader_init(Reader *self, PyObject *args, PyObject *keywds) { - int flags = SD_JOURNAL_LOCAL_ONLY, r; + int flags = 0, r; char *path = NULL; static const char* const kwlist[] = {"flags", "path", NULL}; if (!PyArg_ParseTupleAndKeywords(args, keywds, "|iz", (char**) kwlist, &flags, &path)) - return 1; + 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) @@ -124,11 +133,52 @@ static int Journal_init(Journal *self, PyObject *args, PyObject *keywds) return set_error(r, path, "Invalid flags or path"); } -PyDoc_STRVAR(Journal_get_next__doc__, +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__, + "reliable_fd() -> None\n\n" + "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) +{ + sd_journal_close(self->j); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Reader_get_next__doc__, "get_next([skip]) -> dict\n\n" "Return dictionary of the next log entry. Optional skip value will\n" "return the `skip`\\-th log entry."); -static PyObject* Journal_get_next(Journal *self, PyObject *args) +static PyObject* Reader_get_next(Reader *self, PyObject *args) { PyObject *dict; const void *msg; @@ -208,7 +258,7 @@ static PyObject* Journal_get_next(Journal *self, PyObject *args) if (r < 0) goto error; - PyDict_SetItem(dict, key, tmp_list); + r = PyDict_SetItem(dict, key, tmp_list); if (r < 0) goto error; } @@ -303,11 +353,11 @@ error: return NULL; } -PyDoc_STRVAR(Journal_get_previous__doc__, +PyDoc_STRVAR(Reader_get_previous__doc__, "get_previous([skip]) -> dict\n\n" "Return dictionary of the previous log entry. Optional skip value\n" "will return the -`skip`\\-th log entry. Equivalent to get_next(-skip)."); -static PyObject* Journal_get_previous(Journal *self, PyObject *args) +static PyObject* Reader_get_previous(Reader *self, PyObject *args) { int64_t skip = 1LL; if (!PyArg_ParseTuple(args, "|L", &skip)) @@ -317,13 +367,13 @@ static PyObject* Journal_get_previous(Journal *self, PyObject *args) (char*) "L", -skip); } -PyDoc_STRVAR(Journal_add_match__doc__, +PyDoc_STRVAR(Reader_add_match__doc__, "add_match(match) -> None\n\n" "Add a match to filter journal log entries. All matches of different\n" "fields are combined with logical AND, and matches of the same field\n" "are automatically combined with logical OR.\n" "Match is a string of the form \"FIELD=value\"."); -static PyObject* Journal_add_match(Journal *self, PyObject *args, PyObject *keywds) +static PyObject* Reader_add_match(Reader *self, PyObject *args, PyObject *keywds) { char *match; int match_len, r; @@ -338,10 +388,10 @@ static PyObject* Journal_add_match(Journal *self, PyObject *args, PyObject *keyw Py_RETURN_NONE; } -PyDoc_STRVAR(Journal_add_disjunction__doc__, +PyDoc_STRVAR(Reader_add_disjunction__doc__, "add_disjunction() -> None\n\n" "Inserts a logical OR between matches added before and afterwards."); -static PyObject* Journal_add_disjunction(Journal *self, PyObject *args) +static PyObject* Reader_add_disjunction(Reader *self, PyObject *args) { int r; r = sd_journal_add_disjunction(self->j); @@ -351,78 +401,52 @@ static PyObject* Journal_add_disjunction(Journal *self, PyObject *args) Py_RETURN_NONE; } -PyDoc_STRVAR(Journal_flush_matches__doc__, +PyDoc_STRVAR(Reader_flush_matches__doc__, "flush_matches() -> None\n\n" "Clear all current match filters."); -static PyObject* Journal_flush_matches(Journal *self, PyObject *args) +static PyObject* Reader_flush_matches(Reader *self, PyObject *args) { sd_journal_flush_matches(self->j); Py_RETURN_NONE; } -PyDoc_STRVAR(Journal_seek__doc__, - "seek(offset[, whence]) -> None\n\n" - "Jump `offset` entries in the journal. Argument\n" - "`whence` defines what the offset is relative to:\n" - "os.SEEK_SET (default) from first match in journal;\n" - "os.SEEK_CUR from current position in journal;\n" - "and os.SEEK_END is from last match in journal."); -static PyObject* Journal_seek(Journal *self, PyObject *args, PyObject *keywds) +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) { - int64_t offset; - int whence = SEEK_SET; - PyObject *result = NULL; - - static const char* const kwlist[] = {"offset", "whence", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "L|i", (char**) kwlist, - &offset, &whence)) + int r; + Py_BEGIN_ALLOW_THREADS + r = sd_journal_seek_head(self->j); + Py_END_ALLOW_THREADS + if (set_error(r, NULL, NULL)) return NULL; + Py_RETURN_NONE; +} - switch(whence) { - case SEEK_SET: { - int r; - Py_BEGIN_ALLOW_THREADS - r = sd_journal_seek_head(self->j); - Py_END_ALLOW_THREADS - if (set_error(r, NULL, NULL)) - return NULL; - - if (offset > 0LL) - result = PyObject_CallMethod((PyObject *)self, (char*) "get_next", - (char*) "L", offset); - break; - } - case SEEK_CUR: - result = PyObject_CallMethod((PyObject *)self, (char*) "get_next", - (char*) "L", offset); - break; - case SEEK_END: { - int r; - Py_BEGIN_ALLOW_THREADS - r = sd_journal_seek_tail(self->j); - Py_END_ALLOW_THREADS - if (set_error(r, NULL, NULL)) - return NULL; - - result = PyObject_CallMethod((PyObject *)self, (char*) "get_next", - (char*) "L", offset < 0LL ? offset : -1LL); - break; - } - default: - PyErr_SetString(PyExc_ValueError, "Invalid value for whence"); - } - - Py_XDECREF(result); - if (PyErr_Occurred()) +PyDoc_STRVAR(Reader_seek_tail__doc__, + "seek_tail() -> None\n\n" + "Jump to the beginning of the journal.\n" + "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)) return NULL; Py_RETURN_NONE; } -PyDoc_STRVAR(Journal_seek_realtime__doc__, +PyDoc_STRVAR(Reader_seek_realtime__doc__, "seek_realtime(realtime) -> None\n\n" "Seek to nearest matching journal entry to `realtime`. Argument\n" "`realtime` can must be an integer unix timestamp."); -static PyObject* Journal_seek_realtime(Journal *self, PyObject *args) +static PyObject* Reader_seek_realtime(Reader *self, PyObject *args) { double timedouble; uint64_t timestamp; @@ -445,13 +469,13 @@ static PyObject* Journal_seek_realtime(Journal *self, PyObject *args) Py_RETURN_NONE; } -PyDoc_STRVAR(Journal_seek_monotonic__doc__, +PyDoc_STRVAR(Reader_seek_monotonic__doc__, "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."); -static PyObject* Journal_seek_monotonic(Journal *self, PyObject *args) +static PyObject* Reader_seek_monotonic(Reader *self, PyObject *args) { double timedouble; char *bootid = NULL; @@ -489,7 +513,7 @@ static PyObject* Journal_seek_monotonic(Journal *self, PyObject *args) Py_RETURN_NONE; } -PyDoc_STRVAR(Journal_wait__doc__, +PyDoc_STRVAR(Reader_wait__doc__, "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" @@ -498,7 +522,7 @@ PyDoc_STRVAR(Journal_wait__doc__, "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."); -static PyObject* Journal_wait(Journal *self, PyObject *args, PyObject *keywds) +static PyObject* Reader_wait(Reader *self, PyObject *args, PyObject *keywds) { int r; int64_t timeout = 0LL; @@ -507,18 +531,19 @@ static PyObject* Journal_wait(Journal *self, PyObject *args, PyObject *keywds) return NULL; Py_BEGIN_ALLOW_THREADS - r = sd_journal_wait(self->j, timeout ==0 ? (uint64_t) -1 : timeout * 1E6); + r = sd_journal_wait(self->j, + timeout == 0 ? (uint64_t) -1 : timeout * 1E6); Py_END_ALLOW_THREADS - if (set_error(r, NULL, NULL)) + if (set_error(r, NULL, NULL) < 0) return NULL; return long_FromLong(r); } -PyDoc_STRVAR(Journal_seek_cursor__doc__, +PyDoc_STRVAR(Reader_seek_cursor__doc__, "seek_cursor(cursor) -> None\n\n" "Seek to journal entry by given unique reference `cursor`."); -static PyObject* Journal_seek_cursor(Journal *self, PyObject *args) +static PyObject* Reader_seek_cursor(Reader *self, PyObject *args) { const char *cursor; int r; @@ -534,13 +559,13 @@ static PyObject* Journal_seek_cursor(Journal *self, PyObject *args) Py_RETURN_NONE; } -static PyObject* Journal_iter(PyObject *self) +static PyObject* Reader_iter(PyObject *self) { Py_INCREF(self); return self; } -static PyObject* Journal_iternext(PyObject *self) +static PyObject* Reader_iternext(PyObject *self) { PyObject *dict; Py_ssize_t dict_size; @@ -558,11 +583,11 @@ static PyObject* Journal_iternext(PyObject *self) } } -PyDoc_STRVAR(Journal_query_unique__doc__, +PyDoc_STRVAR(Reader_query_unique__doc__, "query_unique(field) -> a set of values\n\n" "Return a set of unique values appearing in journal for the\n" "given `field`. Note this does not respect any journal matches."); -static PyObject* Journal_query_unique(Journal *self, PyObject *args) +static PyObject* Reader_query_unique(Reader *self, PyObject *args) { char *query; int r; @@ -601,7 +626,7 @@ PyDoc_STRVAR(data_threshold__doc__, "Fields longer than this will be truncated to the threshold size.\n" "Defaults to 64Kb."); -static PyObject* Journal_get_data_threshold(Journal *self, void *closure) +static PyObject* Reader_get_data_threshold(Reader *self, void *closure) { size_t cvalue; int r; @@ -613,7 +638,7 @@ static PyObject* Journal_get_data_threshold(Journal *self, void *closure) return long_FromSize_t(cvalue); } -static int Journal_set_data_threshold(Journal *self, PyObject *value, void *closure) +static int Reader_set_data_threshold(Reader *self, PyObject *value, void *closure) { int r; if (value == NULL) { @@ -628,36 +653,40 @@ static int Journal_set_data_threshold(Journal *self, PyObject *value, void *clos return set_error(r, NULL, NULL); } -static PyGetSetDef Journal_getseters[] = { +static PyGetSetDef Reader_getseters[] = { {(char*) "data_threshold", - (getter) Journal_get_data_threshold, - (setter) Journal_set_data_threshold, + (getter) Reader_get_data_threshold, + (setter) Reader_set_data_threshold, (char*) data_threshold__doc__, NULL}, {NULL} }; -static PyMethodDef Journal_methods[] = { - {"get_next", (PyCFunction) Journal_get_next, METH_VARARGS, Journal_get_next__doc__}, - {"get_previous", (PyCFunction) Journal_get_previous, METH_VARARGS, Journal_get_previous__doc__}, - {"add_match", (PyCFunction) Journal_add_match, METH_VARARGS|METH_KEYWORDS, Journal_add_match__doc__}, - {"add_disjunction", (PyCFunction) Journal_add_disjunction, METH_NOARGS, Journal_add_disjunction__doc__}, - {"flush_matches", (PyCFunction) Journal_flush_matches, METH_NOARGS, Journal_flush_matches__doc__}, - {"seek", (PyCFunction) Journal_seek, METH_VARARGS | METH_KEYWORDS, Journal_seek__doc__}, - {"seek_realtime", (PyCFunction) Journal_seek_realtime, METH_VARARGS, Journal_seek_realtime__doc__}, - {"seek_monotonic", (PyCFunction) Journal_seek_monotonic, METH_VARARGS, Journal_seek_monotonic__doc__}, - {"wait", (PyCFunction) Journal_wait, METH_VARARGS, Journal_wait__doc__}, - {"seek_cursor", (PyCFunction) Journal_seek_cursor, METH_VARARGS, Journal_seek_cursor__doc__}, - {"query_unique", (PyCFunction) Journal_query_unique, METH_VARARGS, Journal_query_unique__doc__}, +static PyMethodDef Reader_methods[] = { + {"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__}, + {"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__}, + {"seek_head", (PyCFunction) Reader_seek_head, METH_NOARGS, Reader_seek_head__doc__}, + {"seek_tail", (PyCFunction) Reader_seek_tail, METH_NOARGS, Reader_seek_tail__doc__}, + {"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__}, {NULL} /* Sentinel */ }; -static PyTypeObject JournalType = { +static PyTypeObject ReaderType = { PyVarObject_HEAD_INIT(NULL, 0) - "_reader._Journal", /*tp_name*/ - sizeof(Journal), /*tp_basicsize*/ + "_reader._Reader", /*tp_name*/ + sizeof(Reader), /*tp_basicsize*/ 0, /*tp_itemsize*/ - (destructor)Journal_dealloc, /*tp_dealloc*/ + (destructor)Reader_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ @@ -673,22 +702,22 @@ static PyTypeObject JournalType = { 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - Journal__doc__, /* tp_doc */ + Reader__doc__, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ - Journal_iter, /* tp_iter */ - Journal_iternext, /* tp_iternext */ - Journal_methods, /* tp_methods */ + Reader_iter, /* tp_iter */ + Reader_iternext, /* tp_iternext */ + Reader_methods, /* tp_methods */ 0, /* tp_members */ - Journal_getseters, /* tp_getset */ + Reader_getseters, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - (initproc) Journal_init, /* tp_init */ + (initproc) Reader_init, /* tp_init */ 0, /* tp_alloc */ PyType_GenericNew, /* tp_new */ }; @@ -724,7 +753,7 @@ init_reader(void) PyDateTime_IMPORT; - if (PyType_Ready(&JournalType) < 0) + if (PyType_Ready(&ReaderType) < 0) #if PY_MAJOR_VERSION >= 3 return NULL; #else @@ -746,11 +775,11 @@ init_reader(void) return; #endif - Py_INCREF(&JournalType); + Py_INCREF(&ReaderType); #if PY_MAJOR_VERSION >= 3 Py_INCREF(&MonotonicType); #endif - if (PyModule_AddObject(m, "_Journal", (PyObject *) &JournalType) || + if (PyModule_AddObject(m, "_Reader", (PyObject *) &ReaderType) || #if PY_MAJOR_VERSION >= 3 PyModule_AddObject(m, "Monotonic", (PyObject*) &MonotonicType) || #endif