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