diff -Nurp util-vserver-0.30.210.orig/ensc_wrappers/wrappers.h util-vserver-0.30.210.vlogin/ensc_wrappers/wrappers.h
--- util-vserver-0.30.210.orig/ensc_wrappers/wrappers.h	2006-01-22 12:18:14.000000000 +0100
+++ util-vserver-0.30.210.vlogin/ensc_wrappers/wrappers.h	2006-04-04 04:18:38.000000000 +0200
@@ -111,6 +111,10 @@
 #  include "wrappers-stat.hc"
 #endif
 
+#ifdef ENSC_WRAPPERS_TERMIOS
+#  include "wrappers-termios.hc"
+#endif
+
 #undef ENSC_DETAIL2
 #undef ENSC_DETAIL1
 #undef ENSC_DOQUOTE_COND
diff -Nurp util-vserver-0.30.210.orig/ensc_wrappers/wrappers-termios.hc util-vserver-0.30.210.vlogin/ensc_wrappers/wrappers-termios.hc
--- util-vserver-0.30.210.orig/ensc_wrappers/wrappers-termios.hc	1970-01-01 01:00:00.000000000 +0100
+++ util-vserver-0.30.210.vlogin/ensc_wrappers/wrappers-termios.hc	2006-04-04 04:18:38.000000000 +0200
@@ -0,0 +1,32 @@
+// $Id$    --*- c -*--
+
+// Copyright (C) 2006 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// 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; version 2 of the License.
+//  
+// 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.
+
+#ifndef H_ENSC_IN_WRAPPERS_H
+#  error wrappers-termios.hc can not be used in this way
+#endif
+
+inline static WRAPPER_DECL void
+Etcgetattr(int fd, struct termios *termios_p)		
+{								
+  FatalErrnoError(tcgetattr(fd, termios_p)==-1, "tcgetattr()");
+}
+
+inline static WRAPPER_DECL void
+Etcsetattr(int fd, int optional_actions, struct termios *termios_p)		
+{								
+  FatalErrnoError(tcsetattr(fd, optional_actions, termios_p)==-1, "tcsetattr()");
+}
diff -Nurp util-vserver-0.30.210.orig/scripts/vserver.functions util-vserver-0.30.210.vlogin/scripts/vserver.functions
--- util-vserver-0.30.210.orig/scripts/vserver.functions	2006-01-22 13:24:25.000000000 +0100
+++ util-vserver-0.30.210.vlogin/scripts/vserver.functions	2006-04-04 04:18:38.000000000 +0200
@@ -39,7 +39,7 @@ declare -a ENTER_SHELL=()
 
 declare -a OPTS_VCONTEXT_CREATE=()
 declare -a OPTS_VCONTEXT_MIGRATE=()
-declare -a OPTS_VCONTEXT_ENTER=()
+declare -a OPTS_VCONTEXT_ENTER=( --vlogin )
 declare -a OPTS_VATTRIBUTE=( --flag fakeinit )
 declare -a OPTS_VSCHED=()
 
diff -Nurp util-vserver-0.30.210.orig/src/Makefile-files util-vserver-0.30.210.vlogin/src/Makefile-files
--- util-vserver-0.30.210.orig/src/Makefile-files	2006-01-22 12:28:00.000000000 +0100
+++ util-vserver-0.30.210.vlogin/src/Makefile-files	2006-04-04 04:18:38.000000000 +0200
@@ -167,7 +167,7 @@ src_chcontext_compat_SOURCES =	src/chcon
 src_chcontext_compat_LDADD =	$(VSERVER_LDADDS) $(LIBINTERNAL)
 src_chcontext_compat_LDFLAGS =	$(VSERVER_LDFLGS)
 
-src_vcontext_SOURCES		=  src/vcontext.c
+src_vcontext_SOURCES		=  src/vcontext.c src/vlogin.c
 src_vcontext_LDADD		=  $(VSERVER_LDADDS) $(LIBINTERNAL)
 src_vcontext_LDFLAGS		=  $(VSERVER_LDFLGS)
 
diff -Nurp util-vserver-0.30.210.orig/src/vcontext.c util-vserver-0.30.210.vlogin/src/vcontext.c
--- util-vserver-0.30.210.orig/src/vcontext.c	2005-10-30 00:38:36.000000000 +0200
+++ util-vserver-0.30.210.vlogin/src/vcontext.c	2006-04-04 04:18:38.000000000 +0200
@@ -62,6 +62,7 @@
 #define CMD_NAMESPACE		0x400d
 #define CMD_PERSTYPE		0x400e
 #define CMD_PERSFLAG		0x400f
+#define CMD_VLOGIN		0x4010
 
 
 struct option const
@@ -85,6 +86,7 @@ CMDLINE_OPTIONS[] = {
   { "syncmsg",      required_argument, 	0, CMD_SYNCMSG },
   { "personality-type",  required_argument, 0, CMD_PERSTYPE },
   { "personality-flags", required_argument, 0, CMD_PERSFLAG },
+  { "vlogin",       no_argument,        0, CMD_VLOGIN },
 #if 1  
   { "fakeinit",     no_argument,       	0, CMD_INITPID },	// compatibility
 #endif  
@@ -100,6 +102,7 @@ struct Arguments {
     bool		is_initpid;
     bool		is_silentexist;
     bool		set_namespace;
+    bool		do_vlogin;
     uint_least32_t	personality_flags;
     uint_least32_t	personality_type;
     int			verbosity;
@@ -112,6 +115,8 @@ struct Arguments {
 
 int		wrapper_exit_code = 255;
 
+void do_vlogin(char *argv[]);
+
 static void
 showHelp(int fd, char const *cmd, int res)
 {
@@ -145,6 +150,7 @@ showHelp(int fd, char const *cmd, int re
 	    "    --syncmsg <message>\n"
 	    "                    ...  use <message> as synchronization message; by\n"
 	    "                         default, 'ok' will be used\n"
+	    "    --vlogin        ...  enable terminal proxy\n"
 	    "\n"
 	    "'vcontext --create' exits with code 254 iff the context exists already.\n"
 	    "\n"
@@ -287,12 +293,15 @@ doit(struct Arguments const *args, char 
 	sys_personality(args->personality_type | args->personality_flags)==-1) {
       perror(ENSC_WRAPPERS_PREFIX "personality()");
       exit(wrapper_exit_code);
-    }  
+    }
 
     doExternalSync(ext_sync_fd, args->sync_msg);
     doSyncStage1(p, args->do_disconnect);
     DPRINTF("doit: pid=%u, ppid=%u\n", getpid(), getppid());
-    execvp (argv[optind],argv+optind);
+    if (!args->do_vlogin)
+      execvp (argv[optind],argv+optind);
+    else
+      do_vlogin(argv+optind);
     doSyncStage2(p, args->do_disconnect);
 
     PERROR_Q(ENSC_WRAPPERS_PREFIX "execvp", argv[optind]);
@@ -341,6 +350,7 @@ int main (int argc, char *argv[])
     .do_migrateself    = false,
     .do_disconnect     = false,
     .do_endsetup       = false,
+    .do_vlogin         = false,
     .is_initpid        = false,
     .is_silentexist    = false,
     .set_namespace     = false,
@@ -363,6 +373,7 @@ int main (int argc, char *argv[])
       case CMD_MIGRATE		:  args.do_migrate     = true;   break;
       case CMD_DISCONNECT	:  args.do_disconnect  = true;   break;
       case CMD_ENDSETUP		:  args.do_endsetup    = true;   break;
+      case CMD_VLOGIN		:  args.do_vlogin      = true;   break;
       case CMD_INITPID		:  args.is_initpid     = true;   break;
       case CMD_CHROOT		:  args.do_chroot      = true;   break;
       case CMD_NAMESPACE	:  args.set_namespace  = true;   break;
diff -Nurp util-vserver-0.30.210.orig/src/vlogin.c util-vserver-0.30.210.vlogin/src/vlogin.c
--- util-vserver-0.30.210.orig/src/vlogin.c	1970-01-01 01:00:00.000000000 +0100
+++ util-vserver-0.30.210.vlogin/src/vlogin.c	2006-04-04 04:18:38.000000000 +0200
@@ -0,0 +1,295 @@
+// $Id$
+
+// Copyright (C) 2006 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+// Based on vserver-utils' vlogin program.
+//  
+// 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; version 2 of the License.
+//  
+// 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.
+
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "util.h"
+#include <lib/vserver.h>
+#include <lib/fmt.h>
+
+#include <stdlib.h>
+#include <getopt.h>
+#include <stdint.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <termios.h>
+#include <signal.h>
+#include <pty.h>
+
+#define ENSC_WRAPPERS_PREFIX	"vlogin: "
+#define ENSC_WRAPPERS_IOCTL	1
+#define ENSC_WRAPPERS_UNISTD	1
+#define ENSC_WRAPPERS_SOCKET	1
+#define ENSC_WRAPPERS_IO	1
+#define ENSC_WRAPPERS_TERMIOS	1
+#include <wrappers.h>
+
+struct terminal {
+  int fd;                           /* terminal file descriptor */
+  struct termios term;              /* terminal settings */
+  struct winsize ws;                /* terminal size */
+  pid_t pid;                        /* terminal process id */
+  struct termios termo;             /* original terminal settings */
+  enum { TS_RESET, TS_RAW } state;  /* terminal state */
+};
+
+static struct terminal t;
+extern int wrapper_exit_code;
+
+/* set terminal to raw mode */
+static void
+terminal_raw(void)
+{
+  struct termios buf;
+
+  /* save original terminal settings */
+  Etcgetattr(STDIN_FILENO, &t.termo);
+
+  buf = t.termo;
+
+  /* echo off
+  ** canonical mode off
+  ** extended input processing off
+  ** signal chars off */
+  buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
+
+  /* no SIGINT on BREAK
+  ** CR-to-NL off
+  ** input parity check off
+  ** don't strip 8th bit on input
+  ** output flow control off */
+  buf.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+
+  /* clear size bits
+  ** parity checking off */
+  buf.c_cflag &= ~(CSIZE | PARENB);
+
+  /* set 8 bits/char */
+  buf.c_cflag |= CS8;
+
+  /* output processing off */
+  buf.c_oflag &= ~(OPOST);
+
+  /* 1 byte at a time
+  ** no timer */
+  buf.c_cc[VMIN] = 1;
+  buf.c_cc[VTIME] = 0;
+
+  Etcsetattr(STDIN_FILENO, TCSAFLUSH, &buf);
+
+  t.state = TS_RAW;
+}
+
+/* reset terminal to original state */
+static void
+terminal_reset(void)
+{
+  if (t.state != TS_RAW)
+    return;
+
+  Etcsetattr(STDIN_FILENO, TCSAFLUSH, &t.termo);
+
+  t.state = TS_RESET;
+}
+
+/* exit handler */
+static void
+terminal_atexit(void)
+{
+  terminal_reset();
+  WRITE_MSG(1, "\n"); /* for cosmetic reasons */
+}
+
+/* send signal to terminal */
+static void
+terminal_kill(int sig)
+{
+  pid_t pgrp = -1;
+
+  /* try to get process group leader */
+  if (ioctl(t.fd, TIOCGPGRP, &pgrp) >= 0 &&
+      pgrp != -1 &&
+      kill(-pgrp, sig) != -1)
+    return;
+
+  /* fallback using terminal pid */
+  kill(-t.pid, sig);
+}
+
+/* redraw the terminal screen */
+static void
+terminal_redraw(void)
+{
+  /* get winsize from stdin */
+  if (ioctl(STDIN_FILENO, TIOCGWINSZ, &t.ws) == -1)
+    return;
+
+  /* set winsize in terminal */
+  ioctl(t.fd, TIOCSWINSZ, &t.ws);
+
+  /* set winsize change signal to terminal */
+  terminal_kill(SIGWINCH);
+}
+
+/* copy terminal activity to user */
+static void
+terminal_activity(void)
+{
+  char buf[64];
+  size_t len;
+
+  /* read terminal activity */
+  len = Eread(t.fd, buf, sizeof(buf));
+
+  /* get the current terminal settings */
+  Etcgetattr(t.fd, &t.term);
+
+  /* set the current terminal settings */
+  Etcsetattr(STDIN_FILENO, TCSANOW, &t.term);
+
+  /* write activity to user */
+  EwriteAll(STDOUT_FILENO, buf, len);
+}
+
+/* copy user activity to terminal */
+static void
+user_activity(void)
+{
+  char buf[64];
+  size_t len;
+
+  len = Eread(STDIN_FILENO, buf, sizeof(buf));
+  EwriteAll(t.fd, buf, len);
+}
+
+/* catch signals */
+static void
+signal_handler(int sig)
+{
+  int status;
+
+  switch(sig) {
+    /* catch interrupt */
+    case SIGINT:
+      terminal_kill(sig);
+      break;
+
+    /* terminal died */
+    case SIGCHLD:
+      wait(&status);
+      exit(status);
+      break;
+
+    /* window size has changed */
+    case SIGWINCH:
+      terminal_redraw();
+      break;
+
+    default:
+      exit(0);
+  }
+
+}
+
+void do_vlogin(char *argv[])
+{
+  int slave;
+  pid_t pid;
+  int n;
+  fd_set rfds;
+
+  if (!isatty(0) || !isatty(1)) {
+    execvp(argv[0], argv);
+    return;
+  }
+
+  /* set terminal to raw mode */
+  terminal_raw();
+
+  /* fork new pseudo terminal */
+  if (openpty(&t.fd, &slave, NULL, NULL, NULL) == -1) {
+    perror(ENSC_WRAPPERS_PREFIX "openpty()");
+    exit(EXIT_FAILURE);
+  }
+
+  pid = Efork();
+
+  /* setup SIGCHLD here, so we're sure to get the signal */
+  signal(SIGCHLD, signal_handler);
+
+  if (pid == 0) {
+    /* we don't need the master side of the terminal */
+    close(t.fd);
+
+    /* login_tty() stupid dietlibc doesn't have it */
+    Esetsid();
+
+    Eioctl(slave, TIOCSCTTY, NULL);
+
+    Edup2(slave, 0);
+    Edup2(slave, 1);
+    Edup2(slave, 2);
+
+    if (slave > 2)
+      close(slave);
+
+    Eexecvp(argv[0], argv);
+  }
+
+  /* setup SIGINT and SIGWINCH here, as they can cause loops in the child */
+  signal(SIGWINCH, signal_handler);
+  signal(SIGINT, signal_handler);
+
+  /* save terminals pid */
+  t.pid = pid;
+
+  /* we want a redraw */
+  atexit(terminal_atexit);
+  terminal_redraw();
+
+  /* main loop */
+  for (;;) {
+    /* init file descriptors for select */
+    FD_ZERO(&rfds);
+    FD_SET(STDIN_FILENO, &rfds);
+    FD_SET(t.fd, &rfds);
+    n = t.fd;
+
+    /* wait for something to happen */
+    while (select(n + 1, &rfds, NULL, NULL, NULL) == -1) {
+      if (errno == EINTR || errno == EAGAIN)
+	continue;
+      perror(ENSC_WRAPPERS_PREFIX "select()");
+      exit(wrapper_exit_code);
+    }
+
+    if (FD_ISSET(STDIN_FILENO, &rfds))
+      user_activity();
+
+    if (FD_ISSET(t.fd, &rfds))
+      terminal_activity();
+  }
+
+  /* never get here, signal handler exits */
+}
