chiark / gitweb /
Always prefer our headers to system headers
[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 #include "macro.h"
35
36 PyDoc_STRVAR(module__doc__,
37         "Python interface to the libsystemd-daemon library.\n\n"
38         "Provides _listen_fds, notify, booted, and is_* functions\n"
39         "which wrap sd_listen_fds, sd_notify, sd_booted, sd_is_* and\n"
40         "useful for socket activation and checking if the system is\n"
41         "running under systemd."
42 );
43
44 PyDoc_STRVAR(booted__doc__,
45              "booted() -> bool\n\n"
46              "Return True iff this system is running under systemd.\n"
47              "Wraps sd_daemon_booted(3)."
48 );
49
50 static PyObject* booted(PyObject *self, PyObject *args) {
51         int r;
52         assert(args == NULL);
53
54         r = sd_booted();
55         if (set_error(r, NULL, NULL) < 0)
56                 return NULL;
57
58         return PyBool_FromLong(r);
59 }
60
61 PyDoc_STRVAR(notify__doc__,
62              "notify(status, unset_environment=False) -> bool\n\n"
63              "Send a message to the init system about a status change.\n"
64              "Wraps sd_notify(3).");
65
66 static PyObject* notify(PyObject *self, PyObject *args, PyObject *keywds) {
67         int r;
68         const char* msg;
69         int unset = false;
70
71         static const char* const kwlist[] = {
72                 "status",
73                 "unset_environment",
74                 NULL,
75         };
76 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 3
77         if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|p:notify",
78                                          (char**) kwlist, &msg, &unset))
79                 return NULL;
80 #else
81         PyObject *obj = NULL;
82         if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|O:notify",
83                                          (char**) kwlist, &msg, &obj))
84                 return NULL;
85         if (obj != NULL)
86                 unset = PyObject_IsTrue(obj);
87         if (unset < 0)
88                 return NULL;
89 #endif
90
91         r = sd_notify(unset, msg);
92         if (set_error(r, NULL, NULL) < 0)
93                 return NULL;
94
95         return PyBool_FromLong(r);
96 }
97
98
99 PyDoc_STRVAR(listen_fds__doc__,
100              "_listen_fds(unset_environment=True) -> int\n\n"
101              "Return the number of descriptors passed to this process by the init system\n"
102              "as part of the socket-based activation logic.\n"
103              "Wraps sd_listen_fds(3)."
104 );
105
106 static PyObject* listen_fds(PyObject *self, PyObject *args, PyObject *keywds) {
107         int r;
108         int unset = true;
109
110         static const char* const kwlist[] = {"unset_environment", NULL};
111 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 3
112         if (!PyArg_ParseTupleAndKeywords(args, keywds, "|p:_listen_fds",
113                                          (char**) kwlist, &unset))
114                 return NULL;
115 #else
116         PyObject *obj = NULL;
117         if (!PyArg_ParseTupleAndKeywords(args, keywds, "|O:_listen_fds",
118                                          (char**) kwlist, &obj))
119                 return NULL;
120         if (obj != NULL)
121                 unset = PyObject_IsTrue(obj);
122         if (unset < 0)
123                 return NULL;
124 #endif
125
126         r = sd_listen_fds(unset);
127         if (set_error(r, NULL, NULL) < 0)
128                 return NULL;
129
130         return long_FromLong(r);
131 }
132
133 PyDoc_STRVAR(is_fifo__doc__,
134              "_is_fifo(fd, path) -> bool\n\n"
135              "Returns True iff the descriptor refers to a FIFO or a pipe.\n"
136              "Wraps sd_is_fifo(3)."
137 );
138
139
140 static PyObject* is_fifo(PyObject *self, PyObject *args) {
141         int r;
142         int fd;
143         const char *path = NULL;
144
145 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
146         if (!PyArg_ParseTuple(args, "i|O&:_is_fifo",
147                               &fd, Unicode_FSConverter, &path))
148                 return NULL;
149 #else
150         if (!PyArg_ParseTuple(args, "i|z:_is_fifo", &fd, &path))
151                 return NULL;
152 #endif
153
154         r = sd_is_fifo(fd, path);
155         if (set_error(r, path, NULL) < 0)
156                 return NULL;
157
158         return PyBool_FromLong(r);
159 }
160
161
162 PyDoc_STRVAR(is_mq__doc__,
163              "_is_mq(fd, path) -> bool\n\n"
164              "Returns True iff the descriptor refers to a POSIX message queue.\n"
165              "Wraps sd_is_mq(3)."
166 );
167
168 static PyObject* is_mq(PyObject *self, PyObject *args) {
169         int r;
170         int fd;
171         const char *path = NULL;
172
173 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
174         if (!PyArg_ParseTuple(args, "i|O&:_is_mq",
175                               &fd, Unicode_FSConverter, &path))
176                 return NULL;
177 #else
178         if (!PyArg_ParseTuple(args, "i|z:_is_mq", &fd, &path))
179                 return NULL;
180 #endif
181
182         r = sd_is_mq(fd, path);
183         if (set_error(r, path, NULL) < 0)
184                 return NULL;
185
186         return PyBool_FromLong(r);
187 }
188
189
190
191 PyDoc_STRVAR(is_socket__doc__,
192              "_is_socket(fd, family=AF_UNSPEC, type=0, listening=-1) -> bool\n\n"
193              "Returns True iff the descriptor refers to a socket.\n"
194              "Wraps sd_is_socket(3).\n\n"
195              "Constants for `family` are defined in the socket module."
196 );
197
198 static PyObject* is_socket(PyObject *self, PyObject *args) {
199         int r;
200         int fd, family = AF_UNSPEC, type = 0, listening = -1;
201
202         if (!PyArg_ParseTuple(args, "i|iii:_is_socket",
203                               &fd, &family, &type, &listening))
204                 return NULL;
205
206         r = sd_is_socket(fd, family, type, listening);
207         if (set_error(r, NULL, NULL) < 0)
208                 return NULL;
209
210         return PyBool_FromLong(r);
211 }
212
213
214 PyDoc_STRVAR(is_socket_inet__doc__,
215              "_is_socket_inet(fd, family=AF_UNSPEC, type=0, listening=-1, port=0) -> bool\n\n"
216              "Wraps sd_is_socket_inet(3).\n\n"
217              "Constants for `family` are defined in the socket module."
218 );
219
220 static PyObject* is_socket_inet(PyObject *self, PyObject *args) {
221         int r;
222         int fd, family = AF_UNSPEC, type = 0, listening = -1, port = 0;
223
224         if (!PyArg_ParseTuple(args, "i|iiii:_is_socket_inet",
225                               &fd, &family, &type, &listening, &port))
226                 return NULL;
227
228         if (port < 0 || port > INT16_MAX) {
229                 set_error(-EINVAL, NULL, "port must fit into uint16_t");
230                 return NULL;
231         }
232
233         r = sd_is_socket_inet(fd, family, type, listening, (uint16_t) port);
234         if (set_error(r, NULL, NULL) < 0)
235                 return NULL;
236
237         return PyBool_FromLong(r);
238 }
239
240
241 PyDoc_STRVAR(is_socket_unix__doc__,
242              "_is_socket_unix(fd, type, listening, path) -> bool\n\n"
243              "Wraps sd_is_socket_unix(3)."
244 );
245
246 static PyObject* is_socket_unix(PyObject *self, PyObject *args) {
247         int r;
248         int fd, type = 0, listening = -1;
249         char* path = NULL;
250         Py_ssize_t length = 0;
251
252 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
253         _cleanup_Py_DECREF_ PyObject *_path = NULL;
254         if (!PyArg_ParseTuple(args, "i|iiO&:_is_socket_unix",
255                               &fd, &type, &listening, Unicode_FSConverter, &_path))
256                 return NULL;
257         if (_path) {
258                 assert(PyBytes_Check(_path));
259                 if (PyBytes_AsStringAndSize(_path, &path, &length))
260                         return NULL;
261         }
262 #else
263         if (!PyArg_ParseTuple(args, "i|iiz#:_is_socket_unix",
264                               &fd, &type, &listening, &path, &length))
265                 return NULL;
266 #endif
267
268         r = sd_is_socket_unix(fd, type, listening, path, length);
269         if (set_error(r, path, NULL) < 0)
270                 return NULL;
271
272         return PyBool_FromLong(r);
273 }
274
275
276 static PyMethodDef methods[] = {
277         { "booted", booted, METH_NOARGS, booted__doc__},
278         { "notify", (PyCFunction) notify, METH_VARARGS | METH_KEYWORDS, notify__doc__},
279         { "_listen_fds", (PyCFunction) listen_fds, METH_VARARGS | METH_KEYWORDS, listen_fds__doc__},
280         { "_is_fifo", is_fifo, METH_VARARGS, is_fifo__doc__},
281         { "_is_mq", is_mq, METH_VARARGS, is_mq__doc__},
282         { "_is_socket", is_socket, METH_VARARGS, is_socket__doc__},
283         { "_is_socket_inet", is_socket_inet, METH_VARARGS, is_socket_inet__doc__},
284         { "_is_socket_unix", is_socket_unix, METH_VARARGS, is_socket_unix__doc__},
285         { NULL, NULL, 0, NULL }        /* Sentinel */
286 };
287
288 #if PY_MAJOR_VERSION < 3
289
290 DISABLE_WARNING_MISSING_PROTOTYPES;
291 PyMODINIT_FUNC init_daemon(void) {
292         PyObject *m;
293
294         m = Py_InitModule3("_daemon", methods, module__doc__);
295         if (m == NULL)
296                 return;
297
298         PyModule_AddIntConstant(m, "LISTEN_FDS_START", SD_LISTEN_FDS_START);
299         PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION);
300 }
301 REENABLE_WARNING;
302
303 #else
304
305 static struct PyModuleDef module = {
306         PyModuleDef_HEAD_INIT,
307         "_daemon", /* name of module */
308         module__doc__, /* module documentation, may be NULL */
309         0, /* size of per-interpreter state of the module */
310         methods
311 };
312
313 DISABLE_WARNING_MISSING_PROTOTYPES;
314 PyMODINIT_FUNC PyInit__daemon(void) {
315         PyObject *m;
316
317         m = PyModule_Create(&module);
318         if (m == NULL)
319                 return NULL;
320
321         if (PyModule_AddIntConstant(m, "LISTEN_FDS_START", SD_LISTEN_FDS_START) ||
322             PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) {
323                 Py_DECREF(m);
324                 return NULL;
325         }
326
327         return m;
328 }
329 REENABLE_WARNING;
330
331 #endif