Hi,

Now that FSF got my papers signed back, here is again my patch to let
screen readers like brltty work with the Hurd. As discussed and agreed
on some time ago on #hurd (and ##hurd), it extends Marco's console
repeater translator to handle symlinks, and adds a vcs repeater that
maintains a symlink to the currently showed console. One can switch
console by mksymlink()ing it.

Changelog for console-client/:
2005-03-05  Samuel Thibault  <[EMAIL PROTECTED]>

        * Makefile (modules): Add `vcs_repeat' and its rule.
        * console.c (console_current_id): New function.
        * input.h (console_current_id): New prototype.
        * trans.c (struct netnode): New member `symlink_path'.
        (console_demuxer): Handle case when node it anonymous.
        (netfs_S_io_select): Likewise.
        (netfs_S_io_read): Likewise.
        (netfs_S_io_write): Likewise.
        (netfs_report_access): Likewise.
        (netfs_attempt_mksymlink): Implement symlinks.
        (netfs_attempt_lookup): Likewise.
        (netfs_attempt_unlink): Likewise.
        (netfs_attempt_link): Likewise.
        (netfs_attempt_mkfile): Likewise.
        (netfs_attempt_readlink): Likewise.
        (netfs_get_dirents): Likewise.
        (netfs_create_consnode): Likewise.
        * trans.h (struct consnode): New members `readlink' and `mksymlink'.
        * vcs-repeat.c: New file.

Changelog for libcons/:
2005-03-05  Samuel Thibault  <[EMAIL PROTECTED]>

        * priv.h (_cons_file): Prototype moved and renamed to...
        * cons.h (cons_file): ... this.
        * init-init.c (cons_init): Updated `_cons_file' reference.
        * opts-std-startup.c (_cons_file): Renamed into `cons_file'.  Updated
        reference.

Regards,
Samuel
Index: console-client/Makefile
===================================================================
RCS file: /cvsroot/hurd/hurd/console-client/Makefile,v
retrieving revision 1.3
diff -u -u -p -r1.3 Makefile
--- console-client/Makefile     6 Jan 2005 21:43:53 -0000       1.3
+++ console-client/Makefile     5 Mar 2005 17:08:06 -0000
@@ -41,7 +41,7 @@ driver-CPPFLAGS = -D'CONSOLE_DEFPATH="$(
 console: ../libcons/libcons.a ../libports/libports.a \
        ../libthreads/libthreads.a ../libshouldbeinlibc/libshouldbeinlibc.a
 
-modules = vga pc_kbd generic_speaker pc_mouse
+modules = vga pc_kbd generic_speaker pc_mouse vcs_repeat
 
 vga-CPPFLAGS = -DDEFAULT_VGA_FONT_DIR=\"${datadir}/hurd/\"
 vga.so.$(hurd-version): $(patsubst %.c,%_pic.o,bdf.c vga-dynafont.c \
@@ -49,6 +49,7 @@ vga.so.$(hurd-version): $(patsubst %.c,%
 pc_kbd.so.$(hurd-version): $(patsubst %.c,%_pic.o,pc-kbd.c kdioctlServer.o 
kbd-repeat.c)
 pc_mouse.so.$(hurd-version): $(patsubst %.c,%_pic.o,pc-mouse.c)
 generic_speaker.so.$(hurd-version): $(patsubst %.c,%_pic.o,generic-speaker.c)
+vcs_repeat.so.$(hurd-version): $(patsubst %.c,%_pic.o,vcs-repeat.c)
 
 ifneq ($(LIBNCURSESW),)
 modules += ncursesw
Index: console-client/console.c
===================================================================
RCS file: /cvsroot/hurd/hurd/console-client/console.c,v
retrieving revision 1.6
diff -u -u -p -r1.6 console.c
--- console-client/console.c    17 Jan 2005 02:00:00 -0000      1.6
+++ console-client/console.c    5 Mar 2005 17:08:07 -0000
@@ -64,6 +64,24 @@ static char *console_node;
 
 /* Callbacks for input source drivers.  */
 
+/* Returns current console ID.  */
+error_t
+console_current_id (int *cur)
+{
+  vcons_t vcons;
+
+  mutex_lock (&global_lock);
+  vcons = active_vcons;
+  if (!vcons)
+    {
+      mutex_unlock (&global_lock);
+      return ENODEV;
+    }
+  *cur = vcons->id;
+  mutex_unlock (&global_lock);
+  return 0;
+}
+
 /* Switch the active console to console ID or DELTA (relative to the
    active console).  */
 error_t
Index: console-client/input.h
===================================================================
RCS file: /cvsroot/hurd/hurd/console-client/input.h,v
retrieving revision 1.2
diff -u -u -p -r1.2 input.h
--- console-client/input.h      6 Jan 2005 21:43:53 -0000       1.2
+++ console-client/input.h      5 Mar 2005 17:08:07 -0000
@@ -55,6 +55,9 @@ error_t console_input (char *buf, size_t
    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);
Index: console-client/trans.c
===================================================================
RCS file: /cvsroot/hurd/hurd/console-client/trans.c,v
retrieving revision 1.1
diff -u -u -p -r1.1 trans.c
--- console-client/trans.c      6 Jan 2005 21:43:53 -0000       1.1
+++ console-client/trans.c      5 Mar 2005 17:08:07 -0000
@@ -41,6 +41,7 @@ static consnode_t node_list = 0;
 struct netnode
 {
   consnode_t node;
+  char *symlink_path;
 };
 
 typedef mach_msg_header_t request_t;
@@ -69,7 +70,7 @@ console_demuxer (mach_msg_header_t *inp,
       return 0;
     }    
   
-  if (!ret && user->po->np->nn->node->demuxer)
+  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);
@@ -125,6 +126,15 @@ 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;
 }
 
@@ -272,8 +282,18 @@ netfs_attempt_lookup (struct iouser *use
            
            nn->node = cn;
            (*node)->nn_stat = netfs_root_node->nn_stat;
-           (*node)->nn_stat.st_mode = S_IFCHR | 
(netfs_root_node->nn_stat.st_mode & ~S_IFMT & ~S_ITRANS);
+           (*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;
          }
@@ -325,7 +345,7 @@ netfs_S_io_select (struct protid *user, 
   
   np = user->po->np;
   
-  if (np->nn->node->select)
+  if (np->nn->node && np->nn->node->select)
     return np->nn->node->select (user, reply, replytype, type);
   return EOPNOTSUPP;
 }
@@ -336,6 +356,21 @@ 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;
 }
 
@@ -378,6 +413,30 @@ 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;
 }
 
@@ -389,7 +448,27 @@ error_t
 netfs_attempt_mkfile (struct iouser *user, struct node *dir,
                             mode_t mode, struct node **np)
 {
-  return EOPNOTSUPP;
+  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;
 }
 
 
@@ -413,6 +492,8 @@ 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;
 }
 
@@ -471,7 +552,7 @@ netfs_S_io_read (struct protid *user,
     return EOPNOTSUPP;
   np = user->po->np;
   
-  if (np->nn->node->read)
+  if (np->nn->node && np->nn->node->read)
     return np->nn->node->read (user, data, datalen, offset, amount);
   return EOPNOTSUPP;
 }
@@ -490,7 +571,7 @@ netfs_S_io_write (struct protid *user,
     return EOPNOTSUPP;
   
   np = user->po->np;
-  if (np->nn->node->read)
+  if (np->nn->node && np->nn->node->write)
     return np->nn->node->write (user, data, datalen, offset, amount);
   return EOPNOTSUPP;
 }
@@ -517,9 +598,15 @@ netfs_report_access (struct iouser *cred
 void netfs_node_norefs (struct node *np)
      
 {
-  if (np->nn->node->close)
-    np->nn->node->close ();
-  np->nn->node->node = 0;
+  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);
@@ -645,7 +732,7 @@ netfs_get_dirents (struct iouser *cred, 
       
       /* Fill in the real directory entries.  */
       for (cn = first_node; cn; cn = cn->next)
-       if (!add_dir_entry (cn->name, cn->id, DT_CHR))
+       if (!add_dir_entry (cn->name, cn->id, cn->readlink ? DT_LNK : DT_CHR))
          break;
     }
       
@@ -689,6 +776,9 @@ console_create_consnode (const char *nam
       return ENOMEM;
     }
 
+  (*cn)->readlink = NULL;
+  (*cn)->mksymlink = NULL;
+
   return 0;
 }
 
Index: console-client/trans.h
===================================================================
RCS file: /cvsroot/hurd/hurd/console-client/trans.h,v
retrieving revision 1.1
diff -u -u -p -r1.1 trans.h
--- console-client/trans.h      6 Jan 2005 21:43:53 -0000       1.1
+++ console-client/trans.h      5 Mar 2005 17:08:07 -0000
@@ -54,6 +54,12 @@ 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;
 };
 
Index: console-client/vcs-repeat.c
===================================================================
RCS file: console-client/vcs-repeat.c
diff -N console-client/vcs-repeat.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ console-client/vcs-repeat.c 5 Mar 2005 17:08:07 -0000
@@ -0,0 +1,222 @@
+/* vcs-repeat.c -- Add a repeater for "current vcs" as a symlink in the
+   console translator node.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+   Written by Samuel Thibault.
+   
+   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 <argp.h>
+#include <driver.h>
+#include <input.h>
+#include <stdio.h>
+#include <error.h>
+#include <sys/mman.h>
+
+#include "trans.h"
+
+
+/* The default name of the node of the repeater.  */
+#define DEFAULT_REPEATER_NODE "vcs"
+
+/* The name of the repeater node.  */
+static char *repeater_node;
+
+/* The repeater node.  */
+static consnode_t vcs_node;
+
+
+/* Callbacks for vcs console node.  */
+
+/* Reading the link to get current vcs, returns length of path (trailing \0
+   excluded).  */
+static error_t
+vcs_readlink (struct iouser *user, struct node *np, char *buf)
+{
+  int cur;
+  error_t ret = 0;
+
+  ret = console_current_id (&cur);
+  if (!ret)
+    {
+      if (!buf)
+       ret = snprintf (NULL, 0, "%s/%d", cons_file, cur);
+      else
+       ret = sprintf (buf, "%s/%d", cons_file, cur);
+
+      if (ret < 0)
+       ret = errno;
+    }
+  return ret;
+}
+
+static error_t
+vcs_read (struct protid *user, char **data,
+         mach_msg_type_number_t * datalen, off_t offset,
+         mach_msg_type_number_t amount)
+{
+  int err;
+  int size;
+  char *buf;
+
+  if (amount > 0)
+    {
+      size = vcs_readlink (user->user, NULL, NULL);
+      if (size < 0)
+       return size;
+
+      buf = alloca (size);
+
+      err = vcs_readlink (user->user, NULL, buf);
+
+      if (err < 0)
+       return err;
+
+      if (offset + amount > size)
+       amount = size - offset;
+      if (amount < 0)
+       amount = 0;
+
+      if (*datalen < amount)
+       {
+         *data = mmap (0, amount, PROT_READ | PROT_WRITE, MAP_ANON, 0, 0);
+         if (*data == MAP_FAILED)
+           return ENOMEM;
+       }
+
+      memcpy (*data, buf + offset, amount);
+      *datalen = amount;
+    }
+  return 0;
+}
+
+/* Making a link to set current vcs.
+   Relative values perform relative switches.  */
+static error_t
+vcs_mksymlink (struct iouser *user, struct node *np, char *name)
+{
+  char *c, *d;
+  int vt, delta = 0;
+
+  c = strrchr (name, '/');
+  if (!c)
+    c = name;
+  else
+    c++;
+  if (!*c)
+    return EINVAL;
+
+  if (*c == '-' || *c == '+')
+    delta = 1;
+
+  vt = strtol (c, &d, 10);
+  if (*d)
+    /* Bad number.  */
+    return EINVAL;
+
+  if (!vt)
+    return 0;
+  return console_switch (delta ? 0 : vt, delta ? vt : 0);
+}
+
+
+static const char doc[] = "VCS Repeater Driver";
+
+static const struct argp_option options[] = 
+  {
+    { "repeater",      'r', "NODE", OPTION_ARG_OPTIONAL,
+      "Set a repeater translator on NODE (default: " DEFAULT_REPEATER_NODE 
")"},
+    { 0 }
+  };
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+  int *pos = (int *) state->input;
+
+  switch (key)
+    {
+    case 'r':
+      repeater_node = arg ? arg: DEFAULT_REPEATER_NODE;
+      break;
+
+    case ARGP_KEY_END:
+      break;
+
+    default:
+      return ARGP_ERR_UNKNOWN;
+    }
+
+  *pos = state->next;
+  return 0;
+}
+
+static struct argp argp = {options, parse_opt, 0, doc};
+
+/* Initialize the VCS Repeater driver.  */
+static error_t
+vcs_repeat_init (void **handle, int no_exit, int argc, char *argv[], int *next)
+{
+  error_t err;
+  int pos = 1;
+
+  /* Parse the arguments.  */
+  err = argp_parse (&argp, argc, argv, ARGP_IN_ORDER | ARGP_NO_EXIT
+                   | ARGP_SILENT, 0, &pos);
+  *next += pos - 1;
+
+  if (err && err != EINVAL)
+    return err;
+
+  return 0;
+}
+
+static error_t
+vcs_repeat_start (void *handle)
+{
+  error_t err;
+  
+  err = console_create_consnode (repeater_node, &vcs_node);
+  if (err)
+    return err;
+
+  vcs_node->read = vcs_read;
+  vcs_node->write = NULL;
+  vcs_node->select = NULL;
+  vcs_node->open = NULL;
+  vcs_node->close = NULL;
+  vcs_node->demuxer = NULL;
+  vcs_node->readlink = vcs_readlink;
+  vcs_node->mksymlink = vcs_mksymlink;
+  console_register_consnode (vcs_node);
+
+  return 0;
+}
+
+static error_t
+vcs_repeat_fini (void *handle, int force)
+{
+  console_unregister_consnode (vcs_node);
+  console_destroy_consnode (vcs_node);
+  return 0;
+}
+
+
+struct driver_ops driver_vcs_repeat_ops =
+  {
+    vcs_repeat_init,
+    vcs_repeat_start,
+    vcs_repeat_fini
+  };
+
Index: libcons/priv.h
===================================================================
RCS file: /cvsroot/hurd/hurd/libcons/priv.h,v
retrieving revision 1.5
diff -u -u -p -r1.5 priv.h
--- libcons/priv.h      6 Jan 2005 21:53:26 -0000       1.5
+++ libcons/priv.h      5 Mar 2005 17:08:07 -0000
@@ -45,9 +45,6 @@ extern int _cons_jump_down_on_input;
 /* If we jump down at output.  */
 extern int _cons_jump_down_on_output;
 
-/* The filename of the console server.  */
-extern char *_cons_file;
-
 /* The type of bell used for the visual bell.  */
 extern bell_type_t _cons_visual_bell;
 
Index: libcons/cons.h
===================================================================
RCS file: /cvsroot/hurd/hurd/libcons/cons.h,v
retrieving revision 1.9
diff -u -u -p -r1.9 cons.h
--- libcons/cons.h      6 Jan 2005 21:53:26 -0000       1.9
+++ libcons/cons.h      5 Mar 2005 17:08:07 -0000
@@ -298,6 +298,9 @@ extern const struct argp cons_startup_ar
 extern struct port_bucket *cons_port_bucket;
 extern struct port_class *cons_port_class;
 
+/* The filename of the console server.  */
+extern char *cons_file;
+
 error_t cons_init (void);
 void cons_server_loop (void);
 int cons_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp);
Index: libcons/init-init.c
===================================================================
RCS file: /cvsroot/hurd/hurd/libcons/init-init.c,v
retrieving revision 1.2
diff -u -u -p -r1.2 init-init.c
--- libcons/init-init.c 8 Sep 2002 21:55:59 -0000       1.2
+++ libcons/init-init.c 5 Mar 2005 17:08:07 -0000
@@ -56,7 +56,7 @@ cons_init (void)
   mutex_init (&cons->lock);
   cons->vcons_list = NULL;
   cons->vcons_last = NULL;
-  cons->dir = opendir (_cons_file);
+  cons->dir = opendir (cons_file);
   cons->slack = _cons_slack;
   if (!cons->dir)
     {
Index: libcons/opts-std-startup.c
===================================================================
RCS file: /cvsroot/hurd/hurd/libcons/opts-std-startup.c,v
retrieving revision 1.7
diff -u -u -p -r1.7 opts-std-startup.c
--- libcons/opts-std-startup.c  6 Jan 2005 21:53:26 -0000       1.7
+++ libcons/opts-std-startup.c  5 Mar 2005 17:08:07 -0000
@@ -58,7 +58,7 @@ int _cons_jump_down_on_input = 1;
 int _cons_jump_down_on_output;
 
 /* The filename of the console server.  */
-char *_cons_file;
+char *cons_file;
 
 /* The type of bell used for the visual bell.  */
 bell_type_t _cons_visual_bell = BELL_VISUAL;
@@ -206,7 +206,7 @@ parse_startup_opt (int opt, char *arg, s
       if (state->arg_num > 0)
        /* Too many arguments.  */
        argp_error (state, "Too many non option arguments");
-      _cons_file = arg;
+      cons_file = arg;
       break;
 
     case ARGP_KEY_NO_ARGS:
_______________________________________________
Bug-hurd mailing list
Bug-hurd@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-hurd

Reply via email to