uvtd: vt: implement VT_GETMODE/SETMODE ioctl state-tracking
[platform/upstream/kmscon.git] / src / uvtd_vt.c
1 /*
2  * uvtd - User-space VT daemon
3  *
4  * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files
8  * (the "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25
26 /*
27  * Virtual Terminals
28  * Every virtual terminal forms a session inside of uvtd. Sessions are scheduled
29  * by the seat/session-scheduler and notified whenever they get active/inactive.
30  */
31
32 #include <errno.h>
33 #include <inttypes.h>
34 #include <linux/kd.h>
35 #include <linux/vt.h>
36 #include <signal.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <termio.h>
40 #include <termios.h>
41 #include <unistd.h>
42 #include "shl_hook.h"
43 #include "shl_log.h"
44 #include "uvt.h"
45 #include "uvtd_seat.h"
46 #include "uvtd_vt.h"
47
48 #define LOG_SUBSYSTEM "vt"
49
50 struct uvtd_vt {
51         unsigned long ref;
52         struct uvt_ctx *uctx;
53         struct shl_hook *hook;
54         struct uvtd_session *session;
55         bool is_legacy;
56
57         unsigned int mode;
58         unsigned int kbmode;
59         struct vt_mode vtmode;
60         pid_t vtpid;
61 };
62
63 static void vt_hup(struct uvtd_vt *vt)
64 {
65         struct uvt_vt_event ev;
66
67         memset(&ev, 0, sizeof(ev));
68         ev.type = UVT_VT_HUP;
69
70         shl_hook_call(vt->hook, vt, &ev);
71 }
72
73 static int vt_session_event(struct uvtd_session *session, unsigned int event,
74                             void *data)
75 {
76         struct uvtd_vt *vt = data;
77
78         switch (event) {
79         case UVTD_SESSION_UNREGISTER:
80                 vt->session = NULL;
81                 vt_hup(vt);
82                 break;
83         case UVTD_SESSION_ACTIVATE:
84                 log_debug("activate %p", vt);
85                 break;
86         case UVTD_SESSION_DEACTIVATE:
87                 log_debug("deactivate %p", vt);
88                 break;
89         }
90
91         return 0;
92 }
93
94 int uvtd_vt_new(struct uvtd_vt **out, struct uvt_ctx *uctx, unsigned int id,
95                 struct uvtd_seat *seat, bool is_legacy)
96 {
97         struct uvtd_vt *vt;
98         int ret;
99
100         if (!out || !uctx)
101                 return -EINVAL;
102
103         vt = malloc(sizeof(*vt));
104         if (!vt)
105                 return -ENOMEM;
106
107         memset(vt, 0, sizeof(*vt));
108         vt->ref = 1;
109         vt->uctx = uctx;
110         vt->is_legacy = is_legacy;
111         vt->mode = KD_TEXT;
112         vt->kbmode = K_UNICODE;
113         vt->vtmode.mode = VT_AUTO;
114
115         ret = shl_hook_new(&vt->hook);
116         if (ret)
117                 goto err_free;
118
119         ret = uvtd_seat_register_session(seat, &vt->session, id,
120                                          vt_session_event, vt);
121         if (ret)
122                 goto err_hook;
123
124         uvt_ctx_ref(vt->uctx);
125         *out = vt;
126         return 0;
127
128 err_hook:
129         shl_hook_free(vt->hook);
130 err_free:
131         free(vt);
132         return ret;
133 }
134
135 void uvtd_vt_ref(struct uvtd_vt *vt)
136 {
137         if (!vt || !vt->ref)
138                 return;
139
140         ++vt->ref;
141 }
142
143 void uvtd_vt_unref(struct uvtd_vt *vt)
144 {
145         if (!vt || !vt->ref || --vt->ref)
146                 return;
147
148         uvtd_session_unregister(vt->session);
149         shl_hook_free(vt->hook);
150         uvt_ctx_unref(vt->uctx);
151         free(vt);
152 }
153
154 int uvtd_vt_register_cb(struct uvtd_vt *vt, uvt_vt_cb cb, void *data)
155 {
156         if (!vt)
157                 return -EINVAL;
158
159         return shl_hook_add_cast(vt->hook, cb, data, false);
160 }
161
162 void uvtd_vt_unregister_cb(struct uvtd_vt *vt, uvt_vt_cb cb, void *data)
163 {
164         if (!vt)
165                 return;
166
167         shl_hook_rm_cast(vt->hook, cb, data);
168 }
169
170 int uvtd_vt_read(struct uvtd_vt *vt, uint8_t *mem, size_t len)
171 {
172         return -EAGAIN;
173 }
174
175 int uvtd_vt_write(struct uvtd_vt *vt, const uint8_t *mem, size_t len)
176 {
177         return len;
178 }
179
180 unsigned int uvtd_vt_poll(struct uvtd_vt *vt)
181 {
182         return UVT_TTY_WRITE;
183 }
184
185 static int vt_ioctl_TCFLSH(void *data, unsigned long arg)
186 {
187         switch (arg) {
188         case TCIFLUSH:
189         case TCOFLUSH:
190         case TCIOFLUSH:
191                 break;
192         default:
193                 return -EINVAL;
194         }
195
196         return 0;
197 }
198
199 static int vt_ioctl_VT_ACTIVATE(void *data, unsigned long arg)
200 {
201         return -EINVAL;
202 }
203
204 static int vt_ioctl_VT_WAITACTIVE(void *data, unsigned long arg)
205 {
206         return -EINVAL;
207 }
208
209 static int vt_ioctl_VT_GETSTATE(void *data, struct vt_stat *arg)
210 {
211         return -EINVAL;
212 }
213
214 static int vt_ioctl_VT_OPENQRY(void *data, unsigned int *arg)
215 {
216         return -EINVAL;
217 }
218
219 static int vt_ioctl_VT_GETMODE(void *data, struct vt_mode *arg)
220 {
221         struct uvtd_vt *vt = data;
222
223         memcpy(arg, &vt->vtmode, sizeof(*arg));
224         return 0;
225 }
226
227 static int vt_ioctl_VT_SETMODE(void *data, const struct vt_mode *arg,
228                                pid_t pid)
229 {
230         struct uvtd_vt *vt = data;
231
232         /* TODO: implement waitv logic (hang on write if not active) */
233         if (arg->waitv)
234                 return -EOPNOTSUPP;
235
236         if (arg->frsig)
237                 return -EINVAL;
238         if (arg->relsig > SIGRTMAX || arg->relsig < 0)
239                 return -EINVAL;
240         if (arg->acqsig > SIGRTMAX || arg->acqsig < 0)
241                 return -EINVAL;
242
243         switch (arg->mode) {
244         case VT_AUTO:
245                 if (arg->acqsig || arg->relsig)
246                         return -EINVAL;
247                 vt->vtpid = 0;
248                 break;
249         case VT_PROCESS:
250                 vt->vtpid = pid;
251                 break;
252         default:
253                 return -EINVAL;
254         }
255
256         memcpy(&vt->vtmode, arg, sizeof(*arg));
257         return 0;
258 }
259
260 static int vt_ioctl_VT_RELDISP(void *data, unsigned long arg)
261 {
262         return -EINVAL;
263 }
264
265 static int vt_ioctl_KDGETMODE(void *data, unsigned int *arg)
266 {
267         struct uvtd_vt *vt = data;
268
269         *arg = vt->mode;
270         return 0;
271 }
272
273 static int vt_ioctl_KDSETMODE(void *data, unsigned int arg)
274 {
275         struct uvtd_vt *vt = data;
276
277         switch (arg) {
278         case KD_TEXT0:
279         case KD_TEXT1:
280                 arg = KD_TEXT;
281                 /* fallthrough */
282         case KD_TEXT:
283         case KD_GRAPHICS:
284                 vt->mode = arg;
285                 break;
286         default:
287                 return -EINVAL;
288         }
289
290         return 0;
291 }
292
293 static int vt_ioctl_KDGKBMODE(void *data, unsigned int *arg)
294 {
295         struct uvtd_vt *vt = data;
296
297         *arg = vt->kbmode;
298         return 0;
299 }
300
301 static int vt_ioctl_KDSKBMODE(void *data, unsigned int arg)
302 {
303         struct uvtd_vt *vt = data;
304
305         switch (arg) {
306         case K_RAW:
307                 /* TODO: what does K_RAW do? */
308         case K_UNICODE:
309         case K_OFF:
310                 vt->kbmode = arg;
311                 break;
312         case K_XLATE:
313         case K_MEDIUMRAW:
314                 /* TODO: do we need these? */
315                 return -EOPNOTSUPP;
316         default:
317                 return -EINVAL;
318         }
319
320         return 0;
321 }
322
323 /* compatibility to UVT-VT ops */
324
325 static void vt_ref(void *vt)
326 {
327         uvtd_vt_ref(vt);
328 }
329
330 static void vt_unref(void *vt)
331 {
332         uvtd_vt_unref(vt);
333 }
334
335 static int vt_register_cb(void *vt, uvt_vt_cb cb, void *data)
336 {
337         return uvtd_vt_register_cb(vt, cb, data);
338 }
339
340 static void vt_unregister_cb(void *vt, uvt_vt_cb cb, void *data)
341 {
342         uvtd_vt_register_cb(vt, cb, data);
343 }
344
345 static int vt_read(void *vt, uint8_t *mem, size_t len)
346 {
347         return uvtd_vt_read(vt, mem, len);
348 }
349
350 static int vt_write(void *vt, const uint8_t *mem, size_t len)
351 {
352         return uvtd_vt_write(vt, mem, len);
353 }
354
355 static unsigned int vt_poll(void *vt)
356 {
357         return uvtd_vt_poll(vt);
358 }
359
360 struct uvt_vt_ops uvtd_vt_ops = {
361         .ref = vt_ref,
362         .unref = vt_unref,
363         .register_cb = vt_register_cb,
364         .unregister_cb = vt_unregister_cb,
365         .read = vt_read,
366         .write = vt_write,
367         .poll = vt_poll,
368
369         .ioctl_TCFLSH = vt_ioctl_TCFLSH,
370
371         .ioctl_VT_ACTIVATE = vt_ioctl_VT_ACTIVATE,
372         .ioctl_VT_WAITACTIVE = vt_ioctl_VT_WAITACTIVE,
373         .ioctl_VT_GETSTATE = vt_ioctl_VT_GETSTATE,
374         .ioctl_VT_OPENQRY = vt_ioctl_VT_OPENQRY,
375         .ioctl_VT_GETMODE = vt_ioctl_VT_GETMODE,
376         .ioctl_VT_SETMODE = vt_ioctl_VT_SETMODE,
377         .ioctl_VT_RELDISP = vt_ioctl_VT_RELDISP,
378         .ioctl_KDGETMODE = vt_ioctl_KDGETMODE,
379         .ioctl_KDSETMODE = vt_ioctl_KDSETMODE,
380         .ioctl_KDGKBMODE = vt_ioctl_KDGKBMODE,
381         .ioctl_KDSKBMODE = vt_ioctl_KDSKBMODE,
382 };