mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
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:
commit
c101b31ccc
97 files changed
+8413
-1238
No files matched your search
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
#============================================================================
|
||||
@@ -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)
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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,4 +1,3 @@
|
||||
/* $Id: gzip_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */
|
||||
/*
|
||||
* Copyright (C) 2003 Hewlett-Packard Company.
|
||||
*
|
||||
|
||||
@@ -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_ */
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_ */
|
||||
@@ -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_ */
|
||||
|
||||
|
||||
|
||||
@@ -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_ */
|
||||
@@ -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 $@ $<
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>')
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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()
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
#============================================================================
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_ */
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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];
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
File diff suppressed because it is too large.
Load diff
@@ -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
|
||||
Executable
+127
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,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"
|
||||
);
|
||||
|
||||
@@ -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(¤t->mm);
|
||||
|
||||
init_idle_task();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __init do_initcalls(void)
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
Whitespace-only changes.
@@ -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;
|
||||
}
|
||||
@@ -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) }
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||