~ubuntu-branches/ubuntu/trusty/systemd/trusty

« back to all changes in this revision

Viewing changes to src/python-systemd/_reader.c

  • Committer: Package Import Robot
  • Author(s): Michael Biebl, Michael Biebl, Michael Stapelberg, Daniel Schaal, Ondrej Balaz
  • Date: 2013-09-12 00:13:11 UTC
  • mfrom: (1.1.11) (9.1.2 experimental)
  • mto: This revision was merged to the branch mainline in revision 53.
  • Revision ID: package-import@ubuntu.com-20130912001311-dz35it34wr2lbday
Tags: 204-3
[ Michael Biebl ]
* Upload to unstable.
* Use /bin/bash in debug-shell.service as Debian doesn't have /sbin/sushell.
* Only import net.ifaces cmdline property for network devices.
* Generate strict dependencies between the binary packages using a
  shlibs.local file and add an explicit versioned dependency on
  libsystemd-login0 to systemd to ensure packages are upgraded in sync.
  Closes: #719444
* Drop obsolete Replaces: libudev0 from udev package.
* Use correct paths for various binaries, like /sbin/quotaon, which are
  installed in / and not /usr in Debian.  Closes: #721347
* Don't install kernel-install(8) man page since we don't install the
  corresponding binary either.  Closes: #722180
* Cherry-pick upstream fixes to make switching runlevels and starting
  reboot via ctrl-alt-del more robust.
* Cherry-pick upstream fix to properly apply ACLs to Journal files.

[ Michael Stapelberg ]
* Make systemctl enable|disable call update-rc.d for SysV init scripts.
  Closes: #709780
* Don't mount /tmp as tmpfs by default and make it possible to enable this
  feature via "systemctl enable tmp.mount".

[ Daniel Schaal ]
* Add bug-script to systemd and udev.  Closes: #711245

[ Ondrej Balaz ]
* Recognize discard option in /etc/crypttab.

Show diffs side-by-side

added added

removed removed

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