- fixed copy&paste bug (GENERIC_WRITE instead of GENERIC_READ)
[wine] / server / console.c
1 /*
2  * Server-side console management
3  *
4  * Copyright (C) 1998 Alexandre Julliard
5  *
6  * FIXME: all this stuff is a hack to avoid breaking
7  *        the client-side console support.
8  */
9
10 #include "config.h"
11
12 #include <assert.h>
13 #include <fcntl.h>
14 #include <signal.h>
15 #include <string.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <sys/time.h>
19 #include <sys/types.h>
20 #include <time.h>
21 #include <unistd.h>
22
23 #include "winnt.h"
24 #include "winbase.h"
25 #include "wincon.h"
26
27 #include "handle.h"
28 #include "process.h"
29 #include "thread.h"
30 #include "request.h"
31
32 struct screen_buffer;
33
34 struct console_input
35 {
36     struct object         obj;           /* object header */
37     int                   mode;          /* input mode */
38     struct screen_buffer *output;        /* associated screen buffer */
39     int                   recnum;        /* number of input records */
40     INPUT_RECORD         *records;       /* input records */
41 };
42
43 struct screen_buffer
44 {
45     struct object         obj;           /* object header */
46     int                   mode;          /* output mode */
47     struct console_input *input;         /* associated console input */
48     int                   cursor_size;   /* size of cursor (percentage filled) */
49     int                   cursor_visible;/* cursor visibility flag */
50     int                   pid;           /* xterm pid (hack) */
51     char                 *title;         /* console title */
52 };
53
54
55 static void console_input_dump( struct object *obj, int verbose );
56 static int console_input_get_poll_events( struct object *obj );
57 static int console_input_get_fd( struct object *obj );
58 static void console_input_destroy( struct object *obj );
59
60 static void screen_buffer_dump( struct object *obj, int verbose );
61 static int screen_buffer_get_poll_events( struct object *obj );
62 static int screen_buffer_get_fd( struct object *obj );
63 static void screen_buffer_destroy( struct object *obj );
64
65 /* common routine */
66 static int console_get_info( struct object *obj, struct get_file_info_request *req );
67
68 static const struct object_ops console_input_ops =
69 {
70     sizeof(struct console_input),     /* size */
71     console_input_dump,               /* dump */
72     default_poll_add_queue,           /* add_queue */
73     default_poll_remove_queue,        /* remove_queue */
74     default_poll_signaled,            /* signaled */
75     no_satisfied,                     /* satisfied */
76     console_input_get_poll_events,    /* get_poll_events */
77     default_poll_event,               /* poll_event */
78     console_input_get_fd,             /* get_fd */
79     no_flush,                         /* flush */
80     console_get_info,                 /* get_file_info */
81     console_input_destroy             /* destroy */
82 };
83
84 static const struct object_ops screen_buffer_ops =
85 {
86     sizeof(struct screen_buffer),     /* size */
87     screen_buffer_dump,               /* dump */
88     default_poll_add_queue,           /* add_queue */
89     default_poll_remove_queue,        /* remove_queue */
90     default_poll_signaled,            /* signaled */
91     no_satisfied,                     /* satisfied */
92     screen_buffer_get_poll_events,    /* get_poll_events */
93     default_poll_event,               /* poll_event */
94     screen_buffer_get_fd,             /* get_fd */
95     no_flush,                         /* flush */
96     console_get_info,                 /* get_file_info */
97     screen_buffer_destroy             /* destroy */
98 };
99
100
101 static struct object *create_console_input( int fd )
102 {
103     struct console_input *console_input;
104
105     if ((fd = (fd != -1) ? dup(fd) : dup(0)) == -1)
106     {
107         file_set_error();
108         return NULL;
109     }
110     if (!(console_input = alloc_object( &console_input_ops, fd ))) return NULL;
111     console_input->mode    = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
112                              ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
113     console_input->output  = NULL;
114     console_input->recnum  = 0;
115     console_input->records = NULL;
116     return &console_input->obj;
117 }
118
119 static struct object *create_console_output( int fd, struct object *input )
120 {
121     struct console_input *console_input = (struct console_input *)input;
122     struct screen_buffer *screen_buffer;
123
124     if ((fd = (fd != -1) ? dup(fd) : dup(1)) == -1)
125     {
126         file_set_error();
127         return NULL;
128     }
129     if (!(screen_buffer = alloc_object( &screen_buffer_ops, fd ))) return NULL;
130     screen_buffer->mode           = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
131     screen_buffer->input          = console_input;
132     screen_buffer->cursor_size    = 100;
133     screen_buffer->cursor_visible = 1;
134     screen_buffer->pid            = 0;
135     screen_buffer->title          = strdup( "Wine console" );
136     console_input->output = screen_buffer;
137     return &screen_buffer->obj;
138 }
139
140 /* allocate a console for this process */
141 int alloc_console( struct process *process )
142 {
143     if (process->console_in || process->console_out)
144     {
145         set_error( STATUS_ACCESS_DENIED );
146         return 0;
147     }
148     if ((process->console_in = create_console_input( -1 )))
149     {
150         if ((process->console_out = create_console_output( -1, process->console_in )))
151             return 1;
152         release_object( process->console_in );
153     }
154     return 0;
155 }
156
157 /* free the console for this process */
158 int free_console( struct process *process )
159 {
160     if (process->console_in) release_object( process->console_in );
161     if (process->console_out) release_object( process->console_out );
162     process->console_in = process->console_out = NULL;
163     return 1;
164 }
165
166 static int set_console_fd( handle_t handle, int fd_in, int fd_out, int pid )
167 {
168     struct console_input *input;
169     struct screen_buffer *output;
170     struct object *obj;
171
172     if (!(obj = get_handle_obj( current->process, handle, 0, NULL )))
173         return 0;
174     if (obj->ops == &console_input_ops)
175     {
176         input = (struct console_input *)obj;
177         output = input->output;
178         grab_object( output );
179     }
180     else if (obj->ops == &screen_buffer_ops)
181     {
182         output = (struct screen_buffer *)obj;
183         input = output->input;
184         grab_object( input );
185     }
186     else
187     {
188         set_error( STATUS_OBJECT_TYPE_MISMATCH );
189         release_object( obj );
190         return 0;
191     }
192
193     /* can't change the fd if someone is waiting on it */
194     assert( !input->obj.head );
195     assert( !output->obj.head );
196
197     change_select_fd( &input->obj, fd_in );
198     change_select_fd( &output->obj, fd_out );
199     output->pid = pid;
200     release_object( input );
201     release_object( output );
202     return 1;
203 }
204
205 static int get_console_mode( handle_t handle )
206 {
207     struct object *obj;
208     int ret = 0;
209
210     if ((obj = get_handle_obj( current->process, handle, GENERIC_READ, NULL )))
211     {
212         if (obj->ops == &console_input_ops)
213             ret = ((struct console_input *)obj)->mode;
214         else if (obj->ops == &screen_buffer_ops)
215             ret = ((struct screen_buffer *)obj)->mode;
216         else
217             set_error( STATUS_OBJECT_TYPE_MISMATCH );
218         release_object( obj );
219     }
220     return ret;
221 }
222
223 static int set_console_mode( handle_t handle, int mode )
224 {
225     struct object *obj;
226     int ret = 0;
227
228     if (!(obj = get_handle_obj( current->process, handle, GENERIC_READ, NULL )))
229         return 0;
230     if (obj->ops == &console_input_ops)
231     {
232         ((struct console_input *)obj)->mode = mode;
233         ret = 1;
234     }
235     else if (obj->ops == &screen_buffer_ops)
236     {
237         ((struct screen_buffer *)obj)->mode = mode;
238         ret = 1;
239     }
240     else set_error( STATUS_OBJECT_TYPE_MISMATCH );
241     release_object( obj );
242     return ret;
243 }
244
245 /* set misc console information (output handle only) */
246 static int set_console_info( handle_t handle, struct set_console_info_request *req,
247                              const char *title, size_t len )
248 {
249     struct screen_buffer *console;
250     if (!(console = (struct screen_buffer *)get_handle_obj( current->process, handle,
251                                                             GENERIC_WRITE, &screen_buffer_ops )))
252         return 0;
253     if (req->mask & SET_CONSOLE_INFO_CURSOR)
254     {
255         console->cursor_size    = req->cursor_size;
256         console->cursor_visible = req->cursor_visible;
257     }
258     if (req->mask & SET_CONSOLE_INFO_TITLE)
259     {
260         char *new_title = mem_alloc( len + 1 );
261         if (new_title)
262         {
263             memcpy( new_title, title, len );
264             new_title[len] = 0;
265             if (console->title) free( console->title );
266             console->title = new_title;
267         }
268     }
269     release_object( console );
270     return 1;
271 }
272
273 /* add input events to a console input queue */
274 static int write_console_input( handle_t handle, int count, INPUT_RECORD *records )
275 {
276     INPUT_RECORD *new_rec;
277     struct console_input *console;
278
279     if (!(console = (struct console_input *)get_handle_obj( current->process, handle,
280                                                             GENERIC_WRITE, &console_input_ops )))
281         return -1;
282     if (!(new_rec = realloc( console->records,
283                              (console->recnum + count) * sizeof(INPUT_RECORD) )))
284     {
285         set_error( STATUS_NO_MEMORY );
286         release_object( console );
287         return -1;
288     }
289     console->records = new_rec;
290     memcpy( new_rec + console->recnum, records, count * sizeof(INPUT_RECORD) );
291     console->recnum += count;
292     release_object( console );
293     return count;
294 }
295
296 /* retrieve a pointer to the console input records */
297 static int read_console_input( handle_t handle, int count, INPUT_RECORD *rec, int flush )
298 {
299     struct console_input *console;
300
301     if (!(console = (struct console_input *)get_handle_obj( current->process, handle,
302                                                             GENERIC_READ, &console_input_ops )))
303         return -1;
304
305     if (!count)
306     {
307         /* special case: do not retrieve anything, but return
308          * the total number of records available */
309         count = console->recnum;
310     }
311     else
312     {
313         if (count > console->recnum) count = console->recnum;
314         memcpy( rec, console->records, count * sizeof(INPUT_RECORD) );
315     }
316     if (flush)
317     {
318         int i;
319         for (i = count; i < console->recnum; i++)
320             console->records[i-count] = console->records[i];
321         if ((console->recnum -= count) > 0)
322         {
323             INPUT_RECORD *new_rec = realloc( console->records,
324                                              console->recnum * sizeof(INPUT_RECORD) );
325             if (new_rec) console->records = new_rec;
326         }
327         else
328         {
329             free( console->records );
330             console->records = NULL;
331         }
332     }
333     release_object( console );
334     return count;
335 }
336
337 static void console_input_dump( struct object *obj, int verbose )
338 {
339     struct console_input *console = (struct console_input *)obj;
340     assert( obj->ops == &console_input_ops );
341     fprintf( stderr, "Console input fd=%d\n", console->obj.fd );
342 }
343
344 static int console_input_get_poll_events( struct object *obj )
345 {
346     return POLLIN;
347 }
348
349 static int console_input_get_fd( struct object *obj )
350 {
351     struct console_input *console = (struct console_input *)obj;
352     assert( obj->ops == &console_input_ops );
353     return console->obj.fd;
354 }
355
356 static int console_get_info( struct object *obj, struct get_file_info_request *req )
357 {
358     if (req)
359     {
360         req->type        = FILE_TYPE_CHAR;
361         req->attr        = 0;
362         req->access_time = 0;
363         req->write_time  = 0;
364         req->size_high   = 0;
365         req->size_low    = 0;
366         req->links       = 0;
367         req->index_high  = 0;
368         req->index_low   = 0;
369         req->serial      = 0;
370     }
371     return FD_TYPE_CONSOLE;
372 }
373
374 static void console_input_destroy( struct object *obj )
375 {
376     struct console_input *console = (struct console_input *)obj;
377     assert( obj->ops == &console_input_ops );
378     if (console->output) console->output->input = NULL;
379 }
380
381 static void screen_buffer_dump( struct object *obj, int verbose )
382 {
383     struct screen_buffer *console = (struct screen_buffer *)obj;
384     assert( obj->ops == &screen_buffer_ops );
385     fprintf( stderr, "Console screen buffer fd=%d\n", console->obj.fd );
386 }
387
388 static int screen_buffer_get_poll_events( struct object *obj )
389 {
390     return POLLOUT;
391 }
392
393 static int screen_buffer_get_fd( struct object *obj )
394 {
395     struct screen_buffer *console = (struct screen_buffer *)obj;
396     assert( obj->ops == &screen_buffer_ops );
397     return console->obj.fd;
398 }
399
400 static void screen_buffer_destroy( struct object *obj )
401 {
402     struct screen_buffer *console = (struct screen_buffer *)obj;
403     assert( obj->ops == &screen_buffer_ops );
404     if (console->input) console->input->output = NULL;
405     if (console->title) free( console->title );
406 }
407
408 /* allocate a console for the current process */
409 DECL_HANDLER(alloc_console)
410 {
411     handle_t in = 0, out = 0;
412
413     if (!alloc_console( current->process )) goto done;
414
415     if ((in = alloc_handle( current->process, current->process->console_in,
416                             req->access, req->inherit )))
417     {
418         if ((out = alloc_handle( current->process, current->process->console_out,
419                                  req->access, req->inherit )))
420             goto done;  /* everything is fine */
421         close_handle( current->process, in, NULL );
422         in = 0;
423     }
424     free_console( current->process );
425
426  done:
427     req->handle_in  = in;
428     req->handle_out = out;
429 }
430
431 /* free the console of the current process */
432 DECL_HANDLER(free_console)
433 {
434     free_console( current->process );
435 }
436
437 /* open a handle to the process console */
438 DECL_HANDLER(open_console)
439 {
440     struct object *obj= req->output ? current->process->console_out : current->process->console_in;
441
442     req->handle = 0;
443     if (obj) req->handle = alloc_handle( current->process, obj, req->access, req->inherit );
444     else set_error( STATUS_ACCESS_DENIED );
445 }
446
447 /* set info about a console (output only) */
448 DECL_HANDLER(set_console_info)
449 {
450     set_console_info( req->handle, req, get_req_data(req), get_req_data_size(req) );
451 }
452
453 /* get info about a console (output only) */
454 DECL_HANDLER(get_console_info)
455 {
456     struct screen_buffer *console;
457     size_t len = 0;
458
459     if ((console = (struct screen_buffer *)get_handle_obj( current->process, req->handle,
460                                                            GENERIC_READ, &screen_buffer_ops )))
461     {
462         req->cursor_size    = console->cursor_size;
463         req->cursor_visible = console->cursor_visible;
464         req->pid            = console->pid;
465         if (console->title)
466         {
467             len = strlen( console->title );
468             if (len > get_req_data_size(req)) len = get_req_data_size(req);
469             memcpy( get_req_data(req), console->title, len );
470         }
471         release_object( console );
472     }
473     set_req_data_size( req, len );
474 }
475
476 /* set a console fd */
477 DECL_HANDLER(set_console_fd)
478 {
479     int fd_out, fd_in  = thread_get_inflight_fd( current, req->fd_in );
480
481     if (req->fd_out == req->fd_in) fd_out = dup( fd_in );
482     else fd_out = thread_get_inflight_fd( current, req->fd_out );
483
484     if (fd_in == -1 || fd_out == -1) set_error( STATUS_INVALID_HANDLE );
485     else if (set_console_fd( req->handle, fd_in, fd_out, req->pid )) return;
486
487     if (fd_in != -1) close( fd_in );
488     if (fd_out != -1) close( fd_out );
489 }
490
491 /* get a console mode (input or output) */
492 DECL_HANDLER(get_console_mode)
493 {
494     req->mode = get_console_mode( req->handle );
495 }
496
497 /* set a console mode (input or output) */
498 DECL_HANDLER(set_console_mode)
499 {
500     set_console_mode( req->handle, req->mode );
501 }
502
503 /* add input records to a console input queue */
504 DECL_HANDLER(write_console_input)
505 {
506     req->written = write_console_input( req->handle, get_req_data_size(req) / sizeof(INPUT_RECORD),
507                                         get_req_data(req) );
508 }
509
510 /* fetch input records from a console input queue */
511 DECL_HANDLER(read_console_input)
512 {
513     size_t size = get_req_data_size(req) / sizeof(INPUT_RECORD);
514     int res = read_console_input( req->handle, size, get_req_data(req), req->flush );
515     /* if size was 0 we didn't fetch anything */
516     if (size) set_req_data_size( req, res * sizeof(INPUT_RECORD) );
517     req->read = res;
518 }