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."
43 static PyObject* set_error(int r, const char* invalid_message) {
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");
52 PyErr_SetFromErrno(PyExc_OSError);
59 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
60 static int Unicode_FSConverter(PyObject* obj, void *_result) {
61 PyObject **result = _result;
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);
75 return PyUnicode_FSConverter(obj, result);
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)."
86 static PyObject* booted(PyObject *self, PyObject *args) {
92 return set_error(r, NULL);
94 return PyBool_FromLong(r);
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)."
105 static PyObject* listen_fds(PyObject *self, PyObject *args) {
109 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 3
110 if (!PyArg_ParseTuple(args, "|p:_listen_fds", &unset))
113 PyObject *obj = NULL;
114 if (!PyArg_ParseTuple(args, "|O:_listen_fds", &obj))
117 unset = PyObject_IsTrue(obj);
122 r = sd_listen_fds(unset);
124 return set_error(r, NULL);
126 return long_FromLong(r);
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)."
136 static PyObject* is_fifo(PyObject *self, PyObject *args) {
139 const char *path = NULL;
141 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
142 if (!PyArg_ParseTuple(args, "i|O&:_is_fifo",
143 &fd, Unicode_FSConverter, &path))
146 if (!PyArg_ParseTuple(args, "i|z:_is_fifo", &fd, &path))
150 r = sd_is_fifo(fd, path);
152 return set_error(r, NULL);
154 return PyBool_FromLong(r);
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"
164 static PyObject* is_mq(PyObject *self, PyObject *args) {
167 const char *path = NULL;
169 #if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
170 if (!PyArg_ParseTuple(args, "i|O&:_is_mq",
171 &fd, Unicode_FSConverter, &path))
174 if (!PyArg_ParseTuple(args, "i|z:_is_mq", &fd, &path))
178 r = sd_is_mq(fd, path);
180 return set_error(r, NULL);
182 return PyBool_FromLong(r);
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."
194 static PyObject* is_socket(PyObject *self, PyObject *args) {
196 int fd, family = AF_UNSPEC, type = 0, listening = -1;
198 if (!PyArg_ParseTuple(args, "i|iii:_is_socket",
199 &fd, &family, &type, &listening))
202 r = sd_is_socket(fd, family, type, listening);
204 return set_error(r, NULL);
206 return PyBool_FromLong(r);
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."
216 static PyObject* is_socket_inet(PyObject *self, PyObject *args) {
218 int fd, family = AF_UNSPEC, type = 0, listening = -1, port = 0;
220 if (!PyArg_ParseTuple(args, "i|iiii:_is_socket_inet",
221 &fd, &family, &type, &listening, &port))
224 if (port < 0 || port > INT16_MAX)
225 return set_error(-EINVAL, "port must fit into uint16_t");
227 r = sd_is_socket_inet(fd, family, type, listening, (uint16_t) port);
229 return set_error(r, NULL);
231 return PyBool_FromLong(r);
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)."
240 static PyObject* is_socket_unix(PyObject *self, PyObject *args) {
242 int fd, type = 0, listening = -1;
244 Py_ssize_t length = 0;
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))
252 assert(PyBytes_Check(_path));
253 if (PyBytes_AsStringAndSize(_path, &path, &length))
257 if (!PyArg_ParseTuple(args, "i|iiz#:_is_socket_unix",
258 &fd, &type, &listening, &path, &length))
262 r = sd_is_socket_unix(fd, type, listening, path, length);
264 return set_error(r, NULL);
266 return PyBool_FromLong(r);
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 */
281 #pragma GCC diagnostic push
282 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
284 #if PY_MAJOR_VERSION < 3
286 PyMODINIT_FUNC init_daemon(void) {
289 m = Py_InitModule3("_daemon", methods, module__doc__);
293 PyModule_AddIntConstant(m, "LISTEN_FDS_START", SD_LISTEN_FDS_START);
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 */
306 PyMODINIT_FUNC PyInit__daemon(void) {
309 m = PyModule_Create(&module);
313 if (PyModule_AddIntConstant(m, "LISTEN_FDS_START", SD_LISTEN_FDS_START)) {
323 #pragma GCC diagnostic pop