]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - src/vt.c
* Generate login and logout events that can be used by the Linux Audit tools
[sojka/lightdm.git] / src / vt.c
1 /*
2  * Copyright (C) 2010-2011 Robert Ancell.
3  * Author: Robert Ancell <robert.ancell@canonical.com>
4  *
5  * This program is free software: you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License as published by the Free Software
7  * Foundation, either version 3 of the License, or (at your option) any later
8  * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
9  * license.
10  */
11
12 #include <string.h>
13 #include <errno.h>
14 #include <unistd.h>
15 #include <glib/gstdio.h>
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 #include <sys/ioctl.h>
19 #ifdef __linux__
20 #include <linux/vt.h>
21 #endif
22
23 #include "vt.h"
24 #include "configuration.h"
25
26 static GList *used_vts = NULL;
27
28 static gint
29 open_console (void)
30 {
31     int fd;
32
33     fd = g_open ("/dev/console", O_RDONLY | O_NOCTTY, 0);
34     if (fd < 0)
35         g_warning ("Error opening /dev/console: %s", strerror (errno));
36     return fd;
37 }
38
39 gboolean
40 vt_can_multi_seat (void)
41 {
42     /* Quick check to see if we can multi seat.  This is intentionally the
43        same check logind does, just without actually reading from the files.
44        Existence will prove whether we have CONFIG_VT built into the kernel.
45        (Reading /dev/console like the rest of the code in this file isn't
46        sufficient -- it may still exist if tty0 doesn't and it may not work
47        in situations where tty0 does exist and thus logind will think we are
48        multi seat.) */
49     return access ("/dev/tty0", F_OK) == 0 &&
50            access ("/sys/class/tty/tty0/active", F_OK) == 0;
51 }
52
53 gint
54 vt_get_active (void)
55 {
56 #ifdef __linux__
57     gint console_fd;
58     gint active = -1;
59
60     /* Pretend always active */
61     if (getuid () != 0)
62         return 1;
63
64     console_fd = open_console ();
65     if (console_fd >= 0)
66     {
67         struct vt_stat console_state = { 0 };
68         if (ioctl (console_fd, VT_GETSTATE, &console_state) < 0)
69             g_warning ("Error using VT_GETSTATE on /dev/console: %s", strerror (errno));
70         else
71             active = console_state.v_active;
72         close (console_fd);
73     }
74
75     return active;
76 #else
77     return -1;
78 #endif
79 }
80
81 void
82 vt_set_active (gint number)
83 {
84 #ifdef __linux__
85     gint console_fd;
86
87     g_debug ("Activating VT %d", number);
88
89     /* Pretend always active */
90     if (getuid () != 0)
91         return;
92
93     console_fd = open_console ();
94     if (console_fd >= 0)
95     {
96         int n = number;
97
98         if (ioctl (console_fd, VT_ACTIVATE, n) < 0)
99             g_warning ("Error using VT_ACTIVATE %d on /dev/console: %s", n, strerror (errno));
100
101         /* Wait for the VT to become active to avoid a suspected
102          * race condition somewhere between LightDM, X, ConsoleKit and the kernel.
103          * See https://bugs.launchpad.net/bugs/851612 */
104         if (ioctl (console_fd, VT_WAITACTIVE) < 0)
105             g_warning ("Error using VT_WAITACTIVE %d on /dev/console: %s", n, strerror (errno));
106
107         close (console_fd);
108     }
109 #endif
110 }
111
112 static gboolean
113 vt_is_used (gint number)
114 {
115     GList *link;
116
117     for (link = used_vts; link; link = link->next)
118     {
119         int n = GPOINTER_TO_INT (link->data);
120         if (n == number)
121             return TRUE;
122     }
123
124     return FALSE;
125 }
126
127 gint
128 vt_get_min (void)
129 {
130     gint number;
131
132     number = config_get_integer (config_get_instance (), "LightDM", "minimum-vt");
133     if (number < 1)
134         number = 1;
135
136     return number;
137 }
138
139 gint
140 vt_get_unused (void)
141 {
142     gint number;
143
144     if (getuid () != 0)
145         return -1;
146
147     number = vt_get_min ();
148     while (vt_is_used (number))
149         number++;
150
151     return number;
152 }
153
154 void
155 vt_ref (gint number)
156 {
157     g_debug ("Using VT %d", number);
158     used_vts = g_list_append (used_vts, GINT_TO_POINTER (number));
159 }
160
161 void
162 vt_unref (gint number)
163 {
164     g_debug ("Releasing VT %d", number);
165     used_vts = g_list_remove (used_vts, GINT_TO_POINTER (number));
166 }