chiark / gitweb /
57dc080215bc4379874f2a36d85f580e3f4c39bc
[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", (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         sd_login_monitor_flush(self->monitor);
275         Py_RETURN_NONE;
276 }
277
278
279 PyDoc_STRVAR(Monitor___enter____doc__,
280              "__enter__() -> self\n\n"
281              "Part of the context manager protocol.\n"
282              "Returns self.\n");
283 static PyObject* Monitor___enter__(PyObject *self, PyObject *args)
284 {
285     assert(self);
286     assert(!args);
287
288     Py_INCREF(self);
289     return self;
290 }
291
292
293 PyDoc_STRVAR(Monitor___exit____doc__,
294              "__exit__(type, value, traceback) -> None\n\n"
295              "Part of the context manager protocol.\n"
296              "Closes the monitor..\n");
297 static PyObject* Monitor___exit__(Monitor *self, PyObject *args)
298 {
299         return Monitor_close(self, args);
300 }
301
302
303 static PyMethodDef Monitor_methods[] = {
304     {"fileno",          (PyCFunction) Monitor_fileno, METH_NOARGS, Monitor_fileno__doc__},
305     {"get_events",      (PyCFunction) Monitor_get_events, METH_NOARGS, Monitor_get_events__doc__},
306     {"get_timeout",     (PyCFunction) Monitor_get_timeout, METH_NOARGS, Monitor_get_timeout__doc__},
307     {"get_timeout_ms",  (PyCFunction) Monitor_get_timeout_ms, METH_NOARGS, Monitor_get_timeout_ms__doc__},
308     {"close",           (PyCFunction) Monitor_close, METH_NOARGS, Monitor_close__doc__},
309     {"flush",           (PyCFunction) Monitor_flush, METH_NOARGS, Monitor_flush__doc__},
310     {"__enter__",       (PyCFunction) Monitor___enter__, METH_NOARGS, Monitor___enter____doc__},
311     {"__exit__",        (PyCFunction) Monitor___exit__, METH_VARARGS, Monitor___exit____doc__},
312     {}  /* Sentinel */
313 };
314
315 static PyTypeObject MonitorType = {
316     PyVarObject_HEAD_INIT(NULL, 0)
317     .tp_name = "login.Monitor",
318     .tp_basicsize = sizeof(Monitor),
319     .tp_dealloc = (destructor) Monitor_dealloc,
320     .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
321     .tp_doc = Monitor__doc__,
322     .tp_methods = Monitor_methods,
323     .tp_init = (initproc) Monitor_init,
324     .tp_new = PyType_GenericNew,
325 };
326
327
328 #pragma GCC diagnostic push
329 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
330
331 #if PY_MAJOR_VERSION < 3
332
333 PyMODINIT_FUNC initlogin(void) {
334         PyObject *m;
335
336         if (PyType_Ready(&MonitorType) < 0)
337                 return;
338
339         m = Py_InitModule3("login", methods, module__doc__);
340         if (m == NULL)
341                 return;
342
343         PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION);
344
345         Py_INCREF(&MonitorType);
346         PyModule_AddObject(m, "Monitor", (PyObject *) &MonitorType);
347 }
348 #else
349
350 static struct PyModuleDef module = {
351         PyModuleDef_HEAD_INIT,
352         "login", /* name of module */
353         module__doc__, /* module documentation, may be NULL */
354         -1, /* size of per-interpreter state of the module */
355         methods
356 };
357
358 PyMODINIT_FUNC PyInit_login(void) {
359         PyObject *m;
360
361         if (PyType_Ready(&MonitorType) < 0)
362                 return NULL;
363
364         m = PyModule_Create(&module);
365         if (m == NULL)
366                 return NULL;
367
368         if (PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) {
369                 Py_DECREF(m);
370                 return NULL;
371         }
372
373         Py_INCREF(&MonitorType);
374         if (PyModule_AddObject(m, "Monitor", (PyObject *) &MonitorType)) {
375                 Py_DECREF(&MonitorType);
376                 Py_DECREF(m);
377                 return NULL;
378         }
379
380         return m;
381 }
382
383 #endif
384
385 #pragma GCC diagnostic pop