1 /* new.c -- console allocation plugin for vlock,
2 * the VT locking program for linux
4 * This program is copyright (C) 2007 Frank Benkstein, and is free
5 * software which is freely distributable under the terms of the
6 * GNU General Public License version 2, included as the file COPYING in this
7 * distribution. It is NOT public domain software, and any
8 * redistribution not permitted by the GNU General Public License is
9 * expressly forbidden without prior written permission from
18 #include <sys/ioctl.h>
20 #include <sys/types.h>
22 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
23 #include <sys/consio.h>
28 #include "vlock_plugin.h"
30 const char *preceeds
[] = { "all", NULL
};
31 const char *requires
[] = { "all", NULL
};
33 /* name of the virtual console device */
34 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
35 #define CONSOLE "/dev/ttyv0"
37 #define CONSOLE "/dev/tty0"
39 /* template for the device of a given virtual console */
40 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
41 #define VTNAME "/dev/ttyv%x"
43 #define VTNAME "/dev/tty%d"
46 /* Get the currently active console from the given
47 * console file descriptor. Returns console number
48 * (starting from 1) on success, -1 on error. */
49 #if defined(__FreeBSD__) || defined (__FreeBSD_kernel__)
50 static int get_active_console(int consfd
)
54 if (ioctl(consfd
, VT_GETACTIVE
, &n
) == 0)
60 static int get_active_console(int consfd
)
62 struct vt_stat vtstate
;
64 /* get the virtual console status */
65 if (ioctl(consfd
, VT_GETSTATE
, &vtstate
) == 0)
66 return vtstate
.v_active
;
72 /* Get the device name for the given console number.
73 * Returns the device name or NULL on error. */
74 static char *get_console_name(int n
)
76 static char name
[sizeof VTNAME
+ 2];
82 /* format the virtual terminal filename from the number */
83 #if defined(__FreeBSD__) || defined (__FreeBSD_kernel__)
84 namelen
= snprintf(name
, sizeof name
, VTNAME
, n
- 1);
86 namelen
= snprintf(name
, sizeof name
, VTNAME
, n
);
89 if (namelen
> sizeof name
) {
90 fprintf(stderr
, "vlock-new: virtual terminal number too large\n");
97 /* Change to the given console number using the given console
99 static int activate_console(int consfd
, int vtno
)
101 int c
= ioctl(consfd
, VT_ACTIVATE
, vtno
);
103 return c
< 0 ? c
: ioctl(consfd
, VT_WAITACTIVE
, vtno
);
106 struct new_console_context
{
115 /* Run switch to a new console and redirect stdio there. */
116 bool vlock_start(void **ctx_ptr
)
118 struct new_console_context
*ctx
;
122 /* Allocate the context. */
123 if ((ctx
= malloc(sizeof *ctx
)) == NULL
)
126 /* Try stdin first. */
127 ctx
->consfd
= dup(STDIN_FILENO
);
129 /* Get the number of the currently active console. */
130 ctx
->old_vtno
= get_active_console(ctx
->consfd
);
132 if (ctx
->old_vtno
< 0) {
133 /* stdin is does not a virtual console. */
134 (void) close(ctx
->consfd
);
136 /* XXX: add optional PAM check here */
138 /* Open the virtual console directly. */
139 if ((ctx
->consfd
= open(CONSOLE
, O_RDWR
)) < 0) {
140 perror("vlock-new: cannot open virtual console");
144 /* Get the number of the currently active console, again. */
145 ctx
->old_vtno
= get_active_console(ctx
->consfd
);
147 if (ctx
->old_vtno
< 0) {
148 perror("vlock-new: could not get the currently active console");
153 /* Get a free virtual terminal number. */
154 if (ioctl(ctx
->consfd
, VT_OPENQRY
, &ctx
->new_vtno
) < 0) {
155 perror("vlock-new: could not find a free virtual terminal");
159 /* Get the device name for the new virtual console. */
160 vtname
= get_console_name(ctx
->new_vtno
);
162 /* Open the free virtual terminal. */
163 if ((vtfd
= open(vtname
, O_RDWR
)) < 0) {
164 perror("vlock-new: cannot open new console");
168 /* Work around stupid X11 bug: When switching immediately after the command
169 * is entered, the enter button may get stuck. */
170 if (getenv("DISPLAY") != NULL
)
173 /* Switch to the new virtual terminal. */
174 if (activate_console(ctx
->consfd
, ctx
->new_vtno
) < 0) {
175 perror("vlock-new: could not activate new terminal");
179 /* Save the stdio file descriptors. */
180 ctx
->saved_stdin
= dup(STDIN_FILENO
);
181 ctx
->saved_stdout
= dup(STDOUT_FILENO
);
182 ctx
->saved_stderr
= dup(STDERR_FILENO
);
184 /* Redirect stdio to virtual terminal. */
185 (void) dup2(vtfd
, STDIN_FILENO
);
186 (void) dup2(vtfd
, STDOUT_FILENO
);
187 (void) dup2(vtfd
, STDERR_FILENO
);
189 /* Close virtual terminal file descriptor. */
200 /* Redirect stdio back und switch to the previous console. */
201 bool vlock_end(void **ctx_ptr
)
203 struct new_console_context
*ctx
= *ctx_ptr
;
208 /* Restore saved stdio file descriptors. */
209 (void) dup2(ctx
->saved_stdin
, STDIN_FILENO
);
210 (void) dup2(ctx
->saved_stdout
, STDOUT_FILENO
);
211 (void) dup2(ctx
->saved_stderr
, STDERR_FILENO
);
213 /* Switch back to previous virtual terminal. */
214 if (activate_console(ctx
->consfd
, ctx
->old_vtno
) < 0)
215 perror("vlock-new: could not activate previous console");
217 #if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
218 /* Deallocate virtual terminal. */
219 if (ioctl(ctx
->consfd
, VT_DISALLOCATE
, ctx
->new_vtno
) < 0)
220 perror("vlock-new: could not disallocate console");
223 (void) close(ctx
->consfd
);