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.
16 #include <sys/errno.h>
19 #include <sys/types.h>
35 struct object obj
; /* object header */
36 struct select_user select
; /* select user */
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 */
45 struct object obj
; /* object header */
46 struct select_user select
; /* select user */
47 int mode
; /* output mode */
48 struct console_input
*input
; /* associated console input */
49 int cursor_size
; /* size of cursor (percentage filled) */
50 int cursor_visible
;/* cursor visibility flag */
51 int pid
; /* xterm pid (hack) */
52 char *title
; /* console title */
56 static void console_input_dump( struct object
*obj
, int verbose
);
57 static int console_input_add_queue( struct object
*obj
, struct wait_queue_entry
*entry
);
58 static void console_input_remove_queue( struct object
*obj
, struct wait_queue_entry
*entry
);
59 static int console_input_signaled( struct object
*obj
, struct thread
*thread
);
60 static int console_input_get_read_fd( struct object
*obj
);
61 static void console_input_destroy( struct object
*obj
);
63 static void screen_buffer_dump( struct object
*obj
, int verbose
);
64 static int screen_buffer_add_queue( struct object
*obj
, struct wait_queue_entry
*entry
);
65 static void screen_buffer_remove_queue( struct object
*obj
, struct wait_queue_entry
*entry
);
66 static int screen_buffer_signaled( struct object
*obj
, struct thread
*thread
);
67 static int screen_buffer_get_write_fd( struct object
*obj
);
68 static void screen_buffer_destroy( struct object
*obj
);
71 static int console_get_info( struct object
*obj
, struct get_file_info_reply
*reply
);
73 static const struct object_ops console_input_ops
=
76 console_input_add_queue
,
77 console_input_remove_queue
,
78 console_input_signaled
,
80 console_input_get_read_fd
,
87 static const struct object_ops screen_buffer_ops
=
90 screen_buffer_add_queue
,
91 screen_buffer_remove_queue
,
92 screen_buffer_signaled
,
95 screen_buffer_get_write_fd
,
102 static int create_console( int fd
, struct object
*obj
[2] )
104 struct console_input
*console_input
;
105 struct screen_buffer
*screen_buffer
;
106 int read_fd
, write_fd
;
108 if ((read_fd
= (fd
!= -1) ? dup(fd
) : dup(0)) == -1)
113 if ((write_fd
= (fd
!= -1) ? dup(fd
) : dup(1)) == -1)
119 if (!(console_input
= mem_alloc( sizeof(struct console_input
) )))
125 if (!(screen_buffer
= mem_alloc( sizeof(struct screen_buffer
) )))
129 free( console_input
);
132 init_object( &console_input
->obj
, &console_input_ops
, NULL
);
133 init_object( &screen_buffer
->obj
, &screen_buffer_ops
, NULL
);
134 console_input
->select
.fd
= read_fd
;
135 console_input
->select
.func
= default_select_event
;
136 console_input
->select
.private = console_input
;
137 console_input
->mode
= ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
|
138 ENABLE_ECHO_INPUT
| ENABLE_MOUSE_INPUT
;
139 console_input
->output
= screen_buffer
;
140 console_input
->recnum
= 0;
141 console_input
->records
= NULL
;
142 screen_buffer
->select
.fd
= write_fd
;
143 screen_buffer
->select
.func
= default_select_event
;
144 screen_buffer
->select
.private = screen_buffer
;
145 screen_buffer
->mode
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
146 screen_buffer
->input
= console_input
;
147 screen_buffer
->cursor_size
= 100;
148 screen_buffer
->cursor_visible
= 1;
149 screen_buffer
->pid
= 0;
150 screen_buffer
->title
= strdup( "Wine console" );
151 register_select_user( &console_input
->select
);
152 register_select_user( &screen_buffer
->select
);
154 obj
[0] = &console_input
->obj
;
155 obj
[1] = &screen_buffer
->obj
;
159 /* allocate a console for this process */
160 int alloc_console( struct process
*process
)
162 struct object
*obj
[2];
163 if (process
->console_in
|| process
->console_out
)
165 SET_ERROR( ERROR_ACCESS_DENIED
);
168 if (!create_console( -1, obj
)) return 0;
169 process
->console_in
= obj
[0];
170 process
->console_out
= obj
[1];
174 /* free the console for this process */
175 int free_console( struct process
*process
)
177 if (process
->console_in
) release_object( process
->console_in
);
178 if (process
->console_out
) release_object( process
->console_out
);
179 process
->console_in
= process
->console_out
= NULL
;
183 static int set_console_fd( int handle
, int fd
, int pid
)
185 struct console_input
*input
;
186 struct screen_buffer
*output
;
190 if (!(obj
= get_handle_obj( current
->process
, handle
, 0, NULL
)))
192 if (obj
->ops
== &console_input_ops
)
194 input
= (struct console_input
*)obj
;
195 output
= input
->output
;
196 grab_object( output
);
198 else if (obj
->ops
== &screen_buffer_ops
)
200 output
= (struct screen_buffer
*)obj
;
201 input
= output
->input
;
202 grab_object( input
);
206 SET_ERROR( ERROR_INVALID_HANDLE
);
207 release_object( obj
);
211 /* can't change the fd if someone is waiting on it */
212 assert( !input
->obj
.head
);
213 assert( !output
->obj
.head
);
215 if ((fd_in
= dup(fd
)) == -1)
218 release_object( input
);
219 release_object( output
);
222 if ((fd_out
= dup(fd
)) == -1)
226 release_object( input
);
227 release_object( output
);
230 unregister_select_user( &input
->select
);
231 unregister_select_user( &output
->select
);
232 close( input
->select
.fd
);
233 close( output
->select
.fd
);
234 input
->select
.fd
= fd_in
;
235 output
->select
.fd
= fd_out
;
237 register_select_user( &input
->select
);
238 register_select_user( &output
->select
);
239 release_object( input
);
240 release_object( output
);
244 static int get_console_mode( int handle
, int *mode
)
249 if (!(obj
= get_handle_obj( current
->process
, handle
, GENERIC_READ
, NULL
)))
251 if (obj
->ops
== &console_input_ops
)
253 *mode
= ((struct console_input
*)obj
)->mode
;
256 else if (obj
->ops
== &screen_buffer_ops
)
258 *mode
= ((struct screen_buffer
*)obj
)->mode
;
261 else SET_ERROR( ERROR_INVALID_HANDLE
);
262 release_object( obj
);
266 static int set_console_mode( int handle
, int mode
)
271 if (!(obj
= get_handle_obj( current
->process
, handle
, GENERIC_READ
, NULL
)))
273 if (obj
->ops
== &console_input_ops
)
275 ((struct console_input
*)obj
)->mode
= mode
;
278 else if (obj
->ops
== &screen_buffer_ops
)
280 ((struct screen_buffer
*)obj
)->mode
= mode
;
283 else SET_ERROR( ERROR_INVALID_HANDLE
);
284 release_object( obj
);
288 /* set misc console information (output handle only) */
289 static int set_console_info( int handle
, struct set_console_info_request
*req
, const char *title
)
291 struct screen_buffer
*console
;
292 if (!(console
= (struct screen_buffer
*)get_handle_obj( current
->process
, handle
,
293 GENERIC_WRITE
, &screen_buffer_ops
)))
295 if (req
->mask
& SET_CONSOLE_INFO_CURSOR
)
297 console
->cursor_size
= req
->cursor_size
;
298 console
->cursor_visible
= req
->cursor_visible
;
300 if (req
->mask
& SET_CONSOLE_INFO_TITLE
)
302 if (console
->title
) free( console
->title
);
303 console
->title
= strdup( title
);
305 release_object( console
);
309 /* get misc console information (output handle only) */
310 static int get_console_info( int handle
, struct get_console_info_reply
*reply
, const char **title
)
312 struct screen_buffer
*console
;
313 if (!(console
= (struct screen_buffer
*)get_handle_obj( current
->process
, handle
,
314 GENERIC_READ
, &screen_buffer_ops
)))
316 reply
->cursor_size
= console
->cursor_size
;
317 reply
->cursor_visible
= console
->cursor_visible
;
318 reply
->pid
= console
->pid
;
319 *title
= console
->title
;
320 release_object( console
);
324 /* add input events to a console input queue */
325 static int write_console_input( int handle
, int count
, INPUT_RECORD
*records
)
327 INPUT_RECORD
*new_rec
;
328 struct console_input
*console
;
330 if (!(console
= (struct console_input
*)get_handle_obj( current
->process
, handle
,
331 GENERIC_WRITE
, &console_input_ops
)))
333 if (!(new_rec
= realloc( console
->records
,
334 (console
->recnum
+ count
) * sizeof(INPUT_RECORD
) )))
336 SET_ERROR( ERROR_NOT_ENOUGH_MEMORY
);
337 release_object( console
);
340 console
->records
= new_rec
;
341 memcpy( new_rec
+ console
->recnum
, records
, count
* sizeof(INPUT_RECORD
) );
342 console
->recnum
+= count
;
343 release_object( console
);
347 /* retrieve a pointer to the console input records */
348 static int read_console_input( int handle
, int count
, int flush
)
350 struct console_input
*console
;
351 struct read_console_input_reply reply
;
353 if (!(console
= (struct console_input
*)get_handle_obj( current
->process
, handle
,
354 GENERIC_READ
, &console_input_ops
)))
356 if ((count
< 0) || (count
> console
->recnum
)) count
= console
->recnum
;
357 send_reply( current
, -1, 2, &reply
, sizeof(reply
),
358 console
->records
, count
* sizeof(INPUT_RECORD
) );
362 for (i
= count
; i
< console
->recnum
; i
++)
363 console
->records
[i
-count
] = console
->records
[i
];
364 if ((console
->recnum
-= count
) > 0)
366 INPUT_RECORD
*new_rec
= realloc( console
->records
,
367 console
->recnum
* sizeof(INPUT_RECORD
) );
368 if (new_rec
) console
->records
= new_rec
;
372 free( console
->records
);
373 console
->records
= NULL
;
376 release_object( console
);
380 static void console_input_dump( struct object
*obj
, int verbose
)
382 struct console_input
*console
= (struct console_input
*)obj
;
383 assert( obj
->ops
== &console_input_ops
);
384 fprintf( stderr
, "Console input fd=%d\n", console
->select
.fd
);
387 static int console_input_add_queue( struct object
*obj
, struct wait_queue_entry
*entry
)
389 struct console_input
*console
= (struct console_input
*)obj
;
390 assert( obj
->ops
== &console_input_ops
);
391 if (!obj
->head
) /* first on the queue */
392 set_select_events( &console
->select
, READ_EVENT
);
393 add_queue( obj
, entry
);
397 static void console_input_remove_queue( struct object
*obj
, struct wait_queue_entry
*entry
)
399 struct console_input
*console
= (struct console_input
*)grab_object(obj
);
400 assert( obj
->ops
== &console_input_ops
);
402 remove_queue( obj
, entry
);
403 if (!obj
->head
) /* last on the queue is gone */
404 set_select_events( &console
->select
, 0 );
405 release_object( obj
);
408 static int console_input_signaled( struct object
*obj
, struct thread
*thread
)
410 struct console_input
*console
= (struct console_input
*)obj
;
411 assert( obj
->ops
== &console_input_ops
);
413 if (check_select_events( &console
->select
, READ_EVENT
))
415 /* stop waiting on select() if we are signaled */
416 set_select_events( &console
->select
, 0 );
421 /* restart waiting on select() if we are no longer signaled */
422 if (obj
->head
) set_select_events( &console
->select
, READ_EVENT
);
427 static int console_input_get_read_fd( struct object
*obj
)
429 struct console_input
*console
= (struct console_input
*)obj
;
430 assert( obj
->ops
== &console_input_ops
);
431 return dup( console
->select
.fd
);
434 static int console_get_info( struct object
*obj
, struct get_file_info_reply
*reply
)
436 memset( reply
, 0, sizeof(*reply
) );
437 reply
->type
= FILE_TYPE_CHAR
;
441 static void console_input_destroy( struct object
*obj
)
443 struct console_input
*console
= (struct console_input
*)obj
;
444 assert( obj
->ops
== &console_input_ops
);
445 unregister_select_user( &console
->select
);
446 close( console
->select
.fd
);
447 if (console
->output
) console
->output
->input
= NULL
;
451 static void screen_buffer_dump( struct object
*obj
, int verbose
)
453 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
454 assert( obj
->ops
== &screen_buffer_ops
);
455 fprintf( stderr
, "Console screen buffer fd=%d\n", console
->select
.fd
);
458 static int screen_buffer_add_queue( struct object
*obj
, struct wait_queue_entry
*entry
)
460 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
461 assert( obj
->ops
== &screen_buffer_ops
);
462 if (!obj
->head
) /* first on the queue */
463 set_select_events( &console
->select
, WRITE_EVENT
);
464 add_queue( obj
, entry
);
468 static void screen_buffer_remove_queue( struct object
*obj
, struct wait_queue_entry
*entry
)
470 struct screen_buffer
*console
= (struct screen_buffer
*)grab_object(obj
);
471 assert( obj
->ops
== &screen_buffer_ops
);
473 remove_queue( obj
, entry
);
474 if (!obj
->head
) /* last on the queue is gone */
475 set_select_events( &console
->select
, 0 );
476 release_object( obj
);
479 static int screen_buffer_signaled( struct object
*obj
, struct thread
*thread
)
481 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
482 assert( obj
->ops
== &screen_buffer_ops
);
484 if (check_select_events( &console
->select
, WRITE_EVENT
))
486 /* stop waiting on select() if we are signaled */
487 set_select_events( &console
->select
, 0 );
492 /* restart waiting on select() if we are no longer signaled */
493 if (obj
->head
) set_select_events( &console
->select
, WRITE_EVENT
);
498 static int screen_buffer_get_write_fd( struct object
*obj
)
500 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
501 assert( obj
->ops
== &screen_buffer_ops
);
502 return dup( console
->select
.fd
);
505 static void screen_buffer_destroy( struct object
*obj
)
507 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
508 assert( obj
->ops
== &screen_buffer_ops
);
509 unregister_select_user( &console
->select
);
510 close( console
->select
.fd
);
511 if (console
->input
) console
->input
->output
= NULL
;
512 if (console
->pid
) kill( console
->pid
, SIGTERM
);
513 if (console
->title
) free( console
->title
);
517 /* allocate a console for the current process */
518 DECL_HANDLER(alloc_console
)
520 struct alloc_console_reply reply
= { -1, -1 };
522 if (!alloc_console( current
->process
)) goto done
;
524 if ((reply
.handle_in
= alloc_handle( current
->process
, current
->process
->console_in
,
525 req
->access
, req
->inherit
)) != -1)
527 if ((reply
.handle_out
= alloc_handle( current
->process
, current
->process
->console_out
,
528 req
->access
, req
->inherit
)) != -1)
529 goto done
; /* everything is fine */
530 close_handle( current
->process
, reply
.handle_in
);
531 reply
.handle_in
= -1;
533 free_console( current
->process
);
536 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
539 /* free the console of the current process */
540 DECL_HANDLER(free_console
)
542 free_console( current
->process
);
543 send_reply( current
, -1, 0 );
546 /* open a handle to the process console */
547 DECL_HANDLER(open_console
)
549 struct open_console_reply reply
= { -1 };
550 struct object
*obj
= req
->output
? current
->process
->console_out
: current
->process
->console_in
;
552 if (obj
) reply
.handle
= alloc_handle( current
->process
, obj
, req
->access
, req
->inherit
);
553 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
556 /* set info about a console (output only) */
557 DECL_HANDLER(set_console_info
)
559 char *name
= (char *)data
;
560 if (!len
) name
= NULL
;
561 else CHECK_STRING( "set_console_info", name
, len
);
562 set_console_info( req
->handle
, req
, name
);
563 send_reply( current
, -1, 0 );
566 /* get info about a console (output only) */
567 DECL_HANDLER(get_console_info
)
569 struct get_console_info_reply reply
;
571 get_console_info( req
->handle
, &reply
, &title
);
572 send_reply( current
, -1, 2, &reply
, sizeof(reply
),
573 title
, title
? strlen(title
)+1 : 0 );
576 /* set a console fd */
577 DECL_HANDLER(set_console_fd
)
579 set_console_fd( req
->handle
, fd
, req
->pid
);
580 send_reply( current
, -1, 0 );
583 /* get a console mode (input or output) */
584 DECL_HANDLER(get_console_mode
)
586 struct get_console_mode_reply reply
;
587 get_console_mode( req
->handle
, &reply
.mode
);
588 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
591 /* set a console mode (input or output) */
592 DECL_HANDLER(set_console_mode
)
594 set_console_mode( req
->handle
, req
->mode
);
595 send_reply( current
, -1, 0 );
598 /* add input records to a console input queue */
599 DECL_HANDLER(write_console_input
)
601 struct write_console_input_reply reply
;
602 INPUT_RECORD
*records
= (INPUT_RECORD
*)data
;
604 if (len
!= req
->count
* sizeof(INPUT_RECORD
))
605 fatal_protocol_error( "write_console_input: bad length %d for %d records\n",
607 reply
.written
= write_console_input( req
->handle
, req
->count
, records
);
608 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
611 /* fetch input records from a console input queue */
612 DECL_HANDLER(read_console_input
)
614 read_console_input( req
->handle
, req
->count
, req
->flush
);