Makefile: adjust CFLAGS to support extern inline. inputdev.h: copied from hurd/console-client/mach-inputdev.h. version.h: copied from configured directory. --- Makefile | 8 +- input.h | 3 + inputdev.h | 6 +- trans.c | 892 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ trans.h | 17 +- version.h | 29 ++ 6 files changed, 946 insertions(+), 9 deletions(-) create mode 100644 trans.c create mode 100644 version.h
diff --git a/Makefile b/Makefile index b940c4f..40f5b07 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -CC = gcc -CFLAGS = -O -g -Wall -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 +CFLAGS = -O -g -Wall -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -I. \ + -std=gnu99 -fgnu89-inline OBJS = kstoucs.o symname.o compose.o xkb.o parser.tab.o lex.o \ xkbdata.o xkbdefaults.o xkbtimer.o timer.o kbd-repeat.o \ kdioctlServer.o @@ -35,8 +35,8 @@ lex.c: lex.l parser.tab.h parser.tab.c parser.tab.h: parser.y $(YACC) -v -d $< -input_driver_test: input_driver_test.c - $(CC) -rdynamic $(CFLAGS) $(LIBS) -ldl input_driver_test.c -o input_driver_test +input_driver_test: input_driver_test.c trans.o + $(CC) -rdynamic $(CFLAGS) $(LIBS) -ldl input_driver_test.c trans.o -o input_driver_test kbd-repeat.o: kdioctl_S.h diff --git a/input.h b/input.h index e5683a8..351fa34 100644 --- a/input.h +++ b/input.h @@ -55,6 +55,9 @@ error_t console_input (char *buf, size_t size); cons_vcons_scrollback. */ int console_scrollback (cons_scroll_t type, float value); +/* Returns current console ID. */ +error_t console_current_id (int *cur); + /* Switch the active console to console ID or DELTA (relative to the active console). */ error_t console_switch (int id, int delta); diff --git a/inputdev.h b/inputdev.h index 9a4ee42..985e1e1 100644 --- a/inputdev.h +++ b/inputdev.h @@ -1,5 +1,5 @@ -/* inputdev.h - Interfaces for the PC pc-kbd and mouse input drivers. - Copyright (C) 2002, 2004 Free Software Foundation, Inc. +/* mach-inputdev.h - Interfaces for the PC pc-kbd and mouse input drivers. + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. Written by Marco Gerards. This file is part of the GNU Hurd. @@ -50,7 +50,7 @@ #ifndef _INPUTDEV_H_ #define _INPUTDEV_H_ 1 -#include "trans.h" +#include <trans.h> typedef u_short kev_type; /* kd event type */ diff --git a/trans.c b/trans.c new file mode 100644 index 0000000..a90b5c5 --- /dev/null +++ b/trans.c @@ -0,0 +1,892 @@ +/* trans.c -- Control a translator node for the repeaters. + + Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc. + + Written by Marco Gerards. + + This program 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. + + This program 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-1307 USA */ + +#include <fcntl.h> +#include <maptime.h> +#include <stddef.h> +#include <dirent.h> +#include <sys/mman.h> +#include <unistd.h> +#include <hurd/hurd_types.h> +#include <error.h> +#include <version.h> + +#include "trans.h" + + +char *netfs_server_name = "console"; +char *netfs_server_version = HURD_VERSION; +int netfs_maxsymlinks = 0; + +/* Handy source of time. */ +static volatile struct mapped_time_value *console_maptime; + +static consnode_t node_list = 0; + +struct netnode +{ + consnode_t node; + char *symlink_path; +}; + +typedef mach_msg_header_t request_t; + + +int +console_demuxer (mach_msg_header_t *inp, + mach_msg_header_t *outp) +{ + int ret; + struct protid *user = (struct protid *) inp; + request_t *inop = (request_t *) inp; + + ret = netfs_demuxer (inp, outp); + if (ret) + return ret; + + user = ports_lookup_port (netfs_port_bucket, inop->msgh_local_port, netfs_protid_class); + if (!user) + return ret; + + /* Don't do anything for the root node. */ + if (user->po->np == netfs_root_node) + { + ports_port_deref (user); + return 0; + } + + if (!ret && user->po->np->nn->node && user->po->np->nn->node->demuxer) + ret = user->po->np->nn->node->demuxer (inp, outp); + + ports_port_deref (user); + return ret; +} + + + +/* Make sure that NP->nn_stat is filled with current information. CRED + identifies the user responsible for the operation. */ +error_t +netfs_validate_stat (struct node *np, struct iouser *cred) +{ + return 0; +} + + +/* This should attempt a chmod call for the user specified by CRED on node + NODE, to change the owner to UID and the group to GID. */ +error_t +netfs_attempt_chown (struct iouser *cred, struct node *np, + uid_t uid, uid_t gid) +{ + return EOPNOTSUPP; +} + + +/* This should attempt a chauthor call for the user specified by CRED on node + NODE, to change the author to AUTHOR. */ +error_t +netfs_attempt_chauthor (struct iouser *cred, struct node *np, + uid_t author) +{ + return EOPNOTSUPP; +} + + +/* This should attempt a chmod call for the user specified by CRED on node + NODE, to change the mode to MODE. Unlike the normal Unix and Hurd meaning + of chmod, this function is also used to attempt to change files into other + types. If such a transition is attempted which is impossible, then return + EOPNOTSUPP. */ +error_t +netfs_attempt_chmod (struct iouser *cred, struct node *np, + mode_t mode) +{ + return EOPNOTSUPP; +} + + +/* Attempt to turn NODE (user CRED) into a symlink with target NAME. */ +error_t +netfs_attempt_mksymlink (struct iouser *cred, struct node *np, + char *name) +{ + if (!np->nn->node) + { + if (np->nn->symlink_path) + free (np->nn->symlink_path); + np->nn->symlink_path = strdup (name); + return 0; + } + else if (np->nn->node->mksymlink) + return np->nn->node->mksymlink (cred, np, name); + return EOPNOTSUPP; +} + + +/* Attempt to turn NODE (user CRED) into a device. TYPE is either S_IFBLK or + S_IFCHR. */ +error_t +netfs_attempt_mkdev (struct iouser *cred, struct node *np, + mode_t type, dev_t indexes) +{ + return EOPNOTSUPP; +} + + +/* This should attempt a chflags call for the user specified by CRED on node + NODE, to change the flags to FLAGS. */ +error_t +netfs_attempt_chflags (struct iouser *cred, struct node *np, + int flags) +{ + return EOPNOTSUPP; +} + + +/* This should attempt a utimes call for the user specified by CRED on + locked node NP, to change the atime to ATIME and the mtime to + MTIME. If ATIME or MTIME is null, then set to the current + time. */ +error_t +netfs_attempt_utimes (struct iouser *cred, struct node *np, + struct timespec *atime, struct timespec *mtime) +{ + error_t err = fshelp_isowner (&np->nn_stat, cred); + int flags = TOUCH_CTIME; + + if (! err) + { + if (mtime) + np->nn_stat.st_mtim = *mtime; + else + flags |= TOUCH_MTIME; + + if (atime) + np->nn_stat.st_atim = *atime; + else + flags |= TOUCH_ATIME; + + fshelp_touch (&np->nn_stat, flags, console_maptime); + } + return err; + +} + + +/* This should attempt to set the size of the locked file NP (for user + CRED) to SIZE bytes long. */ +error_t +netfs_attempt_set_size (struct iouser *cred, struct node *np, + loff_t size) +{ + return EOPNOTSUPP; +} + +/* This should attempt to fetch filesystem status information for the + remote filesystem, for the user CRED. NP is locked. */ +error_t +netfs_attempt_statfs (struct iouser *cred, struct node *np, + fsys_statfsbuf_t *st) +{ + return EOPNOTSUPP; +} + + +/* This should sync the locked file NP completely to disk, for the + user CRED. If WAIT is set, return only after the sync is + completely finished. */ +error_t +netfs_attempt_sync (struct iouser *cred, struct node *np, + int wait) +{ + return 0; +} + + +/* This should sync the entire remote filesystem. If WAIT is set, + return only after the sync is completely finished. */ +error_t +netfs_attempt_syncfs (struct iouser *cred, int wait) +{ + return 0; +} + + +/* Lookup NAME in DIR (which is locked) for USER; set *NP to the found + name upon return. If the name was not found, then return ENOENT. + On any error, clear *NP. (*NP, if found, should be locked and a + reference to it generated. This call should unlock DIR no matter + what.) */ +error_t +netfs_attempt_lookup (struct iouser *user, struct node *dir, + char *name, struct node **node) +{ + error_t err; + consnode_t cn; + + *node = 0; + err = fshelp_access (&dir->nn_stat, S_IEXEC, user); + if (err) + goto out; + + if (strcmp (name, ".") == 0) + { + /* Current directory -- just add an additional reference to DIR + and return it. */ + netfs_nref (dir); + *node = dir; + goto out; + } + + if (strcmp (name, "..") == 0) + { + err = EAGAIN; + goto out; + } + + for (cn = node_list; cn; cn = cn->next) + if (!strcmp (name, cn->name)) + { + if (cn->node == NULL) + { + struct netnode *nn = calloc (1, sizeof *nn); + if (nn == NULL) + { + err = ENOMEM; + goto out; + } + + *node = netfs_make_node (nn); + + nn->node = cn; + (*node)->nn_stat = netfs_root_node->nn_stat; + (*node)->nn_stat.st_mode = (netfs_root_node->nn_stat.st_mode & ~S_IFMT & ~S_ITRANS); + (*node)->nn_stat.st_ino = 5; + if (cn->readlink) + { + (*node)->nn_stat.st_mode |= S_IFLNK; + (*node)->nn_stat.st_size = cn->readlink (user, NULL, NULL); + } + else + { + (*node)->nn_stat.st_mode |= S_IFCHR; + (*node)->nn_stat.st_size = 0; + } + cn->node = *node; + goto out; + } + else + { + *node = cn->node; + + netfs_nref (*node); + goto out; + } + } + + err = ENOENT; + + out: + mutex_unlock (&dir->lock); + if (err) + *node = 0; + else + mutex_lock (&(*node)->lock); + + if (!err && *node != dir && (*node)->nn->node->open) + (*node)->nn->node->open (); + + return err; +} + + +error_t +netfs_S_io_seek (struct protid *user, off_t offset, + int whence, off_t *newoffset) +{ + /* XXX: Will all nodes be device nodes? */ + if (!user) + return EOPNOTSUPP; + else + return ESPIPE; +} + + +error_t +netfs_S_io_select (struct protid *user, mach_port_t reply, + mach_msg_type_name_t replytype, int *type) +{ + struct node *np; + + if (!user) + return EOPNOTSUPP; + + np = user->po->np; + + if (np->nn->node && np->nn->node->select) + return np->nn->node->select (user, reply, replytype, type); + return EOPNOTSUPP; +} + + +/* Delete NAME in DIR (which is locked) for USER. */ +error_t +netfs_attempt_unlink (struct iouser *user, struct node *dir, + char *name) +{ + error_t err; + consnode_t cn; + + err = fshelp_access (&dir->nn_stat, S_IWRITE, user); + if (err) + return err; + + for (cn = node_list; cn; cn = cn->next) + if (!strcmp (name, cn->name)) + { + if (cn->mksymlink) + return 0; + else + break; + } + return EOPNOTSUPP; +} + + +/* Attempt to rename the directory FROMDIR to TODIR. Note that neither + of the specific nodes are locked. */ +error_t +netfs_attempt_rename (struct iouser *user, struct node *fromdir, + char *fromname, struct node *todir, + char *toname, int excl) +{ + return EOPNOTSUPP; +} + + +/* Attempt to create a new directory named NAME in DIR (which is + locked) for USER with mode MODE. */ +error_t +netfs_attempt_mkdir (struct iouser *user, struct node *dir, + char *name, mode_t mode) +{ + return EOPNOTSUPP; +} + + +/* Attempt to remove directory named NAME in DIR (which is locked) for + USER. */ +error_t +netfs_attempt_rmdir (struct iouser *user, + struct node *dir, char *name) +{ + return EOPNOTSUPP; +} + + +/* Create a link in DIR with name NAME to FILE for USER. Note that + neither DIR nor FILE are locked. If EXCL is set, do not delete the + target. Return EEXIST if NAME is already found in DIR. */ +error_t +netfs_attempt_link (struct iouser *user, struct node *dir, + struct node *file, char *name, int excl) +{ + error_t err; + consnode_t cn; + + err = fshelp_access (&dir->nn_stat, S_IWRITE, user); + if (err) + return err; + + if (!file->nn->node && file->nn->symlink_path) + { + for (cn = node_list; cn; cn = cn->next) + if (!strcmp (name, cn->name)) + { + if (cn->mksymlink) + { + file->nn->node = cn; + cn->mksymlink (user, file, file->nn->symlink_path); + free (file->nn->symlink_path); + file->nn->symlink_path = NULL; + return 0; + } + else + break; + } + } + return EOPNOTSUPP; +} + + +/* Attempt to create an anonymous file related to DIR (which is + locked) for USER with MODE. Set *NP to the returned file upon + success. No matter what, unlock DIR. */ +error_t +netfs_attempt_mkfile (struct iouser *user, struct node *dir, + mode_t mode, struct node **np) +{ + error_t err; + struct netnode *nn; + + err = fshelp_access (&dir->nn_stat, S_IWRITE, user); + if (err) + { + *np = 0; + return err; + } + + mutex_unlock (&dir->lock); + + nn = calloc (1, sizeof (*nn)); + if (!nn) + return ENOMEM; + + *np = netfs_make_node (nn); + mutex_lock (&(*np)->lock); + spin_unlock (&netfs_node_refcnt_lock); + + return 0; +} + + +/* Attempt to create a file named NAME in DIR (which is locked) for + USER with MODE. Set *NP to the new node upon return. On any + error, clear *NP. *NP should be locked on success; no matter what, + unlock DIR before returning. */ +error_t +netfs_attempt_create_file (struct iouser *user, struct node *dir, + char *name, mode_t mode, struct node **np) +{ + *np = 0; + mutex_unlock (&dir->lock); + return EOPNOTSUPP; +} + + +/* Read the contents of locked node NP (a symlink), for USER, into + BUF. */ +error_t +netfs_attempt_readlink (struct iouser *user, struct node *np, + char *buf) +{ + if (np->nn->node && np->nn->node->readlink) + return np->nn->node->readlink (user, np, buf); + return EOPNOTSUPP; +} + + +/* Locked node NP is being opened by USER, with FLAGS. NEWNODE is + nonzero if we just created this node. Return an error if we should + not permit the open to complete because of a permission + restriction. */ +error_t +netfs_check_open_permissions (struct iouser *user, struct node *np, + int flags, int newnode) +{ + error_t err = 0; + + if (flags & O_READ) + err = fshelp_access (&np->nn_stat, S_IREAD, user); + if (!err && (flags & O_WRITE)) + err = fshelp_access (&np->nn_stat, S_IWRITE, user); + if (!err && (flags & O_EXEC)) + err = fshelp_access (&np->nn_stat, S_IEXEC, user); + return err; + +} + + +/* This function will never be called. It is only used when a node is + a symlink or by io_read, which is overridden. */ +error_t +netfs_attempt_read (struct iouser *cred, struct node *np, + loff_t offset, size_t *len, void *data) +{ + return EOPNOTSUPP; +} + + +/* This function will never be called. It is only called from + io_write, which is overridden. */ +error_t +netfs_attempt_write (struct iouser *cred, struct node *np, + loff_t offset, size_t *len, void *data) +{ + return EOPNOTSUPP; +} + + +error_t +netfs_S_io_read (struct protid *user, + char **data, + mach_msg_type_number_t *datalen, + off_t offset, + mach_msg_type_number_t amount) +{ + struct node *np; + + if (!user) + return EOPNOTSUPP; + np = user->po->np; + + if (np->nn->node && np->nn->node->read) + return np->nn->node->read (user, data, datalen, offset, amount); + return EOPNOTSUPP; +} + + +error_t +netfs_S_io_write (struct protid *user, + char *data, + mach_msg_type_number_t datalen, + off_t offset, + mach_msg_type_number_t *amount) +{ + struct node *np; + + if (!user) + return EOPNOTSUPP; + + np = user->po->np; + if (np->nn->node && np->nn->node->write) + return np->nn->node->write (user, data, datalen, offset, amount); + return EOPNOTSUPP; +} + + +/* Return the valid access types (bitwise OR of O_READ, O_WRITE, and + O_EXEC) in *TYPES for locked file NP and user CRED. */ +error_t +netfs_report_access (struct iouser *cred, struct node *np, + int *types) +{ + *types = 0; + if (fshelp_access (&np->nn_stat, S_IREAD, cred) == 0) + *types |= O_READ; + if (fshelp_access (&np->nn_stat, S_IWRITE, cred) == 0) + *types |= O_WRITE; + if (fshelp_access (&np->nn_stat, S_IEXEC, cred) == 0) + *types |= O_EXEC; + return 0; + +} + +/* Node NP has no more references; free all its associated storage. */ +void netfs_node_norefs (struct node *np) + +{ + if (np->nn->node) + { + if (np->nn->node->close) + np->nn->node->close (); + np->nn->node->node = 0; + } + + if (np->nn->symlink_path) + free (np->nn->symlink_path); + + spin_unlock (&netfs_node_refcnt_lock); + free (np->nn); + free (np); +} + + +/* Returned directory entries are aligned to blocks this many bytes long. + Must be a power of two. */ +#define DIRENT_ALIGN 4 +#define DIRENT_NAME_OFFS offsetof (struct dirent, d_name) +/* Length is structure before the name + the name + '\0', all + padded to a four-byte alignment. */ +#define DIRENT_LEN(name_len) \ + ((DIRENT_NAME_OFFS + (name_len) + 1 + (DIRENT_ALIGN - 1)) \ + & ~(DIRENT_ALIGN - 1)) + +/* Fill the array *DATA of size BUFSIZE with up to NENTRIES dirents + from DIR (which is locked) starting with entry ENTRY for user CRED. + The number of entries in the array is stored in *AMT and the number + of bytes in *DATACNT. If the supplied buffer is not large enough + to hold the data, it should be grown. */ +error_t +netfs_get_dirents (struct iouser *cred, struct node *dir, + int first_entry, int num_entries, char **data, + mach_msg_type_number_t *data_len, + vm_size_t max_data_len, int *data_entries) +{ + error_t err; + int count = 0; + size_t size = 0; /* Total size of our return block. */ + consnode_t cn = node_list; + consnode_t first_node; + + + /* Add the length of a directory entry for NAME to SIZE and return true, + unless it would overflow MAX_DATA_LEN or NUM_ENTRIES, in which case + return false. */ + int bump_size (const char *name) + { + if (num_entries == -1 || count < num_entries) + { + size_t new_size = size + DIRENT_LEN (strlen (name)); + if (max_data_len > 0 && new_size > max_data_len) + return 0; + size = new_size; + count++; + return 1; + } + else + return 0; + } + + if (dir != netfs_root_node) + return ENOTDIR; + + for (first_node = node_list, count = 2; + first_node && first_entry > count; + first_node = first_node->next); + count++; + + count = 0; + + /* Make space for the `.' and `..' entries. */ + if (first_entry == 0) + bump_size ("."); + if (first_entry <= 1) + bump_size (".."); + + for (cn = first_node; cn; cn = cn->next) + bump_size (cn->name); + + + /* Allocate it. */ + *data = mmap (0, size, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + err = ((void *) *data == (void *) -1) ? errno : 0; + + if (! err) + /* Copy out the result. */ + { + char *p = *data; + + int add_dir_entry (const char *name, ino_t fileno, int type) + { + if (num_entries == -1 || count < num_entries) + { + struct dirent hdr; + size_t name_len = strlen (name); + size_t sz = DIRENT_LEN (name_len); + + if (sz > size) + return 0; + else + size -= sz; + + hdr.d_fileno = fileno; + hdr.d_reclen = sz; + hdr.d_type = type; + hdr.d_namlen = name_len; + + memcpy (p, &hdr, DIRENT_NAME_OFFS); + strcpy (p + DIRENT_NAME_OFFS, name); + p += sz; + + count++; + + return 1; + } + else + return 0; + } + + *data_len = size; + *data_entries = count; + + count = 0; + + /* Add `.' and `..' entries. */ + if (first_entry == 0) + add_dir_entry (".", 2, DT_DIR); + if (first_entry <= 1) + add_dir_entry ("..", 2, DT_DIR); + + /* Fill in the real directory entries. */ + for (cn = first_node; cn; cn = cn->next) + if (!add_dir_entry (cn->name, cn->id, cn->readlink ? DT_LNK : DT_CHR)) + break; + } + + fshelp_touch (&dir->nn_stat, TOUCH_ATIME, console_maptime); + return err; +} + + + +static any_t +console_client_translator (any_t unused) +{ + error_t err; + + do + { + ports_manage_port_operations_multithread (netfs_port_bucket, + console_demuxer, + 1000 * 60 * 2, + 1000 * 60 * 10, + 0); + err = netfs_shutdown (0); + } + while (err); + return 0; +} + + +/* Create a node with the name NAME and return it in *CN. */ +error_t +console_create_consnode (const char *name, consnode_t *cn) +{ + *cn = malloc (sizeof (struct consnode)); + if (!*cn) + return ENOMEM; + + (*cn)->name = strdup (name); + if (!(*cn)->name) + { + free (cn); + return ENOMEM; + } + + (*cn)->readlink = NULL; + (*cn)->mksymlink = NULL; + + return 0; +} + + +/* Destroy the node CN. */ +void +console_destroy_consnode (consnode_t cn) +{ + if (!cn) + return; + free (cn->name); + free (cn); +} + + +/* Register the node CN with the translator. */ +void +console_register_consnode (consnode_t cn) +{ + cn->node = 0; + cn->next = node_list; + node_list = cn; +} + + +/* Unregister the node CN from the translator. */ +void +console_unregister_consnode (consnode_t cn) +{ + if (!cn) + return; + + if (node_list == cn) + node_list = cn->next; + else + { + consnode_t prev = node_list; + + for (prev = node_list; prev->next != cn; prev = prev->next) + ; + + prev->next = cn->next; + } +} + + +error_t +console_setup_node (char *path) +{ + mach_port_t underlying; + mach_port_t bootstrap; + error_t err; + struct stat ul_stat; + file_t node; + struct port_info *newpi; + mach_port_t right; + + node = file_name_lookup (path, O_CREAT|O_NOTRANS, 0664); + if (node == MACH_PORT_NULL) + return errno; + + task_get_bootstrap_port (mach_task_self (), &bootstrap); + netfs_init (); + + /* Create the root node (some attributes initialized below). */ + netfs_root_node = netfs_make_node (0); + if (! netfs_root_node) + error (1, ENOMEM, "Cannot create root node"); + + err = maptime_map (0, 0, &console_maptime); + if (err) + error (1, err, "Cannot map time"); + + err = ports_create_port (netfs_control_class, netfs_port_bucket, sizeof (struct port_info), &newpi); + right = ports_get_send_right (newpi); + err = file_set_translator (node, 0, FS_TRANS_EXCL | FS_TRANS_SET, 0, 0, 0, + right, MACH_MSG_TYPE_COPY_SEND); + mach_port_deallocate (mach_task_self (), right); + underlying = node; + + err = io_stat (node, &ul_stat); + if (err) + error (1, err, "Cannot stat underlying node"); + + netfs_root_node->nn_stat.st_ino = 2; + netfs_root_node->nn_stat.st_uid = ul_stat.st_uid; + netfs_root_node->nn_stat.st_gid = ul_stat.st_gid; + netfs_root_node->nn_stat.st_author = ul_stat.st_author; + netfs_root_node->nn_stat.st_mode = S_IFDIR | (ul_stat.st_mode & ~S_IFMT & ~S_ITRANS); + netfs_root_node->nn_stat.st_fsid = getpid (); + netfs_root_node->nn_stat.st_nlink = 1; + netfs_root_node->nn_stat.st_size = 0; + netfs_root_node->nn_stat.st_blocks = 0; + netfs_root_node->nn_stat.st_fstype = FSTYPE_MISC; + netfs_root_node->nn_translated = 0; + + /* If the underlying node isn't a directory, propagate read permission to + execute permission since we need that for lookups. */ + if (! S_ISDIR (ul_stat.st_mode)) + { + if (ul_stat.st_mode & S_IRUSR) + netfs_root_node->nn_stat.st_mode |= S_IXUSR; + if (ul_stat.st_mode & S_IRGRP) + netfs_root_node->nn_stat.st_mode |= S_IXGRP; + if (ul_stat.st_mode & S_IROTH) + netfs_root_node->nn_stat.st_mode |= S_IXOTH; + } + + fshelp_touch (&netfs_root_node->nn_stat, TOUCH_ATIME|TOUCH_MTIME|TOUCH_CTIME, + console_maptime); + + cthread_detach (cthread_fork (console_client_translator, NULL)); + + return 0; +} diff --git a/trans.h b/trans.h index d8e7a2c..f781e31 100644 --- a/trans.h +++ b/trans.h @@ -1,5 +1,5 @@ /* trans.h -- Control a translator node for the repeaters. - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2005 Free Software Foundation, Inc. Written by Marco Gerards. This program is free software; you can redistribute it and/or @@ -54,15 +54,28 @@ struct consnode /* The demuxer used for this node. */ int (*demuxer) (mach_msg_header_t *inp, mach_msg_header_t *outp); + /* Called when the symlink is read */ + error_t (*readlink) (struct iouser *user, struct node *np, char *buf); + + /* Called when the symlink is written */ + error_t (*mksymlink) (struct iouser *cred, struct node *np, char *name); + struct consnode *next; }; typedef struct consnode *consnode_t; +/* Register the node CN with the translator. */ void console_register_consnode (consnode_t cn); -void console_unregister_consnode (consnode_t node); +/* Unregister the node CN from the translator. */ +void console_unregister_consnode (consnode_t cn); +/* Create a node with the name NAME and return it in *CN. */ error_t console_create_consnode (const char *name, consnode_t *cn); +/* Destroy the node CN. */ void console_destroy_consnode (consnode_t cn); + +/* Setup the translator for console client nodes on PATH. */ +error_t console_setup_node (char *path); diff --git a/version.h b/version.h new file mode 100644 index 0000000..8969db3 --- /dev/null +++ b/version.h @@ -0,0 +1,29 @@ +/* Hurd version + Copyright (C) 1996, 1997, 1999 Free Software Foundation, Inc. + Written by Thomas Bushnell, n/BSG. + + 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. */ + +#ifndef HURD_VERSION +#define HURD_VERSION "0.3" +#endif + +/* The standard way to print versions for --version. */ +#define STANDARD_HURD_VERSION(s) \ + #s " (GNU Hurd) " HURD_VERSION +#define STANDARD_HURD_VERSION_EXTRA(s, extra) \ + #s " (GNU Hurd; " extra ") " HURD_VERSION -- 1.7.2