1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
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.
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.
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/>.
22 #define PY_SSIZE_T_CLEAN
23 #pragma GCC diagnostic push
24 #pragma GCC diagnostic ignored "-Wredundant-decls"
26 #pragma GCC diagnostic pop
30 #include <sys/socket.h>
32 #include <systemd/sd-daemon.h>
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."
44 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
45 static int Unicode_FSConverter(PyObject* obj, void *_result) {
46 PyObject **result = _result;
51 /* cleanup: we don't return Py_CLEANUP_SUPPORTED, so
52 * we can assume that it was PyUnicode_FSConverter. */
53 return PyUnicode_FSConverter(obj, result);
60 return PyUnicode_FSConverter(obj, result);
65 PyDoc_STRVAR(booted__doc__,
66 "booted() -> bool\n\n"
67 "Return True iff this system is running under systemd.\n"
68 "Wraps sd_daemon_booted(3)."
71 static PyObject* booted(PyObject *self, PyObject *args) {
76 if (set_error(r, NULL, NULL))
79 return PyBool_FromLong(r);
82 PyDoc_STRVAR(notify__doc__,
83 "notify(status, unset_environment=False) -> bool\n\n"
84 "Send a message to the init system about a status change.\n"
85 "Wraps sd_notify(3).");
87 static PyObject* notify(PyObject *self, PyObject *args, PyObject *keywds) {
92 static const char* const kwlist[] = {
97 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 3
98 if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|p:notify",
99 (char**) kwlist, &msg, &unset))
102 PyObject *obj = NULL;
103 if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|O:notify",
104 (char**) kwlist, &msg, &obj))
107 unset = PyObject_IsTrue(obj);
112 r = sd_notify(unset, msg);
113 if (set_error(r, NULL, NULL))
116 return PyBool_FromLong(r);
120 PyDoc_STRVAR(listen_fds__doc__,
121 "_listen_fds(unset_environment=True) -> int\n\n"
122 "Return the number of descriptors passed to this process by the init system\n"
123 "as part of the socket-based activation logic.\n"
124 "Wraps sd_listen_fds(3)."
127 static PyObject* listen_fds(PyObject *self, PyObject *args, PyObject *keywds) {
131 static const char* const kwlist[] = {"unset_environment", NULL};
132 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 3
133 if (!PyArg_ParseTupleAndKeywords(args, keywds, "|p:_listen_fds",
134 (char**) kwlist, &unset))
137 PyObject *obj = NULL;
138 if (!PyArg_ParseTupleAndKeywords(args, keywds, "|O:_listen_fds",
139 (char**) kwlist, &unset, &obj))
142 unset = PyObject_IsTrue(obj);
147 r = sd_listen_fds(unset);
148 if (set_error(r, NULL, NULL))
151 return long_FromLong(r);
154 PyDoc_STRVAR(is_fifo__doc__,
155 "_is_fifo(fd, path) -> bool\n\n"
156 "Returns True iff the descriptor refers to a FIFO or a pipe.\n"
157 "Wraps sd_is_fifo(3)."
161 static PyObject* is_fifo(PyObject *self, PyObject *args) {
164 const char *path = NULL;
166 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
167 if (!PyArg_ParseTuple(args, "i|O&:_is_fifo",
168 &fd, Unicode_FSConverter, &path))
171 if (!PyArg_ParseTuple(args, "i|z:_is_fifo", &fd, &path))
175 r = sd_is_fifo(fd, path);
176 if (set_error(r, path, NULL))
179 return PyBool_FromLong(r);
183 PyDoc_STRVAR(is_mq__doc__,
184 "_is_mq(fd, path) -> bool\n\n"
185 "Returns True iff the descriptor refers to a POSIX message queue.\n"
189 static PyObject* is_mq(PyObject *self, PyObject *args) {
192 const char *path = NULL;
194 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
195 if (!PyArg_ParseTuple(args, "i|O&:_is_mq",
196 &fd, Unicode_FSConverter, &path))
199 if (!PyArg_ParseTuple(args, "i|z:_is_mq", &fd, &path))
203 r = sd_is_mq(fd, path);
204 if (set_error(r, path, NULL))
207 return PyBool_FromLong(r);
212 PyDoc_STRVAR(is_socket__doc__,
213 "_is_socket(fd, family=AF_UNSPEC, type=0, listening=-1) -> bool\n\n"
214 "Returns True iff the descriptor refers to a socket.\n"
215 "Wraps sd_is_socket(3).\n\n"
216 "Constants for `family` are defined in the socket module."
219 static PyObject* is_socket(PyObject *self, PyObject *args) {
221 int fd, family = AF_UNSPEC, type = 0, listening = -1;
223 if (!PyArg_ParseTuple(args, "i|iii:_is_socket",
224 &fd, &family, &type, &listening))
227 r = sd_is_socket(fd, family, type, listening);
228 if (set_error(r, NULL, NULL))
231 return PyBool_FromLong(r);
235 PyDoc_STRVAR(is_socket_inet__doc__,
236 "_is_socket_inet(fd, family=AF_UNSPEC, type=0, listening=-1, port=0) -> bool\n\n"
237 "Wraps sd_is_socket_inet(3).\n\n"
238 "Constants for `family` are defined in the socket module."
241 static PyObject* is_socket_inet(PyObject *self, PyObject *args) {
243 int fd, family = AF_UNSPEC, type = 0, listening = -1, port = 0;
245 if (!PyArg_ParseTuple(args, "i|iiii:_is_socket_inet",
246 &fd, &family, &type, &listening, &port))
249 if (port < 0 || port > INT16_MAX) {
250 set_error(-EINVAL, NULL, "port must fit into uint16_t");
254 r = sd_is_socket_inet(fd, family, type, listening, (uint16_t) port);
255 if (set_error(r, NULL, NULL))
258 return PyBool_FromLong(r);
262 PyDoc_STRVAR(is_socket_unix__doc__,
263 "_is_socket_unix(fd, type, listening, path) -> bool\n\n"
264 "Wraps sd_is_socket_unix(3)."
267 static PyObject* is_socket_unix(PyObject *self, PyObject *args) {
269 int fd, type = 0, listening = -1;
271 Py_ssize_t length = 0;
273 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
274 _cleanup_Py_DECREF_ PyObject *_path = NULL;
275 if (!PyArg_ParseTuple(args, "i|iiO&:_is_socket_unix",
276 &fd, &type, &listening, Unicode_FSConverter, &_path))
279 assert(PyBytes_Check(_path));
280 if (PyBytes_AsStringAndSize(_path, &path, &length))
284 if (!PyArg_ParseTuple(args, "i|iiz#:_is_socket_unix",
285 &fd, &type, &listening, &path, &length))
289 r = sd_is_socket_unix(fd, type, listening, path, length);
290 if (set_error(r, path, NULL))
293 return PyBool_FromLong(r);
297 static PyMethodDef methods[] = {
298 { "booted", booted, METH_NOARGS, booted__doc__},
299 { "notify", (PyCFunction) notify, METH_VARARGS | METH_KEYWORDS, notify__doc__},
300 { "_listen_fds", (PyCFunction) listen_fds, METH_VARARGS | METH_KEYWORDS, listen_fds__doc__},
301 { "_is_fifo", is_fifo, METH_VARARGS, is_fifo__doc__},
302 { "_is_mq", is_mq, METH_VARARGS, is_mq__doc__},
303 { "_is_socket", is_socket, METH_VARARGS, is_socket__doc__},
304 { "_is_socket_inet", is_socket_inet, METH_VARARGS, is_socket_inet__doc__},
305 { "_is_socket_unix", is_socket_unix, METH_VARARGS, is_socket_unix__doc__},
306 { NULL, NULL, 0, NULL } /* Sentinel */
309 #pragma GCC diagnostic push
310 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
312 #if PY_MAJOR_VERSION < 3
314 PyMODINIT_FUNC init_daemon(void) {
317 m = Py_InitModule3("_daemon", methods, module__doc__);
321 PyModule_AddIntConstant(m, "LISTEN_FDS_START", SD_LISTEN_FDS_START);
322 PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION);
327 static struct PyModuleDef module = {
328 PyModuleDef_HEAD_INIT,
329 "_daemon", /* name of module */
330 module__doc__, /* module documentation, may be NULL */
331 0, /* size of per-interpreter state of the module */
335 PyMODINIT_FUNC PyInit__daemon(void) {
338 m = PyModule_Create(&module);
342 if (PyModule_AddIntConstant(m, "LISTEN_FDS_START", SD_LISTEN_FDS_START) ||
343 PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) {
353 #pragma GCC diagnostic pop