--- /dev/null
+sipb-xen-console (1) unstable; urgency=low
+
+ * Initial release.
+
+ -- SIPB Xen Project <sipb-xen@mit.edu> Sun, 30 Mar 2008 01:08:50 -0400
--- /dev/null
+Source: sipb-xen-console
+Section: servers
+Priority: important
+Maintainer: sipb-xen@mit.edu
+Build-Depends: @cdbs@
+Standards-Version: 3.7.2
+
+Package: sipb-xen-console
+Architecture: all
+Provides: ${diverted-files}
+Conflicts: ${diverted-files}
+Depends: ${shlibs:Depends}, ${misc:Depends}, fuse-utils, libnss-pgsql1, openssh-client, openssh-server, python-fuse, sipb-xen-database-common
+Description: SIPB Xen serial console server
+ This package should be installed on sipb-xen-console
+ It makes sure that necessary tools are available.
--- /dev/null
+This package was created for internal use of the SIPB Xen Project of
+the MIT Student Information Processing Board. Ask sipb-xen@mit.edu if
+you have questions about redistribution.
--- /dev/null
+#!/usr/bin/make -f
+
+DEB_AUTO_UPDATE_DEBIAN_CONTROL = 1
+DEB_DIVERT_EXTENSION = .sipb-xen
+DEB_DIVERT_FILES_sipb-xen-console += \
+ /etc/nsswitch.conf
+ /etc/ssh/ssh_config
+
+include /usr/share/cdbs/1/rules/debhelper.mk
+include /usr/share/cdbs/1/rules/replace-files.mk
--- /dev/null
+#! /bin/sh
+### BEGIN INIT INFO
+# Provides: sipb-xen-console
+# Required-Start: $local_fs $remote_fs
+# Required-Stop: $local_fs $remote_fs
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: sipb-xen Console Server homedir filesystem
+# Description:
+### END INIT INFO
+
+# Author: SIPB Xen Project <sipb-xen@mit.edu>
+
+# Do NOT "set -e"
+
+# PATH should only include /usr/* if it runs after the mountnfs.sh script
+PATH=/sbin:/usr/sbin:/bin:/usr/bin
+DESC="The sipb-xen console server homedir filesystem"
+NAME=sipb-xen-console
+DAEMON=/usr/bin/sipb-xen-consolefs
+DAEMON_ARGS="/consolefs"
+PIDFILE=/var/run/$NAME.pid
+SCRIPTNAME=/etc/init.d/$NAME
+
+# Exit if the package is not installed
+[ -x "$DAEMON" ] || exit 0
+
+# Read configuration variable file if it is present
+[ -r /etc/default/$NAME ] && . /etc/default/$NAME
+
+# Load the VERBOSE setting and other rcS variables
+. /lib/init/vars.sh
+
+# Define LSB log_* functions.
+# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
+. /lib/lsb/init-functions
+
+#
+# Function that starts the daemon/service
+#
+do_start()
+{
+ # Return
+ # 0 if daemon has been started
+ # 1 if daemon was already running
+ # 2 if daemon could not be started
+ daemon --running -n $NAME && return 1
+ daemon -r -O daemon.info -E daemon.err -n $NAME -U $DAEMON $DAEMON_ARGS || return 2
+}
+
+#
+# Function that stops the daemon/service
+#
+do_stop()
+{
+ # Return
+ # 0 if daemon has been stopped
+ # 1 if daemon was already stopped
+ # 2 if daemon could not be stopped
+ # other if a failure occurred
+ daemon --stop -n $NAME
+ RETVAL="$?"
+ [ "$RETVAL" = 2 ] && return 2
+ # Many daemons don't delete their pidfiles when they exit.
+ rm -f $PIDFILE
+ return "$RETVAL"
+}
+
+case "$1" in
+ start)
+ [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
+ do_start
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ stop)
+ [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
+ do_stop
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ #reload|force-reload)
+ #
+ # If do_reload() is not implemented then leave this commented out
+ # and leave 'force-reload' as an alias for 'restart'.
+ #
+ #log_daemon_msg "Reloading $DESC" "$NAME"
+ #do_reload
+ #log_end_msg $?
+ #;;
+ restart|force-reload)
+ #
+ # If the "reload" option is implemented then remove the
+ # 'force-reload' alias
+ #
+ log_daemon_msg "Restarting $DESC" "$NAME"
+ do_stop
+ case "$?" in
+ 0|1)
+ do_start
+ case "$?" in
+ 0) log_end_msg 0 ;;
+ 1) log_end_msg 1 ;; # Old process is still running
+ *) log_end_msg 1 ;; # Failed to start
+ esac
+ ;;
+ *)
+ # Failed to stop
+ log_end_msg 1
+ ;;
+ esac
+ ;;
+ *)
+ #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
+ echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
+ exit 3
+ ;;
+esac
+
+:
--- /dev/null
+# example configfile for PostgreSQL NSS module
+
+# these are entries as used with the BOFHMS tool (sf.net/projects/bofhms)
+host = sipb-xen-dev
+port = 5432
+database = sipb_xen
+login = sipb-xen
+#passwd = foo
+#passwdtable = machines
+#grouptable = machines
+# you can use anything postgres accepts as table expression
+#groupmembertable = accounts JOIN usergroups ON accounts.uid=usergroups.uid JOIN groups ON usergroups.gid=groups.gid
+
+querypasswd = SELECT name, 'moo', 1000 as uid, 1000, '', '/vmhome/'|| name, '/usr/local/bin/sipb-xen-consolesh' FROM machines
+querygroup = SELECT name, NULL, 1000 as gid FROM machines
+querymembers = SELECT name FROM machines WHERE 1000 = %d
+queryids = SELECT 1000 AS gid FROM machines LIMIT 0;
+
+passwd_name = name
+passwd_uid = uid
+
+group_name = name
+group_gid = gid
--- /dev/null
+# /etc/nsswitch.conf
+#
+# Example configuration of GNU Name Service Switch functionality.
+# If you have the `glibc-doc-reference' and `info' packages installed, try:
+# `info libc "Name Service Switch"' for information about this file.
+
+passwd: compat pgsql
+group: compat
+shadow: compat
+
+hosts: files dns
+networks: files
+
+protocols: db files
+services: db files
+ethers: db files
+rpc: db files
+
+netgroup: nis
--- /dev/null
+
+# This is the ssh client system-wide configuration file. See
+# ssh_config(5) for more information. This file provides defaults for
+# users, and the values can be changed in per-user configuration files
+# or on the command line.
+
+# Configuration data is parsed as follows:
+# 1. command line options
+# 2. user-specific file
+# 3. system-wide file
+# Any configuration value is only changed the first time it is set.
+# Thus, host-specific definitions should be at the beginning of the
+# configuration file, and defaults at the end.
+
+# Site-wide defaults for some commonly used options. For a comprehensive
+# list of available options, their meanings and defaults, please see the
+# ssh_config(5) man page.
+
+Host *
+ SetEnv VM_NAME
+# ForwardAgent no
+# ForwardX11 no
+# ForwardX11Trusted yes
+# RhostsRSAAuthentication no
+# RSAAuthentication yes
+# PasswordAuthentication yes
+# HostbasedAuthentication no
+# BatchMode no
+# CheckHostIP yes
+# AddressFamily any
+# ConnectTimeout 0
+# StrictHostKeyChecking ask
+# IdentityFile ~/.ssh/identity
+# IdentityFile ~/.ssh/id_rsa
+# IdentityFile ~/.ssh/id_dsa
+# Port 22
+# Protocol 2,1
+# Cipher 3des
+# Ciphers aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour,aes192-cbc,aes256-cbc
+# EscapeChar ~
+# Tunnel no
+# TunnelDevice any:any
+# PermitLocalCommand no
+ SendEnv LANG LC_*
+ HashKnownHosts yes
+ GSSAPIAuthentication yes
+ GSSAPIDelegateCredentials no
--- /dev/null
+|1|CoekhjakJDYiibQ38vZna+XKwCg=|Ts2GavZxl8KVEl++tnJnjqfn84s= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAsoOOazVHn04z6s+kQnoFcw9fv7dGB9s/9H1QygYW9QAbvklWx0q4J8KGTATXCFwjooLNqjHYONOQ8x0h1fZPDmhdoHk24wH/EBUAAyhtrwTMpsgfqZwG7yuRpcbO382F3wRv6CIRYZ6hyIlm0Zt3680mO/u7l2wAFoMTyYwSdZ8Gl9p5Ay750TFCZoEI/Z4EQY5lGPHrHIXN+uo0Yus//AmWIzY9y3TSKabHz77rPGIzJc8Y4XjDqA7LzXCY+KGw2Of059AseVHNTCMo6KzVIKgdZoRBtiY7fD1l7ystgKL6lGJr4C1UyWoM41EVkDqsRJZ70C4Elcr1x/MrQFLEgQ==
+|1|SFl+Ci6EXZcVvxvxDm4Cf85nGho=|InwYz5wWUf/NRbBQRa/TO3Lm2uQ= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAsoOOazVHn04z6s+kQnoFcw9fv7dGB9s/9H1QygYW9QAbvklWx0q4J8KGTATXCFwjooLNqjHYONOQ8x0h1fZPDmhdoHk24wH/EBUAAyhtrwTMpsgfqZwG7yuRpcbO382F3wRv6CIRYZ6hyIlm0Zt3680mO/u7l2wAFoMTyYwSdZ8Gl9p5Ay750TFCZoEI/Z4EQY5lGPHrHIXN+uo0Yus//AmWIzY9y3TSKabHz77rPGIzJc8Y4XjDqA7LzXCY+KGw2Of059AseVHNTCMo6KzVIKgdZoRBtiY7fD1l7ystgKL6lGJr4C1UyWoM41EVkDqsRJZ70C4Elcr1x/MrQFLEgQ==
--- /dev/null
+#!/usr/bin/python
+
+import fuse
+from fuse import Fuse
+
+from time import time
+
+import stat # for file properties
+import os # for filesystem modes (O_RDONLY, etc)
+import errno # for error number codes (ENOENT, etc)
+ # - note: these must be returned as negatives
+
+fuse.fuse_python_api = (0, 2)
+
+machines = ['moo17', 'remus']
+realpath = "/home/machines/"
+uid = 1000
+
+def dirFromList(list):
+ """
+ Return a properly formatted list of items suitable to a directory listing.
+ ['a', 'b', 'c'] => [('a', 0), ('b', 0), ('c', 0)]
+ """
+ return [(x, 0) for x in list]
+
+def getDepth(path):
+ """
+ Return the depth of a given path, zero-based from root ('/')
+ """
+ if path == '/':
+ return 0
+ else:
+ return path.count('/')
+
+def getParts(path):
+ """
+ Return the slash-separated parts of a given path as a list
+ """
+ if path == '/':
+ return ['/']
+ else:
+ return path[1:].split('/')
+
+class MyStat:
+ def __init__(self):
+ self.st_mode = 0
+ self.st_ino = 0
+ self.st_dev = 0
+ self.st_nlink = 0
+ self.st_uid = uid
+ self.st_gid = 0
+ self.st_size = 0
+ self.st_atime = 0
+ self.st_mtime = 0
+ self.st_ctime = 0
+
+ def toTuple(self):
+ return (self.st_mode, self.st_ino, self.st_dev, self.st_nlink, self.st_uid, self.st_gid, self.st_size, self.st_atime, self.st_mtime, self.st_ctime)
+
+class ConsoleFS(Fuse):
+ """
+ """
+
+ def __init__(self, *args, **kw):
+ Fuse.__init__(self, *args, **kw)
+ print 'Init complete.'
+
+ def mirrorPath(self, path):
+ return realpath + "/".join(getParts(path)[1:])
+
+ def getattr(self, path):
+ """
+ - st_mode (protection bits)
+ - st_ino (inode number)
+ - st_dev (device)
+ - st_nlink (number of hard links)
+ - st_uid (user ID of owner)
+ - st_gid (group ID of owner)
+ - st_size (size of file, in bytes)
+ - st_atime (time of most recent access)
+ - st_mtime (time of most recent content modification)
+ - st_ctime (platform dependent; time of most recent metadata change on Unix,
+ or the time of creation on Windows).
+ """
+
+ print "*** getattr: " + path
+
+ depth = getDepth(path)
+ parts = getParts(path)
+
+ st = MyStat()
+ if path == '/':
+ st.st_mode = stat.S_IFDIR | 0755
+ st.st_nlink = 2
+ elif depth == 1:
+ if parts[-1] in machines:
+ st.st_mode = stat.S_IFDIR | 0755
+ st.st_nlink = 2
+ else:
+ return -errno.ENOENT
+ elif depth == 2 and parts[-1] == '.k5login':
+ st.st_mode = stat.S_IFREG | 0444
+ st.st_nlink = 1
+ st.st_size = 17
+ else:
+ st = os.lstat(self.mirrorPath(path))
+ return st.toTuple()
+
+ def readdir(self, path, offset):
+ print '*** readdir', path, offset
+ if path == '/':
+ for r in ['.', '..']+machines:
+ yield fuse.Direntry(r)
+ elif getDepth(path) == 1:
+ for r in set(os.listdir(self.mirrorPath(path)) + ['.k5login']):
+ yield fuse.Direntry(r)
+ else:
+ for r in os.listdir(self.mirrorPath(path)):
+ yield fuse.Direntry(r)
+
+ def read ( self, path, length, offset ):
+ print '*** read', path, length, offset
+
+ if getDepth(path) < 2:
+ return -errno.ENOENT
+ elif getParts(path)[1:] == ['.k5login']:
+ pass
+ else:
+ fname = self.mirrorPath(path)
+ if not os.path.isfile(fname):
+ return -errno.ENOENT
+ else:
+ f = open(fname)
+ f.seek(offset)
+ return f.read(length)
+
+if __name__ == '__main__':
+ usage="""
+ConsoleFS [mount_path]
+"""
+ server = ConsoleFS()
+ server.flags = 0
+ server.main()