From b78f64c598c8db7c0106f25a3bd2ad83e7d4ce45 Mon Sep 17 00:00:00 2001
From: Evan Broder <broder@mit.edu>
Date: Sun, 30 Mar 2008 01:39:19 -0400
Subject: [PATCH] First stab at a package to create the console server

svn path=/trunk/packages/sipb-xen-console/; revision=335
---
 debian/changelog                     |    5 ++
 debian/compat                        |    1 +
 debian/control.in                    |   15 ++++
 debian/copyright                     |    3 +
 debian/rules                         |   10 +++
 debian/sipb-xen-console.init         |  124 +++++++++++++++++++++++++++++
 debian/sipb-xen-console.install      |    1 +
 files/etc/nss-pgsql.conf             |   23 ++++++
 files/etc/nsswitch.conf.sipb-xen     |   19 +++++
 files/etc/ssh/ssh_config.sipb-xen    |   47 +++++++++++
 files/home/machines/.ssh/known_hosts |    2 +
 files/usr/bin/sipb-xen-consolefs     |  143 ++++++++++++++++++++++++++++++++++
 12 files changed, 393 insertions(+)
 create mode 100644 debian/changelog
 create mode 100644 debian/compat
 create mode 100644 debian/control.in
 create mode 100644 debian/copyright
 create mode 100755 debian/rules
 create mode 100755 debian/sipb-xen-console.init
 create mode 100644 debian/sipb-xen-console.install
 create mode 100644 files/etc/nss-pgsql.conf
 create mode 100644 files/etc/nsswitch.conf.sipb-xen
 create mode 100644 files/etc/ssh/ssh_config.sipb-xen
 create mode 100644 files/home/machines/.ssh/known_hosts
 create mode 100755 files/usr/bin/sipb-xen-consolefs

diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..92eff1e
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,5 @@
+sipb-xen-console (1) unstable; urgency=low
+
+  * Initial release.
+
+ -- SIPB Xen Project <sipb-xen@mit.edu>  Sun, 30 Mar 2008 01:08:50 -0400
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..7ed6ff8
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+5
diff --git a/debian/control.in b/debian/control.in
new file mode 100644
index 0000000..8b594df
--- /dev/null
+++ b/debian/control.in
@@ -0,0 +1,15 @@
+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.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..7789434
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,3 @@
+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.
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..8dfab96
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,10 @@
+#!/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
diff --git a/debian/sipb-xen-console.init b/debian/sipb-xen-console.init
new file mode 100755
index 0000000..14ed7e8
--- /dev/null
+++ b/debian/sipb-xen-console.init
@@ -0,0 +1,124 @@
+#! /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
+
+:
diff --git a/debian/sipb-xen-console.install b/debian/sipb-xen-console.install
new file mode 100644
index 0000000..9da31b3
--- /dev/null
+++ b/debian/sipb-xen-console.install
@@ -0,0 +1 @@
+files/* .
diff --git a/files/etc/nss-pgsql.conf b/files/etc/nss-pgsql.conf
new file mode 100644
index 0000000..d4ddcfe
--- /dev/null
+++ b/files/etc/nss-pgsql.conf
@@ -0,0 +1,23 @@
+# 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
diff --git a/files/etc/nsswitch.conf.sipb-xen b/files/etc/nsswitch.conf.sipb-xen
new file mode 100644
index 0000000..4fcecf6
--- /dev/null
+++ b/files/etc/nsswitch.conf.sipb-xen
@@ -0,0 +1,19 @@
+# /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
diff --git a/files/etc/ssh/ssh_config.sipb-xen b/files/etc/ssh/ssh_config.sipb-xen
new file mode 100644
index 0000000..3630fc0
--- /dev/null
+++ b/files/etc/ssh/ssh_config.sipb-xen
@@ -0,0 +1,47 @@
+
+# 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
diff --git a/files/home/machines/.ssh/known_hosts b/files/home/machines/.ssh/known_hosts
new file mode 100644
index 0000000..3056107
--- /dev/null
+++ b/files/home/machines/.ssh/known_hosts
@@ -0,0 +1,2 @@
+|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==
diff --git a/files/usr/bin/sipb-xen-consolefs b/files/usr/bin/sipb-xen-consolefs
new file mode 100755
index 0000000..7cd3766
--- /dev/null
+++ b/files/usr/bin/sipb-xen-consolefs
@@ -0,0 +1,143 @@
+#!/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()
-- 
1.7.9.5