Hacked server-side device support
[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 <assert.h>
11 #include <fcntl.h>
12 #include <signal.h>
13 #include <string.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <sys/errno.h>
17 #include <sys/stat.h>
18 #include <sys/time.h>
19 #include <sys/types.h>
20 #include <time.h>
21 #include <unistd.h>
22
23 #include "winerror.h"
24 #include "winnt.h"
25 #include "wincon.h"
26 #include "server/thread.h"
27
28 struct screen_buffer;
29
30 struct console_input
31 {
32     struct object         obj;           /* object header */
33     int                   fd;            /* Unix file descriptor */
34     int                   mode;          /* input mode */
35     struct screen_buffer *output;        /* associated screen buffer */
36 };
37
38 struct screen_buffer
39 {
40     struct object         obj;           /* object header */
41     int                   fd;            /* Unix file descriptor */
42     int                   mode;          /* output mode */
43     struct console_input *input;         /* associated console input */
44     int                   cursor_size;   /* size of cursor (percentage filled) */
45     int                   cursor_visible;/* cursor visibility flag */
46     int                   pid;           /* xterm pid (hack) */
47     char                 *title;         /* console title */
48 };
49
50
51 static void console_input_dump( struct object *obj, int verbose );
52 static int console_input_add_queue( struct object *obj, struct wait_queue_entry *entry );
53 static void console_input_remove_queue( struct object *obj, struct wait_queue_entry *entry );
54 static int console_input_signaled( struct object *obj, struct thread *thread );
55 static int console_input_get_read_fd( struct object *obj );
56 static void console_input_destroy( struct object *obj );
57
58 static void screen_buffer_dump( struct object *obj, int verbose );
59 static int screen_buffer_add_queue( struct object *obj, struct wait_queue_entry *entry );
60 static void screen_buffer_remove_queue( struct object *obj, struct wait_queue_entry *entry );
61 static int screen_buffer_signaled( struct object *obj, struct thread *thread );
62 static int screen_buffer_get_write_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_reply *reply );
67
68 static const struct object_ops console_input_ops =
69 {
70     console_input_dump,
71     console_input_add_queue,
72     console_input_remove_queue,
73     console_input_signaled,
74     no_satisfied,
75     console_input_get_read_fd,
76     no_write_fd,
77     no_flush,
78     console_get_info,
79     console_input_destroy
80 };
81
82 static const struct object_ops screen_buffer_ops =
83 {
84     screen_buffer_dump,
85     screen_buffer_add_queue,
86     screen_buffer_remove_queue,
87     screen_buffer_signaled,
88     no_satisfied,
89     no_read_fd,
90     screen_buffer_get_write_fd,
91     no_flush,
92     console_get_info,
93     screen_buffer_destroy
94 };
95
96 static const struct select_ops select_ops =
97 {
98     default_select_event,
99     NULL   /* we never set a timeout on a console */
100 };
101
102 int create_console( int fd, struct object *obj[2] )
103 {
104     struct console_input *console_input;
105     struct screen_buffer *screen_buffer;
106     int read_fd, write_fd;
107
108     if ((read_fd = (fd != -1) ? dup(fd) : dup(0)) == -1)
109     {
110         file_set_error();
111         return 0;
112     }
113     if ((write_fd = (fd != -1) ? dup(fd) : dup(1)) == -1)
114     {
115         file_set_error();
116         close( read_fd );
117         return 0;
118     }
119     if (!(console_input = mem_alloc( sizeof(struct console_input) )))
120     {
121         close( read_fd );
122         close( write_fd );
123         return 0;
124     }
125     if (!(screen_buffer = mem_alloc( sizeof(struct screen_buffer) )))
126     {
127         close( read_fd );
128         close( write_fd );
129         free( console_input );
130         return 0;
131     }
132     init_object( &console_input->obj, &console_input_ops, NULL );
133     init_object( &screen_buffer->obj, &screen_buffer_ops, NULL );
134     console_input->fd             = read_fd;
135     console_input->mode           = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
136                                     ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
137     console_input->output         = screen_buffer;
138     screen_buffer->fd             = write_fd;
139     screen_buffer->mode           = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
140     screen_buffer->input          = console_input;
141     screen_buffer->cursor_size    = 100;
142     screen_buffer->cursor_visible = 1;
143     screen_buffer->pid            = 0;
144     screen_buffer->title          = strdup( "Wine console" );
145     CLEAR_ERROR();
146     obj[0] = &console_input->obj;
147     obj[1] = &screen_buffer->obj;
148     return 1;
149 }
150
151 int set_console_fd( int handle, int fd, int pid )
152 {
153     struct console_input *input;
154     struct screen_buffer *output;
155     struct object *obj;
156     int fd_in, fd_out;
157
158     if (!(obj = get_handle_obj( current->process, handle, 0, NULL )))
159         return 0;
160     if (obj->ops == &console_input_ops)
161     {
162         input = (struct console_input *)obj;
163         output = input->output;
164         grab_object( output );
165     }
166     else if (obj->ops == &screen_buffer_ops)
167     {
168         output = (struct screen_buffer *)obj;
169         input = output->input;
170         grab_object( input );
171     }
172     else
173     {
174         SET_ERROR( ERROR_INVALID_HANDLE );
175         release_object( obj );
176         return 0;
177     }
178
179     if ((fd_in = dup(fd)) == -1)
180     {
181         file_set_error();
182         release_object( input );
183         release_object( output );
184         return 0;
185     }
186     if ((fd_out = dup(fd)) == -1)
187     {
188         file_set_error();
189         close( fd_in );
190         release_object( input );
191         release_object( output );
192         return 0;
193     }
194     close( input->fd );
195     close( output->fd );
196     input->fd = fd_in;
197     output->fd = fd_out;
198     output->pid = pid;
199     release_object( input );
200     release_object( output );
201     return 1;
202 }
203
204 int get_console_mode( int handle, int *mode )
205 {
206     struct object *obj;
207     int ret = 0;
208
209     if (!(obj = get_handle_obj( current->process, handle, GENERIC_READ, NULL )))
210         return 0;
211     if (obj->ops == &console_input_ops)
212     {
213         *mode = ((struct console_input *)obj)->mode;
214         ret = 1;
215     }
216     else if (obj->ops == &screen_buffer_ops)
217     {
218         *mode = ((struct screen_buffer *)obj)->mode;
219         ret = 1;
220     }
221     else SET_ERROR( ERROR_INVALID_HANDLE );
222     release_object( obj );
223     return ret;
224 }
225
226 int set_console_mode( int handle, int mode )
227 {
228     struct object *obj;
229     int ret = 0;
230
231     if (!(obj = get_handle_obj( current->process, handle, GENERIC_READ, NULL )))
232         return 0;
233     if (obj->ops == &console_input_ops)
234     {
235         ((struct console_input *)obj)->mode = mode;
236         ret = 1;
237     }
238     else if (obj->ops == &screen_buffer_ops)
239     {
240         ((struct screen_buffer *)obj)->mode = mode;
241         ret = 1;
242     }
243     else SET_ERROR( ERROR_INVALID_HANDLE );
244     release_object( obj );
245     return ret;
246 }
247
248 /* set misc console information (output handle only) */
249 int set_console_info( int handle, struct set_console_info_request *req, const char *title )
250 {
251     struct screen_buffer *console;
252     if (!(console = (struct screen_buffer *)get_handle_obj( current->process, handle,
253                                                             GENERIC_WRITE, &screen_buffer_ops )))
254         return 0;
255     if (req->mask & SET_CONSOLE_INFO_CURSOR)
256     {
257         console->cursor_size    = req->cursor_size;
258         console->cursor_visible = req->cursor_visible;
259     }
260     if (req->mask & SET_CONSOLE_INFO_TITLE)
261     {
262         if (console->title) free( console->title );
263         console->title = strdup( title );
264     }
265     release_object( console );
266     return 1;
267 }
268
269 /* get misc console information (output handle only) */
270 int get_console_info( int handle, struct get_console_info_reply *reply, const char **title )
271 {
272     struct screen_buffer *console;
273     if (!(console = (struct screen_buffer *)get_handle_obj( current->process, handle,
274                                                             GENERIC_READ, &screen_buffer_ops )))
275         return 0;
276     reply->cursor_size    = console->cursor_size;
277     reply->cursor_visible = console->cursor_visible;
278     reply->pid            = console->pid;
279     *title                = console->title;
280     release_object( console );
281     return 1;
282 }
283
284 static void console_input_dump( struct object *obj, int verbose )
285 {
286     struct console_input *console = (struct console_input *)obj;
287     assert( obj->ops == &console_input_ops );
288     fprintf( stderr, "Console input fd=%d\n", console->fd );
289 }
290
291 static int console_input_add_queue( struct object *obj, struct wait_queue_entry *entry )
292 {
293     struct console_input *console = (struct console_input *)obj;
294     assert( obj->ops == &console_input_ops );
295     if (!obj->head)  /* first on the queue */
296     {
297         if (!add_select_user( console->fd, READ_EVENT, &select_ops, console ))
298         {
299             SET_ERROR( ERROR_OUTOFMEMORY );
300             return 0;
301         }
302     }
303     add_queue( obj, entry );
304     return 1;
305 }
306
307 static void console_input_remove_queue( struct object *obj, struct wait_queue_entry *entry )
308 {
309     struct console_input *console = (struct console_input *)grab_object(obj);
310     assert( obj->ops == &console_input_ops );
311
312     remove_queue( obj, entry );
313     if (!obj->head)  /* last on the queue is gone */
314         remove_select_user( console->fd );
315     release_object( obj );
316 }
317
318 static int console_input_signaled( struct object *obj, struct thread *thread )
319 {
320     fd_set fds;
321     struct timeval tv = { 0, 0 };
322     struct console_input *console = (struct console_input *)obj;
323     assert( obj->ops == &console_input_ops );
324
325     FD_ZERO( &fds );
326     FD_SET( console->fd, &fds );
327     return select( console->fd + 1, &fds, NULL, NULL, &tv ) > 0;
328 }
329
330 static int console_input_get_read_fd( struct object *obj )
331 {
332     struct console_input *console = (struct console_input *)obj;
333     assert( obj->ops == &console_input_ops );
334     return dup( console->fd );
335 }
336
337 static int console_get_info( struct object *obj, struct get_file_info_reply *reply )
338 {
339     memset( reply, 0, sizeof(*reply) );
340     reply->type = FILE_TYPE_CHAR;
341     return 1;
342 }
343
344 static void console_input_destroy( struct object *obj )
345 {
346     struct console_input *console = (struct console_input *)obj;
347     assert( obj->ops == &console_input_ops );
348     close( console->fd );
349     if (console->output) console->output->input = NULL;
350     free( console );
351 }
352
353 static void screen_buffer_dump( struct object *obj, int verbose )
354 {
355     struct screen_buffer *console = (struct screen_buffer *)obj;
356     assert( obj->ops == &screen_buffer_ops );
357     fprintf( stderr, "Console screen buffer fd=%d\n", console->fd );
358 }
359
360 static int screen_buffer_add_queue( struct object *obj, struct wait_queue_entry *entry )
361 {
362     struct screen_buffer *console = (struct screen_buffer *)obj;
363     assert( obj->ops == &screen_buffer_ops );
364     if (!obj->head)  /* first on the queue */
365     {
366         if (!add_select_user( console->fd, WRITE_EVENT, &select_ops, console ))
367         {
368             SET_ERROR( ERROR_OUTOFMEMORY );
369             return 0;
370         }
371     }
372     add_queue( obj, entry );
373     return 1;
374 }
375
376 static void screen_buffer_remove_queue( struct object *obj, struct wait_queue_entry *entry )
377 {
378     struct screen_buffer *console = (struct screen_buffer *)grab_object(obj);
379     assert( obj->ops == &screen_buffer_ops );
380
381     remove_queue( obj, entry );
382     if (!obj->head)  /* last on the queue is gone */
383         remove_select_user( console->fd );
384     release_object( obj );
385 }
386
387 static int screen_buffer_signaled( struct object *obj, struct thread *thread )
388 {
389     fd_set fds;
390     struct timeval tv = { 0, 0 };
391     struct screen_buffer *console = (struct screen_buffer *)obj;
392     assert( obj->ops == &screen_buffer_ops );
393
394     FD_ZERO( &fds );
395     FD_SET( console->fd, &fds );
396     return select( console->fd + 1, NULL, &fds, NULL, &tv ) > 0;
397 }
398
399 static int screen_buffer_get_write_fd( struct object *obj )
400 {
401     struct screen_buffer *console = (struct screen_buffer *)obj;
402     assert( obj->ops == &screen_buffer_ops );
403     return dup( console->fd );
404 }
405
406 static void screen_buffer_destroy( struct object *obj )
407 {
408     struct screen_buffer *console = (struct screen_buffer *)obj;
409     assert( obj->ops == &screen_buffer_ops );
410     close( console->fd );
411     if (console->input) console->input->output = NULL;
412     if (console->pid) kill( console->pid, SIGTERM );
413     if (console->title) free( console->title );
414     free( console );
415 }