1 /*-*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Steven Hiscocks, Zbigniew Jędrzejewski-Szmek
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <structmember.h>
27 #include <systemd/sd-journal.h>
37 static PyTypeObject ReaderType;
39 static int set_error(int r, const char* path, const char* invalid_message) {
42 if (r == -EINVAL && invalid_message)
43 PyErr_SetString(PyExc_ValueError, invalid_message);
44 else if (r == -ENOMEM)
45 PyErr_SetString(PyExc_MemoryError, "Not enough memory");
48 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
54 PyDoc_STRVAR(module__doc__,
55 "Class to reads the systemd journal similar to journalctl.");
58 #if PY_MAJOR_VERSION >= 3
59 static PyTypeObject MonotonicType;
61 PyDoc_STRVAR(MonotonicType__doc__,
62 "A tuple of (timestamp, bootid) for holding monotonic timestamps");
64 static PyStructSequence_Field MonotonicType_fields[] = {
65 {(char*) "timestamp", (char*) "Time"},
66 {(char*) "bootid", (char*) "Unique identifier of the boot"},
70 static PyStructSequence_Desc Monotonic_desc = {
71 (char*) "journal.Monotonic",
79 static void Reader_dealloc(Reader* self)
81 sd_journal_close(self->j);
82 Py_TYPE(self)->tp_free((PyObject*)self);
85 PyDoc_STRVAR(Reader__doc__,
86 "Reader([flags | path]) -> ...\n\n"
87 "Reader allows filtering and retrieval of Journal entries.\n"
88 "Note: this is a low-level interface, and probably not what you\n"
89 "want, use systemd.journal.Reader instead.\n\n"
90 "Argument `flags` sets open flags of the journal, which can be one\n"
91 "of, or ORed combination of constants: LOCAL_ONLY (default) opens\n"
92 "journal on local machine only; RUNTIME_ONLY opens only\n"
93 "volatile journal files; and SYSTEM_ONLY opens only\n"
94 "journal files of system services and the kernel.\n\n"
95 "Argument `path` is the directory of journal files. Note that\n"
96 "`flags` and `path` are exclusive.\n");
97 static int Reader_init(Reader *self, PyObject *args, PyObject *keywds)
102 static const char* const kwlist[] = {"flags", "path", NULL};
103 if (!PyArg_ParseTupleAndKeywords(args, keywds, "|iz", (char**) kwlist,
108 flags = SD_JOURNAL_LOCAL_ONLY;
111 PyErr_SetString(PyExc_ValueError, "cannot use both flags and path");
115 Py_BEGIN_ALLOW_THREADS
117 r = sd_journal_open_directory(&self->j, path, 0);
119 r = sd_journal_open(&self->j, flags);
122 return set_error(r, path, "Invalid flags or path");
126 PyDoc_STRVAR(Reader_fileno__doc__,
127 "fileno() -> int\n\n"
128 "Get a file descriptor to poll for changes in the journal.\n"
129 "This method invokes sd_journal_get_fd().\n"
130 "See man:sd_journal_get_fd(3).");
131 static PyObject* Reader_fileno(Reader *self, PyObject *args)
134 fd = sd_journal_get_fd(self->j);
135 set_error(fd, NULL, NULL);
138 return long_FromLong(fd);
142 PyDoc_STRVAR(Reader_reliable_fd__doc__,
143 "reliable_fd() -> bool\n\n"
144 "Returns True iff the journal can be polled reliably.\n"
145 "This method invokes sd_journal_reliable_fd().\n"
146 "See man:sd_journal_reliable_fd(3).");
147 static PyObject* Reader_reliable_fd(Reader *self, PyObject *args)
150 r = sd_journal_reliable_fd(self->j);
151 set_error(r, NULL, NULL);
154 return PyBool_FromLong(r);
158 PyDoc_STRVAR(Reader_close__doc__,
159 "close() -> None\n\n"
160 "Free resources allocated by this Reader object.\n"
161 "This method invokes sd_journal_close().\n"
162 "See man:sd_journal_close(3).");
163 static PyObject* Reader_close(Reader *self, PyObject *args)
168 sd_journal_close(self->j);
174 PyDoc_STRVAR(Reader_get_usage__doc__,
175 "get_usage() -> int\n\n"
176 "Returns the total disk space currently used by journal"
177 "files (in bytes). If `SD_JOURNAL_LOCAL_ONLY` was"
178 "passed when opening the journal this value will only reflect"
179 "the size of journal files of the local host, otherwise"
181 "This method invokes sd_journal_get_usage().\n"
182 "See man:sd_journal_get_usage(3).");
183 static PyObject* Reader_get_usage(Reader *self, PyObject *args)
188 r = sd_journal_get_usage(self->j, &bytes);
189 if (set_error(r, NULL, NULL))
192 assert_cc(sizeof(unsigned long long) == sizeof(bytes));
193 return PyLong_FromUnsignedLongLong(bytes);
197 PyDoc_STRVAR(Reader___enter____doc__,
198 "__enter__() -> self\n\n"
199 "Part of the context manager protocol.\n"
201 static PyObject* Reader___enter__(PyObject *self, PyObject *args)
210 PyDoc_STRVAR(Reader___exit____doc__,
211 "__exit__(type, value, traceback) -> None\n\n"
212 "Part of the context manager protocol.\n"
213 "Closes the journal.\n");
214 static PyObject* Reader___exit__(Reader *self, PyObject *args)
218 sd_journal_close(self->j);
224 PyDoc_STRVAR(Reader_get_next__doc__,
225 "get_next([skip]) -> dict\n\n"
226 "Return dictionary of the next log entry. Optional skip value will\n"
227 "return the `skip`\\-th log entry.");
228 static PyObject* Reader_get_next(Reader *self, PyObject *args)
236 if (!PyArg_ParseTuple(args, "|L:_Reader.get_next", &skip))
240 PyErr_SetString(PyExc_ValueError, "skip must be nonzero");
244 Py_BEGIN_ALLOW_THREADS
246 r = sd_journal_next(self->j);
247 else if (skip == -1LL)
248 r = sd_journal_previous(self->j);
250 r = sd_journal_next_skip(self->j, skip);
251 else if (skip < -1LL)
252 r = sd_journal_previous_skip(self->j, -skip);
254 assert_not_reached("should not be here");
257 set_error(r, NULL, NULL);
260 else if (r == 0) /* EOF */
267 SD_JOURNAL_FOREACH_DATA(self->j, msg, msg_len) {
268 PyObject _cleanup_Py_DECREF_ *key = NULL, *value = NULL;
269 const char *delim_ptr;
271 delim_ptr = memchr(msg, '=', msg_len);
273 PyErr_SetString(PyExc_OSError,
274 "journal gave us a field without '='");
278 key = unicode_FromStringAndSize(msg, delim_ptr - (const char*) msg);
282 value = PyBytes_FromStringAndSize(
284 (const char*) msg + msg_len - (delim_ptr + 1) );
288 if (PyDict_Contains(dict, key)) {
289 PyObject *cur_value = PyDict_GetItem(dict, key);
291 if (PyList_CheckExact(cur_value)) {
292 r = PyList_Append(cur_value, value);
296 PyObject _cleanup_Py_DECREF_ *tmp_list = PyList_New(0);
300 r = PyList_Append(tmp_list, cur_value);
304 r = PyList_Append(tmp_list, value);
308 r = PyDict_SetItem(dict, key, tmp_list);
313 r = PyDict_SetItem(dict, key, value);
320 PyObject _cleanup_Py_DECREF_ *key = NULL, *value = NULL;
323 r = sd_journal_get_realtime_usec(self->j, &realtime);
324 if (set_error(r, NULL, NULL))
327 key = unicode_FromString("__REALTIME_TIMESTAMP");
331 assert_cc(sizeof(unsigned long long) == sizeof(realtime));
332 value = PyLong_FromUnsignedLongLong(realtime);
336 if (PyDict_SetItem(dict, key, value))
341 PyObject _cleanup_Py_DECREF_
342 *key = NULL, *timestamp = NULL, *bytes = NULL, *value = NULL;
346 r = sd_journal_get_monotonic_usec(self->j, &monotonic, &id);
347 if (set_error(r, NULL, NULL))
350 assert_cc(sizeof(unsigned long long) == sizeof(monotonic));
351 key = unicode_FromString("__MONOTONIC_TIMESTAMP");
352 timestamp = PyLong_FromUnsignedLongLong(monotonic);
353 bytes = PyBytes_FromStringAndSize((const char*) &id.bytes, sizeof(id.bytes));
354 #if PY_MAJOR_VERSION >= 3
355 value = PyStructSequence_New(&MonotonicType);
357 value = PyTuple_New(2);
359 if (!key || !timestamp || !bytes || !value)
362 Py_INCREF(timestamp);
365 #if PY_MAJOR_VERSION >= 3
366 PyStructSequence_SET_ITEM(value, 0, timestamp);
367 PyStructSequence_SET_ITEM(value, 1, bytes);
369 PyTuple_SET_ITEM(value, 0, timestamp);
370 PyTuple_SET_ITEM(value, 1, bytes);
373 if (PyDict_SetItem(dict, key, value))
378 PyObject _cleanup_Py_DECREF_ *key = NULL, *value = NULL;
379 char _cleanup_free_ *cursor = NULL;
381 r = sd_journal_get_cursor(self->j, &cursor);
382 if (set_error(r, NULL, NULL))
385 key = unicode_FromString("__CURSOR");
389 value = PyBytes_FromString(cursor);
393 if (PyDict_SetItem(dict, key, value))
404 PyDoc_STRVAR(Reader_get_previous__doc__,
405 "get_previous([skip]) -> dict\n\n"
406 "Return dictionary of the previous log entry. Optional skip value\n"
407 "will return the -`skip`\\-th log entry. Equivalent to get_next(-skip).");
408 static PyObject* Reader_get_previous(Reader *self, PyObject *args)
411 if (!PyArg_ParseTuple(args, "|L:_Reader.get_previous", &skip))
414 return PyObject_CallMethod((PyObject *)self, (char*) "get_next",
419 PyDoc_STRVAR(Reader_add_match__doc__,
420 "add_match(match) -> None\n\n"
421 "Add a match to filter journal log entries. All matches of different\n"
422 "fields are combined with logical AND, and matches of the same field\n"
423 "are automatically combined with logical OR.\n"
424 "Match is a string of the form \"FIELD=value\".");
425 static PyObject* Reader_add_match(Reader *self, PyObject *args, PyObject *keywds)
429 if (!PyArg_ParseTuple(args, "s#:_Reader.add_match", &match, &match_len))
432 r = sd_journal_add_match(self->j, match, match_len);
433 set_error(r, NULL, "Invalid match");
441 PyDoc_STRVAR(Reader_add_disjunction__doc__,
442 "add_disjunction() -> None\n\n"
443 "Inserts a logical OR between matches added before and afterwards.");
444 static PyObject* Reader_add_disjunction(Reader *self, PyObject *args)
447 r = sd_journal_add_disjunction(self->j);
448 set_error(r, NULL, NULL);
455 PyDoc_STRVAR(Reader_flush_matches__doc__,
456 "flush_matches() -> None\n\n"
457 "Clear all current match filters.");
458 static PyObject* Reader_flush_matches(Reader *self, PyObject *args)
460 sd_journal_flush_matches(self->j);
465 PyDoc_STRVAR(Reader_seek_head__doc__,
466 "seek_head() -> None\n\n"
467 "Jump to the beginning of the journal.\n"
468 "This method invokes sd_journal_seek_head().\n"
469 "See man:sd_journal_seek_head(3).");
470 static PyObject* Reader_seek_head(Reader *self, PyObject *args)
473 Py_BEGIN_ALLOW_THREADS
474 r = sd_journal_seek_head(self->j);
476 if (set_error(r, NULL, NULL))
482 PyDoc_STRVAR(Reader_seek_tail__doc__,
483 "seek_tail() -> None\n\n"
484 "Jump to the end of the journal.\n"
485 "This method invokes sd_journal_seek_tail().\n"
486 "See man:sd_journal_seek_tail(3).");
487 static PyObject* Reader_seek_tail(Reader *self, PyObject *args)
490 Py_BEGIN_ALLOW_THREADS
491 r = sd_journal_seek_tail(self->j);
493 if (set_error(r, NULL, NULL))
499 PyDoc_STRVAR(Reader_seek_realtime__doc__,
500 "seek_realtime(realtime) -> None\n\n"
501 "Seek to nearest matching journal entry to `realtime`. Argument\n"
502 "`realtime` in specified in seconds.");
503 static PyObject* Reader_seek_realtime(Reader *self, PyObject *args)
508 if (!PyArg_ParseTuple(args, "K:seek_realtime", ×tamp))
511 Py_BEGIN_ALLOW_THREADS
512 r = sd_journal_seek_realtime_usec(self->j, timestamp);
514 if (set_error(r, NULL, NULL))
520 PyDoc_STRVAR(Reader_seek_monotonic__doc__,
521 "seek_monotonic(monotonic[, bootid]) -> None\n\n"
522 "Seek to nearest matching journal entry to `monotonic`. Argument\n"
523 "`monotonic` is an timestamp from boot in microseconds.\n"
524 "Argument `bootid` is a string representing which boot the\n"
525 "monotonic time is reference to. Defaults to current bootid.");
526 static PyObject* Reader_seek_monotonic(Reader *self, PyObject *args)
533 if (!PyArg_ParseTuple(args, "K|z:seek_monotonic", ×tamp, &bootid))
537 r = sd_id128_from_string(bootid, &id);
538 if (set_error(r, NULL, "Invalid bootid"))
541 Py_BEGIN_ALLOW_THREADS
542 r = sd_id128_get_boot(&id);
544 if (set_error(r, NULL, NULL))
548 Py_BEGIN_ALLOW_THREADS
549 r = sd_journal_seek_monotonic_usec(self->j, id, timestamp);
551 if (set_error(r, NULL, NULL))
558 PyDoc_STRVAR(Reader_wait__doc__,
559 "wait([timeout]) -> state change (integer)\n\n"
560 "Wait for a change in the journal. Argument `timeout` specifies\n"
561 "the maximum number of microseconds to wait before returning\n"
562 "regardless of wheter the journal has changed. If `timeout` is -1,\n"
563 "then block forever.\n\n"
564 "Will return constants: NOP if no change; APPEND if new\n"
565 "entries have been added to the end of the journal; and\n"
566 "INVALIDATE if journal files have been added or removed.");
567 static PyObject* Reader_wait(Reader *self, PyObject *args)
572 if (!PyArg_ParseTuple(args, "|L:wait", &timeout))
575 Py_BEGIN_ALLOW_THREADS
576 r = sd_journal_wait(self->j, timeout);
578 if (set_error(r, NULL, NULL) < 0)
581 return long_FromLong(r);
585 PyDoc_STRVAR(Reader_seek_cursor__doc__,
586 "seek_cursor(cursor) -> None\n\n"
587 "Seek to journal entry by given unique reference `cursor`.");
588 static PyObject* Reader_seek_cursor(Reader *self, PyObject *args)
593 if (!PyArg_ParseTuple(args, "s:_Reader.seek_cursor", &cursor))
596 Py_BEGIN_ALLOW_THREADS
597 r = sd_journal_seek_cursor(self->j, cursor);
599 if (set_error(r, NULL, "Invalid cursor"))
605 static PyObject* Reader_iter(PyObject *self)
611 static PyObject* Reader_iternext(PyObject *self)
614 Py_ssize_t dict_size;
616 dict = PyObject_CallMethod(self, (char*) "get_next", (char*) "");
617 if (PyErr_Occurred())
619 dict_size = PyDict_Size(dict);
620 if ((int64_t) dict_size > 0LL) {
624 PyErr_SetNone(PyExc_StopIteration);
630 PyDoc_STRVAR(Reader_query_unique__doc__,
631 "query_unique(field) -> a set of values\n\n"
632 "Return a set of unique values appearing in journal for the\n"
633 "given `field`. Note this does not respect any journal matches.");
634 static PyObject* Reader_query_unique(Reader *self, PyObject *args)
640 PyObject *value_set, *key, *value;
642 if (!PyArg_ParseTuple(args, "s:_Reader.query_unique", &query))
645 Py_BEGIN_ALLOW_THREADS
646 r = sd_journal_query_unique(self->j, query);
648 if (set_error(r, NULL, "Invalid field name"))
651 value_set = PySet_New(0);
652 key = unicode_FromString(query);
654 SD_JOURNAL_FOREACH_UNIQUE(self->j, uniq, uniq_len) {
655 const char *delim_ptr;
657 delim_ptr = memchr(uniq, '=', uniq_len);
658 value = PyBytes_FromStringAndSize(
660 (const char*) uniq + uniq_len - (delim_ptr + 1));
661 PySet_Add(value_set, value);
669 PyDoc_STRVAR(Reader_get_catalog__doc__,
670 "get_catalog() -> str\n\n"
671 "Retrieve a message catalog entry for the current journal entry.\n"
672 "Wraps man:sd_journal_get_catalog(3).");
673 static PyObject* Reader_get_catalog(Reader *self, PyObject *args)
676 char _cleanup_free_ *msg = NULL;
681 Py_BEGIN_ALLOW_THREADS
682 r = sd_journal_get_catalog(self->j, &msg);
684 if (set_error(r, NULL, NULL))
687 return unicode_FromString(msg);
691 PyDoc_STRVAR(get_catalog__doc__,
692 "get_catalog(id128) -> str\n\n"
693 "Retrieve a message catalog entry for the given id.\n"
694 "Wraps man:sd_journal_get_catalog_for_message_id(3).");
695 static PyObject* get_catalog(PyObject *self, PyObject *args)
700 char _cleanup_free_ *msg = NULL;
705 if (!PyArg_ParseTuple(args, "z:get_catalog", &id_))
708 r = sd_id128_from_string(id_, &id);
709 if (set_error(r, NULL, "Invalid id128"))
712 Py_BEGIN_ALLOW_THREADS
713 r = sd_journal_get_catalog_for_message_id(id, &msg);
715 if (set_error(r, NULL, NULL))
718 return unicode_FromString(msg);
722 PyDoc_STRVAR(data_threshold__doc__,
723 "Threshold for field size truncation in bytes.\n\n"
724 "Fields longer than this will be truncated to the threshold size.\n"
725 "Defaults to 64Kb.");
727 static PyObject* Reader_get_data_threshold(Reader *self, void *closure)
732 r = sd_journal_get_data_threshold(self->j, &cvalue);
733 if (set_error(r, NULL, NULL))
736 return long_FromSize_t(cvalue);
739 static int Reader_set_data_threshold(Reader *self, PyObject *value, void *closure)
743 PyErr_SetString(PyExc_AttributeError, "Cannot delete data threshold");
746 if (!long_Check(value)){
747 PyErr_SetString(PyExc_TypeError, "Data threshold must be an int");
750 r = sd_journal_set_data_threshold(self->j, (size_t) long_AsLong(value));
751 return set_error(r, NULL, NULL);
755 PyDoc_STRVAR(closed__doc__,
756 "True iff journal is closed");
757 static PyObject* Reader_get_closed(Reader *self, void *closure)
759 return PyBool_FromLong(self->j == NULL);
763 static PyGetSetDef Reader_getsetters[] = {
764 {(char*) "data_threshold",
765 (getter) Reader_get_data_threshold,
766 (setter) Reader_set_data_threshold,
767 (char*) data_threshold__doc__,
770 (getter) Reader_get_closed,
772 (char*) closed__doc__,
777 static PyMethodDef Reader_methods[] = {
778 {"fileno", (PyCFunction) Reader_fileno, METH_NOARGS, Reader_fileno__doc__},
779 {"reliable_fd", (PyCFunction) Reader_reliable_fd, METH_NOARGS, Reader_reliable_fd__doc__},
780 {"close", (PyCFunction) Reader_close, METH_NOARGS, Reader_close__doc__},
781 {"get_usage", (PyCFunction) Reader_get_usage, METH_NOARGS, Reader_get_usage__doc__},
782 {"__enter__", (PyCFunction) Reader___enter__, METH_NOARGS, Reader___enter____doc__},
783 {"__exit__", (PyCFunction) Reader___exit__, METH_VARARGS, Reader___exit____doc__},
784 {"get_next", (PyCFunction) Reader_get_next, METH_VARARGS, Reader_get_next__doc__},
785 {"get_previous", (PyCFunction) Reader_get_previous, METH_VARARGS, Reader_get_previous__doc__},
786 {"add_match", (PyCFunction) Reader_add_match, METH_VARARGS|METH_KEYWORDS, Reader_add_match__doc__},
787 {"add_disjunction", (PyCFunction) Reader_add_disjunction, METH_NOARGS, Reader_add_disjunction__doc__},
788 {"flush_matches", (PyCFunction) Reader_flush_matches, METH_NOARGS, Reader_flush_matches__doc__},
789 {"seek_head", (PyCFunction) Reader_seek_head, METH_NOARGS, Reader_seek_head__doc__},
790 {"seek_tail", (PyCFunction) Reader_seek_tail, METH_NOARGS, Reader_seek_tail__doc__},
791 {"seek_realtime", (PyCFunction) Reader_seek_realtime, METH_VARARGS, Reader_seek_realtime__doc__},
792 {"seek_monotonic", (PyCFunction) Reader_seek_monotonic, METH_VARARGS, Reader_seek_monotonic__doc__},
793 {"wait", (PyCFunction) Reader_wait, METH_VARARGS, Reader_wait__doc__},
794 {"seek_cursor", (PyCFunction) Reader_seek_cursor, METH_VARARGS, Reader_seek_cursor__doc__},
795 {"query_unique", (PyCFunction) Reader_query_unique, METH_VARARGS, Reader_query_unique__doc__},
796 {"get_catalog", (PyCFunction) Reader_get_catalog, METH_NOARGS, Reader_get_catalog__doc__},
797 {NULL} /* Sentinel */
800 static PyTypeObject ReaderType = {
801 PyVarObject_HEAD_INIT(NULL, 0)
802 "_reader._Reader", /*tp_name*/
803 sizeof(Reader), /*tp_basicsize*/
805 (destructor)Reader_dealloc, /*tp_dealloc*/
812 0, /*tp_as_sequence*/
820 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
821 Reader__doc__, /* tp_doc */
824 0, /* tp_richcompare */
825 0, /* tp_weaklistoffset */
826 Reader_iter, /* tp_iter */
827 Reader_iternext, /* tp_iternext */
828 Reader_methods, /* tp_methods */
830 Reader_getsetters, /* tp_getset */
833 0, /* tp_descr_get */
834 0, /* tp_descr_set */
835 0, /* tp_dictoffset */
836 (initproc) Reader_init, /* tp_init */
838 PyType_GenericNew, /* tp_new */
841 static PyMethodDef methods[] = {
842 { "get_catalog", get_catalog, METH_VARARGS, get_catalog__doc__},
843 { NULL, NULL, 0, NULL } /* Sentinel */
846 #if PY_MAJOR_VERSION >= 3
847 static PyModuleDef module = {
848 PyModuleDef_HEAD_INIT,
853 NULL, NULL, NULL, NULL
857 #if PY_MAJOR_VERSION >= 3
858 static bool initialized = false;
861 #pragma GCC diagnostic push
862 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
865 #if PY_MAJOR_VERSION >= 3
875 if (PyType_Ready(&ReaderType) < 0)
876 #if PY_MAJOR_VERSION >= 3
882 #if PY_MAJOR_VERSION >= 3
883 m = PyModule_Create(&module);
888 PyStructSequence_InitType(&MonotonicType, &Monotonic_desc);
892 m = Py_InitModule3("_reader", methods, module__doc__);
897 Py_INCREF(&ReaderType);
898 #if PY_MAJOR_VERSION >= 3
899 Py_INCREF(&MonotonicType);
901 if (PyModule_AddObject(m, "_Reader", (PyObject *) &ReaderType) ||
902 #if PY_MAJOR_VERSION >= 3
903 PyModule_AddObject(m, "Monotonic", (PyObject*) &MonotonicType) ||
905 PyModule_AddIntConstant(m, "NOP", SD_JOURNAL_NOP) ||
906 PyModule_AddIntConstant(m, "APPEND", SD_JOURNAL_APPEND) ||
907 PyModule_AddIntConstant(m, "INVALIDATE", SD_JOURNAL_INVALIDATE) ||
908 PyModule_AddIntConstant(m, "LOCAL_ONLY", SD_JOURNAL_LOCAL_ONLY) ||
909 PyModule_AddIntConstant(m, "RUNTIME_ONLY", SD_JOURNAL_RUNTIME_ONLY) ||
910 PyModule_AddIntConstant(m, "SYSTEM_ONLY", SD_JOURNAL_SYSTEM_ONLY)) {
911 #if PY_MAJOR_VERSION >= 3
917 #if PY_MAJOR_VERSION >= 3
922 #pragma GCC diagnostic pop