bitkeeper revision 1.1041.13.1 (40eb0eb2uTenw4RI9fetIsxTLmIHyQ)

Merge labyrinth.cl.cam.ac.uk:/auto/groups/xeno/BK/xeno.bk
into labyrinth.cl.cam.ac.uk:/auto/anfs/scratch/labyrinth/iap10/xeno-clone/xeno-ia64.bk
This commit is contained in:
iap10@labyrinth.cl.cam.ac.uk committed 2004-07-06 20:42:26 +00:00
commit c101b31ccc
97 files changed
+8413 -1238

No files matched your search

+39 -7
View File
@@ -201,6 +201,8 @@
3f6dc140C8tAeBfroAF24VrmCS4v_w tools/misc/miniterm/README
3f6dc142IHaf6XIcAYGmhV9nNSIHFQ tools/misc/miniterm/miniterm.c
40c9c469kT0H9COWzA4XzPBjWK0WsA tools/misc/netfix
4022a73cEKvrYe_DVZW2JlAxobg9wg tools/misc/nsplitd/Makefile
4022a73cKms4Oq030x2JBzUB426lAQ tools/misc/nsplitd/nsplitd.c
3f870808_8aFBAcZbWiWGdgrGQyIEw tools/misc/p4perf.h
3f5ef5a2ir1kVAthS14Dc5QIRCEFWg tools/misc/xen-clone
3f5ef5a2dTZP0nnsFoeq2jRf3mWDDg tools/misc/xen-clone.README
@@ -239,6 +241,7 @@
40c9c468xzANp6o2D_MeCYwNmOIUsQ tools/python/xen/xend/XendVnet.py
40c9c468x191zetrVlMnExfsQWHxIQ tools/python/xen/xend/__init__.py
40c9c468S2YnCEKmk4ey8XQIST7INg tools/python/xen/xend/encode.py
40e9808elkoRulOo1GxRTp5ulJGVNw tools/python/xen/xend/packing.py
40c9c468DCpMe542varOolW1Xc68ew tools/python/xen/xend/server/SrvBase.py
40c9c468IxQabrKJSWs0aEjl-27mRQ tools/python/xen/xend/server/SrvConsole.py
40c9c4689Io5bxfbYIfRiUvsiLX0EQ tools/python/xen/xend/server/SrvConsoleDir.py
@@ -257,7 +260,6 @@
40c9c469N2-b3GqpLHHHPZykJPLVvA tools/python/xen/xend/server/channel.py
40c9c469hJ_IlatRne-9QEa0-wlquw tools/python/xen/xend/server/console.py
40c9c469UcNJh_NuLU0ytorM0Lk5Ow tools/python/xen/xend/server/controller.py
40c9c469vHh-qLiiubdbKEQbJf18Zw tools/python/xen/xend/server/cstruct.py
40d83983OXjt-y3HjSCcuoPp9rzvmw tools/python/xen/xend/server/domain.py
40c9c469yrm31i60pGKslTi2Zgpotg tools/python/xen/xend/server/messages.py
40c9c46925x-Rjb0Cv2f1-l2jZrPYg tools/python/xen/xend/server/netif.py
@@ -265,6 +267,7 @@
40c9c469LNxLVizOUpOjEaTKKCm8Aw tools/python/xen/xend/sxp.py
40d05079aFRp6NQdo5wIh5Ly31c0cg tools/python/xen/xm/__init__.py
40cf2937gKQcATgXKGtNeWb1PDH5nA tools/python/xen/xm/create.py
40e41cd2w0I4En6qrJn4em8HkK_oxQ tools/python/xen/xm/help.py
40cf2937isyS250zyd0Q2GuEDoNXfQ tools/python/xen/xm/main.py
40cf2937PSslwBliN1g7ofDy2H_RhA tools/python/xen/xm/opts.py
40cf2937Z8WCNOnO2FcWdubvEAF9QQ tools/python/xen/xm/shutdown.py
@@ -274,6 +277,32 @@
403a3edbVpV2E_wq1zeEkJ_n4Uu2eg tools/xentrace/xentrace.c
403a3edblCUrzSj0mmKhO5HOPrOrSQ tools/xentrace/xentrace_format
4050c413NtuyIq5lsYJV4P7KIjujXw tools/xentrace/xentrace_format.1
40e9808eHO3QprCFKg9l2JJzgt2voA tools/xfrd/Make.xfrd
40e9808epTR4zWrYjGUnaaynK20Q5A tools/xfrd/Makefile
40e9808eysqT4VNDlJFqsZB2rdg4Qw tools/xfrd/connection.c
40e9808eyXfJUi4E0C3WSgrEXqQ1sQ tools/xfrd/connection.h
40e9808eULGwffNOE4kBrAfZ9YAVMA tools/xfrd/debug.h
40e9808eyjiahG5uF6AMelNVujBzCg tools/xfrd/enum.c
40e9808eZpbdn9q2KSSMGCNvY_ZgpQ tools/xfrd/enum.h
40e9808easXCzzAZQodEfKAhgUXSPA tools/xfrd/hash_table.c
40e9808e94BNXIVVKBFHC3rnkvwtJg tools/xfrd/hash_table.h
40e9808epW9iHcLXuO3QfUfLzB7onw tools/xfrd/lexis.c
40e9808egccMhCizayQRGtpBA3L5MQ tools/xfrd/lexis.h
40e9808ePADCSKL1YgGCt2TbYPnYkw tools/xfrd/lzi_stream.c
40e9808eDNAdpF71o5teYb9DTT-PRw tools/xfrd/lzi_stream.h
40e9808eQxi0EzTcPJtosrzxEIjA-Q tools/xfrd/marshal.c
40e9808etg13xfRm0Lqd8vY-jHOoTg tools/xfrd/marshal.h
40e9808eCsmywryb036TdtRMJHDMmQ tools/xfrd/select.c
40e9808e99OcM547cKMTfmCVSoWVAw tools/xfrd/select.h
40e9808e5_PLdodqVOSx0b4T_f5aeg tools/xfrd/sxpr.c
40e9808e0O4sHZtkDv5hlSqjYcdQAQ tools/xfrd/sxpr.h
40e9808eF3NVldqRNS5IHM8gbFAvpw tools/xfrd/xdr.c
40e9808ezXzoRHm7pybXU69NtnjimA tools/xfrd/xdr.h
40e9808edpUtf4bJ8IbqClPJj_OvbA tools/xfrd/xen_domain.c
40e9808eHviFFIwdUKOA234uIeifjA tools/xfrd/xen_domain.h
40e9808eIFeV-MDCNyVTNt5NfMPKeQ tools/xfrd/xfrd.c
40e9808eGIbOoSNJRiwWK2C3mjGWaA tools/xfrd/xfrd.h
40e9808eHXvs_5eggj9McD_J90mhNw tools/xfrd/xfrdClient.py
3f72f1bdJPsV3JCnBqs9ddL9tr6D2g xen/COPYING
3ddb79bcbOVHh38VJzc97-JEGD4dJQ xen/Makefile
3ddb79bcWnTwYsQRWl_PaneJfa6p0w xen/Rules.mk
@@ -285,8 +314,7 @@
40e42bdbNu4MjI750THP_8J1S-Sa0g xen/arch/x86/boot/x86_64.S
3ddb79bcUrk2EIaM5VsT6wUudH1kkg xen/arch/x86/delay.c
40e34414WiQO4h2m3tcpaCPn7SyYyg xen/arch/x86/dom0_ops.c
3e32af9aRnYGl4GMOaDKp7JdfhOGhg xen/arch/x86/domain_page.c
3ddb79bcecupHj56ZbTa3B0FxDowMg xen/arch/x86/entry.S
3ddb79bc1_2bAt67x9MFCP4AZrQnvQ xen/arch/x86/domain.c
3ddb79bcY5zW7KhvI9gvfuPi3ZumEg xen/arch/x86/extable.c
3fe443fdDDb0Sw6NQBCk4GQapayfTA xen/arch/x86/flushtlb.c
3ddb79bcesE5E-lS4QhRhlqXxqj9cA xen/arch/x86/i387.c
@@ -294,7 +322,6 @@
3ddb79bcBit4xJXbwtX0kb1hh2uO1Q xen/arch/x86/idle0_task.c
3ddb79bcKIkRR0kqWaJhe5VUDkMdxg xen/arch/x86/io_apic.c
3ddb79bdqfIcjkz_h9Hvtp8Tk_19Zw xen/arch/x86/irq.c
3ddb79bcHwuCQDjBICDTSis52hWguw xen/arch/x86/mm.c
3ddb79bdS4UeWWXDH-FaBKqcpMFcnw xen/arch/x86/mpparse.c
3f12cff65EV3qOG2j37Qm0ShgvXGRw xen/arch/x86/nmi.c
3ddb79bdHe6_Uij4-glW91vInNtBYQ xen/arch/x86/pci-irq.c
@@ -303,7 +330,6 @@
3ddb79bdIKgipvGoqExEQ7jawfVowA xen/arch/x86/pci-x86.h
40a4dfced2dnSzbKgJFlD3chKHexjQ xen/arch/x86/pdb-linux.c
4022a73czgX7d-2zfF_cb33oVemApQ xen/arch/x86/pdb-stub.c
3ddb79bc1_2bAt67x9MFCP4AZrQnvQ xen/arch/x86/process.c
3ddb79bc7KxGCEJsgBnkDX7XjD_ZEQ xen/arch/x86/rwlock.c
3ddb79bcrD6Z_rUvSDgrvjyb4846Eg xen/arch/x86/setup.c
405b8599xI_PoEr3zZoJ2on-jdn7iw xen/arch/x86/shadow.c
@@ -312,8 +338,14 @@
3ddb79bc-Udq7ol-NX4q9XsYnN7A2Q xen/arch/x86/time.c
3ddb79bccYVzXZJyVaxuv5T42Z1Fsw xen/arch/x86/trampoline.S
3ddb79bcOftONV9h4QCxXOfiT0h91w xen/arch/x86/traps.c
3ddb79bc4nTpGQOe6_-MbyZzkhlhFQ xen/arch/x86/usercopy.c
3ddb79bcOMCu9-5mKpjIh5d0qqBDPg xen/arch/x86/xen.lds
3e32af9aRnYGl4GMOaDKp7JdfhOGhg xen/arch/x86/x86_32/domain_page.c
3ddb79bcecupHj56ZbTa3B0FxDowMg xen/arch/x86/x86_32/entry.S
3ddb79bcHwuCQDjBICDTSis52hWguw xen/arch/x86/x86_32/mm.c
3ddb79bc4nTpGQOe6_-MbyZzkhlhFQ xen/arch/x86/x86_32/usercopy.c
3ddb79bcOMCu9-5mKpjIh5d0qqBDPg xen/arch/x86/x86_32/xen.lds
40e96d3aLDI-nViMuYneD7VKYlZrVg xen/arch/x86/x86_64/entry.S
40e96d3ahBTZqbTViInnq0lM03vs7A xen/arch/x86/x86_64/usercopy.c
40e96d3akN3Hu_J5Bk-WXD8OGscrYQ xen/arch/x86/x86_64/xen.lds
3ddb79bdff-gj-jFGKjOejeHLqL8Lg xen/common/Makefile
3e397e66AyyD5fYraAySWuwi9uqSXg xen/common/ac_timer.c
4022a73c_BbDFd2YJ_NQYVvKX5Oz7w xen/common/debug-linux.c
+2 -2
View File
@@ -77,7 +77,7 @@ Serial Port Configuration
one stream (without the high bit) is the console and
one stream (with the high bit stripped) is the pdb communication.
See: xeno.bk/tools/nsplitd
See: xeno.bk/tools/misc/nsplitd
nsplitd configuration
---------------------
@@ -107,7 +107,7 @@ Serial Port Configuration
characters received.
You can connect to the nsplitd using
'tools/xenctl/lib/console_client.py <host> <port>'
'tools/misc/xencons <host> <port>'
GDB 6.0
pdb has been tested with gdb 6.0. It should also work with
@@ -19,7 +19,7 @@
#define ASSERT(_p) \
if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \
__LINE__, __FILE__); *(int*)0=0; }
#define DPRINTK(_f, _a...) printk("(file=%s, line=%d) " _f, \
#define DPRINTK(_f, _a...) printk(KERN_ALERT "(file=%s, line=%d) " _f, \
__FILE__ , __LINE__ , ## _a )
#else
#define ASSERT(_p) ((void)0)
@@ -217,7 +217,7 @@ int blkif_disconnect(blkif_be_disconnect_t *disconnect, u8 rsp_id)
blkif->status = DISCONNECTING;
blkif->disconnect_rspid = rsp_id;
wmb(); /* Let other CPUs see the status change. */
free_irq(blkif->irq, NULL);
free_irq(blkif->irq, blkif);
blkif_deschedule(blkif);
blkif_put(blkif);
}
@@ -616,7 +616,7 @@ static void blkif_status_change(blkif_fe_interface_status_changed_t *status)
printk(KERN_INFO "VBD driver recovery in progress\n");
/* Prevent new requests being issued until we've fixed things up. */
/* Prevent new requests being issued until we fix things up. */
spin_lock_irq(&io_request_lock);
recovery = 1;
blkif_state = BLKIF_STATE_DISCONNECTED;
@@ -266,7 +266,7 @@ int netif_disconnect(netif_be_disconnect_t *disconnect, u8 rsp_id)
netif->disconnect_rspid = rsp_id;
wmb(); /* Let other CPUs see the status change. */
netif_stop_queue(netif->dev);
free_irq(netif->irq, NULL);
free_irq(netif->irq, netif);
netif_deschedule(netif);
netif_put(netif);
}
@@ -115,7 +115,7 @@ void cpu_idle (void)
}
}
void machine_restart(char * __unused)
void machine_restart(char *__unused)
{
/* We really want to get pending console data out before we die. */
extern void xencons_force_flush(void);
@@ -128,7 +128,11 @@ void machine_halt(void)
/* We really want to get pending console data out before we die. */
extern void xencons_force_flush(void);
xencons_force_flush();
HYPERVISOR_shutdown();
for ( ; ; ) /* loop without wasting cpu cycles */
{
HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_pending = 0;
HYPERVISOR_block();
}
}
void machine_power_off(void)
+72 -16
View File
@@ -8,6 +8,8 @@
* This file handles the architecture-dependent parts of initialization
*/
#define __KERNEL_SYSCALLS__
static int errno;
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -30,6 +32,7 @@
#include <linux/highmem.h>
#include <linux/bootmem.h>
#include <linux/seq_file.h>
#include <linux/reboot.h>
#include <asm/processor.h>
#include <linux/console.h>
#include <linux/module.h>
@@ -1148,10 +1151,10 @@ void __init cpu_init (void)
#include <asm/suspend.h>
/* Treat multiple suspend requests as a single one. */
static int suspending;
/* Ignore multiple shutdown requests. */
static int shutting_down = -1;
static void suspend_task(void *unused)
static void __do_suspend(void)
{
/* Hmmm... a cleaner interface to suspend/resume blkdevs would be nice. */
extern void blkdev_suspend(void);
@@ -1220,7 +1223,7 @@ static void suspend_task(void *unused)
HYPERVISOR_suspend(virt_to_machine(suspend_record) >> PAGE_SHIFT);
suspending = 0;
shutting_down = -1;
memcpy(&start_info, &suspend_record->resume_info, sizeof(start_info));
@@ -1272,25 +1275,78 @@ static void suspend_task(void *unused)
free_page((unsigned long)suspend_record);
}
static struct tq_struct suspend_tq;
static void shutdown_handler(ctrl_msg_t *msg, unsigned long id)
static int shutdown_process(void *__unused)
{
if ( msg->subtype != CMSG_SHUTDOWN_SUSPEND )
static char *envp[] = { "HOME=/", "TERM=linux",
"PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
static char *restart_argv[] = { "/sbin/shutdown", "-r", "now", NULL };
static char *poweroff_argv[] = { "/sbin/halt", "-p", NULL };
extern asmlinkage long sys_reboot(int magic1, int magic2,
unsigned int cmd, void *arg);
daemonize();
switch ( shutting_down )
{
extern void ctrl_alt_del(void);
ctrl_if_send_response(msg);
ctrl_alt_del();
case CMSG_SHUTDOWN_POWEROFF:
if ( execve("/sbin/halt", poweroff_argv, envp) < 0 )
{
sys_reboot(LINUX_REBOOT_MAGIC1,
LINUX_REBOOT_MAGIC2,
LINUX_REBOOT_CMD_POWER_OFF,
NULL);
}
break;
case CMSG_SHUTDOWN_REBOOT:
if ( execve("/sbin/shutdown", restart_argv, envp) < 0 )
{
sys_reboot(LINUX_REBOOT_MAGIC1,
LINUX_REBOOT_MAGIC2,
LINUX_REBOOT_CMD_RESTART,
NULL);
}
break;
}
else if ( !suspending )
return 0;
}
static void __shutdown_handler(void *unused)
{
int err;
if ( shutting_down != CMSG_SHUTDOWN_SUSPEND )
{
suspending = 1;
suspend_tq.routine = suspend_task;
schedule_task(&suspend_tq);
err = kernel_thread(shutdown_process, NULL, CLONE_FS | CLONE_FILES);
if ( err < 0 )
printk(KERN_ALERT "Error creating shutdown process!\n");
else
shutting_down = -1; /* could try again */
}
else
{
printk(KERN_ALERT"Ignore queued suspend request\n");
__do_suspend();
}
}
static void shutdown_handler(ctrl_msg_t *msg, unsigned long id)
{
static struct tq_struct shutdown_tq;
if ( (shutting_down == -1) &&
((msg->subtype == CMSG_SHUTDOWN_POWEROFF) ||
(msg->subtype == CMSG_SHUTDOWN_REBOOT) ||
(msg->subtype == CMSG_SHUTDOWN_SUSPEND)) )
{
shutting_down = msg->subtype;
shutdown_tq.routine = __shutdown_handler;
schedule_task(&shutdown_tq);
}
else
{
printk("Ignore spurious shutdown request\n");
}
ctrl_if_send_response(msg);
+14 -8
View File
@@ -2,17 +2,23 @@
#============================================================================
# Python defaults setup for 'xm create'.
# Edit this file to reflect the configuration of your system.
# This file expects the variable 'vmid' to be set.
#============================================================================
try:
vmid = int(vmid) # convert to integer
except:
raise ValueError, "Variable 'vmid' must be an integer"
# Define script variables here.
# xm_vars is defined automatically, use xm_vars.var() to define a variable.
if vmid <= 0:
raise ValueError, "Variable 'vmid' must be greater than 0"
def vmid_check(var, val):
val = int(val)
if val <= 0:
raise ValueError
return val
xm_vars.var('vmid',
use="Virtual machine id. Integer greater than 0.",
check=vmid_check)
# This checks the script variables.
xm_vars.check()
#----------------------------------------------------------------------------
# Kernel image file.
@@ -87,6 +93,6 @@ extra = "4 VMID=%d usr=/dev/sda6" % vmid
#----------------------------------------------------------------------------
# Set according to whether you want the domain restarted when it exits.
# The default is False.
#restart = True
#autorestart = True
#============================================================================
+14 -15
View File
@@ -2,24 +2,23 @@
#============================================================================
# Python defaults setup for 'xm create'.
# Edit this file to reflect the configuration of your system.
# This file expects the variable 'vmid' to be set.
#============================================================================
def config_usage ():
print >>sys.stderr,"""
The config file '%s' requires the following variable to be defined:
vmid -- Numeric identifier for the new domain, used to calculate
the VM's IP address and root partition. E.g. -Dvmid=1
""" % config_file
# Define script variables here.
# xm_vars is defined automatically, use xm_vars.var() to define a variable.
def vmid_check(var, val):
val = int(val)
if val <= 0:
raise ValueError
return val
xm_vars.var('vmid',
use="Virtual machine id. Integer greater than 0.",
check=vmid_check)
try:
vmid = int(vmid) # convert to integer
except:
raise ValueError, "Variable 'vmid' must be an integer"
if vmid <= 0:
raise ValueError, "Variable 'vmid' must be greater than 0"
# This checks the script variables.
xm_vars.check()
#----------------------------------------------------------------------------
# Kernel image file.
@@ -97,6 +96,6 @@ extra = "4 VMID=%d bootdev=xennet0" % vmid
#----------------------------------------------------------------------------
# Set according to whether you want the domain restarted when it exits.
# The default is False.
#restart = True
#autorestart = True
#============================================================================
+1 -1
View File
@@ -8,7 +8,7 @@ LIB_SRCS += allocate.c
LIB_SRCS += file_stream.c
LIB_SRCS += gzip_stream.c
LIB_SRCS += iostream.c
LIB_SRCS += sys_net.c
#LIB_SRCS += sys_net.c
LIB_SRCS += sys_string.c
LIB_OBJS := $(LIB_SRCS:.c=.o)
+3 -3
View File
@@ -16,8 +16,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _XEN_LIB_ALLOCATE_H_
#define _XEN_LIB_ALLOCATE_H_
#ifndef _XUTIL_ALLOCATE_H_
#define _XUTIL_ALLOCATE_H_
/** Allocate memory for a given type, and cast. */
#define ALLOCATE(ctype) (ctype *)allocate(sizeof(ctype))
@@ -33,7 +33,7 @@ extern void memzero(void *p, int size);
typedef void AllocateFailedFn(int size, int type);
extern AllocateFailedFn *allocate_failed_fn;
#endif /* _XEN_LIB_ALLOCATE_H_ */
#endif /* _XUTIL_ALLOCATE_H_ */
+3 -3
View File
@@ -16,8 +16,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _XEN_LIB_FILE_STREAM_H_
#define _XEN_LIB_FILE_STREAM_H_
#ifndef _XUTIL_FILE_STREAM_H_
#define _XUTIL_FILE_STREAM_H_
#ifndef __KERNEL__
#include "iostream.h"
@@ -32,4 +32,4 @@ extern IOStream get_stream_stdin(void);
extern int file_stream_setvbuf(IOStream *io, char *buf, int mode, size_t size);
#endif
#endif /* !_XEN_LIB_FILE_STREAM_H_ */
#endif /* !_XUTIL_FILE_STREAM_H_ */
-1
View File
@@ -1,4 +1,3 @@
/* $Id: gzip_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */
/*
* Copyright (C) 2003 Hewlett-Packard Company.
*
+3 -4
View File
@@ -1,4 +1,3 @@
#/* $Id: gzip_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */
/*
* Copyright (C) 2003 Hewlett-Packard Company.
*
@@ -17,8 +16,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _SP_GZIP_STREAM_H_
#define _SP_GZIP_STREAM_H_
#ifndef _XUTIL_GZIP_STREAM_H_
#define _XUTIL_GZIP_STREAM_H_
#ifndef __KERNEL__
#include "iostream.h"
@@ -28,4 +27,4 @@ extern IOStream *gzip_stream_new(gzFile *f);
extern IOStream *gzip_stream_fopen(const char *file, const char *flags);
extern IOStream *gzip_stream_fdopen(int fd, const char *flags);
#endif
#endif /* !_SP_FILE_STREAM_H_ */
#endif /* !_XUTIL_GZIP_STREAM_H_ */
+3 -3
View File
@@ -16,8 +16,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _XEN_LIB_KERNEL_STREAM_H_
#define _XEN_LIB_KERNEL_STREAM_H_
#ifndef _XUTIL_KERNEL_STREAM_H_
#define _XUTIL_KERNEL_STREAM_H_
#ifdef __KERNEL__
#include "iostream.h"
@@ -26,4 +26,4 @@ extern IOStream get_stream_kernel(void);
#define get_stream_stdout get_stream_kernel
#endif /* __KERNEL__ */
#endif /* !_XEN_LIB_KERNEL_STREAM_H_ */
#endif /* !_XUTIL_KERNEL_STREAM_H_ */
+3 -44
View File
@@ -25,8 +25,6 @@
#include "string_stream.h"
#include "allocate.h"
static int string_print(IOStream *io, const char *msg, va_list args);
static int string_getc(IOStream *io);
static int string_error(IOStream *io);
static int string_close(IOStream *io);
static void string_free(IOStream *io);
@@ -49,45 +47,6 @@ static inline StringData *get_string_data(IOStream *io){
return (StringData*)io->data;
}
/** Read a character from a string stream.
*
* @param io string stream
* @return character read, IOSTREAM_EOF if no more input
*/
static int string_getc(IOStream *io){
StringData *data = get_string_data(io);
int c = IOSTREAM_EOF;
char *s = data->in;
if(s && s < data->end){
c = (unsigned)*s;
data->in = s+1;
}
return c;
}
/** Print to a string stream.
* Formats the data to an internal buffer and prints it.
* The formatted data must fit into the internal buffer.
*
* @param io string stream
* @param format print format
* @param args print arguments
* @return result of the print
*/
static int string_print(IOStream *io, const char *msg, va_list args){
StringData *data = get_string_data(io);
int k = data->end - data->out;
int n = vsnprintf(data->out, k, (char*)msg, args);
if(n < 0 || n > k ){
n = k;
IOStream_close(io);
} else {
data->out += n;
}
return n;
}
/** Test if a string stream has an error.
*
* @param io string stream
@@ -118,7 +77,7 @@ static int string_close(IOStream *io){
*/
static void string_free(IOStream *io){
StringData *data = get_string_data(io);
zero(data, sizeof(*data));
memzero(data, sizeof(*data));
deallocate(data);
}
@@ -139,13 +98,13 @@ IOMethods *string_stream_get_methods(void){
*/
void string_stream_init(IOStream *io, StringData *data, char *s, int n){
if(data && io){
zero(data, sizeof(*data));
memzero(data, sizeof(*data));
data->string = (char*)s;
data->in = data->string;
data->out = data->string;
data->size = n;
data->end = data->string + n;
zero(io, sizeof(*io));
memzero(io, sizeof(*io));
io->methods = &string_methods;
io->data = data;
}
+3 -4
View File
@@ -1,4 +1,3 @@
/* $Id: string_stream.h,v 1.1 2003/08/22 14:25:48 mjw Exp $ */
/*
* Copyright (C) 2001, 2002 Hewlett-Packard Company.
*
@@ -17,8 +16,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _SP_STRING_STREAM_H_
#define _SP_STRING_STREAM_H_
#ifndef _XUTIL_STRING_STREAM_H_
#define _XUTIL_STRING_STREAM_H_
#include "iostream.h"
@@ -43,4 +42,4 @@ extern IOMethods *string_stream_get_methods(void);
extern IOStream *string_stream_new(char *s, int n);
extern void string_stream_init(IOStream *stream, StringData *data, char *s, int n);
#endif /* !_SP_STRING_STREAM_H_ */
#endif /* !_XUTIL_STRING_STREAM_H_ */
+3 -3
View File
@@ -16,8 +16,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _XEN_LIB_SYS_NET_H_
#define _XEN_LIB_SYS_NET_H_
#ifndef _XUTIL_SYS_NET_H_
#define _XUTIL_SYS_NET_H_
/** @file
*
* Replacement for standard network includes.
@@ -72,7 +72,7 @@ extern int inet_aton(const char *address, struct in_addr *inp);
extern char *mac_ntoa(const unsigned char *macaddr);
extern int mac_aton(const char *addr, unsigned char *macaddr);
#endif /* !_SP_SYS_NET_H_ */
#endif /* !_XUTIL_SYS_NET_H_ */
+3 -3
View File
@@ -16,8 +16,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _XEN_LIB_SYS_STRING_H_
#define _XEN_LIB_SYS_STRING_H_
#ifndef _XUTIL_SYS_STRING_H_
#define _XUTIL_SYS_STRING_H_
/** @file
* Replacement for standard string includes.
* Works in user or kernel code.
@@ -88,4 +88,4 @@ static inline size_t strnlen(const char *s, size_t n){
extern int convert_atoul(const char *s, unsigned long *v);
extern int path_concat(char *s, char *t, char **val);
#endif /* !_XEN_LIB_SYS_STRING_H_ */
#endif /* !_XUTIL_SYS_STRING_H_ */
+22
View File
@@ -0,0 +1,22 @@
CC = gcc
CFLAGS = -Wall -O3
CFILES = $(wildcard *.c)
HDRS = $(wildcard *.h)
OBJS = $(patsubst %.c,%.o,$(wildcard *.c))
TARGET = nsplitd
all: $(TARGET)
install: all
clean:
$(RM) *.o $(TARGET) *~
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^
%.o: %.c $(HDRS) Makefile
$(CC) $(CFLAGS) -c -o $@ $<
+686
View File
@@ -0,0 +1,686 @@
/*
* nsplitd.c
* ---------
*
* $Id: nsplitd.c,v 2.6 1998/09/17 14:28:37 sde1000 Exp $
*
* Copyright (c) 1995, University of Cambridge Computer Laboratory,
* Copyright (c) 1995, Richard Black, All Rights Reserved.
*
*
* A complete re-implementation of DME's nsplitd for use from inetd
*
*/
/* The basic stream comes in (via inetd) and we then conenct to
* somewhere else providing a loop-through service, except we offer
* two other ports for connection - one of which gets a second channel
* using the top bit to distinguish, and the other is a master control
* port (normally used for gdb) which gets complete exclusive access
* for its duration.
*
* Originally designed for multiplexing a xwcons/telnet with a gdb
* post-mortem debugging session.
*
* Here is a picture:
*
* port0 (from inetd)
* 8-bit connection /
* made by us <----> nsplitd <-----gdbport (default port0+2)
* to host:port/tcp |\
* | port1 (default port0+1)
* \
* control (default port0+3)
*
* If port1 is explicitly disabled (through a command-line option) then
* port0 becomes 8-bit clean.
*/
/*
* N.B.: We do NOT support 8 bit stdin/stdout usage on a
* /dev/... because to do that right involves much messing with ioctl
* and TIOC... etc. If you want to do that sort of thing then the
* right way to do it is to chain this onto wconsd (which does know
* about and understand all the ioctl and TIOC grief).
*/
#include <sys/types.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <ctype.h>
#include <netdb.h>
#include <string.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <syslog.h>
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef LOG_DAEMON
#define LOG_DAEMON 0
#endif
#define DB(x) /* ((x), fflush(stderr)) */
extern char *optarg;
extern int optind, opterr, optopt;
static char *prog_name;
static void usage(void)
{
fprintf(stderr, "This program (%s) should be run via inetd (tcp)\n\n",
prog_name);
fprintf(stderr, "usage: %s [-h<highport>][-g<gdbport>]"
"[-c<ctlport>][-8] host:service\n",
prog_name);
exit(1);
}
static void fault(char *format, ...)
{
va_list ap;
char logbuf[1024];
va_start(ap, format);
fprintf(stderr, "%s: ", prog_name);
vfprintf(stderr, format, ap);
fflush(stderr);
va_end(ap);
/* XXX This is a bit dubious, but there is no vsyslog */
va_start(ap, format);
vsprintf(logbuf, format, ap);
syslog(LOG_ERR, logbuf);
va_end(ap);
exit(1);
}
static int getservice(char *name, unsigned short *port)
{
struct servent *se;
if (!name) return -1;
if (isdigit(name[0]))
*port = atoi(name);
else
{
if (!(se = getservbyname(name, "tcp")))
return -1;
*port = ntohs(se->s_port);
}
return 0;
}
/*
* connect_host: connect to ("name", "port")
*/
static int connect_host (char *name, unsigned int port)
{
int fd;
struct hostent *hostent;
struct sockaddr_in sin;
int on;
if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
fault("socket");
if (!(hostent = gethostbyname(name)))
fault("gethostbyname: %s: %s\n", name, strerror(errno));
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons (port);
memcpy(&sin.sin_addr.s_addr, hostent->h_addr, sizeof(struct in_addr));
if (connect(fd, (struct sockaddr *) &sin, sizeof (sin)) < 0)
fault("connect: %s:%u: %s\n", name, port, strerror(errno));
on = 1;
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)) < 0)
syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m");
on = 1;
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
return fd;
}
/*
* open a tcp socket and start listening for connections on it
*/
static int startlistening(unsigned short port)
{
int fd, on;
struct sockaddr_in sin;
if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
fault("socket");
on = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0)
syslog(LOG_WARNING, "setsockopt (SO_REUSEADDR): %m");
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons (port);
sin.sin_addr.s_addr = INADDR_ANY;
if (bind(fd, &sin, sizeof(sin)) < 0)
fault("bind: %u: %s\n", port, strerror(errno));
if (listen(fd, 1) < 0)
fault("listen: %s\n", strerror(errno));
return fd;
}
static void noblock(int fd)
{
int on=1;
if (ioctl(fd, FIONBIO, &on) < 0)
fault("ioctl: FIONBIO: %s\n", strerror(errno));
}
/* You might not believe this, but fd_sets don't have to be a 32-bit
* integer. In particular, in glibc2 it is an array of unsigned
* longs. Hence, this hacked up FD_SET_rjb() that works out if it
* would have been a nop. */
#define FD_SET_rjb(fd, setp) \
do { \
if ((fd) != 32) \
FD_SET((fd), (setp)); \
} while(0)
#define FD_ISSET_rjb(fd, setp) (((fd) != 32)? FD_ISSET((fd), (setp)) : 0)
#define MAXSIZE 256
/* -----------------------------------------------------------------
* The main bit of the algorithm. Note we use 32 to mean not connected
* because this gives us 1<<32 == 0. We could have done this one
* character at a time, but that would have been very inefficient and
* not the unix way. */
static int debug;
static void doit(int actl, int acto, int lish, int lisg, int lisc)
{
int acth, actg, actc;
int gdbmode = FALSE;
char gibuf[MAXSIZE], oibuf[MAXSIZE];
char libuf[MAXSIZE], lobuf[MAXSIZE];
char hibuf[MAXSIZE], hobuf[MAXSIZE];
char ctlbuf[MAXSIZE];
fd_set rdfs, wrfs, exfs;
int gicc, oicc, licc, locc, hicc, hocc, ctlcc;
char *giptr, *oiptr, *liptr, *loptr, *hiptr, *hoptr;
int rc, fromlen;
struct sockaddr_in from;
gicc = oicc = licc = locc = hicc = hocc = ctlcc = 0;
acth = actg = actc = 32; /* XXX yummy */
noblock(actl);
noblock(acto);
for(;;)
{
FD_ZERO(&rdfs);
FD_ZERO(&wrfs);
FD_ZERO(&exfs);
/* always take input from the control port (if it's connected) */
FD_SET_rjb(actc, &rdfs);
if (gdbmode)
{
if (oicc)
FD_SET_rjb(actg, &wrfs);
else
FD_SET_rjb(acto, &rdfs);
if (gicc)
FD_SET_rjb(acto, &wrfs);
else
FD_SET_rjb(actg, &rdfs);
}
else
{
/* There is no such thing as oibuf because its been split into
* lobuf and hobuf
*/
if (locc || hocc)
{
if (locc)
FD_SET_rjb(actl, &wrfs);
if (hocc)
FD_SET_rjb(acth, &wrfs);
}
else
FD_SET_rjb(acto, &rdfs);
if (licc)
FD_SET_rjb(acto, &wrfs);
else
FD_SET_rjb(actl, &rdfs);
if (hicc)
FD_SET_rjb(acto, &wrfs);
else
FD_SET_rjb(acth, &rdfs);
}
if (acth == 32 && lish>=0) FD_SET_rjb(lish, &rdfs);
if (actg == 32) FD_SET_rjb(lisg, &rdfs);
if (actc == 32) FD_SET_rjb(lisc, &rdfs);
/* now make exfs the union of the read and write fd sets, plus
* "actl" */
{
int i;
exfs = rdfs;
for(i=0; i<32; i++) /* XXX we only copy fd numbers up to 31 */
if (FD_ISSET(i, &wrfs))
FD_SET_rjb(i, &exfs);
FD_SET_rjb(actl, &exfs);
}
/* XXX AND: can't print something of type fd_set as %x - it
* might be an array */
DB(fprintf(stderr, "%s: before select: %08x %08x %08x\n",
prog_name, rdfs, wrfs, exfs));
if (select(32, &rdfs, &wrfs, &exfs, NULL) < 0)
fault("select: %s\n", strerror(errno));
DB(fprintf(stderr, "%s: after select: %08x %08x %08x\n",
prog_name, rdfs, wrfs, exfs));
/* XXX it appears that a non-blocking socket may not show up
* correctly in exfs but instead goes readable with no data in
* it. Thus we check for zero and goto the appropriate close
* method. */
/* Deal with exceptions */
if (FD_ISSET_rjb(actg, &exfs))
{
exfs_actg:
close(actg);
gdbmode = FALSE;
oicc = 0;
oiptr = oibuf;
actg = 32;
continue; /* because assumptions changed */
}
if (FD_ISSET_rjb(acth, &exfs))
{
exfs_acth:
close(acth);
hicc = hocc = 0;
hiptr = hibuf;
hoptr = hibuf;
acth = 32;
continue; /* because assumptions changed */
}
if (FD_ISSET_rjb(actl, &exfs) ||
FD_ISSET_rjb(acto, &exfs))
{
exfs_actl:
exfs_acto:
/* Thats all folks ... */
break;
}
if (FD_ISSET_rjb(actc, &exfs))
{
exfs_ctl:
close(actc);
actc = 32;
ctlcc = 0;
continue;
}
/* Deal with reading */
if (FD_ISSET_rjb(acto, &rdfs))
{
if ((oicc = read(acto, oiptr = oibuf, MAXSIZE)) < 0)
fault("read acto: %d: %s\n", oicc, strerror(errno));
if (!oicc) goto exfs_acto;
if (!gdbmode)
{
int t;
assert((locc == 0) && (hocc == 0));
loptr = lobuf;
hoptr = hobuf;
if (lish>=0) {
for(t=0; t<oicc; t++)
if (oibuf[t] & 0x80)
hobuf[hocc++] = oibuf[t] & 0x7f;
else
lobuf[locc++] = oibuf[t];
} else {
for (t=0; t<oicc; t++)
lobuf[locc++] = oibuf[t];
}
/* If no high connection scratch that */
if (acth == 32)
hocc=0;
}
}
if (FD_ISSET_rjb(actl, &rdfs))
{
if ((licc = read(actl, liptr = libuf, MAXSIZE)) < 0)
fault("read actl: %d: %s\n", licc, strerror(errno));
if (!licc) goto exfs_actl;
}
if (FD_ISSET_rjb(acth, &rdfs))
{
int t;
if ((hicc = read(acth, hiptr = hibuf, MAXSIZE)) < 0)
fault("read acth: %d: %s\n", hicc, strerror(errno));
if (!hicc) goto exfs_acth;
for(t=0; t<hicc; t++)
hibuf[t] |= 0x80;
}
if (FD_ISSET_rjb(actg, &rdfs))
{
if ((gicc = read(actg, giptr = gibuf, MAXSIZE)) < 0)
fault("read actg: %d: %s\n", gicc, strerror(errno));
if (debug) write(1, giptr, gicc); /* XXX */
if (!gicc) goto exfs_actg;
}
if (FD_ISSET_rjb(actc, &rdfs))
{
if ((ctlcc = read(actc, ctlbuf, MAXSIZE)) < 0)
fault("read actc: %d: %s\n", ctlcc, strerror(errno));
if (debug) write(1, ctlbuf, gicc);
if (!ctlcc) goto exfs_ctl;
if (ctlbuf[0] == 'r') /* reset command */
{
syslog(LOG_INFO, "reset command read, exiting");
if (debug) write(1, "reseting\n", sizeof("reseting\n"));
break;
}
}
/* Deal with writing */
if (FD_ISSET_rjb(actg, &wrfs))
{
/* We must be in gdb mode so send oi buffer data */
assert(gdbmode);
if (debug) write(2, oiptr, oicc); /* XXX */
if ((rc = write(actg, oiptr, oicc)) <= 0)
fault("write actg: %d: %s\n", rc, strerror(errno));
oiptr += rc;
oicc -= rc;
}
if (FD_ISSET_rjb(actl, &wrfs))
{
if ((rc = write(actl, loptr, locc)) <= 0)
fault("write actl: %d: %s\n", rc, strerror(errno));
loptr += rc;
locc -= rc;
}
if (FD_ISSET_rjb(acth, &wrfs))
{
if ((rc = write(acth, hoptr, hocc)) <= 0)
fault("write acth: %d: %s\n", rc, strerror(errno));
hoptr += rc;
hocc -= rc;
}
if (FD_ISSET_rjb(acto, &wrfs))
{
/* If in gdb mode send gdb input, otherwise send low data
preferentially */
if (gdbmode)
{
assert(gicc);
if ((rc = write(acto, giptr, gicc)) <= 0)
fault("write acto: %d: %s\n", rc, strerror(errno));
giptr += rc;
gicc -= rc;
}
else
{
if (licc)
{
if ((rc = write(acto, liptr, licc)) <= 0)
fault("write acto: %d: %s\n", rc, strerror(errno));
liptr += rc;
licc -= rc;
}
else
{
assert(hicc);
if ((rc = write(acto, hiptr, hicc)) <= 0)
fault("write acto: %d: %s\n", rc, strerror(errno));
hiptr += rc;
hicc -= rc;
}
}
}
/* Deals with new connections */
if ((acth == 32) && lish>=0 && (FD_ISSET_rjb(lish, &rdfs)))
{
fromlen = sizeof(from);
if ((acth = accept(lish, &from, &fromlen)) < 0)
{
syslog(LOG_WARNING, "accept: %m");
acth = 32;
}
else
{
noblock(acth);
hicc = hocc = 0;
syslog(LOG_INFO, "highbit client peer is %s:%u\n",
inet_ntoa(from.sin_addr), ntohs(from.sin_port));
}
}
if ((actg == 32) && (FD_ISSET_rjb(lisg, &rdfs)))
{
fromlen = sizeof(from);
if ((actg = accept(lisg, &from, &fromlen)) < 0)
{
syslog(LOG_WARNING, "accept: %m");
actg = 32;
}
else
{
noblock(actg);
gicc = 0;
gdbmode = TRUE;
syslog(LOG_INFO, "gdb client peer is %s:%u\n",
inet_ntoa(from.sin_addr), ntohs(from.sin_port));
}
}
if ((actc == 32) && (FD_ISSET_rjb(lisc, &rdfs)))
{
fromlen = sizeof(from);
if ((actc = accept(lisc, &from, &fromlen)) < 0)
{
syslog(LOG_WARNING, "accept (ctl): %m");
actc = 32;
}
else
{
noblock(actc);
syslog(LOG_INFO, "ctl client peer is %s:%u\n",
inet_ntoa(from.sin_addr), ntohs(from.sin_port));
}
}
/* Back to top of loop */
}
/* We are bailing because one of the primary connections has gone
* away. We close these all explicitly here because that way the
* timeout on reusing the port numbers is smnaller. */
close(acth);
close(actg);
/* XXX AND: why are we closing all these "character counts" ?? */
close(gicc);
close(oicc);
close(licc);
close(locc);
close(hicc);
close(hocc);
}
/*
* ------------------------------------------------------------
*/
int main(int argc, char **argv)
{
/* In general, suffix "l" is low channel, "h" is high channel, "g"
* is gdb channel, "c" is control channel and "o" is output channel.
*/
struct sockaddr_in from;
int infd = 0, outfd;
unsigned short portl, porth, portg, portc, porto;
int on = 1, c;
char *outname, *outservice;
int fromlen;
int lish, lisg, lisc;
#if 0
FILE *newerr;
#endif /* 0 */
prog_name = argv[0];
if (isatty(infd))
usage();
/* Here, then not just a simple idiot. */
signal(SIGPIPE, SIG_IGN);
openlog(prog_name, LOG_PID, LOG_DAEMON);
fromlen = sizeof(from);
if (getsockname(infd, &from, &fromlen) < 0)
fault("getsockname: %s", strerror(errno));
if ((fromlen != sizeof(from)) || (from.sin_family != AF_INET))
fault("not an inet socket (family=%d)\n", from.sin_family);
portl = ntohs(from.sin_port);
porth = portl+1;
portg = porth+1;
portc = portg+1;
fromlen = sizeof(from);
if (getpeername(infd, &from, &fromlen) < 0)
fault("getpeername: %s", strerror(errno));
if ((fromlen != sizeof(from)) || (from.sin_family != AF_INET))
fault("not an inet socket (family=%d)\n", from.sin_family);
syslog(LOG_INFO, "on port %u peer is %s:%u\n", portl,
inet_ntoa(from.sin_addr), ntohs(from.sin_port));
if (setsockopt(infd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
/* from here on, we map stderr to output on the connection so we can
* report errors to the remote user.
*/
#if 0
if (!(newerr = fdopen(infd, "w")))
syslog(LOG_WARNING, "fdopen: %m");
else
*stderr = *newerr;
#endif
while((c = getopt(argc, argv, "d8h:g:c:")) != EOF)
{
switch(c)
{
case 'd':
debug++;
break;
case 'h':
/* high bit port */
if (getservice(optarg, &porth) < 0)
fault("getservice failed (high port '%s')\n", optarg);
break;
case 'g':
/* gdb port */
if (getservice(optarg, &portg) < 0)
fault("getservice failed (gdb port '%s')\n", optarg);
break;
case 'c':
/* control port */
if (getservice(optarg, &portc) < 0)
fault("getservice failed (control port '%s')\n", optarg);
break;
case '8':
/* 8-bit clean; no high port */
porth=0;
break;
default:
fault("bad argument list!\n");
}
}
if (argc != optind + 1)
fault("unparsed arguments (%d!=%d)\n", argc, optind+1);
outname = argv[optind];
if (!(outservice = strchr(outname, ':')))
fault("output arg '%s' doesn't contain ':'\n", outname);
*outservice++ = 0;
if (getservice(outservice, &porto) < 0)
fault("getservice failed (output port '%s')\n", outservice);
/* Time to start the sockets */
if (porth) {
lish = startlistening(porth);
} else {
lish = -1;
}
lisg = startlistening(portg);
lisc = startlistening(portc);
outfd = connect_host(outname, porto);
doit(infd, outfd, lish, lisg, lisc);
syslog(LOG_INFO, "terminating normally\n");
fclose(stderr);
closelog();
exit(0);
}
/* End $Id: nsplitd.c,v 2.6 1998/09/17 14:28:37 sde1000 Exp $ */
+42 -11
View File
@@ -3,7 +3,7 @@ import re
import socket
import struct
def readlines(fd):
def _readlines(fd):
"""Version of readlines safe against EINTR.
"""
import errno
@@ -21,7 +21,7 @@ def readlines(fd):
lines.append(line)
return lines
def readline(fd):
def _readline(fd):
"""Version of readline safe against EINTR.
"""
while 1:
@@ -42,11 +42,14 @@ as it may have been moved onto the bridge.
NBE_BRIDGE = 'nbe-br'
def get_current_ipaddr(dev='eth0'):
"""Return a string containing the primary IP address for the given
network interface (default 'eth0').
"""Get the primary IP address for the given network interface.
dev network interface (default eth0)
returns interface address as a string
"""
fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' )
lines = readlines(fd)
lines = _readlines(fd)
for line in lines:
m = re.search( '^\s+inet addr:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*',
line )
@@ -57,11 +60,14 @@ def get_current_ipaddr(dev='eth0'):
return None
def get_current_ipmask(dev='eth0'):
"""Return a string containing the primary IP netmask for the given
network interface (default 'eth0').
"""Get the primary IP netmask for a network interface.
dev network interface (default eth0)
returns interface netmask as a string
"""
fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' )
lines = readlines(fd)
lines = _readlines(fd)
for line in lines:
m = re.search( '^.+Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*',
line )
@@ -72,11 +78,14 @@ def get_current_ipmask(dev='eth0'):
return None
def get_current_ipgw(dev='eth0'):
"""Return a string containing the IP gateway for the given
network interface (default 'eth0').
"""Get the IP gateway for a network interface.
dev network interface (default eth0)
returns gateway address as a string
"""
fd = os.popen( '/sbin/route -n' )
lines = readlines(fd)
lines = _readlines(fd)
for line in lines:
m = re.search( '^\S+\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)' +
'\s+\S+\s+\S*G.*' + dev + '.*', line )
@@ -88,24 +97,46 @@ def get_current_ipgw(dev='eth0'):
def inet_aton(addr):
"""Convert an IP addr in IPv4 dot notation into an int.
addr IP address as a string
returns integer
"""
b = socket.inet_aton(addr)
return struct.unpack('!I', b)[0]
def inet_ntoa(n):
"""Convert an int into an IP addr in IPv4 dot notation.
n IP address
returns string
"""
b = struct.pack('!I', n)
return socket.inet_ntoa(b)
def add_offset_to_ip(addr, offset):
"""Add a numerical offset to an IP addr in IPv4 dot notation.
addr IP address
offset offset to add
returns new address
"""
n = inet_aton(addr)
n += offset
return inet_ntoa(n)
def check_subnet( ip, network, netmask ):
"""Check if an IP address is in the subnet defined by
a network address and mask'.
ip IP adress
network network address
netmask network mask
returns 1 if it is in the subnet, 0 if not
"""
n_ip = inet_aton(ip)
n_net = inet_aton(network)
n_mask = inet_aton(netmask)
+33 -2
View File
@@ -1,6 +1,11 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Client API for the HTTP interface on xend.
Callable as a script - see main().
This API is the 'control-plane' for xend.
The 'data-plane' is done separately. For example, consoles
are accessed via sockets on xend, but the list of consoles
is accessible via this API.
"""
import sys
import httplib
@@ -27,6 +32,8 @@ class Foo(httplib.HTTPResponse):
def sxprio(sxpr):
"""Convert an sxpr to a string.
"""
io = StringIO()
sxp.show(sxpr, out=io)
print >> io
@@ -80,6 +87,12 @@ def eventurl(location, root, id=''):
return urljoin(location, root, 'event/', id)
def xend_request(url, method, data=None):
"""Make a request to xend.
url xend request url
method http method: POST or GET
data request argument data (dict)
"""
urlinfo = urlparse.urlparse(url)
(uproto, ulocation, upath, uparam, uquery, ufrag) = urlinfo
if DEBUG: print url, urlinfo
@@ -122,20 +135,37 @@ def xend_request(url, method, data=None):
return val
def xend_get(url, args=None):
"""Make a xend request using GET.
Requests using GET are 'safe' and may be repeated without
nasty side-effects.
"""
return xend_request(url, "GET", args)
def xend_call(url, data):
"""Make xend request using POST.
Requests using POST potentially cause side-effects and should
not be repeated unless it really is wanted to do the side
effect again.
"""
return xend_request(url, "POST", data)
class Xend:
"""Default location of the xend server."""
SRV_DEFAULT = "localhost:8000"
"""Default path to the xend root on the server."""
ROOT_DEFAULT = "/xend/"
def __init__(self, srv=None, root=None):
self.bind(srv, root)
def bind(self, srv=None, root=None):
"""Bind to a given server.
srv server location (host:port)
root server xend root path
"""
if srv is None: srv = self.SRV_DEFAULT
if root is None: root = self.ROOT_DEFAULT
if not root.endswith('/'): root += '/'
@@ -195,9 +225,10 @@ class Xend:
return xend_call(self.domainurl(id),
{'op' : 'pause'})
def xend_domain_shutdown(self, id):
def xend_domain_shutdown(self, id, reason):
return xend_call(self.domainurl(id),
{'op' : 'shutdown'})
{'op' : 'shutdown',
'reason' : reason })
def xend_domain_destroy(self, id):
return xend_call(self.domainurl(id),
+132 -10
View File
@@ -5,8 +5,11 @@
Needs to be persistent for one uptime.
"""
import sys
import traceback
from twisted.internet import defer
defer.Deferred.debug = 1
from twisted.internet import reactor
import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
@@ -28,10 +31,19 @@ __all__ = [ "XendDomain" ]
class XendDomain:
"""Index of all domains. Singleton.
"""
"""Path to domain database."""
dbpath = "domain"
"""Table of domain info indexed by domain id."""
domain = {}
"""Table of configs for domain restart, indexed by domain id."""
restarts = {}
"""Table of delayed calls."""
schedule = {}
def __init__(self):
self.xconsole = XendConsole.instance()
# Table of domain info indexed by domain id.
@@ -49,6 +61,53 @@ class XendDomain:
print 'XendDomain> virq', val
self.reap()
def schedule_later(self, _delay, _name, _fn, *args):
"""Schedule a function to be called later (if not already scheduled).
_delay delay in seconds
_name schedule name
_fn function
args arguments
"""
if self.schedule.get(_name): return
self.schedule[_name] = reactor.callLater(_delay, _fn, *args)
def schedule_cancel(self, name):
"""Cancel a scheduled function call.
name schedule name to cancel
"""
callid = self.schedule.get(name)
if not callid:
return
if callid.active():
callid.cancel()
del self.schedule[name]
def reap_schedule(self, delay=0):
"""Schedule reap to be called later.
delay delay in seconds
"""
self.schedule_later(delay, 'reap', self.reap)
def reap_cancel(self):
"""Cancel any scheduled reap.
"""
self.schedule_cancel('reap')
def refresh_schedule(self, delay=0):
"""Schedule refresh to be called later.
delay delay in seconds
"""
self.schedule_later(delay, 'refresh', self.refresh)
def refresh_cancel(self):
"""Cancel any scheduled refresh.
"""
self.schedule_cancel('refresh')
def rm_all(self):
"""Remove all domain info. Used after reboot.
"""
@@ -145,6 +204,7 @@ class XendDomain:
"""Look for domains that have crashed or stopped.
Tidy them up.
"""
self.reap_cancel()
print 'XendDomain>reap>'
domlist = xc.domain_getinfo()
casualties = []
@@ -158,12 +218,14 @@ class XendDomain:
for d in casualties:
id = str(d['dom'])
print 'XendDomain>reap> died id=', id, d
self.domain_destroy(id, refresh=0)
self.final_domain_destroy(id)
print 'XendDomain>reap<'
def refresh(self):
"""Refresh domain list from Xen.
"""
self.refresh_cancel()
print 'XendDomain>refresh>'
domlist = xc.domain_getinfo()
# Index the domlist by id.
# Add entries for any domains we don't know about.
@@ -184,7 +246,7 @@ class XendDomain:
d.update(dominfo)
else:
self._delete_domain(d.id)
self.reap()
self.reap_schedule(1)
def refresh_domain(self, id):
"""Refresh information for a single domain.
@@ -267,21 +329,70 @@ class XendDomain:
"""Shutdown domain (nicely).
id domain id
reason shutdown type: poweroff, reboot, halt
reason shutdown type: poweroff, reboot, suspend, halt
"""
dom = int(id)
if dom <= 0:
return 0
self.domain_restart_schedule(id, reason)
eserver.inject('xend.domain.shutdown', [id, reason])
if reason == 'halt':
reason = 'poweroff'
val = xend.domain_shutdown(dom, reason)
self.refresh()
self.refresh_schedule()
return val
def domain_destroy(self, id, refresh=1):
"""Terminate domain immediately.
def domain_restart_schedule(self, id, reason):
"""Schedule a restart for a domain if it needs one.
id domain id
reason shutdown reason
"""
if id in self.restarts:
# Don't schedule if already there.
return
restart = 0
if reason in ['poweroff', 'reboot']:
dominfo = self.domain.get(id)
if dominfo and (dominfo.autorestart or reason == 'reboot'):
restart = 1
# Clear autorestart flag to avoid multiple restarts.
dominfo.autorestart = 0
if restart:
self.restarts[id] = dominfo.config
def domain_restart_cancel(self, id):
"""Cancel any restart scheduled for a domain.
id domain id
"""
dominfo = self.domain.get(id)
if dominfo:
dominfo.autorestart = 0
if id in self.restarts:
del self.restarts[id]
def domain_restarts(self):
"""Execute any scheduled domain restarts for domains that have gone.
"""
for id in self.restarts.keys():
if id in self.domain:
# Don't execute restart for domains still running.
continue
config = self.restarts[id]
# Remove it from the restarts.
del self.restarts[id]
try:
self.domain_create(config)
except:
print >>sys.stderr, "XendDomain> Exception restarting domain"
traceback.print_exc(sys.stderr)
def final_domain_destroy(self, id):
"""Final destruction of a domain..
id domain id
refresh send a domain destroy event if true
"""
dom = int(id)
if dom <= 0:
@@ -292,15 +403,26 @@ class XendDomain:
val = dominfo.destroy()
else:
val = xc.domain_destroy(dom=dom)
if refresh: self.refresh()
return val
def domain_destroy(self, id):
"""Terminate domain immediately.
Camcels any restart for the domain.
id domain id
"""
self.domain_restart_cancel(id)
val = self.final_domain_destroy(id)
self.refresh_schedule()
return val
def domain_migrate(self, id, dst):
"""Start domain migration.
id domain id
"""
# Need a cancel too?
# Don't forget to cancel restart for it.
pass
def domain_save(self, id, dst, progress=0):
+31 -15
View File
@@ -15,6 +15,7 @@ import sys
import os
from twisted.internet import defer
defer.Deferred.debug = 1
import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
import xen.util.ip
@@ -291,6 +292,9 @@ def vm_restore(src, progress=0):
if dom < 0:
raise VmError('restore failed')
vmconfig = sxp.from_string(d['vmconfig'])
if not vmconfig:
raise VmError('bad vmconfig s-expression')
vmconfig = vmconfig[0]
vm.config = sxp.child_value(vmconfig, 'config')
deferred = vm.dom_configure(dom)
def vifs_cb(val, vm):
@@ -362,6 +366,8 @@ class XendDomainInfo:
self.state = self.STATE_OK
#todo: set to migrate info if migrating
self.migrate = None
#Whether to auto-restart
self.autorestart = 0
def setdom(self, dom):
self.dom = int(dom)
@@ -417,7 +423,9 @@ class XendDomainInfo:
self.config = config
try:
self.name = sxp.child_value(config, 'name')
self.memory = int(sxp.child_value(config, 'memory', '128'))
self.memory = int(sxp.child_value(config, 'memory') or '128')
if sxp.child(config, 'autorestart'):
self.autorestart = 1
self.configure_backends()
image = sxp.child_value(config, 'image')
image_name = sxp.name(image)
@@ -426,14 +434,18 @@ class XendDomainInfo:
raise VmError('unknown image type: ' + image_name)
image_handler(self, image)
deferred = self.configure()
def cbok(x):
print 'vm_create> cbok', x
return x
def cberr(err):
self.destroy()
return err
deferred.addCallback(cbok)
deferred.addErrback(cberr)
except StandardError, ex:
# Catch errors, cleanup and re-raise.
self.destroy()
raise
def cbok(x):
print 'vm_create> cbok', x
return x
deferred.addCallback(cbok)
print 'vm_create<'
return deferred
@@ -445,7 +457,7 @@ class XendDomainInfo:
"""
devices = []
for d in sxp.children(self.config, 'device'):
dev = sxp.child0(d)
dev = sxp.child(d)
if dev is None: continue
if name == sxp.name(dev):
devices.append(dev)
@@ -576,7 +588,7 @@ class XendDomainInfo:
if self.recreate: return
memory = self.memory
name = self.name
cpu = int(sxp.child_value(self.config, 'cpu', '-1'))
cpu = int(sxp.child_value(self.config, 'cpu') or '-1')
print 'init_domain>', memory, name, cpu
dom = xc.domain_create(mem_kb= memory * 1024, name= name, cpu= cpu)
if dom <= 0:
@@ -641,7 +653,7 @@ class XendDomainInfo:
devices = sxp.children(self.config, 'device')
index = {}
for d in devices:
dev = sxp.child0(d)
dev = sxp.child(d)
if dev is None:
raise VmError('invalid device')
dev_name = sxp.name(dev)
@@ -660,7 +672,7 @@ class XendDomainInfo:
"""Set configuration flags if the vm is a backend for netif of blkif.
"""
for c in sxp.children(self.config, 'backend'):
name = sxp.name(sxp.child0(c))
name = sxp.name(sxp.child(c))
if name == 'blkif':
self.blkif_backend = 1
elif name == 'netif':
@@ -706,6 +718,10 @@ class XendDomainInfo:
self.name = d['name']
self.memory = d['memory']/1024
deferred = self.configure()
def cberr(err):
self.destroy()
return err
deferred.addErrback(cberr)
except StandardError, ex:
self.destroy()
raise
@@ -738,7 +754,7 @@ def vm_image_linux(vm, image):
"""
kernel = sxp.child_value(image, "kernel")
cmdline = ""
ip = sxp.child_value(image, "ip", "dhcp")
ip = sxp.child_value(image, "ip") or "dhcp"
if ip:
cmdline += " ip=" + ip
root = sxp.child_value(image, "root")
@@ -747,7 +763,7 @@ def vm_image_linux(vm, image):
args = sxp.child_value(image, "args")
if args:
cmdline += " " + args
ramdisk = sxp.child_value(image, "ramdisk", '')
ramdisk = sxp.child_value(image, "ramdisk") or ''
vifs = vm.config_devices("vif")
vm.create_domain("linux", kernel, ramdisk, cmdline, len(vifs))
return vm
@@ -764,7 +780,7 @@ def vm_image_netbsd(vm, image):
#todo: Same as for linux. Is that right? If so can unify them.
kernel = sxp.child_value(image, "kernel")
cmdline = ""
ip = sxp.child_value(image, "ip", "dhcp")
ip = sxp.child_value(image, "ip") or "dhcp"
if ip:
cmdline += "ip=" + ip
root = sxp.child_value(image, "root")
@@ -793,7 +809,7 @@ def vm_dev_vif(vm, val, index):
defer = make_vif(vm.dom, vif, vmac, vm.recreate)
def fn(id):
dev = xend.netif_dev(vm.dom, vif)
devid = sxp.attribute(val, 'id')
devid = sxp.child_value(val, 'id')
if devid:
dev.setprop('id', devid)
bridge = sxp.child_value(val, "bridge")
@@ -820,7 +836,7 @@ def vm_dev_vbd(vm, val, index):
dev = sxp.child_value(val, 'dev')
if not dev:
raise VmError('vbd: Missing dev')
mode = sxp.child_value(val, 'mode', 'r')
mode = sxp.child_value(val, 'mode') or 'r'
defer = make_disk(vm.dom, uname, dev, mode, vm.recreate)
def fn(vbd):
dev = xend.blkif_dev(vm.dom, vdev)
@@ -922,7 +938,7 @@ def vm_field_vnet(vm, config, val, index):
if id is None:
raise VmError('vnet: missing vif id')
dev = vm.get_device_by_id('vif', id)
#vnet = sxp.child_value(v, 'vnet', 1)
#vnet = sxp.child_value(v, 'vnet') or '1'
#mac = sxp.child_value(dev, 'mac')
#vif = sxp.child_value(dev, 'vif')
#vnet_bridge(vnet, mac, vm.dom, 0)
+132 -8
View File
@@ -2,22 +2,125 @@
import sys
import socket
import time
from twisted.internet import reactor
from twisted.internet import defer
defer.Deferred.debug = 1
from twisted.internet.protocol import Protocol
from twisted.internet.protocol import ClientFactory
import sxp
import XendDB
import EventServer; eserver = EventServer.instance()
from xen.xend.packing import SxpPacker, SxpUnpacker
from xen.xend import XendDomain
xd = XendDomain.instance()
XFRD_PORT = 8002
XFR_PROTO_MAJOR = 1
XFR_PROTO_MINOR = 0
class Migrate(Protocol):
def __init__(self, minfo):
self.packer = None
self.unpacker = None
self.minfo = minfo
def connectionMade(self):
self.packer = SxpPacker(self.transport)
self.unpacker = SxpPacker()
# Send hello.
self.packer.pack(['xfr.hello', XFR_PROTO_MAJOR, XFR_PROTO_MINOR])
# Send migrate.
vmconfig = self.minfo.vmconfig()
if not vmconfig:
self.loseConnection()
return
self.packer.pack(['xfr.migrate',
self.minfo.src_dom,
vmconfig,
self.minfo.dst_host,
self.minfo.dst_port])
def connectionLost(self, reason):
self.minfo.closed(reason)
def dataReceived(self, data):
try:
self.unpacker.reset(data)
val = self.unpacker.unpack()
print 'dataReceived>', 'val=', val
op = val[0]
op.replace('.', '_')
if op.startwith('xfr_'):
fn = getattr(self, op, self.unknown)
else:
fn = self.unknown
fn(val)
except Exception, ex:
print 'dataReceived>', ex
pass
def unknown(self, val):
print 'unknown>', val
def xfr_progress(self, val):
print 'xfr_progress>', val
def xfr_error(self, val):
# If we get an error with non-zero code the migrate failed.
# An error with code zero indicates hello success.
err = int(val[1])
if not err: return
self.minfo.error(err);
self.loseConnection()
def xfr_ok(self, val):
# An ok indicates migrate completed successfully, and contains
# the new domain id on the remote system.
dom = int(val[1])
self.minfo.ok(dom)
self.loseConnection()
class MigrateClientFactory(ClientFactory):
def __init__(self, minfo):
ClientFactory.__init__(self)
self.minfo = minfo
def startedConnecting(self, connector):
print 'Started to connect', 'self=', self, 'connector=', connector
def buildProtocol(self, addr):
print 'buildProtocol>', addr
return Migrate(self.minfo)
def clientConnectionLost(self, connector, reason):
print 'clientConnectionLost>', 'connector=', connector, 'reason=', reason
def clientConnectionFailed(self, connector, reason):
print 'clientConnectionFailed>', 'connector=', connector, 'reason=', reason
class XendMigrateInfo:
# states: begin, active, failed, succeeded?
def __init__(self, id, dom, dst):
def __init__(self, id, dom, host, port):
self.id = id
self.state = 'begin'
self.src_host = socket.gethostname()
self.src_dom = dom
self.dst_host = dst
self.dst_port = port
self.dst_dom = None
self.start = 0
self.deferred = defer.Deferred()
def set_state(self, state):
self.state = state
@@ -29,12 +132,33 @@ class XendMigrateInfo:
sxpr = ['migrate', ['id', self.id], ['state', self.state] ]
sxpr_src = ['src', ['host', self.src_host], ['domain', self.src_dom] ]
sxpr.append(sxpr_src)
sxpr_dst = ['dst', ['host', self.dst] ]
sxpr_dst = ['dst', ['host', self.dst_host] ]
if self.dst_dom:
sxpr_dst.append(['domain', self.dst_dom])
sxpr.append(sxpr_dst)
return sxpr
def vmconfig(self):
dominfo = xd.domain_get(self.dom)
if dominfo:
val = return sxp.to_string(dominfo)
else:
val = None
return None
def error(self, err):
self.state = 'error'
def ok(self, dom):
self.state = 'ok'
self.dst_dom = dom
def close(self):
if self.state =='ok':
eserver.inject('xend.migrate.ok', self.sxpr())
else:
self.state = 'error'
eserver.inject('xend.migrate.error', self.sxpr())
class XendMigrate:
# Represents migration in progress.
@@ -84,15 +208,15 @@ class XendMigrate:
def migrate_get(self, id):
return self.migrate.get(id)
def migrate_begin(self, dom, dst):
def migrate_begin(self, dom, host):
# Check dom for existence, not migrating already.
# Create migrate info, tell xend to migrate it?
# - or fork migrate command ourselves?
# Subscribe to migrate notifications (for updating).
id = self.nextid()
info = XenMigrateInfo(id, dom, dst)
info = XenMigrateInfo(id, dom, host, XFRD_PORT)
self._add_migrate(id, info)
return id
mcf = MigrateClientFactory(info)
reactor.connectTCP('localhost', XFRD_PORT, mcf)
return info.deferred
def instance():
global inst
+1 -1
View File
@@ -145,7 +145,7 @@ class XendRoot:
val default value (optional, defaults to None)
returns value
"""
return sxp.child_value(self.config, name, val=val)
return sxp.child_value(self.config, name) or val
def instance():
global inst
+329
View File
@@ -0,0 +1,329 @@
# XDR-style packer/unpacker for sxpr.
#
# string -> [STRING] [len:u16] <len bytes>
# atom -> [ATOM] [len:u16] <len bytes>
# int -> [UINT] [value]
# list -> [LIST] {1 elt}* 0
# null -> [NULL]
# none -> [NONE]
# bool -> [BOOL] { 0:u8 | 1:u8 }
#
# types packed as u16.
#
# So (a b c) -> [LIST] 1 a 1 b 1 c 0
# () -> [LIST] 0
import struct
try:
from cStringIO import StringIO as _StringIO
except ImportError:
from StringIO import StringIO as _StringIO
import types
class Error(Exception):
def __init__(self, msg):
self.msg = msg
def __repr__(self):
return repr(self.msg)
def __str__(self):
return str(self.msg)
class ConversionError(Error):
pass
BOOL_SIZE = 1
BOOL_FMT = '>B'
BYTE_SIZE = 1
BYTE_FMT = '>b'
UBYTE_FMT = '>B'
SHORT_SIZE = 2
SHORT_FMT = '>h'
USHORT_FMT = '>H'
INT_SIZE = 4
INT_FMT = '>l'
UINT_FMT = '>L'
NONE_CODE = 0
NULL_CODE = 1
INT_CODE = 2
STRING_CODE = 3
ATOM_CODE = 4
BOOL_CODE = 5
LIST_CODE = 10
class Packer:
def __init__(self, io=None):
self.reset(io=io)
def reset(self, io=None):
if io is None:
io = _StringIO()
self.io = io
def get_buffer(self):
return self.io.getvalue()
def get_io(self):
return self.io
def struct_pack(self, fmt, x):
try:
self.io.write(struct.pack(fmt, x))
except struct.error, msg:
raise ConversionError, msg
def pack_none(self):
pass
def pack_bool(self, x):
# { '1' | '0' }
print 'bool>', x
if x:
self.io.write('\1')
else:
self.io.write('\0')
def pack_byte(self, x):
self.struct_pack(BYTE_FMT, x & 0xff)
def pack_char(self, x):
print 'char>', x
self.io.write(x)
def pack_ubyte(self, x):
print 'ubyte>', x
self.struct_pack(UBYTE_FMT, x & 0xff)
def pack_ushort(self, x):
print 'ushort>', x
self.struct_pack(USHORT_FMT, x & 0xffff)
def pack_short(self, x):
print 'short>', x
self.struct_pack(SHORT_FMT, x & 0xffff)
def pack_uint(self, x):
print 'uint>', x
self.struct_pack(UINT_FMT, x)
def pack_int(self, x):
print 'int>', x
self.struct_pack(INT_FMT, x)
def pack_uhyper(self, x):
print 'uhyper>', x
self.pack_uint(x>>32 & 0xffffffffL)
self.pack_uint(x & 0xffffffffL)
pack_hyper = pack_uhyper
def pack_fstring(self, n, x):
print 'fstring>', x
self.io.write(x)
pack_fopaque = pack_fstring
def pack_string(self, x):
print 'string>', x
n = len(x)
self.pack_ushort(n)
self.pack_fstring(n, x)
pack_opaque = pack_string
pack_bytes = pack_string
def pack_list(self, x, pack_item):
print 'list>', x
# { '1' <item> }* '0'
for item in x:
self.pack_bool(1)
pack_item(item)
self.pack_bool(0)
def pack_farray(self, x, pack_item):
# <item>*
# Can pass n and check length - but is it worth it?
print 'farray>', list
for item in x:
pack_item(item)
def pack_array(self, x, pack_item):
# n <item>*n
print 'array>', x
self.pack_uint(len(x))
self.pack_farray(x, pack_item)
class Unpacker:
def __init__(self, data):
self.reset(data)
def reset(self, data):
if isinstance(data, types.StringType):
data = _StringIO(data)
self.io = data
def get_bytes(self, n):
if n < 0:
raise ConversionError('negative byte count')
data = self.io.read(n)
return data
def struct_unpack(self, fmt, n):
data = self.get_bytes(n)
try:
return struct.unpack(fmt, data)[0]
except struct.error, msg:
raise ConversionError, msg
def unpack_none(self):
return None
def unpack_bool(self):
return self.struct_unpack(BOOL_FMT, BOOL_SIZE)
def unpack_char(self):
return self.get_bytes(1)[0]
def unpack_byte(self):
return self.struct_unpack(BYTE_FMT, BYTE_SIZE)
def unpack_ubyte(self):
return self.struct_unpack(UBYTE_FMT, BYTE_SIZE)
def unpack_ushort(self):
return self.struct_unpack(USHORT_FMT, SHORT_SIZE)
def unpack_short(self):
return self.struct_unpack(SHORT_FMT, SHORT_SIZE)
def unpack_uint(self):
x = self.struct_unpack(UINT_FMT, UINT_SIZE)
try:
return int(x)
except OverflowError:
return x
def unpack_int(self):
return self.struct_unpack(INT_FMT, INT_SIZE)
def unpack_uhyper(self):
hi = self.unpack_uint()
lo = self.unpack_uint()
return long(hi)<<32 | lo
def unpack_hyper(self):
x = self.unpack_uhyper()
if x >= 0x8000000000000000L:
x = x - 0x10000000000000000L
return x
def unpack_fstring(self, n):
return self.get_bytes(n)
unpack_fopaque = unpack_fstring
def unpack_string(self):
n = self.unpack_ushort()
return self.unpack_fstring(n)
unpack_opaque = unpack_string
unpack_bytes = unpack_string
def unpack_list(self, unpack_item):
list = []
while self.unpack_bool():
list.append(unpack_item())
return list
def unpack_farray(self, n, unpack_item):
list = []
for i in range(n):
list.append(unpack_item())
return list
def unpack_array(self, unpack_item):
n = self.unpack_ushort()
return self.unpack_farray(n, unpack_item)
class SxpPacker(Packer):
pack_code = Packer.pack_ushort
def pack(self, x):
if isinstance(x, types.NoneType):
self.pack_code(NONE_CODE)
self.pack_none()
elif isinstance(x, types.IntType):
self.pack_code(INT_CODE)
self.pack_int(x)
elif isinstance(x, types.StringType):
self.pack_code(STRING_CODE)
self.pack_string(x)
elif isinstance(x, types.ListType):
self.pack_code(LIST_CODE)
self.pack_list(x, self.pack)
else:
raise Error('invalid type ' + str(type(x)))
class SxpUnpacker(Unpacker):
unpack_code = Unpacker.unpack_ushort
def unpack(self):
code = self.unpack_code()
if code == NONE_CODE:
val = self.unpack_none()
elif code == INT_CODE:
val = self.unpack_int()
elif code == BOOL_CODE:
val = self.unpack_bool()
elif code == STRING_CODE:
val = self.unpack_string()
elif code == ATOM_CODE:
val = self.unpack_string()
elif code == LIST_CODE:
val = self.unpack_list(self.unpack)
else:
raise Error('invalid code ' + str(code))
return val
def main():
d = "['vfarm', ['@', ['name', 'vfarm1']], ['memory', 1024], ['image', 'splinux'], ['args', 'root=/dev/nfs ip=dhcp'], [ 1, -1, 1000000]]"
print"> len=", len(d), "d=", d
obj = ['vfarm', ['@', ['name', 'vfarm1']],
['memory', 1024],
['image', 'splinux'],
['args', 'root=/dev/nfs ip=dhcp'],
[ 1, -1, 1000000] ]
print "> obj=", obj
pack = SxpPacker()
pack.pack(obj)
data = pack.get_buffer()
print "> len=", len(data), "data=", data
unpack = SxpUnpacker(data)
obj_unpack = unpack.unpack()
print "> obj=", obj_unpack
#obj = [100,101,102, 999.00234, { 'a': 1, 'b': 2 } ]
#pack.reset()
#pack.pack_item(obj)
#data = pack.get_buffer()
#print "> obj=", obj
#print "> len=", len(data), "data=", data
#unpack.reset(data)
#obj_unpack = unpack.unpack_item()
#print "> obj=", obj_unpack
if __name__ == "__main__":
main()
+1
View File
@@ -8,6 +8,7 @@ import types
import StringIO
from twisted.internet import defer
defer.Deferred.debug = 1
from twisted.internet import reactor
from twisted.web import error
from twisted.web import resource
@@ -23,6 +23,7 @@ from twisted.internet import reactor
from twisted.internet import protocol
from twisted.internet import abstract
from twisted.internet import defer
defer.Deferred.debug = 1
from xen.lowlevel import xu
+5 -1
View File
@@ -27,7 +27,11 @@ class SrvDomain(SrvDir):
return val
def op_shutdown(self, op, req):
val = self.xd.domain_shutdown(self.dom.id)
#val = self.xd.domain_shutdown(self.dom.id)
fn = FormFn(self.xd.domain_shutdown,
[['dom', 'int'],
['reason', 'str']])
val = fn(req.args, {'dom': self.dom.id})
req.setResponseCode(202)
req.setHeader("Location", "%s/.." % req.prePathURL())
return val
+25 -7
View File
@@ -1,5 +1,6 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
import traceback
from StringIO import StringIO
from twisted.protocols import http
@@ -24,6 +25,7 @@ class SrvDomainDir(SrvDir):
val = None
try:
dom = self.xd.domain_get(x)
if not dom: raise KeyError('No such domain')
val = SrvDomain(dom)
except KeyError, ex:
print 'SrvDomainDir>', ex
@@ -38,6 +40,9 @@ class SrvDomainDir(SrvDir):
return v
def op_create(self, op, req):
"""Create a domain.
Expects the domain config in request parameter 'config' in SXP format.
"""
ok = 0
try:
configstring = req.args.get('config')[0]
@@ -48,7 +53,8 @@ class SrvDomainDir(SrvDir):
config = pin.get_val()
ok = 1
except Exception, ex:
print 'op_create>', ex
print 'op_create> Exception in config', ex
traceback.print_exc()
if not ok:
req.setResponseCode(http.BAD_REQUEST, "Invalid configuration")
return "Invalid configuration"
@@ -57,19 +63,20 @@ class SrvDomainDir(SrvDir):
"Invalid configuration")
try:
deferred = self.xd.domain_create(config)
deferred.addCallback(self._cb_op_create, configstring, req)
deferred.addCallback(self._op_create_cb, configstring, req)
deferred.addErrback(self._op_create_err, req)
return deferred
except Exception, ex:
raise
#return ['err', str(ex) ]
#req.setResponseCode(http.BAD_REQUEST, "Error creating domain")
#return str(ex)
print 'op_create> Exception creating domain:'
traceback.print_exc()
req.setResponseCode(http.BAD_REQUEST, "Error creating domain")
return str(ex)
#return error.ErrorPage(http.BAD_REQUEST,
# "Error creating domain",
# str(ex))
def _cb_op_create(self, dominfo, configstring, req):
def _op_create_cb(self, dominfo, configstring, req):
"""Callback to handle deferred domain creation.
"""
dom = dominfo.id
@@ -89,7 +96,16 @@ class SrvDomainDir(SrvDir):
out.close()
return val
def _op_create_err(self, err, req):
"""Callback to handle errors in deferred domain creation.
"""
print 'op_create> Deferred Exception creating domain:', err
req.setResponseCode(http.BAD_REQUEST, "Error creating domain")
return str(err)
def op_restore(self, op, req):
"""Restore a domain from file.
"""
fn = FormFn(self.xd.domain_restore,
[['file', 'str']])
val = fn(req.args)
@@ -131,6 +147,8 @@ class SrvDomainDir(SrvDir):
req.write('</ul>')
def form(self, req):
"""Generate the form(s) for domain dir operations.
"""
req.write('<form method="post" action="%s" enctype="multipart/form-data">'
% req.prePathURL())
req.write('<button type="submit" name="op" value="create">Create Domain</button>')
+93 -61
View File
@@ -1,4 +1,7 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from twisted.internet import defer
defer.Deferred.debug = 1
from xen.xend import sxp
from xen.xend import PrettyPrint
@@ -18,53 +21,78 @@ class BlkifControllerFactory(controller.ControllerFactory):
self.majorTypes = [ CMSG_BLKIF_BE ]
self.subTypes = {
CMSG_BLKIF_BE_CREATE : self.recv_be_create,
CMSG_BLKIF_BE_CONNECT : self.recv_be_connect,
CMSG_BLKIF_BE_VBD_CREATE : self.recv_be_vbd_create,
CMSG_BLKIF_BE_VBD_GROW : self.recv_be_vbd_grow,
CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED: self.recv_be_driver_status_changed,
}
self.attached = 1
self.registerChannel()
def createInstance(self, dom, recreate=0):
d = self.addDeferred()
"""Create a block device controller for a domain.
dom domain
recreate if true it's a recreate (after xend restart)
"""
d = defer.Deferred()
blkif = self.getInstanceByDom(dom)
if blkif:
self.callDeferred(blkif)
d.callback(blkif)
else:
blkif = BlkifController(self, dom)
self.addInstance(blkif)
if recreate:
self.callDeferred(blkif)
d.callback(blkif)
else:
blkif.send_be_create()
d1 = defer.Deferred()
d1.addCallback(self.respond_be_create, d)
d1.addErrback(d.errback)
blkif.send_be_create(response=d1)
return d
def getDomainDevices(self, dom):
"""Get the block devices for a domain.
dom domain
returns devices
"""
blkif = self.getInstanceByDom(dom)
return (blkif and blkif.getDevices()) or []
def getDomainDevice(self, dom, vdev):
"""Get a block device from a domain.
dom domain
vdev device index
returns device
"""
blkif = self.getInstanceByDom(dom)
return (blkif and blkif.getDevice(vdev)) or None
def setControlDomain(self, dom, recreate=0):
"""Set the back-end block device controller domain.
dom domain
recreate if true it's a recreate (after xend restart)
"""
if self.dom == dom: return
self.deregisterChannel()
if not recreate:
self.attached = 0
self.dom = dom
self.registerChannel()
#
#if xend.blkif.be_port:
# xend.blkif.recovery = True
#xend.blkif.be_port = xend.main.port_from_dom(dom)
def getControlDomain(self):
"""Get the back-end block device controller domain.
"""
return self.dom
def reattachDevice(self, dom, vdev):
"""Reattach a device (on changing control domain).
dom domain
vdev device index
"""
blkif = self.getInstanceByDom(dom)
if blkif:
blkif.reattachDevice(vdev)
@@ -83,17 +111,20 @@ class BlkifControllerFactory(controller.ControllerFactory):
return attached
def reattached(self):
"""Notify all block interface we have been reattached
(after changing control domain).
"""
for blkif in self.getInstances():
blkif.reattached()
def recv_be_create(self, msg, req):
#print 'recv_be_create>'
def respond_be_create(self, msg, d):
print 'respond_be_create>'
val = unpackMsg('blkif_be_create_t', msg)
blkif = self.getInstanceByDom(val['domid'])
self.callDeferred(blkif)
d.callback(blkif)
def recv_be_connect(self, msg, req):
#print 'recv_be_create>'
def respond_be_connect(self, msg):
print 'respond_be_connect>', self
val = unpackMsg('blkif_be_connect_t', msg)
blkif = self.getInstanceByDom(val['domid'])
if blkif:
@@ -101,25 +132,30 @@ class BlkifControllerFactory(controller.ControllerFactory):
else:
pass
def recv_be_vbd_create(self, msg, req):
#print 'recv_be_vbd_create>'
def respond_be_vbd_create(self, msg, d):
print 'recv_be_vbd_create>', self
val = unpackMsg('blkif_be_vbd_create_t', msg)
blkif = self.getInstanceByDom(val['domid'])
if blkif:
blkif.send_be_vbd_grow(val['vdevice'])
d1 = defer.Deferred()
d1.addCallback(self.respond_be_vbd_grow, d)
if d: d1.addErrback(d.errback)
blkif.send_be_vbd_grow(val['vdevice'], response=d1)
else:
pass
def recv_be_vbd_grow(self, msg, req):
#print 'recv_be_vbd_grow>'
def respond_be_vbd_grow(self, msg, d):
print 'recv_be_vbd_grow>', self
val = unpackMsg('blkif_be_vbd_grow_t', msg)
# Check status?
if self.attached:
self.callDeferred(0)
if d:
d.callback(0)
else:
self.reattachDevice(val['domid'], val['vdevice'])
def recv_be_driver_status_changed(self, msg, req):
print 'recv_be_driver_status_changed>', self, req
val = unpackMsg('blkif_be_driver_status_changed_t', msg)
status = val['status']
if status == BLKIF_DRIVER_STATUS_UP and not self.attached:
@@ -147,7 +183,6 @@ class BlkDev(controller.Dev):
return val
def destroy(self):
print 'BlkDev>destroy>', self.vdev
PrettyPrint.prettyprint(self.sxpr())
self.controller.send_be_vbd_destroy(self.vdev)
@@ -157,7 +192,6 @@ class BlkifController(controller.Controller):
"""
def __init__(self, factory, dom):
#print 'BlkifController> dom=', dom
controller.Controller.__init__(self, factory, dom)
self.devices = {}
@@ -172,7 +206,6 @@ class BlkifController(controller.Controller):
self.attached = 1
self.evtchn = None
self.registerChannel()
#print 'BlkifController<', 'dom=', self.dom, 'idx=', self.idx
def sxpr(self):
val = ['blkif', ['dom', self.dom]]
@@ -182,11 +215,6 @@ class BlkifController(controller.Controller):
self.evtchn['port2']])
return val
def lostChannel(self):
print 'BlkifController>lostChannel>', 'dom=', self.dom
#self.destroyDevices()
controller.Controller.lostChannel(self)
def getDevices(self):
return self.devices.values()
@@ -201,26 +229,32 @@ class BlkifController(controller.Controller):
def attachDevice(self, vdev, mode, segment, recreate=0):
"""Attach a device to the specified interface.
vdev device index
mode read/write mode
segment segment
recreate if true it's being recreated (after xend restart)
returns deferred
"""
#print 'BlkifController>attach_device>', self.dom, vdev, mode, segment
dev = self.addDevice(vdev, mode, segment)
if not dev: return -1
d = defer.Deferred()
if recreate:
d = defer.Deferred()
d.callback(self)
else:
self.send_be_vbd_create(vdev)
d = self.factory.addDeferred()
d1 = defer.Deferred()
d1.addCallback(self.factory.respond_be_vbd_create, d)
d1.addErrback(d.errback)
self.send_be_vbd_create(vdev, response=d1)
return d
def destroy(self):
print 'BlkifController>destroy> dom=', self.dom
def cb_destroy(val):
self.send_be_destroy()
d = self.factory.addDeferred()
d = defer.Deferred()
d.addCallback(cb_destroy)
self.send_be_disconnect()
#self.destroyDevices()
self.send_be_disconnect(response=d)
def destroyDevices(self):
for dev in self.getDevices():
@@ -232,7 +266,9 @@ class BlkifController(controller.Controller):
self.attached = 0
for dev in self.devices.values():
dev.attached = 0
self.send_be_vbd_create(vdev)
d1 = defer.Deferred()
d1.addCallback(self.factory.respond_be_vbd_create, None)
self.send_be_vbd_create(vdev, response=d1)
def reattachDevice(self, vdev):
"""Reattach a device, when the back-end control domain has changed.
@@ -273,51 +309,47 @@ class BlkifController(controller.Controller):
'blkif_handle' : val['handle'],
'evtchn' : self.evtchn['port1'],
'shmem_frame' : val['shmem_frame'] })
self.factory.writeRequest(msg)
pass
d = defer.Deferred()
d.addCallback(self.factory.respond_be_connect)
self.factory.writeRequest(msg, response=d)
#def recv_fe_interface_status_changed(self, msg, req):
# (hnd, status, chan) = unpackMsg('blkif_fe_interface_status_changed_t', msg)
# print 'recv_fe_interface_status_changed>', hnd, status, chan
# pass
def send_fe_interface_status_changed(self):
def send_fe_interface_status_changed(self, response=None):
msg = packMsg('blkif_fe_interface_status_changed_t',
{ 'handle' : 0,
'status' : BLKIF_INTERFACE_STATUS_CONNECTED,
'evtchn' : self.evtchn['port2'] })
self.writeRequest(msg)
self.writeRequest(msg, response=response)
def send_be_create(self):
def send_be_create(self, response=None):
msg = packMsg('blkif_be_create_t',
{ 'domid' : self.dom,
'blkif_handle' : 0 })
self.factory.writeRequest(msg)
self.factory.writeRequest(msg, response=response)
def send_be_disconnect(self):
def send_be_disconnect(self, response=None):
print '>BlkifController>send_be_disconnect>', 'dom=', self.dom
msg = packMsg('blkif_be_disconnect_t',
{ 'domid' : self.dom,
'blkif_handle' : 0 })
self.factory.writeRequest(msg)
self.factory.writeRequest(msg, response=response)
def send_be_destroy(self):
def send_be_destroy(self, response=None):
print '>BlkifController>send_be_destroy>', 'dom=', self.dom
msg = packMsg('blkif_be_destroy_t',
{ 'domid' : self.dom,
'blkif_handle' : 0 })
self.factory.writeRequest(msg)
self.factory.writeRequest(msg, response=response)
def send_be_vbd_create(self, vdev):
def send_be_vbd_create(self, vdev, response=None):
dev = self.devices[vdev]
msg = packMsg('blkif_be_vbd_create_t',
{ 'domid' : self.dom,
'blkif_handle' : 0,
'vdevice' : dev.vdev,
'readonly' : dev.readonly() })
self.factory.writeRequest(msg)
self.factory.writeRequest(msg, response=response)
def send_be_vbd_grow(self, vdev):
def send_be_vbd_grow(self, vdev, response=None):
dev = self.devices[vdev]
msg = packMsg('blkif_be_vbd_grow_t',
{ 'domid' : self.dom,
@@ -326,9 +358,9 @@ class BlkifController(controller.Controller):
'extent.device' : dev.device,
'extent.sector_start' : dev.start_sector,
'extent.sector_length' : dev.nr_sectors })
self.factory.writeRequest(msg)
self.factory.writeRequest(msg, response=response)
def send_be_vbd_destroy(self, vdev):
def send_be_vbd_destroy(self, vdev, response=None):
print '>BlkifController>send_be_vbd_destroy>', 'dom=', self.dom, 'vdev=', vdev
PrettyPrint.prettyprint(self.sxpr())
dev = self.devices[vdev]
@@ -337,5 +369,5 @@ class BlkifController(controller.Controller):
'blkif_handle' : 0,
'vdevice' : dev.vdev })
del self.devices[vdev]
self.factory.writeRequest(msg)
self.factory.writeRequest(msg, response=response)
+11 -7
View File
@@ -1,3 +1,5 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
from xen.lowlevel import xu
from messages import msgTypeName
@@ -24,14 +26,11 @@ class ChannelFactory:
self.notifier = xu.notifier()
def addChannel(self, channel):
"""Add a channel.
"""Add a channel. Registers with the notifier.
"""
idx = channel.idx
self.channels[idx] = channel
self.notifier.bind(idx)
# Try to wake it up
#self.notifier.unmask(idx)
#channel.notify()
def getChannel(self, idx):
"""Get the channel with the given index (if any).
@@ -40,6 +39,7 @@ class ChannelFactory:
def delChannel(self, idx):
"""Remove the channel with the given index (if any).
Deregisters with the notifier.
"""
if idx in self.channels:
del self.channels[idx]
@@ -174,9 +174,9 @@ class VirqChannel(BaseChannel):
"""Close the channel. Calls lostChannel(self) on all its clients and
channelClosed() on the factory.
"""
for c in self.clients:
for c in self.clients[:]:
c.lostChannel(self)
del self.clients
self.clients = []
BaseChannel.close(self)
def registerClient(self, client):
@@ -238,7 +238,7 @@ class Channel(BaseChannel):
"""
if self.closed: return
self.closed = 1
for d in self.devs:
for d in self.devs[:]:
d.lostChannel()
self.factory.channelClosed(self)
self.devs = []
@@ -288,6 +288,8 @@ class Channel(BaseChannel):
self.getRemotePort()))
def handleNotification(self):
"""Process outstanding messages in repsonse to notification on the port.
"""
if self.closed:
print 'handleNotification> Notification on closed channel', self
return
@@ -299,6 +301,8 @@ class Channel(BaseChannel):
self.notify()
def notify(self):
"""Notify the other end of the port that messages have been processed.
"""
if self.closed: return
self.port.notify()
+57 -38
View File
@@ -1,3 +1,4 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from twisted.internet import reactor
from twisted.internet import protocol
@@ -12,11 +13,6 @@ import controller
from messages import *
from params import *
"""Telnet binary option."""
TRANSMIT_BINARY = '0'
WILL = chr(251)
IAC = chr(255)
class ConsoleProtocol(protocol.Protocol):
"""Asynchronous handler for a console TCP socket.
"""
@@ -36,19 +32,12 @@ class ConsoleProtocol(protocol.Protocol):
self.loseConnection()
return
else:
# KAF: A nice quiet successful connect. Don't bother with telnet
# control sequence -- telnet is not the appropriate protocol here.
# KAF: A nice quiet successful connect.
#self.transport.write("Connected to console %d on domain %d\n"
# % (self.idx, self.controller.dom))
#self.setTelnetTransmitBinary()
eserver.inject('xend.console.connect',
[self.idx, self.addr[0], self.addr[1]])
def setTelnetTransmitBinary(self):
"""Send the sequence to set the telnet TRANSMIT-BINARY option.
"""
self.write(IAC + WILL + TRANSMIT_BINARY)
def dataReceived(self, data):
if self.controller.handleInput(self, data):
self.loseConnection()
@@ -104,11 +93,15 @@ class ConsoleController(controller.Controller):
output and the connected TCP sockets to post console input.
"""
STATUS_NEW = 'new'
STATUS_CLOSED = 'closed'
STATUS_CONNECTED = 'connected'
STATUS_LISTENING = 'listening'
def __init__(self, factory, dom, console_port):
#print 'ConsoleController> dom=', dom, type(dom)
controller.Controller.__init__(self, factory, dom)
self.majorTypes = [ CMSG_CONSOLE ]
self.status = "new"
self.status = self.STATUS_NEW
self.addr = None
self.conn = None
self.rbuf = xu.buffer()
@@ -118,7 +111,6 @@ class ConsoleController(controller.Controller):
self.registerChannel()
self.listener = None
self.listen()
#print 'ConsoleController<', 'dom=', self.dom, 'idx=', self.idx
def sxpr(self):
val =['console',
@@ -136,29 +128,31 @@ class ConsoleController(controller.Controller):
return not (self.closed() or self.rbuf.empty())
def closed(self):
return self.status == 'closed'
return self.status == self.STATUS_CLOSED
def connected(self):
return self.status == 'connected'
return self.status == self.STATUS_CONNECTED
def close(self):
try:
#print 'ConsoleController> close dom=', self.dom
self.status = "closed"
if self.conn:
self.conn.loseConnection()
self.listener.stopListening()
self.deregisterChannel()
self.lostChannel()
except Exception, ex:
print 'ConsoleController>close>', ex
raise
"""Close the console controller.
"""
self.lostChannel()
def lostChannel(self):
"""The channel to the domain has been lost.
Cleanup: disconnect TCP connections and listeners, notify the controller.
"""
self.status = self.STATUS_CLOSED
if self.conn:
self.conn.loseConnection()
self.listener.stopListening()
controller.Controller.lostChannel(self)
def listen(self):
"""Listen for TCP connections to the console port..
"""
if self.closed(): return
self.status = "listening"
self.status = self.STATUS_LISTENING
if self.listener:
#self.listener.startListening()
pass
@@ -167,15 +161,25 @@ class ConsoleController(controller.Controller):
self.listener = reactor.listenTCP(self.console_port, f)
def connect(self, addr, conn):
"""Connect a TCP connection to the console.
Fails if closed or already connected.
addr peer address
conn connection
returns 0 if ok, negative otherwise
"""
if self.closed(): return -1
if self.connected(): return -1
self.addr = addr
self.conn = conn
self.status = "connected"
self.status = self.STATUS_CONNECTED
self.handleOutput()
return 0
def disconnect(self):
"""Disconnect the TCP connection to the console.
"""
if self.conn:
self.conn.loseConnection()
self.addr = None
@@ -183,15 +187,29 @@ class ConsoleController(controller.Controller):
self.listen()
def requestReceived(self, msg, type, subtype):
#print '***Console', self.dom, msg.get_payload()
"""Receive console data from the console channel.
msg console message
type major message type
subtype minor message typ
"""
self.rbuf.write(msg.get_payload())
self.handleOutput()
def responseReceived(self, msg, type, subtype):
"""Handle a response to a request written to the console channel.
Just ignore it because the return values are not interesting.
msg console message
type major message type
subtype minor message typ
"""
pass
def produceRequests(self):
# Send as much pending console data as there is room for.
"""Write pending console data to the console channel.
Writes as much to the channel as it can.
"""
work = 0
while not self.wbuf.empty() and self.channel.writeReady():
msg = xu.message(CMSG_CONSOLE, 0, 0)
@@ -201,7 +219,12 @@ class ConsoleController(controller.Controller):
def handleInput(self, conn, data):
"""Handle some external input aimed at the console.
Called from a TCP connection (conn).
Called from a TCP connection (conn). Ignores the input
if the calling connection (conn) is not the one connected
to the console (self.conn).
conn connection
data input data
"""
if self.closed(): return -1
if conn != self.conn: return 0
@@ -215,18 +238,14 @@ class ConsoleController(controller.Controller):
Sends it to the connected console (if any).
"""
if self.closed():
#print 'Console>handleOutput> closed'
return -1
if not self.conn:
#print 'Console>handleOutput> not connected'
return 0
while not self.rbuf.empty():
try:
#print 'Console>handleOutput> writing...'
bytes = self.conn.write(self.rbuf.peek())
if bytes > 0:
self.rbuf.discard(bytes)
except socket.error, error:
pass
#print 'Console>handleOutput<'
return 0
+163 -34
View File
@@ -1,10 +1,50 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from twisted.internet import defer
defer.Deferred.debug = 1
import channel
from messages import msgTypeName
DEBUG=0
class OutOfOrderError(RuntimeError):
"""Error reported when a response arrives out of order.
"""
pass
class Responder:
"""Handler for a response to a message.
"""
def __init__(self, mid, deferred):
"""Create a responder.
mid message id of response to handle
deferred deferred object holding the callbacks
"""
self.mid = mid
self.deferred = deferred
def responseReceived(self, msg):
if self.deferred.called: return
self.deferred.callback(msg)
def error(self, err):
if self.deferred.called: return
self.deferred.errback(err)
class CtrlMsgRcvr:
"""Abstract class for things that deal with a control interface to a domain.
Instance variables:
dom : the domain we are a control interface for
majorTypes: list of major message types we are interested in
subTypes : mapping of message subtypes to methods
channel : channel to the domain
idx : channel index
"""
@@ -15,50 +55,140 @@ class CtrlMsgRcvr:
self.dom = None
self.channel = None
self.idx = None
self.responders = []
# Timeout (in seconds) for deferreds.
self.timeout = 10
def setTimeout(self, timeout):
self.timeout = timeout
def requestReceived(self, msg, type, subtype):
"""Dispatch a request to handlers.
msg message
type major message type
subtype minor message type
"""
msgid = msg.get_header()['id']
if DEBUG:
print 'requestReceived>', self, msgid, msgTypeName(type, subtype)
method = self.subTypes.get(subtype)
if method:
method(msg, 1)
else:
elif DEBUG:
print ('requestReceived> No handler: Message type %s %d:%d'
% (msgTypeName(type, subtype), type, subtype)), self
def responseReceived(self, msg, type, subtype):
"""Dispatch a response to handlers.
msg message
type major message type
subtype minor message type
"""
msgid = msg.get_header()['id']
if DEBUG:
print 'responseReceived>', self, msgid, msgTypeName(type, subtype)
if self.callResponders(msg):
return
method = self.subTypes.get(subtype)
if method:
method(msg, 0)
else:
elif DEBUG:
print ('responseReceived> No handler: Message type %s %d:%d'
% (msgTypeName(type, subtype), type, subtype)), self
def addResponder(self, mid, deferred):
"""Add a responder for a message id.
The deferred is called with callback(msg) when a response
with the given message id arrives. Responses are expected
to arrive in order of message id. When a response arrives,
waiting responders for messages with lower id have errback
called with an OutOfOrder error.
mid message id of response expected
deferred a Deferred to handle the response
returns Responder
"""
if self.timeout > 0:
deferred.setTimeout(self.timeout)
resp = Responder(mid, deferred)
self.responders.append(resp)
return resp
def callResponders(self, msg):
"""Call any waiting responders for a response message.
msg response message
returns 1 if there was a responder for the message, 0 otherwise
"""
hdr = msg.get_header()
mid = hdr['id']
handled = 0
while self.responders:
resp = self.responders[0]
if resp.mid > mid:
break
self.responders.pop()
if resp.mid < mid:
print 'handleResponse> Out of order:', resp.mid, mid
resp.error(OutOfOrderError())
else:
handled = 1
resp.responseReceived(msg)
break
return handled
def lostChannel(self):
"""Called when the channel to the domain is lost.
"""
pass
def registerChannel(self):
#print 'CtrlMsgRcvr>registerChannel>', self
"""Register interest in our major message types with the
channel to our domain.
"""
self.channel = self.channelFactory.domChannel(self.dom)
self.idx = self.channel.getIndex()
if self.majorTypes:
self.channel.registerDevice(self.majorTypes, self)
def deregisterChannel(self):
#print 'CtrlMsgRcvr>deregisterChannel>', self
"""Deregister interest in our major message types with the
channel to our domain.
"""
if self.channel:
self.channel.deregisterDevice(self)
del self.channel
def produceRequests(self):
"""Produce any queued requests.
return number produced
"""
return 0
def writeRequest(self, msg):
def writeRequest(self, msg, response=None):
"""Write a request to the channel.
msg message
response Deferred to handle the response (optional)
"""
if self.channel:
if DEBUG: print 'CtrlMsgRcvr>writeRequest>', self, msg
if response:
self.addResponder(msg.get_header()['id'], response)
self.channel.writeRequest(msg)
else:
print 'CtrlMsgRcvr>writeRequest>', 'no channel!', self
def writeResponse(self, msg):
"""Write a response to the channel.
"""
if self.channel:
if DEBUG: print 'CtrlMsgRcvr>writeResponse>', self, msg
self.channel.writeResponse(msg)
else:
print 'CtrlMsgRcvr>writeResponse>', 'no channel!', self
@@ -66,6 +196,12 @@ class CtrlMsgRcvr:
class ControllerFactory(CtrlMsgRcvr):
"""Abstract class for factories creating controllers.
Maintains a table of instances.
Instance variables:
instances : mapping of index to controller instance
dlist : list of deferreds
dom : domain
"""
def __init__(self):
@@ -73,55 +209,46 @@ class ControllerFactory(CtrlMsgRcvr):
self.instances = {}
self.dlist = []
self.dom = 0
# Timeout (in seconds) for deferreds.
self.timeout = 10
def addInstance(self, instance):
"""Add a controller instance (under its index).
"""
self.instances[instance.idx] = instance
def getInstance(self, idx):
"""Get a controller instance from its index.
"""
return self.instances.get(idx)
def getInstances(self):
"""Get a list of all controller instances.
"""
return self.instances.values()
def getInstanceByDom(self, dom):
"""Get the controller instance for the given domain.
"""
for inst in self.instances.values():
if inst.dom == dom:
return inst
return None
def delInstance(self, instance):
#print 'ControllerFactory>delInstance>', instance.idx
"""Delete an instance from the table.
"""
if instance.idx in self.instances:
#print 'ControllerFactory>delInstance> remove', instance.idx
del self.instances[instance.idx]
def createInstance(self, dom, recreate=0):
"""Create an instance. Define in a subclass.
"""
raise NotImplementedError()
def instanceClosed(self, instance):
#print 'ControllerFactory>instanceClosed>', instance.idx, instance
"""Callback called when an instance is closed (usually by the instance).
"""
self.delInstance(instance)
def addDeferred(self):
d = defer.Deferred()
if self.timeout > 0:
# The deferred will error if not called before timeout.
d.setTimeout(self.timeout)
self.dlist.append(d)
return d
def callDeferred(self, *args):
if self.dlist:
d = self.dlist.pop(0)
d.callback(*args)
def errDeferred(self, *args):
if self.dlist:
d = self.dlist.pop(0)
d.errback(*args)
class Controller(CtrlMsgRcvr):
"""Abstract class for a device controller attached to a domain.
"""
@@ -134,15 +261,20 @@ class Controller(CtrlMsgRcvr):
self.idx = None
def close(self):
self.deregisterChannel()
"""Close the controller.
"""
self.lostChannel()
def lostChannel(self):
#print 'Controller>lostChannel>', self, self.factory
"""The controller channel has been lost.
"""
self.deregisterChannel()
self.factory.instanceClosed(self)
class Dev:
"""Abstract class for a device attached to a device controller.
"""
def __init__(self, controller):
self.controller = controller
self.props = {}
@@ -160,9 +292,6 @@ class Dev:
if k in self.props:
del self.props[k]
#def __repr__(self):
# return str(self.sxpr())
def sxpr(self):
raise NotImplementedError()
-269
View File
@@ -1,269 +0,0 @@
import struct
class Struct:
maxDepth = 10
base = ['x', 'B', 'H', 'I', 'L', 'Q', 'c', 'h', 'i', 'l', 'q', ]
sizes = {'B': 1,
'H': 2,
'I': 4,
'L': 4,
'Q': 8,
'c': 1,
'h': 2,
'i': 4,
'l': 4,
'q': 8,
'x': 1,
}
formats = {
'int8' : 'B',
'int16' : 'H',
'int32' : 'I',
'int64' : 'Q',
'u8' : 'B',
'u16' : 'H',
'u32' : 'I',
'u64' : 'Q'
}
def typedef(self, name, val):
self.formats[name] = val
def struct(self, name, *f):
self.typedef(name, StructInfo(self, f))
def getType(self, name):
return self.formats[name]
def format(self, ty):
d = 0
f = ty
while d < self.maxDepth:
d += 1
f = self.formats[f]
if isinstance(f, StructInfo):
return f.format()
if f in self.base:
return f
return -1
def alignedformat(self, ty):
fmt = self.format(ty)
#print 'alignedformat> %s |%s|' %(ty, fmt)
afmt = self.align(fmt)
#print 'alignedformat< %s |%s| |%s|' % (ty, fmt, afmt)
return afmt
def align(self, fmt):
n1 = 0
afmt = ''
for a in fmt:
n2 = self.getSize(a)
m = n1 % n2
if m:
d = (n2 - m)
afmt += 'x' * d
n1 += d
afmt += a
n1 += n2
return afmt
def fmtsize(self, fmt):
s = 0
for f in fmt:
s += self.getSize(f)
return s
def getSize(self, f):
return self.sizes[f]
def pack(self, ty, data):
return self.getType(ty).pack(data)
def unpack(self, ty, data):
return self.getType(ty).unpack(data)
def show(self):
l = self.formats.keys()
l.sort()
for v in l:
print "%-35s %-10s %s" % (v, self.format(v), self.alignedformat(v))
class StructInfo:
def __init__(self, s, f):
self.fmt = None
self.structs = s
self.fields = f
def alignedformat(self):
if self.afmt: return self.afmt
self.afmt = self.structs.align(self.format())
return self.afmt
def format(self):
if self.fmt: return self.fmt
fmt = ""
for (ty, name) in self.fields:
fmt += self.formatString(ty)
self.fmt = fmt
return fmt
def formatString(self, ty):
if ty in self.fields:
ty = self.fields[ty]
return self.structs.format(ty)
def pack(self, *args):
return struct.pack(self.alignedformat(), *args)
def unpack(self, data):
return struct.unpack(self.alignedformat(), data)
types = Struct()
types.typedef('short' , 'h')
types.typedef('int' , 'i')
types.typedef('long' , 'l')
types.typedef('unsigned short', 'H')
types.typedef('unsigned int' , 'I')
types.typedef('unsigned long' , 'L')
types.typedef('domid_t' , 'u64')
types.typedef('blkif_vdev_t' , 'u16')
types.typedef('blkif_pdev_t' , 'u16')
types.typedef('blkif_sector_t', 'u64')
types.struct('u8[6]',
('u8', 'a1'),
('u8', 'a2'),
('u8', 'a3'),
('u8', 'a4'),
('u8', 'a5'),
('u8', 'a6'))
types.struct('blkif_fe_interface_status_changed_t',
('unsigned int', 'handle'),
('unsigned int', 'status'),
('unsigned int', 'evtchn'))
types.struct('blkif_fe_driver_status_changed_t',
('unsigned int', 'status'),
('unsigned int', 'nr_interfaces'))
types.struct('blkif_fe_interface_connect_t',
('unsigned int' , 'handle'),
('unsigned long', 'shmem_frame'))
types.struct('blkif_fe_interface_disconnect_t',
('unsigned int', 'handle'))
types.struct('blkif_extent_t',
('blkif_pdev_t' , 'device'),
('blkif_sector_t', 'sector_start'),
('blkif_sector_t', 'sector_length'))
types.struct('blkif_be_create_t',
('domid_t' , 'domid'),
('unsigned int', 'blkif_handle'),
('unsigned int', 'status'))
types.struct('blkif_be_destroy_t',
('domid_t' , 'domid'),
('unsigned int', 'blkif_handle'),
('unsigned int', 'status'))
types.struct('blkif_be_connect_t',
('domid_t' , 'domid'),
('unsigned int' , 'blkif_handle'),
('unsigned int' , 'evtchn'),
('unsigned long', 'shmem_frame'),
('unsigned int' , 'status'))
types.struct('blkif_be_disconnect_t',
('domid_t' , 'domid'),
('unsigned int', 'blkif_handle'),
('unsigned int', 'status'))
types.struct('blkif_be_vbd_create_t',
('domid_t' , 'domid'), #Q
('unsigned int', 'blkif_handle'), #I
('blkif_vdev_t', 'vdevice'), #H
('int' , 'readonly'), #i
('unsigned int', 'status')) #I
types.struct('blkif_be_vbd_destroy_t',
('domid_t' , 'domid'),
('unsigned int', 'blkif_handle'),
('blkif_vdev_t', 'vdevice'),
('unsigned int', 'status'))
types.struct('blkif_be_vbd_grow_t',
('domid_t' , 'domid'), #Q
('unsigned int' , 'blkif_handle'), #I
('blkif_vdev_t' , 'vdevice'), #H
('blkif_extent_t', 'extent'), #HQQ
('unsigned int' , 'status')) #I
types.struct('blkif_be_vbd_shrink_t',
('domid_t' , 'domid'),
('unsigned int', 'blkif_handle'),
('blkif_vdev_t', 'vdevice'),
('unsigned int', 'status'))
types.struct('blkif_be_driver_status_changed_t',
('unsigned int', 'status'),
('unsigned int', 'nr_interfaces'))
types.struct('netif_fe_interface_status_changed_t',
('unsigned int', 'handle'),
('unsigned int', 'status'),
('unsigned int', 'evtchn'),
('u8[6]', 'mac'))
types.struct('netif_fe_driver_status_changed_t',
('unsigned int', 'status'),
('unsigned int', 'nr_interfaces'))
types.struct('netif_fe_interface_connect_t',
('unsigned int', 'handle'),
('unsigned long', 'tx_shmem_frame'),
('unsigned long', 'rx_shmem_frame'))
types.struct('netif_fe_interface_disconnect_t',
('unsigned int', 'handle'))
types.struct('netif_be_create_t',
('domid_t' , 'domid'),
('unsigned int', 'netif_handle'),
('u8[6]' , 'mac'),
('unsigned int', 'status'))
types.struct('netif_be_destroy_t',
('domid_t' , 'domid'),
('unsigned int', 'netif_handle'),
('unsigned int', 'status'))
types.struct('netif_be_connect_t',
('domid_t' , 'domid'),
('unsigned int' , 'netif_handle'),
('unsigned int' , 'evtchn'),
('unsigned long', 'tx_shmem_frame'),
('unsigned long', 'rx_shmem_frame'),
('unsigned int' , 'status'))
types.struct('netif_be_disconnect_t',
('domid_t' , 'domid'),
('unsigned int', 'netif_handle'),
('unsigned int', 'status'))
types.struct('netif_be_driver_status_changed_t',
('unsigned int', 'status'),
('unsigned int', 'nr_interfaces'))
if 1 or __name__ == "__main__":
types.show()
+21
View File
@@ -1,3 +1,5 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
import channel
import controller
from messages import *
@@ -7,11 +9,23 @@ class DomainControllerFactory(controller.ControllerFactory):
"""
def createInstance(self, dom):
"""Create a domain controller.
dom domain
returns domain controller
"""
d = DomainController(self, dom)
self.addInstance(d)
return d
def getInstanceByDom(self, dom):
"""Get a domain controller for a domain, creating if necessary.
dom domain
returns domain controller
"""
for inst in self.instances.values():
if inst.dom == dom:
return inst
@@ -21,8 +35,11 @@ class DomainControllerFactory(controller.ControllerFactory):
class DomainController(controller.Controller):
"""Generic controller for a domain.
Used for domain shutdown.
"""
"""Map shutdown reasons to the message type to use.
"""
reasons = {'poweroff' : 'shutdown_poweroff_t',
'reboot' : 'shutdown_reboot_t',
'suspend' : 'shutdown_suspend_t' }
@@ -34,6 +51,10 @@ class DomainController(controller.Controller):
print 'DomainController>', self, self.channel, self.idx
def shutdown(self, reason):
"""Shutdown a domain.
reason shutdown reason
"""
msgtype = self.reasons.get(reason)
if not msgtype:
raise ValueError('invalid reason:' + reason)
+38 -3
View File
@@ -148,6 +148,9 @@ netif_formats = {
msg_formats.update(netif_formats)
#============================================================================
# Domain shutdown message types.
#============================================================================
CMSG_SHUTDOWN = 6
CMSG_SHUTDOWN_POWEROFF = 0
@@ -176,8 +179,23 @@ msg_formats.update(shutdown_formats)
class Msg:
pass
_next_msgid = 0
def nextid():
global _next_msgid
return ++_next_msgid
def packMsg(ty, params):
if DEBUG: print '>packMsg', ty, params
"""Pack a message.
Any 'mac' parameter is passed in as an int[6] array and converted.
ty message type name
params message parameter dict
returns xu message
"""
msgid = nextid()
if DEBUG: print '>packMsg', msgid, ty, params
(major, minor) = msg_formats[ty]
args = {}
for (k, v) in params.items():
@@ -189,11 +207,19 @@ def packMsg(ty, params):
if DEBUG:
for (k, v) in args.items():
print 'packMsg>', k, v, type(v)
msgid = 0
msg = xu.message(major, minor, msgid, args)
return msg
def unpackMsg(ty, msg):
"""Unpack a message.
Any mac addresses in the message are converted to int[6] array
in the return dict.
ty message type
msg xu message
returns parameter dict
"""
args = msg.get_payload()
mac = [0, 0, 0, 0, 0, 0]
macs = []
@@ -208,10 +234,19 @@ def unpackMsg(ty, msg):
args['mac'] = mac
for k in macs:
del args[k]
if DEBUG: print '<unpackMsg', ty, args
if DEBUG:
msgid = msg.get_header()['id']
print '<unpackMsg', msgid, ty, args
return args
def msgTypeName(ty, subty):
"""Convert a message type, subtype pair (ints) to a message type name (string).
ty integer message type
subty integer message subtype
returns message type name (or None)
"""
for (name, info) in msg_formats.items():
if info[0] == ty and info[1] == subty:
return name
+94 -64
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
import random
from twisted.internet import defer
defer.Deferred.debug = 1
from xen.xend import sxp
from xen.xend import PrettyPrint
@@ -21,8 +24,8 @@ class NetifControllerFactory(controller.ControllerFactory):
self.majorTypes = [ CMSG_NETIF_BE ]
self.subTypes = {
CMSG_NETIF_BE_CREATE : self.recv_be_create,
CMSG_NETIF_BE_CONNECT: self.recv_be_connect,
#CMSG_NETIF_BE_CREATE : self.recv_be_create,
#CMSG_NETIF_BE_CONNECT: self.recv_be_connect,
CMSG_NETIF_BE_DRIVER_STATUS_CHANGED: self.recv_be_driver_status_changed,
}
self.attached = 1
@@ -30,8 +33,12 @@ class NetifControllerFactory(controller.ControllerFactory):
def createInstance(self, dom, recreate=0):
"""Create or find the network interface controller for a domain.
dom domain
recreate if true this is a recreate (xend restarted)
returns netif controller
"""
#print 'netif>createInstance> dom=', dom
netif = self.getInstanceByDom(dom)
if netif is None:
netif = NetifController(self, dom)
@@ -39,15 +46,31 @@ class NetifControllerFactory(controller.ControllerFactory):
return netif
def getDomainDevices(self, dom):
"""Get the network device controllers for a domain.
dom domain
returns netif controller
"""
netif = self.getInstanceByDom(dom)
return (netif and netif.getDevices()) or []
def getDomainDevice(self, dom, vif):
"""Get a virtual network interface device for a domain.
dom domain
vif virtual interface index
returns NetDev
"""
netif = self.getInstanceByDom(dom)
return (netif and netif.getDevice(vif)) or None
def setControlDomain(self, dom, recreate=0):
"""Set the 'back-end' device driver domain.
dom domain
recreate if true this is a recreate (xend restarted)
"""
if self.dom == dom: return
self.deregisterChannel()
@@ -55,19 +78,13 @@ class NetifControllerFactory(controller.ControllerFactory):
self.attached = 0
self.dom = dom
self.registerChannel()
#
#if xend.netif.be_port.remote_dom != 0:
# xend.netif.recovery = True
# xend.netif.be_port = xend.main.port_from_dom(dom)
#
def getControlDomain(self):
"""Get the domain id of the back-end control domain.
"""
return self.dom
def recv_be_create(self, msg, req):
self.callDeferred(0)
def recv_be_connect(self, msg, req):
def respond_be_connect(self, msg):
val = unpackMsg('netif_be_connect_t', msg)
dom = val['domid']
vif = val['netif_handle']
@@ -75,7 +92,7 @@ class NetifControllerFactory(controller.ControllerFactory):
if netif:
netif.send_interface_connected(vif)
else:
print "recv_be_connect> unknown vif=", vif
print "respond_be_connect> unknown vif=", vif
pass
def recv_be_driver_status_changed(self, msg, req):
@@ -88,23 +105,6 @@ class NetifControllerFactory(controller.ControllerFactory):
netif.reattach_devices()
self.attached = 1
## pl = msg.get_payload()
## status = pl['status']
## if status == NETIF_DRIVER_STATUS_UP:
## if xend.netif.recovery:
## print "New netif backend now UP, notifying guests:"
## for netif_key in interface.list.keys():
## netif = interface.list[netif_key]
## netif.create()
## print " Notifying %d" % netif.dom
## msg = xu.message(
## CMSG_NETIF_FE,
## CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED, 0,
## { 'handle' : 0, 'status' : 1 })
## netif.ctrlif_tx_req(xend.main.port_from_dom(netif.dom),msg)
## print "Done notifying guests"
## recovery = False
class NetDev(controller.Dev):
"""Info record for a network device.
"""
@@ -130,9 +130,13 @@ class NetDev(controller.Dev):
return val
def get_vifname(self):
"""Get the virtual interface device name.
"""
return "vif%d.%d" % (self.controller.dom, self.vif)
def get_mac(self):
"""Get the MAC address as a string.
"""
return ':'.join(map(lambda x: "%x" % x, self.mac))
def vifctl_params(self):
@@ -141,23 +145,31 @@ class NetDev(controller.Dev):
'ipaddr': self.ipaddr }
def up(self, bridge=None, ipaddr=[]):
"""Bring the device up.
bridge ethernet bridge to connect to
ipaddr list of ipaddrs to filter using iptables
"""
self.bridge = bridge
self.ipaddr = ipaddr
Vifctl.up(self.get_vifname(), **self.vifctl_params())
def down(self):
"""Bring the device down.
"""
Vifctl.down(self.get_vifname(), **self.vifctl_params())
def destroy(self):
"""Destroy the device's resources and disconnect from the back-end
device controller.
"""
def cb_destroy(val):
self.controller.send_be_destroy(self.vif)
print 'NetDev>destroy>', 'vif=', self.vif
PrettyPrint.prettyprint(self.sxpr())
self.down()
d = self.controller.factory.addDeferred()
#d = self.controller.factory.addDeferred()
d = defer.Deferred()
d.addCallback(cb_destroy)
self.controller.send_be_disconnect(self.vif)
#self.controller.send_be_destroy(self.vif)
self.controller.send_be_disconnect(self.vif, response=d)
class NetifController(controller.Controller):
@@ -165,7 +177,6 @@ class NetifController(controller.Controller):
"""
def __init__(self, factory, dom):
#print 'NetifController> dom=', dom
controller.Controller.__init__(self, factory, dom)
self.devices = {}
@@ -178,21 +189,23 @@ class NetifController(controller.Controller):
self.recv_fe_interface_connect,
}
self.registerChannel()
#print 'NetifController<', 'dom=', self.dom, 'idx=', self.idx
def sxpr(self):
val = ['netif', ['dom', self.dom]]
return val
def randomMAC(self):
# VIFs get a random MAC address with a "special" vendor id.
#
# NB. The vendor is currently an "obsolete" one that used to belong
# to DEC (AA-00-00). Using it is probably a bit rude :-)
#
# NB2. The first bit of the first random octet is set to zero for
# all dynamic MAC addresses. This may allow us to manually specify
# MAC addresses for some VIFs with no fear of clashes.
"""Generate a random MAC address.
Uses OUI (Organizationally Unique Identifier) AA:00:00, an
unassigned one that used to belong to DEC. The OUI list is
available at 'standards.ieee.org'.
The remaining 3 fields are random, with the first bit of the first
random field set 0.
returns array of 6 ints
"""
mac = [ 0xaa, 0x00, 0x00,
random.randint(0x00, 0x7f),
random.randint(0x00, 0xff),
@@ -200,29 +213,46 @@ class NetifController(controller.Controller):
return mac
def lostChannel(self):
print 'NetifController>lostChannel>', 'dom=', self.dom
#self.destroyDevices()
"""Method called when the channel has been lost.
"""
controller.Controller.lostChannel(self)
def getDevices(self):
"""Get a list of the devices.
"""
return self.devices.values()
def getDevice(self, vif):
"""Get a device.
vif device index
returns device (or None)
"""
return self.devices.get(vif)
def addDevice(self, vif, vmac):
"""Add a network interface. If vmac is None a random MAC is
assigned. If specified, vmac must be a string of the form
XX:XX:XX:XX:XX where X is hex digit.
vif device index
vmac device MAC
returns device
"""
if vmac is None:
mac = self.randomMAC()
else:
mac = [ int(x, 16) for x in vmac.split(':') ]
if len(mac) != 6: raise ValueError("invalid mac")
#print "attach_device>", "vif=", vif, "mac=", mac
dev = NetDev(self, vif, mac)
self.devices[vif] = dev
return dev
def destroy(self):
print 'NetifController>destroy>', 'dom=', self.dom
"""Destroy the controller and all devices.
"""
self.destroyDevices()
def destroyDevices(self):
@@ -237,20 +267,19 @@ class NetifController(controller.Controller):
@param vmac mac address (string)
"""
self.addDevice(vif, vmac)
d = defer.Deferred()
if recreate:
d = defer.Deferred()
d.callback(self)
else:
d = self.factory.addDeferred()
self.send_be_create(vif)
self.send_be_create(vif, response=d)
return d
def reattach_devices(self):
"""Reattach all devices when the back-end control domain has changed.
"""
d = self.factory.addDeferred()
#d = self.factory.addDeferred()
self.send_be_create(vif)
self.attach_fe_devices(0)
self.attach_fe_devices()
def attach_fe_devices(self):
for dev in self.devices.values():
@@ -279,38 +308,39 @@ class NetifController(controller.Controller):
'evtchn' : dev.evtchn['port1'],
'tx_shmem_frame' : val['tx_shmem_frame'],
'rx_shmem_frame' : val['rx_shmem_frame'] })
self.factory.writeRequest(msg)
d = defer.Deferred()
d.addCallback(self.factory.respond_be_connect)
self.factory.writeRequest(msg, response=d)
def send_interface_connected(self, vif):
def send_interface_connected(self, vif, response=None):
dev = self.devices[vif]
msg = packMsg('netif_fe_interface_status_changed_t',
{ 'handle' : dev.vif,
'status' : NETIF_INTERFACE_STATUS_CONNECTED,
'evtchn' : dev.evtchn['port2'],
'mac' : dev.mac })
self.writeRequest(msg)
self.writeRequest(msg, response=response)
def send_be_create(self, vif):
def send_be_create(self, vif, response=None):
dev = self.devices[vif]
msg = packMsg('netif_be_create_t',
{ 'domid' : self.dom,
'netif_handle' : dev.vif,
'mac' : dev.mac })
self.factory.writeRequest(msg)
self.factory.writeRequest(msg, response=response)
def send_be_disconnect(self, vif):
def send_be_disconnect(self, vif, response=None):
dev = self.devices[vif]
msg = packMsg('netif_be_disconnect_t',
{ 'domid' : self.dom,
'netif_handle' : dev.vif })
self.factory.writeRequest(msg)
self.factory.writeRequest(msg, response=response)
def send_be_destroy(self, vif):
print 'NetifController>send_be_destroy>', 'dom=', self.dom, 'vif=', vif
def send_be_destroy(self, vif, response=None):
PrettyPrint.prettyprint(self.sxpr())
dev = self.devices[vif]
del self.devices[vif]
msg = packMsg('netif_be_destroy_t',
{ 'domid' : self.dom,
'netif_handle' : vif })
self.factory.writeRequest(msg)
self.factory.writeRequest(msg, response=response)
+73 -463
View File
@@ -21,56 +21,19 @@ from StringIO import StringIO
__all__ = [
"mime_type",
"ParseError",
"Parser",
"atomp",
"show",
"show_xml",
"elementp",
"Parser",
"show",
"name",
"attributes",
"attribute",
"children",
"child",
"child_at",
"child0",
"child1",
"child2",
"child3",
"child4",
"child_value",
"has_id",
"with_id",
"child_with_id",
"elements",
"to_string",
"from_string",
"all_from_string",
"parse",
]
mime_type = "application/sxp"
escapes = {
'a': '\a',
'b': '\b',
't': '\t',
'n': '\n',
'v': '\v',
'f': '\f',
'r': '\r',
'\\': '\\',
'\'': '\'',
'\"': '\"'}
k_list_open = "("
k_list_close = ")"
k_attr_open = "@"
k_eval = "!"
escapes_rev = {}
for k in escapes:
escapes_rev[escapes[k]] = k
class ParseError(StandardError):
def __init__(self, parser, value):
@@ -86,7 +49,6 @@ class ParserState:
self.parent = parent
self.buf = ''
self.val = []
self.delim = None
self.fn = fn
def push(self, fn):
@@ -95,28 +57,19 @@ class ParserState:
class Parser:
def __init__(self):
self.error = sys.stderr
self.reset()
def reset(self):
self.val = []
self.eof = 0
self.err = 0
self.line_no = 0
self.char_no = 0
self.state = None
self.state = self.start_state = ParserState(self.state_start)
def push_state(self, fn):
self.state = self.state.push(fn)
def pop_state(self):
val = self.state
self.state = self.state.parent
if self.state and self.state.fn == self.state_start:
# Return to start state - produce the value.
self.val += self.state.val
self.state.val = []
return val
def in_class(self, c, s):
return s.find(c) >= 0
@@ -136,12 +89,6 @@ class Parser:
def in_printable_class(self, c):
return self.in_class(c, string.printable)
def set_error_stream(self, error):
self.error = error
def has_error(self):
return self.err > 0
def at_eof(self):
return self.eof
@@ -166,439 +113,131 @@ class Parser:
self.char_no += 1
if self.state is None:
self.begin_start(None)
self.state = ParserState(self.state_start)
self.state.fn(c)
def ready(self):
return len(self.val) > 0
return len(self.start_state.val) > 0
def get_val(self):
v = self.val[0]
self.val = self.val[1:]
v = self.start_state.val[0]
self.start_state.val = self.start_state.val[1:]
return v
def get_all(self):
return self.val
return self.start_state.val
def begin_start(self, c):
self.state = ParserState(self.state_start)
def end_start(self):
self.val += self.state.val
self.pop_state()
def state_start(self, c):
if self.at_eof():
self.end_start()
elif self.in_space_class(c):
if self.at_eof() or self.in_space_class(c):
pass
elif self.in_comment_class(c):
self.begin_comment(c)
elif c == k_list_open:
self.begin_list(c)
elif c == k_list_close:
self.push_state(self.state_comment)
elif c == '(':
self.push_state(self.state_list)
elif c == ')':
raise ParseError(self, "syntax error: "+c)
elif self.in_string_quote_class(c):
self.begin_string(c)
self.push_state(self.state_string)
self.state.buf = c
elif self.in_printable_class(c):
self.begin_atom(c)
self.push_state(self.state_atom)
self.state.buf = c
elif c == chr(4):
# ctrl-D, EOT: end-of-text.
self.input_eof()
else:
raise ParseError(self, "invalid character: code %d" % ord(c))
def begin_comment(self, c):
self.push_state(self.state_comment)
self.state.buf += c
def end_comment(self):
self.pop_state()
def state_comment(self, c):
if c == '\n' or self.at_eof():
self.end_comment()
else:
self.state.buf += c
self.pop_state()
def begin_string(self, c):
self.push_state(self.state_string)
self.state.delim = c
def end_string(self):
val = self.state.buf
self.state.parent.val.append(val)
self.pop_state()
def state_string(self, c):
if self.at_eof():
raise ParseError(self, "unexpected EOF")
elif c == self.state.delim:
self.end_string()
elif c == '\\':
self.push_state(self.state_escape)
else:
self.state.buf += c
def state_escape(self, c):
if self.at_eof():
raise ParseError(self, "unexpected EOF")
d = escapes.get(c)
if d:
self.state.parent.buf += d
self.state.buf += c
# Look out for non-escaped end delimiter
if self.state.buf[0] == c and self.state.buf[-2] != '\\':
try: # parse escape sequences but fall back to something simple
val = eval(compile(self.state.buf,'','eval'))
except:
val = self.state.buf[1:-1] # just strip the delimiters
self.state.parent.val.append(val)
self.pop_state()
elif c == 'x':
self.state.fn = self.state_hex
self.state.val = 0
else:
self.state.fn = self.state_octal
self.state.val = 0
self.input_char(c)
def state_octal(self, c):
def octaldigit(c):
self.state.val *= 8
self.state.val += ord(c) - ord('0')
self.state.buf += c
if self.state.val < 0 or self.state.val > 0xff:
raise ParseError(self, "invalid octal escape: out of range " + self.state.buf)
if len(self.state.buf) == 3:
octaldone()
def octaldone():
d = chr(self.state.val)
self.state.parent.buf += d
self.pop_state()
if self.at_eof():
raise ParseError(self, "unexpected EOF")
elif '0' <= c <= '7':
octaldigit(c)
elif len(self.buf):
octaldone()
self.input_char(c)
def state_hex(self, c):
def hexdone():
d = chr(self.state.val)
self.state.parent.buf += d
self.pop_state()
def hexdigit(c, d):
self.state.val *= 16
self.state.val += ord(c) - ord(d)
self.state.buf += c
if self.state.val < 0 or self.state.val > 0xff:
raise ParseError(self, "invalid hex escape: out of range " + self.state.buf)
if len(self.state.buf) == 2:
hexdone()
if self.at_eof():
raise ParseError(self, "unexpected EOF")
elif '0' <= c <= '9':
hexdigit(c, '0')
elif 'A' <= c <= 'F':
hexdigit(c, 'A')
elif 'a' <= c <= 'f':
hexdigit(c, 'a')
elif len(buf):
hexdone()
self.input_char(c)
def begin_atom(self, c):
self.push_state(self.state_atom)
self.state.buf = c
def end_atom(self):
val = self.state.buf
self.state.parent.val.append(val)
self.pop_state()
def state_atom(self, c):
if self.at_eof():
self.end_atom()
elif (self.is_separator(c) or
self.in_space_class(c) or
self.in_comment_class(c)):
self.end_atom()
self.input_char(c)
if (self.at_eof() or
self.is_separator(c) or
self.in_space_class(c) or
self.in_comment_class(c)):
val = self.state.buf
self.state.parent.val.append(val)
self.pop_state()
if not self.at_eof():
self.input_char(c)
else:
self.state.buf += c
def begin_list(self, c):
self.push_state(self.state_list)
def end_list(self):
val = self.state.val
self.state.parent.val.append(val)
self.pop_state()
def state_list(self, c):
if self.at_eof():
raise ParseError(self, "unexpected EOF")
elif c == k_list_close:
self.end_list()
elif c == ')':
val = self.state.val
self.state.parent.val.append(val)
self.pop_state()
else:
self.state_start(c)
def atomp(sxpr):
"""Check if an sxpr is an atom.
"""
if sxpr.isalnum() or sxpr == '@':
return 1
for c in sxpr:
if c in string.whitespace: return 0
if c in '"\'\\(){}[]<>$#&%^': return 0
if c in string.ascii_letters: continue
if c in string.digits: continue
if c in '.-_:/~': continue
return 0
return 1
def show(sxpr, out=sys.stdout):
"""Print an sxpr in bracketed (lisp-style) syntax.
"""
if isinstance(sxpr, types.ListType):
out.write(k_list_open)
i = 0
out.write('(')
for x in sxpr:
if i: out.write(' ')
show(x, out)
i += 1
out.write(k_list_close)
elif isinstance(sxpr, types.StringType) and atomp(sxpr):
out.write(sxpr)
out.write(' ')
out.write(')')
else:
#out.write("'" + str(sxpr) + "'")
out.write(repr(str(sxpr)))
def show_xml(sxpr, out=sys.stdout):
"""Print an sxpr in XML syntax.
"""
if isinstance(sxpr, types.ListType):
element = name(sxpr)
out.write('<%s' % element)
for attr in attributes(sxpr):
out.write(' %s=%s' % (attr[0], attr[1]))
out.write('>')
i = 0
for x in children(sxpr):
if i: out.write(' ')
show_xml(x, out)
i += 1
out.write('</%s>' % element)
elif isinstance(sxpr, types.StringType) and atomp(sxpr):
out.write(sxpr)
else:
out.write(str(sxpr))
def elementp(sxpr, elt=None):
"""Check if an sxpr is an element of the given type.
sxpr sxpr
elt element type
"""
return (isinstance(sxpr, types.ListType)
and len(sxpr)
and (None == elt or sxpr[0] == elt))
def name(sxpr):
"""Get the element name of an sxpr.
If the sxpr is not an element (i.e. it's an atomic value) its name
is None.
sxpr
returns name (None if not an element).
"""Get the element name of an sxpr, or None if a bad sxpr.
"""
val = None
if isinstance(sxpr, types.StringType):
val = sxpr
elif isinstance(sxpr, types.ListType) and len(sxpr):
val = sxpr[0]
return val
def attributes(sxpr):
"""Get the attribute list of an sxpr.
sxpr
returns attribute list
"""
val = []
if isinstance(sxpr, types.ListType) and len(sxpr) > 1:
attr = sxpr[1]
if elementp(attr, k_attr_open):
val = attr[1:]
return val
def attribute(sxpr, key, val=None):
"""Get an attribute of an sxpr.
sxpr sxpr
key attribute key
val default value (default None)
returns attribute value
"""
for x in attributes(sxpr):
if x[0] == key:
val = x[1]
break
return val
return sxpr
if isinstance(sxpr, types.ListType) and len(sxpr):
return sxpr[0]
return None
def children(sxpr, elt=None):
"""Get children of an sxpr.
sxpr sxpr
elt optional element type to filter by
returns children (filtered by elt if specified)
"""Get children of an s-expression @sxpr, optionally filtered by
element type @elt.
"""
val = []
if isinstance(sxpr, types.ListType) and len(sxpr) > 1:
i = 1
x = sxpr[i]
if elementp(x, k_attr_open):
i += 1
val = sxpr[i : ]
if not isinstance(sxpr, types.ListType): return []
val = filter(lambda x: isinstance(x, types.ListType) and len(x) > 0, sxpr)
if elt:
def iselt(x):
return elementp(x, elt)
val = filter(iselt, val)
val = filter(lambda x,y=elt: x[0] == y, val)
return val
def child(sxpr, elt, val=None):
"""Get the first child of the given element type.
sxpr sxpr
elt element type
val default value
def child(sxpr, elt=None, idx=0):
"""Get the @idx'th child of the optional filtering type @elt in @sxpr.
"""
for x in children(sxpr):
if elementp(x, elt):
val = x
break
return val
x = children(sxpr, elt)
if len(x) > idx:
return x[idx]
return None
def child_at(sxpr, index, val=None):
"""Get the child at the given index (zero-based).
sxpr sxpr
index index
val default value
def child_value(sxpr, elt=None):
"""Get the value of the first child of @sxpr with the optional type @elt.
"""
kids = children(sxpr)
if len(kids) > index:
val = kids[index]
return val
def child0(sxpr, val=None):
"""Get the zeroth child.
"""
return child_at(sxpr, 0, val)
def child1(sxpr, val=None):
"""Get the first child.
"""
return child_at(sxpr, 1, val)
def child2(sxpr, val=None):
"""Get the second child.
"""
return child_at(sxpr, 2, val)
def child3(sxpr, val=None):
"""Get the third child.
"""
return child_at(sxpr, 3, val)
def child4(sxpr, val=None):
"""Get the fourth child.
"""
return child_at(sxpr, 4, val)
def child_value(sxpr, elt, val=None):
"""Get the value of the first child of the given element type.
Assumes the child has an atomic value.
sxpr sxpr
elt element type
val default value
"""
kid = child(sxpr, elt)
if kid:
val = child_at(kid, 0, val)
return val
def has_id(sxpr, id):
"""Test if an s-expression has a given id.
"""
return attribute(sxpr, 'id') == id
def with_id(sxpr, id, val=None):
"""Find the first s-expression with a given id, at any depth.
sxpr s-exp or list
id id
val value if not found (default None)
return s-exp or val
"""
if isinstance(sxpr, types.ListType):
for n in sxpr:
if has_id(n, id):
val = n
break
v = with_id(n, id)
if v is None: continue
val = v
break
return val
def child_with_id(sxpr, id, val=None):
"""Find the first child with a given id.
sxpr s-exp or list
id id
val value if not found (default None)
return s-exp or val
"""
if isinstance(sxpr, types.ListType):
for n in sxpr:
if has_id(n, id):
val = n
break
return val
def elements(sxpr, ctxt=None):
"""Generate elements (at any depth).
Visit elements in pre-order.
Values generated are (node, context)
The context is None if there is no parent, otherwise
(index, parent, context) where index is the node's index w.r.t its parent,
and context is the parent's context.
sxpr s-exp
returns generator
"""
yield (sxpr, ctxt)
i = 0
for n in children(sxpr):
if isinstance(n, types.ListType):
# Calling elements() recursively does not generate recursively,
# it just returns a generator object. So we must iterate over it.
for v in elements(n, (i, sxpr, ctxt)):
yield v
i += 1
x = child(sxpr, elt)
if not isinstance(x, types.ListType) or len(x) < 2:
return None
return x[1]
def to_string(sxpr):
"""Convert an sxpr to a string.
sxpr sxpr
returns string
"""Convert an s-expression @sxpr to a string.
"""
io = StringIO()
show(sxpr, io)
@@ -608,35 +247,14 @@ def to_string(sxpr):
return val
def from_string(str):
"""Create an sxpr by parsing a string.
str string
returns sxpr
"""
io = StringIO(str)
vals = parse(io)
if vals is []:
return None
else:
return vals[0]
def all_from_string(str):
"""Create an sxpr list by parsing a string.
str string
returns sxpr list
"""Create an sxpr list from a given input string @str.
"""
io = StringIO(str)
vals = parse(io)
return vals
def parse(io):
"""Completely parse all input from 'io'.
io input file object
returns list of values, None if incomplete
raises ParseError on parse error
"""Completely parse all input from file @io.
"""
pin = Parser()
while 1:
@@ -649,19 +267,11 @@ def parse(io):
else:
val = None
return val
if __name__ == '__main__':
print ">main"
pin = Parser()
while 1:
buf = sys.stdin.read(1024)
#buf = sys.stdin.readline()
pin.input(buf)
while pin.ready():
val = pin.get_val()
print
print '****** val=', val
if len(buf) == 0:
break
buf = sys.stdin.read(1024)
pin.input(buf)
while pin.ready():
print '\n****** val=', pin.get_val()
+73 -37
View File
@@ -1,4 +1,5 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Domain creation.
"""
import string
@@ -12,15 +13,25 @@ from xen.util import console_client
from xen.xm.opts import *
gopts = Opts(use="""[options]
gopts = Opts(use="""[options] [vars]
Create a domain.
Domain creation parameters can be set by command-line switches, from
a python configuration script or an SXP config file. See documentation
for --defaults, --config. Configuration variables can be set using
VAR=VAL on the command line. For example vmid=3 sets vmid to 3.
""")
gopts.opt('help', short='h',
fn=set_true, default=0,
use="Print this help.")
gopts.opt('help_config',
fn=set_true, default=0,
use="Print help for configuration file.")
gopts.opt('quiet', short='q',
fn=set_true, default=0,
use="Quiet.")
@@ -31,58 +42,73 @@ gopts.opt('path', val='PATH',
gopts.opt('defaults', short='f', val='FILE',
fn=set_value, default='xmdefaults',
use="Use the given default script.")
use="""Use the given Python defaults script.
The defaults script is loaded after arguments have been processed.
Each command-line option sets a configuration variable named after
its long option name, and these variables are placed in the
environment of the script before it is loaded.
Variables for options that may be repeated have list values.
Other variables can be set using VAR=VAL on the command line.
After the script is loaded, option values that were not set on the
command line are replaced by the values set in the script.
""")
gopts.opt('config', short='F', val='FILE',
fn=set_value, default=None,
use='Domain configuration to use (SXP).')
use="""Domain configuration to use (SXP).
SXP is the underlying configuration format used by Xen.
SXP configs can be hand-written or generated from Python defaults
scripts, using the -n (dryrun) option to print the config.
""")
gopts.opt('load', short='L', val='FILE',
fn=set_value, default=None,
use='Domain saved state to load.')
gopts.opt('define', short='D', val='VAR=VAL',
fn=set_var, default=None,
use="""Set a variable before loading defaults, e.g. '-D vmid=3'
to set vmid. May be repeated to set more thanone variable.""")
gopts.opt('dryrun', short='n',
fn=set_true, default=0,
use="Dry run - print the config but don't create the domain.")
gopts.opt('name', short='N', val='NAME',
fn=set_value, default=None,
use="Domain name.")
use="""Dry run - print the config but don't create the domain.
The defaults file is loaded and the SXP configuration is created and printed.
""")
gopts.opt('console_autoconnect', short='c',
fn=set_true, default=0,
use="Connect to console after domain is created.")
gopts.opt('kernel', short='k', val='FILE',
gopts.var('name', val='NAME',
fn=set_value, default=None,
use="Domain name.")
gopts.var('kernel', val='FILE',
fn=set_value, default=None,
use="Path to kernel image.")
gopts.opt('ramdisk', short='r', val='FILE',
gopts.var('ramdisk', val='FILE',
fn=set_value, default='',
use="Path to ramdisk.")
gopts.opt('builder', short='b', val='FUNCTION',
gopts.var('builder', val='FUNCTION',
fn=set_value, default='linux',
use="Function to use to build the domain.")
gopts.opt('memory', short='m', val='MEMORY',
gopts.var('memory', val='MEMORY',
fn=set_value, default=128,
use="Domain memory in MB.")
gopts.opt('blkif',
fn=set_true, default=0,
gopts.var('autorestart', val='no|yes',
fn=set_bool, default=0,
use="Whether to restart the domain on exit.")
gopts.var('blkif', val='no|yes',
fn=set_bool, default=0,
use="Make the domain a block device backend.")
gopts.opt('netif',
fn=set_true, default=0,
gopts.var('netif', val='no|yes',
fn=set_bool, default=0,
use="Make the domain a network interface backend.")
gopts.opt('disk', short='d', val='phy:DEV,VDEV,MODE',
gopts.var('disk', val='phy:DEV,VDEV,MODE',
fn=append_value, default=[],
use="""Add a disk device to a domain. The physical device is DEV,
which is exported to the domain as VDEV. The disk is read-only if MODE
@@ -90,18 +116,18 @@ gopts.opt('disk', short='d', val='phy:DEV,VDEV,MODE',
The option may be repeated to add more than one disk.
""")
gopts.opt('pci', val='BUS,DEV,FUNC',
gopts.var('pci', val='BUS,DEV,FUNC',
fn=append_value, default=[],
use="""Add a PCI device to a domain, using given params (in hex).
For example '-pci c0,02,1a'.
The option may be repeated to add more than one pci device.
""")
gopts.opt('ipaddr', short='i', val="IPADDR",
gopts.var('ipaddr', val="IPADDR",
fn=append_value, default=[],
use="Add an IP address to the domain.")
gopts.opt('vif', val="mac=MAC,bridge=BRIDGE",
gopts.var('vif', val="mac=MAC,bridge=BRIDGE",
fn=append_value, default=[],
use="""Add a network interface with the given MAC address and bridge.
If mac is not specified a random MAC address is used.
@@ -110,7 +136,7 @@ gopts.opt('vif', val="mac=MAC,bridge=BRIDGE",
Specifying vifs will increase the number of interfaces as needed.
""")
gopts.opt('nics', val="NUM",
gopts.var('nics', val="NUM",
fn=set_int, default=1,
use="""Set the number of network interfaces.
Use the vif option to define interface parameters, otherwise
@@ -118,44 +144,44 @@ gopts.opt('nics', val="NUM",
number of interfaces as needed.
""")
gopts.opt('root', short='R', val='DEVICE',
gopts.var('root', val='DEVICE',
fn=set_value, default='',
use="""Set the root= parameter on the kernel command line.
Use a device, e.g. /dev/sda1, or /dev/nfs for NFS root.""")
gopts.opt('extra', short='E', val="ARGS",
gopts.var('extra', val="ARGS",
fn=set_value, default='',
use="Set extra arguments to append to the kernel command line.")
gopts.opt('ip', short='I', val='IPADDR',
gopts.var('ip', val='IPADDR',
fn=set_value, default='',
use="Set the kernel IP interface address.")
gopts.opt('gateway', val="IPADDR",
gopts.var('gateway', val="IPADDR",
fn=set_value, default='',
use="Set the kernel IP gateway.")
gopts.opt('netmask', val="MASK",
gopts.var('netmask', val="MASK",
fn=set_value, default = '',
use="Set the kernel IP netmask.")
gopts.opt('hostname', val="NAME",
gopts.var('hostname', val="NAME",
fn=set_value, default='',
use="Set the kernel IP hostname.")
gopts.opt('interface', val="INTF",
gopts.var('interface', val="INTF",
fn=set_value, default="eth0",
use="Set the kernel IP interface name.")
gopts.opt('dhcp', val="off|dhcp",
gopts.var('dhcp', val="off|dhcp",
fn=set_value, default='off',
use="Set the kernel dhcp option.")
gopts.opt('nfs_server', val="IPADDR",
gopts.var('nfs_server', val="IPADDR",
fn=set_value, default=None,
use="Set the address of the NFS server for NFS root.")
gopts.opt('nfs_root', val="PATH",
gopts.var('nfs_root', val="PATH",
fn=set_value, default=None,
use="Set the path of the root NFS directory.")
@@ -244,6 +270,8 @@ def make_config(opts):
config.append(['backend', ['blkif']])
if opts.netif:
config.append(['backend', ['netif']])
if opts.autorestart:
config.append(['autorestart'])
configure_image(config, opts)
config_devs = []
@@ -282,7 +310,7 @@ def preprocess_vifs(opts):
d = {}
a = vif.split(',')
for b in a:
(k, v) = b.strip().split('=')
(k, v) = b.strip().split('=', 1)
k = k.strip()
v = v.strip()
if k not in ['mac', 'bridge']:
@@ -352,7 +380,15 @@ def main(argv):
args = opts.parse(argv)
if opts.vals.help:
opts.usage()
if opts.vals.help or opts.vals.help_config:
opts.load_defaults(help=1)
if opts.vals.help or opts.vals.help_config:
return
# Process remaining args as config variables.
for arg in args:
if '=' in arg:
(var, val) = arg.strip().split('=', 1)
gopts.setvar(var.strip(), val.strip())
if opts.vals.config:
pass
else:
+82
View File
@@ -0,0 +1,82 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Variable definition and help support for Python defaults files.
"""
import sys
class Vars:
"""A set of configuration variables.
"""
def __init__(self, name, help, env):
"""Create a variable set.
name name of the defaults file
help help flag
env local environment
"""
self.name = name
self.help = help
self.env = env
self.vars = []
def var(self, name, use=None, check=None):
"""Define a configuration variable.
If provided, the check function will be called as check(var, val)
where var is the variable name and val is its value (string).
It should return a new value for the variable, or raise ValueError if
the value is not acceptable.
name variable name
use variable usage string
check variable check function
"""
self.vars.append(Var(name, use, check))
def check(self):
"""Execute the variable checks or print help, depending on the value
of the help flag passed to the constructor.
"""
if self.help:
self.doHelp()
else:
for v in self.vars:
v.doCheck(self.env)
def doHelp(self, out=sys.stderr):
"""Print help for the variables.
"""
if self.vars:
print >>out, "\nConfiguration variables for %s:\n" % self.name
for v in self.vars:
v.doHelp(out)
print >>out
class Var:
"""A single variable.
"""
def __init__(self, name, use, check):
"""Create a variable.
name variable name
use variable use string
check variable value check function
"""
self.name = name
self.use = use or ''
self.check = check
def doCheck(self, env):
"""Execute the check and set the variable to the new value.
"""
if not self.check: return
env[self.name] = self.check(self.name, env.get(self.name))
def doHelp(self, out):
"""Print help for the variable.
"""
print >>out, "%-12s" % self.name, self.use
+33 -8
View File
@@ -5,10 +5,12 @@ import os
import os.path
import sys
from getopt import getopt
import socket
from xen.xend import PrettyPrint
from xen.xend import sxp
from xen.xend.XendClient import server
from xen.xend.XendClient import main as xend_client_main
from xen.xm import create, shutdown
class Prog:
@@ -65,6 +67,13 @@ class Xm:
sys.exit(1)
def main(self, args):
try:
self.main_call(args)
except socket.error, ex:
print >>sys.stderr, ex
self.err("Error connecting to xend, is xend running?")
def main_call(self, args):
"""Main entry point. Dispatches to the progs.
"""
self.name = args[0]
@@ -237,11 +246,11 @@ class ProgList(Prog):
info = server.xend_domain(dom)
d = {}
d['dom'] = int(dom)
d['name'] = sxp.child_value(info, 'name', '??')
d['mem'] = int(sxp.child_value(info, 'memory', '0'))
d['cpu'] = int(sxp.child_value(info, 'cpu', '0'))
d['state'] = sxp.child_value(info, 'state', '??')
d['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0'))
d['name'] = sxp.child_value(info, 'name') or '??'
d['mem'] = int(sxp.child_value(info, 'memory') or '-1')
d['cpu'] = int(sxp.child_value(info, 'cpu') or '-1')
d['state'] = sxp.child_value(info, 'state') or '??'
d['cpu_time'] = float(sxp.child_value(info, 'cpu_time') or '-1')
print ("%(dom)-4d %(name)-16s %(mem)7d %(cpu)3d %(state)5s %(cpu_time)7.1f" % d)
def long_list(self, doms):
@@ -415,9 +424,9 @@ class ProgConsoles(Prog):
for x in l:
info = server.xend_console(x)
d = {}
d['dom'] = sxp.child(info, 'dst', ['dst', '?', '?'])[1]
d['port'] = sxp.child_value(info, 'port', '?')
d['id'] = sxp.child_value(info, 'id', '?')
d['dom'] = (sxp.child(info, 'dst') or ['dst', '?', '?'])[1]
d['port'] = sxp.child_value(info, 'port') or '?'
d['id'] = sxp.child_value(info, 'id') or '?'
print "%(dom)3s %(port)4s %(id)3s" % d
xm.prog(ProgConsoles)
@@ -444,5 +453,21 @@ class ProgConsole(Prog):
xm.prog(ProgConsole)
class ProgCall(Prog):
name = "call"
info = "Call xend api functions."
def help (self, args):
print "call fn argss..."
print """
Call a xend HTTP API function. The leading 'xend_' on the function
can be omitted. See xen.xend.XendClient for the API functions.
"""
def main(self, args):
xend_client_main(args)
xm.prog(ProgCall)
def main(args):
xm.main(args)
+92 -13
View File
@@ -126,6 +126,42 @@ class Opt:
"""
return self.specified_opt
class OptVar(Opt):
"""An individual option variable.
"""
def __init__(self, opts, name,
val=None, fn=None, use=None, default=None):
"""Create an option.
opts parent options object
name name of the field it controls
val string used to print option args in help.
If val is not specified the option has no arg.
fn function to call when the option is specified.
use usage (help) string
default default value if not specified on command-line
"""
if val is None:
val = name.upper()
Opt.__init__(self, opts, name, val=val, fn=fn, use=use, default=default)
self.optkeys = []
self.optkeys.append(self.long)
def short_opt(self):
return None
def long_opt(self):
return None
def show(self):
print '%s=%s' %(self.optkeys[0], self.val)
print
if self.use:
print '\t',
print self.use
if self.val:
print '\tDefault', self.default or 'None'
class OptVals:
"""Class to hold option values.
"""
@@ -134,6 +170,13 @@ class OptVals:
class Opts:
"""Container for options.
"""
imports = ["import sys",
"import os",
"import os.path",
"from xen.util.ip import *",
]
def __init__(self, use=None):
"""Options constructor.
@@ -168,6 +211,12 @@ class Opts:
self.options_map[name] = x
return x
def var(self, name, **args):
x = OptVar(self, name, **args)
self.options.append(x)
self.options_map[name] = x
return x
def setvar(self, var, val):
"""Set a default script variable.
"""
@@ -232,7 +281,18 @@ class Opts:
else:
print >>sys.stderr, "Error: Unknown option:", k
self.usage()
return args
xargs = []
for arg in args:
isvar = 0
if '=' in arg:
(k, v) = arg.split('=', 1)
for opt in self.options:
if opt.specify(k, v):
isvar = 1
break
if not isvar:
xargs.append(arg)
return xargs
def short_opts(self):
"""Get short options specifier for getopt.
@@ -257,9 +317,10 @@ class Opts:
def usage(self):
print 'Usage: ', self.argv[0], self.use or 'OPTIONS'
for opt in self.options:
print
opt.show()
def load_defaults(self):
def load_defaults(self, help=0):
"""Load a defaults script. Assumes these options set:
'path' search path
'default' script name
@@ -270,12 +331,12 @@ class Opts:
else:
p = self.vals.defaults
if os.path.exists(p):
self.load(p)
self.load(p, help)
break
else:
self.err("Cannot open defaults file %s" % self.vals.defaults)
def load(self, defaults, help=0):
def load(self, defaults, help):
"""Load a defaults file. Local variables in the file
are used to set options with the same names.
Variables are not used to set options that are already specified.
@@ -287,15 +348,22 @@ class Opts:
globals = {}
locals = {}
locals.update(self.vars)
cmd = '\n'.join(["import sys",
"import os",
"import os.path",
"import xen.util.ip",
"xm_file = '%s'" % defaults,
"xm_help = %d" % help ])
cmd = '\n'.join(self.imports +
[ "from xen.xm.help import Vars",
"xm_file = '%s'" % defaults,
"xm_help = %d" % help,
"xm_vars = Vars(xm_file, xm_help, locals())"
])
exec cmd in globals, locals
execfile(defaults, globals, locals)
if help: return
try:
execfile(defaults, globals, locals)
except:
if not help: raise
if help:
print 'The following imports are done automatically:'
for x in self.imports:
print x
return
# Extract the values set by the script and set the corresponding
# options, if not set on the command line.
vtypes = [ types.StringType,
@@ -316,6 +384,17 @@ def set_false(opt, k, v):
"""Set an option false."""
opt.set(0)
def set_bool(opt, k, v):
"""Set a boolean option.
"""
if v in ['yes']:
opt.set(1)
elif v in ['no']:
opt.set(0)
else:
opt.opts.err('Invalid value:' +v)
def set_value(opt, k, v):
"""Set an option to a valoue."""
opt.set(v)
@@ -335,6 +414,6 @@ def append_value(opt, k, v):
def set_var(opt, k, v):
"""Set a default script variable.
"""
(var, val) = v.strip().split('=')
(var, val) = v.strip().split('=', 1)
opt.opts.setvar(var.strip(), val.strip())
+29 -6
View File
@@ -1,4 +1,5 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Domain shutdown.
"""
import string
@@ -10,7 +11,8 @@ from xen.xm.opts import *
gopts = Opts(use="""[options] [DOM]
Shutdown one or more domains gracefully.""")
Shutdown one or more domains gracefully.
""")
gopts.opt('help', short='h',
fn=set_true, default=0,
@@ -24,18 +26,22 @@ gopts.opt('wait', short='w',
fn=set_true, default=0,
use='Wait for shutdown to complete.')
gopts.opt('norestart', short='n',
gopts.opt('halt', short='H',
fn=set_true, default=0,
use='Prevent domain restart.')
use='Shutdown without reboot.')
def shutdown(opts, doms, wait):
gopts.opt('reboot', short='R',
fn=set_true, default=0,
use='Shutdown and reboot.')
def shutdown(opts, doms, mode, wait):
def domains():
return [ int(a) for a in server.xend_domains() ]
if doms == None: doms = domains()
if 0 in doms:
doms.remove(0)
for d in doms:
server.xend_domain_shutdown(d)
server.xend_domain_shutdown(d, mode)
if wait:
while doms:
alive = domains()
@@ -49,6 +55,21 @@ def shutdown(opts, doms, wait):
time.sleep(1)
opts.info("All domains terminated")
def shutdown_mode(opts):
mode = 'poweroff'
if opts.vals.wait:
mode = 'halt'
if opts.vals.reboot:
opts.err("Can't specify wait and reboot")
else:
if opts.vals.halt and opts.vals.reboot:
opts.err("Can't specify halt and reboot")
if opts.vals.halt:
mode = 'halt'
elif opts.vals.reboot:
mode = 'reboot'
return mode
def main_all(opts, args):
shutdown(opts, None, opts.vals.wait)
@@ -59,7 +80,9 @@ def main_dom(opts, args):
domid = int(dom)
except:
opts.err('Invalid domain: ' + dom)
shutdown(opts, [ domid ], opts.vals.wait)
mode = shutdown_mode(opts)
shutdown(opts, [ domid ], mode, opts.vals.wait)
def main(argv):
opts = gopts
+34
View File
@@ -0,0 +1,34 @@
# -*- mode: Makefile; -*-
#============================================================================
UTIL_LIB = libutil.a
UTIL_LIB_SRC =
UTIL_LIB_SRC += allocate.c
UTIL_LIB_SRC += enum.c
UTIL_LIB_SRC += file_stream.c
UTIL_LIB_SRC += gzip_stream.c
UTIL_LIB_SRC += hash_table.c
UTIL_LIB_SRC += iostream.c
UTIL_LIB_SRC += lexis.c
UTIL_LIB_SRC += lzi_stream.c
UTIL_LIB_SRC += marshal.c
UTIL_LIB_SRC += string_stream.c
UTIL_LIB_SRC += sxpr.c
#UTIL_LIB_SRC += sxpr_parser.c
UTIL_LIB_SRC += sys_net.c
UTIL_LIB_SRC += sys_string.c
#UTIL_LIB_SRC += util.c
UTIL_LIB_SRC += xdr.c
#----------------------------------------------------------------------------
# Xfrd.
XFRD_PROG_SRC =
XFRD_PROG_SRC += xfrd.c
#XFRD_PROG_SRC += xfr_msg.c
XFRD_PROG_SRC += xen_domain.c
XFRD_PROG_SRC += select.c
XFRD_PROG_SRC += connection.c
#============================================================================
+68
View File
@@ -0,0 +1,68 @@
# -*- mode: Makefile; -*-
#============================================================================
#
# Mike Wray <mike.wray@hp.com>
#============================================================================
XEN_ROOT = ../..
include $(XEN_ROOT)/tools/Make.defs
XFRD_INSTALL_DIR = /usr/sbin
vpath %.h $(XEN_HYPERVISOR_IFS)
INCLUDES += -I $(XEN_HYPERVISOR_IFS)
vpath %h $(XEN_LINUX_INCLUDE)
INCLUDES += -I $(XEN_LINUX_INCLUDE)
vpath %.h $(XEN_XU)
INCLUDES += -I $(XEN_XU)
vpath %c $(XEN_LIBXUTIL)
INCLUDES += -I $(XEN_LIBXUTIL)
include Make.xfrd
UTIL_LIB_OBJ = $(UTIL_LIB_SRC:.c=.o)
XFRD_PROG_OBJ = $(XFRD_PROG_SRC:.c=.o)
XFRD_PROG_OBJ += $(UTIL_LIB)
CPPFLAGS += -D _XEN_XFR_STUB_
CFLAGS += -g
CFLAGS += -Wall
CFALGS += -Werror
CFLAGS += $(INCLUDES)
# Make gcc generate dependencies.
CFLAGS += -Wp,-MD,.$(@F).d
PROG_DEP = .*.d
#LDFLAGS += -L $(COMPRESS_DIR) -lz
$(warning XFRD_PROG_OBJ= $(XFRD_PROG_OBJ))
$(warning UTIL_LIB= $(UTIL_LIB))
$(warning UTIL_LIB_OBJ= $(UTIL_LIB_OBJ))
all: xfrd
xfrd: $(XFRD_PROG_OBJ) -lz
.PHONY: install
install: xfrd
mkdir -p $(prefix)/$(XFRD_INSTALL_DIR)
install -m 0755 xfrd $(prefix)/$(XFRD_INSTALL_DIR)
.PHONY: libutil
libutil: $(UTIL_LIB)
$(UTIL_LIB): $(UTIL_LIB_OBJ)
$(AR) rc $@ $^
.PHONY: clean
clean:
$(RM) *.o *.a *.so *~ xfrd
$(RM) $(PROG_DEP)
-include $(PROG_DEP)
+163
View File
@@ -0,0 +1,163 @@
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "connection.h"
#include "file_stream.h"
#include "lzi_stream.h"
#define dprintf(fmt, args...) fprintf(stdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args)
#define wprintf(fmt, args...) fprintf(stderr, "[WARN] %s" fmt, __FUNCTION__, ##args)
#define iprintf(fmt, args...) fprintf(stdout, "[INFO] %s" fmt, __FUNCTION__, ##args)
#define eprintf(fmt, args...) fprintf(stderr, "[ERROR] %s" fmt, __FUNCTION__, ##args)
/** Compress magic header. */
char compress_magic[2] = { 0x1f, 0x8b };
/** Plain magic header. */
char plain_magic[2] = { 0x0, 0x0 };
int Conn_read_header(int sock, int *flags){
int err = 0;
char magic[2] = {};
int k, n = sizeof(magic);
k = read(sock, magic, n);
if(k != n){
err = -EINVAL;
goto exit;
}
dprintf("> magic={ 0x%x, 0x%x }\n", magic[0], magic[1]);
if(magic[0] == compress_magic[0] && magic[1] == compress_magic[1]){
*flags |= CONN_READ_COMPRESS;
dprintf("> Using compress read.\n");
} else {
dprintf("> Using plain read.\n");
}
exit:
return err;
}
int Conn_write_header(int sock, int flags){
int err = 0;
if(flags & CONN_WRITE_COMPRESS){
dprintf("> Using compress write.\n");
err = write(sock, compress_magic, 2);
} else {
dprintf("> Using plain write.\n");
err = write(sock, plain_magic, 2);
}
if(err == 2) err = 0;
return err;
}
/** Initialize a file stream from a file desciptor.
*
* @param fd file descriptor
* @param mode file mode
* @param flags control compression and buffering
* @param io return parameter for the stream
* @return 0 on success, error code otherwise
*/
int stream_init(int fd, const char *mode, int flags, int compress, IOStream **io){
int err = 0;
dprintf(">mode=%s flags=%x compress=%d\n", mode, flags, compress);
if(compress){
*io = lzi_stream_fdopen(fd, mode);
} else {
*io = file_stream_fdopen(fd, mode);
}
if(!*io){
err = -errno;
perror("fdopen");
goto exit;
}
if(1 && (flags & CONN_NOBUFFER)){
// Make unbuffered.
dprintf("> unbuffer...\n");
err = file_stream_setvbuf((compress ? lzi_stream_io(*io) : *io), NULL, _IONBF, 0);
if(err){
err = -errno;
perror("setvbuf");
goto exit;
}
}
exit:
if(err && *io){
dprintf("> close err=%d\n", err);
IOStream_close(*io);
*io = NULL;
}
dprintf("< err=%d\n", err);
return err;
}
/** Initialize a connection.
*
* @param conn connection
* @param flags
* @param sock socket
* @param ipaddr ip address
* @return 0 on success, error code otherwise
*/
int Conn_init(Conn *conn, int flags, int sock, struct sockaddr_in addr){
int err = 0;
dprintf("> flags=%x\n", flags);
conn->addr = addr;
conn->sock = sock;
dprintf("> write stream...\n");
err = stream_init(sock, "w", flags, (flags & CONN_WRITE_COMPRESS), &conn->out);
if(err) goto exit;
IOStream_flush(conn->out);
dprintf("> read stream...\n");
err = stream_init(sock, "r", flags, (flags & CONN_READ_COMPRESS) , &conn->in);
if(err) goto exit;
exit:
if(err) eprintf("< err=%d\n", err);
return err;
}
/** Open a connection.
*
* @param conn connection
* @param flags
* @param ipaddr ip address to connect to
* @param port port
* @return 0 on success, error code otherwise
*/
int Conn_connect(Conn *conn, int flags, struct in_addr ipaddr, uint16_t port){
int err = 0;
int sock;
struct sockaddr_in addr_in;
struct sockaddr *addr = (struct sockaddr *)&addr_in;
socklen_t addr_n = sizeof(addr_in);
dprintf("> addr=%s:%d\n", inet_ntoa(ipaddr), ntohs(port));
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0){
err = -errno;
goto exit;
}
addr_in.sin_family = AF_INET;
addr_in.sin_addr = ipaddr;
addr_in.sin_port = port;
err = connect(sock, addr, addr_n);
if(err) goto exit;
//err = Conn_write_header(sock, flags);
//if(err < 0) goto exit;
err = Conn_init(conn, flags, sock, addr_in);
exit:
if(err) eprintf("< err=%d\n", err);
return err;
}
/** Close a connection.
*
* @param conn connection
*/
void Conn_close(Conn *conn){
if(conn->in) IOStream_close(conn->in);
if(conn->out) IOStream_close(conn->out);
shutdown(conn->sock, 2);
}
+32
View File
@@ -0,0 +1,32 @@
/* $Id: connection.h,v 1.1 2003/10/17 15:48:43 mjw Exp $ */
#ifndef _VFC_CONNECTION_H_
#define _VFC_CONNECTION_H_
#include <netinet/in.h>
#include "iostream.h"
/** A connection.
* The underlying transport is a socket.
* Contains in and out streams using the socket.
*/
typedef struct Conn {
struct sockaddr_in addr;
int sock;
IOStream *in;
IOStream *out;
} Conn;
enum {
CONN_NOBUFFER=1,
CONN_READ_COMPRESS=2,
CONN_WRITE_COMPRESS=4,
};
extern int Conn_read_header(int sock, int *flags);
extern int Conn_write_header(int sock, int flags);
extern int Conn_init(Conn *conn, int flags, int sock, struct sockaddr_in addr);
extern int Conn_connect(Conn *conn, int flags, struct in_addr ipaddr, uint16_t port);
extern void Conn_close(Conn *conn);
#endif /* ! _VFC_CONNECTION_H_ */
+72
View File
@@ -0,0 +1,72 @@
/*
* Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _XUTIL_DEBUG_H_
#define _XUTIL_DEBUG_H_
#ifndef MODULE_NAME
#define MODULE_NAME ""
#endif
#ifdef __KERNEL__
#include <linux/config.h>
#include <linux/kernel.h>
#ifdef DEBUG
#define dprintf(fmt, args...) printk(KERN_DEBUG "[DBG] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
#define wprintf(fmt, args...) printk(KERN_WARNING "[WRN] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
#define iprintf(fmt, args...) printk(KERN_INFO "[INF] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
#define eprintf(fmt, args...) printk(KERN_ERR "[ERR] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
#else
#define dprintf(fmt, args...) do {} while(0)
#define wprintf(fmt, args...) printk(KERN_WARNING "[WRN] " MODULE_NAME fmt, ##args)
#define iprintf(fmt, args...) printk(KERN_INFO "[INF] " MODULE_NAME fmt, ##args)
#define eprintf(fmt, args...) printk(KERN_ERR "[ERR] " MODULE_NAME fmt, ##args)
#endif
#else
#include <stdio.h>
#ifdef DEBUG
#define dprintf(fmt, args...) fprintf(stdout, "[DBG] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
#define wprintf(fmt, args...) fprintf(stderr, "[WRN] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
#define iprintf(fmt, args...) fprintf(stderr, "[INF] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
#define eprintf(fmt, args...) fprintf(stderr, "[ERR] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
#else
#define dprintf(fmt, args...) do {} while(0)
#define wprintf(fmt, args...) fprintf(stderr, "[WRN] " MODULE_NAME fmt, ##args)
#define iprintf(fmt, args...) fprintf(stderr, "[INF] " MODULE_NAME fmt, ##args)
#define eprintf(fmt, args...) fprintf(stderr, "[ERR] " MODULE_NAME fmt, ##args)
#endif
#endif
/** Print format for an IP address.
* See NIPQUAD(), HIPQUAD()
*/
#define IPFMT "%u.%u.%u.%u"
#endif /* ! _XUTIL_DEBUG_H_ */
+61
View File
@@ -0,0 +1,61 @@
/*
* Copyright (C) 2002, 2004 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef __KERNEL__
#include <linux/errno.h>
#else
#include <errno.h>
#endif
#include "sys_string.h"
#include "enum.h"
/** Map an enum name to its value using a table.
*
* @param name enum name
* @param defs enum definitions
* @return enum value or -1 if not known
*/
int enum_name_to_val(char *name, EnumDef *defs){
int val = -1;
for(; defs->name; defs++){
if(!strcmp(defs->name, name)){
val = defs->val;
break;
}
}
return val;
}
/** Map an enum value to its name using a table.
*
* @param val enum value
* @param defs enum definitions
* @param defs_n number of definitions
* @return enum name or NULL if not known
*/
char *enum_val_to_name(int val, EnumDef *defs){
char *name = NULL;
for(; defs->name; defs++){
if(val == defs->val){
name = defs->name;
break;
}
}
return name;
}
+30
View File
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2002, 2004 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _XUTIL_ENUM_H_
#define _XUTIL_ENUM_H_
/** Mapping of an enum value to a name. */
typedef struct EnumDef {
int val;
char *name;
} EnumDef;
extern int enum_name_to_val(char *name, EnumDef *defs);
extern char *enum_val_to_name(int val, EnumDef *defs);
#endif /* _XUTIL_ENUM_H_ */
+640
View File
@@ -0,0 +1,640 @@
/*
* Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef __KERNEL__
# include <linux/config.h>
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/errno.h>
#else
# include <errno.h>
# include <stddef.h>
#endif
//#include <limits.h>
#include "allocate.h"
#include "hash_table.h"
/** @file
* Base support for hashtables.
*
* Hash codes are reduced modulo the number of buckets to index tables,
* so there is no need for hash functions to limit the range of hashcodes.
* In fact it is assumed that hashcodes do not change when the number of
* buckets in the table changes.
*/
/*==========================================================================*/
/** Number of bits in half a word. */
//#if __WORDSIZE == 64
//#define HALF_WORD_BITS 32
//#else
#define HALF_WORD_BITS 16
//#endif
/** Mask for lo half of a word. On 32-bit this is
* (1<<16) - 1 = 65535 = 0xffff
* It's 4294967295 = 0xffffffff on 64-bit.
*/
#define LO_HALF_MASK ((1 << HALF_WORD_BITS) - 1)
/** Get the lo half of a word. */
#define LO_HALF(x) ((x) & LO_HALF_MASK)
/** Get the hi half of a word. */
#define HI_HALF(x) ((x) >> HALF_WORD_BITS)
/** Do a full hash on both inputs, using DES-style non-linear scrambling.
* Both inputs are replaced with the results of the hash.
*
* @param pleft input/output word
* @param pright input/output word
*/
void pseudo_des(unsigned long *pleft, unsigned long *pright){
// Bit-rich mixing constant.
static const unsigned long a_mixer[] = {
0xbaa96887L, 0x1e17d32cL, 0x03bcdc3cL, 0x0f33d1b2L, };
// Bit-rich mixing constant.
static const unsigned long b_mixer[] = {
0x4b0f3b58L, 0xe874f0c3L, 0x6955c5a6L, 0x55a7ca46L, };
// Number of iterations - must be 2 or 4.
static const int ncycle = 4;
//static const int ncycle = 2;
unsigned long left = *pleft, right = *pright;
unsigned long v, v_hi, v_lo;
int i;
for(i=0; i<ncycle; i++){
// Flip some bits in right to get v.
v = right;
v ^= a_mixer[i];
// Get lo and hi halves of v.
v_lo = LO_HALF(v);
v_hi = HI_HALF(v);
// Non-linear mix of the halves of v.
v = ((v_lo * v_lo) + ~(v_hi * v_hi));
// Swap the halves of v.
v = (HI_HALF(v) | (LO_HALF(v) << HALF_WORD_BITS));
// Flip some bits.
v ^= b_mixer[i];
// More non-linear mixing.
v += (v_lo * v_hi);
v ^= left;
left = right;
right = v;
}
*pleft = left;
*pright = right;
}
/** Hash a string.
*
* @param s input to hash
* @return hashcode
*/
Hashcode hash_string(char *s){
Hashcode h = 0;
if(s){
for( ; *s; s++){
h = hash_2ul(h, *s);
}
}
return h;
}
/** Get the bucket for a hashcode in a hash table.
*
* @param table to get bucket from
* @param hashcode to get bucket for
* @return bucket
*/
inline HTBucket * get_bucket(HashTable *table, Hashcode hashcode){
return table->buckets + (hashcode % table->buckets_n);
}
/** Initialize a hash table.
* Can be safely called more than once.
*
* @param table to initialize
*/
void HashTable_init(HashTable *table){
int i;
if(!table->init_done){
table->init_done = 1;
table->next_id = 0;
for(i=0; i<table->buckets_n; i++){
HTBucket *bucket = get_bucket(table, i);
bucket->head = 0;
bucket->count = 0;
}
table->entry_count = 0;
}
}
/** Allocate a new hashtable.
* If the number of buckets is not positive the default is used.
* The number of buckets should usually be prime.
*
* @param buckets_n number of buckets
* @return new hashtable or null
*/
HashTable *HashTable_new(int buckets_n){
HashTable *z = ALLOCATE(HashTable);
if(!z) goto exit;
if(buckets_n <= 0){
buckets_n = HT_BUCKETS_N;
}
z->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket));
if(!z->buckets){
deallocate(z);
z = 0;
goto exit;
}
z->buckets_n = buckets_n;
HashTable_init(z);
exit:
return z;
}
/** Free a hashtable.
* Any entries are removed and freed.
*
* @param h hashtable (ignored if null)
*/
void HashTable_free(HashTable *h){
if(h){
HashTable_clear(h);
deallocate(h->buckets);
deallocate(h);
}
}
/** Push an entry on the list in the bucket for a given hashcode.
*
* @param table to add entry to
* @param hashcode for the entry
* @param entry to add
*/
static inline void push_on_bucket(HashTable *table, Hashcode hashcode,
HTEntry *entry){
HTBucket *bucket;
HTEntry *old_head;
bucket = get_bucket(table, hashcode);
old_head = bucket->head;
bucket->count++;
bucket->head = entry;
entry->next = old_head;
}
/** Change the number of buckets in a hashtable.
* No-op if the number of buckets is not positive.
* Existing entries are reallocated to buckets based on their hashcodes.
* The table is unmodified if the number of buckets cannot be changed.
*
* @param table hashtable
* @param buckets_n new number of buckets
* @return 0 on success, error code otherwise
*/
int HashTable_set_buckets_n(HashTable *table, int buckets_n){
int err = 0;
HTBucket *old_buckets = table->buckets;
int old_buckets_n = table->buckets_n;
int i;
if(buckets_n <= 0){
err = -EINVAL;
goto exit;
}
table->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket));
if(!table->buckets){
err = -ENOMEM;
table->buckets = old_buckets;
goto exit;
}
table->buckets_n = buckets_n;
for(i=0; i<old_buckets_n; i++){
HTBucket *bucket = old_buckets + i;
HTEntry *entry, *next;
for(entry = bucket->head; entry; entry = next){
next = entry->next;
push_on_bucket(table, entry->hashcode, entry);
}
}
deallocate(old_buckets);
exit:
return err;
}
/** Adjust the number of buckets so the table is neither too full nor too empty.
* The table is unmodified if adjusting fails.
*
* @param table hash table
* @param buckets_min minimum number of buckets (use default if 0 or negative)
* @return 0 on success, error code otherwise
*/
int HashTable_adjust(HashTable *table, int buckets_min){
int buckets_n = 0;
int err = 0;
if(buckets_min <= 0) buckets_min = HT_BUCKETS_N;
if(table->entry_count >= table->buckets_n){
// The table is dense - expand it.
buckets_n = 2 * table->buckets_n;
} else if((table->buckets_n > buckets_min) &&
(4 * table->entry_count < table->buckets_n)){
// The table is more than minimum size and sparse - shrink it.
buckets_n = 2 * table->entry_count;
if(buckets_n < buckets_min) buckets_n = buckets_min;
}
if(buckets_n){
err = HashTable_set_buckets_n(table, buckets_n);
}
return err;
}
/** Allocate a new entry for a given value.
*
* @param value to put in the entry
* @return entry, or 0 on failure
*/
HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value){
HTEntry *z = ALLOCATE(HTEntry);
if(z){
z->hashcode = hashcode;
z->key = key;
z->value = value;
}
return z;
}
/** Free an entry.
*
* @param z entry to free
*/
inline void HTEntry_free(HTEntry *z){
if(z){
deallocate(z);
}
}
/** Free an entry in a hashtable.
* The table's entry_free_fn is used is defined, otherwise
* the HTEntry itself is freed.
*
* @param table hashtable
* @param entry to free
*/
inline void HashTable_free_entry(HashTable *table, HTEntry *entry){
if(!entry)return;
if(table && table->entry_free_fn){
table->entry_free_fn(table, entry);
} else {
HTEntry_free(entry);
}
}
/** Get the first entry satisfying a test from the bucket for the
* given hashcode.
*
* @param table to look in
* @param hashcode indicates the bucket
* @param test_fn test to apply to elements
* @param arg first argument to calls to test_fn
* @return entry found, or 0
*/
inline HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode,
TableTestFn *test_fn, TableArg arg){
HTBucket *bucket;
HTEntry *entry = 0;
HTEntry *next;
bucket = get_bucket(table, hashcode);
for(entry = bucket->head; entry; entry = next){
next = entry->next;
if(test_fn(arg, table, entry)){
break;
}
}
return entry;
}
/** Test hashtable keys for equality.
* Uses the table's key_equal_fn if defined, otherwise pointer equality.
*
* @param key1 key to compare
* @param key2 key to compare
* @return 1 if equal, 0 otherwise
*/
inline int HashTable_key_equal(HashTable *table, void *key1, void *key2){
return (table->key_equal_fn ? table->key_equal_fn(key1, key2) : key1==key2);
}
/** Compute the hashcode of a hashtable key.
* The table's key_hash_fn is used if defined, otherwise the address of
* the key is hashed.
*
* @param table hashtable
* @param key to hash
* @return hashcode
*/
inline Hashcode HashTable_key_hash(HashTable *table, void *key){
return (table->key_hash_fn ? table->key_hash_fn(key) : hash_ul((unsigned long)key));
}
/** Test if an entry has a given key.
*
* @param arg containing key to test for
* @param table the entry is in
* @param entry to test
* @return 1 if the entry has the key, 0 otherwise
*/
static inline int has_key(TableArg arg, HashTable *table, HTEntry *entry){
return HashTable_key_equal(table, arg.ptr, entry->key);
}
/** Get an entry with a given key.
*
* @param table to search
* @param key to look for
* @return entry if found, null otherwise
*/
#if 0
inline HTEntry * HashTable_get_entry(HashTable *table, void *key){
TableArg arg = { ptr: key };
return HashTable_find_entry(table, HashTable_key_hash(table, key), has_key, arg);
}
#else
inline HTEntry * HashTable_get_entry(HashTable *table, void *key){
Hashcode hashcode;
HTBucket *bucket;
HTEntry *entry = 0;
HTEntry *next;
hashcode = HashTable_key_hash(table, key);
bucket = get_bucket(table, hashcode);
for(entry = bucket->head; entry; entry = next){
next = entry->next;
if(HashTable_key_equal(table, key, entry->key)){
break;
}
}
return entry;
}
#endif
/** Get the value of an entry with a given key.
*
* @param table to search
* @param key to look for
* @return value if an entry was found, null otherwise
*/
inline void * HashTable_get(HashTable *table, void *key){
HTEntry *entry = HashTable_get_entry(table, key);
return (entry ? entry->value : 0);
}
/** Print the buckets in a table.
*
* @param table to print
*/
void show_buckets(HashTable *table, IOStream *io){
int i,j ;
IOStream_print(io, "entry_count=%d buckets_n=%d\n", table->entry_count, table->buckets_n);
for(i=0; i<table->buckets_n; i++){
if(0 || table->buckets[i].count>0){
IOStream_print(io, "bucket %3d %3d %10p ", i,
table->buckets[i].count,
table->buckets[i].head);
for(j = table->buckets[i].count; j>0; j--){
IOStream_print(io, "+");
}
IOStream_print(io, "\n");
}
}
HashTable_print(table, io);
}
/** Print an entry in a table.
*
* @param entry to print
* @param arg a pointer to an IOStream to print to
* @return 0
*/
static int print_entry(TableArg arg, HashTable *table, HTEntry *entry){
IOStream *io = (IOStream*)arg.ptr;
IOStream_print(io, " b=%4lx h=%08lx i=%08lx |-> e=%8p k=%8p v=%8p\n",
entry->hashcode % table->buckets_n,
entry->hashcode,
entry->index,
entry, entry->key, entry->value);
return 0;
}
/** Print a hash table.
*
* @param table to print
*/
void HashTable_print(HashTable *table, IOStream *io){
IOStream_print(io, "{\n");
HashTable_map(table, print_entry, (TableArg){ ptr: io });
IOStream_print(io, "}\n");
}
/*==========================================================================*/
/** Get the next entry id to use for a table.
*
* @param table hash table
* @return non-zero entry id
*/
static inline unsigned long get_next_id(HashTable *table){
unsigned long id;
if(table->next_id == 0){
table->next_id = 1;
}
id = table->next_id++;
return id;
}
/** Add an entry to the bucket for the
* given hashcode.
*
* @param table to insert in
* @param hashcode indicates the bucket
* @param key to add an entry for
* @param value to add an entry for
* @return entry on success, 0 on failure
*/
inline HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value){
HTEntry *entry = HTEntry_new(hashcode, key, value);
if(entry){
entry->index = get_next_id(table);
push_on_bucket(table, hashcode, entry);
table->entry_count++;
}
return entry;
}
/** Move the front entry for a bucket to the correct point in the bucket order as
* defined by the order function. If this is called every time a new entry is added
* the bucket will be maintained in sorted order.
*
* @param table to modify
* @param hashcode indicates the bucket
* @param order entry comparison function
* @return 0 if an entry was moved, 1 if not
*/
int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order){
HTEntry *new_entry = NULL, *prev = NULL, *entry = NULL;
HTBucket *bucket;
int err = 1;
bucket = get_bucket(table, hashcode);
new_entry = bucket->head;
if(!new_entry || !new_entry->next) goto exit;
for(entry = new_entry->next; entry; prev = entry, entry = entry->next){
if(order(new_entry, entry) <= 0) break;
}
if(prev){
err = 0;
bucket->head = new_entry->next;
new_entry->next = entry;
prev->next = new_entry;
}
exit:
return err;
}
/** Add an entry to a hashtable.
* The entry is added to the bucket for its key's hashcode.
*
* @param table to insert in
* @param key to add an entry for
* @param value to add an entry for
* @return entry on success, 0 on failure
*/
inline HTEntry * HashTable_add(HashTable *table, void *key, void *value){
return HashTable_add_entry(table, HashTable_key_hash(table, key), key, value);
}
/** Remove entries satisfying a test from the bucket for the
* given hashcode.
*
* @param table to remove from
* @param hashcode indicates the bucket
* @param test_fn test to apply to elements
* @param arg first argument to calls to test_fn
* @return number of entries removed
*/
inline int HashTable_remove_entry(HashTable *table, Hashcode hashcode,
TableTestFn *test_fn, TableArg arg){
HTBucket *bucket;
HTEntry *entry, *prev = 0, *next;
int removed_count = 0;
bucket = get_bucket(table, hashcode);
for(entry = bucket->head; entry; entry = next){
next = entry->next;
if(test_fn(arg, table, entry)){
if(prev){
prev->next = next;
} else {
bucket->head = next;
}
bucket->count--;
table->entry_count--;
removed_count++;
HashTable_free_entry(table, entry);
entry = 0;
}
prev = entry;
}
return removed_count;
}
/** Remove entries with a given key.
*
* @param table to remove from
* @param key of entries to remove
* @return number of entries removed
*/
inline int HashTable_remove(HashTable *table, void *key){
#if 1
Hashcode hashcode;
HTBucket *bucket;
HTEntry *entry, *prev = 0, *next;
int removed_count = 0;
hashcode = HashTable_key_hash(table, key);
bucket = get_bucket(table, hashcode);
for(entry = bucket->head; entry; entry = next){
next = entry->next;
if(HashTable_key_equal(table, key, entry->key)){
if(prev){
prev->next = next;
} else {
bucket->head = next;
}
bucket->count--;
table->entry_count--;
removed_count++;
HashTable_free_entry(table, entry);
entry = 0;
}
prev = entry;
}
return removed_count;
#else
return HashTable_remove_entry(table, HashTable_key_hash(table, key),
has_key, (TableArg){ ptr: key});
#endif
}
/** Remove (and free) all the entries in a bucket.
*
* @param bucket to clear
*/
static inline void bucket_clear(HashTable *table, HTBucket *bucket){
HTEntry *entry, *next;
for(entry = bucket->head; entry; entry = next){
next = entry->next;
HashTable_free_entry(table, entry);
}
bucket->head = 0;
table->entry_count -= bucket->count;
bucket->count = 0;
}
/** Remove (and free) all the entries in a table.
*
* @param table to clear
*/
void HashTable_clear(HashTable *table){
int i, n = table->buckets_n;
for(i=0; i<n; i++){
bucket_clear(table, table->buckets + i);
}
}
+294
View File
@@ -0,0 +1,294 @@
/*
* Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _XUTIL_HASH_TABLE_H_
#define _XUTIL_HASH_TABLE_H_
#include "iostream.h"
typedef unsigned long Hashcode;
/** Type used to pass parameters to table functions. */
typedef union TableArg {
unsigned long ul;
void *ptr;
} TableArg;
/** An entry in a bucket list. */
typedef struct HTEntry {
/** Hashcode of the entry's key. */
Hashcode hashcode;
/** Identifier for this entry in the table. */
int index;
/** The key for this entry. */
void *key;
/** The value in this entry. */
void *value;
/** The next entry in the list. */
struct HTEntry *next;
} HTEntry;
/** A bucket in a rule table. */
typedef struct HTBucket {
/** Number of entries in the bucket. */
int count;
/** First entry in the bucket (may be null). */
HTEntry *head;
} HTBucket;
/** Default number of buckets in a hash table.
* You want enough buckets so the lists in the buckets will typically be short.
* It's a good idea if this is prime, since that will help to spread hashcodes
* around the table.
*/
//#define HT_BUCKETS_N 1
//#define HT_BUCKETS_N 3
//#define HT_BUCKETS_N 7
//#define HT_BUCKETS_N 17
//#define HT_BUCKETS_N 97
//#define HT_BUCKETS_N 211
//#define HT_BUCKETS_N 401
#define HT_BUCKETS_N 1021
typedef struct HashTable HashTable;
/** Type for a function used to select table entries. */
typedef int TableTestFn(TableArg arg, HashTable *table, HTEntry *entry);
/** Type for a function to map over table entries. */
typedef int TableMapFn(TableArg arg, HashTable *table, HTEntry *entry);
/** Type for a function to free table entries. */
typedef void TableFreeFn(HashTable *table, HTEntry *entry);
/** Type for a function to hash table keys. */
typedef Hashcode TableHashFn(void *key);
/** Type for a function to test table keys for equality. */
typedef int TableEqualFn(void *key1, void *key2);
/** Type for a function to order table entries. */
typedef int TableOrderFn(HTEntry *e1, HTEntry *e2);
/** General hash table.
* A hash table with a list in each bucket.
* Functions can be supplied for freeing entries, hashing keys, and comparing keys.
* These all default to 0, when default behaviour treating keys as integers is used.
*/
struct HashTable {
/** Flag indicating whether the table has been initialised. */
int init_done;
/** Next value for the id field in inserted rules. */
unsigned long next_id;
/** Number of buckets in the bucket array. */
int buckets_n;
/** Array of buckets, each with its own list. */
HTBucket *buckets;
/** Number of entries in the table. */
int entry_count;
/** Function to free keys and values in entries. */
TableFreeFn *entry_free_fn;
/** Function to hash keys. */
TableHashFn *key_hash_fn;
/** Function to compare keys for equality. */
TableEqualFn *key_equal_fn;
/** Place for the user of the table to hang extra data. */
void *user_data;
};
extern HashTable *HashTable_new(int bucket_n);
extern void HashTable_free(HashTable *table);
extern HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value);
extern void HTEntry_free(HTEntry *entry);
extern int HashTable_set_bucket_n(HashTable *table, int bucket_n);
extern void HashTable_clear(HashTable *table);
extern HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value);
extern HTEntry * HashTable_get_entry(HashTable *table, void *key);
extern HTEntry * HashTable_add(HashTable *table, void *key, void *value);
extern void * HashTable_get(HashTable *table, void *key);
extern int HashTable_remove(HashTable *table, void *key);
extern HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode,
TableTestFn *test_fn, TableArg arg);
extern int HashTable_remove_entry(HashTable *table, Hashcode hashcode,
TableTestFn *test_fn, TableArg arg);
//extern int HashTable_map(HashTable *table, TableMapFn *map_fn, TableArg arg);
extern void HashTable_print(HashTable *table, IOStream *out);
extern int HashTable_set_buckets_n(HashTable *table, int buckets_n);
extern int HashTable_adjust(HashTable *table, int buckets_min);
extern void pseudo_des(unsigned long *pleft, unsigned long *pright);
extern Hashcode hash_string(char *s);
extern int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order);
/** Control whether to use hashing based on DES or simple
* hashing. DES hashing is `more random' but much more expensive.
*/
#define HASH_PSEUDO_DES 0
/** Hash a long using a quick and dirty linear congruential random number generator.
* See `Numerical Recipes in C', Chapter 7, "An Even Quicker Generator".
*
* @param a value to hash
* @return hashed input
*/
static inline unsigned long lcrng_hash(unsigned long a){
return (1664525L * a + 1013904223L);
}
/** Hash an unsigned long.
*
* @param a input to hash
* @return hashcode
*/
static inline Hashcode hash_ul(unsigned long a){
#if HASH_PSEUDO_DES
unsigned long left = a;
unsigned long right = 0L;
pseudo_des(&left, &right);
return right;
#else
a = lcrng_hash(a);
a = lcrng_hash(a);
return a;
#endif
}
/** Hash two unsigned longs together.
*
* @param a input to hash
* @param b input to hash
* @return hashcode
*/
static inline Hashcode hash_2ul(unsigned long a, unsigned long b){
#if HASH_PSEUDO_DES
unsigned long left = a;
unsigned long right = b;
pseudo_des(&left, &right);
return right;
#else
a = lcrng_hash(a);
a ^= b;
a = lcrng_hash(a);
return a;
#endif
}
/** Hash a hashcode and an unsigned long together.
*
* @param a input hashcode
* @param b input to hash
* @return hashcode
*/
static inline Hashcode hash_hul(Hashcode a, unsigned long b){
#if HASH_PSEUDO_DES
unsigned long left = a;
unsigned long right = b;
pseudo_des(&left, &right);
return right;
#else
a ^= b;
a = lcrng_hash(a);
return a;
#endif
}
/** Macro to declare variables for HashTable_for_each() to use.
*
* @param entry variable that is set to entries in the table
*/
#define HashTable_for_decl(entry) \
HashTable *_var_table; \
HTBucket *_var_bucket; \
HTBucket *_var_end; \
HTEntry *_var_next; \
HTEntry *entry
/** Macro to iterate over the entries in a hashtable.
* Must be in a scope where HashTable_for_decl() has been used to declare
* variables for it to use.
* The variable 'entry' is iterated over entries in the table.
* The code produced is syntactically a loop, so it must be followed by
* a loop body, typically some statements in braces:
* HashTable_for_each(entry, table){ ...loop body... }
*
* HashTable_for_each() and HashTable_for_decl() cannot be used for nested
* loops as variables will clash.
*
* @note The simplest way to code a direct loop over the entries in a hashtable
* is to use a loop over the buckets, with a nested loop over the entries
* in a bucket. Using this approach in a macro means the macro contains
* an opening brace, and calls to it must be followed by 2 braces!
* To avoid this the code has been restructured so that it is a for loop.
* So that statements could be used in the test expression of the for loop,
* we have used the gcc statement expression extension ({ ... }).
*
* @param entry variable to iterate over the entries
* @param table to iterate over (non-null)
*/
#define HashTable_for_each(entry, table) \
_var_table = table; \
_var_bucket = _var_table->buckets; \
_var_end = _var_bucket + _var_table->buckets_n; \
for(entry=0, _var_next=0; \
({ if(_var_next){ \
entry = _var_next; \
_var_next = entry->next; \
} else { \
while(_var_bucket < _var_end){ \
entry = _var_bucket->head; \
_var_bucket++; \
if(entry){ \
_var_next = entry->next; \
break; \
} \
} \
}; \
entry; }); \
entry = _var_next )
/** Map a function over the entries in a table.
* Mapping stops when the function returns a non-zero value.
* Uses the gcc statement expression extension ({ ... }).
*
* @param table to map over
* @param fn function to apply to entries
* @param arg first argument to call the function with
* @return 0 if fn always returned 0, first non-zero value otherwise
*/
#define HashTable_map(table, fn, arg) \
({ HashTable_for_decl(_var_entry); \
TableArg _var_arg = arg; \
int _var_value = 0; \
HashTable_for_each(_var_entry, table){ \
if((_var_value = fn(_var_arg, _var_table, _var_entry))) break; \
} \
_var_value; })
/** Cast x to the type for a key or value in a hash table.
* This avoids compiler warnings when using short integers
* as keys or values (especially on 64-bit platforms).
*/
#define HKEY(x) ((void*)(unsigned long)(x))
/** Cast x from the type for a key or value in a hash table.
* to an unsigned long. This avoids compiler warnings when using
* short integers as keys or values (especially on 64-bit platforms).
*/
#define HVAL(x) ((unsigned long)(x))
#endif /* !_XUTIL_HASH_TABLE_H_ */
+93
View File
@@ -0,0 +1,93 @@
/*
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** @file
* Lexical analysis.
*/
#include "sys_string.h"
#include "lexis.h"
#include <errno.h>
/** Check if a value lies in a (closed) range.
*
* @param x value to test
* @param lo low end of the range
* @param hi high end of the range
* @return 1 if x is in the interval [lo, hi], 0 otherwise
*/
inline static int in_range(int x, int lo, int hi){
return (lo <= x) && (x <= hi);
}
/** Determine if a string is an (unsigned) decimal number.
*
* @param s pointer to characters to test
* @param n length of string
* @return 1 if s is a decimal number, 0 otherwise.
*/
int is_decimal_number(const char *s, int n){
int i;
if(n <= 0)return 0;
for(i = 0; i < n; i++){
if(!in_decimal_digit_class(s[i])) return 0;
}
return 1;
}
/** Determine if a string is a hex number.
* Hex numbers are 0, or start with 0x or 0X followed
* by a non-zero number of hex digits (0-9,a-f,A-F).
*
* @param s pointer to characters to test
* @param n length of string
* @return 1 if s is a hex number, 0 otherwise.
*/
int is_hex_number(const char *s, int n){
int i;
if(n <= 0) return 0;
if(n == 1){
return s[0]=='0';
}
if(n <= 3) return 0;
if(s[0] != '0' || (s[1] != 'x' && s[1] != 'X')) return 0;
for(i = 2; i < n; i++){
if(!in_hex_digit_class(s[i])) return 0;
}
return 1;
}
/** Test if a string matches a keyword.
* The comparison is case-insensitive.
* The comparison fails if either argument is null.
*
* @param s string
* @param k keyword
* @return 1 if they match, 0 otherwise
*/
int is_keyword(const char *s, const char *k){
return s && k && !strcasecmp(s, k);
}
/** Test if a string matches a character.
*
* @param s string
* @param c character (non-null)
* @return 1 if s contains exactly c, 0 otherwise
*/
int is_keychar(const char *s, char c){
return c && (s[0] == c) && !s[1];
}
+127
View File
@@ -0,0 +1,127 @@
/*
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _XUTIL_LEXIS_H_
#define _XUTIL_LEXIS_H_
#include "sys_string.h"
#ifdef __KERNEL__
# include <linux/ctype.h>
#else
# include <ctype.h>
#endif
/** @file
* Lexical analysis.
*/
/** Class of characters treated as space. */
#define space_class ((char []){ '\n', '\r', '\t', ' ', '\f' , 0 })
/** Class of separator characters. */
#define sep_class "{}()<>[]@!;"
#define comment_class "#"
/** Determine if a character is in a given class.
*
* @param c character to test
* @param s null-terminated string of characters in the class
* @return 1 if c is in the class, 0 otherwise.
*/
static inline int in_class(int c, const char *s){
return s && (strchr(s, c) != 0);
}
/** Determine if a character is in the space class.
*
* @param c character to test
* @return 1 if c is in the class, 0 otherwise.
*/
static inline int in_space_class(int c){
return in_class(c, space_class);
}
static inline int in_comment_class(int c){
return in_class(c, comment_class);
}
/** Determine if a character is in the separator class.
* Separator characters terminate tokens, and do not need space
* to separate them.
*
* @param c character to test
* @return 1 if c is in the class, 0 otherwise.
*/
static inline int in_sep_class(int c){
return in_class(c, sep_class);
}
/** Determine if a character is in the alpha class.
*
* @param c character to test
* @return 1 if c is in the class, 0 otherwise.
*/
static inline int in_alpha_class(int c){
return isalpha(c);
}
/** Determine if a character is in the octal digit class.
*
* @param c character to test
* @return 1 if c is in the class, 0 otherwise.
*/
static inline int in_octal_digit_class(int c){
return '0' <= c && c <= '7';
}
/** Determine if a character is in the decimal digit class.
*
* @param c character to test
* @return 1 if c is in the class, 0 otherwise.
*/
static inline int in_decimal_digit_class(int c){
return isdigit(c);
}
/** Determine if a character is in the hex digit class.
*
* @param c character to test
* @return 1 if c is in the class, 0 otherwise.
*/
static inline int in_hex_digit_class(int c){
return isdigit(c) || in_class(c, "abcdefABCDEF");
}
static inline int in_string_quote_class(int c){
return in_class(c, "'\"");
}
static inline int in_printable_class(int c){
return ('A' <= c && c <= 'Z')
|| ('a' <= c && c <= 'z')
|| ('0' <= c && c <= '9')
|| in_class(c, "!$%&*+,-./:;<=>?@^_`{|}~");
}
extern int is_decimal_number(const char *s, int n);
extern int is_hex_number(const char *s, int n);
extern int is_keyword(const char *s, const char *k);
extern int is_keychar(const char *s, char c);
#endif /* !_XUTIL_LEXIS_H_ */
+533
View File
@@ -0,0 +1,533 @@
/*
* Copyright (C) 2003 Hewlett-Packard Company.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** @file
* An IOStream implementation using LZI to provide compression and decompression.
* This is designed to provide compression without output latency.
* Flushing an LZI stream flushes all pending data to the underlying stream.
* This is essential for stream-based (e.g. networked) applications.
*
* A compressed data stream is a sequence of blocks.
* Each block is the block size followed by the compressed data.
* The last block has size zero.
* Sizes are 4-byte unsigned in network order.
*
* This format allows compressed data to be read from a stream without reading
* past the logical end of compressed data.
*
* @author Mike Wray <mike.wray@hpl.hp.com>
*/
#ifndef __KERNEL__
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include "zlib.h"
#include "allocate.h"
#include "lzi_stream.h"
#include "file_stream.h"
#include "marshal.h"
#define dprintf(fmt, args...) fprintf(stdout, "[DEBUG] LZI>%s" fmt, __FUNCTION__, ##args)
#define wprintf(fmt, args...) fprintf(stderr, "[WARN] LZI>%s" fmt, __FUNCTION__, ##args)
#define iprintf(fmt, args...) fprintf(stdout, "[INFO] LZI>%s" fmt, __FUNCTION__, ##args)
#define eprintf(fmt, args...) fprintf(stderr, "[ERROR] LZI>%s" fmt, __FUNCTION__, ##args)
static int lzi_read(IOStream *s, void *buf, size_t n);
static int lzi_write(IOStream *s, const void *buf, size_t n);
static int lzi_error(IOStream *s);
static int lzi_close(IOStream *s);
static void lzi_free(IOStream *s);
static int lzi_flush(IOStream *s);
enum {
LZI_WRITE = 1,
LZI_READ = 2,
};
/** Methods used by a gzFile* IOStream. */
static const IOMethods lzi_methods = {
read: lzi_read,
write: lzi_write,
error: lzi_error,
close: lzi_close,
free: lzi_free,
flush: lzi_flush,
};
#define BUFFER_SIZE (512 * 1024)
typedef struct LZIState {
z_stream zstream;
void *inbuf;
uint32_t inbuf_size;
void *outbuf;
uint32_t outbuf_size;
/** Underlying stream for I/O. */
IOStream *io;
/** Flags. */
int flags;
/** Error indicator. */
int error;
int eof;
int plain_bytes;
int comp_bytes;
int zstream_initialized;
int flushed;
} LZIState;
static inline int LZIState_writeable(LZIState *s){
return (s->flags & LZI_WRITE) != 0;
}
static inline int LZIState_readable(LZIState *s){
return (s->flags & LZI_READ) != 0;
}
void LZIState_free(LZIState *z){
if(!z) return;
if(z->zstream_initialized){
if(LZIState_writeable(z)){
deflateEnd(&z->zstream);
} else if(LZIState_readable(z)){
inflateEnd(&z->zstream);
}
}
deallocate(z->inbuf);
deallocate(z->outbuf);
deallocate(z);
}
static int mode_flags(const char *mode, int *flags){
int err = 0;
int r=0, w=0;
if(!mode){
err = -EINVAL;
goto exit;
}
for(; *mode; mode++){
if(*mode == 'w') w = 1;
if(*mode == 'r') r = 1;
}
if(r + w != 1){
err = -EINVAL;
goto exit;
}
if(r) *flags |= LZI_READ;
if(w) *flags |= LZI_WRITE;
exit:
return err;
}
/** Get the stream state.
*
* @param s lzi stream
* @return stream state.
*/
static inline LZIState * lzi_state(IOStream *io){
return (LZIState*)io->data;
}
IOStream *lzi_stream_io(IOStream *io){
LZIState *s = lzi_state(io);
return s->io;
}
static inline void set_error(LZIState *s, int err){
if(err < 0 && !s->error){
s->error = err;
}
}
static int zerror(LZIState *s, int err){
if(err){
//dprintf("> err=%d\n", err);
if(err < 0) set_error(s, -EIO);
}
return s->error;
}
int lzi_stream_plain_bytes(IOStream *io){
LZIState *s = lzi_state(io);
return s->plain_bytes;
}
int lzi_stream_comp_bytes(IOStream *io){
LZIState *s = lzi_state(io);
return s->comp_bytes;
}
float lzi_stream_ratio(IOStream *io){
LZIState *s = lzi_state(io);
float ratio = 0.0;
if(s->comp_bytes){
ratio = ((float) s->comp_bytes)/((float) s->plain_bytes);
}
return ratio;
}
static int alloc(void **p, int n){
*p = allocate(n);
return (p ? 0 : -ENOMEM);
}
LZIState * LZIState_new(IOStream *io, int flags){
int err = -ENOMEM;
int zlevel = Z_BEST_SPEED; // Level 1 compression - fastest.
int zstrategy = Z_DEFAULT_STRATEGY;
int zwindow = MAX_WBITS;
int zmemory = 8;
LZIState *z = ALLOCATE(LZIState);
//dprintf(">\n");
if(!z) goto exit;
z->io = io;
z->flags = flags;
if(LZIState_writeable(z)){
z->outbuf_size = BUFFER_SIZE;
/* windowBits is passed < 0 to suppress zlib header */
err = deflateInit2(&z->zstream, zlevel, Z_DEFLATED, -zwindow, zmemory, zstrategy);
if (err != Z_OK) goto exit;
z->zstream_initialized = 1;
err = alloc(&z->outbuf, z->outbuf_size);
if(err) goto exit;
z->zstream.next_out = z->outbuf;
z->zstream.avail_out = z->outbuf_size;
} else {
z->inbuf_size = BUFFER_SIZE;
err = alloc(&z->inbuf, z->inbuf_size);
if(err) goto exit;
///z->zstream.next_in = z->inbuf;
/* windowBits is passed < 0 to tell that there is no zlib header.
* Note that in this case inflate *requires* an extra "dummy" byte
* after the compressed stream in order to complete decompression and
* return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
* present after the compressed stream.
*/
err = inflateInit2(&z->zstream, -zwindow);
if(err != Z_OK) goto exit;
z->zstream_initialized = 1;
}
exit:
if(err){
LZIState_free(z);
z = NULL;
}
//dprintf("< z=%p\n", z);
return z;
}
int read_block(LZIState *s){
int err = 0, k = 0;
//dprintf(">\n");
if(s->eof) goto exit;
err = unmarshal_uint32(s->io, &k);
if(err) goto exit;
if(k > s->inbuf_size){
err = -EINVAL;
goto exit;
}
if(k){
err = unmarshal_bytes(s->io, s->inbuf, k);
if(err) goto exit;
} else {
s->eof = 1;
}
s->zstream.avail_in = k;
s->zstream.next_in = s->inbuf;
s->comp_bytes += 4;
s->comp_bytes += k;
exit:
//dprintf("< err=%d\n", err);
return err;
}
int write_block(LZIState *s){
int err = 0;
int k = ((char*)s->zstream.next_out) - ((char*)s->outbuf);
//int k2 = s->outbuf_size - s->zstream.avail_out;
//dprintf("> k=%d k2=%d\n", k, k2);
if(!k) goto exit;
err = marshal_uint32(s->io, k);
if(err) goto exit;
err = marshal_bytes(s->io, s->outbuf, k);
if(err) goto exit;
s->zstream.next_out = s->outbuf;
s->zstream.avail_out = s->outbuf_size;
s->comp_bytes += 4;
s->comp_bytes += k;
exit:
//dprintf("< err=%d\n", err);
return err;
}
int write_terminator(LZIState *s){
int err = 0;
char c = 0;
err = marshal_uint32(s->io, 1);
if(err) goto exit;
err = marshal_bytes(s->io, &c, 1);
if(err) goto exit;
err = marshal_uint32(s->io, 0);
if(err) goto exit;
s->comp_bytes += 9;
exit:
return err;
}
/** Write to the underlying stream using fwrite();
*
* @param io destination
* @param buf data
* @param n number of bytes to write
* @return number of bytes written
*/
static int lzi_write(IOStream *io, const void *buf, size_t n){
int err = 0;
LZIState *s = lzi_state(io);
//dprintf("> buf=%p n=%d\n", buf, n);
if(!LZIState_writeable(s)){
err = -EINVAL;
goto exit;
}
s->flushed = 0;
s->zstream.next_in = (void*)buf;
s->zstream.avail_in = n;
while(s->zstream.avail_in){
if(s->zstream.avail_out == 0){
err = write_block(s);
if(err) goto exit;
}
//dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
//dprintf("> 1 deflate next_in=%p next_out=%p\n", s->zstream.next_in, s->zstream.next_out);
err = zerror(s, deflate(&s->zstream, Z_NO_FLUSH));
//dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
//dprintf("> 2 deflate next_in=%p next_out=%p\n", s->zstream.next_in, s->zstream.next_out);
if(err) goto exit;
}
err = n;
s->plain_bytes += n;
exit:
//dprintf("< err=%d\n", err);
return err;
}
/** Read from the underlying stream.
*
* @param io input
* @param buf where to put input
* @param n number of bytes to read
* @return number of bytes read
*/
static int lzi_read(IOStream *io, void *buf, size_t n){
int err, zerr;
LZIState *s = lzi_state(io);
//dprintf("> n=%d\n", n);
if(!LZIState_readable(s)){
err = -EINVAL;
goto exit;
}
s->zstream.next_out = buf;
s->zstream.avail_out = n;
while(s->zstream.avail_out){
if(s->zstream.avail_in == 0){
err = read_block(s);
}
//dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
zerr = inflate(&s->zstream, Z_NO_FLUSH);
//dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
if(zerr == Z_STREAM_END) break;
//dprintf("> zerr=%d\n", zerr);
err = zerror(s, zerr);
if(err) goto exit;
}
err = n - s->zstream.avail_out;
s->plain_bytes += err;
exit:
set_error(s, err);
//dprintf("< err=%d\n", err);
return err;
}
static int flush_output(LZIState *s, int mode){
int err = 0, zerr;
int done = 0;
int avail_out_old;
//dprintf("> avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
if(s->flushed == 1 + mode) goto exit;
//s->zstream.avail_in = 0; /* should be zero already anyway */
for(;;){
// Write any available output.
if(done || s->zstream.avail_out == 0){
err = write_block(s);
if(err) goto exit;
if(done) break;
}
//dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
avail_out_old = s->zstream.avail_out;
zerr = deflate(&s->zstream, mode);
err = zerror(s, zerr);
//dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
//dprintf("> deflate=%d\n", err);
//done = (s->zstream.avail_out != 0);
//done = (s->zstream.avail_in == 0) && (s->zstream.avail_out == avail_out_old);
if(0 && mode == Z_FINISH){
done = (zerr == Z_STREAM_END);
} else {
done = (s->zstream.avail_in == 0)
//&& (s->zstream.avail_out == avail_out_old)
&& (s->zstream.avail_out != 0);
}
}
s->flushed = 1 + mode;
exit:
//dprintf("< err=%d\n", err);
return err;
}
/** Flush any pending input to the underlying stream.
*
* @param s lzi stream
* @return 0 on success, error code otherwise
*/
static int lzi_flush(IOStream *io){
int err = 0;
LZIState *s = lzi_state(io);
//dprintf(">\n");
if(!LZIState_writeable(s)){
err = -EINVAL;
goto exit;
}
err = flush_output(s, Z_SYNC_FLUSH);
if(err) goto exit;
err = IOStream_flush(s->io);
exit:
set_error(s, err);
//dprintf("< err=%d\n", err);
return (err < 0 ? err : 0);
}
/** Check if a stream has an error.
*
* @param s lzi stream
* @return code if has an error, 0 otherwise
*/
static int lzi_error(IOStream *s){
int err = 0;
LZIState *state = lzi_state(s);
err = state->error;
if(err) goto exit;
err = IOStream_error(state->io);
exit:
return err;
}
/** Close an lzi stream.
*
* @param s lzi stream to close
* @return result of the close
*/
static int lzi_close(IOStream *io){
int err = 0;
LZIState *s = lzi_state(io);
if(LZIState_writeable(s)){
err = flush_output(s, Z_FINISH);
if(err) goto exit;
err = write_terminator(s);
if(err) goto exit;
err = IOStream_flush(s->io);
}
exit:
err = IOStream_close(s->io);
set_error(s, err);
return err;
}
/** Free an lzi stream.
*
* @param s lzi stream
*/
static void lzi_free(IOStream *s){
LZIState *state = lzi_state(s);
IOStream_free(state->io);
LZIState_free(state);
s->data = NULL;
}
/** Create an lzi stream for an IOStream.
*
* @param io stream to wrap
* @return new IOStream using f for i/o
*/
IOStream *lzi_stream_new(IOStream *io, const char *mode){
int err = -ENOMEM;
int flags = 0;
IOStream *zio = NULL;
LZIState *state = NULL;
zio = ALLOCATE(IOStream);
if(!zio) goto exit;
err = mode_flags(mode, &flags);
if(err) goto exit;
state = LZIState_new(io, flags);
if(!state) goto exit;
err = 0;
zio->data = state;
zio->methods = &lzi_methods;
exit:
if(err){
if(state) LZIState_free(state);
if(zio) deallocate(zio);
zio = NULL;
}
return zio;
}
/** IOStream version of fdopen().
*
* @param fd file descriptor
* @param flags giving the mode to open in (as for fdopen())
* @return new stream for the open file, or NULL if failed
*/
IOStream *lzi_stream_fdopen(int fd, const char *mode){
int err = -ENOMEM;
IOStream *io = NULL, *zio = NULL;
io = file_stream_fdopen(fd, mode);
if(!io) goto exit;
zio = lzi_stream_new(io, mode);
if(!io) goto exit;
err = 0;
exit:
if(err){
IOStream_free(io);
IOStream_free(zio);
zio = NULL;
}
return zio;
}
#endif
+35
View File
@@ -0,0 +1,35 @@
/*
* Copyright (C) 2003 Hewlett-Packard Company.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _XUTIL_LZI_STREAM_H_
#define _XUTIL_LZI_STREAM_H_
#ifndef __KERNEL__
#include "iostream.h"
extern IOStream *lzi_stream_new(IOStream *io, const char *mode);
extern IOStream *lzi_stream_fopen(const char *file, const char *mode);
extern IOStream *lzi_stream_fdopen(int fd, const char *mode);
extern IOStream *lzi_stream_io(IOStream *zio);
extern int lzi_stream_plain_bytes(IOStream *io);
extern int lzi_stream_comp_bytes(IOStream *io);
extern float lzi_stream_ratio(IOStream *io);
#endif
#endif /* !_XUTIL_LZI_STREAM_H_ */
+207
View File
@@ -0,0 +1,207 @@
#include <errno.h>
#include "sys_net.h"
#include "allocate.h"
#include "marshal.h"
#define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args)
#define wprintf(fmt, args...) IOStream_print(iostderr, "[WARN] %s" fmt, __FUNCTION__, ##args)
#define iprintf(fmt, args...) IOStream_print(iostdout, "[INFO] %s" fmt, __FUNCTION__, ##args)
#define eprintf(fmt, args...) IOStream_print(iostderr, "[ERROR] %s" fmt, __FUNCTION__, ##args)
#define ARRAY_SIZE(ary) (sizeof(ary)/sizeof((ary)[0]))
/* Messages are coded as msgid followed by message fields.
* Initial message on any channel is hello - so can check version
* compatibility.
*
* char* -> uint16_t:n <n bytes>
* ints/uints go as suitable number of bytes (e.g. uint16_t is 2 bytes).
* optional fields go as '1' <val> or '0' (the 0/1 is 1 byte).
* lists go as ('1' <elt>)* '0'
*/
int marshal_flush(IOStream *io){
int err = 0;
err = IOStream_flush(io);
return err;
}
int marshal_bytes(IOStream *io, void *s, uint32_t s_n){
int err = 0;
int n;
n = IOStream_write(io, s, s_n);
if(n < 0){
err = n;
} else if (n < s_n){
wprintf("> Wanted %d, got %d\n", s_n, n);
err = -EIO;
}
return err;
}
int unmarshal_bytes(IOStream *io, void *s, uint32_t s_n){
int err = 0;
int n;
//dprintf("> s_n=%d\n", s_n);
n = IOStream_read(io, s, s_n);
//dprintf("> n=%d\n", n);
if(n < 0){
err = n;
} else if(n < s_n){
wprintf("> Wanted %d, got %d\n", s_n, n);
err = -EIO;
}
//dprintf("< err=%d\n", err);
return err;
}
int marshal_uint8(IOStream *io, uint8_t x){
return marshal_bytes(io, &x, sizeof(x));
}
int unmarshal_uint8(IOStream *io, uint8_t *x){
return unmarshal_bytes(io, x, sizeof(*x));
}
int marshal_uint16(IOStream *io, uint16_t x){
x = htons(x);
return marshal_bytes(io, &x, sizeof(x));
}
int unmarshal_uint16(IOStream *io, uint16_t *x){
int err = 0;
err = unmarshal_bytes(io, x, sizeof(*x));
*x = ntohs(*x);
return err;
}
int marshal_int32(IOStream *io, int32_t x){
int err = 0;
//dprintf("> x=%d\n", x);
x = htonl(x);
err = marshal_bytes(io, &x, sizeof(x));
//dprintf("< err=%d\n", err);
return err;
}
int unmarshal_int32(IOStream *io, int32_t *x){
int err = 0;
//dprintf(">\n");
err = unmarshal_bytes(io, x, sizeof(*x));
*x = ntohl(*x);
//dprintf("< err=%d x=%d\n", err, *x);
return err;
}
int marshal_uint32(IOStream *io, uint32_t x){
int err = 0;
//dprintf("> x=%u\n", x);
x = htonl(x);
err = marshal_bytes(io, &x, sizeof(x));
//dprintf("< err=%d\n", err);
return err;
}
int unmarshal_uint32(IOStream *io, uint32_t *x){
int err = 0;
//dprintf(">\n");
err = unmarshal_bytes(io, x, sizeof(*x));
*x = ntohl(*x);
//dprintf("< err=%d x=%u\n", err, *x);
return err;
}
int marshal_uint64(IOStream *io, uint64_t x){
int err;
err = marshal_uint32(io, (uint32_t) ((x >> 32) & 0xffffffff));
if(err) goto exit;
err = marshal_uint32(io, (uint32_t) ( x & 0xffffffff));
exit:
return err;
}
int unmarshal_uint64(IOStream *io, uint64_t *x){
int err = 0;
uint32_t hi, lo;
err = unmarshal_uint32(io, &hi);
if(err) goto exit;
err = unmarshal_uint32(io, &lo);
*x = (((uint64_t) hi) << 32) | lo;
exit:
return err;
}
int marshal_net16(IOStream *io, net16_t x){
return marshal_bytes(io, &x, sizeof(x));
}
int unmarshal_net16(IOStream *io, net16_t *x){
int err = 0;
err = unmarshal_bytes(io, x, sizeof(*x));
return err;
}
int marshal_net32(IOStream *io, net32_t x){
return marshal_bytes(io, &x, sizeof(x));
}
int unmarshal_net32(IOStream *io, net32_t *x){
int err = 0;
err = unmarshal_bytes(io, x, sizeof(*x));
return err;
}
int marshal_string(IOStream *io, char *s, uint32_t s_n){
int err;
//dprintf("> s=%s\n", s);
err = marshal_uint32(io, s_n);
if(err) goto exit;
err = marshal_bytes(io, s, s_n);
exit:
//dprintf("< err=%d\n", err);
return err;
}
int unmarshal_string(IOStream *io, char *s, uint32_t s_n){
int err = 0, val_n = 0;
//dprintf(">\n");
err = unmarshal_uint32(io, &val_n);
if(err) goto exit;
if(val_n >= s_n){
err = -EINVAL;
goto exit;
}
err = unmarshal_bytes(io, s, val_n);
if(err) goto exit;
s[val_n] = '\0';
exit:
//dprintf("< err=%d s=%s\n", err, s);
return err;
}
int unmarshal_new_string(IOStream *io, char **s, uint32_t *s_n){
int err = 0, val_n = 0;
char *val = NULL;
//dprintf(">\n");
err = unmarshal_uint32(io, &val_n);
if(err) goto exit;
val = allocate(val_n + 1);
if(!val){
err = -ENOMEM;
goto exit;
}
err = unmarshal_bytes(io, val, val_n);
if(err) goto exit;
val[val_n] = '\0';
exit:
if(err){
if(val) deallocate(val);
val = NULL;
val_n = 0;
}
*s = val;
if(s_n) *s_n = val_n;
//dprintf("< err=%d s=%s\n", err, *s);
return err;
}
+42
View File
@@ -0,0 +1,42 @@
#ifndef _XUTIL_MARSHAL_H_
#define _XUTIL_MARSHAL_H_
#include "iostream.h"
/** A 16-bit uint in network order, e.g. a port number. */
typedef uint16_t net16_t;
/** A 32-bit uint in network order, e.g. an IP address. */
typedef uint32_t net32_t;
extern int marshal_flush(IOStream *io);
extern int marshal_bytes(IOStream *io, void *s, uint32_t s_n);
extern int unmarshal_bytes(IOStream *io, void *s, uint32_t s_n);
extern int marshal_uint8(IOStream *io, uint8_t x);
extern int unmarshal_uint8(IOStream *io, uint8_t *x);
extern int marshal_uint16(IOStream *io, uint16_t x);
extern int unmarshal_uint16(IOStream *io, uint16_t *x);
extern int marshal_uint32(IOStream *io, uint32_t x);
extern int unmarshal_uint32(IOStream *io, uint32_t *x);
extern int marshal_int32(IOStream *io, int32_t x);
extern int unmarshal_int32(IOStream *io, int32_t *x);
extern int marshal_uint64(IOStream *io, uint64_t x);
extern int unmarshal_uint64(IOStream *io, uint64_t *x);
extern int marshal_net16(IOStream *io, net16_t x);
extern int unmarshal_net16(IOStream *io, net16_t *x);
extern int marshal_net32(IOStream *io, net32_t x);
extern int unmarshal_net32(IOStream *io, net32_t *x);
extern int marshal_string(IOStream *io, char *s, uint32_t s_n);
extern int unmarshal_string(IOStream *io, char *s, uint32_t s_n);
extern int unmarshal_new_string(IOStream *io, char **s, uint32_t *s_n);
#endif /* ! _XUTIL_MARSHAL_H_ */
+50
View File
@@ -0,0 +1,50 @@
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include "select.h"
/** Zero all the file descriptor sets.
*
* @param set select set
* @param fd file descriptor
* @return 0 on success, -1 otherwise
*/
void SelectSet_zero(SelectSet *set){
set->n = 0;
FD_ZERO(&set->rd);
FD_ZERO(&set->wr);
FD_ZERO(&set->er);
}
/** Add a file descriptor to the write set.
*
* @param set select set
* @param fd file descriptor
* @return 0 on success, -1 otherwise
*/
void SelectSet_add_read(SelectSet *set, int fd){
FD_SET(fd, &set->rd);
if(fd > set->n) set->n = fd;
}
/** Add a file descriptor to the write set.
*
* @param set select set
* @param fd file descriptor
* @return 0 on success, -1 otherwise
*/
void SelectSet_add_write(SelectSet *set, int fd){
FD_SET(fd, &set->wr);
if(fd > set->n) set->n = fd;
}
/** Select on file descriptors.
*
* @param set select set
* @param timeout timeout (may be NULL for no timeout)
* @return 0 on success, -1 otherwise
*/
int SelectSet_select(SelectSet *set, struct timeval *timeout){
return select(set->n+1, &set->rd, &set->wr, &set->er, timeout);
}
+16
View File
@@ -0,0 +1,16 @@
#ifndef _XFRD_SELECT_H_
#define _XFRD_SELECT_H_
/** Set of file descriptors for select.
*/
typedef struct SelectSet {
int n;
fd_set rd, wr, er;
} SelectSet;
extern void SelectSet_zero(SelectSet *set);
extern void SelectSet_add_read(SelectSet *set, int fd);
extern void SelectSet_add_write(SelectSet *set, int fd);
extern int SelectSet_select(SelectSet *set, struct timeval *timeout);
#endif /* ! _XFRD_SELECT_H_ */
+950
View File
@@ -0,0 +1,950 @@
/*
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdarg.h>
#include "sys_string.h"
#include "lexis.h"
#include "sys_net.h"
#include "hash_table.h"
#include "sxpr.h"
#include <errno.h>
#undef free
/** @file
* General representation of sxprs.
* Includes print, equal, and free functions for the sxpr types.
*
* Zero memory containing an Sxpr will have the value ONONE - this is intentional.
* When a function returning an sxpr cannot allocate memory we return ONOMEM.
*
*/
static int atom_print(IOStream *io, Sxpr obj, unsigned flags);
static int atom_equal(Sxpr x, Sxpr y);
static void atom_free(Sxpr obj);
static int string_print(IOStream *io, Sxpr obj, unsigned flags);
static int string_equal(Sxpr x, Sxpr y);
static void string_free(Sxpr obj);
static int cons_print(IOStream *io, Sxpr obj, unsigned flags);
static int cons_equal(Sxpr x, Sxpr y);
static void cons_free(Sxpr obj);
static int null_print(IOStream *io, Sxpr obj, unsigned flags);
static int none_print(IOStream *io, Sxpr obj, unsigned flags);
static int int_print(IOStream *io, Sxpr obj, unsigned flags);
static int bool_print(IOStream *io, Sxpr obj, unsigned flags);
/** Type definitions. */
static SxprType types[1024] = {
[T_NONE] { type: T_NONE, name: "none", print: none_print },
[T_NULL] { type: T_NULL, name: "null", print: null_print },
[T_UINT] { type: T_UINT, name: "int", print: int_print, },
[T_BOOL] { type: T_BOOL, name: "bool", print: bool_print, },
[T_ATOM] { type: T_ATOM, name: "atom", print: atom_print,
pointer: TRUE,
free: atom_free,
equal: atom_equal,
},
[T_STRING] { type: T_STRING, name: "string", print: string_print,
pointer: TRUE,
free: string_free,
equal: string_equal,
},
[T_CONS] { type: T_CONS, name: "cons", print: cons_print,
pointer: TRUE,
free: cons_free,
equal: cons_equal,
},
};
/** Number of entries in the types array. */
static int type_sup = sizeof(types)/sizeof(types[0]);
/** Get the type definition for a given type code.
*
* @param ty type code
* @return type definition or null
*/
SxprType *get_sxpr_type(int ty){
if(0 <= ty && ty < type_sup){
return types+ty;
}
return NULL;
}
/** The default print function.
*
* @param io stream to print to
* @param x sxpr to print
* @param flags print flags
* @return number of bytes written on success
*/
int default_print(IOStream *io, Sxpr x, unsigned flags){
return IOStream_print(io, "#<%u %lu>\n", get_type(x), get_ul(x));
}
/** The default equal function.
* Uses eq().
*
* @param x sxpr to compare
* @param y sxpr to compare
* @return 1 if equal, 0 otherwise
*/
int default_equal(Sxpr x, Sxpr y){
return eq(x, y);
}
/** General sxpr print function.
* Prints an sxpr on a stream using the print function for the sxpr type.
* Printing is controlled by flags from the PrintFlags enum.
* If PRINT_TYPE is in the flags the sxpr type is printed before the sxpr
* (for debugging).
*
* @param io stream to print to
* @param x sxpr to print
* @param flags print flags
* @return number of bytes written
*/
int objprint(IOStream *io, Sxpr x, unsigned flags){
SxprType *def = get_sxpr_type(get_type(x));
ObjPrintFn *print_fn = (def && def->print ? def->print : default_print);
int k = 0;
if(!io) return k;
if(flags & PRINT_TYPE){
k += IOStream_print(io, "%s:", def->name);
}
k += print_fn(io, x, flags);
return k;
}
/** General sxpr free function.
* Frees an sxpr using the free function for its type.
* Free functions must recursively free any subsxprs.
* If no function is defined then the default is to
* free sxprs whose type has pointer true.
* Sxprs must not be used after freeing.
*
* @param x sxpr to free
*/
void objfree(Sxpr x){
SxprType *def = get_sxpr_type(get_type(x));
if(def){
if(def->free){
def->free(x);
} else if (def->pointer){
hfree(x);
}
}
}
/** General sxpr equality function.
* Compares x and y using the equal function for x.
* Uses default_equal() if x has no equal function.
*
* @param x sxpr to compare
* @param y sxpr to compare
* @return 1 if equal, 0 otherwise
*/
int objequal(Sxpr x, Sxpr y){
SxprType *def = get_sxpr_type(get_type(x));
ObjEqualFn *equal_fn = (def && def->equal ? def->equal : default_equal);
return equal_fn(x, y);
}
/** Search for a key in an alist.
* An alist is a list of conses, where the cars
* of the conses are the keys. Compares keys using equality.
*
* @param k key
* @param l alist to search
* @return first element of l with car k, or ONULL
*/
Sxpr assoc(Sxpr k, Sxpr l){
for( ; CONSP(l) ; l = CDR(l)){
Sxpr x = CAR(l);
if(CONSP(x) && objequal(k, CAR(x))){
return x;
}
}
return ONULL;
}
/** Search for a key in an alist.
* An alist is a list of conses, where the cars
* of the conses are the keys. Compares keys using eq.
*
* @param k key
* @param l alist to search
* @return first element of l with car k, or ONULL
*/
Sxpr assocq(Sxpr k, Sxpr l){
for( ; CONSP(l); l = CDR(l)){
Sxpr x = CAR(l);
if(CONSP(x) && eq(k, CAR(x))){
return x;
}
}
return ONULL;
}
/** Add a new key and value to an alist.
*
* @param k key
* @param l value
* @param l alist
* @return l with the new cell added to the front
*/
Sxpr acons(Sxpr k, Sxpr v, Sxpr l){
Sxpr x, y;
x = cons_new(k, v);
if(NOMEMP(x)) return x;
y = cons_new(x, l);
if(NOMEMP(y)) cons_free_cells(x);
return y;
}
/** Test if a list contains an element.
* Uses sxpr equality.
*
* @param l list
* @param x element to look for
* @return a tail of l with x as car, or ONULL
*/
Sxpr cons_member(Sxpr l, Sxpr x){
for( ; CONSP(l) && !eq(x, CAR(l)); l = CDR(l)){}
return l;
}
/** Test if a list contains an element satisfying a test.
* The test function is called with v and an element of the list.
*
* @param l list
* @param test_fn test function to use
* @param v value for first argument to the test
* @return a tail of l with car satisfying the test, or 0
*/
Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){
for( ; CONSP(l) && !test_fn(v, CAR(l)); l = CDR(l)){ }
return l;
}
/** Test if the elements of list 't' are a subset of the elements
* of list 's'. Element order is not significant.
*
* @param s element list to check subset of
* @param t element list to check if is a subset
* @return 1 if is a subset, 0 otherwise
*/
int cons_subset(Sxpr s, Sxpr t){
for( ; CONSP(t); t = CDR(t)){
if(!CONSP(cons_member(s, CAR(t)))){
return 0;
}
}
return 1;
}
/** Test if two lists have equal sets of elements.
* Element order is not significant.
*
* @param s list to check
* @param t list to check
* @return 1 if equal, 0 otherwise
*/
int cons_set_equal(Sxpr s, Sxpr t){
return cons_subset(s, t) && cons_subset(t, s);
}
#ifdef USE_GC
/*============================================================================*/
/* The functions inside this ifdef are only safe if GC is used.
* Otherwise they may leak memory.
*/
/** Remove an element from a list (GC only).
* Uses sxpr equality and removes all instances, even
* if there are more than one.
*
* @param l list to remove elements from
* @param x element to remove
* @return modified input list
*/
Sxpr cons_remove(Sxpr l, Sxpr x){
return cons_remove_if(l, eq, x);
}
/** Remove elements satisfying a test (GC only).
* The test function is called with v and an element of the set.
*
* @param l list to remove elements from
* @param test_fn function to use to decide if an element should be removed
* @return modified input list
*/
Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){
Sxpr prev = ONULL, elt, next;
for(elt = l; CONSP(elt); elt = next){
next = CDR(elt);
if(test_fn(v, CAR(elt))){
if(NULLP(prev)){
l = next;
} else {
CDR(prev) = next;
}
}
}
return l;
}
/** Set the value for a key in an alist (GC only).
* If the key is present, changes the value, otherwise
* adds a new cell.
*
* @param k key
* @param v value
* @param l alist
* @return modified or extended list
*/
Sxpr setf(Sxpr k, Sxpr v, Sxpr l){
Sxpr e = assoc(k, l);
if(NULLP(e)){
l = acons(k, v, l);
} else {
CAR(CDR(e)) = v;
}
return l;
}
/*============================================================================*/
#endif /* USE_GC */
/** Create a new atom with the given name.
*
* @param name the name
* @return new atom
*/
Sxpr atom_new(char *name){
Sxpr n, obj = ONOMEM;
n = string_new(name);
if(NOMEMP(n)) goto exit;
obj = HALLOC(ObjAtom, T_ATOM);
if(NOMEMP(obj)) goto exit;
OBJ_ATOM(obj)->name = n;
exit:
return obj;
}
/** Free an atom.
*
* @param obj to free
*/
void atom_free(Sxpr obj){
// Interned atoms are shared, so do not free.
if(OBJ_ATOM(obj)->interned) return;
objfree(OBJ_ATOM(obj)->name);
hfree(obj);
}
/** Print an atom. Prints the atom name.
*
* @param io stream to print to
* @param obj to print
* @param flags print flags
* @return number of bytes printed
*/
int atom_print(IOStream *io, Sxpr obj, unsigned flags){
//return string_print(io, OBJ_ATOM(obj)->name, (flags | PRINT_RAW));
return string_print(io, OBJ_ATOM(obj)->name, flags);
}
/** Atom equality.
*
* @param x to compare
* @param y to compare
* @return 1 if equal, 0 otherwise
*/
int atom_equal(Sxpr x, Sxpr y){
int ok;
ok = eq(x, y);
if(ok) goto exit;
ok = ATOMP(y) && string_equal(OBJ_ATOM(x)->name, OBJ_ATOM(y)->name);
if(ok) goto exit;
ok = STRINGP(y) && string_equal(OBJ_ATOM(x)->name, y);
exit:
return ok;
}
/** Get the name of an atom.
*
* @param obj atom
* @return name
*/
char * atom_name(Sxpr obj){
return string_string(OBJ_ATOM(obj)->name);
}
/** Get the C string from a string sxpr.
*
* @param obj string sxpr
* @return string
*/
char * string_string(Sxpr obj){
return OBJ_STRING(obj);
}
/** Get the length of a string.
*
* @param obj string
* @return length
*/
int string_length(Sxpr obj){
return strlen(OBJ_STRING(obj));
}
/** Create a new string. The input string is copied,
* and must be null-terminated.
*
* @param s characters to put in the string
* @return new sxpr
*/
Sxpr string_new(char *s){
int n = (s ? strlen(s) : 0);
Sxpr obj;
obj = halloc(n+1, T_STRING);
if(!NOMEMP(obj)){
char *str = OBJ_STRING(obj);
strncpy(str, s, n);
str[n] = '\0';
}
return obj;
}
/** Free a string.
*
* @param obj to free
*/
void string_free(Sxpr obj){
hfree(obj);
}
/** Determine if a string needs escapes when printed
* using the given flags.
*
* @param str string to check
* @param flags print flags
* @return 1 if needs escapes, 0 otherwise
*/
int needs_escapes(char *str, unsigned flags){
char *c;
int val = 0;
if(str){
for(c=str; *c; c++){
if(in_alpha_class(*c)) continue;
if(in_decimal_digit_class(*c)) continue;
if(in_class(*c, "/._+:@~-")) continue;
val = 1;
break;
}
}
//printf("\n> val=%d str=|%s|\n", val, str);
return val;
}
/** Print a string to a stream, with escapes if necessary.
*
* @param io stream to print to
* @param str string
* @param flags print flags
* @return number of bytes written
*/
int _string_print(IOStream *io, char *str, unsigned flags){
int k = 0;
if((flags & PRINT_RAW) || !needs_escapes(str, flags)){
k += IOStream_print(io, str);
} else {
k += IOStream_print(io, "\"");
if(str){
char *s;
for(s = str; *s; s++){
if(*s < ' ' || *s >= 127 ){
switch(*s){
case '\a': k += IOStream_print(io, "\\a"); break;
case '\b': k += IOStream_print(io, "\\b"); break;
case '\f': k += IOStream_print(io, "\\f"); break;
case '\n': k += IOStream_print(io, "\\n"); break;
case '\r': k += IOStream_print(io, "\\r"); break;
case '\t': k += IOStream_print(io, "\\t"); break;
case '\v': k += IOStream_print(io, "\\v"); break;
default:
// Octal escape;
k += IOStream_print(io, "\\%o", *s);
break;
}
} else if(*s == c_double_quote ||
*s == c_single_quote ||
*s == c_escape){
k += IOStream_print(io, "\\%c", *s);
} else {
k+= IOStream_print(io, "%c", *s);
}
}
}
k += IOStream_print(io, "\"");
}
return k;
}
/** Print a string to a stream, with escapes if necessary.
*
* @param io stream to print to
* @param obj string
* @param flags print flags
* @return number of bytes written
*/
int string_print(IOStream *io, Sxpr obj, unsigned flags){
return _string_print(io, OBJ_STRING(obj), flags);
}
/** Compare an sxpr with a string for equality.
*
* @param x string to compare with
* @param y sxpr to compare
* @return 1 if equal, 0 otherwise
*/
int string_equal(Sxpr x, Sxpr y){
int ok = 0;
ok = eq(x,y);
if(ok) goto exit;
ok = has_type(y, T_STRING) && !strcmp(OBJ_STRING(x), OBJ_STRING(y));
if(ok) goto exit;
ok = has_type(y, T_ATOM) && !strcmp(OBJ_STRING(x), atom_name(y));
exit:
return ok;
}
/** Create a new cons cell.
* The cell is ONOMEM if either argument is.
*
* @param car sxpr for the car
* @param cdr sxpr for the cdr
* @return new cons
*/
Sxpr cons_new(Sxpr car, Sxpr cdr){
Sxpr obj;
if(NOMEMP(car) || NOMEMP(cdr)){
obj = ONOMEM;
} else {
obj = HALLOC(ObjCons, T_CONS);
if(!NOMEMP(obj)){
ObjCons *z = OBJ_CONS(obj);
z->car = car;
z->cdr = cdr;
}
}
return obj;
}
/** Push a new element onto a list.
*
* @param list list to add to
* @param elt element to add
* @return 0 if successful, error code otherwise
*/
int cons_push(Sxpr *list, Sxpr elt){
Sxpr l;
l = cons_new(elt, *list);
if(NOMEMP(l)) return -ENOMEM;
*list = l;
return 0;
}
/** Free a cons. Recursively frees the car and cdr.
*
* @param obj to free
*/
void cons_free(Sxpr obj){
Sxpr next;
for(; CONSP(obj); obj = next){
next = CDR(obj);
objfree(CAR(obj));
hfree(obj);
}
if(!NULLP(obj)){
objfree(obj);
}
}
/** Free a cons and its cdr cells, but not the car sxprs.
* Does nothing if called on something that is not a cons.
*
* @param obj to free
*/
void cons_free_cells(Sxpr obj){
Sxpr next;
for(; CONSP(obj); obj = next){
next = CDR(obj);
hfree(obj);
}
}
/** Print a cons.
* Prints the cons in list format if the cdrs are conses.
* uses pair (dot) format if the last cdr is not a cons (or null).
*
* @param io stream to print to
* @param obj to print
* @param flags print flags
* @return number of bytes written
*/
int cons_print(IOStream *io, Sxpr obj, unsigned flags){
int first = 1;
int k = 0;
k += IOStream_print(io, "(");
for( ; CONSP(obj) ; obj = CDR(obj)){
if(first){
first = 0;
} else {
k += IOStream_print(io, " ");
}
k += objprint(io, CAR(obj), flags);
}
if(!NULLP(obj)){
k += IOStream_print(io, " . ");
k += objprint(io, obj, flags);
}
k += IOStream_print(io, ")");
return (IOStream_error(io) ? -1 : k);
}
/** Compare a cons with another sxpr for equality.
* If y is a cons, compares the cars and cdrs recursively.
*
* @param x cons to compare
* @param y sxpr to compare
* @return 1 if equal, 0 otherwise
*/
int cons_equal(Sxpr x, Sxpr y){
return CONSP(y) &&
objequal(CAR(x), CAR(y)) &&
objequal(CDR(x), CDR(y));
}
/** Return the length of a cons list.
*
* @param obj list
* @return length
*/
int cons_length(Sxpr obj){
int count = 0;
for( ; CONSP(obj); obj = CDR(obj)){
count++;
}
return count;
}
/** Destructively reverse a cons list in-place.
* If the argument is not a cons it is returned unchanged.
*
* @param l to reverse
* @return reversed list
*/
Sxpr nrev(Sxpr l){
if(CONSP(l)){
// Iterate down the cells in the list making the cdr of
// each cell point to the previous cell. The last cell
// is the head of the reversed list.
Sxpr prev = ONULL;
Sxpr cell = l;
Sxpr next;
while(1){
next = CDR(cell);
CDR(cell) = prev;
if(!CONSP(next)) break;
prev = cell;
cell = next;
}
l = cell;
}
return l;
}
/** Print the null sxpr.
*
* @param io stream to print to
* @param obj to print
* @param flags print flags
* @return number of bytes written
*/
static int null_print(IOStream *io, Sxpr obj, unsigned flags){
return IOStream_print(io, "()");
}
/** Print the `unspecified' sxpr none.
*
* @param io stream to print to
* @param obj to print
* @param flags print flags
* @return number of bytes written
*/
static int none_print(IOStream *io, Sxpr obj, unsigned flags){
return IOStream_print(io, "<none>");
}
/** Print an integer.
*
* @param io stream to print to
* @param obj to print
* @param flags print flags
* @return number of bytes written
*/
static int int_print(IOStream *io, Sxpr obj, unsigned flags){
return IOStream_print(io, "%d", OBJ_INT(obj));
}
/** Print a boolean.
*
* @param io stream to print to
* @param obj to print
* @param flags print flags
* @return number of bytes written
*/
static int bool_print(IOStream *io, Sxpr obj, unsigned flags){
return IOStream_print(io, (OBJ_UINT(obj) ? k_true : k_false));
}
int sxprp(Sxpr obj, Sxpr name){
return CONSP(obj) && objequal(CAR(obj), name);
}
/** Get the name of an element.
*
* @param obj element
* @return name
*/
Sxpr sxpr_name(Sxpr obj){
Sxpr val = ONONE;
if(CONSP(obj)){
val = CAR(obj);
} else if(STRINGP(obj) || ATOMP(obj)){
val = obj;
}
return val;
}
int sxpr_is(Sxpr obj, char *s){
if(ATOMP(obj)) return !strcmp(atom_name(obj), s);
if(STRINGP(obj)) return !strcmp(string_string(obj), s);
return 0;
}
int sxpr_elementp(Sxpr obj, Sxpr name){
int ok = 0;
ok = CONSP(obj) && objequal(CAR(obj), name);
return ok;
}
/** Get the attributes of an sxpr.
*
* @param obj sxpr
* @return attributes
*/
Sxpr sxpr_attributes(Sxpr obj){
Sxpr val = ONULL;
if(CONSP(obj)){
obj = CDR(obj);
if(CONSP(obj)){
obj = CAR(obj);
if(sxprp(obj, intern("@"))){
val = CDR(obj);
}
}
}
return val;
}
Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def){
Sxpr val = ONONE;
val = assoc(sxpr_attributes(obj), key);
if(CONSP(val) && CONSP(CDR(val))){
val = CADR(def);
} else {
val = def;
}
return val;
}
/** Get the children of an sxpr.
*
* @param obj sxpr
* @return children
*/
Sxpr sxpr_children(Sxpr obj){
Sxpr val = ONULL;
if(CONSP(obj)){
val = CDR(obj);
if(CONSP(val) && sxprp(CAR(val), intern("@"))){
val = CDR(val);
}
}
return val;
}
Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def){
Sxpr val = ONONE;
Sxpr l;
for(l = sxpr_children(obj); CONSP(l); l = CDR(l)){
if(sxprp(CAR(l), name)){
val = CAR(l);
break;
}
}
if(NONEP(val)) val = def;
return val;
}
Sxpr sxpr_child0(Sxpr obj, Sxpr def){
Sxpr val = ONONE;
Sxpr l = sxpr_children(obj);
if(CONSP(l)){
val = CAR(l);
} else {
val = def;
}
return val;
}
Sxpr sxpr_childN(Sxpr obj, int n, Sxpr def){
Sxpr val = def;
Sxpr l;
int i;
for (i = 0, l = sxpr_children(obj); CONSP(l); i++, l = CDR(l)){
if(i == n){
val = CAR(l);
break;
}
}
return val;
}
Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def){
Sxpr val = ONONE;
val = sxpr_child(obj, name, ONONE);
if(NONEP(val)){
val = def;
} else {
val = sxpr_child0(val, def);
}
return val;
}
/** Table of interned symbols. Indexed by symbol name. */
static HashTable *symbols = NULL;
/** Hash function for entries in the symbol table.
*
* @param key to hash
* @return hashcode
*/
static Hashcode sym_hash_fn(void *key){
return hash_string((char*)key);
}
/** Key equality function for the symbol table.
*
* @param x to compare
* @param y to compare
* @return 1 if equal, 0 otherwise
*/
static int sym_equal_fn(void *x, void *y){
return !strcmp((char*)x, (char*)y);
}
/** Entry free function for the symbol table.
*
* @param table the entry is in
* @param entry being freed
*/
static void sym_free_fn(HashTable *table, HTEntry *entry){
if(entry){
objfree(((ObjAtom*)entry->value)->name);
HTEntry_free(entry);
}
}
/** Initialize the symbol table.
*
* @return 0 on sucess, error code otherwise
*/
static int init_symbols(void){
symbols = HashTable_new(100);
if(symbols){
symbols->key_hash_fn = sym_hash_fn;
symbols->key_equal_fn = sym_equal_fn;
symbols->entry_free_fn = sym_free_fn;
return 0;
}
return -1;
}
/** Cleanup the symbol table. Frees the table and all its symbols.
*/
void cleanup_symbols(void){
HashTable_free(symbols);
symbols = NULL;
}
/** Get the interned symbol with the given name.
* No new symbol is created.
*
* @return symbol or null
*/
Sxpr get_symbol(char *sym){
HTEntry *entry;
if(!symbols){
if(init_symbols()) return ONOMEM;
return ONULL;
}
entry = HashTable_get_entry(symbols, sym);
if(entry){
return OBJP(T_ATOM, entry->value);
} else {
return ONULL;
}
}
/** Get the interned symbol with the given name.
* Creates a new symbol if necessary.
*
* @return symbol
*/
Sxpr intern(char *sym){
Sxpr symbol = get_symbol(sym);
if(NULLP(symbol)){
if(!symbols) return ONOMEM;
symbol = atom_new(sym);
if(!NOMEMP(symbol)){
OBJ_ATOM(symbol)->interned = TRUE;
HashTable_add(symbols, atom_name(symbol), get_ptr(symbol));
}
}
return symbol;
}
+414
View File
@@ -0,0 +1,414 @@
/*
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _XUTIL_SXPR_H_
#define _XUTIL_SXPR_H_
#include <stdint.h>
#include "hash_table.h"
#include "iostream.h"
#include "allocate.h"
/** @file
* Definitions for rules and sxprs.
*/
#ifndef NULL
#define NULL 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/** Sxpr type. */
typedef int16_t TypeCode;
/** A typed sxpr handle.*/
typedef struct Sxpr {
/** Sxpr type. */
TypeCode type;
union {
/** Sxpr value. */
unsigned long ul;
/** Pointer. */
void *ptr;
} v;
} Sxpr;
/** Sxpr type to indicate out of memory. */
#define T_NOMEM ((TypeCode)-1)
/** The 'unspecified' sxpr. */
#define T_NONE ((TypeCode)0)
/** The empty list. */
#define T_NULL ((TypeCode)1)
/** Unsigned integer. */
#define T_UINT ((TypeCode)2)
/** A string. */
#define T_STRING ((TypeCode)3)
/** An atom. */
#define T_ATOM ((TypeCode)4)
/** A boolean. */
#define T_BOOL ((TypeCode)5)
/** A cons (pair or list). */
#define T_CONS ((TypeCode)10)
/** An error. */
#define T_ERR ((TypeCode)40)
/** An atom. */
typedef struct ObjAtom {
Sxpr name;
Hashcode hashcode;
int interned;
} ObjAtom;
/** A cons (pair). */
typedef struct ObjCons {
Sxpr car;
Sxpr cdr;
} ObjCons;
/** A vector. */
typedef struct ObjVector {
int n;
Sxpr data[0];
} ObjVector;
/** Flags for sxpr printing. */
enum PrintFlags {
PRINT_RAW = 0x001,
PRINT_TYPE = 0x002,
PRINT_PRETTY = 0x004,
PRINT_NUM = 0x008,
};
/** An integer sxpr.
*
* @param ty type
* @param val integer value
*/
#define OBJI(ty, val) (Sxpr){ type: (ty), v: { ul: (val) }}
/** A pointer sxpr.
* If the pointer is non-null, returns an sxpr containing it.
* If the pointer is null, returns ONOMEM.
*
* @param ty type
* @param val pointer
*/
#define OBJP(ty, val) ((val) ? (Sxpr){ type: (ty), v: { ptr: (val) }} : ONOMEM)
/** Make an integer sxpr containing a pointer.
*
* @param val pointer
*/
#define PTR(val) OBJP(T_UINT, (void*)(val))
/** Make an integer sxpr.
* @param x value
*/
#define OINT(x) OBJI(T_UINT, x)
/** Make an error sxpr.
*
* @param x value
*/
#define OERR(x) OBJI(T_ERR, x)
/** Out of memory constant. */
#define ONOMEM OBJI(T_NOMEM, 0)
/** The `unspecified' constant. */
#define ONONE OBJI(T_NONE, 0)
/** Empty list constant. */
#define ONULL OBJI(T_NULL, 0)
/** False constant. */
#define OFALSE OBJI(T_BOOL, 0)
/** True constant. */
#define OTRUE OBJI(T_BOOL, 1)
/* Recognizers for the various sxpr types. */
#define ATOMP(obj) has_type(obj, T_ATOM)
#define BOOLP(obj) has_type(obj, T_BOOL)
#define CONSP(obj) has_type(obj, T_CONS)
#define ERRP(obj) has_type(obj, T_ERR)
#define INTP(obj) has_type(obj, T_UINT)
#define NOMEMP(obj) has_type(obj, T_NOMEM)
#define NONEP(obj) has_type(obj, T_NONE)
#define NULLP(obj) has_type(obj, T_NULL)
#define STRINGP(obj) has_type(obj, T_STRING)
#define TRUEP(obj) get_ul(obj)
/** Convert an sxpr to an unsigned integer. */
#define OBJ_UINT(x) get_ul(x)
/** Convert an sxpr to an integer. */
#define OBJ_INT(x) (int)get_ul(x)
/* Conversions of sxprs to their values.
* No checking is done.
*/
#define OBJ_STRING(x) ((char*)get_ptr(x))
#define OBJ_CONS(x) ((ObjCons*)get_ptr(x))
#define OBJ_ATOM(x) ((ObjAtom*)get_ptr(x))
#define OBJ_SET(x) ((ObjSet*)get_ptr(x))
#define CAR(x) (OBJ_CONS(x)->car)
#define CDR(x) (OBJ_CONS(x)->cdr)
#define CAAR(x) (CAR(CAR(x)))
#define CADR(x) (CAR(CDR(x)))
#define CDAR(x) (CDR(CAR(x)))
#define CDDR(x) (CDR(CDR(x)))
/** Get the integer value from an sxpr.
*
* @param obj sxpr
* @return value
*/
static inline unsigned long get_ul(Sxpr obj){
return obj.v.ul;
}
/** Get the pointer value from an sxpr.
*
* @param obj sxpr
* @return value
*/
static inline void * get_ptr(Sxpr obj){
return obj.v.ptr;
}
/** Create an sxpr containing a pointer.
*
* @param type typecode
* @param val pointer
* @return sxpr
*/
static inline Sxpr obj_ptr(TypeCode type, void *val){
return (Sxpr){ type: type, v: { ptr: val } };
}
/** Create an sxpr containing an integer.
*
* @param type typecode
* @param val integer
* @return sxpr
*/
static inline Sxpr obj_ul(TypeCode type, unsigned long val){
return (Sxpr){ type: type, v: { ul: val } };
}
/** Get the type of an sxpr.
*
* @param obj sxpr
* @return type
*/
static inline TypeCode get_type(Sxpr obj){
return obj.type;
}
/** Check the type of an sxpr.
*
* @param obj sxpr
* @param type to check
* @return 1 if has the type, 0 otherwise
*/
static inline int has_type(Sxpr obj, TypeCode type){
return get_type(obj) == type;
}
/** Compare sxprs for literal equality of type and value.
*
* @param x sxpr to compare
* @param y sxpr to compare
* @return 1 if equal, 0 otherwise
*/
static inline int eq(Sxpr x, Sxpr y){
return ((get_type(x) == get_type(y)) && (get_ul(x) == get_ul(y)));
}
/** Checked version of CAR
*
* @param x sxpr
* @return CAR if a cons, x otherwise
*/
static inline Sxpr car(Sxpr x){
return (CONSP(x) ? CAR(x) : x);
}
/** Checked version of CDR.
*
* @param x sxpr
* @return CDR if a cons, null otherwise
*/
static inline Sxpr cdr(Sxpr x){
return (CONSP(x) ? CDR(x) : ONULL);
}
/** Allocate some memory and return an sxpr containing it.
* Returns ONOMEM if allocation failed.
*
* @param n number of bytes to allocate
* @param ty typecode
* @return sxpr
*/
static inline Sxpr halloc(size_t n, TypeCode ty){
return OBJP(ty, allocate(n));
}
/** Allocate an sxpr containing a pointer to the given type.
*
* @param ty type (uses sizeof to determine how many bytes to allocate)
* @param code typecode
* @return sxpr, ONOMEM if allocation failed
*/
#define HALLOC(ty, code) halloc(sizeof(ty), code)
typedef int ObjPrintFn(IOStream *io, Sxpr obj, unsigned flags);
typedef int ObjEqualFn(Sxpr obj, Sxpr other);
typedef void ObjFreeFn(Sxpr obj);
/** An sxpr type definition. */
typedef struct SxprType {
TypeCode type;
char *name;
int pointer;
ObjPrintFn *print;
ObjEqualFn *equal;
ObjFreeFn *free;
} SxprType;
extern SxprType *get_sxpr_type(int ty);
/** Free the pointer in an sxpr.
*
* @param x sxpr containing a pointer
*/
static inline void hfree(Sxpr x){
deallocate(get_ptr(x));
}
extern int objprint(IOStream *io, Sxpr x, unsigned flags);
extern int objequal(Sxpr x, Sxpr y);
extern void objfree(Sxpr x);
extern void cons_free_cells(Sxpr obj);
extern Sxpr intern(char *s);
extern Sxpr assoc(Sxpr k, Sxpr l);
extern Sxpr assocq(Sxpr k, Sxpr l);
extern Sxpr acons(Sxpr k, Sxpr v, Sxpr l);
extern Sxpr nrev(Sxpr l);
extern Sxpr cons_member(Sxpr l, Sxpr x);
extern Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v);
extern int cons_subset(Sxpr s, Sxpr t);
extern int cons_set_equal(Sxpr s, Sxpr t);
#ifdef USE_GC
extern Sxpr cons_remove(Sxpr l, Sxpr x);
extern Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v);
#endif
extern Sxpr atom_new(char *name);
extern char * atom_name(Sxpr obj);
extern Sxpr string_new(char *s);
extern char * string_string(Sxpr obj);
extern int string_length(Sxpr obj);
extern Sxpr cons_new(Sxpr car, Sxpr cdr);
extern int cons_push(Sxpr *list, Sxpr elt);
extern int cons_length(Sxpr obj);
Sxpr sxpr_name(Sxpr obj);
int sxpr_is(Sxpr obj, char *s);
int sxpr_elementp(Sxpr obj, Sxpr name);
Sxpr sxpr_attributes(Sxpr obj);
Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def);
Sxpr sxpr_children(Sxpr obj);
Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def);
Sxpr sxpr_childN(Sxpr obj, int n, Sxpr def);
Sxpr sxpr_child0(Sxpr obj, Sxpr def);
Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def);
/** Create a new atom.
*
* @param s atom name
* @return new atom
*/
static inline Sxpr mkatom(char *s){
return atom_new(s);
}
/** Create a new string sxpr.
*
* @param s string bytes (copied)
* @return new string
*/
static inline Sxpr mkstring(char *s){
return string_new(s);
}
/** Create an integer sxpr.
*
* @param i value
* @return sxpr
*/
static inline Sxpr mkint(int i){
return OBJI(T_UINT, i);
}
/** Create a boolean sxpr.
*
* @param b value
* @return sxpr
*/
static inline Sxpr mkbool(int b){
return OBJI(T_BOOL, (b ? 1 : 0));
}
/* Constants used in parsing and printing. */
#define k_list_open "("
#define c_list_open '('
#define k_list_close ")"
#define c_list_close ')'
#define k_true "true"
#define k_false "false"
#define c_var '$'
#define c_escape '\\'
#define c_single_quote '\''
#define c_double_quote '"'
#define c_string_open c_double_quote
#define c_string_close c_double_quote
#define c_data_open '['
#define c_data_close ']'
#define c_binary '*'
#define c_eval '!'
#define c_concat_open '{'
#define c_concat_close '}'
#endif /* ! _XUTIL_SXPR_H_ */
+316
View File
@@ -0,0 +1,316 @@
#include <errno.h>
#include "xdr.h"
#define MODULE_NAME "XDR"
//#define DEBUG 1
#undef DEBUG
#include "debug.h"
/** @file
* XDR packer/unpacker for elements.
*
* string -> [T_STRING] [len:u16] <len bytes>
* atom -> [T_ATOM] [len:u16] <len bytes>
* uint -> [T_UINT] [value]
* cons -> [T_LIST] {1 elt}* 0
* null -> [T_NULL]
* none -> [T_NONE]
* bool -> [T_BOOL] { 0:u8 | 1:u8 }
*
* types packed as u16.
*
* So (a b c) -> [T_CONS] a [T_CONS] b [T_CONS] c [T_NULL]
* () -> [T_NULL]
*/
int pack_bool(IOStream *io, int x){
int err=0;
//dprintf("> x=%d\n", x);
err = IOStream_print(io, "%c", 0xff & x);
if(err > 0) err = 0;
//dprintf("< err=%d\n", err);
return err;
}
int unpack_bool(IOStream *io, int *x){
int err = 0;
int c;
//dprintf(">\n");
c = IOStream_getc(io);
*x = (c < 0 ? 0 : c);
err = IOStream_error(io);
if(c < 0 && !err) err = -EIO;
//dprintf("< err=%d x=%d\n", err, *x);
return err;
}
int pack_ushort(IOStream *io, unsigned short x){
int err=0;
//dprintf("> x=%u\n", x);
err = IOStream_print(io, "%c%c",
0xff & (x >> 8),
0xff & (x ));
if(err > 0) err = 0;
//dprintf("< err=%d\n", err);
return err;
}
int unpack_ushort(IOStream *io, unsigned short *x){
int err = 0;
int i, c = 0;
//dprintf(">\n");
*x = 0;
for(i = 0; i< 2; i++){
c = IOStream_getc(io);
if(c < 0) break;
*x <<= 8;
*x |= (0xff & c);
}
err = IOStream_error(io);
if(c < 0 && !err) err = -EIO;
//dprintf("< err=%d x=%u\n", err, *x);
return err;
}
int pack_type(IOStream *io, unsigned short x){
return pack_ushort(io, x);
}
int unpack_type(IOStream *io, unsigned short *x){
return unpack_ushort(io, x);
}
int pack_uint(IOStream *io, unsigned int x){
int err=0;
//dprintf("> x=%u\n", x);
err = IOStream_print(io, "%c%c%c%c",
0xff & (x >> 24),
0xff & (x >> 16),
0xff & (x >> 8),
0xff & (x ));
if(err > 0) err = 0;
//dprintf("< err=%d\n", err);
return err;
}
int unpack_uint(IOStream *io, unsigned int *x){
int err = 0;
int i, c = 0;
//dprintf(">\n");
*x = 0;
for(i = 0; i< 4; i++){
c = IOStream_getc(io);
if(c < 0) break;
*x <<= 8;
*x |= (0xff & c);
}
err = IOStream_error(io);
if(c < 0 && !err) err = -EIO;
//dprintf("< err=%d x=%u\n", err, *x);
return err;
}
int pack_string(IOStream *io, Sxpr x){
int err = 0;
unsigned short n = 0xffff & string_length(x);
char *s = string_string(x);
int i;
//dprintf("> n=%d s=%s\n", n, s);
err = pack_ushort(io, n);
if(err) goto exit;
for(i = 0; i < n; i++){
err = IOStream_print(io, "%c", s[i]);
if(err < 0) break;
}
if(err > 0) err = 0;
exit:
//dprintf("< err=%d\n", err);
return err;
}
int unpack_string(IOStream *io, Sxpr *x){
int err;
unsigned short n;
int i, c = 0;
char *s;
Sxpr val = ONONE;
//dprintf(">\n");
err = unpack_ushort(io, &n);
if(err) goto exit;
val = halloc(n+1, T_STRING);
if(NOMEMP(val)){
err = -ENOMEM;
goto exit;
}
s = string_string(val);
for(i=0; i<n; i++){
c = IOStream_getc(io);
if(c < 0) break;
s[i] = (char)c;
}
s[n] = '\0';
exit:
err = IOStream_error(io);
if(c < 0 && !err) err = -EIO;
if(err){
objfree(val);
val = ONONE;
}
*x = val;
//IOStream_print(iostdout, "n=%d str=", n);
//objprint(iostdout, *x, 0);
//IOStream_print(iostdout, "\n");
//dprintf("< err=%d\n", err);
return err;
}
int pack_cons(IOStream *io, Sxpr x){
int err = 0;
Sxpr l;
//dprintf(">\n");
for(l = x; CONSP(l); l = CDR(l)){
err = pack_bool(io, 1);
if(err) goto exit;
err = pack_sxpr(io, CAR(l));
if(err) goto exit;
}
err = pack_bool(io, 0);
exit:
//dprintf("< err=%d\n", err);
return err;
}
int unpack_cons(IOStream *io, Sxpr *x){
int err = 0;
int more = 0;
Sxpr u = ONONE, v = ONONE, val = ONULL;
dprintf(">\n");
while(1){
err = unpack_bool(io, &more);
if(err) goto exit;
if(!more){
//IOStream_print(iostdout, "unpack_cons 1 val=");
////objprint(iostdout, val, 0);
IOStream_print(iostdout, "\n");
val = nrev(val);
//IOStream_print(iostdout, "unpack_cons 2 val=");
//objprint(iostdout, val, 0);
//IOStream_print(iostdout, "\n");
break;
}
err = unpack_sxpr(io, &u);
if(err) goto exit;
v = cons_new(u, val);
if(NOMEMP(v)){
err = -ENOMEM;
objfree(u);
goto exit;
}
val = v;
}
exit:
if(err){
objfree(val);
val = ONONE;
}
*x = val;
dprintf("< err=%d\n", err);
return err;
}
int pack_sxpr(IOStream *io, Sxpr x){
int err = 0;
unsigned short type = get_type(x);
//dprintf(">\n");
//objprint(iostdout, x, 0);
//IOStream_print(iostdout, "\n");
err = pack_type(io, type);
if(err) goto exit;
switch(type){
case T_NULL:
break;
case T_NONE:
break;
case T_BOOL:
err = pack_bool(io, get_ul(x));
break;
case T_CONS:
err = pack_cons(io, x);
break;
case T_ATOM:
err = pack_string(io, OBJ_ATOM(x)->name);
break;
case T_STRING:
err = pack_string(io, x);
break;
case T_UINT:
err = pack_uint(io, get_ul(x));
break;
default:
err = -EINVAL;
IOStream_print(iostderr, "%s> invalid type %d\n", __FUNCTION__, type);
break;
}
exit:
//dprintf("< err=%d\n", err);
return err;
}
int unpack_sxpr(IOStream *io, Sxpr *x){
int err = 0;
unsigned short type;
unsigned int u;
Sxpr val = ONONE, y;
//dprintf(">\n");
err = unpack_type(io, &type);
if(err) goto exit;
switch(type){
case T_NULL:
val = ONULL;
break;
case T_NONE:
val = ONONE;
break;
case T_CONS:
err = unpack_cons(io, &val);
break;
case T_BOOL:
err = unpack_bool(io, &u);
if(err) goto exit;
val = (u ? OTRUE : OFALSE);
break;
case T_ATOM:
err = unpack_string(io, &y);
if(err) goto exit;
val = intern(string_string(y));
objfree(y);
break;
case T_STRING:
err = unpack_string(io, &val);
break;
case T_UINT:
err = unpack_uint(io, &u);
if(err) goto exit;
val = OBJI(type, u);
break;
default:
err = -EINVAL;
IOStream_print(iostderr, "%s> invalid type %d\n", __FUNCTION__, type);
break;
}
exit:
*x = (err ? ONONE : val);
//IOStream_print(iostdout, "sxpr=");
//objprint(iostdout, *x, 0);
//IOStream_print(iostdout, "\n");
//dprintf("< err=%d\n", err);
return err;
}
+30
View File
@@ -0,0 +1,30 @@
#ifndef _XUTIL_XDR_H_
#define _XUTIL_XDR_H_
#include "iostream.h"
#include "sxpr.h"
int pack_type(IOStream *io, unsigned short x);
int unpack_type(IOStream *io, unsigned short *x);
int pack_bool(IOStream *io, int x);
int unpack_bool(IOStream *io, int *x);
int pack_uint(IOStream *out, unsigned int x);
int unpack_uint(IOStream *in, unsigned int *x);
int pack_string(IOStream *out, Sxpr x);
int unpack_string(IOStream *in, Sxpr *x);
int pack_cons(IOStream *out, Sxpr x);
int unpack_cons(IOStream *in, Sxpr *x);
int pack_sxpr(IOStream *out, Sxpr x);
int unpack_sxpr(IOStream *in, Sxpr *x);
#endif /* _XUTIL_XDR_H_ */
+90
View File
@@ -0,0 +1,90 @@
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#ifndef _XEN_XFR_STUB_
#include "dom0_defs.h"
#include "mem_defs.h"
#endif
#include "xen_domain.h"
#include "marshal.h"
#include "xdr.h"
#define MODULE_NAME "XFRD"
#define DEBUG 1
#include "debug.h"
/** Write domain state.
*
* At some point during this the domain is suspended, and then there's no way back.
* Even if something later goes wrong we can't restart the domain.
*/
int xen_domain_snd(Conn *xend, IOStream *io, uint32_t dom, char *vmconfig, int vmconfig_n){
int err = 0;
char buf[1024];
int n, k, d, buf_n;
dprintf("> dom=%d\n", dom);
#ifdef _XEN_XFR_STUB_
err = marshal_uint32(io, dom);
if(err) goto exit;
err = marshal_string(io, vmconfig, vmconfig_n);
if(err) goto exit;
n = 32 * 1024 * 1024;
buf_n = sizeof(buf);
err = marshal_uint32(io, n);
for(k = 0; k < n; k += d){
d = n - k;
if(d > buf_n) d = buf_n;
err = marshal_bytes(io, buf, d);
if(err) goto exit;
//dprintf("> k=%d n=%d\n", k, n);
}
exit:
#else
#endif
dprintf("< err=%d\n", err);
return err;
}
/** Receive domain state.
* Create a new domain and store the received state into it.
*/
int xen_domain_rcv(IOStream *io, uint32_t *dom, char **vmconfig, int *vmconfig_n){
int err = 0;
char buf[1024];
int n, k, d, buf_n;
dprintf(">\n");
#ifdef _XEN_XFR_STUB_
err = unmarshal_uint32(io, dom);
if(err) goto exit;
err = unmarshal_new_string(io, vmconfig, vmconfig_n);
if(err) goto exit;
err = unmarshal_uint32(io, &n);
buf_n = sizeof(buf);
for(k = 0; k < n; k += d){
d = n - k;
if(d > buf_n) d = buf_n;
err = unmarshal_bytes(io, buf, d);
if(err) goto exit;
//dprintf("> k=%d n=%d\n", k, n);
}
exit:
#else
#endif
dprintf("< err=%d\n", err);
return err;
}
/** Configure a new domain. Talk to xend. Use libcurl?
*/
int xen_domain_configure(uint32_t dom, char *vmconfig, int vmconfig_n){
int err = 0;
dprintf(">\n");
#ifdef _XEN_XFR_STUB_
#else
#endif
dprintf("< err=%d\n", err);
return err;
}
+15
View File
@@ -0,0 +1,15 @@
#ifndef _XFRD_XEN_DOMAIN_H_
#define _XFRD_XEN_DOMAIN_H_
#include <sys/types.h>
#include <iostream.h>
#include "connection.h"
/** Define to use stubs. Undefine to use Xen ops. */
//#define _XEN_XFR_STUB_
extern int xen_domain_snd(Conn *xend, IOStream *io, uint32_t dom, char *vmconfig, int vmconfig_n);
extern int xen_domain_rcv(IOStream *io, uint32_t *dom, char **vmconfig, int *vmconfig_n);
extern int xen_domain_configure(uint32_t dom, char *vmconfig, int vmconfig_n);
#endif
+1127
View File
File diff suppressed because it is too large. Load diff
+14
View File
@@ -0,0 +1,14 @@
#ifndef _XFRD_XFRD_H_
#define _XFRD_XFRD_H_
/** Xend port in host order. */
#define XEND_PORT 8001
/** Xfrd port in host order. */
#define XFRD_PORT 8002
/** Protocol version. */
#define XFR_PROTO_MAJOR 1
#define XFR_PROTO_MINOR 0
#endif
+127
View File
@@ -0,0 +1,127 @@
#!/bin/env python
"""
Test client for the migration daemon (xfrd).
Author: Mike Wray <mike.wray@hp.com>
"""
import getopt
import sys
import os
from socket import *
import StringIO
sys.path.append("/home/mjw/repos-bk/xeno-unstable.bk/tools/python")
import xen.xend.sxp as sxp
from xen.xend.packing import SxpPacker, SxpUnpacker
XFRD_PORT = 8002
verbose = 0
class TCPClient:
def __init__(self, host, port):
print ">TCPClient"
self.sock = socket(AF_INET, SOCK_STREAM, 0)
print ">TCPClient sock=", self.sock
print ">TCPClient> connect ", host, port
v = self.sock.connect((host, port))
print ">TCPClient> connect=", v
# Send plain header (no gzip).
#self.sock.send("\0\0")
self.sockin = self.sock.makefile("r")
self.sockout = self.sock.makefile("w")
self.packer = SxpPacker(self.sockout)
self.unpacker = SxpUnpacker(self.sockin)
#pass
def request(self, req):
print "request>", req
self.packer.pack(req)
self.sockout.flush()
print "request<"
def request_hello(self):
self.request(['xfr.hello', XFR_PROTO_MAJOR, XFR_PROTO_MINOR])
def request_migrate(self, vmid, vhost, vport, vmconfig='(vm)'):
self.request(['xfr.migrate', vmid, vmconfig, vhost, vport])
def read(self):
while(1):
v = self.unpacker.unpack()
print 'read>', v
if v[0] == 'xfr.err' and v[1]: return
if v[0] == 'xfr.ok': return
XFR_PROTO_MAJOR = 1
XFR_PROTO_MINOR = 0
host_default = "localhost"
port_default = XFRD_PORT
vhost_default = "localhost"
vport_default = 8003
vmid_default = 1
# Short options. Options followed by ':' need a parameter.
short_opts = 'h'
# Long options. Options ending in '=' need a parameter.
long_opts = [ 'host=', 'port=', 'vhost=', 'vport=', 'vmid=', 'verbose', 'help']
def usage(err=None):
if err:
out = sys.stderr
else:
out = sys.stdout
print >> out, 'Usage: %s [options] [command...]\n' % sys.argv[0]
print >> out, '--host <host>\n\tHost to initiate transfer on. Default %s.' % host_default
print >> out, '--port <port>\n\tPort to initiate transfer on. Default %d.' % port_default
print >> out, '--vhost <vhost>\n\tHost to transfer VM to. Default %s.' % vhost_default
print >> out, '--vport <vport>\n\tPort to transfer VM to. Default %d.' % vport_default
print >> out, '--vmid <vmid>\n\tVM id. Default %d.' % vmid_default
print >> out, '--help\n\tPrint help.'
def main(argv):
global verbose
host = host_default
port = port_default
vhost = vhost_default
vport = vport_default
vmid = vmid_default
try:
opts, args = getopt.getopt(argv[1:], short_opts, long_opts)
except getopt.GetoptError, ex:
print >>sys.stderr, 'Error:', ex
usage(1)
sys.exit(1)
for key, val in opts:
if key == '--help':
usage()
sys.exit(0)
elif key == '--host':
host = val
elif key == '--port':
port = int(val)
elif key == '--vhost':
vhost = val
elif key == '--vport':
vport = int(val)
elif key == '--vmid':
vmid = int(val)
print "host=%s port=%d" % (host, port)
print "vhost=%s vport=%d vmid=%d" % (vhost, vport, vmid)
client = TCPClient(gethostbyname(host), port)
client.request_hello()
client.request_migrate(vmid, gethostbyname(vhost), vport)
client.read()
if __name__ == '__main__':
main(sys.argv)
+5
View File
@@ -6,6 +6,9 @@ OBJS := $(subst pdb-linux.o,,$(OBJS))
OBJS := $(subst pdb-stub.o,,$(OBJS))
endif
OBJS += $(patsubst %.S,%.o,$(wildcard $(TARGET_SUBARCH)/*.S))
OBJS += $(patsubst %.c,%.o,$(wildcard $(TARGET_SUBARCH)/*.c))
LINK_BASE := 0xFC500000 # Xen is linked here
LOAD_BASE := 0x00100000 # Xen is loaded here
@@ -23,3 +26,5 @@ default: boot/$(TARGET_SUBARCH).o $(OBJS)
clean:
rm -f *.o *~ core boot/*.o boot/*~ boot/core
rm -f $(TARGET_SUBARCH)/*.o $(TARGET_SUBARCH)/*~
rm -f $(TARGETSUBARCH)/core
+1 -1
View File
@@ -8,7 +8,7 @@ CFLAGS := -nostdinc -fno-builtin -fno-common -fno-strict-aliasing -O3
CFLAGS += -iwithprefix include -Wall -Werror -fomit-frame-pointer
CFLAGS += -I$(BASEDIR)/include -Wno-pointer-arith -Wredundant-decls
LDFLAGS := -T xen.lds -N
LDFLAGS := -T $(TARGET_SUBARCH)/xen.lds -N
ifeq ($(TARGET_SUBARCH),x86_32)
CFLAGS += -m32 -march=i686
+3 -3
View File
@@ -491,9 +491,9 @@ void __init init_apic_mappings(void)
*****************************************************************************/
/* used for system time scaling */
static unsigned int bus_freq;
static u32 bus_cycle; /* length of one bus cycle in pico-seconds */
static u32 bus_scale; /* scaling factor convert ns to bus cycles */
static unsigned long bus_freq; /* KAF: pointer-size avoids compile warns. */
static u32 bus_cycle; /* length of one bus cycle in pico-seconds */
static u32 bus_scale; /* scaling factor convert ns to bus cycles */
/*
* The timer chip is already set up at HZ interrupts per second here,
+18 -1
View File
@@ -19,8 +19,25 @@ ENTRY(start)
/* Checksum: must be the negated sum of the first two fields. */
.long -0x1BADB004
bad_cpu_msg:
.asciz "Bad CPU: we need at least a P6-compatible core."
bad_cpu:
jmp bad_cpu
mov $SYMBOL_NAME(bad_cpu_msg)-__PAGE_OFFSET,%esi
mov $0xB8000,%edi # VGA framebuffer
1: mov (%esi),%bl
test %bl,%bl # Terminate on '\0' sentinel
2: je 2b
mov $0x3f8+5,%dx # UART Line Status Register
3: in %dx,%al
test $0x20,%al # Test THR Empty flag
je 3b
mov $0x3f8+0,%dx # UART Transmit Holding Register
mov %bl,%al
out %al,%dx # Send a character over the serial line
movsb # Write a character to the VGA framebuffer
mov $7,%al
stosb # Write an attribute to the VGA framebuffer
jmp 1b
__start:
/* Set up a few descriptors: on entry only CS is guaranteed good. */
+39 -19
View File
@@ -20,20 +20,27 @@ ENTRY(start)
/* Checksum: must be the negated sum of the first two fields. */
.long -0x1BADB004
bad_cpu_msg:
.asciz "Bad CPU: does not support 64-bit (long) mode."
bad_cpu:
jmp bad_cpu
mov $SYMBOL_NAME(bad_cpu_msg)-__PAGE_OFFSET,%esi
mov $0xB8000,%edi # VGA framebuffer
1: mov (%esi),%bl
test %bl,%bl # Terminate on '\0' sentinel
2: je 2b
mov $0x3f8+5,%dx # UART Line Status Register
3: in %dx,%al
test $0x20,%al # Test THR Empty flag
je 3b
mov $0x3f8+0,%dx # UART Transmit Holding Register
mov %bl,%al
out %al,%dx # Send a character over the serial line
movsb # Write a character to the VGA framebuffer
mov $7,%al
stosb # Write an attribute to the VGA framebuffer
jmp 1b
__start:
/* We begin by interrogating the CPU for the presence of long mode. */
mov $0x80000000,%eax
cpuid
cmp $0x80000000,%eax # any function > 0x80000000?
jbe bad_cpu
mov $0x80000001,%eax
cpuid
bt $29,%edx # Long mode feature?
jnc bad_cpu
/* Set up a few descriptors: on entry only CS is guaranteed good. */
lgdt %cs:nopaging_gdt_descr-__PAGE_OFFSET
mov $(__HYPERVISOR_DS),%ecx
@@ -48,6 +55,16 @@ __start:
pushl $0
popf
/* We begin by interrogating the CPU for the presence of long mode. */
mov $0x80000000,%eax
cpuid
cmp $0x80000000,%eax # any function > 0x80000000?
jbe bad_cpu
mov $0x80000001,%eax
cpuid
bt $29,%edx # Long mode feature?
jnc bad_cpu
/* Set up FPU. */
fninit
@@ -82,7 +99,7 @@ __start:
/* Initialise IDT with simple error defaults. */
lea ignore_int,%edx
mov $(__HYPERVISOR_CS << 16),%eax
mov $(__HYPERVISOR_CS64 << 16),%eax
mov %dx,%ax /* selector = 0x0010 = cs */
mov $0x8E00,%dx /* interrupt gate - dpl=0, present */
lea SYMBOL_NAME(idt_table)-__PAGE_OFFSET,%edi
@@ -98,16 +115,19 @@ start_paging:
mov $0x80050033,%eax /* hi-to-lo: PG,AM,WP,NE,ET,MP,PE */
mov %eax,%cr0
jmp 1f
1: /* Now in compatibility mode. Long-jump into 64-bit mode. */
ljmp $(__HYPERVISOR_CS64),$1f
.code64
1: /* Install relocated selectors (FS/GS unused). */
lgdt gdt_descr
mov $(__HYPERVISOR_DS),%ecx
mov %ecx,%ds
mov %ecx,%es
mov %ecx,%ss
ljmp $(__HYPERVISOR_CS),$1f
1: /* Paging enabled, so we can now enable GLOBAL mappings in CR4. */
mov mmu_cr4_features,%ecx
mov %ecx,%cr4
mov mmu_cr4_features,%rcx
mov %rcx,%cr4
/* Relocate ESP */
add $__PAGE_OFFSET,%esp
@@ -123,16 +143,18 @@ start_paging:
/* This is the default interrupt handler. */
int_msg:
.asciz "Unknown interrupt\n"
ALIGN
ignore_int:
cld
mov $(__HYPERVISOR_DS),%eax
mov %eax,%ds
mov %eax,%es
pushl $int_msg
pushq $int_msg
call SYMBOL_NAME(printf)
1: jmp 1b
.code32
.align 8
/*** STACK LOCATION ***/
ENTRY(stack_start)
@@ -144,8 +166,6 @@ ENTRY(stack_start)
.globl SYMBOL_NAME(idt)
.globl SYMBOL_NAME(gdt)
ALIGN
.word 0
idt_descr:
.word 256*8-1
@@ -1,17 +1,10 @@
/*
* linux/arch/i386/kernel/process.c
*
* Copyright (C) 1995 Linus Torvalds
*
* Pentium III FXSR, SSE support
* Gareth Hughes <gareth@valinux.com>, May 2000
*/
/*
* This file handles the architecture-dependent parts of process handling..
*/
#define __KERNEL_SYSCALLS__
#include <xen/config.h>
#include <xen/lib.h>
#include <xen/errno.h>
@@ -192,6 +185,8 @@ void machine_power_off(void)
machine_restart(0);
}
#if defined(__i386__)
void new_thread(struct domain *p,
unsigned long start_pc,
unsigned long start_stack,
@@ -361,3 +356,5 @@ long do_iopl(domid_t domain, unsigned int new_io_pl)
ec->eflags = (ec->eflags & 0xffffcfff) | ((new_io_pl&3) << 12);
return 0;
}
#endif
+4
View File
@@ -89,7 +89,11 @@ void enable_irq(unsigned int irq)
asmlinkage void do_IRQ(struct pt_regs regs)
{
#if defined(__i386__)
unsigned int irq = regs.orig_eax;
#else
unsigned int irq = 0; /* XXX */
#endif
irq_desc_t *desc = &irq_desc[irq];
struct irqaction *action;
+2 -2
View File
@@ -458,7 +458,7 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
if ((clustered_apic_mode == CLUSTERED_APIC_NUMAQ) && mpc->mpc_oemptr) {
/* We need to process the oem mpc tables to tell us which quad things are in ... */
mpc_record = 0;
smp_read_mpc_oem((struct mp_config_oemtable *) mpc->mpc_oemptr, mpc->mpc_oemsize);
smp_read_mpc_oem((struct mp_config_oemtable *)(unsigned long)mpc->mpc_oemptr, mpc->mpc_oemsize);
mpc_record = 0;
}
@@ -824,7 +824,7 @@ void __init get_smp_config (void)
* Read the physical hardware table. Anything here will
* override the defaults.
*/
if (!smp_read_mpc((void *)mpf->mpf_physptr)) {
if (!smp_read_mpc((void *)(unsigned long)mpf->mpf_physptr)) {
smp_found_config = 0;
printk(KERN_ERR "BIOS bug, MP table errors detected!...\n");
printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n");
+6 -6
View File
@@ -6,22 +6,22 @@ asm(
".align 4\n"
".globl __write_lock_failed\n"
"__write_lock_failed:\n"
" " LOCK "addl $" RW_LOCK_BIAS_STR ",(%eax)\n"
" " LOCK "addl $" RW_LOCK_BIAS_STR ",(%"__OP"ax)\n"
"1: rep; nop\n"
" cmpl $" RW_LOCK_BIAS_STR ",(%eax)\n"
" cmpl $" RW_LOCK_BIAS_STR ",(%"__OP"ax)\n"
" jne 1b\n"
" " LOCK "subl $" RW_LOCK_BIAS_STR ",(%eax)\n"
" " LOCK "subl $" RW_LOCK_BIAS_STR ",(%"__OP"ax)\n"
" jnz __write_lock_failed\n"
" ret\n"
".align 4\n"
".globl __read_lock_failed\n"
"__read_lock_failed:\n"
" lock ; incl (%eax)\n"
" lock ; incl (%"__OP"ax)\n"
"1: rep; nop\n"
" cmpl $1,(%eax)\n"
" cmpl $1,(%"__OP"ax)\n"
" js 1b\n"
" lock ; decl (%eax)\n"
" lock ; decl (%"__OP"ax)\n"
" js __read_lock_failed\n"
" ret\n"
);
+14
View File
@@ -28,7 +28,11 @@ extern int do_timer_lists_from_pit;
char ignore_irq13; /* set if exception 16 works */
struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1 };
#if defined(__x86_64__)
unsigned long mmu_cr4_features = X86_CR4_PSE | X86_CR4_PGE | X86_CR4_PAE;
#else
unsigned long mmu_cr4_features = X86_CR4_PSE | X86_CR4_PGE;
#endif
EXPORT_SYMBOL(mmu_cr4_features);
unsigned long wait_init_idle;
@@ -50,6 +54,8 @@ int acpi_force __initdata = 0;
int phys_proc_id[NR_CPUS];
int logical_proc_id[NR_CPUS];
#if defined(__i386__)
/* Standard macro to see if a specific flag is changeable */
static inline int flag_is_changeable_p(u32 flag)
{
@@ -77,6 +83,12 @@ static int __init have_cpuid_p(void)
return flag_is_changeable_p(X86_EFLAGS_ID);
}
#elif defined(__x86_64__)
#define have_cpuid_p() (1)
#endif
void __init get_cpu_vendor(struct cpuinfo_x86 *c)
{
char *v = c->x86_vendor_id;
@@ -255,6 +267,7 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
unsigned long cpu_initialized;
void __init cpu_init(void)
{
#if defined(__i386__) /* XXX */
int nr = smp_processor_id();
struct tss_struct * t = &init_tss[nr];
@@ -293,6 +306,7 @@ void __init cpu_init(void)
write_ptbase(&current->mm);
init_idle_task();
#endif
}
static void __init do_initcalls(void)
+2
View File
@@ -659,7 +659,9 @@ static void __init do_boot_cpu (int apicid)
map_cpu_to_boot_apicid(cpu, apicid);
#if defined(__i386__)
SET_DEFAULT_FAST_TRAP(&idle->thread);
#endif
idle_task[cpu] = idle;
+11 -8
View File
@@ -107,7 +107,8 @@ static struct irqaction irq0 = { timer_interrupt, "timer", NULL};
static unsigned long __init calibrate_tsc(void)
{
unsigned long startlow, starthigh, endlow, endhigh, count;
u64 start, end, diff;
unsigned long count;
/* Set the Gate high, disable speaker */
outb((inb(0x61) & ~0x02) | 0x01, 0x61);
@@ -123,22 +124,24 @@ static unsigned long __init calibrate_tsc(void)
outb(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */
outb(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */
rdtsc(startlow, starthigh);
rdtscll(start);
for ( count = 0; (inb(0x61) & 0x20) == 0; count++ )
continue;
rdtsc(endlow, endhigh);
rdtscll(end);
/* Error if the CTC doesn't behave itself. */
if ( count == 0 )
return 0;
/* [endhigh:endlow] = [endhigh:endlow] - [starthigh:startlow] */
__asm__( "subl %2,%0 ; sbbl %3,%1"
: "=a" (endlow), "=d" (endhigh)
: "g" (startlow), "g" (starthigh), "0" (endlow), "1" (endhigh) );
diff = end - start;
#if defined(_i386__)
/* If quotient doesn't fit in 32 bits then we return error (zero). */
return endhigh ? 0 : endlow;
if ( diff & ~0xffffffffULL )
return 0;
#endif
return (unsigned long)diff;
}
+5 -1
View File
@@ -43,7 +43,11 @@ r_base = .
lmsw %ax # into protected mode
jmp flush_instr
flush_instr:
ljmpl $__HYPERVISOR_CS, $0x100000 # 1MB
#if defined(__x86_64__)
ljmpl $__HYPERVISOR_CS32, $0x100000 # 1MB
#else
ljmpl $__HYPERVISOR_CS, $0x100000 # 1MB
#endif
idt_48:
.word 0 # idt limit = 0
+4
View File
@@ -62,6 +62,8 @@ struct guest_trap_bounce {
unsigned long eip; /* 12 */
} guest_trap_bounce[NR_CPUS] = { { 0 } };
#if defined(__i386__)
#define DOUBLEFAULT_STACK_SIZE 1024
static struct tss_struct doublefault_tss;
static unsigned char doublefault_stack[DOUBLEFAULT_STACK_SIZE];
@@ -906,3 +908,5 @@ unsigned long do_get_debugreg(int reg)
if ( (reg < 0) || (reg > 7) ) return -EINVAL;
return current->thread.debugreg[reg];
}
#endif /* __i386__ */
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
View File
Whitespace-only changes.
+136
View File
@@ -0,0 +1,136 @@
/*
* User address space access functions.
*
* Copyright 1997 Andi Kleen <ak@muc.de>
* Copyright 1997 Linus Torvalds
* Copyright 2002 Andi Kleen <ak@suse.de>
*/
#include <asm/uaccess.h>
/*
* Copy a null terminated string from userspace.
*/
#define __do_strncpy_from_user(dst,src,count,res) \
do { \
long __d0, __d1, __d2; \
__asm__ __volatile__( \
" testq %1,%1\n" \
" jz 2f\n" \
"0: lodsb\n" \
" stosb\n" \
" testb %%al,%%al\n" \
" jz 1f\n" \
" decq %1\n" \
" jnz 0b\n" \
"1: subq %1,%0\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: movq %5,%0\n" \
" jmp 2b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 8\n" \
" .quad 0b,3b\n" \
".previous" \
: "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \
"=&D" (__d2) \
: "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \
: "memory"); \
} while (0)
long
__strncpy_from_user(char *dst, const char *src, long count)
{
long res;
__do_strncpy_from_user(dst, src, count, res);
return res;
}
long
strncpy_from_user(char *dst, const char *src, long count)
{
long res = -EFAULT;
if (access_ok(VERIFY_READ, src, 1))
__do_strncpy_from_user(dst, src, count, res);
return res;
}
/*
* Zero Userspace
*/
unsigned long __clear_user(void *addr, unsigned long size)
{
long __d0;
/* no memory constraint because it doesn't change any memory gcc knows
about */
asm volatile(
" testq %[size8],%[size8]\n"
" jz 4f\n"
"0: movq %[zero],(%[dst])\n"
" addq %[eight],%[dst]\n"
" decl %%ecx ; jnz 0b\n"
"4: movq %[size1],%%rcx\n"
" testl %%ecx,%%ecx\n"
" jz 2f\n"
"1: movb %b[zero],(%[dst])\n"
" incq %[dst]\n"
" decl %%ecx ; jnz 1b\n"
"2:\n"
".section .fixup,\"ax\"\n"
"3: lea 0(%[size1],%[size8],8),%[size8]\n"
" jmp 2b\n"
".previous\n"
".section __ex_table,\"a\"\n"
" .align 8\n"
" .quad 0b,3b\n"
" .quad 1b,2b\n"
".previous"
: [size8] "=c"(size), [dst] "=&D" (__d0)
: [size1] "r"(size & 7), "[size8]" (size / 8), "[dst] "(addr),
[zero] "r" (0UL), [eight] "r" (8UL));
return size;
}
unsigned long clear_user(void *to, unsigned long n)
{
if (access_ok(VERIFY_WRITE, to, n))
return __clear_user(to, n);
return n;
}
/*
* Return the size of a string (including the ending 0)
*
* Return 0 on exception, a value greater than N if too long
*/
long strnlen_user(const char *s, long n)
{
unsigned long res = 0;
char c;
if (!access_ok(VERIFY_READ, s, n))
return 0;
while (1) {
if (get_user(c, s))
return 0;
if (!c)
return res+1;
if (res>n)
return n+1;
res++;
s++;
}
}
unsigned long copy_in_user(void *to, const void *from, unsigned len)
{
if (access_ok(VERIFY_WRITE, to, len) && access_ok(VERIFY_READ, from, len)) {
return copy_user_generic(to, from, len);
}
return len;
}
+85
View File
@@ -0,0 +1,85 @@
/* Excerpts written by Martin Mares <mj@atrey.karlin.mff.cuni.cz> */
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(start)
SECTIONS
{
. = 0xFFFF840000100000;
_text = .; /* Text and read-only data */
.text : {
*(.text)
*(.fixup)
*(.gnu.warning)
} = 0x9090
.text.lock : { *(.text.lock) } /* out-of-line lock text */
_etext = .; /* End of text section */
.rodata : { *(.rodata) *(.rodata.*) }
.kstrtab : { *(.kstrtab) }
. = ALIGN(16); /* Exception table */
__start___ex_table = .;
__ex_table : { *(__ex_table) }
__stop___ex_table = .;
__start___ksymtab = .; /* Kernel symbol table */
__ksymtab : { *(__ksymtab) }
__stop___ksymtab = .;
__start___kallsyms = .; /* All kernel symbols */
__kallsyms : { *(__kallsyms) }
__stop___kallsyms = .;
.data : { /* Data */
*(.data)
CONSTRUCTORS
}
_edata = .; /* End of data section */
. = ALIGN(8192); /* init_task */
.data.init_task : { *(.data.init_task) }
. = ALIGN(4096); /* Init code and data */
__init_begin = .;
.text.init : { *(.text.init) }
.data.init : { *(.data.init) }
. = ALIGN(16);
__setup_start = .;
.setup.init : { *(.setup.init) }
__setup_end = .;
__initcall_start = .;
.initcall.init : { *(.initcall.init) }
__initcall_end = .;
. = ALIGN(4096);
__init_end = .;
. = ALIGN(4096);
.data.page_aligned : { *(.data.idt) }
. = ALIGN(32);
.data.cacheline_aligned : { *(.data.cacheline_aligned) }
__bss_start = .; /* BSS */
.bss : {
*(.bss)
}
_end = . ;
/* Sections to be discarded */
/DISCARD/ : {
*(.text.exit)
*(.data.exit)
*(.exitcall.exit)
}
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
}
+3 -1
View File
@@ -18,8 +18,10 @@
#define CONFIG_ACPI_BOOT 1
#define CONFIG_PCI 1
#define CONFIG_PCI_BIOS 1
#define CONFIG_PCI_DIRECT 1
#if defined(__i386__)
#define CONFIG_PCI_BIOS 1
#endif
#define CONFIG_IDE 1
#define CONFIG_BLK_DEV_IDE 1
+16 -8
View File
@@ -86,6 +86,8 @@ extern char _stext, _etext;
#define __STR(x) #x
#define STR(x) __STR(x)
#if defined(__i386__)
#define SAVE_ALL \
"cld\n\t" \
"pushl %gs\n\t" \
@@ -105,8 +107,11 @@ extern char _stext, _etext;
"movl %edx,%fs\n\t" \
"movl %edx,%gs\n\t"
#define IRQ_NAME2(nr) nr##_interrupt(void)
#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
#else
#define SAVE_ALL
#endif
#define BUILD_SMP_INTERRUPT(x,v) XBUILD_SMP_INTERRUPT(x,v)
#define XBUILD_SMP_INTERRUPT(x,v)\
@@ -115,7 +120,7 @@ asmlinkage void call_##x(void); \
__asm__( \
"\n"__ALIGN_STR"\n" \
SYMBOL_NAME_STR(x) ":\n\t" \
"pushl $"#v"\n\t" \
"push"__OS" $"#v"\n\t" \
SAVE_ALL \
SYMBOL_NAME_STR(call_##x)":\n\t" \
"call "SYMBOL_NAME_STR(smp_##x)"\n\t" \
@@ -128,13 +133,13 @@ asmlinkage void call_##x(void); \
__asm__( \
"\n"__ALIGN_STR"\n" \
SYMBOL_NAME_STR(x) ":\n\t" \
"pushl $"#v"\n\t" \
"push"__OS" $"#v"\n\t" \
SAVE_ALL \
"movl %esp,%eax\n\t" \
"pushl %eax\n\t" \
"mov %"__OP"sp,%"__OP"ax\n\t" \
"push %"__OP"ax\n\t" \
SYMBOL_NAME_STR(call_##x)":\n\t" \
"call "SYMBOL_NAME_STR(smp_##x)"\n\t" \
"addl $4,%esp\n\t" \
"add $4,%"__OP"sp\n\t" \
"jmp ret_from_intr\n");
#define BUILD_COMMON_IRQ() \
@@ -147,12 +152,15 @@ __asm__( \
"call " SYMBOL_NAME_STR(do_IRQ) "\n\t" \
"jmp ret_from_intr\n");
#define IRQ_NAME2(nr) nr##_interrupt(void)
#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
#define BUILD_IRQ(nr) \
asmlinkage void IRQ_NAME(nr); \
__asm__( \
"\n"__ALIGN_STR"\n" \
SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
"pushl $"#nr"\n\t" \
"push"__OS" $"#nr"\n\t" \
"jmp common_interrupt");
extern unsigned long prof_cpu_mask;
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.