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