]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/python-systemd/_daemon.c
move _cleanup_ attribute in front of the type
[thirdparty/systemd.git] / src / python-systemd / _daemon.c
CommitLineData
b04c8c83
ZJS
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
35PyDoc_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
43static 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
60static 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
80PyDoc_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
86static 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
98PyDoc_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
105static 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
129PyDoc_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
136static 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
158PyDoc_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
164static 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
187PyDoc_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
194static 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
210PyDoc_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
216static 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
235PyDoc_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
240static 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
7fd1b19b 247 _cleanup_Py_DECREF_ PyObject *_path = NULL;
b04c8c83
ZJS
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
270static 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
286PyMODINIT_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
298static 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
306PyMODINIT_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