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