X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fpython-systemd%2F_reader.c;h=b754014e9bc50d8a27bceac0ecdf5a3ba03a4182;hb=cac40fbe240565c9431f3f535b0523bd3a7fe225;hp=ae3d77cfe9ef2fdc678d010ebd1e903dffd11f0f;hpb=bf1ced5503bf02fa8c18f0089f4cf74a5456c3c9;p=elogind.git diff --git a/src/python-systemd/_reader.c b/src/python-systemd/_reader.c index ae3d77cfe..b754014e9 100644 --- a/src/python-systemd/_reader.c +++ b/src/python-systemd/_reader.c @@ -1,21 +1,23 @@ -/* -_reader - Python module that reads systemd journal similar to journalctl -Copyright (C) 2012 Steven Hiscocks - -This library 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. - -This library 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 this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + 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 . +***/ #include #include @@ -54,28 +56,26 @@ Journal_init(Journal *self, PyObject *args, PyObject *keywds) int flags=SD_JOURNAL_LOCAL_ONLY; char *path=NULL; - static char *kwlist[] = {"flags", NULL}; - if (! PyArg_ParseTupleAndKeywords(args, keywds, "|is", kwlist, + static char *kwlist[] = {"flags", "path", NULL}; + if (! PyArg_ParseTupleAndKeywords(args, keywds, "|iz", kwlist, &flags, &path)) return 1; int r; + Py_BEGIN_ALLOW_THREADS if (path) { r = sd_journal_open_directory(&self->j, path, 0); }else{ - Py_BEGIN_ALLOW_THREADS r = sd_journal_open(&self->j, flags); - Py_END_ALLOW_THREADS } - if (r == -EINVAL) { - PyErr_SetString(PyExc_ValueError, "Invalid flags or path"); + 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; - }else if (r == -ENOMEM) { - PyErr_SetString(PyExc_MemoryError, "Not enough memory"); - return 1; - }else if (r < 0) { - PyErr_SetString(PyExc_RuntimeError, "Error opening journal"); - return 1; } return 0; @@ -92,30 +92,27 @@ Journal_get_next(Journal *self, PyObject *args) if (! PyArg_ParseTuple(args, "|L", &skip)) return NULL; - int r; + if (skip == 0LL) { + PyErr_SetString(PyExc_ValueError, "Skip number must positive/negative integer"); + return NULL; + } + + int r = -EINVAL; + Py_BEGIN_ALLOW_THREADS if (skip == 1LL) { - Py_BEGIN_ALLOW_THREADS r = sd_journal_next(self->j); - Py_END_ALLOW_THREADS }else if (skip == -1LL) { - Py_BEGIN_ALLOW_THREADS r = sd_journal_previous(self->j); - Py_END_ALLOW_THREADS }else if (skip > 1LL) { - Py_BEGIN_ALLOW_THREADS r = sd_journal_next_skip(self->j, skip); - Py_END_ALLOW_THREADS }else if (skip < -1LL) { - Py_BEGIN_ALLOW_THREADS r = sd_journal_previous_skip(self->j, -skip); - Py_END_ALLOW_THREADS - }else{ - PyErr_SetString(PyExc_ValueError, "Skip number must positive/negative integer"); - return NULL; } + Py_END_ALLOW_THREADS if (r < 0) { - PyErr_SetString(PyExc_RuntimeError, "Error getting next message"); + errno = -r; + PyErr_SetFromErrno(PyExc_OSError); return NULL; }else if ( r == 0) { //EOF return PyDict_New(); @@ -220,117 +217,28 @@ Journal_get_previous(Journal *self, PyObject *args) } PyDoc_STRVAR(Journal_add_match__doc__, -"add_match(match, ..., field=value, ...) -> None\n\n" +"add_match(match) -> None\n\n" "Add a match to filter journal log entries. All matches of different\n" -"field are combined in logical AND, and matches of the same field\n" +"fields are combined in logical AND, and matches of the same field\n" "are automatically combined in logical OR.\n" -"Matches can be passed as strings \"field=value\", or keyword\n" -"arguments field=\"value\"."); +"Match is string of form \"field=value\"."); static PyObject * Journal_add_match(Journal *self, PyObject *args, PyObject *keywds) { - Py_ssize_t arg_match_len; - char *arg_match; - int i, r; - for (i = 0; i < PySequence_Size(args); i++) { -#if PY_MAJOR_VERSION >=3 - PyObject *arg; - arg = PySequence_Fast_GET_ITEM(args, i); - if (PyUnicode_Check(arg)) { -#if PY_MINOR_VERSION >=3 - arg_match = PyUnicode_AsUTF8AndSize(arg, &arg_match_len); -#else - PyObject *temp; - temp = PyUnicode_AsUTF8String(arg); - PyBytes_AsStringAndSize(temp, &arg_match, &arg_match_len); - Py_DECREF(temp); -#endif - }else if (PyBytes_Check(arg)) { - PyBytes_AsStringAndSize(arg, &arg_match, &arg_match_len); - }else{ - PyErr_SetString(PyExc_TypeError, "expected bytes or string"); - } -#else - PyString_AsStringAndSize(PySequence_Fast_GET_ITEM(args, i), &arg_match, &arg_match_len); -#endif - if (PyErr_Occurred()) - return NULL; - r = sd_journal_add_match(self->j, arg_match, arg_match_len); - if (r == -EINVAL) { - PyErr_SetString(PyExc_ValueError, "Invalid match"); - return NULL; - }else if (r == -ENOMEM) { - PyErr_SetString(PyExc_MemoryError, "Not enough memory"); - return NULL; - }else if (r < 0) { - PyErr_SetString(PyExc_RuntimeError, "Error adding match"); - return NULL; - } - } - - if (! keywds) - Py_RETURN_NONE; - - PyObject *key, *value; - Py_ssize_t pos=0, match_key_len, match_value_len; + char *match; int match_len; - char *match_key, *match_value; - void *match; - while (PyDict_Next(keywds, &pos, &key, &value)) { -#if PY_MAJOR_VERSION >=3 - if (PyUnicode_Check(key)) { -#if PY_MINOR_VERSION >=3 - match_key = PyUnicode_AsUTF8AndSize(key, &match_key_len); -#else - PyObject *temp2; - temp2 = PyUnicode_AsUTF8String(key); - PyBytes_AsStringAndSize(temp2, &match_key, &match_key_len); - Py_DECREF(temp2); -#endif - }else if (PyBytes_Check(key)) { - PyBytes_AsStringAndSize(key, &match_key, &match_key_len); - }else{ - PyErr_SetString(PyExc_TypeError, "expected bytes or string"); - } - if (PyUnicode_Check(value)) { -#if PY_MINOR_VERSION >=3 - match_value = PyUnicode_AsUTF8AndSize(value, &match_value_len); -#else - PyObject *temp3; - temp3 = PyUnicode_AsUTF8String(value); - PyBytes_AsStringAndSize(temp3, &match_value, &match_value_len); - Py_DECREF(temp3); -#endif - }else if (PyBytes_Check(value)) { - PyBytes_AsStringAndSize(value, &match_value, &match_value_len); - }else{ - PyErr_SetString(PyExc_TypeError, "expected bytes or string"); - } -#else - PyString_AsStringAndSize(key, &match_key, &match_key_len); - PyString_AsStringAndSize(value, &match_value, &match_value_len); -#endif - if (PyErr_Occurred()) - return NULL; - - match_len = match_key_len + 1 + match_value_len; - match = malloc(match_len); - memcpy(match, match_key, match_key_len); - memcpy(match + match_key_len, "=", 1); - memcpy(match + match_key_len + 1, match_value, match_value_len); + if (! PyArg_ParseTuple(args, "s#", &match, &match_len)) + return NULL; - r = sd_journal_add_match(self->j, match, match_len); - free(match); - if (r == -EINVAL) { - PyErr_SetString(PyExc_ValueError, "Invalid match"); - return NULL; - }else if (r == -ENOMEM) { - PyErr_SetString(PyExc_MemoryError, "Not enough memory"); - return NULL; - }else if (r < 0) { - PyErr_SetString(PyExc_RuntimeError, "Error adding match"); - 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; } Py_RETURN_NONE; @@ -345,11 +253,11 @@ Journal_add_disjunction(Journal *self, PyObject *args) { int r; r = sd_journal_add_disjunction(self->j); - if (r == -ENOMEM) { - PyErr_SetString(PyExc_MemoryError, "Not enough memory"); - return NULL; - }else if (r < 0) { - PyErr_SetString(PyExc_RuntimeError, "Error adding disjunction"); + if (r < 0) { + errno = -r; + PyObject *errtype = r == -ENOMEM ? PyExc_MemoryError : + PyExc_OSError; + PyErr_SetFromErrno(errtype); return NULL; } Py_RETURN_NONE; @@ -390,7 +298,8 @@ Journal_seek(Journal *self, PyObject *args, PyObject *keywds) r = sd_journal_seek_head(self->j); Py_END_ALLOW_THREADS if (r < 0) { - PyErr_SetString(PyExc_RuntimeError, "Error seeking to head"); + errno = -r; + PyErr_SetFromErrno(PyExc_OSError); return NULL; } if (offset > 0LL) { @@ -404,7 +313,8 @@ Journal_seek(Journal *self, PyObject *args, PyObject *keywds) r = sd_journal_seek_tail(self->j); Py_END_ALLOW_THREADS if (r < 0) { - PyErr_SetString(PyExc_RuntimeError, "Error seeking to tail"); + errno = -r; + PyErr_SetFromErrno(PyExc_OSError); return NULL; } if (offset < 0LL) { @@ -416,8 +326,7 @@ Journal_seek(Journal *self, PyObject *args, PyObject *keywds) PyErr_SetString(PyExc_ValueError, "Invalid value for whence"); } - if (result) - Py_DECREF(result); + Py_XDECREF(result); if (PyErr_Occurred()) return NULL; Py_RETURN_NONE; @@ -426,39 +335,19 @@ 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 be an integer unix timestamp in usecs or a " -"datetime instance."); +"`realtime` can must be an integer unix timestamp."); static PyObject * Journal_seek_realtime(Journal *self, PyObject *args) { - PyObject *arg; - if (! PyArg_ParseTuple(args, "O", &arg)) + double timedouble; + if (! PyArg_ParseTuple(args, "d", &timedouble)) return NULL; - uint64_t timestamp=-1LL; - if (PyDateTime_Check(arg)) { - PyObject *temp; - char *timestamp_str; - temp = PyObject_CallMethod(arg, "strftime", "s", "%s%f"); -#if PY_MAJOR_VERSION >=3 - PyObject *temp2; - temp2 = PyUnicode_AsUTF8String(temp); - timestamp_str = PyBytes_AsString(temp2); - Py_DECREF(temp2); -#else - timestamp_str = PyString_AsString(temp); -#endif - Py_DECREF(temp); - timestamp = strtoull(timestamp_str, NULL, 10); - }else if (PyLong_Check(arg)) { - timestamp = PyLong_AsUnsignedLongLong(arg); -#if PY_MAJOR_VERSION <3 - }else if (PyInt_Check(arg)) { - timestamp = PyInt_AsUnsignedLongLongMask(arg); -#endif - } + uint64_t timestamp; + timestamp = (uint64_t) (timedouble * 1.0E6); + if ((int64_t) timestamp < 0LL) { - PyErr_SetString(PyExc_ValueError, "Time must be positive integer or datetime instance"); + PyErr_SetString(PyExc_ValueError, "Time must be positive integer"); return NULL; } @@ -467,7 +356,8 @@ Journal_seek_realtime(Journal *self, PyObject *args) r = sd_journal_seek_realtime_usec(self->j, timestamp); Py_END_ALLOW_THREADS if (r < 0) { - PyErr_SetString(PyExc_RuntimeError, "Error seek to time"); + errno = -r; + PyErr_SetFromErrno(PyExc_OSError); return NULL; } Py_RETURN_NONE; @@ -476,37 +366,22 @@ Journal_seek_realtime(Journal *self, PyObject *args) 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 secs, or a\n" -"timedelta instance.\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) { - PyObject *arg; + double timedouble; char *bootid=NULL; - if (! PyArg_ParseTuple(args, "O|s", &arg, &bootid)) + if (! PyArg_ParseTuple(args, "d|z", &timedouble, &bootid)) return NULL; - uint64_t timestamp=-1LL; - if PyDelta_Check(arg) { - PyObject *temp; - temp = PyObject_CallMethod(arg, "total_seconds", NULL); - timestamp = (uint64_t) (PyFloat_AsDouble(temp) * 1E6); - Py_DECREF(temp); - }else if (PyFloat_Check(arg)) { - timestamp = (uint64_t) (PyFloat_AsDouble(arg) * 1E6); - }else if (PyLong_Check(arg)) { - timestamp = PyLong_AsUnsignedLongLong(arg) * (uint64_t) 1E6; -#if PY_MAJOR_VERSION <3 - }else if (PyInt_Check(arg)) { - timestamp = PyInt_AsUnsignedLongLongMask(arg) * (uint64_t) 1E6; -#endif - - } + uint64_t timestamp; + timestamp = (uint64_t) (timedouble * 1.0E6); if ((int64_t) timestamp < 0LL) { - PyErr_SetString(PyExc_ValueError, "Time must be positive number or timedelta instance"); + PyErr_SetString(PyExc_ValueError, "Time must be positive number"); return NULL; } @@ -517,8 +392,9 @@ Journal_seek_monotonic(Journal *self, PyObject *args) if (r == -EINVAL) { PyErr_SetString(PyExc_ValueError, "Invalid bootid"); return NULL; - } else if (r < 0) { - PyErr_SetString(PyExc_RuntimeError, "Error processing bootid"); + }else if (r < 0) { + errno = -r; + PyErr_SetFromErrno(PyExc_OSError); return NULL; } }else{ @@ -526,8 +402,9 @@ Journal_seek_monotonic(Journal *self, PyObject *args) if (r == -EIO) { PyErr_SetString(PyExc_IOError, "Error getting current boot ID"); return NULL; - } else if (r < 0) { - PyErr_SetString(PyExc_RuntimeError, "Error getting current boot ID"); + }else if (r < 0) { + errno = -r; + PyErr_SetFromErrno(PyExc_OSError); return NULL; } } @@ -536,7 +413,8 @@ Journal_seek_monotonic(Journal *self, PyObject *args) r = sd_journal_seek_monotonic_usec(self->j, sd_id, timestamp); Py_END_ALLOW_THREADS if (r < 0) { - PyErr_SetString(PyExc_RuntimeError, "Error seek to time"); + errno = -r; + PyErr_SetFromErrno(PyExc_OSError); return NULL; } Py_RETURN_NONE; @@ -559,14 +437,19 @@ Journal_wait(Journal *self, PyObject *args, PyObject *keywds) return NULL; int r; + Py_BEGIN_ALLOW_THREADS if ( timeout == 0LL) { - Py_BEGIN_ALLOW_THREADS r = sd_journal_wait(self->j, (uint64_t) -1); - Py_END_ALLOW_THREADS }else{ - Py_BEGIN_ALLOW_THREADS r = sd_journal_wait(self->j, timeout * 1E6); - Py_END_ALLOW_THREADS + } + Py_END_ALLOW_THREADS + if (r < 0) { + errno = -r; + PyObject *errtype = r == -ENOMEM ? PyExc_MemoryError : + PyExc_OSError; + PyErr_SetFromErrno(errtype); + return NULL; } #if PY_MAJOR_VERSION >=3 return PyLong_FromLong(r); @@ -589,14 +472,12 @@ Journal_seek_cursor(Journal *self, PyObject *args) Py_BEGIN_ALLOW_THREADS r = sd_journal_seek_cursor(self->j, cursor); Py_END_ALLOW_THREADS - if (r == -EINVAL) { - PyErr_SetString(PyExc_ValueError, "Invalid cursor"); - return NULL; - }else if (r == -ENOMEM) { - PyErr_SetString(PyExc_MemoryError, "Not enough memory"); - return NULL; - }else if (r < 0) { - PyErr_SetString(PyExc_RuntimeError, "Error seeking to cursor"); + if (r < 0) { + errno = -r; + PyObject *errtype = r == -EINVAL ? PyExc_ValueError : + r == -ENOMEM ? PyExc_MemoryError : + PyExc_OSError; + PyErr_SetFromErrno(errtype); return NULL; } Py_RETURN_NONE; @@ -616,6 +497,8 @@ Journal_iternext(PyObject *self) Py_ssize_t dict_size; dict = PyObject_CallMethod(self, "get_next", ""); + if (PyErr_Occurred()) + return NULL; dict_size = PyDict_Size(dict); if ((int64_t) dict_size > 0LL) { return dict; @@ -626,7 +509,6 @@ Journal_iternext(PyObject *self) } } -#ifdef SD_JOURNAL_FOREACH_UNIQUE 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" @@ -642,14 +524,12 @@ Journal_query_unique(Journal *self, PyObject *args) Py_BEGIN_ALLOW_THREADS r = sd_journal_query_unique(self->j, query); Py_END_ALLOW_THREADS - if (r == -EINVAL) { - PyErr_SetString(PyExc_ValueError, "Invalid field name"); - return NULL; - } else if (r == -ENOMEM) { - PyErr_SetString(PyExc_MemoryError, "Not enough memory"); - return NULL; - } else if (r < 0) { - PyErr_SetString(PyExc_RuntimeError, "Error querying journal"); + if (r < 0) { + errno = -r; + PyObject *errtype = r == -EINVAL ? PyExc_ValueError : + r == -ENOMEM ? PyExc_MemoryError : + PyExc_OSError; + PyErr_SetFromErrno(errtype); return NULL; } @@ -674,7 +554,6 @@ Journal_query_unique(Journal *self, PyObject *args) Py_DECREF(key); return value_set; } -#endif //def SD_JOURNAL_FOREACH_UNIQUE static PyObject * Journal_get_data_threshold(Journal *self, void *closure) @@ -684,8 +563,9 @@ Journal_get_data_threshold(Journal *self, void *closure) int r; r = sd_journal_get_data_threshold(self->j, &cvalue); - if (r < 0){ - PyErr_SetString(PyExc_RuntimeError, "Error getting data threshold"); + if (r < 0) { + errno = -r; + PyErr_SetFromErrno(PyExc_OSError); return NULL; } @@ -718,8 +598,9 @@ Journal_set_data_threshold(Journal *self, PyObject *value, void *closure) #else r = sd_journal_set_data_threshold(self->j, (size_t) PyInt_AsLong(value)); #endif - if (r < 0){ - PyErr_SetString(PyExc_RuntimeError, "Error setting data threshold"); + if (r < 0) { + errno = -r; + PyErr_SetFromErrno(PyExc_OSError); return -1; } return 0; @@ -755,16 +636,14 @@ static PyMethodDef Journal_methods[] = { Journal_wait__doc__}, {"seek_cursor", (PyCFunction)Journal_seek_cursor, METH_VARARGS, Journal_seek_cursor__doc__}, -#ifdef SD_JOURNAL_FOREACH_UNIQUE {"query_unique", (PyCFunction)Journal_query_unique, METH_VARARGS, Journal_query_unique__doc__}, -#endif {NULL} /* Sentinel */ }; static PyTypeObject JournalType = { PyVarObject_HEAD_INIT(NULL, 0) - "_reader.Journal", /*tp_name*/ + "_reader._Journal", /*tp_name*/ sizeof(Journal), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)Journal_dealloc, /*tp_dealloc*/