1#include <stdio.h>
2#include <stdlib.h>
3#include <fcntl.h>
4#include <string.h>
5#include <linux/kd.h>
6#include <linux/vt.h>
7#include <errno.h>
8#include <pthread.h>
9#include <unistd.h>
10#include <sys/ioctl.h>
11
12static int activate_thread_switch_vc;
13static void *activate_thread(void *arg)
14{
15    int res;
16    int fd = (int)arg;
17    while(activate_thread_switch_vc >= 0) {
18        do {
19            res = ioctl(fd, VT_ACTIVATE, (void*)activate_thread_switch_vc);
20        } while(res < 0 && errno == EINTR);
21        if (res < 0) {
22            fprintf(stderr, "ioctl( vcfd, VT_ACTIVATE, vtnum) failed, %d %d %s for %d\n", res, errno, strerror(errno), activate_thread_switch_vc);
23        }
24        if(activate_thread_switch_vc >= 0)
25            sleep(1);
26    }
27    return NULL;
28}
29
30
31int setconsole_main(int argc, char *argv[])
32{
33    int c;
34    int fd;
35    int res;
36
37    int mode = -1;
38    int new_vc = 0;
39    int close_vc = 0;
40    int switch_vc = -1;
41    int printvc = 0;
42    char *ttydev = "/dev/tty0";
43
44    do {
45        c = getopt(argc, argv, "d:gtncv:poh");
46        if (c == EOF)
47            break;
48        switch (c) {
49        case 'd':
50            ttydev = optarg;
51            break;
52        case 'g':
53            if(mode == KD_TEXT) {
54                fprintf(stderr, "%s: cannot specify both -g and -t\n", argv[0]);
55                exit(1);
56            }
57            mode = KD_GRAPHICS;
58            break;
59        case 't':
60            if(mode == KD_GRAPHICS) {
61                fprintf(stderr, "%s: cannot specify both -g and -t\n", argv[0]);
62                exit(1);
63            }
64            mode = KD_TEXT;
65            break;
66        case 'n':
67            new_vc = 1;
68            break;
69        case 'c':
70            close_vc = 1;
71            break;
72        case 'v':
73            switch_vc = atoi(optarg);
74            break;
75        case 'p':
76            printvc |= 1;
77            break;
78        case 'o':
79            printvc |= 2;
80            break;
81        case 'h':
82            fprintf(stderr, "%s [-d <dev>] [-v <vc>] [-gtncpoh]\n"
83                    "  -d <dev>   Use <dev> instead of /dev/tty0\n"
84                    "  -v <vc>    Switch to virtual console <vc>\n"
85                    "  -g         Switch to graphics mode\n"
86                    "  -t         Switch to text mode\n"
87                    "  -n         Create and switch to new virtual console\n"
88                    "  -c         Close unused virtual consoles\n"
89                    "  -p         Print new virtual console\n"
90                    "  -o         Print old virtual console\n"
91                    "  -h         Print help\n", argv[0]);
92            return -1;
93        case '?':
94            fprintf(stderr, "%s: invalid option -%c\n",
95                argv[0], optopt);
96            exit(1);
97        }
98    } while (1);
99    if(mode == -1 && new_vc == 0 && close_vc == 0 && switch_vc == -1 && printvc == 0) {
100        fprintf(stderr,"%s [-d <dev>] [-v <vc>] [-gtncpoh]\n", argv[0]);
101        return -1;
102    }
103
104    fd = open(ttydev, O_RDWR | O_SYNC);
105    if (fd < 0) {
106        fprintf(stderr, "cannot open %s\n", ttydev);
107        return -1;
108    }
109
110    if ((printvc && !new_vc) || (printvc & 2)) {
111        struct vt_stat vs;
112
113        res = ioctl(fd, VT_GETSTATE, &vs);
114        if (res < 0) {
115            fprintf(stderr, "ioctl(vcfd, VT_GETSTATE, &vs) failed, %d\n", res);
116        }
117        printf("%d\n", vs.v_active);
118    }
119
120    if (new_vc) {
121        int vtnum;
122        res = ioctl(fd, VT_OPENQRY, &vtnum);
123        if (res < 0 || vtnum == -1) {
124            fprintf(stderr, "ioctl(vcfd, VT_OPENQRY, &vtnum) failed, res %d, vtnum %d\n", res, vtnum);
125        }
126        switch_vc = vtnum;
127    }
128    if (switch_vc != -1) {
129        pthread_t thread;
130        pthread_attr_t attr;
131        activate_thread_switch_vc = switch_vc;
132        pthread_attr_init(&attr);
133        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
134        pthread_create(&thread, &attr, activate_thread, (void*)fd);
135
136        do {
137            res = ioctl(fd, VT_WAITACTIVE, (void*)switch_vc);
138        } while(res < 0 && errno == EINTR);
139        activate_thread_switch_vc = -1;
140        if (res < 0) {
141            fprintf(stderr, "ioctl( vcfd, VT_WAITACTIVE, vtnum) failed, %d %d %s for %d\n", res, errno, strerror(errno), switch_vc);
142        }
143        if(printvc & 1)
144            printf("%d\n", switch_vc);
145
146        close(fd);
147        fd = open(ttydev, O_RDWR | O_SYNC);
148        if (fd < 0) {
149            fprintf(stderr, "cannot open %s\n", ttydev);
150            return -1;
151        }
152    }
153    if (close_vc) {
154        res = ioctl(fd, VT_DISALLOCATE, 0);
155        if (res < 0) {
156            fprintf(stderr, "ioctl(vcfd, VT_DISALLOCATE, 0) failed, %d\n", res);
157        }
158    }
159    if (mode != -1) {
160        if (ioctl(fd, KDSETMODE, (void*)mode) < 0) {
161            fprintf(stderr, "KDSETMODE %d failed\n", mode);
162            return -1;
163        }
164    }
165    return 0;
166}
167