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