summaryrefslogtreecommitdiff
path: root/daemon/getvt.c
blob: 04f15d99073449bef636937b210477a5e95fad2d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include "config.h"

#include <libgnome/libgnome.h>
#include "gdm.h"
#include "misc.h"
#include "getvt.h"

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>

extern int GdmFirstVT;
extern gboolean GdmVTAllocation;

#ifdef __linux__

#include <sys/vt.h>

static int
open_vt (int vtno)
{
	char *vtname = g_strdup_printf ("/dev/tty%d", vtno);
	int fd = open (vtname, O_RDWR);
	g_free (vtname);
	return fd;
}

static int 
get_free_vt (int *vtfd)
{
	int fd, fdv;
	int vtno;
	GList *to_close_vts = NULL, *li;

	*vtfd = -1;

	fd = open ("/dev/console", O_WRONLY, 0);
	if (fd < 0)
		return -1;

	if ((ioctl(fd, VT_OPENQRY, &vtno) < 0) || (vtno == -1)) {
		close (fd);
		return -1;
	}

	fdv = open_vt (vtno);
	if (fdv < 0) {
		close (fd);
		return -1;
	}

	while (vtno < GdmFirstVT) {
		int oldvt = vtno;
		to_close_vts = g_list_prepend (to_close_vts,
					       GINT_TO_POINTER (fdv));

		if ((ioctl(fd, VT_OPENQRY, &vtno) < 0) || (vtno == -1)) {
			vtno = -1;
			goto cleanup;
		}

		if (oldvt == vtno) {
			vtno = -1;
			goto cleanup;
		}

		fdv = open_vt (vtno);
		if (fdv < 0) {
			vtno = -1;
			goto cleanup;
		}
	}

	*vtfd = fdv;

cleanup:
	for (li = to_close_vts; li != NULL; li = li->next) {
		close (GPOINTER_TO_INT (li->data));
	}
	return vtno;
}

char *
gdm_get_empty_vt_argument (int *fd, int *vt)
{
	if ( ! GdmVTAllocation) {
		*fd = -1;
		return NULL;
	}

	*vt = get_free_vt (fd);
	if (*vt < 0)
		return NULL;
	else
		return g_strdup_printf ("vt%d", *vt);
}

#else /* here this is just a stub, we don't know how to do this outside
	 of linux really */

char *
gdm_get_empty_vt_argument (int *fd, int *vt)
{
	*fd = -1;
	*vt = -1;
	return NULL;
}

#endif