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