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\n"
97 "_Reader implements the context manager protocol: the journal\n"
98 "will be closed when exiting the block.");
99 static int Reader_init(Reader *self, PyObject *args, PyObject *keywds)
104 static const char* const kwlist[] = {"flags", "path", NULL};
105 if (!PyArg_ParseTupleAndKeywords(args, keywds, "|iz", (char**) kwlist,
110 flags = SD_JOURNAL_LOCAL_ONLY;
113 PyErr_SetString(PyExc_ValueError, "cannot use both flags and path");
117 Py_BEGIN_ALLOW_THREADS
119 r = sd_journal_open_directory(&self->j, path, 0);
121 r = sd_journal_open(&self->j, flags);
124 return set_error(r, path, "Invalid flags or path");
128 PyDoc_STRVAR(Reader_fileno__doc__,
129 "fileno() -> int\n\n"
130 "Get a file descriptor to poll for changes in the journal.\n"
131 "This method invokes sd_journal_get_fd().\n"
132 "See man:sd_journal_get_fd(3).");
133 static PyObject* Reader_fileno(Reader *self, PyObject *args)
136 fd = sd_journal_get_fd(self->j);
137 set_error(fd, NULL, NULL);
140 return long_FromLong(fd);
144 PyDoc_STRVAR(Reader_reliable_fd__doc__,
145 "reliable_fd() -> bool\n\n"
146 "Returns True iff the journal can be polled reliably.\n"
147 "This method invokes sd_journal_reliable_fd().\n"
148 "See man:sd_journal_reliable_fd(3).");
149 static PyObject* Reader_reliable_fd(Reader *self, PyObject *args)
152 r = sd_journal_reliable_fd(self->j);
153 set_error(r, NULL, NULL);
156 return PyBool_FromLong(r);
160 PyDoc_STRVAR(Reader_close__doc__,
161 "close() -> None\n\n"
162 "Free resources allocated by this Reader object.\n"
163 "This method invokes sd_journal_close().\n"
164 "See man:sd_journal_close(3).");
165 static PyObject* Reader_close(Reader *self, PyObject *args)
170 sd_journal_close(self->j);
176 PyDoc_STRVAR(Reader_get_usage__doc__,
177 "get_usage() -> int\n\n"
178 "Returns the total disk space currently used by journal"
179 "files (in bytes). If `SD_JOURNAL_LOCAL_ONLY` was"
180 "passed when opening the journal this value will only reflect"
181 "the size of journal files of the local host, otherwise"
183 "This method invokes sd_journal_get_usage().\n"
184 "See man:sd_journal_get_usage(3).");
185 static PyObject* Reader_get_usage(Reader *self, PyObject *args)
190 r = sd_journal_get_usage(self->j, &bytes);
191 if (set_error(r, NULL, NULL))
194 assert_cc(sizeof(unsigned long long) == sizeof(bytes));
195 return PyLong_FromUnsignedLongLong(bytes);
199 PyDoc_STRVAR(Reader___enter____doc__,
200 "__enter__() -> self\n\n"
201 "Part of the context manager protocol.\n"
203 static PyObject* Reader___enter__(PyObject *self, PyObject *args)
212 PyDoc_STRVAR(Reader___exit____doc__,
213 "__exit__(type, value, traceback) -> None\n\n"
214 "Part of the context manager protocol.\n"
215 "Closes the journal.\n");
216 static PyObject* Reader___exit__(Reader *self, PyObject *args)
220 sd_journal_close(self->j);
226 PyDoc_STRVAR(Reader_next__doc__,
227 "next([skip]) -> bool\n\n"
228 "Go to the next log entry. Optional skip value means to go to\n"
229 "the `skip`\\-th log entry.\n"
230 "Returns False if at end of file, True otherwise.");
231 static PyObject* Reader_next(Reader *self, PyObject *args)
236 if (!PyArg_ParseTuple(args, "|L: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 return PyBool_FromLong(r);
264 PyDoc_STRVAR(Reader_get_next__doc__,
265 "get_next([skip]) -> dict\n\n"
266 "Return dictionary of the next log entry. Optional skip value will\n"
267 "return the `skip`\\-th log entry. Returns an empty dict on EOF.");
268 static PyObject* Reader_get_next(Reader *self, PyObject *args)
270 PyObject _cleanup_Py_DECREF_ *tmp = NULL;
276 tmp = Reader_next(self, args);
279 if (tmp == Py_False) /* EOF */
286 SD_JOURNAL_FOREACH_DATA(self->j, msg, msg_len) {
287 PyObject _cleanup_Py_DECREF_ *key = NULL, *value = NULL;
288 const char *delim_ptr;
290 delim_ptr = memchr(msg, '=', msg_len);
292 PyErr_SetString(PyExc_OSError,
293 "journal gave us a field without '='");
297 key = unicode_FromStringAndSize(msg, delim_ptr - (const char*) msg);
301 value = PyBytes_FromStringAndSize(
303 (const char*) msg + msg_len - (delim_ptr + 1) );
307 if (PyDict_Contains(dict, key)) {
308 PyObject *cur_value = PyDict_GetItem(dict, key);
310 if (PyList_CheckExact(cur_value)) {
311 r = PyList_Append(cur_value, value);
315 PyObject _cleanup_Py_DECREF_ *tmp_list = PyList_New(0);
319 r = PyList_Append(tmp_list, cur_value);
323 r = PyList_Append(tmp_list, value);
327 r = PyDict_SetItem(dict, key, tmp_list);
332 r = PyDict_SetItem(dict, key, value);
345 PyDoc_STRVAR(Reader_get_realtime__doc__,
346 "get_realtime() -> int\n\n"
347 "Return the realtime timestamp for the current journal entry\n"
348 "in microseconds.\n\n"
349 "Wraps sd_journal_get_realtime_usec().\n"
350 "See man:sd_journal_get_realtime_usec(3).");
351 static PyObject* Reader_get_realtime(Reader *self, PyObject *args)
359 r = sd_journal_get_realtime_usec(self->j, ×tamp);
360 if (set_error(r, NULL, NULL))
363 assert_cc(sizeof(unsigned long long) == sizeof(timestamp));
364 return PyLong_FromUnsignedLongLong(timestamp);
368 PyDoc_STRVAR(Reader_get_monotonic__doc__,
369 "get_monotonic() -> (timestamp, bootid)\n\n"
370 "Return the monotonic timestamp for the current journal entry\n"
371 "as a tuple of time in microseconds and bootid.\n\n"
372 "Wraps sd_journal_get_monotonic_usec().\n"
373 "See man:sd_journal_get_monotonic_usec(3).");
374 static PyObject* Reader_get_monotonic(Reader *self, PyObject *args)
378 PyObject *monotonic, *bootid, *tuple;
384 r = sd_journal_get_monotonic_usec(self->j, ×tamp, &id);
385 if (set_error(r, NULL, NULL))
388 assert_cc(sizeof(unsigned long long) == sizeof(timestamp));
389 monotonic = PyLong_FromUnsignedLongLong(timestamp);
390 bootid = PyBytes_FromStringAndSize((const char*) &id.bytes, sizeof(id.bytes));
391 #if PY_MAJOR_VERSION >= 3
392 tuple = PyStructSequence_New(&MonotonicType);
394 tuple = PyTuple_New(2);
396 if (!monotonic || !bootid || !tuple) {
397 Py_XDECREF(monotonic);
403 #if PY_MAJOR_VERSION >= 3
404 PyStructSequence_SET_ITEM(tuple, 0, monotonic);
405 PyStructSequence_SET_ITEM(tuple, 1, bootid);
407 PyTuple_SET_ITEM(tuple, 0, monotonic);
408 PyTuple_SET_ITEM(tuple, 1, bootid);
415 PyDoc_STRVAR(Reader_get_previous__doc__,
416 "get_previous([skip]) -> dict\n\n"
417 "Return dictionary of the previous log entry. Optional skip value\n"
418 "will return the -`skip`\\-th log entry. Equivalent to get_next(-skip).");
419 static PyObject* Reader_get_previous(Reader *self, PyObject *args)
422 if (!PyArg_ParseTuple(args, "|L:get_previous", &skip))
425 return PyObject_CallMethod((PyObject *)self, (char*) "get_next",
430 PyDoc_STRVAR(Reader_add_match__doc__,
431 "add_match(match) -> None\n\n"
432 "Add a match to filter journal log entries. All matches of different\n"
433 "fields are combined with logical AND, and matches of the same field\n"
434 "are automatically combined with logical OR.\n"
435 "Match is a string of the form \"FIELD=value\".");
436 static PyObject* Reader_add_match(Reader *self, PyObject *args, PyObject *keywds)
440 if (!PyArg_ParseTuple(args, "s#:add_match", &match, &match_len))
443 r = sd_journal_add_match(self->j, match, match_len);
444 set_error(r, NULL, "Invalid match");
452 PyDoc_STRVAR(Reader_add_disjunction__doc__,
453 "add_disjunction() -> None\n\n"
454 "Inserts a logical OR between matches added before and afterwards.");
455 static PyObject* Reader_add_disjunction(Reader *self, PyObject *args)
458 r = sd_journal_add_disjunction(self->j);
459 set_error(r, NULL, NULL);
466 PyDoc_STRVAR(Reader_flush_matches__doc__,
467 "flush_matches() -> None\n\n"
468 "Clear all current match filters.");
469 static PyObject* Reader_flush_matches(Reader *self, PyObject *args)
471 sd_journal_flush_matches(self->j);
476 PyDoc_STRVAR(Reader_seek_head__doc__,
477 "seek_head() -> None\n\n"
478 "Jump to the beginning of the journal.\n"
479 "This method invokes sd_journal_seek_head().\n"
480 "See man:sd_journal_seek_head(3).");
481 static PyObject* Reader_seek_head(Reader *self, PyObject *args)
484 Py_BEGIN_ALLOW_THREADS
485 r = sd_journal_seek_head(self->j);
487 if (set_error(r, NULL, NULL))
493 PyDoc_STRVAR(Reader_seek_tail__doc__,
494 "seek_tail() -> None\n\n"
495 "Jump to the end of the journal.\n"
496 "This method invokes sd_journal_seek_tail().\n"
497 "See man:sd_journal_seek_tail(3).");
498 static PyObject* Reader_seek_tail(Reader *self, PyObject *args)
501 Py_BEGIN_ALLOW_THREADS
502 r = sd_journal_seek_tail(self->j);
504 if (set_error(r, NULL, NULL))
510 PyDoc_STRVAR(Reader_seek_realtime__doc__,
511 "seek_realtime(realtime) -> None\n\n"
512 "Seek to nearest matching journal entry to `realtime`. Argument\n"
513 "`realtime` in specified in seconds.");
514 static PyObject* Reader_seek_realtime(Reader *self, PyObject *args)
519 if (!PyArg_ParseTuple(args, "K:seek_realtime", ×tamp))
522 Py_BEGIN_ALLOW_THREADS
523 r = sd_journal_seek_realtime_usec(self->j, timestamp);
525 if (set_error(r, NULL, NULL))
531 PyDoc_STRVAR(Reader_seek_monotonic__doc__,
532 "seek_monotonic(monotonic[, bootid]) -> None\n\n"
533 "Seek to nearest matching journal entry to `monotonic`. Argument\n"
534 "`monotonic` is an timestamp from boot in microseconds.\n"
535 "Argument `bootid` is a string representing which boot the\n"
536 "monotonic time is reference to. Defaults to current bootid.");
537 static PyObject* Reader_seek_monotonic(Reader *self, PyObject *args)
544 if (!PyArg_ParseTuple(args, "K|z:seek_monotonic", ×tamp, &bootid))
548 r = sd_id128_from_string(bootid, &id);
549 if (set_error(r, NULL, "Invalid bootid"))
552 Py_BEGIN_ALLOW_THREADS
553 r = sd_id128_get_boot(&id);
555 if (set_error(r, NULL, NULL))
559 Py_BEGIN_ALLOW_THREADS
560 r = sd_journal_seek_monotonic_usec(self->j, id, timestamp);
562 if (set_error(r, NULL, NULL))
569 PyDoc_STRVAR(Reader_wait__doc__,
570 "wait([timeout]) -> state change (integer)\n\n"
571 "Wait for a change in the journal. Argument `timeout` specifies\n"
572 "the maximum number of microseconds to wait before returning\n"
573 "regardless of wheter the journal has changed. If `timeout` is -1,\n"
574 "then block forever.\n\n"
575 "Will return constants: NOP if no change; APPEND if new\n"
576 "entries have been added to the end of the journal; and\n"
577 "INVALIDATE if journal files have been added or removed.");
578 static PyObject* Reader_wait(Reader *self, PyObject *args)
583 if (!PyArg_ParseTuple(args, "|L:wait", &timeout))
586 Py_BEGIN_ALLOW_THREADS
587 r = sd_journal_wait(self->j, timeout);
589 if (set_error(r, NULL, NULL) < 0)
592 return long_FromLong(r);
596 PyDoc_STRVAR(Reader_seek_cursor__doc__,
597 "seek_cursor(cursor) -> None\n\n"
598 "Seek to journal entry by given unique reference `cursor`.");
599 static PyObject* Reader_seek_cursor(Reader *self, PyObject *args)
604 if (!PyArg_ParseTuple(args, "s:seek_cursor", &cursor))
607 Py_BEGIN_ALLOW_THREADS
608 r = sd_journal_seek_cursor(self->j, cursor);
610 if (set_error(r, NULL, "Invalid cursor"))
616 PyDoc_STRVAR(Reader_get_cursor__doc__,
617 "get_cursor() -> str\n\n"
618 "Return a cursor string for the current journal entry.\n\n"
619 "Wraps sd_journal_get_cursor(). See man:sd_journal_get_cursor(3).");
620 static PyObject* Reader_get_cursor(Reader *self, PyObject *args)
622 char _cleanup_free_ *cursor = NULL;
628 r = sd_journal_get_cursor(self->j, &cursor);
629 if (set_error(r, NULL, NULL))
632 return unicode_FromString(cursor);
636 PyDoc_STRVAR(Reader_test_cursor__doc__,
637 "test_cursor(str) -> bool\n\n"
638 "Test whether the cursor string matches current journal entry.\n\n"
639 "Wraps sd_journal_test_cursor(). See man:sd_journal_test_cursor(3).");
640 static PyObject* Reader_test_cursor(Reader *self, PyObject *args)
648 if (!PyArg_ParseTuple(args, "s:test_cursor", &cursor))
651 r = sd_journal_test_cursor(self->j, cursor);
652 set_error(r, NULL, NULL);
656 return PyBool_FromLong(r);
660 static PyObject* Reader_iter(PyObject *self)
666 static PyObject* Reader_iternext(PyObject *self)
669 Py_ssize_t dict_size;
671 dict = PyObject_CallMethod(self, (char*) "get_next", (char*) "");
672 if (PyErr_Occurred())
674 dict_size = PyDict_Size(dict);
675 if ((int64_t) dict_size > 0LL) {
679 PyErr_SetNone(PyExc_StopIteration);
685 PyDoc_STRVAR(Reader_query_unique__doc__,
686 "query_unique(field) -> a set of values\n\n"
687 "Return a set of unique values appearing in journal for the\n"
688 "given `field`. Note this does not respect any journal matches.");
689 static PyObject* Reader_query_unique(Reader *self, PyObject *args)
695 PyObject *value_set, *key, *value;
697 if (!PyArg_ParseTuple(args, "s:query_unique", &query))
700 Py_BEGIN_ALLOW_THREADS
701 r = sd_journal_query_unique(self->j, query);
703 if (set_error(r, NULL, "Invalid field name"))
706 value_set = PySet_New(0);
707 key = unicode_FromString(query);
709 SD_JOURNAL_FOREACH_UNIQUE(self->j, uniq, uniq_len) {
710 const char *delim_ptr;
712 delim_ptr = memchr(uniq, '=', uniq_len);
713 value = PyBytes_FromStringAndSize(
715 (const char*) uniq + uniq_len - (delim_ptr + 1));
716 PySet_Add(value_set, value);
724 PyDoc_STRVAR(Reader_get_catalog__doc__,
725 "get_catalog() -> str\n\n"
726 "Retrieve a message catalog entry for the current journal entry.\n"
727 "Wraps man:sd_journal_get_catalog(3).");
728 static PyObject* Reader_get_catalog(Reader *self, PyObject *args)
731 char _cleanup_free_ *msg = NULL;
736 Py_BEGIN_ALLOW_THREADS
737 r = sd_journal_get_catalog(self->j, &msg);
739 if (set_error(r, NULL, NULL))
742 return unicode_FromString(msg);
746 PyDoc_STRVAR(get_catalog__doc__,
747 "get_catalog(id128) -> str\n\n"
748 "Retrieve a message catalog entry for the given id.\n"
749 "Wraps man:sd_journal_get_catalog_for_message_id(3).");
750 static PyObject* get_catalog(PyObject *self, PyObject *args)
755 char _cleanup_free_ *msg = NULL;
760 if (!PyArg_ParseTuple(args, "z:get_catalog", &id_))
763 r = sd_id128_from_string(id_, &id);
764 if (set_error(r, NULL, "Invalid id128"))
767 Py_BEGIN_ALLOW_THREADS
768 r = sd_journal_get_catalog_for_message_id(id, &msg);
770 if (set_error(r, NULL, NULL))
773 return unicode_FromString(msg);
777 PyDoc_STRVAR(data_threshold__doc__,
778 "Threshold for field size truncation in bytes.\n\n"
779 "Fields longer than this will be truncated to the threshold size.\n"
780 "Defaults to 64Kb.");
782 static PyObject* Reader_get_data_threshold(Reader *self, void *closure)
787 r = sd_journal_get_data_threshold(self->j, &cvalue);
788 if (set_error(r, NULL, NULL))
791 return long_FromSize_t(cvalue);
794 static int Reader_set_data_threshold(Reader *self, PyObject *value, void *closure)
798 PyErr_SetString(PyExc_AttributeError, "Cannot delete data threshold");
801 if (!long_Check(value)){
802 PyErr_SetString(PyExc_TypeError, "Data threshold must be an int");
805 r = sd_journal_set_data_threshold(self->j, (size_t) long_AsLong(value));
806 return set_error(r, NULL, NULL);
810 PyDoc_STRVAR(closed__doc__,
811 "True iff journal is closed");
812 static PyObject* Reader_get_closed(Reader *self, void *closure)
814 return PyBool_FromLong(self->j == NULL);
818 static PyGetSetDef Reader_getsetters[] = {
819 {(char*) "data_threshold",
820 (getter) Reader_get_data_threshold,
821 (setter) Reader_set_data_threshold,
822 (char*) data_threshold__doc__,
825 (getter) Reader_get_closed,
827 (char*) closed__doc__,
832 static PyMethodDef Reader_methods[] = {
833 {"fileno", (PyCFunction) Reader_fileno, METH_NOARGS, Reader_fileno__doc__},
834 {"reliable_fd", (PyCFunction) Reader_reliable_fd, METH_NOARGS, Reader_reliable_fd__doc__},
835 {"close", (PyCFunction) Reader_close, METH_NOARGS, Reader_close__doc__},
836 {"get_usage", (PyCFunction) Reader_get_usage, METH_NOARGS, Reader_get_usage__doc__},
837 {"__enter__", (PyCFunction) Reader___enter__, METH_NOARGS, Reader___enter____doc__},
838 {"__exit__", (PyCFunction) Reader___exit__, METH_VARARGS, Reader___exit____doc__},
839 {"next", (PyCFunction) Reader_next, METH_VARARGS, Reader_next__doc__},
840 {"get_next", (PyCFunction) Reader_get_next, METH_VARARGS, Reader_get_next__doc__},
841 {"get_previous", (PyCFunction) Reader_get_previous, METH_VARARGS, Reader_get_previous__doc__},
842 {"get_realtime", (PyCFunction) Reader_get_realtime, METH_NOARGS, Reader_get_realtime__doc__},
843 {"get_monotonic", (PyCFunction) Reader_get_monotonic, METH_NOARGS, Reader_get_monotonic__doc__},
844 {"add_match", (PyCFunction) Reader_add_match, METH_VARARGS|METH_KEYWORDS, Reader_add_match__doc__},
845 {"add_disjunction", (PyCFunction) Reader_add_disjunction, METH_NOARGS, Reader_add_disjunction__doc__},
846 {"flush_matches", (PyCFunction) Reader_flush_matches, METH_NOARGS, Reader_flush_matches__doc__},
847 {"seek_head", (PyCFunction) Reader_seek_head, METH_NOARGS, Reader_seek_head__doc__},
848 {"seek_tail", (PyCFunction) Reader_seek_tail, METH_NOARGS, Reader_seek_tail__doc__},
849 {"seek_realtime", (PyCFunction) Reader_seek_realtime, METH_VARARGS, Reader_seek_realtime__doc__},
850 {"seek_monotonic", (PyCFunction) Reader_seek_monotonic, METH_VARARGS, Reader_seek_monotonic__doc__},
851 {"wait", (PyCFunction) Reader_wait, METH_VARARGS, Reader_wait__doc__},
852 {"seek_cursor", (PyCFunction) Reader_seek_cursor, METH_VARARGS, Reader_seek_cursor__doc__},
853 {"get_cursor", (PyCFunction) Reader_get_cursor, METH_NOARGS, Reader_get_cursor__doc__},
854 {"test_cursor", (PyCFunction) Reader_test_cursor, METH_VARARGS, Reader_test_cursor__doc__},
855 {"query_unique", (PyCFunction) Reader_query_unique, METH_VARARGS, Reader_query_unique__doc__},
856 {"get_catalog", (PyCFunction) Reader_get_catalog, METH_NOARGS, Reader_get_catalog__doc__},
857 {NULL} /* Sentinel */
860 static PyTypeObject ReaderType = {
861 PyVarObject_HEAD_INIT(NULL, 0)
862 "_reader._Reader", /*tp_name*/
863 sizeof(Reader), /*tp_basicsize*/
865 (destructor)Reader_dealloc, /*tp_dealloc*/
872 0, /*tp_as_sequence*/
880 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
881 Reader__doc__, /* tp_doc */
884 0, /* tp_richcompare */
885 0, /* tp_weaklistoffset */
886 Reader_iter, /* tp_iter */
887 Reader_iternext, /* tp_iternext */
888 Reader_methods, /* tp_methods */
890 Reader_getsetters, /* tp_getset */
893 0, /* tp_descr_get */
894 0, /* tp_descr_set */
895 0, /* tp_dictoffset */
896 (initproc) Reader_init, /* tp_init */
898 PyType_GenericNew, /* tp_new */
901 static PyMethodDef methods[] = {
902 { "get_catalog", get_catalog, METH_VARARGS, get_catalog__doc__},
903 { NULL, NULL, 0, NULL } /* Sentinel */
906 #if PY_MAJOR_VERSION >= 3
907 static PyModuleDef module = {
908 PyModuleDef_HEAD_INIT,
913 NULL, NULL, NULL, NULL
917 #if PY_MAJOR_VERSION >= 3
918 static bool initialized = false;
921 #pragma GCC diagnostic push
922 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
925 #if PY_MAJOR_VERSION >= 3
935 if (PyType_Ready(&ReaderType) < 0)
936 #if PY_MAJOR_VERSION >= 3
942 #if PY_MAJOR_VERSION >= 3
943 m = PyModule_Create(&module);
948 PyStructSequence_InitType(&MonotonicType, &Monotonic_desc);
952 m = Py_InitModule3("_reader", methods, module__doc__);
957 Py_INCREF(&ReaderType);
958 #if PY_MAJOR_VERSION >= 3
959 Py_INCREF(&MonotonicType);
961 if (PyModule_AddObject(m, "_Reader", (PyObject *) &ReaderType) ||
962 #if PY_MAJOR_VERSION >= 3
963 PyModule_AddObject(m, "Monotonic", (PyObject*) &MonotonicType) ||
965 PyModule_AddIntConstant(m, "NOP", SD_JOURNAL_NOP) ||
966 PyModule_AddIntConstant(m, "APPEND", SD_JOURNAL_APPEND) ||
967 PyModule_AddIntConstant(m, "INVALIDATE", SD_JOURNAL_INVALIDATE) ||
968 PyModule_AddIntConstant(m, "LOCAL_ONLY", SD_JOURNAL_LOCAL_ONLY) ||
969 PyModule_AddIntConstant(m, "RUNTIME_ONLY", SD_JOURNAL_RUNTIME_ONLY) ||
970 PyModule_AddIntConstant(m, "SYSTEM_ONLY", SD_JOURNAL_SYSTEM_ONLY)) {
971 #if PY_MAJOR_VERSION >= 3
977 #if PY_MAJOR_VERSION >= 3
982 #pragma GCC diagnostic pop