/* 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 #include #include #include #include #include #include #include #include "cons.h" /* Open the virtual console for VCONS_ENTRY. CONS is locked. Afterwards, R_VCONS will be locked. */ error_t cons_vcons_open (cons_t cons, vcons_list_t vcons_entry, vcons_t *r_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; vcons_t vcons; if (asprintf (&name, "%u", vcons_entry->id) < 0) return err; /* Set up the port we receive notification messages on. */ err = ports_create_port (cons_port_class, cons_port_bucket, sizeof (*vcons), &vcons); if (err) goto err; vcons->notify.cons = NULL; vcons->cons = cons; vcons->vcons_entry = vcons_entry; vcons->id = vcons_entry->id; pthread_mutex_init (&vcons->lock, NULL); vcons->input = -1; vcons->display = MAP_FAILED; vcons->scrolling = 0; /* Open the directory port of the virtual console. */ vconsp = file_name_lookup_under (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 = (conchar_t *) (((uint32_t *) vcons->display) + vcons->display->screen.matrix); vcons->state.changes.length = vcons->display->changes.length; vcons->state.changes.buffer = (cons_change_t *) (((uint32_t *) vcons->display) + vcons->display->changes.buffer); /* Request notification messages. */ notify = ports_get_right (vcons); mach_port_set_qlimit (mach_task_self (), notify, 1); /* When this succeeds, we will immediately receive notification messages for this virtual console. */ pthread_mutex_lock (&vcons->lock); err = file_notice_changes (file, notify, MACH_MSG_TYPE_MAKE_SEND); if (!err) { *r_vcons = vcons; 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); ports_port_deref (vcons); } ports_destroy_right (vcons); 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; }