chiark / gitweb /
macro: introduce nice macro for disabling -Wmissing-prototypes warnigs
[elogind.git] / src / python-systemd / login.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 "systemd/sd-login.h"
29 #include "pyutil.h"
30 #include "util.h"
31 #include "strv.h"
32
33 PyDoc_STRVAR(module__doc__,
34              "Python interface to the libsystemd-login library."
35 );
36
37 #define helper(name)                                                    \
38 static PyObject* name(PyObject *self, PyObject *args) {                 \
39         _cleanup_strv_free_ char **list = NULL;                         \
40         int r;                                                          \
41         PyObject *ans;                                                  \
42                                                                         \
43         assert(args == NULL);                                           \
44                                                                         \
45         r = sd_get_##name(&list);                                       \
46         if (r < 0) {                                                    \
47                 errno = -r;                                             \
48                 return PyErr_SetFromErrno(PyExc_IOError);               \
49         }                                                               \
50                                                                         \
51         ans = PyList_New(r);                                            \
52         if (!ans)                                                       \
53                 return NULL;                                            \
54                                                                         \
55         for (r--; r >= 0; r--) {                                        \
56                 PyObject *s = unicode_FromString(list[r]);              \
57                 if (!s) {                                               \
58                         Py_DECREF(ans);                                 \
59                         return NULL;                                    \
60                 }                                                       \
61                                                                         \
62                 PyList_SetItem(ans, r, s);                              \
63         }                                                               \
64                                                                         \
65         return ans;                                                     \
66 }
67
68 helper(seats)
69 helper(sessions)
70 helper(machine_names)
71 #undef helper
72
73 static PyObject* uids(PyObject *self, PyObject *args) {
74         _cleanup_free_ uid_t *list = NULL;
75         int r;
76         PyObject *ans;
77
78         assert(args == NULL);
79
80         r = sd_get_uids(&list);
81         if (r < 0) {
82                 errno = -r;
83                 return PyErr_SetFromErrno(PyExc_IOError);
84         }
85
86         ans = PyList_New(r);
87         if (!ans)
88                 return NULL;
89
90         for (r--; r >= 0; r--) {
91                 PyObject *s = long_FromLong(list[r]);
92                 if (!s) {
93                         Py_DECREF(ans);
94                         return NULL;
95                 }
96
97                 PyList_SetItem(ans, r, s);
98         }
99
100         return ans;
101 }
102
103 PyDoc_STRVAR(seats__doc__,
104              "seats() -> list\n\n"
105              "Returns a list of currently available local seats.\n"
106              "Wraps sd_get_seats(3)."
107 );
108
109 PyDoc_STRVAR(sessions__doc__,
110              "sessions() -> list\n\n"
111              "Returns a list of current login sessions.\n"
112              "Wraps sd_get_sessions(3)."
113 );
114
115 PyDoc_STRVAR(machine_names__doc__,
116              "machine_names() -> list\n\n"
117              "Returns a list of currently running virtual machines\n"
118              "and containers on the system.\n"
119              "Wraps sd_get_machine_names(3)."
120 );
121
122 PyDoc_STRVAR(uids__doc__,
123              "uids() -> list\n\n"
124              "Returns a list of uids of users who currently have login sessions.\n"
125              "Wraps sd_get_uids(3)."
126 );
127
128 static PyMethodDef methods[] = {
129         { "seats", seats, METH_NOARGS, seats__doc__},
130         { "sessions", sessions, METH_NOARGS, sessions__doc__},
131         { "machine_names", machine_names, METH_NOARGS, machine_names__doc__},
132         { "uids", uids, METH_NOARGS, uids__doc__},
133         {} /* Sentinel */
134 };
135
136
137 typedef struct {
138         PyObject_HEAD
139         sd_login_monitor *monitor;
140 } Monitor;
141 static PyTypeObject MonitorType;
142
143 static void Monitor_dealloc(Monitor* self) {
144         sd_login_monitor_unref(self->monitor);
145         Py_TYPE(self)->tp_free((PyObject*)self);
146 }
147
148 PyDoc_STRVAR(Monitor__doc__,
149              "Monitor([category]) -> ...\n\n"
150              "Monitor may be used to monitor login sessions, users, seats,\n"
151              "and virtual machines/containers. Monitor provides a file\n"
152              "descriptor which can be integrated in an external event loop.\n"
153              "See man:sd_login_monitor_new(3) for the details about what\n"
154              "can be monitored.");
155 static int Monitor_init(Monitor *self, PyObject *args, PyObject *keywds) {
156         const char *category = NULL;
157         int r;
158
159         static const char* const kwlist[] = {"category", NULL};
160         if (!PyArg_ParseTupleAndKeywords(args, keywds, "|z:__init__", (char**) kwlist,
161                                          &category))
162                 return -1;
163
164         Py_BEGIN_ALLOW_THREADS
165         r = sd_login_monitor_new(category, &self->monitor);
166         Py_END_ALLOW_THREADS
167
168         return set_error(r, NULL, "Invalid category");
169 }
170
171
172 PyDoc_STRVAR(Monitor_fileno__doc__,
173              "fileno() -> int\n\n"
174              "Get a file descriptor to poll for events.\n"
175              "This method wraps sd_login_monitor_get_fd(3).");
176 static PyObject* Monitor_fileno(Monitor *self, PyObject *args) {
177         int fd = sd_login_monitor_get_fd(self->monitor);
178         set_error(fd, NULL, NULL);
179         if (fd < 0)
180                 return NULL;
181         return long_FromLong(fd);
182 }
183
184
185 PyDoc_STRVAR(Monitor_get_events__doc__,
186              "get_events() -> int\n\n"
187              "Returns a mask of poll() events to wait for on the file\n"
188              "descriptor returned by .fileno().\n\n"
189              "See man:sd_login_monitor_get_events(3) for further discussion.");
190 static PyObject* Monitor_get_events(Monitor *self, PyObject *args) {
191         int r = sd_login_monitor_get_events(self->monitor);
192         set_error(r, NULL, NULL);
193         if (r < 0)
194                 return NULL;
195         return long_FromLong(r);
196 }
197
198
199 PyDoc_STRVAR(Monitor_get_timeout__doc__,
200              "get_timeout() -> int or None\n\n"
201              "Returns a timeout value for usage in poll(), the time since the\n"
202              "epoch of clock_gettime(2) in microseconds, or None if no timeout\n"
203              "is necessary.\n\n"
204              "The return value must be converted to a relative timeout in\n"
205              "milliseconds if it is to be used as an argument for poll().\n"
206              "See man:sd_login_monitor_get_timeout(3) for further discussion.");
207 static PyObject* Monitor_get_timeout(Monitor *self, PyObject *args) {
208         int r;
209         uint64_t t;
210
211         r = sd_login_monitor_get_timeout(self->monitor, &t);
212         set_error(r, NULL, NULL);
213         if (r < 0)
214                 return NULL;
215
216         if (t == (uint64_t) -1)
217                 Py_RETURN_NONE;
218
219         assert_cc(sizeof(unsigned long long) == sizeof(t));
220         return PyLong_FromUnsignedLongLong(t);
221 }
222
223
224 PyDoc_STRVAR(Monitor_get_timeout_ms__doc__,
225              "get_timeout_ms() -> int\n\n"
226              "Returns a timeout value suitable for usage in poll(), the value\n"
227              "returned by .get_timeout() converted to relative ms, or -1 if\n"
228              "no timeout is necessary.");
229 static PyObject* Monitor_get_timeout_ms(Monitor *self, PyObject *args) {
230         int r;
231         uint64_t t;
232
233         r = sd_login_monitor_get_timeout(self->monitor, &t);
234         set_error(r, NULL, NULL);
235         if (r < 0)
236                 return NULL;
237
238         return absolute_timeout(t);
239 }
240
241
242 PyDoc_STRVAR(Monitor_close__doc__,
243              "close() -> None\n\n"
244              "Free resources allocated by this Monitor object.\n"
245              "This method invokes sd_login_monitor_unref().\n"
246              "See man:sd_login_monitor_unref(3).");
247 static PyObject* Monitor_close(Monitor *self, PyObject *args) {
248         assert(self);
249         assert(!args);
250
251         sd_login_monitor_unref(self->monitor);
252         self->monitor = NULL;
253         Py_RETURN_NONE;
254 }
255
256
257 PyDoc_STRVAR(Monitor_flush__doc__,
258              "flush() -> None\n\n"
259              "Reset the wakeup state of the monitor object.\n"
260              "This method invokes sd_login_monitor_flush().\n"
261              "See man:sd_login_monitor_flush(3).");
262 static PyObject* Monitor_flush(Monitor *self, PyObject *args) {
263         assert(self);
264         assert(!args);
265
266         Py_BEGIN_ALLOW_THREADS
267         sd_login_monitor_flush(self->monitor);
268         Py_END_ALLOW_THREADS
269         Py_RETURN_NONE;
270 }
271
272
273 PyDoc_STRVAR(Monitor___enter____doc__,
274              "__enter__() -> self\n\n"
275              "Part of the context manager protocol.\n"
276              "Returns self.\n");
277 static PyObject* Monitor___enter__(PyObject *self, PyObject *args) {
278         assert(self);
279         assert(!args);
280
281         Py_INCREF(self);
282         return self;
283 }
284
285
286 PyDoc_STRVAR(Monitor___exit____doc__,
287              "__exit__(type, value, traceback) -> None\n\n"
288              "Part of the context manager protocol.\n"
289              "Closes the monitor..\n");
290 static PyObject* Monitor___exit__(Monitor *self, PyObject *args) {
291         return Monitor_close(self, args);
292 }
293
294
295 static PyMethodDef Monitor_methods[] = {
296         {"fileno",          (PyCFunction) Monitor_fileno, METH_NOARGS, Monitor_fileno__doc__},
297         {"get_events",      (PyCFunction) Monitor_get_events, METH_NOARGS, Monitor_get_events__doc__},
298         {"get_timeout",     (PyCFunction) Monitor_get_timeout, METH_NOARGS, Monitor_get_timeout__doc__},
299         {"get_timeout_ms",  (PyCFunction) Monitor_get_timeout_ms, METH_NOARGS, Monitor_get_timeout_ms__doc__},
300         {"close",           (PyCFunction) Monitor_close, METH_NOARGS, Monitor_close__doc__},
301         {"flush",           (PyCFunction) Monitor_flush, METH_NOARGS, Monitor_flush__doc__},
302         {"__enter__",       (PyCFunction) Monitor___enter__, METH_NOARGS, Monitor___enter____doc__},
303         {"__exit__",        (PyCFunction) Monitor___exit__, METH_VARARGS, Monitor___exit____doc__},
304         {}  /* Sentinel */
305 };
306
307 static PyTypeObject MonitorType = {
308         PyVarObject_HEAD_INIT(NULL, 0)
309         .tp_name = "login.Monitor",
310         .tp_basicsize = sizeof(Monitor),
311         .tp_dealloc = (destructor) Monitor_dealloc,
312         .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
313         .tp_doc = Monitor__doc__,
314         .tp_methods = Monitor_methods,
315         .tp_init = (initproc) Monitor_init,
316         .tp_new = PyType_GenericNew,
317 };
318
319 #if PY_MAJOR_VERSION < 3
320
321 DISABLE_WARNING_MISSING_PROTOTYPES;
322 PyMODINIT_FUNC initlogin(void) {
323         PyObject *m;
324
325         if (PyType_Ready(&MonitorType) < 0)
326                 return;
327
328         m = Py_InitModule3("login", methods, module__doc__);
329         if (m == NULL)
330                 return;
331
332         PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION);
333
334         Py_INCREF(&MonitorType);
335         PyModule_AddObject(m, "Monitor", (PyObject *) &MonitorType);
336 }
337 REENABLE_WARNING;
338
339 #else
340
341 static struct PyModuleDef module = {
342         PyModuleDef_HEAD_INIT,
343         "login", /* name of module */
344         module__doc__, /* module documentation, may be NULL */
345         -1, /* size of per-interpreter state of the module */
346         methods
347 };
348
349 DISABLE_WARNING_MISSING_PROTOTYPES;
350 PyMODINIT_FUNC PyInit_login(void) {
351         PyObject *m;
352
353         if (PyType_Ready(&MonitorType) < 0)
354                 return NULL;
355
356         m = PyModule_Create(&module);
357         if (m == NULL)
358                 return NULL;
359
360         if (PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) {
361                 Py_DECREF(m);
362                 return NULL;
363         }
364
365         Py_INCREF(&MonitorType);
366         if (PyModule_AddObject(m, "Monitor", (PyObject *) &MonitorType)) {
367                 Py_DECREF(&MonitorType);
368                 Py_DECREF(m);
369                 return NULL;
370         }
371
372         return m;
373 }
374 REENABLE_WARNING;
375
376 #endif