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` can must be an integer unix timestamp.");
503 static PyObject* Reader_seek_realtime(Reader *self, PyObject *args)
509 if (!PyArg_ParseTuple(args, "d:_Reader.seek_realtime", &timedouble))
512 timestamp = (uint64_t) (timedouble * 1.0E6);
513 if ((int64_t) timestamp < 0LL) {
514 PyErr_SetString(PyExc_ValueError, "Time must be a positive integer");
518 Py_BEGIN_ALLOW_THREADS
519 r = sd_journal_seek_realtime_usec(self->j, timestamp);
521 if (set_error(r, NULL, NULL))
527 PyDoc_STRVAR(Reader_seek_monotonic__doc__,
528 "seek_monotonic(monotonic[, bootid]) -> None\n\n"
529 "Seek to nearest matching journal entry to `monotonic`. Argument\n"
530 "`monotonic` is an timestamp from boot in seconds.\n"
531 "Argument `bootid` is a string representing which boot the\n"
532 "monotonic time is reference to. Defaults to current bootid.");
533 static PyObject* Reader_seek_monotonic(Reader *self, PyObject *args)
541 if (!PyArg_ParseTuple(args, "d|z:_Reader.seek_monotonic", &timedouble, &bootid))
544 timestamp = (uint64_t) (timedouble * 1.0E6);
546 if ((int64_t) timestamp < 0LL) {
547 PyErr_SetString(PyExc_ValueError, "Time must be positive number");
552 r = sd_id128_from_string(bootid, &id);
553 if (set_error(r, NULL, "Invalid bootid"))
556 Py_BEGIN_ALLOW_THREADS
557 r = sd_id128_get_boot(&id);
559 if (set_error(r, NULL, NULL))
563 Py_BEGIN_ALLOW_THREADS
564 r = sd_journal_seek_monotonic_usec(self->j, id, timestamp);
566 if (set_error(r, NULL, NULL))
572 PyDoc_STRVAR(Reader_wait__doc__,
573 "wait([timeout]) -> state change (integer)\n\n"
574 "Wait for a change in the journal. Argument `timeout` specifies\n"
575 "the maximum number of seconds to wait before returning\n"
576 "regardless of wheter the journal has changed. If `timeout` is not given\n"
577 "or is 0, then block forever.\n"
578 "Will return constants: NOP if no change; APPEND if new\n"
579 "entries have been added to the end of the journal; and\n"
580 "INVALIDATE if journal files have been added or removed.");
581 static PyObject* Reader_wait(Reader *self, PyObject *args, PyObject *keywds)
584 int64_t timeout = 0LL;
586 if (!PyArg_ParseTuple(args, "|L:_Reader.wait", &timeout))
589 Py_BEGIN_ALLOW_THREADS
590 r = sd_journal_wait(self->j,
591 timeout == 0 ? (uint64_t) -1 : timeout * 1E6);
593 if (set_error(r, NULL, NULL) < 0)
596 return long_FromLong(r);
600 PyDoc_STRVAR(Reader_seek_cursor__doc__,
601 "seek_cursor(cursor) -> None\n\n"
602 "Seek to journal entry by given unique reference `cursor`.");
603 static PyObject* Reader_seek_cursor(Reader *self, PyObject *args)
608 if (!PyArg_ParseTuple(args, "s:_Reader.seek_cursor", &cursor))
611 Py_BEGIN_ALLOW_THREADS
612 r = sd_journal_seek_cursor(self->j, cursor);
614 if (set_error(r, NULL, "Invalid cursor"))
620 static PyObject* Reader_iter(PyObject *self)
626 static PyObject* Reader_iternext(PyObject *self)
629 Py_ssize_t dict_size;
631 dict = PyObject_CallMethod(self, (char*) "get_next", (char*) "");
632 if (PyErr_Occurred())
634 dict_size = PyDict_Size(dict);
635 if ((int64_t) dict_size > 0LL) {
639 PyErr_SetNone(PyExc_StopIteration);
645 PyDoc_STRVAR(Reader_query_unique__doc__,
646 "query_unique(field) -> a set of values\n\n"
647 "Return a set of unique values appearing in journal for the\n"
648 "given `field`. Note this does not respect any journal matches.");
649 static PyObject* Reader_query_unique(Reader *self, PyObject *args)
655 PyObject *value_set, *key, *value;
657 if (!PyArg_ParseTuple(args, "s:_Reader.query_unique", &query))
660 Py_BEGIN_ALLOW_THREADS
661 r = sd_journal_query_unique(self->j, query);
663 if (set_error(r, NULL, "Invalid field name"))
666 value_set = PySet_New(0);
667 key = unicode_FromString(query);
669 SD_JOURNAL_FOREACH_UNIQUE(self->j, uniq, uniq_len) {
670 const char *delim_ptr;
672 delim_ptr = memchr(uniq, '=', uniq_len);
673 value = PyBytes_FromStringAndSize(
675 (const char*) uniq + uniq_len - (delim_ptr + 1));
676 PySet_Add(value_set, value);
684 PyDoc_STRVAR(Reader_get_catalog__doc__,
685 "get_catalog() -> str\n\n"
686 "Retrieve a message catalog entry for the current journal entry.\n"
687 "Wraps man:sd_journal_get_catalog(3).");
688 static PyObject* Reader_get_catalog(Reader *self, PyObject *args)
691 char _cleanup_free_ *msg = NULL;
696 Py_BEGIN_ALLOW_THREADS
697 r = sd_journal_get_catalog(self->j, &msg);
699 if (set_error(r, NULL, NULL))
702 return unicode_FromString(msg);
706 PyDoc_STRVAR(get_catalog__doc__,
707 "get_catalog(id128) -> str\n\n"
708 "Retrieve a message catalog entry for the given id.\n"
709 "Wraps man:sd_journal_get_catalog_for_message_id(3).");
710 static PyObject* get_catalog(PyObject *self, PyObject *args)
715 char _cleanup_free_ *msg = NULL;
720 if (!PyArg_ParseTuple(args, "z:get_catalog", &id_))
723 r = sd_id128_from_string(id_, &id);
724 if (set_error(r, NULL, "Invalid id128"))
727 Py_BEGIN_ALLOW_THREADS
728 r = sd_journal_get_catalog_for_message_id(id, &msg);
730 if (set_error(r, NULL, NULL))
733 return unicode_FromString(msg);
737 PyDoc_STRVAR(data_threshold__doc__,
738 "Threshold for field size truncation in bytes.\n\n"
739 "Fields longer than this will be truncated to the threshold size.\n"
740 "Defaults to 64Kb.");
742 static PyObject* Reader_get_data_threshold(Reader *self, void *closure)
747 r = sd_journal_get_data_threshold(self->j, &cvalue);
748 if (set_error(r, NULL, NULL))
751 return long_FromSize_t(cvalue);
754 static int Reader_set_data_threshold(Reader *self, PyObject *value, void *closure)
758 PyErr_SetString(PyExc_AttributeError, "Cannot delete data threshold");
761 if (!long_Check(value)){
762 PyErr_SetString(PyExc_TypeError, "Data threshold must be an int");
765 r = sd_journal_set_data_threshold(self->j, (size_t) long_AsLong(value));
766 return set_error(r, NULL, NULL);
770 PyDoc_STRVAR(closed__doc__,
771 "True iff journal is closed");
772 static PyObject* Reader_get_closed(Reader *self, void *closure)
774 return PyBool_FromLong(self->j == NULL);
778 static PyGetSetDef Reader_getsetters[] = {
779 {(char*) "data_threshold",
780 (getter) Reader_get_data_threshold,
781 (setter) Reader_set_data_threshold,
782 (char*) data_threshold__doc__,
785 (getter) Reader_get_closed,
787 (char*) closed__doc__,
792 static PyMethodDef Reader_methods[] = {
793 {"fileno", (PyCFunction) Reader_fileno, METH_NOARGS, Reader_fileno__doc__},
794 {"reliable_fd", (PyCFunction) Reader_reliable_fd, METH_NOARGS, Reader_reliable_fd__doc__},
795 {"close", (PyCFunction) Reader_close, METH_NOARGS, Reader_close__doc__},
796 {"get_usage", (PyCFunction) Reader_get_usage, METH_NOARGS, Reader_get_usage__doc__},
797 {"__enter__", (PyCFunction) Reader___enter__, METH_NOARGS, Reader___enter____doc__},
798 {"__exit__", (PyCFunction) Reader___exit__, METH_VARARGS, Reader___exit____doc__},
799 {"get_next", (PyCFunction) Reader_get_next, METH_VARARGS, Reader_get_next__doc__},
800 {"get_previous", (PyCFunction) Reader_get_previous, METH_VARARGS, Reader_get_previous__doc__},
801 {"add_match", (PyCFunction) Reader_add_match, METH_VARARGS|METH_KEYWORDS, Reader_add_match__doc__},
802 {"add_disjunction", (PyCFunction) Reader_add_disjunction, METH_NOARGS, Reader_add_disjunction__doc__},
803 {"flush_matches", (PyCFunction) Reader_flush_matches, METH_NOARGS, Reader_flush_matches__doc__},
804 {"seek_head", (PyCFunction) Reader_seek_head, METH_NOARGS, Reader_seek_head__doc__},
805 {"seek_tail", (PyCFunction) Reader_seek_tail, METH_NOARGS, Reader_seek_tail__doc__},
806 {"seek_realtime", (PyCFunction) Reader_seek_realtime, METH_VARARGS, Reader_seek_realtime__doc__},
807 {"seek_monotonic", (PyCFunction) Reader_seek_monotonic, METH_VARARGS, Reader_seek_monotonic__doc__},
808 {"wait", (PyCFunction) Reader_wait, METH_VARARGS, Reader_wait__doc__},
809 {"seek_cursor", (PyCFunction) Reader_seek_cursor, METH_VARARGS, Reader_seek_cursor__doc__},
810 {"query_unique", (PyCFunction) Reader_query_unique, METH_VARARGS, Reader_query_unique__doc__},
811 {"get_catalog", (PyCFunction) Reader_get_catalog, METH_NOARGS, Reader_get_catalog__doc__},
812 {NULL} /* Sentinel */
815 static PyTypeObject ReaderType = {
816 PyVarObject_HEAD_INIT(NULL, 0)
817 "_reader._Reader", /*tp_name*/
818 sizeof(Reader), /*tp_basicsize*/
820 (destructor)Reader_dealloc, /*tp_dealloc*/
827 0, /*tp_as_sequence*/
835 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
836 Reader__doc__, /* tp_doc */
839 0, /* tp_richcompare */
840 0, /* tp_weaklistoffset */
841 Reader_iter, /* tp_iter */
842 Reader_iternext, /* tp_iternext */
843 Reader_methods, /* tp_methods */
845 Reader_getsetters, /* tp_getset */
848 0, /* tp_descr_get */
849 0, /* tp_descr_set */
850 0, /* tp_dictoffset */
851 (initproc) Reader_init, /* tp_init */
853 PyType_GenericNew, /* tp_new */
856 static PyMethodDef methods[] = {
857 { "get_catalog", get_catalog, METH_VARARGS, get_catalog__doc__},
858 { NULL, NULL, 0, NULL } /* Sentinel */
861 #if PY_MAJOR_VERSION >= 3
862 static PyModuleDef module = {
863 PyModuleDef_HEAD_INIT,
868 NULL, NULL, NULL, NULL
872 #if PY_MAJOR_VERSION >= 3
873 static bool initialized = false;
876 #pragma GCC diagnostic push
877 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
880 #if PY_MAJOR_VERSION >= 3
890 if (PyType_Ready(&ReaderType) < 0)
891 #if PY_MAJOR_VERSION >= 3
897 #if PY_MAJOR_VERSION >= 3
898 m = PyModule_Create(&module);
903 PyStructSequence_InitType(&MonotonicType, &Monotonic_desc);
907 m = Py_InitModule3("_reader", methods, module__doc__);
912 Py_INCREF(&ReaderType);
913 #if PY_MAJOR_VERSION >= 3
914 Py_INCREF(&MonotonicType);
916 if (PyModule_AddObject(m, "_Reader", (PyObject *) &ReaderType) ||
917 #if PY_MAJOR_VERSION >= 3
918 PyModule_AddObject(m, "Monotonic", (PyObject*) &MonotonicType) ||
920 PyModule_AddIntConstant(m, "NOP", SD_JOURNAL_NOP) ||
921 PyModule_AddIntConstant(m, "APPEND", SD_JOURNAL_APPEND) ||
922 PyModule_AddIntConstant(m, "INVALIDATE", SD_JOURNAL_INVALIDATE) ||
923 PyModule_AddIntConstant(m, "LOCAL_ONLY", SD_JOURNAL_LOCAL_ONLY) ||
924 PyModule_AddIntConstant(m, "RUNTIME_ONLY", SD_JOURNAL_RUNTIME_ONLY) ||
925 PyModule_AddIntConstant(m, "SYSTEM_ONLY", SD_JOURNAL_SYSTEM_ONLY)) {
926 #if PY_MAJOR_VERSION >= 3
932 #if PY_MAJOR_VERSION >= 3
937 #pragma GCC diagnostic pop