diff options
Diffstat (limited to 'Presence/monitortty.c')
-rw-r--r-- | Presence/monitortty.c | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/Presence/monitortty.c b/Presence/monitortty.c new file mode 100644 index 00000000..90e23464 --- /dev/null +++ b/Presence/monitortty.c | |||
@@ -0,0 +1,167 @@ | |||
1 | // monitortty.c | ||
2 | |||
3 | #include <unistd.h> | ||
4 | #include <pthread.h> | ||
5 | #include <stdio.h> | ||
6 | #include <string.h> | ||
7 | #include <stdint.h> | ||
8 | #include <errno.h> | ||
9 | #include <linux/vt.h> | ||
10 | #include <sys/ioctl.h> | ||
11 | #include <fcntl.h> | ||
12 | #include <linux/kd.h> | ||
13 | #include <stdlib.h> | ||
14 | |||
15 | static char *conspath[] = { | ||
16 | "/proc/self/fd/0", | ||
17 | "/dev/tty", | ||
18 | "/dev/tty0", | ||
19 | "/dev/vc/0", | ||
20 | "/dev/systty", | ||
21 | "/dev/console", | ||
22 | NULL | ||
23 | }; | ||
24 | |||
25 | static int | ||
26 | is_a_console(int fd) { | ||
27 | char arg; | ||
28 | |||
29 | arg = 0; | ||
30 | return (isatty (fd) | ||
31 | && ioctl(fd, KDGKBTYPE, &arg) == 0 | ||
32 | && ((arg == KB_101) || (arg == KB_84))); | ||
33 | } | ||
34 | |||
35 | static int | ||
36 | open_a_console(const char *fnam) { | ||
37 | int fd; | ||
38 | |||
39 | /* | ||
40 | * For ioctl purposes we only need some fd and permissions | ||
41 | * do not matter. But setfont:activatemap() does a write. | ||
42 | */ | ||
43 | fd = open(fnam, O_RDWR); | ||
44 | if (fd < 0) | ||
45 | fd = open(fnam, O_WRONLY); | ||
46 | if (fd < 0) | ||
47 | fd = open(fnam, O_RDONLY); | ||
48 | if (fd < 0) | ||
49 | return -1; | ||
50 | return fd; | ||
51 | } | ||
52 | |||
53 | int ttyfd() { | ||
54 | // We try several things because opening /dev/console will fail | ||
55 | // if someone else used X (which does a chown on /dev/console). | ||
56 | int i; | ||
57 | int fd; | ||
58 | for (i = 0; conspath[i]; i++) { | ||
59 | if ((fd = open_a_console(conspath[i])) >= 0) { | ||
60 | if (is_a_console(fd)) { | ||
61 | printf("using %s\n",conspath[i]); | ||
62 | return fd; | ||
63 | } | ||
64 | close(fd); | ||
65 | } | ||
66 | } | ||
67 | for (fd = 0; fd < 3; fd++) | ||
68 | if (is_a_console(fd)) | ||
69 | return fd; | ||
70 | printf("failed to find console fd\n"); | ||
71 | return -1; | ||
72 | } | ||
73 | |||
74 | void vt_wait(int tty_fd) { | ||
75 | struct vt_event vt; | ||
76 | memset(&vt,'\0',sizeof(vt)); | ||
77 | vt.event = VT_EVENT_SWITCH; | ||
78 | int res; | ||
79 | printf("started wait\n"); | ||
80 | res = ioctl (tty_fd, VT_WAITEVENT, &vt); | ||
81 | if (res==-1) { | ||
82 | printf("vt_wait error fd=%i\n",tty_fd); | ||
83 | perror("vt_wait"); | ||
84 | // printf("vt_wait: %u - %s\n", errno, errmsg(errno)); | ||
85 | sleep(1); | ||
86 | } | ||
87 | printf("finished wait\n"); | ||
88 | } | ||
89 | |||
90 | int8_t get_active(int tty_fd) { | ||
91 | struct vt_stat vtstat; | ||
92 | memset(&vtstat,'\0',sizeof(vtstat)); | ||
93 | if (ioctl(tty_fd, VT_GETSTATE, &vtstat)) { | ||
94 | perror ("get_active: VT_GETSTATE"); | ||
95 | return 7; | ||
96 | } | ||
97 | return vtstat.v_active; | ||
98 | } | ||
99 | |||
100 | void chvt(int tty_fd, int n) { | ||
101 | if (ioctl(tty_fd, VT_ACTIVATE, n)) { | ||
102 | perror ("chvt: VT_ACTIVATE"); | ||
103 | } | ||
104 | |||
105 | } | ||
106 | |||
107 | pthread_mutex_t mu; | ||
108 | pthread_t mt; | ||
109 | int tty = -1; | ||
110 | |||
111 | void *write_vtch(void *pfd) { | ||
112 | int fd = (int)(intptr_t)pfd; | ||
113 | printf("START write_vtch fd=%i\n",fd); | ||
114 | pthread_mutex_lock(&mu); | ||
115 | tty = ttyfd(); | ||
116 | pthread_mutex_unlock(&mu); | ||
117 | int8_t active_tty = get_active(tty); | ||
118 | int8_t reported_tty; | ||
119 | ssize_t e; | ||
120 | |||
121 | pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); | ||
122 | for (;;) { | ||
123 | // ssize_t write(int fd, const void *buf, size_t count); | ||
124 | e = write(fd, &active_tty, 1); | ||
125 | if (e<0 ) { | ||
126 | if( errno==EAGAIN) continue; | ||
127 | break; | ||
128 | } | ||
129 | else if(e==1) { | ||
130 | reported_tty = active_tty; | ||
131 | } | ||
132 | do { | ||
133 | vt_wait(tty); | ||
134 | active_tty = get_active(tty); | ||
135 | } while (active_tty==reported_tty); | ||
136 | } | ||
137 | |||
138 | // TODO: | ||
139 | // use VT_GETSTATE | ||
140 | // use VT_WAITEVENT | ||
141 | printf("QUIT write_vtch\n"); | ||
142 | tty = -1; | ||
143 | pthread_mutex_destroy(&mu); | ||
144 | return NULL; | ||
145 | } | ||
146 | |||
147 | |||
148 | void monitorTTY(int fd) { | ||
149 | pthread_mutex_init(&mu,NULL); | ||
150 | printf ("Hello world.\n"); | ||
151 | pthread_create (&mt, NULL, write_vtch, (void*)(intptr_t)fd); | ||
152 | } | ||
153 | |||
154 | void closeTTY() { | ||
155 | int fd = -1; | ||
156 | int active = 7; | ||
157 | pthread_mutex_lock(&mu); | ||
158 | active = get_active(tty); | ||
159 | fd = tty; | ||
160 | pthread_mutex_unlock(&mu); | ||
161 | pthread_cancel(mt); | ||
162 | char cmd[40]; cmd[39] = '\0'; | ||
163 | snprintf(cmd,39,"chvt %i;chvt %i",active+1,active); | ||
164 | system(cmd); | ||
165 | pthread_join(mt,NULL); | ||
166 | close(fd); | ||
167 | } | ||