]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - src/vt.c
Re-enable SIGPIPE for children so they have default behaviour
[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_tty (void)
30 {
31     int fd;
32
33     fd = g_open ("/dev/tty0", O_RDONLY | O_NOCTTY, 0);
34     if (fd < 0)
35         g_warning ("Error opening /dev/tty0: %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     return access ("/dev/tty0", F_OK) == 0 &&
46            access ("/sys/class/tty/tty0/active", F_OK) == 0;
47 }
48
49 gint
50 vt_get_active (void)
51 {
52 #ifdef __linux__
53     gint tty_fd;
54     gint active = -1;
55
56     /* Pretend always active */
57     if (getuid () != 0)
58         return 1;
59
60     tty_fd = open_tty ();
61     if (tty_fd >= 0)
62     {
63         struct vt_stat vt_state = { 0 };
64         if (ioctl (tty_fd, VT_GETSTATE, &vt_state) < 0)
65             g_warning ("Error using VT_GETSTATE on /dev/tty0: %s", strerror (errno));
66         else
67             active = vt_state.v_active;
68         close (tty_fd);
69     }
70
71     return active;
72 #else
73     return -1;
74 #endif
75 }
76
77 void
78 vt_set_active (gint number)
79 {
80 #ifdef __linux__
81     gint tty_fd;
82
83     g_debug ("Activating VT %d", number);
84
85     /* Pretend always active */
86     if (getuid () != 0)
87         return;
88
89     tty_fd = open_tty ();
90     if (tty_fd >= 0)
91     {
92         int n = number;
93
94         if (ioctl (tty_fd, VT_ACTIVATE, n) < 0)
95             g_warning ("Error using VT_ACTIVATE %d on /dev/tty0: %s", n, strerror (errno));
96
97         /* Wait for the VT to become active to avoid a suspected
98          * race condition somewhere between LightDM, X, ConsoleKit and the kernel.
99          * See https://bugs.launchpad.net/bugs/851612 */
100         if (ioctl (tty_fd, VT_WAITACTIVE) < 0)
101             g_warning ("Error using VT_WAITACTIVE %d on /dev/tty0: %s", n, strerror (errno));
102
103         close (tty_fd);
104     }
105 #endif
106 }
107
108 static gboolean
109 vt_is_used (gint number)
110 {
111     GList *link;
112
113     for (link = used_vts; link; link = link->next)
114     {
115         int n = GPOINTER_TO_INT (link->data);
116         if (n == number)
117             return TRUE;
118     }
119
120     return FALSE;
121 }
122
123 gint
124 vt_get_min (void)
125 {
126     gint number;
127
128     number = config_get_integer (config_get_instance (), "LightDM", "minimum-vt");
129     if (number < 1)
130         number = 1;
131
132     return number;
133 }
134
135 gint
136 vt_get_unused (void)
137 {
138     gint number;
139
140     if (getuid () != 0)
141         return -1;
142
143     number = vt_get_min ();
144     while (vt_is_used (number))
145         number++;
146
147     return number;
148 }
149
150 void
151 vt_ref (gint number)
152 {
153     g_debug ("Using VT %d", number);
154     used_vts = g_list_append (used_vts, GINT_TO_POINTER (number));
155 }
156
157 void
158 vt_unref (gint number)
159 {
160     g_debug ("Releasing VT %d", number);
161     used_vts = g_list_remove (used_vts, GINT_TO_POINTER (number));
162 }