]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/python-systemd/_reader.c
systemd-python: fix gcc warning
[thirdparty/systemd.git] / src / python-systemd / _reader.c
CommitLineData
33ed3769 1/*-*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*-*/
d2dd0265
SH
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Steven Hiscocks, Zbigniew Jędrzejewski-Szmek
7
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.
12
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.
17
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/>.
20***/
c4e9b5b5
SH
21
22#include <Python.h>
23#include <structmember.h>
24#include <datetime.h>
76a80d93 25#include <time.h>
6a6633a1
ZJS
26#include <stdio.h>
27
28#include <systemd/sd-journal.h>
29
30#include "pyutil.h"
31#include "macro.h"
32#include "util.h"
affba8e9 33#include "strv.h"
5afbe712 34#include "build.h"
c4e9b5b5
SH
35
36typedef struct {
37 PyObject_HEAD
38 sd_journal *j;
7f41820b
ZJS
39} Reader;
40static PyTypeObject ReaderType;
c4e9b5b5 41
2b01924c
ZJS
42
43PyDoc_STRVAR(module__doc__,
44 "Class to reads the systemd journal similar to journalctl.");
45
46
86e3d32a
ZJS
47#if PY_MAJOR_VERSION >= 3
48static PyTypeObject MonotonicType;
49
50PyDoc_STRVAR(MonotonicType__doc__,
51 "A tuple of (timestamp, bootid) for holding monotonic timestamps");
52
53static PyStructSequence_Field MonotonicType_fields[] = {
54 {(char*) "timestamp", (char*) "Time"},
55 {(char*) "bootid", (char*) "Unique identifier of the boot"},
b92bea5d 56 {} /* Sentinel */
86e3d32a
ZJS
57};
58
59static PyStructSequence_Desc Monotonic_desc = {
60 (char*) "journal.Monotonic",
61 MonotonicType__doc__,
62 MonotonicType_fields,
63 2,
64};
65#endif
66
affba8e9
ZJS
67static int strv_converter(PyObject* obj, void *_result) {
68 char ***result = _result;
69 Py_ssize_t i, len;
70
71 assert(result);
72
73 if (!obj)
74 goto cleanup;
75
76 if (!PySequence_Check(obj))
77 return 0;
78
79 len = PySequence_Length(obj);
80 *result = new0(char*, len + 1);
81
82 for (i = 0; i < len; i++) {
83 PyObject *item;
84#if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
85 int r;
86 PyObject *bytes;
87#endif
88 char *s, *s2;
89
90 item = PySequence_ITEM(obj, i);
91#if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
92 r = PyUnicode_FSConverter(item, &bytes);
93 if (r == 0)
94 goto cleanup;
95
96 s = PyBytes_AsString(bytes);
97#else
98 s = PyString_AsString(item);
99#endif
100 if (!s)
101 goto cleanup;
102
103 s2 = strdup(s);
104 if (!s2)
105 log_oom();
106
107 (*result)[i] = s2;
108 }
109
110 return 1;
111
112cleanup:
113 strv_free(*result);
114 *result = NULL;
115
116 return 0;
117}
ab3a162c 118
7f41820b 119static void Reader_dealloc(Reader* self)
c4e9b5b5
SH
120{
121 sd_journal_close(self->j);
c4e9b5b5
SH
122 Py_TYPE(self)->tp_free((PyObject*)self);
123}
124
7f41820b 125PyDoc_STRVAR(Reader__doc__,
affba8e9 126 "_Reader([flags | path | files]) -> ...\n\n"
5e8ba1a4 127 "_Reader allows filtering and retrieval of Journal entries.\n"
0eff0f3b
ZJS
128 "Note: this is a low-level interface, and probably not what you\n"
129 "want, use systemd.journal.Reader instead.\n\n"
33ed3769
ZJS
130 "Argument `flags` sets open flags of the journal, which can be one\n"
131 "of, or ORed combination of constants: LOCAL_ONLY (default) opens\n"
132 "journal on local machine only; RUNTIME_ONLY opens only\n"
affba8e9
ZJS
133 "volatile journal files; and SYSTEM opens journal files of\n"
134 "system services and the kernel, and CURRENT_USER opens files\n"
135 "of the current user.\n\n"
136 "Argument `path` is the directory of journal files.\n"
137 "Argument `files` is a list of files. Note that\n"
138 "`flags`, `path`, and `files` are exclusive.\n\n"
5e8ba1a4
ZJS
139 "_Reader implements the context manager protocol: the journal\n"
140 "will be closed when exiting the block.");
7f41820b 141static int Reader_init(Reader *self, PyObject *args, PyObject *keywds)
c4e9b5b5 142{
0eff0f3b 143 int flags = 0, r;
118bf4ba 144 char *path = NULL;
affba8e9 145 char **files = NULL;
c4e9b5b5 146
affba8e9
ZJS
147 static const char* const kwlist[] = {"flags", "path", "files", NULL};
148 if (!PyArg_ParseTupleAndKeywords(args, keywds, "|izO&", (char**) kwlist,
149 &flags, &path, strv_converter, &files))
0eff0f3b
ZJS
150 return -1;
151
affba8e9
ZJS
152 if (!!flags + !!path + !!files > 1) {
153 PyErr_SetString(PyExc_ValueError, "cannot use more than one of flags, path, and files");
154 return -1;
155 }
156
0eff0f3b
ZJS
157 if (!flags)
158 flags = SD_JOURNAL_LOCAL_ONLY;
c4e9b5b5 159
71766afa 160 Py_BEGIN_ALLOW_THREADS
0d92ee93 161 if (path)
c4e9b5b5 162 r = sd_journal_open_directory(&self->j, path, 0);
affba8e9
ZJS
163 else if (files)
164 r = sd_journal_open_files(&self->j, (const char**) files, 0);
0d92ee93 165 else
c4e9b5b5 166 r = sd_journal_open(&self->j, flags);
71766afa 167 Py_END_ALLOW_THREADS
c4e9b5b5 168
e82e4f45 169 return set_error(r, path, "Invalid flags or path");
c4e9b5b5
SH
170}
171
ab3a162c 172
f2e82cd5
ZJS
173PyDoc_STRVAR(Reader_fileno__doc__,
174 "fileno() -> int\n\n"
175 "Get a file descriptor to poll for changes in the journal.\n"
176 "This method invokes sd_journal_get_fd().\n"
177 "See man:sd_journal_get_fd(3).");
178static PyObject* Reader_fileno(Reader *self, PyObject *args)
179{
76a80d93 180 int fd = sd_journal_get_fd(self->j);
50a279f8
ZJS
181 set_error(fd, NULL, NULL);
182 if (fd < 0)
f2e82cd5 183 return NULL;
50a279f8 184 return long_FromLong(fd);
f2e82cd5
ZJS
185}
186
ab3a162c 187
f2e82cd5
ZJS
188PyDoc_STRVAR(Reader_reliable_fd__doc__,
189 "reliable_fd() -> bool\n\n"
190 "Returns True iff the journal can be polled reliably.\n"
191 "This method invokes sd_journal_reliable_fd().\n"
192 "See man:sd_journal_reliable_fd(3).");
193static PyObject* Reader_reliable_fd(Reader *self, PyObject *args)
194{
76a80d93 195 int r = sd_journal_reliable_fd(self->j);
f2e82cd5
ZJS
196 set_error(r, NULL, NULL);
197 if (r < 0)
198 return NULL;
199 return PyBool_FromLong(r);
200}
201
ab3a162c 202
76a80d93
ZJS
203PyDoc_STRVAR(Reader_get_events__doc__,
204 "get_events() -> int\n\n"
205 "Returns a mask of poll() events to wait for on the file\n"
206 "descriptor returned by .fileno().\n\n"
207 "See man:sd_journal_get_events(3) for further discussion.");
208static PyObject* Reader_get_events(Reader *self, PyObject *args)
209{
210 int r = sd_journal_get_events(self->j);
211 set_error(r, NULL, NULL);
212 if (r < 0)
213 return NULL;
214 return long_FromLong(r);
215}
216
217
218PyDoc_STRVAR(Reader_get_timeout__doc__,
219 "get_timeout() -> int or None\n\n"
220 "Returns a timeout value for usage in poll(), the time since the\n"
221 "epoch of clock_gettime(2) in microseconds, or None if no timeout\n"
222 "is necessary.\n\n"
7ecec470 223 "The return value must be converted to a relative timeout in\n"
76a80d93
ZJS
224 "milliseconds if it is to be used as an argument for poll().\n"
225 "See man:sd_journal_get_timeout(3) for further discussion.");
226static PyObject* Reader_get_timeout(Reader *self, PyObject *args)
227{
228 int r;
229 uint64_t t;
230
231 r = sd_journal_get_timeout(self->j, &t);
232 set_error(r, NULL, NULL);
233 if (r < 0)
234 return NULL;
235
236 if (t == (uint64_t) -1)
237 Py_RETURN_NONE;
238
239 assert_cc(sizeof(unsigned long long) == sizeof(t));
240 return PyLong_FromUnsignedLongLong(t);
241}
242
243
244PyDoc_STRVAR(Reader_get_timeout_ms__doc__,
245 "get_timeout_ms() -> int\n\n"
246 "Returns a timeout value suitable for usage in poll(), the value\n"
247 "returned by .get_timeout() converted to relative ms, or -1 if\n"
248 "no timeout is necessary.");
249static PyObject* Reader_get_timeout_ms(Reader *self, PyObject *args)
250{
251 int r;
252 uint64_t t;
253
254 r = sd_journal_get_timeout(self->j, &t);
255 set_error(r, NULL, NULL);
256 if (r < 0)
257 return NULL;
258
539e0a4d 259 return absolute_timeout(t);
76a80d93
ZJS
260}
261
262
f2e82cd5 263PyDoc_STRVAR(Reader_close__doc__,
516424a4 264 "close() -> None\n\n"
f2e82cd5
ZJS
265 "Free resources allocated by this Reader object.\n"
266 "This method invokes sd_journal_close().\n"
267 "See man:sd_journal_close(3).");
268static PyObject* Reader_close(Reader *self, PyObject *args)
269{
85b2850b
ZJS
270 assert(self);
271 assert(!args);
272
273 sd_journal_close(self->j);
274 self->j = NULL;
275 Py_RETURN_NONE;
276}
277
ab3a162c 278
50a279f8
ZJS
279PyDoc_STRVAR(Reader_get_usage__doc__,
280 "get_usage() -> int\n\n"
ee6349a7
ZJS
281 "Returns the total disk space currently used by journal\n"
282 "files (in bytes). If `SD_JOURNAL_LOCAL_ONLY` was\n"
283 "passed when opening the journal this value will only reflect\n"
284 "the size of journal files of the local host, otherwise\n"
50a279f8
ZJS
285 "of all hosts.\n\n"
286 "This method invokes sd_journal_get_usage().\n"
287 "See man:sd_journal_get_usage(3).");
288static PyObject* Reader_get_usage(Reader *self, PyObject *args)
289{
290 int r;
291 uint64_t bytes;
292
293 r = sd_journal_get_usage(self->j, &bytes);
294 if (set_error(r, NULL, NULL))
295 return NULL;
296
297 assert_cc(sizeof(unsigned long long) == sizeof(bytes));
298 return PyLong_FromUnsignedLongLong(bytes);
299}
300
301
85b2850b
ZJS
302PyDoc_STRVAR(Reader___enter____doc__,
303 "__enter__() -> self\n\n"
304 "Part of the context manager protocol.\n"
305 "Returns self.\n");
306static PyObject* Reader___enter__(PyObject *self, PyObject *args)
307{
308 assert(self);
309 assert(!args);
310
311 Py_INCREF(self);
312 return self;
313}
314
315PyDoc_STRVAR(Reader___exit____doc__,
316 "__exit__(type, value, traceback) -> None\n\n"
317 "Part of the context manager protocol.\n"
318 "Closes the journal.\n");
319static PyObject* Reader___exit__(Reader *self, PyObject *args)
320{
7ecec470 321 return Reader_close(self, args);
f2e82cd5
ZJS
322}
323
ab3a162c 324
5e8ba1a4
ZJS
325PyDoc_STRVAR(Reader_next__doc__,
326 "next([skip]) -> bool\n\n"
327 "Go to the next log entry. Optional skip value means to go to\n"
328 "the `skip`\\-th log entry.\n"
329 "Returns False if at end of file, True otherwise.");
330static PyObject* Reader_next(Reader *self, PyObject *args)
c4e9b5b5 331{
6a6633a1
ZJS
332 int64_t skip = 1LL;
333 int r;
0d92ee93 334
5e8ba1a4 335 if (!PyArg_ParseTuple(args, "|L:next", &skip))
c4e9b5b5
SH
336 return NULL;
337
71766afa 338 if (skip == 0LL) {
0d92ee93 339 PyErr_SetString(PyExc_ValueError, "skip must be nonzero");
71766afa
SH
340 return NULL;
341 }
342
71766afa 343 Py_BEGIN_ALLOW_THREADS
0d92ee93 344 if (skip == 1LL)
c4e9b5b5 345 r = sd_journal_next(self->j);
0d92ee93 346 else if (skip == -1LL)
c4e9b5b5 347 r = sd_journal_previous(self->j);
0d92ee93 348 else if (skip > 1LL)
c4e9b5b5 349 r = sd_journal_next_skip(self->j, skip);
0d92ee93 350 else if (skip < -1LL)
c4e9b5b5 351 r = sd_journal_previous_skip(self->j, -skip);
6a6633a1
ZJS
352 else
353 assert_not_reached("should not be here");
71766afa 354 Py_END_ALLOW_THREADS
c4e9b5b5 355
e82e4f45
ZJS
356 set_error(r, NULL, NULL);
357 if (r < 0)
c4e9b5b5 358 return NULL;
5e8ba1a4
ZJS
359 return PyBool_FromLong(r);
360}
361
6a58bf41
SH
362PyDoc_STRVAR(Reader_previous__doc__,
363 "previous([skip]) -> bool\n\n"
364 "Go to the previous log entry. Optional skip value means to \n"
365 "go to the `skip`\\-th previous log entry.\n"
366 "Returns False if at start of file, True otherwise.");
367static PyObject* Reader_previous(Reader *self, PyObject *args)
368{
369 int64_t skip = 1LL;
370 if (!PyArg_ParseTuple(args, "|L:previous", &skip))
371 return NULL;
372
373 return PyObject_CallMethod((PyObject *)self, (char*) "_next",
374 (char*) "L", -skip);
375}
376
5e8ba1a4 377
811de196
ZJS
378static int extract(const char* msg, size_t msg_len,
379 PyObject **key, PyObject **value) {
380 PyObject *k = NULL, *v;
381 const char *delim_ptr;
382
383 delim_ptr = memchr(msg, '=', msg_len);
384 if (!delim_ptr) {
385 PyErr_SetString(PyExc_OSError,
386 "journal gave us a field without '='");
387 return -1;
388 }
389
390 if (key) {
391 k = unicode_FromStringAndSize(msg, delim_ptr - (const char*) msg);
392 if (!k)
393 return -1;
394 }
395
396 if (value) {
397 v = PyBytes_FromStringAndSize(delim_ptr + 1,
398 (const char*) msg + msg_len - (delim_ptr + 1));
399 if (!v) {
400 Py_XDECREF(k);
401 return -1;
402 }
403
404 *value = v;
405 }
406
407 if (key)
408 *key = k;
409
410 return 0;
411}
412
413PyDoc_STRVAR(Reader_get__doc__,
414 "get(str) -> str\n\n"
415 "Return data associated with this key in current log entry.\n"
416 "Throws KeyError is the data is not available.");
417static PyObject* Reader_get(Reader *self, PyObject *args)
418{
419 const char* field;
420 const void* msg;
421 size_t msg_len;
422 PyObject *value;
423 int r;
424
425 assert(self);
426 assert(args);
427
428 if (!PyArg_ParseTuple(args, "s:get", &field))
429 return NULL;
430
431 r = sd_journal_get_data(self->j, field, &msg, &msg_len);
432 if (r == -ENOENT) {
433 PyErr_SetString(PyExc_KeyError, field);
434 return NULL;
435 } else if (set_error(r, NULL, "field name is not valid"))
436 return NULL;
437
438 r = extract(msg, msg_len, NULL, &value);
439 if (r < 0)
440 return NULL;
441 return value;
442}
443
444
6a58bf41
SH
445PyDoc_STRVAR(Reader_get_all__doc__,
446 "_get_all() -> dict\n\n"
447 "Return dictionary of the current log entry.");
448static PyObject* Reader_get_all(Reader *self, PyObject *args)
5e8ba1a4 449{
5e8ba1a4
ZJS
450 PyObject *dict;
451 const void *msg;
452 size_t msg_len;
453 int r;
454
c4e9b5b5 455 dict = PyDict_New();
6a6633a1
ZJS
456 if (!dict)
457 return NULL;
c4e9b5b5 458
c4e9b5b5 459 SD_JOURNAL_FOREACH_DATA(self->j, msg, msg_len) {
7fd1b19b 460 _cleanup_Py_DECREF_ PyObject *key = NULL, *value = NULL;
6a6633a1 461
811de196
ZJS
462 r = extract(msg, msg_len, &key, &value);
463 if (r < 0)
6a6633a1
ZJS
464 goto error;
465
c4e9b5b5 466 if (PyDict_Contains(dict, key)) {
6a6633a1
ZJS
467 PyObject *cur_value = PyDict_GetItem(dict, key);
468
3aa8f086 469 if (PyList_CheckExact(cur_value)) {
6a6633a1
ZJS
470 r = PyList_Append(cur_value, value);
471 if (r < 0)
472 goto error;
473 } else {
7fd1b19b 474 _cleanup_Py_DECREF_ PyObject *tmp_list = PyList_New(0);
6a6633a1
ZJS
475 if (!tmp_list)
476 goto error;
477
478 r = PyList_Append(tmp_list, cur_value);
479 if (r < 0)
480 goto error;
481
482 r = PyList_Append(tmp_list, value);
483 if (r < 0)
484 goto error;
485
684ecf30 486 r = PyDict_SetItem(dict, key, tmp_list);
6a6633a1
ZJS
487 if (r < 0)
488 goto error;
c4e9b5b5 489 }
6a6633a1
ZJS
490 } else {
491 r = PyDict_SetItem(dict, key, value);
492 if (r < 0)
493 goto error;
c4e9b5b5 494 }
c4e9b5b5
SH
495 }
496
5e8ba1a4 497 return dict;
811de196 498
5e8ba1a4
ZJS
499error:
500 Py_DECREF(dict);
501 return NULL;
502}
6a6633a1 503
6a6633a1 504
5e8ba1a4
ZJS
505PyDoc_STRVAR(Reader_get_realtime__doc__,
506 "get_realtime() -> int\n\n"
507 "Return the realtime timestamp for the current journal entry\n"
508 "in microseconds.\n\n"
509 "Wraps sd_journal_get_realtime_usec().\n"
510 "See man:sd_journal_get_realtime_usec(3).");
511static PyObject* Reader_get_realtime(Reader *self, PyObject *args)
512{
513 uint64_t timestamp;
514 int r;
6a6633a1 515
5e8ba1a4
ZJS
516 assert(self);
517 assert(!args);
6a6633a1 518
5e8ba1a4
ZJS
519 r = sd_journal_get_realtime_usec(self->j, &timestamp);
520 if (set_error(r, NULL, NULL))
521 return NULL;
c4e9b5b5 522
5e8ba1a4
ZJS
523 assert_cc(sizeof(unsigned long long) == sizeof(timestamp));
524 return PyLong_FromUnsignedLongLong(timestamp);
525}
6a6633a1 526
6a6633a1 527
5e8ba1a4
ZJS
528PyDoc_STRVAR(Reader_get_monotonic__doc__,
529 "get_monotonic() -> (timestamp, bootid)\n\n"
530 "Return the monotonic timestamp for the current journal entry\n"
531 "as a tuple of time in microseconds and bootid.\n\n"
532 "Wraps sd_journal_get_monotonic_usec().\n"
533 "See man:sd_journal_get_monotonic_usec(3).");
534static PyObject* Reader_get_monotonic(Reader *self, PyObject *args)
535{
536 uint64_t timestamp;
537 sd_id128_t id;
538 PyObject *monotonic, *bootid, *tuple;
539 int r;
540
541 assert(self);
542 assert(!args);
543
544 r = sd_journal_get_monotonic_usec(self->j, &timestamp, &id);
545 if (set_error(r, NULL, NULL))
546 return NULL;
547
548 assert_cc(sizeof(unsigned long long) == sizeof(timestamp));
549 monotonic = PyLong_FromUnsignedLongLong(timestamp);
550 bootid = PyBytes_FromStringAndSize((const char*) &id.bytes, sizeof(id.bytes));
86e3d32a 551#if PY_MAJOR_VERSION >= 3
5e8ba1a4 552 tuple = PyStructSequence_New(&MonotonicType);
86e3d32a 553#else
5e8ba1a4 554 tuple = PyTuple_New(2);
86e3d32a 555#endif
5e8ba1a4
ZJS
556 if (!monotonic || !bootid || !tuple) {
557 Py_XDECREF(monotonic);
558 Py_XDECREF(bootid);
559 Py_XDECREF(tuple);
560 return NULL;
561 }
86e3d32a
ZJS
562
563#if PY_MAJOR_VERSION >= 3
5e8ba1a4
ZJS
564 PyStructSequence_SET_ITEM(tuple, 0, monotonic);
565 PyStructSequence_SET_ITEM(tuple, 1, bootid);
86e3d32a 566#else
5e8ba1a4
ZJS
567 PyTuple_SET_ITEM(tuple, 0, monotonic);
568 PyTuple_SET_ITEM(tuple, 1, bootid);
86e3d32a 569#endif
6a6633a1 570
5e8ba1a4 571 return tuple;
c4e9b5b5
SH
572}
573
7f41820b 574PyDoc_STRVAR(Reader_add_match__doc__,
33ed3769
ZJS
575 "add_match(match) -> None\n\n"
576 "Add a match to filter journal log entries. All matches of different\n"
2c076467
ZJS
577 "fields are combined with logical AND, and matches of the same field\n"
578 "are automatically combined with logical OR.\n"
33ed3769 579 "Match is a string of the form \"FIELD=value\".");
7f41820b 580static PyObject* Reader_add_match(Reader *self, PyObject *args, PyObject *keywds)
c4e9b5b5 581{
5bb2b8d5 582 char *match;
0d92ee93 583 int match_len, r;
5e8ba1a4 584 if (!PyArg_ParseTuple(args, "s#:add_match", &match, &match_len))
5bb2b8d5
SH
585 return NULL;
586
5bb2b8d5 587 r = sd_journal_add_match(self->j, match, match_len);
e82e4f45
ZJS
588 set_error(r, NULL, "Invalid match");
589 if (r < 0)
590 return NULL;
c4e9b5b5
SH
591
592 Py_RETURN_NONE;
593}
594
ab3a162c 595
7f41820b 596PyDoc_STRVAR(Reader_add_disjunction__doc__,
33ed3769 597 "add_disjunction() -> None\n\n"
7f876bc4
ZJS
598 "Inserts a logical OR between matches added since previous\n"
599 "add_disjunction() or add_conjunction() and the next\n"
600 "add_disjunction() or add_conjunction().\n\n"
601 "See man:sd_journal_add_disjunction(3) for explanation.");
7f41820b 602static PyObject* Reader_add_disjunction(Reader *self, PyObject *args)
c4e9b5b5
SH
603{
604 int r;
605 r = sd_journal_add_disjunction(self->j);
e82e4f45
ZJS
606 set_error(r, NULL, NULL);
607 if (r < 0)
c4e9b5b5 608 return NULL;
c4e9b5b5
SH
609 Py_RETURN_NONE;
610}
611
ab3a162c 612
7f876bc4
ZJS
613PyDoc_STRVAR(Reader_add_conjunction__doc__,
614 "add_conjunction() -> None\n\n"
615 "Inserts a logical AND between matches added since previous\n"
616 "add_disjunction() or add_conjunction() and the next\n"
617 "add_disjunction() or add_conjunction().\n\n"
618 "See man:sd_journal_add_disjunction(3) for explanation.");
619static PyObject* Reader_add_conjunction(Reader *self, PyObject *args)
620{
621 int r;
622 r = sd_journal_add_conjunction(self->j);
623 set_error(r, NULL, NULL);
624 if (r < 0)
625 return NULL;
626 Py_RETURN_NONE;
627}
628
629
7f41820b 630PyDoc_STRVAR(Reader_flush_matches__doc__,
33ed3769 631 "flush_matches() -> None\n\n"
2c076467 632 "Clear all current match filters.");
7f41820b 633static PyObject* Reader_flush_matches(Reader *self, PyObject *args)
c4e9b5b5
SH
634{
635 sd_journal_flush_matches(self->j);
636 Py_RETURN_NONE;
637}
638
ab3a162c 639
5c1c14b3
ZJS
640PyDoc_STRVAR(Reader_seek_head__doc__,
641 "seek_head() -> None\n\n"
642 "Jump to the beginning of the journal.\n"
643 "This method invokes sd_journal_seek_head().\n"
644 "See man:sd_journal_seek_head(3).");
645static PyObject* Reader_seek_head(Reader *self, PyObject *args)
c4e9b5b5 646{
5c1c14b3
ZJS
647 int r;
648 Py_BEGIN_ALLOW_THREADS
649 r = sd_journal_seek_head(self->j);
650 Py_END_ALLOW_THREADS
651 if (set_error(r, NULL, NULL))
c4e9b5b5 652 return NULL;
5c1c14b3
ZJS
653 Py_RETURN_NONE;
654}
c4e9b5b5 655
ab3a162c 656
5c1c14b3
ZJS
657PyDoc_STRVAR(Reader_seek_tail__doc__,
658 "seek_tail() -> None\n\n"
516424a4 659 "Jump to the end of the journal.\n"
5c1c14b3
ZJS
660 "This method invokes sd_journal_seek_tail().\n"
661 "See man:sd_journal_seek_tail(3).");
662static PyObject* Reader_seek_tail(Reader *self, PyObject *args)
663{
664 int r;
665 Py_BEGIN_ALLOW_THREADS
666 r = sd_journal_seek_tail(self->j);
667 Py_END_ALLOW_THREADS
668 if (set_error(r, NULL, NULL))
bf1ced55 669 return NULL;
c4e9b5b5
SH
670 Py_RETURN_NONE;
671}
672
ab3a162c 673
7f41820b 674PyDoc_STRVAR(Reader_seek_realtime__doc__,
33ed3769
ZJS
675 "seek_realtime(realtime) -> None\n\n"
676 "Seek to nearest matching journal entry to `realtime`. Argument\n"
806bc1cb 677 "`realtime` in specified in seconds.");
7f41820b 678static PyObject* Reader_seek_realtime(Reader *self, PyObject *args)
c4e9b5b5 679{
0d92ee93
ZJS
680 uint64_t timestamp;
681 int r;
682
806bc1cb 683 if (!PyArg_ParseTuple(args, "K:seek_realtime", &timestamp))
c4e9b5b5
SH
684 return NULL;
685
c4e9b5b5
SH
686 Py_BEGIN_ALLOW_THREADS
687 r = sd_journal_seek_realtime_usec(self->j, timestamp);
688 Py_END_ALLOW_THREADS
e82e4f45 689 if (set_error(r, NULL, NULL))
c4e9b5b5 690 return NULL;
c4e9b5b5
SH
691 Py_RETURN_NONE;
692}
693
ab3a162c 694
7f41820b 695PyDoc_STRVAR(Reader_seek_monotonic__doc__,
33ed3769
ZJS
696 "seek_monotonic(monotonic[, bootid]) -> None\n\n"
697 "Seek to nearest matching journal entry to `monotonic`. Argument\n"
806bc1cb 698 "`monotonic` is an timestamp from boot in microseconds.\n"
33ed3769
ZJS
699 "Argument `bootid` is a string representing which boot the\n"
700 "monotonic time is reference to. Defaults to current bootid.");
7f41820b 701static PyObject* Reader_seek_monotonic(Reader *self, PyObject *args)
c4e9b5b5 702{
33ed3769 703 char *bootid = NULL;
0d92ee93 704 uint64_t timestamp;
86e3d32a 705 sd_id128_t id;
0d92ee93
ZJS
706 int r;
707
806bc1cb 708 if (!PyArg_ParseTuple(args, "K|z:seek_monotonic", &timestamp, &bootid))
c4e9b5b5 709 return NULL;
c4e9b5b5 710
c4e9b5b5 711 if (bootid) {
86e3d32a 712 r = sd_id128_from_string(bootid, &id);
e82e4f45 713 if (set_error(r, NULL, "Invalid bootid"))
c4e9b5b5 714 return NULL;
e82e4f45
ZJS
715 } else {
716 Py_BEGIN_ALLOW_THREADS
86e3d32a 717 r = sd_id128_get_boot(&id);
e82e4f45
ZJS
718 Py_END_ALLOW_THREADS
719 if (set_error(r, NULL, NULL))
c4e9b5b5 720 return NULL;
c4e9b5b5
SH
721 }
722
723 Py_BEGIN_ALLOW_THREADS
86e3d32a 724 r = sd_journal_seek_monotonic_usec(self->j, id, timestamp);
c4e9b5b5 725 Py_END_ALLOW_THREADS
e82e4f45 726 if (set_error(r, NULL, NULL))
c4e9b5b5 727 return NULL;
806bc1cb 728
c4e9b5b5
SH
729 Py_RETURN_NONE;
730}
e82e4f45 731
ab3a162c 732
76a80d93
ZJS
733PyDoc_STRVAR(Reader_process__doc__,
734 "process() -> state change (integer)\n\n"
735 "Process events and reset the readable state of the file\n"
736 "descriptor returned by .fileno().\n\n"
737 "Will return constants: NOP if no change; APPEND if new\n"
738 "entries have been added to the end of the journal; and\n"
739 "INVALIDATE if journal files have been added or removed.\n\n"
740 "See man:sd_journal_process(3) for further discussion.");
741static PyObject* Reader_process(Reader *self, PyObject *args)
742{
743 int r;
744
745 assert(!args);
746
747 Py_BEGIN_ALLOW_THREADS
748 r = sd_journal_process(self->j);
749 Py_END_ALLOW_THREADS
750 if (set_error(r, NULL, NULL) < 0)
751 return NULL;
752
753 return long_FromLong(r);
754}
755
756
7f41820b 757PyDoc_STRVAR(Reader_wait__doc__,
2c076467
ZJS
758 "wait([timeout]) -> state change (integer)\n\n"
759 "Wait for a change in the journal. Argument `timeout` specifies\n"
806bc1cb
ZJS
760 "the maximum number of microseconds to wait before returning\n"
761 "regardless of wheter the journal has changed. If `timeout` is -1,\n"
762 "then block forever.\n\n"
33ed3769
ZJS
763 "Will return constants: NOP if no change; APPEND if new\n"
764 "entries have been added to the end of the journal; and\n"
ee6349a7
ZJS
765 "INVALIDATE if journal files have been added or removed.\n\n"
766 "See man:sd_journal_wait(3) for further discussion.");
806bc1cb 767static PyObject* Reader_wait(Reader *self, PyObject *args)
c4e9b5b5 768{
118bf4ba 769 int r;
806bc1cb 770 int64_t timeout;
118bf4ba 771
806bc1cb 772 if (!PyArg_ParseTuple(args, "|L:wait", &timeout))
c4e9b5b5
SH
773 return NULL;
774
71766afa 775 Py_BEGIN_ALLOW_THREADS
806bc1cb 776 r = sd_journal_wait(self->j, timeout);
71766afa 777 Py_END_ALLOW_THREADS
6210afbc 778 if (set_error(r, NULL, NULL) < 0)
71766afa 779 return NULL;
e82e4f45 780
ecb6dfe1 781 return long_FromLong(r);
c4e9b5b5
SH
782}
783
ab3a162c 784
7f41820b 785PyDoc_STRVAR(Reader_seek_cursor__doc__,
33ed3769 786 "seek_cursor(cursor) -> None\n\n"
2c076467 787 "Seek to journal entry by given unique reference `cursor`.");
7f41820b 788static PyObject* Reader_seek_cursor(Reader *self, PyObject *args)
c4e9b5b5
SH
789{
790 const char *cursor;
0d92ee93
ZJS
791 int r;
792
5e8ba1a4 793 if (!PyArg_ParseTuple(args, "s:seek_cursor", &cursor))
c4e9b5b5
SH
794 return NULL;
795
c4e9b5b5
SH
796 Py_BEGIN_ALLOW_THREADS
797 r = sd_journal_seek_cursor(self->j, cursor);
798 Py_END_ALLOW_THREADS
e82e4f45 799 if (set_error(r, NULL, "Invalid cursor"))
c4e9b5b5 800 return NULL;
c4e9b5b5
SH
801 Py_RETURN_NONE;
802}
803
ab3a162c 804
1cdcd71b
ZJS
805PyDoc_STRVAR(Reader_get_cursor__doc__,
806 "get_cursor() -> str\n\n"
807 "Return a cursor string for the current journal entry.\n\n"
808 "Wraps sd_journal_get_cursor(). See man:sd_journal_get_cursor(3).");
809static PyObject* Reader_get_cursor(Reader *self, PyObject *args)
810{
7fd1b19b 811 _cleanup_free_ char *cursor = NULL;
1cdcd71b
ZJS
812 int r;
813
814 assert(self);
815 assert(!args);
816
817 r = sd_journal_get_cursor(self->j, &cursor);
818 if (set_error(r, NULL, NULL))
819 return NULL;
820
821 return unicode_FromString(cursor);
822}
823
824
825PyDoc_STRVAR(Reader_test_cursor__doc__,
826 "test_cursor(str) -> bool\n\n"
827 "Test whether the cursor string matches current journal entry.\n\n"
828 "Wraps sd_journal_test_cursor(). See man:sd_journal_test_cursor(3).");
829static PyObject* Reader_test_cursor(Reader *self, PyObject *args)
830{
831 const char *cursor;
832 int r;
833
834 assert(self);
835 assert(args);
836
5e8ba1a4 837 if (!PyArg_ParseTuple(args, "s:test_cursor", &cursor))
1cdcd71b
ZJS
838 return NULL;
839
840 r = sd_journal_test_cursor(self->j, cursor);
841 set_error(r, NULL, NULL);
842 if (r < 0)
843 return NULL;
844
845 return PyBool_FromLong(r);
846}
847
7f41820b 848PyDoc_STRVAR(Reader_query_unique__doc__,
33ed3769 849 "query_unique(field) -> a set of values\n\n"
2c076467
ZJS
850 "Return a set of unique values appearing in journal for the\n"
851 "given `field`. Note this does not respect any journal matches.");
7f41820b 852static PyObject* Reader_query_unique(Reader *self, PyObject *args)
c4e9b5b5
SH
853{
854 char *query;
0d92ee93
ZJS
855 int r;
856 const void *uniq;
857 size_t uniq_len;
858 PyObject *value_set, *key, *value;
859
5e8ba1a4 860 if (!PyArg_ParseTuple(args, "s:query_unique", &query))
c4e9b5b5
SH
861 return NULL;
862
c4e9b5b5
SH
863 Py_BEGIN_ALLOW_THREADS
864 r = sd_journal_query_unique(self->j, query);
865 Py_END_ALLOW_THREADS
e82e4f45 866 if (set_error(r, NULL, "Invalid field name"))
c4e9b5b5 867 return NULL;
c4e9b5b5 868
c4e9b5b5 869 value_set = PySet_New(0);
ecb6dfe1 870 key = unicode_FromString(query);
c4e9b5b5
SH
871
872 SD_JOURNAL_FOREACH_UNIQUE(self->j, uniq, uniq_len) {
0d92ee93
ZJS
873 const char *delim_ptr;
874
c4e9b5b5 875 delim_ptr = memchr(uniq, '=', uniq_len);
6a6633a1
ZJS
876 value = PyBytes_FromStringAndSize(
877 delim_ptr + 1,
878 (const char*) uniq + uniq_len - (delim_ptr + 1));
c4e9b5b5
SH
879 PySet_Add(value_set, value);
880 Py_DECREF(value);
881 }
882 Py_DECREF(key);
883 return value_set;
884}
c4e9b5b5 885
6808412d
ZJS
886
887PyDoc_STRVAR(Reader_get_catalog__doc__,
888 "get_catalog() -> str\n\n"
889 "Retrieve a message catalog entry for the current journal entry.\n"
811de196
ZJS
890 "Will throw IndexError if the entry has no MESSAGE_ID\n"
891 "and KeyError is the id is specified, but hasn't been found\n"
892 "in the catalog.\n\n"
6808412d
ZJS
893 "Wraps man:sd_journal_get_catalog(3).");
894static PyObject* Reader_get_catalog(Reader *self, PyObject *args)
895{
896 int r;
7fd1b19b 897 _cleanup_free_ char *msg = NULL;
6808412d
ZJS
898
899 assert(self);
900 assert(!args);
901
902 Py_BEGIN_ALLOW_THREADS
903 r = sd_journal_get_catalog(self->j, &msg);
904 Py_END_ALLOW_THREADS
811de196
ZJS
905 if (r == -ENOENT) {
906 const void* mid;
907 size_t mid_len;
908
909 r = sd_journal_get_data(self->j, "MESSAGE_ID", &mid, &mid_len);
910 if (r == 0) {
fd587c87 911 const size_t l = sizeof("MESSAGE_ID");
811de196 912 assert(mid_len > l);
fd587c87 913 PyErr_Format(PyExc_KeyError, "%.*s", (int) (mid_len - l),
811de196
ZJS
914 (const char*) mid + l);
915 } else if (r == -ENOENT)
916 PyErr_SetString(PyExc_IndexError, "no MESSAGE_ID field");
917 else
918 set_error(r, NULL, NULL);
919 return NULL;
920 } else if (set_error(r, NULL, NULL))
6808412d
ZJS
921 return NULL;
922
923 return unicode_FromString(msg);
924}
925
926
2b01924c
ZJS
927PyDoc_STRVAR(get_catalog__doc__,
928 "get_catalog(id128) -> str\n\n"
929 "Retrieve a message catalog entry for the given id.\n"
930 "Wraps man:sd_journal_get_catalog_for_message_id(3).");
931static PyObject* get_catalog(PyObject *self, PyObject *args)
932{
933 int r;
934 char *id_ = NULL;
935 sd_id128_t id;
7fd1b19b 936 _cleanup_free_ char *msg = NULL;
2b01924c
ZJS
937
938 assert(!self);
939 assert(args);
940
ab3a162c 941 if (!PyArg_ParseTuple(args, "z:get_catalog", &id_))
2b01924c
ZJS
942 return NULL;
943
944 r = sd_id128_from_string(id_, &id);
945 if (set_error(r, NULL, "Invalid id128"))
946 return NULL;
947
948 Py_BEGIN_ALLOW_THREADS
949 r = sd_journal_get_catalog_for_message_id(id, &msg);
950 Py_END_ALLOW_THREADS
951 if (set_error(r, NULL, NULL))
952 return NULL;
953
954 return unicode_FromString(msg);
955}
956
957
2c076467 958PyDoc_STRVAR(data_threshold__doc__,
6a6633a1 959 "Threshold for field size truncation in bytes.\n\n"
2c076467
ZJS
960 "Fields longer than this will be truncated to the threshold size.\n"
961 "Defaults to 64Kb.");
962
7f41820b 963static PyObject* Reader_get_data_threshold(Reader *self, void *closure)
c4e9b5b5
SH
964{
965 size_t cvalue;
c4e9b5b5
SH
966 int r;
967
968 r = sd_journal_get_data_threshold(self->j, &cvalue);
e82e4f45 969 if (set_error(r, NULL, NULL))
c4e9b5b5 970 return NULL;
c4e9b5b5 971
ecb6dfe1 972 return long_FromSize_t(cvalue);
c4e9b5b5
SH
973}
974
7f41820b 975static int Reader_set_data_threshold(Reader *self, PyObject *value, void *closure)
c4e9b5b5 976{
0d92ee93 977 int r;
c4e9b5b5 978 if (value == NULL) {
6a6633a1 979 PyErr_SetString(PyExc_AttributeError, "Cannot delete data threshold");
c4e9b5b5
SH
980 return -1;
981 }
ecb6dfe1 982 if (!long_Check(value)){
0d92ee93 983 PyErr_SetString(PyExc_TypeError, "Data threshold must be an int");
c4e9b5b5
SH
984 return -1;
985 }
ecb6dfe1 986 r = sd_journal_set_data_threshold(self->j, (size_t) long_AsLong(value));
e82e4f45 987 return set_error(r, NULL, NULL);
c4e9b5b5
SH
988}
989
ab3a162c 990
6531dac6
ZJS
991PyDoc_STRVAR(closed__doc__,
992 "True iff journal is closed");
993static PyObject* Reader_get_closed(Reader *self, void *closure)
994{
995 return PyBool_FromLong(self->j == NULL);
996}
997
ab3a162c 998
6531dac6 999static PyGetSetDef Reader_getsetters[] = {
118bf4ba 1000 {(char*) "data_threshold",
7f41820b
ZJS
1001 (getter) Reader_get_data_threshold,
1002 (setter) Reader_set_data_threshold,
2c076467 1003 (char*) data_threshold__doc__,
118bf4ba 1004 NULL},
6531dac6
ZJS
1005 {(char*) "closed",
1006 (getter) Reader_get_closed,
1007 NULL,
1008 (char*) closed__doc__,
1009 NULL},
b92bea5d 1010 {} /* Sentinel */
c4e9b5b5
SH
1011};
1012
7f41820b 1013static PyMethodDef Reader_methods[] = {
f2e82cd5
ZJS
1014 {"fileno", (PyCFunction) Reader_fileno, METH_NOARGS, Reader_fileno__doc__},
1015 {"reliable_fd", (PyCFunction) Reader_reliable_fd, METH_NOARGS, Reader_reliable_fd__doc__},
76a80d93
ZJS
1016 {"get_events", (PyCFunction) Reader_get_events, METH_NOARGS, Reader_get_events__doc__},
1017 {"get_timeout", (PyCFunction) Reader_get_timeout, METH_NOARGS, Reader_get_timeout__doc__},
1018 {"get_timeout_ms", (PyCFunction) Reader_get_timeout_ms, METH_NOARGS, Reader_get_timeout_ms__doc__},
f2e82cd5 1019 {"close", (PyCFunction) Reader_close, METH_NOARGS, Reader_close__doc__},
50a279f8 1020 {"get_usage", (PyCFunction) Reader_get_usage, METH_NOARGS, Reader_get_usage__doc__},
85b2850b
ZJS
1021 {"__enter__", (PyCFunction) Reader___enter__, METH_NOARGS, Reader___enter____doc__},
1022 {"__exit__", (PyCFunction) Reader___exit__, METH_VARARGS, Reader___exit____doc__},
6a58bf41
SH
1023 {"_next", (PyCFunction) Reader_next, METH_VARARGS, Reader_next__doc__},
1024 {"_previous", (PyCFunction) Reader_previous, METH_VARARGS, Reader_previous__doc__},
1025 {"_get", (PyCFunction) Reader_get, METH_VARARGS, Reader_get__doc__},
1026 {"_get_all", (PyCFunction) Reader_get_all, METH_NOARGS, Reader_get_all__doc__},
1027 {"_get_realtime", (PyCFunction) Reader_get_realtime, METH_NOARGS, Reader_get_realtime__doc__},
1028 {"_get_monotonic", (PyCFunction) Reader_get_monotonic, METH_NOARGS, Reader_get_monotonic__doc__},
7f41820b
ZJS
1029 {"add_match", (PyCFunction) Reader_add_match, METH_VARARGS|METH_KEYWORDS, Reader_add_match__doc__},
1030 {"add_disjunction", (PyCFunction) Reader_add_disjunction, METH_NOARGS, Reader_add_disjunction__doc__},
7f876bc4 1031 {"add_conjunction", (PyCFunction) Reader_add_conjunction, METH_NOARGS, Reader_add_conjunction__doc__},
7f41820b 1032 {"flush_matches", (PyCFunction) Reader_flush_matches, METH_NOARGS, Reader_flush_matches__doc__},
5c1c14b3
ZJS
1033 {"seek_head", (PyCFunction) Reader_seek_head, METH_NOARGS, Reader_seek_head__doc__},
1034 {"seek_tail", (PyCFunction) Reader_seek_tail, METH_NOARGS, Reader_seek_tail__doc__},
7f41820b
ZJS
1035 {"seek_realtime", (PyCFunction) Reader_seek_realtime, METH_VARARGS, Reader_seek_realtime__doc__},
1036 {"seek_monotonic", (PyCFunction) Reader_seek_monotonic, METH_VARARGS, Reader_seek_monotonic__doc__},
76a80d93 1037 {"process", (PyCFunction) Reader_process, METH_NOARGS, Reader_process__doc__},
7f41820b
ZJS
1038 {"wait", (PyCFunction) Reader_wait, METH_VARARGS, Reader_wait__doc__},
1039 {"seek_cursor", (PyCFunction) Reader_seek_cursor, METH_VARARGS, Reader_seek_cursor__doc__},
6a58bf41 1040 {"_get_cursor", (PyCFunction) Reader_get_cursor, METH_NOARGS, Reader_get_cursor__doc__},
1cdcd71b 1041 {"test_cursor", (PyCFunction) Reader_test_cursor, METH_VARARGS, Reader_test_cursor__doc__},
7f41820b 1042 {"query_unique", (PyCFunction) Reader_query_unique, METH_VARARGS, Reader_query_unique__doc__},
6808412d 1043 {"get_catalog", (PyCFunction) Reader_get_catalog, METH_NOARGS, Reader_get_catalog__doc__},
b92bea5d 1044 {} /* Sentinel */
c4e9b5b5
SH
1045};
1046
7f41820b 1047static PyTypeObject ReaderType = {
c4e9b5b5 1048 PyVarObject_HEAD_INIT(NULL, 0)
b59f043c
ZJS
1049 .tp_name = "_reader._Reader",
1050 .tp_basicsize = sizeof(Reader),
1051 .tp_dealloc = (destructor) Reader_dealloc,
1052 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
1053 .tp_doc = Reader__doc__,
1054 .tp_methods = Reader_methods,
1055 .tp_getset = Reader_getsetters,
1056 .tp_init = (initproc) Reader_init,
1057 .tp_new = PyType_GenericNew,
c4e9b5b5
SH
1058};
1059
2b01924c 1060static PyMethodDef methods[] = {
811de196 1061 { "_get_catalog", get_catalog, METH_VARARGS, get_catalog__doc__},
b59f043c 1062 {} /* Sentinel */
2b01924c 1063};
2c076467 1064
c4e9b5b5 1065#if PY_MAJOR_VERSION >= 3
2b01924c 1066static PyModuleDef module = {
c4e9b5b5
SH
1067 PyModuleDef_HEAD_INIT,
1068 "_reader",
2b01924c 1069 module__doc__,
c4e9b5b5 1070 -1,
2b01924c 1071 methods,
c4e9b5b5
SH
1072};
1073#endif
1074
86e3d32a
ZJS
1075#if PY_MAJOR_VERSION >= 3
1076static bool initialized = false;
1077#endif
1078
118bf4ba
ZJS
1079#pragma GCC diagnostic push
1080#pragma GCC diagnostic ignored "-Wmissing-prototypes"
1081
c4e9b5b5
SH
1082PyMODINIT_FUNC
1083#if PY_MAJOR_VERSION >= 3
1084PyInit__reader(void)
1085#else
118bf4ba 1086init_reader(void)
c4e9b5b5
SH
1087#endif
1088{
1089 PyObject* m;
1090
1091 PyDateTime_IMPORT;
1092
7f41820b 1093 if (PyType_Ready(&ReaderType) < 0)
c4e9b5b5
SH
1094#if PY_MAJOR_VERSION >= 3
1095 return NULL;
1096#else
1097 return;
1098#endif
1099
1100#if PY_MAJOR_VERSION >= 3
2b01924c 1101 m = PyModule_Create(&module);
c4e9b5b5
SH
1102 if (m == NULL)
1103 return NULL;
86e3d32a
ZJS
1104
1105 if (!initialized) {
1106 PyStructSequence_InitType(&MonotonicType, &Monotonic_desc);
1107 initialized = true;
1108 }
c4e9b5b5 1109#else
2b01924c 1110 m = Py_InitModule3("_reader", methods, module__doc__);
c4e9b5b5
SH
1111 if (m == NULL)
1112 return;
1113#endif
1114
7f41820b 1115 Py_INCREF(&ReaderType);
86e3d32a
ZJS
1116#if PY_MAJOR_VERSION >= 3
1117 Py_INCREF(&MonotonicType);
1118#endif
7f41820b 1119 if (PyModule_AddObject(m, "_Reader", (PyObject *) &ReaderType) ||
86e3d32a
ZJS
1120#if PY_MAJOR_VERSION >= 3
1121 PyModule_AddObject(m, "Monotonic", (PyObject*) &MonotonicType) ||
1122#endif
6a6633a1
ZJS
1123 PyModule_AddIntConstant(m, "NOP", SD_JOURNAL_NOP) ||
1124 PyModule_AddIntConstant(m, "APPEND", SD_JOURNAL_APPEND) ||
1125 PyModule_AddIntConstant(m, "INVALIDATE", SD_JOURNAL_INVALIDATE) ||
1126 PyModule_AddIntConstant(m, "LOCAL_ONLY", SD_JOURNAL_LOCAL_ONLY) ||
1127 PyModule_AddIntConstant(m, "RUNTIME_ONLY", SD_JOURNAL_RUNTIME_ONLY) ||
a688baa8 1128 PyModule_AddIntConstant(m, "SYSTEM", SD_JOURNAL_SYSTEM) ||
5afbe712 1129 PyModule_AddIntConstant(m, "SYSTEM_ONLY", SD_JOURNAL_SYSTEM_ONLY) ||
affba8e9 1130 PyModule_AddIntConstant(m, "CURRENT_USER", SD_JOURNAL_CURRENT_USER) ||
5afbe712 1131 PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) {
6a6633a1
ZJS
1132#if PY_MAJOR_VERSION >= 3
1133 Py_DECREF(m);
1134 return NULL;
1135#endif
1136 }
c4e9b5b5
SH
1137
1138#if PY_MAJOR_VERSION >= 3
1139 return m;
1140#endif
1141}
118bf4ba
ZJS
1142
1143#pragma GCC diagnostic pop