[Ocfstest-commits]
rev 2 - in trunk: . Ocfsts Ocfsts/t client server tests
svn-commits at oss.oracle.com
svn-commits at oss.oracle.com
Tue Aug 19 18:31:12 CDT 2003
Author: gmarsden
Date: 2003-08-19 17:31:10 -0500 (Tue, 19 Aug 2003)
New Revision: 2
Added:
trunk/Cmdlist.sample
trunk/Makefile
trunk/Makefile.config
trunk/Nodelist.sample
trunk/Ocfsts/
trunk/Ocfsts/Build.wrapper
trunk/Ocfsts/Changes
trunk/Ocfsts/MANIFEST
trunk/Ocfsts/Makefile.PL
trunk/Ocfsts/Ocfsts.pm
trunk/Ocfsts/Ocfsts.xs
trunk/Ocfsts/README
trunk/Ocfsts/perlobject.map
trunk/Ocfsts/ppport.h
trunk/Ocfsts/t/
trunk/Ocfsts/t/1.t
trunk/Ocfsts/test.pl
trunk/README
trunk/TODO
trunk/client/
trunk/client/Makefile
trunk/client/cdsl.h
trunk/client/client.c
trunk/client/command.c
trunk/client/command.h
trunk/client/exec.c
trunk/client/exec.h
trunk/client/md5.c
trunk/client/md5.h
trunk/client/ocfstsparse.c
trunk/client/ocfstsparse.h
trunk/client/response.c
trunk/client/response.h
trunk/client/testpacket
trunk/monkey/
trunk/ocfsts.h
trunk/ocfsts.sh
trunk/ocfsts_diff.pl
trunk/server/
trunk/server/Makefile
trunk/server/apitest.c
trunk/server/comm.c
trunk/server/comm.h
trunk/server/debug.h
trunk/server/logprint.c
trunk/server/logprint.h
trunk/server/md5print.h
trunk/server/nodelist
trunk/server/ocfs_test.c
trunk/server/ocfs_test.h
trunk/server/ocfs_test_server.c
trunk/server/ocfs_test_server.h
trunk/server/ocfstsapi.c
trunk/server/ocfstsapi.h
trunk/server/syntax.h
trunk/testclient.pl
trunk/tests/
trunk/tests/00_simple.pl
trunk/tests/05_tree.pl
trunk/tests/06_tree_delete.pl
trunk/tests/15_mvtests.pl
trunk/tests/30_manyfiles.pl
trunk/tests/45_openclose.pl
trunk/tests/Makefile
trunk/tests/ocfsts_config
Log:
ocfs test suite
Added: trunk/Cmdlist.sample
===================================================================
--- trunk/Cmdlist.sample 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/Cmdlist.sample 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,16 @@
+
+R mkdir /tmp/foo 0666
+R chmod /tmp/foo 0766
+
+R create /tmp/foo/bar
+R chmod /tmp/foo/bar 0766
+
+R resize /tmp/foo/bar 2048
+R modify /tmp/foo/bar 1
+
+- R delete /tmp/foo/bar/baz
+
+R delete /tmp/foo/bar
+R rmdir /tmp/foo
+
+R quit
Added: trunk/Makefile
===================================================================
--- trunk/Makefile 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/Makefile 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,52 @@
+#
+# ocfsts Makefile
+#
+
+include Makefile.config
+
+SERVERDIR=server
+CLIENTDIR=client
+
+.PHONY: clean tests perl
+
+all: all-redirect library perl
+
+library: $(OCFSTS_LIB_TARGET) $(OCFSTS_LIB_SERVER_TARGET)
+ mv $(OCFSTS_LIB_SERVER_TARGET) $(PERL_DIR)/
+
+perl:
+ make -f Build.wrapper -C $(PERL_DIR)
+
+tests:
+ make -C $(TEST_DIR)
+
+tests-clean:
+ make clean -C $(TEST_DIR)
+
+all-redirect: $(OCFSTS_LIB_TARGET) $(CLIENT_TARGET) $(SERVER_TARGET)
+
+#include Makefile.depend
+#depend:
+# $(CC) $(CXXFLAGS) -MM `find . -name '*.c'` > Makefile.depend
+
+$(OCFSTS_LIB_TARGET):
+ make -e -C $(CLIENTDIR) $@
+ mv $(CLIENTDIR)/$@ .
+
+$(SERVER_TARGET): $(OCFSTS_LIB_TARGET)
+ make -e -C $(SERVERDIR) $@
+ mv $(SERVERDIR)/$@ .
+
+$(CLIENT_TARGET): $(OCFSTS_LIB_TARGET)
+ make -e -C $(CLIENTDIR) $@
+ mv $(CLIENTDIR)/$@ .
+
+$(OCFSTS_LIB_SERVER_TARGET):
+ make -e -C $(SERVERDIR) $@
+ mv $(SERVERDIR)/$@ .
+
+clean:
+ make -e -C $(SERVERDIR) clean
+ make -e -C $(CLIENTDIR) clean
+ rm -f $(OCFSTS_LIB_TARGET) $(CLIENT_TARGET) $(SERVER_TARGET) $(OCFSTS_LIB_SERVER_TARGET) *~
+ make -e -C $(PERL_DIR) -f Build.wrapper clean
Added: trunk/Makefile.config
===================================================================
--- trunk/Makefile.config 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/Makefile.config 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,23 @@
+#
+# Be carefull - this also gets sourced by a bash script.
+# Blame Greg for that one :)
+#
+TARGET=.
+NODEFILE=nodelist
+
+TEST_DIR="tests";
+RESULT_DIR="results";
+ORIGINAL_DIR="diffs";
+PERL_DIR=Ocfsts
+
+SERVER_TARGET=ocfsts_server
+CLIENT_TARGET=ocfsts_client
+OCFSTS_LIB_TARGET=libocfsts.a
+OCFSTS_LIB_SERVER_TARGET=libocfsts_server.so
+
+CLIENT_INSTALL_DIR=/tmp
+CLIENT_USER=root
+
+OCFSTS_PORT=4444
+
+DIFF=ocfsts_diff.pl
Added: trunk/Nodelist.sample
===================================================================
--- trunk/Nodelist.sample 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/Nodelist.sample 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,11 @@
+# Sample node list for OCFS test suite
+verbose.us.oracle.com
+verbose.us.oracle.com
+verbose.us.oracle.com
+verbose.us.oracle.com
+#192.168.0.1
+#192.168.0.2
+#192.168.0.3
+#192.168.0.4
+#192.168.0.5
+#nic1-pc.us.oracle.com
Added: trunk/Ocfsts/Build.wrapper
===================================================================
--- trunk/Ocfsts/Build.wrapper 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/Ocfsts/Build.wrapper 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,10 @@
+#needed to build this from the main makefile
+all:
+ perl Makefile.PL
+ make
+
+.PHONY: clean
+
+clean:
+ - make clean
+ rm -f *~ $(OCFSTS_LIB_SERVER_TARGET)
Added: trunk/Ocfsts/Changes
===================================================================
--- trunk/Ocfsts/Changes 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/Ocfsts/Changes 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,6 @@
+Revision history for Perl extension Ocfsts.
+
+0.01 Thu Dec 5 13:54:20 2002
+ - original version; created by h2xs 1.22 with options
+ -A -d ocfsts
+
Added: trunk/Ocfsts/MANIFEST
===================================================================
--- trunk/Ocfsts/MANIFEST 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/Ocfsts/MANIFEST 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,8 @@
+Changes
+Makefile.PL
+MANIFEST
+Ocfsts.pm
+Ocfsts.xs
+ppport.h
+README
+t/1.t
Added: trunk/Ocfsts/Makefile.PL
===================================================================
--- trunk/Ocfsts/Makefile.PL 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/Ocfsts/Makefile.PL 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,30 @@
+use 5.008;
+use ExtUtils::MakeMaker;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+
+#my own stuff here to support the fatally broken beast that is C++
+#$CC = 'g++';
+
+WriteMakefile(
+ 'NAME' => 'Ocfsts',
+ 'VERSION_FROM' => 'Ocfsts.pm', # finds $VERSION
+ 'PREREQ_PM' => {}, # e.g., Module::Name => 1.1
+ ($] >= 5.005 ? ## Add these new keywords supported since 5.005
+ (ABSTRACT_FROM => 'Ocfsts.pm', # retrieve abstract from module
+ AUTHOR => 'Mark Fasheh <mark.fasheh at oracle.com>') : ()),
+ 'LIBS' => ['-L. -locfsts_server'], # e.g., '-lm'
+ 'DEFINE' => '', # e.g., '-DHAVE_SOMETHING'
+#next two lines added for C++
+# 'CC' => $CC,
+# 'LD' => '$(CC)',
+
+ 'INC' => '-I. -I../server/', # e.g., '-I. -I/usr/include/other'
+ # Un-comment this if you add C files to link with later:
+ # 'OBJECT' => '$(O_FILES)', # link all the C files too
+ #'OBJECT' => '../libocfsts_server.a', # link all the C files too
+
+#next two lines added for C++
+# 'XSOPT' => '-C++',
+# 'TYPEMAPS' => ['perlobject.map' ],
+);
Added: trunk/Ocfsts/Ocfsts.pm
===================================================================
--- trunk/Ocfsts/Ocfsts.pm 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/Ocfsts/Ocfsts.pm 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,343 @@
+package Ocfsts;
+
+use 5.008;
+#use strict;
+use warnings;
+use English;
+
+require Exporter;
+
+our @ISA = qw(Exporter);
+
+# Items to export into callers namespace by default. Note: do not export
+# names by default without a very good reason. Use EXPORT_OK instead.
+# Do not simply export all your public functions/methods/constants.
+
+# This allows declaration use Ocfsts ':all';
+# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
+# will save memory.
+our %EXPORT_TAGS = ( 'all' => [ qw(
+
+) ] );
+
+our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
+
+our @EXPORT = qw(
+
+);
+
+our $VERSION = '0.01';
+
+require XSLoader;
+XSLoader::load('Ocfsts', $VERSION);
+
+# Preloaded methods go here.
+
+%NUMARGS = (
+ "create" => 1,
+ "delete" => 1,
+ "fstat" => 1,
+ "chksum" => 1,
+ "rmdir" => 1,
+ "link" => 2,
+ "symlink" => 2,
+ "mv" => 2,
+ "mkdir" => 2,
+ "chmod" => 2,
+ "resize" => 2,
+ "modify" => 2,
+ "chown" => 3,
+ "mknod" => 4,
+ "open" => 1,
+ "close" => 1
+ );
+
+#children pids
+my @children;
+#are we a parent process or not?
+my $isparent = "true";
+
+sub ocfsts_set_child {
+ #print "Child at pid=", $$, "\n";
+ $isparent = "false";
+}
+
+sub ocfsts_set_parent($) {
+ my $pid = shift;
+
+ #print "Parent pushing $pid onto children array.\n";
+ push @children, $pid;
+}
+
+sub ocfsts_read_nodelist($) {
+ $filename = shift;
+ #print "reading nodelist from ", $filename, "\n";
+ open(NODEFILE, $filename) or return;
+
+ while (<NODEFILE>) {
+ /^\s*([\w.-]+)/ and push @NODES, $1;
+ }
+
+ close (NODEFILE);
+
+ return @NODES;
+}
+
+sub ocfsts_connect(@) {
+ @nodes = @_;
+ #$LIST_SEPARATOR="\n";
+ #print "connecting to these nodes:\n";
+ #print "@nodes";
+ #print "\n";
+ if ($#nodes >= 0) {
+ return Ocfsts::ocfsts_open_connection(@nodes);
+ }
+ return -1;
+}
+
+sub ocfsts_connect_n_procs($@) {
+ my $numprocs = shift;
+ my @nodes = shift;
+ my $i;
+ my $cpid;
+ my $retval;
+
+ #print "Will create $numprocs processes on each node\n";
+
+ #print "On nodes:\n";
+ #print "@nodes\n";
+ #print "\n";
+
+ for ($i=0; $i < ($numprocs-1); $i++) {
+ $cpid = fork();
+
+ if (!defined $cpid) {
+ die "Error[$$]: Couldn't fork!\n";
+ }
+
+ if ($cpid == 0) {
+ Ocfsts::ocfsts_set_child;
+ $retval = Ocfsts::ocfsts_connect @nodes;
+ return $retval;
+ } else {
+ Ocfsts::ocfsts_set_parent $cpid;
+ }
+ }
+
+ $retval = Ocfsts::ocfsts_connect @nodes;
+ return $retval;
+}
+
+sub ocfsts_disconnect {
+ my $child;
+ #If we have a bunch of children, waitpid on them to reap zombies.
+ #This also has the effect of
+ if ($isparent eq "true") {
+ while (@children) {
+ $child = pop @children;
+ waitpid $child, 0;
+ print "Parent: child $child reaped.\n";
+ }
+ }
+
+ #Actually disconnect from the node now.
+ return Ocfsts::ocfsts_close_connection();
+}
+
+
+#
+# expects as the 1st string argument, the actual command
+# after that, all the arguments to that command, then
+# the last two arguments are node name (leave empty for random)
+# and expected outcome ("f" for fail, empty or anything else for success)
+#
+# ocfsts_build_command "command", rest-of-command-args, [$node, $expected];
+#
+sub ocfsts_build_command {
+ my $command;
+ my $str;
+ my $node;
+ my $expected;
+ my $i;
+
+ $command = $_[0];
+ if ($command eq "" || !defined $NUMARGS{$command}) {
+ die "ocfsts_build_command called with a null or nonexistent command!\n";
+ }
+
+ $str = $command;
+ for ($i = 1; $i <= $NUMARGS{$command}; $i++) {
+ if (!defined $_[$i]) {
+ die "ocfsts_build_command: command \"$command\" without enough arguments\n";
+ }
+ $str = $str." ".$_[$i];
+ }
+
+ $node = "";
+ $expected = "";
+ if (defined $_[$i]) {
+ $node = $_[$i];
+ $i++;
+ if (defined $_[$i]) {
+ $expected = $_[$i];
+ }
+ }
+ #print "node is $node and expected is $expected\n";
+
+ if ($node eq "") {
+ $node = "R";
+ }
+ $str = "$node $str";
+ if ($expected eq "f" || $expected eq "F" || $expected eq "FAIL" || $expected eq "fail") {
+ $str = "- ".$str;
+ }
+
+ # print "built command: $str\n";
+ return $str;
+}
+
+sub ocfsts_do_command_full {
+ $command = shift;
+ $str = ocfsts_build_command $command, @_;
+ if ($str eq "") {
+ print "ocfsts_do_command_full: Error building command, not sending.";
+ return;
+ }
+
+ #print "Sending execution string: $str\n";
+ $retval = Ocfsts::ocfsts_execute($str);
+ #print "Execute returns: $retval\n";
+ if ($retval != 0) {
+ print "ocfsts_do_command_full: Error returned from command: \"$str\"\n";
+ return;
+ }
+ $retval = Ocfsts::ocfsts_verify($str);
+ #print "Verify returns: $retval\n";
+ if ($retval != 0) {
+ print "ocfsts_do_command_full: Error verifying command, string = \"$str\"\n";
+ return;
+ }
+ return $retval;
+}
+
+sub ocfsts_create {
+ return ocfsts_do_command_full "create", @_;
+}
+
+sub ocfsts_delete {
+ return ocfsts_do_command_full "delete", @_;
+}
+
+sub ocfsts_fstat {
+ return ocfsts_do_command_full "fstat", @_;
+}
+
+sub ocfsts_chksum {
+ return ocfsts_do_command_full "chksum", @_;
+}
+
+sub ocfsts_rmdir {
+ return ocfsts_do_command_full "rmdir", @_;
+}
+
+sub ocfsts_link {
+ return ocfsts_do_command_full "link", @_;
+}
+
+sub ocfsts_symlink {
+ return ocfsts_do_command_full "symlink", @_;
+}
+
+sub ocfsts_mv {
+ return ocfsts_do_command_full "mv", @_;
+}
+
+sub ocfsts_mkdir {
+ return ocfsts_do_command_full "mkdir", @_;
+}
+
+sub ocfsts_chmod {
+ return ocfsts_do_command_full "chmod", @_;
+}
+
+sub ocfsts_resize {
+ return ocfsts_do_command_full "resize", @_;
+}
+
+sub ocfsts_modify {
+ return ocfsts_do_command_full "modify", @_;
+}
+
+sub ocfsts_chown {
+ return ocfsts_do_command_full "chown", @_;
+}
+
+sub ocfsts_mknod {
+ return ocfsts_do_command_full "mknod", @_;
+}
+
+sub ocfsts_open {
+ return ocfsts_do_command_full "open", @_;
+}
+
+sub ocfsts_close {
+ return ocfsts_do_command_full "close", @_;
+}
+
+
+__END__
+# Below is stub documentation for your module. You'd better edit it!
+
+=head1 NAME
+
+Ocfsts - Perl extension for blah blah blah
+
+=head1 SYNOPSIS
+
+ use Ocfsts;
+ blah blah blah
+
+=head1 ABSTRACT
+
+ This should be the abstract for Ocfsts.
+ The abstract is used when making PPD (Perl Package Description) files.
+ If you don't want an ABSTRACT you should also edit Makefile.PL to
+ remove the ABSTRACT_FROM option.
+
+=head1 DESCRIPTION
+
+Stub documentation for Ocfsts, created by h2xs. It looks like the
+author of the extension was negligent enough to leave the stub
+unedited.
+
+Blah blah blah.
+
+=head2 EXPORT
+
+None by default.
+
+
+
+=head1 SEE ALSO
+
+Mention other useful documentation such as the documentation of
+related modules or operating system documentation (such as man pages
+in UNIX), or any relevant external documentation such as RFCs or
+standards.
+
+If you have a mailing list set up for your module, mention it here.
+
+If you have a web site set up for your module, mention it here.
+
+=head1 AUTHOR
+
+Mark Fasheh, E<lt>mfasheh at localdomainE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 2002 by Mark Fasheh
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut
Added: trunk/Ocfsts/Ocfsts.xs
===================================================================
--- trunk/Ocfsts/Ocfsts.xs 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/Ocfsts/Ocfsts.xs 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,77 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#include "ppport.h"
+
+#include <stdio.h>
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#include "../server/ocfstsapi.h"
+
+
+MODULE = Ocfsts PACKAGE = Ocfsts
+
+int
+ocfsts_open_connection(...)
+ PREINIT:
+ int i = 0;
+ SV* value = NULL;
+ char *str;
+ char** array = NULL;
+ CODE:
+ /* allocate the memory for our array... */
+ //printf("items=%d\n", items);
+ array = (char **) malloc(items * sizeof(char *));
+ for (i = 0; i < items; i++) {
+ value = ST(i);
+ str = SvPV(value, PL_na);
+ //printf("Passing: %s\n", str);
+ array[i] = strdup(str);
+ }
+ RETVAL = ocfsts_open_connection(items, array);
+ //printf("Freeing these values...\n");
+ fflush(stdout);
+ for (i = 0; i < items; i++) {
+ free(array[i]);
+ }
+ free(array);
+ //printf("Free'd\n");
+ OUTPUT:
+ RETVAL
+
+int
+ocfsts_close_connection()
+
+int
+ocfsts_execute(command)
+ char *command;
+ SV* value = NULL;
+ CODE:
+ value = ST(0);
+ command = SvPV(value, PL_na);
+ //printf("command string is %s\n", command);
+ RETVAL = ocfsts_execute(command);
+ OUTPUT:
+ RETVAL
+
+
+int
+ocfsts_verify(command)
+ char *command;
+ SV* value = NULL;
+ CODE:
+ value = ST(0);
+ command = SvPV(value, PL_na);
+ //printf("command string (verify) is %s\n", command);
+ RETVAL = ocfsts_verify(command);
+ //printf("\n\ncofsts_verify: returned from verify\n");
+ OUTPUT:
+ RETVAL
Added: trunk/Ocfsts/README
===================================================================
--- trunk/Ocfsts/README 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/Ocfsts/README 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,38 @@
+Ocfsts version 0.01
+===================
+
+The README is used to introduce the module and provide instructions on
+how to install the module, any machine dependencies it may have (for
+example C compilers and installed libraries) and any other information
+that should be provided before the module is installed.
+
+A README file is required for CPAN modules since CPAN extracts the
+README file from a module distribution so that people browsing the
+archive can use it get an idea of the modules uses. It is usually a
+good idea to provide version information here so that people can
+decide whether fixes for the module are worth downloading.
+
+INSTALLATION
+
+To install this module type the following:
+
+ perl Makefile.PL
+ make
+ make test
+ make install
+
+DEPENDENCIES
+
+This module requires these other modules and libraries:
+
+ blah blah blah
+
+COPYRIGHT AND LICENCE
+
+Put the correct copyright and licence information here.
+
+Copyright (C) 2002 Mark Fasheh
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
Added: trunk/Ocfsts/perlobject.map
===================================================================
--- trunk/Ocfsts/perlobject.map 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/Ocfsts/perlobject.map 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,106 @@
+# "perlobject.map" Dean Roehrich, version 19960302
+#
+# TYPEMAPs
+#
+# HV * -> unblessed Perl HV object.
+# AV * -> unblessed Perl AV object.
+#
+# INPUT/OUTPUT maps
+#
+# O_* -> opaque blessed objects
+# T_* -> opaque blessed or unblessed objects
+#
+# O_OBJECT -> link an opaque C or C++ object to a blessed Perl object.
+# T_OBJECT -> link an opaque C or C++ object to an unblessed Perl object.
+# O_HvRV -> a blessed Perl HV object.
+# T_HvRV -> an unblessed Perl HV object.
+# O_AvRV -> a blessed Perl AV object.
+# T_AvRV -> an unblessed Perl AV object.
+
+TYPEMAP
+
+HV * T_HvRV
+AV * T_AvRV
+
+
+######################################################################
+OUTPUT
+
+# The Perl object is blessed into 'CLASS', which should be a
+# char* having the name of the package for the blessing.
+O_OBJECT
+ sv_setref_pv( $arg, CLASS, (void*)$var );
+
+T_OBJECT
+ sv_setref_pv( $arg, Nullch, (void*)$var );
+
+# Cannot use sv_setref_pv() because that will destroy
+# the HV-ness of the object. Remember that newRV() will increment
+# the refcount.
+O_HvRV
+ $arg = sv_bless( newRV((SV*)$var), gv_stashpv(CLASS,1) );
+
+T_HvRV
+ $arg = newRV((SV*)$var);
+
+# Cannot use sv_setref_pv() because that will destroy
+# the AV-ness of the object. Remember that newRV() will increment
+# the refcount.
+O_AvRV
+ $arg = sv_bless( newRV((SV*)$var), gv_stashpv(CLASS,1) );
+
+T_AvRV
+ $arg = newRV((SV*)$var);
+
+
+######################################################################
+INPUT
+
+O_OBJECT
+ if( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVMG) )
+ $var = ($type)SvIV((SV*)SvRV( $arg ));
+ else{
+ warn( \"${Package}::$func_name() -- $var is not a blessed SV reference\" );
+ XSRETURN_UNDEF;
+ }
+
+T_OBJECT
+ if( SvROK($arg) )
+ $var = ($type)SvIV((SV*)SvRV( $arg ));
+ else{
+ warn( \"${Package}::$func_name() -- $var is not an SV reference\" );
+ XSRETURN_UNDEF;
+ }
+
+O_HvRV
+ if( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVHV) )
+ $var = (HV*)SvRV( $arg );
+ else {
+ warn( \"${Package}::$func_name() -- $var is not a blessed HV reference\" );
+ XSRETURN_UNDEF;
+ }
+
+T_HvRV
+ if( SvROK($arg) && (SvTYPE(SvRV($arg)) == SVt_PVHV) )
+ $var = (HV*)SvRV( $arg );
+ else {
+ warn( \"${Package}::$func_name() -- $var is not an HV reference\" );
+ XSRETURN_UNDEF;
+ }
+
+O_AvRV
+ if( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVAV) )
+ $var = (AV*)SvRV( $arg );
+ else {
+ warn( \"${Package}::$func_name() -- $var is not a blessed AV reference\" );
+ XSRETURN_UNDEF;
+ }
+
+T_AvRV
+ if( SvROK($arg) && (SvTYPE(SvRV($arg)) == SVt_PVAV) )
+ $var = (AV*)SvRV( $arg );
+ else {
+ warn( \"${Package}::$func_name() -- $var is not an AV reference\" );
+ XSRETURN_UNDEF;
+ }
+
Added: trunk/Ocfsts/ppport.h
===================================================================
--- trunk/Ocfsts/ppport.h 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/Ocfsts/ppport.h 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,540 @@
+
+/* ppport.h -- Perl/Pollution/Portability Version 2.0002
+ *
+ * Automatically Created by Devel::PPPort on Thu Dec 5 13:54:20 2002
+ *
+ * Do NOT edit this file directly! -- Edit PPPort.pm instead.
+ *
+ * Version 2.x, Copyright (C) 2001, Paul Marquess.
+ * Version 1.x, Copyright (C) 1999, Kenneth Albanowski.
+ * This code may be used and distributed under the same license as any
+ * version of Perl.
+ *
+ * This version of ppport.h is designed to support operation with Perl
+ * installations back to 5.004, and has been tested up to 5.8.0.
+ *
+ * If this version of ppport.h is failing during the compilation of this
+ * module, please check if a newer version of Devel::PPPort is available
+ * on CPAN before sending a bug report.
+ *
+ * If you are using the latest version of Devel::PPPort and it is failing
+ * during compilation of this module, please send a report to perlbug at perl.com
+ *
+ * Include all following information:
+ *
+ * 1. The complete output from running "perl -V"
+ *
+ * 2. This file.
+ *
+ * 3. The name & version of the module you were trying to build.
+ *
+ * 4. A full log of the build that failed.
+ *
+ * 5. Any other information that you think could be relevant.
+ *
+ *
+ * For the latest version of this code, please retreive the Devel::PPPort
+ * module from CPAN.
+ *
+ */
+
+/*
+ * In order for a Perl extension module to be as portable as possible
+ * across differing versions of Perl itself, certain steps need to be taken.
+ * Including this header is the first major one, then using dTHR is all the
+ * appropriate places and using a PL_ prefix to refer to global Perl
+ * variables is the second.
+ *
+ */
+
+
+/* If you use one of a few functions that were not present in earlier
+ * versions of Perl, please add a define before the inclusion of ppport.h
+ * for a static include, or use the GLOBAL request in a single module to
+ * produce a global definition that can be referenced from the other
+ * modules.
+ *
+ * Function: Static define: Extern define:
+ * newCONSTSUB() NEED_newCONSTSUB NEED_newCONSTSUB_GLOBAL
+ *
+ */
+
+
+/* To verify whether ppport.h is needed for your module, and whether any
+ * special defines should be used, ppport.h can be run through Perl to check
+ * your source code. Simply say:
+ *
+ * perl -x ppport.h *.c *.h *.xs foo/bar*.c [etc]
+ *
+ * The result will be a list of patches suggesting changes that should at
+ * least be acceptable, if not necessarily the most efficient solution, or a
+ * fix for all possible problems. It won't catch where dTHR is needed, and
+ * doesn't attempt to account for global macro or function definitions,
+ * nested includes, typemaps, etc.
+ *
+ * In order to test for the need of dTHR, please try your module under a
+ * recent version of Perl that has threading compiled-in.
+ *
+ */
+
+
+/*
+#!/usr/bin/perl
+ at ARGV = ("*.xs") if !@ARGV;
+%badmacros = %funcs = %macros = (); $replace = 0;
+foreach (<DATA>) {
+ $funcs{$1} = 1 if /Provide:\s+(\S+)/;
+ $macros{$1} = 1 if /^#\s*define\s+([a-zA-Z0-9_]+)/;
+ $replace = $1 if /Replace:\s+(\d+)/;
+ $badmacros{$2}=$1 if $replace and /^#\s*define\s+([a-zA-Z0-9_]+).*?\s+([a-zA-Z0-9_]+)/;
+ $badmacros{$1}=$2 if /Replace (\S+) with (\S+)/;
+}
+foreach $filename (map(glob($_), at ARGV)) {
+ unless (open(IN, "<$filename")) {
+ warn "Unable to read from $file: $!\n";
+ next;
+ }
+ print "Scanning $filename...\n";
+ $c = ""; while (<IN>) { $c .= $_; } close(IN);
+ $need_include = 0; %add_func = (); $changes = 0;
+ $has_include = ($c =~ /#.*include.*ppport/m);
+
+ foreach $func (keys %funcs) {
+ if ($c =~ /#.*define.*\bNEED_$func(_GLOBAL)?\b/m) {
+ if ($c !~ /\b$func\b/m) {
+ print "If $func isn't needed, you don't need to request it.\n" if
+ $changes += ($c =~ s/^.*#.*define.*\bNEED_$func\b.*\n//m);
+ } else {
+ print "Uses $func\n";
+ $need_include = 1;
+ }
+ } else {
+ if ($c =~ /\b$func\b/m) {
+ $add_func{$func} =1 ;
+ print "Uses $func\n";
+ $need_include = 1;
+ }
+ }
+ }
+
+ if (not $need_include) {
+ foreach $macro (keys %macros) {
+ if ($c =~ /\b$macro\b/m) {
+ print "Uses $macro\n";
+ $need_include = 1;
+ }
+ }
+ }
+
+ foreach $badmacro (keys %badmacros) {
+ if ($c =~ /\b$badmacro\b/m) {
+ $changes += ($c =~ s/\b$badmacro\b/$badmacros{$badmacro}/gm);
+ print "Uses $badmacros{$badmacro} (instead of $badmacro)\n";
+ $need_include = 1;
+ }
+ }
+
+ if (scalar(keys %add_func) or $need_include != $has_include) {
+ if (!$has_include) {
+ $inc = join('',map("#define NEED_$_\n", sort keys %add_func)).
+ "#include \"ppport.h\"\n";
+ $c = "$inc$c" unless $c =~ s/#.*include.*XSUB.*\n/$&$inc/m;
+ } elsif (keys %add_func) {
+ $inc = join('',map("#define NEED_$_\n", sort keys %add_func));
+ $c = "$inc$c" unless $c =~ s/^.*#.*include.*ppport.*$/$inc$&/m;
+ }
+ if (!$need_include) {
+ print "Doesn't seem to need ppport.h.\n";
+ $c =~ s/^.*#.*include.*ppport.*\n//m;
+ }
+ $changes++;
+ }
+
+ if ($changes) {
+ open(OUT,">/tmp/ppport.h.$$");
+ print OUT $c;
+ close(OUT);
+ open(DIFF, "diff -u $filename /tmp/ppport.h.$$|");
+ while (<DIFF>) { s!/tmp/ppport\.h\.$$!$filename.patched!; print STDOUT; }
+ close(DIFF);
+ unlink("/tmp/ppport.h.$$");
+ } else {
+ print "Looks OK\n";
+ }
+}
+__DATA__
+*/
+
+#ifndef _P_P_PORTABILITY_H_
+#define _P_P_PORTABILITY_H_
+
+#ifndef PERL_REVISION
+# ifndef __PATCHLEVEL_H_INCLUDED__
+# include "patchlevel.h"
+# endif
+# ifndef PERL_REVISION
+# define PERL_REVISION (5)
+ /* Replace: 1 */
+# define PERL_VERSION PATCHLEVEL
+# define PERL_SUBVERSION SUBVERSION
+ /* Replace PERL_PATCHLEVEL with PERL_VERSION */
+ /* Replace: 0 */
+# endif
+#endif
+
+#define PERL_BCDVERSION ((PERL_REVISION * 0x1000000L) + (PERL_VERSION * 0x1000L) + PERL_SUBVERSION)
+
+/* It is very unlikely that anyone will try to use this with Perl 6
+ (or greater), but who knows.
+ */
+#if PERL_REVISION != 5
+# error ppport.h only works with Perl version 5
+#endif /* PERL_REVISION != 5 */
+
+#ifndef ERRSV
+# define ERRSV perl_get_sv("@",FALSE)
+#endif
+
+#if (PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION <= 5))
+/* Replace: 1 */
+# define PL_Sv Sv
+# define PL_compiling compiling
+# define PL_copline copline
+# define PL_curcop curcop
+# define PL_curstash curstash
+# define PL_defgv defgv
+# define PL_dirty dirty
+# define PL_dowarn dowarn
+# define PL_hints hints
+# define PL_na na
+# define PL_perldb perldb
+# define PL_rsfp_filters rsfp_filters
+# define PL_rsfpv rsfp
+# define PL_stdingv stdingv
+# define PL_sv_no sv_no
+# define PL_sv_undef sv_undef
+# define PL_sv_yes sv_yes
+/* Replace: 0 */
+#endif
+
+#ifdef HASATTRIBUTE
+# if defined(__GNUC__) && defined(__cplusplus)
+# define PERL_UNUSED_DECL
+# else
+# define PERL_UNUSED_DECL __attribute__((unused))
+# endif
+#else
+# define PERL_UNUSED_DECL
+#endif
+
+#ifndef dNOOP
+# define NOOP (void)0
+# define dNOOP extern int Perl___notused PERL_UNUSED_DECL
+#endif
+
+#ifndef dTHR
+# define dTHR dNOOP
+#endif
+
+#ifndef dTHX
+# define dTHX dNOOP
+# define dTHXa(x) dNOOP
+# define dTHXoa(x) dNOOP
+#endif
+
+#ifndef pTHX
+# define pTHX void
+# define pTHX_
+# define aTHX
+# define aTHX_
+#endif
+
+#ifndef UVSIZE
+# define UVSIZE IVSIZE
+#endif
+
+#ifndef NVTYPE
+# if defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE)
+# define NVTYPE long double
+# else
+# define NVTYPE double
+# endif
+typedef NVTYPE NV;
+#endif
+
+#ifndef INT2PTR
+
+#if (IVSIZE == PTRSIZE) && (UVSIZE == PTRSIZE)
+# define PTRV UV
+# define INT2PTR(any,d) (any)(d)
+#else
+# if PTRSIZE == LONGSIZE
+# define PTRV unsigned long
+# else
+# define PTRV unsigned
+# endif
+# define INT2PTR(any,d) (any)(PTRV)(d)
+#endif
+#define NUM2PTR(any,d) (any)(PTRV)(d)
+#define PTR2IV(p) INT2PTR(IV,p)
+#define PTR2UV(p) INT2PTR(UV,p)
+#define PTR2NV(p) NUM2PTR(NV,p)
+#if PTRSIZE == LONGSIZE
+# define PTR2ul(p) (unsigned long)(p)
+#else
+# define PTR2ul(p) INT2PTR(unsigned long,p)
+#endif
+
+#endif /* !INT2PTR */
+
+#ifndef boolSV
+# define boolSV(b) ((b) ? &PL_sv_yes : &PL_sv_no)
+#endif
+
+#ifndef gv_stashpvn
+# define gv_stashpvn(str,len,flags) gv_stashpv(str,flags)
+#endif
+
+#ifndef newSVpvn
+# define newSVpvn(data,len) ((len) ? newSVpv ((data), (len)) : newSVpv ("", 0))
+#endif
+
+#ifndef newRV_inc
+/* Replace: 1 */
+# define newRV_inc(sv) newRV(sv)
+/* Replace: 0 */
+#endif
+
+/* DEFSV appears first in 5.004_56 */
+#ifndef DEFSV
+# define DEFSV GvSV(PL_defgv)
+#endif
+
+#ifndef SAVE_DEFSV
+# define SAVE_DEFSV SAVESPTR(GvSV(PL_defgv))
+#endif
+
+#ifndef newRV_noinc
+# ifdef __GNUC__
+# define newRV_noinc(sv) \
+ ({ \
+ SV *nsv = (SV*)newRV(sv); \
+ SvREFCNT_dec(sv); \
+ nsv; \
+ })
+# else
+# if defined(USE_THREADS)
+static SV * newRV_noinc (SV * sv)
+{
+ SV *nsv = (SV*)newRV(sv);
+ SvREFCNT_dec(sv);
+ return nsv;
+}
+# else
+# define newRV_noinc(sv) \
+ (PL_Sv=(SV*)newRV(sv), SvREFCNT_dec(sv), (SV*)PL_Sv)
+# endif
+# endif
+#endif
+
+/* Provide: newCONSTSUB */
+
+/* newCONSTSUB from IO.xs is in the core starting with 5.004_63 */
+#if (PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION < 63))
+
+#if defined(NEED_newCONSTSUB)
+static
+#else
+extern void newCONSTSUB(HV * stash, char * name, SV *sv);
+#endif
+
+#if defined(NEED_newCONSTSUB) || defined(NEED_newCONSTSUB_GLOBAL)
+void
+newCONSTSUB(stash,name,sv)
+HV *stash;
+char *name;
+SV *sv;
+{
+ U32 oldhints = PL_hints;
+ HV *old_cop_stash = PL_curcop->cop_stash;
+ HV *old_curstash = PL_curstash;
+ line_t oldline = PL_curcop->cop_line;
+ PL_curcop->cop_line = PL_copline;
+
+ PL_hints &= ~HINT_BLOCK_SCOPE;
+ if (stash)
+ PL_curstash = PL_curcop->cop_stash = stash;
+
+ newSUB(
+
+#if (PERL_VERSION < 3) || ((PERL_VERSION == 3) && (PERL_SUBVERSION < 22))
+ /* before 5.003_22 */
+ start_subparse(),
+#else
+# if (PERL_VERSION == 3) && (PERL_SUBVERSION == 22)
+ /* 5.003_22 */
+ start_subparse(0),
+# else
+ /* 5.003_23 onwards */
+ start_subparse(FALSE, 0),
+# endif
+#endif
+
+ newSVOP(OP_CONST, 0, newSVpv(name,0)),
+ newSVOP(OP_CONST, 0, &PL_sv_no), /* SvPV(&PL_sv_no) == "" -- GMB */
+ newSTATEOP(0, Nullch, newSVOP(OP_CONST, 0, sv))
+ );
+
+ PL_hints = oldhints;
+ PL_curcop->cop_stash = old_cop_stash;
+ PL_curstash = old_curstash;
+ PL_curcop->cop_line = oldline;
+}
+#endif
+
+#endif /* newCONSTSUB */
+
+#ifndef START_MY_CXT
+
+/*
+ * Boilerplate macros for initializing and accessing interpreter-local
+ * data from C. All statics in extensions should be reworked to use
+ * this, if you want to make the extension thread-safe. See ext/re/re.xs
+ * for an example of the use of these macros.
+ *
+ * Code that uses these macros is responsible for the following:
+ * 1. #define MY_CXT_KEY to a unique string, e.g. "DynaLoader_guts"
+ * 2. Declare a typedef named my_cxt_t that is a structure that contains
+ * all the data that needs to be interpreter-local.
+ * 3. Use the START_MY_CXT macro after the declaration of my_cxt_t.
+ * 4. Use the MY_CXT_INIT macro such that it is called exactly once
+ * (typically put in the BOOT: section).
+ * 5. Use the members of the my_cxt_t structure everywhere as
+ * MY_CXT.member.
+ * 6. Use the dMY_CXT macro (a declaration) in all the functions that
+ * access MY_CXT.
+ */
+
+#if defined(MULTIPLICITY) || defined(PERL_OBJECT) || \
+ defined(PERL_CAPI) || defined(PERL_IMPLICIT_CONTEXT)
+
+/* This must appear in all extensions that define a my_cxt_t structure,
+ * right after the definition (i.e. at file scope). The non-threads
+ * case below uses it to declare the data as static. */
+#define START_MY_CXT
+
+#if (PERL_VERSION < 4 || (PERL_VERSION == 4 && PERL_SUBVERSION < 68 ))
+/* Fetches the SV that keeps the per-interpreter data. */
+#define dMY_CXT_SV \
+ SV *my_cxt_sv = perl_get_sv(MY_CXT_KEY, FALSE)
+#else /* >= perl5.004_68 */
+#define dMY_CXT_SV \
+ SV *my_cxt_sv = *hv_fetch(PL_modglobal, MY_CXT_KEY, \
+ sizeof(MY_CXT_KEY)-1, TRUE)
+#endif /* < perl5.004_68 */
+
+/* This declaration should be used within all functions that use the
+ * interpreter-local data. */
+#define dMY_CXT \
+ dMY_CXT_SV; \
+ my_cxt_t *my_cxtp = INT2PTR(my_cxt_t*,SvUV(my_cxt_sv))
+
+/* Creates and zeroes the per-interpreter data.
+ * (We allocate my_cxtp in a Perl SV so that it will be released when
+ * the interpreter goes away.) */
+#define MY_CXT_INIT \
+ dMY_CXT_SV; \
+ /* newSV() allocates one more than needed */ \
+ my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1));\
+ Zero(my_cxtp, 1, my_cxt_t); \
+ sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))
+
+/* This macro must be used to access members of the my_cxt_t structure.
+ * e.g. MYCXT.some_data */
+#define MY_CXT (*my_cxtp)
+
+/* Judicious use of these macros can reduce the number of times dMY_CXT
+ * is used. Use is similar to pTHX, aTHX etc. */
+#define pMY_CXT my_cxt_t *my_cxtp
+#define pMY_CXT_ pMY_CXT,
+#define _pMY_CXT ,pMY_CXT
+#define aMY_CXT my_cxtp
+#define aMY_CXT_ aMY_CXT,
+#define _aMY_CXT ,aMY_CXT
+
+#else /* single interpreter */
+
+
+#define START_MY_CXT static my_cxt_t my_cxt;
+#define dMY_CXT_SV dNOOP
+#define dMY_CXT dNOOP
+#define MY_CXT_INIT NOOP
+#define MY_CXT my_cxt
+
+#define pMY_CXT void
+#define pMY_CXT_
+#define _pMY_CXT
+#define aMY_CXT
+#define aMY_CXT_
+#define _aMY_CXT
+
+#endif
+
+#endif /* START_MY_CXT */
+
+#ifndef IVdf
+# if IVSIZE == LONGSIZE
+# define IVdf "ld"
+# define UVuf "lu"
+# define UVof "lo"
+# define UVxf "lx"
+# define UVXf "lX"
+# else
+# if IVSIZE == INTSIZE
+# define IVdf "d"
+# define UVuf "u"
+# define UVof "o"
+# define UVxf "x"
+# define UVXf "X"
+# endif
+# endif
+#endif
+
+#ifndef NVef
+# if defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE) && \
+ defined(PERL_PRIfldbl) /* Not very likely, but let's try anyway. */
+# define NVef PERL_PRIeldbl
+# define NVff PERL_PRIfldbl
+# define NVgf PERL_PRIgldbl
+# else
+# define NVef "e"
+# define NVff "f"
+# define NVgf "g"
+# endif
+#endif
+
+#ifndef AvFILLp /* Older perls (<=5.003) lack AvFILLp */
+# define AvFILLp AvFILL
+#endif
+
+#ifdef SvPVbyte
+# if PERL_REVISION == 5 && PERL_VERSION < 7
+ /* SvPVbyte does not work in perl-5.6.1, borrowed version for 5.7.3 */
+# undef SvPVbyte
+# define SvPVbyte(sv, lp) \
+ ((SvFLAGS(sv) & (SVf_POK|SVf_UTF8)) == (SVf_POK) \
+ ? ((lp = SvCUR(sv)), SvPVX(sv)) : my_sv_2pvbyte(aTHX_ sv, &lp))
+ static char *
+ my_sv_2pvbyte(pTHX_ register SV *sv, STRLEN *lp)
+ {
+ sv_utf8_downgrade(sv,0);
+ return SvPV(sv,*lp);
+ }
+# endif
+#else
+# define SvPVbyte SvPV
+#endif
+
+#endif /* _P_P_PORTABILITY_H_ */
+
+/* End of File ppport.h */
Added: trunk/Ocfsts/t/1.t
===================================================================
--- trunk/Ocfsts/t/1.t 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/Ocfsts/t/1.t 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,15 @@
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl 1.t'
+
+#########################
+
+# change 'tests => 1' to 'tests => last_test_to_print';
+
+use Test::More tests => 1;
+BEGIN { use_ok('Ocfsts') };
+
+#########################
+
+# Insert your test code below, the Test::More module is use()ed here so read
+# its man page ( perldoc Test::More ) for help writing this test script.
+
Added: trunk/Ocfsts/test.pl
===================================================================
--- trunk/Ocfsts/test.pl 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/Ocfsts/test.pl 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,33 @@
+#! /usr/bin/perl
+
+use ExtUtils::testlib;
+#use English;
+use Ocfsts;
+
+ at nodes = ("localhost");
+#pop @nodes;
+#Ocfsts::ocfsts_connect_n_procs 5, @nodes;
+print "connecting, ", $#nodes, " nodes\n";
+$retval = Ocfsts::ocfsts_connect @nodes;
+
+#sleep 4;
+#Ocfsts::ocfsts_disconnect;
+
+print "running commands, connect returned $retval\n";
+Ocfsts::ocfsts_create "/tmp/file_$$";
+sleep 9999;
+Ocfsts::ocfsts_close_connection;
+die;
+
+Ocfsts::ocfsts_chmod "/tmp/myfile", "0777";
+
+Ocfsts::ocfsts_resize "/tmp/myfile", "1000";
+
+Ocfsts::ocfsts_modify "/tmp/myfile", "31337";
+
+Ocfsts::ocfsts_delete "/tmp/myfile";
+
+#expect this to fail
+Ocfsts::ocfsts_delete "/tmp/shouldfail", "localhost", "fail";
+
+Ocfsts::ocfsts_close_connection;
Added: trunk/README
===================================================================
--- trunk/README 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/README 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,147 @@
+
+OCFS Test Suite -- README
+
+Authors:
+ mark.fasheh at oracle.com
+ greg.marsden at oracle.com
+
+Table of Contents
+ 0. Quick Start
+ 1. Architecture description
+ 2. System requirements
+ 3. Configuration file formats
+ 3.1. Node list
+ 3.2. Command list
+ 4. Known bugs
+
+0. Quick Start
+
+The ocfsts.sh script provides a wrapper for all important activies
+in ocfsts, including spawining client processes and cleaning them
+up after the tests have been run and diff files created against
+existing "correct" diff files.
+
+./ocfsts.sh make
+ compile the test server and clients
+./ocfsts.sh makediffs
+ generate the "original" diff files. These files are NOT
+ automatically generated correctly, and must be hand tuned.
+ This is a "bug" which could be fixed in the future.
+ Also note that makediffs starts the clients on each node but does not
+ shut them down.
+./ocfsts.sh run
+ run the tests
+./ocfsts.sh kill
+ kill all clients on the cluster
+
+Note that all configuration options, including placement of directories and
+diff files, is controlled in ocfsts.config
+
+
+1. Architecture description
+
+The OCFS Test Suite is a package for generic cluster-filesystem
+testing from multiple nodes. The package consists of two independent
+executables, one for each cluster node and one for the server (which
+can be run on a single node).
+
+The client waits for input on port 4444, executes the server command,
+and returns the response. The client shuts down only when a "QUIT"
+command is received. The server blocks until the client's response
+is received.
+
+This test suite was designed to exercise the filesystem in routine file
+operations and not under high load conditions. As such, the test server
+is single-threaded, providing only one file operation at a time and does
+not test behavior under multiple simultaneous queries.
+
+A compile-time flag allows the test suite to bypass verifications on
+the specified command node. This function is off by default, except
+in the cdsl case.
+
+
+2. System requirements
+
+OCFS is not required to run the test suite. Multiple instances of the
+local host (or any other host running the client binary) can be added
+to the nodes file.
+
+
+3. Configuration File formats
+
+Running the client:
+ ./ocfs_test_client
+ or
+ while ! [ ] ; do ./ocfs_test_client ; done
+
+Running the server:
+ ./ocfs_test_server nodefile < commands
+ or
+ ./ocfs_test_server nodefile commandlist
+
+3.1. Node file format
+
+The node file format is one node per line, any
+blank lines or extra characters after whitespace
+discarded. The comment character is '#'. Nodes
+can be specified by numeric ip (dotted quad) or
+by hostname.
+
+3.2. Command file format
+
+The command file format is one command per line,
+# or leading space is considered to be a comment
+and blank lines are ignored. The command syntax
+is as follows:
+
+[+-#] <node_name|node_number|R> <command> [filename] [arg1 . . . ] [cdsl[+-]]
+
+Optional success token: (defaults to "expect success")
+ + expect the command to succeed
+ - expect a fail
+ # comment
+
+Node target: (required)
+ R randomly choose a node
+ node_name must be exactly as specified in the node file
+ node_number 1-offset list of nodes specified; this can be
+ verified on startup by consulting the node-table
+ in the test suite log
+
+Command: (required)
+Absolute paths are recommended. Commands are specified with
+their arguments.
+ quit
+ link filename target_filename
+ symlink filename target_filename
+ mv filename target_filename
+ chown filename newuid newgid
+ mkdir filename mode
+ chmod filename mode
+ mknod filename mode major minor
+ rmdir filename
+ create filename
+ delete filename
+ fstat filename
+ resize filename new_size
+ modify filename entropy
+ chksum filename
+ cdsl filename
+ open filename
+ close filename
+
+CDSL status: (optional)
+Because CDSL testing involves an alternative method of
+verification, an optional argument can be appended of the form
+ cdsl
+at the end of the command string, to "creat" a directory or file
+in the cdsl mode. See OCFS documentation for more detailed information.
+
+
+4. Known bugs
+
+Timestamps are calculated against Epoch and not against start time of
+the test program.
+
+Problems with generate_reports do not affect program performance, but does
+not provide correct output.
Added: trunk/TODO
===================================================================
--- trunk/TODO 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/TODO 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,34 @@
+* Fix bug in server having to do with verification of mv commands (can't
+ verify two times in a row)
+
+* Users should have one command to do everything, including any
+ compilation (if needed) and running all the tests
+
+* One test command (make run-tests) to run all the tests. It should
+ report on what tests passed and more importantly, which
+ failed. Detailed logs should be kept somewhere
+
+* The tests run and create a .errors file per test where all errors are logged
+
+* Config should be minimal. At most one or two lines, preferably none.
+
+* Each file (excluding data files) needs to have an Oranotice at the top.
+ This means:
+ Oracle Copyright
+ Author
+ Filename
+ Description
+
+* More tests need to be created. Go through the bug database and
+ create tests to check that each bug hasn't regressed (what i mean is
+ write a test to make sure the bugs fixed)
+
+* Fix some of the test commands. There's no reason why mkdir should
+ have to specify a mode, modify does not need an entropy, etc.
+
+* Add some way to do process synchronization.
+
+* Update README file. It is waaaay out of sync with the rest of the project.
+
+* Have a cleanup script which we can run to basically cleanup $ROOT on all
+ the nodes...
Added: trunk/client/Makefile
===================================================================
--- trunk/client/Makefile 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/client/Makefile 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,29 @@
+#
+# OCFSTS Makefile
+# Client and tslib libraries
+#
+
+GLIB_FLAGS=`glib-config --cflags`
+GLIB_LIBS=`glib-config --libs`
+
+CC = gcc
+CFLAGS= -Wall -ggdb -DOCFSTS_PORT=$(OCFSTS_PORT) ${GLIB_FLAGS}
+
+LIBS= command.o response.o ocfstsparse.o md5.o
+
+include ../Makefile.config
+
+all: $(OCFSTS_LIB_TARGET) $(CLIENT_TARGET)
+ # Calling make from the command line interferes with
+ # running the ocfsts.sh script! If you know what you are
+ # doing, well, do it. Otherwise, don't.
+
+$(OCFSTS_LIB_TARGET): $(LIBS)
+ ar rcs $@ $^
+
+$(CLIENT_TARGET): client.c exec.o $(LIBS)
+ ${CC} $(CFLAGS) ${GLIB_LIBS} $^ -o $@
+
+clean:
+ rm -f core *.o *~ $(CLIENT_TARGET) $(OCFS_LIB_TARGET)
+
Added: trunk/client/cdsl.h
===================================================================
--- trunk/client/cdsl.h 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/client/cdsl.h 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,26 @@
+#ifndef _CDSL_H_
+#define _CDSL_H_
+
+/* ioctl commands */
+#define OCFS_IOC_MAGIC 'O'
+#define OCFS_IOC_GETTYPE _IOR(OCFS_IOC_MAGIC, 1, struct ocfs_ioc)
+
+
+#define OCFS_IOC_CDSL_MODIFY _IOR(OCFS_IOC_MAGIC, 2, OCFS_CDSL)
+#define OCFS_IOC_CDSL_GETINFO _IOR(OCFS_IOC_MAGIC, 3, OCFS_CDSL)
+
+#define OCFS_CDSL_CREATE (0x1)
+#define OCFS_CDSL_DELETE (0x2)
+#define OCFS_FLAG_CDSL_FILE (0x1)
+#define OCFS_FLAG_CDSL_DIR (0x2)
+typedef unsigned char ub1;
+typedef unsigned int ub4;
+typedef struct _OCFS_CDSL
+{
+ ub1 Name[1024];
+ ub4 Flags;
+ ub4 Operation;
+} OCFS_CDSL;
+
+
+#endif /* _CDSL_H_ */
Added: trunk/client/client.c
===================================================================
--- trunk/client/client.c 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/client/client.c 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,257 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "command.h"
+#include "response.h"
+#include "ocfstsparse.h"
+#include "exec.h"
+
+#define RECVSIZE 2048
+//#define LISTENP 4444
+#define LISTENP OCFSTS_PORT
+#define PROC_CLEANUP_SEC 10
+char *prog = NULL;
+int mypid;
+
+/* returns a newly bound socket in the listen state, -1 if error */
+int setup_listener( void );
+
+/* uses a static buffer which is returned. NULL returned on error or
+ end of file */
+char *get_next_command(FILE *f);
+
+/* called after accepting a connection. executes the main functionality
+ of the client */
+void child_main(int pid, int sd, struct sockaddr_in* addr, int addrlen);
+
+/* used as a signal handler for sigalarm. We do this to clean up
+ zombie procs */
+void clean_up_children(int n);
+
+int main(int argc, char **argv) {
+ int ld, sd, cpid;
+ struct sockaddr_in* addr;
+ int addrlen;
+
+ int logfile = open ("/tmp/client.log", O_CREAT|O_APPEND|O_WRONLY, S_IRWXU);
+ if (open < 0)
+ {
+ perror("Unable to open logfile /tmp/client.log");
+ return (1);
+ }
+
+ dup2 (logfile, STDERR_FILENO);
+ dup2 (logfile, STDOUT_FILENO);
+ close (STDIN_FILENO);
+ close(logfile);
+
+ if (daemon(1,1) != 0) {
+ fprintf(stderr, "Could not make daemon process!\n");
+ perror("Error forking daemon");
+ return(1);
+ }
+
+ prog = argv[0];
+ mypid = getpid();
+
+ /* TODO: Set signal handlers here */
+ if (signal(SIGALRM, clean_up_children) == SIG_ERR) {
+ fprintf(stderr, "Could not set signal handler!\n");
+ exit(1);
+ }
+ alarm(PROC_CLEANUP_SEC);
+
+ ld = setup_listener();
+ /*printf("setup listener, ld = %d\n", ld);*/
+ addrlen = sizeof(struct sockaddr_in);
+ addr = malloc(addrlen);
+
+ while (1) {
+ bzero(addr, addrlen);
+ sd = accept(ld, (struct sockaddr *) addr, &addrlen);
+ if (sd == -1) {
+ fprintf(stderr, "%s: accept(2) error: %s\n", prog, strerror(errno));
+ return(1);
+ }
+
+ cpid = fork();
+ if (cpid == 0) {
+ /* we are the child */
+ alarm(0);
+ signal(SIGALRM, SIG_DFL);
+ child_main(cpid, sd, addr, addrlen);
+ close(sd);
+ break;
+ }
+ close(sd);
+ }
+ printf("Client[%d] shutting down\n", mypid);
+ return(0);
+}
+
+void child_main(int pid, int sd, struct sockaddr_in* addr, int addrlen) {
+ char *recvbuff;
+ char *s_response = NULL;
+ command_s * command = NULL;
+ response_s *response = NULL;
+ FILE *sock = fdopen(sd, "r+");
+
+ mypid = pid;
+
+ printf("%s[%d]: Connection established from %s\n", prog, mypid,
+ inet_ntoa(addr->sin_addr));
+
+ /* Make sure we get the inital 'HELO' */
+ recvbuff = get_next_command(sock);
+ if (recvbuff == NULL) {
+ fprintf(stderr, "Client[%d]: HELO expected, but not transmitted.\n",mypid);
+ return;
+ }
+
+ command = ParseCommand(recvbuff);
+ if (command->type != CMD_HELO) {
+ fprintf(stderr, "Client[%d]: HELO expected, but not transmitted.\n",mypid);
+ command_s_free(command);
+ return;
+ }
+ command_s_free(command);
+ write(sd, "HELO\n\n", 6);
+ recvbuff = get_next_command(sock);
+
+ while (recvbuff != NULL) {
+ /* printf("\n--------------------\nraw data received:\n"
+ "%s\n--------------------\n", recvbuff);*/
+ command = ParseCommand(recvbuff);
+ command_s_debug(command);
+ if (command == NULL) {
+ fprintf(stderr, "Client[%d]: child_main: ParseCommand returned a " \
+ "NULL value.\n", mypid);
+ break;
+ }
+ if (command->type == CMD_QUIT) {
+ printf("Client[%d]: QUIT command received.\n", mypid);
+ fclose(sock);
+ return;
+ }
+
+ response = ExecuteCommand(command);
+ if (response == NULL) {
+ fprintf(stderr, "Client[%d]: child_main: failed call to " \
+ "\"ExecuteCommand\".\n", mypid);
+ break;
+ }
+ response_s_debug(response);
+ fflush(stdout);
+ s_response = BuildResponse(response);
+ if (s_response == NULL) {
+ fprintf(stderr, "Client[%d]: child_main: call " \
+ "to \"BuildResponse\" failed\n", mypid);
+ break;
+ }
+ /*printf("\n--------------------\nResponse Built:\n"
+ "%s\n--------------------\n", s_response);*/
+ write(sd, s_response, strlen(s_response));
+
+ free(s_response);
+ response_s_free(response);
+ command_s_free(command);
+
+ recvbuff = get_next_command(sock);
+ if (recvbuff == NULL)
+ fprintf(stderr, "Client[%d]: Error reading from socket!\n", mypid);
+ } /* while (recvbuff != NULL) */
+
+ fprintf(stderr, "Client[%d]: Quitting on error\n", mypid);
+ fclose(sock);
+ return;
+}
+
+int setup_listener( void ) {
+ int sd, dummy=1, retval;
+ struct sockaddr_in sai;
+
+ sd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+ if (sd == -1) {
+ fprintf(stderr, "%s: Socket error: %s\n", prog, strerror(errno));
+ return(-1);
+ }
+
+ retval = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &dummy, sizeof(int));
+
+ if (retval == -1) {
+ fprintf(stderr, "%s: Error setting socket options: %s\n", prog,
+ strerror(errno));
+ return(-1);
+ }
+
+ bzero(&sai, sizeof(struct sockaddr_in));
+ sai.sin_family = AF_INET;
+ sai.sin_port = htons(LISTENP);
+ sai.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ retval = bind(sd, (struct sockaddr *) &sai, sizeof(struct sockaddr_in));
+ if (retval == -1) {
+ fprintf(stderr, "%s: Error binding socket: %s\n", prog, strerror(errno));
+ return(-1);
+ }
+
+ retval = listen(sd, 10);
+ if (retval == -1) {
+ fprintf(stderr, "%s: Error listening on socket: %s\n", prog,
+ strerror(errno));
+ return(-1);
+ }
+
+ return(sd);
+}
+
+char *get_next_command(FILE *f) {
+ /* this could be done slightly easier, but I don't feel like
+ changing the parsing function to read in a line at a time */
+ static char buff[BUFFSIZE];
+ char currline[BUFFSIZE];
+ char *retval;
+ int len = 0;
+
+ bzero(buff, BUFFSIZE);
+
+ do {
+ currline[0] = '\0';
+ retval = fgets(currline, BUFFSIZE - len, f);
+ if (retval == NULL) {
+ fprintf(stderr, "get_next_command: fgets error.\n");
+ return(NULL);
+ }
+
+ len = len + strlen(currline);
+ if (len >= BUFFSIZE) {
+ fprintf(stderr, "get_next_command: input is larger than BUFFSIZE\n");
+ return(NULL);
+ }
+ strcat(buff, currline);
+ } while (currline[0] != '\n'); /* commands are ended with a single newline */
+
+ return(buff);
+}
+
+void clean_up_children(int n) {
+ waitpid(0, NULL, WNOHANG|WUNTRACED);
+ if (signal(SIGALRM, clean_up_children) == SIG_ERR) {
+ fprintf(stderr, "clean_up_children: Could not re-set signal handler, continuing anyway.\n");
+ return;
+ }
+ alarm(PROC_CLEANUP_SEC);
+ return;
+}
Added: trunk/client/command.c
===================================================================
--- trunk/client/command.c 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/client/command.c 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,124 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "command.h"
+
+char *commandstrs[] = {"QUIT", "HELO", "LINK", "SYMLINK", "CHOWN", "MKDIR", "CHMOD", "MKNOD", "RMDIR", "CREATE", "DELETE", "STAT", "RESIZE", "MODIFY", "MD5", "CDSL", "MV", "OPEN", "CLOSE", NULL};
+
+command_s * command_s_new(void) {
+ command_s *c;
+ c = malloc(sizeof(command_s));
+ bzero(c, sizeof(command_s));
+ return(c);
+}
+
+void command_s_debug(command_s *c) {
+ printf("Command Contents:\n");
+ if (c == NULL) {
+ printf("\tEmpty (null) Command!\n");
+ return;
+ }
+ if (c->type < NUMCOMMANDS)
+ printf("\tType:\t%s\n", commandstrs[c->type]);
+ else
+ printf("\tType:\tUNKNOWN\n");
+
+ /* switch (c->type) {
+ case QUIT:
+ printf("\tQUIT\n");
+ break;
+ case HELO:
+ printf("\tHELO\n");
+ break;
+ case LINK:
+ printf("\tLINK\n");
+ break;
+ case SYMLINK:
+ printf("\tSYMLINK\n");
+ break;
+ case CHOWN:
+ printf("\tCHOWN\n");
+ break;
+ case MKDIR:
+ printf("\tMKDIR\n");
+ break;
+ case CHMOD:
+ printf("\tCHMOD\n");
+ break;
+ case MKNOD:
+ printf("\tMKNOD\n");
+ break;
+ case RMDIR:
+ printf("\tRMDIR\n");
+ break;
+ case CREATE:
+ printf("\tCREATE\n");
+ break;
+ case DELETE:
+ printf("\tDELETE\n");
+ break;
+ case STAT:
+ printf("\tSTAT\n");
+ break;
+ case RESIZE:
+ printf("\tRESIZE\n");
+ break;
+ case MODIFY:
+ printf("\tMODIFY\n");
+ break;
+
+ default:
+ printf("\tUNKNOWN!\n");
+ break;
+ }*/
+
+ printf("\tsrc:\t");
+ if (c->src == NULL)
+ printf("(null)\n");
+ else
+ printf("%s\n", c->src);
+ printf("\tdest:\t");
+ if (c->dest == NULL)
+ printf("(null)\n");
+ else
+ printf("%s\n", c->dest);
+
+ printf("\tuid:\t%d\n", c->uid);
+ printf("\tgid:\t%d\n", c->gid);
+ printf("\tmode:\t%04o\n", c->mode);
+ printf("\tdev:\t%llu\n", c->dev);
+ printf("\tsize:\t%ld\n", c->size);
+ printf("\tentropy:%d\n", c->entropy);
+ //#ifdef HAVE_CDSL
+ printf("\tcdslflag:");
+ if (c->cdslflag == OCFS_FLAG_CDSL_FILE)
+ printf("OCFS_FLAG_CDSL_FILE\n");
+ else if (c->cdslflag == OCFS_FLAG_CDSL_DIR)
+ printf("OCFS_FLAG_CDSL_DIR\n");
+ else
+ printf("unknown flag\n");
+ printf("\tcdslop:\t");
+ if (c->cdslop == OCFS_CDSL_CREATE)
+ printf("OCFS_CDSL_CREATE\n");
+ else if (c->cdslop == OCFS_CDSL_DELETE)
+ printf("OCFS_CDSL_DELETE\n");
+ else
+ printf("unknown operation\n");
+ //#endif
+ printf("\n");
+ return;
+}
+
+void command_s_free(command_s *c) {
+ if (c == NULL)
+ return;
+
+ if (c->src != NULL)
+ free(c->src);
+ if (c->dest != NULL)
+ free(c->dest);
+
+ free(c);
+ return;
+}
Added: trunk/client/command.h
===================================================================
--- trunk/client/command.h 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/client/command.h 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,77 @@
+#ifndef _COMMAND_H_
+#define _COMMAND_H_
+
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+//#ifdef HAVE_CDSL
+#include "cdsl.h"
+//#endif
+
+// C++ magic...
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+
+enum commands {
+ CMD_QUIT = 0,
+ CMD_HELO,
+ CMD_LINK,
+ CMD_SYMLINK,
+ CMD_CHOWN,
+ CMD_MKDIR,
+ CMD_CHMOD,
+ CMD_MKNOD,
+ CMD_RMDIR,
+ CMD_CREATE,
+ CMD_DELETE,
+ CMD_STAT,
+ CMD_RESIZE,
+ CMD_MODIFY,
+ CMD_MD5,
+ CMD_CDSL,
+ CMD_MV,
+ CMD_OPEN,
+ CMD_CLOSE
+};
+
+extern char *commandstrs[];
+#define NUMCOMMANDS 19
+#define MD5_DIGEST_LENGTH 16
+
+typedef struct {
+ enum commands type; /* always used */
+
+ char *src; /* always used except for HELO and QUIT */
+ char *dest; /* LINK, SYMLINK, */
+
+ uid_t uid; /* CHOWN */
+ gid_t gid; /* CHOWN */
+
+ mode_t mode; /* MKDIR, CHMOD, MKNOD */
+
+ dev_t dev; /* MKNOD */
+
+ off_t size; /* RESIZE */
+ int entropy; /* MODIFY */
+
+ /* next two are for CDSL */
+ ub4 cdslflag; /* one of either: OCFS_FLAG_CDSL_FILE or OCFS_FLAG_CDSL_DIR */
+ ub4 cdslop; /* always OCFS_CDSL_CREATE for now */
+} command_s;
+
+command_s * command_s_new(void);
+
+void command_s_debug(command_s *c);
+
+void command_s_free(command_s *c);
+
+// C++ magic...
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* _COMMAND_H_ */
Added: trunk/client/exec.c
===================================================================
--- trunk/client/exec.c 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/client/exec.c 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,445 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* #define __USE_GNU */
+#ifndef O_DIRECT
+# warning O_DIRECT is not defined, so making a best guess...
+# warning using for O_DIRECT
+# define O_DIRECT 040000
+#endif
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <libgen.h>
+#include <glib.h>
+
+#include "md5.h"
+#include "exec.h"
+#include "response.h"
+#include "ocfstsparse.h"
+
+/* buffer for reading and writing I/O */
+#define IOBUFFSIZE 1024
+
+static GHashTable *fdtable = NULL; //g_hash_table_new(g_str_hash, g_str_equal);
+
+response_s * do_rmdir(command_s *c);
+response_s * do_create(command_s *c);
+response_s * do_delete(command_s *c);
+response_s * do_stat(command_s *c);
+response_s * do_md5(command_s *c);
+response_s * do_link(command_s *c);
+response_s * do_symlink(command_s *c);
+response_s * do_chown(command_s *c);
+response_s * do_mkdir(command_s *c);
+response_s * do_chmod(command_s *c);
+response_s * do_mknod(command_s *c);
+response_s * do_resize(command_s *c);
+response_s * do_modify(command_s *c);
+response_s * do_cdsl(command_s *c);
+response_s * do_mv(command_s *c);
+response_s * do_open(command_s *c);
+response_s * do_close(command_s *c);
+
+/* computes an md5 digest of the file 'f' and returns it. The digest
+ * is a bunch of chars of length 'MD5_DIGEST_LENGTH' and should be
+ * free'd
+ */
+char * md5sum(const char *f);
+
+/* output is similar to the command 'md5sum [file]' */
+void md5sum_debug(const char *digest);
+
+/* executes our command. a response struct which has the results in
+ * it... return NULL on error
+ */
+response_s * ExecuteCommand(command_s *command) {
+ response_s *retval = NULL;
+
+ /* Initialize our fdtable if need be... */
+ if (fdtable == NULL) {
+ fdtable = g_hash_table_new(g_str_hash, g_str_equal);
+ if (fdtable == NULL) {
+ fprintf(stderr,
+ "ExecuteCommand: glib error, cannot continue.\n");
+ return(NULL);
+ }
+ }
+
+ switch (command->type) {
+ case CMD_RMDIR:
+ retval = do_rmdir(command);
+ break;
+
+ case CMD_CREATE:
+ retval = do_create(command);
+ break;
+
+ case CMD_DELETE:
+ retval = do_delete(command);
+ break;
+
+ case CMD_STAT:
+ retval = do_stat(command);
+ break;
+
+ case CMD_MD5:
+ retval = do_md5(command);
+ break;
+
+ case CMD_LINK:
+ retval = do_link(command);
+ break;
+
+ case CMD_SYMLINK:
+ retval = do_symlink(command);
+ break;
+
+ case CMD_CHOWN:
+ retval = do_chown(command);
+ break;
+
+ case CMD_MKDIR:
+ retval = do_mkdir(command);
+ break;
+
+ case CMD_CHMOD:
+ retval = do_chmod(command);
+ break;
+
+ case CMD_MKNOD:
+ retval = do_mknod(command);
+ break;
+
+ case CMD_RESIZE:
+ retval = do_resize(command);
+ break;
+
+ case CMD_MODIFY:
+ retval = do_modify(command);
+ break;
+
+ case CMD_CDSL:
+ retval = do_cdsl(command);
+ break;
+
+ case CMD_MV:
+ retval = do_mv(command);
+ break;
+
+ case CMD_OPEN:
+ retval = do_open(command);
+ break;
+
+ case CMD_CLOSE:
+ retval = do_close(command);
+ break;
+
+ default:
+ fprintf(stderr, "ExecuteCommand: Uknown command type!\n");
+ return(NULL);
+ break;
+ }
+
+ if (retval == NULL)
+ fprintf(stderr, "ExecuteCommand: internal failure\n");
+
+ return(retval);
+}
+
+response_s * do_rmdir(command_s *c) {
+ int err = rmdir(c->src);
+ if (err == -1)
+ return(response_s_new_fail(CMD_RMDIR, errno, NULL));
+ return(response_s_new_success(CMD_RMDIR));
+}
+
+response_s * do_create(command_s *c) {
+ int err = open(c->src, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ if (err == -1)
+ return(response_s_new_fail(CMD_CREATE, errno, NULL));
+ close(err);
+ return(response_s_new_success(CMD_CREATE));
+}
+
+response_s * do_delete(command_s *c) {
+ int err = unlink(c->src);
+ if (err == -1)
+ return(response_s_new_fail(CMD_DELETE, errno, NULL));
+ return(response_s_new_success(CMD_DELETE));
+}
+
+response_s * do_link(command_s *c) {
+ int err = link(c->src, c->dest);
+ if (err == -1)
+ return(response_s_new_fail(CMD_LINK, errno, NULL));
+ return(response_s_new_success(CMD_LINK));
+}
+
+response_s * do_mv(command_s *c) {
+ int err = rename(c->src, c->dest);
+ if (err == -1)
+ return(response_s_new_fail(CMD_MV, errno, NULL));
+ return(response_s_new_success(CMD_MV));
+}
+
+response_s * do_symlink(command_s *c) {
+ int err = symlink(c->src, c->dest);
+ if (err == -1)
+ return(response_s_new_fail(CMD_SYMLINK, errno, NULL));
+ return(response_s_new_success(CMD_SYMLINK));
+}
+
+response_s * do_chown(command_s *c) {
+ int err = chown(c->src, c->uid, c->gid);
+ if (err == -1)
+ return(response_s_new_fail(CMD_CHOWN, errno, NULL));
+ return(response_s_new_success(CMD_CHOWN));
+}
+
+response_s * do_mkdir(command_s *c) {
+ int err = mkdir(c->src, c->mode);
+ if (err == -1)
+ return(response_s_new_fail(CMD_MKDIR, errno, NULL));
+ return(response_s_new_success(CMD_MKDIR));
+}
+
+response_s * do_chmod(command_s *c) {
+ int err = chmod(c->src, c->mode);
+ if (err == -1)
+ return(response_s_new_fail(CMD_CHMOD, errno, NULL));
+ return(response_s_new_success(CMD_CHMOD));
+}
+
+response_s * do_mknod(command_s *c) {
+ int err = mknod(c->src, c->mode, c->dev);
+ if (err == -1)
+ return(response_s_new_fail(CMD_MKNOD, errno, NULL));
+ return(response_s_new_success(CMD_MKNOD));
+}
+
+response_s * do_resize(command_s *c) {
+ int err = truncate(c->src, c->size);
+ if (err == -1)
+ return(response_s_new_fail(CMD_RESIZE, errno, NULL));
+ return(response_s_new_success(CMD_RESIZE));
+}
+
+response_s * do_open(command_s *c) {
+ int fd;
+ gpointer oldkey;
+ if (g_hash_table_lookup_extended(fdtable, c->src, &oldkey, (gpointer *) &fd)==TRUE)
+ return(response_s_new_fail(CMD_OPEN, -1,
+ "File is already opened."));
+
+/*#ifdef O_DIRECT
+ fd = open(c->src, O_RDWR|O_CREAT|O_DIRECT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+#else
+#warning O_DIRECT not defined, so not using it!
+#warning Your client build will not use direct I/O.
+ fd = open(c->src, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ #endif*/
+
+ fd = open(c->src, O_RDWR|O_CREAT|O_DIRECT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ if (fd == -1)
+ return(response_s_new_fail(CMD_OPEN, errno, NULL));
+ g_hash_table_insert(fdtable, g_strdup(c->src), GINT_TO_POINTER(fd));
+ return(response_s_new_success(CMD_OPEN));
+}
+
+response_s * do_close(command_s *c) {
+ gpointer oldkey = NULL;
+ gpointer fd;
+ if (g_hash_table_lookup_extended(fdtable, c->src, &oldkey, &fd)==FALSE)
+ return(response_s_new_fail(CMD_CLOSE, -1,
+ "File was not previously opened."));
+ g_free(oldkey);
+ if (close(GPOINTER_TO_INT(fd)) == -1)
+ return(response_s_new_fail(CMD_CLOSE, errno, NULL));
+ return(response_s_new_success(CMD_CLOSE));
+}
+
+response_s * do_cdsl(command_s *c) {
+ int fd, err=0;
+ OCFS_CDSL cdsl;
+ struct stat tmp;
+ char *dir, *src, *base;
+
+ bzero(&tmp, sizeof(struct stat));
+
+ src = strdup(c->src);
+ if (src == NULL)
+ return(response_s_new_fail(CMD_CDSL, -1, "Error returned from strdup."));
+
+ dir = dirname(src);
+ free(src);
+ if (dir == NULL)
+ return(response_s_new_fail(CMD_CDSL, errno, NULL));
+ fd = open(dir, O_RDONLY);
+ if (fd == -1)
+ return(response_s_new_fail(CMD_CDSL, errno, NULL));
+
+ src = strdup(c->src);
+ if (src == NULL)
+ return(response_s_new_fail(CMD_CDSL, -1, "Error returned from strdup."));
+
+ base = basename(src);
+ free(src);
+
+ memset(&cdsl, 0, sizeof(OCFS_CDSL));
+ strncpy(cdsl.Name, base, 1023);
+ cdsl.Flags = c->cdslflag;
+ cdsl.Operation = c->cdslop;
+
+ err = ioctl(fd, OCFS_IOC_CDSL_MODIFY, &cdsl);
+ close(fd);
+ if (err == -1)
+ return(response_s_new_fail(CMD_CDSL, errno, NULL));
+ return(response_s_new_success(CMD_CDSL));
+}
+
+response_s * do_modify(command_s *c) {
+ response_s *r = NULL;
+ int numchanges = 0, i, loc, fd;
+ struct stat filestats;
+ char * filler = "abcdefg";
+
+ /* modify the file here */
+
+ if (stat(c->src, &filestats) == -1)
+ return(response_s_new_fail(CMD_MODIFY, errno, NULL));
+
+ fd = open(c->src, O_WRONLY);
+ if (fd == -1)
+ return(response_s_new_fail(CMD_MODIFY, errno, NULL));
+
+ srand(time(NULL));
+ numchanges = 1 + (int) ((float) filestats.st_size * rand()/(RAND_MAX+1.0));
+ /* we never really wanna make too many changes... */
+ numchanges = numchanges % 150;
+
+ /* printf("do_modify: %d changes to file of size %ld\n",
+ numchanges, filestats.st_size);*/
+ for(i = 0; i < numchanges; i++) {
+ loc = 1 + (int) ((float) filestats.st_size * rand()/(RAND_MAX+1.0));
+ if (lseek(fd, loc, SEEK_SET) == -1) {
+ close(fd);
+ return(response_s_new_fail(CMD_MODIFY, errno, NULL));
+ }
+ if (write(fd, &filler[i % 7], 1) == -1) {
+ close(fd);
+ return(response_s_new_fail(CMD_MODIFY, errno, NULL));
+ }
+ }
+ close(fd);
+
+ /* ok, we managed to get this far! now get the md5 and return a response */
+ r = response_s_new_success(CMD_MODIFY);
+ r->md5sum = md5sum(c->src);
+ if (r->md5sum == NULL) {
+ response_s_free(r);
+ return(response_s_new_fail(CMD_MODIFY, -1,
+ "do_modify: error generating md5 digest.\n"));
+ }
+
+ return(r);
+ /*
+ return(response_s_new_fail(CMD_MODIFY, 0, "do_modify: function not implemented yet"));*/
+}
+
+response_s * do_stat(command_s *c) {
+ struct stat fstats;
+ response_s *r = NULL;
+
+ if (stat(c->src, &fstats) == -1)
+ return(response_s_new_fail(CMD_STAT, errno, NULL));
+
+ r = response_s_new();
+ r->status = RESP_OK;
+ r->command = CMD_STAT;
+ r->dev = fstats.st_dev;
+ r->mode = fstats.st_mode;
+ r->uid = fstats.st_uid;
+ r->gid = fstats.st_gid;
+ r->rdev = fstats.st_rdev;
+ r->size = fstats.st_size;
+ return(r);
+ /*
+ return(response_s_new_fail(CMD_STAT, 0, "do_stat: function not implemented yet"));*/
+}
+
+response_s * do_md5(command_s *c) {
+ char *retval = md5sum(c->src);
+ response_s *r;
+
+ if (retval == NULL)
+ response_s_new_fail(CMD_MD5, 0, "do_md5: failed md5sum routine.");
+
+ r = response_s_new_success(CMD_MD5);
+ r->md5sum = retval;
+
+ if (r->md5sum == NULL) {
+ response_s_free(r);
+ return(response_s_new_fail(CMD_MD5, -1, "do_md5: invalid filename, or read error."));
+ }
+ /* debug stuff */
+ /*md5sum_debug(retval);
+ printf("\n");*/
+ /* end debug stuff */
+ return(r);
+}
+
+char *md5sum(const char *f) {
+ md5_state_t *state;
+ md5_byte_t *digest;
+ int fd, len;
+ char buff[IOBUFFSIZE];
+
+ fd = open(f, O_RDONLY);
+ if (fd == -1) {
+ fprintf(stderr, "md5sum: open(2) error\n");
+ return(NULL);
+ }
+
+ state = malloc(sizeof(md5_state_t));
+ bzero(state, sizeof(md5_state_t));
+
+ md5_init(state);
+
+ do {
+ len = read(fd, buff, IOBUFFSIZE);
+ if (len == -1) {
+ fprintf(stderr, "md5sum: read error\n");
+ free(state);
+ close(fd);
+ return(NULL);
+ }
+ md5_append(state, buff, len);
+ } while (len == IOBUFFSIZE);
+
+ digest = malloc(MD5_DIGEST_LENGTH);
+ bzero(digest, MD5_DIGEST_LENGTH);
+ md5_finish(state, digest);
+
+ close(fd);
+ free(state);
+ return(digest);
+}
+
+void md5sum_debug(const char *digest) {
+ int i;
+
+ if (digest == NULL) {
+ fprintf(stderr, "md5sum_debug: null parameters are illegal.\n");
+ return;
+ }
+
+ for(i = 0; i < MD5_DIGEST_LENGTH; i++) {
+ printf("%02hhx", digest[i]);
+ }
+
+}
Added: trunk/client/exec.h
===================================================================
--- trunk/client/exec.h 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/client/exec.h 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,28 @@
+#ifndef _EXEC_H_
+#define _EXEC_H_
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+// C++ magic...
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+/* actually, we only really need command_s from here... */
+#include "ocfstsparse.h"
+#include "response.h"
+
+/*
+ executes our command. a response struct which has the results in it...
+ NULL on error
+*/
+response_s * ExecuteCommand(command_s *command);
+
+// C++ magic...
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* _EXEC_H_ */
Added: trunk/client/md5.c
===================================================================
--- trunk/client/md5.c 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/client/md5.c 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,381 @@
+/*
+ Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ ghost at aladdin.com
+
+ */
+/* $Id: md5.c,v 1.1 2002/10/16 23:21:16 gmarsden Exp $ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.c is L. Peter Deutsch
+ <ghost at aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+ either statically or dynamically; added missing #include <string.h>
+ in library.
+ 2002-03-11 lpd Corrected argument list for main(), and added int return
+ type, in test program and T value program.
+ 2002-02-21 lpd Added missing #include <stdio.h> in test program.
+ 2000-07-03 lpd Patched to eliminate warnings about "constant is
+ unsigned in ANSI C, signed in traditional"; made test program
+ self-checking.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+ 1999-05-03 lpd Original version.
+ */
+
+#include "md5.h"
+#include <string.h>
+
+#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
+#ifdef ARCH_IS_BIG_ENDIAN
+# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
+#else
+# define BYTE_ORDER 0
+#endif
+
+#define T_MASK ((md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3 0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6 0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9 0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13 0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16 0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19 0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22 0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25 0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28 0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31 0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35 0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38 0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41 0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44 0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47 0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50 0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53 0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57 0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60 0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63 0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+
+static void
+md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
+{
+ md5_word_t
+ a = pms->abcd[0], b = pms->abcd[1],
+ c = pms->abcd[2], d = pms->abcd[3];
+ md5_word_t t;
+#if BYTE_ORDER > 0
+ /* Define storage only for big-endian CPUs. */
+ md5_word_t X[16];
+#else
+ /* Define storage for little-endian or both types of CPUs. */
+ md5_word_t xbuf[16];
+ const md5_word_t *X;
+#endif
+
+ {
+#if BYTE_ORDER == 0
+ /*
+ * Determine dynamically whether this is a big-endian or
+ * little-endian machine, since we can use a more efficient
+ * algorithm on the latter.
+ */
+ static const int w = 1;
+
+ if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
+#endif
+#if BYTE_ORDER <= 0 /* little-endian */
+ {
+ /*
+ * On little-endian machines, we can process properly aligned
+ * data without copying it.
+ */
+ if (!((data - (const md5_byte_t *)0) & 3)) {
+ /* data are properly aligned */
+ X = (const md5_word_t *)data;
+ } else {
+ /* not aligned */
+ memcpy(xbuf, data, 64);
+ X = xbuf;
+ }
+ }
+#endif
+#if BYTE_ORDER == 0
+ else /* dynamic big-endian */
+#endif
+#if BYTE_ORDER >= 0 /* big-endian */
+ {
+ /*
+ * On big-endian machines, we must arrange the bytes in the
+ * right order.
+ */
+ const md5_byte_t *xp = data;
+ int i;
+
+# if BYTE_ORDER == 0
+ X = xbuf; /* (dynamic only) */
+# else
+# define xbuf X /* (static only) */
+# endif
+ for (i = 0; i < 16; ++i, xp += 4)
+ xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+ }
+#endif
+ }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+ /* Round 1. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + F(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 7, T1);
+ SET(d, a, b, c, 1, 12, T2);
+ SET(c, d, a, b, 2, 17, T3);
+ SET(b, c, d, a, 3, 22, T4);
+ SET(a, b, c, d, 4, 7, T5);
+ SET(d, a, b, c, 5, 12, T6);
+ SET(c, d, a, b, 6, 17, T7);
+ SET(b, c, d, a, 7, 22, T8);
+ SET(a, b, c, d, 8, 7, T9);
+ SET(d, a, b, c, 9, 12, T10);
+ SET(c, d, a, b, 10, 17, T11);
+ SET(b, c, d, a, 11, 22, T12);
+ SET(a, b, c, d, 12, 7, T13);
+ SET(d, a, b, c, 13, 12, T14);
+ SET(c, d, a, b, 14, 17, T15);
+ SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+ /* Round 2. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + G(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 1, 5, T17);
+ SET(d, a, b, c, 6, 9, T18);
+ SET(c, d, a, b, 11, 14, T19);
+ SET(b, c, d, a, 0, 20, T20);
+ SET(a, b, c, d, 5, 5, T21);
+ SET(d, a, b, c, 10, 9, T22);
+ SET(c, d, a, b, 15, 14, T23);
+ SET(b, c, d, a, 4, 20, T24);
+ SET(a, b, c, d, 9, 5, T25);
+ SET(d, a, b, c, 14, 9, T26);
+ SET(c, d, a, b, 3, 14, T27);
+ SET(b, c, d, a, 8, 20, T28);
+ SET(a, b, c, d, 13, 5, T29);
+ SET(d, a, b, c, 2, 9, T30);
+ SET(c, d, a, b, 7, 14, T31);
+ SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+ /* Round 3. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + H(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 5, 4, T33);
+ SET(d, a, b, c, 8, 11, T34);
+ SET(c, d, a, b, 11, 16, T35);
+ SET(b, c, d, a, 14, 23, T36);
+ SET(a, b, c, d, 1, 4, T37);
+ SET(d, a, b, c, 4, 11, T38);
+ SET(c, d, a, b, 7, 16, T39);
+ SET(b, c, d, a, 10, 23, T40);
+ SET(a, b, c, d, 13, 4, T41);
+ SET(d, a, b, c, 0, 11, T42);
+ SET(c, d, a, b, 3, 16, T43);
+ SET(b, c, d, a, 6, 23, T44);
+ SET(a, b, c, d, 9, 4, T45);
+ SET(d, a, b, c, 12, 11, T46);
+ SET(c, d, a, b, 15, 16, T47);
+ SET(b, c, d, a, 2, 23, T48);
+#undef SET
+
+ /* Round 4. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + I(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 6, T49);
+ SET(d, a, b, c, 7, 10, T50);
+ SET(c, d, a, b, 14, 15, T51);
+ SET(b, c, d, a, 5, 21, T52);
+ SET(a, b, c, d, 12, 6, T53);
+ SET(d, a, b, c, 3, 10, T54);
+ SET(c, d, a, b, 10, 15, T55);
+ SET(b, c, d, a, 1, 21, T56);
+ SET(a, b, c, d, 8, 6, T57);
+ SET(d, a, b, c, 15, 10, T58);
+ SET(c, d, a, b, 6, 15, T59);
+ SET(b, c, d, a, 13, 21, T60);
+ SET(a, b, c, d, 4, 6, T61);
+ SET(d, a, b, c, 11, 10, T62);
+ SET(c, d, a, b, 2, 15, T63);
+ SET(b, c, d, a, 9, 21, T64);
+#undef SET
+
+ /* Then perform the following additions. (That is increment each
+ of the four registers by the value it had before this block
+ was started.) */
+ pms->abcd[0] += a;
+ pms->abcd[1] += b;
+ pms->abcd[2] += c;
+ pms->abcd[3] += d;
+}
+
+void
+md5_init(md5_state_t *pms)
+{
+ pms->count[0] = pms->count[1] = 0;
+ pms->abcd[0] = 0x67452301;
+ pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+ pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+ pms->abcd[3] = 0x10325476;
+}
+
+void
+md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
+{
+ const md5_byte_t *p = data;
+ int left = nbytes;
+ int offset = (pms->count[0] >> 3) & 63;
+ md5_word_t nbits = (md5_word_t)(nbytes << 3);
+
+ if (nbytes <= 0)
+ return;
+
+ /* Update the message length. */
+ pms->count[1] += nbytes >> 29;
+ pms->count[0] += nbits;
+ if (pms->count[0] < nbits)
+ pms->count[1]++;
+
+ /* Process an initial partial block. */
+ if (offset) {
+ int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+ memcpy(pms->buf + offset, p, copy);
+ if (offset + copy < 64)
+ return;
+ p += copy;
+ left -= copy;
+ md5_process(pms, pms->buf);
+ }
+
+ /* Process full blocks. */
+ for (; left >= 64; p += 64, left -= 64)
+ md5_process(pms, p);
+
+ /* Process a final partial block. */
+ if (left)
+ memcpy(pms->buf, p, left);
+}
+
+void
+md5_finish(md5_state_t *pms, md5_byte_t digest[16])
+{
+ static const md5_byte_t pad[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ md5_byte_t data[8];
+ int i;
+
+ /* Save the length before padding. */
+ for (i = 0; i < 8; ++i)
+ data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+ /* Pad to 56 bytes mod 64. */
+ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+ /* Append the length. */
+ md5_append(pms, data, 8);
+ for (i = 0; i < 16; ++i)
+ digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
Added: trunk/client/md5.h
===================================================================
--- trunk/client/md5.h 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/client/md5.h 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,91 @@
+/*
+ Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ ghost at aladdin.com
+
+ */
+/* $Id: md5.h,v 1.1 2002/10/16 23:21:16 gmarsden Exp $ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.h is L. Peter Deutsch
+ <ghost at aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Removed support for non-ANSI compilers; removed
+ references to Ghostscript; clarified derivation from RFC 1321;
+ now handles byte order either statically or dynamically.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
+ added conditionalization for C++ compilation from Martin
+ Purschke <purschke at bnl.gov>.
+ 1999-05-03 lpd Original version.
+ */
+
+#ifndef md5_INCLUDED
+# define md5_INCLUDED
+
+/*
+ * This package supports both compile-time and run-time determination of CPU
+ * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
+ * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
+ * defined as non-zero, the code will be compiled to run only on big-endian
+ * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
+ * run on either big- or little-endian CPUs, but will run slightly less
+ * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
+ */
+
+typedef unsigned char md5_byte_t; /* 8-bit byte */
+typedef unsigned int md5_word_t; /* 32-bit word */
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct md5_state_s {
+ md5_word_t count[2]; /* message length in bits, lsw first */
+ md5_word_t abcd[4]; /* digest buffer */
+ md5_byte_t buf[64]; /* accumulate block */
+} md5_state_t;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Initialize the algorithm. */
+void md5_init(md5_state_t *pms);
+
+/* Append a string to the message. */
+void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
+
+/* Finish the message and return the digest. */
+void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+#endif /* md5_INCLUDED */
Added: trunk/client/ocfstsparse.c
===================================================================
--- trunk/client/ocfstsparse.c 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/client/ocfstsparse.c 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,629 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+/* #include <openssl/md5.h> */
+
+#include "command.h"
+#include "response.h"
+#include "cdsl.h"
+#include "ocfstsparse.h"
+
+mode_t parse_mode(char *str);
+dev_t parse_dev(char *str);
+char ctoi(char c);
+
+mode_t parse_mode(char *str) {
+ mode_t m;
+ if (str == NULL) {
+ fprintf(stderr, "parse_mode: Null parameters are illegal\n");
+ return(0);
+ }
+
+ sscanf(str, "%o", &m);
+ return(m);
+}
+
+dev_t parse_dev(char *str) {
+ dev_t d;
+ int major, minor;
+
+ if (str == NULL) {
+ fprintf(stderr, "parse_mode: Null parameters are illegal\n");
+ return(0);
+ }
+
+ sscanf(str, "%d %d\n", &major, &minor);
+ d = makedev(major, minor);
+
+ return(d);
+}
+
+command_s * ParseCommand(char * str) {
+ char *tok = NULL,
+ *next = NULL,
+ *end = NULL; /* make sure we never go over the end of the string */
+ command_s *c;
+ int i;
+
+ if (str == NULL) {
+ fprintf(stderr, "ParseCommand: String parameter cannot be null.\n");
+ return(NULL);
+ }
+
+ /* just grab tokens as we need them. */
+ end = index(str, '\0');
+ tok = str;
+ next = index(tok, '\n');
+ *next = '\0';
+ if (end == NULL) {
+ fprintf(stderr, "ParseCommand: Parse error.\n");
+ return(NULL);
+ }
+
+ c = command_s_new();
+
+ /* figure out the command type */
+ for (i = 0; i < NUMCOMMANDS+1; i++) {
+ if (commandstrs[i] == NULL) {
+ fprintf(stderr, "ParseCommand: Invalid command type received.\n");
+ command_s_free(c);
+ return(NULL);
+ }
+ if (strcasecmp(commandstrs[i], tok) == 0) {
+ c->type = i;
+ break;
+ }
+ }
+ if ((c->type == CMD_QUIT) || (c->type == CMD_HELO)) /* no more args needed */
+ return(c);
+
+ /* all other commands need at least a string 'src' argument. get that now. */
+ if (next >= end) {
+ fprintf(stderr, "ParseCommand: Premature end of input\n");
+ command_s_free(c);
+ return(NULL);
+ }
+ tok = next+1;
+ next = index(tok, '\n');
+ *next = '\0';
+ if (next == NULL) {
+ fprintf(stderr, "ParseCommand: Parse error.\n");
+ command_s_free(c);
+ return(NULL);
+ }
+ c->src = strdup(tok);
+
+ /* for the command whose only argument is a src string, exit now */
+ switch (c->type) {
+ case CMD_RMDIR:
+ case CMD_CREATE:
+ case CMD_DELETE:
+ case CMD_STAT:
+ case CMD_MD5:
+ case CMD_OPEN:
+ case CMD_CLOSE:
+ return(c);
+ break;
+ default:
+ /* for all other commands, we want to continue parsing */
+ break;
+ }
+
+ /* get the next token */
+ if (next >= end) {
+ fprintf(stderr, "ParseCommand: Premature end of input\n");
+ command_s_free(c);
+ return(NULL);
+ }
+ tok = next+1;
+ next = index(tok, '\n');
+ *next = '\0';
+ if (next == NULL) {
+ fprintf(stderr, "ParseCommand: Parse error.\n");
+ command_s_free(c);
+ return(NULL);
+ }
+
+ switch(c->type) {
+ case CMD_MKNOD:
+ /* need mode, and dev arguments */
+ c->mode = parse_mode(tok);
+
+ if (next >= end) {
+ fprintf(stderr, "ParseCommand: Premature end of input\n");
+ command_s_free(c);
+ return(NULL);
+ }
+ tok = next+1;
+ next = index(tok, '\n');
+ *next = '\0';
+ if (next == NULL) {
+ fprintf(stderr, "ParseCommand: Parse error.\n");
+ command_s_free(c);
+ return(NULL);
+ }
+ c->dev = parse_dev(tok);
+ break;
+
+ case CMD_MV:
+ case CMD_LINK:
+ case CMD_SYMLINK:
+ /* these two need a 'dest' string */
+ c->dest = strdup(tok);
+ break;
+
+ case CMD_MKDIR:
+ case CMD_CHMOD:
+ /* these two need a 'mode' argument */
+ c->mode = parse_mode(tok);
+ break;
+
+ case CMD_RESIZE:
+ /* needs a 'size' argument */
+ sscanf(tok, "%ld", &(c->size));
+ break;
+
+ case CMD_CHOWN:
+ /* needs username and group ids */
+ sscanf(tok, "%d", &(c->uid));
+ if (next >= end) {
+ fprintf(stderr, "ParseCommand: Premature end of input\n");
+ command_s_free(c);
+ return(NULL);
+ }
+ tok = next+1;
+ next = index(tok, '\n');
+ *next = '\0';
+ if (next == NULL) {
+ fprintf(stderr, "ParseCommand: Parse error.\n");
+ command_s_free(c);
+ return(NULL);
+ }
+ sscanf(tok, "%d", &(c->gid));
+ break;
+
+ case CMD_MODIFY:
+ /* needs an entropy argument */
+ sscanf(tok, "%d", &(c->entropy));
+ break;
+
+ case CMD_CDSL:
+ /* get the operation from here */
+ if (strcasecmp(tok, "create") == 0) {
+ c->cdslflag = OCFS_FLAG_CDSL_FILE;
+ c->cdslop = OCFS_CDSL_CREATE;
+ } else if (strcasecmp(tok, "mkdir") == 0) {
+ c->cdslflag = OCFS_FLAG_CDSL_DIR;
+ c->cdslop = OCFS_CDSL_CREATE;
+ } else {
+ fprintf(stderr,"ParseCommand: Unknown/Missing option to CDSL command\n");
+ command_s_free(c);
+ return(NULL);
+ }
+ break;
+
+ default:
+ fprintf(stderr, "ParseCommand: Unknown command type.\n");
+ command_s_free(c);
+ return(NULL);
+ }
+
+ return(c);
+}
+
+char * BuildResponse(response_s *r) {
+ char buff[BUFFSIZE];
+ char *curr;
+ int len = 0;
+ int i;
+
+ if (r == NULL) {
+ fprintf(stderr, "BuildResponse: response_s parameter cannot be null.\n");
+ return(NULL);
+ }
+
+ bzero(buff, BUFFSIZE);
+
+ if (r->command >= NUMCOMMANDS) {
+ fprintf(stderr, "BuildResponse: unknown command type.\n");
+ return(NULL);
+ }
+
+ len = sprintf(buff, "%s\n%s\n", commandstrs[r->command],
+ responsestrs[r->status]);
+ curr = &buff[len];
+
+ if (r->status == RESP_FAIL) {
+ /* add the error code, string and final newline, then quit */
+ snprintf(curr, BUFFSIZE-len, "%d\n%s\n\n", r->err, r->desc);
+ return(strdup(buff));
+ }
+
+ switch (r->command) {
+ case CMD_OPEN:
+ case CMD_CLOSE:
+ case CMD_MV:
+ case CMD_LINK:
+ case CMD_SYMLINK:
+ case CMD_CHOWN:
+ case CMD_MKDIR:
+ case CMD_CHMOD:
+ case CMD_MKNOD:
+ case CMD_RMDIR:
+ case CMD_CREATE:
+ case CMD_DELETE:
+ case CMD_HELO:
+ case CMD_RESIZE:
+ case CMD_CDSL:
+ /* yes, we're done */
+ break;
+
+ case CMD_MODIFY:
+ case CMD_MD5:
+ /* print out the md5sum */
+ for(i = 0; i < MD5_DIGEST_LENGTH; i++) {
+ len += sprintf(curr, "%02hhx", r->md5sum[i]);
+ curr = &buff[len];
+ }
+ len += sprintf(curr, "\n");
+ curr = &buff[len];
+ break;
+
+ case CMD_STAT:
+ /* dev */
+ len += snprintf(curr, BUFFSIZE-len, "%d %d\n", major(r->dev),
+ minor(r->dev));
+ curr = &buff[len];
+
+ /* dev type, skipped for now */
+
+ /* mode */
+ len += snprintf(curr, BUFFSIZE-len, "%04o\n", r->mode);
+ curr = &buff[len];
+
+ /* uid */
+ len += snprintf(curr, BUFFSIZE-len, "%d\n", r->uid);
+ curr = &buff[len];
+
+ /* gid */
+ len += snprintf(curr, BUFFSIZE-len, "%d\n", r->gid);
+ curr = &buff[len];
+
+ /* size */
+ len += snprintf(curr, BUFFSIZE-len, "%ld\n", r->size);
+ curr = &buff[len];
+
+ /* cdsl status */
+ /* TODO */
+ break;
+
+ default:
+ fprintf(stderr, "BuildResponse: Unknown command type in response.\n");
+ return(NULL);
+ break;
+ }
+
+ len += snprintf(curr, BUFFSIZE - len, "\n");
+ return(strdup(buff));
+}
+
+
+char * BuildCommand(command_s *c) {
+ char buff[BUFFSIZE];
+ int len=0;
+ char *curr;
+
+ if (c == NULL) {
+ fprintf(stderr, "BuildResponse: response_s parameter cannot be null.\n");
+ return(NULL);
+ }
+
+ if (c->type >= NUMCOMMANDS) {
+ fprintf(stderr, "BuildCommand: unknown command type. (NUMCOMMANDS=%d)\n", NUMCOMMANDS);
+ return(NULL);
+ }
+
+ /* get rid of the trivial cases */
+ if (c->type == CMD_HELO)
+ return(strdup("HELO\n\n"));
+ if (c->type == CMD_QUIT)
+ return(strdup("QUIT\n\n"));
+
+ bzero(buff, BUFFSIZE);
+ len = sprintf(buff, "%s\n", commandstrs[c->type]);
+ curr = &buff[len];
+
+ /* all the remaining commands need at least a src filename */
+ if (c->src == NULL) {
+ fprintf(stderr, "BuildCommand: Source filename cannot be null.");
+ return(NULL);
+ }
+ len += snprintf(curr, BUFFSIZE - len, "%s\n", c->src);
+ curr = &buff[len];
+
+ /* do the other fields now */
+
+ switch (c->type) {
+ case CMD_OPEN:
+ case CMD_CLOSE:
+ case CMD_MD5:
+ case CMD_STAT:
+ case CMD_RMDIR:
+ case CMD_CREATE:
+ case CMD_DELETE:
+ /* yes, we're done */
+ break;
+
+ case CMD_MKNOD:
+ /* put in mode and device info */
+ len += snprintf(curr, BUFFSIZE - len, "%04o\n", c->mode);
+ curr = &buff[len];
+ len += snprintf(curr, BUFFSIZE - len, "%d %d\n", major(c->dev),
+ minor(c->dev));
+ curr = &buff[len];
+ break;
+
+ case CMD_MKDIR:
+ case CMD_CHMOD:
+ /* put in mode info */
+ len += snprintf(curr, BUFFSIZE - len, "%04o\n", c->mode);
+ curr = &buff[len];
+ break;
+
+ case CMD_CHOWN:
+ /* put in owner and group ids */
+ len += snprintf(curr, BUFFSIZE - len, "%d\n%d\n", c->uid, c->gid);
+ curr = &buff[len];
+ break;
+
+ case CMD_MV:
+ case CMD_LINK:
+ case CMD_SYMLINK:
+ /* put in destination file */
+ if (c->dest == NULL) {
+ fprintf(stderr, "BuildCommand: Destination filename cannot be null.");
+ return(NULL);
+ }
+ len += snprintf(curr, BUFFSIZE - len, "%s\n", c->dest);
+ curr = &buff[len];
+ break;
+
+ case CMD_RESIZE:
+ /* put in new size */
+ len += snprintf(curr, BUFFSIZE - len, "%ld\n", c->size);
+ curr = &buff[len];
+ break;
+
+ case CMD_MODIFY:
+ /* put in entropy */
+ len += snprintf(curr, BUFFSIZE - len, "%d\n", c->entropy);
+ curr = &buff[len];
+ break;
+
+ case CMD_CDSL:
+ /* put in the op */
+ if (c->cdslop == OCFS_CDSL_CREATE && c->cdslflag == OCFS_FLAG_CDSL_FILE) {
+ len += snprintf(curr, BUFFSIZE - len, "create\n");
+ curr = &buff[len];
+ } else if (c->cdslop == OCFS_CDSL_CREATE &&
+ c->cdslflag == OCFS_FLAG_CDSL_DIR) {
+ len += snprintf(curr, BUFFSIZE - len, "mkdir\n");
+ curr = &buff[len];
+ } else {
+ fprintf(stderr, "BuildCommand: Invalid cdsl flag/operation.");
+ return(NULL);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /* insert the final newline */
+ len += snprintf(curr, BUFFSIZE - len, "\n");
+ curr = &buff[len];
+ return(strdup(buff));
+}
+
+response_s * ParseResponse(char *str) {
+ char *tok = NULL;
+ response_s *r;
+ int i, maj, min;
+
+ if (str == NULL) {
+ fprintf(stderr, "ParseResponse: String parameter cannot be null.\n");
+ return(NULL);
+ }
+
+ /* just grab tokens as we need them. */
+ tok = strtok(str, "\n");
+ if (tok == NULL) {
+ fprintf(stderr, "ParseResponse: Parse error.\n");
+ return(NULL);
+ }
+
+ r = response_s_new();
+
+ /* figure out the command this is a response to */
+ for (i = 0; i < NUMCOMMANDS+1; i++) {
+ if (commandstrs[i] == NULL) {
+ fprintf(stderr, "ParseResponse: Invalid command type received.\n");
+ return(NULL);
+ }
+ if (strcasecmp(commandstrs[i], tok) == 0) {
+ r->command = i;
+ break;
+ }
+ }
+
+ /* trivial cases */
+ if ((r->command == CMD_QUIT) || (r->command == CMD_HELO)) {
+ r->status = RESP_OK;
+ return(r);
+ }
+
+ tok = strtok(NULL, "\n");
+ if (tok == NULL) {
+ fprintf(stderr, "ParseResponse: Parse error.\n");
+ return(NULL);
+ }
+
+ /* get the status from the response */
+ if (strcasecmp(responsestrs[RESP_FAIL], tok) == 0) {
+ /* it's a failure response. they all look the same so
+ get the other fields now */
+ r->status = RESP_FAIL;
+ tok = strtok(NULL, "\n");
+ if (tok == NULL) {
+ fprintf(stderr, "ParseResponse: Parse error.\n");
+ return(NULL);
+ }
+ sscanf(tok, "%d", &(r->err));
+
+ tok = strtok(NULL, "\n");
+ if (tok == NULL) {
+ fprintf(stderr, "ParseResponse: Parse error.\n");
+ return(NULL);
+ }
+ r->desc = strdup(tok);
+ return(r);
+ } else if (strcasecmp(responsestrs[RESP_OK], tok) != 0) {
+ fprintf(stderr, "ParseResponse: Illegal response type\n");
+ return(NULL);
+ }
+
+ /* It's a success response... */
+ r->status = RESP_OK;
+
+ switch(r->command) {
+ case CMD_OPEN:
+ case CMD_CLOSE:
+ case CMD_MV:
+ case CMD_QUIT:
+ case CMD_HELO:
+ case CMD_LINK:
+ case CMD_SYMLINK:
+ case CMD_CHOWN:
+ case CMD_MKDIR:
+ case CMD_CHMOD:
+ case CMD_MKNOD:
+ case CMD_RMDIR:
+ case CMD_CREATE:
+ case CMD_DELETE:
+ case CMD_RESIZE:
+ case CMD_CDSL:
+ break;
+
+ /* only need to deal with MD5/MODIFY and STAT */
+
+ case CMD_MD5:
+ case CMD_MODIFY:
+ /* these two get an md5sum */
+ tok = strtok(NULL, "\n");
+ if (tok == NULL) {
+ fprintf(stderr, "ParseResponse: Parse error.\n");
+ return(NULL);
+ }
+ if (strlen(tok) != (2 * MD5_DIGEST_LENGTH)) {
+ fprintf(stderr, "ParseResponse: Invalid Digest.\n");
+ return(NULL);
+ }
+ r->md5sum = malloc(MD5_DIGEST_LENGTH);
+ for(i = 0; i < strlen(tok); i+=2)
+ r->md5sum[i/2] = ctoi(tok[i+1]) | (ctoi(tok[i]) << 4);
+ break;
+
+ case CMD_STAT:
+ /* dev */
+ tok = strtok(NULL, "\n");
+ if (tok == NULL) {
+ fprintf(stderr, "ParseResponse: Parse error.\n");
+ return(NULL);
+ }
+ sscanf(tok, "%d %d", &maj, &min);
+ r->dev = makedev(maj, min);
+
+ /* dev type, skipped for now */
+
+ /* mode */
+ tok = strtok(NULL, "\n");
+ if (tok == NULL) {
+ fprintf(stderr, "ParseResponse: Parse error.\n");
+ return(NULL);
+ }
+ sscanf(tok, "%o", &(r->mode));
+
+ /* uid */
+ tok = strtok(NULL, "\n");
+ if (tok == NULL) {
+ fprintf(stderr, "ParseResponse: Parse error.\n");
+ return(NULL);
+ }
+ sscanf(tok, "%d", &(r->uid));
+
+ /* gid */
+ tok = strtok(NULL, "\n");
+ if (tok == NULL) {
+ fprintf(stderr, "ParseResponse: Parse error.\n");
+ return(NULL);
+ }
+ sscanf(tok, "%d", &(r->gid));
+
+ /* size */
+ tok = strtok(NULL, "\n");
+ if (tok == NULL) {
+ fprintf(stderr, "ParseResponse: Parse error.\n");
+ return(NULL);
+ }
+ sscanf(tok, "%ld", &(r->size));
+ break;
+
+ } /* switch(r->command) */
+
+ return(r);
+}
+
+char ctoi(char c) {
+ switch (c) {
+ case '0':
+ return(0);
+ case '1':
+ return(1);
+ case '2':
+ return(2);
+ case '3':
+ return(3);
+ case '4':
+ return(4);
+ case '5':
+ return(5);
+ case '6':
+ return(6);
+ case '7':
+ return(7);
+ case '8':
+ return(8);
+ case '9':
+ return(9);
+ case 'a':
+ case 'A':
+ return(10);
+ case 'b':
+ case 'B':
+ return(11);
+ case 'c':
+ case 'C':
+ return(12);
+ case 'd':
+ case 'D':
+ return(13);
+ case 'e':
+ case 'E':
+ return(14);
+ case 'f':
+ case 'F':
+ return(15);
+ }
+ fprintf(stderr, "ctoi: character not in 0-9a-zA-Z encountered.\n");
+ return(-1);
+}
Added: trunk/client/ocfstsparse.h
===================================================================
--- trunk/client/ocfstsparse.h 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/client/ocfstsparse.h 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,65 @@
+#ifndef _OCFSTSPARSE_H_
+#define _OCFSTSPARSE_H_
+
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "command.h"
+#include "response.h"
+
+// C++ magic...
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#define BUFFSIZE (NAME_MAX *2 + 300)
+
+/*
+ stolen from coreutils. needed to make a dev_t from a major/minor
+ int pair
+*/
+#ifndef makedev
+#define makedev(maj, min) (((maj) << 8) | (min))
+#endif
+
+/*
+ Build a command string from the command struct.
+ The returned string needs to be free'd
+ NULL will be returned on error.
+*/
+char * BuildCommand(command_s *c);
+
+/*
+ Given a string, parse out the command. Each field on the command
+ should be ended with a '\n'. Only one command can be passed per
+ call
+ Return a new command type or NULL on error
+ The string str will be changed.
+*/
+command_s * ParseCommand(char * str);
+
+/*
+ Build a response string from the response struct.
+ The returned string needs to be free'd
+ NULL will be returned on error.
+*/
+char * BuildResponse(response_s *r);
+
+/*
+ Given a string, parse out the response. Each field on the response
+ should be ended with a '\n'. Only one response can be passed per
+ call return a parsed response.
+ Return a new command type or NULL on error
+ The string str will be changed.
+*/
+response_s * ParseResponse(char *str);
+
+// C++ magic...
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* OCFSTSPARSE */
Added: trunk/client/response.c
===================================================================
--- trunk/client/response.c 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/client/response.c 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,93 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include "response.h"
+#include "command.h" /* for MD5_DIGEST_LENGTH */
+
+char *responsestrs[] = {"OK", "FAIL"};
+
+response_s * response_s_new( void ) {
+ response_s *r = malloc(sizeof(response_s));
+ bzero(r, sizeof(response_s));
+ return(r);
+}
+
+response_s * response_s_new_fail(enum commands c, int err, char *error) {
+ response_s *r = response_s_new();
+ r->status = RESP_FAIL;
+ r->command = c;
+ r->err = err;
+
+ if (error == NULL)
+ error = strerror(err);
+
+ r->desc = strdup(error);
+ return(r);
+}
+
+response_s * response_s_new_success(enum commands c) {
+ response_s *r = response_s_new();
+ r->status = RESP_OK;
+ r->command = c;
+ return(r);
+}
+
+void response_s_debug(response_s *r) {
+ int i;
+
+ if (r == NULL) {
+ fprintf(stderr, "response_s_debug: handed a null value.\n");
+ return;
+ }
+
+ printf("Command Response:\n");
+ if (r->command < NUMCOMMANDS)
+ printf("\tcommand:%s\n", commandstrs[r->command]);
+ else
+ printf("\tcommand:UNKNOWN\n");
+ printf("\tstatus:\t");
+ if (r->status == RESP_OK)
+ printf("%s\n", responsestrs[RESP_OK]);
+ else {
+ printf("%s\n", responsestrs[RESP_FAIL]);
+ printf("\terr:\t%d\n", r->err);
+ printf("\tdesc:\t%s\n", r->desc);
+ }
+
+ if (r->md5sum != NULL) {
+ printf("\tmd5sum:\t");
+ for(i = 0; i < MD5_DIGEST_LENGTH; i++) {
+ printf("%02hhx", r->md5sum[i]);
+ }
+ printf("\n");
+ }
+
+ if (r->command == CMD_STAT) {
+ printf("\tmajor:\t%d\n", major(r->dev));
+ printf("\tminor:\t%d\n", minor(r->dev));
+ printf("\tmode:\t%04o\n", r->mode);
+ printf("\tuid:\t%d\n", r->uid);
+ printf("\tgid:\t%d\n", r->gid);
+ printf("\tsize:\t%ld\n", r->size);
+ }
+
+ printf("\n");
+ return;
+}
+
+/* response_t destructor. */
+void response_s_free(response_s *r) {
+ if (r == NULL)
+ return;
+
+ if (r->desc != NULL)
+ free(r->desc);
+
+ if (r->md5sum != NULL)
+ free(r->md5sum);
+
+ free(r);
+ return;
+}
Added: trunk/client/response.h
===================================================================
--- trunk/client/response.h 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/client/response.h 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,63 @@
+#ifndef _RESPONSE_H_
+#define _RESPONSE_H_
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "command.h"
+
+// C++ magic...
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+enum responses {RESP_OK=0, RESP_FAIL};
+extern char *responsestrs[];
+#define NUMRESPONSES 2
+
+typedef struct {
+ enum responses status;
+ enum commands command; /* the command type this is a response to */
+ /* used if there's an error */
+ int err; /* what is errno set to? -1 for internal errors */
+ char *desc; /* the results of strerror or a copy of our own internal string*/
+
+ /* from an md5 or modify command */
+ char *md5sum; /* IMPORTANT! This is not an actual string. It is
+ simply a byte array of length
+ 'MD5_DIGEST_LENGTH'. It is not NULL terminated.*/
+
+ /* return values from a stat command */
+ dev_t dev; /* device */
+ dev_t rdev; /* device type (if inode device) */
+ mode_t mode; /* protection */
+ uid_t uid; /* user ID of owner */
+ gid_t gid; /* group ID of owner */
+ off_t size; /* total size, in bytes */
+} response_s;
+
+
+response_s * response_s_new( void );
+
+/*
+ returns a FAILURE response. The errno field is automatically
+ populated by 'err' and desc is pointed to a copy of 'error'. if
+ 'error' is null, then a copy of the string returned by strerror(err)
+ is used instead.
+ */
+response_s * response_s_new_fail(enum commands c, int err, char *error);
+
+response_s * response_s_new_success(enum commands c);
+
+/* response_t destructor. */
+void response_s_free(response_s *r);
+
+void response_s_debug(response_s *r);
+
+// C++ magic...
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* _RESPONSE_H_ */
Added: trunk/client/testpacket
===================================================================
--- trunk/client/testpacket 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/client/testpacket 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,44 @@
+helo
+
+delete
+/home/mfasheh/foobarbaz
+
+create
+/home/mfasheh/foobarbaz
+
+resize
+/home/mfasheh/foobarbaz
+409600
+
+modify
+/home/mfasheh/foobarbaz
+1000
+
+md5
+/home/mfasheh/foobarbaz
+
+md5
+/home/mfasheh/foobarbaz
+
+md5
+/home/mfasheh/foobarbaz
+
+quit
+
+chmod
+/tmp/foo
+644
+
+resize
+/tmp/foo
+4096
+
+modify
+/tmp/foo
+9999
+
+md5
+/tmp/foo
+
+quit
+
Added: trunk/ocfsts.h
===================================================================
--- trunk/ocfsts.h 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/ocfsts.h 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,8 @@
+#ifndef _ocfsts_h_
+#define _ocfsts_h_
+
+#include "client/ocfstsparse.h"
+#include "client/command.h"
+#include "client/response.h"
+
+#endif //_ocfsts_h_
Added: trunk/ocfsts.sh
===================================================================
--- trunk/ocfsts.sh 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/ocfsts.sh 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,162 @@
+#!/bin/bash
+#
+# OCFS testing script
+#
+
+source Makefile.config
+
+do_usage() {
+ echo "usage: $0 make"
+ echo " $0 makediffs"
+ echo " $0 run"
+ echo " $0 kill"
+ echo ""
+ echo "$0 is a simple command line interface to the "
+ echo "ocfs test suite. Run 'make' to begin installation."
+ echo ""
+ echo "$0 commands:"
+ echo "make - compile ocfsts"
+ echo "makediffs - prepare default 'correct' output in $ORIGINAL_DIR"
+ echo "run - perform tests and place diff output in $RESULT_DIR"
+ echo "kill - close client processes on each node"
+ echo ""
+}
+
+
+do_installer() {
+ echo "Building binaries..."
+
+ export SERVER_TARGET CLIENT_TARGET OCFSTS_LIB_TARGET
+
+ make -e clean
+
+ if ! make -e all-redirect
+ then
+ echo "Compile/make error."
+ exit -1;
+ fi
+
+ echo "done."
+
+ echo -e "Installing binaries..."
+ echo "done."
+
+ echo -e "Setting up directories..."
+ mkdir -p $TARGET/$TEST_DIR
+ mkdir -p $TARGET/$RESULT_DIR
+ mkdir -p $TARGET/$ORIGINAL_DIR
+ echo "done"
+
+ echo " * * * "
+ echo " Now set up diffs by running \"$0 makediffs\" and"
+ echo " hand correcting the output in the $ORIGINAL_DIR directory."
+ echo " * * * "
+}
+
+do_makediffs() {
+ echo "WARNING!!!";
+ echo " You are about to nuke potentially hand edited files."
+ echo " You WILL have to re-edit these files by hand!"
+ echo " "
+ echo " Press CTRL-C now to abort."
+ read
+
+ spawn_clients
+
+ for i in `ls -1 $TEST_DIR/test*`
+ do
+ VAR=$(echo $i | sed -e "s/$TEST_DIR/$ORIGINAL_DIR/" | sed -e "s/$/.orig/");
+ echo ...creating $VAR
+ touch $VAR
+ $TARGET/$SERVER_TARGET $NODEFILE < $i > $VAR
+ done
+}
+
+do_tests() {
+
+ spawn_clients
+
+ DATE=$(date)
+
+ for i in `ls -1 $TEST_DIR/test*`
+ do
+ ORIGINAL=$(echo $i | sed -e "s/$TEST_DIR/$ORIGINAL_DIR/" | sed -e "s/$/.orig/");
+ NEW=$(echo $i | sed -e "s/$TEST_DIR/$RESULT_DIR/" | sed -e "s/$/.$DATE/");
+ LOG=$(echo $i | sed -e "s/$TEST_DIR/$RESULT_DIR/" | sed -e "s/$/.$DATE.out/");
+
+ echo testing $i now...;
+ #$TARGET/$SERVER_TARGET $NODEFILE < $i | tee "$NEW" | $DIFF "$ORIGINAL" | tee "$LOG"
+ $TARGET/$SERVER_TARGET $NODEFILE < $i | tee "$NEW"
+
+ $TARGET/$DIFF "$ORIGINAL" "$NEW" | tee "$LOG"
+
+ echo done;
+ done
+
+ kill_clients
+}
+
+kill_clients() {
+ for node in `cat $NODEFILE | awk '{print $1}'|grep -v ^#|sort|uniq`
+ do
+ ping -c1 $node >& /dev/null
+ if [ $? -eq 0 ]
+ then
+ echo "Killing client on $node."
+ ssh $CLIENT_USER@$node killall -9 $CLIENT_TARGET
+ else
+ echo "Host $node not alive!"
+ fi
+
+ done
+}
+
+spawn_clients() {
+ for node in `cat $NODEFILE | awk '{print $1}'|grep -v ^#|sort|uniq`
+ do
+ ping -c1 $node >& /dev/null
+ if [ $? -eq 0 ]
+ then
+ echo "Testing port $OCFSTS_PORT on $node"
+ nc $node $OCFSTS_PORT -q0 < /dev/null >& /dev/null
+ if [ $? -eq 0 ]
+ then
+ echo "Client already started"
+ else
+ echo "Starting client on $node"
+ echo "Use authorized_keys on target machine to avoid entering password."
+ scp $CLIENT_TARGET root@$node:$CLIENT_INSTALL_DIR/
+ ssh $CLIENT_USER@$node $CLIENT_INSTALL_DIR/$CLIENT_TARGET
+ fi
+ else
+ echo "Host $node not alive!"
+ fi
+
+ done
+}
+
+
+# Handle options
+
+case "$1" in
+ make)
+ do_installer
+ ;;
+ kill)
+ kill_clients
+ ;;
+ spawn)
+ spawn_clients
+ ;;
+ makediffs)
+ do_makediffs
+ ;;
+ run)
+ do_tests
+ ;;
+ *)
+ do_usage
+ exit 1
+ ;;
+esac
+
Property changes on: trunk/ocfsts.sh
___________________________________________________________________
Name: svn:executable
+
Added: trunk/ocfsts_diff.pl
===================================================================
--- trunk/ocfsts_diff.pl 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/ocfsts_diff.pl 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,20 @@
+#!/usr/bin/perl -w
+
+unless (defined $ARGV[0] and defined $ARGV[1]) {
+ usage();
+ exit;
+}
+
+open (ORIGINAL, $ARGV[0]) or die "no original file";
+open (OUTPUT, $ARGV[1]) or die "no output data!";
+
+while ($orig_line=<ORIGINAL>) {
+ $out_line = <OUTPUT>;
+ if ($out_line =~ /Time/) {
+ next;
+ }
+ if ($orig_line ne $out_line) {
+ print "> $out_line";
+ print "< $orig_line";
+ }
+}
Property changes on: trunk/ocfsts_diff.pl
___________________________________________________________________
Name: svn:executable
+
Added: trunk/server/Makefile
===================================================================
--- trunk/server/Makefile 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/server/Makefile 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,43 @@
+#
+# OCFSTS Makefile
+# Server
+#
+#
+
+CC=gcc
+CFLAGS= -Wall -ggdb -p -DOCFSTS_PORT=$(OCFSTS_PORT)
+LDFLAGS=
+CFLAGSLIBRARY=-DOCFSTS_LIBRARY
+
+OBJS= comm.o ocfs_test_server.o ocfs_test.o logprint.o ocfstsapi.o
+
+include ../Makefile.config
+
+all: depend $(SERVER_TARGET)
+
+Makefile.depend: depend
+
+include Makefile.depend
+depend:
+ $(CC) $(CXXFLAGS) -MM `find . -name '*.c'` > Makefile.depend
+
+$(SERVER_TARGET): $(OBJS) ../$(OCFSTS_LIB_TARGET)
+ $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
+
+clean:
+ rm -f *.o $(SERVER_TARGET)
+
+$(OCFSTS_LIB_SERVER_TARGET): $(OBJS) ../$(OCFSTS_LIB_TARGET)
+ $(CC) $(CFLAGS) $(CFLAGSLIBRARY) -c ocfs_test_server.c
+ #ar rcs $@ $^
+ $(CC) $(CFLAGS) -shared -o $@ $^
+
+#ocfs_test.o: ocfs_test.c ocfs_test.h
+# $(CC) $(CFLAGS) $< $(CLIENT_OBJS) -c -o $@
+#
+
+
+apitest:
+ make -C .. clean all library
+ g++ -Wall -ggdb -p -DOCFSTS_PORT=4444 -DOCFSTS_LIBRARY comm.o ocfs_test_server.o ocfs_test.o logprint.o ocfstsapi.o ../libocfsts.a apitest.c -o apitest
+
Added: trunk/server/apitest.c
===================================================================
--- trunk/server/apitest.c 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/server/apitest.c 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,40 @@
+#include <stdio.h>
+#include "ocfstsapi.h"
+
+/* to run this
+ * do make -C .. clean library
+ * then
+ * g++ -Wall -ggdb -p -DOCFSTS_PORT=4444 -DOCFSTS_LIBRARY comm.o ocfs_test_server.o ocfs_test.o logprint.o ocfstsapi.o ../libocfsts.a apitest.c -o apitest -lefence
+ * hehe
+ */
+
+char *nodes[]={"expo.us.oracle.com"};
+int
+main (void)
+{
+ ocfsts_open_connection (1, nodes);
+/* ocfsts_execute ("R create /tmp/myfile1");
+ ocfsts_verify ("R create /tmp/myfile1");
+ ocfsts_execute ("R chmod /tmp/myfile1 0666");
+ ocfsts_execute ("R chksum /tmp/myfile1");
+ ocfsts_verify ("R chksum /tmp/myfile1");
+*/
+ ocfsts_execute ("R create /tmp/myfile");
+ ocfsts_verify ("R create /tmp/myfile");
+
+ ocfsts_execute ("R chmod /tmp/myfile 0777");
+ ocfsts_verify ("R chmod /tmp/myfile 0777");
+
+ ocfsts_execute ("R resize /tmp/myfile 1000");
+ ocfsts_verify ("R resize /tmp/myfile 1000");
+
+ ocfsts_execute ("R modify /tmp/myfile 31337");
+ ocfsts_verify ("R modify /tmp/myfile 31337");
+
+ ocfsts_execute ("R delete /tmp/myfile");
+ ocfsts_verify ("R delete /tmp/myfile");
+
+ ocfsts_close_connection();
+
+}
+
Added: trunk/server/comm.c
===================================================================
--- trunk/server/comm.c 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/server/comm.c 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,150 @@
+/*
+ * comm.c
+ * --
+ * Communication protocol for ocfs test server;
+ * the "Master" side is a client which connects
+ * to servers running on the "Slave" machines.
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+
+#include "comm.h"
+#include "debug.h"
+#include "../ocfsts.h"
+
+#define MAXBUF 102400
+
+typedef struct ocfs_socket_real
+{
+ int sd;
+ struct sockaddr_in ServerSocket;
+} ocfs_socket_real;
+
+bool
+comm_send_command (ocfs_socket os, char *buffer)
+{
+ if (send(os->sd, buffer, strlen(buffer), 0) == -1)
+ {
+ perror("send");
+ return false;
+ }
+ return true;
+}
+
+bool
+comm_get_response (ocfs_socket os, char *buffer, int maxlen)
+{
+ int stat;
+ stat = recv (os->sd, buffer, maxlen, 0);
+ if (stat == -1)
+ {
+ perror("recv");
+ return false;
+ }
+ else
+ buffer[stat] = 0;
+ return true;
+}
+
+bool
+say_helo_ok (ocfs_socket os)
+{
+ char *b;
+ char buffer[2048];
+ command_s *cs = command_s_new();
+ response_s *rs;
+ int stat = 0;
+
+ cs->type = CMD_HELO;
+ b = BuildCommand(cs);
+
+ comm_send_command (os, b);
+ free(b);
+
+ comm_get_response (os, buffer, 2048);
+ rs = ParseResponse(buffer);
+
+ if (rs && rs->status == RESP_OK)
+ stat = 1;
+
+ command_s_free(cs);
+ response_s_free(rs);
+
+ DEBUG((stderr, "[DD] Got helo.\n"));
+
+ return stat;
+}
+
+ocfs_socket
+comm_open_connection (struct hostent *hp)
+{
+ ocfs_socket_real *os;
+ //char send_buffer[MAXBUF];
+ //char recv_buffer[MAXBUF];
+ //command_T command, return_command;
+
+ os = (ocfs_socket_real *) malloc (sizeof(ocfs_socket_real));
+
+ // Open socket
+ os->sd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (os->sd == -1)
+ {
+ perror("socket");
+ return NULL;
+ }
+
+ /*
+ // Establish Connection
+ if ((hp = gethostbyname (node)) == NULL)
+ {
+ perror("gethostbyname");
+ return NULL;
+ }
+ */
+
+ os->ServerSocket.sin_family = AF_INET;
+ os->ServerSocket.sin_port = htons(OCFS_DEFAULT_PORT);
+
+ memcpy (&os->ServerSocket.sin_addr,
+ hp->h_addr,
+ hp->h_length);
+
+ if (connect (os->sd, (struct sockaddr*) &os->ServerSocket,
+ sizeof (struct sockaddr_in)) == -1)
+ {
+ perror("connect");
+ return NULL;
+ }
+
+ // Send HELO to server and confirm response
+ if (say_helo_ok(os))
+ return os;
+
+ return NULL;
+}
+
+int
+comm_close_connection (ocfs_socket os)
+{
+ int stat = close(os->sd);
+ //char send_buffer[MAXBUF];
+ //command_T command;
+
+ /* send goodbye command */
+
+ close(os->sd);
+ free(os);
+ return stat;
+}
+
Added: trunk/server/comm.h
===================================================================
--- trunk/server/comm.h 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/server/comm.h 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,23 @@
+/* comm.h
+ * --
+ * Master communications library.
+ */
+
+#ifndef _COMM_H_
+#define _COMM_H_
+
+#define OCFS_DEFAULT_PORT OCFSTS_PORT
+//#define OCFS_DEFAULT_NODE "192.68.0.1"
+
+#define OCFS_CONNECT_ERROR -1
+
+typedef struct ocfs_socket_real* ocfs_socket;
+
+ocfs_socket comm_open_connection (struct hostent *hp);
+int comm_close_connection (ocfs_socket os);
+
+bool comm_send_command (ocfs_socket os, char *buffer);
+bool comm_get_response (ocfs_socket os, char *buffer, int maxlen);
+
+
+#endif // _COMM_H_
Added: trunk/server/debug.h
===================================================================
--- trunk/server/debug.h 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/server/debug.h 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,7 @@
+#ifndef DEBUG
+
+//#define DEBUG(a) fprintf a
+#undef DEBUG
+#define DEBUG(a) ;
+
+#endif //DEBUG
Added: trunk/server/logprint.c
===================================================================
--- trunk/server/logprint.c 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/server/logprint.c 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,177 @@
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <time.h>
+#include "logprint.h"
+
+#include "../ocfsts.h"
+
+void
+logprint_header(int mode)
+{
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ fprintf (stdout, "\n%s\nTime: %ld.%lds\n",
+ mode == C_COMMAND?"-----------------------------------":"--",
+ tv.tv_sec, tv.tv_usec);
+
+}
+
+void
+logprint_footer()
+{
+ fprintf (stdout,"\n\n");
+}
+
+void
+logprint_vfymethod (const struct cmdline *cmdline)
+{
+ switch (cmdline->vmethod)
+ {
+ case VFY_EXIST:
+ fprintf (stdout, "\tfstat %s\n", cmdline->arg[0]);
+ break;
+ case VFY_NEXIST:
+ fprintf (stdout, "\tfstat %s (file should not exist)\n", cmdline->arg[0]);
+ break;
+ case VFY_OWNER:
+ fprintf (stdout, "\tfstat %s for owner \n", cmdline->arg[0]);
+ break;
+ case VFY_MODE:
+ fprintf (stdout, "\tfstat %s for file mode\n", cmdline->arg[0]);
+ break;
+ case VFY_SIZE:
+ fprintf (stdout, "\fstat %s for file size\n", cmdline->arg[0]);
+ break;
+ case VFY_MD5:
+ fprintf (stdout, "\tmd5 %s\n", cmdline->arg[0]);
+ break;
+
+ case VFY_NONE:
+ default:
+ break;
+ };
+}
+
+void
+logprint_success (const struct cmdline *cmdline, int mode, int target)
+{
+ logprint_header(mode);
+
+ if (target == -1)
+ target = cmdline->targetnode;
+
+ target += 1; // pretty print format
+
+ if (mode == C_COMMAND)
+ {
+ fprintf (stdout, "(CMD Success) (Node %d) (Line %d) %s"
+ "\tExpected %s, got %s.\n",
+ target, cmdline->lineno, cmdline->raw,
+ cmdline->expecttrue?"success":"failure",
+ cmdline->expecttrue?"success":"failure");
+ }
+ else
+ {
+ fprintf (stdout, "(VFY Success) (Node %d) (Line %d) %s",
+ target, cmdline->lineno, cmdline->raw);
+ logprint_vfymethod(cmdline);
+ }
+
+ /*
+ fprintf (stdout, "[ %s%s ] <Node %d, Line %d> (%s %s), %s %s\n",
+ cmdline->expecttrue?"+":"-",
+ mode==C_COMMAND?"c":" ",
+ target, cmdline->lineno,
+ get_command_for_action(cmdline->command),
+ cmdline->arg[0],
+ mode==C_COMMAND?"cmd":"vfy",
+ cmdline->expecttrue?"succeeded":"failed");
+ */
+ logprint_footer();
+}
+
+void
+logprint_state (const struct cmdline *cmdline, const response_s *rs)
+{
+ if (cmdline->cs != NULL)
+ {
+ //fprintf (stdout, "<contents of command_s...>\n");
+ command_s_debug ((command_s*)cmdline->cs);
+ }
+
+ if (rs != NULL)
+ {
+ //fprintf (stdout, "<contents of response_s...>\n");
+ response_s_debug((response_s*)rs);
+ }
+}
+
+void
+logprint_failure (const struct cmdline *cmdline, const response_s *rs, int mode, int target)
+{
+
+ logprint_header(mode);
+
+ if (target == -1) target = cmdline->targetnode;
+ target += 1;
+
+ if (mode == C_COMMAND)
+ {
+ fprintf (stdout,
+ "(CMD FAILURE) (Node %d) (Line %d) %s"
+ "\tExpected %s, got %s.\n"
+ "\t(%d) %s\n",
+ target+1, cmdline->lineno, cmdline->raw,
+ cmdline->expecttrue?"success":"failure",
+ !cmdline->expecttrue?"success":"failure",
+ rs->err, rs->desc);
+ }
+ else
+ {
+ fprintf (stdout, "(VFY FAILURE) (Node %d) (Line %d) %s",
+ target, cmdline->lineno, cmdline->raw);
+ logprint_vfymethod(cmdline);
+ fprintf (stdout, "\t(%d) %s\n",
+ rs->err, rs->desc);
+ }
+
+ logprint_state(cmdline, rs);
+
+ logprint_footer();
+}
+
+void
+logprint_syntax_real (const struct cmdline *cmdline, const char *desc, int opti, char *opts)
+{
+ logprint_header(0);
+ fprintf (stderr, "(SYNTAX) Line %d, %s\n", cmdline->lineno, desc);
+
+ if (opti != -1)
+ fprintf (stdout, "(SYNTAX) %s %d\n"
+ "\t cmd: %s", desc, opti, cmdline->raw);
+ else if (opts != NULL)
+ fprintf (stdout, "(SYNTAX) %s %s\n"
+ "\t cmd: %s", desc, opts, cmdline->raw);
+ logprint_footer();
+}
+void
+logprint_syntax (const struct cmdline *cmdline, const char *desc)
+{
+ logprint_syntax_real (cmdline, desc, -1, NULL);
+}
+
+void
+logprint_syntax_int (const struct cmdline *cmdline, const char *desc, int opti)
+{
+ logprint_syntax_real (cmdline, desc, opti, NULL);
+}
+
+void
+logprint_syntax_str (const struct cmdline *cmdline, const char *desc, char *opts)
+{
+ logprint_syntax_real (cmdline, desc, -1, opts);
+}
+
+
Added: trunk/server/logprint.h
===================================================================
--- trunk/server/logprint.h 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/server/logprint.h 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,15 @@
+#ifndef _logprint_h_
+#define _logprint_h_
+
+#include "ocfs_test.h"
+#include "../ocfsts.h"
+
+void logprint_success (const struct cmdline *cmdline, int mode, int target);
+
+void logprint_failure (const struct cmdline *cmdline, const response_s *rs, int mode, int target);
+
+void logprint_syntax (const struct cmdline *cmdline, const char *desc);
+void logprint_syntax_int (const struct cmdline *cmdline, const char *desc, int opti);
+void logprint_syntax_str (const struct cmdline *cmdline, const char *desc, char *opts);
+
+#endif //_logprint_h_
Added: trunk/server/md5print.h
===================================================================
--- trunk/server/md5print.h 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/server/md5print.h 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,18 @@
+#ifndef _md5out_h_
+#define _md5out_h_
+
+void md5sum_debug(const char *digest) {
+ int i;
+
+ if (digest == NULL) {
+ fprintf(stderr, "md5sum_debug: null parameters are illegal.\n");
+ return;
+ }
+
+ for(i = 0; i < MD5_DIGEST_LENGTH; i++) {
+ printf("%02hhx", digest[i]);
+ }
+
+}
+
+#endif //_md5out_h_
Added: trunk/server/nodelist
===================================================================
--- trunk/server/nodelist 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/server/nodelist 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,10 @@
+verbose.us.oracle.com
+verbose.us.oracle.com
+verbose.us.oracle.com
+verbose.us.oracle.com
+#192.168.0.1
+#192.168.0.2
+#192.168.0.3
+#192.168.0.4
+#192.168.0.5
+#nic1-pc.us.oracle.com
Added: trunk/server/ocfs_test.c
===================================================================
--- trunk/server/ocfs_test.c 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/server/ocfs_test.c 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,661 @@
+/*
+ * ocfs_test
+ * --
+ * This file parses the command line from stdin or a command file,
+ * uses client code to generate a client-request, waits for response,
+ * then generates a series of tests for every other node in the system
+ * to validate that the test was successful
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "debug.h"
+#include "ocfs_test.h"
+#include "ocfs_test_server.h"
+#include "logprint.h"
+#include "syntax.h"
+//#include "md5print.h"
+
+#define STRTOK_NEXT_TOKEN(a) strtok (a, " "); \
+ if (!ptr || !ptr[0]) { \
+ logprint_syntax (cmdline, "unexpected end of command");\
+ free (tmp);\
+ return SYNTAX_ERR; \
+ }
+
+
+
+// BEHAVIOR FLAGS
+#define IGNORE_ORIGINAL_NODE 0
+#define IGNORE_CDSL_VERIFY 1
+
+#define COMMENT 1
+#define SYNTAX_ERR -1
+#define SYNTAX_OK 0
+
+#define MAX_BUF 2048
+
+
+static char lastmd5[MD5_DIGEST_LENGTH];
+
+void
+set_md5_result(const char *chksum)
+{
+ bcopy (chksum, lastmd5, MD5_DIGEST_LENGTH);
+ //fprintf (stderr, ">> Setting md5 = %16s\n", chksum);
+}
+
+int
+compare_md5_result (const char *chksum)
+{
+ return !bcmp (chksum, lastmd5, MD5_DIGEST_LENGTH);
+}
+
+
+
+const char *
+get_command_for_action(const int c)
+{
+ int i;
+ for (i=0; i<NUM_SERVER_COMMANDS; i++)
+ {
+ if (cmdtab[i].type == c)
+ return cmdtab[i].name;
+ }
+ return NULL;
+}
+
+int
+aredigits(const char *string)
+{
+ char *p = (char *)string;
+ while (*p)
+ {
+ if(!isdigit(*p))
+ return 0;
+ p++;
+ }
+ return 1;
+
+}
+
+int
+get_command_type (const char *cmd, int *type, int *numargs, int *vtype)
+{
+ int i;
+ for (i=0;i<NUM_SERVER_COMMANDS; i++)
+ {
+ if (!strcmp(cmdtab[i].name, cmd))
+ {
+ *type = cmdtab[i].type;
+ *numargs = cmdtab[i].numargs;
+ *vtype = cmdtab[i].vtype;
+ return cmdtab[i].type;
+ }
+ }
+ return -1;
+}
+
+int
+analyze_command (const char *cmd, struct cmdline *cmdline)
+{
+ if (get_command_type (cmd, &(cmdline->command), &(cmdline->num_attrs), &(cmdline->vmethod)) == -1)
+ return SYNTAX_ERR;
+
+ return SYNTAX_OK;
+}
+
+
+int
+parse_command (const char *cmd, struct cmdline *cmdline)
+{
+ /* Syntax:
+ * [+|-|#] <R|#|Node> <Cmd> [arg1] [arg2] [arg3]
+ * At the moment, disallow escaped arguments (" or ')
+ */
+ char *tmp = strdup(cmd);
+ char *ptr = tmp;
+ char *ptr2;
+ int num_arguments_remaining;
+ int i;
+
+ if (!ptr || !ptr[0] || ptr[0] == '\n' || ptr[0] == ' ')
+ return COMMENT;
+
+ //ptr[strlen(ptr)-1] = '\0'; // chop string .... NO ... CHOMP it.
+ if ((ptr2 = strchr(ptr, '\n')) != NULL)
+ *ptr2 = '\0';
+
+ ptr = STRTOK_NEXT_TOKEN(ptr);
+
+ // Catch optional first argument [+-#]
+ if (ptr && *ptr && (*ptr == '+' || *ptr == '-' || *ptr == '#'))
+ {
+ if (*ptr == '+' || *ptr == '-')
+ cmdline->expecttrue = (*ptr == '+');
+ else
+ return COMMENT;
+
+ ptr = STRTOK_NEXT_TOKEN(NULL);
+ }
+ else
+ cmdline->expecttrue = 1;
+
+ /* Get node destination */
+ if (!strcmp(ptr, "R"))
+ cmdline->targetnode = ocfs_get_random_nodenum();
+ else if (aredigits(ptr))
+ {
+ cmdline->targetnode = atoi(ptr);
+ cmdline->targetnode -= 1; // nodenum index starts at 1, arrays are 0-offset
+ }
+ else
+ {
+ cmdline->targetnode = ocfs_get_node_by_name(ptr);
+ if (cmdline->targetnode == -1)
+ {
+ logprint_syntax (cmdline, "Invalid node name");
+ free(tmp);
+ return SYNTAX_ERR;
+ }
+ }
+
+ // Get the command action
+ ptr= STRTOK_NEXT_TOKEN(NULL);
+
+ if (analyze_command(ptr, cmdline) == SYNTAX_ERR)
+ {
+ logprint_syntax (cmdline, "Invalid command keyword");
+ free(tmp);
+ return SYNTAX_ERR;
+ }
+
+ // Get arguments
+ num_arguments_remaining = num_args_per_type [cmdline->num_attrs];
+ for(i=0; ptr && ptr[0] && num_arguments_remaining; i++)
+ {
+ ptr = strtok(NULL, " ");
+ if (ptr == NULL)
+ {
+ logprint_syntax_int (cmdline, "Expected number of arguments:",
+ cmdline->num_attrs);
+ free(tmp);
+ return SYNTAX_ERR;
+ }
+
+ cmdline->arg[i] = strdup (ptr);
+ num_arguments_remaining -= 1;
+ }
+
+ // Check for command length overrun, CDSL mode
+ cmdline->cdsl = 0;
+ while (ptr && ptr[0])
+ {
+ ptr = strtok(NULL," ");
+ if (!ptr || !ptr[0])
+ break;
+
+ if (!strcmp("cdsl", ptr) || !strcmp("CDSL", ptr))
+ {
+ cmdline->cdsl = 1;
+ }
+ else if (!strcmp("cdsl+", ptr) || !strcmp("CDSL+", ptr))
+ {
+ cmdline->cdsl = 1;
+ cmdline->cdsl_pass_other_nodes = 1;
+ }
+ else if (!strcmp("cdsl-", ptr) || !strcmp("CDSL-", ptr))
+ {
+ cmdline->cdsl = 1;
+ cmdline->cdsl_pass_other_nodes = 0;
+ }
+ else
+ {
+ logprint_syntax (cmdline, "Too many arguments to command.");
+ free(tmp);
+ return SYNTAX_ERR;
+ }
+ }
+
+ free(tmp);
+ return SYNTAX_OK;
+}
+
+char *
+make_cdsl_op (struct cmdline *cmdline, int mode)
+{
+ char *p;
+ command_s *cs = command_s_new();
+ if (cmdline->command == CMD_CREATE ||
+ cmdline->command == CMD_MKDIR)
+ {
+ cmdline->cs = cs;
+ cs->type = (enum commands) CMD_CDSL;
+
+ cs->src = cmdline->arg[0];
+ if (cmdline->command == CMD_CREATE)
+ cs->cdslflag = OCFS_FLAG_CDSL_FILE;
+ else
+ cs->cdslflag = OCFS_FLAG_CDSL_DIR;
+
+ cs->cdslop = OCFS_CDSL_CREATE;
+
+ p = BuildCommand(cs);
+ return p;
+ }
+
+ logprint_syntax (cmdline, "CDSL flag toggled for unsupported operation");
+ return NULL; // error!
+}
+
+char *
+generate_command (struct cmdline *cmdline, int mode)
+{
+ char *p;
+ command_s *cs = command_s_new();
+
+ if (cmdline->cdsl)
+ return make_cdsl_op (cmdline, mode);
+
+ cmdline->cs = cs;
+ cs->type = (enum commands)cmdline->command;
+
+ if (mode == C_VERIFY)
+ {
+ if (cmdline->vmethod == VFY_MD5)
+ cs->type = CMD_MD5;
+ else if (cmdline->expecttrue)
+ cs->type = CMD_STAT;
+ }
+
+ // command arg. 1
+ if (cmdline->num_attrs != NO_ARGS)
+ cs->src = cmdline->arg[0];
+
+ // command arg. 2..n
+ switch (cmdline->num_attrs) {
+
+ case SRC_ARG:
+ break;
+
+ case SRC_DST_ARG:
+ cs->dest = cmdline->arg[1];
+ break;
+
+ case UID_ARG:
+ cs->uid = atoi(cmdline->arg[1]);
+ cs->gid = atoi(cmdline->arg[2]);
+ break;
+
+ case NODE_ARG:
+ cs->mode= strtol(cmdline->arg[1], NULL, 8);
+ cs->dev = makedev(atoi(cmdline->arg[2]), atoi(cmdline->arg[3]));
+ break;
+
+ case MODE_ARG:
+ cs->mode= strtol(cmdline->arg[1], NULL, 8);
+ break;
+
+ case SIZE_ARG:
+ cs->size = atoi(cmdline->arg[1]);
+ break;
+
+ case ENTPY_ARG:
+ cs->entropy = atoi(cmdline->arg[1]);
+ break;
+
+ default:
+ fprintf (stderr, "ERROR... Too few arguments? (%d)\n", cmdline->num_attrs);
+ break;
+ }
+
+
+ p = BuildCommand(cs);
+ return p;
+}
+
+void
+exec_quit (struct cmdline *cmdline)
+{
+ char *p = generate_command (cmdline, C_COMMAND);
+ ocfs_send_command(p, cmdline->targetnode);
+}
+
+bool
+exec_command (struct cmdline *cmdline)
+{
+ char buffer[MAX_BUF];
+ char *p;
+ response_s *rs;
+ bool success = false;
+
+ p = generate_command (cmdline, C_COMMAND);
+ if (p == NULL)
+ {
+ fprintf (stderr, "\n(ocfs_test server) server error: generate command NULL\n");
+ return false;
+ }
+
+ ocfs_send_command(p, cmdline->targetnode);
+
+ ocfs_get_response(buffer, MAX_BUF, cmdline->targetnode);
+ rs = ParseResponse(buffer);
+
+ if (rs)
+ {
+ if (rs->status == RESP_OK)
+ {
+ if (cmdline->expecttrue)
+ {
+ logprint_success(cmdline, C_COMMAND, -1);
+ success = true;
+ }
+ else
+ logprint_failure(cmdline, rs, C_COMMAND, -1);
+
+ }
+ else
+ {
+ if (cmdline->expecttrue)
+ logprint_failure(cmdline, rs, C_COMMAND, -1);
+ else
+ {
+ logprint_success(cmdline, C_COMMAND, -1);
+ success = true;
+ }
+ }
+ }
+
+ if (rs->md5sum != NULL &&
+ (cmdline->command == CMD_MD5 || cmdline->command == CMD_MODIFY))
+ set_md5_result(rs->md5sum);
+
+ response_s_free(rs);
+ return success;
+}
+
+bool
+check_result (response_s *rs, struct cmdline *cmdline)
+{
+ bool success = (rs->status==RESP_OK);
+
+ if (rs && rs->status == RESP_OK)
+ {
+ switch(cmdline->vmethod)
+ {
+ case VFY_EXIST:
+ return (success);
+
+ case VFY_NEXIST:
+ return (!success);
+
+ case VFY_OWNER:
+ return (rs->uid == cmdline->cs->uid && rs->gid == cmdline->cs->gid);
+
+ case VFY_MODE:
+ return ((rs->mode&0777) == cmdline->cs->mode);
+ break;
+
+ case VFY_SIZE:
+ return (rs->size == cmdline->cs->size);
+
+ case VFY_MD5:
+ return compare_md5_result(rs->md5sum);
+ //(!memcmp(rs->md5sum, cmdline->md5sum, MD5_DIGEST_LENGTH));
+
+ case VFY_NONE:
+ default:
+ return true;
+ }
+ }
+ else
+ {
+ switch (cmdline->vmethod)
+ {
+ case VFY_EXIST:
+ return (success);
+
+ case VFY_NEXIST:
+ return (!success);
+
+ default:
+ return false;
+ }
+ }
+}
+
+
+
+bool
+verify_command (struct cmdline *cmdline)
+{
+ char buffer[MAX_BUF];
+ char *p;
+ response_s *rs;
+ int numnodes = ocfs_get_numnodes();
+ bool success = true;
+ int i;
+
+ if (IGNORE_CDSL_VERIFY && cmdline->cdsl)
+ return true;
+
+ for (i=0; i<numnodes; i++)
+ {
+ if (IGNORE_ORIGINAL_NODE || (cmdline->cdsl && (cmdline->targetnode == i)))
+ {
+ if (i==numnodes)
+ continue;
+ }
+
+ if (0) // Randomly choose nodes to verify?
+ continue;
+
+ p = generate_command (cmdline, C_VERIFY);
+ ocfs_send_command(p, cmdline->targetnode);
+ ocfs_get_response(buffer, MAX_BUF, cmdline->targetnode);
+ rs = ParseResponse(buffer);
+
+ if (!rs)
+ {
+ DEBUG((stderr, "[WARN] Ack, empty response from client!\n"));
+ continue;
+ }
+
+ if (!cmdline->expecttrue)
+ {
+ if (rs->status == RESP_OK)
+ {
+ logprint_failure (cmdline, rs, C_VERIFY, i);
+ success = false;
+ }
+ else
+ {
+ logprint_success (cmdline, C_VERIFY, i);
+ }
+ }
+ else
+ {
+ if (check_result (rs, cmdline))
+ {
+ logprint_success (cmdline, C_VERIFY, i);
+ }
+ else
+ {
+ logprint_failure (cmdline, rs, C_VERIFY, i);
+ success = false;
+ }
+ }
+
+ response_s_free(rs);
+ }
+ return success;
+}
+
+void
+free_cmdline_members (struct cmdline *cmdline)
+{
+ /*
+ if (cmdline->command == CMD_MD5)
+ free (cmdline->md5sum);
+ */
+
+ // freeing args is handled by command_s_free
+
+ free(cmdline->raw);
+ command_s_free(cmdline->cs);
+}
+
+void
+report_init (struct report *report)
+{
+ int i;
+
+ for (i=0; i<OCFSTS_NUMCOMMANDS; i++)
+ {
+ report->cmd_success[i] = 0;
+ report->cmd_failure[i] = 0;
+ report->vfy_success[i] = 0;
+ report->vfy_failure[i] = 0;
+ }
+ report->syntax = 0;
+}
+
+void
+report_update (struct report *report, struct cmdline *cmdline,
+ bool cmd_status, bool vfy_status)
+{
+ if (cmd_status)
+ report->cmd_success[cmdline->command] += 1;
+ else
+ report->cmd_failure[cmdline->command] += 1;
+
+ if (vfy_status)
+ report->vfy_success[cmdline->command] += 1;
+ else
+ report->vfy_failure[cmdline->command] += 1;
+}
+
+int
+report_generate(struct report *report)
+{
+#if 0
+ fprintf (stdout, "--------------------------------------\n");
+ fprintf (stdout, "|%11s%5s%5s%5s%5s |\n", "CMD", "C_S", "C_F", "V_S", "V_F");
+ fprintf (stdout, "--------------------------------------\n");
+ for (int i=2; i<OCFSTS_NUMCOMMANDS; i++)
+ {
+ fprintf (stdout, "%12s%5d%5d%5d%5d\n", cmd_strings[i],
+ report->cmd_success[i], report->cmd_failure[i],
+ report->vfy_success[i], report->vfy_failure[i]);
+ }
+ fprintf (stdout, "-------------------------------------\n");
+#endif //0
+ fprintf (stdout, "%d syntax errors.\n", report->syntax);
+
+ return 0;
+}
+
+void
+ocfs_test (char *cmd, int lineno, struct report *report)
+{
+ struct cmdline cmdline;
+ bool cmd_status, vfy_status;
+ int stat;
+
+ cmdline.lineno = lineno;
+ cmdline.raw = strdup(cmd);
+ stat = parse_command(cmd, &cmdline);
+
+ if (stat == SYNTAX_ERR)
+ {
+ report->syntax += 1;
+ //fprintf (stderr,
+ //"[WARN] Command syntax errorSyntax error in command file, line %d\n"
+ // "[WW] Command: %s", lineno, cmd); // not "chomp"ed
+ return;
+ }
+ else if (stat == COMMENT)
+ return;
+
+ if (cmdline.command == CMD_QUIT)
+ {
+ exec_quit(&cmdline);
+ return;
+ }
+
+ cmd_status = exec_command (&cmdline);
+
+ vfy_status = verify_command (&cmdline);
+
+ report_update (report, &cmdline, cmd_status, vfy_status);
+ free_cmdline_members (&cmdline);
+}
+
+int
+ocfs_exec_only (char *cmd)
+{
+ struct cmdline cmdline;
+ bool cmd_status;
+ int stat;
+
+ cmdline.lineno = 0;
+ cmdline.raw = strdup(cmd);
+ stat = parse_command(cmd, &cmdline);
+
+ if (stat == SYNTAX_ERR)
+ {
+ fprintf (stderr, "Syntax error in call to library: %s\n", cmd);
+ return SYNTAX_ERR;
+ }
+ else if (stat == COMMENT)
+ return 0;
+
+ if (cmdline.command == CMD_QUIT)
+ {
+ exec_quit(&cmdline);
+ return 0;
+ }
+
+ cmd_status = exec_command (&cmdline);
+ free_cmdline_members (&cmdline);
+
+ return cmd_status;
+}
+
+
+int
+ocfs_vfy_only (char *cmd)
+{
+
+ struct cmdline cmdline;
+ bool vfy_status;
+ int stat;
+
+ cmdline.lineno = 0;
+ cmdline.raw = strdup(cmd);
+ stat = parse_command(cmd, &cmdline);
+
+ if (stat == SYNTAX_ERR)
+ {
+ fprintf (stderr, "Syntax error in verify-call to library: %s\n", cmd);
+ return SYNTAX_ERR;
+ }
+ else if (stat == COMMENT)
+ return 0;
+
+ if (cmdline.command == CMD_QUIT)
+ {
+ exec_quit(&cmdline);
+ return 0;
+ }
+
+ vfy_status = verify_command (&cmdline);
+ free(cmdline.raw);
+ //free_cmdline_members_vfy (&cmdline);
+
+ return vfy_status;
+}
Added: trunk/server/ocfs_test.h
===================================================================
--- trunk/server/ocfs_test.h 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/server/ocfs_test.h 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,49 @@
+#ifndef _ocfs_test_h_
+#define _ocfs_test_h_
+
+#include "../ocfsts.h"
+
+#define MAX_ARGS 12
+
+struct report {
+ int cmd_success[NUMCOMMANDS];
+ int cmd_failure[NUMCOMMANDS];
+ int vfy_success[NUMCOMMANDS];
+ int vfy_failure[NUMCOMMANDS];
+ int syntax;
+};
+
+enum {C_COMMAND, C_VERIFY};
+
+struct cmdline {
+ int command, num_attrs, vmethod;
+
+ // Flags
+ int expecttrue;
+ int cdsl;
+ int cdsl_pass_other_nodes;
+
+ char *arg[MAX_ARGS];
+ char *raw;
+
+ int lineno;
+ int targetnode;
+ char *md5sum;
+
+ command_s *cs;
+};
+
+enum verify {VFY_NONE, VFY_EXIST, VFY_NEXIST, VFY_OWNER, VFY_MODE, VFY_SIZE, VFY_MD5};
+
+
+
+void ocfs_test (char *cmd, int lineno, struct report *report);
+void report_init(struct report *report);
+int report_generate (struct report *report);
+const char * get_command_for_action (const int c);
+
+
+int ocfs_exec_only (char *cmd);
+int ocfs_vfy_only (char *cmd);
+
+#endif //_ocfs_test_h_
Added: trunk/server/ocfs_test_server.c
===================================================================
--- trunk/server/ocfs_test_server.c 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/server/ocfs_test_server.c 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,285 @@
+/*
+ * OCFS Test Server
+ * --
+ * greg.marsden at oracle.com
+ *
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+
+#include "comm.h"
+
+#include "ocfs_test.h"
+#include "debug.h"
+
+#define MAX_BUF 1024
+
+/** Globals */
+static int g_numnodes = 0;
+static struct node {
+ char *name;
+ struct hostent *hp;
+ ocfs_socket os;
+} g_nodes[1024];
+
+void
+usage(char **argv)
+{
+ fprintf (stdout,
+ "%s: OCFS Test Server\n Usage: \n"
+ "\t %s nodelist < command_file -or-\n"
+ "\t %s nodelist command_file \n"
+ " See documentation for nodelist and command_file format.\n",
+ argv[0], argv[0], argv[0]);
+}
+
+struct hostent *
+validate_address(char *addr)
+{
+ struct hostent *hp;
+ if ((hp = gethostbyname(addr)))
+ return hp;
+ else
+ {
+ fprintf (stderr, "Invalid node: %s\n", addr);
+ return NULL;
+ }
+}
+
+int
+read_node_file (FILE *NODES)
+{
+ char buffer[MAX_BUF];
+ int numnodes = 0;
+ char *ptr;
+ int lineno;
+
+ for (lineno=1; fgets(buffer, MAX_BUF-1, NODES); lineno++)
+ {
+ struct hostent *hp;
+ //DEBUG((stderr, "[IN-Node] %s", buffer));
+
+ while ((ptr = strchr(buffer, ' '))
+ || (ptr = strchr(buffer, '\n'))
+ || (ptr = strchr(buffer, '#')))
+ ptr[0] = '\0';
+
+ if (strlen(buffer) && (hp = validate_address(buffer)))
+ {
+ fprintf (stdout, "[II] Adding node %02d [%s]\n", numnodes+1, buffer);
+ g_nodes[numnodes].hp = hp;
+ g_nodes[numnodes].name = strdup(buffer);
+ numnodes++;
+ }
+ }
+ g_numnodes = numnodes;
+ fclose(NODES);
+ return numnodes;
+}
+
+int
+read_node_strings (int n, char **nodes)
+{
+ char *node_p;
+ int numnodes = 0;
+ int i;
+
+ for (i=0; i<n; i++)
+ {
+ struct hostent *hp;
+ node_p = nodes[i];
+ if (*node_p && (hp = validate_address(node_p)))
+ {
+ fprintf (stdout, "[II] Adding node %02d [%s]\n", numnodes, node_p);
+ g_nodes[numnodes].hp = hp;
+ g_nodes[numnodes].name = strdup(node_p);
+ numnodes ++;
+ }
+ else
+ {
+ perror("validate_address:");
+ }
+ }
+
+ g_numnodes = numnodes;
+ return n;
+}
+
+int
+disconnect_from_nodes()
+{
+ int i;
+
+ for (i=0; i< g_numnodes; i++)
+ {
+ comm_close_connection (g_nodes[i].os);
+ }
+ return 0;
+}
+
+int
+connect_to_nodes()
+{
+ int i;
+
+ for (i=0; i< g_numnodes; i++)
+ {
+ DEBUG((stderr, "[DD] Connecting to %s.\n", g_nodes[i].name));
+ g_nodes[i].os = comm_open_connection (g_nodes[i].hp);
+ if (g_nodes[i].os == NULL)
+ {
+ perror("[EE] Failed!");
+ return 0;
+ }
+ DEBUG((stderr, "[DD] Connected to %s.\n", g_nodes[i].name));
+ }
+ return g_numnodes;
+}
+
+int
+generate_report (struct report *report)
+{
+ fprintf (stderr, "Generating report....\n");
+ return 0;
+}
+
+int
+execute_tests (FILE *TSCRIPT)
+{
+ char cmd[MAX_BUF];
+ struct report report;
+ int lineno;
+
+ if (!connect_to_nodes())
+ return -1;
+
+ report_init (&report);
+
+ /* Parse and execute commands */
+ for (lineno=1; fgets(cmd, MAX_BUF -1, TSCRIPT); lineno++)
+ {
+ //DEBUG((stderr, "[IN] %s", cmd));
+
+ if (strlen(cmd) >= MAX_BUF -1)
+ {
+ fprintf (stderr, "Line %02d too long, operation cancelled.\n",
+ lineno);
+ return -1;
+ }
+
+ ocfs_test (cmd, lineno, &report);
+ }
+
+ disconnect_from_nodes();
+
+ return report_generate (&report);
+}
+
+#ifndef OCFSTS_LIBRARY
+int
+main(int argc, char **argv)
+{
+ FILE *NODES, *TSCRIPT;
+ int stat;
+
+ if (argc > 3 || argc < 2
+ || !strcmp(argv[1], "-help")
+ || !strcmp(argv[1], "-h")
+ || !strcmp(argv[1], "--help"))
+ {
+ usage(argv);
+ return 1;
+ }
+ else
+ {
+ if (! (argv[1] && argv[1][0] &&
+ (NODES = fopen(argv[1], "r"))))
+ {
+ usage(argv);
+ perror("[EE] Invalid node list.");
+ return -1;
+ }
+
+ if (argc == 2)
+ {
+ DEBUG((stderr, "[DD] Reading test script from stdin\n"));
+ TSCRIPT = stdin;
+ }
+ else
+ {
+ DEBUG((stderr, "[DE] Reading test script from %s\n", argv[2]));
+ if (! (argv[2] && argv[2][0] &&
+ (TSCRIPT = fopen(argv[2], "r"))))
+ {
+ perror ("Unable open input file.");
+ return -1;
+ }
+ }
+
+ }
+
+ stat = read_node_file (NODES);
+ if (!stat)
+ {
+ perror ("[EE] No valid nodes in file.");
+ return -1;
+ }
+ else
+ fprintf (stdout, "[II] %02d nodes read from file.\n", stat);
+
+ execute_tests(TSCRIPT);
+
+ return 0;
+}
+#endif //OCFSTS_LIBRARY
+
+int
+ocfs_get_random_nodenum()
+{
+ //return (rand()/RAND_MAX * g_numnodes);
+ return (int) ((double)(g_numnodes)*(double)rand()/(RAND_MAX+1.0));
+}
+
+int
+ocfs_get_node_by_name (const char *name)
+{
+ int i;
+
+ for (i=0; i<g_numnodes; i++)
+ {
+ if (!strcmp(g_nodes[i].name, name))
+ return i;
+ }
+ return -1;
+}
+
+int
+ocfs_get_numnodes ()
+{
+ return g_numnodes;
+}
+
+bool
+ocfs_send_command (char *buffer, int nodenum)
+{
+ if (g_nodes[nodenum].os != NULL)
+ return comm_send_command (g_nodes[nodenum].os, buffer);
+
+ fprintf (stderr, "[EE] Node %d not valid, connection not open!\n", nodenum);
+ return false;
+}
+
+bool
+ocfs_get_response (char *buffer, int maxlen, int nodenum)
+{
+ if (g_nodes[nodenum].os != NULL)
+ return comm_get_response (g_nodes[nodenum].os, buffer, maxlen);
+
+ fprintf (stderr, "[EE] Node %d not valid, connection not open!\n", nodenum);
+ return false;
+}
+
Added: trunk/server/ocfs_test_server.h
===================================================================
--- trunk/server/ocfs_test_server.h 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/server/ocfs_test_server.h 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,15 @@
+#ifndef _ocfs_test_server_h_
+#define _ocfs_test_server_h_
+
+// helper semi-OO functions
+int ocfs_get_random_nodenum();
+int ocfs_get_node_by_name(const char *name);
+int ocfs_get_numnodes ();
+
+bool ocfs_get_response (char *buffer, int maxlen, int nodenum);
+bool ocfs_send_command (char *buffer, int nodenum);
+
+int read_node_strings (int n, char **nodes);
+int connect_to_nodes();
+int disconnect_from_nodes();
+#endif //_ocfs_test_server_h_
Added: trunk/server/ocfstsapi.c
===================================================================
--- trunk/server/ocfstsapi.c 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/server/ocfstsapi.c 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,30 @@
+#include <stdbool.h>
+
+#include "ocfstsapi.h"
+#include "ocfs_test.h"
+#include "ocfs_test_server.h"
+
+int
+ocfsts_open_connection(int num_nodes, char **nodes)
+{
+ read_node_strings(num_nodes, nodes);
+ return connect_to_nodes()?0:1;
+}
+
+int
+ocfsts_close_connection(void)
+{
+ return disconnect_from_nodes()?0:1;
+}
+
+int
+ocfsts_execute (char * command)
+{
+ return ocfs_exec_only(command)?0:1;
+}
+
+int
+ocfsts_verify (char * command)
+{
+ return ocfs_vfy_only(command)?0:1;
+}
Added: trunk/server/ocfstsapi.h
===================================================================
--- trunk/server/ocfstsapi.h 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/server/ocfstsapi.h 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,15 @@
+/* API for connecting to testserver */
+#ifndef _ocfsapi_h_
+#define _ocfsapi_h_
+
+int ocfsts_open_connection (int num_nodes, char **nodes);
+int ocfsts_close_connection (void);
+
+/*
+ * By convention, exec/vfy return 0 if success and 1 if fail
+ * (not true/false as expected!)
+ */
+int ocfsts_execute (char * command);
+int ocfsts_verify (char * command);
+
+#endif //_ocfsapi_h_
Added: trunk/server/syntax.h
===================================================================
--- trunk/server/syntax.h 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/server/syntax.h 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,57 @@
+#ifndef _syntax_h_
+#define _syntax_h_
+
+#include "../ocfsts.h"
+#define OCFSTS_NUMCOMMANDS NUMCOMMANDS
+
+enum {MAP_TYPE, MAP_ARGTYPE, MAP_VFYTYPE};
+enum {NO_ARGS, SRC_ARG, SRC_DST_ARG, UID_ARG, MODE_ARG, NODE_ARG, SIZE_ARG, ENTPY_ARG};
+int num_args_per_type[] = {
+ 0, //NO_ARGS
+ 1, //SRC_ARG
+ 2, //SRC_DST_ARG
+ 3, //UID_ARG
+ 2, //MODE_ARG
+ 2, //NODE_ARG
+ 2, //SIZE_ARG
+ 2, //ENTPY_ARG
+};
+
+
+
+#define NUM_SERVER_COMMANDS 22
+
+struct cmd {
+ char *name;
+ int type;
+ int numargs;
+ int vtype;
+} cmdtab[] = {
+ {"quit", CMD_QUIT, NO_ARGS, VFY_NONE},
+ {"helo", CMD_HELO, NO_ARGS, VFY_NONE},
+ {"link", CMD_LINK, SRC_DST_ARG, VFY_EXIST},
+ {"symlink", CMD_SYMLINK, SRC_DST_ARG, VFY_EXIST},
+ {"chown", CMD_CHOWN, UID_ARG, VFY_OWNER},
+ {"mkdir", CMD_MKDIR, MODE_ARG, VFY_EXIST},
+ {"chmod", CMD_CHMOD, MODE_ARG, VFY_MODE},
+ {"mknod", CMD_MKNOD, NODE_ARG, VFY_EXIST},
+ {"rmdir", CMD_RMDIR, SRC_ARG, VFY_NEXIST},
+ {"create", CMD_CREATE, SRC_ARG, VFY_EXIST},
+ {"delete", CMD_DELETE, SRC_ARG, VFY_NEXIST},
+ {"rm", CMD_DELETE, SRC_ARG, VFY_NEXIST},
+ {"fstat", CMD_STAT, SRC_ARG, VFY_NONE},
+ {"stat", CMD_STAT, SRC_ARG, VFY_NONE},
+ {"resize", CMD_RESIZE, SIZE_ARG, VFY_SIZE},
+ {"modify", CMD_MODIFY, ENTPY_ARG, VFY_MD5},
+ {"chksum", CMD_MD5, SRC_ARG, VFY_MD5},
+ {"md5", CMD_MD5, SRC_ARG, VFY_MD5},
+ {"mv", CMD_MV, SRC_DST_ARG, VFY_EXIST},
+ {"move", CMD_MV, SRC_DST_ARG, VFY_EXIST},
+ {"open", CMD_OPEN, SRC_ARG, VFY_NONE},
+ {"close", CMD_CLOSE, SRC_ARG, VFY_NONE}
+};
+
+/* known bug: name of listed command in output does not correspond to cmdline
+ * name, but to first name which appears in this list */
+
+#endif //_syntax_h_
Added: trunk/testclient.pl
===================================================================
--- trunk/testclient.pl 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/testclient.pl 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,29 @@
+#!/usr/bin/perl -w
+
+use strict;
+use Socket;
+
+my ($remote, $port, $iaddr, $paddr, $proto, $line);
+
+$remote = shift || 'verbose';
+$port = shift || 4444;
+if ($port =~ /\D/) { $port = getservbyname($port, 'tcp') }
+die "No or Bad port" unless $port;
+
+$iaddr = inet_aton($remote)
+ || die "no host: $remote";
+$paddr=sockaddr_in($port, $iaddr);
+$proto = getprotobyname('tcp');
+
+socket (SOCK, PF_INET, SOCK_STREAM, $proto)
+ || die "socket: $!";
+connect (SOCK, $paddr)
+ || die "connect: $!";
+
+print SOCK "HELO\n\n";
+print SOCK "STAT\n/tmp/foo\n\n";
+print SOCK "QUIT\n\n";
+
+close (SOCK)
+ || die "close: $!";
+exit 0;
Property changes on: trunk/testclient.pl
___________________________________________________________________
Name: svn:executable
+
Added: trunk/tests/00_simple.pl
===================================================================
--- trunk/tests/00_simple.pl 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/tests/00_simple.pl 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,134 @@
+#!/bin/perl
+
+#
+# Description goes here
+#
+
+use ExtUtils::testlib;
+use Ocfsts;
+use English;
+
+do "ocfsts_config";
+
+if (!defined @NODES) {
+ die "No nodes defined!\n";
+}
+
+$retval = Ocfsts::ocfsts_connect @NODES;
+
+if ($retval != 0) {
+ die "Unable to connect!\n";
+}
+
+
+###
+# File creation and stat tests
+Ocfsts::ocfsts_create "$ROOT/file1";
+Ocfsts::ocfsts_fstat "$ROOT/file1";
+
+###
+# File deletion test
+Ocfsts::ocfsts_delete "$ROOT/file1";
+
+###
+# Can we stat a nonexistant file?
+Ocfsts::ocfsts_fstat "$ROOT/file1", "R", "f";
+
+###
+# Directory creation and stat tests
+Ocfsts::ocfsts_mkdir "$ROOT/dir1", "777";
+Ocfsts::ocfsts_fstat "$ROOT/dir1";
+
+###
+# Directory deletion test
+Ocfsts::ocfsts_rmdir "$ROOT/dir1";
+
+###
+# Can we stat a nonexistant directory?
+Ocfsts::ocfsts_fstat "$ROOT/dir1", "R", "f";
+
+###
+# Hard and symbolic link tests
+Ocfsts::ocfsts_create "$ROOT/source";
+Ocfsts::ocfsts_mkdir "$ROOT/dir1", "777";
+
+Ocfsts::ocfsts_link "$ROOT/source", "$ROOT/link1";
+Ocfsts::ocfsts_symlink "$ROOT/source", "$ROOT/symlink1";
+Ocfsts::ocfsts_symlink "$ROOT/dir1", "$ROOT/dirsymlink1";
+
+Ocfsts::ocfsts_fstat "$ROOT/link1";
+Ocfsts::ocfsts_fstat "$ROOT/symlink1";
+#R fstat $ROOT/dirlink1
+Ocfsts::ocfsts_fstat "$ROOT/dirsymlink1";
+
+Ocfsts::ocfsts_delete "$ROOT/link1";
+Ocfsts::ocfsts_delete "$ROOT/symlink1";
+#R delete $ROOT/dirlink1
+Ocfsts::ocfsts_delete "$ROOT/dirsymlink1";
+Ocfsts::ocfsts_delete "$ROOT/source";
+Ocfsts::ocfsts_rmdir "$ROOT/dir1";
+
+Ocfsts::ocfsts_fstat "$ROOT/link1", "R", "f";
+Ocfsts::ocfsts_fstat "$ROOT/symlink1", "R", "f";
+Ocfsts::ocfsts_fstat "$ROOT/dirlink1", "R", "f";
+Ocfsts::ocfsts_fstat "$ROOT/dirsymlink1", "R", "f";
+
+
+###
+# Permission tests
+Ocfsts::ocfsts_mkdir "$ROOT/dir1","755";
+Ocfsts::ocfsts_fstat "$ROOT/dir1";
+Ocfsts::ocfsts_create "$ROOT/dir1/unreachable";
+Ocfsts::ocfsts_chmod "$ROOT/dir1", "000";
+Ocfsts::ocfsts_fstat "$ROOT/dir1/unreachable", "R", "f";
+Ocfsts::ocfsts_delete "$ROOT/dir1/unreachable", "R", "f";
+Ocfsts::ocfsts_create "$ROOT/dir1/uncreatable", "R", "f";
+
+#cleanup
+Ocfsts::ocfsts_chmod "$ROOT/dir1", "755";
+Ocfsts::ocfsts_delete "$ROOT/dir1/unreachable";
+Ocfsts::ocfsts_rmdir "$ROOT/dir1";
+
+###
+# Grow and shrink files
+Ocfsts::ocfsts_create "$ROOT/grow";
+Ocfsts::ocfsts_create "$ROOT/shrink";
+
+#just setup the sizes and content here
+Ocfsts::ocfsts_resize "$ROOT/grow", "10240";
+Ocfsts::ocfsts_resize "$ROOT/shrink", "10240";
+Ocfsts::ocfsts_modify "$ROOT/grow", "999";
+Ocfsts::ocfsts_modify "$ROOT/shrink", "999";
+
+Ocfsts::ocfsts_chksum "$ROOT/grow";
+Ocfsts::ocfsts_chksum "$ROOT/shrink";
+
+Ocfsts::ocfsts_resize "$ROOT/shrink", "256";
+Ocfsts::ocfsts_resize "$ROOT/grow", "40960";
+Ocfsts::ocfsts_modify "$ROOT/grow", "999";
+Ocfsts::ocfsts_modify "$ROOT/shrink", "999";
+
+Ocfsts::ocfsts_chksum "$ROOT/grow";
+Ocfsts::ocfsts_chksum "$ROOT/shrink";
+
+Ocfsts::ocfsts_resize "$ROOT/shrink", "128";
+Ocfsts::ocfsts_resize "$ROOT/grow", "81920";
+Ocfsts::ocfsts_modify "$ROOT/grow", "999";
+Ocfsts::ocfsts_modify "$ROOT/shrink", "999";
+
+Ocfsts::ocfsts_chksum "$ROOT/grow";
+Ocfsts::ocfsts_chksum "$ROOT/shrink";
+
+Ocfsts::ocfsts_delete "$ROOT/grow";
+Ocfsts::ocfsts_delete "$ROOT/shrink";
+
+###
+# Try to delete a dir with a file in it
+Ocfsts::ocfsts_mkdir "$ROOT/dir1", "777";
+Ocfsts::ocfsts_create "$ROOT/dir1/file1";
+Ocfsts::ocfsts_rmdir "$ROOT/dir1", "R", "f";
+Ocfsts::ocfsts_delete "$ROOT/dir1/file1";
+Ocfsts::ocfsts_rmdir "$ROOT/dir1";
+
+Ocfsts::ocfsts_disconnect;
+
Added: trunk/tests/05_tree.pl
===================================================================
--- trunk/tests/05_tree.pl 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/tests/05_tree.pl 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,66 @@
+#!/bin/perl
+
+#
+# Make a tree of dirs
+#
+#
+#$ROOT
+#
+# foo bar baz bat
+# | | |
+# | | --> foo
+# | | --> bar
+# | | --> gar
+# | --> foo |
+# | --> bar -->foo
+# | |
+# | --> foo
+# | |
+# | --> baz
+# --> foo
+# |
+# --> bar
+# |
+# --> baz
+# |
+# --> bat
+#
+
+
+use ExtUtils::testlib;
+use Ocfsts;
+use English;
+
+do "ocfsts_config";
+
+if (!defined @NODES) {
+ die "No nodes defined!\n";
+}
+
+$retval = Ocfsts::ocfsts_connect @NODES;
+
+if ($retval != 0) {
+ die "Unable to connect!\n";
+}
+
+Ocfsts::ocfsts_mkdir "$ROOT/foo", "777";
+Ocfsts::ocfsts_mkdir "$ROOT/bar", "777";
+Ocfsts::ocfsts_mkdir "$ROOT/baz", "777";
+Ocfsts::ocfsts_mkdir "$ROOT/bat", "777";
+
+Ocfsts::ocfsts_mkdir "$ROOT/bat/foo", "777";
+Ocfsts::ocfsts_mkdir "$ROOT/bat/bar", "777";
+Ocfsts::ocfsts_mkdir "$ROOT/bat/gar", "777";
+Ocfsts::ocfsts_mkdir "$ROOT/bat/gar/foo", "777";
+
+Ocfsts::ocfsts_mkdir "$ROOT/baz/foo", "777";
+Ocfsts::ocfsts_mkdir "$ROOT/baz/bar", "777";
+Ocfsts::ocfsts_mkdir "$ROOT/baz/baz", "777";
+Ocfsts::ocfsts_mkdir "$ROOT/baz/bar/foo", "777";
+
+Ocfsts::ocfsts_mkdir "$ROOT/foo/foo", "777";
+Ocfsts::ocfsts_mkdir "$ROOT/foo/bar", "777";
+Ocfsts::ocfsts_mkdir "$ROOT/foo/bar/baz", "777";
+Ocfsts::ocfsts_mkdir "$ROOT/foo/bar/bat", "777";
+
+Ocfsts::ocfsts_disconnect;
Added: trunk/tests/06_tree_delete.pl
===================================================================
--- trunk/tests/06_tree_delete.pl 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/tests/06_tree_delete.pl 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,43 @@
+#!/bin/perl
+
+#
+# Delete our wonderful tree of directories
+#
+
+use ExtUtils::testlib;
+use Ocfsts;
+use English;
+
+do "ocfsts_config";
+
+if (!defined @NODES) {
+ die "No nodes defined!\n";
+}
+
+$retval = Ocfsts::ocfsts_connect @NODES;
+
+if ($retval != 0) {
+ die "Unable to connect!\n";
+}
+
+Ocfsts::ocfsts_rmdir "$ROOT/foo/bar/bat";
+Ocfsts::ocfsts_rmdir "$ROOT/foo/bar/baz";
+Ocfsts::ocfsts_rmdir "$ROOT/foo/bar";
+Ocfsts::ocfsts_rmdir "$ROOT/foo/foo";
+
+Ocfsts::ocfsts_rmdir "$ROOT/baz/bar/foo";
+Ocfsts::ocfsts_rmdir "$ROOT/baz/baz";
+Ocfsts::ocfsts_rmdir "$ROOT/baz/bar";
+Ocfsts::ocfsts_rmdir "$ROOT/baz/foo";
+
+Ocfsts::ocfsts_rmdir "$ROOT/bat/gar/foo";
+Ocfsts::ocfsts_rmdir "$ROOT/bat/gar";
+Ocfsts::ocfsts_rmdir "$ROOT/bat/bar";
+Ocfsts::ocfsts_rmdir "$ROOT/bat/foo";
+
+Ocfsts::ocfsts_rmdir "$ROOT/bat";
+Ocfsts::ocfsts_rmdir "$ROOT/baz";
+Ocfsts::ocfsts_rmdir "$ROOT/bar";
+Ocfsts::ocfsts_rmdir "$ROOT/foo";
+
+Ocfsts::ocfsts_disconnect;
Added: trunk/tests/15_mvtests.pl
===================================================================
--- trunk/tests/15_mvtests.pl 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/tests/15_mvtests.pl 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,41 @@
+#!/bin/perl
+
+#
+# mv gave us some particularly bad problems and that's
+# why there's a separate file for these tests.
+#
+
+
+use ExtUtils::testlib;
+use Ocfsts;
+use English;
+
+do "ocfsts_config";
+
+if (!defined @NODES) {
+ die "No nodes defined!\n";
+}
+
+$retval = Ocfsts::ocfsts_connect @NODES;
+
+if ($retval != 0) {
+ die "Unable to connect!\n";
+}
+
+#
+# Simple mv tests
+#
+Ocfsts::ocfsts_create "$ROOT/file1";
+Ocfsts::ocfsts_mkdir "$ROOT/dir1", "777";
+
+Ocfsts::ocfsts_mv "$ROOT/file1", "$ROOT/file2";
+
+Ocfsts::ocfsts_create "$ROOT/dir1/file3";
+Ocfsts::ocfsts_mv "$ROOT/dir1/file3", "$ROOT/file3";
+
+#cleanup
+Ocfsts::ocfsts_delete "$ROOT/file2";
+Ocfsts::ocfsts_delete "$ROOT/file3";
+Ocfsts::ocfsts_rmdir "$ROOT/dir1";
+
+Ocfsts::ocfsts_disconnect;
Added: trunk/tests/30_manyfiles.pl
===================================================================
--- trunk/tests/30_manyfiles.pl 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/tests/30_manyfiles.pl 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,37 @@
+#!/bin/perl
+
+#
+# Create/delete a ton of files to test dirnode boundaries
+#
+
+use ExtUtils::testlib;
+use Ocfsts;
+
+do "ocfsts_config";
+
+my $NUMFILES=1024;
+my $i;
+
+if (!defined @NODES) {
+ die "No nodes defined!\n";
+}
+
+$retval = Ocfsts::ocfsts_connect @NODES;
+
+if ($retval != 0) {
+ die "Unable to connect!\n";
+}
+
+Ocfsts::ocfsts_mkdir "$ROOT/manyfiles", "755";
+
+for ($i = 0; $i < $NUMFILES; $i++) {
+ Ocfsts::ocfsts_create "$ROOT/manyfiles/myfile$i";
+}
+
+for ($i = 0; $i < $NUMFILES; $i++) {
+ Ocfsts::ocfsts_delete "$ROOT/manyfiles/myfile$i";
+}
+
+Ocfsts::ocfsts_rmdir "$ROOT/manyfiles";
+
+Ocfsts::ocfsts_close_connection;
Added: trunk/tests/45_openclose.pl
===================================================================
--- trunk/tests/45_openclose.pl 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/tests/45_openclose.pl 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,44 @@
+#!/bin/perl
+
+#
+# Tests the open/close stuff
+#
+
+use ExtUtils::testlib;
+use Ocfsts;
+use English;
+
+do "ocfsts_config";
+
+#if you're gonna make this larger than 1000, you should
+#change the file descriptor limits on the OS!
+my $NUMFILES=768;
+my $i;
+
+if (!defined @NODES) {
+ die "No nodes defined!\n";
+}
+
+$retval = Ocfsts::ocfsts_connect @NODES;
+
+if ($retval != 0) {
+ die "Unable to connect!\n";
+}
+
+#Ocfsts::ocfsts_delete("$ROOT/myfile");
+#Ocfsts::ocfsts_create("$ROOT/myfile");
+for ($i = 0; $i < $NUMFILES; $i++) {
+ Ocfsts::ocfsts_open "$ROOT/myfile$i";
+}
+
+#don't want to do this for O_DIRECT
+#for ($i = 0; $i < $NUMFILES; $i++) {
+# Ocfsts::ocfsts_resize "$ROOT/myfile$i", "1024";
+#}
+
+for ($i = 0; $i < $NUMFILES; $i++) {
+ Ocfsts::ocfsts_close "$ROOT/myfile$i";
+}
+
+Ocfsts::ocfsts_close_connection;
+
Added: trunk/tests/Makefile
===================================================================
--- trunk/tests/Makefile 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/tests/Makefile 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,18 @@
+
+include ../Makefile.config
+
+#objects=00_simple.test 05_tree.test 06_tree_delete.test 15_mvtests.test
+
+#ROOT=\/ocfs
+
+#all: $(objects) perl
+
+#%.test: %.in
+# cat $< | sed 's/\$$ROOT/${ROOT}/' > $@
+
+perl:
+ ln -fs ../Ocfsts/blib blib
+
+.PHONY: clean
+clean:
+ rm -f *~ *.test blib
Added: trunk/tests/ocfsts_config
===================================================================
--- trunk/tests/ocfsts_config 2003-08-19 22:26:13 UTC (rev 1)
+++ trunk/tests/ocfsts_config 2003-08-19 22:31:10 UTC (rev 2)
@@ -0,0 +1,17 @@
+#
+# This config file is read in by perl before the tests are executed
+# Any perl code is valid.
+#
+
+# This is where all the action will take place. Choose something on
+# an OCFS mounted volume :)
+$ROOT="/tmp";
+
+# put your client nodes in here. a sample is below for a three node cluster
+# with nodes called node1, node2, node3.
+#@NODES = ("node1", "node2", "node3");
+
+ at NODES = ("localhost");
+
+#this is deprecated
+#$NODELIST_FILE="nodelist";
More information about the Ocfstest-commits
mailing list