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))
384 PyDoc_STRVAR(Reader_get_previous__doc__,
385 "get_previous([skip]) -> dict\n\n"
386 "Return dictionary of the previous log entry. Optional skip value\n"
387 "will return the -`skip`\\-th log entry. Equivalent to get_next(-skip).");
388 static PyObject* Reader_get_previous(Reader *self, PyObject *args)
391 if (!PyArg_ParseTuple(args, "|L:_Reader.get_previous", &skip))
394 return PyObject_CallMethod((PyObject *)self, (char*) "get_next",
399 PyDoc_STRVAR(Reader_add_match__doc__,
400 "add_match(match) -> None\n\n"
401 "Add a match to filter journal log entries. All matches of different\n"
402 "fields are combined with logical AND, and matches of the same field\n"
403 "are automatically combined with logical OR.\n"
404 "Match is a string of the form \"FIELD=value\".");
405 static PyObject* Reader_add_match(Reader *self, PyObject *args, PyObject *keywds)
409 if (!PyArg_ParseTuple(args, "s#:_Reader.add_match", &match, &match_len))
412 r = sd_journal_add_match(self->j, match, match_len);
413 set_error(r, NULL, "Invalid match");
421 PyDoc_STRVAR(Reader_add_disjunction__doc__,
422 "add_disjunction() -> None\n\n"
423 "Inserts a logical OR between matches added before and afterwards.");
424 static PyObject* Reader_add_disjunction(Reader *self, PyObject *args)
427 r = sd_journal_add_disjunction(self->j);
428 set_error(r, NULL, NULL);
435 PyDoc_STRVAR(Reader_flush_matches__doc__,
436 "flush_matches() -> None\n\n"
437 "Clear all current match filters.");
438 static PyObject* Reader_flush_matches(Reader *self, PyObject *args)
440 sd_journal_flush_matches(self->j);
445 PyDoc_STRVAR(Reader_seek_head__doc__,
446 "seek_head() -> None\n\n"
447 "Jump to the beginning of the journal.\n"
448 "This method invokes sd_journal_seek_head().\n"
449 "See man:sd_journal_seek_head(3).");
450 static PyObject* Reader_seek_head(Reader *self, PyObject *args)
453 Py_BEGIN_ALLOW_THREADS
454 r = sd_journal_seek_head(self->j);
456 if (set_error(r, NULL, NULL))
462 PyDoc_STRVAR(Reader_seek_tail__doc__,
463 "seek_tail() -> None\n\n"
464 "Jump to the end of the journal.\n"
465 "This method invokes sd_journal_seek_tail().\n"
466 "See man:sd_journal_seek_tail(3).");
467 static PyObject* Reader_seek_tail(Reader *self, PyObject *args)
470 Py_BEGIN_ALLOW_THREADS
471 r = sd_journal_seek_tail(self->j);
473 if (set_error(r, NULL, NULL))
479 PyDoc_STRVAR(Reader_seek_realtime__doc__,
480 "seek_realtime(realtime) -> None\n\n"
481 "Seek to nearest matching journal entry to `realtime`. Argument\n"
482 "`realtime` in specified in seconds.");
483 static PyObject* Reader_seek_realtime(Reader *self, PyObject *args)
488 if (!PyArg_ParseTuple(args, "K:seek_realtime", ×tamp))
491 Py_BEGIN_ALLOW_THREADS
492 r = sd_journal_seek_realtime_usec(self->j, timestamp);
494 if (set_error(r, NULL, NULL))
500 PyDoc_STRVAR(Reader_seek_monotonic__doc__,
501 "seek_monotonic(monotonic[, bootid]) -> None\n\n"
502 "Seek to nearest matching journal entry to `monotonic`. Argument\n"
503 "`monotonic` is an timestamp from boot in microseconds.\n"
504 "Argument `bootid` is a string representing which boot the\n"
505 "monotonic time is reference to. Defaults to current bootid.");
506 static PyObject* Reader_seek_monotonic(Reader *self, PyObject *args)
513 if (!PyArg_ParseTuple(args, "K|z:seek_monotonic", ×tamp, &bootid))
517 r = sd_id128_from_string(bootid, &id);
518 if (set_error(r, NULL, "Invalid bootid"))
521 Py_BEGIN_ALLOW_THREADS
522 r = sd_id128_get_boot(&id);
524 if (set_error(r, NULL, NULL))
528 Py_BEGIN_ALLOW_THREADS
529 r = sd_journal_seek_monotonic_usec(self->j, id, timestamp);
531 if (set_error(r, NULL, NULL))
538 PyDoc_STRVAR(Reader_wait__doc__,
539 "wait([timeout]) -> state change (integer)\n\n"
540 "Wait for a change in the journal. Argument `timeout` specifies\n"
541 "the maximum number of microseconds to wait before returning\n"
542 "regardless of wheter the journal has changed. If `timeout` is -1,\n"
543 "then block forever.\n\n"
544 "Will return constants: NOP if no change; APPEND if new\n"
545 "entries have been added to the end of the journal; and\n"
546 "INVALIDATE if journal files have been added or removed.");
547 static PyObject* Reader_wait(Reader *self, PyObject *args)
552 if (!PyArg_ParseTuple(args, "|L:wait", &timeout))
555 Py_BEGIN_ALLOW_THREADS
556 r = sd_journal_wait(self->j, timeout);
558 if (set_error(r, NULL, NULL) < 0)
561 return long_FromLong(r);
565 PyDoc_STRVAR(Reader_seek_cursor__doc__,
566 "seek_cursor(cursor) -> None\n\n"
567 "Seek to journal entry by given unique reference `cursor`.");
568 static PyObject* Reader_seek_cursor(Reader *self, PyObject *args)
573 if (!PyArg_ParseTuple(args, "s:_Reader.seek_cursor", &cursor))
576 Py_BEGIN_ALLOW_THREADS
577 r = sd_journal_seek_cursor(self->j, cursor);
579 if (set_error(r, NULL, "Invalid cursor"))
585 PyDoc_STRVAR(Reader_get_cursor__doc__,
586 "get_cursor() -> str\n\n"
587 "Return a cursor string for the current journal entry.\n\n"
588 "Wraps sd_journal_get_cursor(). See man:sd_journal_get_cursor(3).");
589 static PyObject* Reader_get_cursor(Reader *self, PyObject *args)
591 char _cleanup_free_ *cursor = NULL;
597 r = sd_journal_get_cursor(self->j, &cursor);
598 if (set_error(r, NULL, NULL))
601 return unicode_FromString(cursor);
605 PyDoc_STRVAR(Reader_test_cursor__doc__,
606 "test_cursor(str) -> bool\n\n"
607 "Test whether the cursor string matches current journal entry.\n\n"
608 "Wraps sd_journal_test_cursor(). See man:sd_journal_test_cursor(3).");
609 static PyObject* Reader_test_cursor(Reader *self, PyObject *args)
617 if (!PyArg_ParseTuple(args, "s:_Reader.get_cursor", &cursor))
620 r = sd_journal_test_cursor(self->j, cursor);
621 set_error(r, NULL, NULL);
625 return PyBool_FromLong(r);
629 static PyObject* Reader_iter(PyObject *self)
635 static PyObject* Reader_iternext(PyObject *self)
638 Py_ssize_t dict_size;
640 dict = PyObject_CallMethod(self, (char*) "get_next", (char*) "");
641 if (PyErr_Occurred())
643 dict_size = PyDict_Size(dict);
644 if ((int64_t) dict_size > 0LL) {
648 PyErr_SetNone(PyExc_StopIteration);
654 PyDoc_STRVAR(Reader_query_unique__doc__,
655 "query_unique(field) -> a set of values\n\n"
656 "Return a set of unique values appearing in journal for the\n"
657 "given `field`. Note this does not respect any journal matches.");
658 static PyObject* Reader_query_unique(Reader *self, PyObject *args)
664 PyObject *value_set, *key, *value;
666 if (!PyArg_ParseTuple(args, "s:_Reader.query_unique", &query))
669 Py_BEGIN_ALLOW_THREADS
670 r = sd_journal_query_unique(self->j, query);
672 if (set_error(r, NULL, "Invalid field name"))
675 value_set = PySet_New(0);
676 key = unicode_FromString(query);
678 SD_JOURNAL_FOREACH_UNIQUE(self->j, uniq, uniq_len) {
679 const char *delim_ptr;
681 delim_ptr = memchr(uniq, '=', uniq_len);
682 value = PyBytes_FromStringAndSize(
684 (const char*) uniq + uniq_len - (delim_ptr + 1));
685 PySet_Add(value_set, value);
693 PyDoc_STRVAR(Reader_get_catalog__doc__,
694 "get_catalog() -> str\n\n"
695 "Retrieve a message catalog entry for the current journal entry.\n"
696 "Wraps man:sd_journal_get_catalog(3).");
697 static PyObject* Reader_get_catalog(Reader *self, PyObject *args)
700 char _cleanup_free_ *msg = NULL;
705 Py_BEGIN_ALLOW_THREADS
706 r = sd_journal_get_catalog(self->j, &msg);
708 if (set_error(r, NULL, NULL))
711 return unicode_FromString(msg);
715 PyDoc_STRVAR(get_catalog__doc__,
716 "get_catalog(id128) -> str\n\n"
717 "Retrieve a message catalog entry for the given id.\n"
718 "Wraps man:sd_journal_get_catalog_for_message_id(3).");
719 static PyObject* get_catalog(PyObject *self, PyObject *args)
724 char _cleanup_free_ *msg = NULL;
729 if (!PyArg_ParseTuple(args, "z:get_catalog", &id_))
732 r = sd_id128_from_string(id_, &id);
733 if (set_error(r, NULL, "Invalid id128"))
736 Py_BEGIN_ALLOW_THREADS
737 r = sd_journal_get_catalog_for_message_id(id, &msg);
739 if (set_error(r, NULL, NULL))
742 return unicode_FromString(msg);
746 PyDoc_STRVAR(data_threshold__doc__,
747 "Threshold for field size truncation in bytes.\n\n"
748 "Fields longer than this will be truncated to the threshold size.\n"
749 "Defaults to 64Kb.");
751 static PyObject* Reader_get_data_threshold(Reader *self, void *closure)
756 r = sd_journal_get_data_threshold(self->j, &cvalue);
757 if (set_error(r, NULL, NULL))
760 return long_FromSize_t(cvalue);
763 static int Reader_set_data_threshold(Reader *self, PyObject *value, void *closure)
767 PyErr_SetString(PyExc_AttributeError, "Cannot delete data threshold");
770 if (!long_Check(value)){
771 PyErr_SetString(PyExc_TypeError, "Data threshold must be an int");
774 r = sd_journal_set_data_threshold(self->j, (size_t) long_AsLong(value));
775 return set_error(r, NULL, NULL);
779 PyDoc_STRVAR(closed__doc__,
780 "True iff journal is closed");
781 static PyObject* Reader_get_closed(Reader *self, void *closure)
783 return PyBool_FromLong(self->j == NULL);
787 static PyGetSetDef Reader_getsetters[] = {
788 {(char*) "data_threshold",
789 (getter) Reader_get_data_threshold,
790 (setter) Reader_set_data_threshold,
791 (char*) data_threshold__doc__,
794 (getter) Reader_get_closed,
796 (char*) closed__doc__,
801 static PyMethodDef Reader_methods[] = {
802 {"fileno", (PyCFunction) Reader_fileno, METH_NOARGS, Reader_fileno__doc__},
803 {"reliable_fd", (PyCFunction) Reader_reliable_fd, METH_NOARGS, Reader_reliable_fd__doc__},
804 {"close", (PyCFunction) Reader_close, METH_NOARGS, Reader_close__doc__},
805 {"get_usage", (PyCFunction) Reader_get_usage, METH_NOARGS, Reader_get_usage__doc__},
806 {"__enter__", (PyCFunction) Reader___enter__, METH_NOARGS, Reader___enter____doc__},
807 {"__exit__", (PyCFunction) Reader___exit__, METH_VARARGS, Reader___exit____doc__},
808 {"get_next", (PyCFunction) Reader_get_next, METH_VARARGS, Reader_get_next__doc__},
809 {"get_previous", (PyCFunction) Reader_get_previous, METH_VARARGS, Reader_get_previous__doc__},
810 {"add_match", (PyCFunction) Reader_add_match, METH_VARARGS|METH_KEYWORDS, Reader_add_match__doc__},
811 {"add_disjunction", (PyCFunction) Reader_add_disjunction, METH_NOARGS, Reader_add_disjunction__doc__},
812 {"flush_matches", (PyCFunction) Reader_flush_matches, METH_NOARGS, Reader_flush_matches__doc__},
813 {"seek_head", (PyCFunction) Reader_seek_head, METH_NOARGS, Reader_seek_head__doc__},
814 {"seek_tail", (PyCFunction) Reader_seek_tail, METH_NOARGS, Reader_seek_tail__doc__},
815 {"seek_realtime", (PyCFunction) Reader_seek_realtime, METH_VARARGS, Reader_seek_realtime__doc__},
816 {"seek_monotonic", (PyCFunction) Reader_seek_monotonic, METH_VARARGS, Reader_seek_monotonic__doc__},
817 {"wait", (PyCFunction) Reader_wait, METH_VARARGS, Reader_wait__doc__},
818 {"seek_cursor", (PyCFunction) Reader_seek_cursor, METH_VARARGS, Reader_seek_cursor__doc__},
819 {"get_cursor", (PyCFunction) Reader_get_cursor, METH_NOARGS, Reader_get_cursor__doc__},
820 {"test_cursor", (PyCFunction) Reader_test_cursor, METH_VARARGS, Reader_test_cursor__doc__},
821 {"query_unique", (PyCFunction) Reader_query_unique, METH_VARARGS, Reader_query_unique__doc__},
822 {"get_catalog", (PyCFunction) Reader_get_catalog, METH_NOARGS, Reader_get_catalog__doc__},
823 {NULL} /* Sentinel */
826 static PyTypeObject ReaderType = {
827 PyVarObject_HEAD_INIT(NULL, 0)
828 "_reader._Reader", /*tp_name*/
829 sizeof(Reader), /*tp_basicsize*/
831 (destructor)Reader_dealloc, /*tp_dealloc*/
838 0, /*tp_as_sequence*/
846 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
847 Reader__doc__, /* tp_doc */
850 0, /* tp_richcompare */
851 0, /* tp_weaklistoffset */
852 Reader_iter, /* tp_iter */
853 Reader_iternext, /* tp_iternext */
854 Reader_methods, /* tp_methods */
856 Reader_getsetters, /* tp_getset */
859 0, /* tp_descr_get */
860 0, /* tp_descr_set */
861 0, /* tp_dictoffset */
862 (initproc) Reader_init, /* tp_init */
864 PyType_GenericNew, /* tp_new */
867 static PyMethodDef methods[] = {
868 { "get_catalog", get_catalog, METH_VARARGS, get_catalog__doc__},
869 { NULL, NULL, 0, NULL } /* Sentinel */
872 #if PY_MAJOR_VERSION >= 3
873 static PyModuleDef module = {
874 PyModuleDef_HEAD_INIT,
879 NULL, NULL, NULL, NULL
883 #if PY_MAJOR_VERSION >= 3
884 static bool initialized = false;
887 #pragma GCC diagnostic push
888 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
891 #if PY_MAJOR_VERSION >= 3
901 if (PyType_Ready(&ReaderType) < 0)
902 #if PY_MAJOR_VERSION >= 3
908 #if PY_MAJOR_VERSION >= 3
909 m = PyModule_Create(&module);
914 PyStructSequence_InitType(&MonotonicType, &Monotonic_desc);
918 m = Py_InitModule3("_reader", methods, module__doc__);
923 Py_INCREF(&ReaderType);
924 #if PY_MAJOR_VERSION >= 3
925 Py_INCREF(&MonotonicType);
927 if (PyModule_AddObject(m, "_Reader", (PyObject *) &ReaderType) ||
928 #if PY_MAJOR_VERSION >= 3
929 PyModule_AddObject(m, "Monotonic", (PyObject*) &MonotonicType) ||
931 PyModule_AddIntConstant(m, "NOP", SD_JOURNAL_NOP) ||
932 PyModule_AddIntConstant(m, "APPEND", SD_JOURNAL_APPEND) ||
933 PyModule_AddIntConstant(m, "INVALIDATE", SD_JOURNAL_INVALIDATE) ||
934 PyModule_AddIntConstant(m, "LOCAL_ONLY", SD_JOURNAL_LOCAL_ONLY) ||
935 PyModule_AddIntConstant(m, "RUNTIME_ONLY", SD_JOURNAL_RUNTIME_ONLY) ||
936 PyModule_AddIntConstant(m, "SYSTEM_ONLY", SD_JOURNAL_SYSTEM_ONLY)) {
937 #if PY_MAJOR_VERSION >= 3
943 #if PY_MAJOR_VERSION >= 3
948 #pragma GCC diagnostic pop