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.
18 #ifdef HAVE_SYS_ERRNO_H
19 #include <sys/errno.h>
23 #include <sys/types.h>
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 */
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
);
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
),
84 console_input_add_queue
,
85 console_input_remove_queue
,
86 console_input_signaled
,
88 console_input_get_read_fd
,
95 static const struct object_ops screen_buffer_ops
=
97 sizeof(struct screen_buffer
),
99 screen_buffer_add_queue
,
100 screen_buffer_remove_queue
,
101 screen_buffer_signaled
,
104 screen_buffer_get_write_fd
,
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)
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
);
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)
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
);
162 console_input
->output
= screen_buffer
;
163 return &screen_buffer
->obj
;
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
);
177 if ((process
->console_in
= create_console_input( -1 )))
179 if ((process
->console_out
= create_console_output( -1, process
->console_in
)))
181 release_object( process
->console_in
);
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
;
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
;
201 if (!(obj
= get_handle_obj( current
->process
, handle
, 0, NULL
)))
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
);
217 set_error( ERROR_INVALID_HANDLE
);
218 release_object( obj
);
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
);
231 release_object( input
);
232 release_object( output
);
236 static int get_console_mode( int handle
)
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
;
248 set_error( ERROR_INVALID_HANDLE
);
249 release_object( obj
);
254 static int set_console_mode( int handle
, int mode
)
259 if (!(obj
= get_handle_obj( current
->process
, handle
, GENERIC_READ
, NULL
)))
261 if (obj
->ops
== &console_input_ops
)
263 ((struct console_input
*)obj
)->mode
= mode
;
266 else if (obj
->ops
== &screen_buffer_ops
)
268 ((struct screen_buffer
*)obj
)->mode
= mode
;
271 else set_error( ERROR_INVALID_HANDLE
);
272 release_object( obj
);
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
)))
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 );
294 memcpy( new_title
, title
, len
);
296 if (console
->title
) free( console
->title
);
297 console
->title
= new_title
;
300 release_object( console
);
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
)))
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
);
320 console
->records
= new_rec
;
321 memcpy( new_rec
+ console
->recnum
, records
, count
* sizeof(INPUT_RECORD
) );
322 console
->recnum
+= count
;
323 release_object( console
);
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
)))
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
) );
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
;
351 free( console
->records
);
352 console
->records
= NULL
;
355 release_object( console
);
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
);
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 );
400 /* restart waiting on select() if we are no longer signaled */
401 if (obj
->head
) set_select_events( console
->select
, POLLIN
);
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
;
417 req
->access_time
= 0;
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
);
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 );
477 /* restart waiting on select() if we are no longer signaled */
478 if (obj
->head
) set_select_events( console
->select
, POLLOUT
);
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
);
515 free_console( current
->process
);
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
)
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
);
572 fd_out
= obj
->ops
->get_write_fd( obj
);
573 release_object( obj
);
576 if (set_console_fd( req
->handle
, fd_in
, fd_out
, req
->pid
)) return;
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),