Whamcloud - gitweb
This commit was generated by cvs2svn to compensate for changes in r45924,
authorjacob <jacob>
Sun, 19 Dec 2004 22:54:41 +0000 (22:54 +0000)
committerjacob <jacob>
Sun, 19 Dec 2004 22:54:41 +0000 (22:54 +0000)
which included commits to RCS files with non-trunk default branches.

112 files changed:
libsysio/AUTHORS [new file with mode: 0644]
libsysio/COPYING [new file with mode: 0644]
libsysio/ChangeLog [new file with mode: 0644]
libsysio/Makefile.am [new file with mode: 0644]
libsysio/NEWS [new file with mode: 0644]
libsysio/README [new file with mode: 0644]
libsysio/Rules.make [new file with mode: 0644]
libsysio/autogen.sh [new file with mode: 0755]
libsysio/configure.in [new file with mode: 0644]
libsysio/dev/stdfd/module.mk [new file with mode: 0644]
libsysio/dev/stdfd/stdfd.c [new file with mode: 0644]
libsysio/dev/stdfd/stdfd.h [new file with mode: 0644]
libsysio/drivers/incore/README [new file with mode: 0644]
libsysio/drivers/incore/fs_incore.c [new file with mode: 0644]
libsysio/drivers/incore/fs_incore.h [new file with mode: 0644]
libsysio/drivers/incore/module.mk [new file with mode: 0644]
libsysio/drivers/native/fs_native.c [new file with mode: 0644]
libsysio/drivers/native/fs_native.h [new file with mode: 0644]
libsysio/drivers/native/module.mk [new file with mode: 0644]
libsysio/drivers/sockets/module.mk [new file with mode: 0644]
libsysio/drivers/sockets/sockets.c [new file with mode: 0644]
libsysio/drivers/yod/fs_yod.c [new file with mode: 0644]
libsysio/drivers/yod/fs_yod.h [new file with mode: 0644]
libsysio/drivers/yod/module.mk [new file with mode: 0644]
libsysio/include/cplant-yod.h [new file with mode: 0644]
libsysio/include/dev.h [new file with mode: 0644]
libsysio/include/file.h [new file with mode: 0644]
libsysio/include/fs.h [new file with mode: 0644]
libsysio/include/inode.h [new file with mode: 0644]
libsysio/include/module.mk [new file with mode: 0644]
libsysio/include/mount.h [new file with mode: 0644]
libsysio/include/namespace.h [new file with mode: 0644]
libsysio/include/sysio-symbols.h [new file with mode: 0644]
libsysio/include/sysio.h [new file with mode: 0644]
libsysio/include/xtio.h [new file with mode: 0644]
libsysio/misc/gdb-libsysio [new file with mode: 0644]
libsysio/misc/init-env.sh [new file with mode: 0644]
libsysio/src/access.c [new file with mode: 0644]
libsysio/src/chdir.c [new file with mode: 0644]
libsysio/src/chmod.c [new file with mode: 0644]
libsysio/src/chown.c [new file with mode: 0644]
libsysio/src/dev.c [new file with mode: 0644]
libsysio/src/dup.c [new file with mode: 0644]
libsysio/src/fcntl.c [new file with mode: 0644]
libsysio/src/file.c [new file with mode: 0644]
libsysio/src/file_hack.c [new file with mode: 0644]
libsysio/src/fs.c [new file with mode: 0644]
libsysio/src/fsync.c [new file with mode: 0644]
libsysio/src/getdirentries.c [new file with mode: 0644]
libsysio/src/init.c [new file with mode: 0644]
libsysio/src/inode.c [new file with mode: 0644]
libsysio/src/ioctl.c [new file with mode: 0644]
libsysio/src/ioctx.c [new file with mode: 0644]
libsysio/src/iowait.c [new file with mode: 0644]
libsysio/src/link.c [new file with mode: 0644]
libsysio/src/lseek.c [new file with mode: 0644]
libsysio/src/mkdir.c [new file with mode: 0644]
libsysio/src/mknod.c [new file with mode: 0644]
libsysio/src/module.mk [new file with mode: 0644]
libsysio/src/mount.c [new file with mode: 0644]
libsysio/src/namei.c [new file with mode: 0644]
libsysio/src/open.c [new file with mode: 0644]
libsysio/src/readlink.c [new file with mode: 0644]
libsysio/src/rename.c [new file with mode: 0644]
libsysio/src/rmdir.c [new file with mode: 0644]
libsysio/src/rw.c [new file with mode: 0644]
libsysio/src/stat.c [new file with mode: 0644]
libsysio/src/stat64.c [new file with mode: 0644]
libsysio/src/statvfs.c [new file with mode: 0644]
libsysio/src/statvfs64.c [new file with mode: 0644]
libsysio/src/stdlib.c [new file with mode: 0644]
libsysio/src/symlink.c [new file with mode: 0644]
libsysio/src/truncate.c [new file with mode: 0644]
libsysio/src/unlink.c [new file with mode: 0644]
libsysio/src/utime.c [new file with mode: 0644]
libsysio/tests/Makefile.am [new file with mode: 0644]
libsysio/tests/README [new file with mode: 0644]
libsysio/tests/cleanup.pl [new file with mode: 0755]
libsysio/tests/drv_init_all.c [new file with mode: 0644]
libsysio/tests/gendrvdata.sh [new file with mode: 0644]
libsysio/tests/help.c [new file with mode: 0644]
libsysio/tests/helper.pm [new file with mode: 0644]
libsysio/tests/module.mk [new file with mode: 0644]
libsysio/tests/populator.pl [new file with mode: 0755]
libsysio/tests/setup.pl [new file with mode: 0755]
libsysio/tests/startup.c [new file with mode: 0644]
libsysio/tests/sysio_stubs.c [new file with mode: 0644]
libsysio/tests/sysio_tests.c [new file with mode: 0644]
libsysio/tests/test.h [new file with mode: 0644]
libsysio/tests/test_all.pl [new file with mode: 0755]
libsysio/tests/test_copy.bash [new file with mode: 0644]
libsysio/tests/test_copy.c [new file with mode: 0644]
libsysio/tests/test_copy.pl [new file with mode: 0755]
libsysio/tests/test_driver.c [new file with mode: 0644]
libsysio/tests/test_driver.h [new file with mode: 0644]
libsysio/tests/test_getcwd.c [new file with mode: 0644]
libsysio/tests/test_getcwd.pl [new file with mode: 0755]
libsysio/tests/test_link.c [new file with mode: 0644]
libsysio/tests/test_list.c [new file with mode: 0644]
libsysio/tests/test_list.pl [new file with mode: 0755]
libsysio/tests/test_path.c [new file with mode: 0644]
libsysio/tests/test_path.pl [new file with mode: 0755]
libsysio/tests/test_regions.c [new file with mode: 0644]
libsysio/tests/test_rename.c [new file with mode: 0644]
libsysio/tests/test_rw.pl [new file with mode: 0755]
libsysio/tests/test_stats.c [new file with mode: 0644]
libsysio/tests/test_stats.pl [new file with mode: 0755]
libsysio/tests/test_stdfd.pl [new file with mode: 0755]
libsysio/tests/test_strided.pl [new file with mode: 0755]
libsysio/tests/test_symlink.pl [new file with mode: 0755]
libsysio/tests/test_unlink.c [new file with mode: 0644]
libsysio/tests/verifier.pl [new file with mode: 0755]

diff --git a/libsysio/AUTHORS b/libsysio/AUTHORS
new file mode 100644 (file)
index 0000000..7293307
--- /dev/null
@@ -0,0 +1 @@
+Lee Ward <lee@sandia.gov>
diff --git a/libsysio/COPYING b/libsysio/COPYING
new file mode 100644 (file)
index 0000000..2bb5b6e
--- /dev/null
@@ -0,0 +1,502 @@
+                 GNU LESSER GENERAL PUBLIC LICENSE
+                      Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+                 GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/libsysio/ChangeLog b/libsysio/ChangeLog
new file mode 100644 (file)
index 0000000..126c27f
--- /dev/null
@@ -0,0 +1,31 @@
+Sat Feb 22 10:32:10 EST 2003
+       Created <lee@sandia.gov>
+---
+
+*Added mount() api call to support sub-mounts.
+
+*Added rudimentary automounts per the namespace chapter in the "Lustre
+Architecture Reference". Note, full URI support is not implemented. See
+the README for details.
+
+Think I have it going for simultaneous 32/64 bit support. Together with
+the nagging build for test_stat.
+
+*Miscellaneous bugs fixed.
+
+---
+Lee -- Sat Mar 22 15:01:45 EST 2003
+
+*Added "incore" file system. An in-memory file system solving boot-strap
+and other annoying little chicken-and-the-egg problems.
+
+*Added support for devices
+
+*Added support for accessing the pre-opened standard file descriptors 0, 1,
+and 2 via the stdfd device driver (major number 0, minor 0, 1, and 2).
+
+---
+Lee -- Mon Jan 26 11:26:14 EST 2004
+
+*Altered the internal interface to pass the xtvec (see .../include/xtio.h) in
+order to support strided-io.
diff --git a/libsysio/Makefile.am b/libsysio/Makefile.am
new file mode 100644 (file)
index 0000000..11e6e3d
--- /dev/null
@@ -0,0 +1,91 @@
+AUTOMAKE_OPTIONS=1.6
+
+if WITH_TESTS
+TESTDIR = tests
+else
+TESTDIR =
+endif
+
+include $(top_srcdir)/src/module.mk 
+include $(top_srcdir)/include/module.mk
+include $(top_srcdir)/tests/module.mk
+include $(top_srcdir)/dev/stdfd/module.mk 
+include $(top_srcdir)/drivers/incore/module.mk 
+include $(top_srcdir)/drivers/native/module.mk 
+include $(top_srcdir)/drivers/yod/module.mk
+include $(top_srcdir)/drivers/sockets/module.mk
+
+lib_LIBRARIES = ${LIBBUILD_DIR}/libsysio.a
+
+if WITH_STDFD_DEV
+OPTIONAL_STDFD_SRCS = $(STDFD_SRCS)
+else
+OPTIONAL_STDFD_SRCS =
+endif
+
+if WITH_INCORE_DRIVER
+OPTIONAL_INCORE_SRCS = $(INCORE_SRCS)
+else
+OPTIONAL_INCORE_SRCS =
+endif
+
+if WITH_NATIVE_DRIVER
+OPTIONAL_NATIVE_SRCS = $(NATIVE_SRCS)
+else
+OPTIONAL_NATIVE_SRCS =
+endif
+
+if WITH_SOCKETS_DRIVER
+OPTIONAL_SOCKETS_SRCS = $(SOCKETS_SRCS)
+else
+OPTIONAL_SOCKETS_SRCS =
+endif
+
+if WITH_CPLANT_YOD
+OPTIONAL_YOD_SRCS = $(YOD_SRCS)
+else
+OPTIONAL_YOD_SRCS =
+endif
+
+if WITH_LUSTRE_HACK
+OPTIONAL_LUSTRE_SRCDIR_SRCS = $(LUSTRE_SRCDIR_SRCS)
+# it would be better that let configure script check this
+AM_CFLAGS = -fPIC
+else
+OPTIONAL_LUSTRE_SRCDIR_SRCS = 
+endif
+
+__LIBBUILD_DIR__libsysio_a_SOURCES = \
+       $(SRCDIR_SRCS) \
+       $(OPTIONAL_LUSTRE_SRCDIR_SRCS) \
+       $(OPTIONAL_STDFD_SRCS) \
+       $(OPTIONAL_INCORE_SRCS) \
+       $(OPTIONAL_SOCKETS_SRCS) \
+       $(OPTIONAL_NATIVE_SRCS) \
+       $(OPTIONAL_YOD_SRCS)
+
+include $(top_srcdir)/Rules.make
+
+EXTRA_DIST = Rules.make misc/init-env.sh $(TESTS_EXTRA) $(SRCDIR_EXTRA) \
+       $(INCLUDE_EXTRA) $(STDFD_EXTRA) $(INCORE_EXTRA) \
+       $(SOCKETS_EXTRA) $(NATIVE_EXTRA) $(YOD_EXTRA)
+
+AM_CPPFLAGS += ${YOD_DRIVER_FLAGS}
+
+really-clean: testsclean maintainer-clean
+       -rm -rf autom4te-2.53.cache
+       -rm -rf .deps
+       -rm -f Makefile.in 
+       -rm -f compile depcomp INSTALL install-sh missing mkinstalldirs \
+               configure aclocal.m4 
+       -rm -f config.guess config.sub
+       -rm -rf $(LIBBUILD_DIR)
+       -rm -f libsysio*.tar.gz
+       cd $(TESTDIR); rm -rf Makefile Makefile.in .deps
+
+tests: $(lib_LIBRARIES) FORCE
+       cd $(TESTDIR); make
+testsclean: FORCE
+       cd $(TESTDIR); make clean
+clean: testsclean clean-am
+FORCE:
diff --git a/libsysio/NEWS b/libsysio/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/libsysio/README b/libsysio/README
new file mode 100644 (file)
index 0000000..76b9b97
--- /dev/null
@@ -0,0 +1,66 @@
+Build
+-----
+
+To bootstrap configuration:
+
+sh autogen.sh
+./configure [options]
+
+Without the supported "--with" options only the core sysio library is
+built.
+
+Option --with-native-driver=yes will cause the "native" host name space test
+driver to be enabled and made available in drivers/native/libsysio_native.a
+when built. This is set by default; Use "no" to disable.
+
+Option --with-tests=yes will cause the test programs in the tests directory
+to be enabled. This is set by default; Use "no" to disable.
+
+Option --with-automount=<automount-file-name> will cause automount support
+to be included. If <automount-file-name> is not supplied, a default value
+of ".mount" will be used, matching the Lustre documentation.
+
+To build:
+
+Just `make' it.
+
+Automounts
+----------
+
+For a full description of this see the "Lustre Book" at:
+       <http://www.lustre.org/docs/lustre.pdf>
+
+In short, though, whenever a component is being looked up in a directory and
+that directory has the "set-UID" bit set, then the directory is
+searched for a special file. By default, that file is called ".mount" but
+you may set it to any name using the --with-automount option described
+earlier.
+
+If the content of that file has something formatted, exactly:
+
+<file-system-type>:<source>
+
+Then the <source> description is mounted on the directory containing the
+special automount file and being used as the parent in the lookup. If the
+mount is successful, the parent is replaced with the newly mounted directory
+and processing continues. If the mount fails, or the automount file
+does not exist or cannot be read, everything continues as though the operation
+had never been attempted.
+
+File systems, or volumes, or file-sets, or whatever they are called, that
+have been automounted may also be automatically unmounted when resource
+is required. They are not on a timer, unless the file system driver implements
+one for them. They just disappear as resource is needed elsewhere. As they
+were automatically mounted to begin with, they should re-establish as needed,
+transparently.
+
+REDSTORM
+--------
+
+The following works for me:
+
+#!/bin/sh
+
+export CFLAGS="-DREDSTORM -nostdinc -isystem /home/lee/REDSTORM/catamount/computeincs/i386 -isystem /home/lee/REDSTORM/catamount/include -g -W -Wall -ansi"
+
+sh configure --with-autmount=".mount" --with-native=yes --with-incore-yes --with-stdfd=yes --with-tests=yes
diff --git a/libsysio/Rules.make b/libsysio/Rules.make
new file mode 100644 (file)
index 0000000..45db68c
--- /dev/null
@@ -0,0 +1,18 @@
+
+if WITH_STDFD_DEV
+STDFD_DEV_CPPFLAGS =-DSTDFD_DEV=1 -I$(top_srcdir)/dev/stdfd
+else
+STFD_DEV_CPPFLAGS =
+endif
+
+if WITH_SOCKETS_DRIVER
+SOCKETS_CPPFLAGS=-DWITH_SOCKETS=1
+else
+SOCKETS_CPPFLAGS=
+endif
+
+DEV_CPPFLAGS = $(STDFD_DEV_CPPFLAGS)
+
+AM_CPPFLAGS = \
+       $(AUTOMOUNT) $(ZERO_SUM_MEMORY) $(DEV_CPPFLAGS) $(SOCKETS_CPPFLAGS) \
+       -I$(top_srcdir)/include 
diff --git a/libsysio/autogen.sh b/libsysio/autogen.sh
new file mode 100755 (executable)
index 0000000..81ad5b6
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+aclocal &&
+automake --add-missing --copy &&
+${AUTOCONF:-autoconf}
diff --git a/libsysio/configure.in b/libsysio/configure.in
new file mode 100644 (file)
index 0000000..9f83269
--- /dev/null
@@ -0,0 +1,427 @@
+AC_INIT(libsysio, 0.1)
+
+AC_CANONICAL_HOST
+
+case "$host_os" in
+  linux*)
+       ;;
+  *)
+       AC_MSG_WARN('***' ${host_os}: Unsupported OS target)
+       ;;
+esac
+
+AM_INIT_AUTOMAKE([subdir-objects])
+AM_PROG_CC_C_O
+
+AC_PROG_CC
+AC_PROG_RANLIB
+AC_PROG_MAKE_SET
+AC_HEADER_STDC
+AC_HEADER_STAT
+AC_HEADER_TIME
+
+have_lib_dir=yes;
+AC_ARG_WITH(lib-dir,
+  AC_HELP_STRING([--with-lib-dir=<sysio lib build directory>],
+  [directory for sysio library]),
+  [     case "${withval}" in
+         "yes"|"no"|"") have_lib_dir=no ;;
+         *) LIBBUILD_DIR=${withval};
+            test -d ${LIBBUILD_DIR} || mkdir ${LIBBUILD_DIR} ||
+                have_lib_dir=no;;
+        esac;],
+  [ LIBBUILD_DIR=`pwd`/lib;
+    test -d ${LIBBUILD_DIR} || mkdir ${LIBBUILD_DIR} || have_lib_dir=no;])
+if test x${have_lib_dir} = xyes; then
+  echo "Using sysio library directory ${LIBBUILD_DIR}"
+else
+  AC_MSG_ERROR(Need writeable path to sysio library directory ${LIBBUILD_DIR})
+fi
+AC_SUBST(LIBBUILD_DIR)
+
+AC_ARG_WITH(native_driver,
+  AC_HELP_STRING([--with-native-driver],[build native test driver]),
+  [    case "${withval}" in
+        yes) ;;
+        no) ;;
+        *) AC_MSG_ERROR(bad value ${withval} for --with-native-driver) ;;
+       esac;],
+  [with_native_driver=yes;])
+AM_CONDITIONAL(WITH_NATIVE_DRIVER, test x$with_native_driver = xyes)
+
+AC_ARG_WITH(incore-driver,
+  AC_HELP_STRING([--with-incore-driver],[build incore test driver]),
+  [    case "${withval}" in
+        yes) ;;
+        no) ;;
+        *) AC_MSG_ERROR(bad value ${withval} for --with-incore-driver) ;;
+       esac],
+  [with_incore_driver=yes])
+AM_CONDITIONAL(WITH_INCORE_DRIVER, test x$with_incore_driver = xyes)
+
+AC_ARG_WITH(tests,
+  AC_HELP_STRING([--with-tests],[build tests]),
+  [    case "${withval}" in
+        yes) ;;
+        no) ;;
+        *) AC_MSG_ERROR(bad value ${withval} for --with-tests) ;;
+       esac],
+  [with_tests=yes])
+AM_CONDITIONAL(WITH_TESTS, test x$with_tests = xyes)
+
+AC_ARG_WITH(automount,
+  AC_HELP_STRING([--with-automount@<:@=<automount-file-name>@:>@],
+    [with automounts @<:@<automount-file-name>=.mount@:>@]),
+  [    if test x${withval} = xyes; then
+        AUTOMOUNT=-DAUTOMOUNT_FILE_NAME="\\\".mount\\\"" 
+       elif test x${withval} != x; then
+        AUTOMOUNT=-DAUTOMOUNT_FILE_NAME="\\\"${withval}\\\""
+       fi])
+AC_SUBST(AUTOMOUNT)
+
+AC_ARG_WITH(stdfd-dev,
+  AC_HELP_STRING([--with-stdfd-dev],
+    [build standard file descriptors pseudo-driver]),
+  [    case "${withval}" in
+        yes) ;;
+        no) ;;
+        *) AC_MSG_ERROR(bad value ${withval} for --with-stdfd-dev) ;;
+       esac],
+  [with_stdfd_dev=yes])
+AM_CONDITIONAL(WITH_STDFD_DEV, test x$with_stdfd_dev = xyes)
+
+AC_ARG_WITH(zero-sum-memory,
+  AC_HELP_STRING([--with-zero-sum-memory],
+    [free all dynamically allocated memory at the end -- useful for debugging]),
+  [    case "${withval}" in
+        yes) ZERO_SUM_MEMORY=-DZERO_SUM_MEMORY=1 ;;
+        no) ;;
+        *) AC_MSG_ERROR(bad value ${withval} for --with-zero-sum-memory) ;;
+       esac],
+  [with_zero_sum_memory=no])
+AC_SUBST(ZERO_SUM_MEMORY)
+
+AC_ARG_WITH(cplant_yod,
+   AC_HELP_STRING([--with-cplant-yod],[build cplant yod I/O driver]),
+   [   case "${withval}" in    
+       yes) if test x${with_stdfd_dev} != xyes; then
+               with_stdfd_dev=yes
+               AM_CONDITIONAL(WITH_STDFD_DEV, test x$with_stdfd_dev = xyes)
+            fi ;;
+       no) ;;
+       *) AC_MSG_ERROR(bad value ${withval} for --with-cplant-yod);;
+       esac],
+    [with_cplant_yod=no])
+AM_CONDITIONAL(WITH_CPLANT_YOD, test x$with_cplant_yod = xyes)
+
+AC_ARG_WITH(cplant_tests,
+   AC_HELP_STRING([--with-cplant-tests=<cplant-build-path>],
+     [build libsysio tests for cplant platform]),
+   [   case "${withval}" in
+       yes) AC_MSG_ERROR(need path to compiler for --with-cplant-tests);;
+       no)  with_cplant_tests=no;;
+       *) CC=${withval}
+          CCDEPMODE=${CC} 
+          CPP="${CC} -E"
+          AC_CHECK_FILE(${CC},
+               [ if test x${with_cplant_yod} != xyes; then
+                       with_cplant_yod=yes
+                       AM_CONDITIONAL(WITH_CPLANT_YOD, test x$with_cplant_yod = xyes)
+                 fi],
+               [ AC_MSG_ERROR(path not found ${CC} for --with-cplant-tests) ]);;
+       esac],
+    [with_cplant_tests=no])
+AM_CONDITIONAL(WITH_CPLANT_TESTS, test x$with_cplant_tests != xno)
+
+AC_ARG_WITH(sockets,
+  AC_HELP_STRING([--with-sockets],
+    [build sockets interface driver (EXPERIMENTAL)]),
+  [    case "${withval}" in
+        yes) ;;
+        no) ;;
+        *) AC_MSG_ERROR(bad value ${withval} for --with-sockets) ;;
+       esac],
+  [with_sockets=no])
+AM_CONDITIONAL(WITH_SOCKETS_DRIVER, test x$with_sockets = xyes)
+
+AC_ARG_WITH(lustre-hack,
+  AC_HELP_STRING([--with-lustre-hack],
+    [have hacking code which needed to support liblustre driver (EXPERIMENTAL)]),
+  [    case "${withval}" in
+        yes) ;;
+        no) ;;
+        *) AC_MSG_ERROR(bad value ${withval} for --with-lustre-hack) ;;
+       esac],
+  [with_lustre_hack=no])
+AM_CONDITIONAL(WITH_LUSTRE_HACK, test x$with_lustre_hack = xyes)
+if test x$with_lustre_hack = xyes; then
+       AC_DEFINE(HAVE_LUSTRE_HACK)
+fi
+
+# We keep the original values in `$config_*' and never modify them, so we
+# can write them unchanged into config.make.  Everything else uses
+# $machine, $vendor, and $os, and changes them whenever convenient.
+config_machine=$host_cpu config_vendor=$host_vendor config_os=$host_os
+
+# Don't allow vendor == "unknown"
+test "$config_vendor" = unknown && config_vendor=
+config_os="`echo $config_os | sed 's/^unknown-//'`"
+
+# Some configurations imply other options.
+case "$host_os" in
+  gnu* | linux* | bsd4.4* | netbsd* | freebsd*)
+       # These systems always use GNU tools.
+       gnu_ld=yes gnu_as=yes ;;
+esac
+case "$host_os" in
+  # i586-linuxaout is mangled into i586-pc-linux-gnuaout
+  linux*ecoff* | linux*aout* | gnu*aout* | gnu*ecoff*)
+       ;;
+  gnu* | linux* | freebsd* | netbsd* | sysv4* | solaris2* | irix6*)
+       # These systems (almost) always use the ELF format.
+       elf=yes
+       ;;
+  aix*)
+       # These systems are always xcoff
+       xcoff=yes
+       elf=no
+       ;;
+esac
+
+machine=$config_machine
+vendor=$config_vendor
+os=$config_os
+
+# config.guess on some IBM machines says `rs6000' instead of `powerpc'.
+# Unify this here.
+if test "$machine" = rs6000; then
+       machine="powerpc"
+fi
+
+# If we can't provoke the declaration of stat64 then we assume the
+# environment supports 64-bit file support naturally. Beware!
+AC_MSG_CHECKING(whether _LARGEFILE64_SOURCE definition is required)
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>], [
+struct stat64 st64;],
+sysio_largefile64_source_required=no,
+sysio_largefile64_source_required=maybe)
+if test x$sysio_largefile64_source_required = xmaybe; then
+       AC_TRY_COMPILE([
+#define _LARGEFILE64_SOURCE
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>], [
+struct stat64 st64;],
+                      sysio_largefile64_source_required=yes,
+                      sysio_largefile64_source_required=no)
+fi
+AC_MSG_RESULT($sysio_largefile64_source_required)
+if test x$sysio_largefile64_source_required = xyes; then
+       AC_DEFINE(_LARGEFILE64_SOURCE)
+fi
+
+# Alpha linux defines 
+# 
+AC_MSG_CHECKING(for alpha linux)
+alpha_linux_env=no
+if test `expr ${machine} : "alpha"` = 5 && \
+   test `expr ${os} : "linux"` = 5; then
+       alpha_linux_env=yes
+       AC_DEFINE(ALPHA_LINUX)
+fi
+AC_MSG_RESULT($alpha_linux_env)
+AM_CONDITIONAL(TEST_ALPHA_ARG, test x$alpha_linux_env = xyes)
+
+# check for 64 bit stat, fstat, truncate, ftruncate syscalls
+# 
+AC_MSG_CHECKING(for 64 bit stat and truncate syscalls)
+AC_TRY_COMPILE([
+#include <sys/stat.h>
+#include <syscall.h>
+extern int syscall();],
+[char path[] = "/";
+int fd = 0;
+struct stat buf;
+syscall(SYS_stat64,path,&buf);
+syscall(SYS_fstat64,fd,&buf);
+syscall(SYS_truncate64, path, buf.st_size);
+syscall(SYS_ftruncate64, fd, buf.st_size);
+],
+       sysstat64_exists=yes,
+       sysstat64_exists=no)
+AC_MSG_RESULT($sysstat64_exists)
+if test x$sysstat64_exists = xno; then
+       AC_DEFINE(USE_NATIVE_STAT)
+fi
+
+# Check for fdatasync syscall
+#
+AC_MSG_CHECKING(for fdatasync system call)
+if test x$alpha_linux_env = xyes; then
+       _syscallnum=SYS_osf_fdatasync
+else
+       _syscallnum=SYS_fdatasync
+fi
+AC_TRY_COMPILE([
+#include <syscall.h>
+extern int syscall();],
+[int fd = 0;
+syscall(SYS_fdatasync, fd);],
+       syscall_fdatasync_exists=yes,
+       syscall_fdatasync_exists=no)
+AC_MSG_RESULT($syscall_fdatasync_exists)
+if test x$syscall_fdatasync_exists = xyes; then
+       AC_DEFINE_UNQUOTED(NATIVE_FDATASYNC, $_syscallnum)
+fi
+
+# Check for SYS_utime
+#
+AC_MSG_CHECKING(for utime system call)
+AC_TRY_COMPILE([
+#include <syscall.h>
+extern int syscall();],
+[syscall(SYS_utime);],
+       syscall_utime_exists=yes,
+       syscall_utime_exists=no)
+AC_MSG_RESULT($syscall_utime_exists)
+if test x$syscall_utime_exists = xno; then
+       AC_DEFINE(USE_NATIVE_UTIME)
+fi
+# Check for __st_ino 
+#
+AC_MSG_CHECKING(for __st_ino)
+AC_TRY_COMPILE([
+#include <sys/stat.h>],
+[struct stat st;
+st.__st_ino = 0;],
+       have__st_ino=yes,
+       have__st_ino=no)
+AC_MSG_RESULT($have__st_ino)
+if test x$have__st_ino = xyes; then
+       AC_DEFINE(HAVE__ST_INO)
+fi
+
+# Check for st_gen 
+#
+AC_MSG_CHECKING(for st_gen)
+AC_TRY_COMPILE([
+#include <sys/stat.h>],
+[struct stat st;
+st.st_gen = 0;],
+       have_st_gen=yes,
+       have_st_gen=no)
+AC_MSG_RESULT($have_st_gen)
+if test x$have_st_gen = xyes; then
+       AC_DEFINE(HAVE_GENERATION)
+fi
+
+AC_MSG_CHECKING(whether .text pseudo-op must be used)
+AC_CACHE_VAL(sysio_asm_dot_text, [dnl
+cat > conftest.s <<EOF
+       .text
+EOF
+       sysio_asm_dot_text=
+       if ${CC-cc} $CFLAGS -c conftest.s 2>/dev/null; then
+               sysio_asm_dot_text=.text
+       fi
+       rm -f conftest*])
+if test -z "$sysio_dot_text"; then
+       AC_MSG_RESULT(no)
+else
+       AC_MSG_RESULT(yes)
+fi
+
+AC_CACHE_CHECK(for assembler global-symbol directive,
+  sysio_asm_global_directive, [dnl
+sysio_asm_global_directive=UNKNOWN
+for ac_globl in .globl .global .EXPORT; do
+       cat > conftest.s <<EOF
+               ${sysio_asm_dot_text}
+               ${ac_globl} foo
+foo:
+EOF
+       if ${CC-cc} $CFLAGS -c conftest.s 2>/dev/null; then
+       sysio_asm_global_directive=${ac_globl}
+       fi
+       rm -f conftest*
+       test $sysio_asm_global_directive != UNKNOWN && break
+done])
+if test $sysio_asm_global_directive = UNKNOWN; then
+       AC_MSG_ERROR(cannot determine asm global directive)
+#else
+#      AC_DEFINE_UNQUOTED(ASM_GLOBAL_DIRECTIVE, ${sysio_asm_global_directive})
+fi
+
+AC_CACHE_CHECK(for .set assembler directive,
+  sysio_asm_set_directive, [dnl
+cat > conftest.s<<EOF
+${sysio_asm_dot_text}
+foo:
+.set bar, foo
+${sysio_asm_global_directive} bar
+EOF
+       # The alpha-dec-osf1 assembler gives only a warning for `.set'
+       # (but it doesn't work), so we must do a linking check to be sure.
+cat > conftest1.c <<EOF
+extern int bar;
+main () { printf ("%d\n", bar); }
+EOF
+       if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS \
+          -o conftest conftest.s conftest1.c 1>&AC_FD_CC 2>&AC_FD_CC; then
+               sysio_asm_set_directive=yes
+       else
+               sysio_asm_set_directive=no
+       fi
+       rm -f conftest*])
+#if test $sysio_asm_set_directive = yes; then
+#      AC_DEFINE(HAVE_ASM_SET_DIRECTIVE)
+#fi
+
+AC_CACHE_CHECK(for assembler .weak directive, sysio_asm_weak_directive,
+              [dnl
+cat > conftest.s <<EOF
+${sysio_dot_text}
+foo:
+.weak foo
+EOF
+       if ${CC-cc} $CFLAGS -c conftest.s 2>/dev/null; then
+               sysio_asm_weak_directive=yes
+       else
+               sysio_asm_weak_directive=no
+       fi
+       rm -f conftest*])
+
+if test $sysio_asm_weak_directive = no; then
+       AC_CACHE_CHECK(for assembler .weakext directive,
+                      sysio_asm_weakext_directive, [dnl
+cat > conftest.s <<EOF
+${sysio_dot_text}
+${sysio_asm_global_directive} foo
+foo:
+.weakext bar foo
+.weakext baz
+${sysio_asm_global_directive} baz
+baz:
+EOF
+               if ${CC-cc} $CFLAGS -c conftest.s 2>/dev/null; then
+                       sysio_asm_weakext_directive=yes
+               else
+                       sysio_asm_weakext_directive=no
+               fi
+               rm -f conftest*])
+fi # no .weak
+
+if test x$sysio_asm_weak_directive = xyes; then
+       AC_DEFINE(HAVE_ASM_WEAK_DIRECTIVE)
+fi
+if test x$sysio_asm_weakext_directive = xyes; then
+       AC_DEFINE(HAVE_ASM_WEAKEXT_DIRECTIVE)
+fi
+
+AC_OUTPUT(
+       Makefile
+       tests/Makefile)
+
diff --git a/libsysio/dev/stdfd/module.mk b/libsysio/dev/stdfd/module.mk
new file mode 100644 (file)
index 0000000..ad034fb
--- /dev/null
@@ -0,0 +1,2 @@
+STDFD_SRCS  = dev/stdfd/stdfd.c
+STDFD_EXTRA = dev/stdfd/stdfd.h dev/stdfd/module.mk
diff --git a/libsysio/dev/stdfd/stdfd.c b/libsysio/dev/stdfd/stdfd.c
new file mode 100644 (file)
index 0000000..5a14e8b
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#ifdef __linux__
+#define _BSD_SOURCE
+#endif
+
+#include <errno.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <sys/uio.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "inode.h"
+#include "dev.h"
+
+#include "stdfd.h"
+
+#ifdef CPLANT_YOD
+#include <sys/statfs.h>
+#include "cplant-yod.h"
+#define dowrite(f, b, n) write_yod(f, b, n)
+#define doread(f, b, n) read_yod(f, b, n)
+#else
+#define dowrite(f, b, n) syscall(SYS_write, f, b, n)
+#define doread(f, b, n) syscall(SYS_read, f, b, n)
+#endif
+
+/*
+ * Pre-opened standard file descriptors driver.
+ */
+
+static int stdfd_open(struct pnode *pno, int flags, mode_t mode);
+static int stdfd_close(struct inode *ino);
+static int stdfd_read(struct inode *ino, struct ioctx *ioctx);
+static int stdfd_write(struct inode *ino, struct ioctx *ioctx);
+static int stdfd_iodone(struct ioctx *ioctx);
+static int stdfd_datasync(struct inode *ino);
+static int stdfd_ioctl(struct inode *ino,
+                      unsigned long int request,
+                      va_list ap);
+
+int
+_sysio_stdfd_init()
+{
+       struct inode_ops stdfd_operations;
+
+       stdfd_operations = _sysio_nodev_ops;
+       stdfd_operations.inop_open = stdfd_open;
+       stdfd_operations.inop_close = stdfd_close;
+       stdfd_operations.inop_read = stdfd_read;
+       stdfd_operations.inop_write = stdfd_write;
+       stdfd_operations.inop_iodone = stdfd_iodone;
+       stdfd_operations.inop_datasync = stdfd_datasync;
+       stdfd_operations.inop_ioctl = stdfd_ioctl;
+
+       return _sysio_char_dev_register(SYSIO_C_STDFD_MAJOR,
+                                       "stdfd",
+                                       &stdfd_operations);
+}
+
+static int
+stdfd_open(struct pnode *pno __IS_UNUSED,
+          int flags __IS_UNUSED,
+          mode_t mode __IS_UNUSED)
+{
+
+       return 0;
+}
+
+static int
+stdfd_close(struct inode *ino __IS_UNUSED)
+{
+
+       return 0;
+}
+
+static int
+doio(ssize_t (*f)(void *, size_t, _SYSIO_OFF_T, struct inode *),
+     struct inode *ino,
+     struct ioctx *ioctx)
+{
+
+       if (ioctx->ioctx_xtvlen != 1) {
+               /*
+                * No scatter/gather to "file" address space (we're not
+                * seekable) and "nowhere" makes no sense.
+                */
+               return -EINVAL;
+       }
+       ioctx->ioctx_cc =
+           _sysio_doio(ioctx->ioctx_xtv, ioctx->ioctx_xtvlen,
+                       ioctx->ioctx_iov, ioctx->ioctx_iovlen,
+                       (ssize_t (*)(void *, size_t, _SYSIO_OFF_T, void *))f,
+                       ino);
+       if (ioctx->ioctx_cc < 0) {
+               ioctx->ioctx_errno = -ioctx->ioctx_cc;
+               ioctx->ioctx_cc = -1;
+       }
+       return 0;
+}
+
+static ssize_t
+stdfd_read_simple(void *buf,
+                 size_t nbytes,
+                 _SYSIO_OFF_T off __IS_UNUSED,
+                 struct inode *ino)
+{
+
+       int     fd = SYSIO_MINOR_DEV(ino->i_rdev);
+
+       return doread(fd, buf, nbytes);
+}
+
+static int
+stdfd_read(struct inode *ino, struct ioctx *ioctx)
+{
+
+       return doio(stdfd_read_simple, ino, ioctx);
+}
+
+static ssize_t
+stdfd_write_simple(const void *buf,
+                  size_t nbytes,
+                  _SYSIO_OFF_T off __IS_UNUSED,
+                  struct inode *ino)
+{
+       int     fd = SYSIO_MINOR_DEV(ino->i_rdev);
+
+       return dowrite(fd, buf, nbytes);
+}
+
+static int
+stdfd_write(struct inode *ino, struct ioctx *ioctx)
+{
+
+       return doio((ssize_t (*)(void *,
+                                size_t,
+                                _SYSIO_OFF_T,
+                                struct inode *))stdfd_write_simple,
+                   ino,
+                   ioctx);
+}
+
+static int
+stdfd_iodone(struct ioctx *iocp __IS_UNUSED)
+{
+
+       /*
+        * It's always done in this driver. It completed when posted.
+        */
+       return 1;
+}
+
+static int
+stdfd_datasync(struct inode *ino __IS_UNUSED)
+{
+
+       /*
+        * We don't buffer, so nothing to do.
+        */
+       return 0;
+}
+
+static int
+stdfd_ioctl(struct inode *ino __IS_UNUSED,
+           unsigned long int request __IS_UNUSED,
+           va_list ap __IS_UNUSED)
+{
+
+       return -ENOTTY;
+}
diff --git a/libsysio/dev/stdfd/stdfd.h b/libsysio/dev/stdfd/stdfd.h
new file mode 100644 (file)
index 0000000..3bac7c1
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+/*
+ * Std{in,out,err} pseudo-device-driver support.
+ */
+
+#define SYSIO_C_STDFD_MAJOR    0
+
+extern int _sysio_stdfd_init(void);
diff --git a/libsysio/drivers/incore/README b/libsysio/drivers/incore/README
new file mode 100644 (file)
index 0000000..2f8c4b8
--- /dev/null
@@ -0,0 +1,27 @@
+This "incore" file system driver is a self-contained file system. It does
+not use any resource external to the node.
+
+It is primarily intended for enabling an efficient compute-node bootstrap. It
+might also be useful for a very small scratch file system, holding device
+files, and the like.
+
+The root directory i-node is manufactured on the fly. The source specification
+for the mount() call should be something like:
+
+       <perms>+<uid>+<gid>
+
+Where:
+       <perms>         are the directory permissions masked by 0777
+                       Note -- no umask is applied.
+       <uid>           should be the owner's uid
+       <gid>           should be the owner's gid
+
+Most operations are supported, with the notable exception of symbolic
+links.
+
+In the implementation, the driver is really set up to export most
+useful symbols without polluting the name space or contending with
+other public symbols. However, the symbols are not yet exported. If
+we ever require a proc-fs style file system, this could be very useful
+provided a little extra work is done to allow other drivers to overload
+some operations. Particularly the file ops, I would think.
diff --git a/libsysio/drivers/incore/fs_incore.c b/libsysio/drivers/incore/fs_incore.c
new file mode 100644 (file)
index 0000000..b6eb1c0
--- /dev/null
@@ -0,0 +1,1693 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#ifdef __linux__
+#define _BSD_SOURCE
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <limits.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/uio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#ifdef _HAVE_STATVFS
+#include <sys/statvfs.h>
+#endif
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "fs.h"
+#include "mount.h"
+#include "inode.h"
+#include "dev.h"
+
+#include "fs_incore.h"
+
+
+/*
+ * In-core file system pseudo-driver.
+ */
+
+/*
+ * Pseudo-blocksize.
+ */
+#define INCORE_BLKSIZE         (8192)
+
+/*
+ * Format of an incore inode.
+ */
+struct incore_inode {
+       LIST_ENTRY(incore_inode) ici_link;              /* i-nodes list link */
+       unsigned ici_revalidate                 : 1;    /* synch sys inode? */
+       struct intnl_stat ici_st;                       /* attrs */
+       struct file_identifier ici_fileid;              /* file ID */
+       void    *ici_data;                              /* file data */
+};
+
+/*
+ * Given pointer to inode, return pointer to incore-inode.
+ */
+#define I2IC(ino)      ((struct incore_inode *)(ino)->i_private)
+
+struct incore_filesys {
+       LIST_HEAD(, incore_inode) icfs_icinodes;        /* all i-nodes list */
+};
+
+/*
+ * Given pointer to filesys, return pointer to incore-filesys.
+ */
+#define FS2ICFS(fs)    ((struct incore_filesys *)(fs)->fs_private)
+
+static int _sysio_incore_fsswop_mount(const char *source,
+                                     unsigned flags,
+                                     const void *data,
+                                     struct pnode *tocover,
+                                     struct mount **mntp);
+
+static struct fssw_ops incore_fssw_ops = {
+               _sysio_incore_fsswop_mount
+};
+
+static void _sysio_incore_fsop_gone(struct filesys *fs);
+
+static struct filesys_ops incore_fs_ops = {
+               _sysio_incore_fsop_gone,
+};
+
+static int _sysio_incore_dirop_lookup(struct pnode *pno,
+                                     struct inode **inop,
+                                     struct intent *intnt,
+                                     const char *path);
+static int _sysio_incore_inop_getattr(struct pnode *pno,
+                                     struct inode *ino,
+                                     struct intnl_stat *stbuf);
+static int _sysio_incore_inop_setattr(struct pnode *pno,
+                                     struct inode *ino,
+                                     unsigned mask,
+                                     struct intnl_stat *stbuf);
+static ssize_t _sysio_incore_dirop_getdirentries(struct inode *ino,
+                                          char *buf,
+                                          size_t nbytes,
+                                          _SYSIO_OFF_T *basep);
+static int _sysio_incore_dirop_mkdir(struct pnode *pno, mode_t mode);
+static int _sysio_incore_dirop_rmdir(struct pnode *pno);
+static int _sysio_incore_inop_open(struct pnode *pno, int flags, mode_t mode);
+static int _sysio_incore_inop_close(struct inode *ino);
+static int _sysio_incore_dirop_link(struct pnode *old, struct pnode *new);
+static int _sysio_incore_dirop_unlink(struct pnode *pno);
+static int _sysio_incore_dirop_rename(struct pnode *old, struct pnode *new);
+static int _sysio_incore_filop_read(struct inode *ino, struct ioctx *ioctx);
+static int _sysio_incore_filop_write(struct inode *ino, struct ioctx *ioctx);
+static _SYSIO_OFF_T _sysio_incore_filop_pos(struct inode *ino,
+                                           _SYSIO_OFF_T off);
+static int _sysio_incore_filop_iodone(struct ioctx *ioctx);
+static int _sysio_incore_filop_fcntl(struct inode *ino, int cmd, va_list ap);
+static int _sysio_incore_inop_sync(struct inode *ino);
+static int _sysio_incore_filop_ioctl(struct inode *ino,
+                                   unsigned long int request,
+                                   va_list ap);
+static int _sysio_incore_dirop_mknod(struct pnode *pno, mode_t mode, dev_t dev);
+#ifdef _HAVE_STATVFS
+static int _sysio_incore_inop_statvfs(struct pnode *pno,
+                                     struct inode *ino,
+                                     struct intnl_statvfs *buf);
+#endif
+static void _sysio_incore_inop_gone(struct inode *ino);
+
+#define _sysio_incore_dirop_symlink \
+       (int (*)(struct pnode *, const char *))_sysio_do_enosys
+#define _sysio_incore_dirop_readlink \
+       (int (*)(struct pnode *, char *, size_t))_sysio_do_einval
+#define _sysio_incore_dirop_read \
+       (int (*)(struct inode *, \
+                struct ioctx *))_sysio_do_eisdir
+#define _sysio_incore_dirop_write \
+       (int (*)(struct inode *, \
+                struct ioctx *))_sysio_do_eisdir
+#define _sysio_incore_dirop_pos \
+       (_SYSIO_OFF_T (*)(struct inode *, \
+                         _SYSIO_OFF_T))_sysio_do_eisdir
+#define _sysio_incore_dirop_iodone \
+       (int (*)(struct ioctx *))_sysio_do_illop
+#define _sysio_incore_dirop_fcntl \
+       (int (*)(struct inode *, int, va_list))_sysio_do_eisdir
+#define _sysio_incore_dirop_ioctl \
+       (int (*)(struct inode *, \
+                unsigned long int, \
+                va_list))_sysio_do_eisdir
+
+static struct inode_ops _sysio_incore_dir_ops = {
+       _sysio_incore_dirop_lookup,
+       _sysio_incore_inop_getattr,
+       _sysio_incore_inop_setattr,
+       _sysio_incore_dirop_getdirentries,
+       _sysio_incore_dirop_mkdir,
+       _sysio_incore_dirop_rmdir,
+       _sysio_incore_dirop_symlink,
+       _sysio_incore_dirop_readlink,
+       _sysio_incore_inop_open,
+       _sysio_incore_inop_close,
+       _sysio_incore_dirop_link,
+       _sysio_incore_dirop_unlink,
+       _sysio_incore_dirop_rename,
+       _sysio_incore_dirop_read,
+       _sysio_incore_dirop_write,
+       _sysio_incore_dirop_pos,
+       _sysio_incore_dirop_iodone,
+       _sysio_incore_dirop_fcntl,
+       _sysio_incore_inop_sync,
+       _sysio_incore_inop_sync,
+       _sysio_incore_dirop_ioctl,
+       _sysio_incore_dirop_mknod,
+#ifdef _HAVE_STATVFS
+       _sysio_incore_inop_statvfs,
+#endif
+       _sysio_incore_inop_gone
+};
+
+#define _sysio_incore_filop_lookup \
+       (int (*)(struct pnode *, \
+                struct inode **, \
+                struct intent *, \
+                const char *))_sysio_do_illop
+#define _sysio_incore_filop_getdirentries \
+       (ssize_t (*)(struct inode *, \
+                char *, \
+                size_t, \
+                _SYSIO_OFF_T *))_sysio_do_illop
+#define _sysio_incore_filop_mkdir \
+       (int (*)(struct pnode *, mode_t))_sysio_do_illop
+#define _sysio_incore_filop_rmdir \
+       (int (*)(struct pnode *))_sysio_do_illop
+#define _sysio_incore_filop_symlink \
+       (int (*)(struct pnode *, const char *))_sysio_do_illop
+#define _sysio_incore_symlinkop_readlink \
+       (int (*)(struct pnode *, char *, size_t))_sysio_do_illop
+#define _sysio_incore_filop_link \
+       (int (*)(struct pnode *old, struct pnode *new))_sysio_do_illop
+#define _sysio_incore_filop_unlink \
+       (int (*)(struct pnode *pno))_sysio_do_illop
+#define _sysio_incore_filop_rename \
+       (int (*)(struct pnode *old, struct pnode *new))_sysio_do_illop
+#define _sysio_incore_filop_mknod \
+       (int (*)(struct pnode *pno, mode_t, dev_t))_sysio_do_illop
+
+static struct inode_ops _sysio_incore_file_ops = {
+       _sysio_incore_filop_lookup,
+       _sysio_incore_inop_getattr,
+       _sysio_incore_inop_setattr,
+       _sysio_incore_filop_getdirentries,
+       _sysio_incore_filop_mkdir,
+       _sysio_incore_filop_rmdir,
+       _sysio_incore_filop_symlink,
+       _sysio_incore_symlinkop_readlink,
+       _sysio_incore_inop_open,
+       _sysio_incore_inop_close,
+       _sysio_incore_filop_link,
+       _sysio_incore_filop_unlink,
+       _sysio_incore_filop_rename,
+       _sysio_incore_filop_read,
+       _sysio_incore_filop_write,
+       _sysio_incore_filop_pos,
+       _sysio_incore_filop_iodone,
+       _sysio_incore_filop_fcntl,
+       _sysio_incore_inop_sync,
+       _sysio_incore_inop_sync,
+       _sysio_incore_filop_ioctl,
+       _sysio_incore_filop_mknod,
+#ifdef _HAVE_STATVFS
+       _sysio_incore_inop_statvfs,
+#endif
+       _sysio_incore_inop_gone
+};
+
+static struct inode_ops _sysio_incore_dev_ops = {
+       _sysio_incore_filop_lookup,
+       _sysio_incore_inop_getattr,
+       _sysio_incore_inop_setattr,
+       _sysio_incore_filop_getdirentries,
+       _sysio_incore_filop_mkdir,
+       _sysio_incore_filop_rmdir,
+       _sysio_incore_filop_symlink,
+       _sysio_incore_symlinkop_readlink,
+       _sysio_nodev_inop_open,
+       _sysio_nodev_inop_close,
+       _sysio_incore_filop_link,
+       _sysio_incore_filop_unlink,
+       _sysio_incore_filop_rename,
+       _sysio_nodev_inop_read,
+       _sysio_nodev_inop_write,
+       _sysio_nodev_inop_pos,
+       _sysio_nodev_inop_iodone,
+       _sysio_incore_filop_fcntl,
+       _sysio_incore_inop_sync,
+       _sysio_nodev_inop_sync,
+       _sysio_nodev_inop_ioctl,
+       _sysio_incore_filop_mknod,
+#ifdef _HAVE_STATVFS
+       _sysio_incore_inop_statvfs,
+#endif
+       _sysio_incore_inop_gone
+};
+
+typedef void *(*probe_ty)(void *data, size_t len, void *arg);
+
+/*
+ * Lookup data argument bundle record.
+ */
+struct lookup_data {
+       struct qstr *name;                              /* desired entry name */
+       struct intnl_dirent *de;                        /* last dirent */
+       size_t  minsiz;                                 /* min hole needed */
+       struct {
+               void    *p;                             /* best hole */
+               size_t  len;                            /* best hole len */
+       } hole;
+};
+
+/*
+ * Initialize lookup data argument bundle.
+ */
+#define INCORE_LD_INIT(ld, minsz, qs) \
+       do { \
+               (ld)->name = (qs); \
+               (ld)->de = NULL; \
+               (ld)->minsiz = (minsz); \
+               (ld)->hole.p = NULL; \
+               (ld)->hole.len = 0; \
+       } while (0)
+
+/*
+ * Calculate size of a directory entry given length of the entry name.
+ */
+#define INCORE_D_RECLEN(namlen) \
+       (((size_t )&((struct intnl_dirent *)0)->d_name + \
+         (namlen) + 1 + sizeof(void *)) & \
+        ~(sizeof(void *) - 1))
+
+/*
+ * Given mode bits, return directory entry type code.
+ */
+#define INCORE_D_TYPEOF(m)     (((m) & S_IFMT) >> 12)
+
+static char incore_dir_template[INCORE_D_RECLEN(1) + INCORE_D_RECLEN(2)];
+#if 0
+static struct intnl_dirent incore_dir_template[] = {
+       {
+               0,
+               INCORE_D_RECLEN(1),
+               INCORE_D_RECLEN(1),
+               INCORE_D_TYPEOF(S_IFDIR),
+               { '.', '\0' }
+       },
+       {
+               0,
+               INCORE_D_RECLEN(1) + INCORE_D_RECLEN(2),
+               INCORE_D_RECLEN(2),
+               INCORE_D_TYPEOF(S_IFDIR),
+               { '.', '.', '\0' }
+       }
+};
+#endif
+
+/*
+ * Initialize this driver.
+ */
+int
+_sysio_incore_init()
+{
+       struct intnl_dirent *de;
+       off_t   off;
+
+       /*
+        * Fill in the directory template.
+        */
+       de = (struct intnl_dirent *)incore_dir_template;
+#ifdef _DIRENT_HAVE_D_OFF
+       de->d_off =
+#endif
+           off = de->d_reclen = INCORE_D_RECLEN(1);
+       de->d_type = INCORE_D_TYPEOF(S_IFDIR);
+       de->d_name[0] = '.';
+#ifdef _DIRENT_HAVE_D_NAMLEN
+       de->d_namlen = 1;
+#endif
+       /*
+        * Move to entry for `..'
+        */
+       de = (struct intnl_dirent *)((char *)de + off);
+       de->d_reclen = INCORE_D_RECLEN(2);
+#ifdef _DIRENT_HAVE_D_NAMLEN
+       de->d_namlen = 2;
+#endif
+#ifdef _DIRENT_HAVE_D_OFF
+       de->d_off =
+#endif
+           off += de->d_reclen;
+       de->d_type = INCORE_D_TYPEOF(S_IFDIR);
+       de->d_name[0] = de->d_name[1] = '.';
+       de->d_name[2] = ' ';
+
+       return _sysio_fssw_register("incore", &incore_fssw_ops);
+}
+
+static ino_t
+incore_inum_alloc()
+{
+       static ino_t nxtnum = 1;
+
+       assert(nxtnum);
+       return nxtnum++;
+}
+
+static struct incore_inode *
+incore_i_alloc(struct incore_filesys *icfs, struct intnl_stat *st)
+{
+       struct incore_inode *icino;
+
+       assert(st->st_ino);
+       assert(!st->st_size);
+
+       icino = malloc(sizeof(struct incore_inode));
+       if (!icino)
+               return NULL;
+       icino->ici_revalidate = 0;
+       icino->ici_st = *st;
+       icino->ici_fileid.fid_data = &icino->ici_st.st_ino;
+       icino->ici_fileid.fid_len = sizeof(icino->ici_st.st_ino);
+       icino->ici_data = NULL;
+
+       LIST_INSERT_HEAD(&icfs->icfs_icinodes, icino, ici_link);
+
+       return icino;
+}
+
+static int
+incore_trunc(struct incore_inode *icino, _SYSIO_OFF_T size, int clear)
+{
+       _SYSIO_OFF_T n;
+       void    *p;
+
+       if (size < 0) 
+               return -EINVAL;
+       n = size;
+       if (!size) {
+               if (icino->ici_data) {
+                       free(icino->ici_data);
+                       icino->ici_data = NULL;
+               }
+               n = 0;
+               goto out;
+       }
+       p = realloc(icino->ici_data, (size_t )n);
+       if (!p)
+               return -ENOSPC;
+       icino->ici_data = p;
+       if (clear && n > icino->ici_st.st_size)
+               (void )memset((char *)icino->ici_data + icino->ici_st.st_size,
+                             0,
+                             (size_t )(n - icino->ici_st.st_size));
+out:
+       icino->ici_st.st_size = n;
+       icino->ici_st.st_blocks =
+           (n + icino->ici_st.st_blksize - 1) / icino->ici_st.st_blksize;
+       icino->ici_st.st_mtime = time(NULL);
+       return 0;
+}
+
+static void
+incore_i_destroy(struct incore_inode *icino)
+{
+
+       LIST_REMOVE(icino, ici_link);
+       (void )incore_trunc(icino, 0, 0);
+       free(icino);
+}
+
+static struct incore_inode *
+incore_directory_new(struct incore_filesys *icfs,
+                    struct incore_inode *parent,
+                    struct intnl_stat *st)
+{
+       struct incore_inode *icino;
+       int     err;
+       struct intnl_dirent *de;
+
+       icino = incore_i_alloc(icfs, st);
+       if (!icino)
+               return NULL;
+
+       if (!parent)
+               parent = icino;                         /* root */
+
+       /*
+        * Allocate and init directory data.
+        */
+       err = incore_trunc(icino, sizeof(incore_dir_template), 1);
+       if (err) {
+               incore_i_destroy(icino);
+               return NULL;
+       }
+       (void )memcpy(icino->ici_data,
+                     &incore_dir_template,
+                     sizeof(incore_dir_template));
+       de = icino->ici_data;
+       de->d_ino = st->st_ino;
+       de =
+           (struct intnl_dirent *)((char *)de +
+#ifdef _DIRENT_HAVE_D_OFF
+                                   de->d_off
+#else
+                                   de->d_reclen
+#endif
+                                   );
+       de->d_ino = parent->ici_st.st_ino;
+
+       /*
+        * Set creation time to modify time set by truncate.
+        */
+       st->st_ctime = st->st_mtime;
+
+       return icino;
+}
+
+static int
+_sysio_incore_fsswop_mount(const char *source,
+                          unsigned flags,
+                          const void *data __IS_UNUSED,
+                          struct pnode *tocover,
+                          struct mount **mntp)
+{
+       char    *cp;
+       unsigned long ul;
+       long    l;
+       mode_t  mode;
+       uid_t   uid;
+       gid_t   gid;
+       int     err;
+       dev_t   dev;
+       struct intnl_stat stat;
+       struct incore_filesys *icfs;
+       ino_t   inum;
+       struct incore_inode *icino;
+       struct filesys *fs;
+       struct inode *rooti;
+       struct pnode_base *rootpb;
+       struct mount *mnt;
+       static struct qstr noname = { NULL, 0, 0 };
+
+       /*
+        * Source is a specification for the root attributes of this
+        * new file system in the format:
+        *
+        * <permissions>+<owner>+<group>
+        */
+       ul = strtoul(source, &cp, 0);
+       mode = (mode_t )ul & 07777;
+       if (*cp != '+' ||
+           (ul == ULONG_MAX && errno == ERANGE) ||
+           (unsigned long)mode != ul ||
+           mode > 07777)
+               return -EINVAL;
+       source = cp;
+       l = strtol(source, &cp, 0);
+       uid = (uid_t )l;
+       if (*cp != '+' ||
+           ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) ||
+           (long )uid != l)
+               return -EINVAL;
+       source = cp;
+       l = strtol(source, &cp, 0);
+       gid = (gid_t )l;
+       if (*cp ||
+           ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) ||
+           (long )gid != l)
+               return -EINVAL;
+
+       err = 0;
+
+       dev = _sysio_dev_alloc();
+
+       mnt = NULL;
+       rootpb = NULL;
+       rooti = NULL;
+       fs = NULL;
+       icino = NULL;
+       icfs = NULL;
+
+       /*
+        * Create new FS.
+        */
+       icfs = malloc(sizeof(struct incore_filesys));
+       if (!icfs) {
+               err = -ENOMEM;
+               goto error;
+       }
+       (void )memset(icfs, 0, sizeof(struct incore_filesys));
+       LIST_INIT(&icfs->icfs_icinodes);
+
+       /*
+        * Create root i-node.
+        */
+       (void )memset(&stat, 0, sizeof(stat));
+       stat.st_dev = dev;
+       inum = incore_inum_alloc();
+#ifdef HAVE__ST_INO
+       stat.__st_ino = inum; 
+#endif
+       stat.st_mode = S_IFDIR | (mode & 07777);
+       stat.st_nlink = 2;
+       stat.st_uid = uid;
+       stat.st_gid = gid;
+       stat.st_size = 0;
+       stat.st_blksize = INCORE_BLKSIZE;
+       stat.st_blocks = 0;
+       stat.st_ctime = stat.st_mtime = stat.st_atime = 0;
+       stat.st_ino = inum;
+       icino = incore_directory_new(icfs, NULL, &stat);
+       if (!icino)
+               return -ENOSPC;
+       icino->ici_st.st_atime = icino->ici_st.st_mtime;
+
+       fs =
+           _sysio_fs_new(&incore_fs_ops,
+                         (flags & MOUNT_F_RO) ? FS_F_RO : 0,
+                         icfs);
+       if (!fs) {
+               err = -ENOMEM;
+               goto error;
+       }
+
+       /*
+        * Create root for system.
+        *
+        * Persistent across remounts because we ask for immunity.
+        */
+       rooti =
+           _sysio_i_new(fs,
+                        &icino->ici_fileid,
+                        icino->ici_st.st_mode,
+                        0,
+                        1,
+                        &_sysio_incore_dir_ops,
+                        icino);
+       if (!rooti) {
+               err = -ENOMEM;
+               goto error;
+       }
+       rootpb = _sysio_pb_new(&noname, NULL, rooti);
+       if (!rootpb) {
+               err = -ENOMEM;
+               goto error;
+       }
+
+       /*
+        * Have path-node specified by the given source argument. Let the
+        * system finish the job, now.
+        */
+       mnt = NULL;
+       err =
+           _sysio_do_mount(fs,
+                           rootpb,
+                           flags,
+                           tocover,
+                           &mnt);
+       if (err)
+               goto error;
+
+       *mntp = mnt;
+
+       goto out;
+
+error:
+       if (mnt && _sysio_do_unmount(mnt) != 0)
+                       abort();
+       if (rootpb) {
+               _sysio_pb_gone(rootpb);
+               rooti = NULL;
+       }
+       if (rooti)
+               I_RELE(rooti);
+       if (fs) {
+               FS_RELE(fs);
+               goto out;
+       }
+       if (icino) {
+               incore_i_destroy(icino);
+               goto out;
+       }
+       if (icfs) {
+               free(icfs);
+               goto out;
+       }
+
+out:
+       return err;
+}
+
+static void
+_sysio_incore_fsop_gone(struct filesys *fs)
+{
+       struct incore_filesys *icfs;
+       struct incore_inode *icino, *oicino;
+
+       icfs = FS2ICFS(fs);
+
+       /*
+        * Free up i-node resource associated with this file system.
+        */
+       icino = icfs->icfs_icinodes.lh_first;
+       while (icino) {
+               oicino = icino;
+               icino = icino->ici_link.le_next;
+               incore_i_destroy(oicino);
+       }
+
+       /*
+        * Free the FS record.
+        */
+       free(icfs);
+}
+
+/*
+ * A directory search engine. Various functions are carried out by
+ * supplying appropriate callback functions.
+ *
+ * The two arguments, entry and hole, are called, if not null, for each
+ * directory entry and hole, respectively.
+ */
+static void *
+incore_directory_probe(void *data,
+                      size_t siz,
+                      _SYSIO_OFF_T origin
+#ifndef _DIRENT_HAVE_D_OFF
+                               __IS_UNUSED
+#endif
+                      ,
+                      probe_ty entry,
+                      probe_ty hole,
+                      void *arg)
+{
+       struct intnl_dirent *de;
+       void    *p;
+       size_t  n;
+
+       de = data;
+       for (;;) {
+#ifdef _DIRENT_HAVE_D_OFF
+               assert(de->d_off);
+#else
+               assert(de->d_reclen);
+#endif
+               if (entry && (p = (*entry)(de, de->d_reclen, arg)))
+                       return p;
+               n =
+#ifdef _DIRENT_HAVE_D_OFF
+                   de->d_off - origin;
+#else
+                   ((void *)de - data) + de->d_reclen;
+#endif
+               if (hole) {
+                       p = (*hole)((void *)de, de->d_reclen, arg);
+                       if (p)
+                               return p;
+               }
+               if (n >= siz)
+                       break;
+               de = (struct intnl_dirent *)((char *)data + n);
+       }
+
+       return NULL;
+}
+
+static struct intnl_dirent *
+incore_directory_match(struct intnl_dirent *de,
+                      size_t reclen __IS_UNUSED,
+                      struct lookup_data *ld)
+{
+
+#if defined(BSD) || defined(REDSTORM)
+       if (IFTODT(de->d_type) == DT_WHT)
+               return NULL;
+#endif
+       if (
+#ifdef _DIRENT_HAVE_D_NAMLEN
+           ld->name->len == de->d_namlen &&
+#endif
+           strncmp(de->d_name, ld->name->name, ld->name->len) == 0)
+               return de;
+       ld->de = de;
+       return NULL;
+}
+
+static int
+_sysio_incore_dirop_lookup(struct pnode *pno,
+                          struct inode **inop,
+                          struct intent *intnt __IS_UNUSED,
+                          const char *path __IS_UNUSED)
+{
+       struct inode *ino;
+       struct intnl_dirent *de;
+       struct incore_inode *icino;
+       struct lookup_data lookup_data;
+       struct file_identifier fileid;
+#ifdef notdef
+       struct inode_ops *ops;
+#endif
+
+       /*
+        * Revalidate?
+        */
+       if (*inop) {
+               icino = I2IC(*inop);
+               assert(icino);
+               if (icino->ici_revalidate) {
+                       (*inop)->i_mode = icino->ici_st.st_mode;
+                       icino->ici_revalidate = 0;
+               }
+               return 0;
+       }
+
+       ino = pno->p_parent->p_base->pb_ino;
+       icino = I2IC(ino);
+       INCORE_LD_INIT(&lookup_data,
+                      ULONG_MAX,
+                      &pno->p_base->pb_name);
+       de =
+           incore_directory_probe(icino->ici_data,
+                                  icino->ici_st.st_size,
+                                  0,
+                                  (probe_ty )incore_directory_match,
+                                  NULL,
+                                  &lookup_data);
+       if (!de)
+               return -ENOENT;
+
+       fileid.fid_data = &de->d_ino;
+       fileid.fid_len = sizeof(de->d_ino);
+       ino =
+           _sysio_i_find(ino->i_fs, &fileid);
+#ifdef notdef
+       if (ino)
+               goto out;
+       icino->ici_fileid.fid_data = &icino->ici_st.st_ino;
+       icino->ici_fileid.fid_len = sizeof(icino->ici_st.st_ino);
+       ops = NULL;
+       switch (icino->ici_st.st_mode & S_IFMT) {
+       case S_IFDIR:
+               ops = &_sysio_incore_dir_ops;
+               break;
+       case S_IFREG:
+               ops = &_sysio_incore_file_ops;
+               break;
+       default:
+               break;
+       }
+       if (!ops)
+               abort();
+       ino =
+           _sysio_i_new(ino->i_fs,
+                        &icino->ici_fileid,
+                        icino->ici_st.st_mode,
+                        0,
+                        1,
+                        ops,
+                        icino);
+#endif
+       if (!ino)
+               return -ENOMEM;
+
+#ifdef notdef
+out:
+#endif
+       *inop = ino;
+       return 0;
+}
+
+static int
+_sysio_incore_inop_getattr(struct pnode *pno,
+                          struct inode *ino,
+                          struct intnl_stat *stbuf)
+{
+       struct incore_inode *icino;
+
+       if (!ino)
+               ino = pno->p_base->pb_ino;
+       icino = I2IC(ino);
+       *stbuf = icino->ici_st;
+       return 0;
+}
+
+static int
+_sysio_incore_inop_setattr(struct pnode *pno,
+                          struct inode *ino,
+                          unsigned mask,
+                          struct intnl_stat *stbuf)
+{
+       struct incore_inode *icino;
+       int     err;
+
+       if (!ino)
+               ino = pno->p_base->pb_ino;
+       if (!ino)
+               return -EBADF;
+       icino = I2IC(ino);
+
+       err = 0;
+       if (mask & SETATTR_LEN) {
+               err = incore_trunc(icino, stbuf->st_size, 1);
+               if (err)
+                       goto out;
+               mask &= ~SETATTR_LEN;
+       }
+       if (mask & SETATTR_MODE) {
+               icino->ici_st.st_mode =
+                   (icino->ici_st.st_mode & S_IFMT) | (stbuf->st_mode & 07777);
+               icino->ici_revalidate = 1;
+       }
+       if (mask & SETATTR_MTIME)
+               icino->ici_st.st_mtime = stbuf->st_mtime;
+       if (mask & SETATTR_ATIME)
+               icino->ici_st.st_atime = stbuf->st_atime;
+       if (mask & SETATTR_UID)
+               icino->ici_st.st_uid = stbuf->st_uid;
+       if (mask & SETATTR_GID)
+               icino->ici_st.st_gid = stbuf->st_gid;
+       icino->ici_st.st_ctime = time(NULL);
+
+out:
+       return err;
+}
+
+static void *
+incore_directory_position(struct intnl_dirent *de,
+                         size_t reclen __IS_UNUSED,
+                         void *p)
+{
+
+       return (void *)de >= p ? de : NULL;
+}
+
+struct copy_info {
+       void    *data;
+       size_t  nbytes;
+};
+
+/*
+ * Eumeration callback.
+ *
+ * Note:
+ * On those systems supporting white-out entries, they are returned. On
+ * systems without, they are not.
+ */
+static void *
+incore_directory_enumerate(struct intnl_dirent *de,
+                          size_t reclen,
+                          struct copy_info *cinfo) {
+
+       if (reclen > cinfo->nbytes)
+               return de;
+       (void *)memcpy(cinfo->data, de, reclen);
+       cinfo->data = (char *)cinfo->data + reclen;
+       cinfo->nbytes -= reclen;
+       return NULL;
+}
+
+static ssize_t
+_sysio_incore_dirop_getdirentries(struct inode *ino,
+                                char *buf,
+                                size_t nbytes,
+                                _SYSIO_OFF_T *basep)
+{
+       struct incore_inode *icino = I2IC(ino);
+       off_t   off;
+       struct intnl_dirent *de;
+       struct copy_info copy_info;
+
+       if (*basep > icino->ici_st.st_size)
+               return 0;
+
+       de =
+           incore_directory_probe(icino->ici_data,
+                                  icino->ici_st.st_size,
+                                  *basep,
+                                  (probe_ty )incore_directory_position,
+                                  NULL,
+                                  (char *)icino->ici_data + *basep);
+       if (!de) {
+               /*
+                * Past EOF.
+                */
+               *basep = 0;
+               return 0;
+       }
+
+       copy_info.data = buf;
+       copy_info.nbytes = nbytes;
+       off = (char *)de - (char *)icino->ici_data;
+       de =
+           incore_directory_probe(de,
+                                  icino->ici_st.st_size - off,
+                                  off,
+                                  (probe_ty )incore_directory_enumerate,
+                                  NULL,
+                                  &copy_info);
+       nbytes -= copy_info.nbytes;
+       icino->ici_st.st_atime = time(NULL);
+       if (!nbytes)
+               return -EOVERFLOW;
+       *basep = nbytes;
+       return (ssize_t )nbytes;
+}
+
+static struct intnl_dirent *
+incore_directory_best_fit(void *data, size_t len, struct lookup_data *ld)
+{
+
+       if (!ld->hole.len || len < ld->hole.len) {
+               ld->hole.p = data;
+               ld->hole.len = len;
+       }
+
+       return NULL;
+}
+
+static int
+incore_directory_insert(struct incore_inode *parent,
+                       struct qstr *name,
+                       ino_t inum,
+                       unsigned char type)
+{
+       size_t  reclen;
+       struct lookup_data lookup_data;
+       struct intnl_dirent *de;
+       size_t  xt;
+       size_t  n;
+       size_t  r;
+
+       reclen = INCORE_D_RECLEN(name->len);
+       INCORE_LD_INIT(&lookup_data, reclen, name);
+       de =
+           incore_directory_probe(parent->ici_data,
+                                  parent->ici_st.st_size,
+                                  0,
+                                  (probe_ty )incore_directory_match,
+                                  (probe_ty )incore_directory_best_fit,
+                                  &lookup_data);
+       if (de)
+               return -EEXIST;
+       de = lookup_data.de;
+       xt = (char *)lookup_data.de - (char *)parent->ici_data;
+       n =
+#ifdef _DIRENT_HAVE_D_OFF
+           de->d_off;
+#else
+           xt + de->d_reclen;
+#endif
+       r =
+#ifdef _DIRENT_HAVE_D_OFF
+           de->d_reclen;
+#else
+           INCORE_D_RECLEN(de->d_namlen);
+#endif
+       if (!parent->ici_st.st_size ||
+           xt + r + reclen > (size_t )parent->ici_st.st_size) {
+               int     err;
+
+               err = incore_trunc(parent, xt + r + reclen, 1);
+               if (err)
+                       return err;
+               de = (struct intnl_dirent *)((char *)parent->ici_data + xt);
+               n = parent->ici_st.st_size;
+       }
+
+#ifdef _DIRENT_HAVE_D_OFF
+       de->d_off = xt + r;                             /* trim */
+#else
+       de->d_reclen = r;
+#endif
+       de = (struct intnl_dirent *)((char *)de + r);                           /* reposition */
+       xt += r;
+
+#ifndef _DIRENT_HAVE_D_OFF
+       /*
+        * Will we split this hole or use all of it?
+        */
+       if (lookup_data.hole.len - reclen &&
+           lookup_data.hole.len - reclen <= INCORE_D_RECLEN(1))
+               reclen = lookup_data.hole.len;
+#endif
+
+       /*
+        * Insert new.
+        */
+       de->d_ino = inum;
+#ifdef _DIRENT_HAVE_D_OFF
+       de->d_off = n;
+#endif
+       de->d_reclen = reclen;
+       de->d_type = type;
+       (void )memcpy(de->d_name, name->name, name->len);
+#ifdef _DIRENT_HAVE_D_NAMLEN
+       de->d_namlen = name->len;
+#endif
+
+#ifndef _DIRENT_HAVE_D_OFF
+       xt += reclen;
+       if (n - xt) {
+               /*
+                * White-out remaining part of the hole.
+                */
+               (void *)de += reclen;
+               de->d_ino = 0;
+               de->d_reclen = n - xt;
+               de->d_type = DT_WHT;
+               de->d_namlen = 0;
+       }
+#endif
+
+       /*
+        * Update attributes to reflect the new entry.
+        */
+       parent->ici_st.st_nlink++;
+       assert(parent->ici_st.st_nlink);
+       parent->ici_st.st_atime = parent->ici_st.st_mtime = time(NULL);
+
+       return 0;
+}
+
+static int
+_sysio_incore_dirop_mkdir(struct pnode *pno, mode_t mode)
+{
+       struct intnl_stat stat;
+       struct incore_inode *icino, *parent;
+       ino_t   inum;
+       int     err;
+       struct intnl_dirent *de = NULL;
+       struct inode *ino;
+
+       ino = pno->p_parent->p_base->pb_ino;
+       parent = I2IC(ino);
+
+       if (!S_ISDIR(parent->ici_st.st_mode))
+               return -ENOTDIR;
+
+       (void )memset(&stat, 0, sizeof(stat));
+       stat.st_dev = pno->p_parent->p_base->pb_ino->i_fs->fs_dev;
+       inum = incore_inum_alloc();
+#ifdef HAVE__ST_INO
+       stat.__st_ino = inum;
+#endif
+       stat.st_mode = S_IFDIR | (mode & 07777);
+       stat.st_nlink = 2;
+       stat.st_uid = getuid();
+       stat.st_gid = getgid();
+       stat.st_size = 0;
+       stat.st_blksize = 4096;
+       stat.st_blocks = 0;
+       stat.st_ctime = stat.st_mtime = stat.st_atime = 0;
+       stat.st_ino = inum;
+       icino = incore_directory_new(FS2ICFS(ino->i_fs), parent, &stat);
+       if (!icino)
+               return -ENOSPC;
+
+       /*
+        * Tell the system about the new inode.
+        *
+        * Persistent across remounts because we ask for immunity.
+        */
+       ino =
+           _sysio_i_new(pno->p_parent->p_base->pb_ino->i_fs,
+                        &icino->ici_fileid,
+                        stat.st_mode,
+                        0,
+                        1,
+                        &_sysio_incore_dir_ops,
+                        icino);
+       if (!ino) {
+               incore_i_destroy(icino);
+               return -ENOMEM;
+       }
+
+       /*
+        * Insert into parent.
+        */
+       err =
+           incore_directory_insert(parent,
+                                   &pno->p_base->pb_name,
+                                   stat.st_ino,
+                                   INCORE_D_TYPEOF(S_IFDIR));
+
+       if (err) {
+               de->d_ino = 0;                          /* bad parent */
+               I_RELE(ino);
+               _sysio_i_gone(ino);
+               return err;
+       }
+
+       pno->p_base->pb_ino = ino;
+       return 0;
+}
+
+static int
+incore_unlink_entry(struct incore_inode *icino,
+                   struct qstr *name)
+{
+       struct lookup_data lookup_data;
+       struct intnl_dirent *de;
+       size_t  reclen;
+#ifdef _DIRENT_HAVE_D_OFF
+       size_t  off;
+#endif
+
+       if (!S_ISDIR(icino->ici_st.st_mode))
+               return -ENOTDIR;
+
+       INCORE_LD_INIT(&lookup_data, 0, name);
+       de =
+           incore_directory_probe(icino->ici_data,
+                                  icino->ici_st.st_size,
+                                  0,
+                                  (probe_ty )incore_directory_match,
+                                  NULL,
+                                  &lookup_data);
+       if (!de)
+               return -ENOENT;
+       assert((size_t )((char *)de - (char *)icino->ici_data) >=
+              sizeof(incore_dir_template));
+#ifndef _DIRENT_HAVE_D_OFF
+       reclen = de->d_reclen;
+#else
+       off = de->d_off;
+       reclen = off - ((char *)de - (char *)icino->ici_data);
+#endif
+       (void )memset(de, 0, reclen);
+#ifndef _DIRENT_HAVE_D_OFF
+       de->d_type = (__uint8_t )DTTOIF(DT_WHT);
+       de->d_reclen = reclen;
+#else
+       lookup_data.de->d_off = off;
+#endif
+
+       /*
+        * Adjust link count.
+        */
+       assert(icino->ici_st.st_nlink > 2);
+       icino->ici_st.st_nlink--;
+
+       return 0;
+}
+
+static int
+_sysio_incore_dirop_rmdir(struct pnode *pno)
+{
+       struct inode *ino = pno->p_base->pb_ino;
+       struct incore_inode *icino = I2IC(ino);
+       int     err;
+
+       if (!pno->p_base->pb_name.len ||
+           (pno->p_base->pb_name.name[0] == '.' &&
+            (pno->p_base->pb_name.len == 1 ||
+             (pno->p_base->pb_name.len == 2 &&
+              pno->p_base->pb_name.name[1] == '.'))))
+               return -EINVAL;
+
+       if (!S_ISDIR(icino->ici_st.st_mode))
+               return -ENOTDIR;
+
+       if (icino->ici_st.st_nlink > 2)
+               return -ENOTEMPTY;
+
+       pno->p_base->pb_ino = NULL;
+       err =
+           incore_unlink_entry(I2IC(pno->p_parent->p_base->pb_ino),
+                               &pno->p_base->pb_name);
+       return err;
+}
+
+static int
+incore_create(struct pnode *pno, struct intnl_stat *st)
+{
+       struct inode *dino, *ino;
+       struct incore_inode *icino;
+       int     err;
+
+       dino = pno->p_parent->p_base->pb_ino;
+       assert(dino);
+
+       icino = incore_i_alloc(FS2ICFS(dino->i_fs), st);
+       if (!icino)
+               return -ENOSPC;
+
+       /*
+        * Tell the system about the new inode.
+        */
+       ino =
+           _sysio_i_new(dino->i_fs,
+                        &icino->ici_fileid,
+                        st->st_mode,
+                        st->st_rdev,
+                        1,
+                        S_ISREG(st->st_mode)
+                          ? &_sysio_incore_file_ops
+                          : &_sysio_incore_dev_ops,
+                        icino);
+       if (!ino) {
+               incore_i_destroy(icino);
+               return -ENOMEM;
+       }
+
+       /*
+        * Insert into parent.
+        */
+       err =
+           incore_directory_insert(I2IC(dino),
+                                   &pno->p_base->pb_name,
+                                   st->st_ino,
+                                   INCORE_D_TYPEOF(icino->ici_st.st_mode));
+       if (err) {
+               I_RELE(ino);
+               _sysio_i_gone(ino);
+               return err;
+       }
+
+       pno->p_base->pb_ino = ino;
+       return 0;
+}
+
+static int
+_sysio_incore_inop_open(struct pnode *pno, int flags __IS_UNUSED, mode_t mode)
+{
+       struct intnl_stat stat;
+       ino_t   inum;
+
+       /*
+        * File exists. Nothing to do.
+        */
+       if (pno->p_base->pb_ino)
+               return 0;
+
+       /*
+        * Must create a new, regular, file.
+        */
+       (void )memset(&stat, 0, sizeof(stat));
+       stat.st_dev = pno->p_parent->p_base->pb_ino->i_fs->fs_dev;
+       inum = incore_inum_alloc();
+#ifdef HAVE__ST_INO
+       stat.__st_ino = inum;
+#endif
+       stat.st_mode = S_IFREG | (mode & 07777);
+       stat.st_nlink = 1;
+       stat.st_uid = getuid();
+       stat.st_gid = getgid();
+       stat.st_rdev = 0;
+       stat.st_size = 0;
+       stat.st_blksize = 4096;
+       stat.st_blocks = 0;
+       stat.st_ctime = stat.st_mtime = stat.st_atime = 0;
+       stat.st_ino = inum;
+
+       return incore_create(pno, &stat);
+}
+
+static int
+_sysio_incore_inop_close(struct inode *ino __IS_UNUSED)
+{
+
+       return 0;
+}
+
+static int
+_sysio_incore_dirop_link(struct pnode *old, struct pnode *new)
+{
+       struct incore_inode *icino = I2IC(old->p_base->pb_ino);
+       int     err;
+
+       assert(!new->p_base->pb_ino);
+       assert(!S_ISDIR(old->p_base->pb_ino->i_mode));
+
+       /*
+        * Can bump the link count?
+        */
+       if (!(icino->ici_st.st_nlink + 1))
+               return -EMLINK;
+       /*
+        * Insert into parent.
+        */
+       err =
+           incore_directory_insert(I2IC(new->p_parent->p_base->pb_ino),
+                                   &new->p_base->pb_name,
+                                   icino->ici_st.st_ino,
+                                   INCORE_D_TYPEOF(icino->ici_st.st_mode));
+       if (err)
+               return err;
+       /*
+        * Bump the link count.
+        */
+       icino->ici_st.st_nlink++;
+
+       return 0;
+}
+
+static int
+_sysio_incore_dirop_rename(struct pnode *old, struct pnode *new)
+{
+       int     err;
+       struct incore_inode *icino = I2IC(old->p_base->pb_ino);
+
+       if (new->p_base->pb_ino) {
+               /*
+                * Have to kill off the target first.
+                */
+               if (S_ISDIR(I2IC(new->p_base->pb_ino)->ici_st.st_mode) &&
+                   I2IC(new->p_base->pb_ino)->ici_st.st_nlink > 2)
+                       return -ENOTEMPTY;
+               err =
+                   incore_unlink_entry(I2IC(new->p_parent->p_base->pb_ino),
+                                       &new->p_base->pb_name);
+               if (err)
+                       return err;
+       }
+
+       /*
+        * Insert into new parent.
+        */
+       err =
+           incore_directory_insert(I2IC(new->p_parent->p_base->pb_ino),
+                                   &new->p_base->pb_name,
+                                   icino->ici_st.st_ino,
+                                   INCORE_D_TYPEOF(icino->ici_st.st_mode));
+       if (err)
+               abort();
+       /*
+        * Remove from the old parent.
+        */
+       err =
+           incore_unlink_entry(I2IC(old->p_parent->p_base->pb_ino),
+                               &old->p_base->pb_name);
+       if (err)
+               abort();
+
+       if (S_ISDIR(icino->ici_st.st_mode)) {
+               struct intnl_dirent *de;
+
+               /*
+                * We moved a directory. The entry for `..' must be corrected.
+                */
+               de = icino->ici_data;
+               de++;
+               assert(strcmp(de->d_name, "..") == 0);
+               de->d_ino = I2IC(new->p_parent->p_base->pb_ino)->ici_st.st_ino;
+       }
+       return 0;
+}
+
+static int
+_sysio_incore_dirop_unlink(struct pnode *pno)
+{
+       struct inode *ino = pno->p_base->pb_ino;
+       struct incore_inode *icino = I2IC(ino);
+       int     err;
+
+       if (S_ISDIR(icino->ici_st.st_mode))
+               return -EISDIR;
+
+       err =
+           incore_unlink_entry(I2IC(pno->p_parent->p_base->pb_ino),
+                               &pno->p_base->pb_name);
+       return err;
+}
+
+static int
+doio(ssize_t (*f)(void *, size_t, _SYSIO_OFF_T, struct incore_inode *),
+     struct inode *ino,
+     struct ioctx *ioctx)
+{
+
+       ioctx->ioctx_cc =
+           _sysio_doio(ioctx->ioctx_xtv, ioctx->ioctx_xtvlen,
+                       ioctx->ioctx_iov, ioctx->ioctx_iovlen,
+                       (ssize_t (*)(void *, size_t, _SYSIO_OFF_T, void *))f,
+                       I2IC(ino));
+       if (ioctx->ioctx_cc  < 0) {
+               ioctx->ioctx_errno = -ioctx->ioctx_cc;
+               ioctx->ioctx_cc = -1;
+       }
+       ioctx->ioctx_done = 1;
+
+       return 0;
+}
+
+static ssize_t
+incore_read(void *buf, size_t nbytes,
+           _SYSIO_OFF_T off,
+           struct incore_inode *icino)
+{
+       size_t  n;
+
+       if (off < 0)
+               return -EINVAL;
+       if (!nbytes || off > icino->ici_st.st_size)
+               return 0;
+       n = icino->ici_st.st_size - (size_t )off;
+       if (n > nbytes)
+               n = nbytes;
+       (void )memcpy(buf, (char *)icino->ici_data + off, (size_t )n);
+
+       return (ssize_t )n;
+}
+
+static int
+_sysio_incore_filop_read(struct inode *ino, struct ioctx *ioctx)
+{
+       
+
+       return doio(incore_read, ino, ioctx);
+}
+
+static ssize_t
+incore_write(const void *buf, size_t nbytes,
+            _SYSIO_OFF_T off,
+            struct incore_inode *icino)
+{
+       _SYSIO_OFF_T pos;
+
+       if (off < 0)
+               return -EINVAL;
+       if (!nbytes || off > icino->ici_st.st_size)
+               return 0;
+       pos = off + nbytes;
+       if (off && pos <= off) {
+               /*
+                * It's all or nothing. We won't write just part of
+                * the buffer.
+                */
+               return -EFBIG;
+       }
+       if (pos > icino->ici_st.st_size) {
+               int     err;
+
+               err = incore_trunc(icino, (size_t )pos, 0);
+               if (err)
+                       return err;
+       }
+       (void )memcpy((char *)icino->ici_data + off, buf, nbytes);
+
+       return (ssize_t )nbytes;
+}
+
+static int
+_sysio_incore_filop_write(struct inode *ino, struct ioctx *ioctx)
+{
+
+       return doio((ssize_t (*)(void *, size_t,
+                                _SYSIO_OFF_T,
+                                struct incore_inode *))incore_write,
+                   ino,
+                   ioctx);
+}
+
+static _SYSIO_OFF_T
+_sysio_incore_filop_pos(struct inode *ino __IS_UNUSED, _SYSIO_OFF_T off)
+{
+
+       return off;
+}
+
+static int
+_sysio_incore_filop_iodone(struct ioctx *iocp __IS_UNUSED)
+{
+
+       /*
+        * It's always done in this driver. It completed when posted.
+        */
+       return 1;
+}
+
+static int
+_sysio_incore_filop_fcntl(struct inode *ino __IS_UNUSED,
+                         int cmd __IS_UNUSED,
+                         va_list ap __IS_UNUSED)
+{
+
+       /*
+        * No fcntl's supported.
+        */
+       return -ENOTTY;
+}
+
+static int
+_sysio_incore_inop_sync(struct inode *ino __IS_UNUSED)
+{
+
+       /*
+        * With what?
+        */
+       return 0;
+}
+
+static int
+_sysio_incore_filop_ioctl(struct inode *ino __IS_UNUSED,
+                         unsigned long int request __IS_UNUSED,
+                         va_list ap __IS_UNUSED)
+{
+
+       /*
+        * No ioctl's supported.
+        */
+       return -ENOTTY;
+}
+
+static int
+_sysio_incore_dirop_mknod(struct pnode *pno, mode_t mode, dev_t dev)
+{
+       mode_t  m;
+       struct intnl_stat stat;
+       ino_t   inum;
+
+       assert(!pno->p_base->pb_ino);
+
+       m = mode & S_IFMT;
+       if (S_ISCHR(m))
+               m &= ~S_IFCHR;
+       else if (S_ISFIFO(m))
+               m &= ~S_IFIFO;
+       else if (S_ISBLK(m))
+               m &= ~S_IFCHR;
+       else
+               return -EINVAL;
+       if (m)
+               return -EINVAL;
+
+       /*
+        * Initialize attributes.
+        */
+       (void )memset(&stat, 0, sizeof(stat));
+       stat.st_dev = pno->p_parent->p_base->pb_ino->i_fs->fs_dev;
+       inum = incore_inum_alloc();
+#ifdef HAVE__ST_INO
+       stat.__st_ino = inum;
+#endif
+       stat.st_mode = mode;
+       stat.st_nlink = 1;
+       stat.st_uid = getuid();
+       stat.st_gid = getgid();
+       stat.st_rdev = dev;
+       stat.st_size = 0;
+       stat.st_blksize = 4096;
+       stat.st_blocks = 0;
+       stat.st_ctime = stat.st_mtime = stat.st_atime = 0;
+       stat.st_ino = inum;
+
+       return incore_create(pno, &stat);
+}
+
+#ifdef _HAVE_STATVFS
+static int
+_sysio_incore_inop_statvfs(struct pnode *pno,
+                          struct inode *ino,
+                          struct intnl_statvfs *buf)
+{
+       struct filesys *fs;
+
+       if (!ino)
+               ino = pno->p_base->pb_ino;
+       assert(ino);
+
+       fs = pno->p_base->pb_ino->i_fs;
+
+       (void )memset(buf, 0, sizeof(struct intnl_statvfs));
+
+       /*
+        * Mostly, we lie.
+        */
+       buf->f_bsize = fs->fs_bsize;
+       buf->f_frsize = buf->f_bsize;
+       buf->f_blocks = ~0;
+       buf->f_blocks /= buf->f_bsize;
+       buf->f_bfree = buf->f_blocks - 1;
+       buf->f_bavail = buf->f_bfree;
+       buf->f_files = buf->f_blocks;
+       buf->f_ffree = buf->f_files - 1;
+       buf->f_favail = buf->f_ffree;
+       buf->f_fsid = fs->fs_id;
+       buf->f_flag = 0;
+       buf->f_namemax = ULONG_MAX;
+
+       return 0;
+}
+#endif
+
+void
+_sysio_incore_inop_gone(struct inode *ino)
+{
+       struct incore_inode *icino = I2IC(ino);
+
+       incore_i_destroy(icino);
+}
diff --git a/libsysio/drivers/incore/fs_incore.h b/libsysio/drivers/incore/fs_incore.h
new file mode 100644 (file)
index 0000000..84fa631
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+/*
+ * Native file system driver support.
+ */
+
+extern int _sysio_incore_init(void);
diff --git a/libsysio/drivers/incore/module.mk b/libsysio/drivers/incore/module.mk
new file mode 100644 (file)
index 0000000..140d69b
--- /dev/null
@@ -0,0 +1,2 @@
+INCORE_SRCS  = drivers/incore/fs_incore.c
+INCORE_EXTRA = drivers/incore/fs_incore.h drivers/incore/module.mk
diff --git a/libsysio/drivers/native/fs_native.c b/libsysio/drivers/native/fs_native.c
new file mode 100644 (file)
index 0000000..c66c1ed
--- /dev/null
@@ -0,0 +1,1722 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2004 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#ifdef __linux__
+#define _BSD_SOURCE
+#endif
+
+#include <stdio.h>                                     /* for NULL */
+#include <stdlib.h>
+#ifdef __linux__
+#include <string.h>
+#endif
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <syscall.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#if 0
+#include <sys/vfs.h>
+#endif
+#ifdef _HAVE_STATVFS
+#include <sys/statvfs.h>
+#include <sys/statfs.h>
+#endif
+#include <utime.h>
+#include <sys/queue.h>
+#if !(defined(REDSTORM) || defined(MAX_IOVEC))
+#include <limits.h>
+#endif
+
+#include "sysio.h"
+#include "fs.h"
+#include "mount.h"
+#include "inode.h"
+#include "xtio.h"
+
+#include "fs_native.h"
+
+#ifdef REDSTORM
+#include <sys/uio.h>
+#endif
+
+#if defined(SYS_getdirentries)
+#define DIR_STREAMED 0
+#define DIR_CVT_64 0
+#elif defined(SYS_getdents64)
+#define DIR_STREAMED 1
+#define DIR_CVT_64 0
+#elif defined(SYS_getdents)
+#define DIR_STREAMED 1
+#if defined(_LARGEFILE64_SOURCE)
+#define DIR_CVT_64 1
+/*
+ * Kernel version of directory entry.
+ */
+struct linux_dirent {
+       unsigned long ld_ino;
+       unsigned long ld_off;
+       unsigned short ld_reclen;
+       char    ld_name[1];
+};
+#include <dirent.h>
+#else /* !defined(_LARGEFILE64_SOURCE) */
+#define DIR_CVT_64 0
+#endif /* defined(_LARGEFILE64_SOURCE) */
+#else /* catch-none */
+#error No usable directory fill entries interface available
+#endif
+
+/*
+ * Local host file system driver.
+ */
+
+#if defined(ALPHA_LINUX)
+
+/* stat struct from asm/stat.h, as returned 
+ * by alpha linux kernel
+ */
+struct __native_stat {
+       unsigned int    st_dev;
+       unsigned int    st_ino;
+       unsigned int    st_mode;
+       unsigned int    st_nlink;
+       unsigned int    st_uid;
+       unsigned int    st_gid;
+       unsigned int    st_rdev;
+       long            st_size;
+       unsigned long   st_atime;
+       unsigned long   st_mtime;
+       unsigned long   st_ctime;
+       unsigned int    st_blksize;
+       int             st_blocks;
+       unsigned int    st_flags;
+       unsigned int    st_gen;
+};
+
+#define COPY_STAT(src, dest)                    \
+do {                                            \
+       memset((dest), 0, sizeof((*dest)));     \
+       (dest)->st_dev     = (src)->st_dev;     \
+       (dest)->st_ino     = (src)->st_ino;     \
+       (dest)->st_mode    = (src)->st_mode;    \
+       (dest)->st_nlink   = (src)->st_nlink;   \
+       (dest)->st_uid     = (src)->st_uid;     \
+       (dest)->st_gid     = (src)->st_gid;     \
+       (dest)->st_rdev    = (src)->st_rdev;    \
+       (dest)->st_size    = (src)->st_size;    \
+       (dest)->st_atime   = (src)->st_atime;   \
+       (dest)->st_mtime   = (src)->st_mtime;   \
+       (dest)->st_ctime   = (src)->st_ctime;   \
+       (dest)->st_blksize = (src)->st_blksize; \
+       (dest)->st_blocks  = (src)->st_blocks;  \
+       (dest)->st_flags   = (src)->st_flags;   \
+       (dest)->st_gen     = (src)->st_gen;     \
+} while (0);
+
+#else 
+#define __native_stat intnl_stat
+#define COPY_STAT(src, dest) *(dest) = *(src) 
+#endif
+
+#if defined(USE_NATIVE_STAT)
+#define __SYS_STAT SYS_lstat
+#define __SYS_FSTAT SYS_fstat
+#define __SYS_TRUNCATE SYS_truncate
+#define __SYS_FTRUNCATE SYS_ftruncate
+#else
+#define __SYS_STAT SYS_lstat64
+#define __SYS_FSTAT SYS_fstat64
+#define __SYS_TRUNCATE SYS_truncate64
+#define __SYS_FTRUNCATE SYS_ftruncate64
+#endif
+
+#if defined(USE_NATIVE_FDATASYNC)
+#define __SYS_FDATASYNC SYS_osf_fdatasync
+#else
+#define __SYS_FDATASYNC SYS_fdatasync
+#endif
+
+#if defined(USE_NATIVE_UTIME)
+#define __SYS_UTIME SYS_utimes
+#else
+#define __SYS_UTIME SYS_utime
+#endif
+
+/*
+ * Native file identifiers format.
+ */
+struct native_inode_identifier {
+       dev_t   dev;                                    /* device number */
+       ino_t   ino;                                    /* i-number */
+#ifdef HAVE_GENERATION
+       unsigned int gen;                               /* generation number */
+#endif
+};
+
+/*
+ * Driver-private i-node information we keep about local host file
+ * system objects.
+ */
+struct native_inode {
+       unsigned
+               ni_seekok               : 1;            /* can seek? */
+       struct native_inode_identifier ni_ident;        /* unique identifier */
+       struct file_identifier ni_fileid;               /* ditto */
+       int     ni_fd;                                  /* host fildes */
+       int     ni_oflags;                              /* flags, from open */
+       unsigned ni_nopens;                             /* soft ref count */
+       _SYSIO_OFF_T ni_fpos;                           /* current pos */
+};
+
+/*
+ * Native IO path arguments.
+ */
+struct native_io {
+       char    nio_op;                                 /* 'r' or 'w' */
+       struct native_inode *nio_nino;                  /* native ino */
+};
+
+static int native_inop_lookup(struct pnode *pno,
+                             struct inode **inop,
+                             struct intent *intnt,
+                             const char *path);
+static int native_inop_getattr(struct pnode *pno,
+                              struct inode *ino,
+                              struct intnl_stat *stbuf);
+static int native_inop_setattr(struct pnode *pno,
+                              struct inode *ino,
+                              unsigned mask,
+                              struct intnl_stat *stbuf);
+static ssize_t native_getdirentries(struct inode *ino,
+                                   char *buf,
+                                   size_t nbytes,
+                                   _SYSIO_OFF_T *basep);
+static int native_inop_mkdir(struct pnode *pno, mode_t mode);
+static int native_inop_rmdir(struct pnode *pno);
+static int native_inop_symlink(struct pnode *pno, const char *data);
+static int native_inop_readlink(struct pnode *pno, char *buf, size_t bufsiz);
+static int native_inop_open(struct pnode *pno, int flags, mode_t mode);
+static int native_inop_close(struct inode *ino);
+static int native_inop_link(struct pnode *old, struct pnode *new);
+static int native_inop_unlink(struct pnode *pno);
+static int native_inop_rename(struct pnode *old, struct pnode *new);
+static int native_inop_read(struct inode *ino, struct ioctx *ioctx);
+static int native_inop_write(struct inode *ino, struct ioctx *ioctx);
+static _SYSIO_OFF_T native_inop_pos(struct inode *ino, _SYSIO_OFF_T off);
+static int native_inop_iodone(struct ioctx *ioctx);
+static int native_inop_fcntl(struct inode *ino, int cmd, va_list ap);
+static int native_inop_sync(struct inode *ino);
+static int native_inop_datasync(struct inode *ino);
+static int native_inop_ioctl(struct inode *ino,
+                            unsigned long int request,
+                            va_list ap);
+static int native_inop_mknod(struct pnode *pno, mode_t mode, dev_t dev);
+#ifdef _HAVE_STATVFS
+static int native_inop_statvfs(struct pnode *pno,
+                              struct inode *ino,
+                              struct intnl_statvfs *buf);
+#endif
+static void native_inop_gone(struct inode *ino);
+
+static struct inode_ops native_i_ops = {
+       native_inop_lookup,
+       native_inop_getattr,
+       native_inop_setattr,
+       native_getdirentries,
+       native_inop_mkdir,
+       native_inop_rmdir,
+       native_inop_symlink,
+       native_inop_readlink,
+       native_inop_open,
+       native_inop_close,
+       native_inop_link,
+       native_inop_unlink,
+       native_inop_rename,
+       native_inop_read,
+       native_inop_write,
+       native_inop_pos,
+       native_inop_iodone,
+       native_inop_fcntl,
+       native_inop_sync,
+       native_inop_datasync,
+       native_inop_ioctl,
+       native_inop_mknod,
+#ifdef _HAVE_STATVFS
+       native_inop_statvfs,
+#endif
+       native_inop_gone
+};
+
+static int native_fsswop_mount(const char *source,
+                              unsigned flags,
+                              const void *data,
+                              struct pnode *tocover,
+                              struct mount **mntp);
+
+static struct fssw_ops native_fssw_ops = {
+       native_fsswop_mount
+};
+
+static void native_fsop_gone(struct filesys *fs);
+
+static struct filesys_ops native_inodesys_ops = {
+       native_fsop_gone,
+};
+
+/*
+ * This example driver plays a strange game. It maintains a private,
+ * internal mount -- It's own separate, rooted, name space. The local
+ * file system's entire name space is available via this tree.
+ *
+ * This simplifies the implementation. At mount time, we need to generate
+ * a path-node to be used as a root. This allows us to look up the needed
+ * node in the host name space and leverage a whole lot of support from
+ * the system.
+ */
+static struct mount *native_internal_mount = NULL;
+
+/*
+ * Given i-node, return driver private part.
+ */
+#define I2NI(ino)      ((struct native_inode *)((ino)->i_private))
+
+/*
+ * stat -- by path.
+ */
+static int
+native_stat(const char *path, struct intnl_stat *buf)
+{
+       int     err;
+       struct __native_stat stbuf;
+
+       err = syscall(__SYS_STAT, path, &stbuf);
+       if (err)
+               err = -errno;
+       COPY_STAT(&stbuf, buf);
+
+       return err;
+}
+
+/*
+ * stat -- by fildes
+ */
+static int
+native_fstat(int fd, struct intnl_stat *buf)
+{
+       int     err;
+       struct __native_stat stbuf;
+
+       err = syscall(__SYS_FSTAT, fd, &stbuf);
+       if (err)
+               err = -errno;
+       COPY_STAT(&stbuf, buf);
+
+       return err;
+}
+
+/*
+ * Introduce an i-node to the system.
+ */
+static struct inode *
+native_i_new(struct filesys *fs, struct intnl_stat *buf)
+{
+       struct native_inode *nino;
+       struct inode *ino;
+
+       nino = malloc(sizeof(struct native_inode));
+       if (!nino)
+               return NULL;
+       bzero(&nino->ni_ident, sizeof(nino->ni_ident));
+       nino->ni_ident.dev = buf->st_dev;
+       nino->ni_ident.ino = buf->st_ino;
+#ifdef HAVE_GENERATION
+       nino->ni_ident.gen = buf->st_gen;
+#endif
+       nino->ni_fileid.fid_data = &nino->ni_ident;
+       nino->ni_fileid.fid_len = sizeof(nino->ni_ident);
+       nino->ni_fd = -1;
+       nino->ni_oflags = 0;
+       nino->ni_nopens = 0;
+       nino->ni_fpos = 0;
+       ino =
+           _sysio_i_new(fs,
+                        &nino->ni_fileid,
+#ifndef AUTOMOUNT_FILE_NAME
+                        buf->st_mode & S_IFMT,
+#else
+                        buf->st_mode,                  /* all of the bits! */
+#endif
+                        0,
+                        0,
+                        &native_i_ops,
+                        nino);
+       if (!ino)
+               free(nino);
+       return ino;
+}
+
+/*
+ * Initialize this driver.
+ */
+int
+_sysio_native_init()
+{
+
+       /*
+        * Capture current process umask and reset our process umask to
+        * zero. All permission bits to open/creat/setattr are absolute --
+        * They've already had a umask applied, when appropriate.
+        */
+       _sysio_umask = syscall(SYS_umask, 0);
+
+       return _sysio_fssw_register("native", &native_fssw_ops);
+}
+
+/*
+ * Create private, internal, view of the hosts name space.
+ */
+static int
+create_internal_namespace()
+{
+       int     err;
+       struct mount *mnt;
+       struct inode *rootino;
+       struct pnode_base *rootpb;
+       static struct qstr noname = { NULL, 0, 0 };
+       struct filesys *fs;
+       struct intnl_stat stbuf;
+
+       if (native_internal_mount) {
+               /*
+                * Reentered!
+                */
+               abort();
+       }
+
+       /*
+        * We maintain an artificial, internal, name space in order to
+        * have access to fully qualified path names in the various routines.
+        * Initialize that name space now.
+        */
+       mnt = NULL;
+       rootino = NULL;
+       rootpb = NULL;
+       fs = _sysio_fs_new(&native_inodesys_ops, 0, NULL);
+       if (!fs) {
+               err = -ENOMEM;
+               goto error;
+       }
+
+       /*
+        * Get root i-node.
+        */
+       err = native_stat("/", &stbuf);
+       if (err)
+               goto error;
+       rootino = native_i_new(fs, &stbuf);
+       if (!rootino) {
+               err = -ENOMEM;
+               goto error;
+       }
+
+       /*
+        * Generate base path-node for root.
+        */
+       rootpb = _sysio_pb_new(&noname, NULL, rootino);
+       if (!rootpb) {
+               err = -ENOMEM;
+               goto error;
+       }
+
+       /*
+        * Mount it. This name space is disconnected from the
+        * rest of the system -- Only available within this driver.
+        */
+       err = _sysio_do_mount(fs, rootpb, 0, NULL, &mnt);
+       if (err)
+               goto error;
+
+       native_internal_mount = mnt;
+       return 0;
+error:
+       if (mnt) {
+               if (_sysio_do_unmount(mnt) != 0)
+                       abort();
+               fs = NULL;
+               rootpb = NULL;
+               rootino = NULL;
+       }
+       if (rootpb)
+               _sysio_pb_gone(rootpb);
+       if (fs) {
+               FS_RELE(fs);
+               _sysio_fs_gone(fs);
+       }
+
+       return err;
+}
+
+static int
+native_fsswop_mount(const char *source,
+                   unsigned flags,
+                   const void *data __IS_UNUSED,
+                   struct pnode *tocover,
+                   struct mount **mntp)
+{
+       int     err;
+       struct nameidata nameidata;
+       struct mount *mnt;
+
+       /*
+        * Caller must use fully qualified path names when specifying
+        * the source.
+        */
+       if (*source != '/')
+               return -ENOENT;
+
+       if (!native_internal_mount) {
+               err = create_internal_namespace();
+               if (err)
+                       return err;
+       }
+
+       /*
+        * Lookup the source in the internally maintained name space.
+        */
+       ND_INIT(&nameidata, 0, source, native_internal_mount->mnt_root, NULL);
+       err = _sysio_path_walk(native_internal_mount->mnt_root, &nameidata);
+       if (err)
+               return err;
+
+       /*
+        * Have path-node specified by the given source argument. Let the
+        * system finish the job, now.
+        */
+       err =
+           _sysio_do_mount(native_internal_mount->mnt_fs,
+                           nameidata.nd_pno->p_base,
+                           flags,
+                           tocover,
+                           &mnt);
+       /*
+        * Release the internal name space pnode and clean up any
+        * aliases we might have generated. We really don't need to cache them
+        * as they are only used at mount time..
+        */
+       P_RELE(nameidata.nd_pno);
+       (void )_sysio_p_prune(native_internal_mount->mnt_root);
+
+       if (!err) {
+               FS_REF(native_internal_mount->mnt_fs);
+               *mntp = mnt;
+       }
+       return err;
+}
+
+static int
+native_i_invalid(struct inode *inop, struct intnl_stat stbuf)
+{
+       /*
+        * Validate passed in inode against stat struct info
+        */
+       struct native_inode *nino = I2NI(inop);
+       
+       if ((nino->ni_ident.dev != stbuf.st_dev ||
+            nino->ni_ident.ino != stbuf.st_ino ||
+#ifdef HAVE_GENERATION
+            nino->ni_ident.gen != stbuf.st_gen ||
+#endif
+            ((inop)->i_mode & S_IFMT) != (stbuf.st_mode & S_IFMT)) ||
+           (((inop)->i_rdev != stbuf.st_rdev) &&
+              (S_ISCHR((inop)->i_mode) || S_ISBLK((inop)->i_mode))))
+               return 1;
+       
+       return 0;
+}
+
+/*
+ * Find, and validate, or create i-node by host-relative path. Returned i-node
+ * is referenced.
+ */
+static int
+native_iget(struct filesys *fs,
+           const char *path,
+           struct inode **inop,
+           int forced)
+{
+       int     err;
+       struct inode *ino;
+       struct intnl_stat stbuf;
+       struct native_inode_identifier ident;
+       struct file_identifier fileid;
+
+       /*
+        * Get file status.
+        */
+       err = native_stat(path, &stbuf);
+       if (err) {
+               *inop = NULL;
+               return err;
+       }
+
+       /* 
+        * Validate?
+        */
+       if (*inop) {
+               if (!native_i_invalid(*inop, stbuf))
+                       return 0;
+               /*
+                * Invalidate.
+                */
+               *inop = NULL;
+       }
+
+       /*
+        * I-node is not already known. Find or create it.
+        */
+       bzero(&ident, sizeof(ident)); 
+       ident.dev = stbuf.st_dev;
+       ident.ino = stbuf.st_ino;
+#ifdef HAVE_GENERATION
+       ident.gen = stbuf.st_gen;
+#endif
+       fileid.fid_data = &ident;
+       fileid.fid_len = sizeof(ident);
+       ino = _sysio_i_find(fs, &fileid);
+       if (ino && forced) {
+               /*
+                * Insertion was forced but it's already present!
+                */
+               if (native_i_invalid(ino, stbuf)) {
+                       /* 
+                        * Cached inode has stale attrs
+                        * make way for the new one
+                        */
+                       I_GONE(ino);
+                       ino = NULL;
+               } else
+                       /* 
+                        * OK to reuse cached inode
+                        */
+                       goto out;
+       }
+
+       if (!ino) {
+               ino = native_i_new(fs, &stbuf);
+               if (!ino)
+                       err = -ENOMEM;
+       }
+out:
+       if (!err)
+               *inop = ino;
+       return err;
+}
+
+/*
+ * Look up named object in host's name space by path.
+ */
+static int
+native_path_lookup(struct filesys *fs, const char *path, struct inode **inop)
+{
+
+       return native_iget(fs, path, inop, 0);
+}
+
+/*
+ * Look up object by it's path node.
+ */
+static int
+native_i_lookup(struct filesys *fs, struct pnode_base *pb, struct inode **inop)
+{
+       int     err;
+       char    *path;
+
+       path = _sysio_pb_path(pb, '/');
+       if (!path)
+               return -ENOMEM;
+       err = native_path_lookup(fs, path, inop);
+       free(path);
+       return err;
+}
+
+static int
+native_inop_lookup(struct pnode *pno,
+                  struct inode **inop,
+                  struct intent *intnt __IS_UNUSED,
+                  const char *path __IS_UNUSED)
+{
+       int     err;
+
+       *inop = pno->p_base->pb_ino;
+
+       /*
+        * Don't have an inode yet. Because we translate everything back to
+        * a single name space for the host, we will assume the object the
+        * caller is looking for has no existing alias in our internal
+        * name space. We don't see the same file on different mounts in the
+        * underlying host FS as the same file.
+        *
+        * The file identifier *will* be unique. It's got to have a different
+        * dev.
+        */
+       err = native_i_lookup(pno->p_mount->mnt_fs, pno->p_base, inop);
+       if (err)
+               *inop = NULL;
+       return err;
+}
+
+static int
+native_inop_getattr(struct pnode *pno, struct inode *ino, struct intnl_stat *stbuf)
+{
+       char    *path;
+       int     err;
+
+       path = NULL;
+       if (!ino || I2NI(ino)->ni_fd < 0) {
+               path = _sysio_pb_path(pno->p_base, '/');
+               if (!path)
+                       return -ENOMEM;
+       }
+       err =
+           path
+             ? native_stat(path, stbuf)
+             : native_fstat(I2NI(ino)->ni_fd, stbuf);
+       if (path)
+               free(path);
+       return err;
+}
+
+static int
+native_inop_setattr(struct pnode *pno,
+                   struct inode *ino,
+                   unsigned mask,
+                   struct intnl_stat *stbuf)
+{
+       char    *path;
+       int     fd;
+       struct intnl_stat st;
+       int     err;
+
+       path = NULL;
+       fd = ino ? I2NI(ino)->ni_fd : -1;
+       if (fd < 0 || mask & (SETATTR_MTIME|SETATTR_ATIME)) {
+               if (!pno)
+                       return -EEXIST;
+               path = _sysio_pb_path(pno->p_base, '/');
+               if (!path)
+                       return -ENOMEM;
+       }
+
+       /*
+        * Get current status for undo.
+        */
+       err =
+           fd < 0
+             ? native_stat(path, &st)
+             : native_fstat(fd, &st);
+       if (err)
+               goto out;
+
+       if (mask & SETATTR_MODE) {
+               mode_t  mode;
+
+               /*
+                * Alter permissions attribute.
+                */
+               mode = stbuf->st_mode & 07777;
+               err =
+                   fd < 0
+                     ? syscall(SYS_chmod, path, mode)
+                     : syscall(SYS_fchmod, fd, mode);
+               if (err)
+                       err = -errno;
+       }
+       if (err)
+               mask &= ~SETATTR_MODE;
+       else if (mask & (SETATTR_MTIME|SETATTR_ATIME)) {
+               struct utimbuf ut;
+
+               /*
+                * Alter access and/or modify time attributes.
+                */
+               ut.actime = st.st_atime;
+               ut.modtime = st.st_mtime;
+               if (mask & SETATTR_MTIME)
+                       ut.modtime = stbuf->st_mtime;
+               if (mask & SETATTR_ATIME)
+                       ut.actime = stbuf->st_atime;
+               err = syscall(__SYS_UTIME, path, &ut);
+               if (err)
+                       err = -errno;
+       }
+       if (err)
+               mask &= ~(SETATTR_MTIME|SETATTR_ATIME);
+       else if (mask & (SETATTR_UID|SETATTR_GID)) {
+
+               /*
+                * Alter owner and/or group identifiers.
+                */
+               err =
+                   fd < 0
+                     ? syscall(SYS_chown,
+                               path,
+                               mask & SETATTR_UID
+                                 ? stbuf->st_uid
+                                 : (uid_t )-1,
+                               mask & SETATTR_GID
+                                 ? stbuf->st_gid
+                                 : (gid_t )-1)
+                     : syscall(SYS_fchown,
+                               fd,
+                               mask & SETATTR_UID
+                                 ? stbuf->st_uid
+                                 : (uid_t )-1,
+                               mask & SETATTR_GID
+                                 ? stbuf->st_gid
+                                 : (gid_t )-1);
+               if (err)
+                       err = -errno;
+       }
+       if (err)
+               mask &= ~(SETATTR_UID|SETATTR_GID);
+       else if (mask & SETATTR_LEN) {
+               /*
+                * Do the truncate last. It can't be undone.
+                */
+                (void )(fd < 0
+                          ? syscall(__SYS_TRUNCATE, path, stbuf->st_size)
+                          : syscall(__SYS_FTRUNCATE, fd, stbuf->st_size));
+       }
+       if (!err)
+               goto out;
+       /*
+        * Undo after error. Some or all of this might not work... We
+        * can but try.
+        */
+       if (mask & (SETATTR_UID|SETATTR_GID)) {
+                (void )(fd < 0
+                          ? syscall(SYS_chown,
+                                    path,
+                                    mask & SETATTR_UID
+                                      ? st.st_uid
+                                      : (uid_t )-1,
+                                    mask & SETATTR_GID
+                                      ? st.st_gid
+                                      : (gid_t )-1)
+                          : syscall(SYS_fchown,
+                                    fd,
+                                    mask & SETATTR_UID
+                                      ? st.st_uid
+                                      : (uid_t )-1,
+                                    mask & SETATTR_GID
+                                      ? st.st_gid
+                                      : (gid_t )-1));
+       }
+       if (mask & (SETATTR_MTIME|SETATTR_ATIME)) {
+               struct utimbuf ut;
+
+               ut.actime = st.st_atime;
+               ut.modtime = st.st_mtime;
+               (void )syscall(__SYS_UTIME, path, &ut);
+       }
+       if (mask & SETATTR_MODE) {
+               fd < 0
+                 ? syscall(SYS_chmod, path, st.st_mode & 07777)
+                 : syscall(SYS_fchmod, fd, st.st_mode & 07777);
+       }
+out:
+       if (path)
+               free(path);
+       return err;
+}
+
+static int
+native_pos(int fd, _SYSIO_OFF_T *offset, int whence)
+{
+       _SYSIO_OFF_T off;
+
+       assert(fd >= 0);
+       assert(*offset >= 0);
+
+       off = *offset;
+#if _LARGEFILE64_SOURCE && defined(SYS__llseek)
+       {
+               int     err;
+               err =
+                   syscall(SYS__llseek,
+                           (unsigned int)fd,
+                           (unsigned int)(off >> 32),
+                           (unsigned int)off,
+                           &off,
+                           whence);
+               if (err == -1)
+                       return -errno;
+       }
+#else
+       off =
+           syscall(SYS_lseek,
+                   fd,
+                   off,
+                   whence);
+       if (off == -1)
+               return -errno;
+#endif
+       *offset = off;
+
+       return 0;
+}
+
+static ssize_t
+native_filldirentries(struct native_inode *nino,
+                     char *buf,
+                     size_t nbytes,
+                     _SYSIO_OFF_T *basep)
+{
+       int     err;
+       ssize_t cc;
+
+       if (*basep < 0)
+               return -EINVAL;
+
+#if DIR_STREAMED
+       /*
+        * Stream-oriented access requires that we reposition prior to the
+        * fill call.
+        */
+       if ((err = native_pos(nino->ni_fd, basep, SEEK_SET)) != 0)
+               return err;
+#endif
+       nino->ni_fpos = *basep;
+
+       cc =
+#if defined(SYS_getdirentries)
+           syscall(SYS_getdirentries,
+                   nino->ni_fd,
+                   buf,
+                   nbytes,
+                   basep);
+#elif defined(SYS_getdents64)
+           syscall(SYS_getdents64, nino->ni_fd, buf, nbytes);
+#elif defined(SYS_getdents)
+           syscall(SYS_getdents, nino->ni_fd, buf, nbytes);
+#endif
+
+       if (cc < 0)
+               return -errno;
+#if DIR_STREAMED
+       /*
+        * Stream-oriented access requires that we discover where we are
+        * after the call.
+        */
+       *basep = 0;
+       if ((err = native_pos(nino->ni_fd, basep, SEEK_CUR)) != 0)
+               return err;
+#endif
+       nino->ni_fpos = *basep;
+       return cc;
+}
+
+static ssize_t
+native_getdirentries(struct inode *ino,
+                    char *buf,
+                    size_t nbytes,
+                    _SYSIO_OFF_T *basep)
+{
+       struct native_inode *nino = I2NI(ino);
+#if DIR_CVT_64
+       char    *bp;
+       size_t  count;
+       struct linux_dirent *ldp;
+       struct dirent64 *d64p;
+       size_t  namlen;
+       size_t  reclen;
+#else
+#define bp buf
+#define count nbytes
+#endif
+       ssize_t cc;
+
+       assert(nino->ni_fd >= 0);
+
+#if DIR_CVT_64
+       count = nbytes;
+       while (!(bp = malloc(count))) {
+               count /= 2;
+               if (count < sizeof(struct dirent))
+                       return -ENOMEM;
+       }
+#endif
+       cc = native_filldirentries(nino, bp, count, basep);
+       if (cc < 0) {
+#if DIR_CVT_64
+               free(bp);
+#endif
+               return cc;
+       }
+#if DIR_CVT_64
+       ldp = (struct linux_dirent *)bp;
+       d64p = (struct dirent64 *)buf;
+       for (;;) {
+               if (cc < 0 || (size_t )cc <= sizeof(*ldp))
+                       break;
+               namlen = strlen(ldp->ld_name);
+               reclen = sizeof(*d64p) - sizeof(d64p->d_name) + namlen + 1;
+               if (nbytes < reclen)
+                       break;
+               d64p->d_ino = ldp->ld_ino;
+               d64p->d_off = ldp->ld_off;
+               d64p->d_reclen = 
+                   (((reclen + sizeof(long) - 1)) / sizeof(long)) *
+                   sizeof(long);
+               if (nbytes < d64p->d_reclen)
+                       d64p->d_reclen = reclen;
+               d64p->d_type = DT_UNKNOWN;              /* you lose -- sorry. */
+               (void )strncpy(d64p->d_name, ldp->ld_name, namlen);
+               *(d64p->d_name + namlen) = '\0';
+               cc -= ldp->ld_reclen;
+               ldp = (struct linux_dirent *)((char *)ldp + ldp->ld_reclen);
+               nbytes -= d64p->d_reclen;
+               d64p = (struct dirent64 *)((char *)d64p + d64p->d_reclen);
+       }
+       free(bp);
+       if (d64p == (struct dirent64 *)buf && cc)
+               cc = -EINVAL;                           /* buf too small */
+       cc = (char *)d64p - buf;
+#else
+#undef bp
+#undef count
+#endif
+       return cc;
+}
+
+static int
+native_inop_mkdir(struct pnode *pno, mode_t mode)
+{
+       char    *path;
+       int     err;
+
+       path = _sysio_pb_path(pno->p_base, '/');
+       if (!path)
+               return -ENOMEM;
+
+       err = syscall(SYS_mkdir, path, mode);
+       if (err != 0)
+               err = -errno;
+       free(path);
+       return err;
+}
+
+static int
+native_inop_rmdir(struct pnode *pno)
+{
+       char    *path;
+       int     err;
+
+       path = _sysio_pb_path(pno->p_base, '/');
+       if (!path)
+               return -ENOMEM;
+
+       err = syscall(SYS_rmdir, path);
+       if (err != 0)
+               err = -errno;
+       free(path);
+       return err;
+}
+
+static int
+native_inop_symlink(struct pnode *pno, const char *data)
+{
+       char    *path;
+       int     err;
+
+       path = _sysio_pb_path(pno->p_base, '/');
+       if (!path)
+               return -ENOMEM;
+
+       err = syscall(SYS_symlink, data, path);
+       if (err != 0)
+               err = -errno;
+       free(path);
+       return err;
+}
+
+static int
+native_inop_readlink(struct pnode *pno, char *buf, size_t bufsiz)
+{
+       char    *path;
+       int     i;
+
+       path = _sysio_pb_path(pno->p_base, '/');
+       if (!path)
+               return -ENOMEM;
+       i = syscall(SYS_readlink, path, buf, bufsiz);
+       if (i < 0)
+               i = -errno;
+       free(path);
+       return i;
+}
+
+static int 
+native_inop_open(struct pnode *pno, int flags, mode_t mode)
+{
+       struct native_inode *nino;
+       char    *path;
+       int     fd;
+
+       path = _sysio_pb_path(pno->p_base, '/');
+       if (!path)
+               return -ENOMEM;
+
+       /*
+        * Whether the file is already open, or not, makes no difference.
+        * Want to always give the host OS a chance to authorize in case
+        * something has changed underneath us.
+        */
+       if (flags & O_WRONLY) {
+               /*
+                * Promote write-only attempt to RW.
+                */
+               flags &= ~O_WRONLY;
+               flags |= O_RDWR;
+       }
+#ifdef O_LARGEFILE
+       flags |= O_LARGEFILE;
+#endif
+       fd = syscall(SYS_open, path, flags, mode);
+       if (!pno->p_base->pb_ino && fd >= 0) {
+               int     err;
+
+               /*
+                * Success but we need to return an i-node.
+                */
+               err =
+                   native_iget(pno->p_mount->mnt_fs,
+                               path,
+                               &pno->p_base->pb_ino,
+                               1);
+               if (err) {
+                       (void )syscall(SYS_close, fd);
+                       if (err == -EEXIST)
+                               abort();
+                       fd = err;
+               }
+       }
+       free(path);
+       if (fd < 0)
+               return -errno;
+
+       /*
+        * Remember this new open.
+        */
+       nino = I2NI(pno->p_base->pb_ino);
+       nino->ni_nopens++;
+       assert(nino->ni_nopens);
+
+       if (nino->ni_fd >= 0) {
+               if ((nino->ni_oflags & O_RDWR) ||
+                   (flags & (O_RDONLY|O_WRONLY|O_RDWR)) == O_RDONLY) {
+                       /*
+                        * Keep existing.
+                        */
+                       (void )syscall(SYS_close, fd);
+                       return 0;
+               }
+               (void )syscall(SYS_close, nino->ni_fd);
+       }
+       /*
+        * Invariant; First open. Must init.
+        */
+       nino->ni_fpos = 0;
+       nino->ni_fd = fd;
+       /*
+        * Need to know whether we can seek on this
+        * descriptor.
+        */
+       nino->ni_seekok =
+           native_pos(nino->ni_fd, &nino->ni_fpos, SEEK_CUR) != 0 ? 0 : 1;
+
+       return 0;
+}
+
+static int
+native_inop_close(struct inode *ino)
+{
+       struct native_inode *nino = I2NI(ino);
+       int     err;
+
+       if (nino->ni_fd < 0)
+               abort();
+
+       assert(nino->ni_nopens);
+       if (--nino->ni_nopens) {
+               /*
+                * Hmmm. We really don't need anything else. However, some
+                * filesystems try to implement a sync-on-close semantic.
+                * As this appears now, that is lost. Might want to change
+                * it somehow in the future?
+                */
+               return 0;
+       }
+
+       err = syscall(SYS_close, nino->ni_fd);
+       if (err)
+               return -errno;
+
+       nino->ni_fd = -1;
+       nino->ni_fpos = 0;
+       return 0;
+}
+
+static int
+native_inop_link(struct pnode *old, struct pnode *new)
+{
+       int     err;
+       char    *opath, *npath;
+
+       err = 0;
+
+       opath = _sysio_pb_path(old->p_base, '/');
+       npath = _sysio_pb_path(new->p_base, '/');
+       if (!(opath && npath)) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       err = syscall(SYS_link, opath, npath);
+       if (err != 0)
+               err = -errno;
+
+out:
+       if (opath)
+               free(opath);
+       if (npath)
+               free(npath);
+
+       return err;
+}
+
+static int
+native_inop_unlink(struct pnode *pno)
+{
+       char    *path;
+       int     err = 0;
+
+       path = _sysio_pb_path(pno->p_base, '/');
+       if (!path)
+               return -ENOMEM;
+
+       /*
+        * For this driver, unlink is easy with open files. Since the
+        * file remains open to the system, too, the descriptors are still
+        * valid.
+        *
+        * Other drivers will have some difficulty here as the entry in the
+        * file system name space must be removed without sacrificing access
+        * to the file itself. In NFS this is done with a mechanism referred
+        * to as a `silly delete'. The file is moved to a temporary name
+        * (usually .NFSXXXXXX, where the X's are replaced by the PID and some
+        * unique characters) in order to simulate the proper semantic.
+        */
+       if (syscall(SYS_unlink, path) != 0)
+               err = -errno;
+       free(path);
+       return err;
+}
+
+static int
+native_inop_rename(struct pnode *old, struct pnode *new)
+{
+       int     err;
+       char    *opath, *npath;
+
+       opath = _sysio_pb_path(old->p_base, '/');
+       npath = _sysio_pb_path(new->p_base, '/');
+       if (!(opath && npath)) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       err = syscall(SYS_rename, opath, npath);
+       if (err != 0)
+               err = -errno;
+
+out:
+       if (opath)
+               free(opath);
+       if (npath)
+               free(npath);
+
+       return err;
+}
+
+static ssize_t
+dopio(void *buf, size_t count, _SYSIO_OFF_T off, struct native_io *nio)
+{
+#if defined(_LARGEFILE64_SOURCE) && \
+    defined(SYS_pread64) && \
+    defined(SYS_pwrite64)
+#define _NATIVE_SYSCALL_PREAD SYS_pread64
+#define _NATIVE_SYSCALL_PWRITE SYS_pwrite64
+#else
+#define _NATIVE_SYSCALL_PREAD SYS_pread
+#define _NATIVE_SYSCALL_PWRITE SYS_pwrite
+#endif
+       ssize_t cc;
+
+       if (!(off == nio->nio_nino->ni_fpos || nio->nio_nino->ni_seekok))
+               return -ESPIPE;
+               
+       if (!nio->nio_nino->ni_seekok) {
+               if (off != nio->nio_nino->ni_fpos) {
+                       /*
+                        * They've done a p{read,write} or somesuch. Can't
+                        * seek on this descriptor so we err out now.
+                        */
+                       errno = ESPIPE;
+                       return -1;
+               }
+               cc =
+                   syscall(nio->nio_op == 'r' ? SYS_read : SYS_write,
+                           nio->nio_nino->ni_fd,
+                           buf,
+                           count);
+               if (cc > 0)
+                       nio->nio_nino->ni_fpos += cc;
+       } else
+               cc =
+                   syscall((nio->nio_op == 'r'
+                              ? _NATIVE_SYSCALL_PREAD
+                              : _NATIVE_SYSCALL_PWRITE),
+                           nio->nio_nino->ni_fd,
+                           buf,
+                           count,
+                           off);
+
+       return cc;
+#undef _NATIVE_SYSCALL_PREAD
+#undef _NATIVE_SYSCALL_PWRITE
+}
+
+static ssize_t
+doiov(const struct iovec *iov,
+      int count,
+      _SYSIO_OFF_T off,
+      ssize_t limit,
+      struct native_io *nio)
+{
+       ssize_t cc;
+
+#if !(defined(REDSTORM) || defined(MAX_IOVEC))
+#define MAX_IOVEC      INT_MAX
+#endif
+
+       if (count <= 0)
+               return -EINVAL;
+
+       /*
+        * Avoid the reposition call if we're already at the right place.
+        * Allows us to access pipes and fifos.
+        */
+       if (off != nio->nio_nino->ni_fpos) {
+               int     err;
+
+               err = native_pos(nio->nio_nino->ni_fd, &off, SEEK_SET);
+               if (err)
+                       return err;
+               nio->nio_nino->ni_fpos = off;
+       }
+
+       /*
+        * The {read,write}v is safe as this routine is only ever called
+        * by _sysio_enumerate_extents() and that routine is exact. It never
+        * passes iovectors including tails.
+        */
+       cc =
+#ifndef REDSTORM
+           count <= MAX_IOVEC
+             ? syscall(nio->nio_op == 'r' ? SYS_readv : SYS_writev,
+                       nio->nio_nino->ni_fd,
+                       iov,
+                       count)
+             :
+#endif
+               _sysio_enumerate_iovec(iov,
+                                      count,
+                                      off,
+                                      limit,
+                                      (ssize_t (*)(void *,
+                                                   size_t,
+                                                   _SYSIO_OFF_T,
+                                                   void *))dopio,
+                                      nio);
+       if (cc < 0)
+               cc = -errno;
+       else
+               nio->nio_nino->ni_fpos += cc;
+       return cc;
+
+#if !(defined(REDSTORM) || defined(MAX_IOVEC))
+#undef MAX_IOVEC
+#endif
+}
+
+#if 0
+static int
+lockop_all(struct native_inode *nino,
+          struct intnl_xtvec *xtv,
+          size_t count,
+          short op)
+{
+       struct flock flock;
+       int     err;
+
+       if (!count)
+               return -EINVAL;
+       flock.l_type = op;
+       flock.l_whence = SEEK_SET;
+       while (count--) {
+               flock.l_start = xtv->xtv_off;
+               flock.l_len = xtv->xtv_len;
+               xtv++;
+               err =
+                   syscall(
+#if !_LARGEFILE64_SOURCE
+                           SYS_fcntl64
+#else
+                           SYS_fcntl
+#endif
+                           ,
+                           nino->ni_fd,
+                           F_SETLK,
+                           &flock);
+               if (err != 0)
+                       return -errno;
+       }
+       return 0;
+}
+
+static int
+order_xtv(const struct intnl_xtvec *xtv1, const struct intnl_xtvec *xtv2)
+{
+
+       if (xtv1->xtv_off < xtv2->xtv_off)
+               return -1;
+       if (xtv1->xtv_off > xtv2->xtv_off)
+               return 1;
+       return 0;
+}
+#endif
+
+static int
+doio(char op, struct ioctx *ioctx)
+{
+       struct native_inode *nino;
+#if 0
+       int     dolocks;
+       struct intnl_xtvec *oxtv;
+       int     err;
+#endif
+       struct native_io arguments;
+       ssize_t cc;
+#if 0
+       struct intnl_xtvec *front, *rear, tmp;
+#endif
+
+       nino = I2NI(ioctx->ioctx_ino);
+#if 0
+       dolocks = ioctx->ioctx_xtvlen > 1 && nino->ni_seekok;
+       if (dolocks) {
+               /*
+                * Must lock the regions (in order!) since we can't do
+                * strided-IO as a single atomic operation.
+                */
+               oxtv = malloc(ioctx->ioctx_xtvlen * sizeof(struct intnl_xtvec));
+               if (!oxtv)
+                       return -ENOMEM;
+               (void )memcpy(oxtv,
+                             ioctx->ioctx_xtv, 
+                             ioctx->ioctx_xtvlen * sizeof(struct intnl_xtvec));
+               qsort(oxtv,
+                     ioctx->ioctx_xtvlen,
+                     sizeof(struct intnl_xtvec),
+                     (int (*)(const void *, const void *))order_xtv);
+               err =
+                   lockop_all(nino,
+                              oxtv, ioctx->ioctx_xtvlen,
+                              op == 'r' ? F_RDLCK : F_WRLCK);
+               if (err) {
+                       free(oxtv);
+                       return err;
+               }
+       }
+#endif
+       arguments.nio_op = op;
+       arguments.nio_nino = nino;
+       cc =
+           _sysio_enumerate_extents(ioctx->ioctx_xtv, ioctx->ioctx_xtvlen, 
+                                    ioctx->ioctx_iov, ioctx->ioctx_iovlen,
+                                    (ssize_t (*)(const struct iovec *,
+                                                 int,
+                                                 _SYSIO_OFF_T,
+                                                 ssize_t,
+                                                 void *))doiov,
+                                    &arguments);
+#if 0
+       if (dolocks) {
+               /*
+                * Must unlock in reverse order.
+                */
+               front = oxtv;
+               rear = front + ioctx->ioctx_xtvlen - 1;
+               while (front < rear) {
+                       tmp = *front;
+                       *front++ = *rear;
+                       *rear-- = tmp;
+               }
+               if (lockop_all(nino, oxtv, ioctx->ioctx_xtvlen, F_UNLCK) != 0)
+                       abort();
+               free(oxtv);
+       }
+#endif
+       if ((ioctx->ioctx_cc = cc) < 0) {
+               ioctx->ioctx_errno = -ioctx->ioctx_cc;
+               ioctx->ioctx_cc = -1;
+       }
+       return 0;
+}
+
+static int
+native_inop_read(struct inode *ino __IS_UNUSED, struct ioctx *ioctx)
+{
+
+       return doio('r', ioctx);
+}
+
+static int
+native_inop_write(struct inode *ino __IS_UNUSED, struct ioctx *ioctx)
+{
+
+       return doio('w', ioctx);
+}
+
+static _SYSIO_OFF_T
+native_inop_pos(struct inode *ino, _SYSIO_OFF_T off)
+{
+       struct native_inode *nino = I2NI(ino);
+       int     err;
+
+       err = native_pos(nino->ni_fd, &off, SEEK_SET);
+       return err < 0 ? err : off;
+}
+
+static int
+native_inop_iodone(struct ioctx *ioctxp __IS_UNUSED)
+{
+
+       /*
+        * It's always done in this driver. It completed when posted.
+        */
+       return 1;
+}
+
+static int
+native_inop_fcntl(struct inode *ino,
+                 int cmd,
+                 va_list ap)
+{
+       struct native_inode *nino = I2NI(ino);
+       long    arg;
+       int     err;
+
+       if (nino->ni_fd < 0)
+               abort();
+
+       switch (cmd) {
+       case F_GETFD:
+       case F_GETFL:
+       case F_GETOWN:
+               err = syscall(SYS_fcntl, nino->ni_fd, cmd);
+               if (err < 0)
+                       err = -errno;
+       case F_DUPFD:
+       case F_SETFD:
+       case F_SETFL:
+       case F_GETLK:
+       case F_SETLK:
+       case F_SETLKW:
+       case F_SETOWN:
+               arg = va_arg(ap, long);
+               err = syscall(SYS_fcntl, nino->ni_fd, cmd, arg);
+               if (err)
+                       err = -errno;
+       default:
+               err = -EINVAL;
+       }
+       return err;
+}
+
+static int
+native_inop_mknod(struct pnode *pno __IS_UNUSED,
+                 mode_t mode __IS_UNUSED,
+                 dev_t dev __IS_UNUSED)
+{
+
+       return -ENOSYS;
+}
+
+#ifdef _HAVE_STATVFS
+static int
+native_inop_statvfs(struct pnode *pno,
+                   struct inode *ino,
+                   struct intnl_statvfs *buf)
+{
+       char    *path;
+       int    rc;
+       struct statfs fs;
+
+       path = NULL;
+       if (!ino || I2NI(ino)->ni_fd < 0) {
+               path = _sysio_pb_path(pno->p_base, '/');
+               if (!path)
+                       return -ENOMEM;
+       }
+
+       /*
+        * The syscall interface does not support SYS_fstatvfs.
+        * Should possibly return ENOSYS, but thought it
+        * better to use SYS_fstatfs and fill in as much of
+        * the statvfs structure as possible.  This allows
+        * for more of a test of the sysio user interface.
+        */
+       rc =
+           path
+             ? syscall(SYS_statfs, path, &fs)
+             : syscall(SYS_fstatfs, I2NI(ino)->ni_fd, &fs);
+       if (path)
+               free(path);
+       if (rc < 0)
+               return -errno;
+
+       buf->f_bsize = fs.f_bsize;  /* file system block size */
+       buf->f_frsize = fs.f_bsize; /* file system fundamental block size */
+       buf->f_blocks = fs.f_blocks;
+       buf->f_bfree = fs.f_bfree;
+       buf->f_bavail = fs.f_bavail;
+       buf->f_files = fs.f_files;  /* Total number serial numbers */
+       buf->f_ffree = fs.f_ffree;  /* Number free serial numbers */
+       buf->f_favail = fs.f_ffree; /* Number free ser num for non-privileged*/
+       buf->f_fsid = fs.f_fsid.__val[1];
+       buf->f_flag = 0;            /* No equiv in statfs; maybe use type? */
+       buf->f_namemax = fs.f_namelen;
+       return 0;
+}
+#endif
+
+static int
+native_inop_sync(struct inode *ino)
+{
+       int     err;
+
+       assert(I2NI(ino)->ni_fd >= 0);
+
+       err = syscall(SYS_fsync, I2NI(ino)->ni_fd);
+       if (err)
+               err = -errno;
+       return err;
+}
+
+static int
+native_inop_datasync(struct inode *ino)
+{
+       int     err;
+
+       assert(I2NI(ino)->ni_fd >= 0);
+
+#ifdef NATIVE_FDATASYNC
+       err = syscall(NATIVE_FDATASYNC, I2NI(ino)->ni_fd);
+#else
+#if 0
+#warning No fdatasync system call -- Using fsync instead!
+#endif
+       err = syscall(SYS_fsync, I2NI(ino)->ni_fd);
+#endif
+       if (err)
+               err = -errno;
+       return err;
+}
+
+static int
+native_inop_ioctl(struct inode *ino __IS_UNUSED,
+                 unsigned long int request __IS_UNUSED,
+                 va_list ap __IS_UNUSED)
+{
+
+       /*
+        * I'm lazy. Maybe implemented later.
+        */
+       errno = ENOTTY;
+       return -1;
+}
+
+static void
+native_inop_gone(struct inode *ino)
+{
+       struct native_inode *nino = I2NI(ino);
+
+       if (nino->ni_fd >= 0)
+               (void )syscall(SYS_close, nino->ni_fd);
+       free(ino->i_private);
+}
+
+static void
+native_fsop_gone(struct filesys *fs __IS_UNUSED)
+{
+
+       /*
+        * Do nothing. There is no private part maintained for the
+        * native file interface.
+        */
+}
diff --git a/libsysio/drivers/native/fs_native.h b/libsysio/drivers/native/fs_native.h
new file mode 100644 (file)
index 0000000..1590379
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+/*
+ * Native file system driver support.
+ */
+
+extern int _sysio_native_init(void);
diff --git a/libsysio/drivers/native/module.mk b/libsysio/drivers/native/module.mk
new file mode 100644 (file)
index 0000000..8cada8a
--- /dev/null
@@ -0,0 +1,2 @@
+NATIVE_SRCS  = drivers/native/fs_native.c
+NATIVE_EXTRA = drivers/native/fs_native.h drivers/native/module.mk
diff --git a/libsysio/drivers/sockets/module.mk b/libsysio/drivers/sockets/module.mk
new file mode 100644 (file)
index 0000000..261fcfa
--- /dev/null
@@ -0,0 +1,2 @@
+SOCKETS_SRCS = drivers/sockets/sockets.c
+SOCKETS_EXTRA = drivers/sockets/module.mk
diff --git a/libsysio/drivers/sockets/sockets.c b/libsysio/drivers/sockets/sockets.c
new file mode 100644 (file)
index 0000000..b8da195
--- /dev/null
@@ -0,0 +1,569 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#ifdef __linux__
+#define _BSD_SOURCE
+#endif
+
+#include <stdio.h>                                     /* for NULL */
+#include <stdlib.h>
+#ifdef __linux__
+#include <string.h>
+#endif
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <syscall.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#include <sys/queue.h>
+#include <sys/syscall.h>
+#include <sys/socket.h>
+#include <linux/net.h>
+
+#include "sysio.h"
+#include "fs.h"
+#include "inode.h"
+#include "file.h"
+#include "dev.h"                                       /* _sysio_nodev_ops */
+
+/*
+ * Sockets interface driver
+ */
+
+/*
+ * Sockets file identifiers format.
+ */
+struct sockets_ino_identifier {
+       ino_t   inum;                                   /* i-number */
+};
+
+/*
+ * Driver-private i-node information we keep about in-use sockets.
+ */
+struct socket_info {
+       struct sockets_ino_identifier ski_ident;        /* unique identifier */
+       struct file_identifier ski_fileid;              /* ditto */
+       int     ski_fd;                         /* host fildes */
+};
+
+static int sockets_inop_close(struct inode *ino);
+static int sockets_inop_read(struct inode *ino,
+                            struct ioctx *ioctx);
+static int sockets_inop_write(struct inode *ino,
+                             struct ioctx *ioctxp);
+static _SYSIO_OFF_T sockets_inop_pos(struct inode *ino,
+                                    _SYSIO_OFF_T off);
+static int sockets_inop_iodone(struct ioctx *ioctx);
+static int sockets_inop_sync(struct inode *ino);
+static int sockets_inop_datasync(struct inode *ino);
+static int sockets_inop_fcntl(struct inode *ino, int cmd, va_list ap);
+static int sockets_inop_ioctl(struct inode *ino,
+                            unsigned long int request,
+                            va_list ap);
+static void sockets_inop_gone(struct inode *ino);
+static void sockets_illop(void);
+
+/*
+ * Given i-node, return driver private part.
+ */
+#define I2SKI(ino)     ((struct socket_info *)((ino)->i_private))
+
+struct filesys_ops sockets_filesys_ops = {
+       (void (*)(struct filesys *))sockets_illop
+};
+
+static struct filesys *sockets_fs;
+
+static struct inode_ops sockets_i_ops;
+
+/*
+ * Initialize this driver.
+ */
+int
+_sysio_sockets_init()
+{
+
+       sockets_i_ops = _sysio_nodev_ops;
+       sockets_i_ops.inop_close = sockets_inop_close;
+       sockets_i_ops.inop_read = sockets_inop_read;
+       sockets_i_ops.inop_write = sockets_inop_write;
+       sockets_i_ops.inop_pos = sockets_inop_pos;
+       sockets_i_ops.inop_iodone = sockets_inop_iodone;
+       sockets_i_ops.inop_fcntl = sockets_inop_fcntl;
+       sockets_i_ops.inop_sync = sockets_inop_sync;
+       sockets_i_ops.inop_datasync = sockets_inop_datasync;
+       sockets_i_ops.inop_ioctl = sockets_inop_ioctl;
+       sockets_i_ops.inop_gone = sockets_inop_gone;
+
+       sockets_fs = _sysio_fs_new(&sockets_filesys_ops, 0, NULL);
+       if (!sockets_fs)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static int
+sockets_inop_close(struct inode *ino)
+{
+       struct socket_info *ski = I2SKI(ino);
+       int     err;
+
+       if (ski->ski_fd < 0)
+               return -EBADF;
+
+       err = syscall(SYS_close, ski->ski_fd);
+       if (err)
+               return -errno;
+       ski->ski_fd = -1;
+       return 0;
+}
+
+/*
+ * A helper function performing the real IO operation work.
+ *
+ * We don't really have async IO. We'll just perform the function
+ * now.
+ */
+static int
+doio(ssize_t (*f)(int, const struct iovec *, int),
+     struct inode *ino,
+     struct ioctx *ioctx)
+{
+       struct socket_info *ski = I2SKI(ino);
+
+       assert(ski->ski_fd >= 0);
+
+       /* XXX there's no way to check the position
+        * here we only could ingore the extends
+        */
+       if (ioctx->ioctx_xtvlen != 1)
+               return -EINVAL;
+
+       if (ioctx->ioctx_iovlen && (int) ioctx->ioctx_iovlen < 0)
+               return -EINVAL;
+
+       /*
+        * Call the appropriate (read/write) IO function to
+        * transfer the data now.
+        */
+       ioctx->ioctx_cc =
+           (*f)(ski->ski_fd, ioctx->ioctx_iov, ioctx->ioctx_iovlen);
+       if (ioctx->ioctx_cc < 0)
+               ioctx->ioctx_errno = errno;
+
+       ioctx->ioctx_done = 1;
+       return 0;
+}
+
+/*
+ * Helper function passed to doio(), above, to accomplish a real readv.
+ */
+static ssize_t
+_readv(int fd, const struct iovec *vector, int count)
+{
+
+       return syscall(SYS_readv, fd, vector, count);
+}
+
+static int
+sockets_inop_read(struct inode *ino,
+                 struct ioctx *ioctx)
+{
+
+       return doio(_readv, ino, ioctx);
+}
+
+/*
+ * Helper function passed to doio(), above, to accomplish a real writev.
+ */
+static ssize_t
+_writev(int fd, const struct iovec *vector, int count)
+{
+
+       return syscall(SYS_writev, fd, vector, count);
+}
+
+static int
+sockets_inop_write(struct inode *ino,
+                  struct ioctx *ioctx)
+{
+
+       return doio(_writev, ino, ioctx);
+}
+
+static _SYSIO_OFF_T
+sockets_inop_pos(struct inode *ino, _SYSIO_OFF_T off)
+{
+       return -EINVAL;
+}
+
+static int
+sockets_inop_iodone(struct ioctx *ioctxp __IS_UNUSED)
+{
+
+       /*
+        * It's always done in this driver. It completed when posted.
+        */
+       return 1;
+}
+
+static int
+sockets_inop_fcntl(struct inode *ino __IS_UNUSED,
+                 int cmd __IS_UNUSED,
+                 va_list ap __IS_UNUSED)
+{
+       long arg;
+
+       assert(I2SKI(ino)->ski_fd >= 0);
+
+       switch (cmd) {
+       case F_GETFD:
+       case F_GETFL:
+       case F_GETOWN:
+               return syscall(SYS_fcntl, I2SKI(ino)->ski_fd, cmd);
+       case F_DUPFD:
+       case F_SETFD:
+       case F_SETFL:
+       case F_GETLK:
+       case F_SETLK:
+       case F_SETLKW:
+       case F_SETOWN:
+               arg = va_arg(ap, long);
+               return syscall(SYS_fcntl, I2SKI(ino)->ski_fd, cmd, arg);
+       default:
+               printf("uncatched cmd %d\n", cmd);
+               abort();
+       }
+       return -1;
+}
+
+static int
+sockets_inop_sync(struct inode *ino)
+{
+
+       assert(I2SKI(ino)->ski_fd >= 0);
+
+       return syscall(SYS_fsync, I2SKI(ino)->ski_fd);
+}
+
+static int
+sockets_inop_datasync(struct inode *ino)
+{
+
+       assert(I2SKI(ino)->ski_fd >= 0);
+
+       return syscall(SYS_fdatasync, I2SKI(ino)->ski_fd);
+}
+
+static int
+sockets_inop_ioctl(struct inode *ino __IS_UNUSED,
+                 unsigned long int request __IS_UNUSED,
+                 va_list ap __IS_UNUSED)
+{
+       /*
+        * I'm lazy. Maybe implemented later.
+        */
+       return -ENOTTY;
+}
+
+static void
+sockets_inop_gone(struct inode *ino)
+{
+
+       (void )sockets_inop_close(ino);
+       free(ino->i_private);
+}
+
+static void
+sockets_illop(void)
+{
+
+       abort();
+}
+
+static struct inode *
+_sysio_sockets_inew()
+{
+       static ino_t inum = 1;
+       struct socket_info *ski;
+       struct inode *ino;
+
+       ski = malloc(sizeof(struct socket_info));
+       if (!ski)
+               return NULL;
+       ski->ski_ident.inum = inum++;
+       ski->ski_fileid.fid_data = &ski->ski_ident;
+       ski->ski_fileid.fid_len = sizeof(ski->ski_ident);
+       ski->ski_fd = -1;
+
+       ino =
+           _sysio_i_new(sockets_fs,
+                        &ski->ski_fileid,
+                        0,
+                        0,
+                        0,
+                        &sockets_i_ops,
+                        ski);
+       if (!ino)
+               free(ski);
+
+       return ino;
+}
+
+int
+socket(int domain, int type, int protocol)
+{
+       int     err;
+       struct inode *ino;
+       struct socket_info *ski;
+       struct file *fil;
+
+       err = 0;
+       fil = NULL;
+
+       ino = _sysio_sockets_inew();
+       if (!ino) {
+               err = -ENOMEM;
+               goto error;
+       }
+
+       ski = I2SKI(ino);
+#ifndef SYS_socketcall
+       ski->ski_fd = syscall(SYS_socket, domain, type, protocol);
+#else
+       {
+               unsigned long avec[3] = {domain, type, protocol};
+               ski->ski_fd = syscall(SYS_socketcall, SYS_SOCKET, avec);
+       }
+#endif
+       if (ski->ski_fd < 0) {
+               err = -errno;
+               goto error;
+       }
+
+       fil = _sysio_fnew(ino, O_RDWR);
+       if (!fil) {
+               err = -ENOMEM;
+               goto error;
+       }
+
+       err = _sysio_fd_set(fil, ski->ski_fd);
+       if (err < 0)
+               goto error;
+
+       return err;
+
+error:
+       if (fil)
+               F_RELE(fil);
+       if (ino)
+               I_RELE(ino);
+
+       errno = -err;
+       return -1;
+}
+
+int
+accept(int s, struct sockaddr *addr, socklen_t *addrlen)
+{
+       int     err;
+       struct inode *ino;
+       struct socket_info *ski;
+       struct file *ofil, *nfil;
+
+       err = 0;
+       nfil = NULL;
+       ino = NULL;
+
+       ofil = _sysio_fd_find(s);
+       if (!ofil) {
+               err = -EBADF;
+               goto error;
+       }
+
+       ino = _sysio_sockets_inew();
+       if (!ino) {
+               err = -ENOMEM;
+               goto error;
+       }
+
+       nfil = _sysio_fnew(ino, O_RDWR);
+       if (!nfil) {
+               err = -ENOMEM;
+               goto error;
+       }
+
+       ski = I2SKI(ino);
+#ifndef SYS_socketcall
+       ski->ski_fd = syscall(SYS_accept, I2SKI(ofil->f_ino)->ski_fd,
+                               addr, addrlen);
+#else
+       {
+               unsigned long avec[3] = {
+                       (unsigned long) I2SKI(ofil->f_ino)->ski_fd,
+                       (unsigned long) addr,
+                       (unsigned long) addrlen};
+               ski->ski_fd = syscall(SYS_socketcall, SYS_ACCEPT, avec);
+       }
+#endif
+       if (ski->ski_fd < 0) {
+               err = -errno;
+               goto error;
+       }
+
+       err = _sysio_fd_set(nfil, ski->ski_fd);
+       if (err < 0)
+               goto error;
+
+       return err;
+
+error:
+       if (nfil)
+               F_RELE(nfil);
+       if (ino)
+               I_RELE(ino);
+
+       errno = -err;
+       return -1;
+}
+
+int
+bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen)
+{
+       int     err;
+       struct file *fil;
+       unsigned long avec[3];
+
+       err = 0;
+
+       fil = _sysio_fd_find(sockfd);
+       if (!fil) {
+               err = -EBADF;
+               goto out;
+       }
+
+#ifndef SYS_socketcall
+       if (syscall(SYS_bind, I2SKI(fil->f_ino)->ski_fd, my_addr, addrlen)) {
+#else
+       avec[0] = I2SKI(fil->f_ino)->ski_fd;
+       avec[1] = (unsigned long )my_addr;
+       avec[2] = addrlen;
+       if (syscall(SYS_socketcall, SYS_BIND, avec) != 0) {
+#endif
+               err = -errno;
+               goto out;
+       }
+
+       return 0;
+out:
+       errno = -err;
+       return -1;
+}
+
+int
+listen(int s, int backlog)
+{
+       int     err;
+       struct file *fil;
+       unsigned long avec[2];
+
+       err = 0;
+
+       fil = _sysio_fd_find(s);
+       if (!fil) {
+               err = -EBADF;
+               goto out;
+       }
+
+#ifndef SYS_socketcall
+       if (syscall(SYS_listen, I2SKI(fil->f_ino)->ski_fd, backlog) != 0) {
+#else
+       avec[0] = I2SKI(fil->f_ino)->ski_fd;
+       avec[1] = backlog;
+       if (syscall(SYS_socketcall, SYS_LISTEN, avec) != 0) {
+#endif
+               err = -errno;
+               goto out;
+       }
+
+       return 0;
+out:
+       errno = -err;
+       return -1;
+}
+
+int
+connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen)
+{
+       int     err;
+       struct file *fil;
+       unsigned long avec[3];
+
+       err = 0;
+
+       fil = _sysio_fd_find(sockfd);
+       if (!fil) {
+               err = -EBADF;
+               goto out;
+       }
+
+#ifndef SYS_socketcall
+       if (syscall(SYS_connect, I2SKI(fil->f_ino)->ski_fd,
+                   serv_addr, addrlen) != 0) {
+#else
+       avec[0] = I2SKI(fil->f_ino)->ski_fd;
+       avec[1] = (unsigned long )serv_addr;
+       avec[2] = addrlen;
+       if (syscall(SYS_socketcall, SYS_CONNECT, avec) != 0) {
+#endif
+               err = -errno;
+               goto out;
+       }
+
+       return 0;
+out:
+       errno = -err;
+       return -1;
+}
diff --git a/libsysio/drivers/yod/fs_yod.c b/libsysio/drivers/yod/fs_yod.c
new file mode 100644 (file)
index 0000000..d651b88
--- /dev/null
@@ -0,0 +1,1224 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#ifdef __linux__
+#define _BSD_SOURCE
+#endif
+
+#include <stdio.h>                                     /* for NULL */
+#include <stdlib.h>
+#ifdef __linux__
+#include <string.h>
+#endif
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <syscall.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#if 0
+#include <sys/vfs.h>
+#endif
+#ifdef _HAVE_STATVFS
+#include <sys/statvfs.h>
+#endif
+#include <utime.h>
+#include <sys/queue.h>
+#include <sys/uio.h>
+
+#include "sysio.h"
+#include "fs.h"
+#include "mount.h"
+#include "inode.h"
+
+#include "fs_yod.h"
+
+/*
+ * Remote file system driver
+ * calls are re-directed to the initiating yod
+ */
+#include "cplant-yod.h"
+
+/* stat struct used by yod, which
+ * is not compiled with __USE_FILE_OFFSET64
+ */
+#define __yod_stat stat
+#ifdef ALPHA_LINUX
+#define COPY_STAT(src, dest)                    \
+do {                                            \
+       memset((dest), 0, sizeof((*dest)));     \
+       (dest)->st_dev     = (src)->st_dev;     \
+       (dest)->st_ino     = (src)->st_ino;     \
+       (dest)->st_mode    = (src)->st_mode;    \
+       (dest)->st_nlink   = (src)->st_nlink;   \
+       (dest)->st_uid     = (src)->st_uid;     \
+       (dest)->st_gid     = (src)->st_gid;     \
+       (dest)->st_rdev    = (src)->st_rdev;    \
+       (dest)->st_size    = (src)->st_size;    \
+       (dest)->st_atime   = (src)->st_atime;   \
+       (dest)->st_mtime   = (src)->st_mtime;   \
+       (dest)->st_ctime   = (src)->st_ctime;   \
+       (dest)->st_blksize = (src)->st_blksize; \
+       (dest)->st_blocks  = (src)->st_blocks;  \
+       (dest)->st_flags   = (src)->st_flags;   \
+       (dest)->st_gen     = (src)->st_gen;     \
+} while (0);
+#else
+#define COPY_STAT(src, dest)                    \
+do {                                            \
+       memset((dest), 0, sizeof((*dest)));     \
+       (dest)->st_dev     = (src)->st_dev;     \
+       (dest)->st_ino     = (src)->st_ino;     \
+       (dest)->st_mode    = (src)->st_mode;    \
+       (dest)->st_nlink   = (src)->st_nlink;   \
+       (dest)->st_uid     = (src)->st_uid;     \
+       (dest)->st_gid     = (src)->st_gid;     \
+       (dest)->st_rdev    = (src)->st_rdev;    \
+       (dest)->st_size    = (src)->st_size;    \
+       (dest)->st_atime   = (src)->st_atime;   \
+       (dest)->st_mtime   = (src)->st_mtime;   \
+       (dest)->st_ctime   = (src)->st_ctime;   \
+       (dest)->st_blksize = (src)->st_blksize; \
+       (dest)->st_blocks  = (src)->st_blocks;  \
+} while (0);
+#endif
+
+/*
+ * Yod file identifiers format.
+ */
+struct yod_inode_identifier {
+       dev_t   dev;                                    /* device number */
+       ino_t   ino;                                    /* i-number */
+#ifdef HAVE_GENERATION
+       unsigned int gen;                               /* generation number */
+#endif
+};
+
+/*
+ * Driver-private i-node information we keep about local host file
+ * system objects.
+ */
+struct yod_inode {
+       unsigned ni_seekok              : 1;            /* can seek? */
+       struct yod_inode_identifier ni_ident;           /* unique identifier */
+       struct file_identifier ni_fileid;               /* ditto */
+       int     ni_fd;                                  /* host fildes */
+       int     ni_oflags;                              /* flags, from open */
+       unsigned ni_nopens;                             /* soft ref count */
+       _SYSIO_OFF_T ni_fpos;                           /* current pos */
+};
+
+static int yod_inop_lookup(struct pnode *pno,
+                             struct inode **inop,
+                             struct intent *intnt,
+                             const char *path);
+static int yod_inop_getattr(struct pnode *pno,
+                              struct inode *ino,
+                              struct intnl_stat *stbuf);
+static int yod_inop_setattr(struct pnode *pno,
+                              struct inode *ino,
+                              unsigned mask,
+                              struct intnl_stat *stbuf);
+static ssize_t yod_getdirentries(struct inode *ino,
+                                   char *buf,
+                                   size_t nbytes,
+                                   off64_t *basep);
+static int yod_inop_mkdir(struct pnode *pno, mode_t mode);
+static int yod_inop_rmdir(struct pnode *pno);
+static int yod_inop_symlink(struct pnode *pno, const char *data);
+static int yod_inop_readlink(struct pnode *pno, char *buf, size_t bufsiz);
+static int yod_inop_open(struct pnode *pno, int flags, mode_t mode);
+static int yod_inop_close(struct inode *ino);
+static int yod_inop_link(struct pnode *old, struct pnode *new);
+static int yod_inop_unlink(struct pnode *pno);
+static int yod_inop_rename(struct pnode *old, struct pnode *new);
+static _SYSIO_OFF_T yod_inop_pos (struct inode *ino, _SYSIO_OFF_T off);  
+static int yod_inop_read(struct inode *ino, struct ioctx *ioctx);
+static int yod_inop_write(struct inode *ino, struct ioctx *ioctx);
+static int yod_inop_iodone(struct ioctx *ioctx);
+static int yod_inop_fcntl(struct inode *ino, int cmd, va_list ap);
+static int yod_inop_sync(struct inode *ino);
+static int yod_inop_datasync(struct inode *ino);
+static int yod_inop_ioctl(struct inode *ino,
+                            unsigned long int request,
+                            va_list ap);
+static int yod_inop_mknod(struct pnode *pno, mode_t mode, dev_t dev);
+#ifdef _HAVE_STATVFS
+static int yod_inop_statvfs(struct pnode *pno,
+                              struct inode *ino,
+                              struct intnl_statvfs *buf);
+#endif
+static void yod_inop_gone(struct inode *ino);
+
+static struct inode_ops yod_i_ops = {
+       yod_inop_lookup,
+       yod_inop_getattr,
+       yod_inop_setattr,
+       yod_getdirentries,
+       yod_inop_mkdir,
+       yod_inop_rmdir,
+       yod_inop_symlink,
+       yod_inop_readlink,
+       yod_inop_open,
+       yod_inop_close,
+       yod_inop_link,
+       yod_inop_unlink,
+       yod_inop_rename,
+       yod_inop_read,
+       yod_inop_write,
+       yod_inop_pos,
+       yod_inop_iodone,
+       yod_inop_fcntl,
+       yod_inop_sync,
+       yod_inop_datasync,
+       yod_inop_ioctl,
+       yod_inop_mknod,
+#ifdef _HAVE_STATVFS
+       yod_inop_statvfs,
+#endif
+       yod_inop_gone
+};
+
+static int yod_fsswop_mount(const char *source,
+                              unsigned flags,
+                              const void *data,
+                              struct pnode *tocover,
+                              struct mount **mntp);
+
+static struct fssw_ops yod_fssw_ops = {
+       yod_fsswop_mount
+};
+
+static void yod_fsop_gone(struct filesys *fs);
+
+static struct filesys_ops yod_inodesys_ops = {
+       yod_fsop_gone
+};
+
+/* 
+ * Placeholder internal mount as in native driver
+ */
+static struct mount *yod_internal_mount = NULL;
+
+/*
+ * Given i-node, return driver private part.
+ */
+#define I2NI(ino)      ((struct yod_inode *)((ino)->i_private))
+
+/*
+ * stat -- by path.
+ */
+static int
+yod_stat(const char *path, struct intnl_stat *buf)
+{
+       int     err;
+       struct __yod_stat stbuf;
+       
+       err = stat_yod(path, &stbuf); 
+       if (err)
+               err = -errno;
+       COPY_STAT(&stbuf, buf);
+
+       return err;
+}
+
+/*
+ * stat -- by fildes
+ */
+static int
+yod_fstat(int fd, struct intnl_stat *buf)
+{
+       int     err;
+       struct __yod_stat stbuf;
+
+       err = fstat_yod(fd, &stbuf);
+       if (err)
+               err = -errno;
+       COPY_STAT(&stbuf, buf);
+
+       return err;
+}
+
+/*
+ * Introduce an i-node to the system.
+ */
+static struct inode *
+yod_i_new(struct filesys *fs, struct intnl_stat *buf)
+{
+       struct yod_inode *nino;
+       struct inode *ino;
+
+       nino = malloc(sizeof(struct yod_inode));
+       if (!nino)
+               return NULL;
+       bzero(&nino->ni_ident, sizeof(nino->ni_ident));
+       nino->ni_ident.dev = buf->st_dev;
+       nino->ni_ident.ino = buf->st_ino;
+#ifdef HAVE_GENERATION
+       nino->ni_ident.gen = buf->st_gen;
+#endif
+       nino->ni_fileid.fid_data = &nino->ni_ident;
+       nino->ni_fileid.fid_len = sizeof(nino->ni_ident);
+       nino->ni_fd = -1;
+       nino->ni_oflags = 0;
+       nino->ni_nopens = 0;
+       nino->ni_fpos = 0;
+       ino =
+           _sysio_i_new(fs,
+                        &nino->ni_fileid,
+#ifndef AUTOMOUNT_FILE_NAME
+                        buf->st_mode & S_IFMT,
+#else
+                        buf->st_mode,                  /* all of the bits! */
+#endif
+                        0,
+                        0,
+                        &yod_i_ops,
+                        nino);
+       if (!ino)
+               free(nino);
+       return ino;
+}
+
+/*
+ * Initialize this driver.
+ */
+int
+_sysio_yod_init()
+{
+
+       /*
+        * Capture current process umask and reset our process umask to
+        * zero. All permission bits to open/creat/setattr are absolute --
+        * They've already had a umask applied, when appropriate.
+        */
+       _sysio_umask = syscall(SYS_umask, 0);
+
+       return _sysio_fssw_register("yod", &yod_fssw_ops);
+}
+
+/*
+ * Create private, internal, view of the hosts name space.
+ */
+static int
+create_internal_namespace()
+{
+       int     err;
+       struct mount *mnt;
+       struct inode *rootino;
+       struct pnode_base *rootpb;
+       static struct qstr noname = { NULL, 0, 0 };
+       struct filesys *fs;
+       struct intnl_stat stbuf;
+
+       if (yod_internal_mount) {
+               /*
+                * Reentered!
+                */
+               abort();
+       }
+
+       /*
+        * We maintain an artificial, internal, name space in order to
+        * have access to fully qualified path names in the various routines.
+        * Initialize that name space now.
+        */
+       mnt = NULL;
+       rootino = NULL;
+       rootpb = NULL;
+       fs = _sysio_fs_new(&yod_inodesys_ops, 0, NULL);
+       if (!fs) {
+               err = -ENOMEM;
+               goto error;
+       }
+
+       /*
+        * Get root i-node.
+        */
+       err = yod_stat("/", &stbuf);
+       if (err)
+               goto error;
+       rootino = yod_i_new(fs, &stbuf);
+       if (!rootino) {
+               err = -ENOMEM;
+               goto error;
+       }
+
+       /*
+        * Generate base path-node for root.
+        */
+       rootpb = _sysio_pb_new(&noname, NULL, rootino);
+       if (!rootpb) {
+               err = -ENOMEM;
+               goto error;
+       }
+
+       /*
+        * Mount it. This name space is disconnected from the
+        * rest of the system -- Only available within this driver.
+        */
+       err = _sysio_do_mount(fs, rootpb, 0, NULL, &mnt);
+       if (err)
+               goto error;
+
+       yod_internal_mount = mnt;
+       return 0;
+error:
+       if (mnt) {
+               if (_sysio_do_unmount(mnt) != 0)
+                       abort();
+               fs = NULL;
+               rootpb = NULL;
+               rootino = NULL;
+       }
+       if (rootpb)
+               _sysio_pb_gone(rootpb);
+       if (fs) {
+               FS_RELE(fs);
+               _sysio_fs_gone(fs);
+       }
+
+       return err;
+}
+
+static int
+yod_fsswop_mount(const char *source,
+                unsigned flags,
+                const void *data __IS_UNUSED,
+                struct pnode *tocover,
+                struct mount **mntp)
+{
+       int     err;
+       struct nameidata nameidata;
+       struct mount *mnt;
+
+       /*
+        * Caller must use fully qualified path names when specifying
+        * the source.
+        */
+       if (*source != '/')
+               return -ENOENT;
+
+       if (!yod_internal_mount) {
+               err = create_internal_namespace();
+               if (err)
+                       return err;
+       }
+
+       /*
+        * Lookup the source in the internally maintained name space.
+        */
+       ND_INIT(&nameidata, 0, source, yod_internal_mount->mnt_root, NULL);
+       err = _sysio_path_walk(yod_internal_mount->mnt_root, &nameidata);
+       if (err)
+               return err;
+
+       /*
+        * Have path-node specified by the given source argument. Let the
+        * system finish the job, now.
+        */
+       err =
+           _sysio_do_mount(yod_internal_mount->mnt_fs,
+                           nameidata.nd_pno->p_base,
+                           flags,
+                           tocover,
+                           &mnt);
+       /*
+        * Release the internal name space pnode and clean up any
+        * aliases we might have generated. We really don't need to cache them
+        * as they are only used at mount time..
+        */
+       P_RELE(nameidata.nd_pno);
+       (void )_sysio_p_prune(yod_internal_mount->mnt_root);
+
+       if (!err) {
+               FS_REF(yod_internal_mount->mnt_fs);
+               *mntp = mnt;
+       }
+       return err;
+}
+
+static int
+yod_i_invalid(struct inode *inop, struct intnl_stat stbuf)
+{
+       /*
+        * Validate passed in inode against stat struct info
+        */
+       struct yod_inode *nino = I2NI(inop);
+       
+       if ((nino->ni_ident.dev != stbuf.st_dev ||
+            nino->ni_ident.ino != stbuf.st_ino ||
+#ifdef HAVE_GENERATION
+            nino->ni_ident.gen != stbuf.st_gen ||
+#endif
+            ((inop)->i_mode & S_IFMT) != (stbuf.st_mode & S_IFMT)) ||
+           (((inop)->i_rdev != stbuf.st_rdev) &&
+              (S_ISCHR((inop)->i_mode) || S_ISBLK((inop)->i_mode))))
+               return 1;
+       
+       return 0;
+}
+
+/*
+ * Find, and validate, or create i-node by host-relative path. Returned i-node
+ * is referenced.
+ */
+static int
+yod_iget(struct filesys *fs,
+           const char *path,
+           struct inode **inop,
+           int forced)
+{
+       int     err;
+       struct inode *ino;
+       struct intnl_stat stbuf;
+       struct yod_inode_identifier ident;
+       struct file_identifier fileid;
+
+       /*
+        * Get file status.
+        */
+       err = yod_stat(path, &stbuf);
+       if (err) {
+               *inop = NULL;
+               return err;
+       }
+
+       /*
+        * Validate?
+        */
+       if (*inop) {
+               if (!yod_i_invalid(*inop, stbuf))
+                       return 0;
+               /*
+                * Invalidate.
+                */
+               *inop = NULL;
+       }
+
+       /*
+        * I-node is not already known. Find or create it.
+        */
+       bzero(&ident, sizeof(ident)); 
+       ident.dev = stbuf.st_dev;
+       ident.ino = stbuf.st_ino;
+#ifdef HAVE_GENERATION
+       ident.gen = stbuf.st_gen;
+#endif
+       fileid.fid_data = &ident;
+       fileid.fid_len = sizeof(ident);
+       ino = _sysio_i_find(fs, &fileid);
+       if (ino && forced) {
+               /*
+                * Insertion was forced but it's already present!
+                */
+               if (yod_i_invalid(ino, stbuf)) {
+                       /* 
+                        * Cached inode has stale attrs
+                        * make way for the new one
+                        */
+                       I_RELE(ino);
+                       _sysio_i_undead(ino);
+                       ino = NULL;
+               } else
+                       /* 
+                        * OK to reuse cached inode
+                        */
+                       goto out;
+       }
+
+       if (!ino) {
+               ino = yod_i_new(fs, &stbuf);
+               if (!ino)
+                       err = -ENOMEM;
+       }
+out:
+       if (!err)
+               *inop = ino;
+       return err;
+}
+
+/*
+ * Look up named object in host's name space by path.
+ */
+static int
+yod_path_lookup(struct filesys *fs, const char *path, struct inode **inop)
+{
+
+       return yod_iget(fs, path, inop, 0);
+}
+
+/*
+ * Look up object by it's path node.
+ */
+static int
+yod_i_lookup(struct filesys *fs, struct pnode_base *pb, struct inode **inop)
+{
+       int     err;
+       char    *path;
+
+       path = _sysio_pb_path(pb, '/');
+       if (!path)
+               return -ENOMEM;
+       err = yod_path_lookup(fs, path, inop);
+       free(path);
+       return err;
+}
+
+static int
+yod_inop_lookup(struct pnode *pno,
+                  struct inode **inop,
+                  struct intent *intnt __IS_UNUSED,
+                  const char *path __IS_UNUSED)
+{
+       int     err;
+
+       *inop = pno->p_base->pb_ino;
+
+       /*
+        * Don't have an inode yet. Because we translate everything back to
+        * a single name space for the host, we will assume the object the
+        * caller is looking for has no existing alias in our internal
+        * name space. We don't see the same file on different mounts in the
+        * underlying host FS as the same file.
+        *
+        * The file identifier *will* be unique. It's got to have a different
+        * dev.
+        */
+       err = yod_i_lookup(pno->p_mount->mnt_fs, pno->p_base, inop);
+       if (err)
+               *inop = NULL;
+       return err;
+}
+
+static int
+yod_inop_getattr(struct pnode *pno, struct inode *ino, struct intnl_stat *stbuf)
+{
+       char    *path;
+       int     err;
+
+       path = NULL;
+       if (!ino || I2NI(ino)->ni_fd < 0) {
+               path = _sysio_pb_path(pno->p_base, '/');
+               if (!path)
+                       return -ENOMEM;
+       }
+       err =
+           path
+             ? yod_stat(path, stbuf)
+             : yod_fstat(I2NI(ino)->ni_fd, stbuf);
+       if (path)
+               free(path);
+       return err;
+}
+
+static int
+yod_inop_setattr(struct pnode *pno,
+                   struct inode *ino,
+                   unsigned mask,
+                   struct intnl_stat *stbuf)
+{
+       char    *path;
+       int     fd;
+       struct intnl_stat st;
+       int     err;
+
+       path = NULL;
+       fd = ino ? I2NI(ino)->ni_fd : -1;
+       if (fd < 0 || mask & (SETATTR_MTIME|SETATTR_ATIME)) {
+               if (!pno)
+                       return -EEXIST;
+               path = _sysio_pb_path(pno->p_base, '/');
+               if (!path)
+                       return -ENOMEM;
+       }
+
+       /*
+        * Get current status for undo.
+        */
+       err =
+           fd < 0
+             ? yod_stat(path, &st)
+             : yod_fstat(fd, &st);
+       if (err)
+               goto out;
+
+       if (mask & SETATTR_MODE) {
+               mode_t  mode;
+
+               /*
+                * Alter permissions attribute.
+                */
+               mode = stbuf->st_mode & 07777;
+               err = chmod_yod(path, mode);
+       }
+       if (err)
+               mask &= ~SETATTR_MODE;
+
+       if (mask & (SETATTR_UID|SETATTR_GID)) {
+
+               /*
+                * Alter owner and/or group identifiers.
+                */
+               err = chown_yod(path,
+                               mask & SETATTR_UID
+                                 ? stbuf->st_uid
+                                 : (uid_t )-1,
+                               mask & SETATTR_GID
+                                 ? stbuf->st_gid
+                                 : (gid_t )-1);
+       }
+       if (err)
+               mask &= ~(SETATTR_UID|SETATTR_GID);
+       else if (mask & SETATTR_LEN) {
+               /*
+                * Do the truncate last. It can't be undone.
+                */
+                (void )(fd < 0
+                          ? truncate_yod(path, stbuf->st_size)
+                          : ftruncate_yod(fd, stbuf->st_size));
+       }
+       if (!err)
+               goto out;
+       /*
+        * Undo after error. Some or all of this might not work... We
+        * can but try.
+        */
+       if (mask & (SETATTR_UID|SETATTR_GID)) {
+                (void )chown_yod(path,
+                                 mask & SETATTR_UID
+                                   ? st.st_uid
+                                   : (uid_t )-1,
+                                 mask & SETATTR_GID
+                                   ? st.st_gid
+                                   : (gid_t )-1);
+       }
+       if (mask & SETATTR_MODE) {
+               chmod_yod(path, st.st_mode & 07777);
+       }
+out:
+       if (path)
+               free(path);
+       return err;
+}
+
+static ssize_t
+yod_getdirentries(struct inode *ino,
+                    char *buf,
+                    size_t nbytes,
+                    off64_t *basep)
+{
+       struct yod_inode *nino = I2NI(ino);
+       loff_t  result;
+       ssize_t cc;
+
+       assert(nino->ni_fd >= 0);
+
+       result = *basep;
+       if (*basep != nino->ni_fpos &&
+           (result = lseek_yod(nino->ni_fd,
+                               *basep,
+                               SEEK_SET) == -1))
+               return -errno;
+       nino->ni_fpos = result;
+       cc = getdirentries_yod(nino->ni_fd, buf, nbytes, &result);
+       if (cc < 0)
+               return -errno;
+       nino->ni_fpos += cc;
+       return cc;
+}
+
+static int
+yod_inop_mkdir(struct pnode *pno, mode_t mode)
+{
+       char    *path;
+       int     err;
+
+       path = _sysio_pb_path(pno->p_base, '/');
+       if (!path)
+               return -ENOMEM;
+
+       err = mkdir_yod(path, mode);
+       free(path);
+       return err;
+}
+
+static int
+yod_inop_rmdir(struct pnode *pno)
+{
+       char    *path;
+       int     err;
+
+       path = _sysio_pb_path(pno->p_base, '/');
+       if (!path)
+               return -ENOMEM;
+
+       err = rmdir_yod(path);
+       free(path);
+       return err;
+}
+
+static int
+yod_inop_symlink(struct pnode *pno, const char *data)
+{
+       char    *path;
+       int     err;
+
+       path = _sysio_pb_path(pno->p_base, '/');
+       if (!path)
+               return -ENOMEM;
+
+       err = symlink_yod(data, path);
+       free(path);
+       return err;
+}
+
+static int
+yod_inop_readlink(struct pnode *pno __IS_UNUSED, 
+                 char *buf __IS_UNUSED, 
+                 size_t bufsiz __IS_UNUSED)
+{
+
+       return -ENOSYS;
+}
+
+static int
+yod_inop_open(struct pnode *pno, int flags, mode_t mode)
+{
+       struct yod_inode *nino;
+       char    *path;
+       int     fd;
+
+       path = _sysio_pb_path(pno->p_base, '/');
+       if (!path)
+               return -ENOMEM;
+
+       /*
+        * Whether the file is already open, or not, makes no difference.
+        * Want to always give the host OS a chance to authorize in case
+        * something has changed underneath us.
+        */
+       if (flags & O_WRONLY) {
+               /*
+                * Promote write-only attempt to RW.
+                */
+               flags &= ~O_WRONLY;
+               flags |= O_RDWR;
+       }
+       fd = open_yod(path, flags, mode);
+       if (!pno->p_base->pb_ino && fd >= 0) {
+               int     err;
+
+               /*
+                * Success but we need to return an i-node.
+                */
+               err =
+                   yod_iget(pno->p_mount->mnt_fs,
+                               path,
+                               &pno->p_base->pb_ino,
+                               1);
+               if (err) {
+                       (void )close_yod(fd);
+                       if (err == -EEXIST)
+                               abort();
+                       fd = err;
+               }
+       }
+       free(path);
+       if (fd < 0)
+               return -errno;
+
+       /*
+        * Remember this new open.
+        */
+       nino = I2NI(pno->p_base->pb_ino);
+       nino->ni_nopens++;
+       assert(nino->ni_nopens);
+
+       if (nino->ni_fd >= 0) {
+               if ((nino->ni_oflags & O_RDWR) ||
+                   (flags & (O_RDONLY|O_WRONLY|O_RDWR)) == O_RDONLY) {
+                       /*
+                        * Keep existing.
+                        */
+                       (void )close_yod(fd);
+                       return 0;
+               }
+               (void )close_yod(nino->ni_fd);
+       }
+       /*
+        * Invariant; First open. Must init.
+        */
+       nino->ni_fpos = 0;
+       nino->ni_fd = fd;
+
+        /*
+         * Need to know whether we can seek on this
+         * descriptor.
+         */
+        nino->ni_seekok =
+            lseek_yod(nino->ni_fd, 0, SEEK_CUR) != 0 ? 0 : 1;
+
+       return 0;
+}
+
+static int
+yod_inop_close(struct inode *ino)
+{
+       struct yod_inode *nino = I2NI(ino);
+       int     err;
+
+       if (nino->ni_fd < 0)
+               abort();
+
+       assert(nino->ni_nopens);
+       if (--nino->ni_nopens)
+               return 0;
+
+       err = close_yod(nino->ni_fd);
+       if (err)
+               return -errno;
+
+       nino->ni_fd = -1;
+       nino->ni_fpos = 0;
+       return 0;
+}
+
+static int
+yod_inop_link(struct pnode *old, struct pnode *new)
+{
+       int     err;
+       char    *opath, *npath;
+
+       err = 0;
+
+       opath = _sysio_pb_path(old->p_base, '/');
+       npath = _sysio_pb_path(new->p_base, '/');
+       if (!(opath && npath)) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       err = link_yod(opath, npath);
+
+out:
+       if (opath)
+               free(opath);
+       if (npath)
+               free(npath);
+
+       return err;
+}
+
+static int
+yod_inop_unlink(struct pnode *pno)
+{
+       char    *path;
+       int     err = 0;
+
+       path = _sysio_pb_path(pno->p_base, '/');
+       if (!path)
+               return -ENOMEM;
+
+       /*
+        * For this driver, unlink is easy with open files. Since the
+        * file remains open to the system, too, the descriptors are still
+        * valid.
+        *
+        * Other drivers will have some difficulty here as the entry in the
+        * file system name space must be removed without sacrificing access
+        * to the file itself. In NFS this is done with a mechanism referred
+        * to as a `silly delete'. The file is moved to a temporary name
+        * (usually .NFSXXXXXX, where the X's are replaced by the PID and some
+        * unique characters) in order to simulate the proper semantic.
+        */
+       if (unlink_yod(path) != 0)
+               err = -errno;
+       free(path);
+       return err;
+}
+
+/*
+ * A helper function performing the real IO operation work.
+ *
+ * We don't really have async IO. We'll just perform the function
+ * now.
+ */
+static int
+doio(ssize_t (*f)(void *, size_t, _SYSIO_OFF_T, struct yod_inode *),
+       struct ioctx *ioctx)
+{
+       struct yod_inode *nino = I2NI(ioctx->ioctx_ino);
+
+       ioctx->ioctx_cc =
+               _sysio_doio(ioctx->ioctx_xtv, ioctx->ioctx_xtvlen,
+                           ioctx->ioctx_iov, ioctx->ioctx_iovlen,
+                           (ssize_t (*)(void *, size_t, 
+                                        _SYSIO_OFF_T, void *))f,
+                           nino);
+       if (ioctx->ioctx_cc < 0) {
+               ioctx->ioctx_errno = -ioctx->ioctx_cc;
+               ioctx->ioctx_cc = -1;
+               return -1;
+       }
+       nino->ni_fpos += ioctx->ioctx_cc;
+       ioctx->ioctx_done = 1;
+       return 0;
+}       
+
+static ssize_t
+yod_read_simple(void *buf,
+               size_t nbytes,
+               _SYSIO_OFF_T off,
+               struct yod_inode *nino)
+{
+       if (off != nino->ni_fpos) {
+               _SYSIO_OFF_T rtn;
+
+               rtn = lseek_yod(nino->ni_fd, off, SEEK_SET);
+               if (rtn < 0) 
+                       return -1;
+               nino->ni_fpos = rtn;
+       }
+       return read_yod(nino->ni_fd, buf, nbytes);
+}
+
+static int
+yod_inop_read(struct inode *ino __IS_UNUSED, struct ioctx *ioctx)
+{
+
+       return doio(yod_read_simple, ioctx);
+}
+
+static int
+yod_inop_rename(struct pnode *old, struct pnode *new)
+{
+       int     err;
+       char    *opath, *npath;
+
+       opath = _sysio_pb_path(old->p_base, '/');
+       npath = _sysio_pb_path(new->p_base, '/');
+       if (!(opath && npath)) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       err = rename_yod(opath, npath);
+
+out:
+       if (opath)
+               free(opath);
+       if (npath)
+               free(npath);
+
+       return err;
+}
+
+static ssize_t
+yod_write_simple(void *buf,
+               size_t nbytes,
+               _SYSIO_OFF_T off,
+               struct yod_inode *nino)
+{
+
+       if (off != nino->ni_fpos) {
+               _SYSIO_OFF_T rtn;
+
+               rtn = lseek_yod(nino->ni_fd, off, SEEK_SET);
+               if (rtn < 0) 
+                       return -1;
+               nino->ni_fpos = rtn;
+       }
+       return write_yod(nino->ni_fd, buf, nbytes);
+}
+
+static int
+yod_inop_write(struct inode *ino __IS_UNUSED, struct ioctx *ioctx)
+{
+
+       return doio(yod_write_simple, ioctx);
+}
+
+static _SYSIO_OFF_T
+yod_inop_pos(struct inode *ino, _SYSIO_OFF_T off)
+{
+       struct yod_inode *nino = I2NI(ino);
+       int     err;
+
+       err = lseek_yod(nino->ni_fd, off, SEEK_SET);
+       return err < 0 ? err : off;
+}
+
+static int
+yod_inop_iodone(struct ioctx *ioctxp __IS_UNUSED)
+{
+
+       /*
+        * It's always done in this driver. It completed when posted.
+        */
+       return 1;
+}
+
+static int
+yod_inop_fcntl(struct inode *ino __IS_UNUSED, int cmd, va_list ap __IS_UNUSED)
+{
+       switch (cmd) 
+       {
+       case F_DUPFD: /* do something to the ino */
+               break;
+       default:
+               errno = EINVAL; 
+               return -1;
+       }
+       return 0;
+               
+}
+
+static int
+yod_inop_mknod(struct pnode *pno __IS_UNUSED,
+                 mode_t mode __IS_UNUSED,
+                 dev_t dev __IS_UNUSED)
+{
+
+       return -ENOSYS;
+}
+
+#ifdef _HAVE_STATVFS
+static int
+yod_inop_statvfs(struct pnode *pno,
+                   struct inode *ino,
+                   struct intnl_statvfs *buf)
+{
+       char    *path;
+       int    rc;
+       struct statfs fs;
+
+       path = NULL;
+       if (!ino || I2NI(ino)->ni_fd < 0) {
+               path = _sysio_pb_path(pno->p_base, '/');
+               if (!path)
+                       return -ENOMEM;
+       }
+
+       /*
+        * The syscall interface does not support SYS_fstatvfs.
+        * Should possibly return ENOSYS, but thought it
+        * better to use SYS_fstatfs and fill in as much of
+        * the statvfs structure as possible.  This allows
+        * for more of a test of the sysio user interface.
+        */
+       rc =
+           path
+             ? statfs_yod(path, &fs)
+             : fstatfs_yod(I2NI(ino)->ni_fd, &fs);
+       if (path)
+               free(path);
+       if (rc < 0)
+               return -errno;
+
+       buf->f_bsize = fs.f_bsize;  /* file system block size */
+       buf->f_frsize = fs.f_bsize; /* file system fundamental block size */
+       buf->f_blocks = fs.f_blocks;
+       buf->f_bfree = fs.f_bfree;
+       buf->f_bavail = fs.f_bavail;
+       buf->f_files = fs.f_files;  /* Total number serial numbers */
+       buf->f_ffree = fs.f_ffree;  /* Number free serial numbers */
+       buf->f_favail = fs.f_ffree; /* Number free ser num for non-privileged*/
+       buf->f_fsid = fs.f_fsid.__val[1];
+       buf->f_flag = 0;            /* No equiv in statfs; maybe use type? */
+       buf->f_namemax = fs.f_namelen;
+       return 0;
+}
+#endif
+
+static int
+yod_inop_sync(struct inode *ino)
+{
+
+       assert(I2NI(ino)->ni_fd >= 0);
+
+       return fsync_yod(I2NI(ino)->ni_fd);
+}
+
+static int
+yod_inop_datasync(struct inode *ino)
+{
+
+       assert(I2NI(ino)->ni_fd >= 0);
+
+       return fsync_yod(I2NI(ino)->ni_fd);
+}
+
+static int
+yod_inop_ioctl(struct inode *ino __IS_UNUSED,
+                 unsigned long int request __IS_UNUSED,
+                 va_list ap __IS_UNUSED)
+{
+
+       /*
+        * I'm lazy. Maybe implemented later.
+        */
+       errno = ENOTTY;
+       return -1;
+}
+
+static void
+yod_inop_gone(struct inode *ino)
+{
+       struct yod_inode *nino = I2NI(ino);
+
+       if (nino->ni_fd)
+               (void )close(nino->ni_fd);
+       free(ino->i_private);
+}
+
+static void
+yod_fsop_gone(struct filesys *fs __IS_UNUSED)
+{
+
+       /*
+        * Do nothing. There is no private part maintained for the
+        * yod file interface. 
+        */
+}
diff --git a/libsysio/drivers/yod/fs_yod.h b/libsysio/drivers/yod/fs_yod.h
new file mode 100644 (file)
index 0000000..174b82d
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+/*
+ * Remote file system driver support.
+ */
+
+extern int _sysio_yod_init();
diff --git a/libsysio/drivers/yod/module.mk b/libsysio/drivers/yod/module.mk
new file mode 100644 (file)
index 0000000..1c2cc91
--- /dev/null
@@ -0,0 +1,10 @@
+if WITH_CPLANT_YOD
+YOD_SRCS = drivers/yod/fs_yod.c
+YOD_DRIVER_FLAGS = -DCPLANT_YOD
+else
+YOD_SRCS = 
+YOD_DRIVER_FLAGS = 
+endif
+
+# Bring yod files along in the distribution regardless
+YOD_EXTRA = include/cplant-yod.h drivers/yod/fs_yod.h drivers/yod/module.mk
diff --git a/libsysio/include/cplant-yod.h b/libsysio/include/cplant-yod.h
new file mode 100644 (file)
index 0000000..8aa4b50
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+/* 
+ * cplant yod I/O functions
+ */
+extern int chmod_yod(const char* path, mode_t);
+extern int chown_yod(const char* path, uid_t, gid_t);
+extern int stat_yod(const char *path, struct stat *sbuf);
+extern int fstat_yod(int fd, struct stat *buf);
+#ifdef _HAVE_STATVFS
+extern int statfs_yod(const char *path, struct statfs *sbuf);
+extern int fstatfs_yod(int fd, struct statfs *buf);
+#endif
+extern int mkdir_yod(const char *path, mode_t mode);
+extern int rmdir_yod(const char *path);
+extern int getdirentries_yod(int fd, char *buf, size_t nbytes, loff_t *basep);
+extern int link_yod(const char *path1,  const char *path2);
+extern int unlink_yod(const char *path);
+extern int symlink_yod(const  char *path1, const char *path2 );
+extern int rename_yod( const char *path1, const char *path2 );
+extern int open_yod(const char *fname, int flags, mode_t mode);
+extern int close_yod(int);
+extern ssize_t write_yod(int fd, const void *buff, size_t nbytes);
+extern ssize_t read_yod(int fd, void *buff, size_t nbytes);
+extern int fsync_yod(int fd);
+extern int truncate_yod(const char *path, off_t length);
+extern int ftruncate_yod(int fd, long length);
+extern off_t lseek_yod(int fd, off_t offset, int whence);
diff --git a/libsysio/include/dev.h b/libsysio/include/dev.h
new file mode 100644 (file)
index 0000000..0fe459b
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+/*
+ * Device support.
+ */
+
+/*
+ * Make a device number, composed of major and minor parts. We *assume* that
+ * the system version of a dev_t is 16 bits or more.
+ */
+#define SYSIO_MKDEV(major, minor) \
+       ((((major) & 0xff) << 8) | ((minor) & 0xff))
+
+/*
+ * Return major unit given dev number.
+ */
+#define SYSIO_MAJOR_DEV(dev) \
+       (((dev) >> 8) & 0xff)
+
+/*
+ * Return minor unit given dev number.
+ */
+#define SYSIO_MINOR_DEV(dev) \
+       ((dev) & 0xff)
+
+extern const struct inode_ops _sysio_nodev_ops;
+
+#define _sysio_nodev_inop_lookup \
+       (int (*)(struct pnode *, \
+                struct inode **, \
+                struct intent *, \
+                const char *))_sysio_do_illop
+#define _sysio_nodev_inop_getattr \
+       (int (*)(struct pnode *, \
+                struct inode *, \
+                struct intnl_stat *))_sysio_do_ebadf
+#define _sysio_nodev_inop_setattr \
+       (int (*)(struct pnode *, \
+                struct inode *, \
+                unsigned , \
+                struct intnl_stat *))_sysio_do_ebadf
+#define _sysio_nodev_getdirentries \
+       (ssize_t (*)(struct inode *, \
+                    char *, \
+                    size_t , \
+                    _SYSIO_OFF_T *))_sysio_do_illop
+#define _sysio_nodev_inop_mkdir \
+       (int (*)(struct pnode *, \
+                mode_t))_sysio_do_illop
+#define _sysio_nodev_inop_rmdir \
+       (int (*)(struct pnode *))_sysio_do_illop
+#define _sysio_nodev_inop_symlink \
+       (int (*)(struct pnode *, \
+                const char *))_sysio_do_illop
+#define _sysio_nodev_inop_readlink \
+       (int (*)(struct pnode *, \
+                char *, \
+                size_t))_sysio_do_illop
+#define _sysio_nodev_inop_open \
+       (int (*)(struct pnode *, \
+                int, \
+                mode_t))_sysio_do_enoent
+#define _sysio_nodev_inop_close \
+       (int (*)(struct inode *))_sysio_do_ebadf
+#define _sysio_nodev_inop_link \
+       (int (*)(struct pnode *, struct pnode *))_sysio_do_illop
+#define _sysio_nodev_inop_unlink \
+       (int (*)(struct pnode *))_sysio_do_illop
+#define _sysio_nodev_inop_rename \
+       (int (*)(struct pnode *, struct pnode *))_sysio_do_illop
+#define _sysio_nodev_inop_read \
+       (int (*)(struct inode *, \
+                struct ioctx *))_sysio_do_ebadf
+#define _sysio_nodev_inop_write \
+       (int (*)(struct inode *, \
+                struct ioctx *))_sysio_do_ebadf
+#define _sysio_nodev_inop_pos \
+       (_SYSIO_OFF_T (*)(struct inode *, _SYSIO_OFF_T))_sysio_do_ebadf
+#define _sysio_nodev_inop_iodone \
+       (int (*)(struct ioctx *))_sysio_do_einval
+#define _sysio_nodev_inop_fcntl \
+       (int (*)(struct inode *, \
+                int, \
+                va_list))_sysio_do_ebadf
+#define _sysio_nodev_inop_sync \
+       (int (*)(struct inode *))_sysio_do_ebadf
+#define _sysio_nodev_inop_datasync \
+       (int (*)(struct inode *))_sysio_do_ebadf
+#define _sysio_nodev_inop_ioctl \
+       (int (*)(struct inode *, \
+                unsigned long int, \
+                va_list))_sysio_do_ebadf
+#define _sysio_nodev_inop_mknod \
+       (int (*)(struct pnode *, \
+                mode_t, \
+                dev_t))_sysio_do_illop
+#ifdef _HAVE_STATVFS
+#define _sysio_nodev_inop_statvfs \
+       (int (*)(struct pnode *, \
+                struct inode *, \
+                struct intnl_statvfs *))_sysio_do_illop
+#endif
+#define _sysio_nodev_inop_gone \
+       (void (*)(struct inode *ino))_sysio_do_noop
+
+extern int _sysio_dev_init(void);
+extern dev_t _sysio_dev_alloc(void);
+extern struct inode_ops *_sysio_dev_lookup(mode_t mode, dev_t dev);
+extern int _sysio_char_dev_register(int major,
+                                   const char *name,
+                                   struct inode_ops *ops);
diff --git a/libsysio/include/file.h b/libsysio/include/file.h
new file mode 100644 (file)
index 0000000..ed15f6b
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+/*
+ * Open file support.
+ */
+
+/*
+ * A file record is maintained for each open file in the system. It holds
+ * all the info necessary to track the context and parameters for the
+ * operations that may be performed.
+ */
+struct file {
+       struct inode *f_ino;                            /* path node */
+       _SYSIO_OFF_T f_pos;                             /* current stream pos */
+       unsigned f_ref;                                 /* ref count */
+       int     f_flags;                                /* open/fcntl flags */
+};
+
+/*
+ * Reference a file record.
+ */
+#define F_REF(fil) \
+       do { \
+               (fil)->f_ref++; \
+               assert((fil)->f_ref); \
+               I_REF((fil)->f_ino); \
+       } while (0)
+
+/*
+ * Release reference to a file record.
+ */
+#define F_RELE(fil) \
+       do { \
+               struct inode *ino; \
+               \
+               assert((fil)->f_ref); \
+               (fil)->f_ref--; \
+               ino = (fil)->f_ino; \
+               if (!(fil)->f_ref) \
+                       _sysio_fgone(fil); \
+               I_RELE(ino); \
+       } while (0)
+
+/*
+ * Init file record.
+ *
+ * NB: Don't forget to take a reference to the inode too!
+ */
+#define _SYSIO_FINIT(fil, ino, flags) \
+       do { \
+               (fil)->f_ino = (ino); \
+               (fil)->f_pos = 0; \
+               (fil)->f_ref = 1; \
+               (fil)->f_flags = (flags); \
+       } while (0)
+
+struct ioctx;
+
+extern struct file *_sysio_fnew(struct inode *ino, int flags);
+extern void _sysio_fgone(struct file *fil);
+extern void _sysio_fcompletio(struct ioctx *ioctx, struct file *fil);
+extern int _sysio_fd_close(int fd);
+extern struct file *_sysio_fd_find(int fd);
+extern int _sysio_fd_set(struct file *fil, int fd);
+extern int _sysio_fd_dup2(int oldfd, int newfd);
+extern int _sysio_fd_close_all(void);
+#if ZERO_SUM_MEMORY
+extern void _sysio_fd_shutdown(void);
+#endif
diff --git a/libsysio/include/fs.h b/libsysio/include/fs.h
new file mode 100644 (file)
index 0000000..8c7e782
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+/*
+ * File system or volume support.
+ */
+
+struct filesys;
+
+struct pnode;
+struct mount;
+
+/*
+ * File system switch operations.
+ */
+struct fssw_ops {
+       int     (*fsswop_mount)(const char *source,
+                               unsigned flags,
+                               const void *data,
+                               struct pnode *tocover,
+                               struct mount **mntp);
+};
+
+/*
+ * File system switch entry record.
+ *
+ * Each available file system or volume access driver is represented by
+ * one of these switch entries in the switch.
+ */
+struct fsswent {
+       const char *fssw_name;                          /* entry name */
+       LIST_ENTRY(fsswent) fssw_link;                  /* link to next */
+       struct fssw_ops fssw_ops;                       /* operations */
+};
+
+/*
+ * Init file system switch entry record.
+ */
+#define FSSWENT_INIT(fsswent, name, ops) \
+       do { \
+               (fsswent)->fssw_name = (name); \
+               (fsswent)->fssw_ops = (ops); \
+       } while (0)
+
+struct inode;
+
+/*
+ * File system operations.
+ */
+struct filesys_ops {
+       void    (*fsop_gone)(struct filesys *);
+};
+
+/*
+ * Define the desired size of the file system record's inode table. This should
+ * probably be something fancy that tries to use up a system page, or the
+ * like. I'm not feeling adventurous right now though. It is prime though.
+ * That should help out the hash.
+ */
+#ifndef FS_ITBLSIZ
+#define FS_ITBLSIZ     503
+#endif
+
+/*
+ * Inode list head record.
+ */
+LIST_HEAD(itable_entry, inode);
+
+/*
+ * A filesys record is maintained for each active file system or volume.
+ */
+struct filesys {
+       dev_t   fs_dev;                                 /* device ID */
+       unsigned fs_ref;                                /* soft ref count */
+       unsigned fs_flags;                              /* flags (see below) */
+       struct filesys_ops fs_ops;                      /* operations */
+       void    *fs_private;                            /* driver data */
+       struct itable_entry fs_itbl[FS_ITBLSIZ];        /* inodes hash */
+       unsigned long fs_id;                            /* ID */
+       size_t  fs_bsize;                               /* block size */
+};
+
+#define FS_F_RO                        0x01                    /* read-only */
+
+/*
+ * Init file system record.
+ */
+#define FS_INIT(fs, flags, ops, private) \
+       do { \
+               size_t  __i; \
+               struct itable_entry *__head; \
+ \
+               (fs)->fs_ref = 1; \
+               (fs)->fs_flags = (flags); \
+               (fs)->fs_ops = *(ops); \
+               (fs)->fs_private = (private); \
+               __i = FS_ITBLSIZ; \
+               __head = (fs)->fs_itbl; \
+               do { \
+                       LIST_INIT(__head); \
+                       __head++; \
+               } while (--__i); \
+       } while (0)
+
+/*
+ * Reference file system record.
+ */
+#define FS_REF(fs) \
+       do { \
+               ++(fs)->fs_ref; \
+               assert((fs)->fs_ref); \
+       } while (0)
+
+/*
+ * Release reference to file system record.
+ */
+#define FS_RELE(fs) \
+       do { \
+               assert((fs)->fs_ref); \
+               if (!--(fs)->fs_ref) \
+                       _sysio_fs_gone(fs); \
+       } while (0)
+
+extern struct fsswent *_sysio_fssw_lookup(const char *name);
+extern int _sysio_fssw_register(const char *name, struct fssw_ops *ops);
+extern struct filesys * _sysio_fs_new(struct filesys_ops *ops,
+                                     unsigned mask,
+                                     void *private);
+extern void _sysio_fs_gone(struct filesys *fs);
+#if ZERO_SUM_MEMORY
+extern void _sysio_fssw_shutdown(void);
+#endif
diff --git a/libsysio/include/inode.h b/libsysio/include/inode.h
new file mode 100644 (file)
index 0000000..d6ee2ff
--- /dev/null
@@ -0,0 +1,517 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#if defined(AUTOMOUNT_FILE_NAME) && !defined(MAX_MOUNT_DEPTH)
+/*
+ * Maximum number of automounts to attempt in path traversal.
+ */
+#define MAX_MOUNT_DEPTH                64
+#endif
+
+/*
+ * Each i-node is uniquely identified by a file identifier, supplied by
+ * the relevant file system driver. The i-node number returned in the getattrs
+ * call is not always enough.
+ */
+struct file_identifier {
+    void    *fid_data;
+    size_t  fid_len;
+};
+
+struct pnode;
+struct inode;
+struct intent;
+struct intnl_dirent;
+struct intnl_stat;
+#ifdef _HAVE_STATVFS
+struct intnl_statvfs;
+#endif
+struct io_arguments;
+struct ioctx;
+
+/*
+ * Operations on i-nodes.
+ *
+ * Should this be split up into file and name space operations?
+ */
+struct inode_ops {
+    int (*inop_lookup)(struct pnode *pno,
+                       struct inode **inop,
+                       struct intent *intnt,
+                       const char *path);
+    int (*inop_getattr)(struct pnode *pno,
+                        struct inode *ino,
+                        struct intnl_stat *stbuf);
+    int (*inop_setattr)(struct pnode *pno,
+                        struct inode *ino,
+                        unsigned mask,
+                        struct intnl_stat *stbuf);
+    ssize_t (*inop_getdirentries)(struct inode *ino,
+                                 char *buf,
+                                 size_t nbytes,
+                                 _SYSIO_OFF_T *basep);
+    int (*inop_mkdir)(struct pnode *pno, mode_t mode);
+    int (*inop_rmdir)(struct pnode *pno);
+    int (*inop_symlink)(struct pnode *pno, const char *data);
+    int (*inop_readlink)(struct pnode *pno, char *buf, size_t bufsiz);
+    int (*inop_open)(struct pnode *pno, int flags, mode_t mode);
+    int (*inop_close)(struct inode *ino);
+    int (*inop_link)(struct pnode *old, struct pnode *new);
+    int (*inop_unlink)(struct pnode *pno);
+    int (*inop_rename)(struct pnode *old, struct pnode *new);
+    int (*inop_read)(struct inode *ino, struct ioctx *ioctx);
+    int (*inop_write)(struct inode *ino, struct ioctx *ioctx);
+    _SYSIO_OFF_T (*inop_pos)(struct inode *ino, _SYSIO_OFF_T off);
+    int (*inop_iodone)(struct ioctx *iocp);
+    int (*inop_fcntl)(struct inode *ino, int cmd, va_list ap);
+    int (*inop_sync)(struct inode *ino);
+    int (*inop_datasync)(struct inode *ino);
+    int (*inop_ioctl)(struct inode *ino, unsigned long int request, va_list ap);
+    int (*inop_mknod)(struct pnode *pno, mode_t mode, dev_t dev);
+#ifdef _HAVE_STATVFS
+    int (*inop_statvfs)(struct pnode *pno,
+                        struct inode *ino,
+                        struct intnl_statvfs *buf);
+#endif
+    void    (*inop_gone)(struct inode *ino);
+};
+
+/*
+ * Values for the mask to inop_setattr.
+ */
+#define SETATTR_MODE        0x01
+#define SETATTR_MTIME       0x02
+#define SETATTR_ATIME       0x04
+#define SETATTR_UID         0x08
+#define SETATTR_GID         0x10
+#define SETATTR_LEN         0x20
+
+/*
+ * An i-node record is maintained for each file object in the system.
+ */
+struct inode {
+    LIST_ENTRY(inode) i_link;                           /* FS i-nodes link */
+    unsigned
+       i_immune                        : 1,            /* immune from GC */
+       i_zombie                        : 1;            /* stale inode */
+    unsigned i_ref;                                     /* soft ref counter */
+    mode_t  i_mode;                                     /* mode (see stat.h) */
+    dev_t   i_rdev;                                    /* dev (if device) */
+    struct inode_ops i_ops;                             /* operations */
+    struct filesys *i_fs;                               /* file system ptr */
+    struct file_identifier *i_fid;                      /* file ident */
+    void    *i_private;                                 /* driver data */
+    TAILQ_ENTRY(inode) i_nodes;                         /* all i-nodes link */
+};
+
+/*
+ * Init an i-node record.
+ */
+#define I_INIT(ino, fs, mode, rdev, ops, fid, immunity, private) \
+    do { \
+        (ino)->i_immune = (immunity) ? 1 : 0; \
+        (ino)->i_zombie = 0; \
+        (ino)->i_ref = 0; \
+        (ino)->i_mode = (mode); \
+        (ino)->i_rdev = (rdev); \
+        (ino)->i_ops = *(ops); \
+        (ino)->i_fs = (fs); \
+        (ino)->i_fid = (fid); \
+        (ino)->i_private = (private); \
+    } while (0)
+
+/*
+ * Take soft reference to i-node.
+ */
+#define I_REF(ino) \
+    do { \
+        TAILQ_REMOVE(&_sysio_inodes, (ino), i_nodes); \
+        TAILQ_INSERT_TAIL(&_sysio_inodes, (ino), i_nodes); \
+        (ino)->i_ref++; \
+        assert((ino)->i_ref); \
+    } while (0)
+
+/*
+ * Release soft reference to i-node.
+ */
+#define I_RELE(ino) \
+    do { \
+        assert((ino)->i_ref); \
+       if (!--(ino)->i_ref && (ino)->i_zombie) \
+               _sysio_i_gone(ino); \
+    } while (0)
+
+/*
+ * Attempt to kill an inode.
+ */
+#define I_GONE(ino) \
+    do { \
+       _sysio_i_undead(ino); \
+       I_RELE(ino); \
+    } while (0)
+
+/*
+ * The "quick string" record (inspired by the structure of the same name
+ * from Linux) is used to pass a string without delimiters as well as useful
+ * information about the string.
+ */
+struct qstr {
+    const char *name;
+    size_t  len;
+    unsigned hashval;
+};
+
+/*
+ * A path node is an entry in a directory. It may have many aliases, one
+ * for each name space in which it occurs. This record holds the
+ * common information.
+ */
+struct pnode_base {
+    struct qstr pb_name;                                /* entry name */
+    struct inode *pb_ino;                               /* inode */
+    LIST_HEAD(, pnode_base) pb_children;                /* children if a dir */
+    LIST_ENTRY(pnode_base) pb_sibs;                     /* links to siblings */
+    LIST_ENTRY(pnode_base) pb_names;                    /* near names links */
+    LIST_HEAD(, pnode) pb_aliases;                      /* aliases */
+    struct pnode_base *pb_parent;                       /* parent */
+};
+
+/*
+ * Since a file system may be multiply mounted, in different parts of the local
+ * tree, a file system object may appear in different places. We handle that
+ * with aliases. There is one pnode for every alias the system is tracking.
+ *
+ * Name space traversal depends heavily on the interpretation of many
+ * of the fields in this structure. For that reason a detailed discussion
+ * of the various fields is given.
+ *
+ * The reference field records soft references to the record. For instance,
+ * it tracks file and directory opens. It does not track sibling references,
+ * though, as those are hard references and can be found by examining the
+ * aliases list in the base part of the node.
+ *
+ * The parent value points to the parent directory for this entry, in the
+ * *system* name space -- Not the mounted volumes. If you want to examine
+ * the moutned volume name space, use the base record.
+ *
+ * The base value points to the base path node information. It is info common
+ * to all of the aliases.
+ *
+ * The mount value points to the mount record for the rooted name space in
+ * which the alias is found. Notably, if a node is the root of a sub-tree then
+ * the mount record, among other things, indicates another node
+ * (in another sub-tree) that is covered by this one.
+ *
+ * Another sub-tree, mounted on this node, is indicated by a non-null cover.
+ * The pnode pointed to, then, is the root of the mounted sub-tree.
+ *
+ * The links list entry holds pointers to other aliases for the base path
+ * node entry.
+ *
+ * The nodes link is bookkeeping.
+ */
+struct pnode {
+    unsigned p_ref;                                     /* soft ref count */
+    struct pnode *p_parent;                             /* parent */
+    struct pnode_base *p_base;                          /* base part */
+    struct mount *p_mount;                              /* mount info */
+    struct pnode *p_cover;                              /* covering pnode */
+    LIST_ENTRY(pnode) p_links;                          /* other aliases */
+    TAILQ_ENTRY(pnode) p_nodes;                         /* all nodes links */
+};
+
+/*
+ * Reference path-tree node.
+ */
+#define P_REF(pno) \
+    do { \
+        TAILQ_REMOVE(&_sysio_pnodes, (pno), p_nodes); \
+        TAILQ_INSERT_TAIL(&_sysio_pnodes, (pno), p_nodes); \
+        (pno)->p_ref++; \
+        assert((pno)->p_ref); \
+    } while (0)
+
+/*
+ * Release reference to path-tree node.
+ */
+#define P_RELE(pno) \
+    do { \
+        assert((pno)->p_ref); \
+        --(pno)->p_ref; \
+    } while (0)
+
+/*
+ * An intent record allows callers of namei and lookup to pass some information
+ * about what they want to accomplish in the end.
+ */
+struct intent {
+    unsigned int_opmask;                
+    void    *int_arg1;
+    void    *int_arg2;
+};
+
+/*
+ * Intent operations.
+ */
+#define INT_GETATTR         0x01                        /* get attrs */
+#define INT_SETATTR         0x02                        /* set attrs */
+#define INT_UPDPARENT       0x04                        /* insert/delete */
+#define INT_OPEN            0x08                        /* open */
+#define INT_CREAT           (INT_UPDPARENT|0x10)        /* insert */
+#define INT_READLINK        0x12                        /* readlink */
+
+#define INTENT_INIT(intnt, mask, arg1, arg2) \
+    do { \
+        (intnt)->int_opmask = (mask); \
+        (intnt)->int_arg1 = (arg1); \
+        (intnt)->int_arg2 = (arg2); \
+    } while (0)
+
+/*
+ * Bundled up arguments to _sysio_path_walk.
+ */
+struct nameidata {
+    unsigned nd_flags;                                  /* flags (see below) */
+    const char *nd_path;                                /* path arg */
+    struct pnode *nd_pno;                               /* returned pnode */
+    struct pnode *nd_root;                              /* system/user root */
+    struct intent *nd_intent;                           /* intent (NULL ok) */
+    unsigned nd_slicnt;                                        /* symlink indirects */
+#ifdef AUTOMOUNT_FILE_NAME
+    unsigned nd_amcnt;                                 /* automounts */
+#endif
+};
+
+/*
+ * Values for nameidata flags field.
+ */
+#define ND_NOFOLLOW     0x01                           /* no follow symlinks */
+#define ND_NEGOK        0x02                           /* last missing is ok */
+
+#ifdef AUTOMOUNT_FILE_NAME
+#define _ND_INIT_AUTOMOUNT(nd) ((nd)->nd_amcnt = 0)
+#else
+#define _ND_INIT_AUTOMOUNT(nd)
+#endif
+
+#define _ND_INIT_OTHERS(nd) \
+    _ND_INIT_AUTOMOUNT(nd)
+
+/*
+ * Init nameidata record.
+ */
+#define ND_INIT(nd, flags, path, root, intnt) \
+    do { \
+       (nd)->nd_flags = (flags); \
+        (nd)->nd_path = (path); \
+        (nd)->nd_pno = NULL; \
+        (nd)->nd_root = (root); \
+        (nd)->nd_intent = (intnt); \
+        (nd)->nd_slicnt = 0; \
+       _ND_INIT_OTHERS(nd); \
+    } while (0)
+
+/*
+ * IO completion callback record.
+ */
+struct ioctx_callback {
+    TAILQ_ENTRY(ioctx_callback) iocb_next;             /* list link */
+    void    (*iocb_f)(struct ioctx *, void *);         /* cb func */
+    void    *iocb_data;                                /* cb data */
+};
+
+/*
+ * All IO internally is done with an asynchronous mechanism. This record
+ * holds the completion information. It's too big :-(
+ */
+struct ioctx {
+    LIST_ENTRY(ioctx) ioctx_link;                       /* AIO list link */
+    unsigned
+        ioctx_fast                      : 1,           /* from stack space */
+       ioctx_done                      : 1,            /* transfer complete */
+       ioctx_write                     : 1;            /* op is a write */
+    ioid_t  ioctx_id;                                   /* unique ident */
+    struct inode *ioctx_ino;                            /* i-node */
+    const struct iovec *ioctx_iov;                      /* scatter/gather vec */
+    size_t  ioctx_iovlen;                               /* iovec length */
+    const struct intnl_xtvec *ioctx_xtv;                /* extents */
+    size_t  ioctx_xtvlen;                               /* xtv length */
+    ssize_t ioctx_cc;                                   /* rtn char count */
+    int ioctx_errno;                                    /* error number */
+    TAILQ_HEAD(, ioctx_callback) ioctx_cbq;             /* callback queue */
+    void *ioctx_private;                               /* driver data */
+};
+
+/*
+ * Init IO context record.
+ */
+#define IOCTX_INIT(ioctx, fast, id, wr, ino, iov, iovlen, xtv, xtvlen) \
+    do { \
+       (ioctx)->ioctx_fast = (fast); \
+       (ioctx)->ioctx_done = 0; \
+       (ioctx)->ioctx_write = (wr) ? 1 : 0; \
+        (ioctx)->ioctx_id = (id); \
+        (ioctx)->ioctx_ino = (ino); \
+        (ioctx)->ioctx_iov = (iov); \
+        (ioctx)->ioctx_iovlen = (iovlen); \
+        (ioctx)->ioctx_xtv = (xtv); \
+        (ioctx)->ioctx_xtvlen = (xtvlen); \
+        (ioctx)->ioctx_cc = 0; \
+        (ioctx)->ioctx_errno = 0; \
+        TAILQ_INIT(&(ioctx)->ioctx_cbq); \
+        (ioctx)->ioctx_private = NULL; \
+    } while (0)
+
+/*
+ * Return whether a pnode/inode is on a read-only mount or file system.
+ */
+#define IS_RDONLY(pno, ino) \
+       ((((struct pnode *)(pno)) && \
+         ((((struct pnode *)(pno))->p_mount->mnt_flags & MOUNT_F_RO) || \
+          (((struct pnode *)(pno))->p_base->pb_ino && \
+           (((struct pnode *)(pno))->p_base->pb_ino->i_fs->fs_flags & \
+            FS_F_RO)))) || \
+        (((struct inode *)(ino)) && \
+         (((struct inode *)(ino))->i_fs->fs_flags & FS_F_RO)))
+
+extern struct pnode *_sysio_root;
+
+extern TAILQ_HEAD(inodes_head, inode) _sysio_inodes;
+extern TAILQ_HEAD(pnodes_head, pnode) _sysio_pnodes;
+
+extern int _sysio_i_init(void);
+#if ZERO_SUM_MEMORY
+extern void _sysio_i_shutdown(void);
+#endif
+extern struct inode *_sysio_i_new(struct filesys *fs,
+                                  struct file_identifier *fid,
+                                  mode_t type,
+                                  dev_t rdev,
+                                 unsigned immunity,
+                                  struct inode_ops *ops,
+                                  void *private);
+extern struct inode *_sysio_i_find(struct filesys *fs,
+                                   struct file_identifier *fid);
+extern void _sysio_i_gone(struct inode *ino);
+extern void _sysio_i_undead(struct inode *ino);
+extern int _sysio_p_find_alias(struct pnode *parent,
+                               struct qstr *name,
+                               struct pnode **pnop);
+extern int _sysio_p_validate(struct pnode *pno,
+                             struct intent *intnt,
+                             const char *path);
+extern struct pnode_base *_sysio_pb_new(struct qstr *name,
+                                        struct pnode_base *parent,
+                                        struct inode *ino);
+extern void _sysio_pb_gone(struct pnode_base *pb);
+extern struct pnode *_sysio_p_new_alias(struct pnode *parent,
+                                        struct pnode_base *pb,
+                                        struct mount *mnt);
+extern void _sysio_p_gone(struct pnode *pno);
+extern size_t _sysio_p_prune(struct pnode *root);
+extern int _sysio_p_kill_all(struct pnode *root);
+extern char *_sysio_pb_path(struct pnode_base *pb, char separator);
+extern int _sysio_setattr(struct pnode *pno,
+                         struct inode *ino,
+                         unsigned mask,
+                         struct intnl_stat *stbuf);
+extern void _sysio_do_noop(void);
+extern void _sysio_do_illop(void);
+extern int _sysio_do_ebadf(void);
+extern int _sysio_do_einval(void);
+extern int _sysio_do_enoent(void);
+extern int _sysio_do_espipe(void);
+extern int _sysio_do_eisdir(void);
+extern int _sysio_do_enosys(void);
+extern int _sysio_path_walk(struct pnode *parent, struct nameidata *nd);
+#ifdef AUTOMOUNT_FILE_NAME
+extern void _sysio_next_component(const char *path, struct qstr *name);
+#endif
+extern int _sysio_namei(struct pnode *pno,
+                        const char *path,
+                        unsigned flags,
+                        struct intent *intnt,
+                        struct pnode **pnop);
+extern int _sysio_p_chdir(struct pnode *pno);
+extern int _sysio_ioctx_init(void);
+extern void _sysio_ioctx_enter(struct ioctx *ioctx);
+extern struct ioctx *_sysio_ioctx_new(struct inode *ino,
+                                     int wr,
+                                      const struct iovec *iov,
+                                     size_t iovlen,
+                                      const struct intnl_xtvec *xtv,
+                                     size_t xtvlen);
+extern int _sysio_ioctx_cb(struct ioctx *ioctx,
+                          void (*f)(struct ioctx *, void *),
+                          void *data);
+extern void _sysio_ioctx_cb_free(struct ioctx_callback *cb);
+extern struct ioctx *_sysio_ioctx_find(ioid_t id);
+extern ssize_t _sysio_ioctx_wait(struct ioctx *ioctx);
+extern void _sysio_ioctx_complete(struct ioctx *ioctx);
+extern ssize_t _sysio_validx(const struct intnl_xtvec *xtv, size_t xtvlen,
+                            const struct iovec *iov, size_t iovlen,
+                            _SYSIO_OFF_T limit);
+extern ssize_t _sysio_enumerate_extents(const struct intnl_xtvec *xtv,
+                                       size_t xtvlen,
+                                       const struct iovec *iov,
+                                       size_t iovlen,
+                                       ssize_t (*f)(const struct iovec *,
+                                                    int,
+                                                    _SYSIO_OFF_T,
+                                                    ssize_t,
+                                                    void *),
+                                       void *arg);
+extern ssize_t _sysio_enumerate_iovec(const struct iovec *iov,
+                                     size_t count,
+                                     _SYSIO_OFF_T off,
+                                     ssize_t limit,
+                                     ssize_t (*f)(void *,
+                                                  size_t,
+                                                  _SYSIO_OFF_T,
+                                                  void *),
+                                     void *arg);
+extern ssize_t _sysio_doio(const struct intnl_xtvec *xtv, size_t xtvlen,
+                          const struct iovec *iov, size_t iovlen,
+                          ssize_t (*f)(void *, size_t, _SYSIO_OFF_T, void *),
+                          void *arg);
+extern int _sysio_open(struct pnode *pno, int flags, mode_t mode);
diff --git a/libsysio/include/module.mk b/libsysio/include/module.mk
new file mode 100644 (file)
index 0000000..ce1c427
--- /dev/null
@@ -0,0 +1,4 @@
+INCLUDE_EXTRA = include/dev.h include/file.h include/fs.h \
+       include/inode.h include/mount.h include/sysio.h \
+       include/sysio-symbols.h include/cplant-yod.h \
+       include/module.mk include/xtio.h
diff --git a/libsysio/include/mount.h b/libsysio/include/mount.h
new file mode 100644 (file)
index 0000000..24f631d
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+/*
+ * Mount support.
+ */
+
+struct filesys;
+struct pnode;
+
+/*
+ * Each file system may be mounted multiple times and in various places
+ * in the name space. The mount record maintains the binding information
+ * between the system name space and the file system's.
+ */
+struct mount {
+       struct filesys *mnt_fs;                         /* file system */
+       unsigned mnt_flags;                             /* flags (see below) */
+       struct pnode *mnt_root;                         /* fs sub-tree root */
+       struct pnode *mnt_covers;                       /* covered pnode */
+       LIST_ENTRY(mount) mnt_link;                     /* link to next */
+};
+
+/*
+ * Mount flags definitions.
+ */
+#define MOUNT_F_RO             0x01                    /* read-only */
+#ifdef AUTOMOUNT_FILE_NAME
+#define MOUNT_F_AUTO           0x02                    /* automount enabled */
+#endif
+
+#ifdef AUTOMOUNT_FILE_NAME
+extern struct qstr _sysio_mount_file_name;
+#endif
+
+struct pnode_base;
+
+extern int _sysio_mount_init(void);
+extern int _sysio_do_mount(struct filesys *fs,
+                          struct pnode_base *rootpb,
+                          unsigned flags,
+                          struct pnode *tocover,
+                          struct mount **mntp);
+extern int _sysio_do_unmount(struct mount *fs);
+extern int _sysio_mount_root(const char *source,
+                            const char *type,
+                            unsigned flags,
+                            const void *data);
+extern int _sysio_mount(struct pnode *cwd,
+                       const char *source,
+                       const char *target,
+                       const char *filesystemtype,
+                       unsigned long mountflags,
+                       const void *data);
+extern int _sysio_unmount_all(void);
+#ifdef AUTOMOUNT_FILE_NAME
+extern int _sysio_automount(struct pnode *mntpno);
+#endif
diff --git a/libsysio/include/namespace.h b/libsysio/include/namespace.h
new file mode 100644 (file)
index 0000000..23c1f78
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+/* 
+ * Boot time namespace assembly function
+ */
+extern int run_cmds(char *buf);
+
diff --git a/libsysio/include/sysio-symbols.h b/libsysio/include/sysio-symbols.h
new file mode 100644 (file)
index 0000000..4b7cf56
--- /dev/null
@@ -0,0 +1,26 @@
+#if defined(HAVE_ASM_WEAK_DIRECTIVE) || defined(HAVE_ASM_WEAKEXT_DIRECTIVE)
+#define HAVE_WEAK_SYMBOLS
+#endif
+
+#define STRINGOF(x) #x
+
+/*
+ * Define alias, asym, as a strong alias for symbol, sym.
+ */
+#define sysio_sym_strong_alias(sym, asym) \
+  extern __typeof(sym) asym __attribute__((alias(STRINGOF(sym))));
+
+#ifdef HAVE_WEAK_SYMBOLS
+
+/*
+ * Define alias, asym, as a strong alias for symbol, sym.
+ */
+#define sysio_sym_weak_alias(sym, asym) \
+  extern __typeof(sym) asym __attribute__((weak, alias(STRINGOF(sym))));
+#else /* !defined(HAVE_ASM_WEAK_DIRECTIVE) */
+
+/*
+ * Weak symbols not supported. Make it a strong alias then.
+ */
+#define sysio_sym_weak_alias(sym, asym) sysio_sym_strong_alias(sym, asym)
+#endif
diff --git a/libsysio/include/sysio.h b/libsysio/include/sysio.h
new file mode 100644 (file)
index 0000000..fb05d75
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2004 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+/*
+ * System IO common information.
+ */
+
+#include <limits.h>
+#include <stdarg.h>
+
+#ifndef _IOID_T_DEFINED
+#define _IOID_T_DEFINED
+/*
+ * FIXME:
+ *
+ * This section about ioid_t and it's failure belong in <sys/types.h>
+ */
+typedef void *ioid_t;
+
+#define IOID_FAIL                      0
+#endif
+
+#if !defined(__IS_UNUSED) && defined(__GNUC__)
+#define __IS_UNUSED    __attribute__ ((unused))
+#else
+#define __IS_UNUSED
+#endif
+
+#ifndef PATH_SEPARATOR
+/*
+ * Path separator.
+ */
+#define PATH_SEPARATOR                 '/'
+#endif
+
+#ifndef MAX_SYMLINK
+/*
+ * Max recursion depth allowed when resoving symbolic links.
+ */
+#define MAX_SYMLINK                    250
+#endif
+
+#ifndef _LARGEFILE64_SOURCE
+/*
+ * Not glibc I guess. Define this ourselves.
+ */
+#define _LARGEFILE64_SOURCE            0
+#endif
+
+/*
+ * Define internal file-offset type and it's maximum value.
+ */
+#if _LARGEFILE64_SOURCE
+#define _SYSIO_OFF_T                   off64_t
+#ifdef LLONG_MAX
+#define _SYSIO_OFF_T_MAX               (LLONG_MAX)
+#else
+/*
+ * Don't have LLONG_MAX before C99. We'll need to define it ourselves.
+ */
+#define _SYSIO_OFF_T_MAX               (9223372036854775807LL)
+#endif
+#else
+#define _SYSIO_OFF_T                   off_t
+#define _SYSIO_OFF_T_MAX               LONG_MAX
+#endif
+
+/*
+ * Internally, all directory entries are carried in the 64-bit capable
+ * structure.
+ */
+#if _LARGEFILE64_SOURCE
+#define intnl_dirent dirent64
+#else
+#define intnl_dirent dirent
+#endif
+struct dirent;
+
+/*
+ * Internally, all file status is carried in the 64-bit capable
+ * structure.
+ */
+#if _LARGEFILE64_SOURCE
+#define intnl_stat stat64
+#else
+#define intnl_stat stat
+#endif
+struct stat;
+
+#ifdef _HAVE_STATVFS
+#if _LARGEFILE64_SOURCE
+#define intnl_statvfs statvfs64
+#else
+#define intnl_statvfs statvfs
+#define INTNL_STATVFS_IS_NATURAL       1
+#endif
+struct statvfs;
+struct intnl_statvfs;
+#endif
+
+/*
+ * Internally, all file status is carried in the 64-bit capable
+ * structure.
+ */
+#if _LARGEFILE64_SOURCE
+#define intnl_xtvec xtvec64
+#else
+#define intnl_xtvec xtvec
+#endif
+struct intnl_xtvec;
+
+struct iovec;
+
+struct utimbuf;
+
+struct intnl_stat;
+
+struct pnode;
+
+extern struct pnode *_sysio_cwd;
+
+extern mode_t _sysio_umask;
+
+extern int _sysio_init(void);
+extern void _sysio_shutdown(void);
+extern int _sysio_boot(const char *buf);
+
+/*
+ * SYSIO name label macros
+ */
+#define XPREPEND(p,x) p ## x
+#define PREPEND(p,x) XPREPEND(p,x)
+#define SYSIO_LABEL_NAMES 0
+#if SYSIO_LABEL_NAMES
+#define SYSIO_INTERFACE_NAME(x) PREPEND(sysio__, x)
+#else
+#define SYSIO_INTERFACE_NAME(x) x
+#endif
+
+/*
+ * The following should be defined by the system includes, and probably are,
+ * but it's not illegal to have multiple externs, so long as they are the
+ * same. It helps when building the library in a standalone fashion.
+ */
+extern int SYSIO_INTERFACE_NAME(access)(const char *path, int amode);
+extern int SYSIO_INTERFACE_NAME(chdir)(const char *path);
+extern int SYSIO_INTERFACE_NAME(chmod)(const char *path, mode_t mode);
+extern int SYSIO_INTERFACE_NAME(fchmod)(int fd, mode_t mode);
+extern int SYSIO_INTERFACE_NAME(chown)(const char *path, uid_t owner,
+                                      gid_t group);
+extern int SYSIO_INTERFACE_NAME(fchown)(int fd, uid_t owner, gid_t group);
+extern int SYSIO_INTERFACE_NAME(close)(int d);
+extern int SYSIO_INTERFACE_NAME(dup)(int oldfd);
+extern int SYSIO_INTERFACE_NAME(dup2)(int oldfd, int newfd);
+extern int SYSIO_INTERFACE_NAME(fcntl)(int fd, int cmd, ...);
+extern int SYSIO_INTERFACE_NAME(fstat)(int fd, struct stat *buf);
+extern int SYSIO_INTERFACE_NAME(fsync)(int fd);
+extern char *SYSIO_INTERFACE_NAME(getcwd)(char *buf, size_t size);
+extern off_t SYSIO_INTERFACE_NAME(lseek)(int fd, off_t offset, int whence);
+#if _LARGEFILE64_SOURCE
+extern off64_t SYSIO_INTERFACE_NAME(lseek64)(int fd, off64_t offset, 
+                                            int whence);
+#endif
+extern int SYSIO_INTERFACE_NAME(lstat)(const char *path, struct stat *buf);
+#ifdef BSD
+extern int SYSIO_INTERFACE_NAME(getdirentries)(int fd, char *buf, int nbytes , 
+                                              long *basep);
+#else
+extern ssize_t SYSIO_INTERFACE_NAME(getdirentries)(int fd, char *buf, 
+                                                  size_t nbytes, off_t *basep);
+#if _LARGEFILE64_SOURCE
+extern ssize_t SYSIO_INTERFACE_NAME(getdirentries64)(int fd,
+                                                    char *buf,
+                                                    size_t nbytes,
+                                                    off64_t *basep);
+#endif
+#endif
+extern int SYSIO_INTERFACE_NAME(mkdir)(const char *path, mode_t mode);
+extern int SYSIO_INTERFACE_NAME(open)(const char *path, int flag, ...);
+#if _LARGEFILE64_SOURCE
+extern int SYSIO_INTERFACE_NAME(open64)(const char *path, int flag, ...);
+#endif
+extern int SYSIO_INTERFACE_NAME(creat)(const char *path, mode_t mode);
+#if _LARGEFILE64_SOURCE
+extern int SYSIO_INTERFACE_NAME(creat64)(const char *path, mode_t mode);
+#endif
+extern int SYSIO_INTERFACE_NAME(stat)(const char *path, struct stat *buf);
+#if _LARGEFILE64_SOURCE
+extern int SYSIO_INTERFACE_NAME(stat64)(const char *path, struct stat64 *buf);
+#endif
+#ifdef _HAVE_STATVFS
+extern int SYSIO_INTERFACE_NAME(statvfs)(const char *path, struct statvfs *buf);
+#if _LARGEFILE64_SOURCE
+extern int SYSIO_INTERFACE_NAME(statvfs64)(const char *path, 
+                               struct statvfs64 *buf);
+#endif
+extern int SYSIO_INTERFACE_NAME(fstatvfs)(int fd, struct statvfs *buf);
+#if _LARGEFILE64_SOURCE
+extern int SYSIO_INTERFACE_NAME(fstatvfs64)(int fd, struct statvfs64 *buf);
+#endif
+#endif
+extern int SYSIO_INTERFACE_NAME(truncate)(const char *path, off_t length);
+#if _LARGEFILE64_SOURCE
+extern int SYSIO_INTERFACE_NAME(truncate64)(const char *path, off64_t length);
+#endif
+extern int SYSIO_INTERFACE_NAME(ftruncate)(int fd, off_t length);
+#if _LARGEFILE64_SOURCE
+extern int SYSIO_INTERFACE_NAME(ftruncate64)(int fd, off64_t length);
+#endif
+extern int SYSIO_INTERFACE_NAME(rmdir)(const char *path);
+extern int SYSIO_INTERFACE_NAME(symlink)(const char *path1, const char *path2);
+extern int SYSIO_INTERFACE_NAME(readlink)(const char *path,
+                               char *buf,
+                               size_t bufsiz);
+extern int SYSIO_INTERFACE_NAME(link)(const char *oldpath, const char *newpath);
+extern int SYSIO_INTERFACE_NAME(unlink)(const char *path);
+extern int SYSIO_INTERFACE_NAME(rename)(const char *oldpath, 
+                                       const char *newpath);
+extern int SYSIO_INTERFACE_NAME(fdatasync)(int fd);
+extern int SYSIO_INTERFACE_NAME(ioctl)(int fd, unsigned long request, ...);
+extern mode_t SYSIO_INTERFACE_NAME(umask)(mode_t mask);
+extern int SYSIO_INTERFACE_NAME(iodone)(ioid_t ioid);
+extern ssize_t SYSIO_INTERFACE_NAME(iowait)(ioid_t ioid);
+extern ioid_t SYSIO_INTERFACE_NAME(ipreadv)(int fd, const struct iovec *iov, 
+                                  size_t count, off_t offset);
+#if _LARGEFILE64_SOURCE
+extern ioid_t SYSIO_INTERFACE_NAME(ipread64v)(int fd, const struct iovec *iov, 
+                                             size_t count, off64_t offset);
+#endif
+extern ioid_t SYSIO_INTERFACE_NAME(ipread)(int fd, void *buf, size_t count, 
+                                          off_t offset);
+#if _LARGEFILE64_SOURCE
+extern ioid_t SYSIO_INTERFACE_NAME(ipread64)(int fd, void *buf, size_t count, 
+                                            off64_t offset);
+#endif
+extern ssize_t SYSIO_INTERFACE_NAME(preadv)(int fd, const struct iovec *iov, 
+                                           size_t count, off_t offset);
+#if _LARGEFILE64_SOURCE
+extern ssize_t SYSIO_INTERFACE_NAME(pread64v)(int fd, const struct iovec *iov, 
+                                             size_t count, off64_t offset);
+#endif
+extern ssize_t SYSIO_INTERFACE_NAME(pread)(int fd, void *buf, size_t count, 
+                                          off_t offset);
+#if _LARGEFILE64_SOURCE
+extern ssize_t SYSIO_INTERFACE_NAME(pread64)(int fd, void *buf, size_t count, 
+                                            off64_t offset);
+#endif
+extern ioid_t SYSIO_INTERFACE_NAME(ireadv)(int fd, const struct iovec *iov, 
+                                          int count);
+extern ioid_t SYSIO_INTERFACE_NAME(iread)(int fd, void *buf, size_t count);
+extern ssize_t SYSIO_INTERFACE_NAME(readv)(int fd, const struct iovec *iov, 
+                                          int count);
+extern ssize_t SYSIO_INTERFACE_NAME(read)(int fd, void *buf, size_t count);
+extern ioid_t SYSIO_INTERFACE_NAME(ipwritev)(int fd, const struct iovec *iov, 
+                                            size_t count, off_t offset);
+#if _LARGEFILE64_SOURCE
+extern ioid_t SYSIO_INTERFACE_NAME(ipwrite64v)(int fd, const struct iovec *iov, 
+                                              size_t count, off64_t offset);
+#endif
+extern ioid_t SYSIO_INTERFACE_NAME(ipwrite)(int fd, const void *buf, 
+                                           size_t count, off_t offset);
+#if _LARGEFILE64_SOURCE
+extern ioid_t SYSIO_INTERFACE_NAME(ipwrite64)(int fd, const void *buf, 
+                                             size_t count, off64_t offset);
+#endif
+extern ssize_t SYSIO_INTERFACE_NAME(pwritev)(int fd, const struct iovec *iov, 
+                                            size_t count, off_t offset);
+#if _LARGEFILE64_SOURCE
+extern ssize_t SYSIO_INTERFACE_NAME(pwrite64v)(int fd, const struct iovec *iov, 
+                                              size_t count, off64_t offset);
+#endif
+extern ssize_t SYSIO_INTERFACE_NAME(pwrite)(int fd, const void *buf, 
+                                           size_t count, off_t offset);
+#if _LARGEFILE64_SOURCE
+extern ssize_t SYSIO_INTERFACE_NAME(pwrite64)(int fd, const void *buf, 
+                                             size_t count, off64_t offset);
+#endif
+extern ioid_t SYSIO_INTERFACE_NAME(iwritev)(int fd, 
+                                           const struct iovec *iov, 
+                                           int count);
+extern ioid_t SYSIO_INTERFACE_NAME(iwrite)(int fd, const void *buf, 
+                                          size_t count);
+extern ssize_t SYSIO_INTERFACE_NAME(writev)(int fd, const struct iovec *iov, 
+                                           int count);
+extern ssize_t SYSIO_INTERFACE_NAME(write)(int fd, const void *buf, 
+                                          size_t count);
+extern int SYSIO_INTERFACE_NAME(mknod)(const char *path, 
+                                      mode_t mode, dev_t dev);
+extern int SYSIO_INTERFACE_NAME(utime)(const char *path, 
+                                      const struct utimbuf *buf);
+extern int SYSIO_INTERFACE_NAME(mount)(const char *source, const char *target,
+                                      const char *filesystemtype,
+                                      unsigned long mountflags,
+                                      const void *data);
+extern int SYSIO_INTERFACE_NAME(umount)(const char *target);
+
+/* for debugging */
+#if 0
+#define ASSERT(cond)                                                   \
+       if (!(cond)) {                                                  \
+               printf("ASSERTION(" #cond ") failed: " __FILE__ ":"     \
+                       __FUNCTION__ ":%d\n", __LINE__);                \
+               abort();                                                \
+       }
+
+#define ERROR(fmt, a...)                                               \
+       do {                                                            \
+               printf("ERROR(" __FILE__ ":%d):" fmt, __LINE__, ##a);   \
+       while(0)
+
+#else
+#define ERROR(fmt)     do{}while(0)
+#define ASSERT         do{}while(0)
+#endif
+
+/*
+ * SYSIO interface frame macros
+ *
+ * + DISPLAY_BLOCK; Allocates storage on the stack for use by the set of
+ *     macros.
+ * + ENTER; Performs entry point work
+ * + RETURN; Returns a value and performs exit point work
+ *
+ * NB: For RETURN, the arguments are the return value and value for errno.
+ * If the value for errno is non-zero then that value, *negated*, is set
+ * into errno.
+ */
+#define SYSIO_INTERFACE_DISPLAY_BLOCK \
+       int _saved_errno;
+#define SYSIO_INTERFACE_ENTER \
+       do { \
+               _saved_errno = errno; \
+               SYSIO_ENTER; \
+       } while (0)
+#define SYSIO_INTERFACE_RETURN(rtn, err) \
+       do { \
+               SYSIO_LEAVE; \
+               errno = (err) ? -(err) : _saved_errno; \
+               return (rtn); \
+       } while(0) 
+
+/* syscall enter/leave hook functions  */
+#if 0
+extern void _sysio_sysenter();
+extern void _sysio_sysleave();
+
+#define SYSIO_ENTER                                                    \
+       do {                                                            \
+               _sysio_sysenter();                                      \
+       } while(0)
+
+#define SYSIO_LEAVE                                                    \
+       do {                                                            \
+               _sysio_sysleave();                                      \
+       } while(0)
+#else
+#define SYSIO_ENTER
+#define SYSIO_LEAVE
+
+#endif
diff --git a/libsysio/include/xtio.h b/libsysio/include/xtio.h
new file mode 100644 (file)
index 0000000..765aaf8
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2004 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+/*
+ * Structure for strided I/O.
+ */
+struct xtvec {
+#ifndef __USE_FILE_OFFSET64
+       __off_t xtv_off;                        /* Stride/Extent offset. */
+#else
+       __off64_t xtv_off;                      /* Stride/Extent offset. */
+#endif
+       size_t  xtv_len;                        /* Stride/Extent length. */
+};
+
+#ifdef __USE_LARGEFILE64
+struct xtvec64 {
+       __off64_t xtv_off;                      /* Stride/Extent offset. */
+       size_t  xtv_len;                        /* Stride/Extent length. */
+};
+#endif
+
+extern ioid_t SYSIO_INTERFACE_NAME(ireadx)(int fd,
+                                          const struct iovec *iov, 
+                                          size_t iov_count,
+                                          const struct xtvec *xtv, 
+                                          size_t xtv_count);
+#ifdef __USE_LARGEFILE64
+extern ioid_t SYSIO_INTERFACE_NAME(iread64x)(int fd,
+                                            const struct iovec *iov, 
+                                            size_t iov_count,
+                                            const struct xtvec64 *xtv, 
+                                            size_t xtv_count);
+#endif
+extern ssize_t SYSIO_INTERFACE_NAME(readx)(int fd,
+                                          const struct iovec *iov, 
+                                          size_t iov_count,
+                                          const struct xtvec *xtv, 
+                                          size_t xtv_count);
+#ifdef __USE_LARGEFILE64
+extern ssize_t SYSIO_INTERFACE_NAME(read64x)(int fd,
+                                            const struct iovec *iov, 
+                                            size_t iov_count,
+                                            const struct xtvec64 *xtv, 
+                                            size_t xtv_count);
+#endif
+extern ioid_t SYSIO_INTERFACE_NAME(iwritex)(int fd,
+                                           const struct iovec *iov, 
+                                           size_t iov_count,
+                                           const struct xtvec *xtv, 
+                                           size_t xtv_count);
+#ifdef __USE_LARGEFILE64
+extern ioid_t SYSIO_INTERFACE_NAME(iwrite64x)(int fd,
+                                             const struct iovec *iov, 
+                                             size_t iov_count,
+                                             const struct xtvec64 *xtv, 
+                                             size_t xtv_count);
+#endif
+extern ssize_t SYSIO_INTERFACE_NAME(writex)(int fd,
+                                           const struct iovec *iov, 
+                                           size_t iov_count,
+                                           const struct xtvec *xtv, 
+                                           size_t xtv_count);
+#ifdef __USE_LARGEFILE64
+extern ssize_t SYSIO_INTERFACE_NAME(write64x)(int fd,
+                                             const struct iovec *iov, 
+                                             size_t iov_count,
+                                             const struct xtvec64 *xtv, 
+                                             size_t xtv_count);
+#endif
diff --git a/libsysio/misc/gdb-libsysio b/libsysio/misc/gdb-libsysio
new file mode 100644 (file)
index 0000000..dd3f613
--- /dev/null
@@ -0,0 +1,127 @@
+#    This Cplant(TM) source code is the property of Sandia National
+#    Laboratories.
+#
+#    This Cplant(TM) source code is copyrighted by Sandia National
+#    Laboratories.
+#
+#    The redistribution of this Cplant(TM) source code is subject to the
+#    terms of the GNU Lesser General Public License
+#    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+#
+#    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+#    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+#    license for use of this work by or on behalf of the US Government.
+#    Export of this program may require a license from the United States
+#    Government.
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+# 
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+# 
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# Questions or comments about this library should be sent to:
+#
+# Lee Ward
+# Sandia National Laboratories, New Mexico
+# P.O. Box 5800
+# Albuquerque, NM 87185-1110
+#
+# lee@sandia.gov
+
+#
+# Useful commands for debugging libsysio in gdb
+#
+
+define x_dump_pbnode
+       printf "%p: ", $arg0
+       if $arg0->pb_name.name
+               printf " \"%s\"", \
+                 $arg0->pb_name.name
+       else
+               printf " <NULL>"
+       end
+       printf " aliases:["
+       set $x_p = $arg0->pb_aliases.lh_first
+       while $x_p
+               printf "<%p r:%d mnt:%p>", \
+                 $x_p, \
+                 $x_p->p_ref, \
+                 $x_p->p_mount
+               set $x_p = $x_p->p_links.le_next
+       end
+       printf "]\n"
+end
+document x_dump_pbnode
+Dump path-base node and it's aliases
+
+Usage: x_dump_pbnode <pbnode>
+end
+
+define __x_dump_pnode
+       printf "%spnode %p, mount %p, base: ", $arg0, $arg1, $arg1->p_mount
+       x_dump_pbnode $arg1->p_base
+end
+
+define x_dump_pnode
+       __x_dump_pnode "" $arg0
+end
+document x_dump_pnode
+Dump path node information
+
+Usage: x_dump_pnode <pnode>
+end
+
+define x_dump_mount
+       printf "MOUNT %p: root pnode %p, covers %p\n", \
+           $arg0, $arg0->mnt_root, $arg0->mnt_covers
+       set $_x_dump_mount_var_pno = _sysio_pnodes->tqh_first
+       while $_x_dump_mount_var_pno != 0
+printf "%p, %p\n", $_x_dump_mount_var_pno, $arg0
+               if $_x_dump_mount_var_pno->p_mount == $arg0
+                       __x_dump_pnode " " $_x_dump_mount_var_pno
+               end
+               set $_x_dump_mount_var_pno = \
+                   $_x_dump_mount_var_pno->p_nodes.tqe_next
+       end
+end
+document x_dump_mount
+Dump single mount record information
+
+Usage: x_dump_mount <mnt>
+end
+
+define x_dump_mounts
+       set $__x_dump_mounts_var_mnt = mounts.lh_first
+       while $__x_dump_mounts_var_mnt
+               x_dump_mount $__x_dump_mounts_var_mnt
+               set $__x_dump_mounts_var_mnt = \
+                   $__x_dump_mounts_var_mnt->mnt_link.le_next
+       end
+end
+document x_dump_mounts
+Dump the contents of the libsysio mount table
+
+Usage: x_dump_mounts
+end
+
+define x_dump_pnodes
+       set $_x_dump_pnodes_var_pno = _sysio_pnodes.tqh_first
+       while $_x_dump_pnodes_var_pno
+               x_dump_pnode $_x_dump_pnodes_var_pno
+               set $_x_dump_pnodes_var_pno = \
+                   $_x_dump_pnodes_var_pno->p_nodes.tqe_next
+       end
+end
+
+br _sysio_unmount_all
+run -r /tmp/lee foo bar
+x_dump_pnodes
diff --git a/libsysio/misc/init-env.sh b/libsysio/misc/init-env.sh
new file mode 100644 (file)
index 0000000..167f421
--- /dev/null
@@ -0,0 +1,38 @@
+#
+# Source this file. It will craft a usable name space for your testing.
+#
+# Lee; Sun Feb  8 18:02:16 EST 2004
+#
+# Note: We really should support symlinks someday.
+#
+unset _root_flags
+unset _extras
+if [ "x${SYSIO_AUTOMOUNT}" == "xyes" ]; then
+       _root_flags="2"
+       #
+       # Add a /auto directory for automounted file systems. We
+       # craft one automount that mounts /usr/home from the native
+       # file system. Further automounts in the sub-mounts are not enabled.
+       #
+       _extras=" \
+               {mnt,   dev=\"incore:0755+0+0\",dir=\"/mnt\",fl=2} \
+               {creat, ft=dir,nm=\"/mnt/home\",pm=04755,ow=0,gr=0} \
+               {creat, ft=file,nm=\"/mnt/home/.mount\",pm=0600, \
+                       str=\"native:/home\"} \
+       "
+fi
+export SYSIO_NAMESPACE="\
+       {mnt,   dev=\"native:/\",dir=/,fl=${_root_flags:-0}} \
+       {mnt,   dev=\"incore:0755+0+0\",dir=\"/dev\"} \
+       {creat, ft=chr,nm=\"/dev/stdin\",pm=0400,mm=0+0} \
+       {creat, ft=chr,nm=\"/dev/stdout\",pm=0200,mm=0+1} \
+       {creat, ft=chr,nm=\"/dev/stderr\",pm=0200,mm=0+2} \
+       {creat, ft=dir,nm=\"/dev/fd\",pm=0755,ow=0,gr=0} \
+       {creat, ft=chr,nm=\"/dev/fd/0\",pm=0400,mm=0+0} \
+       {creat, ft=chr,nm=\"/dev/fd/1\",pm=0200,mm=0+1} \
+       {creat, ft=chr,nm=\"/dev/fd/2\",pm=0200,mm=0+2} \
+       {cd,    dir=\"$HOME\"} \
+       ${_extras} \
+"
+unset _root_flags
+unset _extras
diff --git a/libsysio/src/access.c b/libsysio/src/access.c
new file mode 100644 (file)
index 0000000..e2f6211
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "sysio-symbols.h"
+#include "sysio.h"
+
+int
+SYSIO_INTERFACE_NAME(access)(const char *path, int amode)
+{
+       gid_t   *list, *entry;
+       size_t  n;
+       int     err = 0;
+       unsigned mask, mode;
+       struct stat stbuf;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       err = 0;
+
+       n = getgroups(0, NULL);
+       list = NULL;
+       if (n) {
+               list = malloc(n * sizeof(gid_t));
+               if (!list) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+       }
+       err = getgroups(n, list);
+       if (err != (int ) n)
+               goto out;
+
+       err = SYSIO_INTERFACE_NAME(stat)(path, &stbuf);
+       if (err) {
+               err = -errno;
+               goto out;
+       }
+
+       mask = 0;
+       if (amode & R_OK)
+               mask |= S_IRUSR;
+       if (amode & W_OK)
+               mask |= S_IWUSR;
+       if (amode & X_OK)
+               mask |= S_IXUSR;
+
+       mode = stbuf.st_mode;
+       if (stbuf.st_uid == getuid() && (mode & mask) == mask) 
+               goto out;
+
+       mask >>= 3;
+       if (stbuf.st_gid == getgid() && (mode & mask) == mask)
+               goto out;
+
+       entry = list;
+       while (n--)
+               if (stbuf.st_gid == *entry++ && (mode & mask) == mask)
+                       goto out;
+
+       mask >>= 3;
+       if ((mode & mask) == mask)
+               goto out;
+
+       err = -EACCES;
+
+out:
+       if (list)
+               free(list);
+
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#ifdef REDSTORM
+#undef __access
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(access),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(access)))
+#endif
diff --git a/libsysio/src/chdir.c b/libsysio/src/chdir.c
new file mode 100644 (file)
index 0000000..36c4757
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * #############################################################################
+ * #
+ * #     This Cplant(TM) source code is the property of Sandia National
+ * #     Laboratories.
+ * #
+ * #     This Cplant(TM) source code is copyrighted by Sandia National
+ * #     Laboratories.
+ * #
+ * #     The redistribution of this Cplant(TM) source code is subject to the
+ * #     terms of the GNU Lesser General Public License
+ * #     (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ * #
+ * #     Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ * #     Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ * #     license for use of this work by or on behalf of the US Government.
+ * #     Export of this program may require a license from the United States
+ * #     Government.
+ * #
+ * #############################################################################
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "inode.h"
+#include "mount.h"
+#include "file.h"
+#include "sysio-symbols.h"
+
+struct pnode *_sysio_cwd = NULL;
+
+/*
+ * Change to directory specified by the given pnode.
+ */
+int
+_sysio_p_chdir(struct pnode *pno)
+{
+       int     err;
+
+       /*
+        * Revalidate the pnode, and ensure it's a directory
+        */
+       err = _sysio_p_validate(pno, NULL, NULL);
+       if (err)
+               return err;
+
+       if (!(pno->p_base->pb_ino &&
+             S_ISDIR(pno->p_base->pb_ino->i_mode)))
+               return -ENOTDIR;
+       /*
+        * Release old if set.
+        */
+        if (_sysio_cwd)
+                P_RELE(_sysio_cwd);
+
+       /*
+        * Finally, change to the new.
+        */
+        _sysio_cwd = pno;
+
+        return 0;
+}
+
+int
+SYSIO_INTERFACE_NAME(chdir)(const char *path)
+{
+        int     err;
+        struct pnode *pno;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+        err = _sysio_namei(_sysio_cwd, path, 0, NULL, &pno);
+        if (err)
+               SYSIO_INTERFACE_RETURN(-1, err);
+
+       err = _sysio_p_chdir(pno);
+       if (err)
+               P_RELE(pno);
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#ifdef REDSTORM
+#undef __chdir
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(chdir),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(chdir)))
+#endif
+
+/*
+ * Return path tracked by the path ancestor chain.
+ *
+ * If the buf pointer is NULL, a buffer large enough to hold the path
+ * is allocated from the heap.
+ */
+
+static int
+_sysio_p_path(struct pnode *pno, char **buf, size_t size)
+{
+       struct pnode *cur;
+       size_t  len;
+       size_t  n;
+       char    *cp;
+
+       cur = pno;
+
+       /*
+        * Walk up the tree to the root, summing the component name
+        * lengths and counting the vertices.
+        */
+       len = 0;
+       n = 0;
+       do {
+               /*
+                * If this is a covering path-node then the name should be
+                * the *covered* nodes name, not this one unless we are at
+                * the root of the name-space.
+                */
+               while (pno == pno->p_mount->mnt_root && pno != pno->p_parent )
+                       pno = pno->p_mount->mnt_covers;
+
+               /*
+                * Add length of this component to running sum and
+                * account for this vertex.
+                */
+               assert((len >= pno->p_base->pb_name.len &&
+                       (size_t )~0 - pno->p_base->pb_name.len > len) ||
+                      (size_t )~0 - len > pno->p_base->pb_name.len);
+               len += pno->p_base->pb_name.len;
+               n++;
+               assert(n);
+               pno = pno->p_parent;
+       } while (pno != pno->p_parent);
+
+       if (!*buf)
+               size = len + n + 1;
+       if (len >= size || n >= size - len)
+               return -ERANGE;
+       if (!*buf) {
+               /*
+                * Allocate path buffer from the heap.
+                */
+               *buf = malloc(size * sizeof(char));
+               if (!*buf)
+                       return -ENOMEM;
+       }
+
+       /*
+        * Fill in the path buffer.
+        */
+       pno = cur;
+       cp = *buf + len + n;
+       *cp = '\0';                                     /* NUL terminate */
+       do {
+               /*
+                * If this is a covering path-node then the name should be
+                * the *covered* nodes name, not this one unless we are at
+                * the root of the name-space.
+                */
+               while (pno == pno->p_mount->mnt_root && pno != pno->p_parent )
+                       pno = pno->p_mount->mnt_covers;
+
+               /*
+                * Add component and separator.
+                */
+               cp -= pno->p_base->pb_name.len;
+               (void )memcpy(cp, pno->p_base->pb_name.name,
+                             pno->p_base->pb_name.len);
+
+               *--cp = PATH_SEPARATOR;
+               pno = pno->p_parent;
+       } while (pno != pno->p_parent);
+
+       return 0;
+}
+
+char *
+SYSIO_INTERFACE_NAME(getcwd)(char *buf, size_t size)
+{
+       int     err;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       err = _sysio_p_path(_sysio_cwd, &buf, buf ? size : 0);
+       SYSIO_INTERFACE_RETURN(err ? NULL : buf, err);
+}
+
+#ifdef __GLIBC__
+#undef __getcwd
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(getcwd), 
+                    PREPEND(__, SYSIO_INTERFACE_NAME(getcwd)))
+#endif
+
+#if defined(PATH_MAX) && !(defined(REDSTORM))
+char    *
+SYSIO_INTERFACE_NAME(getwd)(char *buf)
+{
+
+       if (!buf) {
+               errno = EFAULT;
+               return NULL;
+       }
+
+       return SYSIO_INTERFACE_NAME(getcwd)(buf, PATH_MAX);
+}
+#endif
diff --git a/libsysio/src/chmod.c b/libsysio/src/chmod.c
new file mode 100644 (file)
index 0000000..936dec4
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "inode.h"
+#include "file.h"
+#include "sysio-symbols.h"
+
+static int
+do_chmod(struct pnode *pno, struct inode *ino, mode_t mode)
+{
+       int     err;
+       struct intnl_stat stbuf;
+       unsigned mask;
+
+       (void )memset(&stbuf, 0, sizeof(struct intnl_stat));
+       stbuf.st_mode = mode & 07777;
+       mask = SETATTR_MODE;
+       err = _sysio_setattr(pno, ino, mask, &stbuf);
+       return err;
+}
+
+int
+SYSIO_INTERFACE_NAME(chmod)(const char *path, mode_t mode)
+{
+       int     err;
+       struct pnode *pno;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       err = _sysio_namei(_sysio_cwd, path, 0, NULL, &pno);
+       if (err)
+               goto out;
+       err = do_chmod(pno, pno->p_base->pb_ino, mode);
+       P_RELE(pno);
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#ifdef REDSTORM
+#undef __chmod
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(chmod), 
+                    PREPEND(__, SYSIO_INTERFACE_NAME(chmod)))
+#endif
+
+int
+SYSIO_INTERFACE_NAME(fchmod)(int fd, mode_t mode)
+{
+       int     err;
+       struct file *fil;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       err = 0;
+       fil = _sysio_fd_find(fd);
+       if (!fil) {
+               err = -EBADF;
+               goto out;
+       }
+
+       err = do_chmod(NULL, fil->f_ino, mode);
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#ifdef REDSTORM
+#undef __fchmod
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(fchmod),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(fchmod)))
+#endif
diff --git a/libsysio/src/chown.c b/libsysio/src/chown.c
new file mode 100644 (file)
index 0000000..827a815
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "inode.h"
+#include "file.h"
+#include "sysio-symbols.h"
+
+static int
+_do_chown(struct pnode *pno, struct inode *ino, uid_t owner, gid_t group)
+{
+       int     err;
+       struct intnl_stat stbuf;
+       unsigned mask;
+
+       (void )memset(&stbuf, 0, sizeof(struct intnl_stat));
+       mask = 0;
+       if (owner != (uid_t )-1) {
+               stbuf.st_uid = owner;
+               mask |= SETATTR_UID;
+       }
+       if (group != (gid_t )-1) {
+               stbuf.st_gid = group;
+               mask |= SETATTR_GID;
+       }
+       err = _sysio_setattr(pno, ino, mask, &stbuf);
+       return err;
+}
+
+int
+SYSIO_INTERFACE_NAME(chown)(const char *path, uid_t owner, gid_t group)
+{
+       int     err;
+       struct pnode *pno;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       err = _sysio_namei(_sysio_cwd, path, 0, NULL, &pno);
+       if (err)
+               goto out;
+
+       err = _do_chown(pno, pno->p_base->pb_ino, owner, group);
+       P_RELE(pno);
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#ifdef REDSTORM
+#undef __chown
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(chown), 
+                    PREPEND(__, SYSIO_INTERFACE_NAME(chown)))
+#endif
+
+int
+SYSIO_INTERFACE_NAME(fchown)(int fd, uid_t owner, gid_t group)
+{
+       int     err;
+       struct file *fil;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       err = 0;
+       fil = _sysio_fd_find(fd);
+       if (!fil) {
+               err = -EBADF;
+               goto out;
+       }
+
+       err = _do_chown(NULL, fil->f_ino, owner, group);
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#ifdef REDSTORM
+#undef __fchown
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(fchown), 
+                    PREPEND(__, SYSIO_INTERFACE_NAME(fchown)))
+#endif
+
diff --git a/libsysio/src/dev.c b/libsysio/src/dev.c
new file mode 100644 (file)
index 0000000..046e35f
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "inode.h"
+#include "dev.h"
+
+const struct inode_ops _sysio_nodev_ops = {
+       _sysio_nodev_inop_lookup,
+       _sysio_nodev_inop_getattr,
+       _sysio_nodev_inop_setattr,
+       _sysio_nodev_getdirentries,
+       _sysio_nodev_inop_mkdir,
+       _sysio_nodev_inop_rmdir,
+       _sysio_nodev_inop_symlink,
+       _sysio_nodev_inop_readlink,
+       _sysio_nodev_inop_open,
+       _sysio_nodev_inop_close,
+       _sysio_nodev_inop_link,
+       _sysio_nodev_inop_unlink,
+       _sysio_nodev_inop_rename,
+       _sysio_nodev_inop_read,
+       _sysio_nodev_inop_write,
+       _sysio_nodev_inop_pos,
+       _sysio_nodev_inop_iodone,
+       _sysio_nodev_inop_fcntl,
+       _sysio_nodev_inop_sync,
+       _sysio_nodev_inop_datasync,
+       _sysio_nodev_inop_ioctl,
+       _sysio_nodev_inop_mknod,
+#ifdef _HAVE_STATVFS
+       _sysio_nodev_inop_statvfs,
+#endif
+       _sysio_nodev_inop_gone
+};
+
+/*
+ * Support for pseudo-devices.
+ */
+
+struct device {
+       const char *dev_name;
+       struct inode_ops dev_ops;
+};
+
+static struct device cdev[128];
+
+int
+_sysio_dev_init()
+{
+       unsigned major;
+
+       major = 0;
+       do {
+               cdev[major].dev_name = NULL;
+               cdev[major].dev_ops = _sysio_nodev_ops;
+       } while (++major < sizeof(cdev) / sizeof(struct device));
+
+       return 0;
+}
+
+/*
+ * Allocate major dev number in the dynamic range [128-255].
+ */
+dev_t
+_sysio_dev_alloc()
+{
+       unsigned short major;
+       static unsigned char c_major = 128;
+
+       assert(c_major);
+       major = c_major++;
+       return SYSIO_MKDEV(major, 0);
+}
+
+static int
+dev_register(struct device devtbl[],
+            int major,
+            const char *name,
+            struct inode_ops *ops)
+{
+
+       assert(major < 128);
+
+       if (major < 0) {
+               major = sizeof(cdev) / sizeof(struct device);
+               while (major--) {
+                       if (!devtbl[major].dev_name)
+                               break;
+               }
+       }
+       if (major < 0)
+               return -ENXIO;                          /* I dunno, what? */
+       if (devtbl[major].dev_name)
+               return -EEXIST;
+       devtbl[major].dev_name = name;
+       devtbl[major].dev_ops = *ops;
+
+       return major;
+}
+
+int
+_sysio_char_dev_register(int major, const char *name, struct inode_ops *ops)
+{
+
+       return dev_register(cdev, major, name, ops);
+}
+
+struct inode_ops *
+_sysio_dev_lookup(mode_t mode, dev_t dev)
+{
+       struct device *devtbl;
+       dev_t   major;
+
+       if (S_ISCHR(mode) || S_ISFIFO(mode))
+               devtbl = cdev;
+       else
+               return (struct inode_ops *)&_sysio_nodev_ops;
+
+       major = SYSIO_MAJOR_DEV(dev);
+       if (!(major < 128) || !devtbl[major].dev_name)
+               return (struct inode_ops *)&_sysio_nodev_ops;
+
+       return &devtbl[major].dev_ops;
+}
diff --git a/libsysio/src/dup.c b/libsysio/src/dup.c
new file mode 100644 (file)
index 0000000..9226a5a
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "file.h"
+#include "sysio-symbols.h"
+
+int
+SYSIO_INTERFACE_NAME(dup2)(int oldfd, int newfd)
+{
+       int     fd;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       if (newfd < 0)
+               SYSIO_INTERFACE_RETURN(-1, -EBADF);
+
+       if (oldfd == newfd) {
+               struct file *fil;
+
+               fil = _sysio_fd_find(oldfd);
+               if (!(fil && fil->f_ino))
+                       SYSIO_INTERFACE_RETURN(-1, -EBADF);
+               SYSIO_INTERFACE_RETURN(newfd, 0);
+       }
+
+       fd = _sysio_fd_dup2(oldfd, newfd);
+       SYSIO_INTERFACE_RETURN(fd < 0 ? -1 : fd, fd < 0 ? fd : 0);
+}
+
+#ifdef REDSTORM
+#undef __dup2 
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(dup2), 
+                    PREPEND(__, SYSIO_INTERFACE_NAME(dup2)))
+#endif
+
+int
+SYSIO_INTERFACE_NAME(dup)(int oldfd)
+{
+       int     fd;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fd = _sysio_fd_dup2(oldfd, -1);
+       SYSIO_INTERFACE_RETURN(fd < 0 ? -1 : fd, fd < 0 ? fd : 0);
+}
+
+#ifdef __GLIBC__
+#undef __dup
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(dup), 
+                    PREPEND(__, SYSIO_INTERFACE_NAME(dup)))
+#endif
diff --git a/libsysio/src/fcntl.c b/libsysio/src/fcntl.c
new file mode 100644 (file)
index 0000000..63fb920
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "inode.h"
+#include "file.h"
+
+#include "sysio-symbols.h"
+
+#ifdef HAVE_LUSTRE_HACK
+#include <syscall.h>
+
+static int
+_sysio_fcntl(int fd, int cmd, va_list ap)
+{
+       int     err;
+       long    arg;
+
+       switch (cmd) {
+       case F_GETFD:
+       case F_GETFL:
+       case F_GETOWN:
+               return syscall(SYS_fcntl, fd, cmd);
+       case F_DUPFD:
+       case F_SETFD:
+       case F_SETFL:
+       case F_GETLK:
+       case F_SETLK:
+       case F_SETLKW:
+       case F_SETOWN:
+               arg = va_arg(ap, long);
+               return syscall(SYS_fcntl, fd, cmd, arg);
+       }
+
+       errno = ENOSYS;
+       return -1;
+}
+#endif
+
+int
+SYSIO_INTERFACE_NAME(fcntl)(int fd, int cmd, ...)
+{
+       int     err;
+       struct file *fil;
+       va_list ap;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       err = 0;
+       fil = _sysio_fd_find(fd);
+       if (!fil) {
+#ifdef HAVE_LUSTRE_HACK
+               va_start(ap, cmd);
+               err = _sysio_fcntl(fd, cmd, ap);
+               va_end(ap);
+               if (err == -1)
+                       err = -errno;
+               goto out;
+#else
+               err = -EBADF;
+               goto out;
+#endif
+       }
+
+       switch (cmd) {
+
+           case F_DUPFD:
+               {
+                       long    newfd;
+
+                       va_start(ap, cmd);
+                       newfd = va_arg(ap, long);
+                       va_end(ap);
+                       if (newfd != (int )newfd || newfd < 0) {
+                               err = -EBADF;
+                               goto out;
+                       }
+                       err = _sysio_fd_dup2(fd, (int )newfd);
+               }
+               break;
+           default:
+               va_start(ap, cmd);
+               err = fil->f_ino->i_ops.inop_fcntl(fil->f_ino, cmd, ap);
+               va_end(ap);
+               break;
+       }
+
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#ifdef __GLIBC__
+#undef __fcntl
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(fcntl), 
+                    PREPEND(__, SYSIO_INTERFACE_NAME(fcntl)))
+#endif
+
+#ifdef BSD
+#undef _fcntl
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(fcntl), 
+                    PREPEND(_, SYSIO_INTERFACE_NAME(fcntl)))
+#endif
diff --git a/libsysio/src/file.c b/libsysio/src/file.c
new file mode 100644 (file)
index 0000000..8d2c3a8
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "file.h"
+#include "inode.h"
+#include "xtio.h"
+
+/*
+ * Support for file IO.
+ */
+
+/*
+ * The open files table and it's size.
+ */
+static struct file **_sysio_oftab = NULL;
+static size_t _sysio_oftab_size = 0;
+
+/*
+ * Create and initialize open file record.
+ */
+struct file *
+_sysio_fnew(struct inode *ino, int flags)
+{
+       struct file *fil;
+
+       fil = malloc(sizeof(struct file));
+       if (!fil)
+               return NULL;
+
+       _SYSIO_FINIT(fil, ino, flags);
+       I_REF(ino);
+
+       return fil;
+}
+
+/*
+ * Destroy open file record.
+ */
+void
+_sysio_fgone(struct file *fil)
+{
+       int     err;
+
+       assert(!fil->f_ref);
+       assert(fil->f_ino);
+       err = (*fil->f_ino->i_ops.inop_close)(fil->f_ino);
+       assert(!err);
+       free(fil);
+}
+
+/*
+ * IO operation completion handler.
+ */
+void
+_sysio_fcompletio(struct ioctx *ioctx, struct file *fil)
+{
+       _SYSIO_OFF_T off;
+
+       if (ioctx->ioctx_cc <= 0)
+               return;
+
+       assert(ioctx->ioctx_ino == fil->f_ino);
+       off = fil->f_pos + ioctx->ioctx_cc;
+       if (fil->f_pos && off <= fil->f_pos)
+               abort();
+       fil->f_pos = off;
+}
+
+/*
+ * Grow (or truncate) the file descriptor table.
+ */
+static int
+fd_grow(size_t n)
+{
+       int     fd;
+       size_t  count;
+       struct file **noftab, **filp;
+
+       /*
+        * Sanity check the new size.
+        */
+       fd = (int )n;
+       if ((size_t )fd != n)
+               return -EMFILE;
+
+       if (n < 8)
+               n = 8;
+       if (n >= _sysio_oftab_size && n - _sysio_oftab_size < _sysio_oftab_size)
+               n = (n + 1) * 2;
+       noftab = realloc(_sysio_oftab, n * sizeof(struct file *));
+       if (!noftab)
+               return -ENOMEM;
+       _sysio_oftab = noftab;
+       count = _sysio_oftab_size;
+       _sysio_oftab_size = n;
+       if (n < count)
+               return 0;
+       filp = _sysio_oftab + count;
+       n -= count;
+       while (n--)
+               *filp++ = NULL;
+       return 0;
+}
+
+#if ZERO_SUM_MEMORY
+void
+_sysio_fd_shutdown()
+{
+
+       free(_sysio_oftab);
+       _sysio_oftab_size = 0;
+}
+#endif
+
+/*
+ * Find a free slot in the open files table.
+ */
+static int
+find_free_fildes()
+{
+       size_t  n;
+       int     err;
+       struct file **filp;
+
+       for (n = 0, filp = _sysio_oftab;
+            n < _sysio_oftab_size && *filp;
+            n++, filp++)
+               ;
+       if (n >= _sysio_oftab_size) {
+               err = fd_grow(n);
+               if (err)
+                       return err;
+               filp = &_sysio_oftab[n];
+               assert(!*filp);
+       }
+
+       return n;
+}
+
+/*
+ * Find open file record from file descriptor.
+ */
+struct file *
+_sysio_fd_find(int fd)
+{
+       if (fd < 0 || (unsigned )fd >= _sysio_oftab_size)
+               return NULL;
+
+       return _sysio_oftab[fd];
+}
+
+/*
+ * Close an open descriptor.
+ */
+int
+_sysio_fd_close(int fd)
+{
+       struct file *fil;
+
+       fil = _sysio_fd_find(fd);
+       if (!fil)
+               return -EBADF;
+
+       _sysio_oftab[fd] = NULL;
+
+       F_RELE(fil);
+
+       return 0;
+}
+
+/*
+ * Associate open file record with given file descriptor or any available
+ * file descriptor if less than zero.
+ */
+int
+_sysio_fd_set(struct file *fil, int fd)
+{
+       int     err;
+       struct file *ofil;
+
+       /*
+        * New fd < 0 => any available descriptor.
+        */
+       if (fd < 0) {
+               fd = find_free_fildes();
+               if (fd < 0)
+                       return fd;
+       }
+
+       if ((unsigned )fd >= _sysio_oftab_size) {
+               err = fd_grow(fd);
+               if (err)
+                       return err;
+       }
+
+       /*
+        * Remember old.
+        */
+       ofil = _sysio_fd_find(fd);
+       /*
+        * Take the entry.
+        */
+       _sysio_oftab[fd] = fil;
+       if (ofil)
+               F_RELE(ofil);
+
+       return fd;
+}
+
+/*
+ * Duplicate old file descriptor.
+ *
+ * If the new file descriptor is less than zero, the new file descriptor
+ * is chosen freely.
+ */
+int
+_sysio_fd_dup2(int oldfd, int newfd)
+{
+       struct file *fil;
+       int     fd;
+
+       if (oldfd == newfd)
+               return 0;
+
+       fil = _sysio_fd_find(oldfd);
+       if (!fil)
+               return -EBADF;
+
+       fd = _sysio_fd_set(fil, newfd);
+       if (fd >= 0)
+               F_REF(fil);
+       return fd;
+}
+
+int
+_sysio_fd_close_all()
+{
+       int     fd;
+       struct file **filp;
+
+       /*
+        * Close all open descriptors.
+        */
+       for (fd = 0, filp = _sysio_oftab;
+            (size_t )fd < _sysio_oftab_size;
+            fd++, filp++) {
+               if (!*filp)
+                       continue;
+               F_RELE(*filp);
+               *filp = NULL;
+       }
+
+       /*
+        * Release current working directory.
+        */
+       if (_sysio_cwd) {
+               P_RELE(_sysio_cwd);
+               _sysio_cwd = NULL;
+       }
+
+       return 0;
+}
diff --git a/libsysio/src/file_hack.c b/libsysio/src/file_hack.c
new file mode 100644 (file)
index 0000000..bad70be
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "file.h"
+#include "inode.h"
+#include "xtio.h"
+
+/*
+ * Support for file IO.
+ */
+
+/*
+ * The open files table
+ */
+typedef struct oftab {
+       struct file   **table;  /* table array */
+       size_t          size;   /* current table size */
+       int             offset; /* base fd number */
+       int             max;    /* max size */
+} oftab_t;
+
+#define OFTAB_NATIVE   (0)
+#define OFTAB_VIRTUAL  (1)
+
+static oftab_t _sysio_oftab[2] = {
+       {NULL, 0, 0, 0},
+       {NULL, 0, 0, 1024*1024},
+};
+
+static int native_max_fds = 0;
+
+static inline void init_oftab()
+{
+       if (!native_max_fds) {
+               native_max_fds = sysconf(_SC_OPEN_MAX);
+               if (native_max_fds <= 0)
+                       abort();
+               _sysio_oftab[OFTAB_NATIVE].max = native_max_fds - 1;
+               _sysio_oftab[OFTAB_VIRTUAL].offset = native_max_fds;
+       }
+}
+
+static inline oftab_t *select_oftab(int fd)
+{
+       return & _sysio_oftab[fd >= native_max_fds || fd < 0];
+}
+
+/*
+ * Create and initialize open file record.
+ */
+struct file *
+_sysio_fnew(struct inode *ino, int flags)
+{
+       struct file *fil;
+
+       fil = malloc(sizeof(struct file));
+       if (!fil)
+               return NULL;
+
+       _SYSIO_FINIT(fil, ino, flags);
+       I_REF(ino);
+
+       return fil;
+}
+
+/*
+ * Destroy open file record.
+ */
+void
+_sysio_fgone(struct file *fil)
+{
+       int     err;
+
+       assert(!fil->f_ref);
+       assert(fil->f_ino);
+       err = (*fil->f_ino->i_ops.inop_close)(fil->f_ino);
+       assert(!err);
+       free(fil);
+}
+
+/*
+ * IO operation completion handler.
+ */
+void
+_sysio_fcompletio(struct ioctx *ioctx, struct file *fil)
+{
+       _SYSIO_OFF_T off;
+
+       if (ioctx->ioctx_cc <= 0)
+               return;
+
+       assert(ioctx->ioctx_ino == fil->f_ino);
+       off = fil->f_pos + ioctx->ioctx_cc;
+       if (fil->f_pos && off <= fil->f_pos)
+               abort();
+       fil->f_pos = off;
+}
+
+/*
+ * Grow (or truncate) the file descriptor table.
+ */
+static int
+fd_grow(oftab_t *oftab, size_t n)
+{
+       int     fd;
+       size_t  count;
+       struct file **noftab, **filp;
+
+       /*
+        * Sanity check the new size.
+        */
+       fd = (int )n;
+       if ((size_t )fd != n)
+               return -EMFILE;
+
+       n++;    /* index -> size */
+       assert(n > oftab->size);
+
+       if (n > oftab->max)
+               return -ERANGE;
+
+       if (n < 8)
+               n = 8;
+       if (n - oftab->size < oftab->size)
+               n = (n + 1) * 2;
+       noftab = realloc(oftab->table, n * sizeof(struct file *));
+       if (!noftab)
+               return -ENOMEM;
+       oftab->table = noftab;
+       count = oftab->size;
+       oftab->size = n;
+       if (n < count)
+               return 0;
+       filp = oftab->table + count;
+       n -= count;
+       while (n--)
+               *filp++ = NULL;
+       return 0;
+}
+
+#if ZERO_SUM_MEMORY
+static void free_oftab(oftab_t *ot)
+{
+       if (ot->table) {
+               free(ot->table);
+               ot->size = 0;
+       }
+}
+
+void
+_sysio_fd_shutdown()
+{
+       free_oftab(&_sysio_oftab[OFTAB_NATIVE]);
+       free_oftab(&_sysio_oftab[OFTAB_VIRTUAL]);
+}
+#endif
+
+/*
+ * Find a free slot in the open files table.
+ * target < 0: any free slot
+ * target >= 0: get slot [target]
+ */
+static int
+find_free_fildes(oftab_t *oftab, int target)
+ {
+       int     n;
+       int     err;
+       struct file **filp;
+       if (target < 0) {
+               for (n = 0, filp = oftab->table;
+                    n < oftab->size && *filp;
+                    n++, filp++)
+                       ;
+       } else
+               n = target - oftab->offset;
+
+       if (n >= oftab->size) {
+               err = fd_grow(oftab, n);
+               if (err)
+                       return err;
+               filp = &oftab->table[n];
+               assert(!*filp);
+       }
+#ifdef HAVE_LUSTRE_HACK
+       /* FIXME sometimes we could intercept open/socket to create
+        * a fd, but missing close()? currently we have this problem
+         * with resolv lib. as a workaround simply destroy the file
+        * struct here.
+        */
+       if (oftab->table[n]) {
+               free(oftab->table[n]);
+               oftab->table[n] = NULL;
+       }
+#endif
+
+       return oftab->offset + n;
+}
+
+/*
+ * Find open file record from file descriptor.
+ * clear this entry if 'clear' is non-zero
+ */
+static struct file *
+__sysio_fd_get(int fd, int clear)
+{
+       oftab_t *oftab;
+       struct file *file;
+
+       init_oftab();
+
+       if (fd < 0)
+               return NULL;
+
+       oftab = select_oftab(fd);
+       if (!oftab->table || fd >= oftab->offset + oftab->size)
+               return NULL;
+
+       file = oftab->table[fd - oftab->offset];
+       if (clear)
+               oftab->table[fd - oftab->offset] = NULL;
+
+       return file;
+}
+
+/*
+ * Find open file record from file descriptor.
+ */
+struct file *
+_sysio_fd_find(int fd)
+{
+       return __sysio_fd_get(fd, 0);
+}
+
+/*
+ * Close an open descriptor.
+ */
+int
+_sysio_fd_close(int fd)
+{
+       struct file *fil;
+
+       fil = fil = __sysio_fd_get(fd, 1);
+       if (!fil)
+               return -EBADF;
+
+       F_RELE(fil);
+
+       return 0;
+}
+
+/*
+ * Associate open file record with given file descriptor or any available
+ * file descriptor if less than zero.
+ */
+int
+_sysio_fd_set(struct file *fil, int fd)
+{
+       int     err;
+       struct file *ofil;
+       oftab_t *oftab;
+
+       init_oftab();
+
+       oftab = select_oftab(fd);
+
+       /*
+        * New fd < 0 => any available descriptor.
+        */
+       fd = find_free_fildes(oftab, fd);
+       if (fd < 0)
+               return fd;
+
+       assert(fd < oftab->offset + oftab->size);
+
+       /*
+        * Remember old.
+        */
+       ofil = __sysio_fd_get(fd, 1);
+       if (ofil)
+               F_RELE(ofil);
+
+       oftab->table[fd - oftab->offset] = fil;
+
+       return fd;
+}
+
+/*
+ * Duplicate old file descriptor.
+ *
+ * If the new file descriptor is less than zero, the new file descriptor
+ * is chosen freely.
+ */
+int
+_sysio_fd_dup2(int oldfd, int newfd)
+{
+       struct file *fil;
+       int     fd;
+
+       init_oftab();
+
+       if (oldfd == newfd)
+               return 0;
+
+       fil = _sysio_fd_find(oldfd);
+       if (!fil)
+               return -EBADF;
+
+       /* old & new must belong to the same oftab */
+       if (select_oftab(oldfd) != select_oftab(newfd))
+               return -EINVAL;
+
+       fd = _sysio_fd_set(fil, newfd);
+       if (fd >= 0)
+               F_REF(fil);
+       return fd;
+}
+
+void
+_sysio_oftable_close_all(oftab_t *oftab)
+{
+       struct file **filp;
+       int fd;
+
+       for (fd = 0, filp = oftab->table;
+            (size_t )fd < oftab->size;
+            fd++, filp++) {
+               if (!*filp)
+                       continue;
+               F_RELE(*filp);
+               *filp = NULL;
+       }
+}
+
+int
+_sysio_fd_close_all()
+{
+       int     fd;
+       struct file **filp;
+       oftab_t *oftab;
+       int i;
+
+       /*
+        * Close all open descriptors.
+        */
+       _sysio_oftable_close_all(&_sysio_oftab[OFTAB_VIRTUAL]);
+       /* XXX see liblustre/llite_lib.c for explaination */
+#if 0
+       _sysio_oftable_close_all(&_sysio_oftab[OFTAB_NATIVE]);
+#endif
+
+       /*
+        * Release current working directory.
+        */
+       if (_sysio_cwd) {
+               P_RELE(_sysio_cwd);
+               _sysio_cwd = NULL;
+       }
+
+       return 0;
+}
diff --git a/libsysio/src/fs.c b/libsysio/src/fs.c
new file mode 100644 (file)
index 0000000..29abe4f
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "fs.h"
+#include "inode.h"
+
+/*
+ * File system abstractipon support.
+ */
+
+/*
+ * The "file system switch".
+ */
+static LIST_HEAD(, fsswent) fsswitch = { NULL };
+
+/*
+ * Lookup named entry in the switch.
+ */
+struct fsswent *
+_sysio_fssw_lookup(const char *name)
+{
+       struct fsswent *fssw;
+
+       if (!fsswitch.lh_first)
+               return NULL;
+
+       fssw = fsswitch.lh_first;
+       do {
+               if (strcmp(fssw->fssw_name, name) == 0)
+                       return fssw;
+               fssw = fssw->fssw_link.le_next;
+       } while (fssw);
+       return NULL;
+}
+
+/*
+ * Register driver.
+ */
+int
+_sysio_fssw_register(const char *name, struct fssw_ops *ops)
+{
+       struct fsswent *fssw;
+
+       fssw = _sysio_fssw_lookup(name);
+       if (fssw)
+               return -EEXIST;
+
+       fssw = malloc(sizeof(struct fsswent) + strlen(name) + 1);
+       if (!fssw)
+               return -ENOMEM;
+       fssw->fssw_name = (char *)fssw + sizeof(struct fsswent);
+       (void )strcpy((char *)fssw->fssw_name, name);
+       fssw->fssw_ops = *ops;
+
+       LIST_INSERT_HEAD(&fsswitch, fssw, fssw_link);
+
+       return 0;
+}
+
+#if ZERO_SUM_MEMORY
+/*
+ * Shutdown
+ */
+void
+_sysio_fssw_shutdown()
+{
+       struct fsswent *fssw;
+
+       while ((fssw = fsswitch.lh_first)) {
+               LIST_REMOVE(fssw, fssw_link);
+               free(fssw);
+       }
+}
+#endif
+
+/*
+ * Allocate and initialize a new file system record.
+ */
+struct filesys *
+_sysio_fs_new(struct filesys_ops *ops, unsigned flags, void *private)
+{
+       struct filesys *fs;
+
+       fs = malloc(sizeof(struct filesys));
+       if (!fs)
+               return NULL;
+       FS_INIT(fs, flags, ops, private);
+       return fs;
+}
+
+/*
+ * Dispose of given file system record.
+ */
+void
+_sysio_fs_gone(struct filesys *fs)
+{
+       size_t  n;
+       struct itable_entry *head;
+
+       if (fs->fs_ref)
+               abort();
+       n = FS_ITBLSIZ;
+       do {
+               head = &fs->fs_itbl[--n];
+               while (head->lh_first)
+                       _sysio_i_gone(head->lh_first);
+       } while (n);
+       if (n)
+               abort();
+
+       (*fs->fs_ops.fsop_gone)(fs);
+       free(fs);
+}
diff --git a/libsysio/src/fsync.c b/libsysio/src/fsync.c
new file mode 100644 (file)
index 0000000..988cb50
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "file.h"
+#include "inode.h"
+
+int
+SYSIO_INTERFACE_NAME(fsync)(int fd)
+{
+       struct file *fil;
+       int     err;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fil = _sysio_fd_find(fd);
+       if (!(fil && fil->f_ino))
+               SYSIO_INTERFACE_RETURN(-1, -EBADF);
+       err = (*fil->f_ino->i_ops.inop_sync)(fil->f_ino);
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+int
+SYSIO_INTERFACE_NAME(fdatasync)(int fd)
+{
+       struct file *fil;
+       int     err;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fil = _sysio_fd_find(fd);
+       if (!(fil && fil->f_ino))
+               SYSIO_INTERFACE_RETURN(-1, -EBADF);
+       err = (*fil->f_ino->i_ops.inop_datasync)(fil->f_ino);
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
diff --git a/libsysio/src/getdirentries.c b/libsysio/src/getdirentries.c
new file mode 100644 (file)
index 0000000..7e1a81f
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2004 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * #############################################################################
+ * #
+ * #     This Cplant(TM) source code is the property of Sandia National
+ * #     Laboratories.
+ * #
+ * #     This Cplant(TM) source code is copyrighted by Sandia National
+ * #     Laboratories.
+ * #
+ * #     The redistribution of this Cplant(TM) source code is subject to the
+ * #     terms of the GNU Lesser General Public License
+ * #     (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ * #
+ * #     Cplant(TM) Copyright 1998-2004 Sandia Corporation. 
+ * #     Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ * #     license for use of this work by or on behalf of the US Government.
+ * #     Export of this program may require a license from the United States
+ * #     Government.
+ * #
+ * #############################################################################
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#ifdef __GLIBC__
+#include <alloca.h>
+#endif
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "inode.h"
+#include "file.h"
+#include "sysio-symbols.h"
+
+#ifndef __GNUC__
+#define __restrict
+#endif
+
+static ssize_t
+PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries64))(int fd,
+                                                 char *buf,
+                                                 size_t nbytes,
+                                                 _SYSIO_OFF_T * __restrict
+                                                  basep)
+{
+       struct file *fil;
+       ssize_t cc;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+
+       fil = _sysio_fd_find(fd);
+       if (!(fil && fil->f_ino))
+               SYSIO_INTERFACE_RETURN(-1, -EBADF);
+
+       if (!S_ISDIR(fil->f_ino->i_mode))
+               SYSIO_INTERFACE_RETURN(-1, -ENOTDIR);
+
+       cc =
+           (*fil->f_ino->i_ops.inop_getdirentries)(fil->f_ino,
+                                                   buf,
+                                                   nbytes,
+                                                   basep);
+       SYSIO_INTERFACE_RETURN(cc < 0 ? -1 : cc, cc < 0 ? (int )cc : 0);
+}
+
+#if _LARGEFILE64_SOURCE
+#undef getdirentries64
+sysio_sym_strong_alias(PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries64)),
+                      SYSIO_INTERFACE_NAME(getdirentries64))
+#endif
+
+#undef getdirentries
+
+#ifndef DIRENT64_IS_NATURAL
+
+#ifndef EOVERFLOW
+#define EOVERFLOW      ERANGE
+#endif
+
+#ifdef _DIRENT_HAVE_D_NAMLEN
+#define _namlen(dp)    ((dp)->d_namlen)
+#else
+#define _namlen(dp)    (strlen((dp)->d_name))
+#endif
+
+#ifndef _rndup
+#define _rndup(n, boundary) \
+       ((((n) + (boundary) - 1 ) / (boundary)) * (boundary))
+#endif
+
+#ifndef BSD
+ssize_t
+SYSIO_INTERFACE_NAME(getdirentries)(int fd,
+                                   char *buf,
+                                   size_t nbytes,
+                                   off_t * __restrict basep)
+#else
+int
+SYSIO_INTERFACE_NAME(getdirentries)(int fd,
+                                   char *buf,
+                                   int nbytes,
+                                   long * __restrict basep)
+#endif
+{
+       size_t inbytes;
+       void    *ibuf;
+       _SYSIO_OFF_T ibase;
+       ssize_t cc;
+       struct dirent *dp, *nxtdp;
+#if defined(BSD)
+       int     off;
+#endif
+       struct intnl_dirent *od64p, *d64p;
+       size_t  n;
+       size_t  reclen;
+       char    *cp;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+#define _dbaselen      ((size_t )&((struct dirent *)0)->d_name[0])
+
+#ifdef __GLIBC__
+#define _dreclen(namlen) \
+       ((_dbaselen + (namlen) + __alignof__ (struct dirent)) & \
+        ~(__alignof__ (struct dirent) - 1))
+#else /* !defined(__GLIBC__) */
+#define _dreclen(namlen) \
+       _rndup(_dbaselen + (namlen) + 1, sizeof(int))
+#endif
+
+#if defined(__GLIBC__)
+#define _fast_alloc(n) alloca(n)
+#define _fast_free(p)
+#else /* !defined(__GLIBC__) */
+#define _fast_alloc(n) malloc(n)
+#define _fast_free(p)  free(p)
+#endif
+
+       SYSIO_INTERFACE_ENTER;
+#if defined(BSD)
+       if (nbytes < 0)
+               SYSIO_INTERFACE_RETURN(-1, -EINVAL);
+#endif
+
+       inbytes = nbytes;
+       if (inbytes > 8 * 1024) {
+               /*
+                * Limit stack use.
+                */
+               inbytes = 8 * 1024;
+       }
+       ibuf = _fast_alloc(inbytes);
+       if (!ibuf)
+               SYSIO_INTERFACE_RETURN(-1, -ENOMEM);
+
+       dp = (struct dirent *)buf;
+
+       ibase = *basep;
+       cc =
+           PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries64))(fd,
+                                           ibuf,
+                                           inbytes,
+                                           &ibase);
+       if (cc < 0) {
+               cc = -errno;
+               goto out;
+       }
+       *basep = (off_t )ibase;
+       if (sizeof(*basep) != sizeof(ibase) && *basep != ibase) {
+               cc = -EOVERFLOW;
+               goto out;
+       }
+
+#if defined(BSD)
+       off = *basep;
+#endif
+       od64p = NULL;
+       d64p = ibuf;
+       for (;;) {
+               if (!cc)
+                       break;
+#ifdef HAVE_D_NAMLEN
+               n = d64p->d_namlen;
+#else
+               n = strlen(d64p->d_name);
+#endif
+               reclen = _dreclen(n);
+               if (reclen >= (unsigned )nbytes)
+                       break;
+               dp->d_ino = (ino_t )d64p->d_ino;
+#if !(defined(BSD))
+               dp->d_off = (off_t )d64p->d_off;
+#endif
+               if ((sizeof(dp->d_ino) != sizeof(d64p->d_ino) &&
+                    dp->d_ino != d64p->d_ino)
+                               ||
+#if !(defined(BSD))
+                   (sizeof(dp->d_off) != sizeof(d64p->d_off) &&
+                    dp->d_off != d64p->d_off)
+#else
+                   (off + (int )reclen < off)
+#endif
+                   ) {
+                       cc = -EOVERFLOW;
+                       break;
+               }
+               dp->d_type = d64p->d_type;
+               dp->d_reclen = reclen;
+               nxtdp = (struct dirent *)((char *)dp + dp->d_reclen);
+               (void )memcpy(dp->d_name, d64p->d_name, n);
+               for (cp = dp->d_name + n; cp < (char *)nxtdp; *cp++ = '\0')
+                       ;
+               cc -= d64p->d_reclen;
+               od64p = d64p;
+               d64p = (struct dirent64 *)((char *)d64p + d64p->d_reclen);
+               nbytes -= reclen;
+#if defined(BSD)
+               off += reclen;
+#endif
+               dp = nxtdp;
+       }
+
+out:
+       _fast_free(ibuf);
+
+       if (dp == (struct dirent *)buf && cc < 0)
+               SYSIO_INTERFACE_RETURN(-1, (int )cc);
+       cc = (char *)dp - buf;
+       if (cc)
+               *basep =
+#if !(defined(BSD))
+                   od64p->d_off;
+#else
+                   off;
+#endif
+       SYSIO_INTERFACE_RETURN(cc, 0);
+
+#ifdef __GLIBC__
+#undef _fast_alloc
+#undef _fast_free
+#endif
+#undef _dreclen
+#undef _dbaselen
+}
+#else /* !defined(DIRENT64_IS_NATURAL) */
+sysio_sym_strong_alias(PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries64),
+                      SYSIO_INTERFACE_NAME(getdirentries)))
+#endif
+
+#ifdef REDSTORM
+#undef __getdirentries
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(getdirentries),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(getdirentries)))
+#endif
+#if defined(BSD) || defined(REDSTORM)
+#undef _getdirentries
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(getdirentries),
+                    PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries)))
+#endif
diff --git a/libsysio/src/init.c b/libsysio/src/init.c
new file mode 100644 (file)
index 0000000..38d0794
--- /dev/null
@@ -0,0 +1,625 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2004 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#define _BSD_SOURCE
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/queue.h>
+#include <sys/uio.h>
+
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "sysio.h"
+#include "inode.h"
+#include "fs.h"
+#include "mount.h"
+#include "file.h"
+#include "dev.h"
+#include "xtio.h"
+
+#ifdef STDFD_DEV
+#include "stdfd.h"
+#endif
+
+/*
+ * The namespace assembly buffer passes args with a `name'=`value'
+ * syntax. We use the following to record that in various
+ * routines below.
+ */
+struct named_argument {
+       const char *name;                               /* arg name */
+       char    *value;                                 /* arg value */
+};
+
+/*
+ * White space characters.
+ */
+#define IGNORE_WHITE           " \t\r\n"
+
+/*
+ * Sysio library initialization. Must be called before anything else in the
+ * library.
+ */
+int
+_sysio_init()
+{
+       int     err;
+#ifdef WITH_SOCKETS
+       int     _sysio_sockets_init(void);
+#endif
+
+       err = _sysio_ioctx_init();
+       if (err)
+               goto error;
+       err = _sysio_i_init();
+       if (err)
+               goto error;
+       err = _sysio_mount_init();
+       if (err)
+               goto error;
+
+       err = _sysio_dev_init();
+       if (err)
+               goto error;
+#ifdef STDFD_DEV
+       err = _sysio_stdfd_init();
+       if (err)
+               goto error;
+#endif
+#ifdef WITH_SOCKETS
+       err = _sysio_sockets_init();
+       if (err)
+               goto error;
+#endif
+
+       goto out;
+error:
+       errno = -err;
+out:
+       /*
+        * Unlike all other _sysio routines, this one returns with errno
+        * set. It also returns the error, as usual.
+        */
+       return err;
+}
+
+/*
+ * Sysio library shutdown.
+ */
+void
+_sysio_shutdown()
+{
+
+       if (!(_sysio_fd_close_all() == 0 &&
+             _sysio_unmount_all() == 0))
+                       abort();
+
+#if ZERO_SUM_MEMORY
+       _sysio_fd_shutdown();
+       _sysio_i_shutdown();
+       _sysio_fssw_shutdown();
+#endif
+}
+
+/* 
+ * (kind of)Duplicates strtok function.
+ *
+ * Given a buffer, returns the longest string
+ * that does not contain any delim characters.  Will
+ * remove ws and any characters in the ignore string.  
+ * Returns the token.  
+ *
+ * The parameter controlling acceptance controls whether a positive
+ * match for some delimiter be made or not. If set, then either a delimiter
+ * or NUL character is success.
+ *
+ */
+static const char *
+get_token(const char *buf,
+         int accepts,
+         const char *delim,
+         const char *ignore,
+         char *tbuf)
+{
+       char    c;
+       int     escape, quote;
+
+       /* 
+        * Find the first occurance of delim, recording how many
+        * characters lead up to it.  Ignore indicated characters.
+        */
+       escape = quote = 0;
+       while ((c = *buf) != '\0') {
+               buf++;
+               if (!escape) {
+                       if (c == '\\') {
+                               escape = 1;
+                               continue;
+                       }
+                       if (c == '\"') {
+                               quote ^= 1;
+                               continue;
+                       }
+                       if (!quote) {
+                               if (strchr(delim, c) != NULL) {
+                                       accepts = 1;
+                                       break;
+                               }
+                               if (strchr(ignore, c) != NULL)
+                                       continue;
+                       }
+               } else
+                       escape = 0;
+               *tbuf++ = c;
+       }
+       if (!accepts)
+               return NULL;
+       *tbuf = '\0';                                           /* NUL term */
+       return buf;
+}
+
+/*
+ * Parse and record named arguments given as `name = value', comma-separated
+ * pairs.
+ *
+ * NB: Alters the passed buffer.
+ */
+static char *
+get_args(char *buf, struct named_argument *vec)
+{
+       char    *nxt;
+       char    *name, *value;
+       struct named_argument *v;
+
+       for (;;) {
+               nxt = (char *)get_token(buf, 1, "=,", IGNORE_WHITE, name = buf);
+               if (!nxt ||
+                   (nxt != buf && *name == '\0' && buf + strlen(buf) == nxt)) {
+                       buf = NULL;
+                       break;
+               }
+               if (*name == '\0')
+                       break;
+               buf = (char *)get_token(nxt, 1, ",", IGNORE_WHITE, value = nxt);
+               if (*value == '\0')
+                       value = NULL;
+               for (v = vec; v->name; v++)
+                       if (strcmp(v->name, name) == 0)
+                               break;
+               if (!v->name)
+                       return NULL;
+               v->value = value;
+       }
+
+       return buf;
+}
+
+static int
+parse_mm(const char *s, dev_t *devp)
+{
+       unsigned long ul;
+       char    *cp;
+       dev_t   dev;
+
+       ul = strtoul(s, &cp, 0);
+       if (*cp != '+' || ul > USHRT_MAX)
+               return -EINVAL;
+       dev = ul << 16;
+       s = (const char *)++cp;
+       ul = strtoul(s, &cp, 0);
+       if (*cp != '\0' || ul > USHRT_MAX)
+               return -EINVAL;
+       dev |= ul & 0xffff;
+       *devp = dev;
+       return 0;
+}
+
+/*
+ * Performs the creat command for the namespace assembly
+ *
+ * NB: Alters the passed buffer.
+ */
+static int 
+do_creat(char *args) 
+{
+       size_t  len;
+       struct named_argument v[] = {
+               { "ft",         NULL },                 /* file type */
+               { "nm",         NULL },                 /* name */
+               { "pm",         NULL },                 /* permissions */
+               { "ow",         NULL },                 /* owner */
+               { "gr",         NULL },                 /* group */
+               { "mm",         NULL },                 /* major + minor */
+               { "str",        NULL },                 /* file data */
+               { NULL,         NULL }
+       };
+       const char *cp;
+       long    perms;
+       long    owner, group;
+       struct pnode *dir, *pno;
+       mode_t  mode;
+       struct intent intent;
+       dev_t   dev;
+       int     err;
+  
+       len = strlen(args);
+       if (get_args(args, v) - args != (ssize_t )len ||
+           !(v[0].value &&
+             v[1].value &&
+             v[2].value))
+               return -EINVAL;
+       perms = strtol(v[2].value, (char **)&cp, 0);
+       if (*cp ||
+           perms < 0 ||
+           (perms == LONG_MAX && errno == ERANGE) ||
+           ((unsigned)perms & ~07777))
+               return -EINVAL;
+       if (v[3].value) {
+               owner = strtol(v[3].value, (char **)&cp, 0);
+               if (*cp ||
+                   ((owner == LONG_MIN || owner == LONG_MAX)
+                    && errno == ERANGE))
+                       return -EINVAL;
+       } else
+               owner = getuid();
+       if (v[4].value) {
+               group = strtol(v[4].value, (char **)&cp, 0);
+               if (*cp ||
+                   ((group == LONG_MIN || group == LONG_MAX) &&
+                    errno == ERANGE))
+                       return -EINVAL;
+       } else
+               group = getegid();
+
+       if (!(dir = _sysio_cwd) && !(dir = _sysio_root))
+               return -ENOENT;
+       err = 0;
+       mode = perms;
+       if (strcmp(v[0].value, "dir") == 0) {
+               INTENT_INIT(&intent, INT_CREAT, &mode, 0);
+               err = _sysio_namei(dir, v[1].value, ND_NEGOK, &intent, &pno);
+               if (err)
+                       return err;
+               if (pno->p_base->pb_ino)
+                       err = -EEXIST;
+               else if (IS_RDONLY(pno->p_parent,
+                                  pno->p_parent->p_base->pb_ino))
+                       err = -EROFS;
+               else {
+                       struct inode *ino;
+
+                       ino = pno->p_parent->p_base->pb_ino;
+                       err = (*ino->i_ops.inop_mkdir)(pno, mode);
+               }
+               P_RELE(pno);
+       } else if (strcmp(v[0].value, "chr") == 0) {
+               if (!(v[5].value && parse_mm(v[5].value, &dev) == 0))
+                       return -EINVAL;
+               mode |= S_IFCHR;
+               INTENT_INIT(&intent, INT_CREAT, &mode, 0);
+               err = _sysio_namei(dir, v[1].value, ND_NEGOK, &intent, &pno);
+               if (err)
+                       return err;
+               if (pno->p_base->pb_ino)
+                       err = -EEXIST;
+               else if (IS_RDONLY(pno->p_parent,
+                                  pno->p_parent->p_base->pb_ino))
+                       err = -EROFS;
+               else {
+                       struct inode *ino;
+
+                       ino = pno->p_parent->p_base->pb_ino;
+                       err = (*ino->i_ops.inop_mknod)(pno, mode, dev);
+               }
+               P_RELE(pno);
+       } else if (strcmp(v[0].value, "blk") == 0) {
+               /*
+                * We don't support block special files yet.
+                */
+               return -EINVAL;
+       } else if (strcmp(v[0].value, "file") == 0) {
+               int     i;
+               struct inode *ino;
+
+               i = O_CREAT|O_EXCL;
+               INTENT_INIT(&intent, INT_CREAT, &mode, &i);
+               err = _sysio_namei(dir, v[1].value, ND_NEGOK, &intent, &pno);
+               if (err)
+                       return err;
+               err = _sysio_open(pno, O_CREAT|O_EXCL, mode);
+               if (err) {
+                       P_RELE(pno);
+                       return err;
+               }
+               ino = pno->p_base->pb_ino;
+               if (!err && v[6].value) {
+                       struct iovec iovec;
+                       struct intnl_xtvec xtvec;
+                       struct ioctx io_context;
+
+                       /*
+                        * Deposit optional file content.
+                        */
+                       iovec.iov_base = v[6].value;
+                       iovec.iov_len = strlen(v[6].value);
+                       xtvec.xtv_off = 0;
+                       xtvec.xtv_len = iovec.iov_len;
+                       IOCTX_INIT(&io_context,
+                                  1,
+                                  (ioid_t )&io_context,
+                                  1,
+                                  ino,
+                                  &iovec, 1,
+                                  &xtvec, 1);
+                       _sysio_ioctx_enter(&io_context);
+                       err =
+                           (*ino->i_ops.inop_write)(pno->p_base->pb_ino,
+                                                    &io_context);
+                       if (!err) {
+                               ssize_t cc;
+
+                               cc = _sysio_ioctx_wait(&io_context);
+                               if (cc < 0)
+                                       err = cc;
+                               else if ((size_t )cc != iovec.iov_len)
+                                       err = -EIO;             /* huh? */
+                       } else
+                               _sysio_ioctx_complete(&io_context);
+               }
+               i = (*ino->i_ops.inop_close)(ino);
+               if (!err)
+                       err = i;
+               P_RELE(pno);
+       } else 
+               err = -EINVAL;
+
+       return err;
+}
+
+/*
+ * Do mount.
+ *
+ * NB: The passed buffer is altered.
+ */
+static int 
+do_mnt(char *args) 
+{
+       size_t  len;
+       struct named_argument v[] = {
+               { "dev",        NULL },                 /* source (type:dev) */
+               { "dir",        NULL },                 /* target dir */
+               { "fl",         NULL },                 /* flags */
+               { "da",         NULL },                 /* mount data */
+               { NULL,         NULL }
+       };
+       char    *ty, *name;
+       unsigned long flags;
+       struct pnode *dir;
+  
+       len = strlen(args);
+       if (get_args(args, v) - args != (ssize_t )len ||
+           !(v[0].value && v[1].value))
+               return -EINVAL;
+       ty = (char *)get_token(v[0].value, 1, ":", "", name = v[0].value);
+       flags = 0;
+       if (v[2].value) {
+               char    *cp;
+
+               /*
+                * Optional flags.
+                */
+               flags = strtoul(v[2].value, &cp, 0);
+               if (*cp || (flags == ULONG_MAX && errno == ERANGE))
+                       return -EINVAL;
+       }
+
+       if (strlen(v[1].value) == 1 && v[1].value[0] == PATH_SEPARATOR) {
+               /*
+                * Aha! It's root they want. Have to do that special.
+                */
+               return _sysio_mount_root(ty, name, flags, v[3].value);
+       }
+
+       if (!(dir = _sysio_cwd) && !(dir = _sysio_root))
+               return -ENOENT;
+       return _sysio_mount(dir, ty, v[1].value, name, flags, v[3].value);
+}
+
+
+/*
+ * Chdir
+ *
+ * NB: Alters the passed buffer.
+ */
+static int 
+do_cd(char *args) 
+{
+       size_t  len;
+       struct named_argument v[] = {
+               { "dir",        NULL },                 /* directory */
+               { NULL,         NULL }
+       };
+       int     err;
+       struct pnode *dir, *pno;
+
+       len = strlen(args);
+       if (get_args(args, v) - args != (ssize_t )len || !v[0].value)
+               return -EINVAL;
+
+       if (!(dir = _sysio_cwd) && !(dir = _sysio_root))
+               return -ENOENT;
+       err = _sysio_namei(dir, v[0].value, 0, NULL, &pno);
+       if (err)
+               return err;
+       err = _sysio_p_chdir(pno);
+       if (err)
+               P_RELE(pno);
+       return err;
+}
+
+/*
+ * Does a chmod
+ *
+ * NB: Alters passed buffer.
+ */
+static int 
+do_chmd(char *args)
+{
+       size_t  len;
+       struct named_argument v[] = {
+               { "src",        NULL },                 /* path */
+               { "pm",         NULL },                 /* perms */
+               { NULL,         NULL }
+       };
+       long    perms;
+       char    *cp;
+       struct intnl_stat stbuf;
+       int     err;
+       struct pnode *dir, *pno;
+  
+       len = strlen(args);
+       if (get_args(args, v) - args != (ssize_t )len ||
+           !(v[0].value && v[1].value))
+               return -EINVAL;
+       perms = strtol(v[1].value, &cp, 0);
+       if (*cp ||
+           perms < 0 ||
+           (perms == LONG_MAX && errno == ERANGE) ||
+           ((unsigned)perms & ~07777))
+               return -EINVAL;
+       (void )memset(&stbuf, 0, sizeof(stbuf));
+       stbuf.st_mode = (mode_t)perms;
+
+       if (!(dir = _sysio_cwd) && !(dir = _sysio_root))
+               return -ENOENT;
+       err = _sysio_namei(dir, v[0].value, 0, NULL, &pno);
+       if (err)
+               return err;
+       err = _sysio_setattr(pno, pno->p_base->pb_ino, SETATTR_MODE, &stbuf);
+       P_RELE(pno);
+
+       return err;
+}
+
+/*
+ * Execute the given cmd.
+ *
+ * NB: Buf is altered.
+ */
+static int 
+do_command(char *buf)
+{
+       size_t  len;
+       char    *args, *cmd;
+
+       len = strlen(buf);
+       args = (char *)get_token(buf, 1, ",", IGNORE_WHITE, cmd = buf);
+       if (args) {
+               if (strcmp("creat", cmd) == 0)
+                       return do_creat(args);
+               if (strcmp("mnt", cmd) == 0)
+                       return do_mnt(args);
+               if (strcmp("cd", cmd) == 0)
+                       return do_cd(args);
+               if (strcmp("chmd", cmd) == 0)
+                       return do_chmd(args);
+       }
+       return -EINVAL;
+}
+
+/*
+ * Given a command sequence buffer, parse it and run the given
+ * commands 
+ */
+int 
+_sysio_boot(const char *buf) 
+{
+       char    c, *tok;
+       int     err;
+
+       /*
+        * Allocate token buffer.
+        */
+       tok = malloc(strlen(buf));
+       if (!tok)
+               return -ENOMEM;
+       err = 0;
+       while (1) {
+               /*
+                * Discard leading white space.
+                */
+               while ((c = *buf) != '\0' &&
+                      !(c == '{' || strchr(IGNORE_WHITE, c) == NULL))
+                       buf++;
+               if (c == '\0')
+                       break;
+               if (c != '{') {
+                       err = -EINVAL;
+                       break;
+               }
+               /*
+                * Get the command.
+                */
+               buf = (char *)get_token(buf + 1, 0, "}", IGNORE_WHITE, tok);
+               if (!buf) {
+                       err = -EINVAL;
+                       break;
+               }
+               /*
+                * Perform.
+                */
+               err = do_command(tok);
+               if (err)
+                       break;
+       }
+       free(tok);
+       return err;
+}
diff --git a/libsysio/src/inode.c b/libsysio/src/inode.c
new file mode 100644 (file)
index 0000000..6615918
--- /dev/null
@@ -0,0 +1,958 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "sysio.h"
+#include "fs.h"
+#include "mount.h"
+#include "inode.h"
+#include "dev.h"
+
+/*
+ * Support for path and index nodes.
+ */
+
+/*
+ * Size of all names bucket-hash table.
+ */
+#ifndef NAMES_TABLE_LEN
+#define NAMES_TABLE_LEN                251
+#endif
+
+/*
+ * Desired i-nodes cache size is MAX_INODES_MULTIPLIER times the number
+ * of slots in the names hash table.
+ */
+#define MAX_INODES_MULTIPLIER  3
+
+/*
+ * Active i-nodes in the system and the number of same.
+ */
+struct inodes_head _sysio_inodes;
+static size_t n_inodes = 0;
+/*
+ * Desired number of active i-nodes.
+ */
+static size_t max_inodes = (MAX_INODES_MULTIPLIER * NAMES_TABLE_LEN);
+
+/*
+ * System table for rapid access to component names.
+ */
+static LIST_HEAD(, pnode_base) names[NAMES_TABLE_LEN];
+/*
+ * Number of names tracked by the system.
+ */
+static size_t n_names = 0;
+/*
+ * Desired number of base path nodes to maintain.
+ */
+static size_t max_names = (2 * NAMES_TABLE_LEN);
+
+/*
+ * Number of pnodes to grab per memory allocation when filling the
+ * free list.
+ */
+#define PNODES_PER_CHUNK ((8 * 1024) / sizeof(struct pnode) - 2)
+
+#if ZERO_SUM_MEMORY
+/*
+ * Allocation information for pnodes bulk allocation.
+ */
+struct pnodes_block {
+       LIST_ENTRY(pnodes_block) pnblk_links;
+       struct pnode pnblk_nodes[PNODES_PER_CHUNK];
+};
+
+static LIST_HEAD( ,pnodes_block) pnblocks;
+#endif
+
+/*
+ * List of all path-nodes (aliases) referenced by any tree.
+ */
+struct pnodes_head _sysio_pnodes;
+
+/*
+ * Free path-nodes -- Not referenced by any tree for fas reuse.
+ */
+static LIST_HEAD( ,pnode) free_pnodes;
+
+/*
+ * The system root -- Aka `/'.
+ */
+struct pnode *_sysio_root = NULL;
+
+/*
+ * Initialize path and i-node support. Must be called before any other
+ * routine in this module.
+ */
+int
+_sysio_i_init()
+{
+       unsigned i;
+
+       TAILQ_INIT(&_sysio_inodes);
+
+       for (i = 0; i < NAMES_TABLE_LEN; i++)
+               LIST_INIT(&names[i]);
+
+#if ZERO_SUM_MEMORY
+       LIST_INIT(&pnblocks);
+#endif
+       TAILQ_INIT(&_sysio_pnodes);
+       LIST_INIT(&free_pnodes);
+
+       return 0;
+}
+
+/*
+ * Garbage-collect idle i-nodes. We try to keep resource use limited to
+ * MAX_INODES_MULTIPLIER * max_names.
+ */
+static void
+i_reclaim()
+{
+       struct inode *next, *ino;
+       size_t  t;
+
+       /*
+        * I just can't figure out a good way to reclaim these well without
+        * getting really fancy and using complex algorithms. The
+        * base nodes hold references on them for a long time and then
+        * release them. Those will age to the front of the queue and
+        * we have to skip over them. Oh well...
+        */
+       t = MAX_INODES_MULTIPLIER * max_names;
+       if (max_inodes < t) {
+               /*
+                * Oops. Nope. We want more inodes than names entries.
+                */
+               max_inodes = t;
+               return;
+       }
+       next = _sysio_inodes.tqh_first;
+       if (!next)
+               return;
+       t = max_inodes / 2;
+       do {
+               ino = next;
+               next = ino->i_nodes.tqe_next;
+               if (ino->i_ref || ino->i_immune)
+                       continue;
+               _sysio_i_gone(ino);
+       } while (next && n_inodes > t);
+
+       if (n_inodes > t)
+               max_inodes += t;
+}
+
+static unsigned
+hash(struct file_identifier *fid)
+{
+       size_t  n;
+       unsigned char *ucp;
+       unsigned hkey;
+
+       n = fid->fid_len;
+       ucp = fid->fid_data;
+       hkey = 0;
+       do {
+               hkey <<= 1;
+               hkey += *ucp++;
+       } while (--n);
+       return hkey;
+}
+
+/*
+ * Allocate and initialize a new i-node. Returned i-node is referenced.
+ *
+ * NB: The passed file identifier is not copied. It is, therefor, up to the
+ * caller to assure that the value is static until the inode is destroyed.
+ */
+struct inode *
+_sysio_i_new(struct filesys *fs,
+            struct file_identifier *fid,
+            mode_t type,
+            dev_t rdev,
+            unsigned immunity,
+            struct inode_ops *ops,
+            void *private)
+{
+       struct inode *ino;
+       struct itable_entry *head;
+       struct inode_ops operations;
+
+       if (n_inodes > max_inodes) {
+               /*
+                * Try to limit growth.
+                */
+               i_reclaim();
+       }
+
+       ino = malloc(sizeof(struct inode));
+       if (!ino)
+               return NULL;
+       ino->i_ops = *ops;
+       operations = *ops;
+       if (S_ISBLK(type) || S_ISCHR(type) || S_ISFIFO(type)) {
+               struct inode_ops *o;
+
+               /*
+                * Replace some operations sent with
+                * those from the device table.
+                */
+               o = _sysio_dev_lookup(type, rdev);
+               operations.inop_open = o->inop_open;
+               operations.inop_close = o->inop_close;
+               operations.inop_read = o->inop_read;
+               operations.inop_write = o->inop_write;
+               operations.inop_pos = o->inop_pos;
+               operations.inop_iodone = o->inop_iodone;
+               operations.inop_datasync = o->inop_datasync;
+               operations.inop_ioctl = o->inop_ioctl;
+       }
+       I_INIT(ino, fs, type, rdev, &operations, fid, immunity, private);
+       ino->i_ref = 1;
+       TAILQ_INSERT_TAIL(&_sysio_inodes, ino, i_nodes);
+       head = &fs->fs_itbl[hash(fid) % FS_ITBLSIZ];
+       LIST_INSERT_HEAD(head, ino, i_link);
+
+       n_inodes++;
+       assert(n_inodes);
+
+       return ino;
+}
+
+/*
+ * Find existing i-node given i-number and pointers to FS record
+ * and identifier.
+ */
+struct inode *
+_sysio_i_find(struct filesys *fs, struct file_identifier *fid)
+{
+       struct inode *ino;
+       struct itable_entry *head;
+
+       head = &fs->fs_itbl[hash(fid) % FS_ITBLSIZ];
+       /*
+        * Look for existing.
+        */
+       for (ino = head->lh_first; ino; ino = ino->i_link.le_next)
+               if (ino->i_fid->fid_len == fid->fid_len &&
+                   memcmp(ino->i_fid->fid_data,
+                          fid->fid_data,
+                          fid->fid_len) == 0) {
+                       I_REF(ino);
+                       break;
+               }
+
+       return ino;
+}
+
+/*
+ * Force reclaim of idle i-node.
+ */
+void
+_sysio_i_gone(struct inode *ino)
+{
+
+       if (ino->i_ref)
+               abort();
+       if (!ino->i_zombie) 
+               LIST_REMOVE(ino, i_link);
+       TAILQ_REMOVE(&_sysio_inodes, ino, i_nodes);
+       (*ino->i_ops.inop_gone)(ino);
+       free(ino);
+
+       assert(n_inodes);
+       n_inodes--;
+}
+
+/*
+ * Stale inode, zombie it and move it out of the way 
+ */
+void
+_sysio_i_undead(struct inode *ino)
+{
+       
+       LIST_REMOVE(ino, i_link);
+       ino->i_zombie = 1;
+}
+
+/*
+ * Garbage collect idle path (and base path) nodes tracked by the system.
+ */
+static void
+p_reclaim()
+{
+       struct pnode *next, *pno;
+       size_t  t;
+
+       next = _sysio_pnodes.tqh_first;
+       if (!next)
+               return;
+       t = max_names / 2;
+       do {
+               pno = next;
+               if (pno->p_ref) {
+                       next = pno->p_nodes.tqe_next;
+                       continue;
+               }
+               pno->p_ref++;
+               assert(pno->p_ref);
+               (void )_sysio_p_prune(pno);
+               next = pno->p_nodes.tqe_next;
+               assert(pno->p_ref);
+               pno->p_ref--;
+               if (pno->p_ref)
+                       continue;
+               (void )_sysio_p_prune(pno);
+       } while (n_names > t && next);
+
+       if (n_names > t)
+               max_names += t;
+}
+
+/*
+ * Allocate and initialize a new base path node.
+ */
+struct pnode_base *
+_sysio_pb_new(struct qstr *name, struct pnode_base *parent, struct inode *ino)
+{
+       struct pnode_base *pb;
+
+       if (n_names > max_names) {
+               /*
+                * Try to limit growth.
+                */
+               p_reclaim();
+       }
+
+       pb = malloc(sizeof(struct pnode_base) + name->len);
+       if (!pb)
+               return NULL;
+
+       pb->pb_name.name = NULL;
+       pb->pb_name.len = name->len;
+       if (pb->pb_name.len) {
+               char    *cp;
+
+               /*
+                * Copy the passed name.
+                *
+                * We have put the space for the name immediately behind
+                * the record in order to maximize spatial locality.
+                */
+               cp = (char *)pb + sizeof(struct pnode_base);
+               (void )strncpy(cp, name->name, name->len);
+               pb->pb_name.name = cp;
+               assert(name->hashval);
+               pb->pb_name.hashval = name->hashval;
+               LIST_INSERT_HEAD(&names[name->hashval % NAMES_TABLE_LEN],
+                                pb,
+                                pb_names);
+       }
+       pb->pb_ino = ino;
+       LIST_INIT(&pb->pb_children);
+       LIST_INIT(&pb->pb_aliases);
+       if (parent)
+               LIST_INSERT_HEAD(&parent->pb_children, pb, pb_sibs);
+       pb->pb_parent = parent;
+
+       n_names++;
+       assert(n_names);
+
+       return pb;
+}
+
+/*
+ * Destroy base path node, releasing resources back to the system.
+ *
+ * NB: Caller must release the inode referenced by the record.
+ */
+static void
+pb_destroy(struct pnode_base *pb)
+{
+
+       assert(n_names);
+       n_names--;
+
+       assert(!pb->pb_aliases.lh_first);
+       assert(!pb->pb_children.lh_first);
+       assert(!pb->pb_ino);
+       if (pb->pb_name.len)
+               LIST_REMOVE(pb, pb_names);
+       if (pb->pb_parent)
+               LIST_REMOVE(pb, pb_sibs);
+
+#ifndef NDEBUG
+       /*
+        * This can help us catch pb-nodes that are free'd redundantly.
+        */
+       pb->pb_name.hashval = 0;
+#endif
+       free(pb);
+}
+
+/*
+ * Force reclaim of idle base path node.
+ */
+void
+_sysio_pb_gone(struct pnode_base *pb)
+{
+
+       if (pb->pb_ino)
+               I_RELE(pb->pb_ino);
+       pb->pb_ino = NULL;
+
+       pb_destroy(pb);
+}
+
+/*
+ * Generate more path (alias) nodes for the fast allocator.
+ */
+static void
+more_pnodes()
+{
+       size_t  n;
+#if ZERO_SUM_MEMORY
+       struct pnodes_block *pnblk;
+#endif
+       struct pnode *pno;
+
+#if ZERO_SUM_MEMORY
+       pnblk = malloc(sizeof(struct pnodes_block));
+       pno = NULL;
+       if (pnblk) {
+               LIST_INSERT_HEAD(&pnblocks, pnblk, pnblk_links);
+               pno = pnblk->pnblk_nodes;
+       }
+#else
+       pno = malloc(PNODES_PER_CHUNK * sizeof(struct pnode));
+#endif
+       if (!pno)
+               return;
+       n = PNODES_PER_CHUNK;
+       do {
+               LIST_INSERT_HEAD(&free_pnodes, pno, p_links);
+               pno++;
+       } while (--n);
+}
+
+#if ZERO_SUM_MEMORY
+/*
+ * Shutdown
+ */
+void
+_sysio_i_shutdown()
+{
+       struct pnodes_block *pnblk;
+
+       while ((pnblk = pnblocks.lh_first)) {
+               LIST_REMOVE(pnblk, pnblk_links);
+               free(pnblk);
+       }
+}
+#endif
+
+/*
+ * Allocate, initialize and establish appropriate links for new path (alias)
+ * node.
+ */
+struct pnode *
+_sysio_p_new_alias(struct pnode *parent,
+                  struct pnode_base *pb,
+                  struct mount *mnt)
+{
+       struct pnode *pno;
+
+       assert(!pb->pb_name.name || pb->pb_name.hashval);
+
+       pno = free_pnodes.lh_first;
+       if (!pno) {
+               more_pnodes();
+               pno = free_pnodes.lh_first;
+       }
+       if (!pno)
+               return NULL;
+       LIST_REMOVE(pno, p_links);
+
+       pno->p_ref = 1;
+       pno->p_parent = parent;
+       if (!pno->p_parent)
+               pno->p_parent = pno;
+       pno->p_base = pb;
+       pno->p_mount = mnt;
+       pno->p_cover = NULL;
+       LIST_INSERT_HEAD(&pb->pb_aliases, pno, p_links);
+       TAILQ_INSERT_TAIL(&_sysio_pnodes, pno, p_nodes);
+
+       return pno;
+}
+
+/*
+ * For reclamation of idle path (alias) node.
+ */
+void
+_sysio_p_gone(struct pnode *pno)
+{
+       struct pnode_base *pb;
+
+       assert(!pno->p_ref);
+       assert(!pno->p_cover);
+
+       TAILQ_REMOVE(&_sysio_pnodes, pno, p_nodes);
+       LIST_REMOVE(pno, p_links);
+
+       pb = pno->p_base;
+       if (!(pb->pb_aliases.lh_first || pb->pb_children.lh_first))
+               _sysio_pb_gone(pb);
+
+       LIST_INSERT_HEAD(&free_pnodes, pno, p_links);
+}
+
+/*
+ * (Re)Validate passed path node.
+ */
+int
+_sysio_p_validate(struct pnode *pno, struct intent *intnt, const char *path)
+{
+       struct inode *ino;
+       struct pnode_base *rootpb;
+       int     err;
+
+       ino = pno->p_base->pb_ino;
+       /*
+        * An invalid pnode will not have an associated inode. We'll use
+        * the FS root inode, then -- It *must* be valid.
+        */
+       rootpb = pno->p_mount->mnt_root->p_base;
+       assert(rootpb->pb_ino);
+       err =
+           rootpb->pb_ino->i_ops.inop_lookup(pno,
+                                             &ino,
+                                             intnt,
+                                             path);
+       /*
+        * If the inode lookup returns a different inode, release the old if
+        * present and point to the new.
+        */
+       if (err || pno->p_base->pb_ino != ino) {
+               if (pno->p_base->pb_ino)
+                       I_RELE(pno->p_base->pb_ino);
+               pno->p_base->pb_ino = ino;
+       }
+       return err;
+}
+
+/*
+ * Find (or create!) an alias for the given parent and name. A misnomer,
+ * really -- This is a "get". Returned path node is referenced.
+ */
+int
+_sysio_p_find_alias(struct pnode *parent,
+                   struct qstr *name,
+                   struct pnode **pnop)
+{
+       struct pnode_base *pb;
+       int     err;
+       struct pnode *pno;
+
+       /*
+        * Find the named child.
+        */
+       if (name->len) {
+               /*
+                * Try the names table.
+                */
+               pb = names[name->hashval % NAMES_TABLE_LEN].lh_first;
+               while (pb) {
+                       if (pb->pb_parent == parent->p_base &&
+                           pb->pb_name.len == name->len &&
+                           strncmp(pb->pb_name.name,
+                                   name->name,
+                                   name->len) == 0)
+                               break;
+                       pb = pb->pb_names.le_next;
+               }
+       } else {
+               /*
+                * Brute force through the parent's list of children.
+                */
+               pb = parent->p_base->pb_children.lh_first;
+               while (pb) {
+                       if (pb->pb_parent == parent->p_base &&
+                           pb->pb_name.len == name->len &&
+                           strncmp(pb->pb_name.name,
+                                   name->name,
+                                   name->len) == 0)
+                               break;
+                       pb = pb->pb_sibs.le_next;
+               }
+       }
+       if (!pb) {
+               /*
+                * None found, create new child.
+                */
+               pb = _sysio_pb_new(name, parent->p_base, NULL);
+               if (!pb)
+                       return -ENOMEM;
+       }
+       /*
+        * Now find the proper alias. It's the one with the passed
+        * parent.
+        */
+       err = 0;
+       pno = pb->pb_aliases.lh_first;
+       while (pno) {
+               if (pno->p_parent == parent) {
+                       P_REF(pno);
+                       break;
+               }
+               pno = pno->p_links.le_next;
+       }
+       if (!pno) {
+               /*
+                * Hmm. No alias. Just create an invalid one, to be
+                * validated later.
+                */
+               pno = _sysio_p_new_alias(parent, pb, parent->p_mount);
+               if (!pno)
+                       err = -ENOMEM;
+       }
+       if (!err)
+               *pnop = pno;
+       return err;
+}
+
+/*
+ * Prune idle path base nodes freom the passed sub-tree, including the root.
+ */
+static void
+_sysio_prune(struct pnode_base *rpb)
+{
+       struct pnode_base *nxtpb, *pb;
+
+       nxtpb = rpb->pb_children.lh_first;
+       while ((pb = nxtpb)) {
+               nxtpb = pb->pb_sibs.le_next;
+               if (pb->pb_aliases.lh_first)
+                       continue;
+               if (pb->pb_children.lh_first) {
+                       _sysio_prune(pb);
+                       continue;
+               }
+               _sysio_pb_gone(pb);
+       }
+       if (rpb->pb_children.lh_first)
+               return;
+       _sysio_pb_gone(rpb);
+}
+
+/*
+ * Prune idle nodes from the passed sub-tree, including the root.
+ *
+ * Returns the number of aliases on the same mount that could not be pruned.
+ * i.e. a zero return means the entire sub-tree is gone.
+ */
+size_t
+_sysio_p_prune(struct pnode *root)
+{
+       size_t  count;
+       struct pnode_base *nxtpb, *pb;
+       struct pnode *nxtpno, *pno;
+
+       count = 0;
+       nxtpb = root->p_base->pb_children.lh_first;
+       while ((pb = nxtpb)) {
+               nxtpb = pb->pb_sibs.le_next;
+               nxtpno = pb->pb_aliases.lh_first;
+               if (!nxtpno) {
+                       _sysio_prune(pb);
+                       continue;
+               }
+               while ((pno = nxtpno)) {
+                       nxtpno = pno->p_links.le_next;
+                       if (pno->p_mount != root->p_mount) {
+                               /*
+                                * Not the alias we were looking for.
+                                */
+                               continue;
+                       }
+                       if (pno->p_base->pb_children.lh_first) {
+                               /*
+                                * Node is interior. Recurse.
+                                */
+                               count += _sysio_p_prune(pno);
+                               continue;
+                       }
+                       if (pno->p_ref) {
+                               /*
+                                * Can't prune; It's active.
+                                */
+                               count++;
+                               continue;
+                       }
+                       assert(!pno->p_cover);          /* covered => ref'd! */
+                       assert(!pno->p_base->pb_name.name ||
+                              pno->p_base->pb_name.hashval);
+                       /*
+                        * Ok to prune.
+                        */
+                       if (pno->p_mount->mnt_root == pno) {
+#ifndef AUTOMOUNT_FILE_NAME
+                               count++;
+                               continue;
+#else
+                               /*
+                                * This is an automount-point. Must
+                                * unmount before relcaim.
+                                */
+                               P_REF(pno);
+                               if (_sysio_do_unmount(pno->p_mount) != 0) {
+                                       P_RELE(pno);
+                                       count++;
+                               }
+                               continue;
+#endif
+                       }
+                       _sysio_p_gone(pno);
+               }
+       }
+
+       if (count) {
+               /*
+                * Can't get the root or we disconnect the sub-trees.
+                */
+               return count + (root->p_ref ? 1 : 0);
+       }
+
+       /*
+        * All that is left is the root. Try for it too.
+        */
+       if (root->p_ref) {
+               count++;
+       } else if (root->p_mount->mnt_root == root) {
+#ifndef AUTOMOUNT_FILE_NAME
+               count++;
+#else
+               /*
+                * This is an automount-point. Must
+                * unmount before relcaim.
+                */
+               P_REF(root);
+               if (_sysio_do_unmount(root->p_mount) != 0) {
+                       P_RELE(root);
+                       count++;
+               }
+#endif
+       } else
+               _sysio_p_gone(root);
+
+       return count;
+}
+
+/*
+ * Return path tracked by the base path node ancestor chain.
+ *
+ * Remember, base path nodes track the path relative to the file system and
+ * path (alias) nodes track path relative to our name space -- They cross
+ * mount points.
+ */
+char *
+_sysio_pb_path(struct pnode_base *pb, const char separator)
+{
+       char    *buf;
+       size_t  len, n;
+       struct pnode_base *tmp;
+       char    *cp;
+
+       /*
+        * First pass: Traverse to the root of the sub-tree, remembering
+        * lengths.
+        */
+       len = 0;
+       tmp = pb;
+       do {
+               n = tmp->pb_name.len;
+               len += tmp->pb_name.len;
+               if (n)
+                       len++;
+               tmp = tmp->pb_parent;
+       } while (tmp);
+       if (!len)
+               len++;
+       /*
+        * Alloc space.
+        */
+       buf = malloc(len + 1);
+       if (!buf)
+               return NULL;
+       /*
+        * Fill in the path buffer -- Backwards, since we're starting
+        * from the end.
+        */
+       cp = buf;
+       *cp = separator;
+       cp += len;
+       *cp = '\0';                                     /* NUL term */
+       tmp = pb;
+       do {
+               cp -= tmp->pb_name.len;
+               n = tmp->pb_name.len;
+               if (n) {
+                       (void )strncpy(cp, tmp->pb_name.name, n);
+                       *--cp = separator;
+               }
+               tmp = tmp->pb_parent;
+       } while (tmp);
+
+       return buf;
+}
+
+/*
+ * Common set attributes routine.
+ */
+int
+_sysio_setattr(struct pnode *pno,
+              struct inode *ino,
+              unsigned mask,
+              struct intnl_stat *stbuf)
+{
+       /* It is possible that pno is null (for ftruncate call). */
+
+       if (pno) {
+       assert(!(pno->p_base->pb_ino && ino) || pno->p_base->pb_ino == ino);
+       if (IS_RDONLY(pno, ino))
+               return -EROFS;
+       }
+       if (!ino && pno->p_base->pb_ino)
+               ino = pno->p_base->pb_ino;
+       return (*ino->i_ops.inop_setattr)(pno, ino, mask, stbuf);
+}
+
+/*
+ * Do nothing.
+ */
+void
+_sysio_do_noop()
+{
+
+       return;
+}
+
+/*
+ * Abort.
+ */
+void
+_sysio_do_illop()
+{
+
+       abort();
+}
+
+/*
+ * Return -EBADF
+ */
+int
+_sysio_do_ebadf()
+{
+
+       return -EBADF;
+}
+
+/*
+ * Return -EINVAL
+ */
+int
+_sysio_do_einval()
+{
+
+       return -EINVAL;
+}
+
+/*
+ * Return -ENOENT
+ */
+int
+_sysio_do_enoent()
+{
+
+       return -ENOENT;
+}
+
+/*
+ * Return -ESPIPE
+ */
+int
+_sysio_do_espipe()
+{
+
+       return -ESPIPE;
+}
+
+/*
+ * Return -EISDIR
+ */
+int
+_sysio_do_eisdir()
+{
+
+       return -EISDIR;
+}
+
+/*
+ * Return -ENOSYS
+ */
+int
+_sysio_do_enosys()
+{
+
+       return -ENOSYS;
+}
diff --git a/libsysio/src/ioctl.c b/libsysio/src/ioctl.c
new file mode 100644 (file)
index 0000000..d157c9b
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "inode.h"
+#include "file.h"
+
+#include "sysio-symbols.h"
+
+int
+SYSIO_INTERFACE_NAME(ioctl)(int fd, unsigned long request, ...)
+{
+       int     err;
+       struct file *fil;
+       va_list ap;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       err = 0;
+       fil = _sysio_fd_find(fd);
+       if (!fil) {
+               err = -EBADF;
+               goto out;
+       }
+
+       va_start(ap, request);
+       err = fil->f_ino->i_ops.inop_ioctl(fil->f_ino, request, ap);
+       va_end(ap);
+
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+
+#ifdef __GLIBC__
+#undef __ioctl
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(ioctl), 
+                    PREPEND(__, SYSIO_INTERFACE_NAME(ioctl)))
+#endif
+
+#ifdef BSD
+#undef _ioctl
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(ioctl), 
+                    PREPEND(_, SYSIO_INTERFACE_NAME(ioctl)))
+#endif
diff --git a/libsysio/src/ioctx.c b/libsysio/src/ioctx.c
new file mode 100644 (file)
index 0000000..70c1b3e
--- /dev/null
@@ -0,0 +1,549 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2004 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "inode.h"
+#include "xtio.h"
+
+/*
+ * Asynchronous IO context support.
+ */
+
+/*
+ * Arguments to IO vector enumerator callback when used by _sysio_doio().
+ */
+struct doio_helper_args {
+       ssize_t (*f)(void *, size_t, _SYSIO_OFF_T, void *);     /* base func */
+       void    *arg;                                           /* caller arg */
+};
+
+/*
+ * List of all outstanding (in-flight) asynch IO requests tracked
+ * by the system.
+ */
+static LIST_HEAD( ,ioctx) aioq;
+
+/*
+ * Free callback entry.
+ */
+#define cb_free(cb)            free(cb)
+
+/*
+ * Initialization. Must be called before using any other routine in this
+ * module.
+ */
+int
+_sysio_ioctx_init()
+{
+
+       LIST_INIT(&aioq);
+       return 0;
+}
+
+/*
+ * Enter an IO context onto the async IO events queue.
+ */
+void
+_sysio_ioctx_enter(struct ioctx *ioctx)
+{
+
+       LIST_INSERT_HEAD(&aioq, ioctx, ioctx_link);
+}
+
+/*
+ * Allocate and initialize a new IO context.
+ */
+struct ioctx *
+_sysio_ioctx_new(struct inode *ino,
+                int wr,
+                const struct iovec *iov,
+                size_t iovlen,
+                const struct intnl_xtvec *xtv,
+                size_t xtvlen)
+{
+       struct ioctx *ioctx;
+
+       ioctx = malloc(sizeof(struct ioctx));
+       if (!ioctx)
+               return NULL;
+
+       I_REF(ino);
+
+       IOCTX_INIT(ioctx,
+                  0,
+                  (ioid_t )ioctx,
+                  wr,
+                  ino,
+                  iov, iovlen,
+                  xtv, xtvlen);
+
+       /*
+        * Link request onto the outstanding requests queue.
+        */
+       _sysio_ioctx_enter(ioctx);
+
+       return ioctx;
+}
+
+/*
+ * Add an IO completion call-back to the end of the context call-back queue.
+ * These are called in iowait() as the last thing, right before the context
+ * is destroyed.
+ *
+ * They are called in order. Beware.
+ */
+int
+_sysio_ioctx_cb(struct ioctx *ioctx,
+               void (*f)(struct ioctx *, void *),
+               void *data)
+{
+       struct ioctx_callback *entry;
+
+       entry = malloc(sizeof(struct ioctx_callback));
+       if (!entry)
+               return -ENOMEM;
+
+       entry->iocb_f = f;
+       entry->iocb_data = data;
+
+       TAILQ_INSERT_TAIL(&ioctx->ioctx_cbq, entry, iocb_next);
+
+       return 0;
+}
+
+/*
+ * Find an IO context given it's identifier.
+ *
+ * NB: This is dog-slow. If there are alot of these, we will need to change
+ * this implementation.
+ */
+struct ioctx *
+_sysio_ioctx_find(ioid_t id)
+{
+       struct ioctx *ioctx;
+
+       for (ioctx = aioq.lh_first; ioctx; ioctx = ioctx->ioctx_link.le_next)
+               if (ioctx->ioctx_id == id)
+                       return ioctx;
+
+       return NULL;
+}
+
+/*
+ * Wait for asynchronous IO operation to complete, return status
+ * and dispose of the context.
+ *
+ * Note:
+ * The context is no longer valid after return.
+ */
+ssize_t
+_sysio_ioctx_wait(struct ioctx *ioctx)
+{
+       ssize_t cc;
+
+       /*
+        * Wait for async operation to complete.
+        */
+       while (!(ioctx->ioctx_done ||
+                (*ioctx->ioctx_ino->i_ops.inop_iodone)(ioctx)))
+               ;
+
+       /*
+        * Get status.
+        */
+       cc = ioctx->ioctx_cc;
+       if (cc < 0)
+               cc = -ioctx->ioctx_errno;
+
+       /*
+        * Dispose.
+        */
+       _sysio_ioctx_complete(ioctx);
+
+       return cc;
+}
+
+/*
+ * Free callback entry.
+ */
+void
+_sysio_ioctx_cb_free(struct ioctx_callback *cb)
+{
+
+       cb_free(cb);
+}
+
+/*
+ * Complete an asynchronous IO request.
+ */
+void
+_sysio_ioctx_complete(struct ioctx *ioctx)
+{
+       struct ioctx_callback *entry;
+
+       /*
+        * Run the call-back queue.
+        */
+       while ((entry = ioctx->ioctx_cbq.tqh_first)) {
+               TAILQ_REMOVE(&ioctx->ioctx_cbq, entry, iocb_next);
+               (*entry->iocb_f)(ioctx, entry->iocb_data);
+               cb_free(entry);
+       }
+
+       /*
+        * Unlink from the file record's outstanding request queue.
+        */
+       LIST_REMOVE(ioctx, ioctx_link);
+
+       if (ioctx->ioctx_fast)
+               return;
+
+       I_RELE(ioctx->ioctx_ino);
+
+       free(ioctx);
+}
+
+/*
+ * General help validating strided-IO vectors.
+ *
+ * A driver may call this to make sure underflow/overflow of an off_t can't
+ * occur and overflow of a ssize_t can't occur when writing. The sum
+ * of the reconciled transfer length is returned or some appropriate
+ * error depending on underflow/overflow.
+ *
+ * The following algorithm assumes:
+ *
+ * a) sizeof(size_t) >= sizeof(ssize_t)
+ * b) 2's complement arithmetic
+ * c) The compiler won't optimize away code because it's developers
+ *     believed that something with an undefined result in `C' can't happen.
+ */
+ssize_t
+_sysio_validx(const struct intnl_xtvec *xtv, size_t xtvlen,
+             const struct iovec *iov, size_t iovlen,
+             _SYSIO_OFF_T limit)
+{
+       ssize_t acc, cc;
+       struct iovec iovec;
+       struct intnl_xtvec xtvec;
+       _SYSIO_OFF_T off;
+
+       if (!(xtvlen && iovlen))
+               return -EINVAL;
+
+       acc = 0;
+       xtvec.xtv_len = iovec.iov_len = 0;
+       do {
+               while (!xtvec.xtv_len) {
+                       if (!xtvlen--)
+                               break;
+                       if (!xtv->xtv_len) {
+                               xtv++;
+                               continue;
+                       }
+                       xtvec = *xtv++;
+                       if (xtvec.xtv_off < 0)
+                               return -EINVAL;
+               }
+               if (!xtvec.xtv_len)
+                       break;
+               do {
+                       while (!iovec.iov_len) {
+                               if (!iovlen--)
+                                       break;
+                               if (!iov->iov_len) {
+                                       iov++;
+                                       continue;
+                               }
+                               iovec = *iov++;
+                       }
+                       if (!iovec.iov_len)
+                               break;
+                       cc = iovec.iov_len;
+                       if (cc < 0)
+                               return -EINVAL;
+                       if ((size_t )cc > xtvec.xtv_len)
+                               cc = xtvec.xtv_len;
+                       xtvec.xtv_len -= cc;
+                       iovec.iov_len -= cc;
+                       off = xtvec.xtv_off + cc;
+                       if (xtvec.xtv_off && off <= xtvec.xtv_off)
+                               return off < 0 ? -EINVAL : -EOVERFLOW;
+                       if (off > limit)
+                               return -EFBIG;
+                       xtvec.xtv_off = off;
+                       cc += acc;
+                       if (acc && (cc <= acc))
+                               return -EINVAL;
+                       acc = cc;
+               } while (xtvec.xtv_len && iovlen);
+       } while ((xtvlen || xtvec.xtv_len) && iovlen);
+       return acc;
+}
+
+/*
+ */
+ssize_t
+_sysio_enumerate_extents(const struct intnl_xtvec *xtv, size_t xtvlen,
+                        const struct iovec *iov, size_t iovlen,
+                        ssize_t (*f)(const struct iovec *, int,
+                                     _SYSIO_OFF_T,
+                                     ssize_t,
+                                     void *),
+                        void *arg)
+{
+       ssize_t acc, tmp, cc;
+       struct iovec iovec;
+       struct intnl_xtvec xtvec;
+       const struct iovec *start;
+       _SYSIO_OFF_T off;
+       size_t  n;
+       size_t  remain;
+       
+       acc = 0;
+       iovec.iov_len = 0;
+       while (xtvlen) {
+               /*
+                * Coalesce contiguous extent vector entries.
+                */
+               off = xtvec.xtv_off = xtv->xtv_off;
+               off += xtvec.xtv_len = xtv->xtv_len;
+               while (++xtv, --xtvlen) {
+                       if (off != xtv->xtv_off) {
+                               /*
+                                * Not contiguous.
+                                */
+                               break;
+                       }
+                       if (!xtv->xtv_len) {
+                               /*
+                                * Zero length.
+                                */
+                               continue;
+                       }
+                       off += xtv->xtv_len;
+                       xtvec.xtv_len += xtv->xtv_len;
+               }
+               while (xtvec.xtv_len) {
+                       if (iovec.iov_len) {
+                               tmp = iovec.iov_len; 
+                               if (iovec.iov_len > xtvec.xtv_len) {
+                                       iovec.iov_len = xtvec.xtv_len;
+                               } 
+                               cc =
+                                   (*f)(&iovec, 1,
+                                        xtvec.xtv_off,
+                                        xtvec.xtv_len,
+                                        arg);
+                               if (cc <= 0) {
+                                       if (acc)
+                                               return acc;
+                                       return cc;
+                               }
+                               iovec.iov_base = (char *)iovec.iov_base + cc;
+                               iovec.iov_len = tmp - cc; 
+                               tmp = cc + acc;
+                               if (acc && tmp <= acc)
+                                       abort();                /* paranoia */
+                               acc = tmp;
+                       } else {
+                               start = iov;
+                               n = xtvec.xtv_len;
+                               do {
+                                       if (iov->iov_len > n) {
+                                               /*
+                                                * That'll do.
+                                                */
+                                               break;
+                                       }
+                                       n -= iov->iov_len;
+                                       iov++;
+                               } while (--iovlen);
+                               if (iov == start) {
+                                       iovec = *iov++;
+#if 0
+                                       if (iovec.iov_len > n) {
+                                               iovec.iov_len = n;
+                                       } 
+#endif
+                                       continue;
+                               }
+                               remain = xtvec.xtv_len - n;
+                               cc =
+                                   (*f)(start, iov - start,
+                                                                xtvec.xtv_off,
+                                                                xtvec.xtv_len - n,
+                                        arg);
+                               if (cc <= 0) {
+                                       if (acc)
+                                               return acc;
+                                       return cc;
+                               }
+                                                               
+                               tmp = cc + acc;
+                               if (acc && tmp <= acc)
+                                       abort();                /* paranoia */
+                               acc = tmp;
+                               
+                               if (remain && !iovlen) 
+                                       return acc;
+                               
+                               remain -= cc;
+                               if (remain)
+                                       return acc;             /* short */
+                       }
+                       xtvec.xtv_off += cc;
+                       xtvec.xtv_len -= cc;
+               }
+       }
+       return acc;
+}
+
+ssize_t
+_sysio_enumerate_iovec(const struct iovec *iov, size_t count,
+                      _SYSIO_OFF_T off,
+                      ssize_t limit,
+                      ssize_t (*f)(void *, size_t, _SYSIO_OFF_T, void *),
+                      void *arg)
+{
+       ssize_t acc, cc;
+       size_t  n;
+       unsigned indx;
+       size_t  remain;
+
+       if (!count)
+               return -EINVAL;
+       assert(limit >= 0);
+       acc = 0;
+       n = limit;
+       for (indx = 0; n && indx < count; indx++) {
+               if (iov[indx].iov_len < n) {
+                       cc = (ssize_t )iov[indx].iov_len;
+                       if (cc < 0)
+                               return -EINVAL;
+               } else
+                       cc = (ssize_t )n;
+               if (!cc)
+                       continue;
+               n -= cc;
+               cc += acc;
+               if (acc && cc <= acc)
+                       return -EINVAL;
+               acc = cc;
+       }
+       if (!acc)
+               return 0;
+       acc = 0;
+       do {
+               if (!iov->iov_len) {
+                       iov++;
+                       continue;
+               }
+               n =
+                   iov->iov_len < (size_t )limit
+                     ? iov->iov_len
+                     : (size_t )limit;
+               cc = (*f)(iov->iov_base, n, off, arg);
+               if (cc <= 0) {
+                       if (acc)
+                               return acc;
+                       return cc;
+               }
+               off += cc;
+               limit -= cc;
+               remain = iov->iov_len - cc;
+               cc += acc;
+               if (acc && cc <= acc)
+                       abort();                        /* bad driver! */
+               acc = cc;
+               if (remain || !limit)
+                       break;                          /* short/limited read */
+               iov++;
+       } while (--count);
+       return acc;
+}
+
+static ssize_t
+_sysio_doio_helper(const struct iovec *iov, int count,
+                  _SYSIO_OFF_T off,
+                  ssize_t limit,
+                  struct doio_helper_args *args)
+{
+
+       return _sysio_enumerate_iovec(iov, count,
+                                     off, limit,
+                                     args->f,
+                                     args->arg);
+}
+
+/*
+ * A meta-driver for the whole strided-io process. Appropriate when
+ * the driver can't handle anything but simple p{read,write}-like
+ * interface.
+ */
+ssize_t
+_sysio_doio(const struct intnl_xtvec *xtv, size_t xtvlen,
+           const struct iovec *iov, size_t iovlen,
+           ssize_t (*f)(void *, size_t, _SYSIO_OFF_T, void *),
+           void *arg)
+{
+       struct doio_helper_args arguments;
+
+       arguments.f = f;
+       arguments.arg = arg;
+       return _sysio_enumerate_extents(xtv, xtvlen,
+                                       iov, iovlen,
+                                       (ssize_t (*)(const struct iovec *, int,
+                                                    _SYSIO_OFF_T,
+                                                    ssize_t,
+                                                    void *))_sysio_doio_helper,
+                                       &arguments);
+}
diff --git a/libsysio/src/iowait.c b/libsysio/src/iowait.c
new file mode 100644 (file)
index 0000000..28035e3
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "inode.h"
+
+/*
+ * Asynch IO support for the API.
+ */
+
+/*
+ * Poll status of asynch IO request.
+ */
+int
+SYSIO_INTERFACE_NAME(iodone)(ioid_t ioid)
+{
+       struct ioctx *ioctx;
+       int rc;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       ioctx = _sysio_ioctx_find(ioid);
+       if (!ioctx)
+               SYSIO_INTERFACE_RETURN(-1, -EINVAL);
+
+       rc =
+           (ioctx->ioctx_done ||
+            (*ioctx->ioctx_ino->i_ops.inop_iodone)(ioctx));
+
+       SYSIO_INTERFACE_RETURN(rc < 0 ? -1 : rc, rc < 0 ? rc : 0);
+}
+
+/*
+ * Wait for completion of and return results from identified asynch IO
+ * request.
+ *
+ * The identifier is no longer valid after return.
+ */
+ssize_t
+SYSIO_INTERFACE_NAME(iowait)(ioid_t ioid)
+{
+       struct ioctx *ioctx;
+       ssize_t cc;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       ioctx = _sysio_ioctx_find(ioid);
+       if (!ioctx)
+               SYSIO_INTERFACE_RETURN(-1, -EINVAL);
+
+       cc = _sysio_ioctx_wait(ioctx);
+       SYSIO_INTERFACE_RETURN(cc < 0 ? -1 : cc, cc < 0 ? (int )cc : 0);
+}
diff --git a/libsysio/src/link.c b/libsysio/src/link.c
new file mode 100644 (file)
index 0000000..4c278b5
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "mount.h"
+#include "inode.h"
+#include "sysio-symbols.h"
+
+int
+SYSIO_INTERFACE_NAME(link)(const char *oldpath, const char *newpath)
+{
+       struct intent intent;
+       int     err;
+       struct pnode *old, *new;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       INTENT_INIT(&intent, 0, NULL, NULL);
+       err = _sysio_namei(_sysio_cwd, oldpath, 0, &intent, &old);
+       if (err)
+               goto out;
+       if (S_ISDIR(old->p_base->pb_ino->i_mode)) {
+               err = -EPERM;
+               goto error1;
+       }
+       INTENT_INIT(&intent, INT_UPDPARENT, NULL, NULL);
+       new = NULL;
+       err = _sysio_namei(_sysio_cwd, newpath, ND_NEGOK, &intent, &new);
+       if (err)
+               goto error1;
+       if (new->p_base->pb_ino) {
+               err = -EEXIST;
+               goto error2;
+       }
+       if (old->p_mount->mnt_root != new->p_mount->mnt_root) {
+               err = -EXDEV;
+               goto error2;
+       }
+       err = old->p_base->pb_ino->i_ops.inop_link(old, new);
+       if (err)
+               goto error2;
+       /*
+        * The new p-node must be pointed at the inode referenced by the old.
+        */
+       assert(!new->p_base->pb_ino && old->p_base->pb_ino);
+       new->p_base->pb_ino = old->p_base->pb_ino;
+       I_REF(new->p_base->pb_ino);
+
+error2:
+       P_RELE(new);
+error1:
+       P_RELE(old);
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#ifdef REDSTORM
+#undef __link
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(link), 
+                    PREPEND(__, SYSIO_INTERFACE_NAME(link)))
+#endif
diff --git a/libsysio/src/lseek.c b/libsysio/src/lseek.c
new file mode 100644 (file)
index 0000000..d16efc4
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "inode.h"
+#include "file.h"
+
+#include "sysio-symbols.h"
+
+static _SYSIO_OFF_T
+_sysio_lseek(int fd, _SYSIO_OFF_T offset, int whence)
+{
+       struct file *fil;
+       _SYSIO_OFF_T off, pos;
+       struct intnl_stat stbuf;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fil = _sysio_fd_find(fd);
+       if (!fil)
+               return -EBADF;
+
+       off = -1;
+       switch (whence) {
+       
+       case SEEK_SET:
+               off = 0;
+               break;
+       case SEEK_CUR:
+               off = fil->f_pos;
+               break;
+       case SEEK_END:
+               {
+                       int     err;
+
+                       err =
+                           (*fil->f_ino->i_ops.inop_getattr)(NULL,
+                                                             fil->f_ino,
+                                                             &stbuf);
+                       if (err)
+                               SYSIO_INTERFACE_RETURN((off_t )-1, (int )err);
+       
+               }
+               off = stbuf.st_size;
+               break;
+       default:
+               return -EINVAL;
+       }
+       pos = off + offset;
+       if ((offset < 0 && -offset > off) || (offset > 0 && pos <= off))
+               SYSIO_INTERFACE_RETURN((off_t )-1, -EINVAL);
+
+#ifdef O_LARGEFILE
+       if (pos >= ((fil->f_flags & O_LARGEFILE) ? _SYSIO_OFF_T_MAX : LONG_MAX))
+               SYSIO_INTERFACE_RETURN((off_t )-1, -EOVERFLOW);
+#else
+       if (pos >= _SYSIO_OFF_T_MAX)
+               SYSIO_INTERFACE_RETURN((off_t )-1, -EOVERFLOW);
+#endif
+       pos = (fil->f_ino->i_ops.inop_pos)(fil->f_ino, pos);
+       if (pos < 0)
+               SYSIO_INTERFACE_RETURN((off_t )-1, (int )pos);
+       fil->f_pos = pos;
+       SYSIO_INTERFACE_RETURN((off_t )pos, 0);
+}
+
+#if _LARGEFILE64_SOURCE
+#undef lseek64
+sysio_sym_weak_alias(_sysio_lseek, SYSIO_INTERFACE_NAME(lseek64))
+#ifdef __GLIBC__
+#undef __lseek64
+sysio_sym_weak_alias(_sysio_lseek, PREPEND(__, SYSIO_INTERFACE_NAME(lseek64)))
+#endif
+#ifdef REDSTORM
+#undef __libc_lseek64
+sysio_sym_weak_alias(_sysio_lseek, 
+                    PREPEND(__, SYSIO_INTERFACE_NAME(libc_lseek64)))
+#endif
+#endif
+
+#undef lseek
+
+extern off_t
+SYSIO_INTERFACE_NAME(lseek)(int fd, off_t offset, int whence)
+{
+       _SYSIO_OFF_T off;
+       off_t   rtn;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       off = _sysio_lseek(fd, offset, whence);
+       if (off < 0)
+               SYSIO_INTERFACE_RETURN((off_t )-1, (int )off);
+       rtn = (off_t )off;
+       assert(rtn == off);
+       SYSIO_INTERFACE_RETURN(rtn, 0);
+}
+
+#ifdef __GLIBC__
+#undef __lseek
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(lseek),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(lseek)))
+#endif
+
+#if 0
+#ifdef __linux__
+#undef llseek
+int
+SYSIO_INTERFACE_NAME(llseek)(unsigned int fd __IS_UNUSED,
+       unsigned long offset_high __IS_UNUSED,
+       unsigned long offset_low __IS_UNUSED,
+       loff_t *result __IS_UNUSED,
+       unsigned int whence __IS_UNUSED)
+{
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       /*
+        * Something is very wrong if this was called.
+        */
+       SYSIO_INTERFACE_ENTER;
+       SYSIO_INTERFACE_RETURN(-1, -ENOTSUP);
+}
+
+#undef __llseek
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(llseek), 
+                    PREPEND(__, SYSIO_INTERFACE_NAME(llseek)))
+#endif
+#endif
diff --git a/libsysio/src/mkdir.c b/libsysio/src/mkdir.c
new file mode 100644 (file)
index 0000000..c4c6cb5
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "inode.h"
+#include "fs.h"
+#include "mount.h"
+#include "sysio-symbols.h"
+
+int
+SYSIO_INTERFACE_NAME(mkdir)(const char *path, mode_t mode)
+{
+       int     err;
+       struct intent intent;
+       struct pnode *pno;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       INTENT_INIT(&intent, INT_CREAT, &mode, NULL);
+       err = _sysio_namei(_sysio_cwd, path, ND_NEGOK, &intent, &pno);
+       if (err)
+               goto out;
+       if (pno->p_base->pb_ino) {
+               err = -EEXIST;
+               goto error;
+       }
+
+       if (IS_RDONLY(pno, pno->p_base->pb_ino)) {
+               err = -EROFS;
+               goto error;
+       }
+       err = (*pno->p_parent->p_base->pb_ino->i_ops.inop_mkdir)(pno, mode);
+error:
+       P_RELE(pno);
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#ifdef REDSTORM
+#undef __mkdir
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(mkdir),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(mkdir)))
+#endif
diff --git a/libsysio/src/mknod.c b/libsysio/src/mknod.c
new file mode 100644 (file)
index 0000000..4c947d2
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#if defined(__linux__)
+#define _BSD_SOURCE
+#endif
+
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "inode.h"
+#include "fs.h"
+#include "mount.h"
+
+#include "sysio-symbols.h"
+
+#undef mknod
+#undef __xmknod
+
+#if defined(BSD) || defined(REDSTORM)
+#define _MKNOD_VER     0
+#endif
+
+int
+PREPEND(__, SYSIO_INTERFACE_NAME(xmknod))(int __ver, 
+                                         const char *path, 
+                                         mode_t mode, 
+                                         dev_t *dev)
+{
+       int     err;
+       struct intent intent;
+       struct pnode *pno;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       if (__ver != _MKNOD_VER) {
+               err = -ENOSYS;
+               goto out;
+       }
+
+       /*
+        * Support only character-special and fifos right now.
+        */
+       if (!(S_ISCHR(mode) || S_ISFIFO(mode))) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       INTENT_INIT(&intent, INT_CREAT, &mode, NULL);
+       err = _sysio_namei(_sysio_cwd, path, ND_NEGOK, &intent, &pno);
+       if (err)
+               goto out;
+       if (pno->p_base->pb_ino) {
+               err = -EEXIST;
+               goto error;
+       }
+
+       if (IS_RDONLY(pno, pno->p_base->pb_ino)) {
+               err = -EROFS;
+               goto error;
+       }
+       err =
+           (*pno->p_parent->p_base->pb_ino->i_ops.inop_mknod)(pno, mode, *dev);
+error:
+       P_RELE(pno);
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#ifdef REDSTORM
+#undef _xmknod
+sysio_sym_weak_alias(PREPEND(__, SYSIO_INTERFACE_NAME(xmknod)), 
+                    PREPEND(_, SYSIO_INTERFACE_NAME(xmknod)))
+#endif
+
+static int
+PREPEND(__, SYSIO_INTERFACE_NAME(mknod))(const char *path, 
+                                        mode_t mode, 
+                                        dev_t dev)
+{
+
+       return PREPEND(__, SYSIO_INTERFACE_NAME(xmknod))(_MKNOD_VER, 
+                                                        path, 
+                                                        mode, 
+                                                        &dev);
+}
+
+sysio_sym_weak_alias(PREPEND(__, SYSIO_INTERFACE_NAME(mknod)),
+                    SYSIO_INTERFACE_NAME(mknod))
diff --git a/libsysio/src/module.mk b/libsysio/src/module.mk
new file mode 100644 (file)
index 0000000..306d18f
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# Note; Remove statvfs{,64}.c until we decide what to do with them.
+# Lee; Tue Feb 24 09:37:32 EST 2004
+#
+
+if WITH_LUSTRE_HACK
+FILE_SUPPORT = src/file_hack.c
+else
+FILE_SUPPORT = src/file.c
+endif
+
+if WITH_LUSTRE_HACK
+LUSTRE_SRCDIR_SRCS = src/stdlib.c
+else
+LUSTRE_SRCDIR_SRCS =
+endif
+
+SRCDIR_SRCS = src/access.c src/chdir.c src/chmod.c \
+       src/chown.c src/dev.c src/dup.c src/fcntl.c \
+       src/fs.c src/fsync.c \
+       src/getdirentries.c src/init.c src/inode.c \
+       src/ioctl.c src/ioctx.c src/iowait.c \
+       src/link.c src/lseek.c src/mkdir.c \
+       src/mknod.c src/mount.c src/namei.c \
+       src/open.c src/rw.c src/rename.c \
+       src/rmdir.c src/stat64.c src/stat.c \
+       src/symlink.c src/readlink.c \
+       src/truncate.c src/unlink.c src/utime.c \
+       $(FILE_SUPPORT) $(LUSTRE_SRCDIR_SOURCES)
+
+SRCDIR_EXTRA = src/module.mk
diff --git a/libsysio/src/mount.c b/libsysio/src/mount.c
new file mode 100644 (file)
index 0000000..3e73832
--- /dev/null
@@ -0,0 +1,680 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef AUTOMOUNT_FILE_NAME
+#include <fcntl.h>
+#include <sys/uio.h>
+#endif
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "fs.h"
+#include "mount.h"
+#include "inode.h"
+#ifdef AUTOMOUNT_FILE_NAME
+#include "xtio.h"
+#endif
+
+/*
+ * File system and volume mount support.
+ */
+
+#ifdef AUTOMOUNT_FILE_NAME
+/*
+ * Name of autmount specification file in a directory with
+ * the sticky-bit set.
+ */
+struct qstr _sysio_mount_file_name = { "", 0, 0 };
+#endif
+
+/*
+ * Active mounts.
+ */
+static LIST_HEAD(, mount) mounts;
+
+/*
+ * Initialization. Must be called before any other routine in this module.
+ */
+int
+_sysio_mount_init()
+{
+
+       LIST_INIT(&mounts);
+#ifdef AUTOMOUNT_FILE_NAME
+       _sysio_next_component(AUTOMOUNT_FILE_NAME, &_sysio_mount_file_name);
+#endif
+
+       return 0;
+}
+
+/*
+ * Mount rooted sub-tree somewhere in the existing name space.
+ */
+int
+_sysio_do_mount(struct filesys *fs,
+               struct pnode_base *rootpb,
+               unsigned flags,
+               struct pnode *tocover,
+               struct mount **mntp)
+{
+       struct mount *mnt;
+       int     err;
+
+       /*
+        * It's really poor form to allow the new root to be a
+        * descendant of the pnode being covered.
+        */
+       if (tocover) {
+               struct pnode_base *pb;
+
+               for (pb = rootpb;
+                    pb && pb != tocover->p_base;
+                    pb = pb->pb_parent)
+                       ;
+               if (pb == tocover->p_base)
+                       return -EBUSY;
+       }
+
+       /*
+        * Alloc
+        */
+       mnt = malloc(sizeof(struct mount));
+       if (!mnt)
+               return -ENOMEM;
+       err = 0;
+       /*
+        * Init enough to make the mount record usable to the path node
+        * generation routines.
+        */
+       mnt->mnt_fs = fs;
+       if (fs->fs_flags & FS_F_RO) {
+               /*
+                * Propagate the read-only flag -- Whether they set it or not.
+                */
+               flags |= MOUNT_F_RO;
+       }
+       mnt->mnt_flags = flags;
+       /*
+        * Get alias for the new root.
+        */
+       mnt->mnt_root =
+           _sysio_p_new_alias(tocover ? tocover->p_parent : NULL, rootpb, mnt);
+       if (!mnt->mnt_root) {
+               err = -ENOMEM;
+               goto error;
+       }
+       /*
+        * It may have been a while since the root inode was validated;
+        * better validate again.  And it better be a directory!
+        */
+       err = _sysio_p_validate(mnt->mnt_root, NULL, NULL);
+       if (err)
+               goto error;
+
+       if (!S_ISDIR(mnt->mnt_root->p_base->pb_ino->i_mode)) {
+               err = -ENOTDIR;
+               goto error;
+       }
+       /*
+        * Cover up the mount point.
+        */
+       mnt->mnt_covers = tocover;
+       if (!mnt->mnt_covers) {
+               /*
+                * New graph; It covers itself.
+                */
+               mnt->mnt_covers = tocover = mnt->mnt_root;
+       }
+       tocover->p_cover = mnt->mnt_root;
+
+       LIST_INSERT_HEAD(&mounts, mnt, mnt_link);
+
+       *mntp = mnt;
+       return 0;
+
+error:
+       if (mnt->mnt_root) {
+               P_RELE(mnt->mnt_root);
+               _sysio_p_prune(mnt->mnt_root);
+       }
+       free(mnt);
+       return err;
+}
+
+/*
+ * Remove mounted sub-tree from the system.
+ */
+int
+_sysio_do_unmount(struct mount *mnt)
+{
+       struct pnode *root;
+       struct filesys *fs;
+
+       root = mnt->mnt_root;
+       if (root->p_cover && root->p_cover != root) {
+               /*
+                * Active mount.
+                */
+               return -EBUSY;
+       }
+       assert(mnt->mnt_covers->p_cover == root);
+       if (_sysio_p_prune(root) != 1) {
+               /*
+                * Active aliases.
+                */
+               return -EBUSY;
+       }
+       /*
+        * We're committed.
+        *
+        * Drop ref of covered pnode and break linkage in name space.
+        */
+       if (root->p_cover != root)
+               P_RELE(mnt->mnt_covers);
+       mnt->mnt_covers->p_cover = NULL;
+       LIST_REMOVE(mnt, mnt_link);
+       /*
+        * Kill the root.
+        */
+       P_RELE(root);
+       root->p_cover = NULL;
+       _sysio_p_gone(root);
+       /*
+        * Release mount record resource.
+        */
+       fs = mnt->mnt_fs;
+       free(mnt);
+       FS_RELE(fs);
+
+       return 0;
+}
+
+/*
+ * Establish the system name space.
+ */
+int
+_sysio_mount_root(const char *source,
+                 const char *fstype,
+                 unsigned flags,
+                 const void *data)
+{
+       struct fsswent *fssw;
+       int     err;
+       struct mount *mnt;
+
+       if (_sysio_root)
+               return -EBUSY;
+
+       fssw = _sysio_fssw_lookup(fstype);
+       if (!fssw)
+               return -ENODEV;
+
+       err = (*fssw->fssw_ops.fsswop_mount)(source, flags, data, NULL, &mnt);
+       if (err)
+               return err;
+
+       _sysio_root = mnt->mnt_root;
+       /*
+        * It is very annoying to have to set the current working directory.
+        * So... If it isn't set, make it the root now.
+        */
+       if (!_sysio_cwd) {
+               _sysio_cwd = _sysio_root;
+               P_REF(_sysio_cwd);
+       }
+
+       return 0;
+}
+
+int
+_sysio_mount(struct pnode *cwd,
+            const char *source,
+            const char *target,
+            const char *filesystemtype,
+            unsigned long mountflags,
+            const void *data)
+{
+       int     err;
+       struct fsswent *fssw;
+       struct intent intent;
+       struct pnode *tgt;
+       struct mount *mnt;
+
+       /*
+        * Find the file system switch entry specified.
+        */
+       fssw = _sysio_fssw_lookup(filesystemtype);
+       if (!fssw)
+               return -ENODEV;
+
+       /*
+        * Look up the target path node.
+        */
+        INTENT_INIT(&intent, INT_GETATTR, NULL, NULL);
+       err = _sysio_namei(cwd, target, 0, &intent, &tgt);
+       if (err)
+               return err;
+
+       if (tgt == _sysio_root) {
+               /*
+                * Attempting to mount over root.
+                */
+               err = -EBUSY;
+       } else {
+               /*
+                * Do the deed.
+                */
+               err =
+                   (*fssw->fssw_ops.fsswop_mount)(source,
+                                                  mountflags,
+                                                  data,
+                                                  tgt,
+                                                  &mnt);
+       }
+       if (err)
+               P_RELE(tgt);
+       return err;
+}
+
+int
+SYSIO_INTERFACE_NAME(mount)(const char *source,
+      const char *target,
+      const char *filesystemtype,
+      unsigned long mountflags,
+      const void *data)
+{
+       int     err;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       err =
+           _sysio_mount(_sysio_cwd,
+                        source,
+                        target,
+                        filesystemtype,
+                        mountflags,
+                        data);
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+int
+SYSIO_INTERFACE_NAME(umount)(const char *target)
+{
+       int     err;
+       struct pnode *pno;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       /*
+        * Look up the target path node.
+        */
+       err = _sysio_namei(_sysio_cwd, target, 0, NULL, &pno);
+       if (err)
+               goto out;
+       P_RELE(pno);                            /* was ref'd */
+
+       /*
+        * Do the deed.
+        */
+#if 0  
+       if (!pno->p_cover) {
+               err = -EINVAL;
+               goto error;
+       }
+#endif
+       assert(pno->p_mount);
+       err = _sysio_do_unmount(pno->p_mount);
+
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+/*
+ * Unmount all file systems -- Usually as part of shutting everything down.
+ */
+int
+_sysio_unmount_all()
+{
+       int     err;
+       struct mount *mnt, *nxt;
+       struct pnode *pno;
+
+       err = 0;
+       nxt = mounts.lh_first;
+       while ((mnt = nxt)) {
+               nxt = mnt->mnt_link.le_next;
+               pno = mnt->mnt_root;
+               /*
+                * If this is an automount generated mount, the root
+                * has no reference. We can cause the dismount with a
+                * simple prune.
+                */
+               if (!_sysio_p_prune(pno))
+                       continue;
+#ifdef notdef
+               /*
+                * Need a ref but only if this is not the root of a
+                * disconnected graph. If it is, then it is covered by itself
+                * and, so, already referenced.
+                */
+               if (pno->p_cover != pno)
+                       P_REF(pno);
+#endif
+               err = _sysio_do_unmount(mnt);
+               if (err) {
+#ifdef notdef
+                       if (pno->p_cover != pno)
+                               P_RELE(pno);
+#endif
+                       break;
+               }
+               if (pno == _sysio_root)
+                       _sysio_root = NULL;
+       }
+
+       return err;
+}
+
+#ifdef AUTOMOUNT_FILE_NAME
+/*
+ * Parse automount specification formatted as:
+ *
+ * <fstype>:<source>[[ \t]+<comma-separated-mount-options>]
+ *
+ * NB:
+ * The buffer sent is (almost) always modified.
+ */
+static int
+parse_automount_spec(char *s, char **fstyp, char **srcp, char **optsp)
+{
+       int     err;
+       char    *cp;
+       char    *fsty, *src, *opts;
+
+       err = 0;
+
+       /*
+        * Eat leading white.
+        */
+       while (*s && *s == ' ' && *s == '\t')
+               s++;
+       /*
+        * Get fstype.
+        */
+       fsty = cp = s;
+       while (*cp &&
+              *cp != ':' &&
+              *cp != ' ' &&
+              *cp != '\t' &&
+              *cp != '\r' &&
+              *cp != '\n')
+               cp++;
+       if (fsty == cp || *cp != ':')
+               goto error;
+       *cp++ = '\0';
+
+       s = cp;
+       /*
+        * Eat leading white.
+        */
+       while (*s && *s == ' ' && *s == '\t')
+               s++;
+       /*
+        * Get source.
+        */
+       src = cp = s;
+       while (*cp &&
+              *cp != ' ' &&
+              *cp != '\t' &&
+              *cp != '\r' &&
+              *cp != '\n')
+               cp++;
+       if (src == cp)
+               goto error;
+       if (*cp)
+               *cp++ = '\0';
+
+       s = cp;
+       /*
+        * Eat leading white.
+        */
+       while (*s && *s == ' ' && *s == '\t')
+               s++;
+       /*
+        * Get opts.
+        */
+       opts = cp = s;
+       while (*cp &&
+              *cp != ' ' &&
+              *cp != '\t' &&
+              *cp != '\r' &&
+              *cp != '\n')
+               cp++;
+       if (opts == cp)
+               opts = NULL;
+       if (*cp)
+               *cp++ = '\0';
+
+       if (*cp)
+               goto error;
+
+       *fstyp = fsty;
+       *srcp = src;
+       *optsp = opts;
+       return 0;
+
+error:
+       return -EINVAL;
+}
+
+/*
+ * Parse (and strip) system mount options.
+ */
+static char *
+parse_opts(char *opts, unsigned *flagsp)
+{
+       unsigned flags;
+       char    *src, *dst;
+       char    *cp;
+
+       flags = 0;
+       src = dst = opts;
+       for (;;) {
+               cp = src;
+               while (*cp && *cp != ',')
+                       cp++;
+               if (src + 2 == cp && strncmp(src, "rw", 2) == 0) {
+                       /*
+                        * Do nothing. This is the default.
+                        */
+                       src += 2;
+               } else if (src + 2 == cp && strncmp(src, "ro", 2) == 0) {
+                       /*
+                        * Read-only.
+                        */
+                       flags |= MOUNT_F_RO;
+                       src += 2;
+               }
+               else if (src + 4 == cp && strncmp(src, "auto", 4) == 0) {
+                       /*
+                        * Enable automounts.
+                        */
+                       flags |= MOUNT_F_AUTO;
+                       src += 4;
+               }
+               if (src < cp) {
+                       /*
+                        * Copy what we didn't consume.
+                        */
+                       if (dst != opts)
+                               *dst++ = ',';
+                       do
+                               *dst++ = *src++;
+                       while (src != cp);
+               }
+               if (!*src)
+                       break;
+               *dst = '\0';
+               src++;                                  /* skip comma */
+       }
+       *dst = '\0';
+
+       *flagsp = flags;
+       return opts;
+}
+
+/*
+ * Attempt automount over the given directory.
+ */
+int
+_sysio_automount(struct pnode *mntpno)
+{
+       int     err;
+       struct inode *ino;
+       struct intnl_stat stbuf;
+       struct iovec iovec;
+       struct ioctx iocontext;
+       struct intnl_xtvec xtvec;
+       ssize_t cc;
+       char    *fstype, *source, *opts;
+       unsigned flags;
+       struct fsswent *fssw;
+       struct mount *mnt;
+
+       /*
+        * Revalidate -- Paranoia.
+        */
+       err = _sysio_p_validate(mntpno, NULL, NULL);
+       if (err)
+               return err;
+
+       /*
+        * Read file content.
+        */
+       ino = mntpno->p_base->pb_ino;
+       err = (*ino->i_ops.inop_getattr)(mntpno, ino, &stbuf);
+       if (err)
+               return err;
+       if (stbuf.st_size > 64 * 1024) {
+               /*
+                * Let's be reasonable.
+                */
+               return -EINVAL;
+       }
+       iovec.iov_base = malloc(stbuf.st_size + 1);
+       if (!iovec.iov_base)
+               return -ENOMEM;
+       iovec.iov_len = stbuf.st_size;
+       err = _sysio_open(mntpno, O_RDONLY, 0);
+       if (err)
+               goto out;
+       xtvec.xtv_off = 0;
+       xtvec.xtv_len = stbuf.st_size;
+       IOCTX_INIT(&iocontext,
+                  1,
+                  (ioid_t )&iocontext,
+                  0,
+                  ino,
+                  &iovec, 1,
+                  &xtvec, 1);
+       _sysio_ioctx_enter(&iocontext);
+       err = (*ino->i_ops.inop_read)(ino, &iocontext);
+       if (err) {
+               _sysio_ioctx_complete(&iocontext);
+               (void )(*ino->i_ops.inop_close)(ino);
+               goto out;
+       }
+       cc = _sysio_ioctx_wait(&iocontext);
+       err = (*ino->i_ops.inop_close)(ino);
+       if (err)
+               goto out;
+       if (cc < 0) {
+               err = (int )cc;
+               goto out;
+       }
+       ((char *)iovec.iov_base)[cc] = '\0';
+
+       /*
+        * Parse.
+        */
+       err = parse_automount_spec(iovec.iov_base, &fstype, &source, &opts);
+       if (err)
+               goto out;
+       flags = 0;
+       if (opts)
+               opts = parse_opts(opts, &flags);
+
+       /*
+        * Find the file system switch entry specified.
+        */
+       fssw = _sysio_fssw_lookup(fstype);
+       if (!fssw) {
+               err = -ENODEV;
+               goto out;
+       }
+
+       /*
+        * Do the deed.
+        */
+       P_REF(mntpno->p_parent);
+       err =
+           (*fssw->fssw_ops.fsswop_mount)(source,
+                                          flags,
+                                          opts,
+                                          mntpno->p_parent,
+                                          &mnt);
+       if (err)
+               P_RELE(mntpno->p_parent);
+
+out:
+       if (iovec.iov_base)
+               free(iovec.iov_base);
+       return err;
+}
+#endif
diff --git a/libsysio/src/namei.c b/libsysio/src/namei.c
new file mode 100644 (file)
index 0000000..2d2e905
--- /dev/null
@@ -0,0 +1,471 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#if defined(AUTOMOUNT_FILE_NAME) && defined(__linux__)
+#define _BSD_SOURCE
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "sysio.h"
+#include "mount.h"
+#include "inode.h"
+
+/*
+ * Parse next component in path.
+ */
+#ifndef AUTOMOUNT_FILE_NAME
+static
+#endif
+void
+_sysio_next_component(const char *path, struct qstr *name)
+{
+       while (*path == PATH_SEPARATOR)
+               path++;
+       name->name = path;
+       name->len = 0;
+       name->hashval = 0;
+       while (*path && *path != PATH_SEPARATOR) {
+               name->hashval =
+                   37 * name->hashval + *path++;
+               name->len++;
+       }
+}
+
+/*
+ * Given parent, look up component.
+ */
+static int
+lookup(struct pnode *parent,
+       struct qstr *name,
+       struct pnode **pnop,
+       struct intent *intnt,
+       const char *path)
+{
+       struct pnode *pno;
+       int     err;
+
+       if (!parent->p_base->pb_ino)
+               return -ENOTDIR;
+
+       /*
+        * Short-circuit `.' and `..'; We don't cache those.
+        */
+       pno = NULL;
+       if (name->len == 1 && name->name[0] == '.')
+               pno = parent;
+       else if (name->len == 2 && name->name[0] == '.' && name->name[1] == '.')
+               pno = parent->p_parent;
+       if (pno)
+               P_REF(pno);
+       else {
+               /*
+                * Get cache entry then.
+                */
+               err = _sysio_p_find_alias(parent, name, &pno);
+               if (err)
+                       return err;
+       }
+
+       /*
+        * While covered, move to the covering node.
+        */
+       while (pno->p_cover && pno->p_cover != pno) {
+               struct pnode *cover;
+
+               cover = pno->p_cover;
+               P_REF(cover);
+               P_RELE(pno);
+               pno = cover;
+       }
+
+       *pnop = pno;
+
+       /*
+        * (Re)validate the pnode.
+        */
+       err = _sysio_p_validate(pno, intnt, path);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+/*
+ * The meat. Walk an absolute or relative path, looking up each
+ * component. Various flags in the nameidata argument govern actions
+ * and return values/state. They are:
+ *
+ * ND_NOFOLLOW         symbolic links are not followed
+ * ND_NEGOK            if terminal/leaf does not exist, return
+ *                      path node (alias) anyway.
+ */
+int
+_sysio_path_walk(struct pnode *parent, struct nameidata *nd)
+{
+       int     err;
+       const char *path;
+       struct qstr this, next;
+       struct inode *ino;
+
+       /*
+        * NULL path?
+        */
+       if (!nd->nd_path)
+               return -EFAULT;
+
+       /*
+        * Empty path?
+        */
+       if (!*nd->nd_path)
+               return -ENOENT;
+
+       /*
+        * Leading slash?
+        */
+       if (*nd->nd_path == PATH_SEPARATOR) {
+               /*
+                * Make parent the root of the name space.
+                */
+               parent = nd->nd_root;
+       }
+
+       /*
+        * (Re)Validate the parent.
+        */
+       err = _sysio_p_validate(parent, NULL, NULL);
+       if (err)
+               return err;
+
+       /*
+        * Prime everything for the loop. Will need another reference to the
+        * initial directory. It'll be dropped later.
+        */
+       nd->nd_pno = parent;
+       P_REF(nd->nd_pno);
+       _sysio_next_component(nd->nd_path, &next);
+       path = next.name;
+       parent = NULL;
+       err = 0;
+
+       /*
+        * Derecurse the path tree-walk.
+        */
+       for (;;) {
+               ino = nd->nd_pno->p_base->pb_ino;
+               if (S_ISLNK(ino->i_mode) &&
+                   (next.len || !(nd->nd_flags & ND_NOFOLLOW))) {
+                       char    *lpath;
+                       ssize_t cc;
+                       struct nameidata nameidata;
+
+                       if (nd->nd_slicnt >= MAX_SYMLINK) {
+                               err = -ELOOP;
+                               break;
+                       }
+
+                       /*
+                        * Follow symbolic link.
+                        */
+                       lpath = malloc(MAXPATHLEN + 1);
+                       if (!lpath) {
+                               err = -ENOMEM;
+                               break;
+                       }
+                       cc =
+                           ino->i_ops.inop_readlink(nd->nd_pno,
+                                                    lpath,
+                                                    MAXPATHLEN);
+                       if (cc < 0) {
+                               free(lpath);
+                               err = (int )cc;
+                               break;
+                       }
+                       lpath[cc] = '\0';                       /* NUL term */
+                       /*
+                        * Handle symbolic links with recursion. Yuck!
+                        */
+                       ND_INIT(&nameidata,
+                               (nd->nd_flags | ND_NEGOK),
+                               lpath,
+                               nd->nd_root,
+                               nd->nd_intent);
+                       nameidata.nd_slicnt = nd->nd_slicnt + 1;
+                       err =
+                           _sysio_path_walk(nd->nd_pno->p_parent, &nameidata);
+                       free(lpath);
+                       if (err)
+                               break;
+                       P_RELE(nd->nd_pno);
+                       nd->nd_pno = nameidata.nd_pno;
+                       ino = nd->nd_pno->p_base->pb_ino;
+               }
+#ifdef AUTOMOUNT_FILE_NAME
+               else if (ino &&
+                        S_ISDIR(ino->i_mode) &&
+                        (nd->nd_pno->p_mount->mnt_flags & MOUNT_F_AUTO) &&
+                        nd->nd_amcnt < MAX_MOUNT_DEPTH &&
+                        ino->i_mode & S_ISUID) {
+                       struct pnode *pno;
+
+                       /*
+                        * We're committed to a lookup. It's time to see if
+                        * we're going to do it in an automount-point and
+                        * arrange the mount if so.
+                        */
+                       assert(!nd->nd_pno->p_cover);
+                       err =
+                           lookup(nd->nd_pno,
+                                  &_sysio_mount_file_name,
+                                  &pno,
+                                  NULL,
+                                  NULL);
+                       if (pno)
+                               P_RELE(pno);
+                       if (!err && _sysio_automount(pno) == 0) {
+                               struct pnode *root;
+
+                               /*
+                                * All went well. Need to switch
+                                * parent pno and ino to the
+                                * root of the newly mounted sub-tree.
+                                *
+                                * NB:
+                                * We don't recurseively retry these
+                                * things. It's OK to have the new root
+                                * be an automount-point but it's going
+                                * to take another lookup to accomplish it.
+                                * The alternative could get us into an
+                                * infinite loop.
+                                */
+                               root = nd->nd_pno->p_cover;
+                               assert(root);
+                               P_RELE(nd->nd_pno);
+                               nd->nd_pno = root;
+#if 0
+                               P_REF(nd->nd_pno);
+#endif
+                               ino = nd->nd_pno->p_base->pb_ino;
+                               assert(ino);
+
+                               /*
+                                * Must send the intent-path again.
+                                */
+                               path = nd->nd_path;
+                               nd->nd_amcnt++;
+
+                               /*
+                                * Must go back top and retry with this
+                                * new pnode as parent.
+                                */
+                               continue;
+                       }
+                       err = 0;                        /* it never happened */
+               }
+#endif
+
+               /*
+                * Set up for next component.
+                */
+               this = next;
+               if (path)
+                       path = this.name;
+               if (!this.len)
+                       break;
+               if (!ino) {
+                       /*
+                        * Should only be here if final component was
+                        * target of a symlink.
+                        */
+                       nd->nd_path = this.name + this.len;
+                       err = -ENOENT;
+                       break;
+               }
+               nd->nd_path = this.name + this.len;
+               _sysio_next_component(nd->nd_path, &next);
+               parent = nd->nd_pno;
+               nd->nd_pno = NULL;
+
+               /*
+                * Parent must be a directory.
+                */
+               if (ino && !S_ISDIR(ino->i_mode)) {
+                       err = -ENOTDIR;
+                       break;
+               }
+
+               /*
+                * The extra path arg is passed only on the first lookup in the
+                * walk as we cross into each file system, anew. The intent is
+                * passed both on the first lookup and when trying to look up
+                * the final component -- Of the original path, not on the
+                * file system.
+                *
+                * Confused? Me too and I came up with this weirdness. It's
+                * hints to the file system drivers. Read on.
+                *
+                * The first lookup will give everything one needs to ready
+                * everything for the entire operation before the path is
+                * walked. The file system driver knows it's the first lookup
+                * in the walk because it has both the path and the intent.
+                *
+                * Alternatively, one could split the duties; The first lookup
+                * can be used to prime the file system inode cache with the
+                * interior nodes we'll want in the path-walk. Then, when
+                * looking up the last component, ready everything for the
+                * operations(s) to come. The file system driver knows it's
+                * the last lookup in the walk because it has the intent,
+                * again, but without the path.
+                *
+                * One special case; If we were asked to look up a single
+                * component, we treat it as the last component. The file
+                * system driver never sees the extra path argument. It should
+                * be noted that the driver always has the fully qualified
+                * path, on the target file system, available to it for any
+                * node it is looking up, including the last, via the base
+                * path node and it's ancestor chain.
+                */
+               err =
+                   lookup(parent,
+                          &this,
+                          &nd->nd_pno,
+                          (path || !next.len)
+                            ? nd->nd_intent
+                            : NULL,
+                          (path && next.len) ? path : NULL);
+               if (err) {
+                       if (err == -ENOENT &&
+                           !next.len &&
+                           (nd->nd_flags & ND_NEGOK))
+                               err = 0;
+                       break;
+               }
+               path = NULL;                            /* Stop that! */
+               if ((parent->p_mount->mnt_fs !=
+                    nd->nd_pno->p_mount->mnt_fs)) {
+                       /*
+                        * Crossed into a new fs. We'll want the next lookup
+                        * to include the path again.
+                        */
+                       path = nd->nd_path;
+               }
+
+               /*
+                * Release the parent.
+                */
+               P_RELE(parent);
+               parent = NULL;
+       }
+
+       /*
+        * Trailing separators cause us to break from the loop with
+        * a parent set but no pnode. Check for that.
+        */
+       if (!nd->nd_pno) {
+               nd->nd_pno = parent;
+               parent = NULL;
+               /*
+                * Make sure the last processed component was a directory. The
+                * trailing slashes are illegal behind anything else.
+                */
+               if (!(err || S_ISDIR(nd->nd_pno->p_base->pb_ino->i_mode)))
+                       err = -ENOTDIR;
+       }
+
+       /*
+        * Drop reference to parent if set. Either we have a dup of the original
+        * parent or an intermediate reference.
+        */
+       if (parent)
+               P_RELE(parent);
+
+       /*
+        * On error, we will want to drop our reference to the current
+        * path node if at end.
+        */
+       if (err && nd->nd_pno) {
+               P_RELE(nd->nd_pno);
+               nd->nd_pno = NULL;
+       }
+
+       return err;
+}
+
+#ifdef CPLANT_YOD
+/* 
+ * for backward compatibility w/protocol switch
+ * remove everything up to the first ':'
+ * fortran libs prepend cwd to path, so not much choice
+ */
+#define STRIP_PREFIX(p) strchr(p,':') ? strchr(p,':')+1 : p
+#else
+#define STRIP_PREFIX(p) p
+#endif
+
+/*
+ * Expanded form of the path-walk routine, with the common arguments, builds
+ * the nameidata bundle and calls path-walk.
+ */
+int
+_sysio_namei(struct pnode *parent,
+            const char *path,
+            unsigned flags,
+            struct intent *intnt,
+            struct pnode **pnop)
+{
+       struct nameidata nameidata;
+       int     err;
+
+       ND_INIT(&nameidata, flags, STRIP_PREFIX(path), _sysio_root, intnt);
+       err = _sysio_path_walk(parent, &nameidata);
+       if (!err)
+               *pnop = nameidata.nd_pno;
+       return err;
+}
diff --git a/libsysio/src/open.c b/libsysio/src/open.c
new file mode 100644 (file)
index 0000000..a7c3127
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+/*
+ * Incorporate the GNU flags for open if we can.
+ */
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "inode.h"
+#include "file.h"
+#include "fs.h"
+#include "mount.h"
+#include "sysio-symbols.h"
+
+#include "sysio-symbols.h"
+
+/*
+ * Open file support.
+ */
+
+mode_t _sysio_umask = 0;                               /* process umask. */
+
+/*
+ * Internal form of open.
+ */
+int
+_sysio_open(struct pnode *pno, int flags, mode_t mode)
+{
+       int     ro;
+       int     w;
+       int     err;
+       struct inode *ino;
+
+       ro = IS_RDONLY(pno, pno->p_base->pb_ino);
+       w = flags & (O_WRONLY|O_RDWR);
+       if (w == (O_WRONLY|O_RDWR)) {
+               /*
+                * Huh?
+                */
+               return -EINVAL;
+       }
+       if (w && ro)
+               return -EROFS;
+       ino = pno->p_base->pb_ino;
+       if ((flags & O_CREAT) && !ino) {
+               struct pnode *parent;
+
+               /*
+                * Must create it.
+                */
+               if (ro)
+                       return -EROFS;
+               parent = pno->p_parent;
+               err = _sysio_p_validate(parent, NULL, NULL);
+               if (!err) {
+                       ino = parent->p_base->pb_ino;
+                       assert(ino);
+                       err =
+                           !IS_RDONLY(parent, ino)
+                             ? (*ino->i_ops.inop_open)(pno, flags, mode)
+                             : -EROFS;
+               }
+       } else if ((flags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
+               err = -EEXIST;
+       else if (!ino)
+               err = _sysio_p_validate(pno, NULL, NULL);
+       else {
+               /*
+                * Simple open of pre-existing file.
+                */
+               err = (*ino->i_ops.inop_open)(pno, flags, mode);
+       }
+
+       return err;
+}
+
+#undef open
+
+int
+SYSIO_INTERFACE_NAME(open)(const char *path, int flags, ...)
+{
+       mode_t  mode;
+       unsigned ndflags;
+       struct intent intent;
+       int     rtn;
+       struct pnode *pno;
+       struct file *fil;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       /*
+        * Get mode argument and determine parameters for namei
+        */
+       mode = 0;
+       ndflags = 0;
+       intent.int_opmask = INT_OPEN;
+       if (flags & O_CREAT) {
+               va_list ap;
+
+               /*
+                * Set ndflags to indicate return of negative alias is OK.
+                */
+               ndflags |= ND_NEGOK;
+
+               /*
+                * Will need mode too.
+                */
+               va_start(ap, flags);
+               mode =
+#ifndef REDSTORM
+                   va_arg(ap, mode_t);
+#else
+                   va_arg(ap, int);
+#endif
+               va_end(ap);
+               mode &= ~(_sysio_umask & 0777) | 07000; /* apply umask */
+
+               if (flags & O_EXCL) {
+                       /*
+                        * Tell others we intend to create this file.
+                        */
+                       intent.int_opmask |= INT_CREAT;
+               }
+       }
+#ifdef O_NOFOLLOW
+       if (flags & O_NOFOLLOW)
+               ndflags |= ND_NOFOLLOW;
+#endif
+
+       /*
+        * Find the file.
+        */
+       fil = NULL;
+       INTENT_INIT(&intent, intent.int_opmask, &mode, &flags);
+       pno = NULL;
+       rtn = _sysio_namei(_sysio_cwd, path, ndflags, &intent, &pno);
+       if (rtn)
+               goto error;
+       /*
+        * Ask for the open/creat.
+        */
+       rtn = _sysio_open(pno, flags, mode);
+       if (rtn)
+               goto error;
+       /*
+        * Get a file descriptor.
+        */
+       fil = _sysio_fnew(pno->p_base->pb_ino, flags);
+       if (!fil) {
+               rtn = -ENOMEM;
+               goto error;
+       }
+       rtn = _sysio_fd_set(fil, -1);
+       if (rtn < 0)
+               goto error;
+
+       P_RELE(pno);
+
+       SYSIO_INTERFACE_RETURN(rtn, 0);
+
+error:
+       if (fil)
+               F_RELE(fil);
+       if (pno)
+               P_RELE(pno);
+       SYSIO_INTERFACE_RETURN(-1, rtn);
+}
+
+#ifdef __GLIBC__
+#undef __open
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(open), __open)
+#undef open64
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(open), SYSIO_INTERFACE_NAME(open64))
+#undef __open64
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(open), __open64)
+#endif
+
+#ifdef REDSTORM
+#undef __libc_open64
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(open), __libc_open64)
+#endif
+
+#ifdef BSD
+#undef _open
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(open), _open)
+#endif
+
+int
+SYSIO_INTERFACE_NAME(close)(int fd)
+{
+       int     err;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       err = _sysio_fd_close(fd);
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#ifdef __GLIBC__
+#undef __close
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(close), __close)
+#endif
+
+#ifdef BSD
+#undef _close
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(close), _close)
+#endif
+
+int
+SYSIO_INTERFACE_NAME(creat)(const char *path, mode_t mode)
+{
+
+       return open(path, O_CREAT|O_WRONLY|O_TRUNC, mode);
+}
+
+#ifdef __GLIBC__
+#undef __creat
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(creat), __creat)
+#undef creat64
+#ifndef HAVE_LUSTRE_HACK
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(creat), SYSIO_INTERFACE_NAME(creat64))
+#else
+/* XXX workaround SuSE SLES 8, glibc-2.2.5 */
+sysio_sym_strong_alias(SYSIO_INTERFACE_NAME(creat), SYSIO_INTERFACE_NAME(creat64))
+#endif
+#undef __creat64
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(creat), __creat64)
+#endif
+
+#ifdef REDSTORM
+#undef __libc_creat
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(creat), __libc_creat)
+#endif
+
+#ifdef BSD
+#undef _creat
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(creat), _creat)
+#endif
+
+mode_t
+SYSIO_INTERFACE_NAME(umask)(mode_t mask)
+{
+       mode_t  omask;
+
+       omask = _sysio_umask;
+       _sysio_umask = mask & 0777;
+       return omask;
+}
+
+#ifdef REDSTORM
+#undef __umask
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(umask), __umask)
+#endif
diff --git a/libsysio/src/readlink.c b/libsysio/src/readlink.c
new file mode 100644 (file)
index 0000000..7053c62
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2004 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "inode.h"
+#include "sysio-symbols.h"
+
+int
+SYSIO_INTERFACE_NAME(readlink)(const char *path, char *buf, size_t bufsiz)
+{
+       struct intent intent;
+       int     err;
+       struct pnode *pno;
+       struct inode *ino;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       INTENT_INIT(&intent, INT_GETATTR, NULL, NULL);
+       err = _sysio_namei(_sysio_cwd, path, ND_NOFOLLOW, &intent, &pno);
+       if (err)
+               goto out;
+       ino = pno->p_base->pb_ino;
+       err = (*ino->i_ops.inop_readlink)(pno, buf, bufsiz);
+       if (err)
+               goto error;
+
+error:
+       P_RELE(pno);
+out:
+       SYSIO_INTERFACE_RETURN(err, err >= 0 ? 0 : err);
+}
+
+#ifdef REDSTORM
+#undef __readlink
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(readlink),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(readlink)))
+#endif
diff --git a/libsysio/src/rename.c b/libsysio/src/rename.c
new file mode 100644 (file)
index 0000000..167c74f
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "mount.h"
+#include "inode.h"
+
+int
+SYSIO_INTERFACE_NAME(rename)(const char *oldpath, const char *newpath)
+{
+       struct intent intent;
+       int     err;
+       struct pnode *old, *new;
+       struct pnode_base *nxtpb, *pb;
+       struct intnl_stat ostbuf, nstbuf;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       /*
+        * Resolve oldpath to a path node.
+        */
+       INTENT_INIT(&intent, INT_UPDPARENT, NULL, NULL);
+       err = _sysio_namei(_sysio_cwd, oldpath, 0, &intent, &old);
+       if (err)
+               goto error3;
+       /*
+        * Resolve newpath to a path node.
+        */
+       INTENT_INIT(&intent, INT_UPDPARENT, NULL, NULL);
+       err = _sysio_namei(_sysio_cwd, newpath, ND_NEGOK, &intent, &new);
+       if (err && !new)
+               goto error2;
+
+       if (old->p_mount->mnt_root == old || old->p_cover ||
+           new->p_mount->mnt_root == new) {
+               err = -EBUSY;
+               goto error1;
+       }
+
+       if (old->p_mount->mnt_fs != new->p_mount->mnt_fs) {
+               /*
+                * Oops. They're trying to move it across file systems.
+                */
+               err = -EXDEV;
+               goto error1;
+       }
+
+       /*
+        * Make sure the old pnode can't be found in the ancestor chain
+        * for the new. If it can, they are trying to move into a subdirectory
+        * of the old.
+        */
+       nxtpb = new->p_base;
+       do {
+               pb = nxtpb;
+               nxtpb = pb->pb_parent;
+               if (pb == old->p_base) {
+                       err = -EINVAL;
+                       goto error1;
+               }
+       } while (nxtpb);
+
+       while (new->p_base->pb_ino) {
+               /*
+                * Existing entry. We're replacing the new. Make sure that's
+                * ok.
+                */
+               err =
+                   old->p_base->pb_ino->i_ops.inop_getattr(old, NULL, &ostbuf);
+               if (err)
+                       goto error1;
+               err =
+                   new->p_base->pb_ino->i_ops.inop_getattr(new, NULL, &nstbuf);
+               if (err) {
+                       if (err != ENOENT)
+                               goto error1;
+                       /*
+                        * Rats! It disappeared beneath us.
+                        */
+                       (void )_sysio_p_validate(new, NULL, NULL);
+                       continue;
+               }
+               if (S_ISDIR(ostbuf.st_mode)) {
+                       if (!S_ISDIR(nstbuf.st_mode)) {
+                               err = -ENOTDIR;
+                               goto error1;
+                       }
+                       if (nstbuf.st_nlink > 2) {
+                               err = -ENOTEMPTY;
+                               goto error1;
+                       }
+               } else if (S_ISDIR(nstbuf.st_mode)) {
+                       err = -EEXIST;
+                       goto error1;
+               }
+               break;
+       }
+
+       /*
+        * It's not impossible to clean up the altered name space after
+        * a rename. However, it is onerous and I don't want to do it right
+        * now. If it becomes an issue, we can do it later. For now, I've
+        * elected to use the semantic that says, basically, the entire
+        * sub-tree must be unreferenced. That's per POSIX, but it's a nasty
+        * this to do to the caller.
+        */
+       if (_sysio_p_prune(new) != 1) {
+               err = -EBUSY;
+               goto error1;
+       }
+       err = old->p_base->pb_ino->i_ops.inop_rename(old, new);
+       if (err)
+               goto error1;
+       /*
+        * Reflect the successful rename in the active name space graph.
+        */
+       if (new->p_base->pb_ino)
+               I_GONE(new->p_base->pb_ino);
+       new->p_base->pb_ino = old->p_base->pb_ino;
+       I_REF(new->p_base->pb_ino);
+
+error1:
+       P_RELE(new);
+error2:
+       P_RELE(old);
+error3:
+       if (err)
+               goto out;
+       _sysio_p_gone(old);                                     /* kill it! */
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
diff --git a/libsysio/src/rmdir.c b/libsysio/src/rmdir.c
new file mode 100644 (file)
index 0000000..cbc7632
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "inode.h"
+#include "fs.h"
+#include "mount.h"
+#include "sysio-symbols.h"
+
+int
+SYSIO_INTERFACE_NAME(rmdir)(const char *path)
+{
+       struct intent intent;
+       int     err;
+       struct pnode *pno;
+       struct inode *ino;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       INTENT_INIT(&intent, INT_UPDPARENT, NULL, NULL);
+       err = _sysio_namei(_sysio_cwd, path, 0, &intent, &pno);
+       if (err)
+               goto out;
+       if (IS_RDONLY(pno, pno->p_base->pb_ino)) {
+               err = -EROFS;
+               goto error;
+       }
+       if (pno->p_ref > 1) {
+               err = -EBUSY;
+               goto error;
+       }
+       err = pno->p_base->pb_ino->i_ops.inop_rmdir(pno);
+       if (err)
+               goto error;
+       /*
+        * Invalidate the path-base node and kill the i-node.
+        */
+       ino = pno->p_base->pb_ino;
+       pno->p_base->pb_ino = NULL;
+       I_GONE(ino);
+error:
+       P_RELE(pno);
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#ifdef REDSTORM
+#undef __rmdir
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(rmdir), 
+                    PREPEND(__, SYSIO_INTERFACE_NAME(rmdir)))
+#endif
diff --git a/libsysio/src/rw.c b/libsysio/src/rw.c
new file mode 100644 (file)
index 0000000..ad103b8
--- /dev/null
@@ -0,0 +1,1325 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2004 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/uio.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "file.h"
+#include "inode.h"
+#include "xtio.h"
+
+#include "sysio-symbols.h"
+
+#define IIOXOP_READ(ino)       (ino)->i_ops.inop_read, 0
+#define IIOXOP_WRITE(ino)      (ino)->i_ops.inop_write, 1
+
+/*
+ * Decoding the interface routine names:
+ *
+ * Much of this carries legacy from the POSIX world and the Intel ASCI
+ * Red programming environment. Routine names are composed of prefix,
+ * basic POSIX names, and postfix. The basic POSIX names are read and write.
+ * Prefixes, left-to-right:
+ *
+ *     - 'i' -- asynchronous operation (from ASCI Red)
+ *     - 'p' -- positional (POSIX)
+ * Posfixes, only one:
+ *     - 'v' -- vectored (POSIX)
+ *     - 'x' -- extent-based (new for Red Storm)
+ *
+ * All valid combinations are available and symmetric.
+ */
+
+/*
+ * Post op using iovec with regions specified by the passed extent vector.
+ *
+ * NOTE: There are enough parameters that we should really consider
+ * passing them in a structure.
+ */
+static int
+_sysio_iiox(int (*f)(struct inode *, struct ioctx *),
+           int wr,
+           struct file *fil,
+           const struct iovec *iov,
+           size_t iov_count,
+           void (*iov_free)(struct ioctx *),
+           const struct intnl_xtvec *xtv,
+           size_t xtv_count,
+           void (*xtv_free)(struct ioctx *),
+           void (*completio)(struct ioctx *, void *),
+           struct ioctx **ioctxp)
+{
+       struct inode *ino;
+       ssize_t cc;
+       struct ioctx *ioctx;
+       int     err;
+       struct ioctx_callback *cb;
+
+       /*
+        * Check that it was opened with flags supporting the operation.
+        */
+       if (!(wr
+               ? (fil->f_flags & (O_RDWR | O_WRONLY))
+               : !(fil->f_flags & O_WRONLY)))
+               return -EBADF;
+
+       ino = fil->f_ino;
+       if (!ino) {
+               /*
+                * Huh? It's dead.
+                */
+               return -EBADF;
+       }
+       cc =
+           _sysio_validx(xtv, xtv_count,
+                         iov, iov_count,
+#if _LARGEFILE64_SOURCE && defined(O_LARGEFILE)
+                         (fil->f_flags & O_LARGEFILE) == 0
+                           ? LONG_MAX
+                           :
+#endif
+                         _SYSIO_OFF_T_MAX);
+       if (cc < 0)
+               return cc;
+       ioctx = _sysio_ioctx_new(ino, wr, iov, iov_count, xtv, xtv_count);
+       if (!ioctx)
+               return -ENOMEM;
+       if ((iov_free &&
+            (err = _sysio_ioctx_cb(ioctx,
+                                   (void (*)(struct ioctx *,
+                                             void *))iov_free,
+                                   NULL))) ||
+           (xtv_free &&
+            (err = _sysio_ioctx_cb(ioctx,
+                                   (void (*)(struct ioctx *,
+                                             void *))xtv_free,
+                                   NULL))) ||
+           (completio &&
+            (err = _sysio_ioctx_cb(ioctx,
+                                   (void (*)(struct ioctx *,
+                                             void *))completio,
+                                   fil))) ||
+           (err = (*f)(ino, ioctx))) {
+               /*
+                * Release the callback queue. Don't want it run after all.
+                */
+               while ((cb = ioctx->ioctx_cbq.tqh_first)) {
+                       TAILQ_REMOVE(&ioctx->ioctx_cbq,
+                                    cb,
+                                    iocb_next);
+                       _sysio_ioctx_cb_free(cb);
+               }
+               _sysio_ioctx_complete(ioctx);
+               return err;
+       }
+       *ioctxp = ioctx;
+       return 0;
+}
+
+/*
+ * Sum iovec entries, returning total found or error if range of ssize_t would
+ * be exceeded.
+ */
+static ssize_t
+_sysio_sum_iovec(const struct iovec *iov, int count)
+{
+       ssize_t tmp, cc;
+
+       if (count <= 0)
+               return -EINVAL;
+
+       cc = 0;
+       while (count--) {
+               tmp = cc;
+               cc += iov->iov_len;
+               if (tmp && iov->iov_len && cc <= tmp)
+                       return -EINVAL;
+               iov++;
+       }
+       return cc;
+}
+
+/*
+ * Asynch IO from/to iovec from/to current file offset.
+ */
+static int
+_sysio_iiov(int (*f)(struct inode *, struct ioctx *),
+           int wr,
+           struct file *fil,
+           const struct iovec *iov,
+           int count,
+           void (*iov_free)(struct ioctx *),
+           struct intnl_xtvec *xtv,
+           void (*xtv_free)(struct ioctx *),
+           struct ioctx **ioctxp)
+{
+       ssize_t cc;
+       _SYSIO_OFF_T off;
+       int     err;
+
+       cc = _sysio_sum_iovec(iov, count);
+       if (cc < 0)
+               return (int )cc;
+       xtv->xtv_off = fil->f_pos;
+       xtv->xtv_len = cc;
+       off = xtv->xtv_off + xtv->xtv_len;
+       if (xtv->xtv_off && off <= xtv->xtv_off) {
+               /*
+                * Ouch! The IO vector specifies more bytes than
+                * are addressable. Trim the region to limit how
+                * much of the IO vector is finally transferred.
+                */
+               xtv->xtv_len = _SYSIO_OFF_T_MAX - xtv->xtv_off;
+       }
+       err =
+           _sysio_iiox(f,
+                       wr,
+                       fil,
+                       iov, count, iov_free,
+                       xtv, 1, xtv_free,
+                       (void (*)(struct ioctx *, void *))_sysio_fcompletio,
+                       ioctxp);
+       if (err)
+               return err;
+       return 0;
+}
+
+static void
+free_xtv(struct ioctx *ioctx)
+{
+
+       free((struct iovec *)ioctx->ioctx_xtv);
+       ioctx->ioctx_iov = NULL;
+}
+
+ioid_t
+SYSIO_INTERFACE_NAME(ireadv)(int fd, const struct iovec *iov, int count)
+{
+       struct file *fil;
+       struct intnl_xtvec *xtv;
+       struct ioctx *ioctx;
+       int     err;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fil = _sysio_fd_find(fd);
+       if (!fil)
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF);
+
+       xtv = malloc(sizeof(struct intnl_xtvec));
+       if (!xtv)
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, -ENOMEM);
+
+       err =
+           _sysio_iiov(IIOXOP_READ(fil->f_ino),
+                       fil,
+                       iov, count, NULL,
+                       xtv, free_xtv,
+                       &ioctx);
+       if (err) {
+               free(xtv);
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, err);
+       }
+       SYSIO_INTERFACE_RETURN(ioctx->ioctx_id, 0);
+}
+
+ssize_t
+SYSIO_INTERFACE_NAME(readv)(int fd, const struct iovec *iov, int count)
+{
+       struct file *fil;
+       struct intnl_xtvec xtvector;
+       struct ioctx *ioctx;
+       int     err;
+       ssize_t cc;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fil = _sysio_fd_find(fd);
+       if (!fil)
+               SYSIO_INTERFACE_RETURN(-1, -EBADF);
+
+       err =
+           _sysio_iiov(IIOXOP_READ(fil->f_ino),
+                       fil,
+                       iov, count, NULL,
+                       &xtvector, NULL,
+                       &ioctx);
+       if (!err && (cc = _sysio_ioctx_wait(ioctx)) < 0)
+               err = (int )cc;
+
+       SYSIO_INTERFACE_RETURN(err ? -1 : cc, err);
+}
+
+#if defined(__GLIBC__)
+#undef __readv
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(readv), 
+                    PREPEND(__, SYSIO_INTERFACE_NAME(readv)))
+#undef __libc_readv
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(readv),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(libc_readv)))
+#endif
+
+static void
+free_iov(struct ioctx *ioctx)
+{
+
+       free((struct iovec *)ioctx->ioctx_iov);
+       ioctx->ioctx_iov = NULL;
+}
+
+ioid_t
+SYSIO_INTERFACE_NAME(iread)(int fd, void *buf, size_t count)
+{
+       struct iovec *iov;
+       struct file *fil;
+       struct intnl_xtvec *xtv;
+       struct ioctx *ioctx;
+       int     err;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fil = _sysio_fd_find(fd);
+       if (!fil)
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF);
+
+       iov = malloc(sizeof(struct iovec));
+       if (!iov)
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, -ENOMEM);
+
+       iov->iov_base = buf;
+       iov->iov_len = count;
+       xtv = malloc(sizeof(struct intnl_xtvec));
+       if (!xtv) {
+               free(iov);
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, -ENOMEM);
+       }
+       err =
+           _sysio_iiov(IIOXOP_READ(fil->f_ino),
+                       fil,
+                       iov, 1, free_iov,
+                       xtv, free_xtv,
+                       &ioctx);
+       if (err) {
+               free(xtv);
+               free(iov);
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, err);
+       }
+       SYSIO_INTERFACE_RETURN(ioctx->ioctx_id, 0);
+}
+
+ssize_t
+SYSIO_INTERFACE_NAME(read)(int fd, void *buf, size_t count)
+{
+       struct file *fil;
+       struct iovec iovector;
+       struct intnl_xtvec xtvector;
+       int     err;
+       struct ioctx *ioctx;
+       ssize_t cc;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fil = _sysio_fd_find(fd);
+       if (!fil)
+               SYSIO_INTERFACE_RETURN(-1, -EBADF);
+
+       iovector.iov_base = buf;
+       iovector.iov_len = count;
+       err =
+           _sysio_iiov(IIOXOP_READ(fil->f_ino),
+                       fil,
+                       &iovector, 1, NULL,
+                       &xtvector, NULL,
+                       &ioctx);
+       if (!err && (cc = _sysio_ioctx_wait(ioctx)) < 0)
+               err = (int )cc;
+       SYSIO_INTERFACE_RETURN(err ? -1 : cc, err);
+}
+
+#ifdef __GLIBC__
+#undef __read
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(read),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(read)))
+#undef __libc_read
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(read),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(libc_read)))
+#endif
+
+/*
+ * Asynch IO between iovec and data at the given offset.
+ */
+static int
+_sysio_ipiov(int (*f)(struct inode *, struct ioctx *),
+            int wr,
+            struct file *fil,
+            const struct iovec *iov,
+            int count,
+            void (*iov_free)(struct ioctx *),
+            _SYSIO_OFF_T off,
+            struct intnl_xtvec *xtv,
+            void (*xtv_free)(struct ioctx *),
+            struct ioctx **ioctxp)
+{
+       ssize_t cc;
+       int     err;
+
+       SYSIO_ENTER;
+       cc = _sysio_sum_iovec(iov, count);
+       if (cc < 0) {
+               SYSIO_LEAVE;
+               return (int )cc;
+       }
+       xtv->xtv_off = off,
+       xtv->xtv_len = cc;
+       err =
+           _sysio_iiox(f,
+                       wr,
+                       fil,
+                       iov, count, iov_free,
+                       xtv, 1, xtv_free,
+                       NULL,
+                       ioctxp);
+       SYSIO_LEAVE;
+       if (err)
+               return err;
+       return 0;
+}
+
+static ioid_t
+PREPEND(_, SYSIO_INTERFACE_NAME(ipreadv))(int fd, 
+                                         const struct iovec *iov, 
+                                         size_t count, 
+                                         _SYSIO_OFF_T offset)
+{
+       struct file *fil;
+       struct intnl_xtvec *xtv;
+       struct ioctx *ioctx;
+       int     err;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fil = _sysio_fd_find(fd);
+       if (!fil)
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF);
+
+       xtv = malloc(sizeof(struct intnl_xtvec));
+       if (!xtv)
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, -ENOMEM);
+
+       err =
+           _sysio_ipiov(IIOXOP_READ(fil->f_ino),
+                        fil,
+                        iov, count, NULL,
+                        offset,
+                        xtv, free_xtv,
+                        &ioctx);
+       if (err) {
+               free(xtv);
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, err);
+       }
+       SYSIO_INTERFACE_RETURN(ioctx->ioctx_id, 0);
+}
+
+#if _LARGEFILE64_SOURCE
+#undef ipread64v
+sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(ipreadv)),
+                    SYSIO_INTERFACE_NAME(ipread64v))
+#endif
+
+ioid_t
+SYSIO_INTERFACE_NAME(ipreadv)(int fd, 
+                             const struct iovec *iov, 
+                             size_t count, 
+                             off_t offset)
+{
+
+       return PREPEND(_, SYSIO_INTERFACE_NAME(ipreadv))(fd, 
+                                                        iov, 
+                                                        count, 
+                                                        offset);
+}
+
+static ssize_t
+PREPEND(_, SYSIO_INTERFACE_NAME(preadv))(int fd, 
+                                        const struct iovec *iov, 
+                                        size_t count, 
+                                        _SYSIO_OFF_T offset)
+{
+       struct file *fil;
+       struct intnl_xtvec xtvector;
+       struct ioctx *ioctx;
+       int     err;
+       ssize_t cc;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fil = _sysio_fd_find(fd);
+       if (!fil)
+               SYSIO_INTERFACE_RETURN(-1, -EBADF);
+
+       err =
+           _sysio_ipiov(IIOXOP_READ(fil->f_ino),
+                        fil,
+                        iov, count, NULL,
+                        offset,
+                        &xtvector, NULL,
+                        &ioctx);
+       if (!err && (cc = _sysio_ioctx_wait(ioctx)) < 0)
+               err = (int )cc;
+
+       SYSIO_INTERFACE_RETURN(err ? -1 : cc, err);
+}
+
+#if _LARGEFILE64_SOURCE
+#undef pread64v
+sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(preadv)), 
+                    SYSIO_INTERFACE_NAME(pread64v))
+#endif
+
+ssize_t
+SYSIO_INTERFACE_NAME(preadv)(int fd, 
+                            const struct iovec *iov, 
+                            size_t count, 
+                            off_t offset)
+{
+
+       return PREPEND(_, SYSIO_INTERFACE_NAME(preadv))(fd, 
+                                                       iov, 
+                                                       count, 
+                                                       offset);
+}
+
+static ioid_t
+PREPEND(_, SYSIO_INTERFACE_NAME(ipread))(int fd, 
+                                        void *buf, 
+                                        size_t count, 
+                                        _SYSIO_OFF_T offset)
+{
+       struct file *fil;
+       struct intnl_xtvec *xtv;
+       struct iovec *iov;
+       struct ioctx *ioctx;
+       int     err;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fil = _sysio_fd_find(fd);
+       if (!fil)
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF);
+
+       xtv = malloc(sizeof(struct intnl_xtvec));
+       iov = malloc(sizeof(struct iovec));
+       if (!(xtv && iov)) {
+               err = -ENOMEM;
+               goto error;
+       }
+       xtv->xtv_off = offset;
+       iov->iov_base = buf;
+       xtv->xtv_len = iov->iov_len = count;
+       err =
+           _sysio_ipiov(IIOXOP_READ(fil->f_ino),
+                        fil,
+                        iov, 1, free_iov,
+                        offset,
+                        xtv, free_xtv,
+                        &ioctx);
+error:
+       if (err) {
+               if (iov)
+                       free(iov);
+               if (xtv)
+                       free(xtv);
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, err);
+       }
+       SYSIO_INTERFACE_RETURN(ioctx->ioctx_id, 0);
+}
+
+#if _LARGEFILE64_SOURCE
+#undef ipread64
+sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(ipread)),
+                    SYSIO_INTERFACE_NAME(ipread64))
+#endif
+
+ioid_t
+SYSIO_INTERFACE_NAME(ipread)(int fd, 
+                            void *buf, 
+                            size_t count, 
+                            off_t offset)
+{
+
+       return PREPEND(_, SYSIO_INTERFACE_NAME(ipread))(fd, 
+                                                       buf, 
+                                                       count, 
+                                                       offset);
+}
+
+ssize_t
+PREPEND(_, SYSIO_INTERFACE_NAME(pread))(int fd, 
+                                       void *buf, 
+                                       size_t count, 
+                                       _SYSIO_OFF_T offset)
+{
+       struct file *fil;
+       struct intnl_xtvec xtvec;
+       struct iovec iovec;
+       struct ioctx *ioctx;
+       int     err;
+       ssize_t cc;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fil = _sysio_fd_find(fd);
+       if (!fil)
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF);
+
+       xtvec.xtv_off = offset;
+       iovec.iov_base = buf;
+       xtvec.xtv_len = iovec.iov_len = count;
+       err =
+           _sysio_ipiov(IIOXOP_READ(fil->f_ino),
+                        fil,
+                        &iovec, 1, NULL,
+                        offset,
+                        &xtvec, NULL,
+                        &ioctx);
+       if (!err && (cc = _sysio_ioctx_wait(ioctx)) < 0)
+               err = (int )cc;
+
+       SYSIO_INTERFACE_RETURN(err ? -1 : cc, err);
+}
+
+#if _LARGEFILE64_SOURCE
+#undef pread64
+sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(pread)),
+                    SYSIO_INTERFACE_NAME(pread64))
+#if __GLIBC__
+#undef __pread64
+sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(pread)), 
+                    PREPEND(__, SYSIO_INTERFACE_NAME(pread64)))
+#undef __libc_pread64
+sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(pread)),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(libc_pread64)))
+#endif
+#endif
+
+ssize_t
+SYSIO_INTERFACE_NAME(pread)(int fd, void *buf, size_t count, off_t offset)
+{
+
+       return PREPEND(_, SYSIO_INTERFACE_NAME(pread))(fd, 
+                                                      buf, 
+                                                      count, 
+                                                      offset);
+}
+
+#if __GLIBC__
+#undef __pread
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(pread), 
+                    PREPEND(__, SYSIO_INTERFACE_NAME(pread)))
+#undef __libc_pread
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(pread),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(libc_pread)))
+#endif
+
+static ioid_t
+PREPEND(_, SYSIO_INTERFACE_NAME(ireadx))(int fd,
+                                        const struct iovec *iov, 
+                                        size_t iov_count, 
+                                        const struct intnl_xtvec *xtv, 
+                                        size_t xtv_count)
+{
+       struct file *fil;
+       int     err;
+       struct ioctx *ioctx;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fil = _sysio_fd_find(fd);
+       if (!(fil && xtv_count))
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF);
+
+       err =
+           _sysio_iiox(IIOXOP_READ(fil->f_ino),
+                       fil,
+                       iov, iov_count, NULL,
+                       xtv, xtv_count, NULL,
+                       NULL,
+                       &ioctx);
+
+       SYSIO_INTERFACE_RETURN(err ? IOID_FAIL : ioctx->ioctx_id, err);
+}
+
+#if _LARGEFILE64_SOURCE
+#undef iread64x
+sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(ireadx)),
+                    SYSIO_INTERFACE_NAME(iread64x))
+#endif
+
+#if _LARGEFILE64_SOURCE
+ioid_t
+SYSIO_INTERFACE_NAME(ireadx)(int fd,
+                            const struct iovec *iov, size_t iov_count,
+                            const struct xtvec *xtv, size_t xtv_count)
+{
+       struct file *fil;
+       struct intnl_xtvec *ixtv, *ixtvent;
+       size_t  count;
+       int     err;
+       struct ioctx *ioctx;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fil = _sysio_fd_find(fd);
+       if (!(fil && xtv_count))
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF);
+
+       ixtv = ixtvent = malloc(xtv_count * sizeof(struct intnl_xtvec));
+       if (!ixtv)
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, -ENOMEM);
+
+       count = xtv_count;
+       while (count--) {
+               ixtvent->xtv_off = xtv->xtv_off;
+               ixtvent->xtv_len = xtv->xtv_len;
+               ixtvent++;
+               xtv++;
+       }
+
+       err =
+           _sysio_iiox(IIOXOP_READ(fil->f_ino),
+                       fil,
+                       iov, iov_count, NULL,
+                       ixtv, xtv_count, free_xtv,
+                       NULL,
+                       &ioctx);
+       if (err) {
+               free(ixtv);
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, err);
+       }
+       SYSIO_INTERFACE_RETURN(ioctx->ioctx_id, 0);
+}
+#else
+#undef ireadx
+sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(ireadx)),
+                    SYSIO_INTERFACE_NAME(ireadx))
+#endif
+
+ssize_t
+SYSIO_INTERFACE_NAME(readx)(int fd,
+                           const struct iovec *iov, size_t iov_count,
+                           const struct xtvec *xtv, size_t xtv_count)
+{
+       ioid_t  ioid;
+
+       if ((ioid = SYSIO_INTERFACE_NAME(ireadx)(fd, 
+                                                iov, 
+                                                iov_count, 
+                                                xtv, 
+                                                xtv_count)) == IOID_FAIL)
+               return -1;
+       return iowait(ioid);
+}
+
+#if _LARGEFILE64_SOURCE
+#undef iread64x
+ssize_t
+SYSIO_INTERFACE_NAME(read64x)(int fd,
+                             const struct iovec *iov, size_t iov_count,
+                             const struct xtvec64 *xtv, size_t xtv_count)
+{
+       ioid_t  ioid;
+
+       if ((ioid = SYSIO_INTERFACE_NAME(iread64x)(fd, 
+                                                  iov, 
+                                                  iov_count, 
+                                                  xtv, 
+                                                  xtv_count)) == IOID_FAIL)
+               return -1;
+       return iowait(ioid);
+}
+#endif
+
+#ifdef notdef
+int
+read_list(int fd,
+         int mem_list_count,
+         char *mem_offsets[],
+         int mem_lengths[],
+         int file_list_count,
+         int64_t file_offsets[],
+         int32_t file_lengths[])
+{
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       SYSIO_INTERFACE_RETURN(-1, -ENOSYS);
+}
+#endif
+
+ioid_t
+SYSIO_INTERFACE_NAME(iwritev)(int fd, 
+                             const struct iovec *iov, 
+                             int count)
+{
+       struct file *fil;
+       struct intnl_xtvec *xtv;
+       struct ioctx *ioctx;
+       int     err;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fil = _sysio_fd_find(fd);
+       if (!fil)
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF);
+
+       xtv = malloc(sizeof(struct intnl_xtvec));
+       if (!xtv)
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, -ENOMEM);
+
+       err =
+           _sysio_iiov(IIOXOP_WRITE(fil->f_ino),
+                       fil,
+                       iov, count, NULL,
+                       xtv, free_xtv,
+                       &ioctx);
+       if (err) {
+               free(xtv);
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, err);
+       }
+       SYSIO_INTERFACE_RETURN(ioctx->ioctx_id, 0);
+}
+
+ssize_t
+SYSIO_INTERFACE_NAME(writev)(int fd, const struct iovec *iov, int count)
+{
+       struct file *fil;
+       struct intnl_xtvec xtvector;
+       struct ioctx *ioctx;
+       int     err;
+       ssize_t cc;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fil = _sysio_fd_find(fd);
+       if (!fil)
+               SYSIO_INTERFACE_RETURN(-1, -EBADF);
+
+       err =
+           _sysio_iiov(IIOXOP_WRITE(fil->f_ino),
+                       fil,
+                       iov, count, NULL,
+                       &xtvector, NULL,
+                       &ioctx);
+       if (!err && (cc = _sysio_ioctx_wait(ioctx)) < 0)
+               err = (int )cc;
+
+       SYSIO_INTERFACE_RETURN(err < 0 ? -1 : cc, err);
+}
+
+#ifdef __GLIBC__
+#undef __writev
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(writev),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(writev)))
+#undef __libc_writev
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(writev),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(libc_writev)))
+#endif
+
+ioid_t
+SYSIO_INTERFACE_NAME(iwrite)(int fd, const void *buf, size_t count)
+{
+       struct iovec *iov;
+       struct file *fil;
+       struct intnl_xtvec *xtv;
+       struct ioctx *ioctx;
+       int     err;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fil = _sysio_fd_find(fd);
+       if (!fil)
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF);
+
+       iov = malloc(sizeof(struct iovec));
+       if (!iov)
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, -ENOMEM);
+
+       iov->iov_base = (void *)buf;
+       iov->iov_len = count;
+       xtv = malloc(sizeof(struct intnl_xtvec));
+       if (!xtv) {
+               free(iov);
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, -ENOMEM);
+       }
+       err =
+           _sysio_iiov(IIOXOP_WRITE(fil->f_ino),
+                       fil,
+                       iov, 1, free_iov,
+                       xtv, free_xtv,
+                       &ioctx);
+       if (err) {
+               free(xtv);
+               free(iov);
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, err);
+       }
+       SYSIO_INTERFACE_RETURN(ioctx->ioctx_id, 0);
+}
+
+ssize_t
+SYSIO_INTERFACE_NAME(write)(int fd, const void *buf, size_t count)
+{
+       struct file *fil;
+       struct iovec iovector;
+       struct intnl_xtvec xtvector;
+       int     err;
+       struct ioctx *ioctx;
+       ssize_t cc;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fil = _sysio_fd_find(fd);
+       if (!fil)
+               SYSIO_INTERFACE_RETURN(-1, -EBADF);
+
+       iovector.iov_base = (void *)buf;
+       iovector.iov_len = count;
+       err =
+           _sysio_iiov(IIOXOP_WRITE(fil->f_ino),
+                       fil,
+                       &iovector, 1, NULL,
+                       &xtvector, NULL,
+                       &ioctx);
+       if (!err && (cc = _sysio_ioctx_wait(ioctx)) < 0)
+               err = (int )cc;
+
+       SYSIO_INTERFACE_RETURN(err < 0 ? -1 : cc, err);
+}
+
+#ifdef __GLIBC__
+#undef __write
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(write),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(write)))
+#undef __libc_write
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(write),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(libc_write)))
+#endif 
+
+static ioid_t
+PREPEND(_, SYSIO_INTERFACE_NAME(ipwritev))(int fd, 
+                                          const struct iovec *iov, 
+                                          size_t count, 
+                                          _SYSIO_OFF_T offset)
+{
+       struct file *fil;
+       struct intnl_xtvec *xtv;
+       struct ioctx *ioctx;
+       int     err;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fil = _sysio_fd_find(fd);
+       if (!fil)
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF);
+
+       xtv = malloc(sizeof(struct intnl_xtvec));
+       if (!xtv)
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, -ENOMEM);
+
+       err =
+           _sysio_ipiov(IIOXOP_WRITE(fil->f_ino),
+                        fil,
+                        iov, count, NULL,
+                        offset,
+                        xtv, free_xtv,
+                        &ioctx);
+       if (err) {
+               free(xtv);
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, err);
+       }
+       SYSIO_INTERFACE_RETURN(ioctx->ioctx_id, 0);
+}
+
+#if _LARGEFILE64_SOURCE
+#undef ipwrite64v
+sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(ipwritev)),
+                    SYSIO_INTERFACE_NAME(ipwrite64v))
+#endif
+
+ioid_t
+SYSIO_INTERFACE_NAME(ipwritev)(int fd, 
+                              const struct iovec *iov, 
+                              size_t count, 
+                              off_t offset)
+{
+
+       return PREPEND(_, SYSIO_INTERFACE_NAME(ipwritev))(fd, 
+                                                         iov, 
+                                                         count, 
+                                                         offset);
+}
+
+static ssize_t
+PREPEND(_, SYSIO_INTERFACE_NAME(pwritev))(int fd, 
+                                         const struct iovec *iov, 
+                                         size_t count, 
+                                         _SYSIO_OFF_T offset)
+{
+       struct file *fil;
+       struct intnl_xtvec xtvector;
+       struct ioctx *ioctx;
+       int     err;
+       ssize_t cc;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fil = _sysio_fd_find(fd);
+       if (!fil)
+               SYSIO_INTERFACE_RETURN(-1, -EBADF);
+
+       err =
+           _sysio_ipiov(IIOXOP_WRITE(fil->f_ino),
+                        fil,
+                        iov, count, NULL,
+                        offset,
+                        &xtvector, NULL,
+                        &ioctx);
+       if (!err && (cc = _sysio_ioctx_wait(ioctx)) < 0)
+               err = (int )cc;
+
+       SYSIO_INTERFACE_RETURN(err ? -1 : cc, err);
+}
+
+#if _LARGEFILE64_SOURCE
+#undef pwrite64v
+sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(pwritev)),
+                    SYSIO_INTERFACE_NAME(pwrite64v))
+#endif
+
+ssize_t
+SYSIO_INTERFACE_NAME(pwritev)(int fd, 
+                             const struct iovec *iov, 
+                             size_t count, 
+                             off_t offset)
+{
+
+       return PREPEND(_, SYSIO_INTERFACE_NAME(pwritev))(fd, 
+                                                        iov, 
+                                                        count, 
+                                                        offset);
+}
+
+static ioid_t
+PREPEND(_, SYSIO_INTERFACE_NAME(ipwrite))(int fd, 
+                                         const void *buf, 
+                                         size_t count, 
+                                         _SYSIO_OFF_T offset)
+{
+       struct file *fil;
+       struct intnl_xtvec *xtv;
+       struct iovec *iov;
+       struct ioctx *ioctx;
+       int     err;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fil = _sysio_fd_find(fd);
+       if (!fil)
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF);
+
+       xtv = malloc(sizeof(struct intnl_xtvec));
+       iov = malloc(sizeof(struct iovec));
+       if (!(xtv && iov)) {
+               err = -errno;
+               goto error;
+       }
+       xtv->xtv_off = offset;
+       iov->iov_base = (void *)buf;
+       xtv->xtv_len = iov->iov_len = count;
+       err =
+           _sysio_ipiov(IIOXOP_WRITE(fil->f_ino),
+                        fil,
+                        iov, 1, free_iov,
+                        offset,
+                        xtv, free_xtv,
+                        &ioctx);
+error:
+       if (err) {
+               if (iov)
+                       free(iov);
+               if (xtv)
+                       free(xtv);
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, err);
+       }
+       SYSIO_INTERFACE_RETURN(ioctx->ioctx_id, 0);
+}
+
+#if _LARGEFILE64_SOURCE
+#undef ipwrite64
+sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(ipwrite)),
+                    SYSIO_INTERFACE_NAME(ipwrite64))
+#endif
+
+ioid_t
+SYSIO_INTERFACE_NAME(ipwrite)(int fd, 
+                             const void *buf, 
+                             size_t count, 
+                             off_t offset)
+{
+
+       return PREPEND(_, SYSIO_INTERFACE_NAME(ipwrite))(fd, 
+                                                        buf, 
+                                                        count, 
+                                                        offset);
+}
+
+ssize_t
+PREPEND(_, SYSIO_INTERFACE_NAME(pwrite))(int fd, 
+                                        const void *buf, 
+                                        size_t count, 
+                                        _SYSIO_OFF_T offset)
+{
+       struct file *fil;
+       struct intnl_xtvec xtvec;
+       struct iovec iovec;
+       struct ioctx *ioctx;
+       int     err;
+       ssize_t cc;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fil = _sysio_fd_find(fd);
+       if (!fil)
+               SYSIO_INTERFACE_RETURN(-1, -EBADF);
+
+       xtvec.xtv_off = offset;
+       iovec.iov_base = (void *)buf;
+       xtvec.xtv_len = iovec.iov_len = count;
+       err =
+           _sysio_ipiov(IIOXOP_WRITE(fil->f_ino),
+                        fil,
+                        &iovec, 1, NULL,
+                        offset,
+                        &xtvec, NULL,
+                        &ioctx);
+       if (!err && (cc = _sysio_ioctx_wait(ioctx)) < 0)
+               err = (int )cc;
+
+       SYSIO_INTERFACE_RETURN(err ? -1 : cc, err);
+}
+
+#if _LARGEFILE64_SOURCE
+#undef pwrite64
+sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(pwrite)),
+                    SYSIO_INTERFACE_NAME(pwrite64))
+#ifdef __GLIBC
+#undef __pwrite64
+sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(pwrite)),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(pwrite64)))
+#undef __libc_pwrite64
+sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(pwrite)),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(libc_pwrite64)))
+#endif
+#endif
+
+ssize_t
+SYSIO_INTERFACE_NAME(pwrite)(int fd, 
+                            const void *buf, 
+                            size_t count, 
+                            off_t offset)
+{
+
+       return PREPEND(_, SYSIO_INTERFACE_NAME(pwrite))(fd, 
+                                                       buf, 
+                                                       count, 
+                                                       offset);
+}
+
+#ifdef __GLIBC
+#undef __libc_pwrite
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(pwrite), __libc_pwrite)
+                    PREPEND(__, SYSIO_INTERFACE_NAME(libc_pwrite)))
+#endif
+
+static ioid_t
+PREPEND(_, SYSIO_INTERFACE_NAME(iwritex))(int fd,
+                                         const struct iovec *iov, 
+                                         size_t iov_count, 
+                                         const struct intnl_xtvec *xtv, 
+                                         size_t xtv_count)
+{
+       struct file *fil;
+       int     err;
+       struct ioctx *ioctx;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fil = _sysio_fd_find(fd);
+       if (!(fil && xtv_count))
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF);
+
+       err =
+           _sysio_iiox(IIOXOP_WRITE(fil->f_ino),
+                       fil,
+                       iov, iov_count, NULL,
+                       xtv, xtv_count, NULL,
+                       NULL,
+                       &ioctx);
+
+       SYSIO_INTERFACE_RETURN(err ? IOID_FAIL : ioctx->ioctx_id, err);
+}
+
+#if _LARGEFILE64_SOURCE
+#undef iwrite64x
+sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(iwritex)),
+                    SYSIO_INTERFACE_NAME(iwrite64x))
+#endif
+
+#if _LARGEFILE64_SOURCE
+ioid_t
+SYSIO_INTERFACE_NAME(iwritex)(int fd,
+                             const struct iovec *iov, size_t iov_count,
+                             const struct xtvec *xtv, size_t xtv_count)
+{
+       struct file *fil;
+       struct intnl_xtvec *ixtv, *ixtvent;
+       size_t  count;
+       int     err;
+       struct ioctx *ioctx;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fil = _sysio_fd_find(fd);
+       if (!(fil && xtv_count))
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF);
+
+       ixtv = ixtvent = malloc(xtv_count * sizeof(struct intnl_xtvec));
+       if (!ixtv)
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, -ENOMEM);
+
+       count = xtv_count;
+       while (count--) {
+               ixtvent->xtv_off = xtv->xtv_off;
+               ixtvent->xtv_len = xtv->xtv_len;
+               ixtvent++;
+               xtv++;
+       }
+
+       err =
+           _sysio_iiox(IIOXOP_WRITE(fil->f_ino),
+                       fil,
+                       iov, iov_count, NULL,
+                       ixtv, xtv_count, free_xtv,
+                       NULL,
+                       &ioctx);
+       if (err) {
+               free(ixtv);
+               SYSIO_INTERFACE_RETURN(IOID_FAIL, err);
+       }
+       SYSIO_INTERFACE_RETURN(ioctx->ioctx_id, 0);
+}
+#else
+#undef iwritex
+sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(iwritex)),
+                    SYSIO_INTERFACE_NAME(iwritex))
+#endif
+
+#undef writex
+ssize_t
+SYSIO_INTERFACE_NAME(writex)(int fd,
+                            const struct iovec *iov, size_t iov_count,
+                            const struct xtvec *xtv, size_t xtv_count)
+{
+       ioid_t  ioid;
+
+       if ((ioid = 
+            SYSIO_INTERFACE_NAME(iwritex)(fd, 
+                                          iov, 
+                                          iov_count, 
+                                          xtv, 
+                                          xtv_count)) == IOID_FAIL)
+               return -1;
+       return iowait(ioid);
+}
+
+#if _LARGEFILE64_SOURCE
+#undef write64x
+ssize_t
+SYSIO_INTERFACE_NAME(write64x)(int fd,
+        const struct iovec *iov, size_t iov_count,
+        const struct xtvec64 *xtv, size_t xtv_count)
+{
+       ioid_t  ioid;
+
+       if ((ioid = SYSIO_INTERFACE_NAME(iwrite64x)(fd, 
+                                                   iov, 
+                                                   iov_count, 
+                                                   xtv, 
+                                                   xtv_count)) == IOID_FAIL)
+               return -1;
+       return iowait(ioid);
+}
+#endif
+
+#ifdef notdef
+int
+write_list(int fd,
+          int mem_list_count,
+          char *mem_offsets[],
+          int mem_lengths[],
+          int file_list_count,
+          int64_t file_offsets[],
+          int32_t file_lengths[])
+{
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       SYSIO_INTERFACE_RETURN(-1, -ENOSYS);
+}
+#endif
diff --git a/libsysio/src/stat.c b/libsysio/src/stat.c
new file mode 100644 (file)
index 0000000..4fec1f1
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "inode.h"
+#include "file.h"
+
+#include "sysio-symbols.h"
+
+#ifndef REDSTORM
+#undef fstat
+#undef stat
+#undef lstat
+#endif
+
+#undef __fxstat
+#undef __xstat
+#undef __lxstat
+
+#if !defined(_STAT_VER)
+#define _STAT_VER              0
+#endif
+
+#if _LARGEFILE64_SOURCE
+static void
+convstat(struct stat64 *st64_buf, struct stat *st_buf)
+{
+
+       st_buf->st_dev = st64_buf->st_dev;
+       st_buf->st_ino = st64_buf->st_ino;
+       st_buf->st_mode = st64_buf->st_mode;
+       st_buf->st_nlink = st64_buf->st_nlink;
+       st_buf->st_uid = st64_buf->st_uid;
+       st_buf->st_gid = st64_buf->st_gid;
+       st_buf->st_rdev = st64_buf->st_rdev;
+       st_buf->st_size = st64_buf->st_size;
+       st_buf->st_blksize = st64_buf->st_blksize;
+       st_buf->st_blocks = st64_buf->st_blocks;
+       st_buf->st_atime = st64_buf->st_atime;
+       st_buf->st_mtime = st64_buf->st_mtime;
+       st_buf->st_ctime = st64_buf->st_ctime;
+}
+#endif
+
+int
+PREPEND(__, SYSIO_INTERFACE_NAME(fxstat))(int __ver, 
+                                         int __fildes, 
+                                         struct stat *__stat_buf)
+{
+       struct file *fil;
+       int     err;
+       struct intnl_stat *buf;
+#if _LARGEFILE64_SOURCE
+       struct stat64 st64;
+#endif
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       if (__ver != _STAT_VER) {
+               err = -ENOSYS;
+               goto out;
+       }
+
+       err = 0;
+       fil = _sysio_fd_find(__fildes);
+       if (!fil) {
+               err = -EBADF;
+               goto out;
+       }
+#if _LARGEFILE64_SOURCE
+       buf = &st64;
+#else
+       buf = __stat_buf;
+#endif
+       err =
+           fil->f_ino->i_ops.inop_getattr(NULL, fil->f_ino, buf);
+#if _LARGEFILE64_SOURCE
+       if (!err)
+               convstat(buf, __stat_buf);
+#endif
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#ifdef REDSTORM
+#undef _fxstat
+sysio_sym_weak_alias(PREPEND(__, SYSIO_INTERFACE_NAME(fxstat)), 
+                    PREPEND(_, SYSIO_INTERFACE_NAME(fxstat)))
+#endif
+
+#ifndef REDSTORM
+static int
+PREPEND(__, SYSIO_INTERFACE_NAME(fstat))(int fd, struct stat *buf)
+{
+
+       return PREPEND(__, SYSIO_INTERFACE_NAME(fxstat))(_STAT_VER, 
+                                                        fd, 
+                                                        buf);
+}
+
+sysio_sym_weak_alias(PREPEND(__, SYSIO_INTERFACE_NAME(fstat)), 
+                    SYSIO_INTERFACE_NAME(fstat))
+
+#ifdef BSD
+#undef _fstat
+sysio_sym_weak_alias(PREPEND(__, SYSIO_INTERFACE_NAME(fstat)),
+                    PREPEND(_, SYSIO_INTERFACE_NAME(fstat)))
+#endif
+#endif
+
+int
+PREPEND(__, SYSIO_INTERFACE_NAME(xstat))(int __ver, 
+                                        const char *__filename, 
+                                        struct stat *__stat_buf)
+{
+       struct intent intent;
+       int     err;
+       struct pnode *pno;
+       struct inode *ino;
+       struct intnl_stat *buf;
+#if _LARGEFILE64_SOURCE
+       struct stat64 st64;
+#endif
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       if (__ver != _STAT_VER) {
+               err = -ENOSYS;
+               goto out;
+       }
+
+       INTENT_INIT(&intent, INT_GETATTR, NULL, NULL);
+       err = _sysio_namei(_sysio_cwd, __filename, 0, &intent, &pno);
+       if (err)
+               goto out;
+       ino = pno->p_base->pb_ino;
+#if _LARGEFILE64_SOURCE
+       buf = &st64;
+#else
+       buf = __stat_buf;
+#endif
+       err =
+           ino->i_ops.inop_getattr(pno,
+                                   pno->p_base->pb_ino,
+                                   buf);
+
+       P_RELE(pno);
+#if _LARGEFILE64_SOURCE
+       if (!err)
+               convstat(buf, __stat_buf);
+#endif
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#ifdef REDSTORM
+#undef _xstat
+sysio_sym_weak_alias(PREPEND(__, SYSIO_INTERFACE_NAME(xstat)),
+                    PREPEND(_, SYSIO_INTERFACE_NAME(xstat)))
+#endif
+
+#ifndef REDSTORM
+static int
+PREPEND(__, SYSIO_INTERFACE_NAME(stat))(const char *filename, 
+                                       struct stat *buf)
+{
+
+       return PREPEND(__, SYSIO_INTERFACE_NAME(xstat))(_STAT_VER, 
+                                                       filename,
+                                                       buf);
+}
+
+sysio_sym_weak_alias(PREPEND(__, SYSIO_INTERFACE_NAME(stat)),
+                    SYSIO_INTERFACE_NAME(stat))
+
+#ifdef BSD
+#undef _stat
+sysio_sym_weak_alias(PREPEND(__, SYSIO_INTERFACE_NAME(stat)),
+                    PREPEND(_, SYSIO_INTERFACE_NAME(stat)))
+#endif
+#endif
+
+int
+PREPEND(__, SYSIO_INTERFACE_NAME(lxstat))(int __ver, 
+                                         const char *__filename, 
+                                         struct stat *__stat_buf)
+{
+       struct intent intent;
+       int     err;
+       struct pnode *pno;
+       struct inode *ino;
+       struct intnl_stat *buf;
+#if _LARGEFILE64_SOURCE
+       struct stat64 st64;
+#endif
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       if (__ver != _STAT_VER) {
+               err = -ENOSYS;
+               goto out;
+       }
+
+       INTENT_INIT(&intent, INT_GETATTR, NULL, NULL);
+       err = _sysio_namei(_sysio_cwd, __filename, ND_NOFOLLOW, &intent, &pno);
+       if (err)
+               goto out;
+#if _LARGEFILE64_SOURCE
+       buf = &st64;
+#else
+       buf = __stat_buf;
+#endif
+       ino = pno->p_base->pb_ino;
+       err =
+           ino->i_ops.inop_getattr(pno,
+                                   pno->p_base->pb_ino,
+                                   buf);
+
+       P_RELE(pno);
+#if _LARGEFILE64_SOURCE
+       if (!err)
+               convstat(buf, __stat_buf);
+#endif
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#ifdef REDSTORM
+#undef _lxstat
+sysio_sym_weak_alias(PREPEND(__, SYSIO_INTERFACE_NAME(lxstat)),
+                    PREPEND(_, SYSIO_INTERFACE_NAME(lxstat)))
+#endif
+
+#ifndef REDSTORM
+static int
+PREPEND(__, SYSIO_INTERFACE_NAME(lstat))(const char *filename, struct stat *buf)
+{
+       return PREPEND(__, SYSIO_INTERFACE_NAME(lxstat))(_STAT_VER, 
+                                                        filename,
+                                                        buf);
+}
+
+sysio_sym_weak_alias(PREPEND(__, SYSIO_INTERFACE_NAME(lstat)),
+                    SYSIO_INTERFACE_NAME(lstat))
+
+#ifdef BSD
+#undef _lstat
+sysio_sym_weak_alias(PREPEND(__, SYSIO_INTERFACE_NAME(lstat)),
+                    PREPEND(_, SYSIO_INTERFACE_NAME(lstat)))
+#endif
+#endif
diff --git a/libsysio/src/stat64.c b/libsysio/src/stat64.c
new file mode 100644 (file)
index 0000000..377e2dc
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#ifdef _LARGEFILE64_SOURCE
+
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "inode.h"
+#include "file.h"
+
+#ifndef REDSTORM
+#undef fstat64
+#undef stat64
+#undef lstat64
+#endif
+
+#undef __fxstat64
+#undef __xstat64
+#undef __lxstat64
+
+int
+PREPEND(__, SYSIO_INTERFACE_NAME(fxstat64))(int __ver,
+                                           int __fildes,
+                                           struct stat64 *__stat_buf)
+{
+       struct file *fil;
+       int     err;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       if (__ver != _STAT_VER) {
+               err = -ENOSYS;
+               goto out;
+       }
+
+       err = 0;
+       fil = _sysio_fd_find(__fildes);
+       if (!fil) {
+               err = -EBADF;
+               goto out;
+       }
+       err = fil->f_ino->i_ops.inop_getattr(NULL, fil->f_ino, __stat_buf);
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#ifndef REDSTORM
+int
+SYSIO_INTERFACE_NAME(fstat64)(int fd, struct stat64 *buf)
+{
+
+       return PREPEND(__, SYSIO_INTERFACE_NAME(fxstat64))(_STAT_VER, fd, buf);
+}
+#endif
+
+int
+PREPEND(__, SYSIO_INTERFACE_NAME(xstat64))(int __ver,
+                                          const char *__filename,
+                                          struct stat64 *__stat_buf)
+{
+       struct intent intent;
+       int     err;
+       struct pnode *pno;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       if (__ver != _STAT_VER) {
+               err = -ENOSYS;
+               goto out;
+       }
+
+       INTENT_INIT(&intent, INT_GETATTR, NULL, NULL);
+       err = _sysio_namei(_sysio_cwd, __filename, 0, &intent, &pno);
+       if (err)
+               goto out;
+       err =
+           pno->p_base->pb_ino->i_ops.inop_getattr(pno,
+                                                   pno->p_base->pb_ino,
+                                                   __stat_buf);
+       P_RELE(pno);
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#ifndef REDSTORM
+int
+SYSIO_INTERFACE_NAME(stat64)(const char *filename, struct stat64 *buf)
+{
+
+       return PREPEND(__, SYSIO_INTERFACE_NAME(xstat64))(_STAT_VER,
+                                                         filename,
+                                                         buf);
+}
+#endif
+
+int
+PREPEND(__, SYSIO_INTERFACE_NAME(lxstat64))(int __ver,
+                                           const char *__filename,
+                                           struct stat64 *__stat_buf)
+{
+       struct intent intent;
+       int     err;
+       struct pnode *pno;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       if (__ver != _STAT_VER) {
+               err = -ENOSYS;
+               goto out;
+       }
+
+       INTENT_INIT(&intent, INT_GETATTR, NULL, NULL);
+       err = _sysio_namei(_sysio_cwd, __filename, ND_NOFOLLOW, &intent, &pno);
+       if (err)
+               goto out;
+       err =
+           pno->p_base->pb_ino->i_ops.inop_getattr(pno,
+                                                   pno->p_base->pb_ino,
+                                                   __stat_buf);
+       P_RELE(pno);
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#ifndef REDSTORM
+int
+SYSIO_INTERFACE_NAME(lstat64)(const char *filename, struct stat64 *buf)
+{
+
+       return PREPEND(__, SYSIO_INTERFACE_NAME(lxstat64))(_STAT_VER,
+                                                          filename,
+                                                          buf);
+}
+#endif
+#endif /* !_LARGEFILE64_SOURCE */
diff --git a/libsysio/src/statvfs.c b/libsysio/src/statvfs.c
new file mode 100644 (file)
index 0000000..5f07387
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#ifndef BSD
+
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/statvfs.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "inode.h"
+#include "file.h"
+#include "sysio-symbols.h"
+
+#undef statvfs
+#undef fstatvfs
+
+#ifndef INTNL_STATVFS_IS_NATURAL
+static void
+convstatvfs(struct statvfs *stvfsbuf, struct intnl_statvfs *istvfsbuf)
+{
+       stvfsbuf->f_bsize = istvfsbuf->f_bsize;
+       stvfsbuf->f_frsize = istvfsbuf->f_frsize;
+       stvfsbuf->f_blocks = (unsigned long )istvfsbuf->f_blocks;
+       stvfsbuf->f_bfree = (unsigned long )istvfsbuf->f_bfree;
+       stvfsbuf->f_bavail = (unsigned long )istvfsbuf->f_bavail;
+       stvfsbuf->f_files = (unsigned long )istvfsbuf->f_files;
+       stvfsbuf->f_ffree = (unsigned long )istvfsbuf->f_ffree;
+       stvfsbuf->f_favail = (unsigned long )istvfsbuf->f_favail;
+       stvfsbuf->f_fsid = istvfsbuf->f_fsid;
+       stvfsbuf->f_flag = istvfsbuf->f_flag;
+       stvfsbuf->f_namemax = istvfsbuf->f_namemax;
+}
+#endif
+
+int
+SYSIO_INTERFACE_NAME(statvfs)(const char *path, struct statvfs *buf)
+{
+       int     err;
+       struct pnode *pno;
+#ifdef INTNL_STATVFS_IS_NATURAL
+#define _call_buf buf
+#else
+       struct intnl_statvfs _call_buffer;
+       struct intnl_statvfs *_call_buf = &_call_buffer;
+#endif
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       err = _sysio_namei(_sysio_cwd, path, 0, NULL, &pno);
+       if (err)
+               goto out;
+
+       err = pno->p_base->pb_ino->i_ops.inop_statvfs(pno, NULL, _call_buf);
+       P_RELE(pno);
+       if (err)
+               goto err;
+#ifndef INTNL_STATVFS_IS_NATURAL
+       convstatvfs(buf, _call_buf);
+#endif
+       goto out;
+err:
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#ifdef REDSTORM
+#undef __statvfs
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(statvfs),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(statvfs)))
+#endif
+
+int
+SYSIO_INTERFACE_NAME(fstatvfs)(int fd, struct statvfs *buf)
+{
+       int     err;
+       struct file *filp;
+#ifdef INTNL_STATVFS_IS_NATURAL
+#define _call_buf buf
+#else
+       struct intnl_statvfs _call_buffer;
+       struct intnl_statvfs *_call_buf = &_call_buffer;
+#endif
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       err = 0;
+       filp = _sysio_fd_find(fd);
+       if (!filp) {
+               err = -EBADF;
+               goto out;
+       }
+
+       err = filp->f_ino->i_ops.inop_statvfs(NULL, filp->f_ino, _call_buf);
+       if (err)
+               goto err;
+#ifndef INTNL_STATVFS_IS_NATURAL
+       convstatvfs(buf, _call_buf);
+#endif
+       goto out;
+err:
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#ifdef REDSTORM
+#undef __fstatvfs
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(fstatvfs),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(fstatvfs)))
+#endif
+
+#endif /* ifndef BSD */
diff --git a/libsysio/src/statvfs64.c b/libsysio/src/statvfs64.c
new file mode 100644 (file)
index 0000000..c89c969
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#ifndef BSD
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/vfs.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "inode.h"
+#include "file.h"
+#include "sysio-symbols.h"
+
+int
+SYSIO_INTERFACE_NAME(statvfs64)(const char *path, struct statvfs64 *buf)
+{
+       int     err;
+       struct pnode *pno;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       err = _sysio_namei(_sysio_cwd, path, 0, NULL, &pno);
+       if (err)
+               goto out;
+
+       err = pno->p_base->pb_ino->i_ops.inop_statvfs(pno, NULL, buf);
+       P_RELE(pno);
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#ifdef REDSTORM
+#undef __statvfs64
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(statvfs64),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(statvfs64)))
+#endif
+
+int
+SYSIO_INTERFACE_NAME(fstatvfs64)(int fd, struct statvfs64 *buf)
+{
+       int     err;
+       struct file *filp;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       err = 0;
+       filp = _sysio_fd_find(fd);
+       if (!filp) {
+               err = -EBADF;
+               goto out;
+       }
+
+       err = filp->f_ino->i_ops.inop_statvfs(NULL, filp->f_ino, buf);
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#ifdef REDSTORM
+#undef __fstatvfs64
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(fstatvfs64),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(fstatvfs64)))
+#endif
+
+#endif /* ifndef BSD */
diff --git a/libsysio/src/stdlib.c b/libsysio/src/stdlib.c
new file mode 100644 (file)
index 0000000..7446f35
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/*
+ * stdlib.c
+ *
+ * The only purpose of this file is help liblustre adaptive to more
+ * applications, and specifically for running on Linux. The ideal
+ * final solution would be remove this completely and only rely on
+ * system call interception. Unfortunately we failed to find that
+ * way at the moment.
+ *
+ * Initially we try the simplest implementation here, just get a confidence
+ * it could work.
+ *
+ */
+#if !(defined(BSD) || defined(REDSTORM))
+
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#include <sysio.h>
+
+#include "sysio-symbols.h"
+
+#if !defined(__USE_LARGEFILE64)
+#error "__LARGEFILE64_SOURCE must be defined"
+#endif
+
+
+/***********************************************************
+ * dir series functions                                    *
+ ***********************************************************/
+
+#undef  BUFSIZE
+#define BUFSIZE        4096
+
+struct __dirstream {
+       int               fd;
+       loff_t            base;
+       loff_t            filepos;       /* current pos in dir file stream */
+       struct dirent    *curent;        /* current dirent pointer */
+       struct dirent64  *curent64;      /* current dirent64 pointer */
+       struct dirent    *retent;        /* ent returned to caller */
+       struct dirent64  *retent64;      /* ent64 returned to caller */
+       unsigned int      effective;     /* effective data size in buffer */
+       char              buf[BUFSIZE];
+};
+
+DIR* opendir(const char *name)
+{
+       DIR *dir;
+
+       dir = (DIR *) malloc(sizeof(*dir));
+       if (!dir) {
+               errno = ENOMEM;
+               return NULL;
+       }
+
+#if __USE_LARGEFILE64
+       dir->fd = open64(name, O_RDONLY);
+#else
+       dir->fd = open(name, O_RDONLY);
+#endif
+       if (dir->fd < 0)
+               goto err_out;
+
+       dir->base = 0;
+       dir->filepos = 0;
+       dir->curent = (struct dirent *) dir->buf;
+       dir->curent64 = (struct dirent64 *) dir->buf;
+       dir->retent = NULL;
+       dir->retent64 = NULL;
+       dir->effective = 0;
+
+       return dir;
+err_out:
+       free(dir);
+       return NULL;
+}
+
+sysio_sym_weak_alias(opendir, __opendir);
+
+struct dirent64 *readdir64(DIR *dir)
+{
+       int rc, reclen;
+
+       /* need to read new data? */
+       if ((char*)dir->curent64 - dir->buf >= dir->effective) {
+               rc = getdirentries64(dir->fd, dir->buf, BUFSIZE, &dir->base);
+               /* error or end-of-file */
+               if (rc <= 0)
+                       return NULL;
+
+               dir->curent64 = (struct dirent64 *) dir->buf;
+               dir->effective = rc;
+       }
+
+       dir->retent64 = dir->curent64;
+       dir->curent64 = (struct dirent64*) ((char *)(dir->curent64) +
+                               dir->curent64->d_reclen);
+#ifdef _DIRENT_HAVE_D_OFF
+       dir->filepos = dir->curent64->d_off;
+#else
+       dir->filepos += dir->curent64->d_reclen;
+#endif
+       return dir->retent64;
+}
+
+sysio_sym_weak_alias(readdir64, __readdir64);
+
+/* XXX probably the following assumption is not true */
+#if __WORDSIZE == 64
+#define NATURAL_READDIR64
+#else
+#undef  NATURAL_READDIR64
+#endif
+
+#ifndef NATURAL_READDIR64
+
+struct dirent *readdir(DIR *dir)
+{
+       int rc, reclen;
+
+       /* need to read new data? */
+       if ((char*)dir->curent - dir->buf >= dir->effective) {
+               rc = getdirentries(dir->fd, dir->buf, BUFSIZE, (off_t*) &dir->base);
+               /* error or end-of-file */
+               if (rc <= 0)
+                       return NULL;
+
+               dir->curent = (struct dirent *) dir->buf;
+               dir->effective = rc;
+       }
+
+       dir->retent = dir->curent;
+       dir->curent = (struct dirent*) ((char *)(dir->curent) +
+                               dir->curent->d_reclen);
+#ifdef _DIRENT_HAVE_D_OFF
+       dir->filepos = dir->curent->d_off;
+#else
+       dir->filepos += dir->curent->d_reclen;
+#endif
+       return dir->retent;
+}
+sysio_sym_weak_alias(readdir, __readdir);
+
+#else /* NATURAL_READDIR64 */
+
+struct dirent *readdir(DIR *dir) {
+       return (struct dirent *) readdir64(dir);
+}
+sysio_sym_weak_alias(readdir, __readdir);
+
+#endif /* NATURAL_READDIR64 */
+
+int closedir(DIR *dir)
+{
+       int rc;
+
+       rc = close(dir->fd);
+
+       free(dir);
+       return rc;
+}
+
+sysio_sym_weak_alias(closedir, __closedir);
+
+int dirfd(DIR *dir)
+{
+       return dir->fd;
+}
+
+off_t telldir(DIR *dir)
+{
+       return (dir->filepos);
+}
+
+void seekdir(DIR *dir, off_t offset)
+{
+       dir->filepos = offset;
+
+       dir->base = offset;
+       dir->curent64 = (struct dirent64 *) dir->buf;
+       dir->retent64 = NULL;
+       dir->effective = 0;
+       dir->curent = (struct dirent *) dir->buf;
+       dir->retent = NULL;
+}
+
+void rewinddir(DIR *dir)
+{
+       dir->base = 0;
+       dir->filepos = 0;
+       dir->curent64 = (struct dirent64 *) dir->buf;
+       dir->retent64 = NULL;
+       dir->curent = (struct dirent *) dir->buf;
+       dir->retent = NULL;
+       dir->effective = 0;
+}
+
+int scandir(const char *dir, struct dirent ***namelist,
+            int(*select)(const struct dirent *),
+            int(*compar)(const void *, const void *))
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+int scandir64(const char *dir, struct dirent64 ***namelist,
+              int(*select)(const struct dirent64 *),
+              int(*compar)(const void *, const void *))
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+/***********************************************************
+ * FIXME workaround for linux only                         *
+ ***********************************************************/
+
+#define LINUX
+#if defined(LINUX)
+ssize_t getxattr(char *path, char *name, void *value, size_t size)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+ssize_t lgetxattr(char *path, char *name, void *value, size_t size)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+ssize_t fgetxattr(int fd, char *name, void *value, size_t size)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+long setxattr(char *path, char *name, void *value, size_t size, int flags)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+long lsetxattr(char *path, char *name, void *value, size_t size, int flags)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+long fsetxattr(int fd, char *name, void *value, size_t size, int flags)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+long listxattr(char *path, char *list, size_t size)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+long llistxattr(char *path, char *list, size_t size)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+long flistxattr(int fd, char *list, size_t size)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+long removexattr(char *path, char *name)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+long lremovexattr(char *path, char *name)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+long fremovexattr(int fd, char *name)
+{
+       errno = ENOSYS;
+       return -1;
+}
+#endif
+
+#endif
diff --git a/libsysio/src/symlink.c b/libsysio/src/symlink.c
new file mode 100644 (file)
index 0000000..1142432
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "inode.h"
+#include "fs.h"
+#include "mount.h"
+#include "sysio-symbols.h"
+
+int
+SYSIO_INTERFACE_NAME(symlink)(const char *oldpath, const char *newpath)
+{
+       int     err;
+       struct intent intent;
+       struct pnode *pno;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       INTENT_INIT(&intent, INT_CREAT, NULL, NULL);
+       err = _sysio_namei(_sysio_cwd, newpath, ND_NEGOK, &intent, &pno);
+       if (err)
+               goto out;
+       if (pno->p_base->pb_ino) {
+               err = -EEXIST;
+               goto error;
+       }
+
+       if (IS_RDONLY(pno, pno->p_base->pb_ino)) {
+               err = -EROFS;
+               goto error;
+       }
+       err =
+           (*pno->p_parent->p_base->pb_ino->i_ops.inop_symlink)(pno, oldpath);
+error:
+       P_RELE(pno);
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#ifdef REDSTORM
+#undef __symlink
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(symlink),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(symlink)))
+#endif
diff --git a/libsysio/src/truncate.c b/libsysio/src/truncate.c
new file mode 100644 (file)
index 0000000..718f0af
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "inode.h"
+#include "file.h"
+
+#include "sysio-symbols.h"
+
+/*
+ * Truncate file, given path (alias) or index node.
+ */
+static int
+do_truncate(struct pnode *pno, struct inode *ino, _SYSIO_OFF_T length)
+{
+       struct intnl_stat stbuf;
+       unsigned mask;
+
+       if (length < 0)
+               return -EINVAL;
+
+       if (!ino && pno->p_base->pb_ino)
+               ino = pno->p_base->pb_ino;
+       if (!ino)
+               return -EBADF;
+       if (S_ISDIR(ino->i_mode))                       /* for others too? */
+               return -EISDIR;
+       if (!S_ISREG(ino->i_mode))
+               return -EINVAL;
+
+       (void )memset(&stbuf, 0, sizeof(stbuf));
+       stbuf.st_size = length;
+       mask = SETATTR_LEN;
+       return _sysio_setattr(pno, ino, mask, &stbuf);
+}
+
+static int
+PREPEND(_, SYSIO_INTERFACE_NAME(truncate))(const char *path, 
+                                          _SYSIO_OFF_T length)
+{
+       int     err;
+       struct pnode *pno;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       err = _sysio_namei(_sysio_cwd, path, 0, NULL, &pno);
+       if (err)
+               goto out;
+       err = do_truncate(pno, pno->p_base->pb_ino, length);
+       P_RELE(pno);
+
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#if _LARGEFILE64_SOURCE
+#undef truncate64
+sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(truncate)),
+                    SYSIO_INTERFACE_NAME(truncate64))
+
+#undef truncate
+int
+SYSIO_INTERFACE_NAME(truncate)(const char *path, off_t length)
+{
+
+       return PREPEND(_, SYSIO_INTERFACE_NAME(truncate))(path, length);
+}
+#else
+#undef truncate
+sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(truncate)),
+                    SYSIO_INTERFACE_NAME(truncate))
+#endif
+
+static int
+PREPEND(_, SYSIO_INTERFACE_NAME(ftruncate))(int fd, _SYSIO_OFF_T length)
+{
+       int     err;
+       struct file *fil;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       err = 0;
+       fil = _sysio_fd_find(fd);
+       if (!fil) {
+               err = -EBADF;
+               goto out;
+       }
+       err = do_truncate(NULL, fil->f_ino, length);
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#if _LARGEFILE64_SOURCE
+#undef ftruncate64
+sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(ftruncate)), 
+                    SYSIO_INTERFACE_NAME(ftruncate64))
+
+#undef ftruncate
+int
+SYSIO_INTERFACE_NAME(ftruncate)(int fd, off_t length)
+{
+
+       return PREPEND(_, SYSIO_INTERFACE_NAME(ftruncate))(fd, length);
+}
+#else
+#undef ftruncate
+sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(ftruncate)), 
+                    SYSIO_INTERFACE_NAME(ftruncate))
+#endif
diff --git a/libsysio/src/unlink.c b/libsysio/src/unlink.c
new file mode 100644 (file)
index 0000000..c584fcc
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "inode.h"
+#include "fs.h"
+#include "mount.h"
+#include "sysio-symbols.h"
+
+int
+SYSIO_INTERFACE_NAME(unlink)(const char *path)
+{
+       struct intent intent;
+       int     err;
+       struct pnode *pno;
+       struct inode *ino;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       INTENT_INIT(&intent, INT_UPDPARENT, NULL, NULL);
+       err = _sysio_namei(_sysio_cwd, path, ND_NOFOLLOW, &intent, &pno);
+       if (err)
+               goto out;
+       ino = pno->p_base->pb_ino;
+       if (IS_RDONLY(pno, ino)) {
+               err = -EROFS;
+               goto error;
+       }
+       err = (*ino->i_ops.inop_unlink)(pno);
+       if (err)
+               goto error;
+       assert(pno->p_base->pb_ino);
+       /*
+        * Invalidate the path node.
+        */
+       ino = pno->p_base->pb_ino;
+       pno->p_base->pb_ino = NULL;
+       /*
+        * Kill the i-node. I've thought and thought about this. We
+        * can't allow it to be found via namei any longer because we
+        * can't count on generation numbers support and have no
+        * clue why there might be other soft-references -- Could
+        * be an open file.
+        */
+       I_GONE(ino);
+
+error:
+       P_RELE(pno);
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
+
+#ifdef REDSTORM
+#undef __unlink
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(unlink),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(unlink)))
+#endif
diff --git a/libsysio/src/utime.c b/libsysio/src/utime.c
new file mode 100644 (file)
index 0000000..1124663
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <utime.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "inode.h"
+#include "file.h"
+
+int
+SYSIO_INTERFACE_NAME(utime)(const char *path, const struct utimbuf *buf)
+{
+       int     err;
+       struct pnode *pno;
+       struct utimbuf _utbuffer;
+       struct intnl_stat stbuf;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       err = _sysio_namei(_sysio_cwd, path, 0, NULL, &pno);
+       if (err)
+               goto out;
+       if (!buf) {
+               _utbuffer.actime = _utbuffer.modtime = time(NULL);
+               buf = &_utbuffer;
+       }
+       (void )memset(&stbuf, 0, sizeof(struct intnl_stat));
+       stbuf.st_atime = buf->actime;
+       stbuf.st_mtime = buf->modtime;
+       err =
+           _sysio_setattr(pno,
+                          pno->p_base->pb_ino,
+                          SETATTR_ATIME | SETATTR_MTIME,
+                          &stbuf);
+       P_RELE(pno);
+out:
+       SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
+}
diff --git a/libsysio/tests/Makefile.am b/libsysio/tests/Makefile.am
new file mode 100644 (file)
index 0000000..85c4304
--- /dev/null
@@ -0,0 +1,114 @@
+noinst_PROGRAMS = test_copy test_stats test_path test_list \
+       test_getcwd test_link test_unlink test_rename \
+       test_regions test_driver
+
+CLEANFILES=drv_data.c
+
+if WITH_NATIVE_DRIVER
+NATIVE_DRIVER_NAME=native
+NATIVE_DRIVER_CFLAGS= -I$(top_srcdir)/drivers/native
+else
+NATIVE_DRIVER_NAME=
+NATIVE_DRIVER_CFLAGS=
+endif
+
+if WITH_INCORE_DRIVER
+INCORE_DRIVER_NAME=incore
+INCORE_DRIVER_CFLAGS= -I$(top_srcdir)/drivers/incore
+else
+INCORE_DRIVER_NAME=
+INCORE_DRIVER_CFLAGS=
+endif
+
+if WITH_CPLANT_YOD
+YOD_DRIVER_NAME=yod
+YOD_DRIVER_CFLAGS= -DCPLANT_YOD
+else
+YOD_DRIVER_NAME=
+YOD_DRIVER_CFLAGS=
+endif
+
+if WITH_SOCKETS_DRIVER
+SOCKETS_DRIVER_NAME=sockets
+SOCKETS_DRIVER_CFLAGS= -I$(top_srcdir)/drivers/sockets
+else
+SOCKETS_DRIVER_NAME=
+SOCKETS_DRIVER_CFLAGS=
+endif
+
+DRIVERS=$(NATIVE_DRIVER_NAME) $(INCORE_DRIVER_NAME) $(YOD_DRIVER_NAME) \
+       $(STFD_DEV_NAME) $(SOCKETS_DRIVER_NAME)
+
+CMNSRC=startup.c drv_init_all.c drv_data.c
+
+BUILT_SOURCES=drv_data.c
+check_PROGRAMS=test_driver
+if TEST_ALPHA_ARG
+TESTS_ENVIRONMENT=IS_ALPHA=yes
+else
+TESTS_ENVIRONMENT=IS_ALPHA=no
+endif
+TESTS=test_all.pl
+
+CFL=$(AM_CFLAGS) $(AM_CPPFLAGS) \
+       $(NATIVE_DRIVER_CFLAGS) $(INCORE_DRIVER_CFLAGS) \
+       $(STDFD_DEV_CFLAGS) $(YOD_DRIVER_CFLAGS)
+
+LIBS=$(LIBBUILD_DIR)/libsysio.a
+
+test_copy_SOURCES=test_copy.c $(CMNSRC)
+test_copy_CFLAGS=$(CFL)
+test_copy_LDADD=$(LIBS)
+test_copy_DEPENDENCIES=$(LIBS)
+
+test_stats_SOURCES=test_stats.c $(CMNSRC)
+test_stats_CFLAGS=$(CFL)
+test_stats_LDADD=$(LIBS)
+test_stats_DEPENDENCIES=$(LIBS)
+
+test_path_SOURCES=test_path.c $(CMNSRC)
+test_path_CFLAGS=$(CFL)
+test_path_LDADD=$(LIBS)
+test_path_DEPENDENCIES=$(LIBS)
+
+test_list_SOURCES=test_list.c $(CMNSRC)
+test_list_CFLAGS=$(CFL)
+test_list_LDADD=$(LIBS)
+test_list_DEPENDENCIES=$(LIBS)
+
+test_getcwd_SOURCES=test_getcwd.c $(CMNSRC)
+test_getcwd_CFLAGS=$(CFL)
+test_getcwd_LDADD=$(LIBS)
+test_getcwd_DEPENDENCIES=$(LIBS)
+
+test_link_SOURCES=test_link.c $(CMNSRC)
+test_link_CFLAGS=$(CFL)
+test_link_LDADD=$(LIBS)
+test_link_DEPENDENCIES=$(LIBS)
+
+test_unlink_SOURCES=test_unlink.c $(CMNSRC)
+test_unlink_CFLAGS=$(CFL)
+test_unlink_LDADD=$(LIBS)
+test_unlink_DEPENDENCIES=$(LIBS)
+
+test_rename_SOURCES=test_rename.c $(CMNSRC)
+test_rename_CFLAGS=$(CFL)
+test_rename_LDADD=$(LIBS)
+test_rename_DEPENDENCIES=$(LIBS)
+
+test_regions_SOURCES=test_regions.c $(CMNSRC)
+test_regions_CFLAGS=$(CFL)
+test_regions_LDADD=$(LIBS)
+test_regions_DEPENDENCIES=$(LIBS)
+
+test_driver_SOURCES=test_driver.c sysio_tests.c sysio_stubs.c help.c $(CMNSRC)
+test_driver_CFLAGS=$(CFL)
+test_driver_LDADD=$(LIBS)
+test_driver_DEPENDENCIES=$(LIBS)
+
+drv_data.c: $(CONFIG_DEPENDENCIES) $(top_srcdir)/tests/gendrvdata.sh
+       test -z "drv_data.c" && rm -f drv_data.c; \
+       $(SHELL) $(top_srcdir)/tests/gendrvdata.sh $(DRIVERS) > drv_data.c
+
+AM_CFLAGS = -L$(LIBBUILD_DIR)
+include $(top_srcdir)/Rules.make
diff --git a/libsysio/tests/README b/libsysio/tests/README
new file mode 100644 (file)
index 0000000..a8cb7a8
--- /dev/null
@@ -0,0 +1,185 @@
+To run the tests, just do a "make check" in the tests subdirectory.   
+On the CPlant alpha systems, 3 of the 7 tests in test_all.pl are excluded 
+due to known problems (problems as of the date of writing this; they
+may have since been fixed).  You can also manually run the individual
+tests or ./test_all.pl.  If you are running on CPlant, you need to 
+run test_all.pl with a -alpha argument. Either "make check" or 
+test_all.pl  will run the 7 basic functionality tests (explained 
+below) and report the total number of passes and failures.
+number of passes and failures.  
+
+-----------------------SCRIPTS---------------------------------
+
+There are a total of 8 scripts: test_copy.pl, test_list.pl, 
+test_getcwd.pl, test_stats.pl, test_stdfd.pl, test_path.pl,
+populator.pl, and verifier.pl.  All but the last two scripts
+are ran with the test_all.pl script.  Here is an explanation
+of the scripts.  All scripts take an optional "-alpha" arg
+for running the scripts in an alpha/cplant environment.  The
+alpha arg makes certain assumptions about the running of the
+environment; for example, it does not initilization and it
+starts off the test driver with yod.
+
+test_copy.pl <src> <dest> : This copies a file from src to dest.
+                          : It runs a system cmp to verify that
+                          : the two files are equivalent
+
+test_list.pl [-p] <dir>               : This comes in two forms. 
+test_list.pl [-p] <fstype:mdir> <dir> : In the first form, it will
+                                      : parse through the getdirentries
+                                      : result in order to generate a
+                                      : a listing. If the -p option is
+                                      : given, it will print out the 
+                                      : listing.  In the second form, it
+                                      : mounts mdir into dir and then does
+                                      : the listing
+
+test_getcwd.pl <dir> : Tests getcwd by verifying that setting the current
+                     : working directory to dir and then calling getcwd 
+                     : returns dir    
+
+test_stats.pl <file> : Verifies that the set of stat calls (stat, fstat, 
+                     : fstatvfs, statvfs) return the same set of stats for file 
+                     : and that the calls return the same items as Perl's stat 
+                     : call (which would use a native library and not libsysio)
+
+test_stdfd.pl <file> : Verified that stdin, stdout, and stderr can be opened and 
+                     : either written to or read from
+
+test_path.pl <path1> <path2> ... : Print each path listed and its type.  
+                                 : If no paths are given, paths are read
+                                 : from stdin until a "quit" is given
+
+populator.pl [-seed seed]     : Create a file and populate with random numbers.
+             [-file filename] : Will use the given seed for the random number
+             [-bytes bytes]   : generator if it is given, otherwise it uses the
+                              : the current time as a seed.  The seed used is 
+                              : returned.  If no filename is given, the file
+                              : will be named randfile.seed.procnum, where seed
+                              : is the seed used and procnum is the process number
+                              : of the script.  If no bytes are given, 1024 bytes
+                              : are written.  All write commands use libsysio 
+             
+             
+verifier.pl <-seed seed> <-file fname> : Verifies that all bytes in the file fname
+                                       : (which was created with populator) match the
+                                       : random numbers which would have been used with
+                                       : the populator, using the given seed.
+
+
+
+-----------------------------TEST DRIVER---------------------------------
+   
+
+There are 6 basic commands for the test driver, CALL, PRINT,
+ALLOC, FREE, HELP, and exit (EXIT, quit, or QUIT will also work).
+
+CALL is the main command for running libsysio calls.  The format
+will depend on the particular libsysio command being ran.  
+Basically, the format is CALL cmd args.  The available commands
+used with CALL are (in no particular order):
+
+fstat           iwrite          read            chdir           
+fstatvfs        iwritev         readv           chmod           
+fsync           list            rmdir           chown           
+ftruncate       lseek           sizeof          close           
+getcwd          lstat           stat            cmpstr          
+getdirentries   mkdir           statvfs         creat           
+init            mknod           symlink         debug           
+ioctl           mount           truncate        dup             
+iodone          open            umask           dup2            
+iowait          umount          endian          ipread          
+printline       unlink          ipreadv         pread           
+write           fcntl           ipwrite         preadv          
+writev          fdatasync       ipwritev        pwritev         
+fill            iread           pwrite          ireadv         
+
+The specifics of the commands are explained later.
+
+The return value from a command can be saved and referenced later
+by using a syntax similar to $foo = x.  Commands can be combined, such
+as: 
+
+CALL fstat ( $fd = CALL open foo ) ( $buf = ALLOC 128 ), 
+
+with some cautionary notes.  First, everything needs to be 
+seperated by a space.  File names with spaces in them need to be quoted, 
+as in: 
+
+$fd = CALL open "file with spaces" O_RDONLY
+
+Second, any value that is used needs to be identified with an identifier.
+In other words, the command:
+
+$buf = ALLOC ( CALL sizeof stat )
+
+will not work, but the command
+
+$buf = ALLOC ( $size = CALL sizeof stat )
+
+will.
+
+
+All commands return a 4 digit status code.  The codes are:
+
+0000  : Success.  This does NOT necessarily mean that the libsysio
+      : command returned success, only that there were no errors
+      : in issuing the command to libsysio.  To get the result of
+      : the libsysio command, use PRINT $$ .  PRINT $errno will return
+      : the last error code.
+0x001 : Invalid arguments given to command
+0x002 : Invalid command issued
+0x004 : Invalid variable identifier given
+
+
+ALLOC takes a size argument and an optional alignment argument.
+FREE takes the variable to free as an argument.
+HELP without any arguments displays the list of commands.  
+HELP <cmd> will give information on the specific command
+
+PRINT take several forms.  To just print out a variable, type
+PRINT $var-name.  If the variable is an integer, it will return
+the integer.  If it is a string, it will print out the string.
+If it is a buffer, it will print out the buffer as a series of 
+hex digits.  Note for most buffers, the test driver will not
+know what it contains--just because it should contain a string
+does not mean that the driver will know that.
+
+The other form of PRINT is:
+
+PRINT $var_name <offset> <length> <type>
+
+which will print out length units of the given type starting at
+the given offset.  The length is the total length in bytes, so
+for an integer, a length of 4 would only print out one integer.
+The length argument is ignored for strings.  Allowable types are
+INT SHORT CHAR and LONG.  
+
+For most of the CALL commands, their format is similar to the 
+related sysio call.  The ones that do not have a corresponding
+sysio call are listed below:
+
+init:  This MUST be called prior to any sysio calls.  It initilizes
+    :  libsysio
+
+printline: If debugging is turned on, this will print a line number
+         : with any debug lines
+
+fill <val> <type> <size> <offset> <buf>: Fills buffer buf with size
+                                       : bytes of val starting at
+                                       : buf+offset.  The type of val
+                                       : can be UINT. STR, or PTR and
+                                       : is given by the type arg
+
+list <dir>: Lists contents of dir.  If no dir is given, uses cwd
+
+debug <num>: Sets debug level to num
+
+sizeof <obj>: Gives the size of the obj.  Valid objs are char, int,
+            : long, flock, stat, and statvfs
+
+endian: returns 0 if the machine is little endian, one otherwise
+
+cmpstr <buf1> <buf2>: Issues a strcmp call on the two buffers to 
+                    : see if they are the same.  Returns 0 for a 
+                    : match
diff --git a/libsysio/tests/cleanup.pl b/libsysio/tests/cleanup.pl
new file mode 100755 (executable)
index 0000000..029286d
--- /dev/null
@@ -0,0 +1,96 @@
+#!/usr/bin/perl -w
+
+use IPC::Open2;
+
+use strict;
+use FindBin;
+use lib "$FindBin::Bin";
+use helper;
+
+sub usage
+{
+    print "Usage: ./cleanup.pl <cwd> : Remove system directories used for test\n";
+    exit(-1);
+}
+
+sub do_remove
+{
+    my ($cmdfh, $outfh, $type, $cwd, $lastdir) = @_;
+    my $cmd;
+    if ($type eq "dir") {
+       $cmd = "rmdir";
+    } else {
+       $cmd = "unlink";
+    }
+    my $cmdstr = "CALL $cmd $cwd/$lastdir\n";
+
+    # Now remove the file/dir
+    helper::send_cmd($cmdfh, $outfh, $cmd, $cmdstr);  
+
+    # Verify the directory was made correctly
+    helper::verify_cmd($cmdfh, $outfh, $cmd);      
+ }
+
+
+my $currarg = 0;
+my $is_alpha = 0;
+my $alpha_arg = "";
+if (@ARGV == 0) {
+    usage();
+}
+if ((@ARGV > 1) && ($ARGV[$currarg++] eq "-alpha")){
+    $is_alpha = 1;
+    $alpha_arg = $ARGV[$currarg-1];
+} 
+
+my $cwd = $ARGV[$currarg];
+
+# Get tests directory
+my $testdir = $FindBin::Bin;
+  
+eval {
+    if ($is_alpha == 0) {
+       open2(\*OUTFILE, \*CMDFILE, "$testdir/test_driver --np");
+    } else {
+       open2(\*OUTFILE, \*CMDFILE, 
+             "yod -batch -quiet -sz 1 $testdir/test_driver --np");
+    }
+};
+
+if ($@) {
+    if ($@ =~ /^open2/) {
+       warn "open2 failed: $!\n$@\n";
+       return;
+    }
+    die;
+}
+
+my $outfh = \*OUTFILE;
+my $cmdfh = \*CMDFILE;
+
+if ($is_alpha == 0) {
+    helper::send_cmd($cmdfh, $outfh, "init", "CALL init\n");
+}
+
+# Remove the helper.pms
+do_remove($cmdfh, $outfh, "file", $cwd, "tmp_dir/helper.pm");
+do_remove($cmdfh, $outfh, "file", $cwd, "tmp_dir/test1/helper.pm");
+
+# Remove directories
+do_remove($cmdfh, $outfh, "dir", $cwd, "tmp_dir/test1");
+do_remove($cmdfh, $outfh, "dir", $cwd, "tmp_dir/test2");
+do_remove($cmdfh, $outfh, "dir", $cwd, "tmp_dir");
+
+print $cmdfh "exit\n";
+close $outfh;
+
+# Give test_driver time to finish
+sleep 0.000001;
+
+print STDOUT "cleanup successful\n";
+
+exit 0;
+
+
+
+
diff --git a/libsysio/tests/drv_init_all.c b/libsysio/tests/drv_init_all.c
new file mode 100644 (file)
index 0000000..6a3ad2b
--- /dev/null
@@ -0,0 +1,23 @@
+#include <stdio.h>
+
+extern int (*drvinits[])(void);
+
+/*
+ * Init all the drivers we know about.
+ */
+int
+drv_init_all()
+{
+       int (**f)(void);
+       int     err;
+
+       err = 0;
+       f = drvinits;
+       while (*f) {
+               err = (**f++)();
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
diff --git a/libsysio/tests/gendrvdata.sh b/libsysio/tests/gendrvdata.sh
new file mode 100644 (file)
index 0000000..8b84d82
--- /dev/null
@@ -0,0 +1,61 @@
+#!/bin/sh
+
+#    This Cplant(TM) source code is the property of Sandia National
+#    Laboratories.
+#
+#    This Cplant(TM) source code is copyrighted by Sandia National
+#    Laboratories.
+#
+#    The redistribution of this Cplant(TM) source code is subject to the
+#    terms of the GNU Lesser General Public License
+#    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+#
+#    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+#    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+#    license for use of this work by or on behalf of the US Government.
+#    Export of this program may require a license from the United States
+#    Government.
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+# 
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+# 
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# Questions or comments about this library should be sent to:
+#
+# Lee Ward
+# Sandia National Laboratories, New Mexico
+# P.O. Box 5800
+# Albuquerque, NM 87185-1110
+#
+# lee@sandia.gov
+
+echo '/*'
+echo ' * This file automatically generated by gendrvdata.sh. All changes'
+echo ' * will be lost!'
+echo ' */'
+echo
+echo '#include <stdlib.h>'
+echo
+echo '#include "test.h"'
+echo
+for i in $@; do
+       echo "extern int _sysio_${i}_init(void);"
+done
+echo
+echo 'int (*drvinits[])(void) = {'
+
+for i in $@; do
+       echo "  _sysio_${i}_init,"
+done
+echo " NULL"
+echo "};"
diff --git a/libsysio/tests/help.c b/libsysio/tests/help.c
new file mode 100644 (file)
index 0000000..ad5a769
--- /dev/null
@@ -0,0 +1,551 @@
+#include <stdio.h>
+#include "test_driver.h"
+
+void do_help() {
+  int i, d, count = 0;
+
+  fprintf(outfp, "libsysio test harness\n");
+  fprintf(outfp, "To get help on a specific command, use HELP <cmd>\n");
+  fprintf(outfp, "To exit, type exit or quit\n");
+  
+  fprintf(outfp, "\nTo save the result from a function, use \"$res = CALL command\"\n");
+  fprintf(outfp, "To later use that res, do \"comm $res\"\n");
+
+  fprintf(outfp, "\n\nAvailable commands are (always preceded by CALL):\n\n");
+  
+  /* Get total number of commands */
+  while (cmd_list[count].cmd)  
+    count++;
+
+  d = count/4;
+  if (count % 4)
+    d++;
+  for (i=0; i < d; i++) {
+   
+    if ( (i+d) < count ) {
+      if ( (i + 2*d) < count) {
+       if ( (i+3*d) < count) 
+         fprintf(outfp, "%-15s %-15s %-15s %-15s\n",
+                cmd_list[i].cmd, cmd_list[i+d].cmd, cmd_list[i+2*d].cmd, 
+                cmd_list[i+3*d].cmd);
+       else
+         fprintf(outfp, "%-15s %-15s %-15s\n",
+                cmd_list[i].cmd, cmd_list[i+d].cmd, cmd_list[i+2*d].cmd);
+      } else
+       fprintf(outfp, "%-15s %-15s\n",
+              cmd_list[i].cmd, cmd_list[i+d].cmd);
+    } else
+      fprintf(outfp, "%-15s\n",
+              cmd_list[i].cmd);
+  }
+  fprintf(outfp, "\n");
+}
+
+void usage_setdebug()
+{
+  fprintf(outfp, "setdebug [level]: Set debugging level to level\n");
+}
+
+void usage_setbuf()
+{
+  fprintf(outfp, "setbuf [val] [size] [buf] [off]: fill size bytes of buf with byte val\n");
+}
+
+
+void usage_clear()
+{
+  fprintf(outfp, "clear buf: zero out the buffer\n");
+}
+
+void usage_printline()
+{
+  fprintf(outfp, "printline [0|1]: Turn off (0) or on (1) the printing of line number\n");
+  fprintf(outfp, "               : and file name with debug output\n");
+}
+
+void usage_endian()
+{
+  fprintf(outfp, "endian: returns 1 for bigendian machines and 0 for little endian machines\n");
+}
+
+
+void usage_sizeof()
+{
+  fprintf(outfp, "sizeof [type]: returns the size of the data type.  Currently \n");
+  fprintf(outfp, "             : supported types are char, int, long, flock, stat and \n");
+  fprintf(outfp, "             : statvfs\n");
+}
+
+
+void usage_get_buffer()
+{
+  fprintf(outfp, "alloc [size] <align>: allocates a buffer of size bytes aligned to align\n");
+  fprintf(outfp, "                    : align is optional.  If not there, buffer will be aligned on\n");
+  fprintf(outfp, "                    : a one-byte boundary.  returns an index into an array that \n");
+  fprintf(outfp, "                    : holds the buffer\n");
+}
+
+
+
+void usage_free_buffer()
+{
+  fprintf(outfp, "free [bufidx]: frees buffer at bufidx.  Returns 0 on success, -1 on failure\n"); 
+}
+
+void usage_do_fillbuff()
+{
+  fprintf(outfp, "fill [val] [type] [size] [offset] [buf] : Fills the buffer buf with size \n");
+  fprintf(outfp, "                                        : bytes of val starting at buf+offset\n");
+  fprintf(outfp, "                                        : The type of val is specified by type,\n");
+  fprintf(outfp, "                                        : which can be UINT, STR, or PTR\n");
+}
+
+void usage_do_printbuf()
+{
+  fprintf(outfp, "printbuf [buf] : print out contents of the buffer stored in buf\n");
+  fprintf(outfp, "               : Always returns 0\n");
+}
+
+void usage_cmpbufs()
+{
+  fprintf(outfp, "cmpstr [buf1] [buf2]: Compare the contents of buf1 with buf2 by issuing a \n");
+  fprintf(outfp, "                      strcmp call.  Returns 0 if the buffers match\n");
+}
+
+
+void usage_init()
+{
+  fprintf(outfp, "init <driver> <path> <flags>: Without any arguments, initilizes libsysio\n");
+  fprintf(outfp, "                            : to default values for root directory and\n");
+  fprintf(outfp, "                            : current directory.  Accepts optional\n");
+  fprintf(outfp, "                            : arguments for the root driver, the mount\n");
+  fprintf(outfp, "                            : path, and the mount flags.  Must be called\n");
+  fprintf(outfp, "                            : before any other libsysio calls.  Returns\n");
+  fprintf(outfp,"                             : 0 on success, -1 on failure\n");
+}
+void usage_list()
+{
+  fprintf(outfp, "list <dir>: lists contents of dir.  If dir is ommitted, will list contents\n");
+  fprintf(outfp, "          : of the current working directory\n");
+  fprintf(outfp, "          : Returns 0 on success, -1 on failure\n");
+}
+void usage_chdir()
+{
+  fprintf(outfp, "chdir [dir]: change the current working directory to dir\n");
+  fprintf(outfp, "           : Returns 0 on success, -1 on failure\n");
+}
+void usage_chmod()
+{
+  fprintf(outfp, "chmod [newmode] [file]: change mode of file to newmode.  newmode can be \n");
+  fprintf(outfp, "                      : specifed symbolically (eg, a+x), numerically \n");
+  fprintf(outfp, "                      : (eg, 0777), or using system defines \n"); 
+  fprintf(outfp, "                      : (eg S_IRUSR|S_IWUSR|S_IRGRP)\n");
+  fprintf(outfp, "                      : Returns 0 on success, -1 on failure\n");
+
+}
+
+void  usage_chown()
+{
+  fprintf(outfp, "chown [newown[:newgrp]] [file]: change the owner of file to newown, the group\n");
+  fprintf(outfp, "                              : of file to newgrp, or both\n");
+  fprintf(outfp, "                              : Returns 0 on success, -1 on failure\n");
+}
+
+void usage_open()
+{
+  fprintf(outfp, "open [file] [flags] <mode>: open file with given flags.  The mode is optional\n");
+  fprintf(outfp, "                          : can use defines for open, (eg, open foo O_RDONLY)\n");
+  fprintf(outfp, "                          : If flags are 0, file will be opened with O_RDWR\n");
+  fprintf(outfp, "                          : Returns the file descriptor for the opened file\n");
+}
+
+void usage_close()
+{
+  fprintf(outfp, "close [file]: closes the file.  Returns 0 on success, -1 on failure\n");
+}
+
+void usage_mount()
+{
+  fprintf(outfp, "mount [fstype:source] [target]: mount source (which has fstype as its file\n");
+  fprintf(outfp, "                              : system type) onto target.\n"); 
+  fprintf(outfp, "                              : Returns 0 on success, -1 on failure\n");
+}
+
+void usage_dup()
+{
+  fprintf(outfp, "dup [oldfd]: Duplicate oldfd.  Returns the duplicated file descriptor\n");
+  fprintf(outfp, "           : Returns -1 on failure\n");
+}
+
+void usage_dup2()
+{
+  fprintf(outfp, "dup2 [oldfd] [newfd]: Make newfd be a copy of oldfd.  Returns newfd on \n");
+  fprintf(outfp, "                    : success and -1 on failure\n");
+}
+
+void usage_fcntl()
+{
+  fprintf(outfp, "fcntl [fd] [cmd] <args> : execute fcntl cmd on file with file descriptor fd\n");
+  fprintf(outfp, "                        : using (optional) args.  Accepted (but not \n");
+  fprintf(outfp, "                        : necesarily working) commands are F_DUPFD, \n");
+  fprintf(outfp, "                        : F_GETFD, F_GETFL, F_GETOWN, F_SETFD, F_SETFL,\n");
+  fprintf(outfp, "                        : F_SETOWN, F_SETLK, F_SETLKW, and F_GETLK. \n");
+}
+
+void usage_fstat()
+{
+  fprintf(outfp, "fstat [fd] [buf]: Get the stat structure for file descriptor fd and place it\n");
+  fprintf(outfp, "                : in buf.  Returns 0 on success, -1 on failure\n");
+}
+
+void usage_fsync()
+{
+  fprintf(outfp, "fsync [fd]: ensure all parts of file with file descriptor fd are output to\n");
+  fprintf(outfp, "          : stable storage.  Returns 0 on success, -1 on failure\n");
+}
+
+void usage_fdatasync()
+{
+  fprintf(outfp, "fdatasync [fd]: ensure all parts of file with file descriptor fd except the \n");
+  fprintf(outfp, "              : metadata are output to stable storage.  Returns 0 on \n");
+  fprintf(outfp, "              : success, -1 on failure\n");
+}
+void usage_ftruncate()
+{
+  fprintf(outfp, "ftruncate [fd] [len]: truncate file with file descriptor fd to have be \n");
+  fprintf(outfp, "                    : len bytes in length.  Returns 0 on success, -1 on \n");
+  fprintf(outfp, "                    : failure\n");
+}
+
+void usage_getcwd()
+{
+  fprintf(outfp, "getcwd [buf] [size]: get the current working directory and store it in buf\n");
+  fprintf(outfp, "                   : buf is size bytes in length.  If buf is too short, an \n");
+  fprintf(outfp, "                   : error of ERANGE is returned.  Returns 0 on success, -1\n");
+  fprintf(outfp, "                   : on failure\n");
+}
+
+void usage_lseek()
+{
+  fprintf(outfp, "lseek [fd] [offset] [whence]: Sets the offset of the file descriptor fd to\n");
+  fprintf(outfp, "                            : either offset if whence is SEEK_SET or offset\n");
+  fprintf(outfp, "                            : plus the current location if whence is SEEK_CUR\n");
+  fprintf(outfp, "                            : or offset plus the size of the file if whence\n");
+  fprintf(outfp, "                            : is SEEK_END. Returns 0 on success and -1 on \n");
+  fprintf(outfp, "                            : failure\n");
+}
+void usage_lstat()
+{
+  fprintf(outfp, "lstat [filename] [buf]: Get the stat structure for filename and return it in\n");
+  fprintf(outfp, "                      : buf.  Returns 0 on success and -1 on failure\n");
+}
+
+void usage_getdirentries()
+{
+  fprintf(outfp, "getdirentries [fd] [buf] [nbytes] [basep]: Read dir entries from directory\n");
+  fprintf(outfp, "                                         : with file descriptor fd into buf\n");
+  fprintf(outfp, "                                         : At most nbytes are read.  Reading\n");
+  fprintf(outfp, "                                         : starts at basep, and basep is set\n");
+  fprintf(outfp, "                                         : to new pos. Returns the number of \n");
+  fprintf(outfp, "                                         : bytes read on success or 0 on\n");
+  fprintf(outfp, "                                         : failure\n");
+  fprintf(outfp, "Note that basep does not have to be pre-allocated.  Executing cmd: \n");
+  fprintf(outfp, "\"getdirentries $fd $buf 4096 $basep\", where $fd is the result of an open\n");
+  fprintf(outfp, "and $buf is the result of an alloc (but $basep is totally new) will work\n");
+  fprintf(outfp, "After the execution of the command, $basep holds the new offset and can be\n");
+  fprintf(outfp, "used again for any further getdirentries calls\n");
+}
+void usage_mkdir()
+{
+  fprintf(outfp, "mkdir [newdir] [mode]: make a new directory, newdir, with the permissions \n");
+  fprintf(outfp, "                     : specified in mode.  Permissions can be symbolic \n");
+  fprintf(outfp, "                     : (eg, a+x), numeric (eg, 0777), or can use defines\n");
+  fprintf(outfp, "                     : (eg S_IRUSR|S_IWUSR|S_IRGRP).  Returns 0 on success \n");
+  fprintf(outfp, "                     : -1 on failure.\n");
+}
+
+
+void usage_creat()
+{
+  fprintf(outfp, "creat [newfile] [mode]: create a new file, newfile, with the permissions \n");
+  fprintf(outfp, "                      : specified in mode.  Permissions can be symbolic \n");
+  fprintf(outfp, "                      : (eg, a+x), numeric (eg, 0777), or can use defines\n");
+  fprintf(outfp, "                      : (eg S_IRUSR|S_IWUSR|S_IRGRP).  Returns 0 on success \n");
+  fprintf(outfp, "                      : -1 on failure.\n");
+}
+
+void usage_stat()
+{
+  fprintf(outfp, "stat [filename] [buf]: Get the stat structure for filename and return it in\n");
+  fprintf(outfp, "                     : buf.  Returns 0 on success and -1 on failure\n");
+}
+
+void usage_statvfs()
+{
+  fprintf(outfp, "statvfs [filename] [buf]: Get the statvfs structure for filename and return\n");
+  fprintf(outfp, "                        : it in buf.  Returns 0 on success and -1 on failure\n");
+}
+
+void usage_fstatvfs()
+{
+  fprintf(outfp, "fstatvfs [fd] [buf]: Get the stat structure for file with file descriptor fd\n");
+  fprintf(outfp, "                   : and return it in buf.  Returns 0 on success and -1 on\n"); 
+  fprintf(outfp, "                   : failure\n");
+}
+
+void usage_truncate()
+{
+  fprintf(outfp, "truncate [fname] [len]: truncate file with name fname to be exactly \n");
+  fprintf(outfp, "                      : len bytes in length.  Returns 0 on success, -1 on \n");
+  fprintf(outfp, "                      : failure\n");
+}
+
+void usage_rmdir()
+{
+  fprintf(outfp, "rmdir [dirname]: Remove directory at dirname.  Returns 0 on success, -1 on\n");
+  fprintf(outfp, "               : failure.\n");
+}
+
+void usage_symlink()
+{
+  fprintf(outfp, "symlink [path1] [path2]: Make a symbolic link from path1 to path2.  Returns\n");
+  fprintf(outfp, "                       : 0 on success, -1 on failure\n");
+}
+
+void usage_unlink()
+{
+  fprintf(outfp, "unlink [path]: Unlink path.  If path is the last name to a file, the file is \n");
+  fprintf(outfp, "             : is removed.  If it was a symbolic link, the link is removed. \n");
+  fprintf(outfp, "             : Returns 0 on success, -1 on failure\n");
+}
+
+void usage_ioctl()
+{
+  fprintf(outfp, "ioctl [fd] [cmd] <args> : Issue the ioctl command cmd on the file with file\n");
+  fprintf(outfp, "                        : descriptor fd.  Any arguments are placed in args\n");
+  fprintf(outfp, "                        : At the moment, the only commands understand are the \n");
+  fprintf(outfp, "                        : ioctl commands found in /usr/include/linux/fs.h\n");
+}
+
+void usage_umask()
+{
+  fprintf(outfp, "ioctl [mask] : Sets the umask used by open to set initial file permissions on\n");
+  fprintf(outfp, "             : a newly created file.  Returnds the previous value of the mask\n");
+}
+
+void usage_iodone()
+{
+  fprintf(outfp, "iodone [ioid] : Poll for completion of the asynchronous request identifed by\n");
+  fprintf(outfp, "              : ioid.  Returns 1 if request finished\n");
+}
+
+void usage_iowait()
+{
+  fprintf(outfp, "iowait [ioid] : Wait for completion of the asynchronous request identifed by\n");
+  fprintf(outfp, "              : ioid.  Returns result of asynchronous request \n");
+}
+
+void usage_ipreadv()
+{
+  fprintf(outfp, "ipreadv [fd] [buf] [count] [off]: Reads data asynchrously to file descriptor fd \n");
+  fprintf(outfp, "                                : starting at offset off.  Data comes from \n");
+  fprintf(outfp, "                                : buffer described by buf, which is a pointer to\n");
+  fprintf(outfp, "                                : an iovec strucutre.  Number of buffers is \n");
+  fprintf(outfp, "                                : specified by count.  Returns an iod_t on  \n");
+  fprintf(outfp, "                                : success and -1 on failure\n");
+}
+
+void usage_ipread()
+{
+  fprintf(outfp, "ipread [fd] [buf] [count] [off]: Read asynchrously up to count bytes from file\n");
+  fprintf(outfp, "                               : with file descriptor fd starting at offset off\n");
+  fprintf(outfp, "                               : Read into buffer pointed at by buf.  Returns\n");
+  fprintf(outfp, "                               : an iod_t on success and -1 on failure\n");
+}
+
+void usage_preadv()
+{
+  fprintf(outfp, "preadv [fd] [buf] [count] [off]: Reads data from file descriptor fd starting at\n");
+  fprintf(outfp, "                               : offset off.  Data goes into buffer described\n");
+  fprintf(outfp, "                               : by buf, which is a pointer to an iovec \n");
+  fprintf(outfp, "                               : structure.  Number of buffers is specified by\n");
+  fprintf(outfp, "                               : count. Returns the number of bytes read\n");
+}
+
+void usage_pread()
+{
+  fprintf(outfp, "preadv [fd] [buf] [count] [off]: Reads count bytes of data from file descriptor\n");
+  fprintf(outfp, "                               : fd starting at offset off.  Data goes into buf.\n");
+  fprintf(outfp, "                               : Returns number of bytes read or -1 on failure\n");
+}
+
+void usage_ireadv()
+{
+  fprintf(outfp, "ireadv [fd] [buf] [count] : Reads data asynchrously to file descriptor fd \n");
+  fprintf(outfp, "                          : Data comes from buffer described by buf, which is \n");
+  fprintf(outfp, "                          : an pointer to an iovec structure.  Number of\n");
+  fprintf(outfp, "                          : buffers is specified by count.  Returns an iod_t\n");
+  fprintf(outfp, "                          : on success and -1 on failure\n");
+}
+
+void usage_iread()
+{
+  fprintf(outfp, "iread [fd] [buf] [count]: Read asynchrously up to count bytes from file with\n");
+  fprintf(outfp, "                        : file descriptor fd into buffer pointed at by buf\n");
+  fprintf(outfp, "                        : Returns an iod_t on success and -1 on failure\n");
+}
+
+void usage_readv()
+{
+  fprintf(outfp, "readv [fd] [buf] [count] : Reads data from file descriptor fd.  Data comes from\n");
+  fprintf(outfp, "                         : the buffer described by buf, which is a pointer to an\n");
+  fprintf(outfp, "                         : an iovec structure.  Number of buffers is specified\n");
+  fprintf(outfp, "                         : by count.  Returns the number of bytes read on \n");
+  fprintf(outfp, "                         : on success and -1 on failure\n");
+}
+
+void usage_read()
+{
+  fprintf(outfp, "read [fd] [buf] [count]: Read up to count bytes from file with file \n");
+  fprintf(outfp, "                       : descriptor fd into buffer pointed at by buf\n");
+  fprintf(outfp, "                       : Returns number of bytes read on success or 0 on \n");
+  fprintf(outfp, "                       : on failure\n");
+}
+
+void usage_ipwritev()
+{
+  fprintf(outfp, "ipwritev [fd] [buf] [count] [off]: writes data asynchronously to file with file\n");
+  fprintf(outfp, "                                 : descriptor fd starting at offset off.  Data \n");
+  fprintf(outfp, "                                 : comes from buffers described by buf, which\n");
+  fprintf(outfp, "                                 : is a pointer to an iovec structure.  Number \n");
+  fprintf(outfp, "                                 : of buffers is specified by count.  Returns\n");
+  fprintf(outfp, "                                 : an iod_t on success and -1 on failure\n");
+}
+
+void usage_ipwrite()
+{
+  fprintf(outfp, "ipwrite [fd] [buf] [count] [off]: writes count bytes of data asynchronously to\n");
+  fprintf(outfp, "                                : file with file descriptor fd starting at \n");
+  fprintf(outfp, "                                : offset off.  Data comes from buf. Returns an\n"); 
+  fprintf(outfp, "                                : iod_t on success and -1 on failure\n");
+}
+
+void usage_pwritev()
+{
+  fprintf(outfp, "pwritev [fd] [buf] [count] [off]: writes data to file with file descriptor fd\n");
+  fprintf(outfp, "                                : starting at offset off.  Data comes from \n");
+  fprintf(outfp, "                                : buffers described by buf, which is a pointer\n");
+  fprintf(outfp, "                                : to an iovec structure.  Number of buffers is\n");
+  fprintf(outfp, "                                : by count.  Returns number of bytes read on \n");
+  fprintf(outfp, "                                : success and -1 on failure\n");
+}
+
+void usage_pwrite()
+{
+  fprintf(outfp, "pwrite [fd] [buf] [count] [off]: writes count bytes of data to file with file \n");
+  fprintf(outfp, "                               : descriptor fd starting at offset off.  Data\n");
+  fprintf(outfp, "                               : Data comes from buf. Returns number of bytes\n"); 
+  fprintf(outfp, "                               : written on success and -1 on failure\n");
+}
+
+void usage_iwritev()
+{
+  fprintf(outfp, "iwritev [fd] [buf] [count] : writes data asynchronously to file with file\n");
+  fprintf(outfp, "                           : descriptor fd.  Data comes from buffers described\n");
+  fprintf(outfp, "                           : by buf, which is a pointer to an iovec structure.\n");
+  fprintf(outfp, "                           : Number of buffers is specified by count.  Returns\n");
+  fprintf(outfp, "                           : an iod_t on success and -1 on failure\n");
+}
+
+void usage_iwrite()
+{
+  fprintf(outfp, "iwrite [fd] [buf] [count] : writes count bytes of data asynchronously to\n");
+  fprintf(outfp, "                          : file with file descriptor fd.  Data comes from buf.\n");
+  fprintf(outfp, "                          : Returns an iod_t on success and -1 on failure.\n");
+}
+
+void usage_writev()
+{
+  fprintf(outfp, "writev [fd] [buf] [count]: writes data to file descriptor fd.  Data comes from\n");
+  fprintf(outfp, "                         : buffers described by buf, which is a pointer to a \n");
+  fprintf(outfp, "                         : iovec strucutre.  Number of buffers is specified by \n");
+  fprintf(outfp, "                         : count \n");
+}
+
+void usage_write()
+{
+  fprintf(outfp, "write [fd] [buf] [count] : writes count bytes of data to file with file \n");
+  fprintf(outfp, "                         : descriptor fd.  Data comes from buf.  Returns number\n");
+  fprintf(outfp, "                         : of bytes written on success and -1 on failure.\n");
+}
+
+void usage_mknod()
+{
+  fprintf(outfp, "mknod [path] [mode] [dev] : creates a filesystem node named path with \n");
+  fprintf(outfp, "                          : specified mode using device special file dev\n");
+  fprintf(outfp, "                          : Returns 0 on sucess and -1 on failure\n");
+}
+
+
+void usage_umount()
+{
+  fprintf(outfp, "umount [path] : Umount file at path.  Returns 0 on success and -1 on failure\n");
+}
+
+void usage_init_iovec()
+{
+       fprintf(outfp, "init_iovec buf offset len num iov_buf: Init iovector. iov_uf points to an array of\n");
+       fprintf(outfp, "                                       iovecs, num is the number of the iovec, \n");
+       fprintf(outfp, "                                       buf is the buffer to be used, offset \n");
+       fprintf(outfp, "                                       specifies how far into the buffer the iovec\n");
+       fprintf(outfp, "                                       should point and len is the iov length\n");
+}
+
+void usage_init_xtvec()
+{
+       fprintf(outfp, "init_xtvec offset len num buf: Init xtvector.  Buf points to an array of\n");
+       fprintf(outfp, "                               xtvecs, num is the number of the xtvec, offset\n");
+       fprintf(outfp, "                               is xtv_off and len is the iov lenghth\n");
+       fprintf(outfp, "                               the iov length\n");
+}
+
+void usage_writex()
+{
+       fprintf(outfp, "writex fd iovs iov_cnt xtvs xtvcnt: Write iov_cnt iovecs out to file using\n");
+       fprintf(outfp, "                                    xtvcnt xtvecs\n");
+}
+
+void usage_iwritex()
+{
+       fprintf(outfp, "iwritex fd iovs iov_cnt xtvs xtvcnt: Write iov_cnt iovecs out to file using\n");
+       fprintf(outfp, "                                     xtvcnt xtvecs\n");
+}
+
+void usage_readx()
+{
+       fprintf(outfp, "readx fd iovs iov_cnt xtvs xtvcnt: Read iov_cnt iovecs out from file using\n");
+       fprintf(outfp, "                                    xtvcnt xtvecs\n");
+}
+
+void usage_ireadx()
+{
+       fprintf(outfp, "ireadx fd iovs iov_cnt xtvs xtvcnt: Read iov_cnt iovecs out from file using\n");
+       fprintf(outfp, "                                     xtvcnt xtvecs\n");
+}
+                                       
+
+void usage_checkbuf()
+{
+       fprintf(outfp, "checkbuf [buf] [size] [val] [off]: Staring at offset off, checks to see\n");
+       fprintf(outfp, "                                   if val is in first size bytes of buf\n");
+}
+
+void usage_exit()
+{
+}
diff --git a/libsysio/tests/helper.pm b/libsysio/tests/helper.pm
new file mode 100644 (file)
index 0000000..306c40e
--- /dev/null
@@ -0,0 +1,130 @@
+#!/usr/bin/perl -w
+
+#
+# Provides a set of helper routines for use in the Perl 
+# test scripts
+#
+
+package helper;
+use strict;
+use POSIX;
+
+BEGIN{}
+
+# Print out a given error message, close the command file
+# and exit
+sub print_and_exit
+{
+  my ($cmdfh, $outfh, $exit_num, $exit_str) = @_;
+
+  print STDOUT "$exit_str";
+
+  # Clean up
+  my $cmdstr =  'FREE $buf';
+  $cmdstr = $cmdstr."\n";
+
+  print $cmdfh $cmdstr;
+
+  my $res = <$outfh>;
+  chop($res);
+
+  print $cmdfh "exit\n";
+  close $outfh;
+
+  # Give test_driver time to finish
+  sleep 0.000001;
+
+  exit $exit_num;
+}
+
+
+# Output the given command and make sure that the exit
+# code for the command was valid
+sub send_cmd
+{
+  my ($cmdfh, $outfh, $cmd, $cmdstr) = @_;
+
+  print $cmdfh $cmdstr;
+
+  my $res = <$outfh>;
+  chop($res);
+  if ($res ne "0000 ") {
+    print_and_exit($cmdfh, $outfh, 1, "ERROR! Command $cmd failed with code $res\n");
+  }
+}
+
+# Check the return value from the last libsysio call
+sub verify_cmd
+{
+
+  my ($cmdfh, $outfh, $cmd) = @_;
+
+  # Verify the system call's output
+  my $cmdstr = 'PRINT $$';
+  $cmdstr .= "\n";
+  send_cmd($cmdfh, $outfh, "PRINT", $cmdstr);  
+
+  my $res = <$outfh>;
+  chop($res);
+
+  if ($res eq "0xffffffff") {
+     
+    # Get the errno
+    $cmdstr = 'PRINT $errno';
+    $cmdstr .= "\n";
+    send_cmd($cmdfh, $outfh, "PRINT", $cmdstr);
+    
+    my $err = <$outfh>;
+    chop($err);
+    print_and_exit($cmdfh, $outfh, 1, "ERROR!  $cmd returned $err\n");
+  }
+  return $res;
+}
+
+# Compares two numbers.  Output error message and exit if
+# they differ
+sub cmp_nums
+{
+  my ($cmdfh, $outfh, $ionum, $pnum, $desc) = @_;
+
+  my $str;
+  if (!defined($ionum)) {
+      print_and_exit($cmdfh, $outfh, 1, "ERROR! ionum for $desc undefined");
+  } elsif (!defined($pnum)) {
+      print_and_exit($cmdfh, $outfh, 1, "ERROR! pnum for $desc undefined");
+  }
+  if ($ionum != $pnum) {
+    my $str = sprintf("ERROR!  Sysio's number %x does not match Perl's (%x)\n", 
+                     $ionum, $pnum);
+    $str = sprintf("%s Numbers were %s\n", $str, $desc);
+    print_and_exit($cmdfh, $outfh, 1, $str);
+  }
+}
+
+sub get_type
+{
+  my $mode = $_[0];
+  my $t = '?';
+
+  if (S_ISDIR($mode)) {
+    $t = 'd';
+  } elsif (S_ISCHR($mode)) {
+    $t = 'c';
+  } elsif (S_ISBLK($mode)) {
+    $t = 'b';
+  } elsif (S_ISREG($mode)) {
+    $t = 'f';
+  } elsif (S_ISFIFO($mode)) {
+    $t = 'p';
+  } elsif (S_ISLNK($mode)) {
+    $t = 'S';
+  } elsif (S_ISSOCK($mode)) {
+    $t = 's';
+  }
+
+  return $t;
+}
+
+END{}
+
+1;
diff --git a/libsysio/tests/module.mk b/libsysio/tests/module.mk
new file mode 100644 (file)
index 0000000..b6ed491
--- /dev/null
@@ -0,0 +1,2 @@
+TESTS_EXTRA = $(shell ls tests/*.[ch] tests/*.sh tests/*.p[lm]) \
+       tests/Makefile.am tests/Makefile.in tests/module.mk
diff --git a/libsysio/tests/populator.pl b/libsysio/tests/populator.pl
new file mode 100755 (executable)
index 0000000..b218519
--- /dev/null
@@ -0,0 +1,155 @@
+#!/usr/bin/perl -w
+
+use IPC::Open2;
+
+use strict;
+use helper;
+
+sub usage
+{
+  print "Usage: ./populator.pl <-seed seed>     :\n";
+  print "                      <-file filename> :\n";
+  print "                      <-bytes bytes>   : Create a file, filename, that\n";
+  print "                                       : is bytes long and populate with\n";
+  print "                                       : random numbers using the given\n";
+  print "                                       : seed.  Will use defaults if args\n";
+  print "                                       : not given\n";
+  exit(-1);
+}
+
+sub get_buf
+{
+  my $MAX_SIZE = 2147483648;
+
+  my $str;
+  my $num;
+  my $len = 0;
+
+  while ($len < 512) {
+    $num = rand $MAX_SIZE;
+    my $tmpstr = sprintf("%d", $num);
+    $str .= $tmpstr;
+    $len += length $tmpstr;
+  }
+
+  return ($len, $str);
+}
+
+sub write_file
+{
+  my ($cmdfh, $outfh, $filename, $bytes) = @_;
+
+
+  # Allocate the read buffer
+  my $cmd = '$buf = ALLOC 1024'."\n";
+  helper::send_cmd($cmdfh, $outfh, "alloc", $cmd);  
+  
+  # Open (create) the new file
+  $cmd = '$fd = CALL open '."$filename O_RDWR|O_CREAT S_IRWXU\n";
+  helper::send_cmd($cmdfh, $outfh, "open", $cmd);  
+
+  # Verify the system call's output
+  helper::verify_cmd($cmdfh, $outfh, "open");  
+
+  my $left_bytes = $bytes;
+  while ($left_bytes > 0) {
+    # Get a buffer filled with random numbers
+    # Buffer will be no less than 512 bytes
+    my ($len, $buf) = get_buf;
+    if ($len > $left_bytes) {
+      $len = $left_bytes;
+    }
+
+    # Need to fill $buf with the buffer 
+    $cmd = "CALL fill $buf STR $len 0 ".'$buf'."\n";
+    helper::send_cmd($cmdfh, $outfh, "fill", $cmd);
+
+    # Write out $len bytes to $filename
+    $cmd = 'CALL write $fd $buf '."$len\n";
+   
+    helper::send_cmd($cmdfh, $outfh, "write", $cmd);
+
+    my $written_bytes = helper::verify_cmd($cmdfh, $outfh, "write");
+    $written_bytes = oct($written_bytes);
+    if ($written_bytes != $len) {
+       helper::print_and_exit($cmdfh, $outfh, 1, 
+                          "ERROR! Meant to print out $len but only printed $written_bytes\n");
+     }
+
+    $left_bytes -= $len;
+  }
+}
+
+sub populate_file
+{
+  my ($filename, $bytes, $is_alpha) = @_;
+  
+  eval {
+      if ($is_alpha == 0) {
+         open2(\*OUTFILE, \*CMDFILE, "./test_driver --np");
+      } else {
+         open2(\*OUTFILE, \*CMDFILE, 
+               "yod -batch -quiet -sz 1 ./test_driver --np");
+      }
+  };
+
+  if ($@) {
+    if ($@ =~ /^open2/) {
+      warn "open2 failed: $!\n$@\n";
+      return;
+    }
+    die;
+
+  }
+
+  my $outfh = \*OUTFILE;
+  my $cmdfh = \*CMDFILE;
+
+  if ($is_alpha == 0) {
+    helper::send_cmd($cmdfh, $outfh, "init", "CALL init\n");
+  }
+
+  # Now write the file
+  write_file($cmdfh, $outfh, $filename, $bytes);
+
+  # Close the file
+  my $cmd = 'CALL close $fd'."\n";
+  helper::send_cmd($cmdfh, $outfh, "close", $cmd);
+
+  helper::verify_cmd($cmdfh, $outfh, "close");
+
+  # All done
+  helper::print_and_exit($cmdfh, $outfh, 0, "File $filename successfully created\n");
+}
+
+
+my $is_alpha = 0;
+my $seed = time;
+my $filename = "randfile.$seed.$$";
+my $bytes = 1024;
+for (my $i = 0; $i < @ARGV; $i++) 
+{
+  if ($ARGV[$i] eq "-file") {
+    $i++;
+    $filename = $ARGV[$i];
+  } elsif ($ARGV[$i] eq "-seed") {
+    $i++;
+    $seed = $ARGV[$i];
+  } elsif ($ARGV[$i] eq "-alpha") {
+    $is_alpha = 1;
+  } elsif ($ARGV[$i] eq "-bytes") {
+    $i++;
+    $bytes = $ARGV[$i];
+  }
+}
+
+# seed the randome number generator
+srand $seed;
+
+populate_file($filename, $bytes, $is_alpha);
+
+exit $seed;
+
+
+
+
diff --git a/libsysio/tests/setup.pl b/libsysio/tests/setup.pl
new file mode 100755 (executable)
index 0000000..4270f59
--- /dev/null
@@ -0,0 +1,104 @@
+#!/usr/bin/perl -w
+
+use IPC::Open2;
+
+use strict;
+use FindBin;
+use lib "$FindBin::Bin";
+use helper;
+
+sub usage
+{
+    print "Usage: ./setup.pl <cwd> : Setup initial system directories for test\n";
+    exit(-1);
+}
+
+sub do_makedir
+{
+    my ($cmdfh, $outfh, $cwd, $lastdir) = @_;
+    my $cmd = "CALL mkdir $cwd/$lastdir 0777\n";
+
+    # Now create newdir
+    helper::send_cmd($cmdfh, $outfh, "mkdir", $cmd);  
+
+    # Verify the directory was made correctly
+    helper::verify_cmd($cmdfh, $outfh, "mkdir");      
+ }
+
+
+my $currarg = 0;
+my $is_alpha = 0;
+my $alpha_arg = "";
+if (@ARGV == 0) {
+    usage();
+}
+if ((@ARGV > 1) && ($ARGV[$currarg++] eq "-alpha")){
+    $is_alpha = 1;
+    $alpha_arg = $ARGV[$currarg-1];
+} 
+
+my $cwd = $ARGV[$currarg];
+
+# Get tests directory
+my $testdir = $FindBin::Bin;
+  
+eval {
+    if ($is_alpha == 0) {
+       open2(\*OUTFILE, \*CMDFILE, "$testdir/test_driver --np");
+    } else {
+       open2(\*OUTFILE, \*CMDFILE, 
+             "yod -batch -quiet -sz 1 $testdir/test_driver --np");
+    }
+};
+
+if ($@) {
+    if ($@ =~ /^open2/) {
+       warn "open2 failed: $!\n$@\n";
+       return;
+    }
+    die;
+}
+
+my $outfh = \*OUTFILE;
+my $cmdfh = \*CMDFILE;
+
+if ($is_alpha == 0) {
+    helper::send_cmd($cmdfh, $outfh, "init", "CALL init\n");
+}
+
+
+# Create tmp_dir
+do_makedir($cmdfh, $outfh, $cwd, "tmp_dir");
+do_makedir($cmdfh, $outfh, $cwd, "tmp_dir/test1");
+do_makedir($cmdfh, $outfh, $cwd, "tmp_dir/test2");
+
+# Copy helper.pm
+print STDERR "Copying $testdir/helper.pm to $cwd/tmp_dir/test1/helper.pm\n";
+my $res = `perl $testdir/test_copy.pl $alpha_arg $testdir/helper.pm $cwd/tmp_dir/test1/helper.pm`;
+chop($res);
+
+if ($res ne "copy test successful") {
+  print STDERR "setup (copy test) failed with message: $res\n";
+  print $cmdfh "exit\n";
+  close $outfh;
+
+  # Give test_driver time to finish
+  sleep 0.000001;
+
+  print STDOUT "Copying of helper.pm failed\n";
+  exit 1;
+} 
+
+ print $cmdfh "exit\n";
+close $outfh;
+
+# Give test_driver time to finish
+sleep 0.000001;
+
+print STDOUT "setup successful\n";
+
+exit 0;
+
+
+
+
diff --git a/libsysio/tests/startup.c b/libsysio/tests/startup.c
new file mode 100644 (file)
index 0000000..54c56d1
--- /dev/null
@@ -0,0 +1,27 @@
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+
+#include "test.h"
+
+int
+_test_sysio_startup()
+{
+       int     err;
+       const char *s;
+
+       err = _sysio_init();
+       if (err)
+               return err;
+       err = drv_init_all();
+       if (err)
+               return err;
+       s = getenv("SYSIO_NAMESPACE");
+       err = s ? _sysio_boot(s) : -ENOTTY;
+       if (err)
+               return err;
+       return 0;
+}
diff --git a/libsysio/tests/sysio_stubs.c b/libsysio/tests/sysio_stubs.c
new file mode 100644 (file)
index 0000000..2fc5046
--- /dev/null
@@ -0,0 +1,2705 @@
+#define _BSD_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/uio.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+
+#include "test_driver.h"
+#include "sysio.h"
+#include "xtio.h"
+
+/*
+ * ################################################
+ * # Function stubs                               #
+ * #  These allow all of the different commands   #
+ * #  to be called with the same format           #
+ * ################################################
+ */
+
+int test_do_setdebug(int argc, char **argv) 
+{
+  int level;
+
+  if (argc != 1) {
+    DBG(2, fprintf(outfp, "Invalid number of args (%d) for setdebug\n",
+                  argc));
+    return INVALID_ARGS;
+  }
+
+  level = atoi(argv[0]);
+
+  if (level < 0) {
+    DBG(2, fprintf(outfp, "Invalid debug level %d\n", level));
+    return INVALID_ARGS;
+  }
+  
+  debug_level = level;
+  return SUCCESS;
+}
+
+int test_do_printline(int argc, char **argv) 
+{
+  int on;
+
+  
+  if (argc != 1) {
+    DBG(2, fprintf(outfp, "Invalid number of args (%d) for printline\n",
+                  argc));
+    return INVALID_ARGS;
+  }
+
+  on = atoi(argv[0]);
+  if (on)
+    print_line = 1;
+  else
+    print_line = 0;
+
+  return SUCCESS;
+}
+
+/*
+int test_do_setoutput(int argc, char **argv)
+{
+  FILE *newfp;
+
+  if (argc != 1) {
+    fprintf(outfp, "Invalid number of args (%d) for setoutput\n",
+           argc);
+    return -1;
+  }
+
+  newfp = fopen(argv[0], "w");
+  if (!newfp) {
+    fprintf(outfp, "Unable to open new output file %s\n", argv[0]);
+    return -1;
+  }
+
+  outfp = newfp;
+
+  return 0;
+}
+
+*/
+
+
+int test_do_fillbuff(int argc, char **argv) 
+{
+  char *typestr, *buf;
+  void *valptr;
+  int size, type, index, offset;
+
+  if (argc != 5) {
+    DBG(2, 
+       fprintf(outfp, 
+               "fillbuff requires a value, a type, a size, an offset, and the target buffer\n"));
+    fprintf(stderr, "fillbuff requires 5 args, you gave %d\n", argc);
+    return INVALID_ARGS;
+  }
+
+  offset = get_obj(argv[3]);
+  if (offset < 0) {
+    DBG(2, fprintf(outfp, "Do not understand offset %s\n", argv[3]));
+    return INVALID_VAR;
+  }
+
+  index = get_obj(argv[4]);
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Can't find buffer at %s\n", argv[4]));
+    return INVALID_VAR;
+  }
+  buf = (char *)(buflist[index]->buf)+offset;
+
+  DBG(4, fprintf(outfp, "Buffer start is at %p\n", (void *)buflist[index]));
+
+  typestr = argv[1];
+  size = get_obj(argv[2]);
+  if (size < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand size %s\n", argv[2]));
+    return INVALID_VAR;
+  }
+  
+  if ( (!strcmp(typestr, "UINT")) || (!strcmp(typestr, "SINT")) ){
+    int val = get_obj(argv[0]);
+    valptr = &val;
+    type = UINT;
+    if (val < 0) { /* FIX THIS */
+      DBG(2, fprintf(outfp, "Can't understand value %s\n", argv[0]));
+      return INVALID_VAR;
+    }
+    DBG(4, fprintf(outfp, "Copying %d bytes from %p. Val is %x\n",
+                  size, buf, *((int *)valptr)));
+    memcpy(buf, valptr, size);
+         
+  } else if (!strcmp(typestr,"STR")) {
+    type = STR;
+    valptr = argv[0];
+    DBG(4, fprintf(outfp, "Copying %d bytes from %p. Val is %s\n",
+                  size, buf, (char *)valptr));
+    memcpy(buf, valptr, size);
+  } else if (!strcmp(typestr, "PTR")) {
+    unsigned long val;
+    int index = get_obj(argv[0]);
+    if (index < 0) {
+      DBG(2, fprintf(outfp, "Unable to find buffer at %s\n", argv[0]));
+      return INVALID_VAR;
+    }
+    
+    val = (unsigned long)buflist[index]->buf;
+    valptr = &val;
+    DBG(4, fprintf(outfp, "Copying %d bytes from %p. Val is %p\n",
+                  size, buf, valptr));
+    memcpy(buf, valptr, size);
+  } else {
+    DBG(2, fprintf(outfp, "Unknown type %s.  Valid types are UINT, STR, and PTR\n", 
+                  typestr));
+    fprintf(stderr, "Unknown type %s.  Valid types are UINT, STR, and PTR\n", 
+                  typestr);
+    return INVALID_ARGS;
+  }
+  return SUCCESS;
+}
+    
+
+#define STR_TYPE       1
+#define INT_TYPE       2
+#define SHORT_TYPE     3
+#define CHAR_TYPE      4
+#define LONG_TYPE      5
+
+void print_partial(char *buf, int offset, int len, int type)
+{
+  int i;
+
+  if (type == STR_TYPE) {
+    sprintf(output, "%s%s", output, (char *)(buf+offset));
+    DBG(4, fprintf(outfp, "Printing str %s\n", (char *)(buf+offset)));
+  } else {
+    if (type == SHORT_TYPE) {
+      for (i = 0; i < len; i+= 2) {
+       short *ibuf = (short *)(buf + offset + i);
+       sprintf(output, "%s%#04x ", output, *ibuf);
+       DBG(4, fprintf(outfp, "Printing short %#04x\n", *ibuf));
+      }
+    } else if (type == CHAR_TYPE) {
+      for (i = 0; i < len; i++) {
+       short *ibuf = (short *)(buf+offset+i);
+       sprintf(output, "%s%#02x ", output, (*ibuf & 0x00ff));
+       DBG(4, fprintf(outfp, "Printing char %c\n", (*ibuf & 0x00ff)));
+      }
+    } else if (type == INT_TYPE) {
+      for (i = 0; i < len; i+= 4) {
+       int *ibuf = (int *)(buf + offset + i);
+       sprintf(output, "%s%#08x ", output, *ibuf);
+       DBG(4, fprintf(outfp, "Printing int %#08x\n", *ibuf));
+      }
+    } else {
+      for (i = 0; i < len; i += 8) {
+       unsigned long *lbuf = (unsigned long *)(buf + offset +i);
+       sprintf(output, "%s%#08lx ", output, *lbuf);
+       DBG(4, fprintf(outfp, "Printing int %#016lx\n", *lbuf));
+      }
+    } 
+  }
+}
+      
+int test_do_printbuf(int argc, char **argv)
+{
+  int index, i, type, offset, len;
+  struct buf_t *buf_st;
+  void *buf;
+  char *typestr;
+  struct var_mapping *mobj;
+
+  if (argv[0][0] == '$') {
+    if (argv[0][1] == '$') {
+      sprintf(output, "\n%#010x", (unsigned int)last_ret_val);
+      return SUCCESS;
+    } else if (!strcmp("errno", &argv[0][1])) {
+      sprintf(output, "\n%#010x", my_errno);
+      return SUCCESS;
+    }
+  }
+
+  mobj = get_map(argv[0]);
+  if (mobj == NULL) {
+    DBG(2, fprintf(outfp, "Can't get var at %s\n", argv[0]));
+    return INVALID_VAR;
+  }
+
+  if (mobj->type == UINT)
+    sprintf(output, "\n%#010x", mobj->obj);
+  else if (mobj->type == SINT)
+    sprintf(output, "%d", mobj->obj);
+  else if ((mobj->type == STR) || (mobj->type == PTR)) {
+    index = mobj->obj;
+
+    buf_st = buflist[index];
+    DBG(2, fprintf(outfp, "buf_st is %p:\n", (void *)buf_st));
+    buf = buf_st->buf;
+    DBG(2, fprintf(outfp, "buf %s:\n", argv[0]));
+    if (mobj->type == STR) {
+      sprintf(output, "\n%s", (char *)buf);
+     } else {
+       sprintf(output,"%s\n", output);
+       DBG(2, fprintf(outfp, "buf_st->len is %d, buf is %p\n", buf_st->len, buf));
+       if (argc == 1) {
+        for (i = 0; i < buf_st->len/4; i++) 
+          DBG(2, fprintf(outfp, "%#x ", ((int *)buf)[i]));
+          sprintf(output, "%s%#x ", output, ((int *)buf)[i]);
+        
+       }
+
+       for (i = 1; i < argc; i++) {
+        offset = get_obj(argv[i++]);
+        len = get_obj(argv[i++]);
+        if ((offset < 0) || (len < 0)) {
+          DBG(2, fprintf(outfp, "Invalid offset (%s) or len (%s)\n",
+                         argv[i-2], argv[i-1]));
+          return INVALID_VAR;
+        }
+        typestr = argv[i];
+        if (!strcmp("STR", typestr))
+          type = STR_TYPE;
+        else if (!strcmp("INT", typestr))
+          type = INT_TYPE;
+        else if (!strcmp("SHORT", typestr))
+          type = SHORT_TYPE;
+        else if (!strcmp("CHAR", typestr))
+          type = CHAR_TYPE;
+        else if (!strcmp("LONG", typestr))
+          type = LONG_TYPE;
+        else {
+          DBG(2, fprintf(outfp, "Unable to understand type %s\n",
+                         typestr));
+          return INVALID_ARGS;
+        }
+        print_partial(buf, offset, len, type);
+       }
+     }
+  }
+  DBG(3, fprintf(outfp, "output: %s \n", output));
+  return SUCCESS;
+}
+
+int test_do_mount(int argc, char **argv) 
+{
+  if (argc != 2) {
+    DBG(2, fprintf(outfp, "Invalid number of args (%d) for test_do_mount\n",
+                  argc));
+    return INVALID_ARGS;
+  }
+
+  DBG(4, fprintf(outfp, "Calling mount with from %s and to %s\n",
+                argv[0], argv[1]));
+  last_ret_val = sysio_mount(argv[0], argv[1]);
+  my_errno = errno;
+  last_type = SINT;
+  return SUCCESS;
+}
+
+int test_do_clear(int argc, char **argv) 
+{
+  int index;
+  struct buf_t *buf;
+
+  if (argc != 1) {
+    DBG(2, fprintf(outfp, "Invalid number of args (%d) for clear\n",
+                  argc));
+    return INVALID_ARGS;
+  }
+  index = get_obj(argv[0]);
+  if (index < 0) {
+    fprintf(outfp, "Unable to locate buffer %s\n",
+          argv[0]);
+    return -1;
+  }
+  buf = buflist[index];
+  bzero(buf->buf, buf->len);
+
+  return SUCCESS;
+}
+
+int test_do_list(int argc, char **argv) 
+{
+  char *buf;
+
+  if ((argc) && (argc != 1)) {
+    DBG(2, fprintf(outfp, "Invalid number of args (%d) for list\n",
+                  argc));
+    return INVALID_ARGS;
+  }
+
+  DBG(5,fprintf(outfp, "In test_do_list with args %p\n", (void *)argv));
+  if (!argv) {
+    buf = getcwd(NULL, 0);
+    DBG(4, fprintf(outfp, "Calling list with dir of %s\n", buf));
+    last_ret_val =  sysio_list(buf);
+    my_errno = errno;
+    free(buf);
+    return SUCCESS;
+  } 
+    
+  last_type = SINT;
+  return sysio_list(*argv);
+}
+
+/*
+ * Initlizes sysio library.  Will use default initlization
+ * unless arguments are given
+ */
+int test_do_init(int argc, char **argv) 
+{
+  if (argc > 0) {
+    char *rdriver;
+    char *mpath;
+    int mflags, rsize, msize;
+    if (argc != 3) {
+      DBG(2, fprintf(outfp, "Invalid number of args (%d) for init\n",
+                    argc));
+      return INVALID_ARGS;
+    } 
+
+    rdriver = get_str(argv[0]);
+    rsize = strlen(rdriver)+1;
+    if (rsize > 75) {
+      DBG(2, fprintf(outfp, "%s too long for root driver\n", rdriver));
+      return INVALID_ARGS;
+    }
+    bzero(root_driver, 75);
+    memcpy(root_driver, rdriver, rsize);
+    
+    mpath = get_str(argv[1]);
+    msize = strlen(mpath)+1;
+    if (msize > 250) {
+      DBG(2, fprintf(outfp, "%s too long for mount path\n", mpath));
+      return INVALID_ARGS;
+    }
+    bzero(mntpath, 250);
+    memcpy(mntpath, mpath, msize);
+    
+    mflags = get_obj(argv[2]);
+    if (mflags == -1) {
+      DBG(2, fprintf(outfp, "Invalid flags argument %s\n", argv[2]));
+      return INVALID_ARGS;
+    } 
+  }
+  
+  DBG(5, fprintf(outfp, "In test_do_init\n"));
+  last_type = SINT;
+  DBG(3, fprintf(outfp, "initializing\n"));
+  return initilize_sysio();
+}
+
+
+/*
+ * Returns 1 if the machine is big-endian, 0
+ * otherwise
+ */
+int get_endian(int argc, char **argv) 
+{
+  int x = 1;
+  
+  if ((argc) || (argv)) {
+    DBG(2, fprintf(outfp, "Expected no args for test_do_endian\n"));
+    return INVALID_ARGS;
+  }
+
+  if(*(char *)&x == 1) {
+    /* little-endian, return 0 */
+    last_ret_val= 0;
+  } else {
+    /* big endian, return 1 */
+    last_ret_val= 1;
+  }
+  last_type = UINT;
+  return SUCCESS;
+}
+
+int do_setbuf(int argc, char **argv)
+{
+       int val, size, index, offset;
+       void *buf;
+
+       if (argc != 4) {
+               DBG(2, fprintf(outfp, "Need val, size, buffer, and offset for setbuf\n"));
+               return INVALID_ARGS;
+       }
+       val = get_obj(argv[0]);
+       if (val < 0) {
+               DBG(2, fprintf(outfp, "Unable to understand val of %s\n",
+                                                                        argv[0]));
+               return INVALID_VAR;
+       }
+
+       size = get_obj(argv[1]);
+       if( size <=0 ) {
+               DBG(2, fprintf(outfp, "Size of %s is invalid\n", argv[1]));
+               return INVALID_VAR;
+       }
+
+  index = get_obj(argv[2]);
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer assocated with %s\n",
+                  argv[2]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+       offset = get_obj(argv[3]);
+       
+       if (offset < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[3]));
+    return INVALID_ARGS;
+  }
+       
+       buf = (void *)((char *)buf +offset);
+
+       memset(buf, val, size);
+
+       return SUCCESS;
+}
+
+                               
+int get_sizeof(int argc, char **argv) 
+{
+  char *type;
+  int size;
+
+  if (argc != 1) {
+    DBG(2, fprintf(outfp, "Number of args (%d) invalid for sizeof\n",
+                  argc));
+    return INVALID_ARGS;
+  }
+
+  type = argv[0];
+
+  if (!strcmp(type, "char")) 
+    size =  sizeof(char);
+  else if (!strcmp(type, "int"))
+    size =  sizeof(int);
+  else if (!strcmp(type, "long"))
+    size =  sizeof(long);
+  else if (!strcmp(type, "flock"))
+    size =  sizeof(struct flock);
+  else if (!strcmp(type, "stat"))
+    size =  sizeof(struct stat);
+  else if (!strcmp(type, "statvfs"))
+    size =  sizeof(struct statvfs);
+  else if (!strcmp(type, "iovec"))
+    size =  sizeof(struct iovec);
+ else if (!strcmp(type, "xtvec"))
+    size =  sizeof(struct xtvec);
+  else
+    return INVALID_ARGS;
+
+  DBG(2, fprintf(outfp, "Size is %d\n", size));
+
+  last_type = UINT;
+  last_ret_val = size;
+  return SUCCESS;
+}
+
+int test_do_exit(int argc, char **argv) 
+{
+  int val = 0;
+
+  if (argc) {
+    /* 
+     * If argc is given, need to return the value of
+     * the passed in variable 
+     */
+    val = get_obj(argv[0]);
+  }
+    
+  /*
+   * Clean up.
+   */
+  _sysio_shutdown();
+
+  if (argc)
+    DBG(3, printf("Exiting with %d from %s\n", val, argv[0]));
+
+  exit(val);
+
+  return 0;
+}
+
+int get_buffer(int argc, char **argv) 
+{
+  int size, align;
+  struct buf_t *buf;
+
+  if (argc == 1) /* Just put size, not alignment */
+    align = 16;
+  else if (argc == 2)
+    align = get_obj(argv[1]);
+  else {
+    DBG(2, fprintf(outfp, "Number of args (%d) invalid for alloc\n",
+                  argc));
+    return INVALID_ARGS;
+  }
+    
+  size = get_obj(argv[0]);
+  if (size < 0) {
+    DBG(2, fprintf(outfp, "Invalid size %s\n", argv[0]));
+    return INVALID_ARGS;
+  }
+
+  DBG(3, fprintf(outfp, "Getting buffer of size %d and aligned at %d\n",
+                size, align));
+  buf = (struct buf_t *)malloc(sizeof(struct buf_t));
+  buf->buf = alloc_buff32(size, align);
+  buf->len = size;
+  buflist[next] = buf;
+  DBG(3, fprintf(outfp, "Your buffer (%p) (%p) is at index %d\n",
+                (void *)buf, buf->buf, next));
+  next++;
+
+  last_type = PTR;
+  last_ret_val = next-1;
+  return SUCCESS;
+}
+
+int free_buffer(int argc, char **argv) 
+{
+  int index;
+  char *name = argv[0];
+  
+  if (argc != 1) {
+    DBG(2, fprintf(outfp, "Number of args (%d) invalid for free\n",
+                  argc));
+    return INVALID_ARGS;
+  }
+
+  /* 
+   * Assume that there is one arg and it 
+   * is a variable name which maps to an
+   * index into the buffer array 
+   */  
+   index = get_obj(name);
+   if (index < 0) {
+     DBG(2, fprintf(outfp, "Can't find buffer %s\n",
+                   name));
+     return INVALID_VAR;
+   }
+   DBG(4, fprintf(outfp, "Freeing buffer at index %d\n", index));
+   free(buflist[index]);
+
+   free_obj(name);
+   return SUCCESS;
+}
+
+int cmp_bufs(int argc, char **argv) 
+{
+  int res, index1, index2;
+  char *buf1, *buf2;
+
+  if (argc != 2) {
+    fprintf(outfp, "Need two buffers to compare\n");
+    return INVALID_ARGS;
+  } 
+
+  index1 = get_obj(argv[0]);
+  if (index1 < 0) {
+    fprintf(outfp, "Unable to locate buffer %s\n",
+          argv[0]);
+    return INVALID_VAR;
+  }
+  buf1 = buflist[index1]->buf;
+
+  index2 = get_obj(argv[1]);
+  if (index2 < 0) {
+    fprintf(outfp, "Unable to locate buffer %s\n",
+          argv[1]);
+    return INVALID_VAR;
+  }
+
+  buf2 = buflist[index2]->buf;
+  last_ret_val = strcmp(buf1, buf2);
+
+  DBG(3, fprintf(outfp, "strcmp returned %d\n", res));
+  return SUCCESS;
+}
+
+int test_do_chdir(int argc, char **argv) 
+{
+  if (argc != 1) {
+    DBG(2, fprintf(outfp, "Number of args (%d) invalid for chdir\n",
+                  argc));
+    return INVALID_ARGS;
+  }
+  last_type = SINT;
+  return sysio_chdir(argv[0]);
+}
+
+
+int test_do_chmod(int argc, char **argv) 
+{
+  if (argc != 2) {
+    DBG(2, fprintf(outfp, "Number of args (%d) invalid for chmod\n",
+                  argc));
+    return INVALID_ARGS;
+  }
+  last_type = SINT;
+  return sysio_chmod(argv[0], argv[1]);
+}
+
+int test_do_chown(int argc, char **argv) 
+{
+  if (argc != 2) {
+    DBG(2, fprintf(outfp, "Number of args (%d) invalid for chown\n",
+                  argc));
+    return INVALID_ARGS;
+  }
+  last_type = SINT;
+  return sysio_chown(argv[0], argv[1]);
+}
+
+int test_do_open(int argc, char **argv) 
+{ 
+  char *name = argv[0];
+  int flags = O_RDWR;
+
+  if (argc > 1) 
+    flags = get_obj(argv[1]);
+
+  if (name[0] == '$') {
+    int index = get_obj(name);
+
+    if (index < 0) {
+      DBG(2, fprintf(outfp, "Unable to find buffer at %s\n",
+                    name));
+      return INVALID_VAR;
+    }
+
+    name = buflist[index]->buf;
+  }
+
+  DBG(4,  fprintf(outfp, "Opening file %s with flags %d\n", name, flags));
+  if (argc == 2)
+    return sysio_open(name, flags);
+  else if (argc == 3)
+    return sysio_open3(name, flags, argv[2]);
+  else {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d)\n", argc));
+    return INVALID_ARGS;
+  }
+  last_type = UINT;
+  return SUCCESS;
+}
+
+int test_do_close(int argc, char **argv) 
+{
+  int fd;
+  char *name = argv[0];
+
+  if (argc != 1) {
+    DBG(2, fprintf(outfp, "Number of args (%d) invalid for close\n",
+                  argc));
+    return INVALID_ARGS;
+  }
+
+  /* 
+   * Assume that there is one arg and it 
+   * is a variable name which maps to a file
+   * descriptor 
+   */
+  fd = get_obj(name);
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to map var %s to anything\n", name));
+    return INVALID_VAR;
+  }
+  sysio_close(fd);
+  free_obj(name);
+  return SUCCESS;
+}
+
+int test_do_dup(int argc, char **argv) 
+{
+  int fd;
+  char *var_name = argv[0];
+
+  if (argc != 1) {
+    DBG(2, fprintf(outfp, "Number of args (%d) invalid for dup\n",
+                  argc));
+    return INVALID_ARGS;
+  }
+
+
+  fd = get_obj(var_name);
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to map var %s to any file\n", var_name));
+    return INVALID_VAR;
+  }
+
+  last_ret_val = dup(fd);
+  my_errno = errno;
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+int test_do_dup2(int argc, char **argv) 
+{
+  int fd1, fd2;
+  char *var_name1 = argv[0];
+  char *var_name2 = argv[1];
+
+  if (argc != 2) {
+    DBG(2, fprintf(outfp, "Number of args (%d) invalid for dup2\n",
+                  argc));
+    return INVALID_ARGS;
+  }
+
+  fd1 = get_obj(var_name1);
+  if (fd1 < 0) {
+    DBG(2, fprintf(outfp, "Unable to map var %s to any file\n", var_name1));
+    return INVALID_VAR;
+  }
+
+  fd2 = get_obj(var_name2);
+  if (fd2 < 0) {
+    DBG(2, fprintf(outfp, "Unable to map var %s to any file\n", var_name2));
+    return INVALID_VAR;
+  }
+
+  last_ret_val = dup2(fd1, fd2);
+  my_errno = errno;
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+struct cmd_map fcntl_cmds[] = {
+  { "F_DUPFD", F_DUPFD, 3 },
+  { "F_GETFD", F_GETFD, 2 },
+  { "F_SETFD", F_SETFD, 3 },
+  { "F_GETFL", F_GETFL, 2 },
+  { "F_SETFL", F_SETFL, 3 },
+  { "F_SETLK", F_SETLK, 3 },
+  { "F_SETLKW", F_SETLKW, 3 },
+  { "F_GETLK", F_GETLK, 3 },
+#if defined __USE_BSD || defined __USE_XOPEN2K
+  { "F_GETOWN", F_GETOWN, 2 },
+  { "F_SETOWN", F_SETOWN, 3 },
+#endif
+#ifdef __USE_GNU
+  { "F_GETSIG", F_GETSIG, 2 },
+  { "F_SETSIG", F_SETSIG, 3 },
+  { "F_SETLEASE", F_SETLEASE, 3},
+  { "F_GETLEASE", F_GETLEASE, 2},
+  { "F_NOTIFY", F_NOTIFY, 3} ,
+#endif
+  { NULL, -1, 0 }
+};
+
+struct cmd_map* get_cmd(char *cmd_name, int argc)
+{
+  int i =0;
+
+  while (fcntl_cmds[i].cmd_name) {
+    if (!strcmp(fcntl_cmds[i].cmd_name, cmd_name)) {
+      if (fcntl_cmds[i].num_args == argc)
+       return &fcntl_cmds[i];
+      else
+       return NULL;
+    }
+    i++;
+  }
+  return NULL;
+}
+
+int test_do_fcntl(int argc, char **argv)
+{
+  
+  struct cmd_map *cmd;
+  int fd;
+
+  /* 
+   * get_cmd translates a symbolic command into
+   * into its numerical equivalent. It also
+   * verifies that the number of args is the
+   * correct number for the command. It returns
+   * NULL on failure
+   */
+  cmd = get_cmd(argv[1], argc);
+  if (!cmd) {
+    DBG(2, fprintf(outfp, "Unable to get command %s\n", argv[1]));
+    return INVALID_ARGS;
+  }
+
+  fd = get_obj(argv[0]);
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to map %s to file descriptor \n", argv[0]));
+    return INVALID_VAR;
+  }
+
+  if (argc > 2)
+    last_ret_val =  sysio_fcntl(fd, cmd, argv[2]);
+  else
+    last_ret_val = sysio_fcntl(fd, cmd, NULL);
+  DBG(4, fprintf(outfp, "Got return value of %d\n", (int)last_ret_val));
+  my_errno = errno;
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+int test_do_fstat(int argc, char **argv)
+{
+  int fd, index;
+  void *buf;
+
+  if (argc != 2) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) for fstat\n",
+                  argc));
+    return INVALID_ARGS;
+  }
+
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file assocated with %s\n",
+                  argv[0]));
+    return INVALID_VAR;
+  }
+
+  index = get_obj(argv[1]);
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer assocated with %s\n",
+                  argv[1]));
+    return INVALID_VAR;
+  }
+  
+  buf = buflist[index]->buf;
+  
+  last_ret_val = sysio_fstat(fd, buf);
+  my_errno = errno;
+  last_type = SINT;
+  
+  return SUCCESS;
+}
+
+int test_do_lstat(int argc, char **argv)
+{
+  char *name = argv[0];
+  int index;
+  void *buf;
+
+  if (argc != 2) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) for lstat\n",
+                  argc));
+    return INVALID_ARGS;
+  }
+
+  index = get_obj(argv[1]);
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer assocated with %s\n",
+                  argv[1]));
+    return INVALID_VAR;
+  }
+  
+  buf = buflist[index]->buf;
+  last_type = SINT;  
+
+  return sysio_lstat(name, buf);
+}
+
+int test_do_fsync(int argc, char **argv)
+{
+  int fd;
+
+  if (argc != 1) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to fsync\n", argc));
+    return INVALID_ARGS;
+  }
+
+  
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file assocated with %s\n",
+                  argv[0]));
+    return INVALID_VAR;
+  }
+
+  last_ret_val = fsync(fd);
+  my_errno = errno;
+  last_type = SINT;  
+
+  return SUCCESS;
+}
+
+
+int test_do_fdatasync(int argc, char **argv)
+{
+  int fd;
+
+  if (argc != 1) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to fdatasync\n", argc));
+    return INVALID_ARGS;
+  }
+
+  
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file assocated with %s\n",
+                  argv[0]));
+    return INVALID_VAR;
+  }
+
+  last_ret_val = fdatasync(fd);
+  my_errno = errno;
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+
+int test_do_ftruncate(int argc, char **argv)
+{
+  int fd;
+  off_t length;
+
+  if (argc != 2) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to ftruncate\n", argc));
+    return INVALID_ARGS;
+  }
+
+  
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file assocated with %s\n",
+                  argv[0]));
+    return INVALID_VAR;
+  }
+
+  length = (off_t)get_obj(argv[1]);
+
+  DBG(3, fprintf(outfp, "Setting file %d to %d\n", fd, (int) length));
+
+  last_ret_val = ftruncate(fd, length);
+  my_errno = errno;
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+int test_do_getcwd(int argc, char **argv)
+{
+  char *buf;
+  int size, index;
+
+  if (argc != 2) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to getcwd\n", argc));
+    return INVALID_ARGS;
+  }
+
+  index = get_obj(argv[0]);
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer assocated with %s\n",
+                  argv[1]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  size = get_obj(argv[1]);
+
+  DBG(4, fprintf(outfp, "Getting cwd with buffer size of %d\n", size));
+
+  last_ret_val = 0;
+  if (!getcwd(buf, size)) {
+      last_ret_val = -1;
+      if (errno == ERANGE) {
+         DBG(2, fprintf(outfp, "Need a bigger buffer!\n"));
+      }
+  }
+  my_errno = errno;
+
+  
+  DBG(3, fprintf(outfp, "cwd: %s\n", buf));
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+int test_do_lseek(int argc, char **argv)
+{
+  int fd, whence;
+  off_t offset;
+
+  
+  if (argc != 3) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to lseek\n", argc));
+    return INVALID_ARGS;
+  }
+
+  
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file assocated with %s\n",
+                  argv[0]));
+    return INVALID_VAR;
+  }
+
+  offset = (off_t)get_obj(argv[1]);
+  whence = get_obj(argv[2]);
+
+  if (whence < 0 ) {
+    DBG(2, fprintf(outfp, "Not familiar with whence of %s\n",
+                  argv[2]));
+    return INVALID_ARGS;
+  }
+
+  last_ret_val = lseek(fd, offset, whence);
+  my_errno = errno;
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+int test_do_getdirentries(int argc, char **argv) 
+{
+  int fd, nbytes;
+  int bufindex;
+  off_t basep;
+  char *buf;
+  struct var_mapping *base_map;
+
+  if (argc != 4) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to getdirentries\n", argc));
+    return INVALID_ARGS;
+  }
+
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file assocated with %s\n",
+                  argv[0]));
+    return INVALID_VAR;
+  }
+
+  bufindex = get_obj(argv[1]);
+   
+  if (bufindex < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer assocated with %s\n",
+                  argv[1]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[bufindex]->buf;
+
+  nbytes = get_obj(argv[2]);
+
+  if (nbytes < 0) {
+    DBG(2, fprintf(outfp, "I don't understand %s\n",
+                  argv[2]));
+    return INVALID_ARGS;
+  }
+
+  base_map = get_map(argv[3]);
+  if (!base_map) {
+    DBG(3, fprintf(outfp, "Resetting basep\n"));
+    /* 
+     * Assume that this is the first getdirentries call
+     * and we need to setup the base pointer
+     */
+    basep = 0;
+  } else 
+    basep = base_map->obj;
+      
+  DBG(3, fprintf(outfp, "basep is (starting) %d\n", (int) basep));
+  last_ret_val = sysio_getdirentries(fd, buf, nbytes, &basep);
+  if (base_map)
+    base_map->obj = basep;
+  else
+    store_result(argv[3]+1, basep);
+  DBG(3, fprintf(outfp, "basep is (ending) %d\n", (int) basep));
+  my_errno = errno;
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+int test_do_mkdir(int argc, char **argv)
+{
+  if (argc !=2) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to mkdir\n", argc));
+    return INVALID_ARGS;
+  }
+
+  last_type = SINT;
+  return sysio_mkdir(argv[0], argv[1]);
+}
+
+int test_do_creat(int argc, char **argv)
+{
+  if (argc !=2) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to creat\n", argc));
+    return INVALID_ARGS;
+  }
+
+  last_type = UINT;
+  return sysio_creat(argv[0], argv[1]);
+}
+
+int test_do_stat(int argc, char **argv)
+{
+  int index;
+  void *buf;
+  char *str;
+
+  if (argc != 2) {
+    fprintf(outfp, "Invalid number of arguments (%d) for stat\n",
+          argc);
+    return -1;
+  }
+
+
+  index = get_obj(argv[1]);
+  if (index < 0) {
+    fprintf(outfp, "Unable to find buffer assocated with %s\n",
+          argv[1]);
+  }
+  
+  buf = buflist[index]->buf;
+  last_type = SINT;
+  
+  str = get_str(argv[0]);
+  return sysio_stat(str, buf);
+}
+
+int test_do_statvfs(int argc, char **argv)
+{
+  int index;
+  void *buf;
+
+  if (argc != 2) {
+    fprintf(outfp, "Invalid number of arguments (%d) for statvfs\n",
+          argc);
+    return -1;
+  }
+
+
+  index = get_obj(argv[1]);
+  if (index < 0) {
+    fprintf(outfp, "Unable to find buffer assocated with %s\n",
+          argv[1]);
+  }
+  
+  buf = buflist[index]->buf;
+  last_type = SINT;
+  
+  return sysio_statvfs(argv[0], buf);
+}
+
+int test_do_fstatvfs(int argc, char **argv)
+{
+  int index, fd;
+  void *buf;
+
+  if (argc != 2) {
+    fprintf(outfp, "Invalid number of arguments (%d) for fstatvfs\n",
+          argc);
+    return -1;
+  }
+
+  
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    fprintf(outfp, "Unable to find file assocated with %s\n",
+          argv[0]);
+  }
+
+
+  index = get_obj(argv[1]);
+  if (index < 0) {
+    fprintf(outfp, "Unable to find buffer assocated with %s\n",
+          argv[1]);
+  }
+  
+  buf = buflist[index]->buf;
+  last_type = SINT;
+  
+  return sysio_fstatvfs(fd, buf);
+}
+
+int test_do_truncate(int argc, char **argv)
+{
+  off_t length;
+
+  if (argc != 2) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to truncate\n", argc));
+    return INVALID_ARGS;
+  }
+  
+  length = (off_t)get_obj(argv[1]);
+
+  DBG(3, fprintf(outfp, "Setting file %s to %d\n", argv[0], (int) length));
+
+  last_ret_val = truncate(argv[0], length);
+  my_errno = errno;
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+int test_do_rmdir(int argc, char **argv)
+{
+
+  if (argc != 1) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to rmdir\n", argc));
+    return INVALID_ARGS;
+  }
+
+  DBG(3, fprintf(outfp, "Removing dir %s\n", argv[0]));
+
+  last_ret_val = rmdir(argv[0]);
+  my_errno = errno;
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+int test_do_symlink(int argc, char **argv)
+{
+  if (argc != 2) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to symlink\n", argc));
+    return INVALID_ARGS;
+  }
+
+  DBG(3, fprintf(outfp, "Linking %s to %s\n", argv[0], argv[1]));
+
+  last_ret_val = symlink(argv[0], argv[1]);
+  if (last_ret_val) {
+    if (errno < 0) 
+      errno = errno*-1;
+    my_perror("symlink");
+  } 
+  my_errno = errno;
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+
+struct cmd_map ioctl_cmds[] = {
+#if 0
+  { "BLKROSET", BLKROSET, 3 },
+  { "BLKROGET", BLKROGET, 3 },
+  { "BLKRRPART", BLKRRPART, 3 },
+  { "BLKGETSIZE", BLKGETSIZE, 3 },
+  { "BLKRASET", BLKRASET, 3 },
+  { "BLKRAGET", BLKRAGET, 3 },
+  { "BLKSECTSET", BLKSECTSET, 3 },
+  { "BLKSECTGET", BLKSECTGET, 3 },
+  { "BLKSSZGET", BLKSSZGET, 3 },
+  { "BLKGETLASTSECT", BLKGETLASTSECT, 3 },
+  { "BLKSETLASTSECT", BLKSETLASTSECT, 3 },
+  { "BLKBSZGET", BLKBSZGET, 3 },
+  { "BLKBSZSET", BLKBSZSET, 3 },
+  { "FIBMAP", FIBMAP, 3 },
+  { "FIGETBSZ", FIGETBSZ, 3},
+#endif
+  { NULL, -1, 0 }
+};
+
+int get_ioctl_cmd(char *cmd) 
+{
+  int i = 0;
+
+  while (ioctl_cmds[i].cmd_name != NULL) {
+    if (strcmp(ioctl_cmds[i].cmd_name, cmd))
+      i++;
+    else
+      return ioctl_cmds[i].cmd;
+  }
+
+  return -1;
+}
+
+int test_do_ioctl(int argc, char **argv)
+{
+  int fd, cmd;
+
+  if (argc != 3) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to ioctl\n", argc));
+    return INVALID_ARGS;
+  }
+
+
+  fd = get_obj(argv[0]);
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file %s\n", argv[0]));
+    return INVALID_VAR;
+  }
+
+  cmd = get_ioctl_cmd(argv[1]);
+  if (cmd == -1) {
+    DBG(2, fprintf(outfp, "Do not understand command %s\n", argv[1]));
+    return INVALID_ARGS;
+  }
+
+  DBG(3, fprintf(outfp, "Executing command %s\n", argv[1]));
+
+  last_ret_val = ioctl(fd, cmd, argv[2]);
+  my_errno = errno;
+  if (last_ret_val) 
+    my_perror("ioctl");
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+int test_do_unlink(int argc, char **argv)
+{
+  if (argc != 1) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to unlink\n", argc));
+    return INVALID_ARGS;
+  }
+
+  DBG(4, fprintf(outfp, "Unlinking %s\n", argv[0]));
+
+  last_ret_val = unlink(argv[0]);
+  my_errno = errno;
+  if (last_ret_val) 
+    my_perror("unlink");
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+int test_do_umask(int argc, char **argv)
+{
+  mode_t old_mask;
+
+  if (argc != 1) {
+    DBG(2, fprintf(outfp, "Incorrect number of args (%d) for umask\n", argc));
+    return INVALID_ARGS;
+  }
+
+  last_ret_val = old_mask = sysio_umask(argv[0]);
+  my_errno = errno;
+  DBG(3, fprintf(outfp, "Previous umask was %o\n", old_mask));
+  last_type = UINT;
+  
+  return SUCCESS;
+}
+
+int test_do_iowait(int argc, char **argv)
+{
+  long err;
+  ioid_t ioid;
+
+  if (argc != 1) {
+    DBG(2, fprintf(outfp, "Incorrect amount of args (%d) for iowait\n", argc));
+    return INVALID_ARGS;
+  }
+
+  err = get_obj(argv[0]);
+  if (err < 0) {
+    DBG(2, fprintf(outfp, "Cannot find ioid at %s\n", argv[0]));
+    return INVALID_VAR;
+  }
+  
+  ioid = (ioid_t)err;
+
+  last_ret_val =  iowait(ioid);
+  my_errno = errno;
+  if (last_ret_val < 0) {
+    my_perror("iowait");
+  }
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+int test_do_iodone(int argc, char **argv)
+{
+  long err;
+  ioid_t ioid;
+
+  if (argc != 1) {
+    DBG(2, fprintf(outfp, "Incorrect amount of args (%d) for iodone\n", argc));
+    return INVALID_ARGS;
+  }
+
+  err = get_obj(argv[0]);
+  if (err < 0) {
+    DBG(2, fprintf(outfp, "Cannot find ioid at %s\n", argv[0]));
+    return INVALID_VAR;
+  }
+  ioid = (ioid_t)err;
+
+  last_ret_val =  iowait(ioid);
+  if (last_ret_val < 0) {
+    my_perror("iodone");
+  }
+  my_errno = errno;
+  last_type = SINT;
+
+  return SUCCESS;
+
+}
+
+int test_do_ipread(int argc, char **argv) 
+{
+  int fd, index, count, offset;
+  char *buf;
+
+  if (argc != 4) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to ipread\n", argc));
+    return INVALID_ARGS;
+  }
+
+  fd = get_obj(argv[0]);
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file at %s\n", argv[0]));
+    return INVALID_VAR;
+  }
+
+  index = get_obj(argv[1]);
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer at %s\n", argv[1]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  count = get_obj(argv[2]);
+  if (count < 0) {
+    DBG(2, fprintf(outfp, "Do not understand count %s\n", argv[2]));
+    return INVALID_ARGS;
+  }
+
+  offset = get_obj(argv[3]);
+  if (offset < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand offset of %s\n", argv[3]));
+    return INVALID_ARGS;
+  }
+
+  last_ret_val = (long)ipread(fd, buf, count, offset);
+  if (last_ret_val < 0) {
+    my_perror("ipread");
+  }
+  my_errno = errno;
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+int test_do_iread(int argc, char **argv) 
+{
+  int fd, index, count;
+  char *buf;
+
+  if (argc != 3) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to iread\n", argc));
+    return INVALID_ARGS;
+  }
+
+  fd = get_obj(argv[0]);
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file at %s\n", argv[0]));
+    return INVALID_VAR;
+  }
+
+  index = get_obj(argv[1]);
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer at %s\n", argv[1]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  count = get_obj(argv[2]);
+  if (count < 0) {
+    DBG(2, fprintf(outfp, "Do not understand count %s\n", argv[2]));
+    return INVALID_ARGS;
+  }
+
+  last_ret_val = (long) iread(fd, buf, count);
+  if (last_ret_val < 0) {
+    my_perror("iread");
+  }
+  my_errno = errno;
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+
+int test_do_ipreadv(int argc, char **argv)
+{
+  int fd, count, index;
+  off_t offset;
+  char *buf;
+  struct iovec *iov;
+
+  if (argc != 4) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to ipreadv\n", argc));
+    return INVALID_ARGS;
+  }
+
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0]));
+    return INVALID_VAR;
+  }
+
+  index = get_obj(argv[1]);
+
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  iov = (struct iovec *)buf;
+  count = get_obj(argv[2]);
+
+  if (count < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[2]));
+    return INVALID_ARGS;
+  }
+
+  offset = get_obj(argv[3]);
+  if (offset < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand offset value %s\n", argv[3]));
+    return INVALID_ARGS;
+  }
+
+  DBG(3, fprintf(outfp, "ipreadv(fd: %d vector:{iov_base: %p iov_len %d} count: %d offset: %d\n",
+                fd, iov->iov_base, (int)iov->iov_len, count, (int) offset)); 
+
+  last_ret_val = (long) ipreadv(fd, iov, count, offset);
+  if (last_ret_val < 0)
+    my_perror("ipreadv");
+  my_errno = errno;
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+
+int test_do_preadv(int argc, char **argv)
+{
+  int fd, count, index;
+  off_t offset;
+  char *buf;
+  struct iovec *iov;
+
+  if (argc != 4) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to preadv\n", argc));
+    return INVALID_ARGS;
+  }
+
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0]));
+    return INVALID_VAR;
+  }
+
+  index = get_obj(argv[1]);
+
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  iov = (struct iovec *)buf;
+  count = get_obj(argv[2]);
+
+  if (count < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[2]));
+    return INVALID_ARGS;
+  }
+
+  offset = get_obj(argv[3]);
+  if (offset < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand offset value %s\n", argv[3]));
+    return INVALID_ARGS;
+  }
+
+  DBG(3, fprintf(outfp, "preadv(fd: %d vector:{iov_base: %p iov_len %d} count: %d offset: %d\n",
+                fd, iov->iov_base, (int) iov->iov_len, count, (int) offset)); 
+
+  last_ret_val = preadv(fd, iov, count, offset);
+  my_errno = errno;
+  if (last_ret_val < 0)
+    my_perror("preadv");
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+
+int test_do_pread(int argc, char **argv)
+{
+  int fd, count, index, numbytes, offset;
+  char *buf;
+
+  if (argc != 4) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to pread\n", argc));
+    return INVALID_ARGS;
+  }
+
+  
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file assocated with %s\n",
+                  argv[0]));
+    return INVALID_VAR;
+  }
+  
+  index = get_obj(argv[1]);
+    
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer assocated with %s\n",
+                  argv[1]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  count = get_obj(argv[2]);
+  if (count < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand count of %s\n", argv[1]));
+    return INVALID_ARGS;
+  }
+
+  offset = get_obj(argv[3]);
+  if (count < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand offset of %s\n", argv[2]));
+    return INVALID_ARGS;
+  }
+
+
+  last_ret_val = numbytes = (int) pread(fd, buf, count, offset);
+  my_errno = errno;
+  DBG(4, fprintf(outfp, "Read %d bytes out of %d starting at offset %x\n", 
+                numbytes, count, offset));
+  DBG(3, fprintf(outfp, "Got %s\n", buf));
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+
+int test_do_ireadv(int argc, char **argv)
+{
+  int fd, count, index;
+  char *buf;
+  struct iovec *iov;
+
+  if (argc != 3) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to ireadv\n", argc));
+    return INVALID_ARGS;
+  }
+
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0]));
+    return INVALID_VAR;
+  }
+
+  index = get_obj(argv[1]);
+
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  iov = (struct iovec *)buf;
+  count = get_obj(argv[2]);
+
+  if (count < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[2]));
+    return INVALID_ARGS;
+  }
+
+  DBG(3, fprintf(outfp, "ireadv (fd: %d, vector:{ iov_base: %p iov_len %d }, count: %d\n",
+                fd, iov->iov_base, (int)iov->iov_len, count)); 
+
+  last_ret_val = (long) ireadv(fd, iov, count);
+  if (last_ret_val < 0)
+    my_perror("ireadv");
+  my_errno = errno;
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+int test_do_readv(int argc, char **argv)
+{
+  int fd, count, index;
+  char *buf;
+  struct iovec *iov;
+
+  if (argc != 3) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to readv\n", argc));
+    return INVALID_ARGS;
+  }
+
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0]));
+    return INVALID_VAR;
+  }
+
+  index = get_obj(argv[1]);
+
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  iov = (struct iovec *)buf;
+  count = get_obj(argv[2]);
+
+  if (count < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[2]));
+    return INVALID_ARGS;
+  }
+
+  DBG(3, fprintf(outfp, "ireadv (fd: %d, vector:{ iov_base: %p iov_len %d }, count: %d\n",
+                fd, iov->iov_base, (int)iov->iov_len, count)); 
+
+  last_ret_val = readv(fd, iov, count);
+  if (last_ret_val < 0)
+    my_perror("readv");
+  my_errno = errno;
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+int test_do_read(int argc, char **argv)
+{
+  int fd, count, index, numbytes=0;
+  char *buf;
+
+  if (argc < 3) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to read\n", argc));
+    return INVALID_ARGS;
+  }
+
+  
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file assocated with %s\n",
+                  argv[0]));
+    return INVALID_VAR;
+  }
+  
+  index = get_obj(argv[1]);
+  
+  
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer assocated with %s\n",
+                  argv[1]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  count = get_obj(argv[2]);
+
+  if ( (argc == 4) && (!strcmp(argv[3], "delay")) ){
+    int i;
+    /* Wait a little while for input */
+    for (i=0; i < count; i++) {
+      sleep(0.005);
+      numbytes += (int) read(fd, buf, 1);
+      last_ret_val = numbytes;
+      
+    }
+  } else {
+    last_ret_val = numbytes = (int) read(fd, buf, count);
+  }
+  my_errno = errno;
+
+  DBG(3, fprintf(outfp, "Read %d bytes out of %d\n", numbytes, count));
+  DBG(3, fprintf(outfp, "Got %s\n", buf));
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+int test_do_ipwritev(int argc, char **argv)
+{
+  int fd, count, index, offset;
+  char *buf;
+  struct iovec *iov;
+
+  if (argc != 4) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to ipwritev\n", argc));
+    return INVALID_ARGS;
+  }
+
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0]));
+    return INVALID_VAR;
+  }
+
+  index = get_obj(argv[1]);
+
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  iov = (struct iovec *)buf;
+
+  count = get_obj(argv[2]);
+  if (count < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand count %s\n", argv[2]));
+    return INVALID_ARGS;
+  }
+
+  offset = get_obj(argv[3]);
+  if (offset < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand offset %s\n", argv[3]));
+    return INVALID_ARGS;
+  }
+
+  DBG(3, fprintf(outfp, 
+                "ipwritev(fd: %d, vector: { iov_base: %p iov_len %d }, count: %d, offset: %d\n",
+                fd, iov->iov_base, (int)iov->iov_len, count, offset)); 
+
+  last_ret_val = (long) ipwritev(fd, iov, count, offset);
+  my_errno = errno;
+  if (last_ret_val < 0)
+    my_perror("ipwritev");
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+int test_do_ipwrite(int argc, char **argv)
+{
+  int fd, count, index, offset;
+  char *buf;
+
+  if (argc != 4) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to ipwrite\n", argc));
+    return INVALID_ARGS;
+  }
+
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0]));
+    return INVALID_VAR;
+  }
+
+  index = get_obj(argv[1]);
+
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  count = get_obj(argv[2]);
+  if (count < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand count %s\n", argv[2]));
+    return INVALID_ARGS;
+  }
+
+  offset = get_obj(argv[3]);
+  if (offset < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand offset %s\n", argv[3]));
+    return INVALID_ARGS;
+  }
+
+  last_ret_val = (long) ipwrite(fd, buf, count, offset);
+  if (last_ret_val < 0)
+    my_perror("ipwrite");
+  my_errno = errno;
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+int test_do_pwritev(int argc, char **argv)
+{
+  int fd, count, index, offset;
+  char *buf;
+  struct iovec *iov;
+
+  if (argc != 4) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to pwritev\n", argc));
+    return INVALID_ARGS;
+  }
+
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0]));
+    return INVALID_VAR;
+  }
+
+  index = get_obj(argv[1]);
+
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  iov = (struct iovec *)buf;
+
+  count = get_obj(argv[2]);
+  if (count < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand count %s\n", argv[2]));
+    return INVALID_ARGS;
+  }
+
+  offset = get_obj(argv[3]);
+  if (offset < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand offset %s\n", argv[3]));
+    return INVALID_ARGS;
+  }
+
+
+  DBG(3, fprintf(outfp, 
+                "pwritev(fd: %d, vector: { iov_base: %p iov_len %d }, count: %d, offset: %d\n",
+                fd, iov->iov_base, (int)iov->iov_len, count, offset)); 
+
+  last_ret_val = (long) pwritev(fd, iov, count, offset);
+  if (last_ret_val < 0)
+    my_perror("ipwritev");
+  my_errno = errno;
+  last_type = SINT;
+  
+  return SUCCESS;
+}
+
+int test_do_pwrite(int argc, char **argv)
+{
+  int fd, count, index, offset;
+  char *buf;
+
+  if (argc != 4) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to pwrite\n", argc));
+    return INVALID_ARGS;
+  }
+
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0]));
+    return INVALID_VAR;
+  }
+
+  index = get_obj(argv[1]);
+
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  count = get_obj(argv[2]);
+  if (count < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand count %s\n", argv[2]));
+    return INVALID_ARGS;
+  }
+
+  offset = get_obj(argv[3]);
+  if (offset < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand offset %s\n", argv[3]));
+    return INVALID_ARGS;
+  }
+
+  last_ret_val = pwrite(fd, buf, count, offset);
+  my_errno = errno;
+  if (last_ret_val < 0)
+    my_perror("pwrite");
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+
+int test_do_iwritev(int argc, char **argv)
+{
+  int fd, count, index;
+  char *buf;
+  struct iovec *iov;
+
+  if (argc != 3) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to iwritev\n", argc));
+    return INVALID_ARGS;
+  }
+
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0]));
+    return INVALID_VAR;
+  }
+
+  index = get_obj(argv[1]);
+
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  iov = (struct iovec *)buf;
+
+  count = get_obj(argv[2]);
+  if (count < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand count %s\n", argv[2]));
+    return INVALID_ARGS;
+  }
+
+  DBG(3, fprintf(outfp, "iwritev(fd: %d, vector: { iov_base: %p iov_len %d }, count: %d\n",
+                fd, iov->iov_base, (int)iov->iov_len, count)); 
+
+  last_ret_val = (long) iwritev(fd, iov, count);
+  my_errno = errno;
+  if (last_ret_val < 0)
+    my_perror("iwritev");
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+int test_do_iwrite(int argc, char **argv)
+{
+  int fd, count, index;
+  char *buf;
+
+  if (argc != 3) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to iwrite\n", argc));
+    return INVALID_ARGS;
+  }
+
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0]));
+    return INVALID_VAR;
+  }
+
+  index = get_obj(argv[1]);
+
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  count = get_obj(argv[2]);
+  if (count < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand count %s\n", argv[2]));
+    return INVALID_ARGS;
+  }
+
+  last_ret_val = (long) iwrite(fd, buf, count);
+  my_errno = errno;
+  if (last_ret_val < 0)
+    my_perror("iwrite");
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+
+int test_do_write(int argc, char **argv)
+{
+  int fd, count, index, err;
+  char *buf;
+
+  if (argc != 3) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to write\n", argc));
+    return INVALID_ARGS;
+  }
+
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0]));
+    return INVALID_VAR;
+  }
+
+  index = get_obj(argv[1]);
+
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  count = get_obj(argv[2]);
+  if (count < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand count %s\n", argv[2]));
+    return INVALID_ARGS;
+  }
+
+  DBG(4, fprintf(outfp, "Writing out %d bytes (%s) using fd of %x\n",
+                count, buf, fd));
+  err = write(fd, buf, count);
+  if (err < 0)
+    my_perror("write");
+
+  last_ret_val = err;
+  my_errno = errno;
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+
+int test_do_writev(int argc, char **argv)
+{
+  int fd, count, index;
+  char *buf;
+  struct iovec *iov;
+
+  if (argc != 3) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to writev\n", argc));
+    return INVALID_ARGS;
+  }
+
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0]));
+    return INVALID_ARGS;
+  }
+
+  index = get_obj(argv[1]);
+
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  iov = (struct iovec *)buf;
+  count = get_obj(argv[2]);
+
+  if (count < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[2]));
+    return INVALID_ARGS;
+  }
+
+  DBG(3, fprintf(outfp, "writev(fd: %d, vector: { iov_base: %p iov_len %d }, count: %d\n",
+                fd, iov->iov_base, (int)iov->iov_len, count)); 
+
+  last_ret_val = writev(fd, iov, count);
+  if (last_ret_val < 0)
+    my_perror("writev");
+  my_errno = errno;
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+int test_do_mknod(int argc, char **argv) 
+{
+  int dev;
+
+  if (argc != 3) {
+    DBG(2, fprintf(outfp, "Invalid number of args (%d) for mknod\n", argc));
+    return INVALID_ARGS;
+  }
+
+  dev = get_obj(argv[2]);
+  if (dev < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[2]));
+    return INVALID_ARGS;
+  }
+  last_type = SINT;
+
+  
+  return sysio_mknod(argv[0], argv[1], (dev_t) dev);
+}
+
+int test_do_umount(int argc, char **argv) 
+{
+  int err;
+
+  if (argc != 1) {
+    DBG(2, fprintf(outfp, "Invalid number (%d) of args for umount\n", argc));
+    return INVALID_ARGS;
+  }
+
+  err = umount(argv[0]);
+  if (err)
+    my_perror("umount");
+
+  my_errno = errno;
+  last_ret_val = err;
+  last_type = SINT;
+
+  return SUCCESS;
+}
+int test_do_init_iovec(int argc, char **argv)
+{
+       int iov_index, buf_index;
+       int offset, len, pos;
+       struct iovec *iov_ptr;
+       char *base_ptr;
+
+       if (argc != 5) {
+               DBG(2, fprintf(outfp, "Need buffer, offset, len, array pos, and iov pointer\n"));
+               return INVALID_ARGS;
+       }
+
+       if ((buf_index = get_obj(argv[0])) < 0) {
+               DBG(2, fprintf(outfp, "Unable to find object %s\n", argv[0]));
+               return INVALID_VAR;
+       }
+       base_ptr = buflist[buf_index]->buf;
+
+       if ((offset = get_obj(argv[1])) < 0) {
+               DBG(2, fprintf(outfp, "Cannot understand offset of %s\n", argv[1]));
+               return INVALID_VAR;
+       }
+       
+       if ((len = get_obj(argv[2])) < 0) {
+               DBG(2, fprintf(outfp, "Cannot understand len of %s\n", argv[2]));
+               return INVALID_VAR;
+       }
+       
+       if ((pos = get_obj(argv[3])) < 0) {
+               DBG(2, fprintf(outfp, "Cannot understand array pos of %s\n", argv[3]));
+               return INVALID_VAR;
+       }
+
+       if ((iov_index = get_obj(argv[4])) < 0) {
+               DBG(2, fprintf(outfp, "Unable to find object %s\n", argv[4]));
+               return INVALID_VAR;
+       }
+       iov_ptr = (struct iovec *)(buflist[iov_index]->buf);    
+
+       iov_ptr[pos].iov_len = len;
+       iov_ptr[pos].iov_base = (void *)(base_ptr + offset);
+       
+       DBG(3, fprintf(outfp, "iov_ptr.len is %d and base is %p\n", 
+                      (int)iov_ptr[pos].iov_len, iov_ptr[pos].iov_base));
+   my_errno = errno;
+  last_type = PTR;
+
+       return SUCCESS;
+}
+
+
+int test_do_init_xtvec(int argc, char **argv)
+{
+       int xtv_index;
+       int offset, len, pos;
+       struct xtvec *xtv_ptr;
+
+       if (argc != 4) {
+               DBG(2, fprintf(outfp, "Need offset, len, array pos, and xtv pointer\n"));
+               return INVALID_ARGS;
+       }
+
+       if ((offset = get_obj(argv[0])) < 0) {
+               DBG(2, fprintf(outfp, "Cannot understand offset of %s\n", argv[0]));
+               return INVALID_VAR;
+       }
+       
+       if ((len = get_obj(argv[1])) < 0) {
+               DBG(2, fprintf(outfp, "Cannot understand len of %s\n", argv[1]));
+               return INVALID_VAR;
+       }
+       
+       if ((pos = get_obj(argv[2])) < 0) {
+               DBG(2, fprintf(outfp, "Cannot understand array pos of %s\n", argv[2]));
+               return INVALID_VAR;
+       }
+
+       if ((xtv_index = get_obj(argv[3])) < 0) {
+               DBG(2, fprintf(outfp, "Unable to find object %s\n", argv[3]));
+               return INVALID_VAR;
+       }
+       xtv_ptr = (struct xtvec *)(buflist[xtv_index]->buf);    
+
+       xtv_ptr[pos].xtv_len = len;
+       xtv_ptr[pos].xtv_off = offset;
+       
+       DBG(3, fprintf(outfp, "xtv_ptr.len is %d and offset is %d\n", 
+                      (int)xtv_ptr[pos].xtv_len, (int)xtv_ptr[pos].xtv_off));
+
+       my_errno = errno;
+  last_type = PTR;
+
+       return SUCCESS;
+}
+
+int test_do_writex(int argc, char **argv)
+{
+  int fd, iov_count, xtv_count,index;
+  char *buf;
+  struct iovec *iov;
+       struct xtvec *xtv;
+
+  if (argc != 5) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to writex\n", argc));
+    return INVALID_ARGS;
+  }
+
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0]));
+    return INVALID_ARGS;
+  }
+
+  index = get_obj(argv[1]);
+
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  iov = (struct iovec *)buf;
+  iov_count = get_obj(argv[2]);
+
+  if (iov_count < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[2]));
+    return INVALID_ARGS;
+  }
+
+  index = get_obj(argv[3]);
+
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find xtvs described by %s\n", argv[3]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  xtv = (struct xtvec *)buf;
+  xtv_count = get_obj(argv[4]);
+
+  if (xtv_count < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[4]));
+    return INVALID_ARGS;
+  }
+
+  DBG(3, fprintf(outfp, "writex(fd: %d, iov: %p iov_cnt: %d, xtv: %p, xtv_cnt: %d\n",
+                fd, (void *)iov, iov_count, (void *)xtv, xtv_count)); 
+
+  last_ret_val = writex(fd, iov, iov_count, xtv, xtv_count);
+  if (last_ret_val < 0)
+    my_perror("writex");
+  my_errno = errno;
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+
+int test_do_iwritex(int argc, char **argv)
+{
+  int fd, iov_count, xtv_count,index;
+  char *buf;
+  struct iovec *iov;
+       struct xtvec *xtv;
+
+  if (argc != 5) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to iwritex\n", argc));
+    return INVALID_ARGS;
+  }
+
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0]));
+    return INVALID_ARGS;
+  }
+
+  index = get_obj(argv[1]);
+
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  iov = (struct iovec *)buf;
+  iov_count = get_obj(argv[2]);
+
+  if (iov_count < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[2]));
+    return INVALID_ARGS;
+  }
+
+  index = get_obj(argv[3]);
+
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find xtvs described by %s\n", argv[3]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  xtv = (struct xtvec *)buf;
+  xtv_count = get_obj(argv[4]);
+
+  if (xtv_count < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[4]));
+    return INVALID_ARGS;
+  }
+
+  DBG(3, fprintf(outfp, "iwritex(fd: %d, iov: %p iov_cnt: %d, xtv: %p, xtv_cnt: %d\n",
+                fd, (void *)iov, iov_count, (void *)xtv, xtv_count)); 
+
+  last_ret_val = (long) iwritex(fd, iov, iov_count, xtv, xtv_count);
+  if (last_ret_val < 0)
+    my_perror("iwritex");
+  my_errno = errno;
+  last_type = SINT;
+
+       return SUCCESS;
+}
+
+
+int test_do_readx(int argc, char **argv)
+{
+  int fd, iov_count, xtv_count,index;
+  char *buf;
+  struct iovec *iov;
+       struct xtvec *xtv;
+
+  if (argc != 5) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to readx\n", argc));
+    return INVALID_ARGS;
+  }
+
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0]));
+    return INVALID_ARGS;
+  }
+
+  index = get_obj(argv[1]);
+
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  iov = (struct iovec *)buf;
+  iov_count = get_obj(argv[2]);
+
+  if (iov_count < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[2]));
+    return INVALID_ARGS;
+  }
+
+  index = get_obj(argv[3]);
+
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find xtvs described by %s\n", argv[3]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  xtv = (struct xtvec *)buf;
+  xtv_count = get_obj(argv[4]);
+
+  if (xtv_count < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[4]));
+    return INVALID_ARGS;
+  }
+
+  DBG(3, fprintf(outfp, "readx(fd: %d, iov: %p iov_cnt: %d, xtv: %p, xtv_cnt: %d\n",
+                fd, (void *)iov, iov_count, (void *)xtv, xtv_count)); 
+
+  last_ret_val = readx(fd, iov, iov_count, xtv, xtv_count);
+  if (last_ret_val < 0)
+    my_perror("readx");
+  my_errno = errno;
+  last_type = SINT;
+
+  return SUCCESS;
+}
+
+
+int test_do_ireadx(int argc, char **argv)
+{
+  int fd, iov_count, xtv_count,index;
+  char *buf;
+  struct iovec *iov;
+       struct xtvec *xtv;
+
+  if (argc != 5) {
+    DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to ireadx\n", argc));
+    return INVALID_ARGS;
+  }
+
+  fd = get_obj(argv[0]);
+
+  if (fd < 0) {
+    DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0]));
+    return INVALID_ARGS;
+  }
+
+  index = get_obj(argv[1]);
+
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  iov = (struct iovec *)buf;
+  iov_count = get_obj(argv[2]);
+
+  if (iov_count < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[2]));
+    return INVALID_ARGS;
+  }
+
+  index = get_obj(argv[3]);
+
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find xtvs described by %s\n", argv[3]));
+    return INVALID_VAR;
+  }
+
+  buf = buflist[index]->buf;
+
+  xtv = (struct xtvec *)buf;
+  xtv_count = get_obj(argv[4]);
+
+  if (xtv_count < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[4]));
+    return INVALID_ARGS;
+  }
+
+  DBG(3, fprintf(outfp, "ireadx(fd: %d, iov: %p iov_cnt: %d, xtv: %p, xtv_cnt: %d\n",
+                fd, (void *)iov, iov_count, (void *)xtv, xtv_count)); 
+
+  last_ret_val = (long) ireadx(fd, iov, iov_count, xtv, xtv_count);
+  if (last_ret_val < 0)
+    my_perror("ireadx");
+  my_errno = errno;
+  last_type = SINT;
+
+       return SUCCESS;
+}
+
+
+int do_checkbuf(int argc, char **argv)
+{
+        int size, val, index, i, offset;
+        int *ref_buf, *buf;
+       
+       if (argc != 4) {
+               DBG(2, fprintf(outfp, "Need buffer, val, and offset for checkbuf\n"));
+               return INVALID_ARGS;
+       }
+
+       index = get_obj(argv[0]);
+
+  if (index < 0) {
+    DBG(2, fprintf(outfp, "Unable to find buf described by %s\n", argv[0]));
+    return INVALID_VAR;
+  }
+
+  buf = (int *)buflist[index]->buf;    
+
+
+       size = get_obj(argv[1]);
+
+       if (size < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[1]));
+    return INVALID_ARGS;
+  }
+
+       val = get_obj(argv[2]);
+       
+  if (val < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[2]));
+    return INVALID_ARGS;
+  }
+
+       
+       offset = get_obj(argv[3]);
+       
+       if (offset < 0) {
+    DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[3]));
+    return INVALID_ARGS;
+  }
+       
+
+       ref_buf = (int *)malloc(size);
+       memset((void *)ref_buf, val, size);
+
+       last_ret_val =0;
+       buf = (int *)((char *)buf + offset);
+       for (i=0; (unsigned)i < size/sizeof(int); i++) {
+               if (buf[i] != ref_buf[i]) {
+                       DBG(2, fprintf(stderr, "At pos %d I found a 0x%08x instead of 0x%08x\n",
+                                                                                i, buf[i], ref_buf[i]));
+                       fprintf(stderr, "At pos %d I found a 0x%08x instead of 0x%08x (val was %d)\n",
+                                                                                i, buf[i], ref_buf[i], val);
+                       last_ret_val = 1;
+                       break;
+               }
+       }
+
+  my_errno = errno;
+  last_type = SINT;
+
+       return SUCCESS;
+}
diff --git a/libsysio/tests/sysio_tests.c b/libsysio/tests/sysio_tests.c
new file mode 100644 (file)
index 0000000..8f2f301
--- /dev/null
@@ -0,0 +1,859 @@
+#define _BSD_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <fcntl.h>
+#include <sys/queue.h>
+#include <dirent.h>
+
+#include "sysio.h"
+#include "mount.h"
+#include "test.h"
+#include "test_driver.h"
+
+/*
+ * ###################################################
+ * # Test functions                                  #
+ * #  These functions are used to test libsysio.     #
+ * #  Eventually, there should be one of these for   #
+ * #  every function document in sysio.h             #
+ * ###################################################
+ */
+int initilize_sysio()
+{
+  char *wd;
+  /* 
+   * Attempt to set the cwd by getting it out of the
+   * user's environment.  If that does not work, set
+   * it to /
+   */
+  wd = getenv("PWD");
+  if (wd == NULL) {
+    wd = malloc(5);
+    strcpy(wd, "/");
+  }
+  if (chdir(wd) != 0) {
+    DBG(5, sprintf(output, "%schdir: errno %d\n", output, errno));
+    my_perror(wd);
+    my_errno = errno;
+    last_ret_val = errno;
+    return SUCCESS;
+  }
+
+  DBG(3, sprintf(output, "Your current working directory is %s\n", wd));
+  last_ret_val = 0;
+  return SUCCESS;
+}
+
+
+int sysio_list(char *path)
+{
+  int  fd;
+  size_t       n;
+  struct dirent *buf, *dp;
+  __off_t      base;
+  ssize_t      cc;
+  int numfiles = 0;
+
+  fd = open(path, O_RDONLY);
+  if (fd < 0) {
+    my_errno = errno;
+    last_ret_val = fd;
+    my_perror(path);
+    return SUCCESS;
+  }
+  
+  n = 16 * 1024;
+  buf = malloc(n);
+  if (!buf) {
+    my_perror(path);
+    cc = -1;
+    goto out;
+  }
+  base = 0;
+  DBG(5, sprintf(output, "About to call getdirentries\n"));
+  while ((cc = getdirentries(fd, (char *)buf, n, &base)) > 0) {
+    dp = buf;
+    while (cc > 0) {
+      DBG(4, fprintf(outfp, "\t%s: ino %#08x off %#08x type %#08x\n",
+                    dp->d_name,
+                    (unsigned int)dp->d_ino,
+                    (unsigned int)dp->d_off,
+                    (int )dp->d_type));
+      
+      sprintf(output, "%s\n", dp->d_name);
+      cc -= dp->d_reclen;
+      dp = (struct dirent *)((char *)dp + dp->d_reclen);
+      numfiles++;
+    }
+    printf("Out of inner loop\n");
+    if (!base)
+      break;
+  }
+
+ out:
+  if (cc < 0) {
+    DBG(2, sprintf(output, "cc barfed\n"));
+    my_perror(path);
+  }
+  
+  free(buf);
+  {
+    int        oerrno = errno;
+    
+    if (close(fd) != 0) {
+      DBG(2,sprintf(output, "close barfed\n"));
+      my_perror(path);
+      if (cc < 0)
+       errno = oerrno;
+      else
+       cc = -1;
+    }
+  }
+
+  last_ret_val = numfiles;
+  my_errno = errno;
+
+  return SUCCESS;
+}
+
+int sysio_mount(char *from, char *to)
+{
+  int  err;
+  char *s;
+  char *buf;
+  char *cp;
+  char *fstype, *source, *opts, *target;
+
+  err = 0;
+
+  /*
+   * Copy everything to a buffer we can modify.
+   */
+  s = buf = malloc(strlen(from) + 1);
+  if (!buf) {
+    my_perror(from);
+    last_ret_val = -1;
+    my_errno = errno;
+    return SUCCESS;
+  }
+  (void )strcpy(s, from);
+  
+  /*
+   * Eat leading white.
+   */
+   while (*s && *s == ' ' && *s == '\t')
+     s++;
+  /*
+   * Get fstype.
+   */
+   fstype = cp = s;
+   while (*cp && *cp != ':' && *cp != ' ' && *cp != '\t')
+     cp++;
+   if (fstype == cp || *cp != ':') {
+     DBG(1, sprintf(output, "%s: Missing FS type\n", from));
+     err = -1;
+     goto out;
+   }
+  *cp++ = '\0';
+
+  s = cp;
+  /*
+   * Eat leading white.
+   */
+   while (*s && *s == ' ' && *s == '\t')
+     s++;
+  /*
+   * Get source.
+   */
+   source = cp = s;
+   while (*cp && *cp != ' ' && *cp != '\t')
+     cp++;
+   if (source == cp) {
+     DBG(1, sprintf(output, "%s: Missing source\n", from));
+     err = -1;
+     goto out;
+   }
+   if (*cp)
+     *cp++ = '\0';
+
+   s = to;
+   /*
+    * Eat leading white.
+    */
+    while (*s && *s == ' ' && *s == '\t')
+      s++;
+   /*
+    * Get opts.
+    */
+    opts = cp = s;
+    while (*cp && *cp != ' ' && *cp != '\t')
+      cp++;
+    if (opts == cp) {
+      DBG(1,sprintf(output, "%s: Missing target\n", to));
+      err = -1;
+      goto out;
+    }
+    if (*cp)
+      *cp++ = '\0';
+
+    s = cp;
+    /*
+     * Eat leading white.
+     */
+     while (*s && *s == ' ' && *s == '\t')
+       s++;
+    /*
+     * Get target
+     */
+     target = cp = s;
+     while (*cp && *cp != ' ' && *cp != '\t')
+       cp++;
+     if (target == cp) {
+       target = opts;
+       opts = NULL;
+     }
+     if (*cp)
+       *cp++ = '\0';
+
+     err = mount(source, target, fstype, 0, opts);
+     if (err)
+       my_perror(from);
+
+out:
+     free(buf);
+     last_ret_val = err;
+     my_errno = errno;
+     return SUCCESS;
+}
+
+int sysio_chdir(char *newdir) 
+{
+
+  if (chdir(newdir) != 0) {
+    my_perror(newdir);
+    return -1;
+  }
+  /*  
+  buf = getcwd(NULL, 0);
+  if (!buf) {
+    my_perror(newdir);
+    last_ret_val = -1;
+    my_errno = errno;
+    return SUCCESS;
+  }
+  DBG(4, sprintf(output, "New dir is %s\n", buf));
+
+  free(buf);
+  */
+  return SUCCESS;
+}
+
+static mode_t get_mode(char *arg, int type, int start_mode);
+
+#define SYMBOLIC 0
+#define DEFINED  1
+#define NUMERIC  2 
+/*
+ * Change the permissions on a given file
+ *
+ * sysio_chmod <filename> <permissions>
+ *
+ */
+int sysio_chmod(char *mode_arg, const char *path) 
+{
+  int  err;
+  mode_t mode;
+  struct stat st;
+
+  /* Get the current mode */
+  err = stat(path, &st);
+
+  /* Is the new mode symbolic? */
+  if (isalpha(mode_arg[0])) {
+    /* Could be specifying defines */
+    if (mode_arg[0] == 'S')
+      mode = get_mode(mode_arg, DEFINED, st.st_mode);
+    else
+      mode = get_mode(mode_arg, SYMBOLIC, st.st_mode);
+  } else 
+    mode = get_mode(mode_arg, NUMERIC, st.st_mode);
+  DBG(3,sprintf(output, "Using a mode of %o and a file of %s\n", mode, path));
+
+  if (mode == 0) {
+    DBG(2,sprintf(output, "Invalid mode\n"));
+    return INVALID_ARGS;
+  }
+
+  last_ret_val = chmod(path, mode);
+  my_errno = errno;
+  return SUCCESS;
+  
+}
+
+
+#define USER_STATE 0 /* Specifies that the users are still being listed */
+#define MODE_STATE_ADD 1 
+#define MODE_STATE_REMOVE 2 
+       
+#define READ    00444
+#define WRITE   00222
+#define EXECUTE 00111
+
+#define OWNER  00700
+#define GROUP  00070
+#define OTHER  00007
+
+  
+mode_t
+get_mode(char *arg, int type, int start_mode) 
+{
+  int i, j,digit, total;
+  char c;
+  int state = USER_STATE;
+  int len = strlen(arg);
+  unsigned int users = 0;
+  unsigned int modes = 0;
+
+
+  if (type == DEFINED) {
+    char curr_word[10];
+
+    total = digit = 0;
+    j = 0;
+    DBG(4, sprintf(output, "len is %d\n", len));
+    for (i=0; i < len; i++) {
+      if (arg[i] == '|') {
+       curr_word[j] = '\0';
+       DBG(3, sprintf(output, "Got mode word %s\n", curr_word));
+       digit = get_obj(curr_word);
+       if (digit < 0 ) {
+         DBG(2, sprintf(output, "Unable to understand mode arg %s\n",
+                        curr_word));
+         return -1;
+       } 
+       total |= digit;
+       j = 0;
+      } else 
+       curr_word[j++] = arg[i];
+    }
+    curr_word[j] = '\0';
+    DBG(3, sprintf(output, "Got mode word %s\n", curr_word));
+    digit = get_obj(curr_word);
+    if (digit < 0 ) {
+      DBG(3, sprintf(output, "Unable to understand mode arg %s\n",
+            curr_word));
+      return -1;
+    } 
+    total |= digit;
+    return total;
+  }
+      
+  if (type == SYMBOLIC) {
+    for (i=0; i < len; i++) {
+      c = arg[i];
+      if (state == USER_STATE) {
+       switch(c){
+       case 'u':
+         users |= OWNER;
+         break;
+       case 'g':
+         users |= GROUP;
+         break;
+       case 'o':
+         users |= OTHER;
+         break;
+       case 'a':
+         users |= (OWNER|GROUP|OTHER);
+         break;
+       case '+':
+         state = MODE_STATE_ADD;
+         break;
+       case '-':
+         state = MODE_STATE_REMOVE;
+         break;
+       default:
+         return 0;
+       }
+      } else {
+
+       switch(c){
+       case 'r':
+         modes |= READ;
+         break;
+       case 'w':
+         modes |= WRITE;
+         break;
+       case 'x':
+         modes |= EXECUTE;
+         break;
+       default:
+         return 0;
+       }
+      }
+    }
+
+    if (state == MODE_STATE_ADD) {
+      return (start_mode | (users & modes));
+    } else {
+      return (start_mode & ~(users & modes));
+    }
+
+  } else {
+    /* Digits should be octal digits, so should convert */
+    total = 0;
+    for (i=0; i < len; i++) {
+      c = arg[i];
+      digit = atoi(&c);
+      if (digit > 7)
+       return 0;
+      for (j=len-i-1; j >0; j--)
+       digit *= 8;
+      total += digit;
+    }
+    return total;
+  }
+}
+
+/*
+ * Changes the ownership of the file.  The new_id
+ * is of the format owner:group.  Either the owner
+ * or the group may be omitted, but, in order to 
+ * change the group, the : must preced the group.
+ */
+int sysio_chown(char *new_id, char *file)
+{
+  char *owner = NULL;
+  char *group = NULL;
+  uid_t o_id=-1, g_id=-1;
+  int len, j, i=0;
+  int state = 0; /* Correspond to getting owner name */
+  
+  len = strlen(new_id);
+  for (i=0; i < len; i++) {
+
+    if (new_id[i] == ':') {
+      /* Group name */
+      if (!group) 
+                               group = malloc(strlen(new_id) -i +2);
+      state = 1; /* Now getting group name */
+      j = 0;
+      if (owner)
+                               owner[i] = '\0';
+    }
+               
+    if (!state) {
+      /* Getting owner name */
+      if (!owner)
+                               owner = malloc(strlen(new_id) +1 ); 
+      owner[i] = new_id[i];
+    } else {
+      /* Group name */
+      group[j] = new_id[i];
+      j++;
+    }
+  }
+  if (group)
+    group[i] = '\0';
+  else
+    owner[i] = '\0';
+
+  /* Are the owner and/or group symbolic or numeric? */
+  if (owner) {
+    if (isdigit(owner[0])) {
+      /* Numeric -- just convert */
+      o_id = (uid_t) atoi(owner);
+
+               } else {
+      /* No longer support non-numeric ids */
+                       
+                       DBG(2, sprintf(output, "Error: non-numeric ids unsupported\n"));
+                       return INVALID_ARGS;
+    }
+  }
+
+
+
+  if (group) {
+    if (isdigit(group[0])) {
+      /* Numeric -- just convert */
+      g_id = (uid_t) atoi(group);
+               } else {
+      /* Don't support group names either */
+                       DBG(2, sprintf(output, "Error: non-numeric ids unsupported\n"));
+                       return INVALID_ARGS;
+    }
+  }
+
+  /* Now issue the syscall */
+  DBG(4, sprintf(output, "Changing owner of file %s to %d (group %d)\n",
+                file, o_id, g_id));
+  last_ret_val = chown(file, o_id, g_id);
+  my_errno = errno;
+  return SUCCESS;
+}
+
+int sysio_open(char *path, int flags)
+{
+  last_ret_val = open(path, flags);
+  my_errno = errno;
+  DBG(3, sprintf(output, "Returning with errno set to %s (ret val is %d)\n", 
+                strerror(my_errno), (int)last_ret_val));
+  return SUCCESS;
+}
+
+int sysio_open3(char *path, int flags, char *mode_arg)
+{
+  mode_t mode;
+
+  /* Is the new mode symbolic? */
+  if (isalpha(mode_arg[0])) {
+    /* Could be specifying defines */
+    if (mode_arg[0] == 'S')
+      mode = get_mode(mode_arg, DEFINED, 0);
+    else
+      mode = get_mode(mode_arg, SYMBOLIC, 0);
+  } else 
+    mode = get_mode(mode_arg, NUMERIC, 0);
+  
+  last_ret_val = open(path, flags, mode);
+  my_errno = errno;
+  
+  return SUCCESS;
+}
+
+int sysio_close(int fd)
+{
+
+  last_ret_val = close(fd);
+  my_errno = errno;
+  return SUCCESS;
+}
+
+int sysio_fcntl(int fd, struct cmd_map* cmdptr, char *arg)
+{
+  int fd_new, index, cmd, flag;
+  char *cmdname;
+  void *buf;
+
+  cmd = cmdptr->cmd;
+  cmdname = cmdptr->cmd_name;
+
+  switch(cmd) {
+  case F_DUPFD:
+    fd_new = get_obj(arg);
+    last_ret_val = fcntl(fd, F_DUPFD, fd_new);
+    my_errno = errno;
+    return SUCCESS;
+    break;
+
+  case F_GETFD:
+  case F_GETFL:
+  case F_GETOWN:
+    /* case F_GETSIG:
+       case F_GETLEASE: */
+
+    last_ret_val= fcntl(fd, cmd);
+    my_errno = errno;
+    return SUCCESS;
+    break;
+
+  case F_SETFD:    
+  case F_SETFL:
+  case F_SETOWN:
+    /*case F_SETSIG:
+    case F_SETLEASE:
+    case F_NOTIFY: */
+    flag = atoi(arg);
+    last_ret_val =  fcntl(fd, cmd, flag);
+    my_errno = errno;
+    return SUCCESS;
+    break;
+
+  case F_SETLK:
+  case F_SETLKW:
+  case F_GETLK:
+  
+     /* Get the buffer to hold the lock structure */
+     index = get_obj(arg);
+     if (index < 0) {
+       sprintf(output, "Unable to find buffer %s\n", arg+1);
+       return INVALID_VAR;
+     }
+
+     buf = buflist[index];
+     if (!buf) {
+       sprintf(output, "Buffer at index %d (mapped by %s) is null\n",
+             index, arg);
+       return INVALID_VAR;
+     }
+
+     last_ret_val = fcntl(fd, cmd, (struct flock *)buf);
+     my_errno = errno;
+    return SUCCESS;
+  default:
+    /* THis should be impossible */
+    return INVALID_ARGS;
+  }
+
+  return INVALID_ARGS;
+}
+
+void print_stat(struct stat *st)
+{
+  DBG(3, sprintf(output, "%sstruct stat: \n", output));
+  DBG(3, sprintf(output, "%s  st_dev: %#16x\n", output, (unsigned int)st->st_dev));
+  DBG(3, sprintf(output, "%s  st_ino: %#16x\n", output, (unsigned int) st->st_ino));
+  DBG(3, sprintf(output, "%s  st_mode: %#16x\n", output, st->st_mode));
+  DBG(3, sprintf(output, "%s  st_nlink: %#16x\n", output, (int)st->st_nlink));
+  DBG(3, sprintf(output, "%s  st_uid: %#16x\n", output, st->st_uid));
+  DBG(3, sprintf(output, "%s  st_gid: %#16x\n", output, st->st_gid));
+  DBG(3, sprintf(output, "%s  st_rdev: %#16x\n", output, (int)st->st_rdev));
+  DBG(3, sprintf(output, "%s  st_size: %#16x\n", output, (int) st->st_size));
+  DBG(3, sprintf(output, "%s  st_blksize: %#16x\n", output, (int) st->st_blksize));
+  DBG(3, sprintf(output, "%s  st_blocks: %#16x\n", output, (int) st->st_blocks));
+  DBG(3, sprintf(output, "%s  st_atime: %#16x\n", output, (unsigned int) st->st_atime));
+  DBG(3, sprintf(output, "%s  st_mtime: %#16x\n", output, (unsigned int) st->st_mtime));
+  DBG(3, sprintf(output, "%s  st_ctime: %#16x", output, (unsigned int) st->st_ctime));
+}
+
+int sysio_fstat(int fd, void *buf)
+{
+  int err;
+  struct stat *st = (struct stat *)buf;
+  err = fstat(fd, st); 
+  if (err < 0) {
+    my_perror("fstat");
+  }
+  my_errno = errno;
+  last_ret_val = err;
+  print_stat(st);
+
+  return SUCCESS;
+}
+
+int sysio_lstat(char *filename, void *buf)
+{
+  int err;
+  struct stat *st = (struct stat *)buf;
+  err = lstat(filename, st); 
+  if (err < 0) {
+    my_perror("lstat");
+  }
+
+  my_errno = errno;
+  last_ret_val = err;
+  print_stat(st);
+  return SUCCESS;
+}
+
+
+int sysio_stat(char *filename, void *buf)
+{
+  int err;
+  struct stat *st = (struct stat *)buf;
+
+  err = stat(filename, st); 
+  if (err < 0) {
+    my_perror("stat");
+  }
+
+  my_errno = errno;
+  last_ret_val = err;
+  print_stat(st);
+  return SUCCESS;
+}
+
+
+int sysio_getdirentries(int fd, char *buf, size_t nbytes, off_t *basep)
+{
+  int err;
+  struct dirent *dp;
+
+  err = getdirentries(fd, buf, nbytes, basep); 
+  last_ret_val = err;
+  DBG(4, sprintf(output, "%sRead %d bytes\n", output, err));
+
+  dp = (struct dirent *)buf;
+  while (err > 0) {
+      DBG(3, sprintf(output, "%s\t%s: ino %llu off %llu len %x type %c\n",
+                    output,
+                    dp->d_name,
+                    (unsigned long long )dp->d_ino,
+                    (unsigned long long )dp->d_off,
+                    dp->d_reclen,
+                   (char )dp->d_type));
+      err -= dp->d_reclen;
+      dp = (struct dirent *)((char *)dp + dp->d_reclen);
+  }
+
+  my_errno = errno;
+  return last_ret_val;
+}
+
+
+int sysio_mkdir(char *path, char *mode_arg) 
+{
+  int  err;
+  mode_t mode;
+  struct stat st;
+
+  /* Is the new mode symbolic? */
+  if (isalpha(mode_arg[0])) {
+    /* Could be specifying defines */
+    if (mode_arg[0] == 'S')
+      mode = get_mode(mode_arg, DEFINED, st.st_mode);
+    else
+      mode = get_mode(mode_arg, SYMBOLIC, st.st_mode);
+  } else 
+    mode = get_mode(mode_arg, NUMERIC, st.st_mode);
+
+  DBG(3, sprintf(output, "Using a mode of %o and a file of %s\n", mode, path));
+
+  if (mode == 0) {
+    DBG(2, sprintf(output, "Invalid mode\n"));
+    return INVALID_ARGS;
+  }
+
+  err = mkdir(path, mode);
+  my_errno = errno;
+  last_ret_val = err;
+  return SUCCESS;
+  
+}
+
+int sysio_creat(char *path, char *mode_arg) 
+{
+  mode_t mode;
+  int err;
+
+  /* Is the new mode symbolic? */
+  if (isalpha(mode_arg[0])) {
+    /* Could be specifying defines */
+    if (mode_arg[0] == 'S')
+      mode = get_mode(mode_arg, DEFINED, 0);
+    else
+      mode = get_mode(mode_arg, SYMBOLIC, 0);
+  } else 
+    mode = get_mode(mode_arg, NUMERIC, 0);
+
+  DBG(3, sprintf(output, "Using a mode of %o and a file of %s\n", mode, path));
+
+  if (mode == 0) {
+    DBG(2, sprintf(output, "Invalid mode\n"));
+    return INVALID_ARGS;
+  }
+
+  err = creat(path, mode);
+  my_errno = errno;
+  last_ret_val = err;
+  return SUCCESS;
+}
+
+void print_statvfs(struct statvfs *st)
+{
+  DBG(3, sprintf(output, "%sstruct statvfs: \n", output));
+  DBG(3, sprintf(output, "%s  f_bsize: %x\n", output, (unsigned int) st->f_bsize));
+  DBG(3, sprintf(output, "%s  f_frsize: %x\n", output, (unsigned int) st->f_frsize));
+  DBG(3, sprintf(output, "%s  f_blocks: %x\n", output, (unsigned int) st->f_blocks));
+  DBG(3, sprintf(output, "%s  f_bfree: %x\n", output, (unsigned int) st->f_bfree));
+  DBG(3, sprintf(output, "%s  f_bavail: %x\n", output, (unsigned int) st->f_bavail));
+  DBG(3, sprintf(output, "%s  f_files: %x\n", output, (unsigned int) st->f_files));
+  DBG(3, sprintf(output, "%s  f_ffree: %x\n", output, (unsigned int) st->f_ffree));
+  DBG(3, sprintf(output, "%s  f_favail: %x\n", output, (unsigned int) st->f_favail));
+  DBG(3, sprintf(output, "%s  f_files: %x\n", output, (unsigned int) st->f_files));
+#if (__GLIBC__  == 2 && __GLIBC_MINOR__ == 1)
+  DBG(3, sprintf(output, "%s  f_fsid: %x\n", output, (unsigned int) st->f_fsid.__val[1]));
+#else
+ DBG(3, sprintf(output, "%s  f_fsid: %x\n", output, (unsigned int) st->f_fsid));
+#endif
+  DBG(3, sprintf(output, "%s  f_flag: %x\n", output, (unsigned int) st->f_flag));
+  DBG(3, sprintf(output, "%s  f_fnamemax: %x\n", output, (unsigned int) st->f_namemax));
+}
+
+
+int sysio_statvfs(char *filename, void *buf)
+{
+  int err;
+  struct statvfs *st = (struct statvfs *)buf;
+  
+  err = statvfs(filename, st); 
+  if ( err == -1) { 
+    my_perror("statvfs");
+  }
+
+  my_errno = errno;
+  last_ret_val = err;
+
+  print_statvfs(st);
+  return SUCCESS;
+}
+
+int sysio_fstatvfs(int fd, void *buf)
+{
+  int err;
+  struct statvfs *st = (struct statvfs *)buf;
+
+  err = fstatvfs(fd, st);
+  if (err == -1) { 
+    my_perror("fstatvfs");
+  }
+
+  my_errno = errno;
+  last_ret_val = err;
+
+  print_statvfs(st);
+  return SUCCESS;
+}
+
+int sysio_umask(char *mode_arg)
+{
+  mode_t mode;
+
+   /* Is the new mode symbolic? */
+  if (isalpha(mode_arg[0])) {
+    /* Could be specifying defines */
+    if (mode_arg[0] == 'S')
+      mode = get_mode(mode_arg, DEFINED, 0);
+    else
+      mode = get_mode(mode_arg, SYMBOLIC, 0);
+  } else 
+    mode = get_mode(mode_arg, NUMERIC, 0);
+
+  last_ret_val = umask(mode);
+  my_errno = errno;
+  return SUCCESS;
+}
+
+int sysio_mknod(char *path, char *mode_arg, dev_t dev)
+{
+  int err;
+  int mode;
+
+  mode = get_obj(mode_arg);
+  
+  if (mode < 0) {
+    DBG(2,sprintf(output, "Cant get mode from %s\n", mode_arg));
+    fprintf(stderr, "Cant get mode from %s\n", mode_arg);
+    return INVALID_VAR;
+  }
+
+  err = mknod(path, (mode_t) mode, dev);
+  if (err < 0)
+    my_perror("mknod");
+
+  last_ret_val = err;
+  my_errno = errno;
+  return SUCCESS;
+}
diff --git a/libsysio/tests/test.h b/libsysio/tests/test.h
new file mode 100644 (file)
index 0000000..3357802
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+extern int (*drvinits[])(void);
+
+extern int drv_init_all(void);
diff --git a/libsysio/tests/test_all.pl b/libsysio/tests/test_all.pl
new file mode 100755 (executable)
index 0000000..25586ba
--- /dev/null
@@ -0,0 +1,220 @@
+#!/usr/bin/perl -w
+
+#
+# VERY basic functionality test for sysio.  To run, just type ./test_all.pl
+# Absolutely no guarantees for running on alpha/cplant 
+#
+
+use strict;
+use FindBin;
+
+use Cwd 'abs_path';        
+
+my $alpha_arg = "";
+my $use_system = 1;
+my $is_broke = 1; # Don't test certain areas known to not work on Cplant
+my $arg_count = @ARGV;
+foreach my $arg (@ARGV) {
+    if ($arg eq "-alpha") {
+                       $alpha_arg = "-alpha";
+    } elsif ($arg eq "-nosystem") {
+                       $use_system = 0;
+    }
+}
+my $alpha_env = $ENV{"IS_ALPHA"};
+# Check the environment vars
+if (defined($alpha_env) && ($alpha_env eq "yes")) {
+    $alpha_arg = "-alpha";
+}
+
+my $failures = 0;
+my $success = 0;
+# Get cwd..
+my $cwd = $ENV{PWD};
+
+# Get tests directory
+my $testdir = $FindBin::Bin;
+
+my $namespace_env = "SYSIO_NAMESPACE";
+my $home = $ENV{"HOME"};
+my $auto_mount = $ENV{"SYSIO_AUTOMOUNT"};
+my $root_flags = "0";
+my $extras = "";
+if ((defined($auto_mount)) && ($auto_mount == "xyes")) {
+       $root_flags = "2";
+
+       #
+       # Add a /auto directory for automounted file systems. We
+       # craft one automount that mounts /usr/home from the native
+       # file system. Further automounts in the sub-mounts are not enabled.
+       #
+       $extras=" \
+               {mnt,   dev=\"incore:0755+0+0\",dir=\"/mnt\",fl=2} \
+               {creat, ft=dir,nm=\"/mnt/home\",pm=0755,ow=0,gr=0} \
+               {creat, ft=file,nm=\"/mnt/home/.mount\",pm=0600, \
+                       str=\"native:/usr/home\"}";
+}
+$ENV{$namespace_env} = "\
+       {mnt,   dev=\"native:/\",dir=/,fl=$root_flags} \
+       {mnt,   dev=\"incore:0755+0+0\",dir=\"/dev\"} \
+       {creat, ft=chr,nm=\"/dev/stdin\",pm=0400,mm=0+0} \
+       {creat, ft=chr,nm=\"/dev/stdout\",pm=0200,mm=0+1} \
+       {creat, ft=chr,nm=\"/dev/stderr\",pm=0200,mm=0+2} \
+       {creat, ft=dir,nm=\"/dev/fd\",pm=0755,ow=0,gr=0} \
+       {creat, ft=chr,nm=\"/dev/fd/0\",pm=0400,mm=0+0} \
+       {creat, ft=chr,nm=\"/dev/fd/1\",pm=0200,mm=0+1} \
+       {creat, ft=chr,nm=\"/dev/fd/2\",pm=0200,mm=0+2} \
+       {cd,    dir=\"$home\"} \
+       $extras ";
+
+my $res;
+
+if ($use_system == 1) {
+  # Will use this directory...
+  system("mkdir -p $cwd/tmp_dir");
+
+  # Create a couple of files and subdirectories for use in the tests
+  system("mkdir -p $cwd/tmp_dir/test1");
+  system("mkdir -p $cwd/tmp_dir/test2");
+
+  system("cp $testdir/helper.pm $cwd/tmp_dir/test1");
+} else {
+    $res = `perl $testdir/setup.pl $alpha_arg $cwd`;
+    chop($res);
+    if ($res ne "setup successful") {
+                       print "Test setup failed with $res, bailing out\n";
+                       exit 1;
+    }
+}
+
+
+if (($alpha_arg eq "") || ($is_broke == 0)) {
+    # Test getdirentries
+    $res = `perl $testdir/test_list.pl $alpha_arg $cwd/tmp_dir`;
+    chop($res);
+    if ($res ne "list test successful") {
+                       print "Basic getdirentries test failed with message: $res\n";
+                       $failures++;
+    } else {
+                       print "test_list finished successfully\n";
+                       $success++;
+    }
+}
+
+# Test path
+my $path1 = abs_path($testdir);
+my @resarr = `perl $testdir/test_path.pl $alpha_arg $path1 $cwd $cwd/tmp_dir`;
+$res = $path1.": d\n";
+if ($resarr[0] ne $res) {
+    print "path test returned $resarr[0] instead of $res\n";
+    $failures++;
+} else {
+       $res = $cwd.": d\n";
+       if ($resarr[1] ne $res) {
+               print "path test returned $resarr[1] instead of $res\n";
+               $failures++;
+       } else {
+               $res = $cwd."/tmp_dir: d\n";
+               if ($resarr[2] ne $res) {
+           print "path test returned $resarr[2] instead of $res\n";
+           $failures++;
+               } else {
+           print "test_path finished successfully\n";
+           $success++;
+               }
+       }
+}
+
+# Test getcwd
+$res = `perl $testdir/test_getcwd.pl $alpha_arg $cwd/tmp_dir/test1`;
+chop($res);
+if ($res ne "getcwd test successful") {
+    print "getcwd test failed with message: $res\n";
+    $failures++;
+} else {
+    $success++;
+    print "test_getcwd finished successfully\n";
+}
+
+# Test copy
+$res = `perl $testdir/test_copy.pl $alpha_arg $cwd/tmp_dir/test1/helper.pm $cwd/tmp_dir/helper.pm`;
+chop($res);
+if ($res ne "copy test successful") {
+  print "copy test failed with message: $res\n";
+  $failures++;
+} else {
+  $success++;
+  print "test_copy finished successfully\n";
+}
+
+# Test stats
+$res = `perl $testdir/test_stats.pl $alpha_arg $use_system $cwd/tmp_dir/test1/helper.pm`;
+chop($res);
+if ($res ne "stat test successful") {
+  print "stat test failed with message: $res\n";
+  $failures++;
+} else {
+  $success++;
+  print "test_stats finished successfully\n";
+}
+
+# Test stdfd
+$res = `echo "foobar" | perl $testdir/test_copy.pl $alpha_arg -o /dev/stdin /dev/stdout`;
+chop($res);
+if ($res ne "copy test successful") {
+  print "stdfd test failed with message: $res\n";
+  $failures++;
+} else {
+  $success++;
+  print "test_stdfd finished successfully\n";
+}
+
+# Test symlink
+$res = `perl $testdir/test_symlink.pl $alpha_arg $cwd/tmp_dir/test1/helper.pm $cwd/tmp_dir/helper.foo`;
+chop($res);
+if ($res ne "Symlink test successful") {
+  print "symlink test failed with message: $res\n";
+  $failures++;
+} else {
+  $success++;
+  print "test_symlink finished successfully\n";
+}
+
+# Test r/w calls
+$res = `perl $testdir/test_rw.pl $alpha_arg $cwd/tmp_dir/tmp.foo`;
+chop($res);
+if ($res ne "rw test successful") {
+  print "rw test failed with message: $res\n";
+  $failures++;
+} else {
+  $success++;
+  print "rw test finished successfully\n";
+}
+
+# Test strided I/O
+$res = `perl $testdir/test_strided.pl $alpha_arg $cwd/tmp_dir/tmp2.foo`;
+chop($res);
+if ($res ne "strided IO test successful") {
+  print "strided IO test failed with message: $res\n";
+  $failures++;
+} else {
+  $success++;
+  print "strided IO test finished successfully\n";
+}
+
+print "$failures tests failed and $success tests succeeded\n";
+
+# cleanup -- only if no failures
+if ($failures == 0) {
+       if ($use_system == 1) {
+    system(`rm -rf $cwd/tmp_dir`);
+       } else {
+    $res = `perl $testdir/cleanup.pl $alpha_arg $cwd`;
+    chop($res);
+    if ($res ne "cleanup successful") {
+                       print "Test cleanup failed with $res, bailing out\n";
+                       exit 1;
+    }   
+       }
+}
+exit $failures;
diff --git a/libsysio/tests/test_copy.bash b/libsysio/tests/test_copy.bash
new file mode 100644 (file)
index 0000000..7217ba0
--- /dev/null
@@ -0,0 +1,129 @@
+#!/bin/bash
+#############################################################################
+#
+#     This Cplant(TM) source code is the property of Sandia National
+#     Laboratories.
+#
+#     This Cplant(TM) source code is copyrighted by Sandia National
+#     Laboratories.
+#
+#     The redistribution of this Cplant(TM) source code is subject to the
+#     terms of the GNU Lesser General Public License
+#     (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+#
+#     Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+#     Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+#     license for use of this work by or on behalf of the US Government.
+#     Export of this program may require a license from the United States
+#     Government.
+#
+#############################################################################
+
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+# 
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+# 
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# Questions or comments about this library should be sent to:
+#
+# Lee Ward
+# Sandia National Laboratories, New Mexico
+# P.O. Box 5800
+# Albuquerque, NM 87185-1110
+#
+# lee@sandia.gov
+
+############################################################################
+#
+#   File:  test_copy.bash
+#
+#   Description:  Script to exercise the sysio library.
+#
+#   Usage:  
+#   test_copy.bash 
+# 
+#   Limitations:
+#   1.  Doesn't exercise all of sysio.
+#   2.  Uses hardcoded /native prefix for file names which may not be the
+#       final solution.
+#
+############################################################################
+
+# defaults - change as necessary for local system
+SCRATCH=test_copy.$$
+CWD=`pwd`
+SRC=${CWD}/test_copy.src
+DEST=${CWD}/test_copy.dest
+PREFIX=/native
+
+# main processing logic follows
+cp /dev/null $SCRATCH
+rm -f $SRC $DEST
+if [ -f $SRC ] 
+then 
+  echo "Could not remove $SRC - test INDETERMINATE" >> $SCRATCH
+  exit 5
+fi
+if [ -f $DEST ] 
+then 
+  echo "Could not remove $DEST - test INDETERMINATE" >> $SCRATCH
+  exit 5
+fi
+
+if ( ! cp /usr/include/stdio.h $SRC )  # just picked something handy
+then
+  echo "Could not create source file - test INDETERMINATE" >> $SCRATCH
+  exit 5
+fi
+
+
+#
+#  Run the test
+#
+./test_copy ${PREFIX}/${SRC} ${PREFIX}/${DEST}
+SRC_VERF=`cksum $SRC | awk '{ print $1 }'`
+DEST_VERF=`cksum $DEST | awk '{ print $1 }'`
+if [ "$SRC_VERF" -ne "$DEST_VERF" ]
+then
+    echo "The source and destination files did not match; test FAILED" >> $SCRATCH 2>&1
+else
+    echo "The source and destination files matched; test PASSED" >> $SCRATCH 2>&1
+fi
+
+#
+#  Report test results
+#
+echo ""
+PASSCNT=1
+if grep "FAILED" $SCRATCH > /dev/null
+then
+        echo "TEST $0 FAILED - found failed"
+        cat $SCRATCH
+        RC=8
+elif test `grep -c "PASSED" $SCRATCH` -ne $PASSCNT > /dev/null
+then
+        echo "TEST $0 FAILED - wrong pass count"
+        cat $SCRATCH
+        RC=4
+else
+        echo "TEST $0 PASSED"
+        RC=0
+
+fi
+
+if [ -z "$NOCLEANUP" ]
+then
+  rm -f $SCRATCH $SRC $DEST
+fi
+
+exit $RC
diff --git a/libsysio/tests/test_copy.c b/libsysio/tests/test_copy.c
new file mode 100644 (file)
index 0000000..bda0bd2
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#define _BSD_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#ifndef REDSTORM
+#include <getopt.h>
+#endif
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "mount.h"
+
+#include "fs_native.h"
+
+#include "test.h"
+
+/*
+ * Copy one file to another.
+ *
+ * Usage: test_copy [-o] <src> <dest>
+ *
+ * Destination will not be overwritten if it already exist.
+ */
+
+static int overwrite = 0;                              /* over-write? */
+
+void   usage(void);
+int    copy_file(const char *spath, const char *dpath);
+
+int
+main(int argc, char * const argv[])
+{
+       int     i;
+       int     err;
+       const char *spath, *dpath;
+       extern int _test_sysio_startup(void);
+
+       /*
+        * Parse command-line args.
+        */
+       while ((i = getopt(argc,
+                          argv,
+                          "o"
+                          )) != -1)
+               switch (i) {
+
+               case 'o':
+                       overwrite = 1;
+                       break;
+               default:
+                       usage();
+               }
+
+       if (!(argc - optind))
+               usage();
+       err = _test_sysio_startup();
+       if (err) {
+               errno = -err;
+               perror("sysio startup");
+               exit(1);
+       }
+
+       /*
+        * Source
+        */
+       spath = argv[optind++];
+       if (!(argc - optind))
+               usage();
+       /*
+        * Destination
+        */
+       dpath = argv[optind++];
+       if (argc - optind)
+               usage();
+
+       err = copy_file(spath, dpath);
+
+       _sysio_shutdown();
+
+       return err;
+}
+
+void
+usage()
+{
+
+       (void )fprintf(stderr,
+                      "Usage: test_copy "
+                      " source destination\n");
+       exit(1);
+}
+
+int
+open_file(const char *path, int flags, mode_t mode)
+{
+       int     fd;
+
+       fd = open(path, flags, mode);
+       if (fd < 0)
+               perror(path);
+
+       return fd;
+}
+
+int
+copy_file(const char *spath, const char *dpath)
+{
+       int     sfd, dfd;
+       int     flags;
+       int     rtn;
+       static char buf[1024];
+       ssize_t cc, wcc;
+
+       sfd = dfd = -1;
+       rtn = -1;
+
+       sfd = open_file(spath, O_RDONLY, 0);
+       if (sfd < 0)
+               goto out;
+       flags = O_CREAT|O_WRONLY;
+       if (!overwrite)
+               flags |= O_EXCL;
+       dfd = open_file(dpath, flags, 0666);
+       if (dfd < 0)
+               goto out;
+
+       while ((cc = read(sfd, buf, sizeof(buf))) > 0)
+               if ((wcc = write(dfd, buf, cc)) != cc) {
+                       if (wcc < 0) {
+                               perror(dpath);
+                               break;
+                       }
+                       (void )fprintf(stderr,
+                                      "%s: short write (%u/%u)\n",
+                                      dpath,
+                                      (unsigned )wcc,
+                                      (unsigned )cc);
+                       break;
+               }
+       if (cc < 0)
+               perror(spath);
+
+out:
+       if (sfd >= 0 && close(sfd) != 0)
+               perror(spath);
+       if (dfd >= 0 && (fsync(dfd) != 0 || close(dfd) != 0))
+               perror(dpath);
+
+       return 0;
+}
diff --git a/libsysio/tests/test_copy.pl b/libsysio/tests/test_copy.pl
new file mode 100755 (executable)
index 0000000..6912dcc
--- /dev/null
@@ -0,0 +1,218 @@
+#!/usr/bin/perl -w
+
+#
+# copy test: Copy a file from src to dest and verify that the new file
+#          : is the same as the old
+#
+
+use IPC::Open2;
+
+use strict;
+use FindBin;
+use lib "$FindBin::Bin";
+use helper;
+
+sub usage
+{
+  print "Usage: ./test_copy.pl [-alpha] <src> <dest>: Copy a file from src to dest\n";
+  exit(-1);
+}
+
+sub process_cmd
+{
+  my ($src, $dest, $overwrite, $is_alpha) = @_;
+  
+# Get tests directory
+  my $testdir = $FindBin::Bin;
+
+  eval {
+               if ($is_alpha == 0) {
+                       open2(\*OUTFILE, \*CMDFILE, "$testdir/test_driver --np");
+               } else {
+                       open2(\*OUTFILE, \*CMDFILE, "yod -quiet -sz 1 $testdir/test_driver --np");
+               }
+  };
+
+  if ($@) {
+    if ($@ =~ /^open2/) {
+      warn "open2 failed: $!\n$@\n";
+      return;
+    }
+    die;
+
+  }
+
+  my $outfh = \*OUTFILE;
+  my $cmdfh = \*CMDFILE;
+
+
+
+  if ($is_alpha == 0) {
+    helper::send_cmd($cmdfh, $outfh, "init", "CALL init\n");
+  }
+  
+  # Get the filesize of src
+  my $size = -s $src;
+  my $bufsize;
+
+       # If reading from stdin, just read one line
+       my $line;
+       if ($src eq "/dev/stdin") {
+               $line = <STDIN>;
+               $size = length($line);
+       }
+
+  if ( $size > 1024) { # Arbitrary limit
+    $bufsize = 1024;
+  } else {
+    $bufsize = $size;
+  }
+
+  my $cmdstr;
+  # Open src 
+       if ($src ne "/dev/stdin") {
+               $cmdstr = '$src = CALL open '."$src O_RDONLY\n";
+               helper::send_cmd($cmdfh, $outfh, "open", $cmdstr);
+               helper::verify_cmd($cmdfh, $outfh, "open $src");
+       }
+       if ($dest ne "/dev/stdout") {
+               # Open dest
+               my $flags = "O_WRONLY|O_CREAT";
+               if ($overwrite == 0) {
+                       $flags .= "|O_EXCL";
+               }
+               $cmdstr = '$dest = CALL open '."$dest $flags 0777\n";
+               helper::send_cmd($cmdfh, $outfh, "open", $cmdstr);
+               my $destfile = helper::verify_cmd($cmdfh, $outfh, "open $dest");
+       }
+
+  # Allocate buffer
+  $cmdstr = '$buf = ALLOC '."$bufsize\n";
+  helper::send_cmd($cmdfh, $outfh, "ALLOC", $cmdstr);
+
+  # Read size bytes from src and write them out to dest
+  my $bytes = $size;
+  while ($bytes > 0) {
+
+               my $readb;
+               my $res;
+               if ($src eq "/dev/stdin") {
+                        # Send "delay" option to read which will give us time to 
+                       # put something in stdin (since we can't send an eof)
+                       my $cmdstr = "CALL read ".'0 $buf '."$bytes delay\n";
+                       print $cmdfh $cmdstr;
+                       # Give time to process command
+                       sleep 1;
+
+                       # Send line from stdin
+                       print $cmdfh $line;
+                       sleep 0.5;
+      # Make sure read was OK
+                       $res = <$outfh>;
+                       chop($res);
+                       if ($res ne "0000 ") {
+                               helper::print_and_exit($cmdfh, $outfh, 1, "ERROR! Read failed with code $res\n");
+                       }
+    
+                       # See how many bytes we got...
+                       $readb = helper::verify_cmd($cmdfh, $outfh, "read");
+                       $readb = oct($readb);
+                       if ($readb != $bytes) {
+                               helper::print_and_exit($cmdfh, $outfh, 0, "Short read\n");
+                       }
+
+                       if ($dest eq "/dev/stdout") {
+                               $cmdstr = "CALL write ".'1 $buf '."$readb\n";
+                       } else {
+                               $cmdstr = "CALL write ".'$dest $buf '."$readb\n";
+                       }
+                       print $cmdfh $cmdstr;
+
+                       # Suck up the stdout...
+                       $res = <$outfh>;
+                       chop($res);
+  
+                       $res = <$outfh>;
+                       chop($res);
+                       $res = oct($res);
+
+                       if ($res != 0) {
+                               helper::print_and_exit($cmdfh, $outfh, 1, "ERROR! Write failed with code $res\n");
+                               }
+               } else {
+                       $cmdstr = 'CALL read $src $buf '."$bufsize\n";
+                       helper::send_cmd($cmdfh, $outfh, "read", $cmdstr);
+    
+                       $res = helper::verify_cmd($cmdfh, $outfh, "read");
+                       $readb = oct($res);
+
+                       # Now write $readb back out to dest
+                       $cmdstr = 'CALL write $dest $buf '."$readb\n";
+                       helper::send_cmd($cmdfh, $outfh, "write", $cmdstr);
+    }
+
+    $res = helper::verify_cmd($cmdfh, $outfh, "write");
+
+    if ($readb != oct($res)) {
+      print STDOUT "ERROR!  Read $readb bytes but got back $res bytes\n";
+      exit 1;
+    }
+
+    $bytes -= $readb;
+  } 
+   
+  # Clean up
+       if ($src ne "/dev/stdin") {
+               $cmdstr = 'CALL close $src'."\n";
+               helper::send_cmd($cmdfh, $outfh, "close", $cmdstr);
+       }
+       if ($dest ne "/dev/stdout") {
+               $cmdstr = 'CALL close $dest'."\n";
+               helper::send_cmd($cmdfh, $outfh, "close", $cmdstr);
+       }
+       if ($src ne "/dev/stdin") {
+               my $cmd = "cmp $src $dest " . '2>&1';
+               my $cmpstr = qx($cmd);
+               my $exitval = $? >> 8;
+               if ($exitval != 0) {
+                       if ($exitval == 1) {
+                               print STDOUT "ERROR! File $src differs from $dest\n";
+                               print STDOUT "Comparison returned $cmpstr";
+                       } else {
+                               print STDOUT "ERROR! File comparison failed with msg $cmpstr";
+                       }
+                       exit 1;
+               }
+       }
+  helper::print_and_exit($cmdfh, $outfh, 0, "copy test successful\n");
+}
+
+my $currarg = 0;
+my $is_alpha = 0;
+my $overwrite = 0;
+
+my $len = @ARGV-2;
+
+if (@ARGV < 2) {
+  usage;
+} 
+
+my $i;
+for ($i=0; $i < $len; $i++ ) {
+  if ($ARGV[$i] eq "-alpha") {
+    $is_alpha = 1;
+  }
+       if ($ARGV[$i] eq "-o") {
+               $overwrite = 1;
+       }
+}
+
+my $src = $ARGV[$i++];
+my $dest = $ARGV[$i];
+
+
+process_cmd($src, $dest, $overwrite, $is_alpha);
+
+
+exit 0;
diff --git a/libsysio/tests/test_driver.c b/libsysio/tests/test_driver.c
new file mode 100644 (file)
index 0000000..943cd85
--- /dev/null
@@ -0,0 +1,1085 @@
+#define _BSD_SOURCE
+#define _XOPEN_SOURCE 600
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <sys/statvfs.h>
+#include <fcntl.h>
+#include <sys/queue.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include "sysio.h"
+#include "mount.h"
+#include "test.h"
+#include "test_driver.h"
+
+
+struct queue_t;
+    
+typedef struct cmd_tree_t {
+  char *res_name;
+  char *val;
+  int arg_count;
+  struct queue_t *children;
+} cmd_tree;
+
+struct queue_t {
+    char *val;
+    cmd_tree *cmd;
+    struct queue_t *next;
+};
+
+struct cmd_t cmd_list[] = {
+  {"alloc", get_buffer, usage_get_buffer},
+  {"chdir", test_do_chdir, usage_chdir},
+  {"checkbuf", do_checkbuf, usage_checkbuf},
+  {"chmod", test_do_chmod, usage_chmod},
+  {"chown", test_do_chown, usage_chown},
+  {"clear", test_do_clear, usage_clear},
+  {"close", test_do_close, usage_close},
+  {"cmpstr", cmp_bufs, usage_cmpbufs},
+  {"creat", test_do_creat, usage_creat},
+  {"debug", test_do_setdebug, usage_setdebug},
+  {"dup", test_do_dup, usage_dup},
+  {"dup2", test_do_dup2, usage_dup2},
+  {"endian", get_endian, usage_endian},
+  {"exit", test_do_exit, usage_exit},
+  {"fcntl", test_do_fcntl, usage_fcntl},
+  {"fdatasync", test_do_fdatasync, usage_fdatasync},
+  {"fill", test_do_fillbuff, usage_do_fillbuff},
+  {"free", free_buffer, usage_free_buffer},
+  {"fstat", test_do_fstat, usage_fstat},
+  {"fstatvfs", test_do_fstatvfs, usage_fstatvfs},
+  {"fsync", test_do_fsync, usage_fsync},
+  {"ftruncate", test_do_ftruncate, usage_ftruncate},
+  {"getcwd", test_do_getcwd, usage_getcwd},
+  {"getdirentries", test_do_getdirentries, usage_getdirentries},
+  {"init", test_do_init, usage_init},
+  {"init_iovec", test_do_init_iovec, usage_init_iovec},
+  {"init_xtvec", test_do_init_xtvec, usage_init_xtvec}, 
+  {"ioctl", test_do_ioctl, usage_ioctl},
+  {"iodone", test_do_iodone, usage_iodone},
+  {"iowait", test_do_iowait, usage_iowait},
+  {"ipread", test_do_ipread, usage_ipread},
+  {"ipreadv", test_do_ipreadv, usage_ipreadv},
+  {"ipwrite", test_do_ipwrite, usage_ipwrite},
+  {"ipwritev", test_do_ipwritev, usage_ipwritev},
+  {"iread", test_do_iread, usage_iread},
+  {"ireadv", test_do_ireadv, usage_ireadv},
+       {"ireadx", test_do_ireadx, usage_ireadx},
+  {"iwrite", test_do_iwrite, usage_iwrite},
+  {"iwritev", test_do_iwritev, usage_iwritev},
+  {"iwritex", test_do_iwritex, usage_iwritex},
+  {"list", test_do_list, usage_list},
+  {"lseek", test_do_lseek, usage_lseek},
+  {"lstat", test_do_lstat, usage_lstat},
+  {"mkdir", test_do_mkdir, usage_mkdir},
+  {"mknod", test_do_mknod, usage_mknod},
+  {"mount", test_do_mount, usage_mount},
+  {"open", test_do_open, usage_open},
+  {"printbuf", test_do_printbuf, usage_do_printbuf},
+  {"printline", test_do_printline, usage_printline},
+  {"pread", test_do_pread, usage_pread},
+  {"preadv", test_do_preadv, usage_preadv},
+  {"pwritev", test_do_pwritev, usage_pwritev},
+  {"pwrite", test_do_pwrite, usage_pwrite},
+  {"quit", test_do_exit, usage_exit},
+  {"read", test_do_read, usage_read},
+  {"readv", test_do_readv, usage_readv},
+       {"readx", test_do_readx, usage_readx},
+  {"rmdir", test_do_rmdir, usage_rmdir},
+  {"setbuf", do_setbuf, usage_setbuf},
+  {"sizeof", get_sizeof, usage_sizeof},
+  /*  {"setoutput", test_do_setoutput, usage_setoutput}, */
+  {"stat", test_do_stat, usage_stat},
+  {"statvfs", test_do_statvfs, usage_statvfs},
+  {"symlink", test_do_symlink, usage_symlink},
+  {"truncate", test_do_truncate, usage_truncate},
+  {"umask", test_do_umask, usage_umask},
+  {"umount", test_do_umount, usage_umount},
+  {"unlink", test_do_unlink, usage_unlink},
+  {"write", test_do_write, usage_write},
+  {"writev", test_do_writev, usage_writev},
+  {"writex", test_do_writex, usage_writex},
+  {NULL, NULL, NULL}
+};
+
+int run_cmd(cmd_tree *cmd_arg);
+cmd_tree* build_tree(char **cmd, int *length, int total);
+/*
+ * ##################################################
+ * # Memory functions                               #
+ * #  Intended to allow users to gain access to     #
+ * #  buffers of memory to be manipulated later     #
+ * ##################################################
+ */
+
+void * alloc_buff32(unsigned int size, int align)
+{
+  void* buf;
+  long buf_ptr;
+
+  /*
+  if ((err = memalign(&buf, align, size)) != 0) {
+    perror("memalign");
+    return 0;
+  }
+  */
+  size += align;
+  buf = malloc(size);
+  align--;
+  DBG(3, fprintf(outfp, "Buf is at %p\n", (void *)buf));
+  buf_ptr = (long)buf + ((long)buf & align);
+
+  DBG(3, fprintf(outfp, "Buf is at %p\n", (void *)buf_ptr));
+  return (void *)buf_ptr;
+}
+
+void free_buf32(void * ptr)
+{
+  free(ptr);
+}
+
+long alloc_buff64(unsigned int size, int align)
+{
+  char * buf;
+  long ret_value;
+
+  /*  
+      if (memalign((void **)&buf, align, size))
+      return 0;
+  */
+  size += align;
+  buf = malloc(size);
+  align--;
+  ret_value = (long)buf  + ((long)buf & align);
+  return ret_value;
+}
+
+void free_buf64(long ptr)
+{
+  free((char *)ptr);
+}
+
+  
+/* 
+ * Hash function for variables. Shamelessly stolen
+ * from the ext3 code
+ */
+unsigned int dx_hack_hash (const char *name, int len)
+{
+  unsigned int hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
+  while (len--)
+    {
+      unsigned int hash = hash1 + (hash0 ^ (*name++ * 7152373));
+      if (hash & 0x80000000) hash -= 0x7fffffff;
+      hash1 = hash0;
+      hash0 = hash;
+    }
+  return hash0;
+}
+
+struct var_mapping *get_map(char *var_name)
+{
+  int index;
+  struct var_mapping_list *curr;
+  
+
+ if (var_name[0] == '$') {
+    /* It is a name--chop off the initial and get the mapping $ */
+    var_name++;
+  }
+   
+  index = dx_hack_hash(var_name, strlen(var_name));
+  index %= MAX_VARS -1;
+
+  DBG(5, fprintf(outfp, "Got index of %d for %s\n", index, var_name));
+  curr = &map[index];
+  
+  while ((curr) && (curr->map.obj != -1) ) {
+    if ( (curr->map.name == NULL) || (strcmp(curr->map.name, var_name)) )
+      curr = curr->next;
+    else
+      return &curr->map;
+  }
+
+  return NULL;
+}
+
+char *get_str(char *var_name) 
+{
+  /* See if it is a quoted string */
+  if (var_name[0] == '"') {
+    /* Chop off the beginning and end quotes and return the string */
+    int len = strlen(var_name);
+    var_name[len-1] = '\0';
+    var_name++;
+  }
+
+  return var_name;
+}
+
+static char* 
+get_or_part(char **str, int* did_alloc)
+{
+       char *tmp_str = *str;
+       int i, norm_str=0;
+
+       if (tmp_str == NULL)
+               return NULL;
+
+       if (tmp_str[0] == '|') {
+               tmp_str++;
+               norm_str=1;
+       }
+
+       for (i=0; (unsigned int)i < strlen(tmp_str); i++) {
+               if (tmp_str[i] == '|') {
+                       char *new_str = (char *)malloc(i+1);
+                       memcpy(new_str, tmp_str, i);
+                       new_str[i] = '\0';
+                       *did_alloc = 1;
+                       *str = &tmp_str[i];
+                       return new_str;
+               }
+       }
+
+       if (norm_str) {
+               *did_alloc = 0;
+               *str = NULL;
+               return tmp_str;
+       } 
+
+       return NULL;
+}
+
+int get_obj(char *var_name) 
+{
+       char** str = &var_name;
+       char *str1;
+  struct var_mapping *var_map;
+  int did_alloc=0;
+       int obj=0, got_obj=0;
+
+  DBG(5, fprintf(outfp, "Getting object for %s\n", var_name));
+  
+  /* If var_name is a digit, we assume it is a literal */
+  if (isdigit(var_name[0])) 
+    return atoi(var_name); 
+  /* 
+   * Check for '|', indicates that one or more values are or'd
+   * together
+   */
+       while ((str1 = get_or_part(str, &did_alloc)) != NULL) {
+
+               if (isdigit(str1[0])) {
+                       if (str1[0] == '0') {
+                               /* Assume octal format */
+                               obj |= strtol(str1, NULL, 8);
+                       } else 
+                               obj |= atoi(str1);
+               } else {
+                       var_map = get_map(str1);
+                       if (!var_map) {
+                               if (did_alloc)
+                                       free(str1);
+                               return -1;
+                       }
+                       obj |= var_map->obj;
+               }
+
+               if (did_alloc) {
+                       did_alloc = 0;
+                       free(str1);
+               }
+               got_obj++;
+       }
+
+       if (got_obj)
+               return obj;
+  var_map = get_map(var_name);
+  if (!var_map)
+    return -1;
+  else
+    return var_map->obj;
+}
+
+     
+void store_result(char *var_name, int result)
+{
+  int index = dx_hack_hash(var_name, strlen(var_name));
+  struct var_mapping_list *map_obj;
+  struct var_mapping_list *new_map;
+  index %= MAX_VARS -1 ;
+
+  if (map[index].map.obj >= 0) {
+
+    /* Got a collision --just chain it*/ 
+    new_map = malloc(sizeof(struct var_mapping_list));
+                    
+    map_obj = &map[index];
+    while (map_obj->next != NULL)
+      map_obj = map_obj->next;
+    
+    map_obj->next = new_map;
+  } else
+    new_map = &map[index];
+
+  new_map->map.name = malloc(strlen(var_name) + 1);
+  strcpy(new_map->map.name, var_name);
+  new_map->map.obj = result;
+  new_map->map.type = last_type;
+  new_map->next = NULL;
+  DBG(3, fprintf(outfp, "Stored %d in index %d hashed with %s\n",
+               result, index, var_name));
+}
+
+void free_obj(char *obj_name)
+{
+  int index;
+  struct var_mapping_list *prev, *curr;
+
+
+  /* See if it is a variable name */
+  if (obj_name[0] == '$') {
+    /* It is a name--chop off the initial $ */
+    obj_name++;
+  }
+  index = dx_hack_hash(obj_name, strlen(obj_name));
+  index %= MAX_VARS -1;
+
+  DBG(5, fprintf(outfp, "Got index of %d\n", index));
+  curr = &map[index];
+
+  prev = NULL;
+
+  while ((curr) && (curr->map.obj != -1) ) {
+    if (strcmp(curr->map.name, obj_name)) {
+      prev = curr;
+      curr = curr->next;
+    } else
+      break;
+  }
+
+  /* Remove the object from the chain */
+  if (prev) 
+    prev->next = curr->next;
+  
+  curr->map.obj = -1;
+  free(curr->map.name);
+  if (prev) 
+    free(curr);
+}
+
+
+/*
+ * Given a long string, returns the string divided into
+ * whitespace seperated words in list.  Returns the number
+ * of words
+ */
+int parser(char *str, char** list)
+{
+  int len, i=0, j=0, counter=-1;
+  int in_quotes = 0;
+  char *new_str;
+
+
+  len = strlen(str);
+  DBG(5, fprintf(outfp, "str is %s len is %d\n", str, len));
+  while (i < len) {
+   
+    if ((i==0) || ((str[i] == ' ') && (in_quotes == 0)) ) {
+      if (i != 0) {
+       new_str[j] = '\0';
+       DBG(5, fprintf(outfp, "Got word %s\n", list[counter]));
+       i++;
+      } 
+      while ((str[i] == ' ') && (in_quotes == 0))
+       i++;
+      counter++;
+      new_str = list[counter] = malloc(MAX_WORD);
+      j = 0;
+      
+    }
+    
+    new_str[j] = str[i];
+    if (str[i] == '"') {
+      if (in_quotes)
+       in_quotes = 0;
+      else
+       in_quotes = 1;
+    }
+    if ((str[i] == ' ') && (in_quotes==0)){
+      while (str[i+1] == ' ')
+                               i++;
+      new_str[j] = '\0';
+    }
+    i++;
+    j++;
+
+  }
+  new_str[j] = '\0';
+  DBG(5, fprintf(outfp, "Got word %s\n", list[counter]));
+  return counter +1;
+}
+
+
+int execute_cmd(char *cmd, char **args, int arg_count)
+{
+  int i = 0;
+
+  if (!strcmp(cmd, "help")) {
+    if (arg_count > 0) {
+                       while(cmd_list[i].cmd != NULL) {
+                               if (!strcmp(cmd_list[i].cmd, args[0])) {
+                                       (cmd_list[i].usage)();
+                                       return 0;
+                               }
+                               i++;
+      }
+    } else {
+      do_help();
+      return 0;
+    }
+    return -1;
+  } 
+  while(cmd_list[i].cmd != NULL) {
+    if (!strcmp(cmd_list[i].cmd, cmd)) {
+      return (cmd_list[i].func)(arg_count, args);
+               }
+    i++;
+  }
+  DBG(2, fprintf(outfp, "Command %s was invalid\n", cmd));
+  return INVALID_CMD;
+}
+
+int get_args(struct queue_t *child, char** list, int num_args, int argnum)
+{
+  char *argval;
+
+  if (child->val != NULL) {
+    argval = child->val;
+  } else if (child->cmd != NULL) {
+    run_cmd(child->cmd);
+    if (child->cmd->res_name != NULL)
+      argval = child->cmd->res_name;
+    else {
+      char tmpstr[50];
+      int val = last_ret_val;
+      sprintf(tmpstr, "%x", val);
+      argval = tmpstr;
+    }
+  } else {
+    DBG(2, fprintf(outfp, "I am confused\n"));
+    return INVALID_ARGS;
+  }
+  
+  list[argnum] = malloc(strlen(argval) + 1);
+  strcpy(list[argnum], argval);
+  argnum++;
+
+  if (argnum == num_args)
+    return SUCCESS;
+  else if (child->next == NULL) {
+    DBG(2, fprintf(outfp, "Only on arg number %d out of %d, but ran out of children\n",
+                  argnum, num_args));
+    return INVALID_ARGS;
+  } else 
+    return get_args(child->next, list, num_args, argnum);
+
+  return SUCCESS;
+}
+
+int run_cmd(cmd_tree *cmd_arg)
+{
+  char cmdstr[MAX_COMMAND];
+  char *cmdptr;
+  char **args;
+  int res, i;
+  struct buf_t *buf;
+  char *cmd;
+  struct queue_t *child;
+
+  if (cmd_arg == NULL)
+    return INVALID_CMD;
+
+  cmd = cmd_arg->val;
+  cmdptr = cmdstr;
+  child = cmd_arg->children;
+  if ( (!strcmp("exit", cmd)) || (!strcmp("quit", cmd)) ||
+       (!strcmp("EXIT", cmd)) || (!strcmp("QUIT", cmd)) )
+    strcpy(cmdstr, "exit");
+  else if (!strcmp("ALLOC", cmd)) 
+    strcpy(cmdstr, "alloc");
+  else if (!strcmp("FREE", cmd))
+    strcpy(cmdstr, "free");
+ else if (!strcmp("HELP", cmd))
+    strcpy(cmdstr, "help");
+  else if (!strcmp("CALL", cmd)) {
+    if (cmd_arg->arg_count < 1) {
+      DBG(2, fprintf(outfp, "Need at least one command\n"));
+      return INVALID_CMD;
+    }
+
+    cmd_arg->arg_count--;
+    if (child->val != NULL) 
+      cmdptr = child->val;
+    else {
+      DBG(2, fprintf(outfp, "Need to specify command\n"));
+      return INVALID_CMD;
+    }
+
+    DBG(3, fprintf(outfp, "Got cmd %s\n", child->val));
+    if (cmd_arg->arg_count != 0)
+      child = child->next;
+
+   
+  } else if (!strcmp("DEPOSIT", cmd))
+    strcpy(cmdstr, "fill");
+  else if (!strcmp("PRINT", cmd))
+    strcpy(cmdstr, "printbuf");
+  else {
+    if (cmd_arg->res_name != NULL) {
+      /* 
+       * If the cmd is not a valid command, just store it
+       */
+      res = get_obj(cmd_arg->children->val);
+      last_type = UINT;
+      if (res < 0) {
+                               /* Just store it as a string */
+                               buf = (struct buf_t *)malloc(sizeof(struct buf_t));
+                               buf->len = strlen(cmd);
+                               buf->buf = (char *)malloc(buf->len+1);
+                               strcpy(buf->buf, cmd_arg->children->val);
+                               buflist[next] = buf;
+                               res = next;
+                               DBG(3, fprintf(outfp, "Stored %s in index %d\n", (char *)buf->buf, next));
+                               next++;
+                               last_type = STR;
+      }
+      store_result(cmd_arg->res_name, res);
+      return SUCCESS;
+    } else
+      return INVALID_CMD;
+  }
+
+
+  if (cmd_arg->arg_count == 0)
+    args = NULL;
+  else {
+    args = (char **)malloc(sizeof(char *)*cmd_arg->arg_count);
+    get_args(child, args, cmd_arg->arg_count, 0);
+  } 
+
+  DBG(3, fprintf(outfp, "CMD: %s\n ARGS: ",cmdptr));
+  for (i=0; i < cmd_arg->arg_count; i++)
+    DBG(3, fprintf(outfp, "%s ", args[i]));
+  DBG(3, fprintf(outfp, "\n"));
+  res = execute_cmd(cmdptr, args, cmd_arg->arg_count);
+  if (cmd_arg->res_name != NULL)
+    store_result(cmd_arg->res_name, last_ret_val);
+
+  return res;
+} 
+
+
+int is_command(char *name)
+{
+    if ( (strcmp(name, "CALL"))  && (strcmp(name, "FILL"))  &&
+        (strcmp(name, "ALLOC")) && (strcmp(name, "PRINT")) &&
+        (strcmp(name, "FREE"))  && (strcmp(name, "exit"))  && 
+        (strcmp(name, "HELP"))  && (strcmp(name, "help"))  && 
+        (strcmp(name, "quit"))  && (strcmp(name, "EXIT"))  &&
+        (strcmp(name, "QUIT"))  && (strcmp(name, "DEPOSIT")) )
+       return 0;
+
+    return 1;
+}
+
+#define ARGS 1
+int get_type(char *arg0)
+{
+    if ((arg0[0] == '(') || (is_command(arg0)) ){
+       return 2;
+    }
+
+    return ARGS;
+}
+                    
+       
+int add_args(char **cmd, int length, int total, cmd_tree *tree)
+{
+    int new_len, type;
+    struct queue_t *old, *new;
+
+    old = tree->children;
+    while ((old) && (old->next))
+       old = old->next;
+    new = (struct queue_t *)malloc(sizeof(struct queue_t));
+    if (old)
+       old->next = new;
+    else
+       tree->children = new;
+    new->next = NULL;
+
+    type = get_type(cmd[0]);
+    if (type < 0) {
+       DBG(2, fprintf(outfp, "Don't understand %s\n", cmd[0]));
+       return INVALID_CMD;
+    }
+    if (type == ARGS) {
+       new->val = (char *)malloc(strlen(cmd[0])+1);
+       strcpy(new->val, cmd[0]);
+       new->cmd = NULL;
+       total = 1;
+    } else {
+       new_len = length;
+       if (cmd[0][0] == '(') {
+           new_len--;
+       }
+
+       new->val = NULL;
+       new->cmd = build_tree(&cmd[1], &new_len, total);
+       if (new->cmd == NULL) { /* Invalid command */
+         return length; /* Pretend we used everything up */
+       }
+       total = (length - new_len);
+       DBG(4, fprintf(outfp, "Used %d bytes\n", total));
+    }
+    return total;
+}
+
+void free_tree(cmd_tree* tree) 
+{
+  if (!tree)
+    return;
+
+  if (tree->children) {
+   struct queue_t *child = tree->children;
+   struct queue_t *next;
+   do {
+     next = child->next;  
+     if (child->cmd) 
+       free_tree(child->cmd);
+     free(child->val);
+     free(child);
+     child = next;
+   } while (child);
+ }
+
+ if (tree->res_name)
+   free(tree->res_name);
+
+ if (tree->val)
+   free(tree->val);
+
+ free(tree);
+}
+
+cmd_tree* build_tree(char **cmd, int *length, int total)
+{
+    int index = 0, used_args = 0;
+    cmd_tree *tree;
+    if ((*length < 0) || (!cmd) || (*cmd == NULL)) 
+                       return NULL;
+
+   
+    DBG(4, fprintf(outfp, "length is %d\n", *length));
+    tree = (cmd_tree *)malloc(sizeof(cmd_tree));
+    tree->res_name = NULL;
+    tree->children = NULL;
+    if (cmd[index][0] == '$') {
+                       tree->res_name = (char *)malloc(strlen(cmd[index])+1);
+                       strcpy(tree->res_name, (char*)(cmd[index]+1));
+                       index++;
+                       if (cmd[index][0] == '=')
+                               index++;
+    } else
+      tree->res_name = NULL;
+
+    if (is_command(cmd[index]) == 0) {
+      if (tree->res_name == NULL) {
+                               DBG(2, fprintf(outfp, "command %s is invalid \n", cmd[index]));
+        return NULL;
+      }
+    }
+
+    tree->val = (char *)malloc(strlen(cmd[index])+1);
+    strcpy(tree->val, cmd[index]);    
+    index++;
+    *length -= index;
+    tree->arg_count = 0;
+
+    if (*length == 0) {
+                       /* All done! */
+                       return tree;
+    }
+    
+    /* Got to get the arguments */
+    while (*length > 0) {
+
+                       if (cmd[index][0] == ')') {
+                               *length = *length-1;
+                               DBG(4, fprintf(outfp, "and now len is %d\n", *length));
+                               return tree;
+                       }
+                       
+                       used_args = add_args(&cmd[index], *length, total, tree);
+                       tree->arg_count++;
+                       *length -= used_args;
+                       index += used_args;
+    }
+       
+    return tree;
+}
+
+char *line;
+char *getline(char *prompt)
+{
+  int i=-1;
+  int count=0;
+
+  line = malloc(MAX_LINE);
+  if ((do_prompt) && (infp == stdin)) 
+    printf(prompt);
+
+  do {
+    /* If we get an end of file, just wait */
+    if (feof(infp)) {
+      while (feof(infp) && (line[i] != '\n')) {
+                               clearerr(infp);
+                               count++;
+                               fseek(infp, 0, SEEK_CUR);
+      }
+    } else {
+      i++;
+    }
+    fread(&line[i], 1, 1, infp);
+  } while(line[i] != '\n');
+
+  line[i] = '\0';
+
+  /*  fprintf(stderr, "Got word %s\n", line); */
+  DBG(5, fprintf(outfp, "Got word %s\n", line));
+  return line;
+}
+
+void my_perror(char *msg) 
+{
+  char *errmsg = strerror(errno);
+  
+  DBG(2, fprintf(outfp, "%s: %s\n", msg, errmsg));
+}
+  
+/* Static list of flag names */
+struct var_mapping flags_map[] = {
+  {"O_RDONLY", O_RDONLY, UINT },
+  {"O_WRONLY", O_WRONLY, UINT },
+  {"O_RDWR", O_RDWR, UINT },
+  {"O_CREAT", O_CREAT, UINT },
+  {"O_EXCL", O_EXCL, UINT },
+  {"O_NOCTTY", O_NOCTTY, UINT },
+  {"O_TRUNC", O_TRUNC, UINT },
+  {"O_APPEND", O_APPEND, UINT },
+  {"O_SYNC", O_NONBLOCK, UINT },
+  {"O_NDELAY", O_NDELAY, UINT },
+  {"O_SYNC", O_SYNC, UINT },
+  {"O_FSYNC", O_FSYNC, UINT },
+  {"O_ASYNC", O_ASYNC, UINT },
+  {"SEEK_SET", SEEK_SET, UINT },
+  {"SEEK_CUR", SEEK_CUR, UINT },
+  {"SEEK_END", SEEK_END, UINT },
+  {"S_ISUID", S_ISUID, UINT },
+  {"S_ISGID", S_ISGID, UINT },
+  {"S_ISVTX", S_ISVTX, UINT },
+  {"S_IRWXU", S_IRWXU, UINT },
+  {"S_IRUSR", S_IRUSR, UINT },
+  {"S_IREAD", S_IREAD, UINT },
+  {"S_IWUSR", S_IWUSR, UINT },
+  {"S_IWRITE", S_IWRITE, UINT },
+  {"S_IXUSR", S_IXUSR, UINT },
+  {"S_IEXEC", S_IEXEC, UINT },
+  {"S_IRWXG", S_IRWXG, UINT },
+  {"S_IRGRP", S_IRGRP, UINT },
+  {"S_IWGRP", S_IWGRP, UINT },
+  {"S_IXGRP", S_IXGRP, UINT },
+  {"S_IRWXO", S_IRWXO, UINT },
+  {"S_IROTH", S_IROTH, UINT },
+  {"S_IWOTH", S_IWOTH, UINT },
+  {"S_IXOTH", S_IXOTH, UINT },
+  {"S_IFCHR", S_IFCHR, UINT },
+  {"S_IFMT", S_IFMT, UINT },
+  {"S_IFBLK", S_IFBLK, UINT },
+  {"S_IFREG", S_IFREG, UINT },
+  {"S_IFIFO", S_IFIFO, UINT },
+  {"S_IFLNK", S_IFLNK, UINT },
+  { NULL, -1, SINT }
+};
+void init_map()
+{
+  int index = 0;
+
+  while (flags_map[index].obj != -1) {
+    store_result(flags_map[index].name, flags_map[index].obj);
+    index++;
+  }
+}
+
+int getquotedlen(char *str)
+{
+       int i;
+       
+       if (str[0] != '"' && str[0] != '\'')
+               return -1;
+       
+       for (i=1; str[i] != '\0' && str[i] != '"' && str[i] != '\''; i++);
+
+       return i;
+}
+
+int perform_op(int num1, int num2, char op) 
+{
+       switch(op) {
+               
+       case '+':
+               return num1 + num2;
+               break;
+
+       case '*':
+               return num1 * num2;
+               break;
+
+       case '/':
+               return num1 / num2;
+               break;
+
+       case '-':
+               return num1 - num2;
+               break;
+               
+       case '%':
+               return num1%num2;
+               break;
+               
+       default:
+               return num1;
+       }
+       return 0;
+}
+
+int get_constant_val(char **str_ptr, int type)
+{
+       struct buf_t *buf;
+       char *buf_ptr;
+       char *str = *str_ptr;
+       char ch;
+       int i, j, num1, num2, size;
+
+       printf("Getting constant val from %s\n", str);
+       switch(type) {
+       case 1:
+               size = getquotedlen(str);
+               buf = (struct buf_t *)malloc(sizeof(struct buf_t));
+               buf->buf = alloc_buff32(size, 8);
+               buf->len = size;
+               buf_ptr = buf->buf;
+               buflist[next] = buf;
+               j=0;
+               for (i=1; i < size; i++) {
+                       buf_ptr[j] = str[i];
+                       j++;
+               }
+               buf_ptr[j] = '\0';
+
+               DBG(3, fprintf(outfp, "Your buffer (%p) (%p) is at index %d\n",
+                                                                        (void *)buf, buf->buf, next));
+               next++;
+
+               last_type = PTR;
+               last_ret_val = next-1;
+               return last_ret_val;
+               break;
+
+       case 2:
+               if (str[0] == '$') {
+                       num1 = get_obj(str);
+               } else {        
+                       num1 = atoi(str);
+               }
+               str = str_ptr[1];
+               ch = str_ptr[1][0];
+               if ((ch == '+') || (ch == '/') || (ch == '*') || 
+                               (ch == '-') || (ch == '%')) {
+                       if (str_ptr[2][0] == '$') 
+                               num2 = get_obj(str_ptr[2]);
+                       else
+                               num2 = atoi(str_ptr[2]);
+                       num1 = perform_op(num1, num2, ch);
+               }
+
+               last_type = UINT;
+               last_ret_val = num1;
+
+               break;
+
+       default:
+               DBG(2, fprintf(outfp, "Can't understand type of %d\n", type));
+               return INVALID_ARGS;
+       }
+
+       return last_ret_val;
+}
+
+int is_constant(char *str) 
+{
+       if ((str[0] == '"') || (str[0] == '\''))
+               return 1;
+
+       
+       if ( (str[0] == '$') || 
+                        ( ((int)str[0] > 47) && ((int)str[0] < 57) ) ) 
+               return 2;
+
+       return 0;
+}
+
+int main(int argc, char *argv[])
+{
+  int count, err, i, orig_count;
+  char *input, *name;
+  char **cmd;
+  cmd_tree *tree;
+       extern int _test_sysio_startup(void);
+
+  /*
+   * Init sysio lib.
+   */
+  err = _test_sysio_startup();
+  
+       /* Temp. hack until I do the right thing to fix this...*/
+       open("/dev/stdin",O_RDONLY); 
+       open("/dev/stdout",O_WRONLY); 
+       open("/dev/stderr",O_WRONLY);
+  infp = stdin;
+  outfp = stdout;
+
+  do_prompt = 1;
+
+  errno = 0;
+  /* Get the input/output streams */
+  for (i = 1; i < argc; i++) {
+    if (!strcmp(argv[i], "--input")) {
+      i++;
+      infp = fopen(argv[i], "r");
+      if (!infp) {
+                               fprintf(outfp, "Unable to open file %s for reading\n", argv[i]);
+                               return -1;
+      }
+    } else if (!strcmp(argv[i], "--output")) {
+      i++;
+      outfp = fopen(argv[i], "w");
+      if (!outfp) {
+                               fprintf(stderr, "Unable to open file %s for writing\n", argv[i]);
+                               return -1;
+      }
+    } else if (!strcmp(argv[i], "--np")) {
+      do_prompt = 0;
+    } else {
+      fprintf(stderr, "%s: Invalid arg\n", argv[i]);
+      return -1;
+    }
+  }
+  /* Initilize the mapping */
+  for (i=0; i < MAX_VARS; i++)
+    map[i].map.obj = -1;
+  
+  /* Debug defaults */
+  debug_level = 1;
+  print_line = 0;
+
+
+#if 0
+  /* sysio defaults */
+  strcpy(root_driver, DEFAULT_DRIVER);
+  strcpy(mntpath, "/");
+  mntflgs = 0;
+#endif
+
+  my_errno = 0;
+
+  /* Set up line buffering */
+  setlinebuf(outfp);
+  setlinebuf(infp);
+
+  /* 
+   * This sets up some common flags so that the string
+   * names can be used (for instance 0_RDWR, SEEK_SET, etc
+   */
+  init_map();
+  i=0;
+  next = 0;
+  while (1) {
+    bzero(output, 4096);
+
+    input = getline("> ");
+    cmd = malloc(MAX_COMMAND * sizeof(char *));
+    count = orig_count = parser(input, cmd);
+    name = NULL;
+    if ((!count) || (count > MAX_COMMAND)){
+      fprintf(outfp, "%s: invalid command\n", input);
+    } else {
+      i = 0;
+      if (cmd[0][0] == '$') {
+                               /* Need to store output of command in var name */
+                               name = cmd[0]+1;
+                               DBG(4, fprintf(outfp, "name is %s\n", name));
+                               count--;
+                               /* The '=' is not necessary, but available */
+                               if (!strcmp(cmd[1], "=")){
+                                       i++;
+                                       count--;
+                               }
+                               i++;
+                               if ((err=is_constant(cmd[i])) != 0) {
+                                       store_result((char *)(&cmd[0][1]), get_constant_val(&cmd[i], err));
+                                       tree = NULL;
+                                       err = 0;
+                               } else {
+
+                                       tree = build_tree(&cmd[i], &count, 0);
+                                       if (tree != NULL) {
+                                               err = run_cmd(tree);
+                                               store_result((char *)(&cmd[0][1]), last_ret_val);
+                                       }
+                               }
+                       } else {
+                               
+                               tree = build_tree(cmd, &count, 0);
+                               if (tree != NULL)
+                                       err = run_cmd(tree);
+      }
+      /* Print out return code and any string from command */
+      fprintf(outfp, "%#04x %s\n", err, output);
+      if (tree)
+                               free_tree(tree);
+      /* fprintf(stderr, "%#04x %s\n", err, output); */
+      for (i=0; i < count; i++)
+                               free(cmd[i]);
+    }
+    free(cmd);
+    free(line);
+  }
+}
diff --git a/libsysio/tests/test_driver.h b/libsysio/tests/test_driver.h
new file mode 100644 (file)
index 0000000..d8fabaf
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * I feel like I should be putting a comment here...
+ */
+#include <sys/types.h>
+#include "test.h"
+
+/* Debugging stuff.. */
+#define PRINT_LINE 0
+int debug_level;
+int print_line;
+
+FILE *outfp; /* output file */
+FILE *infp;
+
+#define DBG(level, _x) \
+ do { \
+if (((level) <= (debug_level))) {  \
+  if (print_line) \
+   fprintf(outfp, "From file %s line %d: \n", __FILE__, __LINE__); \
+                         (void)((_x)); \
+} \
+} while(0)  
+
+/* Maximum size of a command or command argument */
+#define MAX_WORD 150 
+
+/* Maximum size of an input line */
+#define MAX_LINE 300
+
+/* Structure to hold commands in */
+struct cmd_t {
+  char *cmd;
+  int (*func)(int, char **);
+  void (*usage)();
+};
+
+extern struct cmd_t cmd_list[];
+
+/* Maximum number of words in a command (command + command args) */
+#define MAX_COMMAND 50
+
+/* 
+ * Holds list of allocated buffers.  To use a pre-allocated
+ * buffer, the index number needs to be passed in.  This should
+ * probably be smarter--perhaps a hash table could store the
+ * list, with the hash being sent back to the user 
+ */
+#define MAX_BUFFERS 50
+struct buf_t {
+  void *buf;
+  int len;
+};
+
+struct buf_t *buflist[MAX_BUFFERS];
+
+int next; /* Next available buffer slot */
+
+
+/* Defaults for libsysio */
+char root_driver[75];
+char mntpath[250];
+unsigned int  mntflgs;
+
+
+
+#define MAX_VARS 250
+
+/* 
+ * Valid types for fill buff and variables.
+ */
+#define UINT 0
+#define SINT 1
+#define STR  2
+#define PTR  3
+/* 
+ * This defines a mapping from a variable name to
+ * some object known by the test harness.  Variable
+ * names are distinguished by '$'. Variables are used
+ * in two possible ways: to capture the output of
+ * a function, as in $my_fd = open name, or to gain
+ * access to that variable, as in open $my_fd.  Variables
+ * do not necessarily have to be initilized before use
+ */
+struct var_mapping {
+  char *name; /* Variable name */
+  int obj;  /* Object will always be an integer -- either a
+              file descriptor or an index into the buffer 
+              array 
+           */
+  int type;
+};
+
+int last_type; 
+
+struct var_mapping_list {
+  struct var_mapping map;
+  struct var_mapping_list *next;
+};
+
+/* 
+ * Again, I am lazy and just use a static array
+ * This should be dynamically remappable
+ */
+struct var_mapping_list map[MAX_VARS];
+char output[4096];
+int pos; /* Pos in output string */
+
+struct cmd_map {
+  char *cmd_name;
+  int cmd;
+  int num_args;
+};
+
+extern struct cmd_map fcntl_cmds[];
+
+/* Return code information */
+#define SUCCESS       0x000
+#define INVALID_ARGS  0x001
+#define INVALID_CMD   0x002
+#define INVALID_VAR   0x004
+
+int do_prompt; /* Prompt for interactive run? */
+int last_ret_val; /* Last return value returned by libsysio call */
+extern int errno;
+int my_errno; /* Not sure what the difference will be */
+
+/* Functions defined in test_driver.c */
+extern unsigned int dx_hack_hash (const char *name, int len);
+extern int get_obj(char *var_name);
+extern void *alloc_buff32(unsigned int size, int align);
+extern void store_result(char *var_name, int result);
+extern struct var_mapping *get_map(char *var_name);
+extern void free_obj(char *obj_name);
+extern void my_perror(char *msg);
+extern char *get_str(char *var_name); 
+  
+/* Stub functions defined in sysio_stubs.c */
+extern int test_do_setdebug(int argc, char **argv);
+extern int test_do_printline(int argc, char **argv);
+extern int cmp_bufs(int argc, char **argv);
+extern int test_do_printbuf(int argc, char **argv);
+extern int test_do_fillbuff(int argc, char **argv);
+extern int test_do_mount(int argc, char **args);
+extern int test_do_list(int argc, char **args);
+extern int test_do_init(int argc, char **args);
+extern int get_endian(int argc, char **args);
+extern int get_sizeof(int argc, char **args);
+extern int do_setbuf(int argc, char **argv);
+extern int test_do_exit(int argc, char **args);
+extern int get_buffer(int argc, char **args);
+extern int free_buffer(int argc, char **args);
+extern int test_do_chdir(int argc, char **args);
+extern int do_checkbuf(int argc, char **argv);
+extern int test_do_chmod(int argc, char **args);
+extern int test_do_chown(int argc, char **args);
+extern int test_do_open(int argc, char **args);
+extern int test_do_close(int argc, char **args);
+extern int test_do_clear(int argc, char **argv);
+extern int test_do_dup(int argc, char **args);
+extern int test_do_dup2(int argc, char **args);
+extern int test_do_fcntl(int argc, char **args);
+extern int test_do_fstat(int argc, char **argv);
+extern int test_do_fsync(int argc, char **argv);
+extern int test_do_ftruncate(int argc, char **argv);
+extern int test_do_getcwd(int argc, char **argv);
+extern int test_do_init_iovec(int argc, char **argv);
+extern int test_do_init_xtvec(int argc, char **argv);
+extern int test_do_lseek(int argc, char **argv);
+extern int test_do_lstat(int argc, char **argv);
+extern int test_do_getdirentries(int argc, char **argv); 
+extern int test_do_mkdir(int argc, char **argv);
+extern int test_do_creat(int argc, char **argv);
+extern int test_do_stat(int argc, char **argv);
+extern int test_do_statvfs(int argc, char **argv);
+extern int test_do_fstatvfs(int argc, char **argv);
+extern int test_do_truncate(int argc, char **argv);
+extern int test_do_rmdir(int argc, char **argv);
+extern int test_do_symlink(int argc, char **argv);
+extern int test_do_unlink(int argc, char **argv);
+extern int test_do_fdatasync(int argc, char **argv);
+extern int test_do_ioctl(int argc, char **argv);
+extern int test_do_umask(int argc, char **argv);
+extern int test_do_iodone(int argc, char **argv);
+extern int test_do_iowait(int argc, char **argv);
+extern int test_do_ipreadv(int argc, char **argv);
+extern int test_do_ipread(int argc, char **argv);
+extern int test_do_preadv(int argc, char **argv);
+extern int test_do_pread(int argc, char **argv);
+extern int test_do_ireadv(int argc, char **argv);
+extern int test_do_ireadx(int argc, char **argv);
+extern int test_do_iread(int argc, char **argv); 
+extern int test_do_readv(int argc, char **argv);
+extern int test_do_readx(int argc, char **argv);
+extern int test_do_read(int argc, char **argv);
+extern int test_do_ipwritev(int argc, char **argv);
+extern int test_do_ipwrite(int argc, char **argv);
+extern int test_do_pwritev(int argc, char **argv);
+extern int test_do_pwrite(int argc, char **argv);
+extern int test_do_iwritev(int argc, char **argv);
+extern int test_do_iwrite(int argc, char **argv);
+extern int test_do_iwritex(int argc, char **argv);
+extern int test_do_writev(int argc, char **argv);
+extern int test_do_writex(int argc, char **argv);
+extern int test_do_write(int argc, char **argv);
+extern int test_do_mknod(int argc, char **argv);
+extern int test_do_umount(int argc, char **argv);
+
+
+/* Functions defined in sysio_tests.c */
+extern int sysio_mount(char *from, char *to);
+extern int sysio_list(char *path);
+extern int initilize_sysio(void);
+extern int sysio_chdir(char *newdir);
+extern int sysio_chmod(char *mode_arg, const char *path);
+extern int sysio_chown(char *new_id, char *file);
+extern int sysio_open(char *path, int flags);
+extern int sysio_open3(char *path, int flags, char *mode_arg);
+extern int sysio_close(int fd);
+extern int sysio_fcntl(int fd, struct cmd_map* cmdptr, char *arg);
+extern int sysio_fstat(int fd, void *buf);
+extern int sysio_lstat(char *filename, void *buf);
+extern int sysio_getdirentries(int fd, char *buf, size_t nbytes, off_t *basep);
+extern int sysio_mkdir(char *path, char *mode); 
+extern int sysio_creat(char *path, char *mode_arg);
+extern int sysio_stat(char *filename, void *buf);
+extern int sysio_statvfs(char *filename, void *buf);
+extern int sysio_fstatvfs(int fd, void *buf);
+extern int sysio_umask(char *mode_arg);
+extern int sysio_mknod(char *path, char *mode_arg, dev_t dev);
+
+/* Usage functions defined in help.c */
+extern void do_help();
+extern void usage_setdebug();
+extern void usage_printline();
+extern void usage_endian();
+extern void usage_sizeof();
+extern void usage_get_buffer();
+extern void usage_free_buffer();
+extern void usage_do_printbuf();
+extern void usage_do_fillbuff();
+extern void usage_init();
+extern void usage_list();
+extern void usage_chdir();
+extern void usage_chmod();
+extern void  usage_chown();
+extern void usage_open();
+extern void usage_close();
+extern void usage_clear();
+extern void usage_mount();
+extern void usage_dup();
+extern void usage_dup2();
+extern void usage_fcntl();
+extern void usage_fstat();
+extern void usage_fsync();
+extern void usage_ftruncate();
+extern void usage_getcwd();
+extern void usage_init_iovec();
+extern void usage_init_xtvec();
+extern void usage_lseek();
+extern void usage_lstat();
+extern void usage_getdirentries();
+extern void usage_mkdir();
+extern void usage_checkbuf();
+extern void usage_cmpbufs();
+extern void usage_creat();
+extern void usage_setbuf();
+extern void usage_stat();
+extern void usage_statvfs();
+extern void usage_fstatvfs();
+extern void usage_truncate();
+extern void usage_rmdir();
+extern void usage_symlink();
+extern void usage_unlink();
+extern void usage_fdatasync();
+extern void usage_ioctl();
+extern void usage_umask();
+extern void usage_iowait();
+extern void usage_iodone();
+extern void usage_ipreadv();
+extern void usage_ipread();
+extern void usage_preadv();
+extern void usage_pread();
+extern void usage_ireadv();
+extern void usage_iread();
+extern void usage_ireadx();
+extern void usage_readv();
+extern void usage_readx();
+extern void usage_read();
+extern void usage_ipwritev();
+extern void usage_ipwrite();
+extern void usage_pwritev();
+extern void usage_pwrite();
+extern void usage_iwritev();
+extern void usage_iwrite();
+extern void usage_iwritex();
+extern void usage_writev();
+extern void usage_write();
+extern void usage_writex();
+extern void usage_mknod();
+extern void usage_umount();
+extern void usage_exit();
diff --git a/libsysio/tests/test_getcwd.c b/libsysio/tests/test_getcwd.c
new file mode 100644 (file)
index 0000000..340180e
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef REDSTORM
+#include <getopt.h>
+#else
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/queue.h>
+#include <dirent.h>
+
+#include "sysio.h"
+#include "mount.h"
+
+#include "test.h"
+
+/*
+ * Test getcwd()
+ *
+ * Usage: test_cwd [<working-dir>...]
+ *
+ * Without any path arguments, the program reads from standard-in, dealing with
+ * each line as an absolute or relative path until EOF.
+ */
+
+static int doit(const char *path);
+static void usage(void);
+
+int
+main(int argc, char *const argv[])
+{
+       int     i;
+       int     err;
+       int     n;
+       extern int _test_sysio_startup(void);
+
+       /*
+        * Parse command line arguments.
+        */
+       while ((i = getopt(argc, argv, "")) != -1)
+               switch (i) {
+
+               default:
+                       usage();
+               }
+       /*
+        * Init sysio lib.
+        */
+       err = _test_sysio_startup();
+       if (err) {
+               errno = -err;
+               perror("sysio startup");
+               exit(1);
+       }
+
+       n = argc - optind;
+
+       /*
+        * Try path(s) listed on command-line.
+        */
+       while (optind < argc) {
+               const char *path;
+
+               path = argv[optind++];
+               (void )doit(path);
+       }
+
+       /*
+        * If no command-line arguments, read from stdin until EOF.
+        */
+       if (!n) {
+               int     doflush;
+               static char buf[4096];
+               size_t  len;
+               char    *cp;
+               char    c;
+
+               doflush = 0;
+               while (fgets(buf, sizeof(buf), stdin) != NULL) {
+                       len = strlen(buf);
+                       cp = buf + len - 1;
+                       c = *cp;
+                       *cp = '\0';
+                       if (!doflush)
+                               doit(buf);
+                       doflush = c == '\n' ? 0 : 1;
+               }
+       }
+
+       /*
+        * Clean up.
+        */
+       _sysio_shutdown();
+
+       return 0;
+}
+
+static int
+doit(const char *path)
+{
+       char    *buf;
+
+       if (chdir(path) != 0) {
+               perror(path);
+               return -1;
+       }
+       buf = getcwd(NULL, 0);
+       if (!buf) {
+               perror(path);
+               return -1;
+       }
+       (void )printf("%s\n", buf);
+       free(buf);
+       return 0;
+}
+
+static void
+usage()
+{
+
+       (void )fprintf(stderr,
+                      "Usage: test_getcwd "
+                      " [<path> ...\n]");
+
+       exit(1);
+}
diff --git a/libsysio/tests/test_getcwd.pl b/libsysio/tests/test_getcwd.pl
new file mode 100755 (executable)
index 0000000..94f33a3
--- /dev/null
@@ -0,0 +1,121 @@
+#!/usr/bin/perl -w
+
+use IPC::Open2;
+
+use strict;
+use FindBin;
+use lib "$FindBin::Bin";
+use helper;
+use Fcntl ':mode';
+
+
+sub usage
+{
+  print "Usage: ./test_getcwd.pl [-alpha] <dir> : Test getcwd by verifying that it \n";
+  print "                                       : setting the directory to dir and \n";
+  print "                                       : verifying that getcwd reflects \n";
+  print "                                       : the change\n";
+  exit(-1);
+}
+
+sub check_wkdir
+{
+  my ($wdir, $outfh, $cmdfh) = @_;
+
+
+  # Get cwd from libsysio
+  my $cmdstr = 'CALL getcwd ( $buf = ALLOC 512 ) 512'."\n";
+  helper::send_cmd($cmdfh, $outfh, "getcwd", $cmdstr);  
+  
+  # Verify the system call's output
+  helper::verify_cmd($cmdfh, $outfh, "getcwd");  
+
+  # Print out the buffer
+  $cmdstr = 'PRINT $buf 0 1 STR'."\n";
+  helper::send_cmd($cmdfh, $outfh, "PRINT", $cmdstr);  
+
+  my $iodir = <$outfh>;
+  chop($iodir);
+       
+       # Only compare the last portion of the working directory
+       my @iodirs = split(/\//, $iodir);
+       my @wdirs = split(/\//, $wdir);
+
+       if ($iodirs[-1]  ne $wdirs[-1]) {
+               helper::print_and_exit
+                               ($cmdfh, 
+                                $outfh, 0, 
+                                "ERROR! topmost wdir ($wdirs[-1]) does not match sysio's ($iodirs[-1])\n");
+               }
+}
+
+sub process_cmd
+{
+  my ($dir, $is_alpha) = @_;
+
+  # Get tests directory
+  my $testdir = $FindBin::Bin;
+  
+  eval {
+      if ($is_alpha == 0) {
+         open2(\*OUTFILE, \*CMDFILE, "$testdir/test_driver --np");
+      } else {
+         open2(\*OUTFILE, \*CMDFILE, 
+               "yod -batch -quiet -sz 1 $testdir/test_driver --np");
+      }
+  };
+
+  if ($@) {
+    if ($@ =~ /^open2/) {
+      warn "open2 failed: $!\n$@\n";
+      return;
+    }
+    die;
+
+  }
+
+  my $outfh = \*OUTFILE;
+  my $cmdfh = \*CMDFILE;
+
+  if ($is_alpha == 0) {
+    helper::send_cmd($cmdfh, $outfh, "init", "CALL init\n");
+
+                       # Get current working directory from environment
+      my $cwd = $ENV{PWD};
+
+     
+  }
+
+  # Now change to dir
+  helper::send_cmd($cmdfh, $outfh, "chdir", "CALL chdir $dir\n");  
+
+ # Verify the system call's output
+  helper::verify_cmd($cmdfh, $outfh, "PRINT");  
+
+  check_wkdir($dir, $outfh, $cmdfh);
+
+  # Clean up
+  helper::print_and_exit($cmdfh, $outfh, 0, "getcwd test successful\n");
+}
+
+
+my $currarg = 0;
+my $is_alpha = 0;
+
+if (@ARGV < 1) {
+  usage;
+} elsif (@ARGV > 1) {
+  if ($ARGV[$currarg++] eq "-alpha") {
+    $is_alpha = 1;
+  }
+}
+
+my $dir = $ARGV[$currarg];
+
+process_cmd($dir, $is_alpha);
+
+exit 0;
+
+
+
+
diff --git a/libsysio/tests/test_link.c b/libsysio/tests/test_link.c
new file mode 100644 (file)
index 0000000..ab4106f
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef REDSTORM
+#include <getopt.h>
+#endif
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/queue.h>
+#if 0
+#include <dirent.h>
+#endif
+
+#include "sysio.h"
+#include "mount.h"
+
+#include "test.h"
+
+/*
+ * Test hard link
+ *
+ * Usage: link oldpath newpath
+ *
+ */
+
+static void usage(void);
+
+int
+main(int argc, char *const argv[])
+{
+       int     i;
+       int     err;
+       int     n;
+       extern int _test_sysio_startup(void);
+
+       /*
+        * Parse command line arguments.
+        */
+       while ((i = getopt(argc, argv, "")) != -1)
+               switch (i) {
+
+               default:
+                       usage();
+               }
+
+       /*
+        * Init sysio lib.
+        */
+       err = _test_sysio_startup();
+       if (err) {
+               errno = -err;
+               perror("sysio startup");
+               exit(1);
+       }
+
+       n = argc - optind;
+       if (n < 2) usage();
+
+       /*
+        * Try paths listed on command-line.
+        */
+       while (optind < argc) {
+               const char *old, *new;
+               struct stat stbuf;
+
+               old = argv[optind++];
+               new = argv[optind++];
+               if ((err = link(old, new)) != 0) {
+                       perror("link");
+                       break;
+               }
+               if ((err = lstat(new, &stbuf)) != 0) {
+                       perror(new);
+                       break;
+               }
+       }
+
+       /*
+        * Clean up.
+        */
+       _sysio_shutdown();
+
+       return err ? -1 : 0;
+}
+
+static void
+usage()
+{
+
+       (void )fprintf(stderr,
+                      "Usage: unlink"
+                      " oldpath newpath\n");
+
+       exit(1);
+}
diff --git a/libsysio/tests/test_list.c b/libsysio/tests/test_list.c
new file mode 100644 (file)
index 0000000..4dc0a82
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef REDSTORM
+#include <getopt.h>
+#else
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/queue.h>
+#include <dirent.h>
+
+#include "sysio.h"
+#include "mount.h"
+
+#include "test.h"
+
+/*
+ * Stat files.
+ *
+ * Usage: test_list [path...]
+ *
+ * Without any path arguments, the program reads from standard-in, dealing with
+ * each line as an absolute or relative path until EOF.
+ */
+
+static int listit(const char *path);
+static void usage(void);
+
+int
+main(int argc, char *const argv[])
+{
+       int     i;
+       int     err;
+       int     n;
+       extern int _test_sysio_startup(void);
+
+       /*
+        * Parse command line arguments.
+        */
+       while ((i = getopt(argc, argv, "")) != -1)
+               switch (i) {
+
+               default:
+                       usage();
+               }
+
+       /*
+        * Init sysio lib.
+        */
+       err = _test_sysio_startup();
+       if (err) {
+               errno = -err;
+               perror("sysio startup");
+               exit(1);
+       }
+
+       n = argc - optind;
+
+       /*
+        * Try path(s) listed on command-line.
+        */
+       while (optind < argc) {
+               const char *path;
+
+               path = argv[optind++];
+               (void )listit(path);
+       }
+
+       /*
+        * If no command-line arguments, read from stdin until EOF.
+        */
+       if (!n) {
+               int     doflush;
+               static char buf[4096];
+               size_t  len;
+               char    *cp;
+               char    c;
+
+               doflush = 0;
+               while (fgets(buf, sizeof(buf), stdin) != NULL) {
+                       len = strlen(buf);
+                       cp = buf + len - 1;
+                       c = *cp;
+                       *cp = '\0';
+                       if (!doflush)
+                               listit(buf);
+                       doflush = c == '\n' ? 0 : 1;
+               }
+       }
+
+       /*
+        * Clean up.
+        */
+       _sysio_shutdown();
+
+       return 0;
+}
+
+static int
+listit(const char *path)
+{
+       int     fd;
+       size_t  n;
+       struct dirent *buf, *dp;
+       off_t   base;
+       ssize_t cc;
+
+       fd = open(path, O_RDONLY);
+       if (fd < 0) {
+               perror(path);
+               return -1;
+       }
+
+       n = 16 * 1024;
+       buf = malloc(n);
+       if (!buf) {
+               perror(path);
+               cc = -1;
+               goto out;
+       }
+
+       base = 0;
+       while ((cc = getdirentries(fd, (char *)buf, n, &base)) > 0) {
+               dp = buf;
+               while (cc > 0) {
+                       (void )printf("\t%s: ino %llu type %u\n",
+                                     dp->d_name,
+                                     (unsigned long long )dp->d_ino,
+                                     (int )dp->d_type);
+                       cc -= dp->d_reclen;
+                       dp = (struct dirent *)((char *)dp + dp->d_reclen);
+               }
+               if (!base)
+                       break;
+       }
+
+out:
+       if (cc < 0)
+               perror(path);
+
+       free(buf);
+       {
+               int     oerrno = errno;
+
+               if (close(fd) != 0) {
+                       perror(path);
+                       if (cc < 0)
+                               errno = oerrno;
+                       else
+                               cc = -1;
+               }
+       }
+
+       return (int )cc;
+}
+
+static void
+usage()
+{
+
+       (void )fprintf(stderr,
+                      "Usage: list_path"
+                      " [<path> ...\n]");
+
+       exit(1);
+}
diff --git a/libsysio/tests/test_list.pl b/libsysio/tests/test_list.pl
new file mode 100755 (executable)
index 0000000..5be13d2
--- /dev/null
@@ -0,0 +1,237 @@
+#!/usr/bin/perl -w
+
+#
+# getdirentries test:  Tests the equivalent of a ls.  Note that this is not
+#                      the most robust test in the world; it simply verifies
+#                      that libsysio returns all the entries in the directory
+#
+#
+
+use IPC::Open2;
+
+use strict;
+
+use FindBin;
+use lib "$FindBin::Bin";
+use helper;
+
+sub usage
+{
+  print "Usage: ./test_list.pl [-p|-alpha] <dir> \n";
+  print "       ./test_list.pl -m [-p|-alpha] fstype:mdir dir\n";
+  print "      In the first form, will attempt to verify libsysio's\n";
+  print "      getdirentries.  If no dir is given, will use the \n";
+  print "      current working directory\n";
+  print "      In the second form, will mount the given mdir (of type fstype) in dir.\n";
+  print "      It will then verify the output of libsysio's getdirentries. It will \n";
+  print "      then umount the directory and verify that the umount worked\n";
+  print "      The -p option will print the directory listing\n";
+  print "      The -alpha option is for alpha architecture \n";
+  exit(-1);
+}
+
+
+sub write_print
+{
+  my ($offset, $outfh, $cmdfh, $do_print, $is_alpha) = @_;
+  my $bytes = 0;
+  
+  my $intsize = 8;
+  my $intcmd = "INT";
+  if ($is_alpha == 1) {
+      $intsize = 16;
+      $intcmd = "LONG"
+  }
+  my $shortoffset = $offset+$intsize;
+  my $charoffset = $shortoffset+2;
+  my $stroffset = $charoffset+1;
+  my $cmdstr = 'PRINT $buf '. 
+    "$offset $intsize $intcmd $shortoffset 2 SHORT $charoffset 1 CHAR $stroffset 1 STR\n";
+  helper::send_cmd($cmdfh, $outfh, "PRINT", $cmdstr);
+
+  my $res = <$outfh>;
+  chop($res);
+  my ($inode, $foffset, $size, $type, @names) = split(' ',$res);
+  $size = oct($size);
+  if ($size == 0) {
+    return -1;
+  }
+  my $name = join(' ', @names);
+
+  if ($do_print == 1) {
+    printf(STDOUT "%-35s %-14s %-14s %-6s %-4s\n", $name, $inode, $foffset, $size, $type);
+  }
+
+  return $size;
+}
+
+sub do_print_cmds
+{
+  my ($numbytes, $outfh, $cmdfh, $start, $do_print, $is_alpha) = @_;
+
+  my $offset = 0;
+  my $bytes = 0;
+  my $numfiles = 0;
+  my $i = $start;
+  
+  if ($numbytes == 0) {
+    $numbytes = 8192;
+  }
+  while ($bytes < $numbytes) {
+    my $len = write_print($offset, $outfh, $cmdfh, $do_print, $is_alpha);
+    if ($len <= 0) {
+      # write_print saw a 0 length record, indicating end of dir
+      return $numfiles;
+    }
+    $numfiles++;
+    if ($is_alpha == 0) {
+       $len += $len%4;
+    } else {
+       $len += $len%8;
+    }
+    $offset += $len;
+    $bytes += $len;
+    $i++;
+  }
+  return $numfiles;
+}
+
+sub print_dir_cmd
+{
+
+  my ($outfh, $cmdfh, $start, $mdir, $do_print, $is_alpha) = @_;
+
+  my $cmdstr = "CALL getdirentries ( ".'$fd = CALL open '."$mdir O_RDONLY ) ( ";
+  $cmdstr .= '$buf = ALLOC 8192 ) 8192 $basep'."\n";
+  helper::send_cmd($cmdfh, $outfh, "getdirentries", $cmdstr);
+  
+  # Verify that the sysio call succeeded
+  my $res = helper::verify_cmd($cmdfh, $outfh, "getdirentries");
+  my $numbytes = oct($res);
+  
+  while ($numbytes > 0) {
+
+    do_print_cmds($numbytes, $outfh, $cmdfh, $start, $do_print, $is_alpha);
+
+    $cmdstr = "CALL getdirentries ".'$fd $buf 8192 $basep'."\n";
+    helper::send_cmd($cmdfh, $outfh, "getdirentries", $cmdstr);
+
+    # Verify that the sysio call succeeded
+    my $res = helper::verify_cmd($cmdfh, $outfh, "getdirentries");
+    $numbytes = oct($res);
+  }
+}
+
+sub process_cmd
+{
+  my ($mdir, $tdir, $do_mount, $is_alpha, $do_print) = @_;
+  my $size = 8192;
+  my $done_files = 0;
+
+  # Get tests directory
+  my $testdir = $FindBin::Bin;
+  eval {
+      if ($is_alpha == 1) {
+         open2(\*OUTFILE, \*CMDFILE, "yod -quiet -sz 1 $testdir/test_driver --np");
+      } else {
+         open2(\*OUTFILE, \*CMDFILE, "$testdir/test_driver --np");
+      }
+  };
+
+  if ($@) {
+    if ($@ =~ /^open2/) {
+      warn "open2 failed: $!\n$@\n";
+      return;
+    }
+    die;
+
+  }
+
+  my $outfh = \*OUTFILE;
+  my $cmdfh = \*CMDFILE;
+
+  if ($is_alpha == 0) {
+    helper::send_cmd($cmdfh, $outfh, "init", "CALL init\n");
+  }
+
+  my $start = 0;
+
+  if ($do_mount == 1) {
+    helper::send_cmd($cmdfh, $outfh, "mount", "CALL mount $mdir $tdir\n");
+    print_dir_cmd($outfh, $cmdfh, $start, $tdir, $do_print, $is_alpha);
+  } else {
+    print_dir_cmd($outfh, $cmdfh, $start, $mdir, $do_print, $is_alpha);
+  }  
+
+  # Attempt to unmount and verify the contents
+  if ($do_mount == 1) {
+
+    # Close the dir before we umount
+    my $cmdstr = 'CALL close $fd'."\n";
+    helper::send_cmd($cmdfh, $outfh, "close", $cmdstr);
+   
+    # umount dir
+    helper::send_cmd($cmdfh, $outfh, "umount", "CALL umount $tdir\n");
+
+   
+    # Verify it is umounted
+    $cmdstr = "CALL getdirentries ( ".'$fd2 = CALL open '."$tdir O_RDONLY ) ";
+    $cmdstr .= '$buf 8192 $newp'."\n";
+    helper::send_cmd($cmdfh, $outfh, "getdirentries", $cmdstr);
+    my $res = helper::verify_cmd($cmdfh, $outfh, "getdirentries");
+
+    my $numbytes = oct($res);
+    # The only entries should be . and .., so should return 32
+    if ($numbytes != 32) {
+      helper::print_and_exit($cmdfh, $outfh, 1, "ERROR! Read in $numbytes bytes\n");
+    }
+    # Clean up
+    $cmdstr = 'CALL close $fd2'."\n";
+    helper::send_cmd($cmdfh, $outfh, "close", $cmdstr);
+
+  } else {
+    my $cmdstr = 'CALL close $fd'."\n";
+    helper::send_cmd($cmdfh, $outfh, "getdirentries", $cmdstr);
+  }
+
+  helper::print_and_exit($cmdfh, $outfh, 0, "list test successful\n");
+}
+
+
+# Default dir is cwd
+my @mydir;
+$mydir[0] = "./";
+my $do_mount = 0;
+my $is_alpha = 0;
+my $do_print = 0;
+my $dircnt = 0;
+for (my $i = 0; $i < @ARGV; $i++) 
+{
+  if ($ARGV[$i] eq "-p") {
+    $do_print = 1;
+  } elsif ($ARGV[$i] eq "-m") {
+    $do_mount = 1;
+  } elsif ($ARGV[$i] eq "-alpha") {
+    $is_alpha = 1;
+  } else {
+    $mydir[$dircnt] = $ARGV[$i];
+    $dircnt++;
+  }
+}
+
+if (  ($dircnt == 0) || ($dircnt > 2) ||
+      (($do_mount==1) && ($dircnt < 2)) ||
+      (($do_mount == 0) && ($dircnt > 1)) ) {
+  usage();
+}
+
+my $dir = $mydir[0];
+if ($do_mount == 1) {
+  my $fstype;
+  ($fstype, $dir) = split(/:/, $mydir[0]);
+}
+
+process_cmd($mydir[0], $mydir[1], $do_mount, $is_alpha, $do_print);
+
+exit 0;
diff --git a/libsysio/tests/test_path.c b/libsysio/tests/test_path.c
new file mode 100644 (file)
index 0000000..a7469b3
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef REDSTORM
+#include <getopt.h>
+#else
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#include <assert.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "sysio.h"
+#include "mount.h"
+
+#include "test.h"
+
+/*
+ * Stat files.
+ *
+ * Usage: test_path [path...]
+ *
+ * Without any path arguments, the program reads from standard-in, dealing with
+ * each line as an absolute or relative path until EOF.
+ */
+
+static int statit(const char *path);
+static void usage(void);
+
+int
+main(int argc, char *const argv[])
+{
+       int     i;
+       int     err;
+       int     n;
+       extern int _test_sysio_startup(void);
+
+       /*
+        * Parse command line arguments.
+        */
+       while ((i = getopt(argc, argv, "")) != -1)
+               switch (i) {
+
+               default:
+                       usage();
+               }
+
+       /*
+        * Init sysio lib.
+        */
+       err = _test_sysio_startup();
+       if (err) {
+               errno = -err;
+               perror("sysio startup");
+               exit(1);
+       }
+
+       n = argc - optind;
+
+       /*
+        * Try path(s) listed on command-line.
+        */
+       while (optind < argc) {
+               const char *path;
+
+               path = argv[optind++];
+               (void )statit(path);
+       }
+
+       /*
+        * If no command-line arguments, read from stdin until EOF.
+        */
+       if (!n) {
+               int     doflush;
+               static char buf[4096];
+               size_t  len;
+               char    *cp;
+               char    c;
+
+               doflush = 0;
+               while (fgets(buf, sizeof(buf), stdin) != NULL) {
+                       len = strlen(buf);
+                       cp = buf + len - 1;
+                       c = *cp;
+                       *cp = '\0';
+                       if (!doflush)
+                               statit(buf);
+                       doflush = c == '\n' ? 0 : 1;
+               }
+       }
+
+       /*
+        * Clean up.
+        */
+       _sysio_shutdown();
+
+       return 0;
+}
+
+static int
+statit(const char *path)
+{
+       int     err;
+       struct stat stbuf;
+       char    t;
+       static char buf[4096];
+       ssize_t cc;
+
+       /*
+        * Get file attrs.
+        */
+       err = lstat(path, &stbuf);
+       if (err) {
+               perror(path);
+               return -1;
+       }
+
+       /*
+        * Get readable representation of file type.
+        */
+       if (S_ISDIR(stbuf.st_mode))
+               t = 'd';
+       else if (S_ISCHR(stbuf.st_mode))
+               t = 'c';
+       else if (S_ISBLK(stbuf.st_mode))
+               t = 'b';
+       else if (S_ISREG(stbuf.st_mode))
+               t = 'f';
+#ifdef S_ISFIFO
+       else if (S_ISFIFO(stbuf.st_mode))
+               t = 'p';
+#endif
+#ifdef S_ISLNK
+       else if (S_ISLNK(stbuf.st_mode))
+               t = 'S';
+#endif
+#ifdef S_ISSOCK
+       else if (S_ISSOCK(stbuf.st_mode))
+               t = 's';
+#endif
+#ifdef S_TYPEISMQ
+       else if (S_TYPEISMQ(&stbuf))
+               t = 'q';
+#endif
+#ifdef S_TYPEISSEM
+       else if (S_TYPEISSEM(&stbuf))
+               t = 'M';
+#endif
+#ifdef S_TYPEISSHM
+       else if (S_TYPEISSHM(&stbuf))
+               t = 'm';
+#endif
+       else
+               t = '?';
+
+       /*
+        * Print path and type.
+        */
+       if (S_ISLNK(stbuf.st_mode)) {
+               cc = readlink(path, buf, sizeof(buf));
+               if (cc < 0) {
+                       perror(path);
+                       return -1;
+               }
+       }
+       (void )printf("%s: %c", path, t);
+       if (S_ISLNK(stbuf.st_mode) && (size_t )cc < sizeof(buf))
+               (void )printf(" %.*s", cc, buf);
+       (void )putchar('\n');
+
+       return 0;
+}
+
+static void
+usage()
+{
+
+       (void )fprintf(stderr,
+                      "Usage: test_path"
+                      " [<path> ...\n]");
+
+       exit(1);
+}
diff --git a/libsysio/tests/test_path.pl b/libsysio/tests/test_path.pl
new file mode 100755 (executable)
index 0000000..c68fdc8
--- /dev/null
@@ -0,0 +1,188 @@
+#!/usr/bin/perl -w 
+
+#
+# path test: reads paths from stdin and prints out the path along with its 
+#          : type
+#
+
+use IPC::Open2;
+
+use strict;
+use FindBin;
+use lib "$FindBin::Bin";
+use helper;
+use POSIX;
+use Fcntl ':mode';
+
+sub usage
+{
+  print "Usage ./test_path.pl [path1 path2...] : Print each path listed and its type\n";
+  print "                                      : If no paths are given, stdin is read\n";
+  exit(-1);
+}
+
+sub get_type
+{
+  my $mode = $_[0];
+  my $t = '?';
+
+  if (S_ISDIR($mode)) {
+    $t = 'd';
+  } elsif (S_ISCHR($mode)) {
+    $t = 'c';
+  } elsif (S_ISBLK($mode)) {
+    $t = 'b';
+  } elsif (S_ISREG($mode)) {
+    $t = 'f';
+  } elsif (S_ISFIFO($mode)) {
+    $t = 'p';
+  } elsif (S_ISLNK($mode)) {
+    $t = 'S';
+  } elsif (S_ISSOCK($mode)) {
+    $t = 's';
+  }
+
+  return $t;
+}
+
+sub print_path
+{
+  my ($mode, $path) = @_;
+  
+  my $typechar = get_type($mode);
+  print STDOUT "$path: $typechar\n";
+}
+
+sub process_path
+{
+  my ($cmdfh, $outfh, $bits, $path) = @_;
+
+  # Issue the stat command
+  my $cmdstr = 'CALL stat "';
+  $cmdstr = sprintf("%s%s%s\n", $cmdstr, $path, '" $buf');
+
+  helper::send_cmd($cmdfh, $outfh, "stat", $cmdstr);  
+  helper::verify_cmd($cmdfh, $outfh, "stat");
+
+  # Print out the stat buffer
+  if ($bits == 32) {
+      $cmdstr = 'PRINT $buf 0 8 LONG 12 24 INT 44 8 LONG 52 8 INT 64 24 LONG';
+  } else {
+      $cmdstr = 'PRINT $buf 0 24 LONG 24 16 INT 48 32 LONG 88 8 LONG 104 8 LONG';
+  }
+  $cmdstr .= "\n";
+  helper::send_cmd($cmdfh, $outfh, "PRINT", $cmdstr);
+  
+  my $res = <$outfh>;
+  chop($res);
+  my ( $iodev, $ioino, $iomode, $ionlink, $iouid, $iogid, $iordev, 
+       $iosize, $ioblksize, $ioblks, $ioatime, $iomtime, $ioctime ) 
+      = split(' ', $res);
+   if ($bits == 64) {
+      ( $iodev, $ioino, $ionlink, $iomode, $iouid, $iogid, $iordev, 
+          $iosize, $ioblksize, $ioblks, $ioatime, $iomtime, $ioctime ) 
+         = split(' ', $res);
+  }
+  $iomode = oct($iomode);
+
+  # Print out the path
+  print_path($iomode, $path);
+}
+  
+sub process_cmd
+{
+  my ($usestdin, $isalpha, @paths) = @_;
+
+  my $path;
+  
+  # Get tests directory
+  my $testdir = $FindBin::Bin;
+  eval {
+    if ($isalpha == 0) {
+      open2(\*OUTFILE, \*CMDFILE, "$testdir/test_driver --np");
+    } else {
+      open2(\*OUTFILE, \*CMDFILE, 
+           "yod -batch -quiet -sz 1 $testdir/test_driver --np");
+    }
+  };
+
+  if ($@) {
+    if ($@ =~ /^open2/) {
+      warn "open2 failed: $!\n$@\n";
+      return;
+    }
+    die;
+
+  }
+  my $outfh = \*OUTFILE;
+  my $cmdfh = \*CMDFILE;
+
+  if ($isalpha == 0) {
+    helper::send_cmd($cmdfh, $outfh, "init", "CALL init\n");
+  }
+
+  # Allocate the stat buffer
+  my $cmdstr = '$buf = ALLOC ( $size = CALL sizeof stat )';
+  $cmdstr .= "\n";
+  helper::send_cmd($cmdfh, $outfh, "alloc", $cmdstr);  
+
+   # Attempt to determine type
+  $cmdstr = 'PRINT $size'."\n";
+  helper::send_cmd($cmdfh, $outfh, "print", $cmdstr);  
+  my $statsize = <$outfh>;
+  chop($statsize);
+  $statsize = oct($statsize);
+  my $bits = 32;
+  if ($statsize == 144) {
+      $bits = 64;
+  }
+
+  my $i=0;
+  if ($usestdin) {
+    $path = <STDIN>;
+    if (defined($path)) {
+      chop($path);
+    }
+  } else {
+    $path = $paths[$i++];
+  }
+
+  # Enter a loop, reading a path argument and processing it with each 
+  # phase of loop.  
+  while (defined($path)) {
+
+    process_path($cmdfh, $outfh, $bits, $path);
+    if ($usestdin) {
+      $path = <STDIN>;
+
+      if (defined($path)) {
+       chop($path);
+      }
+      if ($path eq "quit") {
+       helper::print_and_exit($cmdfh, $outfh, 0, "path test successful\n");
+      }
+    } else {
+      $path = $paths[$i++];
+    }
+  }
+  helper::print_and_exit($cmdfh, $outfh, 0, "path test successful\n");
+}
+
+
+my $usestdin = 0;
+my $isalpha = 0;
+
+# The -alpha arg must be before the paths
+# (if they exist)
+if ( (@ARGV > 0) && ($ARGV[0] eq "-alpha")) {
+  $isalpha = 1;
+  shift(@ARGV);
+}
+
+if (@ARGV == 0) {
+  $usestdin = 1;
+} 
+
+process_cmd($usestdin, $isalpha, @ARGV);
+
diff --git a/libsysio/tests/test_regions.c b/libsysio/tests/test_regions.c
new file mode 100644 (file)
index 0000000..c6120da
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is regionsrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2004 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a regions of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#define _BSD_SOURCE
+
+#if (_LARGEFILE64_SOURCE && \
+     ((defined(__STDC_VERSION__) && __STDC_VERSION__ == 199901L)))
+#define        GO64
+#else
+#warning Cannot prompt the 64-bit interface
+#endif
+
+#if defined(GO64) && defined(__GLIBC__)
+#define  _ISOC99_SOURCE 1
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifndef REDSTORM
+#include <getopt.h>
+#endif
+#include <limits.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "mount.h"
+
+#include "test.h"
+
+/*
+ * Copy one file to another.
+ *
+ * Usage: test_regions [-x] \
+ *             {r,w} <off> <count> <path>
+ *
+ * Destination will not be overwritten if it already exist.
+ */
+
+#if (_LARGEFILE64_SOURCE && \
+     ((defined(__STDC_VERSION__) && __STDC_VERSION__ == 199901L) || \
+      (defined(_ISOC99_SOURCE) && _ISOC99_SOURCE)))
+#define        GO64
+#else
+#warning Cannot prompt the 64-bit interface
+#endif
+
+char   which;
+#ifdef GO64
+int    use64 = 0;                                      /* 64-bit interface? */
+#endif
+
+void   usage(void);
+
+int
+main(int argc, char * const argv[])
+{
+       int     i;
+       int     err;
+       long    l;
+       off_t   off;
+#ifdef GO64
+       long long ll;
+       off64_t off64;
+#endif
+       char    *cp;
+       unsigned long nbytes;
+       const char *path;
+       char    *buf;
+       int     flags;
+       int     fd;
+       ssize_t cc;
+       extern int _test_sysio_startup(void);
+
+       /*
+        * Parse command-line args.
+        */
+       while ((i = getopt(argc,
+                          argv,
+#ifdef __GLIBC__
+                          "+"
+#endif
+#ifdef GO64
+                          "x"
+#endif
+                          "")) != -1)
+               switch (i) {
+
+#ifdef GO64
+               case 'x':
+                       use64 = 1;
+                       break;
+#endif
+               default:
+                       usage();
+               }
+
+       if (argc - optind != 4)
+               usage();
+
+       which = *argv[optind];
+       if (strlen(argv[optind]) != 1 || !(which == 'r' || which == 'w')) {
+               (void )fprintf(stderr, "Which op?\n");
+               exit(1);
+       }
+       optind++;
+       off = l =
+#ifdef GO64
+           ll = strtoll(argv[optind++], &cp, 0);
+#else
+           strtol(argv[optind++], &cp, 0);
+#endif
+#ifdef GO64
+       off64 = ll;
+#endif
+       if (*cp != '\0' ||
+#ifdef GO64
+           ((ll == LLONG_MIN || ll == LLONG_MAX) && errno == ERANGE) ||
+           off64 != ll || (!use64 && off != ll)
+#else
+           ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) ||
+           off != l
+#endif
+          ) {
+               (void )fprintf(stderr, "Offset out of range\n");
+               exit(1);
+       }
+       nbytes = strtoul(argv[optind++], &cp, 0);
+       if (*cp != '\0' || (nbytes == ULONG_MAX && errno == ERANGE)) {
+               (void )fprintf(stderr, "Transfer count out of range\n");
+               exit(1);
+       }
+       if (!(argc - optind))
+               usage();
+       path = argv[optind++];
+
+       err = _test_sysio_startup();
+       if (err) {
+               errno = -err;
+               perror("sysio startup");
+               exit(1);
+       }       
+
+       (void )umask(022);
+
+       buf = malloc(nbytes);
+       if (!buf) {
+               perror("malloc");
+               err = 1;
+               goto out;
+       }
+       (void )memset(buf, 0, nbytes);
+
+       err = 0;
+       flags = which == 'r' ? O_RDONLY : (O_WRONLY|O_CREAT|O_EXCL);
+#ifdef GO64
+       if (use64)
+               flags |= O_LARGEFILE;
+#endif
+       fd = open(path, flags, 0666);
+       if (fd < 0) {
+               perror(path);
+               err = 1;
+               goto error;
+       }
+#ifdef GO64
+       if (use64)
+               off64 = lseek64(fd, off64, SEEK_SET);
+       else
+               off64 =
+#endif
+                 off = lseek(fd, off, SEEK_SET);
+#ifdef GO64
+       if ((use64 && off64 < 0) || (!use64 && off < 0)) {
+               perror(use64 ? "lseek64" : "lseek");
+               err = 1;
+               goto error;
+       }
+#else
+       if (off < 0) {
+               perror("lseek");
+               err = 1;
+               goto error;
+       }
+#endif
+       if (which == 'r')
+               cc = read(fd, buf, nbytes);
+       else
+               cc = write(fd, buf, nbytes);
+       if (cc < 0) {
+               perror(path);
+               err = 1;
+               goto error;
+       }
+#ifdef GO64
+       if (use64) {
+               off64 = lseek64(fd, 0, SEEK_CUR);
+       } else
+               off64 =
+#endif
+                 off = lseek(fd, 0, SEEK_CUR);
+       (void )printf(("%s%s@"
+#ifdef GO64
+                      "%lld"
+#else
+                      "%ld"
+#endif
+                      ": %ld, off "
+#ifdef GO64
+                      "%lld"
+#else
+                      "%ld"
+#endif
+                      "\n"),
+                     which == 'r' ? "read" : "write",
+#ifdef GO64
+                     use64 ? "64" : "",
+                     ll,
+#else
+                     "",
+                     l,
+#endif
+                     (long )cc,
+#ifdef GO64
+                     (long long int)off64
+#else
+                     off
+#endif
+                     );
+
+error:
+       if (fd > 0 && close(fd) != 0)
+               perror(path);
+       free(buf);
+out:
+       _sysio_shutdown();
+
+       return err;
+}
+
+void
+usage()
+{
+
+       (void )fprintf(stderr,
+                      "Usage: test_regions "
+#ifdef GO64
+                      "[-x] "
+#endif
+                      " {r,w} <offset> <nbytes> <path>\n");
+       exit(1);
+}
diff --git a/libsysio/tests/test_rename.c b/libsysio/tests/test_rename.c
new file mode 100644 (file)
index 0000000..7b78429
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#define _BSD_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#ifndef REDSTORM
+#include <getopt.h>
+#endif
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/queue.h>
+
+#include "sysio.h"
+#include "mount.h"
+
+#include "fs_native.h"
+
+#include "test.h"
+
+/*
+ * Rename a file system object.
+ *
+ * Usage: test_rename <src> <dest>
+ */
+
+void   usage(void);
+int    rename_file(const char *spath, const char *dpath);
+
+int
+main(int argc, char * const argv[])
+{
+       int     i;
+       int     err;
+       const char *spath, *dpath;
+       extern int _test_sysio_startup(void);
+
+       /*
+        * Parse command-line args.
+        */
+       while ((i = getopt(argc,
+                          argv,
+                          ""
+                          )) != -1)
+               switch (i) {
+
+               default:
+                       usage();
+               }
+
+       if (!(argc - optind))
+               usage();
+
+       err = _test_sysio_startup();
+       if (err) {
+               errno = -err;
+               perror("sysio startup");
+               exit(1);
+       }       
+
+       (void )umask(022);
+
+       /*
+        * Source
+        */
+       spath = argv[optind++];
+       if (!(argc - optind))
+               usage();
+       /*
+        * Destination
+        */
+       dpath = argv[optind++];
+       if (argc - optind)
+               usage();
+
+       err = rename(spath, dpath);
+       if (err)
+               perror("rename");
+
+       _sysio_shutdown();
+
+       return err;
+}
+
+void
+usage()
+{
+
+       (void )fprintf(stderr,
+                      "Usage: test_rename"
+                      " source destination\n");
+       exit(1);
+}
diff --git a/libsysio/tests/test_rw.pl b/libsysio/tests/test_rw.pl
new file mode 100755 (executable)
index 0000000..74a7fa0
--- /dev/null
@@ -0,0 +1,537 @@
+#!/usr/bin/perl -w
+
+#
+# rw test: Write a buffer out using all the different writes, read it back
+#          and make sure it matches
+# 
+#
+
+use IPC::Open2;
+
+use strict;
+use FindBin;
+use lib "$FindBin::Bin";
+use helper;
+
+sub usage
+{
+  print "Usage: ./test_rw.pl [-alpha] <file>: Write to/read from file\n";
+  exit(-1);
+}
+
+sub verify_result
+{
+       my ($cmdfh, $outfh, $cmdstr, $exp_val, $eq_op) = @_;
+       my $print_err = 0;
+
+       my $res = helper::verify_cmd($cmdfh, $outfh, $cmdstr);
+       $res = oct($res);
+
+       if ($eq_op eq "!=") {
+               if ($res != $exp_val) {
+                       print STDOUT "Error! $cmdstr returned $res insted of $exp_val\n";
+                       exit 1;
+               }
+       } else {
+               if ($eq_op eq ">") {
+                       if ($res > $exp_val) {
+                               $print_err = 1;
+                       }
+               } elsif ($eq_op eq "<")  {
+                       if ($res < $exp_val) {
+                               $print_err = 1;
+                       }
+               } elsif ($eq_op eq "==") {
+                       if ($res == $exp_val) {
+                               $print_err = 1;
+                       }
+               }
+               if ($print_err == 1) {
+                       helper::print_and_exit($cmdfh, $outfh, 1, "Error! $cmdstr returned $res\n");
+               }
+       }
+}
+               
+sub do_iowait
+{
+       my ($cmdfh, $outfh, $id, $rwcmd, $exp_size) = @_;
+
+       my $cmdstr = "CALL iowait $id\n";
+       helper::send_cmd($cmdfh, $outfh, "iowait", $cmdstr);
+
+       my $descstr = "iowait:$rwcmd";
+       verify_result($cmdfh, $outfh, $descstr, $exp_size, "!=");
+}
+
+sub set_iovecs
+{
+       my ($cmdfh, $outfh, $callnum) = @_;
+       my $NUMVECS = 8;
+       my $VECLEN = $NUMVECS * 1024;
+
+       my $varname = "iovbuf$callnum";
+
+       # Get size of iovecs
+       my $cmdstr = '$iovsize = CALL sizeof iovec'."\n";
+       helper::send_cmd($cmdfh, $outfh, "sizeof", $cmdstr);
+       my $size = helper::verify_cmd($cmdfh, $outfh, "sizeof iovec");
+       $size = oct($size);
+       $size = $size * $NUMVECS;
+
+       # Allocate iovec buffer
+       $cmdstr = '$'."$varname = ALLOC $size\n";
+       helper::send_cmd($cmdfh, $outfh, "alloc", $cmdstr);
+       
+
+       # Now initilize all of them
+       my $off = 0;
+       for (my $i=0; $i < $NUMVECS; $i++) {
+               $cmdstr = 'CALL init_iovec $buf '."$off $VECLEN $i ". '$'."$varname\n";
+               helper::send_cmd($cmdfh, $outfh, "init_iovec", $cmdstr);
+               helper::verify_cmd($cmdfh, $outfh, "init_iovec");
+               $off += $VECLEN;
+       }
+
+       return $varname;
+}
+
+
+sub set_xtvecs
+{
+       my ($cmdfh, $outfh, $callnum, $startoff) = @_;
+       my $VECLEN = 4 * 8 * 1024;
+
+       my $varname = "xtvbuf$callnum";
+
+       # Get size of iovecs
+       my $cmdstr = '$xtvsize = CALL sizeof xtvec'."\n";
+       helper::send_cmd($cmdfh, $outfh, "sizeof", $cmdstr);
+       my $size = helper::verify_cmd($cmdfh, $outfh, "sizeof xtvec");
+       $size = oct($size);
+       $size = $size * 2;
+
+       # Allocate iovec buffer
+       $cmdstr = '$'."$varname = ALLOC $size\n";
+       helper::send_cmd($cmdfh, $outfh, "alloc", $cmdstr);
+       
+
+       # Now initilize all of them
+       my $off = $startoff;
+       for (my $i=0; $i < 2; $i++) {
+               $cmdstr = "CALL init_xtvec $off $VECLEN $i ". '$'."$varname\n";
+               helper::send_cmd($cmdfh, $outfh, "init_xtvec", $cmdstr);
+               helper::verify_cmd($cmdfh, $outfh, "init_xtvec");
+               $off += $VECLEN;
+       }
+
+       return $varname;
+}
+
+sub check_buf
+{
+
+       my ($cmdfh, $outfh, $bufsize, $readcmd) = @_;
+       my $i;
+       my $digit = 0;
+       my $offset = 0;
+       my $cmdstr;
+
+       for ($i =0; $i < 64; $i++) {
+               $cmdstr = 'CALL checkbuf $buf'. " 1024 $digit $offset\n";
+               helper::send_cmd($cmdfh, $outfh, "checkbuf", $cmdstr);
+               my $res = helper::verify_cmd($cmdfh, $outfh, "checkbuf");
+               $res = oct($res);
+
+               if ($res != 0) {
+                       print STDOUT "Checkbuf returned $res\n";
+                       helper::print_and_exit($cmdfh, $outfh, 1, "$readcmd did not return all $digit 's\n");
+               } 
+       
+               $offset += 1024;
+               $digit++;
+               if ($digit == 10) {
+                       $digit = 0;
+               }
+       }
+
+       # Now fill the buffer with 0s
+       $cmdstr = '$buf = CALL setbuf 0 '."$bufsize ".'$buf'." 0\n";
+  helper::send_cmd($cmdfh, $outfh, "setbuf", $cmdstr);
+       
+}
+
+sub fill_buf
+{
+       my ($cmdfh, $outfh) = @_;
+       my $i;
+       my $digit=0;
+       my $cmdstr;
+       my $offset = 0;
+
+       # Fill up the buffer with alternating digits
+       # from 0-9
+
+       for ($i=0; $i < 64 ; $i++) {
+               my $cmdstr = "CALL setbuf $digit 1024 ".'$buf'." $offset\n";
+               helper::send_cmd($cmdfh, $outfh, "setbuf", $cmdstr);            
+               $offset += 1024;
+               $digit++;
+               if ($digit == 10) {
+                       $digit = 0;
+               }
+       }
+}
+
+sub do_rwcalls
+{
+               my ($cmdfh, $outfh, $bufsize) = @_;
+               my $IOID_FAIL = 0;
+               my $NUMVECS = 8;
+
+               # Initilize buffer
+               fill_buf($cmdfh, $outfh);
+
+               # write 64K bytes at pos 0
+               my $cmdstr = 'CALL write $fd $buf '."$bufsize\n";
+               helper::send_cmd($cmdfh, $outfh, "write", $cmdstr);
+               verify_result($cmdfh, $outfh, "write", $bufsize, "!=");
+
+               # Initilize buffer
+               fill_buf($cmdfh, $outfh);
+
+               # iwrite 64K bytes at pos 64K
+               $cmdstr = '$id1 = CALL iwrite $fd $buf '."$bufsize\n";
+               helper::send_cmd($cmdfh, $outfh, "iwrite", $cmdstr);
+               verify_result($cmdfh, $outfh, "iwrite", $IOID_FAIL, "==");
+               do_iowait($cmdfh, $outfh, '$id1', "iwrite", $bufsize);
+               
+               # Set up the iovecs
+               my $iovcnt = 0;
+               my $iovname = set_iovecs($cmdfh, $outfh, $iovcnt);
+
+               # Initilize buffer
+               fill_buf($cmdfh, $outfh);
+               
+               # writev 64K bytes using 8 iovecs at pos 128K
+               $cmdstr = 'CALL writev $fd $'."$iovname $NUMVECS\n";
+               helper::send_cmd($cmdfh, $outfh, "writev", $cmdstr);
+               verify_result($cmdfh, $outfh, "writev", $bufsize, "!=");
+
+               # Initilize buffer
+               fill_buf($cmdfh, $outfh);
+               
+               # iwritev 64K bytes using 8 iovecs at pos 192K
+               $cmdstr = '$id2 = CALL iwritev $fd $'."$iovname $NUMVECS\n";
+               helper::send_cmd($cmdfh, $outfh, "iwritev", $cmdstr);
+               verify_result($cmdfh, $outfh, "iwritev", $IOID_FAIL, "==");
+               do_iowait($cmdfh, $outfh, '$id2', "iwritev", $bufsize);
+
+               # Initilize buffer
+               fill_buf($cmdfh, $outfh);
+
+               # pwrite 64K bytes starting at pos 256K
+               my $offset = 256 * 1024;
+               $cmdstr = 'CALL pwrite $fd $buf '."$bufsize $offset\n";
+               helper::send_cmd($cmdfh, $outfh, "pwrite", $cmdstr);
+               verify_result($cmdfh, $outfh, "pwrite", $bufsize, "!=");
+               
+               # Initilize buffer
+               fill_buf($cmdfh, $outfh);
+
+               # ipwrite 64K bytes starting at pos 320K
+               $offset = 320 * 1024;
+               $cmdstr = '$id3 = CALL ipwrite $fd $buf '."$bufsize $offset\n";
+               helper::send_cmd($cmdfh, $outfh, "ipwrite", $cmdstr);
+               verify_result($cmdfh, $outfh, "ipwrite", $IOID_FAIL, "==");
+               do_iowait($cmdfh, $outfh, '$id3', "ipwrite", $bufsize);
+
+               $iovcnt++;
+
+               # Initilize buffer
+               fill_buf($cmdfh, $outfh);
+
+               # pwritev using 8 8K buffers at offset 384
+               $offset = 384 * 1024;
+               $cmdstr = 'CALL pwritev $fd $'."$iovname $NUMVECS $offset\n";
+               helper::send_cmd($cmdfh, $outfh, "pwritev", $cmdstr);
+               verify_result($cmdfh, $outfh, "pwritev", $bufsize, "!=");       
+
+               # Initilize buffer
+               fill_buf($cmdfh, $outfh);
+
+               # ipwritev using 8 8k buffers at offset 448
+               $offset = 448 * 1024;
+               $cmdstr = '$id4 = CALL ipwritev $fd $'."$iovname $NUMVECS $offset\n";
+               helper::send_cmd($cmdfh, $outfh, "ipwritev", $cmdstr);
+               verify_result($cmdfh, $outfh, "ipwritev", $IOID_FAIL, "==");
+               do_iowait($cmdfh, $outfh, '$id4', "ipwritev", $bufsize);
+
+               # Set up the xtvecs.  Starting offset is 512K
+               my $xtvcnt = 0;
+               my $xtvname = set_xtvecs($cmdfh, $outfh, $xtvcnt, 512 * 1024);
+
+               $iovcnt++;
+
+               # Initilize buffer
+               fill_buf($cmdfh, $outfh);
+               
+               # Call writex using 8 8k buffers at offset 512
+               $cmdstr = 'CALL writex $fd $'."$iovname $NUMVECS ".'$'."$xtvname 2\n";
+               helper::send_cmd($cmdfh, $outfh, "writex", $cmdstr);
+               verify_result($cmdfh, $outfh, "writex", $bufsize, "!=");
+
+               # Call iwritex using 8 8k buffers starting at offset 576
+               # Re-setup xtvs since I am lazy.  This is leaking memory like
+               # a seive...
+               $xtvcnt++;
+               $xtvname = set_xtvecs($cmdfh, $outfh, $xtvcnt, 576 * 1024);
+
+               $iovcnt++;
+
+               # Initilize buffer
+               fill_buf($cmdfh, $outfh);
+
+               $cmdstr = '$id5 = CALL iwritex $fd $'."$iovname $NUMVECS ".'$'."$xtvname 2\n";
+               helper::send_cmd($cmdfh, $outfh, "iwritex", $cmdstr);
+               verify_result($cmdfh, $outfh, "iwritex", $IOID_FAIL, "==");
+               do_iowait($cmdfh, $outfh, '$id5', "iwritex", $bufsize);
+
+               # Now do the reads
+
+               # Lseek back to pos 0
+               $cmdstr = 'CALL lseek $fd 0 SEEK_SET'."\n";
+               helper::send_cmd($cmdfh, $outfh, "sizeof", $cmdstr);
+               helper::verify_cmd($cmdfh, $outfh, "sizeof xtvec");
+
+               # fill the buffer with 0's
+               $cmdstr = '$buf = CALL setbuf 0 '."$bufsize ".'$buf'." 0\n";
+               helper::send_cmd($cmdfh, $outfh, "setbuf", $cmdstr);
+
+               # read 64K bytes from pos 0
+               $cmdstr = 'CALL read $fd $buf '."$bufsize\n";
+               helper::send_cmd($cmdfh, $outfh, "read", $cmdstr);
+               verify_result($cmdfh, $outfh, "read", $bufsize, "!=");
+
+               # Check the buffer to make sure it matches
+               check_buf($cmdfh, $outfh, $bufsize, "read");
+
+               # iread 64K bytes at pos 64K
+               $cmdstr = '$id6 = CALL iread $fd $buf '."$bufsize\n";
+               helper::send_cmd($cmdfh, $outfh, "iread", $cmdstr);
+               verify_result($cmdfh, $outfh, "iread", $IOID_FAIL, "==");
+               do_iowait($cmdfh, $outfh, '$id6', "iread", $bufsize);
+               check_buf($cmdfh, $outfh, $bufsize, "iread");
+
+               $iovcnt++;
+
+               # readv 64K bytes using 8 iovecs at pos 128K
+               $cmdstr = 'CALL readv $fd $'."$iovname $NUMVECS\n";
+               helper::send_cmd($cmdfh, $outfh, "readv", $cmdstr);
+               verify_result($cmdfh, $outfh, "readv", $bufsize, "!=");
+               check_buf($cmdfh, $outfh, $bufsize, "readv");           
+
+               # ireadv 64K bytes using 8 iovecs at pos 192K
+               $cmdstr = '$id7 = CALL ireadv $fd $'."$iovname $NUMVECS\n";
+               helper::send_cmd($cmdfh, $outfh, "ireadv", $cmdstr);
+               verify_result($cmdfh, $outfh, "ireadv", $IOID_FAIL, "==");
+               do_iowait($cmdfh, $outfh, '$id7', "ireadv", $bufsize);
+               check_buf($cmdfh, $outfh, $bufsize, "ireadv");
+
+               # pread64K bytes starting at pos 256K
+               $offset = 256 * 1024;
+               $cmdstr = 'CALL pread $fd $buf '."$bufsize $offset\n";
+               helper::send_cmd($cmdfh, $outfh, "pread", $cmdstr);
+               verify_result($cmdfh, $outfh, "pread", $bufsize, "!=");
+               check_buf($cmdfh, $outfh, $bufsize, "pread");
+               
+               # ipread 64K bytes starting at pos 320K
+               $offset = 320 * 1024;
+               $cmdstr = '$id8 = CALL ipread $fd $buf '."$bufsize $offset\n";
+               helper::send_cmd($cmdfh, $outfh, "ipread", $cmdstr);
+               verify_result($cmdfh, $outfh, "ipread", $IOID_FAIL, "==");
+               do_iowait($cmdfh, $outfh, '$id8', "ipread", $bufsize);
+               check_buf($cmdfh, $outfh, $bufsize, "ipread");
+
+
+               $iovcnt++;
+
+               # preadv using 8 8K buffers at offset 384
+               $offset = 384 * 1024;
+               $cmdstr = 'CALL preadv $fd $'."$iovname $NUMVECS $offset\n";
+               helper::send_cmd($cmdfh, $outfh, "preadv", $cmdstr);
+               verify_result($cmdfh, $outfh, "preadv", $bufsize, "!=");        
+               check_buf($cmdfh, $outfh, $bufsize, "preadv");
+               
+               # ipreadv using 8 8k buffers at offset 448
+               $offset = 448 * 1024;
+               $cmdstr = '$id9 = CALL ipreadv $fd $'."$iovname $NUMVECS $offset\n";
+               helper::send_cmd($cmdfh, $outfh, "ipreadv", $cmdstr);
+               verify_result($cmdfh, $outfh, "ipreadv", $IOID_FAIL, "==");
+               do_iowait($cmdfh, $outfh, '$id9', "ipreadv", $bufsize);
+               check_buf($cmdfh, $outfh, $bufsize, "ipreadv");
+
+               # Set up the xtvecs.  Starting offset is 512K
+               $xtvcnt++;
+               $xtvname = set_xtvecs($cmdfh, $outfh, $xtvcnt, 512 * 1024);
+
+               $iovcnt++;
+               
+               # Call readx using 8 8k buffers at offset 512
+               $cmdstr = 'CALL readx $fd $'."$iovname $NUMVECS ".'$'."$xtvname 2\n";
+               helper::send_cmd($cmdfh, $outfh, "readx", $cmdstr);
+               verify_result($cmdfh, $outfh, "readx", $bufsize, "!=");
+               check_buf($cmdfh, $outfh, $bufsize, "readx");
+
+               # Call ireadx using 8 8k buffers starting at offset 576
+               # Re-setup xtvs since I am lazy.  This is leaking memory like
+               # a seive...
+               $xtvcnt++;
+               $xtvname = set_xtvecs($cmdfh, $outfh, $xtvcnt, 576 * 1024);
+
+               $iovcnt++;
+
+               $cmdstr = '$id10 = CALL ireadx $fd $'."$iovname $NUMVECS ".'$'."$xtvname 2\n";
+               helper::send_cmd($cmdfh, $outfh, "ireadx", $cmdstr);
+               verify_result($cmdfh, $outfh, "ireadx", $IOID_FAIL, "==");
+               do_iowait($cmdfh, $outfh, '$id10', "ireadx", $bufsize);
+               check_buf($cmdfh, $outfh, $bufsize, "ireadx");
+}
+
+
+sub check_array
+{
+       my ($exp_digit, @arr) = @_;
+       my $exp_char;
+       my $pos = 0;
+
+       if ($exp_digit == 0) {
+               $exp_char = "\\0";
+       } elsif ($exp_digit < 7) {
+               $exp_char = "00".$exp_digit;
+       } elsif ($exp_digit == 7) {
+               $exp_char = "\\a";
+       } elsif ($exp_digit == 8) {
+               $exp_char = "\\b";
+       } elsif ($exp_digit == 9) {
+               $exp_char = "\\t";
+       } else {
+               print STDERR "Invalid expected digit $exp_digit\n";
+               return(1);
+       }
+
+       foreach my $str (@arr) {
+               if ($str ne $exp_char) {
+                       print STDERR "At pos $pos got digit $str instead of $exp_char\n";
+                       return(1);
+               }
+               $pos++;
+       }
+
+       return(0);
+}
+
+# Perform an od on the output and verify that the output makes
+# sense
+sub od_verify
+{
+       my ($cmdfh, $outfh, $file) = @_;
+       my $exp_digit = 0;
+
+       # Do an od in order to verify the contents of the file
+       system("od -c $file > tmp.out.$$");
+       open(ODFILE, "<tmp.out.$$") || 
+                       helper::print_and_exit($cmdfh, $outfh, 1, "Unable to open tmp.out.$$\n");
+
+       while (<ODFILE>) {
+               if (/^\*/) {
+                       # Do nothing...
+               } else {
+                       my ($lineno, @nums) = split($_);
+                       if (check_array($exp_digit, @nums) != 0) {
+                               helper::print_and_exit($cmdfh, $outfh, 1, "At line $lineno, got unexpected result\n");
+                       }
+                       if ($exp_digit < 9) {
+                               $exp_digit ++;
+                       } else {
+                               $exp_digit = 0;
+                       }
+               }
+       }
+
+       close(ODFILE);
+       system("rm -f tmp.out.$$");
+}
+
+sub process_cmd
+{
+  my ($file, $is_alpha) = @_;
+  
+  # Get tests directory
+  my $testdir = $FindBin::Bin;
+       my $bufsize = 65536;
+
+  eval {
+      if ($is_alpha == 0) {
+                                       open2(\*OUTFILE, \*CMDFILE, "$testdir/test_driver --np");
+      } else {
+                                       open2(\*OUTFILE, \*CMDFILE, "yod -quiet -sz 1 $testdir/test_driver --np");
+      }
+  };
+
+  if ($@) {
+    if ($@ =~ /^open2/) {
+      warn "open2 failed: $!\n$@\n";
+      return;
+    }
+    die;
+
+  }
+
+  my $outfh = \*OUTFILE;
+  my $cmdfh = \*CMDFILE;
+
+  if ($is_alpha == 0) {
+    helper::send_cmd($cmdfh, $outfh, "init", "CALL init\n");
+  }
+  
+  # Open file
+  my $cmdstr = '$fd = CALL open '."$file O_RDWR|O_CREAT 0777\n";
+  helper::send_cmd($cmdfh, $outfh, "open", $cmdstr);
+       helper::verify_cmd($cmdfh, $outfh, $cmdstr);
+
+   
+  # Allocate buffer
+  $cmdstr = '$buf = ALLOC '."$bufsize\n";
+  helper::send_cmd($cmdfh, $outfh, "ALLOC", $cmdstr);
+
+
+       do_rwcalls($cmdfh, $outfh, $bufsize);
+
+  # Clean up
+  $cmdstr = 'CALL close $fd'."\n";
+  helper::send_cmd($cmdfh, $outfh, "close", $cmdstr);
+
+       # Verify it worked
+       od_verify($cmdfh, $outfh, $file);
+
+       system("rm -f $file");
+  helper::print_and_exit($cmdfh, $outfh, 0, "rw test successful\n");
+}
+
+my $currarg = 0;
+my $is_alpha = 0;
+
+if (@ARGV < 1) {
+  usage;
+} elsif (@ARGV > 1 ) {
+  if ($ARGV[$currarg++] eq "-alpha") {
+    $is_alpha = 1;
+  }
+}
+
+my $file = $ARGV[$currarg];
+
+process_cmd($file, $is_alpha);
+
+
+exit 0;
diff --git a/libsysio/tests/test_stats.c b/libsysio/tests/test_stats.c
new file mode 100644 (file)
index 0000000..2865a02
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#define _BSD_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#ifndef REDSTORM
+#include <getopt.h>
+#endif
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/queue.h>
+#ifdef notdef
+#include <sys/statvfs.h>
+#endif
+
+#include "sysio.h"
+#include "mount.h"
+
+#include "test.h"
+
+/*
+ * Get stats of file and file system.
+ *
+ * Usage: test_stats [<path> ...]
+ */
+
+void   usage(void);
+void   do_stats(const char *path);
+
+int
+main(int argc, char * const argv[])
+{
+       int     i;
+       int     err;
+       extern int _test_sysio_startup(void);
+
+       /*
+        * Parse command-line args.
+        */
+       while ((i = getopt(argc, argv, "")) != -1)
+               switch (i) {
+
+               default:
+                       usage();
+               }
+
+       err = _test_sysio_startup();
+       if (err) {
+               errno = -err;
+               perror("sysio startup");
+               exit(1);
+       }       
+
+       (void )umask(022);
+
+       while (optind < argc)
+               do_stats(argv[optind++]);
+
+       /*
+        * Clean up.
+        */
+       _sysio_shutdown();
+
+       return 0;
+}
+
+void
+usage()
+{
+
+       (void )fprintf(stderr,
+                      "Usage: test_stats"
+                      " source destination\n");
+       exit(1);
+}
+
+void
+do_stats(const char *path)
+{
+       int     fd;
+       int     err;
+       struct stat stbuf1, stbuf2;
+#ifdef  notdef
+       struct statvfs stvfsbuf1, stvfsbuf2;
+#endif
+
+       fd = open(path, O_RDONLY);
+       if (fd < 0) {
+               perror(path);
+               return;
+       }
+       err = fstat(fd, &stbuf1);
+       if (!err)
+               err = stat(path, &stbuf2);
+#ifdef notdef
+       if (!err)
+               err = fstatvfs(fd, &stvfsbuf1);
+       if (!err)
+               err = statvfs(path, &stvfsbuf1);
+#endif
+       if (err) {
+               perror(path);
+               goto out;
+       }
+       if (stbuf1.st_dev != stbuf2.st_dev ||
+           stbuf1.st_ino != stbuf2.st_ino) {
+               (void )fprintf(stderr, "%s: [f]stat info mismatch\n", path);
+               goto out;
+       }
+#ifdef notdef
+       if (stvfsbuf1.f_fsid != stvfsbuf2.f_fsid) {
+               (void )fprintf(stderr, "%s: [f]statvfs info mismatch\n", path);
+       }
+#endif
+       printf("%s:"
+              " dev %lu,"
+              " ino %lu,"
+              " mode %lu,"
+              " nlink %lu,"
+              " uid %lu,"
+              " gid %lu,"
+              " rdev %lu,"
+              " size %llu,"
+              " blksize %lu,"
+              " blocks %lu,"
+              " atime %lu,"
+              " mtime %lu,"
+              " ctime %lu"
+              "\n",
+              path,
+              (unsigned long )stbuf1.st_dev,
+              (unsigned long )stbuf1.st_ino,
+              (unsigned long )stbuf1.st_mode,
+              (unsigned long )stbuf1.st_nlink,
+              (unsigned long )stbuf1.st_uid,
+              (unsigned long )stbuf1.st_gid,
+              (unsigned long )stbuf1.st_rdev,
+              (unsigned long long)stbuf1.st_size,
+              (unsigned long )stbuf1.st_blksize,
+              (unsigned long )stbuf1.st_blocks,
+              (unsigned long )stbuf1.st_atime,
+              (unsigned long )stbuf1.st_mtime,
+              (unsigned long )stbuf1.st_ctime);
+out:
+       if (close(fd) != 0)
+               perror("closing file");
+}
diff --git a/libsysio/tests/test_stats.pl b/libsysio/tests/test_stats.pl
new file mode 100755 (executable)
index 0000000..fee6a32
--- /dev/null
@@ -0,0 +1,268 @@
+#!/usr/bin/perl -w
+
+#
+# stats test: Verifies that the set of stat calls (stat, fstat, fstatvfs, and 
+#             statvfs) return the same items and that the calls return the
+#             same items as Perl's stat call (which would use a native library
+#             and not libsysio)
+#
+#
+
+use IPC::Open2;
+
+use strict;
+use FindBin;
+use lib "$FindBin::Bin";
+use helper;
+
+sub usage
+{
+  print "Usage ./test_stats.pl file : Verifies that the set of stat calls (stat, \n";
+  print "                           : fstat, fstatvfs, statvfs) return the same set\n";
+  print "                           : of stats for file and that the calls return \n";
+  print "                           : the same items as Perl's stat call (which \n";
+  print "                           : would use a native library and not libsysio)\n";
+  exit(-1);
+}
+
+# Compares the output of Perl's stat function with the output
+# from libsysio's stat
+sub cmp_stats
+{
+
+    my ( $cmdfh, $outfh, $is_alpha, $bits, @stats) = @_;
+
+
+    my ($iodev, $ioino, $iomode, $ionlink, $iouid, $iogid, $iordev, 
+       $iosize, $ioblksize, $ioblks, $ioatime, $iomtime, $ioctime, @pstats) =
+           @stats;
+
+    if ($is_alpha == 1) {
+       ($iodev, $ioino, $iomode, $ionlink, $iouid, $iogid, $iordev, 
+           $iosize, $ioatime, $iomtime, $ioctime, $ioblks, $ioblksize, @pstats) =
+               @stats;
+    }
+    if ($bits == 64) {
+       ($iodev, $ioino, $ionlink, $iomode,  $iouid, $iogid, $iordev, 
+           $iosize, $ioblksize, $ioblks, $ioatime, $iomtime, $ioctime,@pstats) =
+               @stats;
+    }
+    my ($pdev, $pino, $pmode, $pnlink, $puid, $pgid, $prdev,
+       $psize, $patime, $pmtime, $pctime, $pblksize, $pblks) = @pstats;
+
+#  helper::cmp_nums($cmdfh, $outfh, $iodev, $pdev, "device numbers");
+  helper::cmp_nums($cmdfh, $outfh, $ioino, $pino, "inode numbers");
+  helper::cmp_nums($cmdfh, $outfh, $iomode, $pmode, "file modes");
+  helper::cmp_nums($cmdfh, $outfh, $ionlink, $pnlink, "number of links");
+  helper::cmp_nums($cmdfh, $outfh, $iouid, $puid, "user ids");
+  helper::cmp_nums($cmdfh, $outfh, $iogid, $pgid, "group ids");
+  helper::cmp_nums($cmdfh, $outfh, $iordev, $prdev, "device ids");
+  helper::cmp_nums($cmdfh, $outfh, $iosize, $psize, "file sizes");
+  helper::cmp_nums($cmdfh, $outfh, $ioatime, $patime, "access times");
+  helper::cmp_nums($cmdfh, $outfh, $iomtime, $pmtime, "modification times");
+  helper::cmp_nums($cmdfh, $outfh, $ioctime, $pctime, "inode change times");
+  helper::cmp_nums($cmdfh, $outfh, $ioblksize, $pblksize, "block sizes");
+  helper::cmp_nums($cmdfh, $outfh, $ioblks, $pblks, "blocks allocated");
+}
+
+  
+# Prints out the stat buffer and verifies that it matches
+# Perl's output
+sub verify_stat
+{
+  my ($cmdfh, $outfh, $cmd, $is_alpha, $bits, @stats) = @_;
+  my $i=0;
+
+  my $cmdstr;
+  # Print out the stat buffer
+  if ($is_alpha == 1) {
+      $cmdstr = 'PRINT $buf 0 16 LONG 16 16 INT 32 8 LONG 40 4 INT 48 40 LONG'."\n";
+  } elsif ($bits == 32) {
+      $cmdstr = 'PRINT $buf 0 8 LONG 12 24 INT 44 8 LONG 48 8 INT 56 24 LONG'."\n";
+  } else {
+      $cmdstr = 'PRINT $buf 0 24 LONG 24 16 INT 48 32 LONG 88 8 LONG 104 8 LONG'."\n";     
+  }
+  helper::send_cmd($cmdfh, $outfh, "PRINT", $cmdstr);
+
+  my $res = <$outfh>;
+  chop($res);
+
+  my @iostats = split(' ', $res);
+  foreach my $iostat (@iostats) {
+    $iostats[$i] = oct($iostat);
+    $i++;
+  }
+
+  cmp_stats($cmdfh, $outfh, $is_alpha, $bits, @iostats, @stats);
+}
+
+sub process_cmd
+{
+  my ($file, $use_system, $is_alpha) = @_;
+  
+# Get tests directory
+  my $testdir = $FindBin::Bin;
+
+  eval {
+      if ($is_alpha == 0) {
+         open2(\*OUTFILE, \*CMDFILE, "$testdir/test_driver --np");
+      } else {
+         open2(\*OUTFILE, \*CMDFILE, 
+               "yod -batch -quiet -sz 1 $testdir/test_driver --np");
+      }
+  };
+
+  if ($@) {
+    if ($@ =~ /^open2/) {
+      warn "open2 failed: $!\n$@\n";
+      return;
+    }
+    die;
+
+  }
+
+  my $outfh = \*OUTFILE;
+  my $cmdfh = \*CMDFILE;
+
+  if ($is_alpha == 0) {
+    helper::send_cmd($cmdfh, $outfh, "init", "CALL init\n");
+  }
+
+  my @stats;
+  if ($use_system == 1) {
+      # Get stats for file
+      @stats = stat($file);
+  } 
+  # Allocate the buffer
+  my $cmdstr = '$buf = ALLOC ( $size = CALL sizeof stat )'."\n";
+  helper::send_cmd($cmdfh, $outfh, "alloc", $cmdstr);  
+
+
+  # Issue the stat command
+  $cmdstr = 'CALL stat '."$file ".'$buf'."\n";
+  helper::send_cmd($cmdfh, $outfh, "stat", $cmdstr);  
+  helper::verify_cmd($cmdfh, $outfh, "stat");
+
+  # Attempt to determine type
+  $cmdstr = 'PRINT $size'."\n";
+  helper::send_cmd($cmdfh, $outfh, "print", $cmdstr);  
+  my $statsize = <$outfh>;
+  chop($statsize);
+  $statsize = oct($statsize);
+  my $bits = 32;
+  if ($statsize == 144) {
+      $bits = 64;
+  }
+  
+  if ($use_system == 1) {
+      # Now print the buffer out and verify that it matches
+      # what Perl has
+      verify_stat($cmdfh, $outfh, "stat", $is_alpha, $bits, @stats);
+  }
+
+  # Open the file
+  $cmdstr = '$fd = CALL open '."$file O_RDONLY\n";
+  helper::send_cmd($cmdfh, $outfh, "open", $cmdstr);  
+  helper::verify_cmd($cmdfh, $outfh, "open");
+
+
+  # Now issue an fstat call
+  $cmdstr = 'CALL fstat $fd $buf'."\n";
+  helper::send_cmd($cmdfh, $outfh, "fstat", $cmdstr);  
+  helper::verify_cmd($cmdfh, $outfh, "fstat");
+
+  if ($use_system == 1) {
+      verify_stat($cmdfh, $outfh, "fstat", $is_alpha, $bits, @stats);
+  }
+
+  # Test lstat
+  if ($use_system == 1) {
+      @stats = lstat($file);
+  }
+  
+  $cmdstr = 'CALL lstat '."$file ".'$buf'."\n";
+  helper::send_cmd($cmdfh, $outfh, "lstat", $cmdstr);  
+  helper::verify_cmd($cmdfh, $outfh, "lstat");
+
+  if ($use_system == 1) {
+      verify_stat($cmdfh, $outfh, "lstat", $is_alpha, $bits, @stats);
+  }
+
+  if (0) {
+      # Now do statvfs functions
+      $cmdstr = '$buf2 = ALLOC ( $size2 = CALL sizeof statvfs )'."\n";
+      helper::send_cmd($cmdfh, $outfh, "alloc", $cmdstr);
+      
+      # Clear out the buffer
+      $cmdstr = 'CALL clear $buf2'."\n";
+      helper::send_cmd($cmdfh, $outfh, "CLEAR", $cmdstr);
+      
+      $cmdstr = 'CALL statvfs '."$file ".'$buf2'."\n";
+      helper::send_cmd($cmdfh, $outfh, "statvfs", $cmdstr);  
+      helper::verify_cmd($cmdfh, $outfh, "statvfs");
+               
+      # Print out the statvfs buffer
+      $cmdstr = 'PRINT $buf2 0 16 LONG 16 32 INT 48 16 LONG'."\n";
+      helper::send_cmd($cmdfh, $outfh, "PRINT", $cmdstr);
+      
+      my $res = <$outfh>;
+      chop($res);
+      my @vfsstats1 = split(' ', $res);
+               
+      # Clear out the buffer
+      $cmdstr = 'CALL clear $buf2'."\n";
+      helper::send_cmd($cmdfh, $outfh, "CLEAR", $cmdstr);
+               
+      # Now do fstatvfs
+      $cmdstr = 'CALL fstatvfs $fd $buf2'."\n";
+      helper::send_cmd($cmdfh, $outfh, "fstatvfs", $cmdstr);  
+      helper::verify_cmd($cmdfh, $outfh, "fstatvfs");
+      
+      # Print out the statvfs buffer
+      $cmdstr = 'PRINT $buf2 0 16 LONG 16 32 INT 48 16 LONG'."\n";
+      helper::send_cmd($cmdfh, $outfh, "PRINT", $cmdstr);
+      
+      $res = <$outfh>;
+      chop($res);
+      my @vfsstats2 = split(' ', $res);
+  
+      # Verify the two vfsstats arrays match
+      if (@vfsstats1 != @vfsstats2) {
+         helper::print_and_exit($cmdfh, $outfh, 1, "Two vfsstat arrays unequal lengths\n");
+       }
+      
+      my $i=0;
+
+      foreach my $stat1 (@vfsstats1) {
+         if ($stat1 ne $vfsstats2[$i++]) {
+             my $str = sprintf("vfsstats field %d are not equal (%s != %s)\n",
+                               $i-1, $stat1, $vfsstats2[$i-1]);
+             helper::print_and_exit($cmdfh, $outfh, 1, $str);
+      }
+      }
+  }
+  
+  helper::print_and_exit($cmdfh, $outfh, 0, "stat test successful\n");
+}
+
+
+
+
+my $currarg = 0;
+my $is_alpha = 0;
+if (@ARGV < 2) {
+  usage;
+} elsif (@ARGV > 2) {
+  if ($ARGV[$currarg++] eq "-alpha") {
+    $is_alpha = 1;
+  }
+}
+
+my $use_system= $ARGV[$currarg++];
+my $file = $ARGV[$currarg];
+
+process_cmd($file, $use_system, $is_alpha);
+
diff --git a/libsysio/tests/test_stdfd.pl b/libsysio/tests/test_stdfd.pl
new file mode 100755 (executable)
index 0000000..afd5548
--- /dev/null
@@ -0,0 +1,242 @@
+#!/usr/bin/perl -w
+
+#
+# stdfd test: Verifies that stdin, stdout, and stderr can be opened and 
+#             either written to or read from (in the case of stdin)
+
+use IPC::Open2;
+
+use strict;
+use FindBin;
+use lib "$FindBin::Bin";
+use helper;
+
+sub usage
+{
+  print "Usage ./test_stdfd : Verifies that stdin, stdout, and stderr can be opened and ";
+  print "                   : either written to or read from (in the case of stdin)";
+  exit(-1);
+}
+
+sub mkdev
+{
+  my ($major, $minor) = @_;
+  my $devno = ( (($major & 0xff) << 8) | ($minor & 0xff) );
+
+  return $devno;
+}
+
+sub statit
+{
+  my ($cmdfh, $outfh, $do_print, $name) = @_;
+
+  my $cmd = "CALL stat $name ".'$buf'."\n";
+
+  helper::send_cmd($cmdfh, $outfh, "stat", $cmd);
+  helper::verify_cmd($cmdfh, $outfh, "stat $name");
+
+  # Print out the stat buffer
+  $cmd = 'PRINT $buf 0 8 LONG 12 24 INT 44 8 LONG 52 8 INT 64 24 LONG';
+  $cmd .= "\n";
+  helper::send_cmd($cmdfh, $outfh, "PRINT", $cmd);
+  
+  my $res = <$outfh>;
+  chop($res);
+  my ( $iodev, $ioino, $iomode, $ionlink, $iouid, $iogid, $iordev, 
+       $iosize, $ioblksize, $ioblks, $ioatime, $iomtime, $ioctime ) 
+    = split(' ', $res);
+
+  $iomode = oct($iomode);
+
+  if ($do_print == 1) {
+    # Print out the path
+    my $typechar = helper::get_type($iomode);
+    print STDOUT "$name: $typechar\n";
+  }
+  return 0;
+}
+
+sub do_open
+{
+
+  my ($cmdfh, $outfh, $name, $mode, $num) = @_;
+
+  helper::send_cmd($cmdfh, $outfh, "open", "CALL open $name $mode\n");
+  
+  my $res = helper::verify_cmd($cmdfh, $outfh, "open $name");
+
+  #chop($res);
+  $res = oct($res);
+  if ($res < 0) {
+    helper::print_and_exit($cmdfh, $outfh, 1, "Unable to open $name\n");
+  }
+
+
+  if ($res == $num) {
+      return $res;
+  }
+
+  helper::send_cmd($cmdfh, $outfh, "dup2", "CALL dup2 $res $num\n");
+  $res = helper::verify_cmd($cmdfh, $outfh, "dup2");
+  $res = oct($res);
+
+  if ($res != $num) {
+    helper::print_and_exit($cmdfh, $outfh, 1, "Unable to dup $name (res was $res)\n");
+  }
+}
+
+sub do_mknod
+{
+
+  my ($cmdfh, $outfh, $do_print, $name, $perm_num, $minor) = @_;
+
+  my $perm = 'S_IFCHR|'.$perm_num;
+  my $devno = mkdev(0, $minor);
+
+  helper::send_cmd($cmdfh, $outfh, "mknod", "CALL mknod $name $perm $devno\n");
+  
+  helper::verify_cmd($cmdfh, $outfh, "mknod $name");
+
+  my $statres = statit($cmdfh, $outfh, $do_print, $name);
+  if ($statres != 0) {
+    helper::print_and_exit($cmdfh, $outfh, 1, "stat on $name failed\n");
+  }
+}
+
+sub process_cmd
+{
+  my ($dirname, $do_print, $is_alpha) = @_;
+# Get tests directory
+my $testdir = $0;
+$testdir =~ s/\/\w+.pl$//;
+  eval {
+      if ($is_alpha == 1) {
+         open2(\*OUTFILE, \*CMDFILE, "yod -sz 1 -quiet -batch $testdir/test_driver --np");
+      } else {
+         open2(\*OUTFILE, \*CMDFILE, "$testdir/test_driver --np");
+      }
+  };
+
+  if ($@) {
+    if ($@ =~ /^open2/) {
+      warn "open2 failed: $!\n$@\n";
+      return;
+    }
+    die;
+
+  }
+
+  my $outfh = \*OUTFILE;
+  my $cmdfh = \*CMDFILE;
+
+  if ($is_alpha == 0) {
+      helper::send_cmd($cmdfh, $outfh, "init", "CALL init incore ".'"0777+0+0"'." 0\n");
+      helper::verify_cmd($cmdfh, $outfh, "init incore");
+  }
+
+
+  # Get a stat buffer
+  my $cmd = '$buf = ALLOC ( $size = CALL sizeof stat )'."\n";
+  helper::send_cmd($cmdfh, $outfh, "alloc", $cmd);
+
+  if ($is_alpha == 0) {
+  # Make the test directory
+  $cmd = "CALL mkdir $dirname 0777\n";
+  helper::send_cmd($cmdfh, $outfh, "mkdir", $cmd);
+  helper::verify_cmd($cmdfh, $outfh, "mkdir");
+
+
+  # Change working dir to test dir
+  $cmd = "CALL chdir $dirname\n";
+  helper::send_cmd($cmdfh, $outfh, "chdir", $cmd);
+  helper::verify_cmd($cmdfh, $outfh, "chdir");
+
+
+  # Create the 3 special files
+  do_mknod($cmdfh, $outfh, $do_print, "stdin", "0444", 0);
+  do_mknod($cmdfh, $outfh, $do_print, "stdout", "0222", 1);
+  do_mknod($cmdfh, $outfh, $do_print, "stderr", "0222", 2);
+
+  # Open the 3 files
+  do_open($cmdfh, $outfh, "stdin", "O_RDONLY", 0);
+  do_open($cmdfh, $outfh, "stdout", "O_WRONLY", 1);
+  do_open($cmdfh, $outfh, "stderr", "O_WRONLY", 2);
+ } 
+  #helper::send_cmd($cmdfh, $outfh, "debug", "CALL debug 5\n");
+
+  # Read from stdin, write to stdout and stderr
+
+  # Send "delay" option to read which will give us time to 
+  # put something in stdin (since we can't send an eof)
+  $cmd = "CALL read 0 ".'$buf 38'." delay\n";
+  print $cmdfh $cmd;
+  # Give time to process command
+  sleep 1;
+
+  # Send random junk...
+  print $cmdfh "This message is exactly 38 bytes long\n";
+  sleep 0.5;
+
+  # Make sure read was OK
+  my $res = <$outfh>;
+  chop($res);
+  if ($res ne "0000 ") {
+    helper::print_and_exit($cmdfh, $outfh, 1, "ERROR! Command $cmd failed with code $res\n");
+  }
+    
+  # See how many bytes we got...
+  my $bytes = helper::verify_cmd($cmdfh, $outfh, "read");
+  $bytes = oct($bytes);
+  if ($bytes == 0) {
+    helper::print_and_exit($cmdfh, $outfh, 0, "test_stdfd successful but read nothing\n");
+  }
+
+  if ($bytes < 0) {
+    helper::print_and_exit($cmdfh, $outfh, 0, "test_stdfd unsuccessful\n");
+  }
+
+  $cmd = "CALL write 1 ".'$buf '."$bytes\n";
+  print $cmdfh $cmd;
+
+  # Suck up the stdout...
+  $res = <$outfh>;
+  chop($res);
+  
+  $res = <$outfh>;
+  chop($res);
+  $res = oct($res);
+
+  if ($res != 0) {
+    helper::print_and_exit($cmdfh, $outfh, 1, "ERROR! Command $cmd failed with code $res\n");
+  }
+
+  helper::verify_cmd($cmdfh, $outfh, "write stdout");
+
+  $cmd = "CALL write 2 ".'$buf '."$bytes\n";
+  helper::send_cmd($cmdfh, $outfh, "write stderr", $cmd);
+  helper::verify_cmd($cmdfh, $outfh, "write stderr");
+
+  helper::print_and_exit($cmdfh, $outfh, 0, "test_stdfd successful\n");
+}
+
+
+my $is_alpha = 0;
+my $do_print = 0;
+my $i;
+for ($i=0; $i < @ARGV; $i++) {
+  if ($ARGV[$i] eq "-alpha") {
+    $is_alpha =1;
+  } elsif ($ARGV[$i] eq "-print") {
+    $do_print = 1;
+  }
+}
+
+$i--;
+my $dirname = $ARGV[$i];
+
+process_cmd($dirname, $do_print, $is_alpha);
+
+exit 0;
+
diff --git a/libsysio/tests/test_strided.pl b/libsysio/tests/test_strided.pl
new file mode 100755 (executable)
index 0000000..5468d9b
--- /dev/null
@@ -0,0 +1,462 @@
+#!/usr/bin/perl -w
+
+#
+# strided IO test: Perform a series of different reads/writes
+#                  using readx and writex with different buffer
+#                  configurations 
+#
+
+use IPC::Open2;
+
+use strict;
+use FindBin;
+use lib "$FindBin::Bin";
+use helper;
+
+sub usage
+{
+  print "Usage: ./test_rw.pl [-alpha] <file>: Write to/read from file\n";
+  exit(-1);
+}
+
+sub verify_result
+{
+       my ($cmdfh, $outfh, $cmdstr, $exp_val, $eq_op) = @_;
+       my $print_err = 0;
+
+       my $res = helper::verify_cmd($cmdfh, $outfh, $cmdstr);
+       $res = oct($res);
+
+       if ($eq_op eq "!=") {
+               if ($res != $exp_val) {
+                       print STDOUT "Error! $cmdstr returned $res insted of $exp_val\n";
+                       system("killall test_driver");
+                       exit(1);
+               }
+       } else {
+               if ($eq_op eq ">") {
+                       if ($res > $exp_val) {
+                               $print_err = 1;
+                       }
+               } elsif ($eq_op eq "<")  {
+                       if ($res < $exp_val) {
+                               $print_err = 1;
+                       }
+               } elsif ($eq_op eq "==") {
+                       if ($res == $exp_val) {
+                               $print_err = 1;
+                       }
+               }
+               if ($print_err == 1) {
+                       print STDOUT "Error! $cmdstr returned $res\n";
+               }
+       }
+
+}
+
+# Initilize the iovec number $vecnum
+# in the iovec buffer $vecname with buffer
+# pos $buf and using len $veclen
+sub set_iovec
+{
+       my ($cmdfh, $outfh, $vecname, $vecnum, $buf, $veclen) = @_;
+
+       my $cmdstr = 'CALL init_iovec $'.$buf." 0 $veclen ";
+       $cmdstr .= "$vecnum ".'$'."$vecname\n";
+
+       helper::send_cmd($cmdfh, $outfh, "init_iovec", $cmdstr);
+       helper::verify_cmd($cmdfh, $outfh, "init_iovec");
+}
+
+
+sub setup_xtvecs
+{
+       my ($cmdfh, $outfh) = @_;
+
+       # Get size of iovecs
+       my $cmdstr = '$xtvsize = CALL sizeof xtvec'."\n";
+       helper::send_cmd($cmdfh, $outfh, "sizeof", $cmdstr);
+       my $size = helper::verify_cmd($cmdfh, $outfh, "sizeof xtvec");
+       $size = oct($size);
+       $size = $size * 2;
+
+       # Allocate iovec buffer
+       $cmdstr = '$xtvbuf'." = ALLOC $size\n";
+       helper::send_cmd($cmdfh, $outfh, "alloc", $cmdstr);
+       
+
+       # Now initilize xtvbuf
+       $cmdstr = "CALL init_xtvec 0 100 0 ". '$xtvbuf'."\n";
+       helper::send_cmd($cmdfh, $outfh, "init_xtvec", $cmdstr);
+       helper::verify_cmd($cmdfh, $outfh, "init_xtvec");
+
+       $cmdstr = "CALL init_xtvec 1000 100 1 ". '$xtvbuf'."\n";
+       helper::send_cmd($cmdfh, $outfh, "init_xtvec", $cmdstr);
+       helper::verify_cmd($cmdfh, $outfh, "init_xtvec");
+}
+
+sub check_buf
+{
+
+       my ($cmdfh, $outfh, $bufsize, $bufname, 
+                       $readcmd, $digit, $offset) = @_;
+       
+       my $cmdstr = 'CALL checkbuf $'. "$bufname $bufsize $digit $offset\n";
+       helper::send_cmd($cmdfh, $outfh, "checkbuf", $cmdstr);
+       my $res = helper::verify_cmd($cmdfh, $outfh, "checkbuf");
+       $res = oct($res);
+
+       if ($res != 0) {
+               print STDOUT "$readcmd did not return all $digit 's\n";
+} 
+}
+
+# Fill given buffer with $digit up to $size
+# starting at $offset
+sub fill_buf
+{
+       my ($cmdfh, $outfh, $buf, $digit, $size, $off) = @_;
+
+       my $cmdstr = "CALL setbuf $digit $size ".'$'."$buf $off\n";
+       helper::send_cmd($cmdfh, $outfh, "setbuf", $cmdstr);            
+}
+
+sub alloc_iovbuf
+{
+       my ($cmdfh, $outfh, $numbufs, $num) = @_;
+
+       # Get size of iovecs
+       my $cmdstr = '$iovsize = CALL sizeof iovec'."\n";
+       helper::send_cmd($cmdfh, $outfh, "sizeof", $cmdstr);
+       my $size = helper::verify_cmd($cmdfh, $outfh, "sizeof iovec");
+       $size = oct($size);
+       $size = $size * $numbufs;
+
+       # Allocate iovec buffer
+       $cmdstr = '$iovbuf'."$num = ALLOC $size\n";
+       helper::send_cmd($cmdfh, $outfh, "alloc", $cmdstr);
+
+       my $retstr = "iovbuf".$num;
+       
+       return $retstr;
+}
+
+sub do_rwcalls
+{
+       my ($cmdfh, $outfh, $fh) = @_;
+
+       # Allocate and initilize xtvecs
+       setup_xtvecs($cmdfh, $outfh);
+
+       # Allocate 2 different iovecs, one for cases
+       # (a) and (d) and one for cases (b) and (c)
+       my $iovbuf1 = alloc_iovbuf($cmdfh, $outfh, 3, 0);
+       my $iovbuf2 = alloc_iovbuf($cmdfh, $outfh, 1, 1);
+       
+       # Allocate four buffers, each 200 bytes long
+       my $cmdstr = '$buf1 '. "= ALLOC 200\n";
+       helper::send_cmd($cmdfh, $outfh, "alloc", $cmdstr);
+       $cmdstr = '$buf2 '. "= ALLOC 200\n";
+       helper::send_cmd($cmdfh, $outfh, "alloc", $cmdstr);
+       $cmdstr = '$buf3 '. "= ALLOC 200\n";
+       helper::send_cmd($cmdfh, $outfh, "alloc", $cmdstr);
+       $cmdstr = '$buf4 '. "= ALLOC 200\n";
+       helper::send_cmd($cmdfh, $outfh, "alloc", $cmdstr);
+       
+       # Case (a):
+       #  xtvec[] = { { 0, 100 }, {1000, 100} }
+       #  iovec[] = { { buf1, 50}, {buf2, 50}, {buf3, 100}
+
+       # Fill each of the 3 buffers of.  They will be filled
+       # as follows:
+       #  buf1 -->    0- 49:  1
+       #       -->   49-200:  2
+       #  buf2 -->    0- 49:  3
+       #       -->   49-200:  4
+       #  buf3 -->    0-100:  5
+       #       -->  100-200:  6
+       fill_buf($cmdfh, $outfh, "buf1", 1, 50, 0);
+       fill_buf($cmdfh, $outfh, "buf1", 2, 150, 50);
+       fill_buf($cmdfh, $outfh, "buf2", 3, 50, 0);
+       fill_buf($cmdfh, $outfh, "buf2", 4, 150, 50);
+       fill_buf($cmdfh, $outfh, "buf3", 5, 100, 0);
+       fill_buf($cmdfh, $outfh, "buf3", 6, 100, 100);
+
+       # Initiize iovecs
+       set_iovec($cmdfh, $outfh, $iovbuf1, 0, "buf1", 50);
+       set_iovec($cmdfh, $outfh, $iovbuf1, 1, "buf2", 50);
+       set_iovec($cmdfh, $outfh, $iovbuf1, 2, "buf3", 100);
+
+       # Write out to $fh
+       $cmdstr = 'CALL writex $'."$fh $iovbuf1 3 ".'$xtvbuf '."2\n";
+       helper::send_cmd($cmdfh, $outfh, "writex", $cmdstr);
+       verify_result($cmdfh, $outfh, "writex (case a)", 200, "!=");
+
+       # Clear out the buffers
+       fill_buf($cmdfh, $outfh, "buf1", 0, 200, 0);
+       fill_buf($cmdfh, $outfh, "buf2", 0, 200, 0);
+       fill_buf($cmdfh, $outfh, "buf3", 0, 200, 0);
+
+       # Read it back
+       $cmdstr = 'CALL readx $'."$fh $iovbuf1 3 ".'$xtvbuf '."2\n";
+       helper::send_cmd($cmdfh, $outfh, "readx", $cmdstr);
+       verify_result($cmdfh, $outfh, "readx (case a)", 200, "!=");
+
+       # Make sure we got what we expected...
+       check_buf($cmdfh, $outfh, 50, "buf1", "readx (case a)", 1, 0);
+       check_buf($cmdfh, $outfh, 50, "buf2", "readx (case a)", 3, 0);
+       check_buf($cmdfh, $outfh, 100, "buf3", "readx (case a)", 5, 0);
+
+  # Case (b):
+       #  xtvec[] = { { 0, 100 }, {1000, 100} }
+       #  iovec[] = { { buf4, 200} }
+
+
+       # Fill buf4 with 7's...
+       fill_buf($cmdfh, $outfh, "buf4", 7, 200, 0);
+
+       # Initiize iovecs
+       set_iovec($cmdfh, $outfh, $iovbuf2, 0, "buf4", 200);
+
+       # Write out to $fh
+       $cmdstr = 'CALL writex $'."$fh ".'$'."$iovbuf2 1 ".'$xtvbuf '."2\n";
+       helper::send_cmd($cmdfh, $outfh, "writex", $cmdstr);
+       verify_result($cmdfh, $outfh, "writex (case b)", 200, "!=");
+
+       # Clear out the buffer
+       fill_buf($cmdfh, $outfh, "buf4", 0, 200, 0);
+
+       # Read it back
+       $cmdstr = 'CALL readx $'."$fh $iovbuf2 1 ".'$xtvbuf '."2\n";
+       helper::send_cmd($cmdfh, $outfh, "readx", $cmdstr);
+       verify_result($cmdfh, $outfh, "readx (case b)", 200, "!=");
+
+       # Make sure we got what we expected...
+       check_buf($cmdfh, $outfh, 200, "buf4", "readx (case b)", 7, 0);
+
+
+       # Case (c):
+       #  xtvec[] = { { 0, 100 }, {1000, 100} }
+       #  iovec[] = { { buf4, 40} }
+
+       # Fill buf4 with 8's...
+       fill_buf($cmdfh, $outfh, "buf4", 8, 200, 0);
+
+       # Initiize iovecs
+       set_iovec($cmdfh, $outfh, $iovbuf2, 0, "buf4", 40);
+
+       # Write out to $fh
+       $cmdstr = 'CALL writex $'."$fh $iovbuf2 1 ".'$xtvbuf '."2\n";
+       helper::send_cmd($cmdfh, $outfh, "writex", $cmdstr);
+       verify_result($cmdfh, $outfh, "writex (case c)", 40, "!=");
+
+       # Clear out the buffer
+       fill_buf($cmdfh, $outfh, "buf4", 0, 200, 0);
+
+       # Read it back
+       $cmdstr = 'CALL readx $'."$fh $iovbuf2 1 ".'$xtvbuf '."2\n";
+       helper::send_cmd($cmdfh, $outfh, "readx", $cmdstr);
+       verify_result($cmdfh, $outfh, "readx (case c)", 40, "!=");
+
+       # Make sure we got what we expected...
+       check_buf($cmdfh, $outfh, 40, "buf4", "readx (case c)", 8, 0);
+
+
+       # Case (d):
+       #  xtvec[] = { { 0, 100 }, {1000, 100} }
+       #  iovec[] = { { buf1, 40}, {buf2, 150}, {buf3, 200} }
+
+       # Fill each of the 3 buffers of.  They will be filled
+       # as follows:
+       #  buf1 -->    0- 39:  1
+       #       -->   39-200:  2
+       #  buf2 -->    0-150:  3
+       #       -->  150-200:  4
+       #  buf3 -->    0-  9:  5
+       #       -->   10-200:  6
+       fill_buf($cmdfh, $outfh, "buf1", 1, 40, 0);
+       fill_buf($cmdfh, $outfh, "buf1", 2, 160, 40);
+       fill_buf($cmdfh, $outfh, "buf2", 3, 150, 0);
+       fill_buf($cmdfh, $outfh, "buf2", 4, 50, 150);
+       fill_buf($cmdfh, $outfh, "buf3", 5, 10, 0);
+       fill_buf($cmdfh, $outfh, "buf3", 6, 190, 10);
+
+       # Initiize iovecs
+       set_iovec($cmdfh, $outfh, $iovbuf1, 0, "buf1", 40);
+       set_iovec($cmdfh, $outfh, $iovbuf1, 1, "buf2", 150);
+       set_iovec($cmdfh, $outfh, $iovbuf1, 2, "buf3", 200);
+
+       # Write out to $fh
+       $cmdstr = 'CALL writex $'."$fh $iovbuf1 3 ".'$xtvbuf '."2\n";
+       helper::send_cmd($cmdfh, $outfh, "writex", $cmdstr);
+       verify_result($cmdfh, $outfh, "writex (case d)", 200, "!=");
+
+       # Clear out the buffers
+       fill_buf($cmdfh, $outfh, "buf1", 0, 200, 0);
+       fill_buf($cmdfh, $outfh, "buf2", 0, 200, 0);
+       fill_buf($cmdfh, $outfh, "buf3", 0, 200, 0);
+
+       # Read it back
+       $cmdstr = 'CALL readx $'."$fh $iovbuf1 3 ".'$xtvbuf '."2\n";
+       helper::send_cmd($cmdfh, $outfh, "readx", $cmdstr);
+       verify_result($cmdfh, $outfh, "readx (case d)", 200, "!=");
+
+       # Make sure we got what we expected...
+       check_buf($cmdfh, $outfh, 40, "buf1", "readx (case d)", 1, 0);
+       check_buf($cmdfh, $outfh, 150, "buf2", "readx (case d)", 3, 0);
+       check_buf($cmdfh, $outfh, 10, "buf3", "readx (case d)", 5, 0);
+
+       # Case (e):
+  #  xtvec[] = { { 0, 100 }, {1000, 100} }
+  #  iovec[] = { { buf1, 30}, {buf2, 30}, {buf3, 30} }
+
+       # Fill each of the 3 buffers as follows:
+       # buf1 -->   0- 30: 1
+       #      -->  30-200: 2
+       # buf2 -->   0- 30: 3
+       #      -->  30-200: 4
+       # buf3 -->   0- 30: 5
+       #      -->  30-200: 6
+       fill_buf($cmdfh, $outfh, "buf1", 1, 30, 0);
+       fill_buf($cmdfh, $outfh, "buf1", 2, 170, 30);
+       fill_buf($cmdfh, $outfh, "buf2", 3, 30, 0);
+       fill_buf($cmdfh, $outfh, "buf2", 4, 170, 30);
+       fill_buf($cmdfh, $outfh, "buf3", 5, 30, 0);
+       fill_buf($cmdfh, $outfh, "buf3", 6, 170, 30);
+
+               # Initiize iovecs
+       set_iovec($cmdfh, $outfh, $iovbuf1, 0, "buf1", 30);
+       set_iovec($cmdfh, $outfh, $iovbuf1, 1, "buf2", 30);
+       set_iovec($cmdfh, $outfh, $iovbuf1, 2, "buf3", 30);
+
+       # Write out to $fh
+       $cmdstr = 'CALL writex $'."$fh $iovbuf1 3 ".'$xtvbuf '."2\n";
+       helper::send_cmd($cmdfh, $outfh, "writex", $cmdstr);
+       verify_result($cmdfh, $outfh, "writex (case e)", 90, "!=");
+
+       # Clear out the buffers
+       fill_buf($cmdfh, $outfh, "buf1", 0, 200, 0);
+       fill_buf($cmdfh, $outfh, "buf2", 0, 200, 0);
+       fill_buf($cmdfh, $outfh, "buf3", 0, 200, 0);
+
+       # Read it back
+       $cmdstr = 'CALL readx $'."$fh $iovbuf1 3 ".'$xtvbuf '."2\n";
+       helper::send_cmd($cmdfh, $outfh, "readx", $cmdstr);
+       verify_result($cmdfh, $outfh, "readx (case e)", 90, "!=");
+
+       # Make sure we got what we expected...
+       check_buf($cmdfh, $outfh, 30, "buf1", "readx (case e)", 1, 0);
+       check_buf($cmdfh, $outfh, 30, "buf2", "readx (case e)", 3, 0);
+       check_buf($cmdfh, $outfh, 30, "buf3", "readx (case e)", 5, 0);
+       
+  # Case (f):
+  #  xtvec[] = { { 0, 100 }, {1000, 100} }
+  #  iovec[] = { { buf1, 30}, {buf2, 90}, {buf3, 200} }
+
+       # Fill each of the 3 buffers as follows:
+       # buf1 -->   0- 30: 1
+       #      -->  30-200: 2
+       # buf2 -->   0- 70: 3
+  #      -->  70- 90: 4
+       #      -->  90-200: 5
+       # buf3 -->   0-200: 6
+       fill_buf($cmdfh, $outfh, "buf1", 1, 30, 0);
+       fill_buf($cmdfh, $outfh, "buf1", 2, 170, 30);
+       fill_buf($cmdfh, $outfh, "buf2", 3, 70, 0);
+       fill_buf($cmdfh, $outfh, "buf2", 4, 90, 70);
+       fill_buf($cmdfh, $outfh, "buf2", 5, 110, 90);
+       fill_buf($cmdfh, $outfh, "buf3", 6, 200, 0);
+
+               # Initiize iovecs
+       set_iovec($cmdfh, $outfh, $iovbuf1, 0, "buf1", 30);
+       set_iovec($cmdfh, $outfh, $iovbuf1, 1, "buf2", 90);
+       set_iovec($cmdfh, $outfh, $iovbuf1, 2, "buf3", 200);
+
+       # Write out to $fh
+       $cmdstr = 'CALL writex $'."$fh $iovbuf1 3 ".'$xtvbuf '."2\n";
+       helper::send_cmd($cmdfh, $outfh, "writex", $cmdstr);
+       verify_result($cmdfh, $outfh, "writex (case f)", 200, "!=");
+
+       # Clear out the buffers
+       fill_buf($cmdfh, $outfh, "buf1", 0, 200, 0);
+       fill_buf($cmdfh, $outfh, "buf2", 0, 200, 0);
+       fill_buf($cmdfh, $outfh, "buf3", 0, 200, 0);
+
+       # Read it back
+       $cmdstr = 'CALL readx $'."$fh $iovbuf1 3 ".'$xtvbuf '."2\n";
+       helper::send_cmd($cmdfh, $outfh, "readx", $cmdstr);
+       verify_result($cmdfh, $outfh, "readx (case f)", 200, "!=");
+
+       # Make sure we got what we expected...
+       check_buf($cmdfh, $outfh, 30, "buf1", "readx (case f)", 1, 0);
+       check_buf($cmdfh, $outfh, 70, "buf2", "readx (case f)", 3, 0);
+       check_buf($cmdfh, $outfh, 20, "buf2", "readx (case f)", 4, 70);
+       check_buf($cmdfh, $outfh, 70, "buf3", "readx (case f)", 6, 0);
+       
+}
+
+
+sub process_cmd
+{
+  my ($file, $is_alpha) = @_;
+  
+  # Get tests directory
+  my $testdir = $FindBin::Bin;
+
+  eval {
+      if ($is_alpha == 0) {
+                                       open2(\*OUTFILE, \*CMDFILE, "$testdir/test_driver --np");
+      } else {
+                                       open2(\*OUTFILE, \*CMDFILE, 
+                                                               "yod -quiet -sz 1 $testdir/test_driver --np");
+      }
+  };
+
+  if ($@) {
+    if ($@ =~ /^open2/) {
+      warn "open2 failed: $!\n$@\n";
+      return;
+    }
+    die;
+
+  }
+
+  my $outfh = \*OUTFILE;
+  my $cmdfh = \*CMDFILE;
+
+  if ($is_alpha == 0) {
+    helper::send_cmd($cmdfh, $outfh, "init", "CALL init\n");
+  }
+  
+  # Open file
+  my $cmdstr = '$fd = CALL open '."$file O_RDWR|O_CREAT|O_TRUNC S_IRWXU\n";
+  helper::send_cmd($cmdfh, $outfh, "open", $cmdstr);
+       helper::verify_cmd($cmdfh, $outfh, $cmdstr);
+
+   
+       do_rwcalls($cmdfh, $outfh, "fd");
+
+  # Clean up
+  $cmdstr = 'CALL close $fd'."\n";
+  helper::send_cmd($cmdfh, $outfh, "close", $cmdstr);
+
+#      system("rm -f $file");
+  helper::print_and_exit($cmdfh, $outfh, 0, "strided IO test successful\n");
+}
+
+my $currarg = 0;
+my $is_alpha = 0;
+
+if (@ARGV < 1) {
+  usage;
+} elsif (@ARGV > 1 ) {
+  if ($ARGV[$currarg++] eq "-alpha") {
+    $is_alpha = 1;
+  }
+}
+
+my $file = $ARGV[$currarg];
+
+process_cmd($file, $is_alpha);
+
+exit 0;
diff --git a/libsysio/tests/test_symlink.pl b/libsysio/tests/test_symlink.pl
new file mode 100755 (executable)
index 0000000..23d5185
--- /dev/null
@@ -0,0 +1,247 @@
+#!/usr/bin/perl -w
+
+#
+# symlink test: Verify that symbolic links work
+#
+
+use IPC::Open2;
+
+use strict;
+use FindBin;
+use lib "$FindBin::Bin";
+use helper;
+
+sub usage
+{
+  print "Usage: ./test_symlink.pl [-alpha] <src> <dest>: Create a symlink from src to dest\n";
+  exit(-1);
+}
+
+sub clean_exit
+{
+  my ($cmdfh, $outfh, $exit_num, $exit_str) = @_;
+
+  print STDOUT "$exit_str";
+
+  # Free buffers
+  my $cmdstr =  'FREE $srcbuf'."\n";
+
+  print $cmdfh $cmdstr;
+
+  my $res = <$outfh>;
+  chop($res);
+  if ($res ne "0000 ") {
+    print STDOUT "ERROR! Failed to free srcbuf (code $res)\n";
+  }
+
+  $cmdstr =  'FREE $destbuf'."\n";
+
+  print $cmdfh $cmdstr;
+
+  $res = <$outfh>;
+  chop($res);
+  if ($res ne "0000 ") {
+    print STDOUT "ERROR! Failed to free destbuf (code $res)\n";
+  }
+
+  print $cmdfh "exit\n";
+  close $outfh;
+
+  # Give test_driver time to finish
+  sleep 0.000001;
+
+  exit $exit_num;
+}
+
+sub process_cmd
+{
+  my ($src, $dest, $is_alpha) = @_;
+  
+  # Get tests directory
+  my $testdir = $FindBin::Bin;
+
+  eval {
+      if ($is_alpha == 0) {
+         open2(\*OUTFILE, \*CMDFILE, "$testdir/test_driver --np");
+      } else {
+         open2(\*OUTFILE, \*CMDFILE, "yod -quiet -sz 1 $testdir/test_driver --np");
+      }
+  };
+
+  if ($@) {
+    if ($@ =~ /^open2/) {
+      warn "open2 failed: $!\n$@\n";
+      return;
+    }
+    die;
+
+  }
+
+  my $outfh = \*OUTFILE;
+  my $cmdfh = \*CMDFILE;
+
+  if ($is_alpha == 0) {
+    helper::send_cmd($cmdfh, $outfh, "init", "CALL init\n");
+  }
+  
+  # Get the filesize of src
+  my $size = -s $src;
+  my $bufsize;
+
+  if ( $size > 1024) { # Arbitrary limit
+    $bufsize = 1024;
+  } else {
+    $bufsize = $size;
+  }
+
+  # Create the symbolic link from src to dest
+  my $cmdstr = "CALL symlink $src $dest\n";
+  helper::send_cmd($cmdfh, $outfh, "open", $cmdstr);
+
+  helper::verify_cmd($cmdfh, $outfh, "symlink");
+
+  # Open src 
+  $cmdstr = '$src = CALL open '."$src O_RDONLY\n";
+  helper::send_cmd($cmdfh, $outfh, "open", $cmdstr);
+
+  # Open dest 
+  $cmdstr = '$dest = CALL open '."$dest O_RDONLY\n";
+  helper::send_cmd($cmdfh, $outfh, "open", $cmdstr);
+  
+  my $res = helper::verify_cmd($cmdfh, $outfh, "open $dest");
+
+  # Allocate buffer for src
+  $cmdstr = '$srcbuf = ALLOC '."$bufsize\n";
+  helper::send_cmd($cmdfh, $outfh, "ALLOC", $cmdstr);
+
+  # Allocate buffer for dest
+  $cmdstr = '$destbuf = ALLOC '."$bufsize\n";
+  helper::send_cmd($cmdfh, $outfh, "ALLOC", $cmdstr);
+
+
+  # Read size bytes from src and dest, then compare them and verify they
+  # are the same
+  $cmdstr = 'CALL read $src $srcbuf '."$bufsize\n";
+  helper::send_cmd($cmdfh, $outfh, "read $src", $cmdstr);
+    
+  $res = helper::verify_cmd($cmdfh, $outfh, "read $src");
+  my $readb = oct($res);
+
+  # Now read $readb from dest
+  $cmdstr = 'CALL read $dest $destbuf '."$readb\n";
+  helper::send_cmd($cmdfh, $outfh, "read $dest", $cmdstr);
+    
+  $res = helper::verify_cmd($cmdfh, $outfh, "read $dest");
+
+  my $errstr;
+  if ($readb != oct($res)) {
+      $errstr = "ERROR!  Read $readb bytes from src but only $res bytes from dest\n";
+      clean_exit($cmdfh, $outfh, 1, $errstr);
+  }
+
+  # Compare the two buffers
+  $cmdstr = 'CALL cmpstr $srcbuf $destbuf'."\n";
+  helper::send_cmd($cmdfh, $outfh, "cmpstr", $cmdstr);
+
+  # Verify that it returned an error
+  $cmdstr = 'PRINT $$';
+  $cmdstr .= "\n";
+  helper::send_cmd($cmdfh, $outfh, "PRINT", $cmdstr);  
+
+  $res = <$outfh>;
+  chop($res);
+
+  $res = helper::verify_cmd($cmdfh, $outfh, "cmpstr");
+  $res = oct($res);
+  if ($res != 0) {
+      $errstr = "ERROR! Buffers from $src and $dest do not match\n";
+      clean_exit($cmdfh, $outfh, 1, $errstr);
+  }
+
+  # Clean up
+  $cmdstr = 'CALL close $src'."\n";
+  helper::send_cmd($cmdfh, $outfh, "close", $cmdstr);
+  $cmdstr = 'CALL close $dest'."\n";
+  helper::send_cmd($cmdfh, $outfh, "close", $cmdstr);
+
+ # Clear out destbuf
+  $cmdstr = 'CALL clear $destbuf'."\n";
+  helper::send_cmd($cmdfh, $outfh, "CLEAR", $cmdstr);
+
+  # Now remove the symbolic link and make sure everything stays the same
+  
+  # Remove the link (this assumes the link is not in incore)
+  $cmdstr = "CALL unlink $dest\n";
+  helper::send_cmd($cmdfh, $outfh, "unlink", $cmdstr);
+  helper::verify_cmd($cmdfh, $outfh, "unlink");
+
+  # Attempt to open the symbolic link.  This should return an error
+  $cmdstr = 'CALL open '."$dest O_RDONLY\n";
+  helper::send_cmd($cmdfh, $outfh, "open", $cmdstr);
+  
+  # Verify that it returned an error
+  $cmdstr = 'PRINT $$';
+  $cmdstr .= "\n";
+  helper::send_cmd($cmdfh, $outfh, "PRINT", $cmdstr);  
+
+  $res = <$outfh>;
+  chop($res);
+
+  if ($res ne "0xffffffff") {
+      $errstr = "ERROR! Open on $dest succeeded (should have failed)\n";
+      clean_exit($cmdfh, $outfh, 1, $errstr);
+  }
+
+  # Now read from the src again and make sure it matches the original
+
+  # Open src 
+  $cmdstr = '$src2 = CALL open '."$src O_RDONLY\n";
+  helper::send_cmd($cmdfh, $outfh, "open", $cmdstr);
+  helper::verify_cmd($cmdfh, $outfh, "open $src(2)");
+
+  $cmdstr = 'CALL read $src2 $destbuf '."$readb\n";
+  helper::send_cmd($cmdfh, $outfh, "read $src(2)", $cmdstr);
+    
+  $res = helper::verify_cmd($cmdfh, $outfh, "read $src(2)");
+
+  if ($readb != oct($res)) {
+      $errstr = "ERROR!  Read $readb bytes from src originally but now only $res bytes\n";
+      clean_exit($cmdfh, $outfh, 1, $errstr);
+  }
+
+  # Compare the two buffers
+  $cmdstr = 'CALL cmpstr $srcbuf $destbuf'."\n";
+  helper::send_cmd($cmdfh, $outfh, "cmpstr", $cmdstr);
+  $res = helper::verify_cmd($cmdfh, $outfh, "cmpstr");
+  $res = oct($res);
+  if ($res != 0) {
+      $errstr = "ERROR! Original buffers from $src and new buf do not match\n";
+      clean_exit($cmdfh, $outfh, 1, $errstr);
+  }
+
+  # Clean up
+  $cmdstr = 'CALL close $src2'."\n";
+  helper::send_cmd($cmdfh, $outfh, "close", $cmdstr);
+
+  clean_exit($cmdfh, $outfh, 0, "Symlink test successful\n");
+  exit 0;
+}
+
+my $currarg = 0;
+my $is_alpha = 0;
+
+if (@ARGV < 2) {
+  usage;
+} elsif (@ARGV > 2 ) {
+  if ($ARGV[$currarg++] eq "-alpha") {
+    $is_alpha = 1;
+  }
+}
+
+my $src = $ARGV[$currarg++];
+my $dest = $ARGV[$currarg];
+
+process_cmd($src, $dest, $is_alpha);
+
+
+exit 0;
diff --git a/libsysio/tests/test_unlink.c b/libsysio/tests/test_unlink.c
new file mode 100644 (file)
index 0000000..9d019d5
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ *    This Cplant(TM) source code is the property of Sandia National
+ *    Laboratories.
+ *
+ *    This Cplant(TM) source code is copyrighted by Sandia National
+ *    Laboratories.
+ *
+ *    The redistribution of this Cplant(TM) source code is subject to the
+ *    terms of the GNU Lesser General Public License
+ *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
+ *
+ *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
+ *    license for use of this work by or on behalf of the US Government.
+ *    Export of this program may require a license from the United States
+ *    Government.
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Questions or comments about this library should be sent to:
+ *
+ * Lee Ward
+ * Sandia National Laboratories, New Mexico
+ * P.O. Box 5800
+ * Albuquerque, NM 87185-1110
+ *
+ * lee@sandia.gov
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef REDSTORM
+#include <getopt.h>
+#else
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#if 0
+#include <dirent.h>
+#endif
+
+#include "sysio.h"
+#include "mount.h"
+
+#include "test.h"
+
+/*
+ * Unlink files.
+ *
+ * Usage: unlink [path...]
+ *
+ * Without any path arguments, the program unlinks files named
+ * by the ocmmand line args.
+ */
+
+static int unlinkit(const char *path);
+static void usage(void);
+
+int
+main(int argc, char *const argv[])
+{
+       int     i;
+       int     err;
+       int     n;
+       extern int _test_sysio_startup(void);
+
+       /*
+        * Parse command line arguments.
+        */
+       while ((i = getopt(argc, argv, "")) != -1)
+               switch (i) {
+
+               default:
+                       usage();
+               }
+
+       /*
+        * Init sysio lib.
+        */
+       err = _test_sysio_startup();
+       if (err) {
+               errno = -err;
+               perror("sysio startup");
+               exit(1);
+       }
+
+       n = argc - optind;
+
+       /*
+        * Try path(s) listed on command-line.
+        */
+       while (optind < argc) {
+               const char *path;
+
+               path = argv[optind++];
+               (void )unlinkit(path);
+       }
+
+       /*
+        * If no command-line arguments, read from stdin until EOF.
+        */
+       if (!n) {
+               int     doflush;
+               static char buf[4096];
+               size_t  len;
+               char    *cp;
+               char    c;
+
+               doflush = 0;
+               while (fgets(buf, sizeof(buf), stdin) != NULL) {
+                       len = strlen(buf);
+                       cp = buf + len - 1;
+                       c = *cp;
+                       *cp = '\0';
+                       if (!doflush)
+                               unlinkit(buf);
+                       doflush = c == '\n' ? 0 : 1;
+               }
+       }
+
+       /*
+        * Clean up.
+        */
+       _sysio_shutdown();
+
+       return 0;
+}
+
+static int
+unlinkit(const char *path)
+{
+
+       if (unlink(path) != 0) {
+               perror(path);
+               return -1;
+       }
+
+       return 0;
+}
+
+static void
+usage()
+{
+
+       (void )fprintf(stderr,
+                      "Usage: unlink"
+                      " [<path> ...\n]");
+
+       exit(1);
+}
diff --git a/libsysio/tests/verifier.pl b/libsysio/tests/verifier.pl
new file mode 100755 (executable)
index 0000000..3afc51b
--- /dev/null
@@ -0,0 +1,161 @@
+#!/usr/bin/perl -w
+
+# Verifies that the contents of a given file produced by producer.pl with the given
+# seed are good
+
+use IPC::Open2;
+
+use strict;
+use helper;
+
+sub usage
+{
+  print "Usage: ./verifier.pl <-seed seed> <-file fname> : Verifies that file fname,\n";
+  print "                                                : produced with the given \n";
+  print "                                                : seed matches\n";
+  exit(-1);
+}
+
+sub get_buf
+{
+  my $MAX_SIZE = 2147483648;
+
+  my $str;
+  my $num;
+  my $len = 0;
+
+  while ($len < 512) {
+    $num = rand $MAX_SIZE;
+    my $tmpstr = sprintf("%d", $num);
+    $str .= $tmpstr;
+    $len += length $tmpstr;
+  }
+
+  return ($len, $str);
+}
+
+
+sub check_file
+{
+  my ($cmdfh, $outfh, $filename) = @_;
+
+
+  # Allocate the read buffer
+  my $cmd = '$buf = ALLOC 1024'."\n";
+  helper::send_cmd($cmdfh, $outfh, "alloc", $cmd);  
+  
+  # Open the file
+  $cmd = '$fd = CALL open '."$filename O_RDONLY\n";
+  helper::send_cmd($cmdfh, $outfh, "open", $cmd);  
+
+  # Verify the system call's output
+  helper::verify_cmd($cmdfh, $outfh, "open");  
+
+  my $total = 0;
+  my $bytes = 0;
+
+  # Read all of the file in 1024 byte chunks
+  do {
+
+    # Clear the buffer
+    $cmd = 'CALL clear $buf'."\n";
+    helper::send_cmd($cmdfh, $outfh, "clear", $cmd);  
+
+    my ($len, $buf) = get_buf;
+
+    $cmd = 'CALL read $fd $buf '."$len\n";
+    helper::send_cmd($cmdfh, $outfh, "read", $cmd);  
+    $bytes = helper::verify_cmd($cmdfh, $outfh, "read");  
+    $bytes = oct($bytes);
+    $total += $bytes;
+    if ($bytes > 0) {
+     
+      # Print out the buffer
+      $cmd = 'PRINT $buf 0 1 STR'."\n";
+      helper::send_cmd($cmdfh, $outfh, "print", $cmd);  
+      my $str = <$outfh>;
+      chop($str);
+      if ($bytes > $len) {
+       $str = substr($str, 0, $len-1);
+      } elsif ($len > $bytes) {
+       $buf = substr($buf, 0, $bytes);
+      }
+      if ($str ne $buf) {
+       my $errstr = "ERROR! Str $str is not equal to str $buf\n";
+       helper::print_and_exit($cmdfh, $outfh, 1, $errstr);
+      }
+    }
+  } while ($bytes > 0);
+
+}
+
+sub verify_file
+{
+  my ($filename, $is_alpha) = @_;
+  
+  eval {
+      if ($is_alpha == 0) {
+         open2(\*OUTFILE, \*CMDFILE, "./test_driver --np");
+      } else {
+         open2(\*OUTFILE, \*CMDFILE, 
+               "yod -batch -quiet -sz 1 ./test_driver --np");
+      }
+  };
+
+  if ($@) {
+    if ($@ =~ /^open2/) {
+      warn "open2 failed: $!\n$@\n";
+      return;
+    }
+    die;
+
+  }
+
+  my $outfh = \*OUTFILE;
+  my $cmdfh = \*CMDFILE;
+
+  if ($is_alpha == 0) {
+    helper::send_cmd($cmdfh, $outfh, "init", "CALL init\n");
+  }
+
+  # Now check the file
+  check_file($cmdfh, $outfh, $filename);
+
+  # Close the file
+  my $cmd = 'CALL close $fd'."\n";
+  helper::send_cmd($cmdfh, $outfh, "close", $cmd);
+
+  helper::verify_cmd($cmdfh, $outfh, "close");
+
+  # All done
+  helper::print_and_exit($cmdfh, $outfh, 0, "File $filename valid\n");
+}
+
+
+my $is_alpha = 0;
+my $seed = time;
+my $filename = "randfile.$seed.$$";
+my $bytes = 1024;
+for (my $i = 0; $i < @ARGV; $i++) 
+{
+  if ($ARGV[$i] eq "-file") {
+    $i++;
+    $filename = $ARGV[$i];
+  } elsif ($ARGV[$i] eq "-seed") {
+    $i++;
+    $seed = $ARGV[$i];
+  } elsif ($ARGV[$i] eq "-alpha") {
+    $is_alpha = 1;
+  } 
+}
+
+# seed the randome number generator
+srand $seed;
+
+verify_file($filename, $is_alpha);
+
+exit 0;
+
+
+
+