chiark / gitweb /
bus: properly handle if new objects are installed in the node tree while we are dispa...
[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 {
145         sd_login_monitor_unref(self->monitor);
146         Py_TYPE(self)->tp_free((PyObject*)self);
147 }
148
149 PyDoc_STRVAR(Monitor__doc__,
150              "Monitor([category]) -> ...\n\n"
151              "Monitor may be used to monitor login sessions, users, seats,\n"
152              "and virtual machines/containers. Monitor provides a file\n"
153              "descriptor which can be integrated in an external event loop.\n"
154              "See man:sd_login_monitor_new(3) for the details about what\n"
155              "can be monitored.");
156 static int Monitor_init(Monitor *self, PyObject *args, PyObject *keywds)
157 {
158         const char *category = NULL;
159         int r;
160
161         static const char* const kwlist[] = {"category", NULL};
162         if (!PyArg_ParseTupleAndKeywords(args, keywds, "|z:__init__", (char**) kwlist,
163                                          &category))
164                 return -1;
165
166         Py_BEGIN_ALLOW_THREADS
167         r = sd_login_monitor_new(category, &self->monitor);
168         Py_END_ALLOW_THREADS
169
170         return set_error(r, NULL, "Invalid category");
171 }
172
173
174 PyDoc_STRVAR(Monitor_fileno__doc__,
175              "fileno() -> int\n\n"
176              "Get a file descriptor to poll for events.\n"
177              "This method wraps sd_login_monitor_get_fd(3).");
178 static PyObject* Monitor_fileno(Monitor *self, PyObject *args)
179 {
180         int fd = sd_login_monitor_get_fd(self->monitor);
181         set_error(fd, NULL, NULL);
182         if (fd < 0)
183                 return NULL;
184         return long_FromLong(fd);
185 }
186
187
188 PyDoc_STRVAR(Monitor_get_events__doc__,
189              "get_events() -> int\n\n"
190              "Returns a mask of poll() events to wait for on the file\n"
191              "descriptor returned by .fileno().\n\n"
192              "See man:sd_login_monitor_get_events(3) for further discussion.");
193 static PyObject* Monitor_get_events(Monitor *self, PyObject *args)
194 {
195         int r = sd_login_monitor_get_events(self->monitor);
196         set_error(r, NULL, NULL);
197         if (r < 0)
198                 return NULL;
199         return long_FromLong(r);
200 }
201
202
203 PyDoc_STRVAR(Monitor_get_timeout__doc__,
204              "get_timeout() -> int or None\n\n"
205              "Returns a timeout value for usage in poll(), the time since the\n"
206              "epoch of clock_gettime(2) in microseconds, or None if no timeout\n"
207              "is necessary.\n\n"
208              "The return value must be converted to a relative timeout in\n"
209              "milliseconds if it is to be used as an argument for poll().\n"
210              "See man:sd_login_monitor_get_timeout(3) for further discussion.");
211 static PyObject* Monitor_get_timeout(Monitor *self, PyObject *args)
212 {
213         int r;
214         uint64_t t;
215
216         r = sd_login_monitor_get_timeout(self->monitor, &t);
217         set_error(r, NULL, NULL);
218         if (r < 0)
219                 return NULL;
220
221         if (t == (uint64_t) -1)
222                 Py_RETURN_NONE;
223
224         assert_cc(sizeof(unsigned long long) == sizeof(t));
225         return PyLong_FromUnsignedLongLong(t);
226 }
227
228
229 PyDoc_STRVAR(Monitor_get_timeout_ms__doc__,
230              "get_timeout_ms() -> int\n\n"
231              "Returns a timeout value suitable for usage in poll(), the value\n"
232              "returned by .get_timeout() converted to relative ms, or -1 if\n"
233              "no timeout is necessary.");
234 static PyObject* Monitor_get_timeout_ms(Monitor *self, PyObject *args)
235 {
236         int r;
237         uint64_t t;
238
239         r = sd_login_monitor_get_timeout(self->monitor, &t);
240         set_error(r, NULL, NULL);
241         if (r < 0)
242                 return NULL;
243
244         return absolute_timeout(t);
245 }
246
247
248 PyDoc_STRVAR(Monitor_close__doc__,
249              "close() -> None\n\n"
250              "Free resources allocated by this Monitor object.\n"
251              "This method invokes sd_login_monitor_unref().\n"
252              "See man:sd_login_monitor_unref(3).");
253 static PyObject* Monitor_close(Monitor *self, PyObject *args)
254 {
255         assert(self);
256         assert(!args);
257
258         sd_login_monitor_unref(self->monitor);
259         self->monitor = NULL;
260         Py_RETURN_NONE;
261 }
262
263
264 PyDoc_STRVAR(Monitor_flush__doc__,
265              "flush() -> None\n\n"
266              "Reset the wakeup state of the monitor object.\n"
267              "This method invokes sd_login_monitor_flush().\n"
268              "See man:sd_login_monitor_flush(3).");
269 static PyObject* Monitor_flush(Monitor *self, PyObject *args)
270 {
271         assert(self);
272         assert(!args);
273
274         Py_BEGIN_ALLOW_THREADS
275         sd_login_monitor_flush(self->monitor);
276         Py_END_ALLOW_THREADS
277         Py_RETURN_NONE;
278 }
279
280
281 PyDoc_STRVAR(Monitor___enter____doc__,
282              "__enter__() -> self\n\n"
283              "Part of the context manager protocol.\n"
284              "Returns self.\n");
285 static PyObject* Monitor___enter__(PyObject *self, PyObject *args)
286 {
287         assert(self);
288         assert(!args);
289
290         Py_INCREF(self);
291         return self;
292 }
293
294
295 PyDoc_STRVAR(Monitor___exit____doc__,
296              "__exit__(type, value, traceback) -> None\n\n"
297              "Part of the context manager protocol.\n"
298              "Closes the monitor..\n");
299 static PyObject* Monitor___exit__(Monitor *self, PyObject *args)
300 {
301         return Monitor_close(self, args);
302 }
303
304
305 static PyMethodDef Monitor_methods[] = {
306         {"fileno",          (PyCFunction) Monitor_fileno, METH_NOARGS, Monitor_fileno__doc__},
307         {"get_events",      (PyCFunction) Monitor_get_events, METH_NOARGS, Monitor_get_events__doc__},
308         {"get_timeout",     (PyCFunction) Monitor_get_timeout, METH_NOARGS, Monitor_get_timeout__doc__},
309         {"get_timeout_ms",  (PyCFunction) Monitor_get_timeout_ms, METH_NOARGS, Monitor_get_timeout_ms__doc__},
310         {"close",           (PyCFunction) Monitor_close, METH_NOARGS, Monitor_close__doc__},
311         {"flush",           (PyCFunction) Monitor_flush, METH_NOARGS, Monitor_flush__doc__},
312         {"__enter__",       (PyCFunction) Monitor___enter__, METH_NOARGS, Monitor___enter____doc__},
313         {"__exit__",        (PyCFunction) Monitor___exit__, METH_VARARGS, Monitor___exit____doc__},
314         {}  /* Sentinel */
315 };
316
317 static PyTypeObject MonitorType = {
318         PyVarObject_HEAD_INIT(NULL, 0)
319         .tp_name = "login.Monitor",
320         .tp_basicsize = sizeof(Monitor),
321         .tp_dealloc = (destructor) Monitor_dealloc,
322         .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
323         .tp_doc = Monitor__doc__,
324         .tp_methods = Monitor_methods,
325         .tp_init = (initproc) Monitor_init,
326         .tp_new = PyType_GenericNew,
327 };
328
329
330 #pragma GCC diagnostic push
331 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
332
333 #if PY_MAJOR_VERSION < 3
334
335 PyMODINIT_FUNC initlogin(void) {
336         PyObject *m;
337
338         if (PyType_Ready(&MonitorType) < 0)
339                 return;
340
341         m = Py_InitModule3("login", methods, module__doc__);
342         if (m == NULL)
343                 return;
344
345         PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION);
346
347         Py_INCREF(&MonitorType);
348         PyModule_AddObject(m, "Monitor", (PyObject *) &MonitorType);
349 }
350 #else
351
352 static struct PyModuleDef module = {
353         PyModuleDef_HEAD_INIT,
354         "login", /* name of module */
355         module__doc__, /* module documentation, may be NULL */
356         -1, /* size of per-interpreter state of the module */
357         methods
358 };
359
360 PyMODINIT_FUNC PyInit_login(void) {
361         PyObject *m;
362
363         if (PyType_Ready(&MonitorType) < 0)
364                 return NULL;
365
366         m = PyModule_Create(&module);
367         if (m == NULL)
368                 return NULL;
369
370         if (PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) {
371                 Py_DECREF(m);
372                 return NULL;
373         }
374
375         Py_INCREF(&MonitorType);
376         if (PyModule_AddObject(m, "Monitor", (PyObject *) &MonitorType)) {
377                 Py_DECREF(&MonitorType);
378                 Py_DECREF(m);
379                 return NULL;
380         }
381
382         return m;
383 }
384
385 #endif
386
387 #pragma GCC diagnostic pop