From ff6dbcca9c8beba5c9942f1d9e704e1b4b1b1465 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Fri, 24 May 2002 22:44:42 -0400 Subject: [PATCH] Add EVMS FSIM plugin to e2fsprogs. --- ChangeLog | 6 + configure | 405 ++++--- configure.in | 16 + lib/evms/Makefile.in | 53 + lib/evms/common.h | 287 +++++ lib/evms/dlist.h | 2357 ++++++++++++++++++++++++++++++++++++++ lib/evms/enginestructs.h | 302 +++++ lib/evms/evms_common.h | 161 +++ lib/evms/evms_ioctl.h | 297 +++++ lib/evms/evms_user.h | 28 + lib/evms/fs_ext2.c | 1141 ++++++++++++++++++ lib/evms/fsimext2.c | 578 ++++++++++ lib/evms/fsimext2.h | 276 +++++ lib/evms/options.h | 315 +++++ lib/evms/plugfuncs.h | 1128 ++++++++++++++++++ lib/evms/plugin.h | 32 + 16 files changed, 7191 insertions(+), 191 deletions(-) create mode 100644 lib/evms/Makefile.in create mode 100644 lib/evms/common.h create mode 100644 lib/evms/dlist.h create mode 100644 lib/evms/enginestructs.h create mode 100644 lib/evms/evms_common.h create mode 100644 lib/evms/evms_ioctl.h create mode 100644 lib/evms/evms_user.h create mode 100644 lib/evms/fs_ext2.c create mode 100644 lib/evms/fsimext2.c create mode 100644 lib/evms/fsimext2.h create mode 100644 lib/evms/options.h create mode 100644 lib/evms/plugfuncs.h create mode 100644 lib/evms/plugin.h diff --git a/ChangeLog b/ChangeLog index da51af79..9506d932 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2002-05-24 + + * configure.in: Add makefile for lib/evms for the EVMS FSIM + plugin. Add --enable-old-evms configure option which uses + the EVMS 1.0.0 ABI, instead of the ABI used by EVMS 1.1.0. + 2002-05-21 Theodore Ts'o * configure.in: On Linux systems, if the prefix is defaulted to diff --git a/configure b/configure index 30d0d1e6..57d13488 100644 --- a/configure +++ b/configure @@ -23,6 +23,8 @@ ac_help="$ac_help --with-root-prefix=PREFIX override prefix variable for files to be placed in the root" ac_help="$ac_help --enable-compression enable EXPERIMENTAL compression support" +ac_help="$ac_help + --enable-old-evms use EVMS 1.0 ABI (instead of EVMS 1.1)" ac_help="$ac_help --enable-dll-shlibs select DLL libraries" ac_help="$ac_help @@ -632,7 +634,7 @@ else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } fi echo $ac_n "checking host system type""... $ac_c" 1>&6 -echo "configure:636: checking host system type" >&5 +echo "configure:638: checking host system type" >&5 host_alias=$host case "$host_alias" in @@ -666,7 +668,7 @@ export CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:670: checking for $ac_word" >&5 +echo "configure:672: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -696,7 +698,7 @@ if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:700: checking for $ac_word" >&5 +echo "configure:702: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -747,7 +749,7 @@ fi # Extract the first word of "cl", so it can be a program name with args. set dummy cl; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:751: checking for $ac_word" >&5 +echo "configure:753: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -779,7 +781,7 @@ fi fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 -echo "configure:783: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 +echo "configure:785: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. @@ -790,12 +792,12 @@ cross_compiling=$ac_cv_prog_cc_cross cat > conftest.$ac_ext << EOF -#line 794 "configure" +#line 796 "configure" #include "confdefs.h" main(){return(0);} EOF -if { (eval echo configure:799: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:801: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then ac_cv_prog_cc_works=yes # If we can't run a trivial program, we are probably using a cross compiler. if (./conftest; exit) 2>/dev/null; then @@ -821,12 +823,12 @@ if test $ac_cv_prog_cc_works = no; then { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 -echo "configure:825: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "configure:827: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 cross_compiling=$ac_cv_prog_cc_cross echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 -echo "configure:830: checking whether we are using GNU C" >&5 +echo "configure:832: checking whether we are using GNU C" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -835,7 +837,7 @@ else yes; #endif EOF -if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:839: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:841: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no @@ -854,7 +856,7 @@ ac_test_CFLAGS="${CFLAGS+set}" ac_save_CFLAGS="$CFLAGS" CFLAGS= echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 -echo "configure:858: checking whether ${CC-cc} accepts -g" >&5 +echo "configure:860: checking whether ${CC-cc} accepts -g" >&5 if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -903,7 +905,7 @@ if test "${with_ccopts+set}" = set; then CFLAGS=$withval fi echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 -echo "configure:907: checking how to run the C preprocessor" >&5 +echo "configure:909: checking how to run the C preprocessor" >&5 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= @@ -918,13 +920,13 @@ else # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:928: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:930: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -935,13 +937,13 @@ else rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:945: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:947: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -952,13 +954,13 @@ else rm -rf conftest* CPP="${CC-cc} -nologo -E" cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:962: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:964: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -984,17 +986,17 @@ echo "$ac_t""$CPP" 1>&6 ac_safe=`echo "linux/fs.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for linux/fs.h""... $ac_c" 1>&6 -echo "configure:988: checking for linux/fs.h" >&5 +echo "configure:990: checking for linux/fs.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:998: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1000: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -1059,6 +1061,25 @@ else fi +# Check whether --enable-old-evms or --disable-old-evms was given. +if test "${enable_old_evms+set}" = set; then + enableval="$enable_old_evms" + if test "$enableval" = "no" +then + echo "Using EVMS 1.1.0 ABI" +else + cat >> confdefs.h <<\EOF +#define ABI_EVMS_1_0 1 +EOF + + echo "Enabling EVMS 1.0.0 ABI" +fi + +else + echo "Using EVMS 1.1.0 ABI by default" + +fi + # Check whether --enable-dll-shlibs or --disable-dll-shlibs was given. if test "${enable_dll_shlibs+set}" = set; then enableval="$enable_dll_shlibs" @@ -1370,7 +1391,7 @@ EOF ALL_LINGUAS="it nyc tr" echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 -echo "configure:1374: checking whether ${MAKE-make} sets \${MAKE}" >&5 +echo "configure:1395: checking whether ${MAKE-make} sets \${MAKE}" >&5 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -1399,7 +1420,7 @@ fi # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1403: checking for $ac_word" >&5 +echo "configure:1424: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1427,7 +1448,7 @@ else fi echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&6 -echo "configure:1431: checking for POSIXized ISC" >&5 +echo "configure:1452: checking for POSIXized ISC" >&5 if test -d /etc/conf/kconfig.d && grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1 then @@ -1448,12 +1469,12 @@ else fi echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 -echo "configure:1452: checking for ANSI C header files" >&5 +echo "configure:1473: checking for ANSI C header files" >&5 if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include @@ -1461,7 +1482,7 @@ else #include EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1465: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1486: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -1478,7 +1499,7 @@ rm -f conftest* if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat > conftest.$ac_ext < EOF @@ -1496,7 +1517,7 @@ fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat > conftest.$ac_ext < EOF @@ -1517,7 +1538,7 @@ if test "$cross_compiling" = yes; then : else cat > conftest.$ac_ext < #define ISLOWER(c) ('a' <= (c) && (c) <= 'z') @@ -1528,7 +1549,7 @@ if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } EOF -if { (eval echo configure:1532: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:1553: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then : else @@ -1552,12 +1573,12 @@ EOF fi echo $ac_n "checking for working const""... $ac_c" 1>&6 -echo "configure:1556: checking for working const" >&5 +echo "configure:1577: checking for working const" >&5 if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1631: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_const=yes else @@ -1627,21 +1648,21 @@ EOF fi echo $ac_n "checking for inline""... $ac_c" 1>&6 -echo "configure:1631: checking for inline" >&5 +echo "configure:1652: checking for inline" >&5 if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1666: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_inline=$ac_kw; break else @@ -1667,12 +1688,12 @@ EOF esac echo $ac_n "checking for off_t""... $ac_c" 1>&6 -echo "configure:1671: checking for off_t" >&5 +echo "configure:1692: checking for off_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS @@ -1700,12 +1721,12 @@ EOF fi echo $ac_n "checking for size_t""... $ac_c" 1>&6 -echo "configure:1704: checking for size_t" >&5 +echo "configure:1725: checking for size_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS @@ -1735,19 +1756,19 @@ fi # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works # for constant arguments. Useless! echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6 -echo "configure:1739: checking for working alloca.h" >&5 +echo "configure:1760: checking for working alloca.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { char *p = alloca(2 * sizeof(int)); ; return 0; } EOF -if { (eval echo configure:1751: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:1772: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_header_alloca_h=yes else @@ -1768,12 +1789,12 @@ EOF fi echo $ac_n "checking for alloca""... $ac_c" 1>&6 -echo "configure:1772: checking for alloca" >&5 +echo "configure:1793: checking for alloca" >&5 if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:1826: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_func_alloca_works=yes else @@ -1833,12 +1854,12 @@ EOF echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6 -echo "configure:1837: checking whether alloca needs Cray hooks" >&5 +echo "configure:1858: checking whether alloca needs Cray hooks" >&5 if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 if test $ac_cv_os_cray = yes; then for ac_func in _getb67 GETB67 getb67; do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:1867: checking for $ac_func" >&5 +echo "configure:1888: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:1916: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -1918,7 +1939,7 @@ done fi echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6 -echo "configure:1922: checking stack direction for C alloca" >&5 +echo "configure:1943: checking stack direction for C alloca" >&5 if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1926,7 +1947,7 @@ else ac_cv_c_stack_direction=0 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:1970: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_c_stack_direction=1 else @@ -1970,17 +1991,17 @@ for ac_hdr in unistd.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:1974: checking for $ac_hdr" >&5 +echo "configure:1995: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1984: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:2005: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -2009,12 +2030,12 @@ done for ac_func in getpagesize do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:2013: checking for $ac_func" >&5 +echo "configure:2034: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2062: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -2062,7 +2083,7 @@ fi done echo $ac_n "checking for working mmap""... $ac_c" 1>&6 -echo "configure:2066: checking for working mmap" >&5 +echo "configure:2087: checking for working mmap" >&5 if eval "test \"`echo '$''{'ac_cv_func_mmap_fixed_mapped'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2070,7 +2091,7 @@ else ac_cv_func_mmap_fixed_mapped=no else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:2235: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_func_mmap_fixed_mapped=yes else @@ -2238,17 +2259,17 @@ unistd.h sys/param.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:2242: checking for $ac_hdr" >&5 +echo "configure:2263: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2252: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:2273: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -2278,12 +2299,12 @@ done strdup __argz_count __argz_stringify __argz_next do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:2282: checking for $ac_func" >&5 +echo "configure:2303: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2331: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -2335,12 +2356,12 @@ done for ac_func in stpcpy do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:2339: checking for $ac_func" >&5 +echo "configure:2360: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2388: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -2397,19 +2418,19 @@ EOF if test $ac_cv_header_locale_h = yes; then echo $ac_n "checking for LC_MESSAGES""... $ac_c" 1>&6 -echo "configure:2401: checking for LC_MESSAGES" >&5 +echo "configure:2422: checking for LC_MESSAGES" >&5 if eval "test \"`echo '$''{'am_cv_val_LC_MESSAGES'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { return LC_MESSAGES ; return 0; } EOF -if { (eval echo configure:2413: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2434: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* am_cv_val_LC_MESSAGES=yes else @@ -2430,7 +2451,7 @@ EOF fi fi echo $ac_n "checking whether NLS is requested""... $ac_c" 1>&6 -echo "configure:2434: checking whether NLS is requested" >&5 +echo "configure:2455: checking whether NLS is requested" >&5 # Check whether --enable-nls or --disable-nls was given. if test "${enable_nls+set}" = set; then enableval="$enable_nls" @@ -2450,7 +2471,7 @@ fi EOF echo $ac_n "checking whether included gettext is requested""... $ac_c" 1>&6 -echo "configure:2454: checking whether included gettext is requested" >&5 +echo "configure:2475: checking whether included gettext is requested" >&5 # Check whether --with-included-gettext or --without-included-gettext was given. if test "${with_included_gettext+set}" = set; then withval="$with_included_gettext" @@ -2469,17 +2490,17 @@ fi ac_safe=`echo "libintl.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for libintl.h""... $ac_c" 1>&6 -echo "configure:2473: checking for libintl.h" >&5 +echo "configure:2494: checking for libintl.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2483: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:2504: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -2496,19 +2517,19 @@ fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 echo $ac_n "checking for gettext in libc""... $ac_c" 1>&6 -echo "configure:2500: checking for gettext in libc" >&5 +echo "configure:2521: checking for gettext in libc" >&5 if eval "test \"`echo '$''{'gt_cv_func_gettext_libc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { return (int) gettext ("") ; return 0; } EOF -if { (eval echo configure:2512: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2533: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* gt_cv_func_gettext_libc=yes else @@ -2524,7 +2545,7 @@ echo "$ac_t""$gt_cv_func_gettext_libc" 1>&6 if test "$gt_cv_func_gettext_libc" != "yes"; then echo $ac_n "checking for bindtextdomain in -lintl""... $ac_c" 1>&6 -echo "configure:2528: checking for bindtextdomain in -lintl" >&5 +echo "configure:2549: checking for bindtextdomain in -lintl" >&5 ac_lib_var=`echo intl'_'bindtextdomain | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -2532,7 +2553,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lintl $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2568: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -2559,12 +2580,12 @@ fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 echo $ac_n "checking for gettext in libintl""... $ac_c" 1>&6 -echo "configure:2563: checking for gettext in libintl" >&5 +echo "configure:2584: checking for gettext in libintl" >&5 if eval "test \"`echo '$''{'gt_cv_func_gettext_libintl'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else echo $ac_n "checking for gettext in -lintl""... $ac_c" 1>&6 -echo "configure:2568: checking for gettext in -lintl" >&5 +echo "configure:2589: checking for gettext in -lintl" >&5 ac_lib_var=`echo intl'_'gettext | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -2572,7 +2593,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lintl $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2608: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -2622,7 +2643,7 @@ EOF # Extract the first word of "msgfmt", so it can be a program name with args. set dummy msgfmt; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2626: checking for $ac_word" >&5 +echo "configure:2647: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_MSGFMT'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2656,12 +2677,12 @@ fi for ac_func in dcgettext do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:2660: checking for $ac_func" >&5 +echo "configure:2681: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2709: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -2711,7 +2732,7 @@ done # Extract the first word of "gmsgfmt", so it can be a program name with args. set dummy gmsgfmt; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2715: checking for $ac_word" >&5 +echo "configure:2736: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_GMSGFMT'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2747,7 +2768,7 @@ fi # Extract the first word of "xgettext", so it can be a program name with args. set dummy xgettext; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2751: checking for $ac_word" >&5 +echo "configure:2772: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_XGETTEXT'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2779,7 +2800,7 @@ else fi cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2812: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* CATOBJEXT=.gmo DATADIRNAME=share @@ -2810,7 +2831,7 @@ fi if test "$CATOBJEXT" = "NONE"; then echo $ac_n "checking whether catgets can be used""... $ac_c" 1>&6 -echo "configure:2814: checking whether catgets can be used" >&5 +echo "configure:2835: checking whether catgets can be used" >&5 # Check whether --with-catgets or --without-catgets was given. if test "${with_catgets+set}" = set; then withval="$with_catgets" @@ -2823,7 +2844,7 @@ fi if test "$nls_cv_use_catgets" = "yes"; then echo $ac_n "checking for main in -li""... $ac_c" 1>&6 -echo "configure:2827: checking for main in -li" >&5 +echo "configure:2848: checking for main in -li" >&5 ac_lib_var=`echo i'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -2831,14 +2852,14 @@ else ac_save_LIBS="$LIBS" LIBS="-li $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2863: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -2866,12 +2887,12 @@ else fi echo $ac_n "checking for catgets""... $ac_c" 1>&6 -echo "configure:2870: checking for catgets" >&5 +echo "configure:2891: checking for catgets" >&5 if eval "test \"`echo '$''{'ac_cv_func_catgets'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2919: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_catgets=yes" else @@ -2916,7 +2937,7 @@ EOF # Extract the first word of "gencat", so it can be a program name with args. set dummy gencat; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2920: checking for $ac_word" >&5 +echo "configure:2941: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_GENCAT'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2952,7 +2973,7 @@ fi # Extract the first word of "gmsgfmt", so it can be a program name with args. set dummy gmsgfmt; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2956: checking for $ac_word" >&5 +echo "configure:2977: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_GMSGFMT'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2989,7 +3010,7 @@ fi # Extract the first word of "msgfmt", so it can be a program name with args. set dummy msgfmt; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2993: checking for $ac_word" >&5 +echo "configure:3014: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_GMSGFMT'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3024,7 +3045,7 @@ fi # Extract the first word of "xgettext", so it can be a program name with args. set dummy xgettext; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3028: checking for $ac_word" >&5 +echo "configure:3049: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_XGETTEXT'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3082,7 +3103,7 @@ fi # Extract the first word of "msgfmt", so it can be a program name with args. set dummy msgfmt; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3086: checking for $ac_word" >&5 +echo "configure:3107: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_MSGFMT'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3116,7 +3137,7 @@ fi # Extract the first word of "gmsgfmt", so it can be a program name with args. set dummy gmsgfmt; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3120: checking for $ac_word" >&5 +echo "configure:3141: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_GMSGFMT'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3152,7 +3173,7 @@ fi # Extract the first word of "xgettext", so it can be a program name with args. set dummy xgettext; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3156: checking for $ac_word" >&5 +echo "configure:3177: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_XGETTEXT'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3245,7 +3266,7 @@ fi LINGUAS= else echo $ac_n "checking for catalogs to be installed""... $ac_c" 1>&6 -echo "configure:3249: checking for catalogs to be installed" >&5 +echo "configure:3270: checking for catalogs to be installed" >&5 NEW_LINGUAS= for lang in ${LINGUAS=$ALL_LINGUAS}; do case "$ALL_LINGUAS" in @@ -3273,17 +3294,17 @@ echo "configure:3249: checking for catalogs to be installed" >&5 if test "$CATOBJEXT" = ".cat"; then ac_safe=`echo "linux/version.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for linux/version.h""... $ac_c" 1>&6 -echo "configure:3277: checking for linux/version.h" >&5 +echo "configure:3298: checking for linux/version.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:3287: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:3308: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -3349,7 +3370,7 @@ fi echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 -echo "configure:3353: checking whether ${MAKE-make} sets \${MAKE}" >&5 +echo "configure:3374: checking whether ${MAKE-make} sets \${MAKE}" >&5 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -3378,7 +3399,7 @@ fi # Extract the first word of "ln", so it can be a program name with args. set dummy ln; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3382: checking for $ac_word" >&5 +echo "configure:3403: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_LN'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3412,7 +3433,7 @@ else fi echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6 -echo "configure:3416: checking whether ln -s works" >&5 +echo "configure:3437: checking whether ln -s works" >&5 if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3435,7 +3456,7 @@ fi # Extract the first word of "mv", so it can be a program name with args. set dummy mv; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3439: checking for $ac_word" >&5 +echo "configure:3460: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_MV'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3471,7 +3492,7 @@ fi # Extract the first word of "cp", so it can be a program name with args. set dummy cp; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3475: checking for $ac_word" >&5 +echo "configure:3496: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_CP'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3507,7 +3528,7 @@ fi # Extract the first word of "rm", so it can be a program name with args. set dummy rm; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3511: checking for $ac_word" >&5 +echo "configure:3532: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_RM'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3543,7 +3564,7 @@ fi # Extract the first word of "chmod", so it can be a program name with args. set dummy chmod; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3547: checking for $ac_word" >&5 +echo "configure:3568: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_CHMOD'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3579,7 +3600,7 @@ fi # Extract the first word of "awk", so it can be a program name with args. set dummy awk; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3583: checking for $ac_word" >&5 +echo "configure:3604: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_AWK'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3615,7 +3636,7 @@ fi # Extract the first word of "sed", so it can be a program name with args. set dummy sed; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3619: checking for $ac_word" >&5 +echo "configure:3640: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_SED'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3651,7 +3672,7 @@ fi # Extract the first word of "perl", so it can be a program name with args. set dummy perl; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3655: checking for $ac_word" >&5 +echo "configure:3676: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_PERL'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3687,7 +3708,7 @@ fi # Extract the first word of "ldconfig", so it can be a program name with args. set dummy ldconfig; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3691: checking for $ac_word" >&5 +echo "configure:3712: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_LDCONFIG'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3721,7 +3742,7 @@ else fi echo $ac_n "checking build system type""... $ac_c" 1>&6 -echo "configure:3725: checking build system type" >&5 +echo "configure:3746: checking build system type" >&5 build_alias=$build case "$build_alias" in @@ -3747,7 +3768,7 @@ fi # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3751: checking for $ac_word" >&5 +echo "configure:3772: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3779,7 +3800,7 @@ if test -n "$ac_tool_prefix"; then # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3783: checking for $ac_word" >&5 +echo "configure:3804: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3814,7 +3835,7 @@ fi # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3818: checking for $ac_word" >&5 +echo "configure:3839: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3846,7 +3867,7 @@ if test -n "$ac_tool_prefix"; then # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3850: checking for $ac_word" >&5 +echo "configure:3871: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3881,7 +3902,7 @@ fi # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3885: checking for $ac_word" >&5 +echo "configure:3906: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_STRIP'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3913,7 +3934,7 @@ if test -n "$ac_tool_prefix"; then # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3917: checking for $ac_word" >&5 +echo "configure:3938: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_STRIP'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3957,7 +3978,7 @@ fi # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 -echo "configure:3961: checking for a BSD compatible install" >&5 +echo "configure:3982: checking for a BSD compatible install" >&5 if test -z "$INSTALL"; then if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -4019,7 +4040,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:4023: checking for $ac_word" >&5 +echo "configure:4044: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_BUILD_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4053,17 +4074,17 @@ for ac_hdr in stdlib.h unistd.h stdarg.h errno.h malloc.h mntent.h paths.h diren do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:4057: checking for $ac_hdr" >&5 +echo "configure:4078: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:4067: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:4088: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -4090,12 +4111,12 @@ fi done echo $ac_n "checking for vprintf""... $ac_c" 1>&6 -echo "configure:4094: checking for vprintf" >&5 +echo "configure:4115: checking for vprintf" >&5 if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4143: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_vprintf=yes" else @@ -4142,12 +4163,12 @@ fi if test "$ac_cv_func_vprintf" != yes; then echo $ac_n "checking for _doprnt""... $ac_c" 1>&6 -echo "configure:4146: checking for _doprnt" >&5 +echo "configure:4167: checking for _doprnt" >&5 if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4195: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func__doprnt=yes" else @@ -4195,12 +4216,12 @@ fi fi echo $ac_n "checking whether struct dirent has a d_namlen field""... $ac_c" 1>&6 -echo "configure:4199: checking whether struct dirent has a d_namlen field" >&5 +echo "configure:4220: checking whether struct dirent has a d_namlen field" >&5 if eval "test \"`echo '$''{'e2fsprogs_cv_struct_d_namlen'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include @@ -4208,7 +4229,7 @@ int main() { struct dirent de; de.d_namlen = 0; ; return 0; } EOF -if { (eval echo configure:4212: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:4233: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* e2fsprogs_cv_struct_d_namlen=yes else @@ -4228,19 +4249,19 @@ EOF fi echo $ac_n "checking whether llseek declared in unistd.h""... $ac_c" 1>&6 -echo "configure:4232: checking whether llseek declared in unistd.h" >&5 +echo "configure:4253: checking whether llseek declared in unistd.h" >&5 if eval "test \"`echo '$''{'e2fsprogs_cv_have_llseek_prototype'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { extern int llseek(int); ; return 0; } EOF -if { (eval echo configure:4244: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:4265: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* e2fsprogs_cv_have_llseek_prototype=no else @@ -4260,12 +4281,12 @@ EOF fi echo $ac_n "checking whether lseek64 declared in unistd.h""... $ac_c" 1>&6 -echo "configure:4264: checking whether lseek64 declared in unistd.h" >&5 +echo "configure:4285: checking whether lseek64 declared in unistd.h" >&5 if eval "test \"`echo '$''{'e2fsprogs_cv_have_lseek64_prototype'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:4299: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* e2fsprogs_cv_have_lseek64_prototype=no else @@ -4302,7 +4323,7 @@ if test "$cross_compiling" = yes -a "$ac_cv_sizeof_long" = ""; then echo "configure: warning: Cross-compiling, so cannot check type sizes; assuming short=2, int=4, long=4, long long=8" 1>&2 fi echo $ac_n "checking size of short""... $ac_c" 1>&6 -echo "configure:4306: checking size of short" >&5 +echo "configure:4327: checking size of short" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_short'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4310,7 +4331,7 @@ else { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < #include @@ -4322,7 +4343,7 @@ main() exit(0); } EOF -if { (eval echo configure:4326: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:4347: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_sizeof_short=`cat conftestval` else @@ -4342,7 +4363,7 @@ EOF echo $ac_n "checking size of int""... $ac_c" 1>&6 -echo "configure:4346: checking size of int" >&5 +echo "configure:4367: checking size of int" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_int'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4350,7 +4371,7 @@ else { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < #include @@ -4362,7 +4383,7 @@ main() exit(0); } EOF -if { (eval echo configure:4366: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:4387: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_sizeof_int=`cat conftestval` else @@ -4382,7 +4403,7 @@ EOF echo $ac_n "checking size of long""... $ac_c" 1>&6 -echo "configure:4386: checking size of long" >&5 +echo "configure:4407: checking size of long" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_long'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4390,7 +4411,7 @@ else { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < #include @@ -4402,7 +4423,7 @@ main() exit(0); } EOF -if { (eval echo configure:4406: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:4427: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_sizeof_long=`cat conftestval` else @@ -4422,7 +4443,7 @@ EOF echo $ac_n "checking size of long long""... $ac_c" 1>&6 -echo "configure:4426: checking size of long long" >&5 +echo "configure:4447: checking size of long long" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_long_long'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4430,7 +4451,7 @@ else { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < #include @@ -4442,7 +4463,7 @@ main() exit(0); } EOF -if { (eval echo configure:4446: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:4467: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_sizeof_long_long=`cat conftestval` else @@ -4470,14 +4491,14 @@ SIZEOF_LONG_LONG=$ac_cv_sizeof_long_long echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6 -echo "configure:4474: checking whether byte ordering is bigendian" >&5 +echo "configure:4495: checking whether byte ordering is bigendian" >&5 if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_cv_c_bigendian=unknown # See if sys/param.h defines the BYTE_ORDER macro. cat > conftest.$ac_ext < #include @@ -4488,11 +4509,11 @@ int main() { #endif ; return 0; } EOF -if { (eval echo configure:4492: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:4513: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* # It does; now see whether it defined to BIG_ENDIAN or not. cat > conftest.$ac_ext < #include @@ -4503,7 +4524,7 @@ int main() { #endif ; return 0; } EOF -if { (eval echo configure:4507: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:4528: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_bigendian=yes else @@ -4523,7 +4544,7 @@ if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:4561: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_c_bigendian=no else @@ -4560,19 +4581,19 @@ EOF fi echo $ac_n "checking whether struct stat has a st_flags field""... $ac_c" 1>&6 -echo "configure:4564: checking whether struct stat has a st_flags field" >&5 +echo "configure:4585: checking whether struct stat has a st_flags field" >&5 if eval "test \"`echo '$''{'e2fsprogs_cv_struct_st_flags'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { struct stat stat; stat.st_flags = 0; ; return 0; } EOF -if { (eval echo configure:4576: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:4597: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* e2fsprogs_cv_struct_st_flags=yes else @@ -4587,19 +4608,19 @@ fi echo "$ac_t""$e2fsprogs_cv_struct_st_flags" 1>&6 if test "$e2fsprogs_cv_struct_st_flags" = yes; then echo $ac_n "checking whether st_flags field is useful""... $ac_c" 1>&6 -echo "configure:4591: checking whether st_flags field is useful" >&5 +echo "configure:4612: checking whether st_flags field is useful" >&5 if eval "test \"`echo '$''{'e2fsprogs_cv_struct_st_flags_immut'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { struct stat stat; stat.st_flags |= UF_IMMUTABLE; ; return 0; } EOF -if { (eval echo configure:4603: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:4624: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* e2fsprogs_cv_struct_st_flags_immut=yes else @@ -4622,12 +4643,12 @@ fi for ac_func in chflags getrusage llseek lseek64 open64 getmntinfo strcasecmp srandom fchown mallinfo fdatasync strnlen sysconf do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:4626: checking for $ac_func" >&5 +echo "configure:4647: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4675: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -4676,7 +4697,7 @@ done SOCKET_LIB='' echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6 -echo "configure:4680: checking for socket in -lsocket" >&5 +echo "configure:4701: checking for socket in -lsocket" >&5 ac_lib_var=`echo socket'_'socket | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -4684,7 +4705,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lsocket $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4720: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -4717,12 +4738,12 @@ fi echo $ac_n "checking for optreset""... $ac_c" 1>&6 -echo "configure:4721: checking for optreset" >&5 +echo "configure:4742: checking for optreset" >&5 if eval "test \"`echo '$''{'ac_cv_have_optreset'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF @@ -4794,20 +4815,20 @@ fi echo $ac_n "checking whether linker accepts -static""... $ac_c" 1>&6 -echo "configure:4798: checking whether linker accepts -static" >&5 +echo "configure:4819: checking whether linker accepts -static" >&5 if eval "test \"`echo '$''{'ac_cv_e2fsprogs_use_static'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else SAVE_LDFLAGS=$LDFLAGS; LDFLAGS="$LDFLAGS -static" cat > conftest.$ac_ext < int main() { fflush(stdout); ; return 0; } EOF -if { (eval echo configure:4811: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4832: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_e2fsprogs_use_static=yes else @@ -4964,6 +4985,7 @@ ac_given_INSTALL="$INSTALL" trap 'rm -fr `echo "MCONFIG Makefile util/Makefile util/subst.conf lib/et/Makefile lib/ss/Makefile lib/ext2fs/Makefile lib/e2p/Makefile lib/uuid/Makefile + lib/evms/Makefile misc/Makefile ext2ed/Makefile e2fsck/Makefile debugfs/Makefile \ tests/Makefile tests/progs/Makefile $rmakefile doc/Makefile intl/Makefile po/Makefile.in" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 @@ -5143,6 +5165,7 @@ cat >> $CONFIG_STATUS < /* will pull in platform specific data type info from linux/include/asm */ + +/* Need these to satisfy dependencies in evms_user.h + * on systems running a 2.5.8 or newer kernel. + */ +typedef __u8 u8; +typedef __u16 u16; +typedef __u32 u32; +typedef __u64 u64; + +#include + +/* Defines for storage object names */ +#define EVMS_NAME_SIZE EVMS_VOLUME_NAME_SIZE + +/* Defines for the flags in the storage_object_t structure */ +#define SOFLAG_DIRTY (1<<0) +#define SOFLAG_NEW (1<<1) +#define SOFLAG_READ_ONLY (1<<2) +#define SOFLAG_FEATURE_HEADER_DIRTY (1<<3) +#define SOFLAG_MUST_BE_TOP (1<<4) +#define SOFLAG_IO_ERROR (1<<5) +#define SOFLAG_CORRUPT (1<<6) +#define SOFLAG_BIOS_READABLE (1<<7) +#define SOFLAG_MUST_BE_VOLUME (1<<8) +#define SOFLAG_NOT_CLAIMED (1<<9) + +/* Defines for flags in the storage_container_t structure */ +#define SCFLAG_DIRTY (1<<0) +#define SCFLAG_NEW (1<<1) + +/* Defines for the flags in the logical_volume_t structure */ +#define VOLFLAG_DIRTY (1<<0) +#define VOLFLAG_NEW (1<<1) +#define VOLFLAG_READ_ONLY (1<<2) +#define VOLFLAG_NEEDS_DEV_NODE (1<<3) +#define VOLFLAG_COMPATIBILITY (1<<4) +#define VOLFLAG_FOREIGN (1<<5) +#define VOLFLAG_MKFS (1<<6) +#define VOLFLAG_UNMKFS (1<<7) +#define VOLFLAG_FSCK (1<<8) +#define VOLFLAG_DEFRAG (1<<9) +#define VOLFLAG_EXPAND_FS (1<<10) +#define VOLFLAG_SHRINK_FS (1<<11) +#define VOLFLAG_SYNC_FS (1<<12) + +/* A BOOLEAN variable is one which is either TRUE or FALSE. */ +#ifndef BOOLEAN_DEFINED + #define BOOLEAN_DEFINED 1 + typedef u_int8_t BOOLEAN; +#endif + +#ifndef TRUE + #define TRUE 1 +#endif +#ifndef FALSE + #define FALSE 0 +#endif + +/* + * Logical Sector Number: This is a physical sector address on a + * system drive. + */ +typedef u_int64_t lsn_t; + +/* + * Logical Block Address: This is a sector address on a volume which + * will be translated to a Logical Sector Number. + */ +typedef u_int64_t lba_t; + +/* + * A sector_count_t is a count of sectors. It is mainly used to hold the size + * of a disk, segment, region, etc. + */ +typedef u_int64_t sector_count_t; + +/* + * A module_handle_t variable is one which holds a handle (or descriptor) + * referencing a loaded module. + */ +typedef void * module_handle_t; + +/* + * The standard data type for Engine handles. + */ +typedef u_int32_t engine_handle_t; + +/* + * An object_handle_t holds a handle for an EVMS Engine object. + */ +typedef engine_handle_t object_handle_t; + +/* + * A plugin_handle_t holds a handle for an EVMS Engine plug-in. + */ +typedef engine_handle_t plugin_handle_t; + +/* + * A plugin_ID_t holds a unique ID for a plug-in. + */ +typedef u_int32_t plugin_id_t; + +/* + * A plugin_type_t holds the type field of a plug-in's ID. + */ +typedef u_int8_t plugin_type_t; + +/* + * The various modes in which the Engine can be. + */ +typedef enum { + ENGINE_CLOSED = 0, + ENGINE_READONLY, + ENGINE_READWRITE +} engine_mode_t; + +/* + * The geometry of a disk, segment, region, etc. + */ +typedef struct geometry_s { + u_int64_t cylinders; + u_int32_t heads; + u_int32_t sectors_per_track; + u_int32_t bytes_per_sector; + u_int64_t boot_cylinder_limit; + u_int64_t block_size; +} geometry_t; + +/* + * The data types which a storage object can be. + */ +typedef enum { + META_DATA_TYPE = (1<<0), + DATA_TYPE = (1<<1), + FREE_SPACE_TYPE = (1<<2) +} data_type_t; + +/* + * The types of structures the Engine exports + */ +typedef enum { + PLUGIN = (1<<0), + DISK = (1<<1), + SEGMENT = (1<<2), + REGION = (1<<3), + EVMS_OBJECT = (1<<4), + CONTAINER = (1<<5), + VOLUME = (1<<6) +} object_type_t; + +/* + * Flags that can be used for filtering plug-ins on the evms_get_plugin_list API + */ +typedef enum { + SUPPORTS_CONTAINERS = (1<<0) +} plugin_search_flags_t; + +/* + * Flags that can be used for filtering objects on the evms_get_object_list API + */ +typedef enum { + TOPMOST = (1<<0), + NOT_MUST_BE_TOP = (1<<1), + WRITEABLE = (1<<2) +} object_search_flags_t; + +#define VALID_INPUT_OBJECT (TOPMOST | NOT_MUST_BE_TOP | WRITEABLE) + +/* + * Debug levels + * These levels should be kept in sync with the debug levels defined for the + * EVMS kernel in linux/evms/evms.h. + */ +typedef enum { + /* + * Use CRITICAL for messages that indicate that the health of the + * system/Engine is in jeopardy. Something _really_ bad happened, + * such as failure to allocate memory or control structures are + * corrupted. + */ + CRITICAL = 0, + + /* + * Use SERIOUS for messages that something bad has happened, but not + * as bad a CRITICAL. + */ + SERIOUS = 1, + + /* + * Use ERROR for messages that indicate the user caused an error, + * such as passing a bad parameter. The message should help the + * user correct the problem. + */ + ERROR = 2, + + /* + * Use WARNING for messages that indicate that something is not quite + * right and the user should know about it. You may or may not be able + * to work around the problem. + */ + WARNING = 3, + + /* + * Use DEFAULT for informational messages that do not indicate problems, or + * that a problem occurred but there was a work-around. DEFAULT messages + * should be things that the user would usually want to know during any run + * of the Engine, such as how many volumes were discovered on the system, + * and not necessarily what a developer would want to know (use DETAILS or + * DEBUG for that). Since DEFAULT is the default debug level, be careful + * not to put DEFAULT messages in loops or frequently executed code as they + * will bloat the log file. + */ + DEFAULT = 5, + + /* + * Use DETAILS to provide more detailed information about the system. The + * message may provide additional information about the progress of the + * system. It may contain more information about a DEFAULT message or more + * information about an error condition. + */ + DETAILS = 6, + + /* + * Use DEBUG for messages that would help debug a problem, such as tracing + * code paths or dumping the contents of variables. + */ + DEBUG = 7, + + /* + * Use EXTRA to provided more information than your standard debug messages + * provide. + */ + + EXTRA = 8, + + /* + * Use ENTRY_EXIT to trace entries and exits from functions. + */ + ENTRY_EXIT = 9, + + /* + * Use EVERYTHING for all manner of verbose output. Feel free to bloat the + * log file with any messages that would help you debug a problem. + */ + EVERYTHING = 10 + +} debug_level_t; + + +/* + * Handy macros for finding the min and max of two numbers. + */ +#ifndef min + #define min(a,b) (((a)<(b))?(a):(b)) +#endif +#ifndef max + #define max(a,b) (((a)>(b))?(a):(b)) +#endif + + +#endif + diff --git a/lib/evms/dlist.h b/lib/evms/dlist.h new file mode 100644 index 00000000..fd20a72a --- /dev/null +++ b/lib/evms/dlist.h @@ -0,0 +1,2357 @@ +/* + * + * Copyright (c) International Business Machines Corp., 2000 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Module: dlist.h + * + * Functions: dlist_t CreateList + * int InsertItem + * int InsertObject + * int DeleteItem + * int DeleteAllItems + * int GetItem + * int GetNextItem + * int GetPreviousItem + * int GetObject + * int BlindGetObject + * int GetNextObject + * int GetPreviousObject + * int ExtractItem + * int ExtractObject + * int BlindExtractObject + * int ReplaceItem + * int ReplaceObject + * int GetTag + * int GetHandle + * int GetListSize + * BOOLEAN ListEmpty + * BOOLEAN AtEndOfList + * BOOLEAN AtStartOfList + * int DestroyList + * int NextItem + * int PreviousItem + * int GoToStartOfList + * int GoToEndOfList + * int GoToSpecifiedItem + * int SortList + * int ForEachItem + * int PruneList + * int AppendList + * int TransferItem + * int CopyList + * BOOLEAN CheckListIntegrity + * + * Description: This module implements a simple, generic, doubly linked list. + * Data objects of any type can be placed into a linked list + * created by this module. Furthermore, data objects of different + * types may be placed into the same linked list. + * + * Notes: This linked list implementation makes use of the concept of the + * current item. In any non-empty list, one item in the list will + * be designated as the current item. When any of the following + * functions are called, they will operate upon the current item + * only: GetItem, ReplaceItem, DeleteItem, GetTag, NextItem, + * PreviousItem, GetObject, ExtractItem, and ExtractObject. The + * user of this module may set the current item through the use of + * the GoToStartOfList, GoToEndOfList, NextItem, PreviousItem, + * and GoToSpecifiedItem functions. + * + * Since a linked list created by this module may contain items + * of different types, the user will need a way to identify items + * of different types which may be in the same list. To allow users + * to do this, the concept of an item tag is used. When an item is + * added to the list, the user must enter an item tag. The item + * tag is merely some identifier that the user wishes to associate + * with the item being placed into the list. When used as intended, + * each type of data item will have a unique tag associated with it. + * This way, all data items of the same type will have the same tag + * while data items of different types will have different tags. + * Thus, by using the GetTag function, the user can get the item + * tag for the current item without having to get the item from the + * list. This allows the user to differentiate between items of + * different types which reside in the same list. + * + * This module is single threaded. If used in a multi-threaded + * environment, the user must implement appropriate access controls. + * + * When an item is inserted or appended to a list, this module + * allocates memory on the heap to hold the item and then copies + * the item to the memory that it allocated. This allows local + * variables to be safely inserted or appended to a list. However, + * it should be noted that under certain circumstances a copy of the + * entire data item will NOT be made. Specifically, if the data item + * is a structure or array containing pointers, then the data pointed + * to by the pointers will NOT be copied even though the structure or + * array is! This results from the fact that, when an item is being + * inserted or appended to a list, the user provides just an address + * and size. This module assumes that the item to inserted or append + * lies in a contiguous block of memory at the address provided by the + * user. This module has no way of knowing the structure of the data + * at the specified address, and therefore can not know about any + * embedded pointers which may lie within that block of memory. + * + * This module now employs the concept of a handle. A handle is a + * reference to a specific item in a list which allows that item to + * be made the current item in the list quickly. Example: If you + * use the GetHandle function to get a handle for the current item + * (lets call the item B1), then, regardless of where you are in the + * list (or any reodering of the items in the list), you can make item + * B1 the current item by passing its handle to the GoToSpecifiedItem + * function. Alternatively, you could operate directly on B1 using + * the other handle based functions, such as GetItem_By_Handle, for + * example. GetItem_By_Handle gets the item associated with the + * specified handle without changing which item in the list is the + * current item in the list. + * + * The functions of this module refer to user data as either items or + * objects. The difference between the two is simple, yet subtle. It + * deals with who is responsible for the memory used to hold the data. + * In the case of an item, this module is responsible for the memory + * used to hold the user data. In the case of an object, the user + * is responsible for the memory used to hold the data. + * + * What this means is that, for functions adding ITEMS to a list, + * this module will be responsible for allocating memory to hold + * the user data and then copying the user data into the memory + * that was allocated. For functions which return items, this + * module will COPY the user data from the LIST into a buffer + * specified by the user. For functions which add objects to a + * list, the user provides a pointer to a block of memory holding + * user data. This block of memory was allocated by the user, and + * becomes the "property" of this module once it has been added to + * a LIST. For functions which return objects, a pointer to the + * memory where the data is stored is returned. As long as an item/object + * is in a LIST, this module will be responsible for the memory that + * is used to store the data associated with that item. This means that + * users of this module should not call free on an object returned by this + * module as long as that object is still within a list. + * + * + */ + +#ifndef DLISTHANDLER + +#define DLISTHANDLER 1 + +#include /* will pull in platform specific data type info from linux/include/asm */ +#include + +#ifndef BOOLEAN_DEFINED + #define BOOLEAN_DEFINED 1 + typedef u_int8_t BOOLEAN; +#endif + +typedef void * ADDRESS; +typedef ulong TAG; + +struct LinkNodeRecord +{ + ADDRESS DataLocation; /* Where the data associated with this LinkNode is */ + uint DataSize; /* The size of the data associated with this LinkNode. */ + TAG DataTag; /* The item tag the user gave to the data. */ + struct MasterListRecord * ControlNodeLocation; /* The control node of the list containing this item. */ + struct LinkNodeRecord * NextLinkNode; /* The LinkNode of the next item in the list. */ + struct LinkNodeRecord * PreviousLinkNode; /* The LinkNode of the item preceding this one in the list. */ +}; + +typedef struct LinkNodeRecord LinkNode; + +struct MasterListRecord +{ + uint ItemCount; /* The number of items in the list. */ + LinkNode * StartOfList; /* The address of the LinkNode of the first item in the list. */ + LinkNode * EndOfList; /* The address of the LinkNode of the last item in the list. */ + LinkNode * CurrentItem; /* The address of the LinkNode of the current item in the list. */ +#ifdef USE_POOLMAN + POOL NodePool; /* The pool of LinkNodes for this dlist_t. */ +#endif + uint Verify; /* A field to contain the VerifyValue which marks this as a list created by this module. */ +}; + +typedef struct MasterListRecord ControlNode; + + +typedef ControlNode * dlist_t; + + +#ifndef TRUE + #define TRUE 1 +#endif +#ifndef FALSE + #define FALSE 0 +#endif + + +typedef enum _Insertion_Modes { + InsertAtStart, + InsertBefore, + InsertAfter, + AppendToList, + } Insertion_Modes; + +/* Update the IS_DLIST_ERROR() macro below if you add, remove, or change */ +/* error codes. */ + +#define DLIST_SUCCESS 0 +#define DLIST_OUT_OF_MEMORY ENOMEM + +#define DLIST_CORRUPTED 201 +#define DLIST_BAD 202 +#define DLIST_NOT_INITIALIZED 203 +#define DLIST_EMPTY 204 +#define DLIST_ITEM_SIZE_WRONG 205 +#define DLIST_BAD_ITEM_POINTER 206 +#define DLIST_ITEM_SIZE_ZERO 207 +#define DLIST_ITEM_TAG_WRONG 208 +#define DLIST_END_OF_LIST 209 +#define DLIST_ALREADY_AT_START 210 +#define DLIST_BAD_HANDLE 211 +#define DLIST_INVALID_INSERTION_MODE 212 +#define DLIST_OBJECT_NOT_FOUND 213 +#define DLIST_OBJECT_ALREADY_IN_LIST 214 + +/* Macro to determine if an error code is a dlist error code. */ + +#define IS_DLIST_ERROR(rc) ((abs(rc) >= DLIST_CORRUPTED) && (abs(rc) <= DLIST_OBJECT_ALREADY_IN_LIST)) + +/* The following code is special. It is for use with the PruneList and ForEachItem functions. Basically, these functions + can be thought of as "searching" a list. They present each item in the list to a user supplied function which can then + operate on the items. If the user supplied function returns a non-zero error code, ForEachItem and PruneList abort and + return an error to the caller. This may be undesirable. If the user supplied function used with PruneList and ForEachItem + returns the code below, PruneList/ForEachItem will abort and return DLIST_SUCCESS. This allows PruneList and ForEachItem + to be used to search a list and terminate the search when the desired item is found without having to traverse the + remaining items in the list. */ + +#define DLIST_SEARCH_COMPLETE 0xFF + +#ifdef USE_POOLMAN + + +/*********************************************************************/ +/* */ +/* Function Name: CreateList */ +/* */ +/* Descriptive Name: This function allocates and initializes the */ +/* data structures associated with a list and */ +/* then returns a pointer to these structures. */ +/* */ +/* Input: uint InitialPoolSize - Each List gets a pool of */ +/* link nodes. When items are */ +/* added to the List, a link node*/ +/* is removed from the pool. */ +/* When an item is removed from */ +/* the List, the link node used */ +/* for that item is returned to */ +/* the pool. InitialPoolSize is */ +/* the number of link nodes to */ +/* place in the pool when the */ +/* pool is created. */ +/* uint MaximumPoolSize - When the pool runs out of */ +/* link nodes, new nodes are */ +/* allocated by the pool. When */ +/* these links start being */ +/* returned to the pool, the pool*/ +/* will grow. This parameter */ +/* puts a limit on how big the */ +/* pool may grow to. Once the */ +/* pool reaches this size, any */ +/* link nodes being returned to */ +/* the pool will be deallocated. */ +/* uint PoolIncrement - When the pool runs out of link*/ +/* nodes and more are required, */ +/* the pool will allocate one or */ +/* more link nodes. This tells the*/ +/* pool how many link nodes to */ +/* allocate at one time. */ +/* */ +/* Output: If Success : The function return value will be non-NULL */ +/* */ +/* If Failure : The function return value will be NULL. */ +/* */ +/* Error Handling: The function will only fail if it can not */ +/* allocate enough memory to create the new list */ +/* and its associated pool of link nodes. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: None. */ +/* */ +/*********************************************************************/ +dlist_t CreateList(uint InitialPoolSize, + uint MaximumPoolSize, + uint PoolIncrement); + +#else + + +/*********************************************************************/ +/* */ +/* Function Name: CreateList */ +/* */ +/* Descriptive Name: This function allocates and initializes the */ +/* data structures associated with a list and */ +/* then returns a pointer to these structures. */ +/* */ +/* Input: None. */ +/* */ +/* Output: If Success : The function return value will be non-NULL */ +/* */ +/* If Failure : The function return value will be NULL. */ +/* */ +/* Error Handling: The function will only fail if it can not */ +/* allocate enough memory to create the new list. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: None. */ +/* */ +/*********************************************************************/ +dlist_t CreateList( void ); + +#endif + + +/*********************************************************************/ +/* */ +/* Function Name: InsertItem */ +/* */ +/* Descriptive Name: This function inserts an item into a dlist_t.*/ +/* The item can be placed either before or */ +/* after the current item in the dlist_t. */ +/* */ +/* Input: dlist_t ListToAddTo : The list to which the */ +/* data item is to be */ +/* added. */ +/* uint ItemSize : The size of the data item, in */ +/* bytes. */ +/* ADDRESS ItemLocation : The address of the data */ +/* to append to the list */ +/* TAG ItemTag : The item tag to associate with */ +/* item being appended to the list */ +/* ADDRESS TargetHandle : The item in ListToAddTo which */ +/* is used to determine where */ +/* the item being transferred will */ +/* be placed. If this is NULL, */ +/* then the current item in */ +/* ListToAddTo will be used. */ +/* Insertion_Modes InsertMode : This indicates where, */ +/* relative to the item in */ +/* ListToAddTo specified by */ +/* Target_Handle, the item being */ +/* inserted can be placed. */ +/* BOOLEAN MakeCurrent : If TRUE, the item being inserted */ +/* into ListToAddTo becomes the */ +/* current item in ListToAddTo. */ +/* ADDRESS * Handle : The address of a variable to hold */ +/* the handle for the item that was */ +/* inserted into the list. */ +/* */ +/* Output: If all went well, the return value will be */ +/* DLIST_SUCCESS and *Handle will contain the ADDRESS of */ +/* the new item. If errors were encountered, the . */ +/* return value will be the error code and *Handle will */ +/* be NULL. */ +/* */ +/* Error Handling: This function will fail under the following */ +/* conditions: */ +/* ListToAddTo does not point to a valid */ +/* list */ +/* ItemSize is 0 */ +/* ItemLocation is NULL */ +/* The memory required to hold a copy of the */ +/* item can not be allocated. */ +/* The memory required to create a LINK NODE */ +/* can not be allocated. */ +/* TargetHandle is invalid or is for an item */ +/* in another list. */ +/* If this routine fails, an error code is returned*/ +/* and any memory allocated by this function is */ +/* freed. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: The item to add is copied to the heap to */ +/* avoid possible conflicts with the usage of */ +/* local variables in functions which process */ +/* dlist_ts. However, a pointer to a local variable */ +/* should not be appended to the dlist_t. */ +/* */ +/* It is assumed that TargetHandle is valid, or is at least*/ +/* the address of an accessible block of storage. If */ +/* TargetHandle is invalid, or is not the address of an */ +/* accessible block of storage, then a trap or exception */ +/* may occur. */ +/* */ +/* It is assumed that if ItemLocation is not NULL, then */ +/* it is a valid address that can be dereferenced. If */ +/* this assumption is violated, an exception or trap may */ +/* occur. */ +/* */ +/*********************************************************************/ +int InsertItem (dlist_t ListToAddTo, + uint ItemSize, + ADDRESS ItemLocation, + TAG ItemTag, + ADDRESS TargetHandle, + Insertion_Modes Insert_Mode, + BOOLEAN MakeCurrent, + ADDRESS * Handle); + + + +/*********************************************************************/ +/* */ +/* Function Name: InsertObject */ +/* */ +/* Descriptive Name: This function inserts an object into a */ +/* dlist_t. The object can be inserted before */ +/* or after the current item in the list. */ +/* */ +/* Input: dlist_t ListToAddTo : The list to which the */ +/* data object is to be */ +/* inserted. */ +/* uint ItemSize : The size of the data item, in */ +/* bytes. */ +/* ADDRESS ItemLocation : The address of the data */ +/* to append to the list */ +/* TAG ItemTag : The item tag to associate with */ +/* the item being appended to the */ +/* list */ +/* ADDRESS TargetHandle : The item in ListToAddTo which */ +/* is used to determine where */ +/* the item being transferred will */ +/* be placed. If this is NULL, */ +/* then the current item in */ +/* ListToAddTo will be used. */ +/* Insertion_Modes Insert_Mode : This indicates where, */ +/* relative to the item in */ +/* ListToAddTo specified by */ +/* Target_Handle, the item being */ +/* inserted can be placed. */ +/* BOOLEAN MakeCurrent : If TRUE, the item being inserted */ +/* into ListToAddTo becomes the */ +/* current item in ListToAddTo. */ +/* ADDRESS * Handle : The address of a variable to hold */ +/* the handle for the item that was */ +/* inserted into the list. */ +/* */ +/* Output: If all went well, the return value will be */ +/* DLIST_SUCCESS and *Handle will contain the ADDRESS of */ +/* the new item. If errors were encountered, the . */ +/* return value will be the error code and *Handle will */ +/* be NULL. */ +/* */ +/* Error Handling: This function will fail under the following */ +/* conditions: */ +/* ListToAddTo does not point to a valid */ +/* list */ +/* ItemSize is 0 */ +/* ItemLocation is NULL */ +/* The memory required for a LINK NODE can not */ +/* be allocated. */ +/* TargetHandle is invalid or is for an item */ +/* in another list. */ +/* If this routine fails, an error code is returned*/ +/* and any memory allocated by this function is */ +/* freed. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: The item to insert is NOT copied to the heap. Instead, */ +/* the location of the item is stored in the list. This */ +/* is the major difference between InsertObject and */ +/* InsertItem. InsertItem allocates memory on the heap, */ +/* copies the item to the memory it allocated, and stores */ +/* the address of the memory it allocated in the list. */ +/* InsertObject stores the address provided by the user. */ +/* */ +/* It is assumed that TargetHandle is valid, or is at least*/ +/* the address of an accessible block of storage. If */ +/* TargetHandle is invalid, or is not the address of an */ +/* accessible block of storage, then a trap or exception */ +/* may occur. */ +/* */ +/* It is assumed that if ItemLocation is not NULL, then */ +/* it is a valid address that can be dereferenced. If */ +/* this assumption is violated, an exception or trap may */ +/* occur. */ +/* */ +/*********************************************************************/ +int InsertObject (dlist_t ListToAddTo, + uint ItemSize, + ADDRESS ItemLocation, + TAG ItemTag, + ADDRESS TargetHandle, + Insertion_Modes Insert_Mode, + BOOLEAN MakeCurrent, + ADDRESS * Handle); + + +/*********************************************************************/ +/* */ +/* Function Name: ExclusiveInsertObject */ +/* */ +/* Descriptive Name: This function inserts an object into a */ +/* dlist_t. The object can be inserted before */ +/* or after the current item in the list. If */ +/* object is already in the list, it is not */ +/* added again. */ +/* */ +/* Input: dlist_t ListToAddTo : The list to which the */ +/* data object is to be */ +/* inserted. */ +/* uint ItemSize : The size of the data item, in */ +/* bytes. */ +/* ADDRESS ItemLocation : The address of the data */ +/* to append to the list */ +/* TAG ItemTag : The item tag to associate with */ +/* the item being appended to the */ +/* list */ +/* ADDRESS TargetHandle : The item in ListToAddTo which */ +/* is used to determine where */ +/* the item being transferred will */ +/* be placed. If this is NULL, */ +/* then the current item in */ +/* ListToAddTo will be used. */ +/* Insertion_Modes Insert_Mode : This indicates where, */ +/* relative to the item in */ +/* ListToAddTo specified by */ +/* Target_Handle, the item being */ +/* inserted can be placed. */ +/* BOOLEAN MakeCurrent : If TRUE, the item being inserted */ +/* into ListToAddTo becomes the */ +/* current item in ListToAddTo. */ +/* ADDRESS * Handle : The address of a variable to hold */ +/* the handle for the item that was */ +/* inserted into the list. */ +/* */ +/* Output: If all went well, the return value will be */ +/* DLIST_SUCCESS and *Handle will contain the ADDRESS of */ +/* the new item. If errors were encountered, the . */ +/* return value will be the error code and *Handle will */ +/* be NULL. */ +/* */ +/* Error Handling: This function will fail under the following */ +/* conditions: */ +/* ListToAddTo does not point to a valid */ +/* list */ +/* ItemSize is 0 */ +/* ItemLocation is NULL */ +/* The memory required for a LINK NODE can not */ +/* be allocated. */ +/* TargetHandle is invalid or is for an item */ +/* in another list. */ +/* If this routine fails, an error code is returned*/ +/* and any memory allocated by this function is */ +/* freed. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: The item to insert is NOT copied to the heap. Instead, */ +/* the location of the item is stored in the list. This */ +/* is the major difference between InsertObject and */ +/* InsertItem. InsertItem allocates memory on the heap, */ +/* copies the item to the memory it allocated, and stores */ +/* the address of the memory it allocated in the list. */ +/* InsertObject stores the address provided by the user. */ +/* */ +/* It is assumed that TargetHandle is valid, or is at least*/ +/* the address of an accessible block of storage. If */ +/* TargetHandle is invalid, or is not the address of an */ +/* accessible block of storage, then a trap or exception */ +/* may occur. */ +/* */ +/* It is assumed that if ItemLocation is not NULL, then */ +/* it is a valid address that can be dereferenced. If */ +/* this assumption is violated, an exception or trap may */ +/* occur. */ +/* */ +/*********************************************************************/ +int ExclusiveInsertObject (dlist_t ListToAddTo, + uint ItemSize, + ADDRESS ItemLocation, + TAG ItemTag, + ADDRESS TargetHandle, + Insertion_Modes Insert_Mode, + BOOLEAN MakeCurrent, + ADDRESS * Handle); + + +/*********************************************************************/ +/* */ +/* Function Name: DeleteItem */ +/* */ +/* Descriptive Name: This function removes the specified item from*/ +/* the list and optionally frees the memory */ +/* associated with it. */ +/* */ +/* Input: dlist_t ListToDeleteFrom : The list whose current */ +/* item is to be deleted. */ +/* BOOLEAN FreeMemory : If TRUE, then the memory */ +/* associated with the current */ +/* item will be freed. If FALSE */ +/* then the current item will be */ +/* removed from the list but its */ +/* memory will not be freed. */ +/* ADDRESS Handle : The handle of the item to get. This */ +/* handle must be of an item which resides*/ +/* in ListToDeleteFrom, or NULL. If */ +/* NULL is used, then the current item */ +/* in ListToDeleteFrom will be deleted. */ +/* */ +/* Output: Return DLIST_SUCCESS if successful, else an error code.*/ +/* */ +/* Error Handling: This function will fail if ListToDeleteFrom is */ +/* not a valid list, or if ListToDeleteFrom is */ +/* empty, or if Handle is invalid. */ +/* If this routine fails, an error code is */ +/* returned. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: Items in a list can be accessed in two ways: A copy of */ +/* the item can be obtained using GetItem and its related */ +/* calls, or a pointer to the item can be obtained using */ +/* GetObject and its related calls. If you have a copy of */ +/* the data and wish to remove the item from the list, set */ +/* FreeMemory to TRUE. This will remove the item from the */ +/* list and deallocate the memory used to hold it. If you */ +/* have a pointer to the item in the list (from one of the */ +/* GetObject style functions) and wish to remove the item */ +/* from the list, set FreeMemory to FALSE. This removes */ +/* the item from the list without freeing its memory, so */ +/* that the pointer obtained with the GetObject style */ +/* functions is still useable. */ +/* */ +/* It is assumed that Handle is valid, or is at least the */ +/* address of an accessible block of storage. If Handle */ +/* is invalid, or is not the address of an accessible block*/ +/* of storage, then a trap or exception may occur. */ +/* */ +/* This function does not alter which item is the current */ +/* item in the list, unless the handle specified belongs */ +/* to the current item in the list, in which case this */ +/* function behaves the same as DeleteItem. */ +/* */ +/*********************************************************************/ +int DeleteItem (dlist_t ListToDeleteFrom, + BOOLEAN FreeMemory, + ADDRESS Handle); + + +/*********************************************************************/ +/* */ +/* Function Name: DeleteAllItems */ +/* */ +/* Descriptive Name: This function deletes all of the items in the*/ +/* specified list and optionally frees the */ +/* memory associated with each item deleted. */ +/* */ +/* Input: dlist_t ListToDeleteFrom : The list whose items */ +/* are to be deleted. */ +/* BOOLEAN FreeMemory : If TRUE, then the memory */ +/* associated with each item in the*/ +/* list will be freed. If FALSE */ +/* then the each item will be */ +/* removed from the list but its */ +/* memory will not be freed. */ +/* */ +/* Output: Return DLIST_SUCCESS if successful, else an error code.*/ +/* */ +/* Error Handling: This function will fail if ListToDeleteFrom is */ +/* not a valid list, or if ListToDeleteFrom is */ +/* empty. */ +/* If this routine fails, an error code is */ +/* returned. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: Items in a list can be accessed in two ways: A copy of */ +/* the item can be obtained using GetItem and its related */ +/* calls, or a pointer to the item can be obtained using */ +/* GetObject and its related calls. If you have a copy of */ +/* the data and wish to remove the item from the list, set */ +/* FreeMemory to TRUE. This will remove the item from the */ +/* list and deallocate the memory used to hold it. If you */ +/* have a pointer to the item in the list (from one of the */ +/* GetObject style functions) and wish to remove the item */ +/* from the list, set FreeMemory to FALSE. This removes */ +/* the item from the list without freeing its memory, so */ +/* that the pointer obtained with the GetObject style */ +/* functions is still useable. */ +/* */ +/*********************************************************************/ +int DeleteAllItems (dlist_t ListToDeleteFrom, + BOOLEAN FreeMemory); + + +/*********************************************************************/ +/* */ +/* Function Name: DeleteObject */ +/* */ +/* Descriptive Name: This function removes the specified object */ +/* from the list. */ +/* */ +/* Input: dlist_t ListToDeleteFrom : The list whose current */ +/* item is to be deleted. */ +/* ADDRESS Object : The address of the object to be removed*/ +/* from the list. */ +/* */ +/* Output: Return DLIST_SUCCESS if successful, else an error code.*/ +/* */ +/* Error Handling: This function will fail if ListToDeleteFrom is */ +/* not a valid list, or if ListToDeleteFrom is */ +/* empty, or if Handle is invalid. */ +/* If this routine fails, an error code is */ +/* returned. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: This function does not alter which item is the current */ +/* item in the list, unless the handle specified belongs */ +/* to the current item in the list, in which case this */ +/* function behaves the same as DeleteItem. */ +/* */ +/*********************************************************************/ +int DeleteObject (dlist_t ListToDeleteFrom, + ADDRESS Object); + + +/*********************************************************************/ +/* */ +/* Function Name: GetItem */ +/* */ +/* Descriptive Name: This function copies the specified item in */ +/* the list to a buffer provided by the caller. */ +/* */ +/* Input: dlist_t ListToGetItemFrom : The list whose current item */ +/* is to be copied and returned*/ +/* to the caller. */ +/* uint ItemSize : What the caller thinks the size of*/ +/* the current item is. */ +/* ADDRESS ItemLocation : This is the location of the */ +/* buffer into which the current*/ +/* item is to be copied. */ +/* TAG ItemTag : What the caller thinks the item tag */ +/* of the current item is. */ +/* ADDRESS Handle : The handle of the item to get. This */ +/* handle must be of an item which resides*/ +/* in ListToGetItemFrom, or NULL. If */ +/* NULL, then the current item in the list*/ +/* will be used. */ +/* BOOLEAN MakeCurrent : If TRUE, the item to get will */ +/* become the current item in the */ +/* list. */ +/* */ +/* Output: If Successful : */ +/* Return DLIST_SUCCESS. */ +/* The buffer at ItemLocation will contain a copy of */ +/* the current item from ListToGetItemFrom. */ +/* If Failure : */ +/* Return an error code. */ +/* */ +/* */ +/* Error Handling: This function will fail under any of the */ +/* following conditions: */ +/* ListToGetItemFrom is not a valid list */ +/* ItemSize does not match the size of the */ +/* current item in the list */ +/* ItemLocation is NULL */ +/* ItemTag does not match the item tag */ +/* of the current item in the list */ +/* Handle is invalid, or is for an item */ +/* which is not in ListToGetItemFrom */ +/* If any of these conditions occur, an error code */ +/* will be returned. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: It is assumed that if ItemLocation is not NULL, then */ +/* it is a valid address that can be dereferenced. If */ +/* this assumption is violated, an exception or trap may */ +/* occur. */ +/* */ +/* It is assumed that Handle is valid, or is at least the */ +/* address of an accessible block of storage. If Handle */ +/* is invalid, or is not the address of an accessible block*/ +/* of storage, then a trap or exception may occur. */ +/* NOTE: For this function, NULL is considered a valid */ +/* handle corresponding to the current item in the */ +/* list. */ +/* */ +/* This function does not alter which item is the current */ +/* item in the list. */ +/* */ +/*********************************************************************/ +int GetItem( dlist_t ListToGetItemFrom, + uint ItemSize, + ADDRESS ItemLocation, + TAG ItemTag, + ADDRESS Handle, + BOOLEAN MakeCurrent); + + +/*********************************************************************/ +/* */ +/* Function Name: GetNextItem */ +/* */ +/* Descriptive Name: This function advances the current item */ +/* pointer and then copies the current item in */ +/* the list to a buffer provided by the caller. */ +/* */ +/* Input: dlist_t ListToGetItemFrom : The list whose current item */ +/* is to be copied and returned*/ +/* to the caller. */ +/* uint ItemSize : What the caller thinks the size of*/ +/* the current item is. */ +/* ADDRESS ItemLocation : This is the location of the */ +/* buffer into which the current*/ +/* item is to be copied. */ +/* TAG ItemTag : What the caller thinks the item tag */ +/* of the current item is. */ +/* */ +/* Output: If Successful : */ +/* Return DLIST_SUCCESS. */ +/* The buffer at ItemLocation will contain a copy of */ +/* the current item from ListToGetItemFrom. */ +/* If Failure : */ +/* Return an error code. */ +/* The current item pointer will NOT be advanced. */ +/* The current item in the list will be the same */ +/* as before the call to this function. */ +/* */ +/* Error Handling: This function will fail under any of the */ +/* following conditions: */ +/* ListToGetItemFrom is not a valid list */ +/* ItemSize does not match the size of the */ +/* current item in the list */ +/* ItemLocation is NULL */ +/* ItemTag does not match the item tag */ +/* of the current item in the list */ +/* The current item in the list before this */ +/* function is called is the last item */ +/* item in the list. */ +/* If any of these conditions occur, an error */ +/* code will be returned. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: It is assumed that if ItemLocation is not NULL, then */ +/* it is a valid address that can be dereferenced. If */ +/* this assumption is violated, an exception or trap may */ +/* occur. */ +/* */ +/*********************************************************************/ +int GetNextItem(dlist_t ListToGetItemFrom, + uint ItemSize, + ADDRESS ItemLocation, + TAG ItemTag); + + +/*********************************************************************/ +/* */ +/* Function Name: GetPreviousItem */ +/* */ +/* Descriptive Name: This function makes the previous item in the */ +/* list the current item in the list and then */ +/* copies that item to a buffer provided by the */ +/* user. */ +/* */ +/* Input: dlist_t ListToGetItemFrom : The list whose current item */ +/* is to be copied and returned*/ +/* to the caller. */ +/* uint ItemSize : What the caller thinks the size of*/ +/* the current item is. */ +/* ADDRESS ItemLocation : This is the location of the */ +/* buffer into which the current */ +/* item is to be copied. */ +/* TAG ItemTag : What the caller thinks the item tag */ +/* of the current item is. */ +/* */ +/* Output: If Successful : */ +/* Return DLIST_SUCCESS. */ +/* The buffer at ItemLocation will contain a copy of */ +/* the current item from ListToGetItemFrom. */ +/* If Failure : */ +/* Return an error code. */ +/* The current item pointer will NOT be advanced. */ +/* The current item in the list will be the same */ +/* as before the call to this function. */ +/* */ +/* Error Handling: This function will fail under any of the */ +/* following conditions: */ +/* ListToGetItemFrom is not a valid list */ +/* ItemSize does not match the size of the */ +/* current item in the list */ +/* ItemLocation is NULL */ +/* ItemTag does not match the item tag */ +/* of the current item in the list */ +/* The current item in the list before this */ +/* function is called is the last item */ +/* item in the list. */ +/* If any of these conditions occur, an error */ +/* code will be returned. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: It is assumed that if ItemLocation is not NULL, then */ +/* it is a valid address that can be dereferenced. If */ +/* this assumption is violated, an exception or trap may */ +/* occur. */ +/* */ +/*********************************************************************/ +int GetPreviousItem(dlist_t ListToGetItemFrom, + uint ItemSize, + ADDRESS ItemLocation, + TAG ItemTag); + + +/*********************************************************************/ +/* */ +/* Function Name: GetObject */ +/* */ +/* Descriptive Name: This function returns the address of the data*/ +/* associated with the specified item in the */ +/* list. */ +/* */ +/* Input: dlist_t ListToGetItemFrom : The list whose current item */ +/* is to have its address */ +/* returned to the caller. */ +/* uint ItemSize : What the caller thinks the size of*/ +/* the current item is. */ +/* TAG ItemTag : What the caller thinks the item tag */ +/* of the current item is. */ +/* ADDRESS Handle : The handle of the item to get. This */ +/* handle must be of an item which resides*/ +/* in ListToGetItemFrom, or NULL. If */ +/* NULL, then the current item in the list*/ +/* BOOLEAN MakeCurrent : If TRUE, the item to get will */ +/* become the current item in the */ +/* list. */ +/* ADDRESS * Object : The address of a variable to hold */ +/* the ADDRESS of data associated */ +/* with the current item. */ +/* */ +/* Output: If Successful : */ +/* Return DLIST_SUCCESS. */ +/* *Object will be the address of the data */ +/* associated with the current item in the list. */ +/* If Failure : */ +/* Return an error code. */ +/* *Object will be NULL. */ +/* */ +/* Error Handling: This function will fail under any of the */ +/* following conditions: */ +/* ListToGetItemFrom is not a valid list */ +/* ItemSize does not match the size of the */ +/* current item in the list */ +/* ItemTag does not match the item tag */ +/* of the current item in the list */ +/* Handle is invalid, or is for an item */ +/* which is not in ListToGetItemFrom */ +/* If any of these conditions occur, an error code */ +/* will be returned. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: The user should not free the memory associated with */ +/* the address returned by this function as the object is */ +/* still in the list. */ +/* */ +/* It is assumed that Handle is valid, or is at least the */ +/* address of an accessible block of storage. If Handle */ +/* is invalid, or is not the address of an accessible block*/ +/* of storage, then a trap or exception may occur. */ +/* NOTE: For this function, NULL is considered a valid */ +/* handle designating the current item in the list. */ +/* */ +/* It is assumed that Object is a valid address. If not, */ +/* an exception or trap may occur. */ +/* */ +/* This function does not alter which item is the current */ +/* item in the list. */ +/* */ +/*********************************************************************/ +int GetObject(dlist_t ListToGetItemFrom, + uint ItemSize, + TAG ItemTag, + ADDRESS Handle, + BOOLEAN MakeCurrent, + ADDRESS * Object); + + +/*********************************************************************/ +/* */ +/* Function Name: BlindGetObject */ +/* */ +/* Descriptive Name: This function returns the address of the data*/ +/* associated with the specified item in the */ +/* list. */ +/* */ +/* Input: dlist_t ListToGetItemFrom : The list whose current */ +/* item is to have its address */ +/* returned to the caller. */ +/* uint * ItemSize : The size of the current item */ +/* TAG * ItemTag : The tag of the current item */ +/* ADDRESS Handle : The handle of the item to get. This */ +/* handle must be of an item which resides*/ +/* in ListToGetItemFrom, or NULL. If */ +/* NULL, then the current item in the list*/ +/* BOOLEAN MakeCurrent : If TRUE, the item to get will */ +/* become the current item in the */ +/* list. */ +/* ADDRESS * Object : The address of a variable to hold */ +/* the ADDRESS of data associated */ +/* with the current item. */ +/* */ +/* Output: If Successful : */ +/* Return DLIST_SUCCESS. */ +/* *Object will be the address of the data */ +/* associated with the current item in the list. */ +/* If Failure : */ +/* Return an error code. */ +/* *Object will be NULL. */ +/* */ +/* Error Handling: This function will fail under any of the */ +/* following conditions: */ +/* ListToGetItemFrom is not a valid list */ +/* ItemSize does not match the size of the */ +/* current item in the list */ +/* ItemTag does not match the item tag */ +/* of the current item in the list */ +/* Handle is invalid, or is for an item */ +/* which is not in ListToGetItemFrom */ +/* If any of these conditions occur, an error code */ +/* will be returned. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: The user should not free the memory associated with */ +/* the address returned by this function as the object is */ +/* still in the list. */ +/* */ +/* It is assumed that Handle is valid, or is at least the */ +/* address of an accessible block of storage. If Handle */ +/* is invalid, or is not the address of an accessible block*/ +/* of storage, then a trap or exception may occur. */ +/* NOTE: For this function, NULL is considered a valid */ +/* handle designating the current item in the list. */ +/* */ +/* It is assumed that Object is a valid address. If not, */ +/* an exception or trap may occur. */ +/* */ +/* This function does not alter which item is the current */ +/* item in the list. */ +/* */ +/*********************************************************************/ +int BlindGetObject(dlist_t ListToGetItemFrom, + uint * ItemSize, + TAG * ItemTag, + ADDRESS Handle, + BOOLEAN MakeCurrent, + ADDRESS * Object); + + +/*********************************************************************/ +/* */ +/* Function Name: GetNextObject */ +/* */ +/* Descriptive Name: This function advances the current item */ +/* pointer and then returns the address of the */ +/* data associated with the current item in the */ +/* list. */ +/* */ +/* Input: dlist_t ListToGetItemFrom : The list whose current item */ +/* is to be copied and returned*/ +/* to the caller. */ +/* uint ItemSize : What the caller thinks the size of*/ +/* the current item is. */ +/* TAG ItemTag : What the caller thinks the item tag */ +/* of the current item is. */ +/* ADDRESS * Object : The address of a variable to hold */ +/* the ADDRESS of data associated */ +/* with the next item. */ +/* */ +/* Output: If Successful : */ +/* Return DLIST_SUCCESS. */ +/* *Object will be the address of the data */ +/* associated with the current item in the list. */ +/* If Failure : */ +/* Return an error code. */ +/* *Object will be NULL. */ +/* The current item pointer will NOT be advanced. */ +/* The current item in the list will be the same */ +/* as before the call to this function. */ +/* */ +/* Error Handling: This function will fail under any of the */ +/* following conditions: */ +/* ListToGetItemFrom is not a valid list */ +/* ItemSize does not match the size of the */ +/* current item in the list */ +/* ItemTag does not match the item tag */ +/* of the current item in the list */ +/* The current item in the list before this */ +/* function is called is the last item */ +/* item in the list. */ +/* If any of these conditions occur, an error code */ +/* will be returned. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: The user should not free the memory associated with */ +/* the address returned by this function as the object is */ +/* still in the list. */ +/* */ +/* It is assumed that Object is a valid address. If not, */ +/* an exception or trap may occur. */ +/* */ +/*********************************************************************/ +int GetNextObject(dlist_t ListToGetItemFrom, + uint ItemSize, + TAG ItemTag, + ADDRESS * Object); + + +/*********************************************************************/ +/* */ +/* Function Name: GetPreviousObject */ +/* */ +/* Descriptive Name: This function makes the previous item in the */ +/* list the current item and then returns the */ +/* address of the data associated with the */ +/* current item in the list. */ +/* */ +/* Input: dlist_t ListToGetItemFrom : The list whose current item */ +/* is to be copied and returned*/ +/* to the caller. */ +/* uint ItemSize : What the caller thinks the size of*/ +/* the current item is. */ +/* TAG ItemTag : What the caller thinks the item tag */ +/* of the current item is. */ +/* ADDRESS * Object : The address of a variable to hold */ +/* the ADDRESS of data associated */ +/* with the previous item. */ +/* */ +/* Output: If Successful : */ +/* Return DLIST_SUCCESS. */ +/* *Object will be the address of the data */ +/* associated with the current item in the list. */ +/* If Failure : */ +/* Return an error code. */ +/* *Object will be NULL. */ +/* The current item pointer will NOT be advanced. */ +/* The current item in the list will be the same */ +/* as before the call to this function. */ +/* */ +/* Error Handling: This function will fail under any of the */ +/* following conditions: */ +/* ListToGetItemFrom is not a valid list */ +/* ItemSize does not match the size of the */ +/* current item in the list */ +/* ItemTag does not match the item tag */ +/* of the current item in the list */ +/* The current item in the list before this */ +/* function is called is the last item */ +/* item in the list. */ +/* If any of these conditions occur, an error code */ +/* will be returned. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: The user should not free the memory associated with */ +/* the address returned by this function as the object is */ +/* still in the list. */ +/* */ +/* It is assumed that Object is a valid address. If not, */ +/* an exception or trap may occur. */ +/* */ +/*********************************************************************/ +int GetPreviousObject(dlist_t ListToGetItemFrom, + uint ItemSize, + TAG ItemTag, + ADDRESS * Object); + + +/*********************************************************************/ +/* */ +/* Function Name: ExtractItem */ +/* */ +/* Descriptive Name: This function copies the specified item in */ +/* the list to a buffer provided by the caller */ +/* and removes the item from the list. */ +/* */ +/* Input: dlist_t ListToGetItemFrom : The list whose current item */ +/* is to be copied and returned*/ +/* to the caller. */ +/* uint ItemSize : What the caller thinks the size of*/ +/* the current item is. */ +/* ADDRESS ItemLocation : This is the location of the */ +/* buffer into which the current*/ +/* item is to be copied. */ +/* TAG ItemTag : What the caller thinks the item tag */ +/* of the current item is. */ +/* ADDRESS Handle : The handle of the item to get. This */ +/* handle must be of an item which resides*/ +/* in ListToGetItemFrom, or NULL. If */ +/* NULL, then the current item in the list*/ +/* will be used. */ +/* */ +/* Output: If Successful : */ +/* Return DLIST_SUCCESS. */ +/* The buffer at ItemLocation will contain a copy of */ +/* the current item from ListToGetItemFrom. */ +/* The item will have been removed from the list and */ +/* its memory deallocated. */ +/* If Failure : */ +/* Return an error code. */ +/* */ +/* Error Handling: This function will fail under any of the */ +/* following conditions: */ +/* ListToGetItemFrom is not a valid list */ +/* ItemSize does not match the size of the */ +/* current item in the list */ +/* ItemLocation is NULL */ +/* ItemTag does not match the item tag */ +/* of the current item in the list */ +/* Handle is invalid, or is for an item */ +/* which is not in ListToGetItemFrom */ +/* If any of these conditions occur, *Error will */ +/* contain a non-zero error code. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: It is assumed that if ItemLocation is not NULL, then */ +/* it is a valid address that can be dereferenced. If */ +/* these assumptions are violated, an exception or trap */ +/* may occur. */ +/* */ +/* It is assumed that Handle is valid, or is at least the */ +/* address of an accessible block of storage. If Handle */ +/* is invalid, or is not the address of an accessible block*/ +/* of storage, then a trap or exception may occur. */ +/* NOTE: For this function, NULL is considered a valid */ +/* handle which refers to the current item in the */ +/* list. */ +/* */ +/* This function does not alter which item is the current */ +/* item in the list, unless the handle specified belongs */ +/* to the current item in the list, in which case the */ +/* item following the current item becomes the current */ +/* item in the list. If there is no item following the */ +/* current item in the list, then the item preceding the */ +/* current item will become the current item in the list. */ +/* */ +/*********************************************************************/ +int ExtractItem(dlist_t ListToGetItemFrom, + uint ItemSize, + ADDRESS ItemLocation, + TAG ItemTag, + ADDRESS Handle); + + +/*********************************************************************/ +/* */ +/* Function Name: ExtractObject */ +/* */ +/* Descriptive Name: This function returns the address of the data*/ +/* associated with the specified item in the */ +/* list and then removes that item from the list*/ +/* */ +/* Input: dlist_t ListToGetItemFrom : The list whose current item */ +/* is to be copied and returned*/ +/* to the caller. */ +/* uint ItemSize : What the caller thinks the size of*/ +/* the current item is. */ +/* TAG ItemTag : What the caller thinks the item tag */ +/* of the current item is. */ +/* ADDRESS Handle : The handle of the item to get. This */ +/* handle must be of an item which resides*/ +/* in ListToGetItemFrom, or NULL. If */ +/* NULL, then the current item in the */ +/* list will be used. */ +/* ADDRESS * Object : The address of a variable to hold */ +/* the ADDRESS of data associated */ +/* with the current item. */ +/* */ +/* Output: If Successful : */ +/* Return DLIST_SUCCESS. */ +/* *Object will be the address of the data */ +/* associated with the current item in the list. */ +/* If Failure : */ +/* Return an error code. */ +/* *Object will be NULL. */ +/* */ +/* Error Handling: This function will fail under any of the */ +/* following conditions: */ +/* ListToGetItemFrom is not a valid list */ +/* ItemSize does not match the size of the */ +/* current item in the list */ +/* ItemTag does not match the item tag */ +/* of the current item in the list */ +/* Handle is invalid, or is for an item */ +/* which is not in ListToGetItemFrom */ +/* If any of these conditions occur, an error code */ +/* will be returned. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: The user is responsible for the memory associated with */ +/* the address returned by this function since this */ +/* function removes that object from the list. This means */ +/* that, when the user is through with the object, they */ +/* should free it. */ +/* */ +/* It is assumed that Handle is valid, or is at least the */ +/* address of an accessible block of storage. If Handle */ +/* is invalid, or is not the address of an accessible block*/ +/* of storage, then a trap or exception may occur. */ +/* NOTE: For this function, NULL is considered a valid */ +/* handle which refers to the current item in the */ +/* list. */ +/* */ +/* It is assumed that Object is a valid address. If not, */ +/* an exception or trap may occur. */ +/* */ +/* This function does not alter which item is the current */ +/* item in the list, unless the handle specified belongs */ +/* to the current item in the list, in which case the */ +/* item following the current item becomes the current */ +/* item in the list. If there is no item following the */ +/* current item in the list, then the item preceding the */ +/* current item will become the current item in the list. */ +/* */ +/*********************************************************************/ +int ExtractObject(dlist_t ListToGetItemFrom, + uint ItemSize, + TAG ItemTag, + ADDRESS Handle, + ADDRESS * Object); + + +/*********************************************************************/ +/* */ +/* Function Name: BlindExtractObject */ +/* */ +/* Descriptive Name: This function returns the address of the data*/ +/* associated with the specified item in the */ +/* list and then removes that item from the list*/ +/* */ +/* Input: dlist_t ListToGetItemFrom : The list whose current */ +/* item is to be copied and */ +/* returned to the caller. */ +/* uint * ItemSize : The size of the current item */ +/* TAG * ItemTag : The tag of the current item */ +/* ADDRESS Handle : The handle of the item to get. This */ +/* handle must be of an item which resides*/ +/* in ListToGetItemFrom, or NULL. If */ +/* NULL, then the current item in the */ +/* list will be used. */ +/* ADDRESS * Object : The address of a variable to hold */ +/* the ADDRESS of data associated */ +/* with the current item. */ +/* */ +/* Output: If Successful : */ +/* Return DLIST_SUCCESS. */ +/* *Object will be the address of the data */ +/* associated with the current item in the list. */ +/* If Failure : */ +/* Return an error code. */ +/* *Object will be NULL. */ +/* */ +/* Error Handling: This function will fail under any of the */ +/* following conditions: */ +/* ListToGetItemFrom is not a valid list */ +/* ItemSize does not match the size of the */ +/* current item in the list */ +/* ItemTag does not match the item tag */ +/* of the current item in the list */ +/* Handle is invalid, or is for an item */ +/* which is not in ListToGetItemFrom */ +/* If any of these conditions occur, an error code */ +/* will be returned. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: The user is responsible for the memory associated with */ +/* the address returned by this function since this */ +/* function removes that object from the list. This means */ +/* that, when the user is through with the object, they */ +/* should free it. */ +/* */ +/* It is assumed that Handle is valid, or is at least the */ +/* address of an accessible block of storage. If Handle */ +/* is invalid, or is not the address of an accessible block*/ +/* of storage, then a trap or exception may occur. */ +/* NOTE: For this function, NULL is considered a valid */ +/* handle which refers to the current item in the */ +/* list. */ +/* */ +/* It is assumed that Object is a valid address. If not, */ +/* an exception or trap may occur. */ +/* */ +/* This function does not alter which item is the current */ +/* item in the list, unless the handle specified belongs */ +/* to the current item in the list, in which case the */ +/* item following the current item becomes the current */ +/* item in the list. If there is no item following the */ +/* current item in the list, then the item preceding the */ +/* current item will become the current item in the list. */ +/* */ +/*********************************************************************/ +int BlindExtractObject(dlist_t ListToGetItemFrom, + uint * ItemSize, + TAG * ItemTag, + ADDRESS Handle, + ADDRESS * Object); + + +/*********************************************************************/ +/* */ +/* Function Name: ReplaceItem */ +/* */ +/* Descriptive Name: This function replaces the specified item in */ +/* the list with the one provided as its */ +/* argument. */ +/* */ +/* Input: dlist_t ListToReplaceItemIn : The list whose current item*/ +/* is to be replaced */ +/* uint ItemSize : The size, in bytes, of the */ +/* replacement item */ +/* ADDRESS ItemLocation : The address of the replacement */ +/* item */ +/* TAG ItemTag : The item tag that the user wishes to */ +/* associate with the replacement item */ +/* ADDRESS Handle : The handle of the item to get. This */ +/* handle must be of an item which resides */ +/* in ListToGetItemFrom, or NULL. If NULL */ +/* then the current item in the list will */ +/* used. */ +/* BOOLEAN MakeCurrent : If TRUE, the item to get will */ +/* become the current item in the */ +/* list. */ +/* */ +/* Output: If Successful then return DLIST_SUCCESS. */ +/* If Unsuccessful, then return an error code. */ +/* */ +/* Error Handling: This function will fail under the following */ +/* conditions: */ +/* ListToReplaceItemIn is empty */ +/* ItemSize is 0 */ +/* ItemLocation is NULL */ +/* The memory required can not be allocated. */ +/* Handle is invalid, or is for an item */ +/* which is not in ListToGetItemFrom */ +/* If any of these conditions occurs, an error */ +/* code will be returned. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: It is assumed that if ItemLocation is not NULL, then */ +/* it is a valid address that can be dereferenced. If */ +/* these assumptions are violated, an exception or trap */ +/* may occur. */ +/* */ +/* It is assumed that Handle is valid, or is at least the */ +/* address of an accessible block of storage. If Handle */ +/* is invalid, or is not the address of an accessible block*/ +/* of storage, then a trap or exception may occur. */ +/* NOTE: For this function, NULL is a valid handle which */ +/* refers to the current item in the list. */ +/* */ +/* This function does not alter which item is the current */ +/* item in the list. */ +/* */ +/*********************************************************************/ +int ReplaceItem(dlist_t ListToReplaceItemIn, + uint ItemSize, + ADDRESS ItemLocation, + TAG ItemTag, + ADDRESS Handle, + BOOLEAN MakeCurrent); + + +/*********************************************************************/ +/* */ +/* Function Name: ReplaceObject */ +/* */ +/* Descriptive Name: This function replaces the specified object */ +/* in the list with the one provided as its */ +/* argument. */ +/* */ +/* Input: dlist_t ListToReplaceItemIn : The list whose current */ +/* object is to be replaced */ +/* uint ItemSize : The size, in bytes, of the */ +/* replacement object */ +/* ADDRESS ItemLocation : The address of the replacement */ +/* item */ +/* TAG ItemTag : The item tag that the user wishes to */ +/* associate with the replacement item */ +/* ADDRESS Handle : The handle of the item to get. This */ +/* handle must be of an item which resides */ +/* in ListToGetItemFrom, or NULL. If NULL */ +/* then the current item in the list will */ +/* be used. */ +/* BOOLEAN MakeCurrent : If TRUE, the item to get will */ +/* become the current item in the */ +/* list. */ +/* ADDRESS * Object : The address of a variable to hold */ +/* the ADDRESS of the object that */ +/* was replaced. */ +/* */ +/* Output: If Successful then return DLIST_SUCCESS and the */ +/* *Object will contain the address of the object that */ +/* was replaced. */ +/* If Unsuccessful, then return an error code and */ +/* *Object will be NULL. */ +/* */ +/* Error Handling: This function will fail under the following */ +/* conditions: */ +/* ListToReplaceItemIn is empty */ +/* ItemSize is 0 */ +/* ItemLocation is NULL */ +/* The memory required can not be allocated. */ +/* Handle is invalid, or is for an item */ +/* which is not in ListToGetItemFrom */ +/* If any of these conditions occurs, an error */ +/* code will be returned. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: The user is responsible for the memory associated with */ +/* the object returned by this function as that object is */ +/* removed from the list. This means that, when the user */ +/* is through with the object returned by this function, */ +/* they should free it. */ +/* */ +/* It is assumed that if ItemLocation is not NULL, then */ +/* it is a valid address that can be dereferenced. If */ +/* these assumptions are violated, an exception or trap */ +/* may occur. */ +/* */ +/* It is assumed that Handle is valid, or is at least the */ +/* address of an accessible block of storage. If Handle */ +/* is invalid, or is not the address of an accessible block*/ +/* of storage, then a trap or exception may occur. */ +/* NOTE: For this function, NULL is a valid handle for the */ +/* current item in the list. */ +/* */ +/* It is assumed that Object is a valid address. If not, */ +/* an exception or trap may occur. */ +/* */ +/* This function does not alter which item is the current */ +/* item in the list. */ +/* */ +/*********************************************************************/ +int ReplaceObject(dlist_t ListToReplaceItemIn, + uint * ItemSize, /* On input - size of new object. On return = size of old object. */ + ADDRESS ItemLocation, + TAG * ItemTag, /* On input - TAG of new object. On return = TAG of old object. */ + ADDRESS Handle, + BOOLEAN MakeCurrent, + ADDRESS * Object); + + +/*********************************************************************/ +/* */ +/* Function Name: GetTag */ +/* */ +/* Descriptive Name: This function returns the item tag associated*/ +/* with the current item in the list. */ +/* */ +/* Input: dlist_t ListToGetTagFrom : The list from which the item */ +/* tag of the current item is to*/ +/* be returned */ +/* ADDRESS Handle : The handle of the item whose TAG and */ +/* size we are to get. This handle must */ +/* be of an item which resides in */ +/* in ListToGetTagFrom, or NULL. If NULL */ +/* then the current item in the list will */ +/* be used. */ +/* uint * ItemSize : The size, in bytes, of the */ +/* current item in the list. */ +/* TAG * Tag : The address of a variable to hold */ +/* the returned tag. */ +/* */ +/* Output: If successful, the function returns DLIST_SUCCESS. */ +/* *ItemSize contains the size of the item. *Tag */ +/* contains the tag. */ +/* If unsuccessful, an error code is returned. */ +/* */ +/* Error Handling: This function will fail if ListToGetTagFrom is */ +/* not a valid list or is an empty list. In either*/ +/* of these cases, an error code is returned. */ +/* */ +/* Side Effects: None. */ +/* */ +/*********************************************************************/ +int GetTag(dlist_t ListToGetTagFrom, + ADDRESS Handle, + uint * ItemSize, + TAG * Tag); + + +/*********************************************************************/ +/* */ +/* Function Name: GetHandle */ +/* */ +/* Descriptive Name: This function returns a handle for the */ +/* current item in the list. This handle is */ +/* then associated with that item regardless of */ +/* its position in the list. This handle can be*/ +/* used to make its associated item the current */ +/* item in the list. */ +/* */ +/* Input: dlist_t ListToGetHandleFrom : The list from which a */ +/* handle is needed. */ +/* ADDRESS * Handle : The address of a variable to hold */ +/* the handle */ +/* */ +/* Output: If successful, the function returns DLIST_SUCCESS and */ +/* *Handle is set to the handle for the current item */ +/* in ListToGetHandleFrom. */ +/* If unsuccessful, an error code is returned and *Handle */ +/* is set to 0. */ +/* */ +/* Error Handling: This function will fail if ListToGetHandleFrom */ +/* is not a valid list or is an empty list. In */ +/* either of these cases, an error code is */ +/* returned. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: The handle returned is a pointer to the LinkNode of the */ +/* current item in the list. This allows the item to move */ +/* around in the list without losing its associated handle.*/ +/* However, if the item is deleted from the list, then the */ +/* handle is invalid and its use could result in a trap. */ +/* */ +/*********************************************************************/ +int GetHandle (dlist_t ListToGetHandleFrom, + ADDRESS * Handle); + + + +/*********************************************************************/ +/* */ +/* Function Name: GetListSize */ +/* */ +/* Descriptive Name: This function returns the number of items in */ +/* a list. */ +/* */ +/* Input: dlist_t ListToGetSizeOf : The list whose size we wish to*/ +/* know */ +/* uint * Size : The address of a variable to hold */ +/* the size of the list. */ +/* */ +/* Output: If successful, the function returns DLIST_SUCCESS and */ +/* *Size contains the a count of the number of items */ +/* in the list. */ +/* If unsuccessful, an error code is returned and *Size */ +/* is set to 0. */ +/* */ +/* Error Handling: This function will fail if ListToGetSizeOf is */ +/* not a valid list. If this happens, then an */ +/* error code is returned. . */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: It is assumed that Size contains a valid address. If */ +/* this assumption is violated, an exception or trap */ +/* may occur. */ +/* */ +/*********************************************************************/ +int GetListSize(dlist_t ListToGetSizeOf, + uint * Size); + + +/*********************************************************************/ +/* */ +/* Function Name: ListEmpty */ +/* */ +/* Descriptive Name: This function returns TRUE if the */ +/* specified list is empty, otherwise it returns*/ +/* FALSE. */ +/* */ +/* Input: dlist_t ListToCheck : The list to check to see if it*/ +/* is empty */ +/* */ +/* Output: If successful, the function returns TRUE if the */ +/* number of items in the list is 0, otherwise it */ +/* returns FALSE. */ +/* If unsuccessful, the function returns TRUE. */ +/* */ +/* Error Handling: This function will return TRUE if ListToCheck */ +/* is not a valid list. */ +/* */ +/* Side Effects: None. */ +/* */ +/*********************************************************************/ +BOOLEAN ListEmpty(dlist_t ListToCheck); + + +/*********************************************************************/ +/* */ +/* Function Name: AtEndOfList */ +/* */ +/* Descriptive Name: This function returns TRUE if the */ +/* current item in the list is the last item */ +/* in the list. Returns FALSE otherwise. */ +/* */ +/* Input: dlist_t ListToCheck : The list to check. */ +/* */ +/* Output: If successful, the function returns TRUE if the */ +/* current item in the list is the last item in the */ +/* list. If it is not the last item in the list, */ +/* FALSE is returned. */ +/* If unsuccessful, the function returns FALSE. */ +/* */ +/* Error Handling: This function will return FALSE ListToCheck is */ +/* not a valid list. */ +/* */ +/* Side Effects: None. */ +/* */ +/*********************************************************************/ +BOOLEAN AtEndOfList(dlist_t ListToCheck); + + +/*********************************************************************/ +/* */ +/* Function Name: AtStartOfList */ +/* */ +/* Descriptive Name: This function returns TRUE if the */ +/* current item in the list is the first item */ +/* in the list. Returns FALSE otherwise. */ +/* */ +/* Input: dlist_t ListToCheck : The list to check. */ +/* */ +/* Output: If successful, the function returns TRUE if the */ +/* current item in the list is the first item in the */ +/* list. If it is not the first item in the list, */ +/* FALSE is returned. */ +/* If unsuccessful, the function returns FALSE */ +/* */ +/* Error Handling: This function will return FALSE if ListToCheck */ +/* is not a valid list. */ +/* */ +/* Side Effects: None. */ +/* */ +/*********************************************************************/ +BOOLEAN AtStartOfList(dlist_t ListToCheck); + + +/*********************************************************************/ +/* */ +/* Function Name: DestroyList */ +/* */ +/* Descriptive Name: This function releases the memory associated */ +/* with the internal data structures of a */ +/* dlist_t. Once a dlist_t has been destroyed */ +/* by this function, it must be reinitialized */ +/* before it can be used again. */ +/* */ +/* Input: dlist_t ListToDestroy : The list to be eliminated */ +/* from memory. */ +/* BOOLEAN FreeItemMemory : If TRUE, all items in the list */ +/* will be freed. If FALSE, all */ +/* items in the list are not */ +/* freed, only the list structures*/ +/* associated with them are. */ +/* */ +/* Output: If successful, return DLIST_SUCCESS */ +/* If unsuccessful, return an error code. */ +/* */ +/* Error Handling: This function will fail if ListToDestroy is not */ +/* a valid list. If this happens, then an error */ +/* code is returned. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: If FreeItemMemory is TRUE, then this function will try */ +/* to delete any items which may be in the list. However, */ +/* since this function has no way of knowing the internal */ +/* structure of an item, items which contain embedded */ +/* pointers will not be entirely freed. This can lead to */ +/* memory leaks. The programmer should ensure that any */ +/* list passed to this function when the FreeItemMemory */ +/* parameter is TRUE is empty or does not contain any */ +/* items with embedded pointers. */ +/* */ +/*********************************************************************/ +int DestroyList(dlist_t * ListToDestroy, + BOOLEAN FreeItemMemory); + + +/*********************************************************************/ +/* */ +/* Function Name: NextItem */ +/* */ +/* Descriptive Name: This function makes the next item in the list*/ +/* the current item in the list (i.e. it */ +/* advances the current item pointer). */ +/* */ +/* Input: dlist_t ListToAdvance : The list whose current item */ +/* pointer is to be advanced */ +/* */ +/* Output: If successful, return DLIST_SUCCESS. */ +/* If unsuccessful, return error code. */ +/* */ +/* Error Handling: This function will fail under the following */ +/* conditions: */ +/* ListToAdvance is not a valid list */ +/* ListToAdvance is empty */ +/* The current item is the last item in the */ +/* list */ +/* If any of these conditions occurs, then an */ +/* error code is returned. */ +/* */ +/* Side Effects: None. */ +/* */ +/*********************************************************************/ +int NextItem(dlist_t ListToAdvance); + + +/*********************************************************************/ +/* */ +/* Function Name: PreviousItem */ +/* */ +/* Descriptive Name: This function makes the previous item in the */ +/* list the current item in the list. */ +/* */ +/* Input: dlist_t ListToChange : The list whose current item */ +/* pointer is to be changed */ +/* */ +/* Output: If successful, return DLIST_SUCCESS. */ +/* If unsuccessful, return an error code. */ +/* */ +/* Error Handling: This function will fail under the following */ +/* conditions: */ +/* ListToChange is not a valid list */ +/* ListToChange is empty */ +/* The current item is the first item in the */ +/* list */ +/* If any of these conditions occurs, then return */ +/* an error code. */ +/* */ +/* Side Effects: None. */ +/* */ +/*********************************************************************/ +int PreviousItem(dlist_t ListToChange); + + +/*********************************************************************/ +/* */ +/* Function Name: GoToStartOfList */ +/* */ +/* Descriptive Name: This function makes the first item in the */ +/* list the current item in the list. */ +/* */ +/* Input: dlist_t ListToReset : The list whose current item */ +/* is to be set to the first */ +/* item in the list */ +/* */ +/* Output: If successful, return DLIST_SUCCESS. */ +/* If unsuccessful, return an error code */ +/* */ +/* Error Handling: This function will fail if ListToAdvance is not */ +/* a valid list. If this occurs, then an error */ +/* code is returned. */ +/* */ +/* Side Effects: None. */ +/* */ +/*********************************************************************/ +int GoToStartOfList(dlist_t ListToReset); + + +/*********************************************************************/ +/* */ +/* Function Name: GoToEndOfList */ +/* */ +/* Descriptive Name: This function makes the last item in the */ +/* list the current item in the list. */ +/* */ +/* Input: dlist_t ListToSet : The list whose current item */ +/* is to be set to the last item */ +/* in the list */ +/* */ +/* Output: If successful, return DLIST_SUCCESS. */ +/* If unsuccessful, return an error code */ +/* */ +/* Error Handling: This function will fail if ListToAdvance is not */ +/* a valid list. If this occurs, then an error */ +/* code is returned. */ +/* */ +/* Side Effects: None. */ +/* */ +/*********************************************************************/ +int GoToEndOfList(dlist_t ListToSet); + + +/*********************************************************************/ +/* */ +/* Function Name: GoToSpecifiedItem */ +/* */ +/* Descriptive Name: This function makes the item associated with */ +/* Handle the current item in the list. */ +/* */ +/* Input: dlist_t ListToReposition: The list whose current item */ +/* is to be set to the item */ +/* associated with Handle. */ +/* ADDRESS Handle : A handle obtained by using the */ +/* GetHandle function. This handle */ +/* identifies a unique item in the list. */ +/* */ +/* Output: If successful, return DLIST_SUCCESS. */ +/* If unsuccessful, return an error code */ +/* */ +/* Error Handling: This function will fail if ListToAdvance is not */ +/* a valid list. If this occurs, then an error */ +/* code is returned. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: It is assumed that Handle is a valid handle and that */ +/* the item associated with Handle is still in the list. */ +/* If these conditions are not met, an exception or trap */ +/* may occur. */ +/* */ +/*********************************************************************/ +int GoToSpecifiedItem(dlist_t ListToReposition, + ADDRESS Handle); + + +/*********************************************************************/ +/* */ +/* Function Name: SortList */ +/* */ +/* Descriptive Name: This function sorts the contents of a list. */ +/* The sorting algorithm used is a stable sort */ +/* whose performance is not dependent upon the */ +/* initial order of the items in the list. */ +/* */ +/* Input: dlist_t ListToSort : The dlist_t that is to be sorted. */ +/* */ +/* int (*Compare) ( ... ) */ +/* */ +/* This is a pointer to a function that can compare any */ +/* two items in the list. It should return -1 if */ +/* Object1 is less than Object2, 0 if Object1 is equal */ +/* to Object2, and 1 if Object1 is greater than Object2.*/ +/* This function will be called during the sort whenever*/ +/* the sorting algorithm needs to compare two objects. */ +/* */ +/* The Compare function takes the following parameters: */ +/* */ +/* ADDRESS Object1 : The address of the data for the */ +/* first object to be compared. */ +/* TAG Object1Tag : The user assigned TAG value for the */ +/* first object to be compared. */ +/* ADDRESS Object2 : The address of the data for the */ +/* second object to be compared. */ +/* TAG Object2Tag : The user assigned TAG value for the */ +/* second object to be compared. */ +/* uint * Error : The address of a variable to hold the */ +/* error return value. */ +/* */ +/* If this function ever sets *Error to a non-zero value*/ +/* the sort will terminate and the error code will be */ +/* returned to the caller of the SortList function. */ +/* */ +/* */ +/* Output: If successful, this function will return DLIST_SUCCESS */ +/* and ListToSort will have been sorted. */ +/* If unsuccessful, an error code will be returned. */ +/* The order of the items in ListToSort is undefined */ +/* and may have changed. */ +/* */ +/* Error Handling: This function will terminate if *Compare sets */ +/* *Error to a non-zero value, or if ListToSort */ +/* is invalid. If this function does terminate in */ +/* the middle of a sort, the order of the items in */ +/* ListToSort may be different than it was before */ +/* the function was called. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: This function works by breaking the list into sublists */ +/* and merging the sublists back into one list. The size */ +/* of the sublists starts at 1, and with each pass, the */ +/* of the sublists is doubled. The sort ends when the size*/ +/* of a sublist is greater than the size of the original */ +/* list. */ +/* */ +/*********************************************************************/ +int SortList(dlist_t ListToSort, + int (*Compare) (ADDRESS Object1, + TAG Object1Tag, + ADDRESS Object2, + TAG Object2Tag, + uint * Error)); + + +/*********************************************************************/ +/* */ +/* Function Name: ForEachItem */ +/* */ +/* Descriptive Name: This function passes a pointer to each item */ +/* in a list to a user provided function for */ +/* processing by the user provided function. */ +/* */ +/* Input: dlist_t ListToProcess : The dlist_t whose items are to */ +/* be processed by the user */ +/* provided function. */ +/* */ +/* int (*ProcessItem) (...) */ +/* */ +/* This is a pointer to the user provided function. */ +/* This user provided function takes the following */ +/* parameters: */ +/* */ +/* ADDRESS Object : A pointer to an item in */ +/* ListToProcess. */ +/* TAG Object1Tag : The user assigned TAG value for */ +/* the item pointed to by Object. */ +/* ADDRESS Parameter : The address of a block of */ +/* memory containing any */ +/* parameters that the user */ +/* wishes to have passed to this*/ +/* function. */ +/* */ +/* ADDRESS Parameters : This field is passed through to */ +/* *ProcessItem. This function does */ +/* not even look at the contents of */ +/* this field. This field is here to */ +/* provide the user a way to pass */ +/* additional data to *ProcessItem */ +/* that *ProcessItem may need to */ +/* function correctly. */ +/* */ +/* Output: If successful, return DLIST_SUCCESS. */ +/* If unsuccessful, return an error code. */ +/* */ +/* Error Handling: This function aborts immediately when an error */ +/* is detected, and any remaining items in the list*/ +/* will not be processed. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: This function allows the user to access all of the items */ +/* in a list and perform an operation on them. The */ +/* operation performed must not free any items in the list, */ +/* or perform any list operations on the list being */ +/* processed. */ +/* */ +/* As an example of when this would be useful, consider a */ +/* a list of graphic objects (rectangles, triangles, circles*/ +/* etc.) which comprise a drawing. To draw the picture */ +/* that these graphic objects represent, one could build a */ +/* loop which gets and draws each item. Another way to */ +/* do this would be to build a drawing function which can */ +/* draw any of the graphic objects, and then use that */ +/* function as the ProcessItem function in a call to */ +/* ForEachItem. */ +/* */ +/* If the ProcessItem function returns an error code */ +/* other than DLIST_SUCCESS, then ForEachItem will terminate*/ +/* and return an error to whoever called it. The single */ +/* exception to this is if ProcessItem returns */ +/* DLIST_SEARCH_COMPLETE, in which case ForEachItem */ +/* terminates and returns DLIST_SUCCESS. This is */ +/* useful for using ForEachItem to search a list and then */ +/* terminating the search once the desired item is found. */ +/* */ +/* A word about the Parameters parameter. This parameter */ +/* is passed through to *ProcessItem and is never looked at */ +/* by this function. This means that the user can put any */ +/* value they desire into Parameters as long as it is the */ +/* same size (in bytes) as Parameters. The intended use of */ +/* Parameters is to allow the user to pass information to */ +/* *ProcessItem that *ProcessItem may need. Either way, */ +/* how Parameters is used is literally up to the user. */ +/* */ +/*********************************************************************/ +int ForEachItem(dlist_t ListToProcess, + int (*ProcessItem) (ADDRESS Object, + TAG ObjectTag, + uint ObjectSize, + ADDRESS ObjectHandle, + ADDRESS Parameters), + ADDRESS Parameters, + BOOLEAN Forward); + + +/*********************************************************************/ +/* */ +/* Function Name: PruneList */ +/* */ +/* Descriptive Name: This function allows the caller to examine */ +/* each item in a list and optionally delete */ +/* it from the list. */ +/* */ +/* Input: dlist_t ListToProcess : The dlist_t to be pruned. */ +/* */ +/* BOOLEAN (*KillItem) (...) */ +/* */ +/* This is a pointer to a user provided function. */ +/* This user provided function takes the following */ +/* parameters: */ +/* */ +/* ADDRESS Object : A pointer to an item in */ +/* ListToProcess. */ +/* TAG Object1Tag : The user assigned TAG value for */ +/* the item pointed to by Object. */ +/* ADDRESS Parameter : The address of a block of */ +/* memory containing any */ +/* parameters that the user */ +/* wishes to have passed to this*/ +/* function. */ +/* BOOLEAN * FreeMemory : The address of a BOOLEAN */ +/* variable which this */ +/* function will set to */ +/* either TRUE or FALSE. */ +/* If the function return */ +/* value is TRUE, then the */ +/* value in *FreeMemory will */ +/* be examined. If it is */ +/* TRUE, then PruneList will */ +/* free the memory associated*/ +/* with the item being */ +/* deleted. If *FreeMemory */ +/* is FALSE, then the item */ +/* being removed from the */ +/* dlist_t will not be freed,*/ +/* and it is up to the user */ +/* to ensure that this memory*/ +/* is handled properly. */ +/* uint * Error : The address of a variable to*/ +/* hold the error return value.*/ +/* */ +/* ADDRESS Parameters : This field is passed through to */ +/* *KillItem. This function does */ +/* not even look at the contents of */ +/* this field. This field is here to */ +/* provide the user a way to pass */ +/* additional data to *ProcessItem */ +/* that *ProcessItem may need to */ +/* function correctly. */ +/* */ +/* */ +/* Output: If successful, return DLIST_SUCCESS. */ +/* If unsuccessful, return an error code. */ +/* */ +/* Error Handling: This function aborts immediately when an error */ +/* is detected, and any remaining items in the list*/ +/* will not be processed. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: This function allows the user to access all of the items */ +/* in a list, perform an operation on them, and then */ +/* optionally delete ("remove") them from the dlist_t. The */ +/* operation performed must not free any items in the list, */ +/* or perform any list operations on the list being */ +/* processed. */ +/* */ +/* If the KillItem function sets *Error to something other */ +/* than DLIST_SUCCESS, then PruneList will terminate and */ +/* return an error to whoever called it. The single */ +/* exception to this is if KillItem sets *Error to */ +/* DLIST_SEARCH_COMPLETE, in which case KillItem */ +/* terminates and sets *Error to DLIST_SUCCESS. This is */ +/* useful for using KillItem to search a list and then */ +/* terminating the search once the desired item is found. */ +/* */ +/* A word about the Parameters parameter. This parameter */ +/* is passed through to *ProcessItem and is never looked at */ +/* by this function. This means that the user can put any */ +/* value they desire into Parameters as long as it is the */ +/* same size (in bytes) as Parameters. The intended use of */ +/* Parameters is to allow the user to pass information to */ +/* *ProcessItem that *ProcessItem may need. Either way, */ +/* how Parameters is used is literally up to the user. */ +/* */ +/*********************************************************************/ +int PruneList(dlist_t ListToProcess, + BOOLEAN (*KillItem) (ADDRESS Object, + TAG ObjectTag, + uint ObjectSize, + ADDRESS ObjectHandle, + ADDRESS Parameters, + BOOLEAN * FreeMemory, + uint * Error), + ADDRESS Parameters); + +/*********************************************************************/ +/* */ +/* Function Name: AppendList */ +/* */ +/* Descriptive Name: Removes the items in SourceList and appends */ +/* them to TargetList. */ +/* */ +/* Input: dlist_t TargetList : The dlist_t which is to have the */ +/* items from SourceList appended to */ +/* it. */ +/* dlist_t SourceList : The dlist_t whose items are to be */ +/* removed and appended to TargetList.*/ +/* */ +/* Output: If successful, return DLIST_SUCCESS. */ +/* SourceList will be empty, and TargetList will contain*/ +/* all of its original items and all of the items that */ +/* were in SourceList. */ +/* If unsuccessful, return an error code. SourceList and */ +/* TargetList will be unmodified. */ +/* */ +/* Error Handling: This function will abort immediately upon */ +/* detection of an error. All errors that can be */ +/* detected are detected before the contents of */ +/* SourceList are appended to TargetList, so if an*/ +/* error is detected and the function aborts, */ +/* SourceList and TargetList are unaltered. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: None. */ +/* */ +/*********************************************************************/ +int AppendList(dlist_t TargetList, + dlist_t SourceList); + + +/*********************************************************************/ +/* */ +/* Function Name: TransferItem */ +/* */ +/* Descriptive Name: Removes an item in SourceList and places in */ +/* TargetList. */ +/* */ +/* Input: dlist_t SourceList : The dlist_t containing the item */ +/* which is to be transferred. */ +/* ADDRESS SourceHandle : The handle of the item in */ +/* SourceList which is to be */ +/* transferred to another dlist_t. */ +/* If this is NULL, then the */ +/* current item in SourceList will */ +/* be used. */ +/* dlist_t TargetList : The dlist_t which is to receive the*/ +/* item being transferred. */ +/* ADDRESS TargetHandle : The item in TargetList which */ +/* is used to determine where */ +/* the item being transferred will */ +/* be placed. If this is NULL, */ +/* then the current item in */ +/* TargetList will be used. */ +/* Insertion_Modes TransferMode : This indicates where, */ +/* relative to the item in */ +/* TargetList specified by */ +/* Target_Handle, the item being */ +/* transferred can be placed. */ +/* BOOLEAN MakeCurrent : If TRUE, the item transferred to */ +/* TargetList becomes the current */ +/* item in TargetList. */ +/* */ +/* Output: If successful, return DLIST_SUCCESS, SourceList will be */ +/* empty, and TargetList will contain all of its */ +/* original items and all of the items that were in */ +/* SourceList. */ +/* If unsuccessful, an error code will be returned and */ +/* SourceList and TargetList will be unmodified. */ +/* */ +/* Error Handling: This function will abort immediately upon */ +/* detection of an error. All errors that can be */ +/* detected are detected before the contents of */ +/* SourceList are appended to TargetList, so if an*/ +/* error is detected and the function aborts, */ +/* SourceList and TargetList are unaltered. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: None. */ +/* */ +/*********************************************************************/ +int TransferItem(dlist_t SourceList, + ADDRESS SourceHandle, + dlist_t TargetList, + ADDRESS TargetHandle, + Insertion_Modes TransferMode, + BOOLEAN MakeCurrent); + + +/*********************************************************************/ +/* */ +/* Function Name: CopyList */ +/* */ +/* Descriptive Name: Copies the items in SourceList to the */ +/* TargetList. */ +/* */ +/* Input: dlist_t TargetList : The dlist_t which is to have the */ +/* items from SourceList copied to it.*/ +/* dlist_t SourceList : The dlist_t whose items are to be */ +/* copied to TargetList. */ +/* */ +/* Output: If successful, return DLIST_SUCCESS. */ +/* SourceList will be unchanged and TargetList will */ +/* contain all of its original items and all of the */ +/* items that were in SourceList. */ +/* If unsuccessful, return an error code. SourceList and */ +/* TargetList will be unmodified. */ +/* */ +/* Error Handling: This function will abort immediately upon */ +/* detection of an error. All errors that can be */ +/* detected are detected before the contents of */ +/* SourceList are appended to TargetList, so if an*/ +/* error is detected and the function aborts, */ +/* SourceList and TargetList are unaltered. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: None. */ +/* */ +/*********************************************************************/ +int CopyList(dlist_t TargetList, + dlist_t SourceList, + Insertion_Modes Insert_Mode); + + +/*********************************************************************/ +/* */ +/* Function Name: CheckListIntegrity */ +/* */ +/* Descriptive Name: Checks the integrity of a dlist_t. All link */ +/* nodes in the list are checked, as are all */ +/* fields in the list control block. */ +/* */ +/* Input: dlist_t ListToCheck - The list whose integrity is to be */ +/* checked. */ +/* */ +/* Output: The function return value will be TRUE if all of the */ +/* elements in the dlist_t are correct. If this function */ +/* returns FALSE, then the dlist_t being checked has been */ +/* corrupted! */ +/* */ +/* Error Handling: If this function encounters an error in a */ +/* dlist_t, it will return FALSE. */ +/* */ +/* Side Effects: None. */ +/* */ +/* Notes: None. */ +/* */ +/*********************************************************************/ +BOOLEAN CheckListIntegrity(dlist_t ListToCheck); + + +#endif + + diff --git a/lib/evms/enginestructs.h b/lib/evms/enginestructs.h new file mode 100644 index 00000000..f74d5bbb --- /dev/null +++ b/lib/evms/enginestructs.h @@ -0,0 +1,302 @@ +/* + * + * Copyright (c) International Business Machines Corp., 2001 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Module: enginestructs.h + */ + +#ifndef EVMS_ENGINESTRUCTS_H_INCLUDED +#define EVMS_ENGINESTRUCTS_H_INCLUDED 1 + +#include +#include +#include +#include +#include + +struct plugin_functions_s; +struct fsim_functions_s; +struct container_functions_s; + +/* + * The so_record_t contains information about a .so that was loaded which + * contains plug-in(s). + */ +typedef struct so_record_s { + char * name; + module_handle_t handle; + dlist_t plugin_list; +} so_record_t; + + +typedef struct plugin_record_s { + object_handle_t app_handle; /* External API handle for this structure; */ + /* used only by the Engine */ + plugin_id_t id; /* Plug-in's ID */ + evms_version_t version; /* Plug-in's version */ + evms_version_t required_api_version; /* Version of the Engine plug-in API */ + /* that the plug-in requires */ + so_record_t * so_record; /* Record for the shared object from */ + /* which the plug-in was loaded */ + char * short_name; + char * long_name; + char * oem_name; + union { + struct plugin_functions_s * plugin; + struct fsim_functions_s * fsim; + } functions; + struct container_functions_s * container_functions; /* Optional container functions if the */ + /* plug-in supports containers */ +} plugin_record_t; + + +typedef struct storage_object_s { + object_handle_t app_handle; /* External API handle for this structure; */ + /* used only by the Engine */ + object_type_t object_type; /* SEGMENT, REGION, DISK ,... */ + data_type_t data_type; /* DATA_TYPE, META_DATA_TYPE, FREE_SPACE_TYPE */ + plugin_record_t * plugin; /* Plug-in record of plug-in that manages this object */ + struct storage_container_s * producing_container; /* storage_container that produced this object */ + struct storage_container_s * consuming_container; /* storage_container that consumed this object */ + dlist_t parent_objects; /* List of parent objects, filled in by parent */ + dlist_t child_objects; /* List of child objects, filled in by owner */ + struct storage_object_s * associated_object; /* Object to which this object is associated */ + u_int32_t flags; /* Defined by SOFLAG_???? in common.h */ + lba_t start; /* Relative starting block of this object */ + sector_count_t size; /* Size of object in sectors */ + struct logical_volume_s * volume; /* Volume which comprises this object */ + evms_feature_header_t * feature_header; /* Copy of EVMS storage object's top feature header */ + /* read in by Engine */ + /* NULL if it does not exist */ + geometry_t geometry; /* Optional geometry of the object */ + void * private_data; /* Optional plug-in's data for the object */ + void * consuming_private_data;/* Optional consuming plug-in's data for the object */ + char name[EVMS_NAME_SIZE+1];/* Object's name, filled in by owner */ +} storage_object_t; + + +typedef struct storage_container_s { + object_handle_t app_handle; /* External API handle for this structure; */ + /* used only by the Engine */ + plugin_record_t * plugin; /* Plug-in record of the plug-in that manages */ + /* this container */ + /* Filled in by the plug-in during discover */ + /* or create_container() */ + uint flags; /* Defined by SCFLAG_???? in common.h */ + dlist_t objects_consumed; /* List of objects in this container */ + /* The Engine allocate_container API will create the */ + /* dlist_t anchor for this list. */ + /* The plug-in inserts storage_object_t structures */ + /* into this list when it assigns objects to this */ + /* container. */ + dlist_t objects_produced; /* List of objects produced from this container, */ + /* including free space objects */ + /* The Engine allocate_container API will create the */ + /* dlist_t anchor for this list. */ + /* The plug-in inserts storage_object_t structures */ + /* into this list when it produces objects from this */ + /* container. */ + sector_count_t size; /* Total size of all objects on the objects_produced list */ + void * private_data; /* Optional plug-in data for the container */ + char name[EVMS_NAME_SIZE+1]; /* Container name, filled in by the plug-in */ +} storage_container_t; + + +/* + * The logical_volume structures are created and managed by the Engine. + */ +typedef struct logical_volume_s { + object_handle_t app_handle; /* External API handle for this structure; */ + /* used only by the Engine */ + plugin_record_t * file_system_manager; /* Plug-in record of the File System Interface */ + /* Module that handles this volume */ + plugin_record_t * original_fsim; /* Plug-in record of the File System Interface */ + /* Module that was initially discovered for this volume */ + char * mount_point; /* Dir where the volume is mounted, NULL if not mounted */ + sector_count_t fs_size; /* Size of the file system */ + sector_count_t min_fs_size; /* Minimum size for the file system */ + sector_count_t max_fs_size; /* Maximum size for the file system */ + sector_count_t original_vol_size; /* Size of the file system before expand or shrink */ + sector_count_t vol_size; /* Size of the volume */ + sector_count_t max_vol_size; /* Maximum size for the volume */ +#ifndef ABI_EVMS_1_0 + sector_count_t shrink_vol_size; /* Size to which to shrink the volume */ +#endif + struct logical_volume_s * associated_volume; /* Volume to which this volume is associated */ + /* by an associative feature */ + option_array_t * mkfs_options; /* Options for mkfs */ + option_array_t * fsck_options; /* Options for fsck */ + option_array_t * defrag_options; /* Options for defrag */ + storage_object_t * object; /* Top level storage_object_t for the volume */ + uint minor_number; /* Volume's minor number */ + u_int64_t serial_number; /* Volume's serial number */ + u_int32_t flags; /* Defined by VOLFLAG_???? defines */ + void * private_data; /* Private data pointer for FSIMs. */ + char name[EVMS_VOLUME_NAME_SIZE+1]; + /* Volume name, filled in by the Engine */ +#ifndef ABI_EVMS_1_0 + char dev_node[EVMS_VOLUME_NAME_SIZE+1]; + /* Device node */ +#endif +} logical_volume_t; + + +/* + * Structure for a declined object. Includes a pointer to the declined object + * and a reason (usually an error code). + */ +typedef struct declined_object_s { + storage_object_t * object; + int reason; +} declined_object_t; + + +/* + * Tags for objects in dlists + */ +typedef enum { + PLUGIN_TAG = PLUGIN, + DISK_TAG = DISK, + SEGMENT_TAG = SEGMENT, + REGION_TAG = REGION, + EVMS_OBJECT_TAG = EVMS_OBJECT, + CONTAINER_TAG = CONTAINER, + VOLUME_TAG = VOLUME, + DECLINED_OBJECT_TAG = (1<<7), + VOLUME_DATA_TAG = (1<<8), + TASK_TAG = (1<<9), + KILL_SECTOR_TAG = (1<<10), + BLOCK_RUN_TAG = (1<<11), + EXPAND_OBJECT_TAG = (1<<12), + SHRINK_OBJECT_TAG = (1<<13) +} dlist_tag_t; + + +typedef struct chs_s { + u_int32_t cylinder; + u_int32_t head; + u_int32_t sector; +} chs_t; + +/* + * The block_run_t is used to describe a run of contiguous physical sectors on + * a disk. + */ +typedef struct block_run_s { + storage_object_t * disk; + lba_t lba; + u_int64_t number_of_blocks; +} block_run_t; + +/* + * The kill_sector_record_t structure records a run of contiguous physical + * sectors on a disk that are to be zeroed out as part of the committing of + * changes to the disk. Kill sectors are used to wipe data off of the disk + * so that it will not be found on a rediscover. + */ +typedef struct kill_sector_record_s { + storage_object_t * logical_disk; + lsn_t sector_offset; + sector_count_t sector_count; +} kill_sector_record_t; + +/* + * The expand_object_info_t structure contains information about an object + * that is a candidate for expanding. It contains a pointer to the object + * and the maximum delta size by which the object can expand. + */ +typedef struct expand_object_info_s { + storage_object_t * object; + sector_count_t max_expand_size; +} expand_object_info_t; + +/* + * The shrink_object_info_t structure contains information about an object + * that is a candidate for shrinking. It contains a pointer to the object + * and the maximum delta size by which the object can shrink. + */ +typedef struct shrink_object_info_s { + storage_object_t * object; + sector_count_t max_shrink_size; +} shrink_object_info_t; + +/* + * Option descriptor structure + */ +typedef struct option_desc_array_s { + u_int32_t count; /* Number of option descriptors in the following array */ + option_descriptor_t option[1]; /* option_descriptor_t is defined in option.h */ +} option_desc_array_t; + + +/* + * Task context structure + */ +typedef struct task_context_s { + plugin_record_t * plugin; /* Plug-in being communicated with */ + storage_object_t * object; /* Object upon which to do the action */ + storage_container_t * container; /* Container upon which to do the action */ + logical_volume_t * volume; /* Volume upon which to do the action */ + task_action_t action; /* API application is interested in calling */ + option_desc_array_t * option_descriptors; /* Array of current task option descriptors */ + dlist_t acceptable_objects; /* Current list of acceptable parameters */ + dlist_t selected_objects; /* Current list of selected parameters */ + u_int32_t min_selected_objects; /* Minimum number of objects that must be selected. */ + u_int32_t max_selected_objects; /* Maximum number of objects that can be selected. */ +} task_context_t; + + +/* Enum for the phases of the commit process. */ +typedef enum { + SETUP = 0, + FIRST_METADATA_WRITE = 1, + SECOND_METADATA_WRITE = 2, + POST_REDISCOVER = 3 +} commit_phase_t; + + +/* + * Macros for referencing fields in disk structures. + * EVMS writes all disk structures in little endian format. These macros can + * be used to access the fields of structures on disk regardless of the + * endianness of the CPU architecture. + */ + +#if __BYTE_ORDER == __BIG_ENDIAN +#define CPU_TO_DISK16(x) (bswap_16(x)) +#define CPU_TO_DISK32(x) (bswap_32(x)) +#define CPU_TO_DISK64(x) (bswap_64(x)) + +#define DISK_TO_CPU16(x) (bswap_16(x)) +#define DISK_TO_CPU32(x) (bswap_32(x)) +#define DISK_TO_CPU64(x) (bswap_64(x)) + +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#define CPU_TO_DISK16(x) (x) +#define CPU_TO_DISK32(x) (x) +#define CPU_TO_DISK64(x) (x) + +#define DISK_TO_CPU16(x) (x) +#define DISK_TO_CPU32(x) (x) +#define DISK_TO_CPU64(x) (x) + +#else +#error "__BYTE_ORDER must be defined as __LITTLE_ENDIAN or __BIG_ENDIAN" + +#endif + +#endif diff --git a/lib/evms/evms_common.h b/lib/evms/evms_common.h new file mode 100644 index 00000000..28249eac --- /dev/null +++ b/lib/evms/evms_common.h @@ -0,0 +1,161 @@ +/* -*- linux-c -*- */ +/* + * + * Copyright (c) International Business Machines Corp., 2000 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* + * linux/include/linux/evms/evms_common.h + * + * EVMS common (kernel and user) header file + * + */ + +#ifndef __EVMS_COMMON_INCLUDED__ +#define __EVMS_COMMON_INCLUDED__ + +/* version info */ +#define EVMS_MAJOR 63 /* use experimental major 63 for now */ +#define EVMS_MAJOR_VERSION 1 +#define EVMS_MINOR_VERSION 1 +#define EVMS_PATCHLEVEL_VERSION 0 + +#define MAX_EVMS_VOLUMES 256 /* There are 256 minors */ +#define EVMS_VOLUME_NAME_SIZE 127 + +#define IBM_OEM_ID 8112 // could be anything, but used + // I=8, B=1, M=12 +// this one going away as well. +#define EVMS_OEM_IBM IBM_OEM_ID + +#define EVMS_INITIAL_CRC 0xFFFFFFFF +#define EVMS_MAGIC_CRC 0x31415926 + +#define EVMS_VSECTOR_SIZE 512 +#define EVMS_VSECTOR_SIZE_SHIFT 9 + +#define DEV_PATH "/dev" +#define EVMS_DIR_NAME "evms" +#define EVMS_DEV_NAME "block_device" +#define EVMS_DEV_NODE_PATH DEV_PATH "/" EVMS_DIR_NAME "/" +#define EVMS_DEVICE_NAME DEV_PATH "/" EVMS_DIR_NAME "/" EVMS_DEV_NAME + +/* EVMS will always use 64-bit fields */ +typedef u_int64_t evms_sector_t; + +/* EVMS specific device handle type definition */ +typedef u_int64_t evms_dev_handle_t; + +typedef struct evms_version_s { + /* major changes when incompatible differences are introduced */ + u_int32_t major; + /* minor changes when additions are made */ + u_int32_t minor; + /* patchlevel changes when bugs are fixed */ + u_int32_t patchlevel; +} evms_version_t; + +typedef enum evms_plugin_code_s { + EVMS_NO_PLUGIN, // 0 + EVMS_DEVICE_MANAGER, // 1 + EVMS_SEGMENT_MANAGER, // 2 + EVMS_REGION_MANAGER, // 3 + EVMS_FEATURE, // 4 + EVMS_ASSOCIATIVE_FEATURE, // 5 + EVMS_FILESYSTEM_INTERFACE_MODULE, // 6 + EVMS_CLUSTER_MANAGER_INTERFACE_MODULE, // 7 + EVMS_DISTRIBUTED_LOCK_MANAGER_INTERFACE_MODULE // 8 +} evms_plugin_code_t; + +#define SetPluginID(oem, type, id) ((oem << 16) | (type << 12) | id) +#define GetPluginOEM(pluginid) (pluginid >> 16) +#define GetPluginType(pluginid) ((pluginid >> 12) & 0xf) +#define GetPluginID(pluginid) (pluginid & 0xfff) + +/* bit definitions for the flags field in + * the EVMS LOGICAL NODE (kernel) and + * the EVMS LOGICAL VOLUME (user) structures. + */ +#define EVMS_FLAGS_WIDTH 32 +#define EVMS_VOLUME_FLAG (1<<0) +#define EVMS_VOLUME_PARTIAL_FLAG (1<<1) +#define EVMS_VOLUME_PARTIAL (1<<1) +#define EVMS_VOLUME_SET_READ_ONLY (1<<2) +#define EVMS_VOLUME_READ_ONLY (1<<2) +/* queued flags bits */ +#define EVMS_REQUESTED_DELETE (1<<5) +#define EVMS_REQUESTED_QUIESCE (1<<6) +#define EVMS_REQUESTED_VFS_QUIESCE (1<<7) +/* this bit indicates corruption */ +#define EVMS_VOLUME_CORRUPT (1<<8) +/* these bits define the source of the corruption */ +#define EVMS_VOLUME_SOFT_DELETED (1<<9) +#define EVMS_DEVICE_UNAVAILABLE (1<<10) +/* these bits define volume status */ +#define EVMS_MEDIA_CHANGED (1<<20) +#define EVMS_DEVICE_UNPLUGGED (1<<21) +/* these bits used for removable status */ +#define EVMS_DEVICE_MEDIA_PRESENT (1<<24) +#define EVMS_DEVICE_PRESENT (1<<25) +#define EVMS_DEVICE_LOCKABLE (1<<26) +#define EVMS_DEVICE_REMOVABLE (1<<27) + +/* version info for evms_feature_header_t */ +#define EVMS_FEATURE_HEADER_MAJOR 3 +#define EVMS_FEATURE_HEADER_MINOR 0 +#define EVMS_FEATURE_HEADER_PATCHLEVEL 0 + +/* bit definitions of FEATURE HEADER bits in the FLAGS field */ +#define EVMS_FEATURE_ACTIVE (1<<0) +#define EVMS_FEATURE_VOLUME_COMPLETE (1<<1) +/* bit definitions for VOLUME bits in the FLAGS field */ +#define EVMS_VOLUME_DATA_OBJECT (1<<16) +#define EVMS_VOLUME_DATA_STOP (1<<17) + +#define EVMS_FEATURE_HEADER_SIGNATURE 0x54414546 //FEAT +typedef struct evms_feature_header_s { +/* 0*/ u_int32_t signature; +/* 4*/ u_int32_t crc; +/* 8*/ evms_version_t version; /* structure version */ +/* 20*/ evms_version_t engine_version; /* version of the Engine that */ + /* wrote this feature header */ +/* 32*/ u_int32_t flags; +/* 36*/ u_int32_t feature_id; +/* 40*/ u_int64_t sequence_number; +/* 48*/ u_int64_t alignment_padding; + //required: starting lsn to 1st copy of feature's metadata. +/* 56*/ evms_sector_t feature_data1_start_lsn; +/* 64*/ evms_sector_t feature_data1_size; //in 512 byte units + //optional: starting lsn to 2nd copy of feature's metadata. + // if unused set size field to 0. +/* 72*/ evms_sector_t feature_data2_start_lsn; +/* 80*/ evms_sector_t feature_data2_size; //in 512 byte units +/* 88*/ u_int64_t volume_serial_number; +/* 96*/ u_int32_t volume_system_id; /* the minor is stored here */ +/*100*/ u_int32_t object_depth; /* depth of object in the volume tree */ +/*104*/ char object_name[EVMS_VOLUME_NAME_SIZE+1]; +/*232*/ char volume_name[EVMS_VOLUME_NAME_SIZE+1]; +/*360*/ unsigned char pad[152]; +/*512*/ +} evms_feature_header_t; + +/* EVMS specific error codes */ +#define EVMS_FEATURE_FATAL_ERROR 257 +#define EVMS_VOLUME_FATAL_ERROR 258 + +#define EVMS_FEATURE_INCOMPLETE_ERROR 259 + +#endif diff --git a/lib/evms/evms_ioctl.h b/lib/evms/evms_ioctl.h new file mode 100644 index 00000000..11315494 --- /dev/null +++ b/lib/evms/evms_ioctl.h @@ -0,0 +1,297 @@ +/* -*- linux-c -*- */ +/* + * + * Copyright (c) International Business Machines Corp., 2000 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* + * linux/include/linux/evms.h + * + * EVMS public kernel header file + * + */ + +#ifndef __EVMS_IOCTL_INCLUDED__ +#define __EVMS_IOCTL_INCLUDED__ + +#include + +/* IOCTL interface version definitions */ +#define EVMS_IOCTL_INTERFACE_MAJOR 10 +#define EVMS_IOCTL_INTERFACE_MINOR 0 +#define EVMS_IOCTL_INTERFACE_PATCHLEVEL 0 + +/* IOCTL definitions */ +typedef enum evms_ioctl_cmds_s { + /* version commands */ + EVMS_GET_IOCTL_VERSION_NUMBER = 0, + EVMS_GET_VERSION_NUMBER, +#ifdef __KERNEL__ + /* EVMS internal commands */ + EVMS_GET_DISK_LIST_NUMBER = 0x40, + EVMS_CHECK_MEDIA_CHANGE_NUMBER, + EVMS_REVALIDATE_DISK_NUMBER, + EVMS_OPEN_VOLUME_NUMBER, + EVMS_CLOSE_VOLUME_NUMBER, + EVMS_QUIESCE_VOLUME_NUMBER, + EVMS_CHECK_DEVICE_STATUS_NUMBER, +#endif + /* configuration commands */ + EVMS_GET_INFO_LEVEL_NUMBER = 0x80, + EVMS_SET_INFO_LEVEL_NUMBER, + EVMS_REDISCOVER_VOLUMES_NUMBER, + EVMS_DELETE_VOLUME_NUMBER, + EVMS_PLUGIN_IOCTL_NUMBER, + EVMS_PROCESS_NOTIFY_EVENT_NUMBER, + /* query info commands */ + EVMS_GET_LOGICAL_DISK_NUMBER = 0xC0, + EVMS_GET_LOGICAL_DISK_INFO_NUMBER, + EVMS_SECTOR_IO_NUMBER, + EVMS_GET_MINOR_NUMBER, + EVMS_GET_VOLUME_DATA_NUMBER, + EVMS_GET_PLUGIN_NUMBER, + EVMS_COMPUTE_CSUM_NUMBER, + EVMS_GET_BMAP_NUMBER, +} evms_ioctl_cmds_t; + +/* version commands */ +#define EVMS_GET_IOCTL_VERSION_STRING "EVMS_GET_IOCTL_VERSION" +#define EVMS_GET_IOCTL_VERSION _IOR(EVMS_MAJOR, EVMS_GET_IOCTL_VERSION_NUMBER, evms_version_t) + +#define EVMS_GET_VERSION_STRING "EVMS_GET_VERSION" +#define EVMS_GET_VERSION _IOR(EVMS_MAJOR, EVMS_GET_VERSION_NUMBER, evms_version_t) + +#ifdef __KERNEL__ + +/* EVMS internal commands */ +#define EVMS_GET_DISK_LIST_STRING "EVMS_GET_DISK_LIST" +#define EVMS_GET_DISK_LIST _IOWR(EVMS_MAJOR, EVMS_GET_DISK_LIST_NUMBER, evms_list_node_t **) + +#define EVMS_CHECK_MEDIA_CHANGE_STRING "EVMS_CHECK_MEDIA_CHANGE" +#define EVMS_CHECK_MEDIA_CHANGE _IO(EVMS_MAJOR, EVMS_CHECK_MEDIA_CHANGE_NUMBER) + +#define EVMS_REVALIDATE_DISK_STRING "EVMS_REVALIDATE_DISK" +#define EVMS_REVALIDATE_DISK _IO(EVMS_MAJOR, EVMS_REVALIDATE_DISK_NUMBER) + +#define EVMS_OPEN_VOLUME_STRING "EVMS_OPEN_VOLUME" +#define EVMS_OPEN_VOLUME _IO(EVMS_MAJOR, EVMS_OPEN_VOLUME_NUMBER) + +#define EVMS_CLOSE_VOLUME_STRING "EVMS_CLOSE_VOLUME" +#define EVMS_CLOSE_VOLUME _IO(EVMS_MAJOR, EVMS_CLOSE_VOLUME_NUMBER) + +/* field: command: defines */ +#define EVMS_UNQUIESCE 0 +#define EVMS_QUIESCE 1 + +/* field: do_vfs: defines */ +/* see evms_delete_volume */ +typedef struct evms_quiesce_volume_s { + int command; /* 0 = unquiesce, 1 = quiesce */ + int minor; /* minor device number of target volume */ + int do_vfs; /* 0 = do nothing, 1 = also perform equivalent VFS operation */ + int status; /* 0 = success */ +} evms_quiesce_volume_t; + +#define EVMS_QUIESCE_VOLUME_STRING "EVMS_QUIESCE_VOLUME" +#define EVMS_QUIESCE_VOLUME _IOR(EVMS_MAJOR, EVMS_QUIESCE_VOLUME_NUMBER, evms_quiesce_volume_t) + +#define EVMS_CHECK_DEVICE_STATUS_STRING "EVMS_CHECK_DEVICE_STATUS" +#define EVMS_CHECK_DEVICE_STATUS _IOR(EVMS_MAJOR, EVMS_CHECK_DEVICE_STATUS_NUMBER, int) + +#endif + +/* configuration commands */ +#define EVMS_GET_INFO_LEVEL_STRING "EVMS_GET_INFO_LEVEL" +#define EVMS_GET_INFO_LEVEL _IOR(EVMS_MAJOR, EVMS_GET_INFO_LEVEL_NUMBER, int) + +#define EVMS_SET_INFO_LEVEL_STRING "EVMS_SET_INFO_LEVEL" +#define EVMS_SET_INFO_LEVEL _IOW(EVMS_MAJOR, EVMS_SET_INFO_LEVEL_NUMBER, int) + +/* field: drive_count: defines */ +#define REDISCOVER_ALL_DEVICES 0xFFFFFFFF +typedef struct evms_rediscover_s { + int status; + unsigned int drive_count; /* 0xffffffff = rediscover all known disks */ + unsigned long *drive_array; +} evms_rediscover_t; + +#define EVMS_REDISCOVER_VOLUMES_STRING "EVMS_REDISCOVER_VOLUMES" +#define EVMS_REDISCOVER_VOLUMES _IOWR(EVMS_MAJOR, EVMS_REDISCOVER_VOLUMES_NUMBER, evms_rediscover_t) + +/* field: command: defines */ +#define EVMS_SOFT_DELETE 0 +#define EVMS_HARD_DELETE 1 + +/* field: do_vfs: defines */ +#define EVMS_VFS_DO_NOTHING 0 +#define EVMS_VFS_DO 1 +typedef struct evms_delete_volume_s { + int command; /* 0 = "temp", 1 = "permanent" */ + int minor; /* minor device number of target volume */ + int do_vfs; /* 0 = do nothing, 1 = perform VFS operations */ + int associative_minor; /* optional minor of associative volume */ + /* must be 0 when not in use */ + int status; /* 0 = success, other is error */ +} evms_delete_volume_t; + +#define EVMS_DELETE_VOLUME_STRING "EVMS_DELETE_VOLUME" +#define EVMS_DELETE_VOLUME _IOR(EVMS_MAJOR, EVMS_DELETE_VOLUME_NUMBER, evms_delete_volume_t) + +typedef struct evms_plugin_ioctl_s { + unsigned long feature_id; /* ID of feature to receive this ioctl */ + int feature_command; /* feature specific ioctl command */ + int status; /* 0 = completed, non-0 = error */ + void *feature_ioctl_data; /* ptr to feature specific struct */ +} evms_plugin_ioctl_t; + +#define EVMS_PLUGIN_IOCTL_STRING "EVMS_PLUGIN_IOCTL" +#define EVMS_PLUGIN_IOCTL _IOR(EVMS_MAJOR, EVMS_PLUGIN_IOCTL_NUMBER, evms_plugin_ioctl_t) + +/* field: eventid: defines */ +#define EVMS_EVENT_END_OF_DISCOVERY 0 +typedef struct evms_event_s { + int pid; /* PID to act on */ + int eventid; /* event id to respond to */ + int signo; /* signal # to send when event occurs */ +} evms_event_t; + +/* field: command: defines */ +#define EVMS_EVENT_UNREGISTER 0 +#define EVMS_EVENT_REGISTER 1 +typedef struct evms_notify_s { + int command; /* 0 = unregister, 1 = register */ + evms_event_t eventry; /* event structure */ + int status; /* return status */ +} evms_notify_t; + +#define EVMS_PROCESS_NOTIFY_EVENT_STRING "EVMS_PROCESS_NOTIFY_EVENT" +#define EVMS_PROCESS_NOTIFY_EVENT _IOWR(EVMS_MAJOR, EVMS_PROCESS_NOTIFY_EVENT_NUMBER, evms_notify_t) + +/* query info commands */ + +/* field: command: defines */ +#define EVMS_FIRST_DISK 0 +#define EVMS_NEXT_DISK 1 + +/* field: status: defines */ +#define EVMS_DISK_INVALID 0 +#define EVMS_DISK_VALID 1 +typedef struct evms_user_disk_s { + int command; /* 0 = first disk, 1 = next disk */ + int status; /* 0 = no more disks, 1 = valid disk info */ + unsigned long disk_handle; /* only valid when status == 1 */ +} evms_user_disk_t; + +#define EVMS_GET_LOGICAL_DISK_STRING "EVMS_GET_LOGICAL_DISK" +#define EVMS_GET_LOGICAL_DISK _IOWR(EVMS_MAJOR, EVMS_GET_LOGICAL_DISK_NUMBER, evms_user_disk_t) + +/* flags fields described in evms_common.h */ +typedef struct evms_user_disk_info_s { + unsigned int status; + unsigned int flags; + unsigned long disk_handle; + unsigned int disk_dev; + struct hd_geometry geometry; + unsigned int block_size; + unsigned int hardsect_size; + u_int64_t total_sectors; + char disk_name[EVMS_VOLUME_NAME_SIZE]; +} evms_user_disk_info_t; + +#define EVMS_GET_LOGICAL_DISK_INFO_STRING "EVMS_GET_LOGICAL_DISK_INFO" +#define EVMS_GET_LOGICAL_DISK_INFO _IOWR(EVMS_MAJOR, EVMS_GET_LOGICAL_DISK_INFO_NUMBER, evms_user_disk_info_t) + +/* field: io_flag: defines */ +#define EVMS_SECTOR_IO_READ 0 +#define EVMS_SECTOR_IO_WRITE 1 +typedef struct evms_sector_io_s { + unsigned long disk_handle; /* valid disk handle */ + int io_flag; /* 0 = READ, 1 = WRITE */ + evms_sector_t starting_sector; /* disk relative LBA */ + evms_sector_t sector_count; /* number of sectors in IO */ + unsigned char *buffer_address; /* IO address */ + int status; /* 0 = success, not 0 = error */ +} evms_sector_io_t; + +#define EVMS_SECTOR_IO_STRING "EVMS_SECTOR_IO" +#define EVMS_SECTOR_IO _IOWR(EVMS_MAJOR, EVMS_SECTOR_IO_NUMBER, evms_sector_io_t) + +/* field: command: defines */ +#define EVMS_FIRST_VOLUME 0 +#define EVMS_NEXT_VOLUME 1 + +/* field: status: defines */ +#define EVMS_VOLUME_INVALID 0 +#define EVMS_VOLUME_VALID 1 +typedef struct evms_user_minor_s { + int command; /* 0 = first volume, 1 = next volume */ + int status; /* 0 = no more, 1 = valid info */ + int minor; /* only valid when status == 1 */ +} evms_user_minor_t; + +#define EVMS_GET_MINOR_STRING "EVMS_GET_MINOR" +#define EVMS_GET_MINOR _IOWR(EVMS_MAJOR, EVMS_GET_MINOR_NUMBER, evms_user_minor_t) + +/* flags field described in evms_common.h */ +typedef struct evms_volume_data_s { + int minor; /* minor of target volume */ + int flags; + char volume_name[EVMS_VOLUME_NAME_SIZE + 1]; + int status; +} evms_volume_data_t; + +#define EVMS_GET_VOLUME_DATA_STRING "EVMS_GET_VOLUME_DATA" +#define EVMS_GET_VOLUME_DATA _IOWR(EVMS_MAJOR, EVMS_GET_VOLUME_DATA_NUMBER, evms_volume_data_t) + +/* field: command: defines */ +#define EVMS_FIRST_PLUGIN 0 +#define EVMS_NEXT_PLUGIN 1 + +/* field: status: defines */ +#define EVMS_PLUGIN_INVALID 0 +#define EVMS_PLUGIN_VALID 1 +typedef struct evms_kernel_plugin_s { + int command; /* 0 = first item, 1 = next item */ + u_int32_t id; /* returned plugin id */ + evms_version_t version; /* maj,min,patch of plugin */ + int status; /* 0 = no more, 1 = valid info */ +} evms_kernel_plugin_t; + +#define EVMS_GET_PLUGIN_STRING "EVMS_GET_PLUGIN" +#define EVMS_GET_PLUGIN _IOWR(EVMS_MAJOR, EVMS_GET_PLUGIN_NUMBER, evms_kernel_plugin_t) + +typedef struct evms_compute_csum_s { + unsigned char *buffer_address; /* IO address */ + int buffer_size; /* byte size of buffer */ + unsigned int insum; /* previous csum to be factored in */ + unsigned int outsum; /* resulting csum value of buffer */ + int status; /* 0 = success, not 0 = error */ +} evms_compute_csum_t; + +#define EVMS_COMPUTE_CSUM_STRING "EVMS_COMPUTE_CSUM" +#define EVMS_COMPUTE_CSUM _IOWR(EVMS_MAJOR, EVMS_COMPUTE_CSUM_NUMBER, evms_compute_csum_t) + +typedef struct evms_get_bmap_s { + u_int64_t rsector; /* input: volume relative rsector value */ + /* output: disk relative rsector value */ + u_int32_t dev; /* output = physical device */ + int status; /* 0 = success, not 0 = error */ +} evms_get_bmap_t; + +#define EVMS_GET_BMAP_STRING "EVMS_GET_BMAP" +#define EVMS_GET_BMAP _IOWR(EVMS_MAJOR, EVMS_GET_BMAP_NUMBER, evms_get_bmap_t) + +#endif diff --git a/lib/evms/evms_user.h b/lib/evms/evms_user.h new file mode 100644 index 00000000..cd13a81e --- /dev/null +++ b/lib/evms/evms_user.h @@ -0,0 +1,28 @@ +/* -*- linux-c -*- */ +/* + * + * Copyright (c) International Business Machines Corp., 2000 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* + * linux/include/linux/evms_user.h + * + * EVMS (master) user header file + * + */ + +#include +#include diff --git a/lib/evms/fs_ext2.c b/lib/evms/fs_ext2.c new file mode 100644 index 00000000..baa954fa --- /dev/null +++ b/lib/evms/fs_ext2.c @@ -0,0 +1,1141 @@ +/* + * + * Copyright (c) International Business Machines Corp., 2000 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Module: fs_ext2.c + * + */ + +#include +#include +#include +#include +#include +#include +#include "fsimext2.h" + +static plugin_record_t *pMyPluginRecord = &ext2_plugrec; + +/*-------------------------------------------------------------------------------------+ ++ + ++ Start Of EVMS Plugin Functions + ++ (exported to engine via function table) + ++ + ++-------------------------------------------------------------------------------------*/ + + +static int fs_setup( engine_mode_t mode, engine_functions_t *engine_function_table) +{ + int rc = 0; + EngFncs = engine_function_table; + + LOGENTRY(); + + /* + * We don't really care about the e2fsprogs version, but we leave + * this here in case we do at a later date.... + */ + rc = fsim_test_version(); + if ( rc ) { + MESSAGE( "e2fsprogs must be version 1.XXX or later to function properly with this FSIM." ); + MESSAGE( "Please get the current version of e2fsprogs from http://e2fsprogs.sourceforge.net" ); + rc = ENOSYS; + } + + LOGEXIT(); + return rc; +} + + +/* + * Free all of the private data item we have left on volumes. + */ +static void fs_cleanup() +{ + int rc = 0; + dlist_t global_volumes; + logical_volume_t * volume; + LOGENTRY(); + + rc = EngFncs->get_volume_list(pMyPluginRecord, &global_volumes); + if (!rc) { + while (ExtractObject(global_volumes, sizeof(logical_volume_t), VOLUME_TAG, NULL, (void**)&volume)==0) { + if (volume->private_data) { + EngFncs->engine_free(volume->private_data); + } + } + } + LOGEXIT(); +} + + +/* + * Does this FSIM manage the file system on this volume? + * Return 0 for "yes", else a reason code. + */ +static int fs_probe(logical_volume_t * volume) +{ + int rc = 0; + struct ext2_super_block *sb_ptr; + + LOGENTRY(); + + /* allocate space for copy of superblock in private data */ + sb_ptr = EngFncs->engine_alloc( SIZE_OF_SUPER ); + + if ( sb_ptr ) { + memset( (void *) sb_ptr, 0, SIZE_OF_SUPER ); + + /* get and validate ext2 superblock */ + rc = fsim_get_ext2_superblock( volume, sb_ptr ); + + if ( !rc ) { + /* store copy of valid EXT2/3 superblock in private data */ + volume->private_data = (void*)sb_ptr; + } else { + /* could not get valid EXT2/3 superblock */ + volume->private_data = NULL; + } + } else { + rc = ENOMEM; + } + + LOGEXITRC(); + return rc; +} + + +/* + * Can mkfs this volume? + */ +static int fs_can_mkfs(logical_volume_t * volume) +{ + int rc=0; + + LOGENTRY(); + + /***************************************************** + * FUTURE - ensure mke2fs exists * + *****************************************************/ + + if (EVMS_IS_MOUNTED(volume)) { + /* If mounted, can't format. */ + rc = EBUSY; + } else if ((volume->vol_size * PBSIZE) < MINEXT2) { + /* voluem size must be >= MINEXT2 */ + rc = EPERM; + } + + LOGEXITRC(); + return rc; +} + + +/* + * Can unmkfs this volume? + */ +static int fs_can_unmkfs(logical_volume_t * volume) +{ + int rc=0; + + LOGENTRY(); + + if (EVMS_IS_MOUNTED(volume)) { + /* If mounted, can't unmkfs. */ + rc = EBUSY; + } + + LOGEXITRC(); + return rc; + +} + + +/* + * Can fsck this volume? + */ +static int fs_can_fsck(logical_volume_t * volume) +{ + int rc=0; + + LOGENTRY(); + + /***************************************************** + * FUTURE - ensure e2fsck exists * + * match version with available functions * + *****************************************************/ + + LOGEXITRC(); + return rc; +} + + +/* + * Get the current size of this volume + */ +static int fs_get_fs_size( logical_volume_t * volume, + sector_count_t * size ) +{ + int rc = EINVAL; + struct ext2_super_block *sb = (struct ext2_super_block *)volume->private_data; + + LOGENTRY(); + + if (!sb) { + LOGEXITRC(); + return rc; + } + + /* get and validate current ext2/3 superblock */ + rc = fsim_get_ext2_superblock( volume, sb ); + + if (!rc && sb) { + *size = sb->s_blocks_count << (1 + sb->s_log_block_size); + rc = 0; + } + + LOGEXITRC(); + return rc; +} + + +/* + * Get the size limits for this volume. + */ +static int fs_get_fs_limits( logical_volume_t * volume, + sector_count_t * min_size, + sector_count_t * max_volume_size, + sector_count_t * max_object_size) +{ + int rc = EINVAL; + struct ext2_super_block *sb_ptr = (struct ext2_super_block *) volume->private_data; + + LOGENTRY(); + + if (!sb_ptr) { + LOGEXITRC(); + return rc; + } + + /* get and validate current ext2 superblock */ + rc = fsim_get_ext2_superblock( volume, sb_ptr ); + + if ( !rc ) { + rc = fsim_get_volume_limits( sb_ptr, min_size, max_volume_size, max_object_size); + LOG_EXTRA("volume:%s, min:%lld, max:%lld\n",EVMS_GET_DEVNAME(volume), *min_size, *max_volume_size); + LOG_EXTRA("fssize:%lld, vol_size:%lld\n",volume->fs_size,volume->vol_size ); + + if (*min_size > volume->vol_size) { + LOG_ERROR("EXT2 FSIM returned min size > volume size, setting min size to volume size\n"); + *min_size = volume->vol_size; + } + } + + LOGEXITRC(); + return rc; +} + + +/* + * Expand the volume to new_size. If the volume is not expanded exactly to + * new_size, set new_sie to the new_size of the volume. + */ +static int fs_expand( logical_volume_t * volume, + sector_count_t * new_size ) +{ + /* unsupported at this time */ + int rc = ENOSYS; + + LOGENTRY(); + LOGEXITRC(); + return rc; +} + + +/* + * "unmkfs" the volume + */ +static int fs_unmkfs(logical_volume_t * volume) +{ + int rc = EINVAL; + LOGENTRY(); + + if (EVMS_IS_MOUNTED(volume)) { + /* If mounted, can't unmkfs. */ + rc = EBUSY; + } else if ( (rc = fsim_unmkfs(volume)) == FSIM_SUCCESS ){ + volume->private_data = NULL; + } + + LOGEXITRC(); + return rc; +} + + +/* + * Shrink the volume to new_size. If the volume is not expanded exactly to + * new_size, set new_size to the new_size of the volume. + */ +static int fs_shrink( logical_volume_t * volume, + sector_count_t requested_size, + sector_count_t * new_size ) +{ + /* unsupported at this time */ + int rc = ENOSYS; + + LOGENTRY(); + LOGEXITRC(); + return rc; +} + + + +/* + * Format the volume. + */ +static int fs_mkfs(logical_volume_t * volume, option_array_t * options ) +{ + int rc = 0; + + LOGENTRY(); + + /* don't format if mounted */ + if (EVMS_IS_MOUNTED(volume)) { + return EBUSY; + } + + rc = fsim_mkfs(volume, options); + + /* probe to set up private data */ + if ( !rc ) { + rc = fs_probe(volume); + } + + LOGEXITRC(); + return rc; +} + + +/* + * Run fsck on the volume. + */ +static int fs_fsck(logical_volume_t * volume, option_array_t * options ) +{ + int rc = EINVAL; + + LOGENTRY(); + + rc = fsim_fsck( volume, options ); + + /* + * If fsck.ext2 returns FSCK_CORRECTED, the + * file system is clean, so return FSCK_OK. + */ + if ( rc == FSCK_CORRECTED ) { + rc = FSCK_OK; + /* + * The value of FSCK_CORRECTED is the same as + * EPERM, so fsim_fsck will return -1 for EPERM. + */ + } else if (rc == -1) { + rc = EPERM; + } + + /* + * If the volume is mounted, e2fsck checked READ ONLY + * regardless of options specified. If the check was READ ONLY + * and errors were found, let the user know how to fix them. + */ + if (EVMS_IS_MOUNTED(volume) && rc) { + MESSAGE( "%s is mounted.", EVMS_GET_DEVNAME(volume) ); + MESSAGE( "e2fsck checked the volume READ ONLY and found, but did not fix, errors." ); + MESSAGE( "Unmount %s and run e2fsck again to repair the file system.", EVMS_GET_DEVNAME(volume) ); + } + + LOGEXITRC(); + return rc; +} + + +/* + * Return the total number of supported options for the specified task. + */ +static int fs_get_option_count(task_context_t * context) +{ + int count = 0; + + LOGENTRY(); + + switch(context->action) { + case EVMS_Task_mkfs: + count = MKFS_EXT2_OPTIONS_COUNT; + break; + case EVMS_Task_fsck: + count = FSCK_EXT2_OPTIONS_COUNT; + break; + default: + count = -1; + break; + } + + LOGEXIT(); + return count; +} + + +/* + * Fill in the initial list of acceptable objects. Fill in the minimum and + * maximum nuber of objects that must/can be selected. Set up all initial + * values in the option_descriptors in the context record for the given + * task. Some fields in the option_descriptor may be dependent on a + * selected object. Leave such fields blank for now, and fill in during the + * set_objects call. + */ +static int fs_init_task( task_context_t * context ) +{ + dlist_t global_volumes; + logical_volume_t * volume; + void* waste; + int size, tag; + int rc = 0; + option_descriptor_t *opt; + + LOGENTRY(); + + context->min_selected_objects = 0; + context->max_selected_objects = 1; + context->option_descriptors->count = 0; + + /* Parameter check */ + if (!context) { + return EFAULT; + } + + rc = EngFncs->get_volume_list(NULL, &global_volumes); + + while (!(rc = BlindExtractObject(global_volumes, &size, (TAG *)&tag, NULL, (void **)&volume))) { + + switch (context->action) { + case EVMS_Task_mkfs: + /* only mkfs unformatted volumes */ + if (volume->file_system_manager == NULL) { + rc = InsertObject(context->acceptable_objects, sizeof(logical_volume_t), volume, VOLUME_TAG, NULL, InsertAtStart, TRUE, (void **)&waste); + } + break; + + case EVMS_Task_fsck: + /* only fsck our stuff */ + if (volume->file_system_manager == &ext2_plugrec) { + rc = InsertObject(context->acceptable_objects, sizeof(logical_volume_t), volume, VOLUME_TAG, NULL, InsertAtStart, TRUE, (void **)&waste); + } + break; + + default: + rc = ENOSYS; + break; + } + } + + if (rc == DLIST_EMPTY || rc == DLIST_END_OF_LIST) { + rc = 0; + } + + switch (context->action) { + + case EVMS_Task_mkfs: + + context->option_descriptors->count = MKFS_EXT2_OPTIONS_COUNT; + + /* check for bad blocks option */ + opt = &context->option_descriptors->option[MKFS_CHECKBB_INDEX]; + SET_STRING(opt->name, "badblocks" ); + SET_STRING(opt->title, "Check For Bad Blocks" ); + SET_STRING(opt->tip, "Check the volume for bad blocks before building the file system." ); + opt->help = NULL; + opt->type = EVMS_Type_Boolean; + opt->unit = EVMS_Unit_None; +#ifdef ABI_EVMS_1_0 + opt->size = 0; +#endif + opt->flags = EVMS_OPTION_FLAGS_NOT_REQUIRED; + opt->constraint_type = EVMS_Collection_None; + opt->value.bool = FALSE; + + /* check for r/w bad blocks option */ + opt = &context->option_descriptors->option[MKFS_CHECKRW_INDEX]; + SET_STRING(opt->name, "badblocks_rw" ); + SET_STRING(opt->title, "RW Check For Bad Blocks" ); + SET_STRING(opt->tip, "Do a read/write check for bad blocks before building the file system." ); + opt->help = NULL; + opt->type = EVMS_Type_Boolean; + opt->unit = EVMS_Unit_None; +#ifdef ABI_EVMS_1_0 + opt->size = 0; +#endif + opt->flags = EVMS_OPTION_FLAGS_NOT_REQUIRED; + opt->constraint_type = EVMS_Collection_None; + opt->value.bool = FALSE; + + /* Set Volume Label option */ + opt = &context->option_descriptors->option[MKFS_SETVOL_INDEX]; + SET_STRING(opt->name, "vollabel" ); + SET_STRING(opt->title, "Volume Label" ); + SET_STRING(opt->tip, "Set the volume label for the file system." ); + opt->help = NULL; + opt->type = EVMS_Type_String; + opt->unit = EVMS_Unit_None; +#ifdef ABI_EVMS_1_0 + opt->size = 16; +#else + opt->min_len = 0; + opt->max_len = 16; +#endif + opt->flags = EVMS_OPTION_FLAGS_NOT_REQUIRED | EVMS_OPTION_FLAGS_NO_INITIAL_VALUE; + opt->constraint_type = EVMS_Collection_None; + opt->value.s = EngFncs->engine_alloc(17); + if (opt->value.s == NULL) { + LOGEXIT(); + return ENOMEM; + } + + /* create ext3 journal option */ + opt = &context->option_descriptors->option[MKFS_JOURNAL_INDEX]; + SET_STRING(opt->name, "journal" ); + SET_STRING(opt->title, "Create Ext3 Journal" ); + SET_STRING(opt->tip, "Create a journal for use with the ext3 file system." ); + opt->help = NULL; + opt->type = EVMS_Type_Boolean; + opt->unit = EVMS_Unit_None; +#ifdef ABI_EVMS_1_0 + opt->size = 0; +#endif + opt->flags = EVMS_OPTION_FLAGS_NOT_REQUIRED; + opt->constraint_type = EVMS_Collection_None; + opt->value.bool = TRUE; + + break; + + case EVMS_Task_fsck: + + context->option_descriptors->count = FSCK_EXT2_OPTIONS_COUNT; + + /* force check option */ + opt = &context->option_descriptors->option[FSCK_FORCE_INDEX]; + SET_STRING(opt->name, "force" ); + SET_STRING(opt->title, "Force Check" ); + SET_STRING(opt->tip, "Force complete file system check." ); + opt->help = NULL; + opt->type = EVMS_Type_Boolean; + opt->unit = EVMS_Unit_None; +#ifdef ABI_EVMS_1_0 + opt->size = 0; +#endif + opt->flags = EVMS_OPTION_FLAGS_NOT_REQUIRED; + opt->constraint_type = EVMS_Collection_None; + opt->value.bool = FALSE; + + /* read-only check option */ + opt = &context->option_descriptors->option[FSCK_READONLY_INDEX]; + SET_STRING(opt->name, "readonly" ); + SET_STRING(opt->title, "Check Read-Only" ); + SET_STRING(opt->tip, "Check the file system READ ONLY. Report but do not correct errors." ); + opt->help = NULL; + opt->type = EVMS_Type_Boolean; + opt->unit = EVMS_Unit_None; +#ifdef ABI_EVMS_1_0 + opt->size = 0; +#endif + opt->flags = EVMS_OPTION_FLAGS_NOT_REQUIRED; + opt->constraint_type = EVMS_Collection_None; + /* if volume is mounted, only possible fsck.ext2 options is READONLY */ + if (EVMS_IS_MOUNTED(context->volume)) { + opt->value.bool = TRUE; + } else { + opt->value.bool = FALSE; + } + + /* check for bad blocks option */ + opt = &context->option_descriptors->option[FSCK_CHECKBB_INDEX]; + SET_STRING(opt->name, "badblocks" ); + SET_STRING(opt->title, "Check For Bad Blocks" ); + SET_STRING(opt->tip, "Check for bad blocks and mark them as busy." ); + opt->help = NULL; +#ifdef ABI_EVMS_1_0 + opt->size = 0; +#endif + opt->type = EVMS_Type_Boolean; + opt->unit = EVMS_Unit_None; + if (EVMS_IS_MOUNTED(context->volume)) { + opt->flags = EVMS_OPTION_FLAGS_INACTIVE; + } else { + opt->flags = EVMS_OPTION_FLAGS_NOT_REQUIRED; + } + opt->constraint_type = EVMS_Collection_None; + opt->value.bool = FALSE; + + /* check for r/w bad blocks option */ + opt = &context->option_descriptors->option[FSCK_CHECKRW_INDEX]; + SET_STRING(opt->name, "badblocks_rw" ); + SET_STRING(opt->title, "RW Check For Bad Blocks" ); + SET_STRING(opt->tip, "Do a read/write check for bad blocks and mark them as busy." ); + opt->help = NULL; + opt->type = EVMS_Type_Boolean; + opt->unit = EVMS_Unit_None; +#ifdef ABI_EVMS_1_0 + opt->size = 0; +#endif + if (EVMS_IS_MOUNTED(context->volume)) { + opt->flags = EVMS_OPTION_FLAGS_INACTIVE; + } else { + opt->flags = EVMS_OPTION_FLAGS_NOT_REQUIRED; + } + opt->constraint_type = EVMS_Collection_None; + opt->value.bool = FALSE; + + /* timing option */ + opt = &context->option_descriptors->option[FSCK_TIMING_INDEX]; + SET_STRING(opt->name, "timing" ); + SET_STRING(opt->title, "Timing Statistics" ); + SET_STRING(opt->tip, "Print timing statistics." ); + opt->help = NULL; + opt->type = EVMS_Type_Boolean; + opt->unit = EVMS_Unit_None; +#ifdef ABI_EVMS_1_0 + opt->size = 0; +#endif + opt->flags = EVMS_OPTION_FLAGS_NOT_REQUIRED | EVMS_OPTION_FLAGS_INACTIVE; + opt->constraint_type = EVMS_Collection_None; + opt->value.bool = FALSE; + break; + + default: + break; + } + + LOGEXITRC(); + + return rc; + +} + + +/* + * Examine the specified value, and determine if it is valid for the task + * and option_descriptor index. If it is acceptable, set that value in the + * appropriate entry in the option_descriptor. The value may be adjusted + * if necessary/allowed. If so, set the effect return value accordingly. + */ +static int fs_set_option( task_context_t * context, + u_int32_t index, + value_t * value, + task_effect_t * effect ) +{ + int rc= 0, other; + + LOGENTRY(); + + /* Parameter check */ + if (!context || !value || !effect) { + return EFAULT; + } + + *effect = 0; + + switch (context->action) { + + case EVMS_Task_mkfs: + switch (index) { + + case MKFS_CHECKBB_INDEX: + case MKFS_CHECKRW_INDEX: + /* Conflicts with each other */ + if (index == MKFS_CHECKBB_INDEX) + other = MKFS_CHECKRW_INDEX; + else + other = MKFS_CHECKBB_INDEX; + if (context->option_descriptors->option[other].value.bool) { + context->option_descriptors->option[other].value.bool = FALSE; + *effect = EVMS_Effect_Reload_Options; + } + /* Fall through */ + + case MKFS_JOURNAL_INDEX: + context->option_descriptors->option[index].value.bool = value->bool; + break; + + case MKFS_SETVOL_INDEX: + /* 'set volume label' option set? */ + strncpy(context->option_descriptors->option[index].value.s, value->s, 16); + break; + + default: + break; + } + break; + + case EVMS_Task_fsck: + switch (index) { + + case FSCK_READONLY_INDEX: + /* 'check read only' option set? */ + context->option_descriptors->option[index].value.bool = value->bool; + + /* If mounted, only allow 'yes' for check read only */ + if (EVMS_IS_MOUNTED(context->volume) && !value->bool) { + context->option_descriptors->option[index].value.bool = TRUE; + *effect = EVMS_Effect_Reload_Options; + } + + /* If read-only, we can't check for bad blocks */ + if (context->option_descriptors->option[FSCK_CHECKBB_INDEX].value.bool || + context->option_descriptors->option[FSCK_CHECKRW_INDEX].value.bool) { + context->option_descriptors->option[FSCK_CHECKBB_INDEX].value.bool = FALSE; + context->option_descriptors->option[FSCK_CHECKRW_INDEX].value.bool = FALSE; + *effect = EVMS_Effect_Reload_Options; + break; + } + + break; + + case FSCK_CHECKBB_INDEX: + case FSCK_CHECKRW_INDEX: + if (EVMS_IS_MOUNTED(context->volume) && value->bool) { + MESSAGE("Can't check for bad blocks when the volume is mounted."); + context->option_descriptors->option[index].value.bool = FALSE; + *effect = EVMS_Effect_Reload_Options; + break; + } + + /* Conflicts with each other */ + if (index == FSCK_CHECKBB_INDEX) + other = FSCK_CHECKRW_INDEX; + else + other = FSCK_CHECKBB_INDEX; + if (context->option_descriptors->option[other].value.bool) { + context->option_descriptors->option[other].value.bool = FALSE; + *effect = EVMS_Effect_Reload_Options; + } + + /* Conflicts with read-only option */ + if (context->option_descriptors->option[FSCK_READONLY_INDEX].value.bool) { + context->option_descriptors->option[FSCK_READONLY_INDEX].value.bool = FALSE; + *effect = EVMS_Effect_Reload_Options; + } + + /* Fall Through */ + + case FSCK_FORCE_INDEX: + case FSCK_TIMING_INDEX: + context->option_descriptors->option[index].value.bool = value->bool; + + break; + + default: + break; + } + break; + + default: + break; + } + + LOGEXITRC(); + return rc; +} + + +/* + * Validate the volumes in the selected_objects dlist in the task context. + * Remove from the selected objects lists any volumes which are not + * acceptable. For unacceptable volumes, create a declined_handle_t + * structure with the reason why it is not acceptable, and add it to the + * declined_volumes dlist. Modify the accepatble_objects dlist in the task + * context as necessary based on the selected objects and the current + * settings of the options. Modify any option settings as necessary based + * on the selected objects. Return the appropriate task_effect_t settings + * if the object list(s), minimum or maximum objects selected, or option + * settings have changed. + */ +static int fs_set_volumes( task_context_t * context, + dlist_t declined_volumes, /* of type declined_handle_t */ + task_effect_t * effect ) +{ + int rc = 0; + int64_t log_size; + unsigned int max_log_size; + logical_volume_t * vol; + + LOGENTRY(); + + if (effect) + *effect = 0; + + if (context->action == EVMS_Task_mkfs) { + + /* get the selected volume */ + rc = GetObject(context->selected_objects,sizeof(logical_volume_t),VOLUME_TAG,NULL,FALSE,(ADDRESS *) &vol); + + if (!rc) { + if (EVMS_IS_MOUNTED(vol)) { + /* If mounted, can't mkfs.ext2. */ + rc = EBUSY; + } else { + if ( (vol->vol_size * PBSIZE) < MINEXT2) { + + /***************************************************** + * FUTURE - move this volume to unacceptable list * + *****************************************************/ + + MESSAGE( "The size of volume %s is %d bytes.", EVMS_GET_DEVNAME(vol), vol->vol_size * PBSIZE ); + MESSAGE( "mke2fs requires a minimum of %u bytes to build the ext2/3 file system.", MINEXT2 ); + rc = EPERM; + } + } + } + } + + LOGEXITRC(); + return rc; +} + + +/* + * Return any additional information that you wish to provide about the + * volume. The Engine privides an external API to get the information + * stored in the logical_volume_t. This call is to get any other + * information about the volume that is not specified in the + * logical_volume_t. Any piece of information you wish to provide must be + * in an extended_info_t structure. Use the Engine's engine_alloc() to + * allocate the memory for the extended_info_t. Also use engine_alloc() to + * allocate any strings that may go into the extended_info_t. Then use + * engine_alloc() to allocate an extended_info_array_t with enough entries + * for the number of exteneded_info_t structures you are returning. Fill + * in the array and return it in *info. + * If you have extended_info_t descriptors that themselves may have more + * extended information, set the EVMS_EINFO_FLAGS_MORE_INFO_AVAILABLE flag + * in the extended_info_t flags field. If the caller wants more information + * about a particular extended_info_t item, this API will be called with a + * pointer to the sotrage_object_t and with a pointer to the name of the + * extended_info_t item. In that case, return an extended_info_array_t with + * further information about the item. Each of those items may have the + * EVMS_EINFO_FLAGS_MORE_INFO_AVAILABLE flag set if you desire. It is your + * resposibility to give the items unique names so that you know which item + * the caller is asking additional information for. If info_name is NULL, + * the caller just wants top level information about the object. + */ +static int fs_get_volume_info( logical_volume_t * volume, + char * info_name, + extended_info_array_t * * info ) +{ + int rc = EINVAL; + extended_info_array_t *Info; + struct ext2_super_block *sb_ptr = (struct ext2_super_block *)volume->private_data; + + + LOGENTRY(); + + if (!sb_ptr) { + LOGEXITRC(); + return rc; + } + + /* get and validate current ext2 superblock */ + rc = fsim_get_ext2_superblock( volume, sb_ptr ); + + if (info_name || rc) { + rc = EINVAL; + goto errout; + } + + /* reset limits. */ + fs_get_fs_limits( volume, &volume->min_fs_size, + &volume->max_vol_size, &volume->max_fs_size); + + Info = EngFncs->engine_alloc( sizeof(extended_info_array_t) + ( 5 * sizeof(extended_info_t) ) ); + + if (!Info) { + rc = ENOMEM; + goto errout; + } + + Info->count = 5; + + SET_STRING_FIELD( Info->info[0].name, "Version" ); + SET_STRING_FIELD( Info->info[0].title, "Ext2 Revision Number" ); + SET_STRING_FIELD( Info->info[0].desc, "Ext2 Revision Number."); + Info->info[0].type = EVMS_Type_Unsigned_Int32; + Info->info[0].unit = EVMS_Unit_None; + Info->info[0].value.ui64 = sb_ptr->s_rev_level; + Info->info[0].collection_type = EVMS_Collection_None; + memset( &Info->info[0].group, 0, sizeof(group_info_t)); + + SET_STRING_FIELD( Info->info[1].name, "State" ); + SET_STRING_FIELD( Info->info[1].title, "Ext2 State" ); + SET_STRING_FIELD( Info->info[1].desc, "The state of Ext2."); + Info->info[1].type = EVMS_Type_String; + Info->info[1].unit = EVMS_Unit_None; + if (sb_ptr->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) { + SET_STRING_FIELD(Info->info[1].value.s, "Needs journal replay"); + } else if (sb_ptr->s_state & EXT2_ERROR_FS) { + SET_STRING_FIELD(Info->info[1].value.s, "Had errors"); + } else if (sb_ptr->s_state & EXT2_VALID_FS) { + SET_STRING_FIELD(Info->info[1].value.s, "Clean"); + } else { + SET_STRING_FIELD(Info->info[1].value.s, "Dirty"); + } + Info->info[1].collection_type = EVMS_Collection_None; + memset( &Info->info[1].group, 0, sizeof(group_info_t)); + + SET_STRING_FIELD( Info->info[2].name, "VolLabel" ); + SET_STRING_FIELD( Info->info[2].title, "Volume Label" ); + SET_STRING_FIELD( Info->info[2].desc, "File system volume label."); + Info->info[2].type = EVMS_Type_String; + Info->info[2].unit = EVMS_Unit_None; + + Info->info[2].value.s = EngFncs->engine_alloc(17); + if (!Info->info[2].value.s) + return -ENOMEM; + Info->info[2].value.s[16] = 0; + memcpy(Info->info[2].value.s, sb_ptr->s_volume_name, 16); + Info->info[2].collection_type = EVMS_Collection_None; + memset( &Info->info[2].group, 0, sizeof(group_info_t)); + + SET_STRING_FIELD( Info->info[3].name, "Size" ); + SET_STRING_FIELD( Info->info[3].title, "File System Size" ); + SET_STRING_FIELD( Info->info[3].desc, "Size of the file system."); + Info->info[3].type = EVMS_Type_Unsigned_Int64; + Info->info[3].unit = EVMS_Unit_Sectors; + Info->info[3].value.ui64 = sb_ptr->s_blocks_count << + (1 + sb_ptr->s_log_block_size); + Info->info[3].collection_type = EVMS_Collection_None; + memset( &Info->info[3].group, 0, sizeof(group_info_t)); + + SET_STRING_FIELD( Info->info[4].name, "FreeSpace" ); + SET_STRING_FIELD( Info->info[4].title, "Free File System Space" ); + SET_STRING_FIELD( Info->info[4].desc, "Amount of unused space in the file system."); + Info->info[4].type = EVMS_Type_Unsigned_Int64; + Info->info[4].unit = EVMS_Unit_Sectors; + Info->info[4].value.ui64 = sb_ptr->s_free_blocks_count << + (1 + sb_ptr->s_log_block_size); + Info->info[3].collection_type = EVMS_Collection_None; + memset( &Info->info[3].group, 0, sizeof(group_info_t)); + + *info = Info; + + rc = 0; + +errout: + LOGEXITRC(); + return rc; +} + + +/* + * Returns Plugin specific information ... + */ +static int fs_get_plugin_info( char * descriptor_name, extended_info_array_t * * info ) +{ + int rc = EINVAL; + extended_info_array_t *Info; + extended_info_t *iptr; + char version_string[64]; + char required_version_string[64]; + + LOGENTRY(); + + if (info) { + + if (descriptor_name == NULL) { + *info = NULL; // init to no info returned + + Info = EngFncs->engine_alloc( sizeof(extended_info_array_t) + (8*sizeof(extended_info_t)) ); + if (Info) { + + Info->count = 0; + + sprintf(version_string, "%d.%d.%d", + MAJOR_VERSION, + MINOR_VERSION, + PATCH_LEVEL ); + + sprintf(required_version_string, "%d.%d.%d", + pMyPluginRecord->required_api_version.major, + pMyPluginRecord->required_api_version.minor, + pMyPluginRecord->required_api_version.patchlevel ); + + iptr = &Info->info[Info->count++]; + SET_STRING_FIELD( iptr->name, "Short Name" ); + SET_STRING_FIELD( iptr->title, "Short Name" ); + SET_STRING_FIELD( iptr->desc, "A short name given to this plugin."); + iptr->type = EVMS_Type_String; + iptr->unit = EVMS_Unit_None; + SET_STRING_FIELD( iptr->value.s, pMyPluginRecord->short_name ); + iptr->collection_type = EVMS_Collection_None; + memset( &iptr->group, 0, sizeof(group_info_t)); + + iptr = &Info->info[Info->count++]; + SET_STRING_FIELD( iptr->name, "Long Name" ); + SET_STRING_FIELD( iptr->title, "Long Name" ); + SET_STRING_FIELD( iptr->desc, "A long name given to this plugin."); + iptr->type = EVMS_Type_String; + iptr->unit = EVMS_Unit_None; + SET_STRING_FIELD( iptr->value.s, pMyPluginRecord->long_name ); + iptr->collection_type = EVMS_Collection_None; + memset( &iptr->group, 0, sizeof(group_info_t)); + + iptr = &Info->info[Info->count++]; + SET_STRING_FIELD( iptr->name, "Type" ); + SET_STRING_FIELD( iptr->title, "Plugin Type" ); + SET_STRING_FIELD( iptr->desc, "There are various types of plugins; each responsible for some kind of storage object."); + iptr->type = EVMS_Type_String; + iptr->unit = EVMS_Unit_None; + SET_STRING_FIELD( iptr->value.s, "File System Interface Module" ); + iptr->collection_type = EVMS_Collection_None; + memset( &iptr->group, 0, sizeof(group_info_t)); + + iptr = &Info->info[Info->count++]; + SET_STRING_FIELD( iptr->name, "Version" ); + SET_STRING_FIELD( iptr->title, "Plugin Version" ); + SET_STRING_FIELD( iptr->desc, "This is the version number of the plugin."); + iptr->type = EVMS_Type_String; + iptr->unit = EVMS_Unit_None; + SET_STRING_FIELD( iptr->value.s, version_string ); + iptr->collection_type = EVMS_Collection_None; + memset( &iptr->group, 0, sizeof(group_info_t)); + + iptr = &Info->info[Info->count++]; + SET_STRING_FIELD( iptr->name, "Required Version" ); + SET_STRING_FIELD( iptr->title, "Required Engine Version" ); + SET_STRING_FIELD( iptr->desc, "This is the version of the engine that the plugin requires. It will not run on older versions of the Engine."); + iptr->type = EVMS_Type_String; + iptr->unit = EVMS_Unit_None; + SET_STRING_FIELD( iptr->value.s, required_version_string ); + iptr->collection_type = EVMS_Collection_None; + memset( &iptr->group, 0, sizeof(group_info_t)); + +#ifdef VERSION + iptr = &Info->info[Info->count++]; + SET_STRING_FIELD( iptr->name, "E2fsprogs Version" ); + SET_STRING_FIELD( iptr->title, "E2fsprogs Version" ); + SET_STRING_FIELD( iptr->desc, "This is the version of the e2fsprogs that this plugin was shipped with."); + iptr->type = EVMS_Type_String; + iptr->unit = EVMS_Unit_None; + SET_STRING_FIELD( iptr->value.s, VERSION ); + iptr->collection_type = EVMS_Collection_None; + memset( &iptr->group, 0, sizeof(group_info_t)); +#endif + + *info = Info; + + rc = 0; + } else { + rc = ENOMEM; + } + + } else { + /* There is no more information on any of the descriptors. */ + rc = EINVAL; + } + } + + LOGEXITRC(); + return rc; +} + + +/* + * How much can file system expand? + */ +static int fs_can_expand_by(logical_volume_t * volume, + sector_count_t * delta) +{ + /* unsupported at this time */ + int rc = ENOSYS; + + LOGENTRY(); + LOGEXITRC(); + return rc; + +} + + +/* + * How much can file system shrink? + */ +static int fs_can_shrink_by(logical_volume_t * volume, + sector_count_t * delta) +{ + /* unsupported at this time */ + int rc = ENOSYS; + + LOGENTRY(); + LOGEXITRC(); + return rc; +} + + +/*-------------------------------------------------------------------------------------+ ++ + ++ PLUGIN FUNCTION TABLE + ++ + ++--------------------------------------------------------------------------------------*/ +static fsim_functions_t fsim_ops = { + + setup_evms_plugin: fs_setup, + cleanup_evms_plugin:fs_cleanup, + is_this_yours: fs_probe, + can_mkfs: fs_can_mkfs, + can_unmkfs: fs_can_unmkfs, + can_fsck: fs_can_fsck, + get_fs_size: fs_get_fs_size, + get_fs_limits: fs_get_fs_limits, + can_expand_by: fs_can_expand_by, + can_shrink_by: fs_can_shrink_by, + expand: fs_expand, + shrink: fs_shrink, + mkfs: fs_mkfs, + fsck: fs_fsck, + unmkfs: fs_unmkfs, + get_option_count: fs_get_option_count, + init_task: fs_init_task, + set_option: fs_set_option, + set_volumes: fs_set_volumes, + get_volume_info: fs_get_volume_info, + get_plugin_info: fs_get_plugin_info +}; + + +/*-------------------------------------------------------------------------------------+ ++ + ++ PLUGIN RECORD + ++ + ++-------------------------------------------------------------------------------------*/ + +plugin_record_t ext2_plugrec = { + id: SetPluginID(EVMS_OEM_IBM, EVMS_FILESYSTEM_INTERFACE_MODULE, FS_TYPE_EXT2 ), + version: {MAJOR_VERSION, MINOR_VERSION, PATCH_LEVEL}, + required_api_version: {ENGINE_PLUGIN_API_MAJOR_VERION, + ENGINE_PLUGIN_API_MINOR_VERION, + ENGINE_PLUGIN_API_PATCH_LEVEL}, + short_name: "Ext2/3", + long_name: "Ext2 File System Interface Module", + oem_name: "IBM", + functions: {fsim: &fsim_ops}, + container_functions: NULL + +}; + diff --git a/lib/evms/fsimext2.c b/lib/evms/fsimext2.c new file mode 100644 index 00000000..b826dd2c --- /dev/null +++ b/lib/evms/fsimext2.c @@ -0,0 +1,578 @@ +/* + * + * Copyright (c) International Business Machines Corp., 2000 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Module: fsimext2.c + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fsimext2.h" + +int fsim_rw_diskblocks( int, int64_t, int32_t, void *, int ); +void set_mkfs_options( option_array_t *, char **, logical_volume_t *, char * ); +void set_fsck_options( option_array_t *, char **, logical_volume_t * ); + +// Vector of plugin record ptrs that we export for the EVMS Engine. +plugin_record_t *evms_plugin_records[] = { + &ext2_plugrec, + NULL +}; + +static plugin_record_t * pMyPluginRecord = &ext2_plugrec; + +/*-------------------------------------------------------------------------------------+ ++ + ++ Common Routines + ++ + ++--------------------------------------------------------------------------------------*/ + + +/* + * Get the size limits for this volume. + */ +int fsim_get_volume_limits( struct ext2_super_block * sb, + sector_count_t * min_size, + sector_count_t * max_volume_size, + sector_count_t * max_object_size) +{ + int rc = 0; + sector_count_t fs_size; + + /* + * Since ext2/3 does not yet support shrink or expand, + * all values are actual file system size. + */ + fs_size = sb->s_blocks_count << (1 + sb->s_log_block_size); + *max_volume_size = fs_size; + *max_object_size = fs_size; + *min_size = fs_size; + + return rc; +} + + +/* + * Un-Format the volume. + */ +int fsim_unmkfs( logical_volume_t * volume ) +{ + int fd; + int rc = 0; + + fd = open(EVMS_GET_DEVNAME(volume), O_RDWR|O_EXCL, 0); + if (fd < 0) return -1; + + if ( volume->private_data ) { + /* clear private data */ + memset( (void *) volume->private_data, 0, SIZE_OF_SUPER ); + /* zero primary superblock */ + rc = fsim_rw_diskblocks( fd, EXT2_SUPER_LOC, SIZE_OF_SUPER, + volume->private_data, PUT ); + } else { + rc = ERROR; + } + + fd = close(fd); + + return rc; +} + + +/* + * Format the volume. + */ +int fsim_mkfs(logical_volume_t * volume, option_array_t * options ) +{ + int rc = FSIM_ERROR; + char *argv[MKFS_EXT2_OPTIONS_COUNT + 6]; + char logsize[sizeof(unsigned int) + 1]; + pid_t pidm; + int status; + + /* Fork and execute the correct program. */ + switch (pidm = fork()) { + + /* error */ + case -1: + return EIO; + + /* child */ + case 0: + set_mkfs_options( options, argv, volume, logsize ); + + /* close stderr, stdout to suppress mke2fs output */ + close(1); + close(2); + open("/dev/null", O_WRONLY); + open("/dev/null", O_WRONLY); + + (void) execvp(argv[0], argv); + /* using exit() can hang GUI, use _exit */ + _exit(errno); + + /* parent */ + default: + /* wait for child to complete */ + pidm = waitpid( pidm, &status, 0 ); + if ( WIFEXITED(status) ) { + /* get mke2fs exit code */ + rc = WEXITSTATUS(status); + } + } + + return rc; +} + + +/* + * NAME: set_mkfs_options + * + * FUNCTION: Build options array (argv) for mkfs.ext2 + * + * PARAMETERS: + * options - options array passed from EVMS engine + * argv - mkfs options array + * vol_name - volume name on which program will be executed + * + */ +void set_mkfs_options( option_array_t * options, + char ** argv, + logical_volume_t * volume, + char * logsize ) +{ + int i, opt_count = 2; + + argv[0] = "mke2fs"; + + /* 'quiet' option */ + argv[1] = "-q"; + + for ( i=0; icount; i++ ) { + + if ( options->option[i].is_number_based ) { + + switch (options->option[i].number) { + + case MKFS_CHECKBB_INDEX: + /* 'check for bad blocks' option */ + if ( options->option[i].value.bool == TRUE ) { + argv[opt_count++] = "-c"; + } + break; + + case MKFS_CHECKRW_INDEX: + /* 'check for r/w bad blocks' option */ + if ( options->option[i].value.bool == TRUE ) { + argv[opt_count++] = "-cc"; + } + break; + + case MKFS_JOURNAL_INDEX: + /* 'create ext3 journal' option */ + if ( options->option[i].value.bool == TRUE ) { + argv[opt_count++] = "-j"; + } + break; + + case MKFS_SETVOL_INDEX: + /* 'set volume name' option */ + if ( options->option[i].value.s ) { + argv[opt_count++] = "-L"; + argv[opt_count++] = options->option[i].value.s; + } + break; + + default: + break; + } + + } else { + + if ( !strcmp(options->option[i].name, "badblocks") ) { + /* 'check for bad blocks' option */ + if ( options->option[i].value.bool == TRUE ) { + argv[opt_count++] = "-c"; + } + } + + if ( !strcmp(options->option[i].name, "badblocks_rw") ) { + /* 'check for r/w bad blocks' option */ + if ( options->option[i].value.bool == TRUE ) { + argv[opt_count++] = "-cc"; + } + } + + if ( !strcmp(options->option[i].name, "journal") ) { + /* 'create ext3 journal' option */ + if ( options->option[i].value.bool == TRUE ) { + argv[opt_count++] = "-j"; + } + } + + if ( !strcmp(options->option[i].name, "vollabel") ) { + /* 'check for bad blocks' option */ + if ( options->option[i].value.s ) { + argv[opt_count++] = "-L"; + argv[opt_count++] = options->option[i].value.s; + } + } + } + } + + argv[opt_count++] = EVMS_GET_DEVNAME(volume); + argv[opt_count] = NULL; + + { + FILE *f; + + f = fopen("/var/tmp/evms-log", "a"); + for ( i=0; argv[i]; i++) { + fprintf(f, "'%s' ", argv[i]); + } + fprintf(f, "\n"); + fclose(f); + } + + return; +} + + +/* + * Run fsck on the volume. + */ +int fsim_fsck(logical_volume_t * volume, option_array_t * options ) +{ + int rc = FSIM_ERROR; + char *argv[FSCK_EXT2_OPTIONS_COUNT + 3]; + pid_t pidf; + int status, bytes_read; + char *buffer = NULL; + int fds2[2]; + int banner = 0; + + /* open pipe, alloc buffer for collecting fsck.jfs output */ + rc = pipe(fds2); + if (rc) { + return(rc); + } + if (!(buffer = EngFncs->engine_alloc(MAX_USER_MESSAGE_LEN))) { + return(ENOMEM); + } + + /* Fork and execute the correct program. */ + switch (pidf = fork()) { + + /* error */ + case -1: + return EIO; + + /* child */ + case 0: + set_fsck_options( options, argv, volume ); + + /* pipe stderr, stdout */ + dup2(fds2[1],1); /* fds2[1] replaces stdout */ + dup2(fds2[1],2); /* fds2[1] replaces stderr */ + close(fds2[0]); /* don't need this here */ + + rc = execvp( argv[0], argv ); + + /* + * The value of fsck exit code FSCK_CORRECTED is the same + * as errno EPERM. Thus, if EPERM is returned from execv, + * exit out of the child with rc = -1 instead of EPERM. + */ + if( rc && (errno == EPERM) ) { + /* using exit() can hang GUI, use _exit */ + _exit(-1); + } else { + /* using exit() can hang GUI, use _exit */ + _exit(errno); + } + + /* parent */ + default: + close(fds2[1]); + + /* wait for child to complete */ + while (!(pidf = waitpid( pidf, &status, WNOHANG ))) { + /* read e2fsck output */ + bytes_read = read(fds2[0],buffer,MAX_USER_MESSAGE_LEN); + if (bytes_read > 0) { + /* display e2fsck output */ + if (!banner) + MESSAGE("e2fsck output: \n\n%s",buffer); + else + banner = 1; + memset(buffer,0,bytes_read); //clear out message + } + usleep(10000); /* don't hog all the cpu */ + } + + /* wait for child to complete */ + pidf = waitpid( pidf, &status, 0 ); + if ( WIFEXITED(status) ) { + /* get e2fsck exit code */ + rc = WEXITSTATUS(status); + LOG("e2fsck completed with exit code %d \n", rc); + } + } + + if (buffer) { + EngFncs->engine_free(buffer); + } + + return rc; +} + + +/* + * NAME: set_fsck_options + * + * FUNCTION: Build options array (argv) for e2fsck + * + * PARAMETERS: + * options - options array passed from EVMS engine + * argv - fsck options array + * volume - volume on which program will be executed + * + */ +void set_fsck_options( option_array_t * options, char ** argv, logical_volume_t * volume ) +{ + int i, opt_count = 1; + int do_preen = 1; + + argv[0] = "e2fsck"; + + for ( i=0; icount; i++) { + + if ( options->option[i].is_number_based ) { + + /* 'force check' option */ + if ( (options->option[i].number == FSCK_FORCE_INDEX) && + (options->option[i].value.bool == TRUE) ) { + argv[opt_count++] = "-f"; + } + + /* 'check read only' option or mounted */ + if ((options->option[i].number == FSCK_READONLY_INDEX) && + ((options->option[i].value.bool == TRUE) || + EVMS_IS_MOUNTED(volume))) { + argv[opt_count++] = "-n"; + do_preen = 0; + } + + /* 'bad blocks check' option and NOT mounted */ + if ( (options->option[i].number == FSCK_CHECKBB_INDEX) && + (options->option[i].value.bool == TRUE) && + !EVMS_IS_MOUNTED(volume) ) { + argv[opt_count++] = "-c"; + do_preen = 0; + } + + /* 'bad blocks check' option and NOT mounted */ + if ( (options->option[i].number == FSCK_CHECKRW_INDEX) && + (options->option[i].value.bool == TRUE) && + !EVMS_IS_MOUNTED(volume) ) { + argv[opt_count++] = "-cc"; + do_preen = 0; + } + + /* timing option */ + if ( (options->option[i].number == FSCK_TIMING_INDEX) && + (options->option[i].value.bool == TRUE) ) { + argv[opt_count++] = "-tt"; + } + + } else { + + /* 'force check' option selected and NOT mounted */ + if ( !strcmp(options->option[i].name, "force") && + (options->option[i].value.bool == TRUE) && + !EVMS_IS_MOUNTED(volume) ) { + argv[opt_count++] = "-f"; + } + + /* 'check read only' option selected or mounted */ + if ((!strcmp(options->option[i].name, "readonly")) && + ((options->option[i].value.bool == TRUE) || + EVMS_IS_MOUNTED(volume))) { + argv[opt_count++] = "-n"; + do_preen = 0; + } + + /* 'check badblocks' option selected and NOT mounted */ + if (!strcmp(options->option[i].name, "badblocks") && + (options->option[i].value.bool == TRUE) && + !EVMS_IS_MOUNTED(volume)) { + argv[opt_count++] = "-c"; + do_preen = 0; + } + + /* 'check r/w badblocks' option selected and NOT mounted */ + if (!strcmp(options->option[i].name, "badblocks_rw") && + (options->option[i].value.bool == TRUE) && + !EVMS_IS_MOUNTED(volume)) { + argv[opt_count++] = "-cc"; + do_preen = 0; + } + + /* 'timing' option selected */ + if (!strcmp(options->option[i].name, "badblocks") && + (options->option[i].value.bool == TRUE)) { + argv[opt_count++] = "-tt"; + } + } + } + + if (do_preen) + argv[opt_count++] = "-p"; + argv[opt_count++] = EVMS_GET_DEVNAME(volume); + argv[opt_count] = NULL; + + { + FILE *f; + + f = fopen("/var/tmp/evms-log", "a"); + for ( i=0; argv[i]; i++) { + fprintf(f, "'%s' ", argv[i]); + } + fprintf(f, "\n"); + fclose(f); + } + + return; +} + + +/* + * NAME: fsim_get_ext2_superblock + * + * FUNCTION: Get and validate a ext2/3 superblock + * + * PARAMETERS: + * volume - pointer to volume from which to get the superblock + * sb_ptr - pointer to superblock + * + * RETURNS: + * (0) for success + * != 0 otherwise + * + */ +int fsim_get_ext2_superblock( logical_volume_t *volume, struct ext2_super_block *sb_ptr ) +{ + int fd; + int rc = 0; + + fd = open(EVMS_GET_DEVNAME(volume), O_RDONLY, 0); + if (fd < 0) return EIO; + + /* get primary superblock */ + rc = fsim_rw_diskblocks( fd, EXT2_SUPER_LOC, SIZE_OF_SUPER, sb_ptr, GET ); + + if( rc == 0 ) { + /* see if superblock is ext2/3 */ + if (( sb_ptr->s_magic != EXT2_SUPER_MAGIC ) || + ( sb_ptr->s_rev_level > 1 )) + rc = FSIM_ERROR; + } + + close(fd); + + return rc; +} + + +/* + * NAME: fsim_rw_diskblocks + * + * FUNCTION: Read or write specific number of bytes for an opened device. + * + * PARAMETERS: + * dev_ptr - file handle of an opened device to read/write + * disk_offset - byte offset from beginning of device for start of disk + * block read/write + * disk_count - number of bytes to read/write + * data_buffer - On read this will be filled in with data read from + * disk; on write this contains data to be written + * mode - GET (read) or PUT (write) + * + * RETURNS: + * FSIM_SUCCESS (0) for success + * ERROR (-1) can't lseek + * EINVAL + * EIO + * + */ +int fsim_rw_diskblocks( int dev_ptr, + int64_t disk_offset, + int32_t disk_count, + void *data_buffer, + int mode ) +{ + off_t Actual_Location; + size_t Bytes_Transferred; + + Actual_Location = lseek(dev_ptr,disk_offset, SEEK_SET); + if ( ( Actual_Location < 0 ) || ( Actual_Location != disk_offset ) ) + return ERROR; + + switch ( mode ) { + case GET: + Bytes_Transferred = read(dev_ptr,data_buffer,disk_count); + break; + case PUT: + Bytes_Transferred = write(dev_ptr,data_buffer,disk_count); + break; + default: + return EINVAL; + break; + } + + if ( Bytes_Transferred != disk_count ) { + return EIO; + } + + return FSIM_SUCCESS; +} + + +/* + * Test e2fsprogs version. + * + * We don't bother since we don't need any special functionality that + * hasn't been around for *years* + */ +int fsim_test_version( ) +{ + return 0; +} + + + + + diff --git a/lib/evms/fsimext2.h b/lib/evms/fsimext2.h new file mode 100644 index 00000000..dd7d44bb --- /dev/null +++ b/lib/evms/fsimext2.h @@ -0,0 +1,276 @@ +/* Version number of the ext2 plugin */ +#define MAJOR_VERSION 1 +#define MINOR_VERSION 0 +#define PATCH_LEVEL 0 + +/* + * + * Copyright (c) International Business Machines Corp., 2000 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Module: fsimext2.h + * + */ + +/* + * EVMS 1.0 backwards compatibility functions + */ +#ifdef ABI_EVMS_1_0 +#define EVMS_IS_MOUNTED(vol) ((vol)->mount_point != 0) +#define EVMS_GET_DEVNAME(vol) ((vol)->name) +#else +#define EVMS_IS_MOUNTED(vol) (EngFncs->is_mounted((vol)->dev_node, NULL)) +#define EVMS_GET_DEVNAME(vol) ((vol)->dev_node) +#endif + +/******************** + ******************** + ** ** + ** EVMS defines ** + ** ** + ******************** + ********************/ + +extern plugin_record_t ext2_plugrec; +engine_functions_t *EngFncs; + +// file system type ... used by the SetPluginID macro +#define FS_TYPE_EXT2 7 + +// logging macros +#define LOGENTRY() EngFncs->write_log_entry(ENTRY_EXIT, pMyPluginRecord, "%s: Enter.\n", __FUNCTION__) +#define LOGEXIT() EngFncs->write_log_entry(ENTRY_EXIT, pMyPluginRecord, "%s: Exit.\n", __FUNCTION__ ) +#define LOGEXITRC() EngFncs->write_log_entry(ENTRY_EXIT, pMyPluginRecord, "%s: Exit. RC= %d.\n", __FUNCTION__, rc) +#define MESSAGE(msg, args...) EngFncs->user_message(pMyPluginRecord, NULL, NULL, msg, ##args) +#define LOG_CRITICAL(msg, args...) EngFncs->write_log_entry(CRITICAL, pMyPluginRecord, __FUNCTION__ ": " msg, ## args) +#define LOG_SERIOUS(msg, args...) EngFncs->write_log_entry(SERIOUS, pMyPluginRecord, __FUNCTION__ ": " msg, ## args) +#define LOG_ERROR(msg, args...) EngFncs->write_log_entry(ERROR, pMyPluginRecord, __FUNCTION__ ": " msg, ## args) +#define LOG_WARNING(msg, args...) EngFncs->write_log_entry(WARNING, pMyPluginRecord, __FUNCTION__ ": " msg, ## args) +#define LOG(msg, args...) EngFncs->write_log_entry(DEFAULT, pMyPluginRecord, __FUNCTION__ ": " msg, ## args) +#define LOG_DETAILS(msg, args...) EngFncs->write_log_entry(DETAILS, pMyPluginRecord, __FUNCTION__ ": " msg, ## args) +#define LOG_DEBUG(msg, args...) EngFncs->write_log_entry(DEBUG, pMyPluginRecord, __FUNCTION__ ": " msg, ## args) +#define LOG_EXTRA(msg, args...) EngFncs->write_log_entry(EXTRA, pMyPluginRecord, __FUNCTION__ ": " msg, ## args) + +// useful macro for option code +#define SET_STRING_FIELD(a,b)\ +a = EngFncs->engine_alloc( strlen(b)+1 );\ +if (a ) {\ + strcpy(a, b);\ +}\ +else {\ + return -ENOMEM;\ +} + +#define SET_STRING(a,b) a = EngFncs->engine_alloc( strlen(b)+1 );if (a ) { strcpy(a, b); } else { rc = ENOMEM; LOG_EXIT(rc);} +#define LOG_EXIT(x) LOG_PROC("Exiting: rc = %d\n", x) +#define LOG_PROC(msg, args...) EngFncs->write_log_entry(ENTRY_EXIT, pMyPluginRecord, "%s: " msg, __FUNCTION__ , ## args) + + +/********************************** + ********************************** + ** ** + ** fsck.jfs, mkfs.jfs defines ** + ** ** + ********************************** + **********************************/ + +/* fsck.jfs, mkfs.jfs option counts */ + +/* fsck.jfs option array indices */ +#define FSCK_FORCE_INDEX 0 +#define FSCK_READONLY_INDEX 1 +#define FSCK_CHECKBB_INDEX 2 +#define FSCK_CHECKRW_INDEX 3 +#define FSCK_TIMING_INDEX 4 +#define FSCK_EXT2_OPTIONS_COUNT 5 + +/* mkfs.jfs option array indices */ +#define MKFS_CHECKBB_INDEX 0 +#define MKFS_CHECKRW_INDEX 1 +#define MKFS_SETVOL_INDEX 2 +#define MKFS_JOURNAL_INDEX 3 +#define MKFS_EXT2_OPTIONS_COUNT 4 + +/* fsck exit codes */ +#define FSCK_OK 0 +#define FSCK_CORRECTED 1 +#define FSCK_REBOOT 2 +#define FSCK_ERRORS_UNCORRECTED 4 +#define FSCK_OP_ERROR 8 +#define FSCK_USAGE_ERROR 16 + + +/* + * EXT2/3 defines and structs + */ + +/* generic defines */ +#define FSIM_SUCCESS 0 +#define FSIM_ERROR -1 +#define GET 0 +#define PUT 1 + +#define EXT2_SUPER_LOC 1024 + +#define EXT2_SUPER_MAGIC 0xEF53 + +#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */ + +#define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */ +#define EXT2_ERROR_FS 0x0002 /* Errors detected */ + +/* + * Structure of the ext2 super block + */ +struct ext2_super_block { + __u32 s_inodes_count; /* Inodes count */ + __u32 s_blocks_count; /* Blocks count */ + __u32 s_r_blocks_count; /* Reserved blocks count */ + __u32 s_free_blocks_count; /* Free blocks count */ + __u32 s_free_inodes_count; /* Free inodes count */ + __u32 s_first_data_block; /* First Data Block */ + __u32 s_log_block_size; /* Block size */ + __s32 s_log_frag_size; /* Fragment size */ + __u32 s_blocks_per_group; /* # Blocks per group */ + __u32 s_frags_per_group; /* # Fragments per group */ + __u32 s_inodes_per_group; /* # Inodes per group */ + __u32 s_mtime; /* Mount time */ + __u32 s_wtime; /* Write time */ + __u16 s_mnt_count; /* Mount count */ + __s16 s_max_mnt_count; /* Maximal mount count */ + __u16 s_magic; /* Magic signature */ + __u16 s_state; /* File system state */ + __u16 s_errors; /* Behaviour when detecting errors */ + __u16 s_minor_rev_level; /* minor revision level */ + __u32 s_lastcheck; /* time of last check */ + __u32 s_checkinterval; /* max. time between checks */ + __u32 s_creator_os; /* OS */ + __u32 s_rev_level; /* Revision level */ + __u16 s_def_resuid; /* Default uid for reserved blocks */ + __u16 s_def_resgid; /* Default gid for reserved blocks */ + /* + * These fields are for EXT2_DYNAMIC_REV superblocks only. + * + * Note: the difference between the compatible feature set and + * the incompatible feature set is that if there is a bit set + * in the incompatible feature set that the kernel doesn't + * know about, it should refuse to mount the filesystem. + * + * e2fsck's requirements are more strict; if it doesn't know + * about a feature in either the compatible or incompatible + * feature set, it must abort and not try to meddle with + * things it doesn't understand... + */ + __u32 s_first_ino; /* First non-reserved inode */ + __u16 s_inode_size; /* size of inode structure */ + __u16 s_block_group_nr; /* block group # of this superblock */ + __u32 s_feature_compat; /* compatible feature set */ + __u32 s_feature_incompat; /* incompatible feature set */ + __u32 s_feature_ro_compat; /* readonly-compatible feature set */ + __u8 s_uuid[16]; /* 128-bit uuid for volume */ + char s_volume_name[16]; /* volume name */ + char s_last_mounted[64]; /* directory where last mounted */ + __u32 s_algorithm_usage_bitmap; /* For compression */ + /* + * Performance hints. Directory preallocation should only + * happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on. + */ + __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ + __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ + __u16 s_padding1; + /* + * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set. + */ + __u8 s_journal_uuid[16]; /* uuid of journal superblock */ + __u32 s_journal_inum; /* inode number of journal file */ + __u32 s_journal_dev; /* device number of journal file */ + __u32 s_last_orphan; /* start of list of inodes to delete */ + + __u32 s_reserved[197]; /* Padding to the end of the block */ +}; + +#define L2MEGABYTE 20 +#define MEGABYTE (1 << L2MEGABYTE) +#define MEGABYTE32 (MEGABYTE << 5) +#define MAX_LOG_PERCENTAGE 10 /* Log can be at most 10% of disk */ + +/* + * buffer cache configuration + */ +/* page size */ +#ifdef PSIZE +#undef PSIZE +#endif +#define PSIZE 4096 /* page size (in byte) */ + +#define PBSIZE 512 /* physical block size (in byte) */ + +/* + * Minimum number of bytes supported for an ext2 partition + * (64k, quite small!) + */ +#define MINEXT2 (64*1024) + +/* + * SIZE_OF_SUPER defines the total amount of space reserved on disk for the + * superblock. This is not the same as the superblock structure, since all of + * this space is not currently being used. + */ +#define SIZE_OF_SUPER sizeof(struct ext2_super_block) + +/* + * SIZE_OF_MAP_PAGE defines the amount of disk space reserved for each page of + * the inode allocation map (to hold iag) + */ +#define SIZE_OF_MAP_PAGE PSIZE + +/* + * directory configuration + */ +#define JFS_NAME_MAX 255 +#define JFS_PATH_MAX BPSIZE + +/* + * file system state (superblock state) + */ +#define FM_CLEAN 0x00000000 /* file system is unmounted and clean */ +#define FM_MOUNT 0x00000001 /* file system is mounted cleanly */ +#define FM_DIRTY 0x00000002 /* file system was not unmounted and clean + * when mounted or + * commit failure occurred while being mounted: + * fsck() must be run to repair + */ +#define FM_LOGREDO 0x00000004 /* log based recovery (logredo()) failed: + * fsck() must be run to repair + */ +#define FM_EXTENDFS 0x00000008 /* file system extendfs() in progress */ + + +/******************* + ******************* + ** ** + ** Common code ** + ** ** + ******************* + *******************/ + +int fsim_get_ext2_superblock( logical_volume_t *, struct ext2_super_block * ); +int fsim_unmkfs( logical_volume_t * ); +int fsim_mkfs( logical_volume_t *, option_array_t * ); +int fsim_fsck( logical_volume_t *, option_array_t * ); +int fsim_get_volume_limits( struct ext2_super_block *, sector_count_t *, + sector_count_t *, sector_count_t * ); +int fsim_test_version( void ); diff --git a/lib/evms/options.h b/lib/evms/options.h new file mode 100644 index 00000000..b109231b --- /dev/null +++ b/lib/evms/options.h @@ -0,0 +1,315 @@ +/* + * + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (C) 1997-1999 David Mosberger-Tang and Andreas Beck + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Module: options.h + */ + +#ifndef EVMS_OPTIONS_H_INCLUDED +#define EVMS_OPTIONS_H_INCLUDED 1 + +#include + +/* + * Dear Reader, + * + * Yes, some of the structures look a lot like the ones the SANE + * (Scanner Access Now Easy) folks use for negotiating options + * between a frontend and backend. In fact, some of the structures + * here were derived from their solution with some tweaks for EVMS. + * + * Kindest regards and most humble apologies to the SANE folks for + * borrowing their solution. + */ + +/* + * Task API typedefs + */ + +typedef u_int32_t task_handle_t; + +/* + * Task actions correspond to the low-level API available to frontends. + * The task API allows binding of action, plugin, target objects, and + * plugin-specific options. This allows for interaction with the backend + * to validate the correctness of parameters and options necessary to + * fulfill the requirements of the low-level API which eventually is invoked. + */ + +typedef enum { + EVMS_Task_Create = 0, + EVMS_Task_Create_Container, + EVMS_Task_Assign_Plugin, + EVMS_Task_Expand_Container, + EVMS_Task_Set_Info, + EVMS_Task_Expand, + EVMS_Task_Shrink, + EVMS_Task_Slide, + EVMS_Task_Move, + EVMS_Task_mkfs, + EVMS_Task_fsck, + EVMS_Task_defrag, + EVMS_Task_Message, + EVMS_Task_Add_Feature, + EVMS_Task_Plugin_Function = 0x1000 /* Base number for plug-in funtions */ +} task_action_t; + + +typedef struct function_info_s { + task_action_t function; /* Plugin function number */ + char * title; /* Short title for the function */ + /* e.g. "Add a spare" */ + /* Example usage: A UI might put this in */ + /* a menu of functions to select. */ + char * verb; /* One or two action words for the function */ + /* e.g. "Add" */ + /* Example usage: A GUI may use this on an */ + /* action button for the function. */ + char * help; /* Full help text */ + /* e.g. "Use this function to add a spare blah blah blah..." */ +} function_info_t; + +typedef struct function_info_array_s { + uint count; + function_info_t info[1]; +} function_info_array_t; + + +/* + * Object API typedefs + */ + +typedef struct declined_handle_s { + object_handle_t handle; /* Handle of object declined */ + int reason; /* Reason for being declined */ +} declined_handle_t; + +typedef struct declined_handle_array_s { + uint count; + declined_handle_t declined[1]; +} declined_handle_array_t; + +/* + * Option API typedefs and constants + */ + +typedef enum { + EVMS_Type_String = 1, /* char* */ + EVMS_Type_Boolean, /* BOOLEAN */ + EVMS_Type_Char, /* char */ + EVMS_Type_Unsigned_Char, /* unsigned char */ + EVMS_Type_Real32, /* float */ + EVMS_Type_Real64, /* double */ + EVMS_Type_Int, /* int */ + EVMS_Type_Int8, /* int8_t */ + EVMS_Type_Int16, /* int16_t */ + EVMS_Type_Int32, /* int32_t */ + EVMS_Type_Int64, /* int64_t */ + EVMS_Type_Unsigned_Int, /* uint */ + EVMS_Type_Unsigned_Int8, /* u_int8_t */ + EVMS_Type_Unsigned_Int16, /* u_int16_t */ + EVMS_Type_Unsigned_Int32, /* u_int32_t */ + EVMS_Type_Unsigned_Int64 /* u_int64_t */ +} value_type_t; + +typedef enum { + EVMS_Unit_None = 0, + EVMS_Unit_Disks, + EVMS_Unit_Sectors, + EVMS_Unit_Segments, + EVMS_Unit_Regions, + EVMS_Unit_Percent, + EVMS_Unit_Milliseconds, + EVMS_Unit_Microseconds, + EVMS_Unit_Bytes, + EVMS_Unit_Kilobytes, + EVMS_Unit_Megabytes, + EVMS_Unit_Gigabytes, + EVMS_Unit_Terabytes, + EVMS_Unit_Petabytes +} value_unit_t; + +typedef enum { + EVMS_Collection_None = 0, /* No collection */ + EVMS_Collection_List, /* Use a value_list_t structure */ + EVMS_Collection_Range /* Use a value_range_t structure */ +} collection_type_t; + +typedef enum { + EVMS_Format_Normal = 0, + EVMS_Format_Hex, + EVMS_Format_Ascii, + EVMS_Format_Binary +} value_format_t; + +typedef union { + char c; /* one character, e.g. 'C' */ + char *s; /* string pointer */ + u_char uc; + int bool; + int i; + int8_t i8; + int16_t i16; + int32_t i32; + int64_t i64; + u_int ui; + u_int8_t ui8; + u_int16_t ui16; + u_int32_t ui32; + u_int64_t ui64; + float r32; + double r64; + struct value_list_s *list; +} value_t; + +/* + * The struct key_value_pair_s allows some generic passing + * of a key/value pair for some basic data type values. The + * key can be a name (a string) or a number. The sending + * and receiving ends denote, through the is_number_based flag, + * which key should be looked at for identification purposes. + */ + +typedef struct key_value_pair_s { + char *name; /* Key if name-based */ + u_int16_t number; /* Key if number-based */ + BOOLEAN is_number_based; /* TRUE if number-based */ + value_type_t type; /* Value type */ + value_t value; /* Union of basic data types */ +} key_value_pair_t; + +/* + * Some frontends may supply plugin-specific data as "options" through + * the API functions, e.g. evms_create(), available to a frontend. + * Options are essentially key/value pairs where the key and value types + * are known ahead-of-time or were interrogated through the option + * descriptor API. + */ + +typedef struct option_array_s { + u_int count; + key_value_pair_t option[1]; +} option_array_t; + +typedef struct value_list_s { + u_int count; + value_t value[1]; +} value_list_t; + +typedef struct value_range_s { + value_t min; /* Minimum value */ + value_t max; /* Maximum value */ + value_t increment; /* Step or increment for changes in-between */ +} value_range_t; + +typedef union { + value_list_t *list; /* Array of values of the same type */ + value_range_t *range; /* Range of values for numeric types */ +} value_collection_t; + +typedef struct group_info_s { + u_int32_t group_number; /* group number, 0 if not grouped */ + u_int32_t group_level; /* possibly used for indenting, or sub fields */ + char *group_name; /* name of group */ +} group_info_t; + +typedef struct option_descriptor_s { + char *name; /* Option name/key */ + char *title; /* One or two word description of option */ + char *tip; /* Multi-sentence description of option for tip */ + char *help; /* Multi-paragraph detailed option help */ + value_type_t type; /* Defines option data type */ + value_unit_t unit; /* Defines unit value */ +#ifdef ABI_EVMS_1_0 + u_int32_t size; /* Maximum size (in bytes) of option value */ +#else + value_format_t format; /* Suggested format for display of values */ + u_int32_t min_len; /* Minimum length for string types */ + u_int32_t max_len; /* Maximum length for string types */ +#endif + u_int64_t flags; /* Option flags (defined below) */ + collection_type_t constraint_type; /* Constraint type (none, range, list) */ + value_collection_t constraint; /* Either a list or range of valid input values */ + value_t value; /* Initial/current value */ + group_info_t group; /* Group information for display purposes */ +} option_descriptor_t; + +/* + * option_descriptor_t flags bitset + */ + +#define EVMS_OPTION_FLAGS_NOT_REQUIRED (1 << 0) /* A key_value_pair_t for this option can be provided */ + /* but is not absolutely required by the plug-in */ +#define EVMS_OPTION_FLAGS_NO_INITIAL_VALUE (1 << 1) /* The plug-in has not provided an initial value */ +#define EVMS_OPTION_FLAGS_AUTOMATIC (1 << 2) /* Backend is capable of selecting reasonable value */ +#define EVMS_OPTION_FLAGS_INACTIVE (1 << 3) /* Option exists but is neither optional or required */ +#define EVMS_OPTION_FLAGS_ADVANCED (1 << 4) /* Option is an "advanced user option" */ +#define EVMS_OPTION_FLAGS_VALUE_IS_LIST (1 << 5) /* Value is/is expected to be a pointer to value_list_t */ +#define EVMS_OPTION_FLAGS_NO_UNIT_CONVERSION (1 << 6) /* Don't convert unit measurements, e.g. I really mean */ + /* to have the user specify/see sectors not KB or MB */ + +#define EVMS_OPTION_IS_ACTIVE(flags) (((flags) & EVMS_OPTION_FLAGS_INACTIVE) == 0) +#define EVMS_OPTION_IS_REQUIRED(flags) (((flags) & EVMS_OPTION_FLAGS_NOT_REQUIRED) == 0) +#define EVMS_OPTION_HAS_VALUE(flags) (((flags) & EVMS_OPTION_FLAGS_NO_INITIAL_VALUE) == 0) +#define EVMS_OPTION_VALUE_IS_LIST(flags) (((flags) & EVMS_OPTION_FLAGS_VALUE_IS_LIST) != 0) + +/* + * Following bitset indicating additional information of + * the outcome of a set_object or a set action on a option value. + */ + +typedef enum { + EVMS_Effect_Inexact = (1 << 0), /* Option value was adjusted by backend */ + EVMS_Effect_Reload_Options = (1 << 1), /* Setting of an object or option has affected */ + /* the value or availability of other options */ + EVMS_Effect_Reload_Objects = (1 << 2) /* Setting of an object or option has affected */ + /* the acceptable and/or selected objects */ + /* or the limits of objects selected. */ +} task_effect_t; + +/* + * Extended information structure. Plug-ins generate an + * array of these to supply plugin-specific information. + * They are similar to option descriptors but lighter. + */ + +typedef struct extended_info_s { + char *name; /* Info field name */ + char *title; /* One or two word description of info field */ + char *desc; /* Multi-sentence description of info field */ + value_type_t type; /* Defines info data type */ + value_unit_t unit; /* Defines info unit value */ + value_format_t format; /* Suggested format for display of values */ + value_t value; /* Single value if not a collection */ + collection_type_t collection_type; /* Defines if either a list or range of values */ + value_collection_t collection; /* Either a list or range of values of value_type_t */ + group_info_t group; /* Group information for display purposes */ + u_int16_t flags; /* Extended info flags (defined below) */ +} extended_info_t; + +#define EVMS_EINFO_FLAGS_NO_UNIT_CONVERSION (1 << 0) /* Don't convert unit measurements, e.g. I really */ + /* mean the user to see sectors not KB or MB */ +#define EVMS_EINFO_FLAGS_MORE_INFO_AVAILABLE (1 << 1)/* This entry has more information if */ + /* queried by name. */ + +typedef struct extended_info_array_s { + u_int count; /* Count of extended_info_t structs in array */ + extended_info_t info[1]; /* Info descriptors */ +} extended_info_array_t; + +#endif diff --git a/lib/evms/plugfuncs.h b/lib/evms/plugfuncs.h new file mode 100644 index 00000000..9b887efa --- /dev/null +++ b/lib/evms/plugfuncs.h @@ -0,0 +1,1128 @@ +/* + * + * Copyright (c) International Business Machines Corp., 2001 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Module: plugfuncs.h + */ + +#ifndef EVMS_PLUGFUNCS_H_INCLUDED +#define EVMS_PLUGFUNCS_H_INCLUDED 1 + +#include +#include +#include +#include + +#ifdef ABI_EVMS_1_0 +#define ENGINE_PLUGIN_API_MAJOR_VERION 3 +#else +#define ENGINE_PLUGIN_API_MAJOR_VERION 7 +#endif +#define ENGINE_PLUGIN_API_MINOR_VERION 0 +#define ENGINE_PLUGIN_API_PATCH_LEVEL 0 + +/* Maximum length of a user message. */ +#define MAX_USER_MESSAGE_LEN 10240 + +/* + * For all can_????() functions, the function returns 0 if "yes", else a reason code. + */ + +typedef struct engine_functions_s { +#ifndef ABI_EVMS_1_0 + /* + * Get the version of the plug-in API that this Engine provides. + */ + void (*get_engine_plugin_api_version)(evms_version_t * version); +#endif + + /* + * Get a list of the user space plug-ins that are loaded, optionally + * filtering by type and flags. If the type parameter is not 0, only + * plug-ins of that type will be returned. If type is 0, all plug-ins will + * be returned. See common.h for the definitions of plugin_search_flags_t. + */ + int (*get_plugin_list)(plugin_type_t type, + plugin_search_flags_t flags, + dlist_t * plugins); + + /* + * Get the plugin_record_t for a given plug-in ID. + */ + int (*get_plugin_by_ID)(plugin_id_t plugin_id, + plugin_record_t * * plugin); + + /* + * Get the plugin_record_t for a given plug-in short name. + */ + int (*get_plugin_by_name)(char * plugin_short_name, + plugin_record_t * * plugin); + + /* + * Get a list of volumes, optionally filtering by FSIM. If FSIM is + * specified, only volumes managed by that FSIM will be returned. If FSIM + * is NULL, all volumes will be returned. + */ + int (*get_volume_list)(plugin_record_t * fsim, + dlist_t * volume_list); + + /* + * Get a list of objects, optionally filtering by object type, data type, + * and plug-in. See the object_type_t, data_type_t, and + * object_search_flags_t enums in common.h. If object_type is 0, objects of + * any type will be returned. If data_type is 0, objects of any data type + * will be returned. If plugin is NULL, objects managed by any plug-in will + * be returned. + */ + int (*get_object_list)(object_type_t object_type, + data_type_t data_type, + plugin_record_t * plugin, + object_search_flags_t flags, + dlist_t * objects); + + /* + * Get a list of storage containers, optionally filtering by plug-in. + * If plugin is specified, only containers managed by that plug-in + * will be returned. If plugin is NULL, all containers will be returned. + */ + int (*get_container_list)(plugin_record_t * plugin, + dlist_t * container_list); + + /* + * Issue an ioctl to the EVMS kernel block device. The Engine opens + * and locks the EVMS kernel block device. While the Engine is open + * for writing, no other application, not even Engine plug-ins, can + * open the EVMS kernel block device. Plug-ins use this service + * to have the Engine issue an ioctl to the EVMS kernel block device + * on their behalf. + */ + int (*ioctl_evms_kernel)(unsigned long cmd, + void * arg); + /* + * Allocate a storage_object_t for a logical disk structure. + */ + int (*allocate_logical_disk)(char * name, + storage_object_t * * new_disk); + + /* + * Free a storage_object_t for a logical disk. + */ + int (*free_logical_disk)(storage_object_t * disk); + + /* + * Allocate a storage_object_t for a disk_segment. The caller is + * responsible for putting the storage_object_t for the logical disk from + * which this segment comes into the child_objects list in the + * storage_object_t for the segment. Additionally, the caller must add the + * storage_object_t for the disk segment to the parent_objects list in the + * storage_object_t for the logical disk. + */ + int (*allocate_segment)(char * name, + storage_object_t * * new_segment); + + /* + * Free a storage_object_t for a disk_segment. + */ + int (*free_segment)(storage_object_t * segment); + + /* + * Allocate a storage_container_t structure. The caller fills in the + * objects_consumed and objects_produced lists in the container. The caller + * fills in the appropriate consuming_container and producing_container + * fields in the storage_object_t(s) that are consumed or produced by the + * container. + */ + int (*allocate_container)(char * name, + storage_container_t * * new_container); + + /* + * Free a storage_container_t structure. + */ + int (*free_container)(storage_container_t * container); + + /* + * Allocate a storage_object_t for a storage_region. The caller is + * responsible for putting the storage_object_t from which this region comes + * into the child_objects list in the storage_object_t for the region. + * Additionally, the caller must add the storage_object_t for the region to + * the parent_objects list in the storage_object_t from which this region + * comes. + */ + int (*allocate_region)(char * name, + storage_object_t * * new_region); + + /* + * Free the storage_region structure. + */ + int (*free_region)(storage_object_t * region); + + /* + * Allocate a storage_object_t for an EVMS object. The caller is + * responsible for putting the storage_object_t from which this EVMS object + * comes into the child_objects list in the storage_object_t for the EVMS + * object. Additionally, the caller must add the storage_object_t for the + * EVMS object to the parent_objects list in the storage_object_t from which + * this EVMS object comes. + */ + int (*allocate_evms_object)(char * name, + storage_object_t * * new_object); + + /* + * Free a storage_object_t for an EVMS object. + */ + int (*free_evms_object)(storage_object_t * object); + + /* + * engine_alloc is the generic memory allocation service provided by the + * Engine. For any memory that plug-ins return to the Engine, the plug-in + * must use the same malloc() that the Engine uses so that the Engine can + * properly free() the memory. To assist the plug-ins, the Engine provides + * a common allocation function which the plug-ins can use so that all + * memory allocations are managed by the same memory manager. Memory will + * be zero filled. + */ + void * (*engine_alloc)(u_int32_t size); + + /* + * engine_free is the generic memory deallocation service provided by the + * Engine. + */ + void (*engine_free)(void *); + + /* + * Check if there are any changes pending in the Engine. + */ + BOOLEAN (*changes_pending)(void); + + /* + * Tell the Engine that there are changes pending, i.e., there is stuff to + * be committed to disk. + */ + void (*set_changes_pending)(void); + + /* + * Check if the Engine is in the process of committing changes. + */ + BOOLEAN (*commit_in_progress)(void); + + /* + * Write data to the Engine's log file. + */ + int (*write_log_entry)(debug_level_t level, + plugin_record_t * plugin, + char * fmt, + ...); + + /* + * Calculate a 32-bit CRC for a buffer of a given size. + * On the first call to calculate_CRC() the CRC parameter must be + * 0xffffffff. + * calculate_CRC() can be called multiple times to get the CRC for an + * aggregate of buffers. To do so, subsequent calls set the CRC parameter + * to the resulting CRC that was returned from the previous call. + * To calculate a new CRC, the CRC parameter must be set to 0xffffffff. + */ + u_int32_t (*calculate_CRC)(u_int32_t crc, + void * buffer, + u_int32_t buffer_size); + + /* + * Calculate a checksum on a buffer of given size. This Engine service + * actually issues an ioctl() to the EVMS kernel to use the kernel's + * checksum function so that checksums are consistent with the runtime + * code. An error code is returned if the ioctl to the kernel fails. + * "insum" is the initial checksum value, useful if you are doing a + * single checksum on a series of multiple data blocks. + */ + int (*calculate_checksum)(unsigned char * buffer, + int buffer_size, + unsigned int insum, + unsigned int * outsum); + + /* + * Add sectors that are to be written with zeros to the Engine's Kill Sector + * list. Should only be called by device managers + */ + int (*add_sectors_to_kill_list)(storage_object_t * disk, /* Disk on which the sectors reside */ + lba_t lba, /* Sector number of the first sector */ + /* to wipe out */ + sector_count_t count); /* Number of sectors to wipe out */ + + + /* + * Tell the Engine that this volume should be rediscovered when the changes + * are committed. Call this function if you make changes to the volume's + * underlying objects, regions, etc. that will have to be discovered by the + * kernel runtime code in order to build the volume correctly. + * Set sync_fs to TRUE if you want the file system on the volume to + * be synced in a safe state before the volume is rediscovered. + */ + int (*rediscover_volume)(logical_volume_t * volume, + BOOLEAN sync_fs); + + /* + * Check to make sure this name is valid and no other object has the same + * name. + */ + int (*validate_name)(char * name); + + /* + * Register the name for an object. The Engine will make sure that there is + * no other object with the same name. If the name is not valid (e.g., it's + * too long) or another object has already registered the name, an error + * will be returned. + */ + int (*register_name)(char * name); + + /* + * Unregister the name of an object. + */ + int (*unregister_name)(char * name); + + /* + * Ask all the parent objects of this object if they can handle this object + * expanding by the specified amount. Parent plug-ins may modify the size + * according to any constrains they have. If the size has not been changed + * by any of the parents, the Engine will return 0. If all the parents + * don't return an error but the size has been updated, the Engine will + * return EAGAIN. + */ + int (*can_expand_by)(storage_object_t * object, + sector_count_t * delta_size); + + /* + * Ask all the parent objects of this object if they can handle this object + * shrinking by the specified amount. Parent plug-ins may modify the size + * according to any constrains they have. If the size has not been changed + * by any of the parents, the Engine will return 0. If all the parents + * don't return an error but the size has been updated, the Engine will + * return EAGAIN. + */ + int (*can_shrink_by)(storage_object_t * object, + sector_count_t * delta_size); + + /* + * Send a message to the user interface. This service can be used in three + * ways. + * + * 1) Send a notification message to the user expecting no response. + * + * user_message(plugin_record, NULL, NULL, message_fmt, ...); + * + * 2) Ask a question and get one item selected from a list of two or more + * items. + * + * char * choices = {string1, string2, ..., NULL}; + * user_message(plugin_record, &answer, choices, message_fmt, ...); + * + * The "choices" parameter is a NULL terminated array of strings that + * describe each of the choices. "*answer" *must* be initialized to the + * default response. The UI will present the message and the choices to + * the user. On return, *answer will contain the index of the selected + * choice string. + */ + int (*user_message)(plugin_record_t * plugin, + int * answer, + char * * choice_text, + char * message_fmt, + ...); + + /* + * user_communication() uses the option_descriptor_t structures to convey a + * group of choices to the user. Use this service when you have a complex + * list of things to ask of the user, e.g., they are of several different + * types (strings, ints, etc), they have constraints on their selection, or + * they may have dependencies on each other. + * + * The Engine will create a EVMS_Task_Message task for the UI. The UI will + * use the task when calling the evms_get_option_descriptor(), + * evms_set_option_value(), etc. APIs for getting and setting options. + * Your plug-in will be called on its set_option() function with the task + * context. The action will be EVMS_Task_Message, the task object will be + * set to the object_instance parameter that you provide on the call to + * user_communication(). + * + * The "message_text" will be treated by the UI as a title for the options + * that are presented. "options" is an array of option_descriptor_t + * structures. Each of the option descriptors *must* have an initial value. + */ + int (*user_communication)(void * object_instance, + char * message_text, + option_desc_array_t * options); + + /* + * Can this object be renamed? The Engine will figure out if there are any + * restrictions that would prevent the object from being renamed, e.g., the + * object is the topmost object of a compatibility volume (the volume name + * will have been derived from the object) and the volume is mounted. The + * Engine won't allow a volume that is mounted to be renamed. If the + * object cannot be renamed, the Engine will return an error code that + * (hopefully) gives some indication as to why the rename is not allowed. + * Plug-ins call this Engine service before allowing their object name to + * be changed by a set_info() call. + */ + int (*can_rename)(storage_object_t * object); + + /* + * Is this volume mounted? If you want to know the name of the mount point, + * specify a location in mount_name where the service will place a pointer + * to malloced memory that contains the mount point name. Remember to free + * the string when you are finished with it. If you do not want to know the + * mount point and not have the hassle of freeing the memory, specify NULL + * for mount_name. + */ + BOOLEAN (*is_mounted)(char * volume_name, + char * * mount_name); + +} engine_functions_t; + + +typedef struct fsim_functions_s { + int (*setup_evms_plugin)(engine_mode_t mode, + engine_functions_t * functions); + + void (*cleanup_evms_plugin)(void); + + /* + * Does this FSIM manage the file system on this volume? + * Return 0 for "yes", else a reason code. + */ + int (*is_this_yours)(logical_volume_t * volume); + + /* + * Get the current size of the file system on this volume. + */ + int (*get_fs_size)(logical_volume_t * volume, + sector_count_t * fs_size); + + /* + * Get the file system size limits for this volume. + */ + int (*get_fs_limits)(logical_volume_t * volume, + sector_count_t * fs_min_size, + sector_count_t * fs_max_size, + sector_count_t * vol_max_size); + + /* + * Can you install your file system on this volume? + */ + int (*can_mkfs)(logical_volume_t * volume); + + /* + * Can you remove your file system from this volume? + */ + int (*can_unmkfs)(logical_volume_t * volume); + + /* + * Can you fsck this volume? + */ + int (*can_fsck)(logical_volume_t * volume); + + /* + * Can you defrag this volume? + */ + int (*can_defrag)(logical_volume_t * volume); + + /* + * Can you expand this volume by the amount specified? + * If your file system cannot handle expansion at all, return an + * error code that indicates why it cannot be expanded.. + * If your file system can expand but cannot handle having unused + * space after the end of your file system, adjust the *delta_size + * to the maximum you allow and return 0. + * If your file system cannot fill the resulting size but your file + * system can handle extra unused space after the end of the file + * system, then do not change the *delta_size and return 0. + */ + int (*can_expand_by)(logical_volume_t * volume, + sector_count_t * delta_size); + + /* + * Can you shrink this volume by the amount specified? + * If your file system cannot handle shrinking at all, return an + * error code that indicates why it cannot be shrunk. + * If your file system can shrink but the *delta_size is too much to + * shrink by, adjust the *delta_size to the maximum shrinkage you allow and + * return 0. + */ + int (*can_shrink_by)(logical_volume_t * volume, + sector_count_t * delta_size); + + /* + * Install your file system on the volume. + */ + int (*mkfs)(logical_volume_t * volume, + option_array_t * options); + + /* + * Remove your file system from the volume. This could be as simple as + * wiping out critical sectors, such as a superblock, so that you will + * no longer detect that your file system is installed on the volume. + */ + int (*unmkfs)(logical_volume_t * volume); + + /* + * Run fsck on the volume. + */ + int (*fsck)(logical_volume_t * volume, + option_array_t * options); + + /* + * Defragment on the volume. + */ + int (*defrag)(logical_volume_t * volume, + option_array_t * options); + + /* + * Expand the volume to new_size. If the volume is not expanded exactly to + * new_size, set new_sie to the new_size of the volume. + */ + int (*expand)(logical_volume_t * volume, + sector_count_t * new_size); + + /* + * Shrink the volume to new_size. If the volume is not expanded exactly to + * new_size, set new_size to the new_size of the volume. + */ + int (*shrink)(logical_volume_t * volume, + sector_count_t requested_size, + sector_count_t * new_size); + + /* + * Return the total number of supported options for the specified task. + */ + int (*get_option_count)(task_context_t * context); + + /* + * Fill in the initial list of acceptable objects. Fill in the minimum and + * maximum number of objects that must/can be selected. Set up all initial + * values in the option_descriptors in the context record for the given + * task. Some fields in the option_descriptor may be dependent on a + * selected object. Leave such fields blank for now, and fill in during the + * set_objects call. + */ + int (*init_task)(task_context_t * context); + + /* + * Examine the specified value, and determine if it is valid for the task + * and option_descriptor index. If it is acceptable, set that value in the + * appropriate entry in the option_descriptor. The value may be adjusted + * if necessary/allowed. If so, set the effect return value accordingly. + */ + int (*set_option)(task_context_t * context, + u_int32_t index, + value_t * value, + task_effect_t * effect); + + /* + * Validate the volumes in the selected_objects dlist in the task context. + * Remove from the selected objects lists any volumes which are not + * acceptable. For unacceptable volumes, create a declined_handle_t + * structure with the reason why it is not acceptable, and add it to the + * declined_volumes dlist. Modify the acceptable_objects dlist in the task + * context as necessary based on the selected objects and the current + * settings of the options. Modify any option settings as necessary based + * on the selected objects. Return the appropriate task_effect_t settings + * if the object list(s), minimum or maximum objects selected, or option + * settings have changed. + */ + int (*set_volumes)(task_context_t * context, + dlist_t declined_volumes, /* of type declined_handle_t */ + task_effect_t * effect); + + + /* + * Return any additional information that you wish to provide about the + * volume. The Engine provides an external API to get the information + * stored in the logical_volume_t. This call is to get any other + * information about the volume that is not specified in the + * logical_volume_t. Any piece of information you wish to provide must be + * in an extended_info_t structure. Use the Engine's engine_alloc() to + * allocate the memory for the extended_info_t. Also use engine_alloc() to + * allocate any strings that may go into the extended_info_t. Then use + * engine_alloc() to allocate an extended_info_array_t with enough entries + * for the number of extended_info_t structures you are returning. Fill + * in the array and return it in *info. + * If you have extended_info_t descriptors that themselves may have more + * extended information, set the EVMS_EINFO_FLAGS_MORE_INFO_AVAILABLE flag + * in the extended_info_t flags field. If the caller wants more information + * about a particular extended_info_t item, this API will be called with a + * pointer to the storage_object_t and with a pointer to the name of the + * extended_info_t item. In that case, return an extended_info_array_t with + * further information about the item. Each of those items may have the + * EVMS_EINFO_FLAGS_MORE_INFO_AVAILABLE flag set if you desire. It is your + * responsibility to give the items unique names so that you know which item + * the caller is asking additional information for. If info_name is NULL, + * the caller just wants top level information about the object. + */ + int (*get_volume_info)(logical_volume_t * volume, + char * info_name, + extended_info_array_t * * info); + + /* + * Apply the settings of the options to the given volume. + */ + int (*set_volume_info)(logical_volume_t * volume, + option_array_t * options); + + /* + * Return any additional information that you wish to provide about your + * plug-in. The Engine provides an external API to get the information + * stored in the plugin_record_t. This call is to get any other + * information about the plug-in that is not specified in the + * plugin_record_t. Any piece of information you wish to provide must be + * in an extended_info_t structure. Use the Engine's engine_alloc() to + * allocate the memory for the extended_info_t. Also use engine_alloc() to + * allocate any strings that may go into the extended_info_t. Then use + * engine_alloc() to allocate an extended_info_array_t with enough entries + * for the number of extended_info_t structures you are returning. Fill + * in the array and return it in *info. + * If you have extended_info_t descriptors that themselves may have more + * extended information, set the EVMS_EINFO_FLAGS_MORE_INFO_AVAILABLE flag + * in the extended_info_t flags field. If the caller wants more information + * about a particular extended_info_t item, this API will be called with a + * pointer to the storage_object_t and with a pointer to the name of the + * extended_info_t item. In that case, return an extended_info_array_t with + * further information about the item. Each of those items may have the + * EVMS_EINFO_FLAGS_MORE_INFO_AVAILABLE flag set if you desire. It is your + * responsibility to give the items unique names so that you know which item + * the caller is asking additional information for. If info_name is NULL, + * the caller just wants top level information about the object. + */ + int (*get_plugin_info)(char * info_name, + extended_info_array_t * * info); + +#ifndef ABI_EVMS_1_0 + /* + * Return an array of private actions that you support for this volume. + */ + int (*get_plugin_functions)(logical_volume_t * volume, + function_info_array_t * * actions); + + /* + * Execute the private action on the volume. + */ + int (*plugin_function)(logical_volume_t * volume, + task_action_t action, + dlist_t objects, + option_array_t * options); +#endif + + /* + * Generic method for communicating with your plug-in. + */ + int (*direct_plugin_communication)(void * thing, + BOOLEAN target_kernel_plugin, + void * arg); + +} fsim_functions_t; + + +typedef struct plugin_functions_s { + int (*setup_evms_plugin)(engine_mode_t mode, + engine_functions_t * functions); + + void (*cleanup_evms_plugin)(void); + +#ifndef ABI_EVMS_1_0 + /* + * Can you apply your plug-in to the input_object? If yes, return the size + * of the object you would create. + * The Engine will only call this function on EVMS feature plug-ins. + * Other plug-ins may choose whether or not to support this API. + */ + int (*can_add_feature)(storage_object_t * input_object, + sector_count_t * size); +#endif + + /* + * Can you delete this object? + */ + int (*can_delete)(storage_object_t * object); + +#ifndef ABI_EVMS_1_0 + /* + * Can you unassign your plug-in from this object? + */ + int (*can_unassign)(storage_object_t * object); +#endif + + /* + * Can you expand this object? If yes, build an expand_object_info_t and + * add it to the expand_points list. If you can't expand, but allow one of + * your children to expand, call can_expand on whichever child you will + * allow to expand. If you can not handle expanding below you, do not pass + * the command down to your child. + */ + int (*can_expand)(storage_object_t * object, + sector_count_t * expand_limit, // a delta size + dlist_t expand_points); // of type expand_object_info_t, + // tag = EXPAND_OBJECT_TAG + + /* + * Can you allow your child object to expand by "size"? Return 0 if yes, + * else an error code. "size" is the delta expand BY size, not the + * resulting size. Update the "size" if your object would expand by a + * different delta size when your child object expanded by the given size. + */ + int (*can_expand_by)(storage_object_t * object, + sector_count_t * size); + + /* + * Can you shrink this object? If yes, build a shrink_object_info_t and + * add it to the shrink_points list. If you can't shrink, but allow one of + * your children to shrink, call can_shrink on whichever child you will + * allow to shrink. If you can not handle shrinking below you, do not pass + * the command down to your child. + */ + int (*can_shrink)(storage_object_t * object, + sector_count_t * shrink_limit, // a delta size + dlist_t shrink_points); // of type shrink_object_info_t, + // tag = SHRINK_OBJECT_TAG + + + /* + * Can you allow your child object to shrink by "size"? Return 0 if yes, + * else an error code. "size" is the delta shrink BY size, not the + * resulting size. Update the "size" if your object would shrink by a + * different delta size when your child object shrunk by the given size. + */ + int (*can_shrink_by)(storage_object_t * object, + sector_count_t * size); + + /* + * Can you move this object? + */ + int (*can_move)(storage_object_t * object); + + /* + * Will you allow your object to be made into a volume? (We don't see + * any reason why you wouldn't.) Will you allow a volume to be reverted + * off the top of your object? The "flag" parameter says whether the + * volume is to be created (TRUE) or removed (FALSE). + */ + int (*can_set_volume)(storage_object_t * object, + BOOLEAN flag); + + /* + * Claim objects by removing them from the list. Create a storage_object_t + * for the object you are discovering, fill in the appropriate fields and + * put the new object on the output_objects list. If you do not claim an + * object from the input list, then just copy/move it to the output list. + * The input list can be modified at will. The output list must contain + * all the storage objects in the system after yours are discovered, i.e., + * it is the input list, minus the objects you claim, plus the objects you + * produce. + */ + int (*discover)(dlist_t input_objects, + dlist_t output_objects, + BOOLEAN final_call); + + /* + * Create storage_object_t(s) from the list of objects using the given + * options. Return the newly allocated storage_object_t(s) in new_objects + * list. + */ + int (*create)(dlist_t input_objects, + option_array_t * options, + dlist_t output_objects); + +#ifndef ABI_EVMS_1_0 + /* + * Assign your plug-in to produce storage objects from the given storage + * object. This function makes sense mainly for segment managers that are + * assigned to disks (or segments). + */ + int (*assign)(storage_object_t * object, + option_array_t * options); +#endif + + /* + * Delete the object. Free any privately allocated data. Remove your + * parent pointer from your child objects. Do any cleanup necessary to + * remove your plug-in from your child objects. Put your object's children + * from the object's child_objects dlist_t onto the dlist_t provided in the + * second parameter. Call the Engine's free_?????t() to free the object. + */ + int (*delete)(storage_object_t * object, + dlist_t child_objects); + +#ifndef ABI_EVMS_1_0 + /* + * Unassign your plug-in from producing storage objects from the given + * storage object. This function makes sense mainly for segment managers + * that are assigned to disks (or segments). + */ + int (*unassign)(storage_object_t * object); +#endif + + /* + * If the "object" is not the "expand_object", then your child is going to + * expand. Do any necessary work to get ready for your child to expand, + * e.g., read in meta data, then call expand() on your child object which + * will expand. Upon return from the call to your child's expand(), do + * any work necessary to adjust this object to account for the child + * object's new size, e.g., update the location of meta data. + * If the "object" is the same as the "expand_object", then this is the + * object targeted for expanding. Expand the object according to the + * input_objects given and the options selected. + */ + int (*expand)(storage_object_t * object, + storage_object_t * expand_object, + dlist_t input_objects, + option_array_t * options); + + /* + * If the "object" is not the "shrink_object", then your child is going to + * shrink. Do any necessary work to get ready for your child to shrink, + * e.g., read in meta data, then call shrink() on your child object which + * will shrink. Upon return from the call to your child's shrink(), do + * any work necessary to adjust this object to account for the child + * object's new size, e.g., update the location of meta data. + * If the "object" is the same as the "shrink_object", then this is the + * object targeted for shrinking. Shrink the object according to the + * input_objects given and the options selected. + */ + int (*shrink)(storage_object_t * object, + storage_object_t * shrink_object, + dlist_t input_objects, + option_array_t * options); + + /* + * Move the contents of the source object to the target object using the + * given options. + */ + int (*move)(storage_object_t * source, + storage_object_t * target, + option_array_t * options); + + /* + * This call notifies you that your object is being made into (or part of) + * a volume or that your object is no longer part of a volume. The "flag" + * parameter indicates whether the volume is being created (TRUE) or + * removed (FALSE). + */ + void (*set_volume)(storage_object_t * object, + BOOLEAN flag); + + /* + * Put sectors on the kill list. The plug-in translates the lsn and count + * into lsn(s) and count(s) for its child object(s) and calls the child + * object's add_sectors_to_kill_list(). + * The Device Manager calls the Engine's add_sectors_to_kill_list service + * to put the sectors on the Engine's kill list. + */ + int (*add_sectors_to_kill_list)(storage_object_t * object, + lsn_t lsn, + sector_count_t count); + + /* + * Write your plug-ins data, e.g., feature header and feature meta data, to + * disk. Clear the SOFLAG_DIRTY in the storage_object_t(s). + * Committing changes in done in several (two for now) phases. "phase" + * says which phase of the commit is being performed. + * Write your first copy of meta data during phase 1; write your second + * copy of meta data (if you have one) during phase 2. + */ + int (*commit_changes)(storage_object_t * object, + uint phase); + + /* + * Return the total number of supported options for the specified task. + */ + int (*get_option_count)(task_context_t * context); + + /* + * Fill in the initial list of acceptable objects. Fill in the minimum and + * maximum number of objects that must/can be selected. Set up all initial + * values in the option_descriptors in the context record for the given + * task. Some fields in the option_descriptor may be dependent on a + * selected object. Leave such fields blank for now, and fill in during the + * set_objects call. + */ + int (*init_task)(task_context_t * context); + + /* + * Examine the specified value, and determine if it is valid for the task + * and option_descriptor index. If it is acceptable, set that value in the + * appropriate entry in the option_descriptor. The value may be adjusted + * if necessary/allowed. If so, set the effect return value accordingly. + */ + int (*set_option)(task_context_t * context, + u_int32_t index, + value_t * value, + task_effect_t * effect); + + /* + * Validate the objects in the selected_objects dlist in the task context. + * Remove from the selected objects lists any objects which are not + * acceptable. For unacceptable objects, create a declined_handle_t + * structure with the reason why it is not acceptable, and add it to the + * declined_objects dlist. Modify the acceptable_objects dlist in the task + * context as necessary based on the selected objects and the current + * settings of the options. Modify any option settings as necessary based + * on the selected objects. Return the appropriate task_effect_t settings + * if the object list(s), minimum or maximum objects selected, or option + * settings have changed. + */ + int (*set_objects)(task_context_t * context, + dlist_t declined_objects, /* of type declined_handle_t */ + task_effect_t * effect); + + /* + * Return any additional information that you wish to provide about the + * object. The Engine provides an external API to get the information + * stored in the storage_object_t. This call is to get any other + * information about the object that is not specified in the + * storage_object_t. Any piece of information you wish to provide must be + * in an extended_info_t structure. Use the Engine's engine_alloc() to + * allocate the memory for the extended_info_t. Also use engine_alloc() to + * allocate any strings that may go into the extended_info_t. Then use + * engine_alloc() to allocate an extended_info_array_t with enough entries + * for the number of extended_info_t structures you are returning. Fill + * in the array and return it in *info. + * If you have extended_info_t descriptors that themselves may have more + * extended information, set the EVMS_EINFO_FLAGS_MORE_INFO_AVAILABLE flag + * in the extended_info_t flags field. If the caller wants more information + * about a particular extended_info_t item, this API will be called with a + * pointer to the storage_object_t and with a pointer to the name of the + * extended_info_t item. In that case, return an extended_info_array_t with + * further information about the item. Each of those items may have the + * EVMS_EINFO_FLAGS_MORE_INFO_AVAILABLE flag set if you desire. It is your + * responsibility to give the items unique names so that you know which item + * the caller is asking additional information for. If info_name is NULL, + * the caller just wants top level information about the object. + */ + int (*get_info)(storage_object_t * object, + char * info_name, + extended_info_array_t * * info); + + /* + * Apply the settings of the options to the given object. + */ + int (*set_info)(storage_object_t * object, + option_array_t * options); + + /* + * Return any additional information that you wish to provide about your + * plug-in. The Engine provides an external API to get the information + * stored in the plugin_record_t. This call is to get any other + * information about the plug-in that is not specified in the + * plugin_record_t. Any piece of information you wish to provide must be + * in an extended_info_t structure. Use the Engine's engine_alloc() to + * allocate the memory for the extended_info_t. Also use engine_alloc() to + * allocate any strings that may go into the extended_info_t. Then use + * engine_alloc() to allocate an extended_info_array_t with enough entries + * for the number of extended_info_t structures you are returning. Fill + * in the array and return it in *info. + * If you have extended_info_t descriptors that themselves may have more + * extended information, set the EVMS_EINFO_FLAGS_MORE_INFO_AVAILABLE flag + * in the extended_info_t flags field. If the caller wants more information + * about a particular extended_info_t item, this API will be called with a + * pointer to the storage_object_t and with a pointer to the name of the + * extended_info_t item. In that case, return an extended_info_array_t with + * further information about the item. Each of those items may have the + * EVMS_EINFO_FLAGS_MORE_INFO_AVAILABLE flag set if you desire. It is your + * responsibility to give the items unique names so that you know which item + * the caller is asking additional information for. If info_name is NULL, + * the caller just wants top level information about the object. + */ + int (*get_plugin_info)(char * info_name, + extended_info_array_t * * info); + + /* + * Convert lsn and count to lsn and count on the child object(s) and and + * call the read function of child objects. + */ + int (*read)(storage_object_t * object, + lsn_t lsn, + sector_count_t count, + void * buffer); + + /* + * Convert lsn and count to lsn and count on the child object(s) and and + * call the write function of child objects. + */ + int (*write)(storage_object_t * object, + lsn_t lsn, + sector_count_t count, + void * buffer); + +#ifndef ABI_EVMS_1_0 + /* + * Return an array of private actions that you support for this object. + */ + int (*get_plugin_functions)(storage_object_t * object, + function_info_array_t * * actions); + + /* + * Execute the private action on the object. + */ + int (*plugin_function)(storage_object_t * object, + task_action_t action, + dlist_t objects, + option_array_t * options); +#endif + + /* + * Generic method for communicating with your plug-in. + */ + int (*direct_plugin_communication)(void * thing, + BOOLEAN target_kernel_plugin, + void * arg); + +} plugin_functions_t; + + +typedef struct container_functions_s { + + /* + * Can you create a container from this list of data segments? + */ + int (*can_create_container)(dlist_t objects); + + /* + * Can you destroy the container? You must check to be sure that no regions + * are exported from this container. + */ + int (*can_delete_container)(storage_container_t * container); + + /* + * Can you add this object to the container? + * Return 0 if you can, else return an error code. + */ + int (*can_add_object)(storage_object_t * object, + storage_container_t * container); + + /* + * Can you remove this object from the container that currently consumes + * it? Return 0 if you can, else return an error code. + */ + int (*can_remove_object)(storage_object_t * object); + + /* + * Create and fill in the container adding newly created unallocated objects + * produced as appropriate. The plug-in must claim the objects, as it does + * in discovery. Mark the container dirty. Must use allocate_container + * engine API to allocate the container structure. + */ + int (*create_container)(dlist_t objects, + option_array_t * options, + storage_container_t * * container); + + /* + * Engine will remove the object from its current container before calling + * this API. Claim the object and add it to a container objects_consumed + * list. Mark the container dirty. Update/allocate the unallocated object + * that is exported from the container. If container is NULL, add the + * object to default (or unassigned) container. + */ + int (*add_object)(storage_object_t * object, + storage_container_t * container, + option_array_t * options); + + /* + * Transfer the object from its current container to the specified + * container. Mark the container dirty. If container is NULL, transfer + * the object to the default (or unassigned) container. + */ + int (*transfer_object)(storage_object_t * object, + storage_container_t * container, + option_array_t * options); + + /* + * Remove object from its current container. Make sure there are no + * allocated objects produced by the container that are using space in the + * object. Does not destroy segment. + */ + int (*remove_object)(storage_object_t * object); + + /* + * Destroy the container. Make sure there are no allocated objects being + * produced by the container. Put your consumed objects from the + * container's objects_consumed dlist_t onto the dlist_t provided in the + * second parameter. Free any private data, then use the Engine's + * free_container() to deallocate the container object. + */ + int (*delete_container)(storage_container_t * container, + dlist_t objects_consumed); + + /* + * Write any container meta data, to disk. Clear the SCFLAG_DIRTY in the + * container. + * Committing changes in done in several (two for now) phases. "phase" + * says which phase of the commit is being performed. + * Write your first copy of meta data during phase 1; write your second + * copy of meta data (if you have one) during phase 2. + */ + int (*commit_container_changes)(storage_container_t * container, + uint phase); + + /* + * Return any additional information that you wish to provide about the + * container. The Engine provides an external API to get the information + * stored in the storage_container_t. This call is to get any other + * information about the container that is not specified in the + * storage_container_t. Any piece of information you wish to provide must + * be in an extended_info_t structure. Use the Engine's engine_alloc() to + * allocate the memory for the extended_info_t. Also use engine_alloc() to + * allocate any strings that may go into the extended_info_t. Then use + * engine_alloc() to allocate an extended_info_array_t with enough entries + * for the number of extended_info_t structures you are returning. Fill + * in the array and return it in *info. + * If you have extended_info_t descriptors that themselves may have more + * extended information, set the EVMS_EINFO_FLAGS_MORE_INFO_AVAILABLE flag + * in the extended_info_t flags field. If the caller wants more information + * about a particular extended_info_t item, this API will be called with a + * pointer to the storage_container_t and with a pointer to the name of the + * extended_info_t item. In that case, return an extended_info_array_t with + * further information about the item. Each of those items may have the + * EVMS_EINFO_FLAGS_MORE_INFO_AVAILABLE flag set if you desire. It is your + * responsibility to give the items unique names so that you know which item + * the caller is asking additional information for. If info_name is NULL, + * the caller just wants top level information about the object. + */ + int (*get_container_info)(storage_container_t * container, + char * info_name, + extended_info_array_t * * info); + + /* + * Apply the settings of the options to the given container. + */ + int (*set_container_info)(storage_container_t * container, + option_array_t * options); + +#ifndef ABI_EVMS_1_0 + /* + * Return an array of private actions that you support for this container. + */ + int (*get_plugin_functions)(storage_container_t * container, + function_info_array_t * * actions); + + /* + * Execute the private action on the container. + */ + int (*plugin_function)(storage_container_t * container, + task_action_t action, + dlist_t objects, + option_array_t * options); +#endif + +} container_functions_t; + +#endif + diff --git a/lib/evms/plugin.h b/lib/evms/plugin.h new file mode 100644 index 00000000..acb86259 --- /dev/null +++ b/lib/evms/plugin.h @@ -0,0 +1,32 @@ +/* + * + * Copyright (c) International Business Machines Corp., 2001 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Module: plugin.h + */ + +#ifndef EVMS_PLUGIN_H_INCLUDED + #define EVMS_PLUGIN_H_INCLUDED 1 + + #include + #include + #include + + #include + #include + +#endif