--- /dev/null
+Lee Ward <lee@sandia.gov>
--- /dev/null
+ 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!
--- /dev/null
+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.
--- /dev/null
+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:
--- /dev/null
+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
--- /dev/null
+
+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
--- /dev/null
+#!/bin/sh
+
+aclocal &&
+automake --add-missing --copy &&
+${AUTOCONF:-autoconf}
--- /dev/null
+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)
+
--- /dev/null
+STDFD_SRCS = dev/stdfd/stdfd.c
+STDFD_EXTRA = dev/stdfd/stdfd.h dev/stdfd/module.mk
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+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.
--- /dev/null
+/*
+ * 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,
+ ©_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);
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+INCORE_SRCS = drivers/incore/fs_incore.c
+INCORE_EXTRA = drivers/incore/fs_incore.h drivers/incore/module.mk
--- /dev/null
+/*
+ * 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.
+ */
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+NATIVE_SRCS = drivers/native/fs_native.c
+NATIVE_EXTRA = drivers/native/fs_native.h drivers/native/module.mk
--- /dev/null
+SOCKETS_SRCS = drivers/sockets/sockets.c
+SOCKETS_EXTRA = drivers/sockets/module.mk
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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.
+ */
+}
--- /dev/null
+/*
+ * 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();
--- /dev/null
+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
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
--- /dev/null
+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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
+
--- /dev/null
+#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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+# 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
--- /dev/null
+#
+# 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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))
--- /dev/null
+#
+# 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+#!/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;
+
+
+
+
--- /dev/null
+#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;
+}
--- /dev/null
+#!/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 "};"
--- /dev/null
+#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()
+{
+}
--- /dev/null
+#!/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;
--- /dev/null
+TESTS_EXTRA = $(shell ls tests/*.[ch] tests/*.sh tests/*.p[lm]) \
+ tests/Makefile.am tests/Makefile.in tests/module.mk
--- /dev/null
+#!/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;
+
+
+
+
--- /dev/null
+#!/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;
+
+
+
+
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+#!/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;
--- /dev/null
+#!/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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#!/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;
--- /dev/null
+#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);
+ }
+}
--- /dev/null
+/*
+ * 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();
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+#!/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;
+
+
+
+
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+#!/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;
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+#!/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);
+
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+#!/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;
--- /dev/null
+/*
+ * 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");
+}
--- /dev/null
+#!/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);
+
--- /dev/null
+#!/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;
+
--- /dev/null
+#!/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;
--- /dev/null
+#!/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;
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+#!/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;
+
+
+
+