X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fpython-systemd%2F_reader.c;h=95e60941622356ac2d5f3a35cd04e19b46550070;hb=518dc5dff557116db3f072eb9d0a9492b6226778;hp=ce6631782f8003d6065a7f588e904d3fce073a45;hpb=25523db4e1a3da09916ed69c1e90a52d027ac765;p=elogind.git diff --git a/src/python-systemd/_reader.c b/src/python-systemd/_reader.c index ce6631782..95e609416 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}; + static char *kwlist[] = {"flags", "path", NULL}; if (! PyArg_ParseTupleAndKeywords(args, keywds, "|is", 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; @@ -383,77 +291,64 @@ Journal_seek(Journal *self, PyObject *args, PyObject *keywds) &offset, &whence)) return NULL; - PyObject *arg; + PyObject *result=NULL; if (whence == SEEK_SET){ int r; Py_BEGIN_ALLOW_THREADS 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) { - Py_DECREF(PyObject_CallMethod((PyObject *)self, "get_next", "L", offset)); + result = PyObject_CallMethod((PyObject *)self, "get_next", "L", offset); } }else if (whence == SEEK_CUR){ - Py_DECREF(PyObject_CallMethod((PyObject *)self, "get_next", "L", offset)); + result = PyObject_CallMethod((PyObject *)self, "get_next", "L", offset); }else if (whence == SEEK_END){ int r; Py_BEGIN_ALLOW_THREADS 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; } - Py_DECREF(PyObject_CallMethod((PyObject *)self, "get_next", "L", -1LL)); if (offset < 0LL) { - Py_DECREF(PyObject_CallMethod((PyObject *)self, "get_next", "L", offset)); + result = PyObject_CallMethod((PyObject *)self, "get_next", "L", offset); + }else{ + result = PyObject_CallMethod((PyObject *)self, "get_next", "L", -1LL); } }else{ PyErr_SetString(PyExc_ValueError, "Invalid value for whence"); - return NULL; } + + if (result) + Py_DECREF(result); + if (PyErr_Occurred()) + return NULL; Py_RETURN_NONE; } 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; } @@ -462,7 +357,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; @@ -471,37 +367,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; } @@ -512,8 +393,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{ @@ -521,8 +403,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; } } @@ -531,7 +414,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; @@ -554,14 +438,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); @@ -584,14 +473,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; @@ -607,7 +494,7 @@ Journal_iter(PyObject *self) static PyObject * Journal_iternext(PyObject *self) { - PyObject *dict, *arg; + PyObject *dict; Py_ssize_t dict_size; dict = PyObject_CallMethod(self, "get_next", ""); @@ -637,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; } @@ -671,70 +556,6 @@ Journal_query_unique(Journal *self, PyObject *args) } #endif //def SD_JOURNAL_FOREACH_UNIQUE -PyDoc_STRVAR(Journal_this_boot__doc__, -"this_boot() -> None\n\n" -"Sets match filter for the current _BOOT_ID."); -static PyObject * -Journal_this_boot(Journal *self, PyObject *args) -{ - sd_id128_t sd_id; - int r; - 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) { - PyErr_SetString(PyExc_RuntimeError, "Error getting current boot ID"); - return NULL; - } - - char bootid[33]; - sd_id128_to_string(sd_id, bootid); - - PyObject *arg, *keywds; - arg = PyTuple_New(0); - keywds = Py_BuildValue("{s:s}", "_BOOT_ID", bootid); - Journal_add_match(self, arg, keywds); - Py_DECREF(arg); - Py_DECREF(keywds); - if (PyErr_Occurred()) - return NULL; - - Py_RETURN_NONE; -} - -PyDoc_STRVAR(Journal_this_machine__doc__, -"this_machine() -> None\n\n" -"Sets match filter for the current _MACHINE_ID."); -static PyObject * -Journal_this_machine(Journal *self, PyObject *args) -{ - sd_id128_t sd_id; - int r; - r = sd_id128_get_machine(&sd_id); - 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"); - return NULL; - } - - char machineid[33]; - sd_id128_to_string(sd_id, machineid); - - PyObject *arg, *keywds; - arg = PyTuple_New(0); - keywds = Py_BuildValue("{s:s}", "_MACHINE_ID", machineid); - Journal_add_match(self, arg, keywds); - Py_DECREF(arg); - Py_DECREF(keywds); - if (PyErr_Occurred()) - return NULL; - - Py_RETURN_NONE; -} - static PyObject * Journal_get_data_threshold(Journal *self, void *closure) { @@ -743,8 +564,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; } @@ -777,8 +599,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; @@ -818,10 +641,6 @@ static PyMethodDef Journal_methods[] = { {"query_unique", (PyCFunction)Journal_query_unique, METH_VARARGS, Journal_query_unique__doc__}, #endif - {"this_boot", (PyCFunction)Journal_this_boot, METH_NOARGS, - Journal_this_boot__doc__}, - {"this_machine", (PyCFunction)Journal_this_machine, METH_NOARGS, - Journal_this_machine__doc__}, {NULL} /* Sentinel */ };