diff options
author | Marcus Brinkmann <marcus@gnu.org> | 2002-08-22 19:24:19 +0000 |
---|---|---|
committer | Marcus Brinkmann <marcus@gnu.org> | 2002-08-22 19:24:19 +0000 |
commit | 9cc0d6d3f8a89f35ddea92e30bdc2822c4164358 (patch) | |
tree | d182cfe90532231aaff4411a9d0118e9e5a15e7e /libcons/vcons-open.c | |
parent | 4062fb2fcf938bb6a9c5d8f6404586cab11fe227 (diff) | |
download | hurd-9cc0d6d3f8a89f35ddea92e30bdc2822c4164358.tar.gz hurd-9cc0d6d3f8a89f35ddea92e30bdc2822c4164358.tar.bz2 hurd-9cc0d6d3f8a89f35ddea92e30bdc2822c4164358.zip |
libcons/
2002-08-22 Marcus Brinkmann <marcus@gnu.org>
* demuxer.c, init-init.c, init-loop.c, opts-version.c,
extra-version.c, dir-changed.c, file-changed.c,
opts-std-startup.c, cons-lookup.c, cons-switch.c, vcons-remove.c,
vcons-add.c, vcons-open.c, vcons-close.c, vcons-refresh.c, priv.h,
mutations.h, cons.h: New files.
Diffstat (limited to 'libcons/vcons-open.c')
-rw-r--r-- | libcons/vcons-open.c | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/libcons/vcons-open.c b/libcons/vcons-open.c new file mode 100644 index 00000000..7256b4c8 --- /dev/null +++ b/libcons/vcons-open.c @@ -0,0 +1,162 @@ +/* vcons-open.c - Open a virtual console. + Copyright (C) 2002 Free Software Foundation, Inc. + Written by Marcus Brinkmann. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +#include <errno.h> +#include <unistd.h> +#include <stdio.h> +#include <sys/mman.h> +#include <sys/fcntl.h> + +#include <hurd.h> +#include <mach.h> + +#include "cons.h" + +/* Open the virtual console VCONS. VCONS->cons is locked. */ +error_t +cons_vcons_open (vcons_t vcons) +{ + error_t err = 0; + char *name; + file_t vconsp = MACH_PORT_NULL; + file_t file = MACH_PORT_NULL; + int fd = -1; + struct stat statbuf; + mach_port_t notify = MACH_PORT_NULL; + + if (asprintf (&name, "%u", vcons->id) < 0) + return err; + + /* Open the directory port of the virtual console. */ + vconsp = file_name_lookup_under (vcons->cons->dirport, name, + O_DIRECTORY | O_RDONLY, 0); + if (vconsp == MACH_PORT_NULL) + { + err = errno; + goto err; + } + + /* Within that directory, open the input node. */ + file = file_name_lookup_under (vconsp, "input", O_WRONLY /* | O_NONBLOCK */, 0); + if (file == MACH_PORT_NULL) + err = errno; + else + { + vcons->input = openport (file, O_WRONLY /* | O_NONBLOCK */); + if (vcons->input < 0) + err = errno; + else + /* openport() consumed the reference. */ + file = MACH_PORT_NULL; + } + if (err) + goto err; + + /* Within that directory, also open the display node. */ + file = file_name_lookup_under (vconsp, "display", O_RDONLY, 0); + if (file == MACH_PORT_NULL) + err = errno; + else + { + /* Acquire an additional reference for openport(). */ + err = mach_port_mod_refs (mach_task_self (), file, + MACH_PORT_RIGHT_SEND, +1); + if (err) + goto err; + fd = openport (file, O_RDONLY); + if (fd < 0) + err = errno; + } + if (err) + goto err; + + /* Map the whole file. */ + if (fstat (fd, &statbuf) < 0) + { + err = errno; + goto err; + } + vcons->display_size = statbuf.st_size; + vcons->display = mmap (0, vcons->display_size, PROT_READ, MAP_SHARED, fd, 0); + if (vcons->display == MAP_FAILED) + { + err = errno; + goto err; + } + + if (vcons->display->magic != CONS_MAGIC + || vcons->display->version >> CONS_VERSION_MAJ_SHIFT != 0) + { + err = EINVAL; + goto err; + } + vcons->state.screen.width = vcons->display->screen.width; + vcons->state.screen.height = vcons->display->screen.height; + vcons->state.screen.lines = vcons->display->screen.lines; + vcons->state.screen.matrix = ((wchar_t *) vcons->display) + + vcons->display->screen.matrix; + vcons->state.changes.length = vcons->display->changes.length; + vcons->state.changes.buffer = ((uint32_t *) vcons->display) + + vcons->display->changes.buffer; + + /* Set up the port we receive notification messages on. */ + err = ports_create_port (cons_port_class, cons_port_bucket, + sizeof (*vcons->notify), &vcons->notify); + if (err) + goto err; + vcons->notify->cons = NULL; + vcons->notify->vcons = vcons; + + /* Request notification messages. */ + notify = ports_get_right (vcons->notify); + mach_port_set_qlimit (mach_task_self (), notify, 1); + + /* When this succeeds, we will immediately receive notification + messages for this virtual console. */ + err = file_notice_changes (file, notify, MACH_MSG_TYPE_MAKE_SEND); + if (!err) + goto out; + + err: + if (vcons->input >= 0) + { + close (vcons->input); + vcons->input = -1; + } + if (vcons->display != MAP_FAILED) + { + munmap (vcons->display, vcons->display_size); + vcons->display = MAP_FAILED; + } + if (notify) + { + mach_port_deallocate (mach_task_self (), notify); + vcons->notify = MACH_PORT_NULL; + } + out: + if (fd > 0) + close (fd); + if (file != MACH_PORT_NULL) + mach_port_deallocate (mach_task_self (), file); + if (vconsp != MACH_PORT_NULL) + mach_port_deallocate (mach_task_self (), vconsp); + free (name); + return err; +} |