chiark / gitweb /
journal: add ability to filter by current user
[elogind.git] / src / python-systemd / _daemon.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Zbigniew JÄ™drzejewski-Szmek <zbyszek@in.waw.pl>
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 #define PY_SSIZE_T_CLEAN
23 #pragma GCC diagnostic push
24 #pragma GCC diagnostic ignored "-Wredundant-decls"
25 #include <Python.h>
26 #pragma GCC diagnostic pop
27
28 #include <stdbool.h>
29 #include <assert.h>
30 #include <sys/socket.h>
31
32 #include <systemd/sd-daemon.h>
33 #include "pyutil.h"
34
35 PyDoc_STRVAR(module__doc__,
36         "Python interface to the libsystemd-daemon library.\n\n"
37         "Provides _listen_fds, notify, booted, and is_* functions\n"
38         "which wrap sd_listen_fds, sd_notify, sd_booted, sd_is_* and\n"
39         "useful for socket activation and checking if the system is\n"
40         "running under systemd."
41 );
42
43
44 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
45 static int Unicode_FSConverter(PyObject* obj, void *_result) {
46         PyObject **result = _result;
47
48         assert(result);
49
50         if (!obj)
51                 /* cleanup: we don't return Py_CLEANUP_SUPPORTED, so
52                  * we can assume that it was PyUnicode_FSConverter. */
53                 return PyUnicode_FSConverter(obj, result);
54
55         if (obj == Py_None) {
56                 *result = NULL;
57                 return 1;
58         }
59
60         return PyUnicode_FSConverter(obj, result);
61 }
62 #endif
63
64
65 PyDoc_STRVAR(booted__doc__,
66              "booted() -> bool\n\n"
67              "Return True iff this system is running under systemd.\n"
68              "Wraps sd_daemon_booted(3)."
69 );
70
71 static PyObject* booted(PyObject *self, PyObject *args) {
72         int r;
73         assert(args == NULL);
74
75         r = sd_booted();
76         if (set_error(r, NULL, NULL))
77                 return NULL;
78
79         return PyBool_FromLong(r);
80 }
81
82
83 PyDoc_STRVAR(listen_fds__doc__,
84              "_listen_fds(unset_environment=True) -> int\n\n"
85              "Return the number of descriptors passed to this process by the init system\n"
86              "as part of the socket-based activation logic.\n"
87              "Wraps sd_listen_fds(3)."
88 );
89
90 static PyObject* listen_fds(PyObject *self, PyObject *args) {
91         int r;
92         int unset = true;
93
94 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 3
95         if (!PyArg_ParseTuple(args, "|p:_listen_fds", &unset))
96                 return NULL;
97 #else
98         PyObject *obj = NULL;
99         if (!PyArg_ParseTuple(args, "|O:_listen_fds", &obj))
100                 return NULL;
101         if (obj != NULL)
102                 unset = PyObject_IsTrue(obj);
103         if (unset < 0)
104                 return NULL;
105 #endif
106
107         r = sd_listen_fds(unset);
108         if (set_error(r, NULL, NULL))
109                 return NULL;
110
111         return long_FromLong(r);
112 }
113
114 PyDoc_STRVAR(is_fifo__doc__,
115              "_is_fifo(fd, path) -> bool\n\n"
116              "Returns True iff the descriptor refers to a FIFO or a pipe.\n"
117              "Wraps sd_is_fifo(3)."
118 );
119
120
121 static PyObject* is_fifo(PyObject *self, PyObject *args) {
122         int r;
123         int fd;
124         const char *path = NULL;
125
126 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
127         if (!PyArg_ParseTuple(args, "i|O&:_is_fifo",
128                               &fd, Unicode_FSConverter, &path))
129                 return NULL;
130 #else
131         if (!PyArg_ParseTuple(args, "i|z:_is_fifo", &fd, &path))
132                 return NULL;
133 #endif
134
135         r = sd_is_fifo(fd, path);
136         if (set_error(r, path, NULL))
137                 return NULL;
138
139         return PyBool_FromLong(r);
140 }
141
142
143 PyDoc_STRVAR(is_mq__doc__,
144              "_is_mq(fd, path) -> bool\n\n"
145              "Returns True iff the descriptor refers to a POSIX message queue.\n"
146              "Wraps sd_is_mq(3)."
147 );
148
149 static PyObject* is_mq(PyObject *self, PyObject *args) {
150         int r;
151         int fd;
152         const char *path = NULL;
153
154 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
155         if (!PyArg_ParseTuple(args, "i|O&:_is_mq",
156                               &fd, Unicode_FSConverter, &path))
157                 return NULL;
158 #else
159         if (!PyArg_ParseTuple(args, "i|z:_is_mq", &fd, &path))
160                 return NULL;
161 #endif
162
163         r = sd_is_mq(fd, path);
164         if (set_error(r, path, NULL))
165                 return NULL;
166
167         return PyBool_FromLong(r);
168 }
169
170
171
172 PyDoc_STRVAR(is_socket__doc__,
173              "_is_socket(fd, family=AF_UNSPEC, type=0, listening=-1) -> bool\n\n"
174              "Returns True iff the descriptor refers to a socket.\n"
175              "Wraps sd_is_socket(3).\n\n"
176              "Constants for `family` are defined in the socket module."
177 );
178
179 static PyObject* is_socket(PyObject *self, PyObject *args) {
180         int r;
181         int fd, family = AF_UNSPEC, type = 0, listening = -1;
182
183         if (!PyArg_ParseTuple(args, "i|iii:_is_socket",
184                               &fd, &family, &type, &listening))
185                 return NULL;
186
187         r = sd_is_socket(fd, family, type, listening);
188         if (set_error(r, NULL, NULL))
189                 return NULL;
190
191         return PyBool_FromLong(r);
192 }
193
194
195 PyDoc_STRVAR(is_socket_inet__doc__,
196              "_is_socket_inet(fd, family=AF_UNSPEC, type=0, listening=-1, port=0) -> bool\n\n"
197              "Wraps sd_is_socket_inet(3).\n\n"
198              "Constants for `family` are defined in the socket module."
199 );
200
201 static PyObject* is_socket_inet(PyObject *self, PyObject *args) {
202         int r;
203         int fd, family = AF_UNSPEC, type = 0, listening = -1, port = 0;
204
205         if (!PyArg_ParseTuple(args, "i|iiii:_is_socket_inet",
206                               &fd, &family, &type, &listening, &port))
207                 return NULL;
208
209         if (port < 0 || port > INT16_MAX) {
210                 set_error(-EINVAL, NULL, "port must fit into uint16_t");
211                 return NULL;
212         }
213
214         r = sd_is_socket_inet(fd, family, type, listening, (uint16_t) port);
215         if (set_error(r, NULL, NULL))
216                 return NULL;
217
218         return PyBool_FromLong(r);
219 }
220
221
222 PyDoc_STRVAR(is_socket_unix__doc__,
223              "_is_socket_unix(fd, type, listening, path) -> bool\n\n"
224              "Wraps sd_is_socket_unix(3)."
225 );
226
227 static PyObject* is_socket_unix(PyObject *self, PyObject *args) {
228         int r;
229         int fd, type = 0, listening = -1;
230         char* path = NULL;
231         Py_ssize_t length = 0;
232
233 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
234         _cleanup_Py_DECREF_ PyObject *_path = NULL;
235         if (!PyArg_ParseTuple(args, "i|iiO&:_is_socket_unix",
236                               &fd, &type, &listening, Unicode_FSConverter, &_path))
237                 return NULL;
238         if (_path) {
239                 assert(PyBytes_Check(_path));
240                 if (PyBytes_AsStringAndSize(_path, &path, &length))
241                         return NULL;
242         }
243 #else
244         if (!PyArg_ParseTuple(args, "i|iiz#:_is_socket_unix",
245                               &fd, &type, &listening, &path, &length))
246                 return NULL;
247 #endif
248
249         r = sd_is_socket_unix(fd, type, listening, path, length);
250         if (set_error(r, path, NULL))
251                 return NULL;
252
253         return PyBool_FromLong(r);
254 }
255
256
257 static PyMethodDef methods[] = {
258         { "booted", booted, METH_NOARGS, booted__doc__},
259         { "_listen_fds", listen_fds, METH_VARARGS, listen_fds__doc__},
260         { "_is_fifo", is_fifo, METH_VARARGS, is_fifo__doc__},
261         { "_is_mq", is_mq, METH_VARARGS, is_mq__doc__},
262         { "_is_socket", is_socket, METH_VARARGS, is_socket__doc__},
263         { "_is_socket_inet", is_socket_inet, METH_VARARGS, is_socket_inet__doc__},
264         { "_is_socket_unix", is_socket_unix, METH_VARARGS, is_socket_unix__doc__},
265         { NULL, NULL, 0, NULL }        /* Sentinel */
266 };
267
268 #pragma GCC diagnostic push
269 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
270
271 #if PY_MAJOR_VERSION < 3
272
273 PyMODINIT_FUNC init_daemon(void) {
274         PyObject *m;
275
276         m = Py_InitModule3("_daemon", methods, module__doc__);
277         if (m == NULL)
278                 return;
279
280         PyModule_AddIntConstant(m, "LISTEN_FDS_START", SD_LISTEN_FDS_START);
281         PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION);
282 }
283
284 #else
285
286 static struct PyModuleDef module = {
287         PyModuleDef_HEAD_INIT,
288         "_daemon", /* name of module */
289         module__doc__, /* module documentation, may be NULL */
290         0, /* size of per-interpreter state of the module */
291         methods
292 };
293
294 PyMODINIT_FUNC PyInit__daemon(void) {
295         PyObject *m;
296
297         m = PyModule_Create(&module);
298         if (m == NULL)
299                 return NULL;
300
301         if (PyModule_AddIntConstant(m, "LISTEN_FDS_START", SD_LISTEN_FDS_START) ||
302             PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) {
303                 Py_DECREF(m);
304                 return NULL;
305         }
306
307         return m;
308 }
309
310 #endif
311
312 #pragma GCC diagnostic pop