X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fpython-systemd%2F_reader.c;h=207b9e76cb26ba12cdc6681dfb4f69f03112b307;hb=5c083fa815d7357d107e76ffb9a5161956c3aec5;hp=b754014e9bc50d8a27bceac0ecdf5a3ba03a4182;hpb=6d0c634ca32c772c72b0bb4207866e2a35f4eadb;p=elogind.git diff --git a/src/python-systemd/_reader.c b/src/python-systemd/_reader.c index b754014e9..207b9e76c 100644 --- a/src/python-systemd/_reader.c +++ b/src/python-systemd/_reader.c @@ -1,4 +1,4 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +/*-*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*-*/ /*** This file is part of systemd. @@ -24,115 +24,123 @@ #include #include +#if PY_MAJOR_VERSION >=3 +# define unicode_FromStringAndSize PyUnicode_FromStringAndSize +# define unicode_FromString PyUnicode_FromString +# define long_FromLong PyLong_FromLong +# define long_FromSize_t PyLong_FromSize_t +# define long_Check PyLong_Check +# define long_AsLong PyLong_AsLong +#else +/* Python 3 type naming convention is used */ +# define unicode_FromStringAndSize PyString_FromStringAndSize +# define unicode_FromString PyString_FromString +# define long_FromLong PyInt_FromLong +# define long_FromSize_t PyInt_FromSize_t +# define long_Check PyInt_Check +# define long_AsLong PyInt_AsLong +#endif + typedef struct { PyObject_HEAD sd_journal *j; } Journal; static PyTypeObject JournalType; -static void -Journal_dealloc(Journal* self) +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; +} + +static void Journal_dealloc(Journal* self) { sd_journal_close(self->j); Py_TYPE(self)->tp_free((PyObject*)self); } PyDoc_STRVAR(Journal__doc__, -"Journal([flags][,path]) -> ...\n" -"Journal instance\n\n" -"Returns instance of Journal, which allows filtering and return\n" -"of journal entries.\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" -"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) + "Journal([flags][,path]) -> ...\n\n" + "Journal allows filtering and retrieval of Journal entries.\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" + "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) { - int flags=SD_JOURNAL_LOCAL_ONLY; - char *path=NULL; + int flags = SD_JOURNAL_LOCAL_ONLY, r; + char *path = NULL; - static char *kwlist[] = {"flags", "path", NULL}; - if (! PyArg_ParseTupleAndKeywords(args, keywds, "|iz", kwlist, - &flags, &path)) + static const char* const kwlist[] = {"flags", "path", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "|iz", (char**) kwlist, + &flags, &path)) return 1; - int r; Py_BEGIN_ALLOW_THREADS - if (path) { + if (path) r = sd_journal_open_directory(&self->j, path, 0); - }else{ + else r = sd_journal_open(&self->j, flags); - } Py_END_ALLOW_THREADS - if (r < 0) { - errno = -r; - PyObject *errtype = r == -EINVAL ? PyExc_ValueError : - r == -ENOMEM ? PyExc_MemoryError : - PyExc_OSError; - PyErr_SetFromErrnoWithFilename(errtype, path); - return -1; - } - return 0; + return set_error(r, path, "Invalid flags or path"); } PyDoc_STRVAR(Journal_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) + "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) { - int64_t skip=1LL; - if (! PyArg_ParseTuple(args, "|L", &skip)) + PyObject *dict; + const void *msg; + size_t msg_len; + const char *delim_ptr; + PyObject *key, *value, *cur_value, *tmp_list; + + int64_t skip = 1LL, r = -EINVAL; + if (!PyArg_ParseTuple(args, "|L", &skip)) return NULL; if (skip == 0LL) { - PyErr_SetString(PyExc_ValueError, "Skip number must positive/negative integer"); + PyErr_SetString(PyExc_ValueError, "skip must be nonzero"); return NULL; } - int r = -EINVAL; Py_BEGIN_ALLOW_THREADS - if (skip == 1LL) { + if (skip == 1LL) r = sd_journal_next(self->j); - }else if (skip == -1LL) { + else if (skip == -1LL) r = sd_journal_previous(self->j); - }else if (skip > 1LL) { + else if (skip > 1LL) r = sd_journal_next_skip(self->j, skip); - }else if (skip < -1LL) { + else if (skip < -1LL) r = sd_journal_previous_skip(self->j, -skip); - } Py_END_ALLOW_THREADS - if (r < 0) { - errno = -r; - PyErr_SetFromErrno(PyExc_OSError); + set_error(r, NULL, NULL); + if (r < 0) return NULL; - }else if ( r == 0) { //EOF + else if (r == 0) /* EOF */ return PyDict_New(); - } - PyObject *dict; dict = PyDict_New(); - const void *msg; - size_t msg_len; - const char *delim_ptr; - PyObject *key, *value, *cur_value, *tmp_list; - SD_JOURNAL_FOREACH_DATA(self->j, msg, msg_len) { delim_ptr = memchr(msg, '=', msg_len); -#if PY_MAJOR_VERSION >=3 - key = PyUnicode_FromStringAndSize(msg, delim_ptr - (const char*) msg); -#else - key = PyString_FromStringAndSize(msg, delim_ptr - (const char*) msg); -#endif + key = unicode_FromStringAndSize(msg, delim_ptr - (const char*) msg); value = PyBytes_FromStringAndSize(delim_ptr + 1, (const char*) msg + msg_len - (delim_ptr + 1) ); if (PyDict_Contains(dict, key)) { cur_value = PyDict_GetItem(dict, key); @@ -152,177 +160,155 @@ Journal_get_next(Journal *self, PyObject *args) Py_DECREF(value); } - uint64_t realtime; - if (sd_journal_get_realtime_usec(self->j, &realtime) == 0) { - char realtime_str[20]; - sprintf(realtime_str, "%llu", (long long unsigned) realtime); - -#if PY_MAJOR_VERSION >=3 - key = PyUnicode_FromString("__REALTIME_TIMESTAMP"); -#else - key = PyString_FromString("__REALTIME_TIMESTAMP"); -#endif - value = PyBytes_FromString(realtime_str); - PyDict_SetItem(dict, key, value); - Py_DECREF(key); - Py_DECREF(value); + { + uint64_t realtime; + if (sd_journal_get_realtime_usec(self->j, &realtime) == 0) { + char realtime_str[20]; + sprintf(realtime_str, "%llu", (long long unsigned) realtime); + key = unicode_FromString("__REALTIME_TIMESTAMP"); + value = PyBytes_FromString(realtime_str); + PyDict_SetItem(dict, key, value); + Py_DECREF(key); + Py_DECREF(value); + } } - sd_id128_t sd_id; - uint64_t monotonic; - if (sd_journal_get_monotonic_usec(self->j, &monotonic, &sd_id) == 0) { - char monotonic_str[20]; - sprintf(monotonic_str, "%llu", (long long unsigned) monotonic); -#if PY_MAJOR_VERSION >=3 - key = PyUnicode_FromString("__MONOTONIC_TIMESTAMP"); -#else - key = PyString_FromString("__MONOTONIC_TIMESTAMP"); -#endif - value = PyBytes_FromString(monotonic_str); + { + sd_id128_t sd_id; + uint64_t monotonic; + if (sd_journal_get_monotonic_usec(self->j, &monotonic, &sd_id) == 0) { + char monotonic_str[20]; + sprintf(monotonic_str, "%llu", (long long unsigned) monotonic); + key = unicode_FromString("__MONOTONIC_TIMESTAMP"); + value = PyBytes_FromString(monotonic_str); - PyDict_SetItem(dict, key, value); - Py_DECREF(key); - Py_DECREF(value); + PyDict_SetItem(dict, key, value); + Py_DECREF(key); + Py_DECREF(value); + } } - char *cursor; - if (sd_journal_get_cursor(self->j, &cursor) > 0) { //Should return 0... -#if PY_MAJOR_VERSION >=3 - key = PyUnicode_FromString("__CURSOR"); -#else - key = PyString_FromString("__CURSOR"); -#endif - value = PyBytes_FromString(cursor); - PyDict_SetItem(dict, key, value); - free(cursor); - Py_DECREF(key); - Py_DECREF(value); + { + char *cursor; + if (sd_journal_get_cursor(self->j, &cursor) > 0) { //Should return 0... + key = unicode_FromString("__CURSOR"); + value = PyBytes_FromString(cursor); + PyDict_SetItem(dict, key, value); + free(cursor); + Py_DECREF(key); + Py_DECREF(value); + } } return dict; } PyDoc_STRVAR(Journal_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) + "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) { - int64_t skip=1LL; - if (! PyArg_ParseTuple(args, "|L", &skip)) + int64_t skip = 1LL; + if (!PyArg_ParseTuple(args, "|L", &skip)) return NULL; - return PyObject_CallMethod((PyObject *)self, "get_next", "L", -skip); + return PyObject_CallMethod((PyObject *)self, (char*) "get_next", + (char*) "L", -skip); } PyDoc_STRVAR(Journal_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 in logical AND, and matches of the same field\n" -"are automatically combined in logical OR.\n" -"Match is string of form \"field=value\"."); -static PyObject * -Journal_add_match(Journal *self, PyObject *args, PyObject *keywds) + "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) { char *match; - int match_len; - if (! PyArg_ParseTuple(args, "s#", &match, &match_len)) + int match_len, r; + if (!PyArg_ParseTuple(args, "s#", &match, &match_len)) return NULL; - int r; r = sd_journal_add_match(self->j, match, match_len); - if (r < 0) { - errno = -r; - PyObject *errtype = r == -EINVAL ? PyExc_ValueError : - r == -ENOMEM ? PyExc_MemoryError : - PyExc_OSError; - PyErr_SetFromErrno(errtype); - return NULL; - } + set_error(r, NULL, "Invalid match"); + if (r < 0) + return NULL; Py_RETURN_NONE; } PyDoc_STRVAR(Journal_add_disjunction__doc__, -"add_disjunction() -> None\n\n" -"Once called, all matches before and after are combined in logical\n" -"OR."); -static PyObject * -Journal_add_disjunction(Journal *self, PyObject *args) + "add_disjunction() -> None\n\n" + "Inserts a logical OR between matches added before and afterwards."); +static PyObject* Journal_add_disjunction(Journal *self, PyObject *args) { int r; r = sd_journal_add_disjunction(self->j); - if (r < 0) { - errno = -r; - PyObject *errtype = r == -ENOMEM ? PyExc_MemoryError : - PyExc_OSError; - PyErr_SetFromErrno(errtype); + set_error(r, NULL, NULL); + if (r < 0) return NULL; - } Py_RETURN_NONE; } PyDoc_STRVAR(Journal_flush_matches__doc__, -"flush_matches() -> None\n\n" -"Clears all current match filters."); -static PyObject * -Journal_flush_matches(Journal *self, PyObject *args) + "flush_matches() -> None\n\n" + "Clear all current match filters."); +static PyObject* Journal_flush_matches(Journal *self, PyObject *args) { sd_journal_flush_matches(self->j); Py_RETURN_NONE; } PyDoc_STRVAR(Journal_seek__doc__, -"seek(offset[, whence]) -> None\n\n" -"Seek through journal by `offset` number of entries. 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) + "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) { int64_t offset; - int whence=SEEK_SET; - static char *kwlist[] = {"offset", "whence", NULL}; + int whence = SEEK_SET; + PyObject *result = NULL; - if (! PyArg_ParseTupleAndKeywords(args, keywds, "L|i", kwlist, - &offset, &whence)) + static const char* const kwlist[] = {"offset", "whence", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "L|i", (char**) kwlist, + &offset, &whence)) return NULL; - PyObject *result=NULL; - if (whence == SEEK_SET){ + switch(whence) { + case SEEK_SET: { int r; Py_BEGIN_ALLOW_THREADS r = sd_journal_seek_head(self->j); Py_END_ALLOW_THREADS - if (r < 0) { - errno = -r; - PyErr_SetFromErrno(PyExc_OSError); + if (set_error(r, NULL, NULL)) return NULL; - } - if (offset > 0LL) { - result = PyObject_CallMethod((PyObject *)self, "get_next", "L", offset); - } - }else if (whence == SEEK_CUR){ - result = PyObject_CallMethod((PyObject *)self, "get_next", "L", offset); - }else if (whence == SEEK_END){ + + 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 (r < 0) { - errno = -r; - PyErr_SetFromErrno(PyExc_OSError); + if (set_error(r, NULL, NULL)) return NULL; - } - if (offset < 0LL) { - result = PyObject_CallMethod((PyObject *)self, "get_next", "L", offset); - }else{ - result = PyObject_CallMethod((PyObject *)self, "get_next", "L", -1LL); - } - }else{ + + result = PyObject_CallMethod((PyObject *)self, (char*) "get_next", + (char*) "L", offset < 0LL ? offset : -1LL); + break; + } + default: PyErr_SetString(PyExc_ValueError, "Invalid value for whence"); } @@ -333,51 +319,49 @@ Journal_seek(Journal *self, PyObject *args, PyObject *keywds) } PyDoc_STRVAR(Journal_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) + "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) { double timedouble; - if (! PyArg_ParseTuple(args, "d", &timedouble)) + uint64_t timestamp; + int r; + + if (!PyArg_ParseTuple(args, "d", &timedouble)) return NULL; - uint64_t timestamp; timestamp = (uint64_t) (timedouble * 1.0E6); - if ((int64_t) timestamp < 0LL) { - PyErr_SetString(PyExc_ValueError, "Time must be positive integer"); + PyErr_SetString(PyExc_ValueError, "Time must be a positive integer"); return NULL; } - int r; Py_BEGIN_ALLOW_THREADS r = sd_journal_seek_realtime_usec(self->j, timestamp); Py_END_ALLOW_THREADS - if (r < 0) { - errno = -r; - PyErr_SetFromErrno(PyExc_OSError); + if (set_error(r, NULL, NULL)) return NULL; - } Py_RETURN_NONE; } PyDoc_STRVAR(Journal_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) + "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) { double timedouble; - char *bootid=NULL; - if (! PyArg_ParseTuple(args, "d|z", &timedouble, &bootid)) + char *bootid = NULL; + uint64_t timestamp; + sd_id128_t sd_id; + int r; + + if (!PyArg_ParseTuple(args, "d|z", &timedouble, &bootid)) return NULL; - uint64_t timestamp; timestamp = (uint64_t) (timedouble * 1.0E6); if ((int64_t) timestamp < 0LL) { @@ -385,118 +369,83 @@ Journal_seek_monotonic(Journal *self, PyObject *args) return NULL; } - sd_id128_t sd_id; - int r; if (bootid) { r = sd_id128_from_string(bootid, &sd_id); - if (r == -EINVAL) { - PyErr_SetString(PyExc_ValueError, "Invalid bootid"); - return NULL; - }else if (r < 0) { - errno = -r; - PyErr_SetFromErrno(PyExc_OSError); + if (set_error(r, NULL, "Invalid bootid")) return NULL; - } - }else{ + } else { + Py_BEGIN_ALLOW_THREADS r = sd_id128_get_boot(&sd_id); - if (r == -EIO) { - PyErr_SetString(PyExc_IOError, "Error getting current boot ID"); - return NULL; - }else if (r < 0) { - errno = -r; - PyErr_SetFromErrno(PyExc_OSError); + Py_END_ALLOW_THREADS + if (set_error(r, NULL, NULL)) return NULL; - } } Py_BEGIN_ALLOW_THREADS r = sd_journal_seek_monotonic_usec(self->j, sd_id, timestamp); Py_END_ALLOW_THREADS - if (r < 0) { - errno = -r; - PyErr_SetFromErrno(PyExc_OSError); + if (set_error(r, NULL, NULL)) return NULL; - } Py_RETURN_NONE; } - + PyDoc_STRVAR(Journal_wait__doc__, -"wait([timeout]) -> Change state (integer)\n\n" -"Waits until there is a change in the journal. Argument `timeout`\n" -"is the maximum number of seconds to wait before returning\n" -"regardless if journal has changed. If `timeout` is not given or is\n" -"0, then it will block forever.\n" -"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) + "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" + "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) { - int64_t timeout=0LL; - if (! PyArg_ParseTuple(args, "|L", &timeout)) + int r; + int64_t timeout = 0LL; + + if (!PyArg_ParseTuple(args, "|L", &timeout)) return NULL; - int r; Py_BEGIN_ALLOW_THREADS - if ( timeout == 0LL) { - r = sd_journal_wait(self->j, (uint64_t) -1); - }else{ - r = sd_journal_wait(self->j, timeout * 1E6); - } + r = sd_journal_wait(self->j, timeout ==0 ? (uint64_t) -1 : timeout * 1E6); Py_END_ALLOW_THREADS - if (r < 0) { - errno = -r; - PyObject *errtype = r == -ENOMEM ? PyExc_MemoryError : - PyExc_OSError; - PyErr_SetFromErrno(errtype); + if (set_error(r, NULL, NULL)) return NULL; - } -#if PY_MAJOR_VERSION >=3 - return PyLong_FromLong(r); -#else - return PyInt_FromLong(r); -#endif + + return long_FromLong(r); } PyDoc_STRVAR(Journal_seek_cursor__doc__, -"seek_cursor(cursor) -> None\n\n" -"Seeks to journal entry by given unique reference `cursor`."); -static PyObject * -Journal_seek_cursor(Journal *self, PyObject *args) + "seek_cursor(cursor) -> None\n\n" + "Seek to journal entry by given unique reference `cursor`."); +static PyObject* Journal_seek_cursor(Journal *self, PyObject *args) { const char *cursor; - if (! PyArg_ParseTuple(args, "s", &cursor)) + int r; + + if (!PyArg_ParseTuple(args, "s", &cursor)) return NULL; - int r; Py_BEGIN_ALLOW_THREADS r = sd_journal_seek_cursor(self->j, cursor); Py_END_ALLOW_THREADS - if (r < 0) { - errno = -r; - PyObject *errtype = r == -EINVAL ? PyExc_ValueError : - r == -ENOMEM ? PyExc_MemoryError : - PyExc_OSError; - PyErr_SetFromErrno(errtype); + if (set_error(r, NULL, "Invalid cursor")) return NULL; - } Py_RETURN_NONE; } -static PyObject * -Journal_iter(PyObject *self) +static PyObject* Journal_iter(PyObject *self) { Py_INCREF(self); return self; } -static PyObject * -Journal_iternext(PyObject *self) +static PyObject* Journal_iternext(PyObject *self) { PyObject *dict; Py_ssize_t dict_size; - dict = PyObject_CallMethod(self, "get_next", ""); + dict = PyObject_CallMethod(self, (char*) "get_next", (char*) ""); if (PyErr_Occurred()) return NULL; dict_size = PyDict_Size(dict); @@ -510,42 +459,32 @@ Journal_iternext(PyObject *self) } PyDoc_STRVAR(Journal_query_unique__doc__, -"query_unique(field) -> a set of values\n\n" -"Returns a set of unique values in journal for given `field`.\n" -"Note this does not respect any journal matches."); -static PyObject * -Journal_query_unique(Journal *self, PyObject *args) + "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) { char *query; - if (! PyArg_ParseTuple(args, "s", &query)) + int r; + const void *uniq; + size_t uniq_len; + PyObject *value_set, *key, *value; + + if (!PyArg_ParseTuple(args, "s", &query)) return NULL; - int r; Py_BEGIN_ALLOW_THREADS r = sd_journal_query_unique(self->j, query); Py_END_ALLOW_THREADS - if (r < 0) { - errno = -r; - PyObject *errtype = r == -EINVAL ? PyExc_ValueError : - r == -ENOMEM ? PyExc_MemoryError : - PyExc_OSError; - PyErr_SetFromErrno(errtype); + if (set_error(r, NULL, "Invalid field name")) return NULL; - } - const void *uniq; - size_t uniq_len; - const char *delim_ptr; - PyObject *value_set, *key, *value; value_set = PySet_New(0); - -#if PY_MAJOR_VERSION >=3 - key = PyUnicode_FromString(query); -#else - key = PyString_FromString(query); -#endif + key = unicode_FromString(query); SD_JOURNAL_FOREACH_UNIQUE(self->j, uniq, uniq_len) { + const char *delim_ptr; + delim_ptr = memchr(uniq, '=', uniq_len); value = PyBytes_FromStringAndSize(delim_ptr + 1, (const char*) uniq + uniq_len - (delim_ptr + 1)); PySet_Add(value_set, value); @@ -555,63 +494,44 @@ Journal_query_unique(Journal *self, PyObject *args) return value_set; } -static PyObject * -Journal_get_data_threshold(Journal *self, void *closure) +PyDoc_STRVAR(data_threshold__doc__, + "Threshold for field size truncation.\n\n" + "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) { size_t cvalue; - PyObject *value; int r; r = sd_journal_get_data_threshold(self->j, &cvalue); - if (r < 0) { - errno = -r; - PyErr_SetFromErrno(PyExc_OSError); + if (set_error(r, NULL, NULL)) return NULL; - } -#if PY_MAJOR_VERSION >=3 - value = PyLong_FromSize_t(cvalue); -#else - value = PyInt_FromSize_t(cvalue); -#endif - return value; + return long_FromSize_t(cvalue); } -static int -Journal_set_data_threshold(Journal *self, PyObject *value, void *closure) +static int Journal_set_data_threshold(Journal *self, PyObject *value, void *closure) { + int r; if (value == NULL) { PyErr_SetString(PyExc_TypeError, "Cannot delete data threshold"); return -1; } -#if PY_MAJOR_VERSION >=3 - if (! PyLong_Check(value)){ -#else - if (! PyInt_Check(value)){ -#endif - PyErr_SetString(PyExc_TypeError, "Data threshold must be int"); - return -1; - } - int r; -#if PY_MAJOR_VERSION >=3 - r = sd_journal_set_data_threshold(self->j, (size_t) PyLong_AsLong(value)); -#else - r = sd_journal_set_data_threshold(self->j, (size_t) PyInt_AsLong(value)); -#endif - if (r < 0) { - errno = -r; - PyErr_SetFromErrno(PyExc_OSError); + if (!long_Check(value)){ + PyErr_SetString(PyExc_TypeError, "Data threshold must be an int"); return -1; } - return 0; + r = sd_journal_set_data_threshold(self->j, (size_t) long_AsLong(value)); + return set_error(r, NULL, NULL); } static PyGetSetDef Journal_getseters[] = { - {"data_threshold", - (getter)Journal_get_data_threshold, - (setter)Journal_set_data_threshold, - "data threshold", - NULL}, + {(char*) "data_threshold", + (getter)Journal_get_data_threshold, + (setter)Journal_set_data_threshold, + (char*) data_threshold__doc__, + NULL}, {NULL} }; @@ -682,21 +602,27 @@ static PyTypeObject JournalType = { PyType_GenericNew, /* tp_new */ }; +#define SUMMARY \ + "Module that reads the systemd journal similar to journalctl." + #if PY_MAJOR_VERSION >= 3 static PyModuleDef _reader_module = { PyModuleDef_HEAD_INIT, "_reader", - "Module that reads systemd journal similar to journalctl.", + SUMMARY, -1, NULL, NULL, NULL, NULL, NULL }; #endif +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-prototypes" + PyMODINIT_FUNC #if PY_MAJOR_VERSION >= 3 PyInit__reader(void) #else -init_reader(void) +init_reader(void) #endif { PyObject* m; @@ -715,8 +641,7 @@ init_reader(void) if (m == NULL) return NULL; #else - m = Py_InitModule3("_reader", NULL, - "Module that reads systemd journal similar to journalctl."); + m = Py_InitModule3("_reader", NULL, SUMMARY); if (m == NULL) return; #endif @@ -734,3 +659,5 @@ init_reader(void) return m; #endif } + +#pragma GCC diagnostic pop