]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/python-systemd/_daemon.c
python-systemd: fix is_socket_inet to cope with ports
[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
73f860db 32#include "systemd/sd-daemon.h"
b04c8c83 33#include "pyutil.h"
f0f2e63b 34#include "macro.h"
b04c8c83
ZJS
35
36PyDoc_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
b04c8c83
ZJS
44PyDoc_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
50static PyObject* booted(PyObject *self, PyObject *args) {
51 int r;
52 assert(args == NULL);
53
54 r = sd_booted();
a2387338 55 if (set_error(r, NULL, NULL) < 0)
7ecec470 56 return NULL;
b04c8c83
ZJS
57
58 return PyBool_FromLong(r);
59}
60
925d98b3
ZJS
61PyDoc_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
66static 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);
b560cc1c 92 if (set_error(r, NULL, NULL) < 0)
925d98b3
ZJS
93 return NULL;
94
95 return PyBool_FromLong(r);
96}
97
b04c8c83
ZJS
98
99PyDoc_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
925d98b3 106static PyObject* listen_fds(PyObject *self, PyObject *args, PyObject *keywds) {
b04c8c83
ZJS
107 int r;
108 int unset = true;
109
925d98b3 110 static const char* const kwlist[] = {"unset_environment", NULL};
b04c8c83 111#if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 3
925d98b3
ZJS
112 if (!PyArg_ParseTupleAndKeywords(args, keywds, "|p:_listen_fds",
113 (char**) kwlist, &unset))
b04c8c83
ZJS
114 return NULL;
115#else
116 PyObject *obj = NULL;
925d98b3 117 if (!PyArg_ParseTupleAndKeywords(args, keywds, "|O:_listen_fds",
819c7e4f 118 (char**) kwlist, &obj))
b04c8c83
ZJS
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);
b560cc1c 127 if (set_error(r, NULL, NULL) < 0)
7ecec470 128 return NULL;
b04c8c83
ZJS
129
130 return long_FromLong(r);
131}
132
133PyDoc_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
140static 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);
b560cc1c 155 if (set_error(r, path, NULL) < 0)
7ecec470 156 return NULL;
b04c8c83
ZJS
157
158 return PyBool_FromLong(r);
159}
160
161
162PyDoc_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
168static 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);
b560cc1c 183 if (set_error(r, path, NULL) < 0)
7ecec470 184 return NULL;
b04c8c83
ZJS
185
186 return PyBool_FromLong(r);
187}
188
189
190
191PyDoc_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
198static 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);
b560cc1c 207 if (set_error(r, NULL, NULL) < 0)
7ecec470 208 return NULL;
b04c8c83
ZJS
209
210 return PyBool_FromLong(r);
211}
212
213
214PyDoc_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
220static 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
9f1a574d 228 if (port < 0 || port > UINT16_MAX) {
7ecec470
ZJS
229 set_error(-EINVAL, NULL, "port must fit into uint16_t");
230 return NULL;
231 }
b04c8c83
ZJS
232
233 r = sd_is_socket_inet(fd, family, type, listening, (uint16_t) port);
b560cc1c 234 if (set_error(r, NULL, NULL) < 0)
7ecec470 235 return NULL;
b04c8c83
ZJS
236
237 return PyBool_FromLong(r);
238}
239
240
241PyDoc_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
246static 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
7fd1b19b 253 _cleanup_Py_DECREF_ PyObject *_path = NULL;
b04c8c83
ZJS
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);
b560cc1c 269 if (set_error(r, path, NULL) < 0)
7ecec470 270 return NULL;
b04c8c83
ZJS
271
272 return PyBool_FromLong(r);
273}
274
275
276static PyMethodDef methods[] = {
277 { "booted", booted, METH_NOARGS, booted__doc__},
925d98b3
ZJS
278 { "notify", (PyCFunction) notify, METH_VARARGS | METH_KEYWORDS, notify__doc__},
279 { "_listen_fds", (PyCFunction) listen_fds, METH_VARARGS | METH_KEYWORDS, listen_fds__doc__},
b04c8c83
ZJS
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
b04c8c83
ZJS
288#if PY_MAJOR_VERSION < 3
289
f0f2e63b 290DISABLE_WARNING_MISSING_PROTOTYPES;
b04c8c83
ZJS
291PyMODINIT_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);
5afbe712 299 PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION);
b04c8c83 300}
f0f2e63b 301REENABLE_WARNING;
b04c8c83
ZJS
302
303#else
304
305static 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
f0f2e63b 313DISABLE_WARNING_MISSING_PROTOTYPES;
b04c8c83
ZJS
314PyMODINIT_FUNC PyInit__daemon(void) {
315 PyObject *m;
316
317 m = PyModule_Create(&module);
318 if (m == NULL)
319 return NULL;
320
5afbe712
ZJS
321 if (PyModule_AddIntConstant(m, "LISTEN_FDS_START", SD_LISTEN_FDS_START) ||
322 PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) {
b04c8c83
ZJS
323 Py_DECREF(m);
324 return NULL;
325 }
326
327 return m;
328}
f0f2e63b 329REENABLE_WARNING;
b04c8c83
ZJS
330
331#endif