Use poll() instead of select() for the server main loop.
[wine/multimedia.git] / server / console.c
blobd34fee6660bad50f59b71ca4c52bf2ebc078ba8c
1 /*
2 * Server-side console management
4 * Copyright (C) 1998 Alexandre Julliard
6 * FIXME: all this stuff is a hack to avoid breaking
7 * the client-side console support.
8 */
10 #include "config.h"
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>
27 #include "winerror.h"
28 #include "winnt.h"
29 #include "wincon.h"
31 #include "handle.h"
32 #include "process.h"
33 #include "thread.h"
34 #include "request.h"
36 struct screen_buffer;
38 struct console_input
40 struct object obj; /* object header */
41 int fd; /* file descriptor */
42 int select; /* select user id */
43 int mode; /* input mode */
44 struct screen_buffer *output; /* associated screen buffer */
45 int recnum; /* number of input records */
46 INPUT_RECORD *records; /* input records */
49 struct screen_buffer
51 struct object obj; /* object header */
52 int fd; /* file descriptor */
53 int select; /* select user id */
54 int mode; /* output mode */
55 struct console_input *input; /* associated console input */
56 int cursor_size; /* size of cursor (percentage filled) */
57 int cursor_visible;/* cursor visibility flag */
58 int pid; /* xterm pid (hack) */
59 char *title; /* console title */
63 static void console_input_dump( struct object *obj, int verbose );
64 static int console_input_add_queue( struct object *obj, struct wait_queue_entry *entry );
65 static void console_input_remove_queue( struct object *obj, struct wait_queue_entry *entry );
66 static int console_input_signaled( struct object *obj, struct thread *thread );
67 static int console_input_get_read_fd( struct object *obj );
68 static void console_input_destroy( struct object *obj );
70 static void screen_buffer_dump( struct object *obj, int verbose );
71 static int screen_buffer_add_queue( struct object *obj, struct wait_queue_entry *entry );
72 static void screen_buffer_remove_queue( struct object *obj, struct wait_queue_entry *entry );
73 static int screen_buffer_signaled( struct object *obj, struct thread *thread );
74 static int screen_buffer_get_write_fd( struct object *obj );
75 static void screen_buffer_destroy( struct object *obj );
77 /* common routine */
78 static int console_get_info( struct object *obj, struct get_file_info_request *req );
80 static const struct object_ops console_input_ops =
82 sizeof(struct console_input),
83 console_input_dump,
84 console_input_add_queue,
85 console_input_remove_queue,
86 console_input_signaled,
87 no_satisfied,
88 console_input_get_read_fd,
89 no_write_fd,
90 no_flush,
91 console_get_info,
92 console_input_destroy
95 static const struct object_ops screen_buffer_ops =
97 sizeof(struct screen_buffer),
98 screen_buffer_dump,
99 screen_buffer_add_queue,
100 screen_buffer_remove_queue,
101 screen_buffer_signaled,
102 no_satisfied,
103 no_read_fd,
104 screen_buffer_get_write_fd,
105 no_flush,
106 console_get_info,
107 screen_buffer_destroy
111 static struct object *create_console_input( int fd )
113 struct console_input *console_input;
115 if ((fd = (fd != -1) ? dup(fd) : dup(0)) == -1)
117 file_set_error();
118 return NULL;
120 if ((console_input = alloc_object( &console_input_ops )))
122 console_input->fd = fd;
123 console_input->mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
124 ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
125 console_input->output = NULL;
126 console_input->recnum = 0;
127 console_input->records = NULL;
128 console_input->select = add_select_user( fd, default_select_event, console_input );
129 if (console_input->select != -1) return &console_input->obj;
130 release_object( console_input );
131 return NULL;
133 close( fd );
134 return NULL;
137 static struct object *create_console_output( int fd, struct object *input )
139 struct console_input *console_input = (struct console_input *)input;
140 struct screen_buffer *screen_buffer;
142 if ((fd = (fd != -1) ? dup(fd) : dup(1)) == -1)
144 file_set_error();
145 return NULL;
147 if ((screen_buffer = alloc_object( &screen_buffer_ops )))
149 screen_buffer->fd = fd;
150 screen_buffer->mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
151 screen_buffer->input = console_input;
152 screen_buffer->cursor_size = 100;
153 screen_buffer->cursor_visible = 1;
154 screen_buffer->pid = 0;
155 screen_buffer->title = strdup( "Wine console" );
156 screen_buffer->select = add_select_user( fd, default_select_event, screen_buffer );
157 if (screen_buffer->select == -1)
159 release_object( screen_buffer );
160 return NULL;
162 console_input->output = screen_buffer;
163 return &screen_buffer->obj;
165 close( fd );
166 return NULL;
169 /* allocate a console for this process */
170 int alloc_console( struct process *process )
172 if (process->console_in || process->console_out)
174 set_error( ERROR_ACCESS_DENIED );
175 return 0;
177 if ((process->console_in = create_console_input( -1 )))
179 if ((process->console_out = create_console_output( -1, process->console_in )))
180 return 1;
181 release_object( process->console_in );
183 return 0;
186 /* free the console for this process */
187 int free_console( struct process *process )
189 if (process->console_in) release_object( process->console_in );
190 if (process->console_out) release_object( process->console_out );
191 process->console_in = process->console_out = NULL;
192 return 1;
195 static int set_console_fd( int handle, int fd_in, int fd_out, int pid )
197 struct console_input *input;
198 struct screen_buffer *output;
199 struct object *obj;
201 if (!(obj = get_handle_obj( current->process, handle, 0, NULL )))
202 return 0;
203 if (obj->ops == &console_input_ops)
205 input = (struct console_input *)obj;
206 output = input->output;
207 grab_object( output );
209 else if (obj->ops == &screen_buffer_ops)
211 output = (struct screen_buffer *)obj;
212 input = output->input;
213 grab_object( input );
215 else
217 set_error( ERROR_INVALID_HANDLE );
218 release_object( obj );
219 return 0;
222 /* can't change the fd if someone is waiting on it */
223 assert( !input->obj.head );
224 assert( !output->obj.head );
226 change_select_fd( input->select, fd_in );
227 change_select_fd( output->select, fd_out );
228 input->fd = fd_in;
229 output->fd = fd_out;
230 output->pid = pid;
231 release_object( input );
232 release_object( output );
233 return 1;
236 static int get_console_mode( int handle )
238 struct object *obj;
239 int ret = 0;
241 if ((obj = get_handle_obj( current->process, handle, GENERIC_READ, NULL )))
243 if (obj->ops == &console_input_ops)
244 ret = ((struct console_input *)obj)->mode;
245 else if (obj->ops == &screen_buffer_ops)
246 ret = ((struct screen_buffer *)obj)->mode;
247 else
248 set_error( ERROR_INVALID_HANDLE );
249 release_object( obj );
251 return ret;
254 static int set_console_mode( int handle, int mode )
256 struct object *obj;
257 int ret = 0;
259 if (!(obj = get_handle_obj( current->process, handle, GENERIC_READ, NULL )))
260 return 0;
261 if (obj->ops == &console_input_ops)
263 ((struct console_input *)obj)->mode = mode;
264 ret = 1;
266 else if (obj->ops == &screen_buffer_ops)
268 ((struct screen_buffer *)obj)->mode = mode;
269 ret = 1;
271 else set_error( ERROR_INVALID_HANDLE );
272 release_object( obj );
273 return ret;
276 /* set misc console information (output handle only) */
277 static int set_console_info( int handle, struct set_console_info_request *req,
278 const char *title, size_t len )
280 struct screen_buffer *console;
281 if (!(console = (struct screen_buffer *)get_handle_obj( current->process, handle,
282 GENERIC_WRITE, &screen_buffer_ops )))
283 return 0;
284 if (req->mask & SET_CONSOLE_INFO_CURSOR)
286 console->cursor_size = req->cursor_size;
287 console->cursor_visible = req->cursor_visible;
289 if (req->mask & SET_CONSOLE_INFO_TITLE)
291 char *new_title = mem_alloc( len + 1 );
292 if (new_title)
294 memcpy( new_title, title, len );
295 new_title[len] = 0;
296 if (console->title) free( console->title );
297 console->title = new_title;
300 release_object( console );
301 return 1;
304 /* add input events to a console input queue */
305 static int write_console_input( int handle, int count, INPUT_RECORD *records )
307 INPUT_RECORD *new_rec;
308 struct console_input *console;
310 if (!(console = (struct console_input *)get_handle_obj( current->process, handle,
311 GENERIC_WRITE, &console_input_ops )))
312 return -1;
313 if (!(new_rec = realloc( console->records,
314 (console->recnum + count) * sizeof(INPUT_RECORD) )))
316 set_error( ERROR_NOT_ENOUGH_MEMORY );
317 release_object( console );
318 return -1;
320 console->records = new_rec;
321 memcpy( new_rec + console->recnum, records, count * sizeof(INPUT_RECORD) );
322 console->recnum += count;
323 release_object( console );
324 return count;
327 /* retrieve a pointer to the console input records */
328 static int read_console_input( int handle, int count, INPUT_RECORD *rec, int max, int flush )
330 struct console_input *console;
332 if (!(console = (struct console_input *)get_handle_obj( current->process, handle,
333 GENERIC_READ, &console_input_ops )))
334 return -1;
335 if ((count < 0) || (count > console->recnum)) count = console->recnum;
336 if (count > max) count = max;
337 memcpy( rec, console->records, count * sizeof(INPUT_RECORD) );
338 if (flush)
340 int i;
341 for (i = count; i < console->recnum; i++)
342 console->records[i-count] = console->records[i];
343 if ((console->recnum -= count) > 0)
345 INPUT_RECORD *new_rec = realloc( console->records,
346 console->recnum * sizeof(INPUT_RECORD) );
347 if (new_rec) console->records = new_rec;
349 else
351 free( console->records );
352 console->records = NULL;
355 release_object( console );
356 return count;
359 static void console_input_dump( struct object *obj, int verbose )
361 struct console_input *console = (struct console_input *)obj;
362 assert( obj->ops == &console_input_ops );
363 fprintf( stderr, "Console input fd=%d\n", console->fd );
366 static int console_input_add_queue( struct object *obj, struct wait_queue_entry *entry )
368 struct console_input *console = (struct console_input *)obj;
369 assert( obj->ops == &console_input_ops );
370 if (!obj->head) /* first on the queue */
371 set_select_events( console->select, POLLIN );
372 add_queue( obj, entry );
373 return 1;
376 static void console_input_remove_queue( struct object *obj, struct wait_queue_entry *entry )
378 struct console_input *console = (struct console_input *)grab_object(obj);
379 assert( obj->ops == &console_input_ops );
381 remove_queue( obj, entry );
382 if (!obj->head) /* last on the queue is gone */
383 set_select_events( console->select, 0 );
384 release_object( obj );
387 static int console_input_signaled( struct object *obj, struct thread *thread )
389 struct console_input *console = (struct console_input *)obj;
390 assert( obj->ops == &console_input_ops );
392 if (check_select_events( console->fd, POLLIN ))
394 /* stop waiting on select() if we are signaled */
395 set_select_events( console->select, 0 );
396 return 1;
398 else
400 /* restart waiting on select() if we are no longer signaled */
401 if (obj->head) set_select_events( console->select, POLLIN );
402 return 0;
406 static int console_input_get_read_fd( struct object *obj )
408 struct console_input *console = (struct console_input *)obj;
409 assert( obj->ops == &console_input_ops );
410 return dup( console->fd );
413 static int console_get_info( struct object *obj, struct get_file_info_request *req )
415 req->type = FILE_TYPE_CHAR;
416 req->attr = 0;
417 req->access_time = 0;
418 req->write_time = 0;
419 req->size_high = 0;
420 req->size_low = 0;
421 req->links = 0;
422 req->index_high = 0;
423 req->index_low = 0;
424 req->serial = 0;
425 return 1;
428 static void console_input_destroy( struct object *obj )
430 struct console_input *console = (struct console_input *)obj;
431 assert( obj->ops == &console_input_ops );
432 remove_select_user( console->select );
433 if (console->output) console->output->input = NULL;
436 static void screen_buffer_dump( struct object *obj, int verbose )
438 struct screen_buffer *console = (struct screen_buffer *)obj;
439 assert( obj->ops == &screen_buffer_ops );
440 fprintf( stderr, "Console screen buffer fd=%d\n", console->fd );
443 static int screen_buffer_add_queue( struct object *obj, struct wait_queue_entry *entry )
445 struct screen_buffer *console = (struct screen_buffer *)obj;
446 assert( obj->ops == &screen_buffer_ops );
447 if (!obj->head) /* first on the queue */
448 set_select_events( console->select, POLLOUT );
449 add_queue( obj, entry );
450 return 1;
453 static void screen_buffer_remove_queue( struct object *obj, struct wait_queue_entry *entry )
455 struct screen_buffer *console = (struct screen_buffer *)grab_object(obj);
456 assert( obj->ops == &screen_buffer_ops );
458 remove_queue( obj, entry );
459 if (!obj->head) /* last on the queue is gone */
460 set_select_events( console->select, 0 );
461 release_object( obj );
464 static int screen_buffer_signaled( struct object *obj, struct thread *thread )
466 struct screen_buffer *console = (struct screen_buffer *)obj;
467 assert( obj->ops == &screen_buffer_ops );
469 if (check_select_events( console->fd, POLLOUT ))
471 /* stop waiting on select() if we are signaled */
472 set_select_events( console->select, 0 );
473 return 1;
475 else
477 /* restart waiting on select() if we are no longer signaled */
478 if (obj->head) set_select_events( console->select, POLLOUT );
479 return 0;
483 static int screen_buffer_get_write_fd( struct object *obj )
485 struct screen_buffer *console = (struct screen_buffer *)obj;
486 assert( obj->ops == &screen_buffer_ops );
487 return dup( console->fd );
490 static void screen_buffer_destroy( struct object *obj )
492 struct screen_buffer *console = (struct screen_buffer *)obj;
493 assert( obj->ops == &screen_buffer_ops );
494 remove_select_user( console->select );
495 if (console->input) console->input->output = NULL;
496 if (console->title) free( console->title );
499 /* allocate a console for the current process */
500 DECL_HANDLER(alloc_console)
502 int in = -1, out = -1;
504 if (!alloc_console( current->process )) goto done;
506 if ((in = alloc_handle( current->process, current->process->console_in,
507 req->access, req->inherit )) != -1)
509 if ((out = alloc_handle( current->process, current->process->console_out,
510 req->access, req->inherit )) != -1)
511 goto done; /* everything is fine */
512 close_handle( current->process, in );
513 in = -1;
515 free_console( current->process );
517 done:
518 req->handle_in = in;
519 req->handle_out = out;
522 /* free the console of the current process */
523 DECL_HANDLER(free_console)
525 free_console( current->process );
528 /* open a handle to the process console */
529 DECL_HANDLER(open_console)
531 struct object *obj= req->output ? current->process->console_out : current->process->console_in;
533 if (obj) req->handle = alloc_handle( current->process, obj, req->access, req->inherit );
534 else set_error( ERROR_ACCESS_DENIED );
537 /* set info about a console (output only) */
538 DECL_HANDLER(set_console_info)
540 size_t len = get_req_strlen( req->title );
541 set_console_info( req->handle, req, req->title, len );
544 /* get info about a console (output only) */
545 DECL_HANDLER(get_console_info)
547 struct screen_buffer *console;
548 if ((console = (struct screen_buffer *)get_handle_obj( current->process, req->handle,
549 GENERIC_READ, &screen_buffer_ops )))
551 req->cursor_size = console->cursor_size;
552 req->cursor_visible = console->cursor_visible;
553 req->pid = console->pid;
554 strcpy( req->title, console->title ? console->title : "" );
555 release_object( console );
559 /* set a console fd */
560 DECL_HANDLER(set_console_fd)
562 struct object *obj;
563 int fd_in, fd_out;
565 if (!(obj = get_handle_obj( current->process, req->file_handle,
566 GENERIC_READ | GENERIC_WRITE, NULL ))) return;
567 if ((fd_in = obj->ops->get_read_fd( obj )) == -1)
569 release_object( obj );
570 return;
572 fd_out = obj->ops->get_write_fd( obj );
573 release_object( obj );
574 if (fd_out != -1)
576 if (set_console_fd( req->handle, fd_in, fd_out, req->pid )) return;
577 close( fd_out );
579 close( fd_in );
582 /* get a console mode (input or output) */
583 DECL_HANDLER(get_console_mode)
585 req->mode = get_console_mode( req->handle );
588 /* set a console mode (input or output) */
589 DECL_HANDLER(set_console_mode)
591 set_console_mode( req->handle, req->mode );
594 /* add input records to a console input queue */
595 DECL_HANDLER(write_console_input)
597 int max = get_req_size( req + 1, sizeof(INPUT_RECORD) );
598 int count = req->count;
600 if (count > max) count = max;
601 req->written = write_console_input( req->handle, count, (INPUT_RECORD *)(req + 1) );
604 /* fetch input records from a console input queue */
605 DECL_HANDLER(read_console_input)
607 int max = get_req_size( req + 1, sizeof(INPUT_RECORD) );
608 req->read = read_console_input( req->handle, req->count, (INPUT_RECORD *)(req + 1),
609 max, req->flush );